From 3f6b77aae55ce0f4584383365c00fd357ebc2106 Mon Sep 17 00:00:00 2001 From: Sergey Safarov Date: Wed, 1 Aug 2018 19:39:47 +0000 Subject: [PATCH 001/545] FS-11567: freeswitch.spec - relocated modules deps. FS core not use this deps --- freeswitch.spec | 54 +++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/freeswitch.spec b/freeswitch.spec index bc94233a24..1d9313edbb 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -156,13 +156,8 @@ BuildRequires: pcre-devel BuildRequires: speex-devel BuildRequires: sqlite-devel BuildRequires: libtiff-devel -BuildRequires: ldns-devel BuildRequires: libedit-devel -BuildRequires: perl BuildRequires: yasm -%if 0%{?fedora} >= 8 || 0%{?rhel} >= 6 -BuildRequires: perl-ExtUtils-Embed -%endif BuildRequires: pkgconfig %if 0%{?rhel} < 6 && 0%{?fedora} <= 6 BuildRequires: termcap @@ -174,38 +169,17 @@ BuildRequires: db-devel %else BuildRequires: db4-devel %endif -BuildRequires: python-devel BuildRequires: libogg-devel BuildRequires: libvorbis-devel BuildRequires: libjpeg-devel #BuildRequires: mono-devel -BuildRequires: alsa-lib-devel BuildRequires: which BuildRequires: zlib-devel BuildRequires: e2fsprogs-devel BuildRequires: libtheora-devel BuildRequires: libxml2-devel -BuildRequires: bison -BuildRequires: net-snmp-devel -BuildRequires: libmemcached-devel -BuildRequires: portaudio-devel BuildRequires: libsndfile-devel -BuildRequires: broadvoice-devel -BuildRequires: flite-devel -BuildRequires: ilbc2-devel -BuildRequires: g722_1-devel -BuildRequires: codec2-devel -BuildRequires: libsilk-devel BuildRequires: libyuv-devel >= 0.0.1280 -BuildRequires: lua-devel -BuildRequires: mongo-c-driver-devel -BuildRequires: opus-devel -BuildRequires: soundtouch-devel >= 1.7.1 -%if %{build_py26_esl} -BuildRequires: python26-devel -Requires: python26 -%endif -Requires: alsa-lib Requires: libogg Requires: libvorbis Requires: curl @@ -223,7 +197,6 @@ Requires: db4 Requires: gdbm Requires: zlib Requires: libtiff -Requires: python Requires: libtheora Requires: libxml2 Requires: libsndfile @@ -383,6 +356,7 @@ Engine. Uses ODBC to connect to the DB of your choice. Summary: FreeSWITCH mod_enum Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: ldns-devel %description application-enum Provides FreeSWITCH mod_enum, a ENUM dialplan, with API and Dialplan extensions @@ -490,6 +464,7 @@ Provides FreeSWITCH mod_limit, provide application to limit both concurrent and Summary: FreeSWITCH mod_memcache Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: libmemcached-devel %description application-memcache Provides FreeSWITCH mod_memcache, implements an API interface to memcached which @@ -501,6 +476,7 @@ alleviating database load." Summary: FreeSWITCH mod_mongo Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: mongo-c-driver-devel %description application-mongo Provides FreeSWITCH mod_mongo, which implements an API interface to mongodb. @@ -582,6 +558,7 @@ and appearance of the programmable softkeys on Snom phones Summary: FreeSWITCH mod_soundtouch Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: soundtouch-devel >= 1.7.1 %description application-soundtouch Provides FreeSWITCH mod_soundtouch, uses the soundtouch library, which can do @@ -658,6 +635,8 @@ system for backend voicemail systems Summary: FreeSWITCH mod_flite Group: System/Libraries Requires: %{name} = %{version}-%{release} +Requires: flite >= 2.0.0 +BuildRequires: flite-devel >= 2.0.0 %description asrtts-flite Provides FreeSWITCH mod_flite, a interface to the flite text to speech engine @@ -666,6 +645,7 @@ Provides FreeSWITCH mod_flite, a interface to the flite text to speech engine Summary: FreeSWITCH mod_pocketsphinx Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: bison %description asrtts-pocketsphinx Provides FreeSWITCH mod_pocketsphinx, a interface to the OpenSource @@ -715,6 +695,7 @@ Pass-through AMR WideBand Codec support for FreeSWITCH open source telephony pla Summary: BroadVoice16 and BroadVoice32 WideBand Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: broadvoice-devel %description codec-bv BroadVoice16 and BroadVoice32 WideBand Codec support for FreeSWITCH open source telephony platform @@ -723,6 +704,7 @@ BroadVoice16 and BroadVoice32 WideBand Codec support for FreeSWITCH open source Summary: Codec2 Narrow Band Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: codec2-devel %description codec-codec2 CODEC2 narrow band codec support for FreeSWITCH open source telephony platform. @@ -759,6 +741,7 @@ Summary: iLCB Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} Requires: ilbc2 +BuildRequires: ilbc2-devel %description codec-ilbc @@ -792,6 +775,8 @@ MP4V Video Codec support for FreeSWITCH open source telephony platform Summary: Opus Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +Requires: opus >= 1.1 +BuildRequires: opus-devel >= 1.1 %description codec-opus OPUS Codec support for FreeSWITCH open source telephony platform @@ -813,6 +798,7 @@ Sangoma D100 and D500 Codec Card Support Summary: Silk Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: libsilk-devel %description codec-silk Silk Codec (from Skype) support for FreeSWITCH open source telephony platform @@ -821,6 +807,7 @@ Silk Codec (from Skype) support for FreeSWITCH open source telephony platform Summary: Siren Codec support for FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: g722_1-devel %description codec-siren Siren Codec support for FreeSWITCH open source telephony platform. Using @@ -919,6 +906,7 @@ Group: System/Libraries Requires: %{name} = %{version}-%{release} Requires: alsa-lib BuildRequires: alsa-lib-devel +BuildRequires: portaudio-devel %description endpoint-portaudio PortAudio endpoint support for FreeSWITCH open source telephony platform. @@ -1010,7 +998,8 @@ Sangoma SMG-SS7 drivers for FreeTDM %package event-cdr-mongodb Summary: MongoDB CDR Logger for the FreeSWITCH open source telephony platform Group: System/Libraries -Requires: %{name} = %{version}-%{release} +Requires: %{name} = %{version}-%{release} +BuildRequires: mongo-c-driver-devel %description event-cdr-mongodb MongoDB CDR Logger for FreeSWITCH @@ -1156,6 +1145,7 @@ a native format sound file is available then FreeSWITCH can use it. Summary: PortAudio Media Steam support for the FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: portaudio-devel %description format-portaudio-stream Portaudio Streaming interface Audio for FreeSWITCH @@ -1225,6 +1215,7 @@ Implements TGML Tone Generation for the FreeSWITCH open source telephony platfor Summary: Lua support for the FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: lua-devel %description lua @@ -1233,6 +1224,8 @@ Summary: Perl support for the FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} Requires: perl +BuildRequires: perl-devel +BuildRequires: perl-ExtUtils-Embed %description perl @@ -1240,7 +1233,8 @@ Requires: perl Summary: Python support for the FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} -Requires: python +Requires: python +BuildRequires: python-devel %description python @@ -1387,6 +1381,8 @@ The Perl ESL module allows for native interaction with FreeSWITCH over the event %package -n python-ESL Summary: The Python ESL module allows for native interaction with FreeSWITCH over the event socket interface. Group: System Environment/Libraries +Requires: python +BuildRequires: python-devel %description -n python-ESL The Python ESL module allows for native interaction with FreeSWITCH over the event socket interface. From 167294ea2649afd0ffedf4520b0f308979c3ca2a Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Fri, 18 Oct 2019 18:28:07 +0200 Subject: [PATCH 002/545] [mod-sofia] Fix reINVITE after T38 is rejected From FS-11833. After FS sends a reINVITE to T38 which gets rejected by peer it is no longer in a state where it can properly answer a reINVITE which requests a change of the media setup. 1. FS sends INVITE (destination is a fax machine) 2. Call connects with "8 101" 3. FS sends reINVITE to T38 4. T38 rejected (488) 5. FS receives INVITE to "8" 6. FS replies with 200 OK without SDP 7. Call fails The bug is related to TFLAG_SDP. This flag is set when a media session is established. And when there's a reINVITE sofia_glue_do_invite() from sofia_glue.c is called and clears the flag again: sofia_clear_flag_locked(tech_pvt, TFLAG_SDP); So when FS sends a reINVITE to T38 the flag gets cleared. But when the reINVITE is rejected with 488 the flag is not set again. It stays cleared. So the call continues with the previously negotiated media, fax passthrough (8 101 in this case), but TFLAG_SDP is not set. So when FS receives a reINVITE at this point it doesn't see the need to renegotiate anything, even though it realizes that 2833 DTMF is now off: 2019-04-30 16:42:12.478025 [DEBUG] switch_core_media.c:5478 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1] 2019-04-30 16:42:12.478025 [DEBUG] switch_core_media.c:5533 Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match 2019-04-30 16:42:12.478025 [DEBUG] switch_core_media.c:5802 No 2833 in SDP. Disable 2833 dtmf and switch to INFO When FS doesn't send a reINVITE (fax_enable_t38_request=false) and the reINVITE to "8" is received, TFLAG_SDP is still set and then FS understands that it needs to renegotiate and replies with a 200 OK that includes SDP: 2019-04-30 16:41:19.358028 [DEBUG] switch_core_media.c:5478 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1] 2019-04-30 16:41:19.358028 [DEBUG] switch_core_media.c:5533 Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match 2019-04-30 16:41:19.358028 [DEBUG] switch_core_media.c:5802 No 2833 in SDP. Disable 2833 dtmf and switch to INFO 2019-04-30 16:41:19.358028 [DEBUG] sofia.c:8237 skemper was here in line 8232 2019-04-30 16:41:19.358028 [DEBUG] switch_core_media.c:8390 skemper was here in line 8390. 2019-04-30 16:41:19.358028 [DEBUG] switch_core_media.c:8496 Audio params are unchanged for sofia/external/+called_number. 2019-04-30 16:41:19.358028 [DEBUG] sofia.c:8243 Processing updated SDP This fixes the state problem after a rejected T38 reINVITE by setting TFLAG_SDP. Signed-off-by: Sebastian Kemper --- src/mod/endpoints/mod_sofia/sofia.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 38cf504f83..18b3e03b75 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -6507,6 +6507,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_REQ); switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_FAIL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s T38 invite failed\n", switch_channel_get_name(tech_pvt->channel)); + sofia_set_flag(tech_pvt, TFLAG_SDP); } From 70d1cbafe4ab0176cd9fc01f740e34cd1bae326b Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Wed, 13 Nov 2019 20:29:50 +0100 Subject: [PATCH 003/545] [gentls_cert] Update message digest Debian Buster updated /etc/ssl/openssl.cnf to default to MinProtocol = TLSv1.2 CipherString = DEFAULT@SECLEVEL=2 gentls_cert currently uses SHA1 as message digest. According to OpenSSL documentation this only offers 80 bit of security. 80 bits is enough for security level 1, but not 2. The OpenSSL default MD nowadays is SHA256. This commit updates gentls_cert to use it. Issue was reported on the FS mailing list. The certificates created by gentls_cert caused "md too weak" errors and clients were unable to connect. Signed-off-by: Sebastian Kemper --- scripts/gentls_cert.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/gentls_cert.in b/scripts/gentls_cert.in index 43aa8ac605..dd56c9f6dc 100644 --- a/scripts/gentls_cert.in +++ b/scripts/gentls_cert.in @@ -89,7 +89,7 @@ setup_ca() { openssl req -out "${CONFDIR}/CA/cacert.pem" \ -new -x509 -keyout "${CONFDIR}/CA/cakey.pem" \ - -config "${TMPFILE}.cfg" -nodes -days ${DAYS} -sha1 >/dev/null || exit 1 + -config "${TMPFILE}.cfg" -nodes -days ${DAYS} -sha256 >/dev/null || exit 1 cat "${CONFDIR}/CA/cacert.pem" > "${CONFDIR}/cafile.pem" cp $TMPFILE.cfg /tmp/ssl.cfg rm "${TMPFILE}.cfg" @@ -131,11 +131,11 @@ generate_cert() { openssl req -new -out "${TMPFILE}.req" \ -newkey rsa:${KEY_SIZE} -keyout "${TMPFILE}.key" \ - -config "${TMPFILE}.cfg" -nodes -sha1 >/dev/null || exit 1 + -config "${TMPFILE}.cfg" -nodes -sha256 >/dev/null || exit 1 openssl x509 -req -CAkey "${CONFDIR}/CA/cakey.pem" -CA "${CONFDIR}/CA/cacert.pem" -CAcreateserial \ -in "${TMPFILE}.req" -out "${TMPFILE}.crt" -extfile "${TMPFILE}.cfg" \ - -extensions "${EXTENSIONS}" -days ${DAYS} -sha1 >/dev/null || exit 1 + -extensions "${EXTENSIONS}" -days ${DAYS} -sha256 >/dev/null || exit 1 cat "${TMPFILE}.crt" "${TMPFILE}.key" > "${CONFDIR}/${OUTFILE}" From dbea1482e754afb569d804d72e13946dc66eb0a5 Mon Sep 17 00:00:00 2001 From: Andrew Topp Date: Sun, 15 Mar 2020 14:05:53 +1000 Subject: [PATCH 004/545] [mod_xml_curl] Allow XML_CURL_MAX_BYTES to be configured at runtime per-binding * Added "response-max-bytes" config param for mod_xml_curl * XML_CURL_MAX_BYTES still used as default if param omitted * Added example configuration to module example config. --- .../conf/autoload_configs/xml_curl.conf.xml | 4 ++++ src/mod/xml_int/mod_xml_curl/mod_xml_curl.c | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/mod/xml_int/mod_xml_curl/conf/autoload_configs/xml_curl.conf.xml b/src/mod/xml_int/mod_xml_curl/conf/autoload_configs/xml_curl.conf.xml index 30951d83c8..8efee1f9f8 100644 --- a/src/mod/xml_int/mod_xml_curl/conf/autoload_configs/xml_curl.conf.xml +++ b/src/mod/xml_int/mod_xml_curl/conf/autoload_configs/xml_curl.conf.xml @@ -44,6 +44,10 @@ + + + diff --git a/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c b/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c index dab29a550f..5a2e201a72 100644 --- a/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c +++ b/src/mod/xml_int/mod_xml_curl/mod_xml_curl.c @@ -59,6 +59,7 @@ struct xml_binding { int use_dynamic_url; long auth_scheme; int timeout; + switch_size_t curl_max_bytes; }; static int keep_files_around = 0; @@ -218,7 +219,7 @@ static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, con memset(&config_data, 0, sizeof(config_data)); config_data.name = filename; - config_data.max_bytes = XML_CURL_MAX_BYTES; + config_data.max_bytes = binding->curl_max_bytes; if ((config_data.fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { if (!zstr(binding->cred)) { @@ -364,6 +365,7 @@ static switch_status_t do_config(void) char *method = NULL; int disable100continue = 1; int use_dynamic_url = 0, timeout = 0; + switch_size_t curl_max_bytes = XML_CURL_MAX_BYTES; uint32_t enable_cacert_check = 0; char *ssl_cert_file = NULL; char *ssl_key_file = NULL; @@ -452,6 +454,13 @@ static switch_status_t do_config(void) } } else if (!strcasecmp(var, "bind-local")) { bind_local = val; + } else if (!strcasecmp(var, "response-max-bytes")) { + int tmp = atoi(val); + if (tmp >= 0) { + curl_max_bytes = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set a negative maximum response bytes!\n"); + } } } @@ -540,6 +549,8 @@ static switch_status_t do_config(void) } + binding->curl_max_bytes = curl_max_bytes; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Binding [%s] XML Fetch Function [%s] [%s]\n", zstr(bname) ? "N/A" : bname, binding->url, binding->bindings ? binding->bindings : "all"); switch_xml_bind_search_function(xml_url_fetch, switch_xml_parse_section_string(binding->bindings), binding); From 0b9c7c678b395b45976c336f8b5d154903bf1f8b Mon Sep 17 00:00:00 2001 From: Dragos Oancea Date: Wed, 10 Jun 2020 12:17:27 +0000 Subject: [PATCH 005/545] [mod_amrwb] add cfg setting to switch between OA/BE when originating --- src/mod/codecs/mod_amrwb/mod_amrwb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mod/codecs/mod_amrwb/mod_amrwb.c b/src/mod/codecs/mod_amrwb/mod_amrwb.c index 19cde02adf..4f12c27f0b 100644 --- a/src/mod/codecs/mod_amrwb/mod_amrwb.c +++ b/src/mod/codecs/mod_amrwb/mod_amrwb.c @@ -87,6 +87,7 @@ static struct { switch_byte_t default_bitrate; switch_byte_t volte; switch_byte_t adjust_bitrate; + switch_byte_t force_oa; /*force OA when originating*/ int debug; } globals; @@ -209,7 +210,11 @@ static switch_status_t switch_amrwb_init(switch_codec_t *codec, switch_codec_fla context->enc_mode = globals.default_bitrate; /* octet-align = 0 - per RFC - if there's no `octet-align` FMTP value then BE is employed */ - switch_clear_flag(context, AMRWB_OPT_OCTET_ALIGN); + if (!globals.force_oa) { + switch_clear_flag(context, AMRWB_OPT_OCTET_ALIGN); + } else { + switch_set_flag(context, AMRWB_OPT_OCTET_ALIGN); + } if (codec->fmtp_in) { argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0]))); @@ -548,6 +553,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amrwb_load) if (!strcasecmp(var, "adjust-bitrate")) { globals.adjust_bitrate = (switch_byte_t) atoi(val); } + if (!strcasecmp(var, "force-oa")) { + globals.force_oa = (switch_byte_t) atoi(val); + } } } } From 1c0e7070bc9271fa5d623f877e53de1e2a5ca43a Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Thu, 9 Jul 2020 14:45:16 +0400 Subject: [PATCH 006/545] [Core] Fix leak of BIO_METHOD *dtls_bio_filter_methods in switch_rtp_add_dtls() --- src/switch_rtp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 080aee637a..c9485a3aff 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -270,6 +270,9 @@ typedef struct { struct switch_rtp; +static void switch_rtp_dtls_init(); +static void switch_rtp_dtls_destroy(); + #define MAX_DTLS_MTU 4096 typedef struct switch_dtls_s { @@ -1530,6 +1533,7 @@ SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool) srtp_init(); #endif switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool); + switch_rtp_dtls_init(); global_init = 1; } @@ -2519,7 +2523,7 @@ SWITCH_DECLARE(void) switch_rtp_shutdown(void) #ifdef ENABLE_SRTP srtp_crypto_kernel_shutdown(); #endif - + switch_rtp_dtls_destroy(); } SWITCH_DECLARE(switch_port_t) switch_rtp_set_start_port(switch_port_t port) @@ -3589,6 +3593,25 @@ static BIO_METHOD dtls_bio_filter_methods = { static BIO_METHOD *dtls_bio_filter_methods = NULL; #endif +static void switch_rtp_dtls_init() { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + dtls_bio_filter_methods = BIO_meth_new(BIO_TYPE_FILTER | BIO_get_new_index(), "DTLS filter"); + BIO_meth_set_write(dtls_bio_filter_methods, dtls_bio_filter_write); + BIO_meth_set_ctrl(dtls_bio_filter_methods, dtls_bio_filter_ctrl); + BIO_meth_set_create(dtls_bio_filter_methods, dtls_bio_filter_new); + BIO_meth_set_destroy(dtls_bio_filter_methods, dtls_bio_filter_free); +#endif +} + +static void switch_rtp_dtls_destroy() { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (dtls_bio_filter_methods) { + BIO_meth_free(dtls_bio_filter_methods); + dtls_bio_filter_methods = NULL; + } +#endif +} + /////////// @@ -3831,11 +3854,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d #if OPENSSL_VERSION_NUMBER < 0x10100000L dtls->filter_bio = BIO_new(BIO_dtls_filter()); #else - dtls_bio_filter_methods = BIO_meth_new(BIO_TYPE_FILTER | BIO_get_new_index(), "DTLS filter"); - BIO_meth_set_write(dtls_bio_filter_methods, dtls_bio_filter_write); - BIO_meth_set_ctrl(dtls_bio_filter_methods, dtls_bio_filter_ctrl); - BIO_meth_set_create(dtls_bio_filter_methods, dtls_bio_filter_new); - BIO_meth_set_destroy(dtls_bio_filter_methods, dtls_bio_filter_free); + switch_assert(dtls_bio_filter_methods); dtls->filter_bio = BIO_new(dtls_bio_filter_methods); #endif From 715ee3d2a25dc89a03d6fea0e8dde91b8bf219e4 Mon Sep 17 00:00:00 2001 From: "Lin.Sun" Date: Wed, 8 Jul 2020 17:22:46 +0800 Subject: [PATCH 007/545] [mod_silk] switch_silk_decode: Fix invalid condition for return code from switch_jb_peek_frame(). --- src/mod/codecs/mod_silk/mod_silk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/codecs/mod_silk/mod_silk.c b/src/mod/codecs/mod_silk/mod_silk.c index b41b8510eb..507309a362 100644 --- a/src/mod/codecs/mod_silk/mod_silk.c +++ b/src/mod/codecs/mod_silk/mod_silk.c @@ -352,7 +352,7 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec, frame.buflen = sizeof(buf); for (i = 1; i <= MAX_LBRR_DELAY; i++) { - if (switch_jb_peek_frame(jb, codec->cur_frame->timestamp, 0, (uint16_t)i, &frame)) { + if (switch_jb_peek_frame(jb, codec->cur_frame->timestamp, 0, (uint16_t)i, &frame) == SWITCH_STATUS_SUCCESS) { SKP_Silk_SDK_search_for_LBRR(frame.data, (const int)frame.datalen, i, (SKP_uint8*) &context->recbuff, &context->reclen); if (context->reclen) { From 90fb233ac6937109de6b8ebeb5ef853ea600f73a Mon Sep 17 00:00:00 2001 From: MikhailKalashnikov Date: Fri, 17 Jul 2020 16:58:35 +0300 Subject: [PATCH 008/545] [mod_sofia] Fix crash when proxy INFO without body --- src/mod/endpoints/mod_sofia/sofia.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index f3671c3521..a3344fc323 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -9615,7 +9615,7 @@ switch_status_t sofia_proxy_sip_i_message(nua_t *nua, sofia_profile_t *profile, other_tech_pvt = (private_object_t *) switch_core_session_get_private(other_session); - if (sip && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype) { + if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype) { ct = sip->sip_content_type->c_type; } @@ -9658,11 +9658,11 @@ switch_status_t sofia_proxy_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua other_tech_pvt = (private_object_t *) switch_core_session_get_private(other_session); - if (sip && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype) { + if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype) { ct = sip->sip_content_type->c_type; } - if (sip && sip->sip_content_type->c_type && !strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "media_control+xml")) { + if (sip && sip->sip_content_type && sip->sip_content_type->c_type && !strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "media_control+xml")) { if (switch_channel_test_flag(channel, CF_VIDEO)) { switch_core_media_gen_key_frame(session); switch_channel_set_flag(channel, CF_VIDEO_REFRESH_REQ); From 17ebce7e3b8152d10e06a4df5fd3f2b737089ae8 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Mon, 20 Jul 2020 15:34:55 -0400 Subject: [PATCH 009/545] Add v4 sig to http cache (#741) * FS-9676 [mod_http_cache] Support for AWS Signature version 4 and drop support for version 2 Co-authored-by: baonq-me --- src/mod/applications/mod_http_cache/aws.c | 484 ++++++++++++------ src/mod/applications/mod_http_cache/aws.h | 27 +- src/mod/applications/mod_http_cache/common.c | 6 + src/mod/applications/mod_http_cache/common.h | 34 +- .../conf/autoload_configs/http_cache.conf.xml | 113 ++-- .../mod_http_cache/test/s3_auth.py | 144 ++++++ .../mod_http_cache/test/test_aws.c | 357 +++++++++---- .../test/test_aws_http_cache.conf.xml | 66 +++ 8 files changed, 931 insertions(+), 300 deletions(-) create mode 100755 src/mod/applications/mod_http_cache/test/s3_auth.py create mode 100644 src/mod/applications/mod_http_cache/test/test_aws_http_cache.conf.xml diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c index fbbbf00d98..9c49363e6f 100644 --- a/src/mod/applications/mod_http_cache/aws.c +++ b/src/mod/applications/mod_http_cache/aws.c @@ -22,6 +22,7 @@ * * Contributor(s): * Chris Rienzo + * Quoc-Bao Nguyen * * aws.c -- Some Amazon Web Services helper functions * @@ -34,211 +35,378 @@ #include #endif -/* 160 bits / 8 bits per byte */ -#define SHA1_LENGTH 20 -/** - * Create the string to sign for a AWS signature calculation - * @param verb (PUT/GET) - * @param bucket bucket object is stored in - * @param object to access (filename.ext) - * @param content_type optional content type - * @param content_md5 optional content MD5 checksum - * @param date header - * @return the string_to_sign (must be freed) - */ -static char *aws_s3_string_to_sign(const char *verb, const char *bucket, const char *object, const char *content_type, const char *content_md5, const char *date) -{ - /* - * String to sign has the following format: - * \n\n\n\n/bucket/object - */ - return switch_mprintf("%s\n%s\n%s\n%s\n/%s/%s", - verb, content_md5 ? content_md5 : "", content_type ? content_type : "", - date, bucket, object); -} -/** - * Create the AWS S3 signature - * @param signature buffer to store the signature - * @param signature_length length of signature buffer - * @param string_to_sign - * @param aws_secret_access_key secret access key - * @return the signature buffer or NULL if missing input - */ -static char *aws_s3_signature(char *signature, int signature_length, const char *string_to_sign, const char *aws_secret_access_key) -{ #if defined(HAVE_OPENSSL) - unsigned int signature_raw_length = SHA1_LENGTH; - char signature_raw[SHA1_LENGTH]; - signature_raw[0] = '\0'; - if (!signature || signature_length <= 0) { - return NULL; - } - if (zstr(aws_secret_access_key)) { - return NULL; - } - if (!string_to_sign) { - string_to_sign = ""; - } - HMAC(EVP_sha1(), - aws_secret_access_key, - strlen(aws_secret_access_key), - (const unsigned char *)string_to_sign, - strlen(string_to_sign), - (unsigned char *)signature_raw, - &signature_raw_length); - - /* convert result to base64 */ - switch_b64_encode((unsigned char *)signature_raw, signature_raw_length, (unsigned char *)signature, signature_length); +#include +#include #endif - return signature; + +#if defined(HAVE_OPENSSL) +/** + * Calculate HMAC-SHA256 hash of a message + * @param buffer buffer to store the HMAC-SHA256 version of message as byte array + * @param buffer_length length of buffer + * @param key buffer that store the key to run HMAC-SHA256 + * @param key_length length of the key + * @param message message that will be hashed + * @return byte array, equals to buffer + */ +static char *hmac256(char* buffer, unsigned int buffer_length, const char* key, unsigned int key_length, const char* message) +{ + if (zstr(key) || zstr(message) || buffer_length < SHA256_DIGEST_LENGTH) { + return NULL; + } + + HMAC(EVP_sha256(), + key, + (int)key_length, + (unsigned char *)message, + strlen(message), + (unsigned char*)buffer, + &buffer_length); + + return (char*)buffer; +} + + +/** + * Calculate HMAC-SHA256 hash of a message + * @param buffer buffer to store the HMAC-SHA256 version of the message as hex string + * @param key buffer that store the key to run HMAC-SHA256 + * @param key_length length of the key + * @param message message that will be hashed + * @return hex string that store the HMAC-SHA256 version of the message + */ +static char *hmac256_hex(char* buffer, const char* key, unsigned int key_length, const char* message) +{ + char hmac256_raw[SHA256_DIGEST_LENGTH] = { 0 }; + + if (hmac256(hmac256_raw, SHA256_DIGEST_LENGTH, key, key_length, message) == NULL) { + return NULL; + } + + for (unsigned int i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + snprintf(buffer + i*2, 3, "%02x", (unsigned char)hmac256_raw[i]); + } + buffer[SHA256_DIGEST_LENGTH * 2] = '\0'; + + return buffer; +} + + +/** + * Calculate SHA256 hash of a message + * @param buffer buffer to store the SHA256 version of the message as hex string + * @param string string to be hashed + * @return hex string that store the SHA256 version of the message + */ +static char *sha256_hex(char* buffer, const char* string) +{ + unsigned char sha256_raw[SHA256_DIGEST_LENGTH] = { 0 }; + + SHA256((unsigned char*)string, strlen(string), sha256_raw); + + for (unsigned int i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + snprintf(buffer + i*2, 3, "%02x", sha256_raw[i]); + } + buffer[SHA256_DIGEST_LENGTH * 2] = '\0'; + + return buffer; +} + + +/** + * Get current time_stamp. Example: 20190724T110316Z + * @param format format of the time in strftime format + * @param buffer buffer to store the result + * @param buffer_length length of buffer + * @return current time stamp + */ +static char *get_time(char* format, char* buffer, unsigned int buffer_length) +{ + switch_time_exp_t time; + switch_size_t size; + + switch_time_exp_gmt(&time, switch_time_now()); + + switch_strftime(buffer, &size, buffer_length, format, &time); + + return buffer; +} + + +/** + * Get signature key + * @param key_signing buffer to store signature key + * @param aws_s3_profile AWS profile + * @return key_signing + */ +static char* aws_s3_signature_key(char* key_signing, switch_aws_s3_profile* aws_s3_profile) { + + char key_date[SHA256_DIGEST_LENGTH]; + char key_region[SHA256_DIGEST_LENGTH]; + char key_service[SHA256_DIGEST_LENGTH]; + char* aws4_secret_access_key = switch_mprintf("AWS4%s", aws_s3_profile->access_key_secret); + + hmac256(key_date, SHA256_DIGEST_LENGTH, aws4_secret_access_key, strlen(aws4_secret_access_key), aws_s3_profile->date_stamp); + hmac256(key_region, SHA256_DIGEST_LENGTH, key_date, SHA256_DIGEST_LENGTH, aws_s3_profile->region); + hmac256(key_service, SHA256_DIGEST_LENGTH, key_region, SHA256_DIGEST_LENGTH, "s3"); + hmac256(key_signing, SHA256_DIGEST_LENGTH, key_service, SHA256_DIGEST_LENGTH, "aws4_request"); + + switch_safe_free(aws4_secret_access_key); + + return key_signing; } /** - * Create a pre-signed URL for AWS S3 - * @param verb (PUT/GET) - * @param url address (virtual-host-style) - * @param base_domain (optional - amazon aws assumed if not specified) - * @param content_type optional content type - * @param content_md5 optional content MD5 checksum - * @param aws_access_key_id secret access key identifier - * @param aws_secret_access_key secret access key - * @param expires seconds since the epoch - * @return presigned_url + * Get query string that will be put together with the signature + * @param aws_s3_profile AWS profile + * @return the query string (must be freed) */ -SWITCH_MOD_DECLARE(char *) aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires) +static char* aws_s3_standardized_query_string(switch_aws_s3_profile* aws_s3_profile) { - char signature[S3_SIGNATURE_LENGTH_MAX]; - char signature_url_encoded[S3_SIGNATURE_LENGTH_MAX]; - char *string_to_sign; - char *url_dup = strdup(url); - char *bucket; - char *object; + char* credential; + char expires[10]; + char* standardized_query_string; - /* create URL encoded signature */ - parse_url(url_dup, base_domain, "s3", &bucket, &object); - string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, expires); - signature[0] = '\0'; - aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); - switch_url_encode(signature, signature_url_encoded, S3_SIGNATURE_LENGTH_MAX); - free(string_to_sign); - free(url_dup); + credential = switch_mprintf("%s%%2F%s%%2F%s%%2Fs3%%2Faws4_request", aws_s3_profile->access_key_id, aws_s3_profile->date_stamp, aws_s3_profile->region); + switch_snprintf(expires, 9, "%ld", aws_s3_profile->expires); - /* create the presigned URL */ - return switch_mprintf("%s?Signature=%s&Expires=%s&AWSAccessKeyId=%s", url, signature_url_encoded, expires, aws_access_key_id); + standardized_query_string = switch_mprintf( + "X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%s&X-Amz-SignedHeaders=host", + credential, aws_s3_profile->time_stamp, expires + ); + + switch_safe_free(credential); + + return standardized_query_string; } /** - * Create an authentication signature for AWS S3 - * @param authentication buffer to store result - * @param authentication_length maximum result length - * @param verb (PUT/GET) - * @param url address (virtual-host-style) - * @param base_domain (optional - amazon aws assumed if not specified) - * @param content_type optional content type - * @param content_md5 optional content MD5 checksum - * @param aws_access_key_id secret access key identifier - * @param aws_secret_access_key secret access key - * @param date header - * @return signature for Authorization header + * Get request string that is used to build string to sign + * @param aws_s3_profile AWS profile + * @return the request string (must be freed) */ -static char *aws_s3_authentication_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *date) -{ - char signature[S3_SIGNATURE_LENGTH_MAX]; - char *string_to_sign; - char *url_dup = strdup(url); - char *bucket; - char *object; +static char* aws_s3_standardized_request(switch_aws_s3_profile* aws_s3_profile) { - /* create base64 encoded signature */ - parse_url(url_dup, base_domain, "s3", &bucket, &object); - string_to_sign = aws_s3_string_to_sign(verb, bucket, object, content_type, content_md5, date); - signature[0] = '\0'; - aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, string_to_sign, aws_secret_access_key); - free(string_to_sign); - free(url_dup); + char* standardized_query_string = aws_s3_standardized_query_string(aws_s3_profile); - return switch_mprintf("AWS %s:%s", aws_access_key_id, signature); + char* standardized_request = switch_mprintf( + "%s\n/%s\n%s\nhost:%s.%s\n\nhost\nUNSIGNED-PAYLOAD", + aws_s3_profile->verb, aws_s3_profile->object, standardized_query_string, aws_s3_profile->bucket, aws_s3_profile->base_domain + ); + + switch_safe_free(standardized_query_string); + + return standardized_request; } + +/** + * Create the string to sign for a AWS signature version 4 + * @param standardized_request request string that is used to build string to sign + * @param aws_s3_profile AWS profile + * @return the string to sign (must be freed) + */ +static char *aws_s3_string_to_sign(char* standardized_request, switch_aws_s3_profile* aws_s3_profile) { + + char standardized_request_hex[SHA256_DIGEST_LENGTH * 2 + 1] = {'\0'}; + char* string_to_sign; + + sha256_hex(standardized_request_hex, standardized_request); + + string_to_sign = switch_mprintf( + "AWS4-HMAC-SHA256\n%s\n%s/%s/s3/aws4_request\n%s", + aws_s3_profile->time_stamp, aws_s3_profile->date_stamp, aws_s3_profile->region, standardized_request_hex + ); + + return string_to_sign; +} + +/** + * Create a full query string that contains signature version 4 for AWS request + * @param aws_s3_profile AWS profile + * @return full query string that include the signature + */ +static char *aws_s3_authentication_create(switch_aws_s3_profile* aws_s3_profile) { + char signature[SHA256_DIGEST_LENGTH * 2 + 1]; + char *string_to_sign; + + char* standardized_query_string; + char* standardized_request; + char signature_key[SHA256_DIGEST_LENGTH]; + char* query_param; + + // Get standardized_query_string + standardized_query_string = aws_s3_standardized_query_string(aws_s3_profile); + + // Get standardized_request + standardized_request = aws_s3_standardized_request(aws_s3_profile); + + // Get string_to_sign + string_to_sign = aws_s3_string_to_sign(standardized_request, aws_s3_profile); + + // Get signature_key + aws_s3_signature_key(signature_key, aws_s3_profile); + + // Get signature + hmac256_hex(signature, signature_key, SHA256_DIGEST_LENGTH, string_to_sign); + + // Build final query string + query_param = switch_mprintf("%s&X-Amz-Signature=%s", standardized_query_string, signature); + + switch_safe_free(string_to_sign); + switch_safe_free(standardized_query_string); + switch_safe_free(standardized_request); + + return query_param; +} +#endif + +/** + * Append Amazon S3 query params to request if necessary + * @param headers to add to. AWS signature v4 requires no header to be appended + * @param profile with S3 credentials + * @param content_type of object (PUT only) + * @param verb http methods (GET/PUT) + * @param url full url + * @param block_num block number, only used by Azure + * @param query_string pointer to query param string that will be calculated + * @return updated headers + */ +SWITCH_MOD_DECLARE(switch_curl_slist_t) *aws_s3_append_headers( + http_profile_t *profile, + switch_curl_slist_t *headers, + const char *verb, + unsigned int content_length, + const char *content_type, + const char *url, + const unsigned int block_num, + char **query_string +) { +#if defined(HAVE_OPENSSL) + switch_aws_s3_profile aws_s3_profile; + char* url_dup; + + // Get bucket and object name from url + switch_strdup(url_dup, url); + parse_url(url_dup, profile->base_domain, "s3", &aws_s3_profile.bucket, &aws_s3_profile.object); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "bucket: %s\n", aws_s3_profile.bucket); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "object: %s\n", aws_s3_profile.object); + + // Get date and time + get_time("%Y%m%d", aws_s3_profile.date_stamp, DATE_STAMP_LENGTH); + get_time("%Y%m%dT%H%M%SZ", aws_s3_profile.time_stamp, TIME_STAMP_LENGTH); + + // Get access key id and secret + aws_s3_profile.access_key_id = profile->aws_s3_access_key_id; + aws_s3_profile.access_key_secret = profile->secret_access_key; + + // Get base domain + aws_s3_profile.base_domain = profile->base_domain; + aws_s3_profile.region = profile->region; + aws_s3_profile.verb = verb; + aws_s3_profile.expires = profile->expires; + + *query_string = aws_s3_authentication_create(&aws_s3_profile); + + switch_safe_free(url_dup); +#endif + return headers; +} + +/** + * Get key id, secret and region from env variables or config file + * @param xml object that store config file + * @param profile pointer that config will be written to + * @return status + */ SWITCH_MOD_DECLARE(switch_status_t) aws_s3_config_profile(switch_xml_t xml, http_profile_t *profile) { - switch_status_t status = SWITCH_STATUS_SUCCESS; +#if defined(HAVE_OPENSSL) switch_xml_t base_domain_xml = switch_xml_child(xml, "base-domain"); + switch_xml_t region_xml = switch_xml_child(xml, "region"); + switch_xml_t expires_xml = switch_xml_child(xml, "expires"); + // Function pointer to be called to append query params to original url profile->append_headers_ptr = aws_s3_append_headers; /* check if environment variables set the keys */ profile->aws_s3_access_key_id = getenv("AWS_ACCESS_KEY_ID"); profile->secret_access_key = getenv("AWS_SECRET_ACCESS_KEY"); if (!zstr(profile->aws_s3_access_key_id) && !zstr(profile->secret_access_key)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "Using AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables for s3 access on profile \"%s\"\n", profile->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Using AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables for AWS S3 access for profile \"%s\"\n", profile->name); profile->aws_s3_access_key_id = strdup(profile->aws_s3_access_key_id); profile->secret_access_key = strdup(profile->secret_access_key); } else { /* use configuration for keys */ switch_xml_t id = switch_xml_child(xml, "access-key-id"); switch_xml_t secret = switch_xml_child(xml, "secret-access-key"); + if (!id || !secret) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing access-key-id or secret-access-key in http_cache.conf.xml for profile \"%s\"\n", profile->name); + return SWITCH_STATUS_FALSE; + } - if (id && secret) { - profile->aws_s3_access_key_id = switch_strip_whitespace(switch_xml_txt(id)); - profile->secret_access_key = switch_strip_whitespace(switch_xml_txt(secret)); - if (zstr(profile->aws_s3_access_key_id) || zstr(profile->secret_access_key)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing AWS S3 credentials for profile \"%s\"\n", profile->name); - switch_safe_free(profile->aws_s3_access_key_id); - profile->aws_s3_access_key_id = NULL; - switch_safe_free(profile->secret_access_key); - profile->secret_access_key = NULL; - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n"); - status = SWITCH_STATUS_FALSE; + profile->aws_s3_access_key_id = switch_strip_whitespace(switch_xml_txt(id)); + profile->secret_access_key = switch_strip_whitespace(switch_xml_txt(secret)); + if (zstr(profile->aws_s3_access_key_id) || zstr(profile->secret_access_key)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Empty access-key-id or secret-access-key in http_cache.conf.xml for profile \"%s\"\n", profile->name); + switch_safe_free(profile->aws_s3_access_key_id); + switch_safe_free(profile->secret_access_key); + return SWITCH_STATUS_FALSE; } } + // Get region + if (!region_xml) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing region in http_cache.conf.xml for profile \"%s\"\n", profile->name); + return SWITCH_STATUS_FALSE; + } + profile->region = switch_strip_whitespace(switch_xml_txt(region_xml)); + if (zstr(profile->region)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Empty region in http_cache.conf.xml for profile \"%s\"\n", profile->name); + switch_safe_free(profile->region); + return SWITCH_STATUS_FALSE; + } + + // Get base domain for AWS S3 compatible services. Default base domain is s3.amazonaws.com if (base_domain_xml) { profile->base_domain = switch_strip_whitespace(switch_xml_txt(base_domain_xml)); if (zstr(profile->base_domain)) { switch_safe_free(profile->base_domain); - profile->base_domain = NULL; + profile->base_domain = switch_mprintf(DEFAULT_BASE_DOMAIN, profile->region); } + } else + { + profile->base_domain = switch_mprintf(DEFAULT_BASE_DOMAIN, profile->region); } - return status; + + // Get expire time for URL signature + if (expires_xml) { + char* expires = switch_strip_whitespace(switch_xml_txt(expires_xml)); + if (!zstr(expires) && switch_is_number(expires)) + { + profile->expires = switch_safe_atoi(expires, DEFAULT_EXPIRATION_TIME); + } else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid \"expires\" in http_cache.conf.xml for profile \"%s\"\n", profile->name); + profile->expires = DEFAULT_EXPIRATION_TIME; + } + switch_safe_free(expires); + } else + { + profile->expires = DEFAULT_EXPIRATION_TIME; + } + +#endif + + return SWITCH_STATUS_SUCCESS; } -/** - * Append Amazon S3 headers to request if necessary - * @param headers to add to. If NULL, new headers are created. - * @param profile with S3 credentials - * @param content_type of object (PUT only) - * @param verb (GET/PUT) - * @param url - * @return updated headers - */ -SWITCH_MOD_DECLARE(switch_curl_slist_t*) aws_s3_append_headers(http_profile_t *profile, switch_curl_slist_t *headers, - const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string) -{ - char date[256]; - char header[1024]; - char *authenticate; - - /* Date: */ - switch_rfc822_date(date, switch_time_now()); - snprintf(header, 1024, "Date: %s", date); - headers = switch_curl_slist_append(headers, header); - - /* Authorization: */ - authenticate = aws_s3_authentication_create(verb, url, profile->base_domain, content_type, "", profile->aws_s3_access_key_id, profile->secret_access_key, date); - snprintf(header, 1024, "Authorization: %s", authenticate); - free(authenticate); - headers = switch_curl_slist_append(headers, header); - - return headers; -} - - /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/applications/mod_http_cache/aws.h b/src/mod/applications/mod_http_cache/aws.h index 3112bfe989..5ae5b933fc 100644 --- a/src/mod/applications/mod_http_cache/aws.h +++ b/src/mod/applications/mod_http_cache/aws.h @@ -22,7 +22,8 @@ * * Contributor(s): * Chris Rienzo - * + * Quoc-Bao Nguyen + * * aws.h - Some Amazon Web Services helper functions * */ @@ -33,13 +34,27 @@ #include #include "common.h" -/* (SHA1_LENGTH * 1.37 base64 bytes per byte * 3 url-encoded bytes per byte) */ -#define S3_SIGNATURE_LENGTH_MAX 83 +#define DATE_STAMP_LENGTH 9 // 20190729 +#define TIME_STAMP_LENGTH 17 // 20190729T083832Z +#define DEFAULT_BASE_DOMAIN "s3.%s.amazonaws.com" +#define DEFAULT_EXPIRATION_TIME 604800 -SWITCH_MOD_DECLARE(switch_curl_slist_t*) aws_s3_append_headers(http_profile_t *profile, switch_curl_slist_t *headers, - const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string); SWITCH_MOD_DECLARE(switch_status_t) aws_s3_config_profile(switch_xml_t xml, http_profile_t *profile); -SWITCH_MOD_DECLARE(char *) aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, const char *content_type, const char *content_md5, const char *aws_access_key_id, const char *aws_secret_access_key, const char *expires); + +struct aws_s3_profile { + const char* base_domain; + char* bucket; + char* object; + char time_stamp[TIME_STAMP_LENGTH]; + char date_stamp[DATE_STAMP_LENGTH]; + const char* verb; + const char* access_key_id; + const char* access_key_secret; + const char* region; + switch_time_t expires; +}; + +typedef struct aws_s3_profile switch_aws_s3_profile; #endif diff --git a/src/mod/applications/mod_http_cache/common.c b/src/mod/applications/mod_http_cache/common.c index 5db61fcdf9..04e66c7079 100644 --- a/src/mod/applications/mod_http_cache/common.c +++ b/src/mod/applications/mod_http_cache/common.c @@ -22,6 +22,7 @@ * * Contributor(s): * Chris Rienzo + * Quoc-Bao Nguyen * * common.c - Functions common to the store provider * @@ -75,6 +76,7 @@ SWITCH_MOD_DECLARE(void) parse_url(char *url, const char *base_domain, const cha *object = NULL; if (zstr(url)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "url is empty\n"); return; } @@ -86,6 +88,7 @@ SWITCH_MOD_DECLARE(void) parse_url(char *url, const char *base_domain, const cha } if (zstr(bucket_start)) { /* invalid URL */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid url\n"); return; } @@ -96,6 +99,7 @@ SWITCH_MOD_DECLARE(void) parse_url(char *url, const char *base_domain, const cha bucket_end = my_strrstr(bucket_start, base_domain_match); if (!bucket_end) { /* invalid URL */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid url\n"); return; } @@ -104,12 +108,14 @@ SWITCH_MOD_DECLARE(void) parse_url(char *url, const char *base_domain, const cha object_start = strchr(bucket_end + 1, '/'); if (!object_start) { /* invalid URL */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid url\n"); return; } object_start++; if (zstr(bucket_start) || zstr(object_start)) { /* invalid URL */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid url\n"); return; } diff --git a/src/mod/applications/mod_http_cache/common.h b/src/mod/applications/mod_http_cache/common.h index 612b7fb2ad..9092f2a13b 100644 --- a/src/mod/applications/mod_http_cache/common.h +++ b/src/mod/applications/mod_http_cache/common.h @@ -1,10 +1,40 @@ +/* + * aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2013-2014, Grasshopper + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is Grasshopper + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Rienzo + * Quoc-Bao Nguyen + * + * common.h - Functions common to the store provider + * + */ + #ifndef COMMON_H #define COMMON_H #include /** - * An http profile. Defines optional credentials + * An http profile. Defines optional credentials * for access to Amazon S3 and Azure Blob Service */ struct http_profile { @@ -12,6 +42,8 @@ struct http_profile { char *aws_s3_access_key_id; char *secret_access_key; char *base_domain; + char *region; // AWS region. Used by AWS S3 + switch_time_t expires; // Expiration time in seconds for URL signature. Default is 604800 seconds. Used by AWS S3 switch_size_t bytes_per_block; // function to be called to add the profile specific headers to the GET/PUT requests diff --git a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml index 1408e550ac..bf14470ecb 100644 --- a/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml +++ b/src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml @@ -1,47 +1,74 @@ + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 604800 + - - - - - - - - - - - - - - - - - - - - - kOOY4Y/sqZU9bsLjmN+9McVwTry+UIn1Owt4Zs/2S2FQT0eAWLKsk -Z0V6/gGFqCAKVvwXoGjqUn7PNbVjhZiNA== - - - - - - + + + + + + + + + + + + + + + + + + + + 604800 + + + + + + + + + + + + + kOOY4Y/sqZU9bsLjmN+9McVwTry+UIn1Owt4Zs/2S2FQT0eAWLKskZ0V6/gGFqCAKVvwXoGjqUn7PNbVjhZiNA== + + + + + + - diff --git a/src/mod/applications/mod_http_cache/test/s3_auth.py b/src/mod/applications/mod_http_cache/test/s3_auth.py new file mode 100755 index 0000000000..e346c5af8e --- /dev/null +++ b/src/mod/applications/mod_http_cache/test/s3_auth.py @@ -0,0 +1,144 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- +# +# s3_auth.py for unit tests in mod_http_cache +# Copyright (C) 2019 Vinadata Corporation (vinadata.vn). All rights reserved. +# +# Version: MPL 1.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Initial Developer of the Original Code is Quoc-Bao Nguyen +# Portions created by the Initial Developer are Copyright (C) +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Quoc-Bao Nguyen +# +# s3_auth.python - Generate signature for AWS Signature version 4 for unit test +# + +import base64 +import datetime +import hashlib +import hmac +from collections import OrderedDict + +import requests +from requests.utils import quote + + +# hashing methods +def hmac256(key, msg): + return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest() + + +def hmac256_hex(key, msg): + return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).hexdigest() + + +def sha256_hex(msg): + return hashlib.sha256(msg).hexdigest() + + +# region is a wildcard value that takes the place of the AWS region value +# as COS doesn't use regions like AWS, this parameter can accept any string +def createSignatureKey(key, date_stamp, region, service): + keyDate = hmac256(('AWS4' + key).encode('utf-8'), date_stamp) + keyRegion = hmac256(keyDate, region) + keyService = hmac256(keyRegion, service) + keySigning = hmac256(keyService, 'aws4_request') + return keySigning + + +def query_string(access_key, date_stamp, time_stamp, region): + fields = OrderedDict() + fields["X-Amz-Algorithm"] = "AWS4-HMAC-SHA256" + fields["X-Amz-Credential"] = access_key + '/' + date_stamp + '/' + region + '/s3/aws4_request' + fields["X-Amz-Date"] = time_stamp + fields["X-Amz-Expires"] = "604800" # in seconds + fields["X-Amz-SignedHeaders"] = "host" + + queries_string = ''.join("%s=%s&" % (key, val) for (key, val) in fields.iteritems())[:-1] + + return quote(queries_string, safe='&=') + + +def main(): + access_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + + # request elements + http_method = 'GET' + region = 'HCM' + bucket = 'bucket1' + host = 'stg.example.com' + endpoint = 'https://' + bucket + "." + host + object_name = 'document.docx' + + # assemble the standardized request + time = datetime.datetime.utcnow() + time_stamp = time.strftime('%Y%m%dT%H%M%SZ') + date_stamp = time.strftime('%Y%m%d') + + print "time_stamp: " + time_stamp + print "date_stamp: " + date_stamp + + standardized_query_string = query_string(access_key, date_stamp, time_stamp, region) + print 'standardized_query_string: \n' + standardized_query_string + + standardized_request = (http_method + '\n' + + '/' + object_name + '\n' + + standardized_query_string + '\n' + + 'host:' + bucket + '.' + host + '\n\n' + + 'host' + '\n' + + 'UNSIGNED-PAYLOAD') + + print 'standardized_request: ' + hashlib.sha256(standardized_request).hexdigest() + + print "\nStandardized request:\n" + standardized_request + + # assemble string-to-sign + string_to_sign = ('AWS4-HMAC-SHA256' + '\n' + + time_stamp + '\n' + + date_stamp + '/' + region + '/s3/aws4_request' + '\n' + + sha256_hex(standardized_request)) + + print "\nString to Sign:\n" + string_to_sign.replace('\n', "\\n") + + # generate the signature + signature_key = createSignatureKey(secret_key, date_stamp, region, 's3') + + print 'signature_key: ' + base64.b64encode(signature_key) + # signature = hmac.new(signature_key, sts.encode('utf-8'), hashlib.sha256).hexdigest() + signature = hmac256_hex(signature_key, string_to_sign) + + print 'signature: ' + signature + # create and send the request + # the 'requests' package automatically adds the required 'host' header + + request_url = (endpoint + '/' + + object_name + '?' + + standardized_query_string + + '&X-Amz-Signature=' + + signature) + + print '\nRequest URL:\n' + request_url + + request = requests.get(request_url) + + print '\nResponse code: %d\n' % request.status_code + # print '\nResponse code: %s\n' % request.content + # print request.text + + +if __name__ == "__main__": + main() diff --git a/src/mod/applications/mod_http_cache/test/test_aws.c b/src/mod/applications/mod_http_cache/test/test_aws.c index 615f336472..bc857af067 100644 --- a/src/mod/applications/mod_http_cache/test/test_aws.c +++ b/src/mod/applications/mod_http_cache/test/test_aws.c @@ -1,12 +1,66 @@ +/* + * aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2013-2014, Grasshopper + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is Grasshopper + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Rienzo + * Quoc-Bao Nguyen + * + * test_aws.c - Unit tests for functions in aws.c + * + */ #include #include #include "../aws.c" +// Run test +// make && libtool --mode=execute valgrind --leak-check=full --log-file=vg.log ./test/test_aws && cat vg.log + FST_BEGIN() { + FST_SUITE_BEGIN(aws) { + +#if defined(HAVE_OPENSSL) + char url[100] = {'\0'}; + switch_aws_s3_profile aws_s3_profile; + + // Get bucket and object name from url + aws_s3_profile.bucket = "bucket6"; + aws_s3_profile.object = "document.docx"; + memcpy(aws_s3_profile.date_stamp, "20190729", DATE_STAMP_LENGTH); + memcpy(aws_s3_profile.time_stamp, "20190729T083832Z", TIME_STAMP_LENGTH); + aws_s3_profile.access_key_id = "cbc443a53fb06eafb2b83ca1e4233cbc"; + aws_s3_profile.access_key_secret = "4a722120f27518abbb8573ca9005d175"; + + aws_s3_profile.base_domain = "stg.vinadata.vn"; + aws_s3_profile.region = "HCM"; + aws_s3_profile.verb = "GET"; + aws_s3_profile.expires = DEFAULT_EXPIRATION_TIME; + + switch_snprintf(url, sizeof(url), "http://%s.%s/%s", aws_s3_profile.bucket, aws_s3_profile.base_domain, aws_s3_profile.object); +#endif + FST_SETUP_BEGIN() { } @@ -17,153 +71,272 @@ FST_TEARDOWN_BEGIN() } FST_TEARDOWN_END() -FST_TEST_BEGIN(test_string_to_sign) -{ - char *string_to_sign = NULL; - string_to_sign = aws_s3_string_to_sign("GET", "rienzo-vault", "troporocks.mp3", "", "", "Fri, 17 May 2013 19:35:26 GMT") ; - fst_check_string_equals("GET\n\n\nFri, 17 May 2013 19:35:26 GMT\n/rienzo-vault/troporocks.mp3", string_to_sign); - switch_safe_free(string_to_sign); - - string_to_sign = aws_s3_string_to_sign("GET", "foo", "man.chu", "audio/mpeg", "c8fdb181845a4ca6b8fec737b3581d76", "Thu, 17 Nov 2005 18:49:58 GMT"); - fst_check_string_equals("GET\nc8fdb181845a4ca6b8fec737b3581d76\naudio/mpeg\nThu, 17 Nov 2005 18:49:58 GMT\n/foo/man.chu", string_to_sign); - switch_safe_free(string_to_sign); - - string_to_sign = aws_s3_string_to_sign("", "", "", "", "", ""); - fst_check_string_equals("\n\n\n\n//", string_to_sign); - switch_safe_free(string_to_sign); - - string_to_sign = aws_s3_string_to_sign(NULL, NULL, NULL, NULL, NULL, NULL); - fst_check_string_equals("\n\n\n\n//", string_to_sign); - switch_safe_free(string_to_sign); - - string_to_sign = aws_s3_string_to_sign("PUT", "bucket", "voicemails/recording.wav", "audio/wav", "", "Wed, 12 Jun 2013 13:16:58 GMT"); - fst_check_string_equals("PUT\n\naudio/wav\nWed, 12 Jun 2013 13:16:58 GMT\n/bucket/voicemails/recording.wav", string_to_sign); - switch_safe_free(string_to_sign); -} -FST_TEST_END() - -FST_TEST_BEGIN(test_signature) -{ - char signature[S3_SIGNATURE_LENGTH_MAX]; - signature[0] = '\0'; - fst_check_string_equals("weGrLrc9HDlkYPTepVl0A9VYNlw=", aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "GET\n\n\nFri, 17 May 2013 19:35:26 GMT\n/rienzo-vault/troporocks.mp3", "hOIZt1oeTX1JzINOMBoKf0BxONRZNQT1J8gIznLx")); - fst_check_string_equals("jZNOcbfWmD/A/f3hSvVzXZjM2HU=", aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\nx-amz-meta-author:foo@bar.com\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV")); - fst_check_string_equals("5m+HAmc5JsrgyDelh9+a2dNrzN8=", aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "GET\n\n\n\nx-amz-date:Thu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV")); - fst_check_string_equals("OKA87rVp3c4kd59t8D3diFmTfuo=", aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV")); - fst_check_string_equals("OKA87rVp3c4kd59t8D3diFmTfuo=", aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, NULL, "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV")); - fst_check(aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "GET\n\n\n\nx-amz-date:Thu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\n/quotes/nelson", "") == NULL); - fst_check(aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, "", "") == NULL); - fst_check(aws_s3_signature(signature, S3_SIGNATURE_LENGTH_MAX, NULL, NULL) == NULL); - fst_check(aws_s3_signature(NULL, S3_SIGNATURE_LENGTH_MAX, "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\nx-amz-meta-author:foo@bar.com\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV") == NULL); - fst_check(aws_s3_signature(signature, 0, "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\nx-amz-meta-author:foo@bar.com\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV") == NULL); - fst_check_string_equals("jZNO", aws_s3_signature(signature, 5, "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\nx-amz-meta-author:foo@bar.com\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV")); -} -FST_TEST_END() - -FST_TEST_BEGIN(test_parse_url) +#if defined(HAVE_OPENSSL) +FST_TEST_BEGIN(parse_url) { char *bucket; char *object; - char url[512] = { 0 }; + char url_dup[512] = { 0 }; - snprintf(url, sizeof(url), "http://quotes.s3.amazonaws.com/nelson"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), url); + parse_url(url_dup, aws_s3_profile.base_domain, "s3", &bucket, &object); + fst_check_string_equals(aws_s3_profile.bucket, bucket); + fst_check_string_equals(aws_s3_profile.object, object); + + switch_snprintf(url_dup, sizeof(url_dup), "https://bucket99.s3.amazonaws.com/image.png"); + parse_url(url_dup, NULL, "s3", &bucket, &object); + fst_check_string_equals(bucket, "bucket99"); + fst_check_string_equals(object, "image.png"); + + switch_snprintf(url_dup, sizeof(url_dup), "https://bucket99.s3.amazonaws.com/folder5/image.png"); + parse_url(url_dup, NULL, "s3", &bucket, &object); + fst_check_string_equals(bucket, "bucket99"); + fst_check_string_equals(object, "folder5/image.png"); + + switch_snprintf(url_dup, sizeof(url_dup), "https://bucket23.vn-hcm.vinadata.vn/image.png"); + parse_url(url_dup, "vn-hcm.vinadata.vn", "s3", &bucket, &object); + fst_check_string_equals(bucket, "bucket23"); + fst_check_string_equals(object, "image.png"); + + switch_snprintf(url_dup, sizeof(url_dup), "https://bucket335.s3-ap-southeast-1.amazonaws.com/vpnclient-v4.29-9680-rtm-2019.02.28-linux-x64-64bit.tar.gz"); + parse_url(url_dup, NULL, "s3", &bucket, &object); + fst_check_string_equals(bucket, "bucket335"); + fst_check_string_equals(object, "vpnclient-v4.29-9680-rtm-2019.02.28-linux-x64-64bit.tar.gz"); + + switch_snprintf(url_dup, sizeof(url_dup), "https://bucket335.s3-ap-southeast-1.amazonaws.com/vpnclient-v4.29-9680-rtm-2019.02.28-linux-x64-64bit.tar.gz"); + parse_url(url_dup, "s3-ap-southeast-1.amazonaws.com", "s3", &bucket, &object); + fst_check_string_equals(bucket, "bucket335"); + fst_check_string_equals(object, "vpnclient-v4.29-9680-rtm-2019.02.28-linux-x64-64bit.tar.gz"); + + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes.s3.amazonaws.com/nelson"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check_string_equals("quotes", bucket); fst_check_string_equals("nelson", object); - snprintf(url, sizeof(url), "https://quotes.s3.amazonaws.com/nelson.mp3"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "https://quotes.s3.amazonaws.com/nelson.mp3"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check_string_equals("quotes", bucket); fst_check_string_equals("nelson.mp3", object); - snprintf(url, sizeof(url), "http://s3.amazonaws.com/quotes/nelson"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://s3.amazonaws.com/quotes/nelson"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "http://quotes/quotes/nelson"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes/quotes/nelson"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "http://quotes.s3.amazonaws.com/"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes.s3.amazonaws.com/"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "http://quotes.s3.amazonaws.com"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes.s3.amazonaws.com"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "http://quotes"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "%s", ""); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "%s", ""); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - parse_url(NULL, NULL, "s3", &bucket, &object); + switch_snprintf(NULL, 0, "s3", &bucket, &object); fst_check(bucket == NULL); fst_check(object == NULL); - snprintf(url, sizeof(url), "http://bucket.s3.amazonaws.com/voicemails/recording.wav"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://bucket.s3.amazonaws.com/voicemails/recording.wav"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check_string_equals("bucket", bucket); fst_check_string_equals("voicemails/recording.wav", object); - snprintf(url, sizeof(url), "https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check_string_equals("my-bucket-with-dash", bucket); fst_check_string_equals("greeting/file/1002/Lumino.mp3", object); - snprintf(url, sizeof(url), "http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"); - parse_url(url, NULL, "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"); + parse_url(url_dup, NULL, "s3", &bucket, &object); fst_check_string_equals("quotes.s3.foo.bar", bucket); fst_check_string_equals("greeting/file/1002/Lumino.mp3", object); - snprintf(url, sizeof(url), "http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"); - parse_url(url, "example.com", "s3", &bucket, &object); + switch_snprintf(url_dup, sizeof(url_dup), "http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"); + parse_url(url_dup, "example.com", "s3", &bucket, &object); fst_check_string_equals("quotes.s3.foo.bar", bucket); fst_check_string_equals("greeting/file/1002/Lumino.mp3", object); } FST_TEST_END() -FST_TEST_BEGIN(test_authorization_header) +FST_TEST_BEGIN(aws_s3_standardized_query_string) { - char *authentication_header = aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", authentication_header); - switch_safe_free(authentication_header); - - authentication_header = aws_s3_authentication_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", authentication_header); - switch_safe_free(authentication_header); - - authentication_header = aws_s3_authentication_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y=", authentication_header); - switch_safe_free(authentication_header); + char* standardized_query_string = aws_s3_standardized_query_string(&aws_s3_profile); + fst_check_string_equals("X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=cbc443a53fb06eafb2b83ca1e4233cbc%2F20190729%2FHCM%2Fs3%2Faws4_request&X-Amz-Date=20190729T083832Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host", standardized_query_string); + switch_safe_free(standardized_query_string); } FST_TEST_END() -FST_TEST_BEGIN(test_presigned_url) +FST_TEST_BEGIN(get_time) { - char *presigned_url = aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", NULL, "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", presigned_url); - switch_safe_free(presigned_url); + char time_stamp[TIME_STAMP_LENGTH]; + char date_stamp[DATE_STAMP_LENGTH]; + char time_stamp_test[TIME_STAMP_LENGTH]; + char date_stamp_test[DATE_STAMP_LENGTH]; - presigned_url = aws_s3_presigned_url_create("GET", "https://vault.s3.amazonaws.com/awesome.mp3", "s3.amazonaws.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", presigned_url); - switch_safe_free(presigned_url); + // Get date and time for test case + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = gmtime(&rawtime); - presigned_url = aws_s3_presigned_url_create("GET", "https://vault.example.com/awesome.mp3", "example.com", "audio/mpeg", "", "AKIAIOSFODNN7EXAMPLE", "0123456789012345678901234567890123456789", "1234567890"); - fst_check_string_equals("https://vault.example.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE", presigned_url); - switch_safe_free(presigned_url); + // Get date and time to test + get_time("%Y%m%d", date_stamp, DATE_STAMP_LENGTH); + get_time("%Y%m%dT%H%M%SZ", time_stamp, TIME_STAMP_LENGTH); + + // https://fresh2refresh.com/c-programming/c-time-related-functions/ + // https://stackoverflow.com/questions/5141960/get-the-current-time-in-c/5142028 + // https://linux.die.net/man/3/ctime + // https://stackoverflow.com/questions/153890/printing-leading-0s-in-c + switch_snprintf(date_stamp_test, DATE_STAMP_LENGTH, "%d%02d%02d", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday); + switch_snprintf(time_stamp_test, TIME_STAMP_LENGTH, "%d%02d%02dT%02d%02d%02dZ", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + + fst_check_string_equals(time_stamp_test, time_stamp); + fst_check_string_equals(date_stamp_test, date_stamp); } FST_TEST_END() +FST_TEST_BEGIN(hmac256_hex) +{ + char hex[SHA256_DIGEST_LENGTH * 2 + 1]; + + fst_check_string_equals("61d8c60f9c2cd767d3db37a52966965ef508136693d99ea533cff1b712044653", hmac256_hex(hex, "d8a1c4f68b15844de5d07960a57b1669", SHA256_DIGEST_LENGTH, "27a7d569d0c12cc576f20665651fb72c")); + fst_check_string_equals("5a98f20477a538bd29f0903cc30accaf4151b22e1f44577b75bae4cc5068df9e", hmac256_hex(hex, "66b0d6c5b3fd9c57a345b03877c902cb", SHA256_DIGEST_LENGTH, "2da091ff2a9818ce6deb5c4b6d9ad51c")); + fst_check_string_equals("6accbbef08f240dbdebf154cda91f7c66ef178023d53db7f3656d204996effaa", hmac256_hex(hex, "820f6b29b5ca8fa1077b69edf4ee456f", SHA256_DIGEST_LENGTH, "063ee28c963df34342ffb7ac0feae1d9")); +} +FST_TEST_END() + +FST_TEST_BEGIN(sha256_hex) +{ + char hex[SHA256_DIGEST_LENGTH * 2 + 1]; + + fst_check_string_equals("ebab701faffb9cd018d7fa566ca0e7f55dd7a9850cae06e088554238d6fae257", sha256_hex(hex, "eccbb6195a0f08664e2a35c0d686e892")); + fst_check_string_equals("4884c0be257758ded0381f940870a9280b367002e5c518fb42d56641b451a66b", sha256_hex(hex, "1993f63438fe482cd3040aeb2390b98c")); + fst_check_string_equals("1c930bd8e5034a418fef94b1cb753ec82b2a510429bfcdf41b597c6f6c7b21e4", sha256_hex(hex, "3705c5709dc52a04d844ebbcf59e7672")); +} +FST_TEST_END() + +FST_TEST_BEGIN(aws_s3_standardized_request) +{ + char* aws_s3_standardized_request_str = aws_s3_standardized_request(&aws_s3_profile); + + fst_check_string_equals("GET\n/document.docx\nX-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=cbc443a53fb06eafb2b83ca1e4233cbc%2F20190729%2FHCM%2Fs3%2Faws4_request&X-Amz-Date=20190729T083832Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host\nhost:bucket6.stg.vinadata.vn\n\nhost\nUNSIGNED-PAYLOAD", aws_s3_standardized_request_str); + switch_safe_free(aws_s3_standardized_request_str); +} +FST_TEST_END() + +FST_TEST_BEGIN(aws_s3_string_to_sign) +{ + char* aws_s3_standardized_request_str = aws_s3_standardized_request(&aws_s3_profile); + char* aws_s3_string_to_sign_str = aws_s3_string_to_sign(aws_s3_standardized_request_str, &aws_s3_profile); + + fst_check_string_equals("AWS4-HMAC-SHA256\n20190729T083832Z\n20190729/HCM/s3/aws4_request\n945cd2782c8685f5b2472873252fa048eaa37cf8b132ef667bd98b6ad33238ac", aws_s3_string_to_sign_str); + + switch_safe_free(aws_s3_standardized_request_str); + switch_safe_free(aws_s3_string_to_sign_str); +} +FST_TEST_END() + +FST_TEST_BEGIN(aws_s3_signature_key) +{ + char signature_key[SHA256_DIGEST_LENGTH]; + unsigned int aws_s3_signature_key_b64_size = SHA256_DIGEST_LENGTH * 4 / 3 + 5; + unsigned char* aws_s3_signature_key_b64 = (unsigned char*)malloc(aws_s3_signature_key_b64_size); + char* aws_s3_signature_key_buffer = aws_s3_signature_key(signature_key, &aws_s3_profile); + + switch_b64_encode((unsigned char*)aws_s3_signature_key_buffer, SHA256_DIGEST_LENGTH, aws_s3_signature_key_b64, aws_s3_signature_key_b64_size); + fst_check_string_equals("2TBIZBxK1k+qh/pvEs0d2iNQ4SSX63o/8pLzzFPeA7c=", (char*)aws_s3_signature_key_b64); + + switch_safe_free(aws_s3_signature_key_b64); +} +FST_TEST_END() + +FST_TEST_BEGIN(aws_s3_authentication_create) +{ + char* query_param = aws_s3_authentication_create(&aws_s3_profile); + + fst_check_string_equals("X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=cbc443a53fb06eafb2b83ca1e4233cbc%2F20190729%2FHCM%2Fs3%2Faws4_request&X-Amz-Date=20190729T083832Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=3d0e5c18e85440a6cd38bdf8b3d07476fe6f98b8456a39ec401d1c628ce19175", query_param); + + switch_safe_free(query_param); +} +FST_TEST_END() + +FST_TEST_BEGIN(parse_xml_config_with_aws) +{ + switch_xml_t cfg, profiles, profile, aws_s3_profile; + http_profile_t http_profile; + int fd; + int i = 0; + + printf("\n"); + + fd = open("test_aws_http_cache.conf.xml", O_RDONLY); + if (fd < 0) { + fd = open("test/test_aws_http_cache.conf.xml", O_RDONLY); + } + fst_check(fd > 0); + + cfg = switch_xml_parse_fd(fd); + fst_check(cfg != NULL); + + profiles = switch_xml_child(cfg, "profiles"); + fst_check(profiles); + + for (profile = switch_xml_child(profiles, "profile"); profile; profile = profile->next) { + const char *name = NULL; + i++; + + fst_check(profile); + + name = switch_xml_attr_soft(profile, "name"); + printf("testing profile name: %s\n", name); + fst_check(name); + + http_profile.name = name; + http_profile.aws_s3_access_key_id = NULL; + http_profile.secret_access_key = NULL; + http_profile.base_domain = NULL; + http_profile.region = NULL; + http_profile.append_headers_ptr = NULL; + + aws_s3_profile = switch_xml_child(profile, "aws-s3"); + fst_check(aws_s3_profile); + + fst_check(aws_s3_config_profile(aws_s3_profile, &http_profile) == SWITCH_STATUS_SUCCESS); + + fst_check(!zstr(http_profile.region)); + fst_check(!zstr(http_profile.aws_s3_access_key_id)); + fst_check(!zstr(http_profile.secret_access_key)); + printf("base domain: %s\n", http_profile.base_domain); + fst_check(!zstr(http_profile.base_domain)); + switch_safe_free(http_profile.region); + switch_safe_free(http_profile.aws_s3_access_key_id); + switch_safe_free(http_profile.secret_access_key); + switch_safe_free(http_profile.base_domain); + } + + fst_check(i == 2); // test data contain two config + + switch_xml_free(cfg); +} +FST_TEST_END() +#endif + } FST_SUITE_END() diff --git a/src/mod/applications/mod_http_cache/test/test_aws_http_cache.conf.xml b/src/mod/applications/mod_http_cache/test/test_aws_http_cache.conf.xml new file mode 100644 index 0000000000..c21955ee21 --- /dev/null +++ b/src/mod/applications/mod_http_cache/test/test_aws_http_cache.conf.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 604800 + + + + + + + + + + + + + + + + + + + + + + + 604800 + + + + + + + + + + From 64646a3448b65bf2e02005bff8c98b03c70de978 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Tue, 21 Jul 2020 01:51:47 +0400 Subject: [PATCH 010/545] [mod_http_cache] Fix Windows build --- src/mod/applications/mod_http_cache/aws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c index 9c49363e6f..d4b76e7cb2 100644 --- a/src/mod/applications/mod_http_cache/aws.c +++ b/src/mod/applications/mod_http_cache/aws.c @@ -277,7 +277,7 @@ static char *aws_s3_authentication_create(switch_aws_s3_profile* aws_s3_profile) * @param query_string pointer to query param string that will be calculated * @return updated headers */ -SWITCH_MOD_DECLARE(switch_curl_slist_t) *aws_s3_append_headers( +SWITCH_MOD_DECLARE(switch_curl_slist_t *) aws_s3_append_headers( http_profile_t *profile, switch_curl_slist_t *headers, const char *verb, From 3d74cf13791d21739fd64e781ea3a718f5aaef4b Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Wed, 22 Jul 2020 03:00:23 +0400 Subject: [PATCH 011/545] [mod_signalwire] Upgrade code to be able to work on newer libks and signalwire-c v2.0 when released --- .../mod_signalwire/mod_signalwire.c | 101 +++++++++++++++++- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/src/mod/applications/mod_signalwire/mod_signalwire.c b/src/mod/applications/mod_signalwire/mod_signalwire.c index 46f459372c..263307962d 100644 --- a/src/mod/applications/mod_signalwire/mod_signalwire.c +++ b/src/mod/applications/mod_signalwire/mod_signalwire.c @@ -86,8 +86,12 @@ static struct { char relay_connector_id[256]; +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_sess_t *signalwire_session; +#else swclt_sess_t signalwire_session; swclt_hmon_t signalwire_session_monitor; +#endif sw_state_t state; ks_bool_t profile_update; ks_bool_t profile_reload; @@ -221,13 +225,21 @@ static ks_status_t load_credentials_from_json(ks_json_t *json) const char *bootstrap = NULL; const char *relay_connector_id = NULL; +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + if ((bootstrap = ks_json_get_string(json, "bootstrap")) == NULL) { +#else if ((bootstrap = ks_json_get_object_cstr(json, "bootstrap")) == NULL) { +#endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Unable to connect to SignalWire: missing bootstrap URL\n"); status = KS_STATUS_FAIL; goto done; } +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + if ((relay_connector_id = ks_json_get_string(json, "relay_connector_id")) == NULL) { +#else if ((relay_connector_id = ks_json_get_object_cstr(json, "relay_connector_id")) == NULL) { +#endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Unable to connect to SignalWire: missing relay_connector_id\n"); status = KS_STATUS_FAIL; goto done; @@ -251,10 +263,18 @@ static ks_status_t load_credentials_from_json(ks_json_t *json) strncpy(globals.blade_bootstrap, bootstrap, sizeof(globals.blade_bootstrap) - 1); // got adopted, update the client config authentication +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + authentication_str = ks_json_print_unformatted(authentication); +#else authentication_str = ks_json_pprint_unformatted(NULL, authentication); +#endif swclt_config_set_authentication(globals.config, authentication_str); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + switch_safe_free(authentication_str); +#else ks_pool_free(&authentication_str); +#endif done: return status; @@ -425,7 +445,11 @@ static ks_status_t mod_signalwire_adoption_post(void) done: if (rd.data) ks_pool_free(&rd.data); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + switch_safe_free(jsonstr); +#else if (jsonstr) ks_json_free_ex((void **)&jsonstr); +#endif if (json) ks_json_delete(&json); if (curl) { curl_easy_cleanup(curl); @@ -517,6 +541,19 @@ done: return SWITCH_STATUS_SUCCESS; } +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 +static void mod_signalwire_session_state_handler(swclt_sess_t *sess, void *cb_data) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SignalWire Session State Change: %s\n", swclt_sess_state_str(sess->state)); + + if (sess->state != SWCLT_STATE_OFFLINE) { + // Connected with NEW or RESTORED session + globals.signalwire_reconnected = KS_TRUE; + } else { + // Disconnected + } +} +#else static void mod_signalwire_session_state_handler(swclt_sess_t sess, swclt_hstate_change_t *state_change_info, const char *cb_data) { SWCLT_HSTATE new_state = state_change_info->new_state; @@ -530,8 +567,15 @@ static void mod_signalwire_session_state_handler(swclt_sess_t sess, swclt_hstate // Disconnected } } +#endif -static void __on_provisioning_events(swclt_sess_t sess, blade_broadcast_rqu_t *rqu, void *cb_data) +static void __on_provisioning_events( +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 +swclt_sess_t *sess, +#else +swclt_sess_t sess, +#endif +blade_broadcast_rqu_t *rqu, void *cb_data) { if (!strcmp(rqu->event, "update")) { globals.profile_update = KS_TRUE; @@ -717,7 +761,11 @@ done: return status; } +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 +static void mod_signalwire_session_auth_failed_handler(swclt_sess_t *sess) +#else static void mod_signalwire_session_auth_failed_handler(swclt_sess_t sess) +#endif { char path[1024]; @@ -908,7 +956,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_signalwire_load) switch_goto_status(SWITCH_STATUS_TERM, err); } +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_sess_set_state_change_cb(globals.signalwire_session, mod_signalwire_session_state_handler, NULL); +#else swclt_hmon_register(&globals.signalwire_session_monitor, globals.signalwire_session, mod_signalwire_session_state_handler, NULL); +#endif // @todo register nodestore callbacks here if needed @@ -945,7 +997,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_signalwire_load) goto done; err: +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + if (globals.signalwire_session) swclt_sess_destroy(&globals.signalwire_session); +#else if (globals.signalwire_session) ks_handle_destroy(&globals.signalwire_session); +#endif swclt_config_destroy(&globals.config); ks_global_set_logger(NULL); @@ -970,7 +1026,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_signalwire_shutdown) globals.shutdown = KS_TRUE; swclt_sess_disconnect(globals.signalwire_session); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + while (globals.signalwire_session->state == SWCLT_STATE_ONLINE) { +#else while (swclt_hstate_current_get(globals.signalwire_session) == SWCLT_HSTATE_ONLINE) { +#endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sleeping for pending disconnect\n"); ks_sleep_ms(1000); } @@ -980,8 +1040,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_signalwire_shutdown) switch_xml_unbind_search_function_ptr(xml_config_handler); // kill signalwire, so nothing more can come into the system +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_sess_destroy(&globals.signalwire_session); +#else ks_handle_destroy(&globals.signalwire_session); - +#endif // cleanup config swclt_config_destroy(&globals.config); @@ -1047,7 +1110,11 @@ static void mod_signalwire_state_configure(void) switch_port_t external_port; char external_endpoint[256]; char *error = NULL; +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_cmd_reply_t *reply = NULL; +#else swclt_cmd_t cmd; +#endif if (globals.signalwire_reconnected) { globals.signalwire_reconnected = KS_FALSE; @@ -1084,18 +1151,30 @@ static void mod_signalwire_state_configure(void) snprintf(external_endpoint, sizeof(external_endpoint), "%s:%u", external_ip, external_port); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + if (!swclt_sess_provisioning_configure(globals.signalwire_session, "freeswitch", local_endpoint, external_endpoint, globals.relay_connector_id, &reply)) { + if (reply->type == SWCLT_CMD_TYPE_RESULT) { +#else if (!swclt_sess_provisioning_configure(globals.signalwire_session, "freeswitch", local_endpoint, external_endpoint, globals.relay_connector_id, &cmd)) { SWCLT_CMD_TYPE cmd_type; swclt_cmd_type(cmd, &cmd_type); if (cmd_type == SWCLT_CMD_TYPE_RESULT) { const ks_json_t *result; +#endif signalwire_provisioning_configure_response_t *configure_res; - +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + if (!SIGNALWIRE_PROVISIONING_CONFIGURE_RESPONSE_PARSE(reply->pool, reply->json, &configure_res)) { +#else swclt_cmd_result(cmd, &result); result = ks_json_get_object_item(result, "result"); if (!SIGNALWIRE_PROVISIONING_CONFIGURE_RESPONSE_PARSE(ks_handle_pool(cmd), result, &configure_res)) { +#endif const ks_json_t *configuration = configure_res->configuration; +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + const char *configuration_profile = ks_json_get_string(configuration, "profile"); +#else const char *configuration_profile = ks_json_get_object_cstr(configuration, "profile"); +#endif if (globals.signalwire_profile) { switch_xml_free(globals.signalwire_profile); globals.signalwire_profile = NULL; @@ -1121,7 +1200,11 @@ static void mod_signalwire_state_configure(void) } } } +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_cmd_reply_destroy(&reply); +#else ks_handle_destroy(&cmd); +#endif if (globals.state == SW_STATE_CONFIGURE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Failed to receive valid configuration from SignalWire\n"); ks_sleep_ms(4000); @@ -1272,13 +1355,21 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_signalwire_runtime) while (!globals.shutdown) { if (globals.restarting) { swclt_sess_disconnect(globals.signalwire_session); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + while (globals.signalwire_session->state == SWCLT_STATE_ONLINE) { +#else while (swclt_hstate_current_get(globals.signalwire_session) == SWCLT_HSTATE_ONLINE) { +#endif switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sleeping for pending disconnect\n"); ks_sleep_ms(1000); } // kill signalwire, so nothing more can come into the system +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_sess_destroy(&globals.signalwire_session); +#else ks_handle_destroy(&globals.signalwire_session); +#endif // Create a new session and start over swclt_sess_create(&globals.signalwire_session, @@ -1286,7 +1377,11 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_signalwire_runtime) globals.config); swclt_sess_set_auth_failed_cb(globals.signalwire_session, mod_signalwire_session_auth_failed_handler); +#if SIGNALWIRE_CLIENT_C_VERSION_MAJOR >= 2 + swclt_sess_set_state_change_cb(globals.signalwire_session, mod_signalwire_session_state_handler, NULL); +#else swclt_hmon_register(&globals.signalwire_session_monitor, globals.signalwire_session, mod_signalwire_session_state_handler, NULL); +#endif globals.restarting = KS_FALSE; continue; From d4547e6151c420c4e579d52e47d2c10d47958dc6 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Sat, 1 Aug 2020 02:09:50 +0400 Subject: [PATCH 012/545] [Sofia-Sip] Add various accessors and helpers to nua. --- libs/sofia-sip/.update | 2 +- libs/sofia-sip/libsofia-sip-ua/nua/nua.c | 63 ++++++++++++++++++- .../libsofia-sip-ua/nua/sofia-sip/nua.h | 14 +++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index f2ecef0016..67ed62e0fe 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue May 12 18:04:14 UTC 2020 +Fri Jul 31 17:46:57 CDT 2020 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua.c index 451cebb134..fdeac3cad9 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua.c @@ -234,10 +234,14 @@ void nua_destroy(nua_t *nua) #if HAVE_SMIME /* Start NRC Boston */ sm_destroy(nua->sm); #endif /* End NRC Boston */ - su_home_unref(nua->nua_home); + nua_unref(nua); } } +void nua_unref(nua_t *nua) { + if (nua) su_home_unref(nua->nua_home); +} + /** Fetch callback context from nua. * * @param nua Pointer to @nua stack object @@ -1089,3 +1093,60 @@ nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id) } return NULL; } + +/** Get leg from dialog. */ +const nta_leg_t *nua_get_dialog_state_leg(nua_handle_t *nh) +{ + if (nh && nh->nh_ds) + return nh->nh_ds->ds_leg; + else + return NULL; +} + +/** Get su_home_t from nua handle. */ +su_home_t *nua_handle_get_home(nua_handle_t *nh) +{ + if (nh && nh->nh_home) + return nh->nh_home; + else + return NULL; +} + +/** Get su_home_t from nua. */ +su_home_t *nua_get_home(nua_t *nua) +{ + if (nua && nua->nua_home) + return nua->nua_home; + else + return NULL; +} + +/** Get nta_agent_t from nua. */ +nta_agent_t *nua_get_agent(nua_t *nua) +{ + if (nua && nua->nua_nta) + return nua->nua_nta; + else + return NULL; +} + +/** Set has invite of a nua handle */ +void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val) +{ + if (nh) + nh->nh_has_invite = val; +} + +/** Check if nua handle is destroyed */ +unsigned nua_handle_is_destroyed(nua_handle_t *nh) +{ + assert(nh); + return nh->nh_destroyed; +} + +void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh, + unsigned min, unsigned max) { + if (nh && nh->nh_ds && nh->nh_ds->ds_usage) { + nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, min, max); + } +} \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h index 37b7667792..5a698359cb 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h @@ -47,6 +47,10 @@ #include #endif +#ifndef NTA_H +#include +#endif + #ifndef NUA_TAG_H #include #endif @@ -386,6 +390,16 @@ SOFIAPUBFUN nua_handle_t *nua_handle_by_replaces(nua_t *nua, nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id); +SOFIAPUBFUN const nta_leg_t *nua_get_dialog_state_leg(nua_handle_t *nh); +SOFIAPUBFUN su_home_t *nua_handle_get_home(nua_handle_t *nh); +SOFIAPUBFUN void nua_unref(nua_t *nua); +SOFIAPUBFUN su_home_t *nua_get_home(nua_t *nua); +SOFIAPUBFUN nta_agent_t *nua_get_agent(nua_t *nua); +SOFIAPUBFUN void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val); +SOFIAPUBFUN unsigned nua_handle_is_destroyed(nua_handle_t *nh); +SOFIAPUBFUN void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh, + unsigned min, unsigned max); + SOFIA_END_DECLS #endif From b06036e30fcdf6b2c9b57505c3581f7671d0bbc1 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Sat, 1 Aug 2020 02:52:19 +0400 Subject: [PATCH 013/545] [mod_sofia] Cleanup usage of sofia-sip headers. --- src/mod/endpoints/mod_sofia/mod_sofia.c | 4 +- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 - src/mod/endpoints/mod_sofia/sip-dig.c | 3 - src/mod/endpoints/mod_sofia/sofia.c | 132 +++++++++---------- src/mod/endpoints/mod_sofia/sofia_glue.c | 20 +-- src/mod/endpoints/mod_sofia/sofia_presence.c | 54 ++++---- src/mod/endpoints/mod_sofia/sofia_reg.c | 18 +-- 7 files changed, 114 insertions(+), 118 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 84da642aff..e236b09a38 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2456,7 +2456,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi /* Set sip_to_tag to local tag for inbound channels. */ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { const char* to_tag = ""; - to_tag = switch_str_nil(nta_leg_get_tag(tech_pvt->nh->nh_ds->ds_leg)); + to_tag = switch_str_nil(nta_leg_get_tag(nua_get_dialog_state_leg(tech_pvt->nh))); if(to_tag) { switch_channel_set_variable(channel, "sip_to_tag", to_tag); } @@ -5251,7 +5251,7 @@ static int notify_csta_callback(void *pArg, int argc, char **argv, char **column //nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END()); nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(full_to), SIPTAG_TO_STR(full_from), SIPTAG_CONTACT_STR(profile->url), TAG_END()); - cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + cseq = sip_cseq_create(nua_handle_get_home(nh), callsequence, SIP_METHOD_NOTIFY); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 05e50c952f..3249533730 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -142,7 +142,6 @@ typedef struct private_object private_object_t; #include #include #include -#include "nua_stack.h" #include "sofia-sip/msg_parser.h" #include "sofia-sip/sip_parser.h" #include "sofia-sip/tport_tag.h" diff --git a/src/mod/endpoints/mod_sofia/sip-dig.c b/src/mod/endpoints/mod_sofia/sip-dig.c index 2c87f231d3..2d74eb66f6 100644 --- a/src/mod/endpoints/mod_sofia/sip-dig.c +++ b/src/mod/endpoints/mod_sofia/sip-dig.c @@ -133,9 +133,6 @@ #include "switch.h" -#ifndef WIN32 -#include "../../config.h" -#endif #include "sofia-sip/su.h" diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index a3344fc323..bceec9d906 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -237,9 +237,9 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, SWITCH_STANDARD_STREAM(stream); for (rp = sip->sip_route; rp; rp = rp->r_next) { - char *route = sip_header_as_string(nh->nh_home, (void *) rp); + char *route = sip_header_as_string(nua_handle_get_home(nh), (void *) rp); stream.write_function(&stream, x == 0 ? "%s" : ",%s", route); - su_free(nh->nh_home, route); + su_free(nua_handle_get_home(nh), route); x++; } switch_channel_set_variable(channel, "sip_full_route", stream.data); @@ -249,9 +249,9 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { if (sip->sip_contact) { - char *c = sip_header_as_string(nh->nh_home, (void *) sip->sip_contact); + char *c = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_contact); switch_channel_set_variable(channel, "sip_recover_contact", c); - su_free(nh->nh_home, c); + su_free(nua_handle_get_home(nh), c); } } @@ -267,7 +267,7 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, SWITCH_STANDARD_STREAM(reverse_stream); for(rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) { - char *rr = sip_header_as_string(nh->nh_home, (void *) rrp); + char *rr = sip_header_as_string(nua_handle_get_home(nh), (void *) rrp); forward_stream.write_function(&forward_stream, x == 0 ? "%s" : ",%s", rr); tmp[y++] = rr; if (y == 127) break; @@ -280,7 +280,7 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, while(y >= 0) { reverse_stream.write_function(&reverse_stream, x == 0 ? "%s" : ",%s", tmp[y]); - su_free(nh->nh_home, tmp[y]); + su_free(nua_handle_get_home(nh), tmp[y]); y--; x++; } @@ -305,10 +305,10 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, SWITCH_STANDARD_STREAM(stream); for(vp = sip->sip_via; vp; vp = vp->v_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); stream.write_function(&stream, x == 0 ? "%s" : ",%s", v); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); x++; } @@ -330,9 +330,9 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, switch_channel_set_variable(channel, "sip_from_display", p); } if (p != sip->sip_from->a_display) free(p); - if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_from))) { + if ((full = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_from))) { switch_channel_set_variable(channel, "sip_full_from", full); - su_free(nh->nh_home, full); + su_free(nua_handle_get_home(nh), full); } } @@ -345,9 +345,9 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, if (p != sip->sip_to->a_display) free(p); - if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_to))) { + if ((full = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_to))) { switch_channel_set_variable(channel, "sip_full_to", full); - su_free(nh->nh_home, full); + su_free(nua_handle_get_home(nh), full); } } @@ -398,9 +398,9 @@ static void sofia_add_invite_header_to_chanvars(switch_channel_t *channel, nua_h if (sip_header) { char *full; - if ((full = sip_header_as_string(nh->nh_home, sip_header))) { + if ((full = sip_header_as_string(nua_handle_get_home(nh), sip_header))) { switch_channel_set_variable(channel, var, full); - su_free(nh->nh_home, full); + su_free(nua_handle_get_home(nh), full); } } } @@ -464,99 +464,99 @@ static void sofia_parse_all_invite_headers(sip_t const *sip, switch_core_session if (sip->sip_via) { sip_via_t *vp; for (vp = sip->sip_via; vp; vp = vp->v_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_via", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if (sip->sip_record_route) { sip_record_route_t *rrp; for (rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) { - char *rr = sip_header_as_string(nh->nh_home, (void *) rrp); + char *rr = sip_header_as_string(nua_handle_get_home(nh), (void *) rrp); switch_channel_add_variable_var_check(channel, "sip_i_record_route", rr, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, rr); + su_free(nua_handle_get_home(nh), rr); } } if (sip->sip_proxy_authorization) { sip_proxy_authorization_t *vp; for (vp = sip->sip_proxy_authorization; vp; vp = vp->au_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_proxy_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if (sip->sip_call_info) { sip_call_info_t *vp; for (vp = sip->sip_call_info; vp; vp = vp->ci_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_call_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if (sip->sip_accept) { sip_accept_t *vp; for (vp = sip->sip_accept; vp; vp = vp->ac_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_accept", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if (sip->sip_authorization) { sip_authorization_t *vp; for (vp = sip->sip_authorization; vp; vp = vp->au_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if ((alert_info = sip_alert_info(sip))) { sip_alert_info_t *vp; for (vp = alert_info; vp; vp = vp->ai_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_alert_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if ((passerted = sip_p_asserted_identity(sip))) { sip_p_asserted_identity_t *vp; for (vp = passerted; vp; vp = vp->paid_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_p_asserted_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if ((ppreferred = sip_p_preferred_identity(sip))) { sip_p_preferred_identity_t *vp; for (vp = ppreferred; vp; vp = vp->ppid_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_p_preferred_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if ((rpid = sip_remote_party_id(sip))) { sip_remote_party_id_t *vp; for (vp = rpid; vp; vp = vp->rpid_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_remote_party_id", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } if ((reply_to = sip_reply_to(sip))) { sip_reply_to_t *vp; for (vp = reply_to; vp; vp = vp->rplyto_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); + char *v = sip_header_as_string(nua_handle_get_home(nh), (void *) vp); switch_channel_add_variable_var_check(channel, "sip_i_reply_to", v, SWITCH_FALSE, SWITCH_STACK_PUSH); - su_free(nh->nh_home, v); + su_free(nua_handle_get_home(nh), v); } } @@ -1031,7 +1031,7 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, call_info = switch_channel_get_variable(channel, "presence_call_info_full"); if (sip->sip_reason) { - char *reason_header = sip_header_as_string(nh->nh_home, (void *) sip->sip_reason); + char *reason_header = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_reason); if (!zstr(reason_header)) { switch_channel_set_variable(channel, "sip_reason", reason_header); @@ -1641,7 +1641,7 @@ static void our_sofia_event_callback(nua_event_t event, if (sip && sip->sip_payload && sip->sip_payload->pl_data) { if (sip->sip_payload->pl_len != strlen(sip->sip_payload->pl_data)) { - sip->sip_payload->pl_data = su_strndup(nh->nh_home, sip->sip_payload->pl_data, sip->sip_payload->pl_len); + sip->sip_payload->pl_data = su_strndup(nua_handle_get_home(nh), sip->sip_payload->pl_data, sip->sip_payload->pl_len); } } @@ -1669,7 +1669,7 @@ static void our_sofia_event_callback(nua_event_t event, switch_channel_set_variable(channel, "sip_invite_failure_phrase", "CANCEL"); if (sip->sip_reason) { - char *reason_header = sip_header_as_string(nh->nh_home, (void *) sip->sip_reason); + char *reason_header = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_reason); if (!zstr(reason_header)) { switch_channel_set_variable(channel, "sip_reason", reason_header); @@ -1997,11 +1997,11 @@ static void our_sofia_event_callback(nua_event_t event, contact_str = sofia_glue_gen_contact_str(profile, sip, nh, de, &np); call_id = sip->sip_call_id ? sip->sip_call_id->i_id : ""; - full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from); - full_to = sip_header_as_string(nh->nh_home, (void *) sip->sip_to); - full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via); + full_from = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_from); + full_to = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_to); + full_via = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_via); - full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent); + full_agent = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_user_agent); switch_stun_random_string(to_tag, 12, NULL); @@ -2048,7 +2048,7 @@ static void our_sofia_event_callback(nua_event_t event, sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - sip_to_tag(nh->nh_home, sip->sip_to, to_tag); + sip_to_tag(nua_handle_get_home(nh), sip->sip_to, to_tag); } nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_TO(sip->sip_to), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); @@ -2271,14 +2271,14 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep) de->nh, sofia_private, de->sip, de, (tagi_t *) de->data->e_tags); nua_destroy_event(de->event); - su_free(nh->nh_home, de); + su_free(nua_handle_get_home(nh), de); switch_mutex_lock(profile->flag_mutex); profile->queued_events--; switch_mutex_unlock(profile->flag_mutex); nua_handle_unref(nh); - nua_stack_unref(nua); + nua_unref(nua); } @@ -2503,20 +2503,20 @@ void sofia_event_callback(nua_event_t event, profile->queued_events++; switch_mutex_unlock(profile->flag_mutex); - de = su_alloc(nh->nh_home, sizeof(*de)); + de = su_alloc(nua_handle_get_home(nh), sizeof(*de)); memset(de, 0, sizeof(*de)); nua_save_event(nua, de->event); de->nh = nua_handle_ref(nh); de->data = nua_event_data(de->event); de->sip = sip_object(de->data->e_msg); de->profile = profile; - de->nua = nua_stack_ref(nua); + de->nua = (nua_t *)su_home_ref(nua_get_home(nua)); if (event == nua_i_invite && !sofia_private) { switch_core_session_t *session; private_object_t *tech_pvt = NULL; - if (!(sofia_private = su_alloc(nh->nh_home, sizeof(*sofia_private)))) { + if (!(sofia_private = su_alloc(nua_handle_get_home(nh), sizeof(*sofia_private)))) { abort(); } @@ -2563,14 +2563,14 @@ void sofia_event_callback(nua_event_t event, if (!sip || !sip->sip_call_id || zstr(sip->sip_call_id->i_id)) { nua_respond(nh, 503, "INVALID INVITE", TAG_END()); nua_destroy_event(de->event); - su_free(nh->nh_home, de); + su_free(nua_handle_get_home(nh), de); switch_mutex_lock(profile->flag_mutex); profile->queued_events--; switch_mutex_unlock(profile->flag_mutex); nua_handle_unref(nh); - nua_stack_unref(nua); + nua_unref(nua); goto end; } @@ -2601,14 +2601,14 @@ void sofia_event_callback(nua_event_t event, } else { nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END()); nua_destroy_event(de->event); - su_free(nh->nh_home, de); + su_free(nua_handle_get_home(nh), de); switch_mutex_lock(profile->flag_mutex); profile->queued_events--; switch_mutex_unlock(profile->flag_mutex); nua_handle_unref(nh); - nua_stack_unref(nua); + nua_unref(nua); goto end; } @@ -3326,7 +3326,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set params for %s\n", profile->name); if (sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_PORT) || sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT)) { - sip_via_t *vias = nta_agent_via(profile->nua->nua_nta); + sip_via_t *vias = nta_agent_via(nua_get_agent(profile->nua)); sip_via_t *via = NULL; for (via = vias; via; via = via->v_next) { @@ -9620,9 +9620,9 @@ switch_status_t sofia_proxy_sip_i_message(nua_t *nua, sofia_profile_t *profile, } nua_message(other_tech_pvt->nh, - TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(other_tech_pvt->nh->nh_home, ct))), + TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(nua_handle_get_home(other_tech_pvt->nh), ct))), TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(other_tech_pvt->nh->nh_home, pl))), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(nua_handle_get_home(other_tech_pvt->nh), pl))), TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } @@ -9670,9 +9670,9 @@ switch_status_t sofia_proxy_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua } nua_info(other_tech_pvt->nh, - TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(other_tech_pvt->nh->nh_home, ct))), + TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(nua_handle_get_home(other_tech_pvt->nh), ct))), TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(other_tech_pvt->nh->nh_home, pl))), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(nua_handle_get_home(other_tech_pvt->nh), pl))), TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } @@ -10696,7 +10696,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if ((rpid = sip_remote_party_id(sip))) { if (rpid->rpid_url->url_user) { - char *full_rpid_header = sip_header_as_string(nh->nh_home, (void *) rpid); + char *full_rpid_header = sip_header_as_string(nua_handle_get_home(nh), (void *) rpid); from_user = rpid->rpid_url->url_user; if (!zstr(full_rpid_header)) { switch_channel_set_variable(channel, "sip_Remote-Party-ID", full_rpid_header); @@ -10712,7 +10712,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if ((passerted = sip_p_asserted_identity(sip))) { if (passerted->paid_url->url_user) { - char *full_paid_header = sip_header_as_string(nh->nh_home, (void *) passerted); + char *full_paid_header = sip_header_as_string(nua_handle_get_home(nh), (void *) passerted); //char *full_paid_header = (char *)(passerted->paid_common->h_data); from_user = passerted->paid_url->url_user; if (!zstr(full_paid_header)) { @@ -10735,7 +10735,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if ((ppreferred = sip_p_preferred_identity(sip))) { if (ppreferred->ppid_url->url_user) { - char *full_ppid_header = sip_header_as_string(nh->nh_home, (void *) ppreferred); + char *full_ppid_header = sip_header_as_string(nua_handle_get_home(nh), (void *) ppreferred); from_user = ppreferred->ppid_url->url_user; if (!zstr(full_ppid_header)) { switch_channel_set_variable(channel, "sip_P-Preferred-Identity", full_ppid_header); @@ -11024,13 +11024,13 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } if ((alert_info = sip_alert_info(sip))) { - char *tmp = sip_header_as_string(nh->nh_home, (void *) alert_info); + char *tmp = sip_header_as_string(nua_handle_get_home(nh), (void *) alert_info); switch_channel_set_variable(channel, "alert_info", tmp); - su_free(nh->nh_home, tmp); + su_free(nua_handle_get_home(nh), tmp); } if ((call_info = sip_call_info(sip))) { - call_info_str = sip_header_as_string(nh->nh_home, (void *) call_info); + call_info_str = sip_header_as_string(nua_handle_get_home(nh), (void *) call_info); if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE) && switch_stristr("appearance", call_info_str)) { char *p; @@ -11051,7 +11051,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia call_info = call_info->ci_next; while (call_info) { - call_info_str = sip_header_as_string(nh->nh_home, (void *) call_info); + call_info_str = sip_header_as_string(nua_handle_get_home(nh), (void *) call_info); switch_channel_add_variable_var_check(channel, "sip_call_info", call_info_str, SWITCH_FALSE, SWITCH_STACK_PUSH); call_info = call_info->ci_next; } @@ -11304,7 +11304,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } if ((privacy = sip_privacy(sip))) { - char *full_priv_header = sip_header_as_string(nh->nh_home, (void *) privacy); + char *full_priv_header = sip_header_as_string(nua_handle_get_home(nh), (void *) privacy); if (!zstr(full_priv_header)) { switch_channel_set_variable(channel, "sip_Privacy", full_priv_header); } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a412f25cd3..27171890dd 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -475,7 +475,7 @@ void sofia_glue_store_session_id(switch_core_session_t *session, sofia_profile_t struct private_object *tech_pvt = switch_core_session_get_private(session); switch_channel_set_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE, a_id); if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { - tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(nua_handle_get_home(tech_pvt->nh), a_id); } } @@ -532,7 +532,7 @@ char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile struct private_object *tech_pvt = switch_core_session_get_private(session); switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { - tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(nua_handle_get_home(tech_pvt->nh), a_id); } } } @@ -559,7 +559,7 @@ char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile struct private_object *tech_pvt = switch_core_session_get_private(session); switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { - tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(nua_handle_get_home(tech_pvt->nh), a_id); } } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, @@ -601,7 +601,7 @@ char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile struct private_object *tech_pvt = switch_core_session_get_private(session); switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); if (tech_pvt && tech_pvt->sofia_private) { - tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(nua_handle_get_home(tech_pvt->nh), a_id); } } b_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE); @@ -1500,7 +1500,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) switch_safe_free(d_url); - if (!(sofia_private = su_alloc(tech_pvt->nh->nh_home, sizeof(*sofia_private)))) { + if (!(sofia_private = su_alloc(nua_handle_get_home(tech_pvt->nh), sizeof(*sofia_private)))) { abort(); } @@ -1592,14 +1592,14 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_invite_cseq"))) { uint32_t callsequence = (uint32_t) strtoul(val, NULL, 10); - cseq = sip_cseq_create(tech_pvt->nh->nh_home, callsequence, SIP_METHOD_INVITE); + cseq = sip_cseq_create(nua_handle_get_home(tech_pvt->nh), callsequence, SIP_METHOD_INVITE); } switch_channel_clear_flag(channel, CF_MEDIA_ACK); if (handle_full_from) { - tech_pvt->nh->nh_has_invite = 1; + nua_handle_set_has_invite(tech_pvt->nh, 1); } if ((mp = sofia_media_get_multipart(session, "sip_multipart", tech_pvt->mparams.local_sdp_str, &mp_type))) { @@ -3333,8 +3333,8 @@ char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua } if (sip->sip_record_route) { - char *full_contact = sip_header_as_string(nh->nh_home, (void *) contact); - char *route = sofia_glue_strip_uri(sip_header_as_string(nh->nh_home, (void *) sip->sip_record_route)); + char *full_contact = sip_header_as_string(nua_handle_get_home(nh), (void *) contact); + char *route = sofia_glue_strip_uri(sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_record_route)); char *full_contact_dup; char *route_encoded; int route_encoded_len; @@ -3348,7 +3348,7 @@ char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua free(route_encoded); } else if (np->is_nat && np->fs_path) { - char *full_contact = sip_header_as_string(nh->nh_home, (void *) contact); + char *full_contact = sip_header_as_string(nua_handle_get_home(nh), (void *) contact); char *full_contact_dup; char *path_encoded; int path_encoded_len; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index be27121cd1..e1c31c99c8 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -368,7 +368,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) if (is_blocking) { sanity = 200; - while(!mstatus && --sanity && !msg_nh->nh_destroyed) { + while(!mstatus && --sanity && !nua_handle_is_destroyed(msg_nh)) { switch_yield(100000); } @@ -2334,7 +2334,7 @@ static void _send_presence_notify(sofia_profile_t *profile, } nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact), SIPTAG_CONTACT_STR(contact_str), TAG_END()); - cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + cseq = sip_cseq_create(nua_handle_get_home(nh), callsequence, SIP_METHOD_NOTIFY); nua_handle_bind(nh, &mod_sofia_globals.destroy_private); @@ -3712,7 +3712,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, contact_user = sip->sip_contact->m_url->url_user; } - full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent); + full_agent = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_user_agent); //tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); @@ -3726,7 +3726,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, } } - event = sip_header_as_string(nh->nh_home, (void *) sip->sip_event); + event = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_event); if (to) { to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); @@ -3864,9 +3864,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, } call_id = sip->sip_call_id->i_id; - full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from); - full_to = sip_header_as_string(nh->nh_home, (void *) sip->sip_to); - full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via); + full_from = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_from); + full_to = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_to); + full_via = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_via); if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) { @@ -4062,9 +4062,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, } - if (nh && nh->nh_ds->ds_usage) { + if (nh) { /* nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); */ - nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta, exp_delta); + nua_handle_dialog_usage_set_refresh_range(nh, exp_delta, exp_delta); } if (contactstr && (p = strchr(contactstr, '@'))) { @@ -4076,7 +4076,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, } if (nh) { - sip_to_tag(nh->nh_home, sip->sip_to, use_to_tag); + sip_to_tag(nua_handle_get_home(nh), sip->sip_to, use_to_tag); } if (mod_sofia_globals.debug_presence > 0) { @@ -4107,7 +4107,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (zstr(full_agent) || (*full_agent != 'z' && *full_agent != 'Z')) { /* supress endless loop bug with zoiper */ callsequence = sofia_presence_get_cseq(profile); - cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + cseq = sip_cseq_create(nua_handle_get_home(nh), callsequence, SIP_METHOD_NOTIFY); nua_notify(nh, SIPTAG_EXPIRES_STR("0"), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), @@ -4124,7 +4124,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, char *p = NULL; if (sip->sip_call_info) { - full_call_info = sip_header_as_string(nh->nh_home, (void *) sip->sip_call_info); + full_call_info = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_call_info); if ((p = strchr(full_call_info, ';'))) { p++; } @@ -4154,7 +4154,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, NULL); } - su_free(nh->nh_home, full_call_info); + su_free(nua_handle_get_home(nh), full_call_info); } @@ -4165,12 +4165,12 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_time_t now; if (sip->sip_call_info) { - full_call_info = sip_header_as_string(nh->nh_home, (void *) sip->sip_call_info); + full_call_info = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_call_info); if ((p = strchr(full_call_info, ';'))) { p++; } callsequence = sofia_presence_get_cseq(profile); - cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + cseq = sip_cseq_create(nua_handle_get_home(nh), callsequence, SIP_METHOD_NOTIFY); nua_notify(nh, SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), @@ -4205,7 +4205,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, NULL); - su_free(nh->nh_home, full_call_info); + su_free(nua_handle_get_home(nh), full_call_info); } } else if (!strcasecmp(event, "call-info")) { sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, call_id); @@ -4401,21 +4401,21 @@ void sofia_presence_handle_sip_i_subscribe(int status, } if (event) { - su_free(nh->nh_home, event); + su_free(nua_handle_get_home(nh), event); } if (full_from) { - su_free(nh->nh_home, full_from); + su_free(nua_handle_get_home(nh), full_from); } if (full_to) { - su_free(nh->nh_home, full_to); + su_free(nua_handle_get_home(nh), full_to); } if (full_via) { - su_free(nh->nh_home, full_via); + su_free(nua_handle_get_home(nh), full_via); } if (full_agent) { - su_free(nh->nh_home, full_agent); + su_free(nua_handle_get_home(nh), full_agent); } switch_safe_free(d_user); @@ -4608,7 +4608,7 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n char *open_closed = "", *note_txt = ""; if (sip->sip_user_agent) { - full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent); + full_agent = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_user_agent); } if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status")) @@ -4652,7 +4652,7 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n } } - event_type = sip_header_as_string(nh->nh_home, (void *) sip->sip_event); + event_type = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_event); if (count) { if ((sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' " @@ -4702,11 +4702,11 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n } if (event_type) { - su_free(nh->nh_home, event_type); + su_free(nua_handle_get_home(nh), event_type); } if (full_agent) { - su_free(nh->nh_home, full_agent); + su_free(nua_handle_get_home(nh), full_agent); } switch_xml_free(xml); @@ -4859,7 +4859,7 @@ void sofia_presence_handle_sip_i_message(int status, sip_unknown_t *un; int first_history_info = 1; - full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from); + full_from = sip_header_as_string(nua_handle_get_home(nh), (void *) sip->sip_from); if ((p = strchr(to_user, '+')) && p != to_user) { switch_copy_string(proto, to_user, sizeof(proto)); @@ -5013,7 +5013,7 @@ void sofia_presence_handle_sip_i_message(int status, switch_safe_free(from_addr); if (full_from) { - su_free(nh->nh_home, full_from); + su_free(nua_handle_get_home(nh), full_from); } } } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 0ffa235875..81d2ffdabd 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1935,17 +1935,17 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu switch_mutex_unlock(profile->flag_mutex); if (!hnh) { - if (!(sofia_private = su_alloc(nh->nh_home, sizeof(*sofia_private)))) { + if (!(sofia_private = su_alloc(nua_handle_get_home(nh), sizeof(*sofia_private)))) { abort(); } memset(sofia_private, 0, sizeof(*sofia_private)); - sofia_private->call_id = su_strdup(nh->nh_home, call_id); - sofia_private->network_ip = su_strdup(nh->nh_home, network_ip); - sofia_private->network_port = su_strdup(nh->nh_home, network_port_c); - sofia_private->key = su_strdup(nh->nh_home, key); - sofia_private->user = su_strdup(nh->nh_home, to_user); - sofia_private->realm = su_strdup(nh->nh_home, reg_host); + sofia_private->call_id = su_strdup(nua_handle_get_home(nh), call_id); + sofia_private->network_ip = su_strdup(nua_handle_get_home(nh), network_ip); + sofia_private->network_port = su_strdup(nua_handle_get_home(nh), network_port_c); + sofia_private->key = su_strdup(nua_handle_get_home(nh), key); + sofia_private->user = su_strdup(nua_handle_get_home(nh), to_user); + sofia_private->realm = su_strdup(nua_handle_get_home(nh), reg_host); sofia_private->is_static++; *sofia_private_p = sofia_private; @@ -2426,12 +2426,12 @@ void sofia_reg_handle_sip_r_register(int status, char *full; for (; contact; contact = contact->m_next) { - if ((full = sip_header_as_string(nh->nh_home, (void *) contact))) { + if ((full = sip_header_as_string(nua_handle_get_home(nh), (void *) contact))) { if (switch_stristr(gateway->register_contact, full)) { break; } - su_free(nh->nh_home, full); + su_free(nua_handle_get_home(nh), full); } } } From 546bebbe5e7936a834f5be28ade91808f548215b Mon Sep 17 00:00:00 2001 From: Mike Jerris Date: Mon, 3 Aug 2020 15:29:35 -0400 Subject: [PATCH 014/545] [core] fix build with newer build tools against openssl 1.1 --- src/switch_core_cert.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/switch_core_cert.c b/src/switch_core_cert.c index 393baa55a9..53cf538f76 100644 --- a/src/switch_core_cert.c +++ b/src/switch_core_cert.c @@ -36,6 +36,8 @@ static switch_mutex_t **ssl_mutexes; static switch_memory_pool_t *ssl_pool = NULL; static int ssl_count = 0; +#if OPENSSL_VERSION_NUMBER <= 0x10100000 + static inline void switch_ssl_ssl_lock_callback(int mode, int type, char *file, int line) { if (mode & CRYPTO_LOCK) { @@ -51,6 +53,8 @@ static inline void switch_ssl_ssl_thread_id(CRYPTO_THREADID *id) CRYPTO_THREADID_set_numeric(id, (unsigned long)switch_thread_self()); } +#endif + SWITCH_DECLARE(void) switch_ssl_init_ssl_locks(void) { @@ -69,8 +73,10 @@ SWITCH_DECLARE(void) switch_ssl_init_ssl_locks(void) switch_assert(ssl_mutexes[i] != NULL); } +#if OPENSSL_VERSION_NUMBER <= 0x10100000 CRYPTO_THREADID_set_callback(switch_ssl_ssl_thread_id); CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))switch_ssl_ssl_lock_callback); +#endif } ssl_count++; From 2fc0e3b80a41ec34aefbe051093758feeb13ecd4 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Tue, 28 Jul 2020 21:10:23 +0400 Subject: [PATCH 015/545] [Build-System] Remove Sofia-Sip library from the FreeSWITCH tree and use packages instead. --- .drone.yml | 7 +- .gitattributes | 1 - .gitignore | 2 + Makefile.am | 19 +- acinclude.m4 | 4 +- bootstrap.sh | 2 +- .../m4 => build/config}/sac-openssl.m4 | 0 .../m4 => build/config}/sac-pkg-config.m4 | 0 configure.ac | 6 +- debian/bootstrap.sh | 2 +- freeswitch.spec | 1 + libs/.gitignore | 1 - libs/sofia-sip/.update | 1 - libs/sofia-sip/AUTHORS | 49 - libs/sofia-sip/COPYING | 504 - libs/sofia-sip/COPYRIGHTS | 251 - libs/sofia-sip/ChangeLog | 18 - libs/sofia-sip/ChangeLog.ext-trees | 4578 ------ libs/sofia-sip/Makefile.am | 85 - libs/sofia-sip/README | 66 - libs/sofia-sip/README.developers | 134 - libs/sofia-sip/RELEASE | 108 - libs/sofia-sip/RELEASE.template | 73 - libs/sofia-sip/TODO | 29 - libs/sofia-sip/acinclude.m4 | 7 - libs/sofia-sip/autoconf-all.cmd | 5 - libs/sofia-sip/autogen.sh | 8 - libs/sofia-sip/configure.ac | 389 - libs/sofia-sip/configure.gnu | 4 - libs/sofia-sip/docs/build_system.txt | 105 - libs/sofia-sip/docs/devel_platform_notes.txt | 58 - libs/sofia-sip/docs/release_management.txt | 136 - libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog | 25 - .../libsofia-sip-ua-glib/Makefile.am | 60 - .../docs/Doxyfile.aliases | 1 - .../libsofia-sip-ua-glib/docs/Doxyfile.conf | 18 - .../docs/Doxyfile.version | 2 - .../libsofia-sip-ua-glib/su-glib/Doxyfile.in | 12 - .../libsofia-sip-ua-glib/su-glib/Makefile.am | 62 - .../su-glib/sofia-sip/su_glib.h | 50 - .../su-glib/sofia-sip/su_source.h | 56 - .../libsofia-sip-ua-glib/su-glib/su_glib.docs | 59 - .../libsofia-sip-ua-glib/su-glib/su_source.c | 1113 -- .../su-glib/su_source_test.c | 536 - .../su-glib/torture_su_glib_timer.c | 269 - libs/sofia-sip/libsofia-sip-ua/ChangeLog | 427 - libs/sofia-sip/libsofia-sip-ua/Makefile.am | 116 - libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog | 7 - .../sofia-sip/libsofia-sip-ua/bnf/Doxyfile.in | 15 - .../sofia-sip/libsofia-sip-ua/bnf/Makefile.am | 47 - libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c | 922 -- libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs | 19 - .../libsofia-sip-ua/bnf/sofia-sip/bnf.h | 325 - .../bnf/sofia-sip/hostdomain.h | 60 - .../libsofia-sip-ua/bnf/torture_bnf.c | 376 - libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog | 20 - .../libsofia-sip-ua/docs/Doxyfile.aliases | 66 - .../libsofia-sip-ua/docs/Doxyfile.conf | 65 - .../libsofia-sip-ua/docs/Doxyfile.in | 34 - .../libsofia-sip-ua/docs/Doxyfile.version.in | 3 - .../libsofia-sip-ua/docs/Makefile.am | 50 - .../libsofia-sip-ua/docs/conformance.docs | 1289 -- .../libsofia-sip-ua/docs/docguide.docs | 249 - .../libsofia-sip-ua/docs/mainpage.docs | 741 - .../pictures/SIP_basic_incoming_operation.eps | Bin 251693 -> 0 bytes .../pictures/SIP_basic_incoming_operation.gif | Bin 3069 -> 0 bytes .../pictures/SIP_basic_incoming_operation.vsd | Bin 17408 -> 0 bytes .../pictures/SIP_basic_outgoing_operation.eps | Bin 298751 -> 0 bytes .../pictures/SIP_basic_outgoing_operation.gif | Bin 4024 -> 0 bytes .../pictures/SIP_basic_outgoing_operation.vsd | Bin 23040 -> 0 bytes .../docs/pictures/SIP_incoming_call.eps | Bin 393648 -> 0 bytes .../docs/pictures/SIP_incoming_call.gif | Bin 7139 -> 0 bytes .../docs/pictures/SIP_incoming_call.vsd | Bin 32256 -> 0 bytes .../docs/pictures/SIP_outgoing_call.eps | Bin 551934 -> 0 bytes .../docs/pictures/SIP_outgoing_call.gif | Bin 8545 -> 0 bytes .../docs/pictures/SIP_outgoing_call.vsd | Bin 35328 -> 0 bytes .../SIP_outgoing_operation_with_auth.eps | Bin 306825 -> 0 bytes .../SIP_outgoing_operation_with_auth.gif | Bin 4490 -> 0 bytes .../SIP_outgoing_operation_with_auth.vsd | Bin 26112 -> 0 bytes .../docs/pictures/autotools.eps | Bin 499528 -> 0 bytes .../docs/pictures/autotools.gif | Bin 10413 -> 0 bytes .../docs/pictures/autotools.vsd | Bin 51200 -> 0 bytes .../docs/pictures/nta-receiving-message.eps | Bin 108850 -> 0 bytes .../docs/pictures/nta-receiving-message.gif | Bin 7652 -> 0 bytes .../libsofia-sip-ua/docs/sofia-footer.html.in | 4 - .../libsofia-sip-ua/features/ChangeLog | 32 - .../libsofia-sip-ua/features/Doxyfile.in | 23 - .../libsofia-sip-ua/features/Makefile.am | 35 - .../libsofia-sip-ua/features/features.c | 138 - .../libsofia-sip-ua/features/features.docs | 41 - .../features/sofia-sip/sofia_features.h.in | 67 - libs/sofia-sip/libsofia-sip-ua/http/ChangeLog | 7 - .../libsofia-sip-ua/http/Doxyfile.in | 19 - .../libsofia-sip-ua/http/Makefile.am | 93 - libs/sofia-sip/libsofia-sip-ua/http/headers | 48 - .../libsofia-sip-ua/http/http.def.in | 17 - libs/sofia-sip/libsofia-sip-ua/http/http.docs | 40 - .../libsofia-sip-ua/http/http_basic.c | 1667 --- .../libsofia-sip-ua/http/http_extra.c | 471 - .../libsofia-sip-ua/http/http_header.c | 307 - .../libsofia-sip-ua/http/http_inlined.c | 52 - .../libsofia-sip-ua/http/http_parser.c | 572 - .../http/http_parser_table.c.in | 59 - .../libsofia-sip-ua/http/http_status.c | 130 - .../libsofia-sip-ua/http/http_tag.c.in | 68 - .../libsofia-sip-ua/http/http_tag_class.c | 225 - .../libsofia-sip-ua/http/sofia-sip/http.h | 496 - .../http/sofia-sip/http_hclasses.h | 70 - .../http/sofia-sip/http_header.h | 271 - .../http/sofia-sip/http_parser.h | 110 - .../http/sofia-sip/http_protos.h.in | 311 - .../http/sofia-sip/http_status.h | 129 - .../http/sofia-sip/http_tag.h.in | 236 - .../http/sofia-sip/http_tag_class.h | 72 - .../libsofia-sip-ua/http/test_http.c | 1524 -- libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog | 14 - .../sofia-sip/libsofia-sip-ua/ipt/Doxyfile.in | 15 - .../sofia-sip/libsofia-sip-ua/ipt/Makefile.am | 55 - libs/sofia-sip/libsofia-sip-ua/ipt/base64.c | 251 - libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs | 20 - libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c | 264 - .../libsofia-sip-ua/ipt/sofia-sip/base64.h | 65 - .../libsofia-sip-ua/ipt/sofia-sip/rc4.h | 69 - .../libsofia-sip-ua/ipt/sofia-sip/token64.h | 52 - .../libsofia-sip-ua/ipt/sofia-sip/uniqueid.h | 51 - .../libsofia-sip-ua/ipt/sofia-sip/utf8.h | 178 - libs/sofia-sip/libsofia-sip-ua/ipt/token64.c | 103 - .../libsofia-sip-ua/ipt/torture_base64.c | 190 - libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c | 192 - libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c | 216 - libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c | 91 - .../libsofia-sip-ua/ipt/utf8internal.h | 85 - libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c | 188 - .../libsofia-sip-ua/iptsec/ChangeLog | 24 - .../libsofia-sip-ua/iptsec/Doxyfile.in | 26 - .../libsofia-sip-ua/iptsec/Makefile.am | 87 - .../libsofia-sip-ua/iptsec/auth_client.c | 1136 -- .../libsofia-sip-ua/iptsec/auth_client_ntlm.c | 239 - .../libsofia-sip-ua/iptsec/auth_common.c | 204 - .../libsofia-sip-ua/iptsec/auth_digest.c | 351 - .../libsofia-sip-ua/iptsec/auth_module.c | 1553 -- .../libsofia-sip-ua/iptsec/auth_module_http.c | 82 - .../libsofia-sip-ua/iptsec/auth_module_sip.c | 93 - .../libsofia-sip-ua/iptsec/auth_ntlm.c | 323 - .../libsofia-sip-ua/iptsec/auth_plugin.c | 158 - .../iptsec/auth_plugin_delayed.c | 233 - .../libsofia-sip-ua/iptsec/auth_plugin_ntlm.c | 391 - .../libsofia-sip-ua/iptsec/auth_tag.c | 263 - .../libsofia-sip-ua/iptsec/iptsec.docs | 71 - .../libsofia-sip-ua/iptsec/iptsec_debug.c | 70 - .../libsofia-sip-ua/iptsec/iptsec_debug.h | 51 - .../iptsec/sofia-sip/auth_client.h | 108 - .../iptsec/sofia-sip/auth_client_plugin.h | 108 - .../iptsec/sofia-sip/auth_common.h | 55 - .../iptsec/sofia-sip/auth_digest.h | 167 - .../iptsec/sofia-sip/auth_module.h | 404 - .../iptsec/sofia-sip/auth_ntlm.h | 117 - .../iptsec/sofia-sip/auth_plugin.h | 268 - .../libsofia-sip-ua/iptsec/test_auth_digest.c | 1410 -- .../libsofia-sip-ua/iptsec/testpasswd | 3 - libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog | 53 - .../sofia-sip/libsofia-sip-ua/msg/Doxyfile.in | 20 - .../sofia-sip/libsofia-sip-ua/msg/Makefile.am | 126 - libs/sofia-sip/libsofia-sip-ua/msg/msg.c | 409 - libs/sofia-sip/libsofia-sip-ua/msg/msg.docs | 506 - libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c | 157 - .../sofia-sip/libsofia-sip-ua/msg/msg_basic.c | 367 - libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c | 415 - .../libsofia-sip-ua/msg/msg_generic.c | 248 - .../libsofia-sip-ua/msg/msg_header_copy.c | 534 - .../libsofia-sip-ua/msg/msg_header_make.c | 180 - .../libsofia-sip-ua/msg/msg_inlined.c | 47 - .../libsofia-sip-ua/msg/msg_internal.h | 276 - .../libsofia-sip-ua/msg/msg_mclass.c | 370 - libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c | 2168 --- .../libsofia-sip-ua/msg/msg_mime_table.c.in | 70 - .../libsofia-sip-ua/msg/msg_name_hash.c | 58 - .../libsofia-sip-ua/msg/msg_parser.awk | 660 - .../libsofia-sip-ua/msg/msg_parser.c | 3100 ---- .../libsofia-sip-ua/msg/msg_parser_util.c | 2005 --- libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c | 375 - .../libsofia-sip-ua/msg/sofia-sip/msg.h | 173 - .../libsofia-sip-ua/msg/sofia-sip/msg_addr.h | 97 - .../msg/sofia-sip/msg_buffer.h | 57 - .../libsofia-sip-ua/msg/sofia-sip/msg_date.h | 76 - .../msg/sofia-sip/msg_header.h | 315 - .../msg/sofia-sip/msg_mclass.h | 148 - .../msg/sofia-sip/msg_mclass_hash.h | 77 - .../libsofia-sip-ua/msg/sofia-sip/msg_mime.h | 246 - .../msg/sofia-sip/msg_mime_protos.h.in | 323 - .../msg/sofia-sip/msg_parser.h | 341 - .../msg/sofia-sip/msg_protos.h.in | 311 - .../msg/sofia-sip/msg_tag_class.h | 65 - .../libsofia-sip-ua/msg/sofia-sip/msg_types.h | 302 - .../libsofia-sip-ua/msg/test_class.c | 422 - .../libsofia-sip-ua/msg/test_class.h | 179 - .../libsofia-sip-ua/msg/test_inlined.c | 46 - libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c | 1809 --- .../libsofia-sip-ua/msg/test_protos.h.in | 359 - .../libsofia-sip-ua/msg/test_table.c.in | 57 - libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog | 3 - .../sofia-sip/libsofia-sip-ua/nea/Doxyfile.in | 22 - .../sofia-sip/libsofia-sip-ua/nea/Makefile.am | 63 - libs/sofia-sip/libsofia-sip-ua/nea/nea.c | 599 - libs/sofia-sip/libsofia-sip-ua/nea/nea.docs | 123 - .../sofia-sip/libsofia-sip-ua/nea/nea_debug.c | 83 - .../sofia-sip/libsofia-sip-ua/nea/nea_debug.h | 39 - .../sofia-sip/libsofia-sip-ua/nea/nea_event.c | 63 - .../libsofia-sip-ua/nea/nea_server.c | 2391 --- libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c | 64 - .../libsofia-sip-ua/nea/sofia-sip/nea.h | 378 - .../libsofia-sip-ua/nea/sofia-sip/nea_tag.h | 174 - libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog | 102 - .../sofia-sip/libsofia-sip-ua/nta/Doxyfile.in | 26 - .../sofia-sip/libsofia-sip-ua/nta/Makefile.am | 95 - libs/sofia-sip/libsofia-sip-ua/nta/agent.pem | 35 - libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem | 19 - .../sofia-sip/libsofia-sip-ua/nta/check_nta.c | 483 - .../sofia-sip/libsofia-sip-ua/nta/check_nta.h | 133 - .../libsofia-sip-ua/nta/check_nta_api.c | 268 - .../libsofia-sip-ua/nta/check_nta_client.c | 513 - libs/sofia-sip/libsofia-sip-ua/nta/exit77.c | 4 - libs/sofia-sip/libsofia-sip-ua/nta/invite.msc | 159 - libs/sofia-sip/libsofia-sip-ua/nta/nta.c | 12020 ---------------- libs/sofia-sip/libsofia-sip-ua/nta/nta.docs | 573 - .../sofia-sip/libsofia-sip-ua/nta/nta_check.c | 388 - .../libsofia-sip-ua/nta/nta_compat.c | 951 -- .../libsofia-sip-ua/nta/nta_compat.h | 214 - .../libsofia-sip-ua/nta/nta_internal.h | 107 - libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c | 1937 --- libs/sofia-sip/libsofia-sip-ua/nta/portbind.c | 243 - .../libsofia-sip-ua/nta/run_check_nta | 2 - .../libsofia-sip-ua/nta/run_test_nta | 222 - .../libsofia-sip-ua/nta/run_test_nta_api | 39 - .../libsofia-sip-ua/nta/sl_read_payload.c | 126 - .../libsofia-sip-ua/nta/sl_utils.docs | 9 - .../libsofia-sip-ua/nta/sl_utils_log.c | 287 - .../libsofia-sip-ua/nta/sl_utils_print.c | 298 - .../libsofia-sip-ua/nta/sofia-sip/nta.h | 505 - .../nta/sofia-sip/nta_stateless.h | 103 - .../libsofia-sip-ua/nta/sofia-sip/nta_tag.h | 605 - .../libsofia-sip-ua/nta/sofia-sip/nta_tport.h | 99 - .../libsofia-sip-ua/nta/sofia-sip/sl_utils.h | 84 - libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c | 4003 ----- .../libsofia-sip-ua/nta/test_nta_api.c | 1521 -- libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog | 7 - .../sofia-sip/libsofia-sip-ua/nth/Doxyfile.in | 19 - .../sofia-sip/libsofia-sip-ua/nth/Makefile.am | 66 - libs/sofia-sip/libsofia-sip-ua/nth/agent.pem | 35 - libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem | 19 - .../libsofia-sip-ua/nth/http-client.c | 407 - .../libsofia-sip-ua/nth/http-server.c | 293 - libs/sofia-sip/libsofia-sip-ua/nth/nth.docs | 21 - .../libsofia-sip-ua/nth/nth_client.c | 1284 -- .../libsofia-sip-ua/nth/nth_server.c | 1294 -- libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c | 82 - .../libsofia-sip-ua/nth/sofia-sip/nth.h | 202 - .../libsofia-sip-ua/nth/sofia-sip/nth_tag.h | 190 - libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c | 963 -- libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog | 480 - .../sofia-sip/libsofia-sip-ua/nua/Doxyfile.in | 39 - .../sofia-sip/libsofia-sip-ua/nua/Makefile.am | 86 - .../libsofia-sip-ua/nua/check_etsi.c | 362 - .../sofia-sip/libsofia-sip-ua/nua/check_nua.c | 521 - .../sofia-sip/libsofia-sip-ua/nua/check_nua.h | 113 - .../libsofia-sip-ua/nua/check_register.c | 1047 -- .../libsofia-sip-ua/nua/check_session.c | 3670 ----- .../libsofia-sip-ua/nua/check_simple.c | 873 -- libs/sofia-sip/libsofia-sip-ua/nua/nua.c | 1152 -- libs/sofia-sip/libsofia-sip-ua/nua/nua.docs | 2285 --- .../libsofia-sip-ua/nua/nua_client.c | 1655 --- .../libsofia-sip-ua/nua/nua_client.h | 344 - .../libsofia-sip-ua/nua/nua_common.c | 437 - .../libsofia-sip-ua/nua/nua_dialog.c | 674 - .../libsofia-sip-ua/nua/nua_dialog.h | 243 - .../libsofia-sip-ua/nua/nua_event_server.c | 354 - .../libsofia-sip-ua/nua/nua_extension.c | 166 - .../libsofia-sip-ua/nua/nua_message.c | 194 - .../libsofia-sip-ua/nua/nua_notifier.c | 1046 -- .../libsofia-sip-ua/nua/nua_options.c | 114 - .../libsofia-sip-ua/nua/nua_params.c | 1783 --- .../libsofia-sip-ua/nua/nua_params.h | 291 - .../libsofia-sip-ua/nua/nua_publish.c | 538 - .../libsofia-sip-ua/nua/nua_register.c | 2167 --- .../libsofia-sip-ua/nua/nua_registrar.c | 265 - .../libsofia-sip-ua/nua/nua_server.c | 764 - .../libsofia-sip-ua/nua/nua_server.h | 201 - .../libsofia-sip-ua/nua/nua_session.c | 4791 ------ .../sofia-sip/libsofia-sip-ua/nua/nua_stack.c | 1126 -- .../sofia-sip/libsofia-sip-ua/nua/nua_stack.h | 452 - .../libsofia-sip-ua/nua/nua_subnotref.c | 929 -- libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c | 3006 ---- .../sofia-sip/libsofia-sip-ua/nua/nua_types.h | 55 - libs/sofia-sip/libsofia-sip-ua/nua/outbound.c | 1291 -- libs/sofia-sip/libsofia-sip-ua/nua/outbound.h | 144 - .../libsofia-sip-ua/nua/sofia-sip/nua.h | 405 - .../libsofia-sip-ua/nua/sofia-sip/nua_tag.h | 684 - libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog | 55 - .../sofia-sip/libsofia-sip-ua/sdp/Doxyfile.in | 12 - .../sofia-sip/libsofia-sip-ua/sdp/Makefile.am | 63 - libs/sofia-sip/libsofia-sip-ua/sdp/README | 11 - libs/sofia-sip/libsofia-sip-ua/sdp/errata | 14 - .../sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt | 2355 --- .../libsofia-sip-ua/sdp/run_test_sdp | 23 - libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf | 249 - libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c | 1930 --- libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs | 120 - .../sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c | 1931 --- .../sofia-sip/libsofia-sip-ua/sdp/sdp_print.c | 748 - libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c | 47 - .../libsofia-sip-ua/sdp/sofia-sip/sdp.h | 570 - .../libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h | 89 - libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c | 136 - .../libsofia-sip-ua/sdp/tests/message-1.sdp | 1 - .../libsofia-sip-ua/sdp/tests/message-10.sdp | 32 - .../libsofia-sip-ua/sdp/tests/message-11.sdp | 34 - .../libsofia-sip-ua/sdp/tests/message-2.sdp | 13 - .../libsofia-sip-ua/sdp/tests/message-3.sdp | 8 - .../libsofia-sip-ua/sdp/tests/message-4.sdp | 4 - .../libsofia-sip-ua/sdp/tests/message-5.sdp | 5 - .../libsofia-sip-ua/sdp/tests/message-6.sdp | 6 - .../libsofia-sip-ua/sdp/tests/message-7.sdp | 10 - .../libsofia-sip-ua/sdp/tests/message-8.sdp | 10 - .../libsofia-sip-ua/sdp/tests/message-9.sdp | 25 - .../libsofia-sip-ua/sdp/torture_sdp.c | 1022 -- .../libsofia-sip-ua/sip/ADD-A-HEADER | 152 - libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog | 58 - .../sofia-sip/libsofia-sip-ua/sip/Doxyfile.in | 31 - libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR | 537 - .../sofia-sip/libsofia-sip-ua/sip/Makefile.am | 152 - .../libsofia-sip-ua/sip/images/sip-parser.eps | Bin 165734 -> 0 bytes .../libsofia-sip-ua/sip/images/sip-parser.gif | Bin 9727 -> 0 bytes .../sip/images/sip-parser2.eps | Bin 223408 -> 0 bytes .../sip/images/sip-parser2.gif | Bin 16927 -> 0 bytes .../sip/images/sip-parser3.eps | Bin 235727 -> 0 bytes .../sip/images/sip-parser3.gif | Bin 14550 -> 0 bytes .../sip/images/sip-parser4.eps | Bin 154295 -> 0 bytes .../sip/images/sip-parser4.gif | Bin 4272 -> 0 bytes .../sofia-sip/libsofia-sip-ua/sip/rfc2543.txt | 8564 ----------- libs/sofia-sip/libsofia-sip-ua/sip/run-tests | 47 - .../libsofia-sip-ua/sip/run_test_date | 2 - .../libsofia-sip-ua/sip/run_test_sip_msg | 88 - libs/sofia-sip/libsofia-sip-ua/sip/sip.docs | 608 - .../libsofia-sip-ua/sip/sip.doxyaliases | 74 - .../libsofia-sip-ua/sip/sip_bad_mask | 102 - .../sofia-sip/libsofia-sip-ua/sip/sip_basic.c | 2914 ---- .../libsofia-sip-ua/sip/sip_caller_prefs.c | 429 - .../sofia-sip/libsofia-sip-ua/sip/sip_event.c | 551 - .../sofia-sip/libsofia-sip-ua/sip/sip_extra.c | 1419 -- .../libsofia-sip-ua/sip/sip_extra_headers.txt | 34 - .../libsofia-sip-ua/sip/sip_feature.c | 598 - .../libsofia-sip-ua/sip/sip_header.c | 136 - .../libsofia-sip-ua/sip/sip_inlined.c | 50 - libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c | 686 - .../libsofia-sip-ua/sip/sip_parser.c | 691 - .../libsofia-sip-ua/sip/sip_parser.docs | 91 - .../libsofia-sip-ua/sip/sip_parser_table.c.in | 56 - .../sofia-sip/libsofia-sip-ua/sip/sip_prack.c | 204 - .../libsofia-sip-ua/sip/sip_pref_util.c | 607 - .../libsofia-sip-ua/sip/sip_reason.c | 180 - .../sofia-sip/libsofia-sip-ua/sip/sip_refer.c | 558 - .../libsofia-sip-ua/sip/sip_security.c | 846 -- .../libsofia-sip-ua/sip/sip_session.c | 252 - .../libsofia-sip-ua/sip/sip_status.c | 200 - .../libsofia-sip-ua/sip/sip_tag.c.in | 94 - .../libsofia-sip-ua/sip/sip_tag_class.c | 508 - libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c | 107 - libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c | 1442 -- .../libsofia-sip-ua/sip/sofia-sip/sip.h | 943 -- .../sip/sofia-sip/sip_extra.h.in | 176 - .../sip/sofia-sip/sip_hclasses.h.in | 78 - .../sip/sofia-sip/sip_header.h | 524 - .../sip/sofia-sip/sip_parser.h | 222 - .../sip/sofia-sip/sip_protos.h.in | 367 - .../sip/sofia-sip/sip_status.h | 248 - .../sip/sofia-sip/sip_tag.h.in | 256 - .../sip/sofia-sip/sip_tag_class.h | 91 - .../libsofia-sip-ua/sip/sofia-sip/sip_util.h | 212 - .../sofia-sip/libsofia-sip-ua/sip/test_date.c | 118 - .../libsofia-sip-ua/sip/test_sip_msg.c | 293 - .../libsofia-sip-ua/sip/tests/10052.txt | 20 - .../libsofia-sip-ua/sip/tests/own0.txt | 45 - .../libsofia-sip-ua/sip/tests/own1.txt | 18 - .../libsofia-sip-ua/sip/tests/own2.txt | 12 - .../libsofia-sip-ua/sip/tests/own3.txt | 19 - .../libsofia-sip-ua/sip/tests/own4.txt | 19 - .../libsofia-sip-ua/sip/tests/own5.txt | 27 - .../libsofia-sip-ua/sip/tests/own6.txt | 16 - .../libsofia-sip-ua/sip/tests/own8.txt | 2 - .../libsofia-sip-ua/sip/tests/test-ack-1.txt | 8 - .../libsofia-sip-ua/sip/tests/test1.txt | 22 - .../libsofia-sip-ua/sip/tests/test10.txt | 27 - .../libsofia-sip-ua/sip/tests/test10b.txt | 8 - .../libsofia-sip-ua/sip/tests/test10c.txt | 9 - .../libsofia-sip-ua/sip/tests/test11.txt | 11 - .../libsofia-sip-ua/sip/tests/test12.txt | 18 - .../libsofia-sip-ua/sip/tests/test13.txt | 15 - .../libsofia-sip-ua/sip/tests/test14-req.txt | 15 - .../libsofia-sip-ua/sip/tests/test14.txt | 16 - .../libsofia-sip-ua/sip/tests/test15.txt | 15 - .../libsofia-sip-ua/sip/tests/test16.txt | 15 - .../libsofia-sip-ua/sip/tests/test17.txt | 15 - .../libsofia-sip-ua/sip/tests/test18.txt | 19 - .../libsofia-sip-ua/sip/tests/test19.txt | 15 - .../libsofia-sip-ua/sip/tests/test1a.txt | 21 - .../libsofia-sip-ua/sip/tests/test2.txt | 10 - .../libsofia-sip-ua/sip/tests/test20.txt | 9 - .../libsofia-sip-ua/sip/tests/test21.txt | 17 - .../libsofia-sip-ua/sip/tests/test22.txt | 17 - .../libsofia-sip-ua/sip/tests/test23.txt | 17 - .../libsofia-sip-ua/sip/tests/test24.txt | 17 - .../libsofia-sip-ua/sip/tests/test25.txt | 17 - .../libsofia-sip-ua/sip/tests/test26.txt | 17 - .../libsofia-sip-ua/sip/tests/test27.txt | 6 - .../libsofia-sip-ua/sip/tests/test28.txt | 6 - .../libsofia-sip-ua/sip/tests/test29.txt | 18 - .../libsofia-sip-ua/sip/tests/test3.txt | 16 - .../libsofia-sip-ua/sip/tests/test30.txt | 18 - .../libsofia-sip-ua/sip/tests/test31.txt | 18 - .../libsofia-sip-ua/sip/tests/test32.txt | 8 - .../libsofia-sip-ua/sip/tests/test33.txt | 8 - .../libsofia-sip-ua/sip/tests/test34.txt | 50 - .../libsofia-sip-ua/sip/tests/test35.txt | 14 - .../libsofia-sip-ua/sip/tests/test36.txt | 23 - .../libsofia-sip-ua/sip/tests/test37.txt | 7 - .../libsofia-sip-ua/sip/tests/test38.txt | 7 - .../libsofia-sip-ua/sip/tests/test39.txt | 6 - .../libsofia-sip-ua/sip/tests/test4.txt | 9 - .../libsofia-sip-ua/sip/tests/test40.txt | 6 - .../libsofia-sip-ua/sip/tests/test41.txt | 7 - .../libsofia-sip-ua/sip/tests/test42.txt | 6 - .../libsofia-sip-ua/sip/tests/test5.txt | 16 - .../libsofia-sip-ua/sip/tests/test6.txt | 12 - .../libsofia-sip-ua/sip/tests/test7.txt | 15 - .../libsofia-sip-ua/sip/tests/test8.txt | 15 - .../libsofia-sip-ua/sip/tests/test9.txt | 7 - .../libsofia-sip-ua/sip/torture_sip.c | 3671 ----- .../sofia-sip/libsofia-sip-ua/sip/validator.c | 646 - libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog | 325 - .../sofia-sip/libsofia-sip-ua/soa/Doxyfile.in | 30 - .../sofia-sip/libsofia-sip-ua/soa/Makefile.am | 65 - libs/sofia-sip/libsofia-sip-ua/soa/soa.c | 2740 ---- libs/sofia-sip/libsofia-sip-ua/soa/soa.docs | 887 -- .../libsofia-sip-ua/soa/soa_asynch.c | 289 - .../libsofia-sip-ua/soa/soa_static.c | 1599 -- libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c | 649 - .../libsofia-sip-ua/soa/sofia-sip/soa.h | 153 - .../libsofia-sip-ua/soa/sofia-sip/soa_add.h | 48 - .../soa/sofia-sip/soa_session.h | 292 - .../libsofia-sip-ua/soa/sofia-sip/soa_tag.h | 263 - libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c | 2729 ---- libs/sofia-sip/libsofia-sip-ua/sofia.am | 58 - .../libsofia-sip-ua/sresolv/127.zone | 13 - .../libsofia-sip-ua/sresolv/194.2.188 | 14 - .../sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 | 13 - .../3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa | 13 - .../libsofia-sip-ua/sresolv/ChangeLog | 10 - .../libsofia-sip-ua/sresolv/Doxyfile.in | 16 - .../libsofia-sip-ua/sresolv/Makefile.am | 72 - .../libsofia-sip-ua/sresolv/check_sres_sip.c | 1164 -- .../libsofia-sip-ua/sresolv/example.com | 93 - .../libsofia-sip-ua/sresolv/named.conf | 33 - .../sresolv/resolv_timeout.conf | 5 - .../libsofia-sip-ua/sresolv/resolve_sip.c | 322 - .../libsofia-sip-ua/sresolv/rfc1034.txt | 3077 ---- .../libsofia-sip-ua/sresolv/rfc1035.txt | 3077 ---- .../libsofia-sip-ua/sresolv/rfc2671.txt | 395 - .../libsofia-sip-ua/sresolv/rndc.conf | 34 - .../libsofia-sip-ua/sresolv/root.zone | 12 - .../libsofia-sip-ua/sresolv/run_test_sresolv | 191 - .../sresolv/sofia-resolv/sres.h | 277 - .../sresolv/sofia-resolv/sres_async.h | 123 - .../sresolv/sofia-resolv/sres_cache.h | 124 - .../sresolv/sofia-resolv/sres_config.h | 77 - .../sresolv/sofia-resolv/sres_record.h | 266 - .../sresolv/sofia-sip/sres_sip.h | 121 - .../sresolv/sofia-sip/sresolv.h | 79 - libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c | 4389 ------ .../libsofia-sip-ua/sresolv/sres_blocking.c | 446 - .../libsofia-sip-ua/sresolv/sres_cache.c | 695 - .../libsofia-sip-ua/sresolv/sres_sip.c | 1694 --- .../libsofia-sip-ua/sresolv/sresolv.c | 362 - .../libsofia-sip-ua/sresolv/sresolv.docs | 270 - .../libsofia-sip-ua/sresolv/test_sresolv.c | 2066 --- .../libsofia-sip-ua/sresolv/torture_sresolv.c | 455 - libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog | 244 - .../libsofia-sip-ua/stun/Doxyfile.in | 11 - .../libsofia-sip-ua/stun/Makefile.am | 57 - libs/sofia-sip/libsofia-sip-ua/stun/cert.pem | 14 - libs/sofia-sip/libsofia-sip-ua/stun/key.pem | 9 - .../libsofia-sip-ua/stun/lookup_stun_server.c | 106 - .../libsofia-sip-ua/stun/rfc3489.txt | 2635 ---- .../libsofia-sip-ua/stun/sofia-sip/stun.h | 308 - .../stun/sofia-sip/stun_common.h | 238 - .../libsofia-sip-ua/stun/sofia-sip/stun_tag.h | 105 - libs/sofia-sip/libsofia-sip-ua/stun/stun.c | 3132 ---- libs/sofia-sip/libsofia-sip-ua/stun/stun.docs | 29 - .../libsofia-sip-ua/stun/stun_common.c | 828 -- .../sofia-sip/libsofia-sip-ua/stun/stun_dns.c | 251 - .../libsofia-sip-ua/stun/stun_internal.h | 114 - .../libsofia-sip-ua/stun/stun_mini.c | 391 - .../sofia-sip/libsofia-sip-ua/stun/stun_tag.c | 213 - libs/sofia-sip/libsofia-sip-ua/stun/stunc.c | 493 - libs/sofia-sip/libsofia-sip-ua/su/ChangeLog | 102 - libs/sofia-sip/libsofia-sip-ua/su/Doxyfile.in | 26 - libs/sofia-sip/libsofia-sip-ua/su/Makefile.am | 127 - libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c | 164 - libs/sofia-sip/libsofia-sip-ua/su/foo.c | 265 - libs/sofia-sip/libsofia-sip-ua/su/getopt.c | 177 - libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c | 199 - libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c | 231 - libs/sofia-sip/libsofia-sip-ua/su/localinfo.c | 200 - libs/sofia-sip/libsofia-sip-ua/su/memccpy.c | 67 - libs/sofia-sip/libsofia-sip-ua/su/memcspn.c | 44 - libs/sofia-sip/libsofia-sip-ua/su/memmem.c | 58 - libs/sofia-sip/libsofia-sip-ua/su/memspn.c | 46 - libs/sofia-sip/libsofia-sip-ua/su/poll.c | 261 - .../sofia-sip/libsofia-sip-ua/su/run_addrinfo | 3 - .../libsofia-sip-ua/su/run_localinfo | 3 - libs/sofia-sip/libsofia-sip-ua/su/run_test_su | 34 - .../libsofia-sip-ua/su/run_test_su_osx | 24 - .../sofia-sip/libsofia-sip-ua/su/smoothsort.c | 272 - .../libsofia-sip-ua/su/sofia-sip/heap.h | 341 - .../libsofia-sip-ua/su/sofia-sip/htable.h | 264 - .../libsofia-sip-ua/su/sofia-sip/htable2.h | 303 - .../libsofia-sip-ua/su/sofia-sip/rbtree.h | 673 - .../libsofia-sip-ua/su/sofia-sip/string0.h | 47 - .../libsofia-sip-ua/su/sofia-sip/su.h | 486 - .../su/sofia-sip/su_addrinfo.h | 157 - .../libsofia-sip-ua/su/sofia-sip/su_alloc.h | 188 - .../su/sofia-sip/su_alloc_stat.h | 93 - .../libsofia-sip-ua/su/sofia-sip/su_bm.h | 60 - .../libsofia-sip-ua/su/sofia-sip/su_config.h | 135 - .../su/sofia-sip/su_configure.h.in | 140 - .../libsofia-sip-ua/su/sofia-sip/su_debug.h | 224 - .../libsofia-sip-ua/su/sofia-sip/su_errno.h | 278 - .../su/sofia-sip/su_localinfo.h | 113 - .../libsofia-sip-ua/su/sofia-sip/su_log.h | 114 - .../libsofia-sip-ua/su/sofia-sip/su_md5.h | 88 - .../libsofia-sip-ua/su/sofia-sip/su_os_nw.h | 122 - .../su/sofia-sip/su_osx_runloop.h | 53 - .../libsofia-sip-ua/su/sofia-sip/su_string.h | 86 - .../libsofia-sip-ua/su/sofia-sip/su_strlst.h | 129 - .../libsofia-sip-ua/su/sofia-sip/su_tag.h | 237 - .../su/sofia-sip/su_tag_class.h | 138 - .../su/sofia-sip/su_tag_inline.h | 150 - .../libsofia-sip-ua/su/sofia-sip/su_tag_io.h | 65 - .../libsofia-sip-ua/su/sofia-sip/su_tagarg.h | 202 - .../libsofia-sip-ua/su/sofia-sip/su_time.h | 152 - .../libsofia-sip-ua/su/sofia-sip/su_types.h | 166 - .../su/sofia-sip/su_uniqueid.h | 124 - .../libsofia-sip-ua/su/sofia-sip/su_vector.h | 89 - .../libsofia-sip-ua/su/sofia-sip/su_wait.h | 616 - .../libsofia-sip-ua/su/sofia-sip/tstdef.h | 352 - .../sofia-sip/libsofia-sip-ua/su/strcasestr.c | 73 - libs/sofia-sip/libsofia-sip-ua/su/string0.c | 42 - libs/sofia-sip/libsofia-sip-ua/su/strtoull.c | 291 - libs/sofia-sip/libsofia-sip-ua/su/su.c | 649 - libs/sofia-sip/libsofia-sip-ua/su/su.docs | 111 - .../libsofia-sip-ua/su/su_addrinfo.c | 998 -- libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c | 1913 --- .../libsofia-sip-ua/su/su_alloc_lock.c | 134 - .../libsofia-sip-ua/su/su_base_port.c | 639 - libs/sofia-sip/libsofia-sip-ua/su/su_bm.c | 273 - .../libsofia-sip-ua/su/su_default_log.c | 92 - .../libsofia-sip-ua/su/su_devpoll_port.c | 635 - .../libsofia-sip-ua/su/su_epoll_port.c | 588 - libs/sofia-sip/libsofia-sip-ua/su/su_errno.c | 163 - .../libsofia-sip-ua/su/su_global_log.c | 74 - .../libsofia-sip-ua/su/su_kqueue_port.c | 652 - .../libsofia-sip-ua/su/su_localinfo.c | 1699 --- libs/sofia-sip/libsofia-sip-ua/su/su_log.c | 267 - libs/sofia-sip/libsofia-sip-ua/su/su_md5.c | 491 - .../libsofia-sip-ua/su/su_module_debug.h | 53 - .../su/su_open_c_localinfo.cpp | 148 - libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c | 287 - .../libsofia-sip-ua/su/su_osx_runloop.c | 1279 -- libs/sofia-sip/libsofia-sip-ua/su/su_perf.c | 188 - .../libsofia-sip-ua/su/su_poll_port.c | 697 - libs/sofia-sip/libsofia-sip-ua/su/su_port.c | 470 - libs/sofia-sip/libsofia-sip-ua/su/su_port.h | 637 - libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c | 672 - .../libsofia-sip-ua/su/su_pthread_port.c | 622 - libs/sofia-sip/libsofia-sip-ua/su/su_root.c | 1334 -- .../libsofia-sip-ua/su/su_select_port.c | 661 - .../libsofia-sip-ua/su/su_socket_port.c | 198 - .../sofia-sip/libsofia-sip-ua/su/su_sprintf.c | 129 - libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c | 169 - libs/sofia-sip/libsofia-sip-ua/su/su_string.c | 518 - libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c | 713 - libs/sofia-sip/libsofia-sip-ua/su/su_tag.c | 47 - libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c | 69 - .../sofia-sip/libsofia-sip-ua/su/su_taglist.c | 1626 --- libs/sofia-sip/libsofia-sip-ua/su/su_time.c | 484 - libs/sofia-sip/libsofia-sip-ua/su/su_time0.c | 243 - libs/sofia-sip/libsofia-sip-ua/su/su_timer.c | 691 - .../libsofia-sip-ua/su/su_uniqueid.c | 427 - libs/sofia-sip/libsofia-sip-ua/su/su_vector.c | 327 - libs/sofia-sip/libsofia-sip-ua/su/su_wait.c | 346 - .../libsofia-sip-ua/su/su_win32_port.c | 645 - libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk | 183 - .../libsofia-sip-ua/su/test_htable.c | 256 - .../libsofia-sip-ua/su/test_htable2.c | 267 - .../libsofia-sip-ua/su/test_memmem.c | 356 - libs/sofia-sip/libsofia-sip-ua/su/test_poll.c | 108 - libs/sofia-sip/libsofia-sip-ua/su/test_su.c | 583 - .../libsofia-sip-ua/su/test_su_osx.c | 581 - .../libsofia-sip-ua/su/torture_heap.c | 543 - .../libsofia-sip-ua/su/torture_rbtree.c | 713 - .../sofia-sip/libsofia-sip-ua/su/torture_su.c | 524 - .../libsofia-sip-ua/su/torture_su_alloc.c | 784 - .../libsofia-sip-ua/su/torture_su_bm.c | 246 - .../libsofia-sip-ua/su/torture_su_port.c | 349 - .../libsofia-sip-ua/su/torture_su_root.c | 908 -- .../libsofia-sip-ua/su/torture_su_root_osx.c | 366 - .../libsofia-sip-ua/su/torture_su_tag.c | 668 - .../libsofia-sip-ua/su/torture_su_time.c | 262 - .../libsofia-sip-ua/su/torture_su_timer.c | 281 - .../sofia-sip/libsofia-sip-ua/tport/ChangeLog | 45 - .../libsofia-sip-ua/tport/Doxyfile.in | 20 - .../libsofia-sip-ua/tport/Makefile.am | 92 - .../sofia-sip/libsofia-sip-ua/tport/agent.pem | 34 - .../libsofia-sip-ua/tport/cafile.pem | 19 - .../libsofia-sip-ua/tport/certificates-update | 100 - .../libsofia-sip-ua/tport/certificates.html | 61 - .../libsofia-sip-ua/tport/include/switch.h | 16 - .../libsofia-sip-ua/tport/make_node_cert.pl | 59 - .../libsofia-sip-ua/tport/make_root_cert.pl | 56 - .../libsofia-sip-ua/tport/make_test_certs.sh | 26 - .../libsofia-sip-ua/tport/sofia-sip/tport.h | 431 - .../tport/sofia-sip/tport_plugins.h | 171 - .../tport/sofia-sip/tport_tag.h | 344 - .../libsofia-sip-ua/tport/test_tport.c | 1706 --- .../libsofia-sip-ua/tport/tls_test_client.c | 167 - .../libsofia-sip-ua/tport/tls_test_server.c | 264 - libs/sofia-sip/libsofia-sip-ua/tport/tport.c | 4951 ------- .../libsofia-sip-ua/tport/tport.docs | 196 - .../libsofia-sip-ua/tport/tport_internal.h | 615 - .../libsofia-sip-ua/tport/tport_logging.c | 906 -- .../libsofia-sip-ua/tport/tport_rand.c | 46 - .../libsofia-sip-ua/tport/tport_sigcomp.c | 888 -- .../tport/tport_stub_sigcomp.c | 294 - .../libsofia-sip-ua/tport/tport_stub_stun.c | 295 - .../libsofia-sip-ua/tport/tport_tag.c | 617 - .../libsofia-sip-ua/tport/tport_threadpool.c | 818 -- .../libsofia-sip-ua/tport/tport_tls.c | 1064 -- .../libsofia-sip-ua/tport/tport_tls.h | 101 - .../libsofia-sip-ua/tport/tport_tls_test.sh | 6 - .../tport/tport_type_connect.c | 245 - .../libsofia-sip-ua/tport/tport_type_sctp.c | 334 - .../libsofia-sip-ua/tport/tport_type_stun.c | 240 - .../libsofia-sip-ua/tport/tport_type_tcp.c | 562 - .../libsofia-sip-ua/tport/tport_type_tls.c | 702 - .../libsofia-sip-ua/tport/tport_type_udp.c | 537 - .../libsofia-sip-ua/tport/tport_type_ws.c | 660 - .../libsofia-sip-ua/tport/tport_ws.h | 99 - libs/sofia-sip/libsofia-sip-ua/tport/ws.c | 1065 -- libs/sofia-sip/libsofia-sip-ua/tport/ws.h | 145 - libs/sofia-sip/libsofia-sip-ua/url/ChangeLog | 3 - .../sofia-sip/libsofia-sip-ua/url/Doxyfile.in | 14 - .../sofia-sip/libsofia-sip-ua/url/Makefile.am | 62 - .../libsofia-sip-ua/url/sofia-sip/url.h | 319 - .../libsofia-sip-ua/url/sofia-sip/url_tag.h | 74 - .../url/sofia-sip/url_tag_class.h | 56 - .../libsofia-sip-ua/url/torture_url.c | 1110 -- libs/sofia-sip/libsofia-sip-ua/url/url.c | 2149 --- libs/sofia-sip/libsofia-sip-ua/url/url.docs | 187 - libs/sofia-sip/libsofia-sip-ua/url/url_tag.c | 163 - libs/sofia-sip/libsofia-sip-ua/url/urlmap.c | 1167 -- libs/sofia-sip/libsofia-sip-ua/url/urlmap.h | 65 - libs/sofia-sip/m4/sac-coverage.m4 | 129 - libs/sofia-sip/m4/sac-general.m4 | 401 - libs/sofia-sip/m4/sac-su.m4 | 36 - libs/sofia-sip/m4/sac-su2.m4 | 669 - libs/sofia-sip/m4/sac-tport.m4 | 42 - libs/sofia-sip/open_c/Makefile.am | 46 - libs/sofia-sip/open_c/autogen.cmd | 33 - libs/sofia-sip/open_c/build_sources.cmd | 129 - libs/sofia-sip/open_c/config.h.in | 438 - libs/sofia-sip/open_c/group/bld.inf | 146 - .../open_c/group/libsofia-sip-ua-glib.mmp | 54 - .../open_c/group/libsofia-sip-ua.mmp | 304 - .../sofia-sip/open_c/group/su_source_test.mmp | 72 - .../open_c/group/su_source_test_reg.rss | 19 - libs/sofia-sip/open_c/group/test_http.mmp | 58 - libs/sofia-sip/open_c/group/test_http_reg.rss | 19 - libs/sofia-sip/open_c/group/test_msg.mmp | 63 - libs/sofia-sip/open_c/group/test_msg_reg.rss | 19 - libs/sofia-sip/open_c/group/test_nua.mmp | 88 - libs/sofia-sip/open_c/group/test_nua_reg.rss | 19 - libs/sofia-sip/open_c/group/test_tport.mmp | 63 - .../sofia-sip/open_c/group/test_tport_reg.rss | 19 - libs/sofia-sip/open_c/group/torture_sip.mmp | 58 - .../open_c/group/torture_sip_reg.rss | 19 - .../open_c/group/torture_su_alloc.mmp | 50 - .../open_c/group/torture_su_alloc_reg.rss | 19 - .../open_c/group/torture_su_port.mmp | 48 - .../open_c/group/torture_su_port_reg.rss | 13 - .../open_c/group/torture_su_root.mmp | 51 - .../open_c/group/torture_su_root_reg.rss | 19 - .../sofia-sip/open_c/group/torture_su_tag.mmp | 51 - .../open_c/group/torture_su_tag_reg.rss | 19 - libs/sofia-sip/open_c/group/torture_url.mmp | 57 - .../open_c/group/torture_url_reg.rss | 15 - .../open_c/sis/libsofia-sip-ua-glib.pkg | 34 - libs/sofia-sip/open_c/sis/libsofia-sip-ua.pkg | 34 - libs/sofia-sip/open_c/sis/su_source_test.pkg | 35 - libs/sofia-sip/open_c/sis/test_nua.pkg | 35 - libs/sofia-sip/open_c/sis/test_tport.pkg | 35 - .../sofia-sip/open_c/sofia-sip/su_configure.h | 140 - libs/sofia-sip/open_c/version.awk | 51 - libs/sofia-sip/open_c/version_files.cmd | 46 - libs/sofia-sip/packages/ChangeLog | 26 - libs/sofia-sip/packages/Makefile.am | 21 - .../packages/sofia-sip-ua-glib.pc.in | 14 - libs/sofia-sip/packages/sofia-sip-ua.pc.in | 16 - libs/sofia-sip/packages/sofia-sip.spec.in | 247 - libs/sofia-sip/rules/lcov.am | 65 - libs/sofia-sip/rules/recursive.am | 47 - libs/sofia-sip/rules/silent.am | 53 - libs/sofia-sip/rules/sofia.am | 72 - libs/sofia-sip/rules/valcheck.am | 114 - libs/sofia-sip/s2check/Makefile.am | 42 - libs/sofia-sip/s2check/s2_localinfo.c | 205 - libs/sofia-sip/s2check/s2_localinfo.h | 66 - libs/sofia-sip/s2check/s2base.c | 180 - libs/sofia-sip/s2check/s2base.h | 61 - libs/sofia-sip/s2check/s2check.h | 60 - libs/sofia-sip/s2check/s2dns.c | 667 - libs/sofia-sip/s2check/s2dns.h | 59 - libs/sofia-sip/s2check/s2sip.c | 819 -- libs/sofia-sip/s2check/s2sip.h | 123 - libs/sofia-sip/s2check/s2tcase.c | 123 - libs/sofia-sip/s2check/s2time.c | 74 - libs/sofia-sip/s2check/s2util.h | 46 - libs/sofia-sip/scripts/coverage | 114 - libs/sofia-sip/scripts/fix-include-sofia-sip | 209 - libs/sofia-sip/scripts/hide_emails.sh | 41 - libs/sofia-sip/scripts/lcov-report | 71 - libs/sofia-sip/scripts/rpmbuild-snaphot | 129 - libs/sofia-sip/scripts/uncovered | 122 - libs/sofia-sip/tests/Makefile.am | 59 - libs/sofia-sip/tests/check_dlopen_sofia.c | 124 - libs/sofia-sip/tests/check_sofia.c | 64 - libs/sofia-sip/tests/check_sofia.h | 7 - libs/sofia-sip/tests/suite_for_nua.c | 188 - libs/sofia-sip/tests/test_100rel.c | 2647 ---- libs/sofia-sip/tests/test_basic_call.c | 2012 --- libs/sofia-sip/tests/test_call_hold.c | 1180 -- libs/sofia-sip/tests/test_call_reject.c | 1689 --- libs/sofia-sip/tests/test_cancel_bye.c | 1663 --- libs/sofia-sip/tests/test_extension.c | 180 - libs/sofia-sip/tests/test_init.c | 448 - libs/sofia-sip/tests/test_nat.c | 999 -- libs/sofia-sip/tests/test_nat.h | 74 - libs/sofia-sip/tests/test_nat_tags.c | 40 - libs/sofia-sip/tests/test_nua.c | 397 - libs/sofia-sip/tests/test_nua.h | 365 - libs/sofia-sip/tests/test_nua_api.c | 462 - libs/sofia-sip/tests/test_nua_params.c | 656 - libs/sofia-sip/tests/test_offer_answer.c | 479 - libs/sofia-sip/tests/test_ops.c | 566 - libs/sofia-sip/tests/test_proxy.c | 1604 --- libs/sofia-sip/tests/test_proxy.h | 87 - libs/sofia-sip/tests/test_refer.c | 852 -- libs/sofia-sip/tests/test_register.c | 1043 -- libs/sofia-sip/tests/test_session_timer.c | 434 - libs/sofia-sip/tests/test_simple.c | 2101 --- libs/sofia-sip/tests/test_sip_events.c | 601 - libs/sofia-sip/utils/ChangeLog | 28 - libs/sofia-sip/utils/Doxyfile.in | 6358 -------- libs/sofia-sip/utils/Makefile.am | 30 - libs/sofia-sip/utils/apps_utils.h | 129 - libs/sofia-sip/utils/sip-date.c | 170 - libs/sofia-sip/utils/sip-dig.c | 824 -- libs/sofia-sip/utils/sip-options.c | 405 - libs/sofia-sip/utils/utils.docs | 24 - libs/sofia-sip/win32/ChangeLog | 44 - libs/sofia-sip/win32/Makefile.am | 83 - libs/sofia-sip/win32/README.txt | 59 - libs/sofia-sip/win32/SofiaSIP.dsw | 326 - libs/sofia-sip/win32/SofiaSIP.sln | 197 - libs/sofia-sip/win32/autogen.cmd | 39 - libs/sofia-sip/win32/build_sources.cmd | 129 - libs/sofia-sip/win32/check.cmd | 71 - libs/sofia-sip/win32/config.h.in | 513 - libs/sofia-sip/win32/install.cmd | 62 - .../libsofia_sip_ua_static.dsp | 1417 -- .../libsofia_sip_ua_static.vcproj | 4442 ------ .../win32/libsofia-sip-ua/libsofia_sip_ua.dsp | 1437 -- .../libsofia-sip-ua/libsofia_sip_ua.vcproj | 4479 ------ .../win32/libsofia-sip-ua/sofia-sip-ua.def | 573 - libs/sofia-sip/win32/sofia-sip/su_configure.h | 146 - .../win32/tests/test_htable/test_htable.dsp | 95 - .../tests/test_htable/test_htable.vcproj | 239 - .../win32/tests/test_memmem/test_memmem.dsp | 95 - .../tests/test_memmem/test_memmem.vcproj | 237 - .../win32/tests/test_nta/test_nta.dsp | 94 - .../win32/tests/test_nta/test_nta.vcproj | 239 - .../win32/tests/test_nua/test_nat_tags.cpp | 1 - .../win32/tests/test_nua/test_nua.dsp | 187 - .../win32/tests/test_nua/test_nua.vcproj | 673 - .../sofia-sip/win32/tests/test_su/test_su.dsp | 95 - .../win32/tests/test_su/test_su.vcproj | 239 - .../win32/tests/test_tport/test_class.cpp | 1 - .../win32/tests/test_tport/test_table.cpp | 1 - .../win32/tests/test_tport/test_tport.dsp | 110 - .../win32/tests/test_tport/test_tport.vcproj | 289 - .../tests/torture_rbtree/torture_rbtree.dsp | 95 - .../torture_rbtree/torture_rbtree.vcproj | 239 - .../win32/tests/torture_su/torture_su.dsp | 95 - .../win32/tests/torture_su/torture_su.vcproj | 239 - .../torture_su_alloc/torture_su_alloc.dsp | 95 - .../torture_su_alloc/torture_su_alloc.vcproj | 239 - .../tests/torture_su_bm/torture_su_bm.dsp | 95 - .../tests/torture_su_bm/torture_su_bm.vcproj | 239 - .../tests/torture_su_port/torture_su_port.dsp | 95 - .../torture_su_port/torture_su_port.vcproj | 236 - .../tests/torture_su_root/torture_su_root.dsp | 95 - .../torture_su_root/torture_su_root.vcproj | 239 - .../tests/torture_su_tag/torture_su_tag.dsp | 95 - .../torture_su_tag/torture_su_tag.vcproj | 239 - .../tests/torture_su_time/torture_su_time.dsp | 95 - .../torture_su_time/torture_su_time.vcproj | 239 - .../torture_su_timer/torture_su_timer.dsp | 95 - .../torture_su_timer/torture_su_timer.vcproj | 239 - libs/sofia-sip/win32/unistd.h | 49 - .../win32/utils/localinfo/localinfo.dsp | 118 - .../win32/utils/localinfo/localinfo.vcproj | 284 - .../sofia-sip/win32/utils/sip_dig/sip_dig.dsp | 114 - .../win32/utils/sip_dig/sip_dig.vcproj | 260 - .../win32/utils/sip_options/sip_options.dsp | 114 - .../utils/sip_options/sip_options.vcproj | 260 - .../sip_options_static/sip_options_static.dsp | 114 - .../sip_options_static.vcproj | 260 - libs/sofia-sip/win32/utils/stunc/stunc.dsp | 114 - libs/sofia-sip/win32/utils/stunc/stunc.vcproj | 260 - libs/sofia-sip/win32/version.awk | 51 - libs/sofia-sip/win32/version_files.cmd | 46 - libs/unimrcp/configure.gnu | 2 +- .../mrcp-unirtsp/mrcpunirtsp.2017.vcxproj | 285 +- .../sofia/libsofia_sip_ua_static.2017.vcxproj | 2 + src/mod/endpoints/mod_sofia/Makefile.am | 49 +- src/switch_sdp.c | 4 - w32/Library/FreeSwitchCore.2017.vcxproj | 3 + w32/download_sofia-sip.props | 41 + w32/sofia-sip-version.props | 19 + w32/sofia-sip.props | 14 + 848 files changed, 252 insertions(+), 322003 deletions(-) rename {libs/sofia-sip/m4 => build/config}/sac-openssl.m4 (100%) rename {libs/sofia-sip/m4 => build/config}/sac-pkg-config.m4 (100%) delete mode 100644 libs/sofia-sip/.update delete mode 100644 libs/sofia-sip/AUTHORS delete mode 100644 libs/sofia-sip/COPYING delete mode 100644 libs/sofia-sip/COPYRIGHTS delete mode 100644 libs/sofia-sip/ChangeLog delete mode 100644 libs/sofia-sip/ChangeLog.ext-trees delete mode 100644 libs/sofia-sip/Makefile.am delete mode 100644 libs/sofia-sip/README delete mode 100644 libs/sofia-sip/README.developers delete mode 100644 libs/sofia-sip/RELEASE delete mode 100644 libs/sofia-sip/RELEASE.template delete mode 100644 libs/sofia-sip/TODO delete mode 100644 libs/sofia-sip/acinclude.m4 delete mode 100644 libs/sofia-sip/autoconf-all.cmd delete mode 100755 libs/sofia-sip/autogen.sh delete mode 100644 libs/sofia-sip/configure.ac delete mode 100755 libs/sofia-sip/configure.gnu delete mode 100644 libs/sofia-sip/docs/build_system.txt delete mode 100644 libs/sofia-sip/docs/devel_platform_notes.txt delete mode 100644 libs/sofia-sip/docs/release_management.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua-glib/su-glib/torture_su_glib_timer.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/docs/sofia-footer.html.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/features.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/features.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/headers delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http.def.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_basic.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_extra.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_header.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_parser.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_status.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_hclasses.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/http/test_http.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/base64.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/token64.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_plugin.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_class.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/agent.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/check_nta.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/check_nta.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/check_nta_api.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/check_nta_client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/exit77.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/invite.msc delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/portbind.c delete mode 100755 libs/sofia-sip/libsofia-sip-ua/nta/run_check_nta delete mode 100755 libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta delete mode 100755 libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/agent.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/http-client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/http-server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/nth.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_nua.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_nua.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_register.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_session.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_client.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_server.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/nua_types.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/outbound.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/outbound.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/README delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/errata delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt delete mode 100755 libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-11.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt delete mode 100755 libs/sofia-sip/libsofia-sip-ua/sip/run-tests delete mode 100755 libs/sofia-sip/libsofia-sip-ua/sip/run_test_date delete mode 100755 libs/sofia-sip/libsofia-sip-ua/sip/run_test_sip_msg delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_inlined.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/test_date.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/test_sip_msg.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/10052.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sip/validator.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/soa.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/soa.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sofia.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188 delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/check_sres_sip.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/example.com delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1035.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/rfc2671.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/rndc.conf delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/root.zone delete mode 100755 libs/sofia-sip/libsofia-sip-ua/sresolv/run_test_sresolv delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_async.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_config.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_record.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sres_sip.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-sip/sresolv.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sres_blocking.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sres_sip.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/sresolv.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/test_sresolv.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/sresolv/torture_sresolv.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/cert.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/key.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/lookup_stun_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/rfc3489.txt delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_common.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/sofia-sip/stun_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun_common.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun_dns.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun_internal.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun_mini.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stun_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/stun/stunc.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/addrinfo.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/foo.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/getopt.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/inet_ntop.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/inet_pton.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/localinfo.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/memccpy.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/memcspn.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/memmem.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/memspn.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/poll.c delete mode 100755 libs/sofia-sip/libsofia-sip-ua/su/run_addrinfo delete mode 100755 libs/sofia-sip/libsofia-sip-ua/su/run_localinfo delete mode 100755 libs/sofia-sip/libsofia-sip-ua/su/run_test_su delete mode 100755 libs/sofia-sip/libsofia-sip-ua/su/run_test_su_osx delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/smoothsort.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/heap.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/htable2.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/rbtree.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/string0.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_bm.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_debug.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_localinfo.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_log.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_md5.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_os_nw.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_osx_runloop.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_string.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_strlst.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_time.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_uniqueid.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_vector.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_wait.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/tstdef.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/strcasestr.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/string0.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/strtoull.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_alloc.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_alloc_lock.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_bm.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_default_log.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_devpoll_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_epoll_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_errno.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_global_log.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_kqueue_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_localinfo.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_log.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_md5.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_module_debug.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_open_c_localinfo.cpp delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_os_nw.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_osx_runloop.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_perf.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_poll_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_port.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_proxy.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_pthread_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_root.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_select_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_socket_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_sprintf.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_strdup.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_string.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_strlst.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_tag_io.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_time.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_time0.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_timer.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_uniqueid.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_vector.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_wait.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/su_win32_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/tag_dll.awk delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_htable.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_htable2.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_memmem.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_poll.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_su.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/test_su_osx.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_heap.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_rbtree.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_alloc.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_bm.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_port.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_root.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_root_osx.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_time.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/su/torture_su_timer.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/agent.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/cafile.pem delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/certificates-update delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/certificates.html delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/include/switch.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/make_node_cert.pl delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/make_root_cert.pl delete mode 100755 libs/sofia-sip/libsofia-sip-ua/tport/make_test_certs.sh delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_plugins.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/test_tport.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tls_test_client.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tls_test_server.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_rand.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_sigcomp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_stub_stun.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_threadpool.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.h delete mode 100755 libs/sofia-sip/libsofia-sip-ua/tport/tport_tls_test.sh delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_connect.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_stun.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/ws.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/tport/ws.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/ChangeLog delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/Doxyfile.in delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/Makefile.am delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/sofia-sip/url_tag_class.h delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/torture_url.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/url.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/url.docs delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/url_tag.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/urlmap.c delete mode 100644 libs/sofia-sip/libsofia-sip-ua/url/urlmap.h delete mode 100644 libs/sofia-sip/m4/sac-coverage.m4 delete mode 100644 libs/sofia-sip/m4/sac-general.m4 delete mode 100644 libs/sofia-sip/m4/sac-su.m4 delete mode 100644 libs/sofia-sip/m4/sac-su2.m4 delete mode 100644 libs/sofia-sip/m4/sac-tport.m4 delete mode 100644 libs/sofia-sip/open_c/Makefile.am delete mode 100644 libs/sofia-sip/open_c/autogen.cmd delete mode 100644 libs/sofia-sip/open_c/build_sources.cmd delete mode 100644 libs/sofia-sip/open_c/config.h.in delete mode 100644 libs/sofia-sip/open_c/group/bld.inf delete mode 100644 libs/sofia-sip/open_c/group/libsofia-sip-ua-glib.mmp delete mode 100644 libs/sofia-sip/open_c/group/libsofia-sip-ua.mmp delete mode 100644 libs/sofia-sip/open_c/group/su_source_test.mmp delete mode 100644 libs/sofia-sip/open_c/group/su_source_test_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/test_http.mmp delete mode 100644 libs/sofia-sip/open_c/group/test_http_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/test_msg.mmp delete mode 100644 libs/sofia-sip/open_c/group/test_msg_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/test_nua.mmp delete mode 100644 libs/sofia-sip/open_c/group/test_nua_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/test_tport.mmp delete mode 100644 libs/sofia-sip/open_c/group/test_tport_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_sip.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_sip_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_su_alloc.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_su_alloc_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_su_port.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_su_port_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_su_root.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_su_root_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_su_tag.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_su_tag_reg.rss delete mode 100644 libs/sofia-sip/open_c/group/torture_url.mmp delete mode 100644 libs/sofia-sip/open_c/group/torture_url_reg.rss delete mode 100644 libs/sofia-sip/open_c/sis/libsofia-sip-ua-glib.pkg delete mode 100644 libs/sofia-sip/open_c/sis/libsofia-sip-ua.pkg delete mode 100644 libs/sofia-sip/open_c/sis/su_source_test.pkg delete mode 100644 libs/sofia-sip/open_c/sis/test_nua.pkg delete mode 100644 libs/sofia-sip/open_c/sis/test_tport.pkg delete mode 100644 libs/sofia-sip/open_c/sofia-sip/su_configure.h delete mode 100644 libs/sofia-sip/open_c/version.awk delete mode 100644 libs/sofia-sip/open_c/version_files.cmd delete mode 100644 libs/sofia-sip/packages/ChangeLog delete mode 100644 libs/sofia-sip/packages/Makefile.am delete mode 100644 libs/sofia-sip/packages/sofia-sip-ua-glib.pc.in delete mode 100644 libs/sofia-sip/packages/sofia-sip-ua.pc.in delete mode 100644 libs/sofia-sip/packages/sofia-sip.spec.in delete mode 100644 libs/sofia-sip/rules/lcov.am delete mode 100644 libs/sofia-sip/rules/recursive.am delete mode 100644 libs/sofia-sip/rules/silent.am delete mode 100644 libs/sofia-sip/rules/sofia.am delete mode 100644 libs/sofia-sip/rules/valcheck.am delete mode 100644 libs/sofia-sip/s2check/Makefile.am delete mode 100644 libs/sofia-sip/s2check/s2_localinfo.c delete mode 100644 libs/sofia-sip/s2check/s2_localinfo.h delete mode 100644 libs/sofia-sip/s2check/s2base.c delete mode 100644 libs/sofia-sip/s2check/s2base.h delete mode 100644 libs/sofia-sip/s2check/s2check.h delete mode 100644 libs/sofia-sip/s2check/s2dns.c delete mode 100644 libs/sofia-sip/s2check/s2dns.h delete mode 100644 libs/sofia-sip/s2check/s2sip.c delete mode 100644 libs/sofia-sip/s2check/s2sip.h delete mode 100644 libs/sofia-sip/s2check/s2tcase.c delete mode 100644 libs/sofia-sip/s2check/s2time.c delete mode 100644 libs/sofia-sip/s2check/s2util.h delete mode 100755 libs/sofia-sip/scripts/coverage delete mode 100755 libs/sofia-sip/scripts/fix-include-sofia-sip delete mode 100755 libs/sofia-sip/scripts/hide_emails.sh delete mode 100755 libs/sofia-sip/scripts/lcov-report delete mode 100755 libs/sofia-sip/scripts/rpmbuild-snaphot delete mode 100755 libs/sofia-sip/scripts/uncovered delete mode 100644 libs/sofia-sip/tests/Makefile.am delete mode 100644 libs/sofia-sip/tests/check_dlopen_sofia.c delete mode 100644 libs/sofia-sip/tests/check_sofia.c delete mode 100644 libs/sofia-sip/tests/check_sofia.h delete mode 100644 libs/sofia-sip/tests/suite_for_nua.c delete mode 100644 libs/sofia-sip/tests/test_100rel.c delete mode 100644 libs/sofia-sip/tests/test_basic_call.c delete mode 100644 libs/sofia-sip/tests/test_call_hold.c delete mode 100644 libs/sofia-sip/tests/test_call_reject.c delete mode 100644 libs/sofia-sip/tests/test_cancel_bye.c delete mode 100644 libs/sofia-sip/tests/test_extension.c delete mode 100644 libs/sofia-sip/tests/test_init.c delete mode 100644 libs/sofia-sip/tests/test_nat.c delete mode 100644 libs/sofia-sip/tests/test_nat.h delete mode 100644 libs/sofia-sip/tests/test_nat_tags.c delete mode 100644 libs/sofia-sip/tests/test_nua.c delete mode 100644 libs/sofia-sip/tests/test_nua.h delete mode 100644 libs/sofia-sip/tests/test_nua_api.c delete mode 100644 libs/sofia-sip/tests/test_nua_params.c delete mode 100644 libs/sofia-sip/tests/test_offer_answer.c delete mode 100644 libs/sofia-sip/tests/test_ops.c delete mode 100644 libs/sofia-sip/tests/test_proxy.c delete mode 100644 libs/sofia-sip/tests/test_proxy.h delete mode 100644 libs/sofia-sip/tests/test_refer.c delete mode 100644 libs/sofia-sip/tests/test_register.c delete mode 100644 libs/sofia-sip/tests/test_session_timer.c delete mode 100644 libs/sofia-sip/tests/test_simple.c delete mode 100644 libs/sofia-sip/tests/test_sip_events.c delete mode 100644 libs/sofia-sip/utils/ChangeLog delete mode 100644 libs/sofia-sip/utils/Doxyfile.in delete mode 100644 libs/sofia-sip/utils/Makefile.am delete mode 100644 libs/sofia-sip/utils/apps_utils.h delete mode 100644 libs/sofia-sip/utils/sip-date.c delete mode 100644 libs/sofia-sip/utils/sip-dig.c delete mode 100644 libs/sofia-sip/utils/sip-options.c delete mode 100644 libs/sofia-sip/utils/utils.docs delete mode 100644 libs/sofia-sip/win32/ChangeLog delete mode 100644 libs/sofia-sip/win32/Makefile.am delete mode 100644 libs/sofia-sip/win32/README.txt delete mode 100644 libs/sofia-sip/win32/SofiaSIP.dsw delete mode 100644 libs/sofia-sip/win32/SofiaSIP.sln delete mode 100644 libs/sofia-sip/win32/autogen.cmd delete mode 100644 libs/sofia-sip/win32/build_sources.cmd delete mode 100644 libs/sofia-sip/win32/check.cmd delete mode 100644 libs/sofia-sip/win32/config.h.in delete mode 100644 libs/sofia-sip/win32/install.cmd delete mode 100644 libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.dsp delete mode 100644 libs/sofia-sip/win32/libsofia-sip-ua-static/libsofia_sip_ua_static.vcproj delete mode 100644 libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.dsp delete mode 100644 libs/sofia-sip/win32/libsofia-sip-ua/libsofia_sip_ua.vcproj delete mode 100644 libs/sofia-sip/win32/libsofia-sip-ua/sofia-sip-ua.def delete mode 100644 libs/sofia-sip/win32/sofia-sip/su_configure.h delete mode 100644 libs/sofia-sip/win32/tests/test_htable/test_htable.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_htable/test_htable.vcproj delete mode 100644 libs/sofia-sip/win32/tests/test_memmem/test_memmem.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_memmem/test_memmem.vcproj delete mode 100644 libs/sofia-sip/win32/tests/test_nta/test_nta.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_nta/test_nta.vcproj delete mode 100644 libs/sofia-sip/win32/tests/test_nua/test_nat_tags.cpp delete mode 100644 libs/sofia-sip/win32/tests/test_nua/test_nua.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_nua/test_nua.vcproj delete mode 100644 libs/sofia-sip/win32/tests/test_su/test_su.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_su/test_su.vcproj delete mode 100644 libs/sofia-sip/win32/tests/test_tport/test_class.cpp delete mode 100644 libs/sofia-sip/win32/tests/test_tport/test_table.cpp delete mode 100644 libs/sofia-sip/win32/tests/test_tport/test_tport.dsp delete mode 100644 libs/sofia-sip/win32/tests/test_tport/test_tport.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_rbtree/torture_rbtree.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su/torture_su.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su/torture_su.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_alloc/torture_su_alloc.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_bm/torture_su_bm.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_port/torture_su_port.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_root/torture_su_root.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_tag/torture_su_tag.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_time/torture_su_time.vcproj delete mode 100644 libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.dsp delete mode 100644 libs/sofia-sip/win32/tests/torture_su_timer/torture_su_timer.vcproj delete mode 100644 libs/sofia-sip/win32/unistd.h delete mode 100644 libs/sofia-sip/win32/utils/localinfo/localinfo.dsp delete mode 100644 libs/sofia-sip/win32/utils/localinfo/localinfo.vcproj delete mode 100644 libs/sofia-sip/win32/utils/sip_dig/sip_dig.dsp delete mode 100644 libs/sofia-sip/win32/utils/sip_dig/sip_dig.vcproj delete mode 100644 libs/sofia-sip/win32/utils/sip_options/sip_options.dsp delete mode 100644 libs/sofia-sip/win32/utils/sip_options/sip_options.vcproj delete mode 100644 libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.dsp delete mode 100644 libs/sofia-sip/win32/utils/sip_options_static/sip_options_static.vcproj delete mode 100644 libs/sofia-sip/win32/utils/stunc/stunc.dsp delete mode 100644 libs/sofia-sip/win32/utils/stunc/stunc.vcproj delete mode 100644 libs/sofia-sip/win32/version.awk delete mode 100644 libs/sofia-sip/win32/version_files.cmd create mode 100644 w32/download_sofia-sip.props create mode 100644 w32/sofia-sip-version.props create mode 100644 w32/sofia-sip.props diff --git a/.drone.yml b/.drone.yml index 2dd901b34e..f5cdd6d93c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,6 +14,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev - echo "applications/mod_test" >> modules.conf - echo 'codecs/mod_openh264' >> modules.conf - sed -i '/applications\\/mod_http_cache/s/^#//g' modules.conf @@ -27,6 +28,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev - echo '#!/bin/bash\nmake -j`nproc --all` |& tee ./unit-tests-build-result.txt\nexitstatus=$${PIPESTATUS[0]}\necho $$exitstatus > ./build-status.txt\n' > build.sh - chmod +x build.sh - ./build.sh @@ -35,6 +37,7 @@ steps: image: signalwire/freeswitch-public-base pull: true commands: + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev - make install || true - cd tests/unit - ./run-tests.sh @@ -80,6 +83,7 @@ steps: image: signalwire/freeswitch-public-base:stretch pull: true commands: + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev - cp build/modules.conf.most modules.conf #Enable/Uncomment mods - echo 'codecs/mod_openh264' >> modules.conf @@ -109,6 +113,7 @@ steps: image: signalwire/freeswitch-public-base:stretch pull: true commands: + - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev - mkdir -p scan-build - echo '#!/bin/bash\nscan-build-4.0 -o ./scan-build/ make -j`nproc --all` |& tee ./scan-build-result.txt\nexitstatus=$${PIPESTATUS[0]}\necho $$exitstatus > ./scan-build-status.txt\n' > scan.sh - chmod +x scan.sh @@ -139,6 +144,6 @@ trigger: --- kind: signature -hmac: 430f5a243e6029b985fa0219e9fb44c71a59931af44a3230751e238f8b64dd32 +hmac: 9f536d54b3df4db408a9e23a412185d0c95e66d22d15ba7ff00c7cfc85bff3ab ... diff --git a/.gitattributes b/.gitattributes index afc9621833..f031f31535 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,7 +6,6 @@ *.c text eol=lf *.cxx text eol=lf *.cpp text eol=lf -/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask text eol=lf *.txt text eol=lf *.exe -diff binary executable windows dfsg-nonfree debian-ignore *.wav -diff binary sound diff --git a/.gitignore b/.gitignore index 053abd7afb..eef21da305 100644 --- a/.gitignore +++ b/.gitignore @@ -260,6 +260,8 @@ libs/libsilk-*/ libs/rabbitmq-c-*/ libs/rabbitmq-c-*.zip libs/ffmpeg-*/ +libs/sofia-sip*/ +libs/sofia-sip* src/mod/applications/mod_test/test/test_asr src/mod/event_handlers/mod_rayo/test/test_iks diff --git a/Makefile.am b/Makefile.am index 8e3a2e852e..566ada5a41 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,9 +30,8 @@ endif AM_CFLAGS = $(SWITCH_AM_CFLAGS) $(SWITCH_ANSI_CFLAGS) AM_CPPFLAGS = AM_CPPFLAGS += -I$(switch_srcdir)/libs/libvpx -AM_CPPFLAGS += $(SWITCH_AM_CXXFLAGS) -I$(switch_srcdir)/libs/sofia-sip/libsofia-sip-ua/sdp -AM_CPPFLAGS += -I$(switch_srcdir)/libs/sofia-sip/libsofia-sip-ua/su -I$(switch_builddir)/libs/sofia-sip/libsofia-sip-ua/su -AM_LDFLAGS = $(SWITCH_AM_LDFLAGS) $(AM_LIBAPR_LDFLAGS) $(AM_LIBAPU_LDFLAGS) +AM_CPPFLAGS += $(SWITCH_AM_CXXFLAGS) $(SOFIA_SIP_CFLAGS) +AM_LDFLAGS = $(SWITCH_AM_LDFLAGS) $(AM_LIBAPR_LDFLAGS) $(AM_LIBAPU_LDFLAGS) $(SOFIA_SIP_LIBS) DEFAULT_SOUNDS=en-us-callie-8000 MY_DEFAULT_ARGS= --build=$(build) --host=$(host) --target=$(target) --prefix="$(prefix)" --exec_prefix="$(exec_prefix)" --libdir="$(libdir)" @@ -593,14 +592,6 @@ libs/libvpx/Makefile: libs/libvpx/.update libs/libvpx/libvpx.a: libs/libvpx/Makefile libs/libvpx/.update @cd libs/libvpx && $(MAKE) -libs/sofia-sip/Makefile: - cd libs/sofia-sip && sh ./configure.gnu $(MY_DEFAULT_ARGS) - -libs/sofia-sip/libsofia-sip-ua/sdp/.libs/libsdp.a libs/sofia-sip/libsofia-sip-ua/su/.libs/libsu.a: libs/sofia-sip/.update libs/sofia-sip/Makefile - @cd libs/sofia-sip && $(MAKE) noop - @cd libs/sofia-sip && $(MAKE) SOFIA_CFLAGS="$(SWITCH_AM_CFLAGS)" - @$(TOUCH_TARGET) - libs/apr/Makefile: libs/apr/Makefile.in libs/apr/config.status libs/apr libs/apr/.update @cd libs/apr && ./config.status @$(TOUCH_TARGET) @@ -756,7 +747,6 @@ pristine: git reset --hard update-clean: clean python-reconf - cd libs/sofia-sip && $(MAKE) clean cd libs/esl && $(MAKE) clean cd libs/srtp && $(MAKE) clean @@ -796,11 +786,6 @@ spandsp-reconf: cd libs/spandsp && sh ./configure.gnu $(MY_DEFAULT_ARGS) cd libs/spandsp && $(MAKE) -sofia-reconf: - cd libs/sofia-sip && sh ./autogen.sh - cd libs/sofia-sip && $(MAKE) clean - cd libs/sofia-sip && ./configure $(MY_DEFAULT_ARGS) --with-pic --with-glib=no --disable-shared - cluecon: @clear @echo Thank you for updating. This is going to take a while so relax. diff --git a/acinclude.m4 b/acinclude.m4 index 68cad585d9..26630f64ef 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -9,8 +9,8 @@ m4_include([build/config/ax_check_java.m4]) m4_include([build/config/uuid.m4]) m4_include([build/config/erlang.m4]) m4_include([build/config/odbc.m4]) +m4_include([build/config/sac-pkg-config.m4]) +m4_include([build/config/sac-openssl.m4]) m4_include([build/config/sched_setaffinity.m4]) m4_include([libs/apr/build/apr_common.m4]) -m4_include([libs/sofia-sip/m4/sac-pkg-config.m4]) -m4_include([libs/sofia-sip/m4/sac-openssl.m4]) m4_include([libs/iksemel/build/libgnutls.m4]) diff --git a/bootstrap.sh b/bootstrap.sh index 163827dc4d..79d3f0d17e 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -8,7 +8,7 @@ BGJOB=false VERBOSE=false BASEDIR=`pwd`; LIBDIR=${BASEDIR}/libs; -SUBDIRS="apr libzrtp iksemel libdingaling sofia-sip srtp freetdm spandsp unimrcp fs"; +SUBDIRS="apr libzrtp iksemel libdingaling srtp freetdm spandsp unimrcp fs"; while getopts 'jhd:v' o; do case "$o" in diff --git a/libs/sofia-sip/m4/sac-openssl.m4 b/build/config/sac-openssl.m4 similarity index 100% rename from libs/sofia-sip/m4/sac-openssl.m4 rename to build/config/sac-openssl.m4 diff --git a/libs/sofia-sip/m4/sac-pkg-config.m4 b/build/config/sac-pkg-config.m4 similarity index 100% rename from libs/sofia-sip/m4/sac-pkg-config.m4 rename to build/config/sac-pkg-config.m4 diff --git a/configure.ac b/configure.ac index 7c7df126f5..23b741ea61 100644 --- a/configure.ac +++ b/configure.ac @@ -714,6 +714,11 @@ PKG_CHECK_MODULES([MARIADB], [libmariadb >= 3.0.9],[ ]) ]) +PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.12.12],[ + AM_CONDITIONAL([HAVE_SOFIA_SIP],[true])],[ + AC_MSG_ERROR([no usable sofia-sip; please install sofia-sip-ua devel package or equivalent]) +]) + AC_ARG_ENABLE(deprecated-core-db-events, [AS_HELP_STRING([--enable-deprecated-core-db-events], [Keep deprecated core db events])],,[enable_deprecated_core_db_events="no"]) @@ -2104,7 +2109,6 @@ if test "$use_system_aprutil" != "yes"; then fi AC_CONFIG_SUBDIRS([libs/iksemel]) AC_CONFIG_SUBDIRS([libs/libdingaling]) -AC_CONFIG_SUBDIRS([libs/sofia-sip]) AC_CONFIG_SUBDIRS([libs/freetdm]) AC_CONFIG_SUBDIRS([libs/unimrcp]) AC_CONFIG_SUBDIRS([libs/spandsp]) diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index a19eb27281..78a135e4db 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -332,7 +332,7 @@ Build-Depends: uuid-dev, libexpat1-dev, libgdbm-dev, libdb-dev, # used by many modules libcurl4-openssl-dev | libcurl4-gnutls-dev | libcurl-dev, - bison, zlib1g-dev, + bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.12.12) # module build-depends $(debian_wrap "${mod_build_depends}") Standards-Version: 3.9.3 diff --git a/freeswitch.spec b/freeswitch.spec index 4fa2212305..17eebfbf3f 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -152,6 +152,7 @@ BuildRequires: gnutls-devel BuildRequires: libtool >= 1.5.17 BuildRequires: ncurses-devel BuildRequires: openssl-devel >= 1.0.1e +BuildRequires: sofia-sip-devel >= 1.12.12 BuildRequires: pcre-devel BuildRequires: speex-devel BuildRequires: sqlite-devel diff --git a/libs/.gitignore b/libs/.gitignore index 4410a4df8c..7e8bd3ce8a 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -837,7 +837,6 @@ iksemel/configure libdingaling/configure libyuv/Makefile libyuv/convert -sofia-sip/configure spandsp/configure srtp/configure tiff-4.0.2/configure diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update deleted file mode 100644 index 67ed62e0fe..0000000000 --- a/libs/sofia-sip/.update +++ /dev/null @@ -1 +0,0 @@ -Fri Jul 31 17:46:57 CDT 2020 diff --git a/libs/sofia-sip/AUTHORS b/libs/sofia-sip/AUTHORS deleted file mode 100644 index 9b2724149f..0000000000 --- a/libs/sofia-sip/AUTHORS +++ /dev/null @@ -1,49 +0,0 @@ -Current development team ------------------------- - -Pekka Pessi -Martti Mela -Kai Vehmanen - -Contributors (in alphabetical order, surname first) ---------------------------------------------------- - -Alaoui, Youness -Chan, Tat -Ciarkowski, Andrzej -Czapiga, Brian -Denis-Courmont, Remi -Ferrari, Fabio -Filonenko Roman -Haataja, Mikko -Jacobs, Remeres -Jalava, Teemu -Jerris, Michael -Katcipis, Tiago -Knoblich, Stefan -Legostayev, Denis -Lenk, Jeff -Leuenberger, Stefan -Margarido, Fabio -Neuner, Jarod -Paul, Johan -Pizarro, Paulo -Prado, Dimitri E. -Puolakka, Petteri -Puustinen, Ismo -Rinne-Rahkola, Pasi -Richards, Jerry -Rondina, Daniele -Saari, Mika -Sabatini, Stefano -Selin, Jari -Suttner, Bernhard -Underwood, Steve -Urpalainen, Jari -Whittaker, Colin -Zabaluev, Mikhail -Zaikin, Maxim - -Note: for details on who did what, see the version control - system change history, and release notes for past releases at - http://sofia-sip.sourceforge.net/relnotes/ diff --git a/libs/sofia-sip/COPYING b/libs/sofia-sip/COPYING deleted file mode 100644 index 148d531ce4..0000000000 --- a/libs/sofia-sip/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - 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. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - 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. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/libs/sofia-sip/COPYRIGHTS b/libs/sofia-sip/COPYRIGHTS deleted file mode 100644 index f82e57e89d..0000000000 --- a/libs/sofia-sip/COPYRIGHTS +++ /dev/null @@ -1,251 +0,0 @@ -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 - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public License -as published by the Free Software Foundation; either version 2.1 of -the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, 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. - ----------------------------------------------------------------------------- - -libsofia-sip-ua/su/poll.c - -The package also contains files from GNU C Library by Free Software -Foundation. - -These files are distributed with the following copyright notice: - -Copyright (C) 1994,1996,1997,1998,1999,2001,2002 -Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with the GNU C Library; if not, write to the Free -Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA. - ----------------------------------------------------------------------------- diff --git a/libs/sofia-sip/ChangeLog b/libs/sofia-sip/ChangeLog deleted file mode 100644 index 56190603ff..0000000000 --- a/libs/sofia-sip/ChangeLog +++ /dev/null @@ -1,18 +0,0 @@ -=============================================================== -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/ diff --git a/libs/sofia-sip/ChangeLog.ext-trees b/libs/sofia-sip/ChangeLog.ext-trees deleted file mode 100644 index 6931926f32..0000000000 --- a/libs/sofia-sip/ChangeLog.ext-trees +++ /dev/null @@ -1,4578 +0,0 @@ -2006-05-12 Pekka Pessi - - * 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 - 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 - - * Added su_source_create() prototype to su-glib/so_source.c. - -2006-05-11 Pekka Pessi - - * 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 . - - * 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 - - * 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 - - * 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@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 - - * 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@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@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@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 - - * 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 - - * 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 - . - - * Added nta_outgoing_transport() to nta/nta.c and - . - - * 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 . - - * 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 - . 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 - - * 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 - - * sresolv module: - - Added SRESTAG_CACHE() to . - - Added ends0 and no-edns0 options in resolv.conf to sresolv/sres.c. - - Fixed sresolv #includes. - Added #include and 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 - - * 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 - - * 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 . - - * 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 - - * 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 - - * 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 - - 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 . - Moved sigcomp dependencies into . - - 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 . (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 . (pp) - - M ./m4/sac-su2.m4 -1 +3 - - * Fixed HAVE_SOCKADDR_LL in case we have . (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 - - 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 - - * 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 - - * win32 defs, compiles and installs in mingw environment - -2006-03-09 Kai Vehmanen - - * 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 - - * Updated globally unique identifier (uuid) generation. - Using getifaddrs() and /dev/urandom. Added checks for /dev/urandom - and (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 . - 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 - - * 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 . - - * Added SIPS_DEFAULT_PORT and SIPS_DEFAULT_SERV. - - M ./libsofia-sip-ua/sip/sofia-sip/sip.h -1 +7 - - * Removed redundant reference to . - - 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 - - * 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@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 - - * 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@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 - - * 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 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 - - * 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 - - * Fixed problems with sofia-sip/ header prefix in win32. - - * Fixed win32/VC configuration problems. - - * Fixed win32 pthread dist. - - * Fixed include paths. - - * Use #include . - - * 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., - . - - 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 - - * 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 - - * 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 - - * 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 . - - 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 - - * Removed *_dll.h files - defining *_DLL macros in . - - * 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 - - * 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 - - * 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 - - 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 . - - 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 - - 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 for FILE. - - * Fixed include_sofiadir handling in pkg-config and rpm files. - -2005-12-27 Martti Mela - - 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@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 - - 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 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 - - 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 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 - - 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 . [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 - - 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 . - - 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 - - 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 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 - - R ./win32/config.h - -2005-11-28 Martti Mela - - * 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 - - * 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 - - * configure.ac: Added VER_LIBSOFIA_SIP_UA variables. - -2005-11-14 Pekka Pessi - - 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 - - * 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 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 - - * 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 - - * 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 - - 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 - - * 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 - - * 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 - - * 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 - - * 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 - - 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 - - * 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 - - * Added coverage files used by gcc 3.4.3 to MOSTLYCLEANFILES. - - M ./m4/sac-general.m4 -1 +1 - -2005-10-21 Pekka Pessi - - * Fixed lib64 problem. - - M ./packages/sofia-sip.spec.in -6 +9 - -2005-10-13 Pekka Pessi - - * Removed RCS/CVS Ids and dates from files in order to allow - smoother darcs usage. - -2005-10-12 Pekka Pessi - - * 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * Importing darcs-to-cvs-2005-09-29. - -2005-09-28 Pekka Pessi - - * Added nua improvements. - - M ./TODO +3 - -2005-09-23 Pekka Pessi - - * darcs changes: - - Fri Sep 23 18:58:29 EEST 2005 Pekka.Pessi@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@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@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@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@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@nokia.com - tagged pessi-darcs-2 - - Fri Sep 23 17:20:02 EEST 2005 Pekka.Pessi@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@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@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@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@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@nokia.com - * Fixed typo. - - M ./libsofia-sip-ua/soa/soa.docs -1 +1 - - Tue Sep 20 12:51:41 EEST 2005 Pekka.Pessi@nokia.com - * Added SIPS_PORT() - - M ./libsofia-sip-ua/sip/sip_header.h +3 - - Mon Sep 19 20:12:33 EEST 2005 Pekka.Pessi@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@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@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@nokia.com - * Removed merge artifact. - - M ./libsofia-sip-ua/tport/tport.c -7 - - Fri Sep 16 10:21:32 EEST 2005 Pekka.Pessi@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@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@nokia.com - * Added --with-sigcomp to tport. - - M ./m4/sac-tport.m4 +21 - - Thu Sep 15 09:55:57 EEST 2005 Pekka.Pessi@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@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@nokia.com - * Installing m4data into m4dir - - M ./Makefile.am +4 - -2005-09-09 Pekka Pessi - - * darcs changes --from-tag pessi-darcs-1: - - Fri Sep 9 11:38:44 EEST 2005 Pekka.Pessi@nokia.com - * Added --with sigcomp. - - M ./sofia-sip.spec.in +4 - - Fri Sep 9 00:33:36 EEST 2005 Pekka.Pessi@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@nokia.com - * New version. - - M ./configure.ac -1 +1 - - Thu Sep 8 18:51:27 EEST 2005 Pekka.Pessi@nokia.com - * Keeping section headers in configure script. - - M ./configure.ac -17 +16 - - Thu Sep 8 18:26:35 EEST 2005 Pekka.Pessi@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@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@nokia.com - * Checking for netinet/tcp.h, too. - - M ./m4/sac-tport.m4 +2 - -2005-09-08 Kai Vehmanen - - * 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 - - * Makefile.am: Added doxygen target. diff --git a/libs/sofia-sip/Makefile.am b/libs/sofia-sip/Makefile.am deleted file mode 100644 index 9ef3ac8a5b..0000000000 --- a/libs/sofia-sip/Makefile.am +++ /dev/null @@ -1,85 +0,0 @@ -# -# Makefile.am for sofia-sip package -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -AUTOMAKE_OPTIONS = foreign 1.7 - -SUBDIRS = libsofia-sip-ua $(GLIB_SUBDIRS) packages tests s2check utils -DIST_SUBDIRS = s2check libsofia-sip-ua libsofia-sip-ua-glib utils packages \ - tests win32 open_c - -# 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-coverage.m4 \ - m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4 - -EXTRA_DIST += docs/build_system.txt \ - docs/devel_platform_notes.txt \ - docs/release_management.txt - -EXTRA_DIST += scripts/lcov-report scripts/uncovered \ - scripts/hide_emails.sh - -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 - -noop: - @echo ok - -$(dist_man_MANS): manpages - -manpages: - -mkdir -p man man/man1 2> /dev/null -if HAVE_DOXYGEN - $(MAKE) $(AM_MAKEFLAGS) -C libsofia-sip-ua/docs built-sources - @echo 'cd utils && $(DOXYGEN)' - @cd utils && \ - { exec 3>&1 1>&2; { $(DOXYGEN) 2>&1; echo $$? >& 3 ;} | \ - fgrep -v 'Warning: explicit' ;} | { read x; exit $$x ;} - @rm -f man/man1/_*.1 -else - -touch $(dist_man_MANS) -endif - -CLEANFILES = $(dist_man_MANS) - -built-sources clean-built-sources valcheck doxygen: - @failcom='exit 1'; for f in x $$MAKEFLAGS; do \ - case $$f in *=* | --[!k]*);; *k*) failcom='fail=yes';; esac; done; \ - for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do \ - (cd $$i && $(MAKE) $(AM_MAKEFLAGS) $@) || eval $$failcom; \ - done ; \ - test -z "$$fail" - -PHONY = built-sources clean-built-sources valcheck doxygen manpages - -# s2check depends on generated headers within libsofia-sip-ua -all check: built-sources - -if HAVE_LCOV - -include $(top_srcdir)/rules/lcov.am - -lcov-upload: lcov - rsync -rvz -e ssh --delete lcov/* sofia-sip.org:/var/www/coverage/lcov/ - -endif - -.PHONY: $(PHONY) diff --git a/libs/sofia-sip/README b/libs/sofia-sip/README deleted file mode 100644 index a503fb23a9..0000000000 --- a/libs/sofia-sip/README +++ /dev/null @@ -1,66 +0,0 @@ -============================================================= -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. diff --git a/libs/sofia-sip/README.developers b/libs/sofia-sip/README.developers deleted file mode 100644 index 611c7bc2f8..0000000000 --- a/libs/sofia-sip/README.developers +++ /dev/null @@ -1,134 +0,0 @@ -=============================================================== -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. - -/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 - - diff --git a/libs/sofia-sip/RELEASE b/libs/sofia-sip/RELEASE deleted file mode 100644 index 8d9d85ef60..0000000000 --- a/libs/sofia-sip/RELEASE +++ /dev/null @@ -1,108 +0,0 @@ -============================================== -Release notes for current version of Sofia-SIP -============================================== - -Changes since last release --------------------------- - - - -Bugs in blaa and foo have been fixed. The stack now supports -use of foobar... - -API/ABI changes and versioning ------------------------------- - - - -**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). -- Timing out CANCELed INVITE client transactions is now done with timer D. - Previously, the INVITE client transactions were restarted instead of - timing out under certain circumstances. -- An INVITE transaction that has been timed out with stack timer C is now - CANCELed automatically. Previously, such the INVITE client transactions - were restarted instead of timing out under certain circumstances. -- Timing out forked INVITE client transactions is now done by stack. - The stack generates a 408 response to each INVITE transaction fork that - has not received a final response within 32 seconds (or 64 times SIP T1) - after first final response to the INVITE was received. -- The mp_len type was changed from usize_t to unsigned. - The change is binary-incompatible on 64-bit platforms when compiled with - the configure opetion --disable-size-compat -- 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. - -Removed globals which should have been static in first place: - - su_t64_to_time() - - mutex_trylocker() - - su_port_set_system_preferences() - - t_null_next(), t_null_move(), t_null_dup(), t_null_copy(), t_null_find() - - t_skip_next(), t_skip_move(), t_skip_len(), t_skip_dup(), t_skip_filter() - - t_next_next(), t_next_move(), t_next_len(), t_next_dup(), t_next_filter() - - t_filter_with(), t_any_filter() - - sres_record_class(), urandom - - u2s_alloc() - -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 ----------------------------- - -Jarod Neuner -Michael Jerris - - -- **template**: First Surname (patch to nua/soa/msg) - -See the AUTHORS file in the distribution package. - -Notes on new features ---------------------- - -Jarod Neuner has improved certificate validation facilities of TLS -transport. Significant changes include: - -1) The TLS handshake is no longer handled via transparent negotiation. -Certain static methods from tport.c were exposed to make this possible. - -2) Certificate subjects are copied out of the peer certificate before -the first message is sent. The next patch will include code that allows -the stack to reject messages sent to a untrusted peer. - -3) The tport module can now report whether a secondary has a verified -certificate chain and the subjects of the peer certificate. - -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 -- Accept multiple WWW-Authenticate and Authorization headers. - Bug reported by Andrew Rechenberg. diff --git a/libs/sofia-sip/RELEASE.template b/libs/sofia-sip/RELEASE.template deleted file mode 100644 index da6bf2f0ea..0000000000 --- a/libs/sofia-sip/RELEASE.template +++ /dev/null @@ -1,73 +0,0 @@ -============================================== -Release notes for current version of Sofia-SIP -============================================== - -Changes since last release --------------------------- - - - -Bugs in blaa and foo have been fixed. The stack now supports -use of foobar... - -API/ABI changes and versioning ------------------------------- - - - -**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 ----------------------------- - - - -- **template**: First Surname (patch to nua/soa/msg) - -See the AUTHORS file in the distribution package. - -Notes on new features ---------------------- - - - -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 diff --git a/libs/sofia-sip/TODO b/libs/sofia-sip/TODO deleted file mode 100644 index 970f6733e2..0000000000 --- a/libs/sofia-sip/TODO +++ /dev/null @@ -1,29 +0,0 @@ -=============================================================== -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. diff --git a/libs/sofia-sip/acinclude.m4 b/libs/sofia-sip/acinclude.m4 deleted file mode 100644 index c1ea4f9214..0000000000 --- a/libs/sofia-sip/acinclude.m4 +++ /dev/null @@ -1,7 +0,0 @@ -m4_include([m4/sac-pkg-config.m4]) -m4_include([m4/sac-general.m4]) -m4_include([m4/sac-openssl.m4]) -m4_include([m4/sac-su2.m4]) -m4_include([m4/sac-su.m4]) -m4_include([m4/sac-tport.m4]) -m4_include([m4/sac-coverage.m4]) diff --git a/libs/sofia-sip/autoconf-all.cmd b/libs/sofia-sip/autoconf-all.cmd deleted file mode 100644 index e37cec7e60..0000000000 --- a/libs/sofia-sip/autoconf-all.cmd +++ /dev/null @@ -1,5 +0,0 @@ -@setlocal - -@cd open_c -@call autogen.cmd - diff --git a/libs/sofia-sip/autogen.sh b/libs/sofia-sip/autogen.sh deleted file mode 100755 index e8fcf2c6a8..0000000000 --- a/libs/sofia-sip/autogen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -x -AUTOMAKE=${AUTOMAKE:-automake-1.9} ACLOCAL=${ACLOCAL:-aclocal-1.9} -export AUTOMAKE ACLOCAL -${AUTORECONF:-autoreconf} -i -find . \( -name 'run*' -o -name '*.sh' \) -a -type f | xargs chmod +x -chmod +x scripts/* diff --git a/libs/sofia-sip/configure.ac b/libs/sofia-sip/configure.ac deleted file mode 100644 index 9542208cb6..0000000000 --- a/libs/sofia-sip/configure.ac +++ /dev/null @@ -1,389 +0,0 @@ -dnl Copyright (C) 2005-2006 Nokia Corporation -dnl Contact: Pekka Pessi -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.10devel]) - -CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" -CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" -LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" - -AC_CONFIG_SRCDIR([libsofia-sip-ua/sip/sofia-sip/sip.h]) -AC_CONFIG_MACRO_DIR([m4]) -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, [6]) -AC_SUBST(LIBVER_SOFIA_SIP_UA_REV, [0]) -AC_SUBST(LIBVER_SOFIA_SIP_UA_AGE, [6]) -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 - -AC_CONFIG_HEADERS([config.h]) - -AC_GNU_SOURCE - -CFLAGS="$CFLAGS -DSU_DEBUG=0 $DEBUG_CFLAGS" -### 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 -AM_PROG_CC_C_O - -SAC_ENABLE_NDEBUG -SAC_ENABLE_EXPENSIVE_CHECKS - -dnl Add parameters for aclocal -AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") - -AC_ARG_WITH(doxygen, -[ --with-doxygen[[=CMD]] use doxygen command CMD [[doxygen]]],[ -case $enable_doxygen in -yes ) doxygen=doxygen ;; -no ) doxygen=echo ;; -esac], doxygen=doxygen) - -AC_CHECK_PROG([DOXYGEN], [doxygen], [$doxygen], [echo]) -AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN != echo]) - -AC_DEFUN([AX_COMPILER_VENDOR], -[ -AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, - [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown - # note: don't check for gcc first since some other compilers define __GNUC__ - for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do - vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ -#if !($vencpp) - thisisanerror; -#endif -])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) - done - ]) -]) - -AX_COMPILER_VENDOR - -# Enable 64 bit build -AC_ARG_ENABLE(64, -[AC_HELP_STRING([--enable-64],[build with 64 bit support])],[enable_64="$enable_64"],[enable_64="no"]) - -if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then - if test "${enable_64}" = "yes"; then - SOFIA_CFLAGS="$SOFIA_CFLAGS -m64" - LDFLAGS="-m64 -Wl,-64" - export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig - fi -fi - -SOFIA_PLAT_CFLAGS= -# openbsd seems to not define NULL as a void pointer, I blame standards by committee for this. -# This is a dirty hack, but shuts up all the warnings -case "$host" in - *-openbsd*) SOFIA_PLAT_CFLAGS="-DNULL='(void *) 0L'";; - *) ;; -esac - -AC_SUBST(SOFIA_PLAT_CFLAGS, $SOFIA_PLAT_CFLAGS) - - -### checks for header files -### ----------------------- -AC_HEADER_STDC - -### checks for declarations -### ----------------------- - -### checks for types -### ---------------- - -AC_TYPE_SIGNAL -AC_TYPE_LONGLONG - -dnl -dnl Define HAVE_C99_FORMAT to 1 if the formatted IO functions (printf/scanf -dnl et.al.) support the C99 'size specifiers', namely ll, hh, j, z, t -dnl (representing long long int, char, intmax_t, size_t, ptrdiff_t). Some C -dnl compilers supported these specifiers prior to C99 as an extension. -dnl -AC_CACHE_CHECK([whether IO functions support C99 size specifiers], -[ac_cv_c_c99_format],[ - -ac_cv_c_c99_format=yes - -AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], -[[char buf[64]; - if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) - exit(1); - else if (strcmp(buf, "12345")) - exit(2);]])], - [ac_cv_c_c99_format=yes], - [ac_cv_c_c99_format=no], - [ac_cv_c_c99_format=yes]) -]) - -if test $ac_cv_c_c99_format = yes; then - AC_DEFINE([HAVE_C99_FORMAT], [1], [Define to 1 if printf supports C99 size specifiers])dnl - - AC_DEFINE([LLU], ["%llu"], [Format (%llu) for unsigned long long])dnl - AC_DEFINE([LLI], ["%lli"], [Format (%lli) for long long])dnl - AC_DEFINE([LLX], ["%llx"], [Format (%llx) for long long hex])dnl - AC_DEFINE([MOD_ZD], ["%zd"], [Define printf() modifier for ssize_t])dnl - AC_DEFINE([MOD_ZU], ["%zu"], [Define printf() modifier for size_t])dnl - -else - -AC_CACHE_CHECK([whether IO functions support size specifier for long long], -[ac_cv_c_ll_format],[ - -ac_cv_c_ll_format=yes - -AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], -[[char buf[64]; - if (sprintf(buf, "%lld", (long long int)1) != 1) - exit(1); - else if (strcmp(buf, "1")) - exit(2);]])], - [ac_cv_c_ll_format=yes], - [ac_cv_c_ll_format=no], - [ac_cv_c_ll_format=yes]) -]) - -if test $ac_cv_c_ll_format = yes; then - AC_DEFINE([LLU], ["%llu"], [Format (%llu) for unsigned long long])dnl - AC_DEFINE([LLI], ["%lli"], [Format (%lli) for long long])dnl - AC_DEFINE([LLX], ["%llx"], [Format (%llx) for long long hex])dnl -else - AC_MSG_ERROR("printf cannot handle 64-bit integers") -fi - -AC_CACHE_CHECK([whether IO functions support size specifier for size_t], -[ac_cv_c_z_format],[ - -ac_cv_c_z_format=yes - -AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], -[[char buf[64]; - if (sprintf(buf, "%zd", (size_t)1) != 1) - exit(1); - else if (strcmp(buf, "1")) - exit(2);]])], - [ac_cv_c_z_format=yes], - [ac_cv_c_z_format=no], - [ac_cv_c_z_format=yes]) -]) - -if test $ac_cv_c_z_format = yes; then - AC_DEFINE([MOD_ZD], ["%ld"], [Define printf() modifier for ssize_t])dnl - AC_DEFINE([MOD_ZU], ["%lu"], [Define printf() modifier for size_t])dnl -else - dnl Cross fingers - AC_MSG_WARN("printf cannot handle size_t, using long instead") - AC_DEFINE([MOD_ZD], ["%ld"], [Define printf() modifier for ssize_t])dnl - AC_DEFINE([MOD_ZU], ["%lu"], [Define printf() modifier for size_t])dnl -fi - -fi - -### checks for structures -### --------------------- - -### checks for typedefs, structures, and compiler characteristics. -### -------------------------------------------------------------- -AC_C_CONST -AC_C_INLINE -AC_C_INLINE_DEFINE -AC_C_BIGENDIAN(AC_DEFINE([SWITCH_BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([SWITCH_BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian])) - -AC_C_VAR_FUNC -AC_C_MACRO_FUNCTION -AC_C_KEYWORD_STRUCT - -AC_HEADER_TIME -AC_TYPE_SIZE_T - -AC_SYS_SA_LEN - - - -### checks for library functions -### ---------------------------- - -### checks for system services -### -------------------------- - -AC_DEV_URANDOM - -### checks for libraries -### -------------------- - -SAC_SOFIA_SU -SAC_OPENSSL -SAC_TPORT - -dnl Check is used for testing -PKG_CHECK_MODULES(CHECK, check >= 0.9.4, have_check="yes", have_check="no") -AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes") -if test x"$have_check" = "xyes"; then - AC_DEFINE([HAVE_CHECK], 1, [Define to 1 if check library is available]) -fi -AC_CHECK_HEADERS([fnmatch.h]) - -AC_CHECK_LIB(pthread, pthread_setschedparam, [AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM, 1, [Define if you have pthread_setschedparam()])]) -AC_CHECK_LIB(z, compress, [have_zlib=yes],[have_zlib=no]) -if test x"$have_zlib" = "xyes"; then - AC_DEFINE(HAVE_ZLIB_COMPRESS, 1, [Define if you have zlib compress]) -fi -AM_CONDITIONAL([HAVE_ZLIB], [test "x$have_zlib" = xyes]) - -dnl dl is currently used only in testing -AC_CHECK_LIB([dl], [dlopen], [ - dnl Note: -ldl is not added to LIBS - AC_DEFINE([HAVE_LIBDL], 1, [Define to 1 if dl library is available]) -]) - -### 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 -AM_CONDITIONAL([HAVE_STUN], [test "x$enable_stun" = xyes]) - -AC_ARG_ENABLE(nth, -[ --disable-nth disable HTTP-related modules nth and http (enabled)], - , enable_nth=yes) -AM_CONDITIONAL([HAVE_NTH], [test "x$enable_nth" = xyes]) -if test x$enable_nth = xyes ; then - AC_DEFINE([HAVE_SOFIA_NTH], 1, [Define to 1 if we use NTH library]) - AC_DEFINE([HAVE_SOFIA_HTTP], 1, [Define to 1 if we use HTTP parser 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]) - - -AC_ARG_ENABLE(memleak_log, -[ --enable-memleak-log enable logging of possible memory leaks [[disabled]]], - , enable_memleak_log=no) - -if test x$enable_memleak_log = xyes ; then - AC_DEFINE([HAVE_MEMLEAK_LOG], 1, [Define to 1 for memory-leak-related logging]) -fi - -### 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/bnf/Doxyfile -libsofia-sip-ua/docs/Makefile -libsofia-sip-ua/docs/Doxyfile -libsofia-sip-ua/docs/Doxyfile.version -libsofia-sip-ua/docs/sofia-footer.html -libsofia-sip-ua/features/Doxyfile -libsofia-sip-ua/features/Makefile -libsofia-sip-ua/http/Doxyfile -libsofia-sip-ua/http/Makefile -libsofia-sip-ua/ipt/Doxyfile -libsofia-sip-ua/ipt/Makefile -libsofia-sip-ua/iptsec/Doxyfile -libsofia-sip-ua/iptsec/Makefile -libsofia-sip-ua/msg/Doxyfile -libsofia-sip-ua/msg/Makefile -libsofia-sip-ua/nea/Doxyfile -libsofia-sip-ua/nea/Makefile -libsofia-sip-ua/nta/Doxyfile -libsofia-sip-ua/nta/Makefile -libsofia-sip-ua/nth/Doxyfile -libsofia-sip-ua/nth/Makefile -libsofia-sip-ua/nua/Doxyfile -libsofia-sip-ua/nua/Makefile -libsofia-sip-ua/sdp/Doxyfile -libsofia-sip-ua/sdp/Makefile -libsofia-sip-ua/sip/Doxyfile -libsofia-sip-ua/sip/Makefile -libsofia-sip-ua/soa/Doxyfile -libsofia-sip-ua/soa/Makefile -libsofia-sip-ua/sresolv/Doxyfile -libsofia-sip-ua/sresolv/Makefile -libsofia-sip-ua/stun/Doxyfile -libsofia-sip-ua/stun/Makefile -libsofia-sip-ua/su/Doxyfile -libsofia-sip-ua/su/Makefile -libsofia-sip-ua/tport/Doxyfile -libsofia-sip-ua/tport/Makefile -libsofia-sip-ua/url/Doxyfile -libsofia-sip-ua/url/Makefile -libsofia-sip-ua/features/sofia-sip/sofia_features.h -s2check/Makefile -libsofia-sip-ua-glib/Makefile -libsofia-sip-ua-glib/su-glib/Makefile -libsofia-sip-ua-glib/su-glib/Doxyfile -utils/Makefile -utils/Doxyfile -tests/Makefile -win32/Makefile -win32/config.h -open_c/Makefile -open_c/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 diff --git a/libs/sofia-sip/configure.gnu b/libs/sofia-sip/configure.gnu deleted file mode 100755 index 4b64a47b7b..0000000000 --- a/libs/sofia-sip/configure.gnu +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh -srcpath=$(dirname $0 2>/dev/null ) || srcpath="." -$srcpath/configure "$@" --with-pic --with-glib=no --disable-shared --without-doxygen --disable-stun - diff --git a/libs/sofia-sip/docs/build_system.txt b/libs/sofia-sip/docs/build_system.txt deleted file mode 100644 index 6e746a146b..0000000000 --- a/libs/sofia-sip/docs/build_system.txt +++ /dev/null @@ -1,105 +0,0 @@ -============================= -Sofia-SIP build system README -============================= - -:Author: Kai Vehmanen -:Author: Pekka Pessi -: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) - -Makefile fragments ------------------- - -Some common makefile rules are in 'rules' subdirectory. - -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 to -execture. 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. - -On hosts with i386 architecture, it is possible to run tests under -valgrind. Use the make target 'valcheck' for that purpose. - -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/ diff --git a/libs/sofia-sip/docs/devel_platform_notes.txt b/libs/sofia-sip/docs/devel_platform_notes.txt deleted file mode 100644 index c24366dd78..0000000000 --- a/libs/sofia-sip/docs/devel_platform_notes.txt +++ /dev/null @@ -1,58 +0,0 @@ -====================================================== -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. - -Notes to distributors ----------------------- - -Build options such as "--disable-stun" (HAVE_SOFIA_STUN) and -"--disable-nth" (HAVE_SOFIA_NTH) modify the public library API/ABI, -by omitting certain interfaces from the resulting library and installed -header files. - -Options such as '--disable-size-compat' modify the library -ABI by changing the types used in public library function -signatures. - -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 README file -for more information. - -The configure script accepts various options. See "./configure --help" -for the full list. - - -Mac OS X --------- - -TBD - -Win32 / Mingw -------------- - -TBD - -Win32 / Cygwin --------------- - -TBD - -Visual-C on win32 ------------------ - -See sofia-sip/win32/README.txt - - LocalWords: automake diff --git a/libs/sofia-sip/docs/release_management.txt b/libs/sofia-sip/docs/release_management.txt deleted file mode 100644 index 333d948172..0000000000 --- a/libs/sofia-sip/docs/release_management.txt +++ /dev/null @@ -1,136 +0,0 @@ -=================================== -Sofia-SIP release management README -=================================== - -:Author: Kai Vehmanen -: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" (make sure depcomp et - al libtool scripts are correctly created) -- 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 - -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 rsync: - rsync -avP -e ssh sofia-sip-x.y.z.tar.gz USER@frs.sourceforge.net:uploads/ -- 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@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.Zdevel" (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. diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog b/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog deleted file mode 100644 index 73c802609c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/ChangeLog +++ /dev/null @@ -1,25 +0,0 @@ -2006-12-05 Kai Vehmanen - - * 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 - - * libsofia-sip-ua-glib interface v2 frozen, version to 2:0:2 (for 1.12.4 release). - -2006-07-25 Kai Vehmanen - - * libsofia-sip-ua-glib interface v1 frozen, version to 1:0:1 (for 1.12.2 release). - -2006-06-16 Kai Vehmanen - - * libsofia-sip-ua-glib interface v0 frozen, version to 0:0:0. - -2006-04-12 Kai Vehmanen - - * Modified build system to require glib-2.4 or newer to compile libsofia-sip-ua-glib. - -2006-03-09 Kai Vehmanen - - * libsofia-sip-ua-glib created. diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am b/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am deleted file mode 100644 index d491475a45..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -# -# Makefile.am for sofia-sip/libsofia-sip-ua-glib -# -# Copyright (C) 2006 Nokia Corporation -# Contact: Pekka Pessi -# 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 - -doxygen: built-sources - @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 - ${top_srcdir}/scripts/hide_emails.sh docs/html - -PHONY = doxygen - -include $(top_srcdir)/rules/recursive.am - -if HAVE_LCOV -include $(top_srcdir)/rules/lcov.am -endif - -include $(top_srcdir)/rules/silent.am - -.PHONY = $(PHONY) - -CLEANFILES = docs/*.doxytags - -distclean-local: - -rm -rf docs/html diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases b/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases deleted file mode 100644 index f47ab084eb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.aliases +++ /dev/null @@ -1 +0,0 @@ -@INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.aliases diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf b/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf deleted file mode 100644 index 67f58f8a03..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.conf +++ /dev/null @@ -1,18 +0,0 @@ -@INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.conf -@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version b/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version deleted file mode 100644 index 1a8ed1fe1b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/docs/Doxyfile.version +++ /dev/null @@ -1,2 +0,0 @@ -@INCLUDE = ../../libsofia-sip-ua/docs/Doxyfile.version - diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile.in deleted file mode 100644 index b0afbb73f2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Doxyfile.in +++ /dev/null @@ -1,12 +0,0 @@ -PROJECT_NAME = "sofia-sip/su-glib" - -OUTPUT_DIRECTORY = ../docs/html/su-glib - -INPUT = @srcdir@/su_glib.docs @srcdir@ . @srcdir@/sofia-sip - -@INCLUDE_PATH = @srcdir@ . -@INCLUDE = ../docs/Doxyfile.conf - -GENERATE_TAGFILE = ../docs/su_glib.doxytags - -ALIASES += diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am deleted file mode 100644 index 6f54d34128..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -# -# Makefile.am for su-glib module -# -# Copyright (C) 2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. -# - -# ---------------------------------------------------------------------- -# Headers - -S_BASE = $(top_srcdir)/libsofia-sip-ua -B_BASE = $(top_builddir)/libsofia-sip-ua - -AM_CPPFLAGS = -I$(S_BASE)/su -I$(B_BASE)/su $(GLIB_CFLAGS) \ - $(SOFIA_GLIB_CFLAGS) - -# ---------------------------------------------------------------------- -# Build targets - -noinst_LTLIBRARIES = libsu-glib.la - -check_PROGRAMS = su_source_test torture_su_glib_timer - -# ---------------------------------------------------------------------- -# Tests - -TESTS = su_source_test torture_su_glib_timer - -# ---------------------------------------------------------------------- -# 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 $(top_srcdir)/rules/sofia.am diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h deleted file mode 100644 index 4f7dfea7b1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_glib.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - */ - -#ifndef SU_WAIT_H -#include -#endif -#ifndef __GLIB_H__ -#include -#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 *); -SOFIAPUBFUN void su_glib_prefer_gsource(void); - -SOFIA_END_DECLS - -#endif /* !defined SU_GLIB_SOURCE_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h deleted file mode 100644 index 5d8fde163c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/sofia-sip/su_source.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Thu Mar 4 19:58:50 2004 ppessi - * - */ - -#ifndef SU_WAIT_H -#include -#endif -#ifndef __GLIB_H__ -#include -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs deleted file mode 100644 index 2a1878042f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_glib.docs +++ /dev/null @@ -1,59 +0,0 @@ -/** - -@mainpage Sofia-SIP su-glib Module - -@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. - -@CONTACT Pekka Pessi - -@STATUS Core library - -@LICENSE LGPL - -@section su_glib_contents Contents of su-glib Module - -The su-glib module contains the public header files as follows: -- the public API of the module -- deprecated API (1.12.1 and earlier) - -@section su_glib_examples Examples of use - -Below is a simple example of how to use su-glib: -@code - #include - #include - - /* ... */ - - 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); -@endcode - -@section su_glib_todo Todo - -- see sourceforge.net issue tracker for sofia-sip - (-> http://sofia-sip.sourceforge.net/development.html ) - -*/ diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c deleted file mode 100644 index 4237ead3f5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005-2009 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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. - * - * Refs: - * - http://sofia-sip.sourceforge.net/refdocs/su/group__su__wait.html - * - http://developer.gnome.org/doc/API/glib/glib-the-main-event-loop.html - * - * @author Pekka Pessi . - * - * @date Created: Thu Mar 4 15:15:15 2004 ppessi - * - */ - -#include "config.h" - -#ifdef SYMBIAN -#include -#endif - -#ifndef __GLIB_H__ -#include -#endif - -#if HAVE_OPEN_C -#include -#include -#endif - -#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" - -#include -#include -#include -#include -#include - -#if 1 -#define PORT_LOCK_DEBUG(x) ((void)0) -#else -#define PORT_LOCK_DEBUG(x) printf x -#endif - -static su_port_t *su_source_port_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 -GSourceFuncs su_source_funcs[1] = {{ - su_source_prepare, - su_source_check, - su_source_dispatch, - su_source_finalize, - NULL, - NULL - }}; - -static int su_source_port_init(su_port_t *self, su_port_vtable_t const *vtable); -static void su_source_port_deinit(su_port_t *self); - -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_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_thread(su_port_t *self, enum su_port_thread_op op); -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 int su_source_multishot(su_port_t *self, int multishot); -static int su_source_wakeup(su_port_t *self); -static int su_source_is_running(su_port_t const *self); - -static char const *su_source_name(su_port_t const *self); - -static -su_port_vtable_t const su_source_port_vtable[1] = - {{ - /* su_vtable_size: */ sizeof su_source_port_vtable, - su_source_lock, - su_source_unlock, - - su_source_incref, - su_source_decref, - - su_source_gsource, - - su_base_port_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_thread, - su_source_add_prepoll, - su_source_remove_prepoll, - su_base_port_timers, - su_source_multishot, - /*su_source_wait_events*/ NULL, - su_base_port_getmsgs, - su_base_port_getmsgs_from, - su_source_name, - su_base_port_start_shared, - su_base_port_wait, - NULL, - su_base_port_deferrable, - su_base_port_max_defer, - su_source_wakeup, - su_source_is_running, - }}; - -static char const *su_source_name(su_port_t const *self) -{ - return "GSource"; -} - -/** - * Port is a per-thread reactor. - * - * Multiple root objects executed by single thread share a su_port_t object. - */ -struct su_source_s { - su_base_port_t sup_base[1]; - - GThread *sup_tid; - GStaticMutex sup_obtained[1]; - - GStaticMutex sup_mutex[1]; - - GSource *sup_source; /**< Backpointer to source */ - GMainLoop *sup_main_loop; /**< Reference to mainloop while running */ - - /* 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; -}; - -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)) - -#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) - -#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_port_create()); -} - -/** Deprecated */ -su_root_t *su_root_source_create(su_root_magic_t *magic) -{ - return su_glib_root_create(magic); -} - -/** - * Returns a GSource object for the root - * - * Note that you need to unref the GSource with g_source_unref() - * before destroying the root object. - * - * @return NULL on error (for instance if root was not created with - * su_glib_root_create()) - */ -GSource *su_glib_root_gsource(su_root_t *root) -{ - g_assert(root); - return su_root_gsource(root); -} - -/*=============== Private function definitions ===============*/ - -/** Initialize source port */ -static int su_source_port_init(su_port_t *self, - su_port_vtable_t const *vtable) -{ - GSource *gs = (GSource *)((char *)self - offsetof(SuSource, ss_port)); - - self->sup_source = gs; - - g_static_mutex_init(self->sup_obtained); - - g_static_mutex_init(self->sup_mutex); - - return su_base_port_init(self, vtable); -} - - -static void su_source_port_deinit(su_port_t *self) -{ - su_base_port_deinit(self); - - g_static_mutex_free(self->sup_mutex); - g_static_mutex_free(self->sup_obtained); - - if (self->sup_indices) - free (self->sup_indices), self->sup_indices = 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; - - su_home_deinit(self->sup_base->sup_home); -} - - -/** @internal Destroy a port. */ -static -void su_source_finalize(GSource *gs) -{ - SuSource *ss = (SuSource *)gs; - assert(gs); - SU_DEBUG_9(("su_source_finalize() called\n")); - su_source_port_deinit(ss->ss_port); -} - -/** @internal Send a message to the port. */ -int su_source_wakeup(su_port_t *self) -{ - GMainContext *gmc = g_source_get_context(self->sup_source); - - if (gmc) - g_main_context_wakeup(gmc); - - return 0; -} - -/** @internal - * - * Change or query ownership of the port object. - * - * @param self pointer to a port object - * @param op operation - * - * @ERRORS - * @ERROR EALREADY port already has an owner (or has no owner) - */ -static int su_source_thread(su_port_t *self, enum su_port_thread_op op) -{ - GThread *me = g_thread_self(); - - switch (op) { - - case su_port_thread_op_is_obtained: - if (self->sup_tid == me) - return 2; - else if (self->sup_tid) - return 1; - else - return 0; - - case su_port_thread_op_release: - if (self->sup_tid != me) - return errno = EALREADY, -1; - self->sup_tid = NULL; - g_static_mutex_unlock(self->sup_obtained); - return 0; - - case su_port_thread_op_obtain: - if (su_home_threadsafe(su_port_home(self)) == -1) - return -1; - g_static_mutex_lock(self->sup_obtained); - self->sup_tid = me; - return 0; - - default: - return errno = ENOSYS, -1; - } -} - -/* -- Registering and unregistering ------------------------------------- */ - -/* Seconds from 1.1.1900 to 1.1.1970 */ -#define NTP_EPOCH 2208988800UL - -/** Prepare to wait - calculate time to next timer */ -static -gboolean su_source_prepare(GSource *gs, gint *return_tout) -{ - SuSource *ss = (SuSource *)gs; - su_port_t *self = ss->ss_port; - su_duration_t tout = SU_WAIT_FOREVER; - - enter; - - if (self->sup_base->sup_head) { - *return_tout = 0; - return TRUE; - } - - if (self->sup_base->sup_timers || self->sup_base->sup_deferrable) { - su_time_t now; - GTimeVal gtimeval; - - 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_base->sup_timers, now); - - if (self->sup_base->sup_deferrable) { - su_duration_t tout_defer; - - tout_defer = su_timer_next_expires(&self->sup_base->sup_deferrable, now); - - if (tout_defer < self->sup_base->sup_max_defer) - tout_defer = self->sup_base->sup_max_defer; - - if (tout > tout_defer) - tout = tout_defer; - } - } - - *return_tout = (tout >= 0 && tout <= (su_duration_t)G_MAXINT)? - (gint)tout : -1; - - return (tout == 0); -} - -static -gboolean su_source_check(GSource *gs) -{ - SuSource *ss = (SuSource *)gs; - su_port_t *self = ss->ss_port; - gint tout; -#if SU_HAVE_POLL - unsigned i, I; -#endif - - enter; - -#if SU_HAVE_POLL - I = self->sup_n_waits; - - 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_base->sup_head) - su_base_port_getmsgs(self); - - if (self->sup_base->sup_timers || self->sup_base->sup_deferrable) { - 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; - - su_timer_expire(&self->sup_base->sup_timers, &tout, now); - su_timer_expire(&self->sup_base->sup_deferrable, &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) -{ - PORT_LOCK_DEBUG(("%p at %s locking(%p)...", - (void *)g_thread_self(), who, self)); - g_static_mutex_lock(self->sup_mutex); - - PORT_LOCK_DEBUG((" ...%p at %s locked(%p)...", - (void *)g_thread_self(), who, self)); -} - -static void su_source_unlock(su_port_t *self, char const *who) -{ - g_static_mutex_unlock(self->sup_mutex); - - PORT_LOCK_DEBUG((" ...%p at %s unlocked(%p)\n", - (void *)g_thread_self(), who, self)); -} - -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 - * - * 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 - * - * 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. - */ -static -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 Run the main loop. - * - * The main loop runs until su_source_break() is called from a callback. - * - * @param self pointer to port object - * */ -static -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); - } -} - -static int su_source_is_running(su_port_t const *self) -{ - return self->sup_main_loop && g_main_loop_is_running(self->sup_main_loop); -} - -/** @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 - * - */ -static -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)) { - GPollFD *fds = NULL; - gint fds_size = 0; - gint fds_wait; - gint priority = G_MAXINT; - gint src_tout = -1; - - g_main_context_prepare(gmc, &priority); - - fds_wait = g_main_context_query(gmc, priority, &src_tout, NULL, 0); - while (fds_wait > fds_size) { - fds = g_alloca(fds_wait * sizeof(fds[0])); - fds_size = fds_wait; - fds_wait = g_main_context_query(gmc, priority, &src_tout, fds, fds_size); - } - - if (src_tout >= 0 && tout > (su_duration_t)src_tout) - tout = src_tout; - - su_wait((su_wait_t *)fds, fds_wait, tout); - - g_main_context_check(gmc, priority, fds, fds_wait); - - g_main_context_dispatch(gmc); - - g_main_context_release(gmc); - } - - return 0; -} - -static int su_source_add_prepoll(su_port_t *port, - su_root_t *root, - su_prepoll_f *prepoll, - su_prepoll_magic_t *magic) -{ - /* We could call prepoll in su_source_prepare()?? */ - return -1; -} - -static int su_source_remove_prepoll(su_port_t *port, - su_root_t *root) -{ - return -1; -} - -#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 - -/**@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. - */ -static su_port_t *su_source_port_create(void) -{ - SuSource *ss; - su_port_t *self = NULL; - - SU_DEBUG_9(("su_source_port_create() called\n")); - - ss = (SuSource *)g_source_new(su_source_funcs, (sizeof *ss)); - - if (ss) { - self = ss->ss_port; - if (su_source_port_init(self, su_source_port_vtable) < 0) - g_source_unref(ss->ss_source), self = NULL; - } else { - su_perror("su_source_port_create(): g_source_new"); - } - - SU_DEBUG_1(("su_source_port_create() returns %p\n", (void *)self)); - - return self; -} - -/* No su_source_port_start */ - -/** Use su_source implementation when su_root_create() is called. - * - * @NEW_1_12_5 - */ -void su_glib_prefer_gsource(void) -{ - su_port_prefer(su_source_port_create, NULL); -} diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c deleted file mode 100644 index e8bda63081..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/su_source_test.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005-2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Mar 18 19:40:51 1999 pessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -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 -#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"); - } -} - -#if HAVE_SIGNAL -static -RETSIGTYPE term(int n) -{ - exit(1); -} -#endif - -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]; - -#if HAVE_OPEN_C - dup2(1, 2); -#endif - - 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); - } - } - -#if HAVE_OPEN_C - opt_verbatim = 1; - opt_singlethread = 1; - su_log_soft_set_level(su_log_default, 9); -#endif - -#if HAVE_SIGNAL - signal(SIGTERM, term); -#endif - - 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 HAVE_SIGNAL - if (sleeppid) - kill(sleeppid, SIGTERM); -#endif -#endif - -#if HAVE_OPEN_C - sleep(7); -#endif - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/torture_su_glib_timer.c b/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/torture_su_glib_timer.c deleted file mode 100644 index 2d431addfb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua-glib/su-glib/torture_su_glib_timer.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005,2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -/** - * @brief Test program for su-glib timers - * - * Based on torture_su_timer.c of libsofia-sip-ua. - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @internal - * - * @date Created: Fri Oct 19 08:53:55 2001 pessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -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" - -#include - -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; - - printf("timer interval %f\n", 1000 * su_time_diff(now, prev)); - - if (!ti->t_run) - su_timer_set(t, print_stamp, ti); - - 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) -{ - printf("ending test\n"); - 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; - GSource *source; - - 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_glib_root_create(tester); - - source = su_root_gsource(tester->root); - g_source_attach(source, NULL /*g_main_context_default ()*/); - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/ChangeLog deleted file mode 100644 index bde1819aaf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ChangeLog +++ /dev/null @@ -1,427 +0,0 @@ -2007-04-25 Kai Vehmanen - - * libsofia-sip-ua interface v4 frozen (5:0:5) for the 1.12.6 release - -2007-02-09 Kai Vehmanen - - * libsofia-sip-ua interface v4 frozen (4:0:4) for the 1.12.5 release - -2006-10-12 Kai Vehmanen - - * libsofia-sip-ua interface v3 frozen (3:0:3) for the 1.12.3 release - -2006-09-26 Kai Vehmanen - - * libsofia-sip-ua interface v2 frozen (2:0:2) for the 1.12.2 release - -2006-08-30 Pekka Pessi - - * nua: added tag nutag_refer_with_id. - -2006-08-28 Kai Vehmanen - - * libsofia-sip-ua interface v2 opened to development, version to 2:0:2. - -2006-08-25 Pekka Pessi - - * Added urltag_scan(). - -2006-08-23 Pekka Pessi - - * 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 - - * libsofia-sip-ua interface v1 frozen (1.12.1), version to 1:0:1. - -2006-06-16 Kai Vehmanen - - * libsofia-sip-ua interface v0 frozen (1.12.0), version to 0:0:0. - -2005-11-28 Kai Vehmanen - - * /Doxyfile: Fixed the use of doxytags. Now - a separate 'doxytags_MODNAME' file is created for each - module. - -2005-11-15 Kai Vehmanen - - * /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 - - * 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 - - * Shell syntax exercise. - - M ./autogen.sh -4 +4 - -2005-10-13 Pekka Pessi - - * /Makefile.am: fixed COVERAGE_INPUT. - -2005-10-13 Kai Vehmanen - - * /Makefile.am: Build all submodules as proper shared - libraries (noinst_LTLIBRARIES). Fixes sf.net:#1264030. - -2005-09-09 Pekka Pessi - - * darcs changes --from-tag pessi-darcs-1: - - Thu Sep 8 21:50:24 EEST 2005 Pekka.Pessi@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@nokia.com - * Logging. - - M ./nua/nua_stack.c -4 +2 - - Thu Sep 8 21:36:39 EEST 2005 Pekka.Pessi@nokia.com - * Added tests for tport_convert_addr. - - M ./tport/tport_test.c +22 - - Thu Sep 8 21:36:27 EEST 2005 Pekka.Pessi@nokia.com - * Fixed receiving empty SigComp message. - - M ./tport/tport.c +7 - - Thu Sep 8 21:32:48 EEST 2005 Pekka.Pessi@nokia.com - * Updated ChangeLogs. - - M ./nta/ChangeLog -2 +10 - - Thu Sep 8 21:32:37 EEST 2005 Pekka.Pessi@nokia.com - * Updated ChangeLog. - - M ./iptsec/ChangeLog +11 - - Thu Sep 8 21:31:16 EEST 2005 Pekka.Pessi@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@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@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@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@nokia.com - * Log when password file is read. - - M ./iptsec/auth_module.c +3 - - Thu Sep 8 21:12:49 EEST 2005 Pekka.Pessi@nokia.com - * Allow empty allow list. - - M ./iptsec/auth_module.c -1 +1 - - Thu Sep 8 21:12:26 EEST 2005 Pekka.Pessi@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@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@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@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@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@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@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@nokia.com - * Removed SIP_DLL_VAR. - - M ./sip/sip_dll.h -7 - - Thu Sep 8 18:29:27 EEST 2005 Pekka.Pessi@nokia.com - * Avoid __func__. - - M ./sresolv/sresolv.c -3 +4 - - Thu Sep 8 18:29:09 EEST 2005 Pekka.Pessi@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@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@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@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@nokia.com - * Compile without sresolv, too. - - M ./nta/nta.c -3 +5 - - Thu Sep 8 18:12:16 EEST 2005 Pekka.Pessi@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@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@nokia.com - * Silenced vc6 warning. - - M ./iptsec/auth_module.c -1 +1 - - Thu Sep 8 18:05:07 EEST 2005 Pekka.Pessi@nokia.com - * Not using __func__. - - M ./iptsec/auth_digest.c -2 +2 - - Thu Sep 8 18:04:38 EEST 2005 Pekka.Pessi@nokia.com - * Silenced gcc4 warning. - - M ./tport/tport.c -1 +1 - - Thu Sep 8 18:04:16 EEST 2005 Pekka.Pessi@nokia.com - * Better following autoconf macros - - M ./tport/tport.c +9 - - Thu Sep 8 18:02:53 EEST 2005 Pekka.Pessi@nokia.com - * Using TPORT_DLL. - - M ./tport/tport.h -10 +19 - - Thu Sep 8 18:01:58 EEST 2005 Pekka.Pessi@nokia.com - * Not using IS_EXCLUDED_MASK. - - M ./url/url.c -1 +6 - - Thu Sep 8 18:01:17 EEST 2005 Pekka.Pessi@nokia.com - * Explicitly using - - 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@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@nokia.com - * Not using su_home_deinit(). - - M ./nua/nua.c -3 +2 - - Thu Sep 8 16:40:30 EEST 2005 Pekka.Pessi@nokia.com - * Adding soa_asynch.c - - A ./soa/soa_asynch.c - - Thu Sep 8 03:23:00 EEST 2005 Pekka.Pessi@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@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@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@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@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@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 - - * Makefile.am: Workaround for automake bug related to adding - custom targets to RECURSIVE_TARGETS. - -2005-08-25 Kai Vehmanen - - * Makefile.am: soa depends on ipt and sip, so has to - be after them in SUBDIRS. - -2005-08-17 Pekka Pessi - - * Fixed BEGIN()/END() pairs in test programs. - -2005-08-04 Pekka Pessi - - * Added soa module. - -2005-07-18 Kai Vehmanen - - * libsofia-sip-ua created. diff --git a/libs/sofia-sip/libsofia-sip-ua/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/Makefile.am deleted file mode 100644 index d2855be4bf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/Makefile.am +++ /dev/null @@ -1,116 +0,0 @@ -# -# Makefile.am for sofia-sip/libsofia-sip-ua -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. -# -# ref: http://www.gnu.org/software/automake/manual/automake.html - -AUTOMAKE_OPTIONS = foreign - -# select which optional sofia-sip modules have been enabled -# in the build -OPT_LIBADD = -OPT_SUBDIRS_STUN = -OPT_SUBDIRS_HTTP = -OPT_SUBDIRS_NTH = -if HAVE_STUN -OPT_LIBADD += stun/libstun.la -OPT_SUBDIRS_STUN += stun -endif -if HAVE_NTH -OPT_LIBADD += http/libhttp.la nth/libnth.la -OPT_SUBDIRS_HTTP += http -OPT_SUBDIRS_NTH += nth -endif - -# note: order does matter in the subdir list -SUBDIRS = su features bnf sresolv ipt sdp url msg sip $(OPT_SUBDIRS_HTTP) \ - $(OPT_SUBDIRS_STUN) soa tport nta $(OPT_SUBDIRS_NTH) \ - nea iptsec nua -DIST_SUBDIRS = su features bnf sresolv ipt sdp url msg sip http \ - stun soa tport nta nth \ - nea iptsec nua docs - -DOXYGEN = doxygen - -noinst_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 \ - nua/libnua.la \ - sdp/libsdp.la \ - sip/libsip.la \ - soa/libsoa.la \ - sresolv/libsresolv.la \ - su/libsu.la \ - tport/libtport.la \ - url/liburl.la \ - $(OPT_LIBADD) - -# 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 HAVE_ZLIB -libsofia_sip_ua_la_LDFLAGS += -lz -endif - -PHONY = doxygen built-sources - -include $(top_srcdir)/rules/recursive.am - -checklib: checklib-recursive $(lib_LTLIBRARIES) - -doxygen: built-sources - @echo Generating empty doxytags - mkdir -p docs/html ; \ - for d in $(DIST_SUBDIRS); do \ - test -r $$d/Doxyfile || continue ; \ - if ! test -r docs/$$d.doxytags ; then \ - echo '' > docs/$$d.doxytags ; \ - else \ - sed '2,10s!index!'$$d'_index!' \ - docs/$$d.doxytags > docs/$$d.doxytags.tmp && \ - mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \ - fi ; \ - done - for d in $(DIST_SUBDIRS); do \ - ( test -r $$d/Doxyfile && \ - cd $$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|explicit link.*could not be resolved)' ; \ - test -r docs/$$d.doxytags && \ - sed '2,10s!index!'$$d'_index!' \ - docs/$$d.doxytags > docs/$$d.doxytags.tmp && \ - mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \ - done - for d in $(DIST_SUBDIRS); do \ - ( test -r $$d/Doxyfile && \ - cd $$d > /dev/null \ - echo running ${DOXYGEN} second time in $$d && \ - ${DOXYGEN} 2>&1 ) | \ - egrep -v -i -e 'Warning: Unsupported (xml/)?html tag' ; \ - test -r docs/$$d.doxytags && \ - sed '2,10s!index!'$$d'_index!' \ - docs/$$d.doxytags > docs/$$d.doxytags.tmp && \ - mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \ - done - ${top_srcdir}/scripts/hide_emails.sh docs/html - -if HAVE_LCOV -include $(top_srcdir)/rules/lcov.am -endif - -include $(top_srcdir)/rules/silent.am - -.PHONY: $(PHONY) diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog deleted file mode 100644 index 7504442a31..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/ChangeLog +++ /dev/null @@ -1,7 +0,0 @@ -2006-06-15 Kai Vehmanen - - * sofia-sip/hostdomain.h (host_is_local): Function added. - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile.in deleted file mode 100644 index bca76a1aaa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/Doxyfile.in +++ /dev/null @@ -1,15 +0,0 @@ -PROJECT_NAME = "bnf" -OUTPUT_DIRECTORY = ../docs/html/bnf - -INPUT = @srcdir@/bnf.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf - -TAGFILES += ../docs/su.doxytags=../su - -GENERATE_TAGFILE = ../docs/bnf.doxytags - -PREDEFINED += "static=" - -MAX_INITIALIZER_LINES = 2 diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am deleted file mode 100644 index 01f87d9451..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -# -# Makefile.am for bnf module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 ../su/libsu.la - -torture_bnf_LDFLAGS = -static - -# ---------------------------------------------------------------------- -# Install and distribution rules - -EXTRA_DIST = bnf.docs - -# ---------------------------------------------------------------------- -# Tests - -TESTS = torture_bnf - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c b/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c deleted file mode 100644 index 07a503dcd3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.c +++ /dev/null @@ -1,922 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005,2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Thu Jun 8 19:28:55 2000 ppessi - */ - -#include "config.h" - -#include "sofia-sip/bnf.h" -#include "sofia-sip/su_string.h" - -#include -#include - -#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{|}~ */ -}; - -#if 0 /* This escaped lab */ - -#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; -} -#endif - -/** Return length of decimal-octet */ -su_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; - - if (src == NULL) - return -1; - - 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 */ -su_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 */ -su_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. - */ -su_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 + 1 < 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 */ -su_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. */ -su_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 - -/** 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") */ && - su_casenmatch(host, "localhost", 9) && - (n == 9 || - ((n == 10 || /* localhost. */ - n == 21 || /* strlen("localhost.localdomain") */ - n == 22) && /* strlen("localhost.localdomain.") */ - su_casenmatch(host + 9, ".localdomain.", n - 9))); -} - -/** 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 su_casenmatch(string, invalid + 1, 7); - else - return su_casenmatch(string + n - 8, invalid, 8); - } - - return 0; -} - -#include - -static size_t convert_ip_address(char const *s, - uint8_t addr[16], - size_t *return_addrlen) -{ - size_t len; - int canonize = 0; - char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; - -#if SU_HAVE_IN6 - - 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' && su_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 -#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' && su_inet_pton(AF_INET, s, addr) == 1) - return (void)(*return_addrlen = 4), len; - } - - 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; - int retval; - - if (a == NULL || b == NULL) { - retval = (a != NULL) - (b != NULL); - } - else { - alen = convert_ip_address(a, a6, &asize); - blen = convert_ip_address(b, b6, &bsize); - - if (alen > 0 && blen > 0) { - if (asize < bsize) - retval = -1; - else if (asize > bsize) - retval = 1; - else - retval = memcmp(a6, b6, asize); - } - else { - retval = su_strcasecmp(a, b); - } - } - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs b/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs deleted file mode 100644 index bbd1536bb6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/bnf.docs +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- 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 - * . - * - * The interface used for validating hostnames and IP addresses is in - * . - * - * @CONTACT Pekka Pessi - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h b/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h deleted file mode 100644 index f048b9bff4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/bnf.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define BNF_H - -/**@file sofia-sip/bnf.h - * - * Parsing macros and prototypes for HTTP-like protocols. - * - * @author Pekka Pessi - * - * @date Created: Tue Jun 06 10:59:34 2000 ppessi - * - */ - -#include - -#include - -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 */ -/* CR conflicts with Windows SDK 10, so it is now _CR */ -#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 - */ -su_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. */ -su_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; -} - -/** Calculate span of a token characters. */ -su_inline isize_t span_token(char const *s) -{ - char const *e = s; - while (_bnf_table[(unsigned char)(*e)] & bnf_token) - e++; - return e - s; -} - -/** Calculate span of a alphabetic characters. */ -su_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. */ -su_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. */ -su_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 */ -su_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. */ -su_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. */ -su_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. */ -su_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) */ -su_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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h b/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h deleted file mode 100644 index fe9fe95cb0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/sofia-sip/hostdomain.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Thu Mar 9 16:15:22 EET 2006 ppessi - */ - -#ifndef SU_CONFIG_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c b/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c deleted file mode 100644 index 005455dede..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/bnf/torture_bnf.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Aug 21 15:18:26 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "sofia-sip/bnf.h" - -static int test_flags = 0; -#define TSTFLAGS test_flags - -#include - -char const name[] = "torture_bnf"; - -static 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; -} - -static 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(); -} - -static 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 - -static 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); - - TEST(host_is_domain("127.0.0.1"), 0); - TEST(host_is_domain("3.com"), 1); - TEST(host_is_domain("127.0.0.com"), 1); - TEST(host_is_domain("actra.0.1"), 0); - - /* Invalid IP4 address (extra leading zeros) */ - TEST_1(!host_cmp("127.0.0.1", "127.0.0.01")); - /* 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")); -#if SU_HAVE_IN6 - TEST_1(!host_cmp("[ffff:ffff:ffff:ffff:ffff:ffff: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]")); -#endif - TEST_1(host_cmp("::", "0.0.0.0")); - TEST_1(host_cmp("::1", "0.0.0.1")); - - END(); -} - -static void usage(int exitcode) -{ - fprintf(stderr, "usage: %s [-v] [-a]\n", name); - exit(exitcode); -} - -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 if (strcmp(argv[i], "-a") == 0) - test_flags |= tst_abort; - else - usage(1); - } - - retval |= bnf_test(); fflush(stdout); - retval |= ip_test(); fflush(stdout); - retval |= host_test(); fflush(stdout); - - return retval; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog deleted file mode 100644 index 6c841fe7f3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/ChangeLog +++ /dev/null @@ -1,20 +0,0 @@ -2005-10-27 Pekka Pessi - - * 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 - - * Fixed aliases for Doxygen 1.4. - - M ./libsofia-sip-ua/docs/Doxyfile.aliases -6 +6 - -2005-09-08 Kai Vehmanen - - * hide_emails.sh: Fixed bug in hiding addresses of - form foo.bar-bar@something.org. Fixed sf.net - bug #1277167. - - - diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases b/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases deleted file mode 100644 index a8ef6c9235..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.aliases +++ /dev/null @@ -1,66 +0,0 @@ -# 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=Sofia SIP" \ - "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=\internal \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 1.12.2" \ - "VERSION_1_12_2=1.12.2" \ - "NEW_1_12_4=@since New in 1.12.4" \ - "VERSION_1_12_4=1.12.4" \ - "VERSION_1_12_5=1.12.5" \ - "NEW_1_12_5=@since New in 1.12.5" \ - "EXP_1_12_5=@since Experimental in 1.12.5, available if --enable-experimental configuration option is given" \ - "VERSION_1_12_6=1.12.6" \ - "NEW_1_12_6=@since New in 1.12.6" \ - "EXP_1_12_6=@since Experimental in 1.12.6, available if --enable-experimental configuration option is given" \ - "VERSION_1_12_7=1.12.7" \ - "NEW_1_12_7=@since New in 1.12.7" \ - "EXP_1_12_7=@since Experimental in 1.12.7, available if --enable-experimental configuration option is given" \ - "VERSION_1_12_8=1.12.8" \ - "NEW_1_12_8=@since New in 1.12.8" \ - "VERSION_1_12_9=1.12.9" \ - "NEW_1_12_9=@since New in 1.12.9" \ - "VERSION_1_12_10=1.12.10" \ - "NEW_1_12_10=@since New in 1.12.10" \ - "VERSION_1_12_11=1.12.11" \ - "NEW_1_12_11=@since New in 1.12.11" \ - "VERSION_UNRELEASED=UNRELEASED" \ - "NEW_UNRELEASED=@since Not yet released" \ - - diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf b/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf deleted file mode 100644 index bc4a242394..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.conf +++ /dev/null @@ -1,65 +0,0 @@ -# Doxyfile 1.0.0 format -# - -@INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.version" -@INCLUDE = "../../libsofia-sip-ua/docs/Doxyfile.aliases" -@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 -VERBATIM_HEADERS = YES -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.in deleted file mode 100644 index 225c02a785..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.in +++ /dev/null @@ -1,34 +0,0 @@ -PROJECT_NAME = "libsofia-sip-ua" -OUTPUT_DIRECTORY = ../docs/html - -INPUT = @srcdir@/mainpage.docs @srcdir@/docguide.docs @srcdir@/conformance.docs - -# release.docs - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf -@INCLUDE = ../sip/sip.doxyaliases - -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 = @srcdir@/../sip diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in b/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in deleted file mode 100644 index 2fc743cfdf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/Doxyfile.version.in +++ /dev/null @@ -1,3 +0,0 @@ -PROJECT_NUMBER = @VERSION@ - -IMAGE_PATH = @top_srcdir@/libsofia-sip-ua/docs/pictures diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am deleted file mode 100644 index 1fced80046..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -EXTRA_DIST = Doxyfile.aliases Doxyfile.conf \ - docguide.docs \ - mainpage.docs \ - conformance.docs \ - 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: Makefile.am - $(AWK) 'END { b="\\"; q="\\\""; \ - print "# Autogenerated aliases for RFCs "from" .. "to ; \ - print "ALIASES += " b; \ - for (i=from; i < to; i++) { \ - print "RFC"i"=\"RFC "i"\" "b; \ - }}' \ - site=http://www.faqs.org/rfcs/rfc type=.html \ - from=700 to=5500 \ - /dev/null > $@ - -CLEANFILES = Doxyfile.rfc *.doxytags - -distclean-local: - -rm -rf html - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs b/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs deleted file mode 100644 index 0dd8beb11e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/conformance.docs +++ /dev/null @@ -1,1289 +0,0 @@ -/* -*- html -*- */ -/** - -@page sofia_sip_conformance SIP and SDP Protocol Features in Sofia-SIP - -This document describes how Sofia-SIP stack supports specifications listed -below. - - - - -
-RFC 3261
-RFC 2617
-RFC 3262
-RFC 3263
-RFC 3265
-RFC 2806
-RFC 2976
-RFC 3311
-RFC 3313
-RFC 3323
-RFC 3326
-RFC 3325
-RFC 3327
-
-RFC 3329
-RFC 3361
-RFC 3420
-RFC 3428
-RFC 3486
-RFC 3515
-RFC 3581
-RFC 3608
-RFC 3680
-RFC 3824
-RFC 3840
-RFC 3841
-RFC 3842
-
-RFC 3856
-RFC 3857
-RFC 3858
-RFC 3859
-RFC 3860
-RFC 3891
-RFC 3892
-RFC 3903
-RFC 4028
-RFC 4168
-RFC 4320
-RFC 4488
-RFC 5057
-
-RFC 4566
-RFC 2327
-RFC 3264
-RFC 3266
-RFC 3312
-RFC 3388
-RFC 3407
-RFC 3524
-RFC 3551
-RFC 3556
-RFC 3605
-RFC 3890
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureSupported - Notes -
- @RFC3261: Basic SIP Protocol - - 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: - -# message syntax and encoding - -# transport - -# transaction - -# transaction user (UAS and UAC cores, proxy core) - -# SIP elements: user agent - client and server, proxies, - registrars - -   -
- @RFC3261 Sections 19 and 20:
- Syntax and encoding - -
- The supported @RFC3261 methods are: @b REGISTER, @b OPTIONS, @b - INVITE, @b ACK, @b CANCEL, @b BYE, as well as extension methods - INFO, - PRACK, - SUBSCRIBE, - NOTIFY, - UPDATE, - MESSAGE, - REFER, - and - PUBLISH. - - 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_alert_info "Alert-Info" (extension in @VERSION_1_12_7), - @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_p_asserted_identity "P-Asserted-Identity" - (extension in @VERSION_1_12_7), - @ref sip_p_preferred_identity "P-Preferred-Identity" - (extension in @VERSION_1_12_7), - @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_refer_sub "Refer-Sub" (@VERSION_1_12_5), - @ref sip_remote_party_id "Remote-Party-ID" (extension in @VERSION_1_12_7), - @ref sip_reply_to "Reply-To" (extension in @VERSION_1_12_7), - @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. - - - Automatic escaping of reserved characters has not been - implemented. - - Using NUL (zero byte) in double-quoted strings has not been implemented -
- @RFC3261 Section 18:
- UDP and TCP transports -
- 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. - - There is experimental support for SCTP, too. -
- @RFC3261 Section 17:
Transactions -
- 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 - values for T1, T1x64, T2 and T4 can be changed via - configuration tags defined in . - - The SIP timer C is implemented from @VERSION_1_12_7. Also, its value - can be changed via configuration tag NTATAG_TIMER_C() defined in - . - -   -
- @RFC3261 Section 26:
Security -
- TLS and SIPS URIs has been implemented. Currently, TLS does not - require certificate from client nor it does check it if one is - provided. - - Missing: - - Authorizing connections with TLS certificates - - S/MIME -
- @RFC2617: HTTP Digest Authentication - - Sofia-SIP includes 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. - - Missing: - - Using nextnonce - - Mutual authentication -
- @RFC3262: PRACK and 100rel - - 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". - -   -
- @RFC3263: Locating SIP Servers - - Support for SIP server address resolution from SIP or SIPS URI using - NAPTR, SRV, A or AAAA records in DNS as defined in @RFC3263. - - - Resolving any other types of URIs than SIP or SIPS URIs, e.g., IM: - or PRES: URIs. -
- @RFC3265: SIP Event Notifications - - 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. - - Application must take care of: - - Subscribing, generating or processing specific event types - and interpreting the content of event data is up to application -
- @RFC2806: tel URI - - Sofia-SIP supports handling of any URI type. Sofia-SIP parses tel: - URIs. - - Missing: - - Resolving the tel: URIs -
- @RFC2976: INFO - - INFO method is supported within a dialog natively. - - Not implemented: - - Generating or processing contents of INFO requests -
- @RFC3311: UPDATE - - 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. - - Application must take care of: - - Initiating UPDATE requests -
- @RFC3313: Media Authentication - - Sofia-SIP provides generic support for - extension headers and parameters. P-Media-Authorization header is - supported as an @ref sip_unknown "extension header". - - Application must take care of: - - Passing the authorization token to QoS reservation request -
- @RFC3323: Privacy - - @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 @endcode. - - 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. -
- @RFC3326: Reason - - Sofia-SIP supports @ref sip_reason "Reason" header (generating, - parsing and syntax checking). - - Application must take care of: - - Generating or processing Reason headers -
- @RFC3325: Asserted Identity - - Sofia-SIP supports - @ref sip_p_asserted_identity "P-Asserted-Identity" and - @ref sip_p_preferred_identity "P-Preferred-Identity" headers - (generating, parsing and syntax checking). Also the non-standard - header @ref sip_remote_party_id "Remote-Party-ID" is supported. - - @NEW_1_12_7. - - Not implemented: - - id privacy - - Recognizing trust domains and enforcing handling of headers - based on those -
- @RFC3327: Path - - 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). - -   -
- @RFC3329: - Security Agreement - - 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". - - Correct @e d-ver value is not calculated. -
- @RFC3361: DHCPv4 option for locating SIP servers. - - Sofia-SIP supports outbound proxy. - - Application must take care of: - - passing outbound proxy name or address from DHCP client - to Sofia-SIP stack. -
- @RFC3420: message/sipfrag - - Sofia-SIP passes the received SIP message headers to application - which can create a message/sipfrag payload. - - Application must take care of: - - processing the SIP message fragments -
- @RFC3428: MESSAGE - - MESSAGE method is supported natively. - -   -
- @RFC3486: Compressing SIP - - 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. - - SigComp itself is not supported. -
- @RFC3515: REFER - - 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 - RFC 3891 and - RFC 3892. - -   -
- @RFC3608: Service-Route - - 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". - -   -
- @RFC3680: "reg" event - - Sofia-SIP supports generic SIP event support 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. - - Application must take care of: - - Generating subscriptions for "reg" event - - Processing notifications for "reg" event - - Handling of XML document in notifications -
- @RFC3824: ENUM - - 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. - - Stack can not resolve E.164 number to address of next - hop. A proxy in the network must resolve E.164 numbers with ENUM. -
- @RFC3840: Callee Capabilities - - 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. - - Application must take care of: - - Processing the feature parameters received in the Contact header -
- @RFC3841: Caller Preferences - - 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"), - - Application must take care of: - - UAS processing incoming Accept-Contact or Reject-Contact headers -
- @RFC3842: Message waiting event - - Sofia-SIP supports generic SIP event support 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. - - 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 -
- @RFC3856: Presence
- @RFC3859: Common Profile for Presence -
- Sofia-SIP supports generic SIP event support 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. - - 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 -
- @RFC3857: "winfo" event template package
- @RFC3858: winfo format -
- Sofia-SIP supports generic SIP event support 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. - - 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 watcherinfo XML documents -
- @RFC3860: Common Profile for IM - - Sofia-SIP supports handling of any URI type. Sofia-SIP parses "im:" - URIs. - - Application must take care of: - - resolving the "im:" URI -
- @RFC3891: Replaces - - @ref sip_replaces "Replaces" header is explicitly supported - (generating, parsing and syntax checking). - - Application must take care of: - - generating @ref sip_replaces "Replaces" header from a dialog and - matching a dialog with a Replaces header received -
- @RFC3892: Referred-By - - @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. - - 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 -
- @RFC3903: PUBLISH - - 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 user-agent engine keep published - data refreshed until nua_unpublish() is called. - - Application must take care of: - - Including correct @ref sip_event "Event" in the request - - Permanently storing @SIPETag -
- @RFC4028: Session Timers - - The SIP session-timer ("timer") extension is supported. - - The session-expires value and refreshing party is negotiated in - user-agent engine. 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". - -   -
- @RFC4168: SCTP as Transport for SIP - - The transport=sctp URI parameter is supported. The SCTP transport - protocol is supported as experimental. It is enabled with - configure script argument --enable-sctp. - - The framing of SIP messages over SCTP is not specified clearly in - @RFC4168. It is possible to send SIP messages smaller than 64K over - SCTP. - -   -
- @RFC4320: Actions Addressing Identified Issues with SIP's Non-INVITE Transaction - - The action 1 (make the best use of provisional responses) is - supported when NTATAG_EXTRA_100(1) is used with nua_create() or - nta_agent_create(). The 100 Trying provisional response is sent - after T2 is expired or when a retransmission is received after T2/2 - after the initial request. - - The action 2 (remove the useless late-response storm) is supported - by default. The 408 timeout response is not forwarded by default (it's - forwarding can be enabled with NTATAG_PASS_408(1), however). - - Application must include NTATAG_EXTRA_100(1) with nua_create() or - nta_agent_create() tags. -
- @RFC4488: Suppression of REFER Implicit Subscription - - Sofia-SIP supports @ref sip_refer_sub "Refer-Sub" header - (generating, parsing and syntax checking). - - The implicit subscription is suppressed by @nua, if the @ReferSub: - true header is included in the REFER - request (@ref nua_refer "on server side") or - response (@ref nua_i_refer "on client side"). - - @NEW_1_12_5 - - The REFER client application must include SIPTAG_REFER_SUB_STR("true") - in the nua_refer() tags. -
- @RFC5057: Multiple Dialog Usages in SIP - - Sofia-SIP provides function sip_response_terminates_dialog() that - can be used to determine the effect of error response with dialog. - - The nua UA engine uses sip_response_terminates_dialog(). - - The client application must either use NUA or - sip_response_terminates_dialog(). -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureSupported - Notes -
- @RFC4566: SDP: Session Description Protocol - - 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 partially implements @RFC4566. Note that - definition of 'token' was updated in @RFC4566 and the parser has not - been updated yet. - - @RFC4566 obsoletes - - @RFC2327: SDP (Session Description Protocol) - - @RFC3266: IP6 in SDP -
- @RFC3264: SDP Offer/Answer Negotiation - - Generating and processing offers or answers. - - - "a=fmtp" parameters are not taken into account - when generating or processing answer -
- @RFC3312: Preconditions - - Sofia-SIP provides generic support 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. - - Application must take care of: - - Semantics and handling of preconditions - - Reservation of resources -
- @RFC3388: Grouping of Media Lines - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - @RFC3388 defines mid, group, LS and FID are predefined strings to be - used within attribute line - - Application must take care of: - - Generating or processing the attribute lines - - Grouping the media for transport accordingly -
- @RFC3407: Capability Declaration - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - Application must take care of: - - Defining sqn, cdsc, cpar etc. strings needed in a= line - - Generating or processing the attribute lines - - Capability negotiation itself -
- @RFC3524: SRF - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - Application must take care of: - - Defining SRF string needed in a= line - - Generating or processing the attribute lines -
- @RFC3551: RTP/AVP - - Sofia-SIP recognizes the RTP payload types for well-known audio and - video codecs defined in @RFC3551. - - Application must take care of: - - Audio or video processing - - Generating a=rtpmap or a=fmtp lines when needed -
- @RFC3556: Bandwidth - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - Application must take care of: - - Generating or processing RS and RR bandwidth modifiers - - Semantics of bandwidth allocation -
- @RFC3605: RTCP attribute - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - Application must take care of: - - Discovering port numbers - - Generating or processing the RTCP attribute lines -
- @RFC3890: TIAS - - Sofia-SIP provides generic support for attribute - lines that conform to SDP syntax. - - Application must take care of: - - Generating or processing TIAS bandwidth modifiers - - Generating or processing the maxprate attribute lines -
- - -*/ - -/* Overflow: - - - - - @RFC4566: SDP: Session Description Protocol - - - Obsoletes RFC2327 and RFC3266. - - -   - - - - - - - - @RFC3320: SigComp - - - Support for using SigComp for compression and - decompression of SIP/SDP messages. By default, dynamic - compression is used. - - Decompression using UDVM - - -   - - - - - - - @RFC3321: SigComp Extended operations - - - Support for SigComp extended operations. - - - - Explicit Acknowledgment Scheme - - Shared Compression - - Checkpoint State - - Implicit Deletion for Dictionary Update - - - - - - - @RFC3325: Asserted Identity - - - Explicit support (generating, parsing and syntax checking) for the - following SIP headers: P-Asserted-Identity, P-Preferred-Identity - - - - Recognizing trust domains and enforcing handling of headers - based on those - - - - - - - @RFC3485: SIP/SDP Dictionary - - - Support for SigComp static compression using SIP/SDP - dictionary. - - -   - - - - - - - - Implicitly registered user identities - - - - - @RFC3959: early-session - - - Early-session value can be used within Content-Disposition, - Supported and Require headers. - - - - Generating of Content-Disposition, Supported and Require - - Handling of multipart bodies with early and session SDP - - - -*/ \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs b/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs deleted file mode 100644 index 2b01c66aef..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/docguide.docs +++ /dev/null @@ -1,249 +0,0 @@ -/*! - -@page docguide Documentation Guidelines - -@section doxygen Using Doxygen - -Doxygen is a document generation program, used by many C/C++ projects. Its -home page is at http://www.doxygen.org. -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 -@ref doxycommands "special commands". - -In general the the style of the comments and documentation should follow the - -javadoc style guide. - -A Doxygen comment must either contain reference about the entity -it is describing, e.g., command -\@file when describing files: -@verbatim -/** - * @file foo.c - * - * Implementation of foo. The foo takes care of grokking xyzzy. - * - * @author Jaska Jokunen \n - * - * @date Created: Wed Oct 20 15:06:51 EEST 2004 jasjoku - */ -@endverbatim - -Usually the entity that is documented comes straight after the documentation -comment. For example, documenting a function happens like this: -@anchor orch -@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) -{ - ... -} -@endverbatim - -@subsection doxyfile Doxyfile and Doxyfile.conf - -The doxygen options are specified through a configuration file, -Doxyfile. 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: - -@code -PROJECT_NAME = "ipt" -OUTPUT_DIRECTORY = ../docs/ipt - -INPUT = ipt.docs . - -@INCLUDE = ../Doxyfile.conf - -TAGFILES += ../docs/docs/doxytags=../docs -TAGFILES += ../docs/su/doxytags=../su -GENERATE_TAGFILE = ../docs/ipt/doxytags -@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. - -@subsection module_docs Module documentation in \.docs - -Each module contains a documentation file containing at least the module -mainpage called @e \.docs. There should be the module -boilerplate information, for instance the following example is excerpt -contents of file @e ipt.docs: - -@verbatim -/** -@MODULEPAGE "ipt" - Utility Module - -@section ipt_meta Module Meta Information - -Utility library for IP Telephony applications. - -@CONTACT Pekka Pessi - -@STATUS @SofiaSIP Core library - -@LICENSE LGPL - -@section ipt_overview Overview - -This module contain some routines useful for IPT applications, like -- ... -- ... -*/ -@endverbatim - -@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)" - -@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 -@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. -@endcode - -The style commands have synonyms, e.g., @@em and @@e mean same, as -well as @@c and @@p. - -@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. - -@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) -{ - ... -} -@endverbatim - -@subsection doxyexamples Example Blocks - @code, @endcode - -An example code fragment can be included using @@code and @@endcode -commands. -@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) -{ -@endverbatim - -@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. - -@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. - -@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. - -@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. - -@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. - -@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: -@code -@image html sip-parser.gif - -@image latex sip-parser.eps -@endcode - -*/ diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs b/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs deleted file mode 100644 index d00ecc381e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/docs/mainpage.docs +++ /dev/null @@ -1,741 +0,0 @@ -/* -*- text -*- */ - -/**@mainpage Sofia SIP User Agent Library - sofia-sip-ua - -@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:
-nua -su -features -soa -sdp -nta -tport -sresolv -sip -msg -url -stun -iptsec -nea -nth -http -bnf -ipt - -@section who Contact Information - -You can download latest Sofia SIP from the project -home page at -Sourceforge.net. - -Please contact us if you have questions regarding this software: - -
    -
  • Pekka Pessi
  • -
  • Kai Vehmanen
  • -
- -Or post to the Sofia-SIP mailing list: - -
    -
  • mailto:sofia-sip-devel@lists.sourceforge.net
  • -
  • http://lists.sourceforge.net/lists/listinfo/sofia-sip-devel
  • -
- -*/ - -/**@page building Source Tree Structure - -@section subdirs Directory Structure - -In libsofia-sip-ua, there are subdirectories for different modules listed -below. - -Terminal and high-level libraries used for both signaling and media: - -Common runtime library: - - "su" - sockets, memory management, threads - - "sresolv" - Asynchronous DNS resolver - - "ipt" - IPT utility library - -SIP Signaling: - - "nua" - SIP User Agent library - - "nea" - SIP Event API - - "iptsec" - - Digest authentication for HTTP and SIP - - "nta" - SIP transaction engine - - "tport" - Message transport - - "sip" - SIP messages and headers - - "msg" - Message handling - - "url" - URL handling - - "url" - low level parsing - -HTTP subsystem: - - "nth" - HTTP protocol engine - - "http" - HTTP messages and headers - -SDP processing: - - "soa" - SDP Offer/Answer engine for SIP - - "sdp" - SDP parser - -Other: - - "stun" - STUN library - -Features provided by Sofia-SIP library: - - "features" - Features provided by Sofia SIP - -Documentation: - - "docs" - Doxygen reference documentation - -*/ - -/** -@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. - -@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. - -@code -typedef struct foo_s foo_t; -typedef int f_fun(foo_t *f, char const *s); -@endcode - -Struct and union members should have common prefix. For instance, -@code -struct foo_s { - int f_len; - char *f_name; - fun_f *f_fun; -}; -@endcode - -This prefix makes it easier to find where members are used. - -@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, - -@code -void kluge(int foo) -{ - if (foo) { - bar(); - } - else { - switch (baz()) { - case a: - eeny(); - break; - case b: - meeny(); - break; - default: - moe(); - break; - } - } -} -@endcode - -The default indentation can be achieved with GNU indent with options -@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 -@endcode - -Loops without condition use @c for @c (;;) instead of @c while @c (1). - -@code - for (;;) { - foo(); - if (bar()) - break; - baz(); - } -@endcode - -There should be whitespace on both sides of infix operators, except -. or ->, which require no space, or -, (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., - -@code - while (i++ < n) - baz(); - for (;;) { - x->x_foo(); - if (bar()) - break; - z.z_baz++; - } - return (13 * i); -@endcode - - */ - -/** -@page programming Programming Guide - -@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. - -@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) - -@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 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: - -@code -#if HAVE_STDINT_H -#include -#elif HAVE_INTTYPES_H -#include -#else -#error Define HAVE_STDINT_H as 1 if you have , \ - or HAVE_INTTYPES_H if you have -#endif -@endcode - -@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 or to use these functions. - -@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. - -@code -struct foo { - unsigned bar:5; - unsigned foo:2; - unsigned :0; - int something; -} -@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 -@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. - -@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 \.docs -(where the \ 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 \.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. - - -@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. - -@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 , 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 -. The @b msg implementation is also free to change the -internal layout of the structure, only keeping the function interface -unmodified. - -@subsection oo_interface Interfaces - -Abstract interface is another object-oriented practice used in Sofia. Parser -headers, defined in , 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. - -@dontinclude sip_basic.c -@skipline msg_hclass_t sip_contact_class -@skip {{ -@until }}; - -@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 . - -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: - -@code -struct derived -{ - struct base base[1]; - int extra; - char *data; -}; -@endcode - -There are three alternatives to cast a pointer to derived to a pointer to -base: -@code -struct base *base1 = (struct base *)derived; -struct base *base2 = &derived->base; -struct base *base3 = derived->base; -@endcode -The third alternative works because base was used as a 1-element array. - -@subsection oo_templates Templates - -There are a few template types implemented as macros in Sofia libraries. -They include hash table, defined in , which can be used -to define hash tables types and accessor functions for different object, and -red-black tree, defined in . - -@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 and @ref su_alloc "memory managment tutorial" -for more information of memory management services. - -@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. - -@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); - -@endcode - -@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. - -@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; - } -@endcode - -@section testing Testing Your Code - -See 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. - -@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): - -@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 -@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", -@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. - -@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 - -developer.gnome.org. Autobook -provides more detailed documentation for autoconf and automake. -The GNU make manual -is also a good source of information. - -@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 -darcs version control system. - -@code -$ sh autogen.sh -$ ./configure ... with your configure options ... -@endcode - -@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. - -@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. - -@subsection aclocal_m4 aclocal.m4 - -The aclocal.m4 contains the definitions of the autoconf macros used in -@b configure.ac. - -This file is generated by aclocal command. - -@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. - -@subsection configure configure - -When you run configure script, it performs all the checks defined in -@b configure.ac and then replaces all @b xxx.in files with equivalent -@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. - -@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. - -@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. - -@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. - -@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. - -@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. - -*/ - -/** -@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 (nua) debug level (0..9) -- #SOA_DEBUG SDP Offer/Answer engine (soa) debug level (0..9) -- #NEA_DEBUG Event engine (nea) 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 su 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(). - -*/ diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.eps deleted file mode 100644 index 14e9b042db64d29cfa9a7adde2d14827992bad8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 251693 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 z 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 XNQ0+)j>z(+dIUTI9s!Slj==u|HT%7G diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.gif deleted file mode 100644 index 71ebe18d0edc77cb9a8dfba421f65e067b3fd431..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3069 zcmaKrX*d*I8^>>NWoeg4lX*gx8B88cA`+ftt3jA#CyW-mL<=TSL`cM-RMu=0gX}45 zn#z*3Mxhx>$d)zdot_WR^?Z1*_rC5A|LdG{opb$v_y6b_=&Bxcoa6zXc>shE{9XSR z|LA|V{=LH0+@b=|02lyF01o#aZey`XO$}LCAU{787l-I{#AFf$!Eh%yh=V^4q7@-S z1*#51hc1kg0FeQ?Num%PM5Cam;ixGWv6w_jFjN8uE$}ynXgkR8fT}>~h=S1+K)HZQ zCD98V#H65}a5S8YCYVGb=;?ut4S0D$SQyY~P*4CbUqW{`jE!;KaT|}2DMFVKN=Jw( zNdzTB&~gA{f3S-Nj|>Q`f~XEi8HHQ~rAYDx(qSS>4+7l&2aC?Ap{o`s#t)^(p)xvZWg-^*UqF(m zR0qAFAZ9q~$wk9VGyz;dBoa_4K&Aes!(afD2^|DcS0RO+^PzAu^y4|q@ z5eP^}2U%MqZ*LSHj?&UlX(=}j2m?eJAQ6G01ymByEP+7*rY~@)fTFSJz8cE2K$U)| zB@Xq_5r>J0KqLW)0u(AxX+UEDg9%Iya3B8P2L2wG3{r8{H;$Ho!KVohWGnBz8YUYNvANAW99#%o7dmM9xGGmfir>Bti}K7V12mI5kh`>(QtF@E@JfYiemO_Jz1v# zW(8v;CGAM$A0#W6ubnw&G2L#K?yM4b$L6LFBJu;J`Q)(y)}JbqpX#p1%xd)PofvMp zD{ud{x?*OeE&W)UQBCC>=Ou$EWoKPAKlxcY(5GitZS~^xaIP>v@m-2Fp1vMm2NI5q|)s3&^ZR*4M`1SVN{+CLBG;mg7$c{$eK6rA~z zlH~2w93!B3;}Ffq<+ZW2eRnm@cjVCn?VBPR{f?B5>=W71`AhC&w1O=n%1a&Jk7ee2 zkBFSL^7s7oTzmS!`qTjLVWF@TjoQ>pzP)Ld&-Wg)UYs3yTXe-};J}snhLUE(L3IQwSZux^gjlf^{YBkX?}H!rauzr>pkC!RYqlvT+>`&xY8#HG=W4>(=gcGs#_t zjWYSG@keso%MIQkTkAI+JcO^^ti4h2prC<5`w^iN$J^7lklmDYL~J*1Tos4^@NH8# z^F#b)==vS|+(v&$G=y)HHO)UWCD{~(QStdcI<==IR#Go6RP>=#YlN&>vD?>aX=c(s z*S$6dLRoK8)cmKvf1QzSN!@9|DZ!gRG)d=;IqAH97XLoSG`s9Vf4q46wd1#WN57TI zcSN6j5=S`yQ^Bg>ta7yN*iXX8a>);^B>iW52dXd6-ykoPO7vEpCQlRG7QAfof;Wha zZxGM3YC45g2|CnQ>~teU(0AhdV&+gLO~R?rEpeJ%aEB+@V|>Yv+)H!mEOb{N;?z`l z&P=c_``dl4y(y#^bfSFfOKal1&fArPv!hb?kI_ATsX2b{f99(>@JoH+$14AmNJY=p z1B)}?daf9~Th&Waza*yLoIOz;cuu)cHajI!QeLwFpS8lZjA)Knl> zSmIg+A;8gB^jx{bG5bpk65)}`EfNunnXZlz_*`7FzkKDw<7<5{RGn_gb_DE+IIxtp zJ%(3ORWcg$O;s%9p0I(#sja*f&LmNuR~fgAgAPc=EB@^5IUQG&lyFmDc+SN^h!W8q zA(4DZCi!e`g-nWj<)Tcgck4md4{$$g`&fotQCq?uqg@*RpsUUt8IpPVjv(%}!&)T5^!h4;2+Xjz>3rZVhoN6CB8nsi|<4bS*uwJah(P$|Fr8N1 zW!oyO^!Q!pum?S_Ykw}yM)u`pqbn&X;_fCjQV$!=-!T-kYeu z(e7lnjy?L1V9Ae{6>Z-Sn-&wQW;-es z>$el-^bwFJ5N5oGBM{G=Q6N(z^+uje+aGJucq`Q zyR4jWKT&s*b6YaCjht(Cz1wl|`_htI;T^Ko*uAr+WnT;FM+=?H#*7$`OU8fhKi^Q( z!%3X1UG(wsdbvSm#j8QcB2~I_O|!Z~9rl^J&#S(y>gi0yW--?{DrptI@9cRsX7A|9 zYMkyg)>HNC5}?%hQSER3nrw1)wY>OYtWm>1z<=bv?WbT(m4LxU>DmR)7`+G9?8N4> zOCw=nhcA<}vscZ>=)0A#jBB!Mmr2k0P)9@a$j7U%W^{v3%=KuN1kUq?X|8IHWCt5B vPx_w>E|?kFZG?Wska)I>XRZ&ZT@$qT+IpLZqnOb;K3$U#p(s-=0QLU@Ps9PQ diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_incoming_operation.vsd deleted file mode 100644 index 26e24d4c3dd46c7cf6fa226568ce765d80bc19b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17408 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 J2ow#0{|9@mgB<_> diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.gif deleted file mode 100644 index 4bcad0a96690864be5eec521cdeea1ecf5bf66f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4024 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_basic_outgoing_operation.vsd deleted file mode 100644 index 4d929958a542570e492ac034aaa75fd966ce29f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23040 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 M*8fl6|Ggaef1&lIod5s; diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.eps deleted file mode 100644 index b81415cb552e7e64784aed72fbca2d0d3b744fea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 393648 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 Rft-Pyft-Pyfn_rA{{hMWz2E=< diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.gif deleted file mode 100644 index f6e33f2fba1a9bc4d29ab1f208f3cd2737d50fc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7139 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 J=m-MD{udYmA@cwL diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_incoming_call.vsd deleted file mode 100644 index b9e7d46af469fa40f025b5877f18f04bbd5fe24d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32256 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 aKQY>&$;Qs@Yx~WhA diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.gif deleted file mode 100644 index f0c071d0e2100c8c3a145bdf4b21e52dd93b198d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8545 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_call.vsd deleted file mode 100644 index 3adc690e8be41f02f54b25dce3101a5eaa41d9cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35328 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 HIq?4giw}aa diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.eps deleted file mode 100644 index 00e9bd4bb2cb1e2b7a3b587aab1e334d1e41c374..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306825 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 H0y6&w)<(@w diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/SIP_outgoing_operation_with_auth.vsd deleted file mode 100644 index 036136df76eb787b6a164cac446dc09edeaad585..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26112 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 YDr%`xj6sJi%l(+1!KZ5NyuKu*y?y#n- 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

\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "
\n" - "\n" - "\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 - -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 - -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(void) -{ - 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 ;tag=I8hFdg0H3OK\r\n" - "To:\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 ;tag=I8hFdg0H3OK\r\n" - "To: \r\n" - "Call-ID: 0e3dc2b2-dcc6-1226-26ac-258b5ce429ab\r\n" - "CSeq: 32439044 REGISTER\r\n" - "Contact: \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 - }}; - auth_challenger_t pach[1] = - {{ 407, "Proxy Authorization required", - sip_proxy_authenticate_class, - sip_proxy_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_1(aucs == NULL); - TEST(auc_challenge(&aucs, home, sip->sip_www_authenticate, - sip_authorization_class), 1); - TEST_1(aucs != NULL); - msg_destroy(m1); - - TEST(auc_all_credentials(&aucs, "DIGEST", "\"ims3.so.noklab.net\"", - "surf3.private@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@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@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@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@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 (su_casenmatch(au->au_params[i], "realm=", 6)) - 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@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@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 without realm */ - { - msg_auth_t *au; - - TEST_1(am = auth_mod_create(NULL, - AUTHTAG_METHOD("Digest"), - AUTHTAG_DB(testpasswd), - AUTHTAG_ALGORITHM("MD5-sess"), - AUTHTAG_QOP("auth"), - AUTHTAG_OPAQUE("opaque=="), - TAG_END())); - as->as_realm = NULL; - auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 500); - - as->as_realm = "ims3.so.noklab.net"; - 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(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@ims3.so.noklab.net", - sip->sip_payload), 1); - - TEST_1(sip->sip_authorization); - reinit_as(as); - - as->as_realm = "ims3.so.noklab.net"; - 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; - - 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@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@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@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), - AUTHTAG_MAX_NCOUNT(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@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"); - - TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, - 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@ims3.so.noklab.net", - sip->sip_payload), 1); - TEST_1(sip->sip_authorization); - TEST_S(msg_header_find_param(sip->sip_authorization->au_common, "nc="), - "00000001"); - - reinit_as(as); - auth_mod_check_client(am, as, sip->sip_authorization, ach); - TEST(as->as_status, 0); - - /* Test nonce count check */ - 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@ims3.so.noklab.net", - sip->sip_payload), 1); - TEST_1(sip->sip_authorization); - TEST_S(msg_header_find_param(sip->sip_authorization->au_common, "nc="), - "00000002"); - - 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@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 empty realm */ - TEST_1(am = auth_mod_create(root, - AUTHTAG_METHOD("Digest"), - AUTHTAG_REALM(""), - 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, "Digest", "\"\"", "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@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, pach); TEST(as->as_status, 407); - TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response, - sip_proxy_authorization_class), 1); - reinit_as(as); - - TEST(auc_credentials(&aucs, as->as_home, "Digest:\"\":user1:secret"), 1); - msg_header_remove(m2, (void *)sip, (void *)sip->sip_proxy_authorization); - TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name, - (url_t *)"sip:surf3@ims3.so.noklab.net", - sip->sip_payload), 1); - TEST_1(sip->sip_proxy_authorization); - - auth_mod_check_client(am, as, sip->sip_proxy_authorization, pach); - 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@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@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 client with two challenges */ - au = sip_www_authenticate_make( - NULL, - "Digest realm=\"test-realm\", " - "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " - "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""); - au->au_next = sip_www_authenticate_make( - NULL, - "Not-Digest realm=\"test-realm\", " - "zip=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " - "zap=\"5ccc069c403ebaf9f0171e9517f40e41\""); - - TEST_1(auc_challenge(&aucs, home, (msg_auth_t *)au, - sip_authorization_class) >= 1); - TEST_1(auc_all_credentials(&aucs, "Digest", "\"test-realm\"", - "user", "pass")); - 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@ims3.so.noklab.net", - sip->sip_payload), 1); - TEST_1(sip->sip_authorization); - 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@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(); -} - -int -test_auth_client(void) -{ - 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 ;tag=I8hFdg0H3OK\r\n" - "To:\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=\"[::1]\"\r\n" - "Proxy-Authenticate:DIGEST algorithm=MD5,nonce=\"h7wIpP+atU+/+Zau5UwLMA==\",realm=\"\\\"realm\\\"\"\r\n" - "Content-Length:0\r\n" - "Security-Server:digest\r\n" - "r\n"; - - su_home_t *home; - msg_t *msg; - sip_t *sip; - auth_client_t *aucs = NULL; - - TEST_1(home = su_home_new(sizeof(*home))); - - TEST_1(msg = read_message(MSG_DO_EXTRACT_COPY, challenge)); - TEST_1(sip = sip_object(msg)); - - TEST_1(aucs == NULL); - TEST(auc_challenge(&aucs, home, sip->sip_www_authenticate, - sip_authorization_class), 1); - TEST_1(aucs != NULL); - - TEST(auc_credentials(&aucs, home, "Digest:\"[::1]\":user:pass"), 1); - - TEST(auc_challenge(&aucs, home, sip->sip_proxy_authenticate, - sip_proxy_authorization_class), 1); - - TEST(auc_credentials(&aucs, home, "Digest:\"\\\"realm\\\"\":user:pass"), 1); - - msg_destroy(msg); - su_home_unref(home); - } - - END(); -} - -#if HAVE_FLOCK -#include -#endif - -#include - -char tmppasswd[] = "/tmp/test_auth_digest.XXXXXX"; - -#include - -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(void) -{ - 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 - -extern su_log_t iptsec_log[]; - -static -void usage(int exitcode) -{ - fprintf(stderr, "usage: %s [-v] [-a] [-l n]\n", name); - exit(exitcode); -} - -int main(int argc, char *argv[]) -{ - int retval = 0; - int i; - extern void (*_su_time)(su_time_t *tv); - - _su_time = offset_time; - - argv0 = argv[0]; - - su_init(); - - for (i = 1; argv[i]; i++) { - if (strcmp(argv[i], "-v") == 0) - tstflags |= tst_verbatim; - else if (strcmp(argv[i], "-a") == 0) - tstflags |= tst_abort; - 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(1); - - su_log_set_level(iptsec_log, level); - } else { - usage(1); - } - } - - 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_auth_client(); - retval |= test_module_io(); - - su_deinit(); - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd b/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd deleted file mode 100644 index 5e17744b13..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/testpasswd +++ /dev/null @@ -1,3 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog deleted file mode 100644 index bc43f50111..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/ChangeLog +++ /dev/null @@ -1,53 +0,0 @@ -2006-01-17 Martti Mela - - * msg_mime.c: defines for Mac OS X (which are lacking EBADMSG). - -2005-11-08 Pekka Pessi - - * 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 - - * Fixed msg_home() macro. - - M ./libsofia-sip-ua/msg/msg.h -1 +1 - -2005-10-10 Pekka Pessi - - * Dox fix to msg_header_replace(). - - M ./libsofia-sip-ua/msg/msg_parser.c -2 +3 - -2005-08-15 Kai Vehmanen - - * Makefile.am: Do not include msg_test_class.o in libmsg. - -2005-08-01 Pekka Pessi - - * 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 - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile.in deleted file mode 100644 index 6d09607001..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/Doxyfile.in +++ /dev/null @@ -1,20 +0,0 @@ -PROJECT_NAME = "msg" -OUTPUT_DIRECTORY = ../docs/html/msg - -INPUT = @srcdir@/msg.docs @srcdir@/sofia-sip sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf -@INCLUDE = ../sip/sip.doxyaliases - -EXCLUDE_PATTERNS += msg_test*.h msg_test*.c - -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 += @srcdir@/../sip/images diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am deleted file mode 100644 index b0e7a84abb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/Makefile.am +++ /dev/null @@ -1,126 +0,0 @@ -# -# Makefile.am for msg module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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) - -GENERATED_HC = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h - -BUILT_SOURCES = $(GENERATED_HC) - -libmsg_la_SOURCES = msg_internal.h \ - msg.c msg_tag.c msg_inlined.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_class.h \ - test_table.c test_inlined.c test_protos.h - -LDADD = libtest_msg.a libmsg.la \ - ../bnf/libbnf.la \ - ../url/liburl.la \ - ../ipt/libipt.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 = 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 $(top_srcdir)/rules/sofia.am - -MSG_PARSER_AWK = $(srcdir)/msg_parser.awk - -AWK_MSG_AWK = LC_ALL=C $(AWK) -f $(MSG_PARSER_AWK) - -${GENERATED_HC}: ${MSG_PARSER_AWK} Makefile.am - -TEST_CLASS_H = ${srcdir}/test_class.h - -test_protos.h test_table.c: ${TEST_CLASS_H} - -test_protos.h: ${srcdir}/test_protos.h.in - $(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \ - PR=$@ TEMPLATE=${srcdir}/test_protos.h.in ${TEST_CLASS_H} - -test_table.c: ${srcdir}/test_table.c.in - $(AWK_MSG_AWK) module=msg_test prefix=msg \ - MC_HASH_SIZE=127 multipart=msg_multipart \ - PT=$@ TEMPLATE=${srcdir}/test_table.c.in ${TEST_CLASS_H} - -SS_MIME_H = ${srcdir}/sofia-sip/msg_mime.h - -sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h: ${SS_MIME_H} -msg_mime_table.c: ${SS_MIME_H} - -sofia-sip/msg_protos.h: ${srcdir}/sofia-sip/msg_protos.h.in - @-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 \ - ${SS_MIME_H} - -sofia-sip/msg_mime_protos.h: ${srcdir}/sofia-sip/msg_mime_protos.h.in - @-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 \ - ${SS_MIME_H} - -msg_mime_table.c: ${srcdir}/msg_mime_table.c.in - $(AWK_MSG_AWK) module=msg_multipart \ - tprefix=msg prefix=mp MC_HASH_SIZE=127 MC_SHORT_SIZE=26 \ - PT=$@ TEMPLATE=${srcdir}/msg_mime_table.c.in \ - ${SS_MIME_H} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg.c deleted file mode 100644 index 385188835d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file msg.c Message object implementation. - * - * @author Pekka Pessi - * - * @date Created: Thu Jun 8 19:28:55 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include /* XXX */ -#include - -#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 . 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 ). - * - */ -void msg_set_errno(msg_t *msg, int err) -{ - if (msg) - msg->m_errno = err; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs b/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs deleted file mode 100644 index 5ce63d618e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg.docs +++ /dev/null @@ -1,506 +0,0 @@ -/* -*- text -*- */ - -/**@MODULEPAGE "msg" - Message Parser Module - -@section msg_meta Module Meta Information - -This module contains parser and functions for manipulating messages and -headers for text-based protocols like SIP, HTTP or RTSP. It also -provides parsing of MIME headers and MIME multipart messages common to -these protocols. - -@CONTACT Pekka Pessi - -@STATUS @SofiaSIP Core library - -@LICENSE LGPL - -@par Contributor(s): -- Pekka Pessi - -@section msg_contents Contents of msg Module - -The msg module contains the public header files as follows: -- base message interfaces -- message and header struct definitions and typedefs -- prototypes of header-specific functions for generic headers -- function prototypes and macros for manipulating message - headers -- functions for accessing network addresses and I/O vectors - associated with the message -- types and functions for handling dates and times -- types, function prototypes and macros for MIME headers - and @ref msg_multipart "multipart messages" -- 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: -- parsing functions, macros -- message factory object definition -- hashing of header names - -@section msg_overview Parsers, Messages and Headers - -The Sofia @b msg module contains interface to the text-based parsers for -RFC822-like message, the header and message objects. Currently, there -are three parsers defined: SIP, HTTP, and MIME. - -The C structure corresponding to each header is defined either in a - or in a protocol-specific header file. These -protocol-specific header files include , , and -. 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 , there is a typedef suitable for the particular -protocol, for example @b Accept header is defined multiple times: - -@code -typedef struct msg_accept_s sip_accept_t; -typedef struct msg_accept_s http_accept_t; -@endcode - -For header @e X of protocol @e NS, there are types, functions, macros and -header class as follows: - - - @c ns_X_t is the structure used to store parsed header, - - @c ns_hclass_t @c ns_X_class[] contains the @em header @em class - for header X, - - @c NS_X_INIT() initializes a static instance of @c ns_X_t, - - @c ns_X_init() initializes a dynamic instance of @c ns_X_t, - - @c ns_is_X() tests if header object is instance of header X, - - @c ns_X_make() creates a header X object by decoding given string, - - @c ns_X_format() creates a header X object by decoding given - @c printf() list, - - @c ns_X_dup() duplicates (deeply copies) the header X, - - @c ns_X_copy() copies the header X, - - @c NSTAG_X() is used include instance of @c ns_X_t in a tag list, and - - @c NSTAG_X_STR() is used to include string containing value header - in a tag list. - -The declarations of header tags and the prototypes for these functions can -be imported separately from the type definitions, for instance, the tags -related to SIP headers are declared in the include file -, and the header-specific functions in -. - -@section parser_intro Parsing Text Messages - -Sofia text parser follows @em recursive-descent principle. In other words, -it is a program that descends the syntax tree top-down recursively. -(All syntax trees have root at top and they grow downwards.) - -In the case of SIP, HTTP and other similar protocols, such a parser is very -efficient. The parser can choose between different forms based on each -token, as the protocol syntax is carefully designed so that it requires only -minimal scan-ahead. It is also easy to extend a recursive-descent parser via -a standard API, unlike, for instance, a LALR parser generated by @em Bison. - -The abstract message module @b msg contains a high-level parser engine that -drives the parsing process and invokes the protocol-specific parser for each -header. As there is no low-layer framing between the RFC822-style messages, -the parser considers any received data, be it a UDP datagram or a TCP -stream, as a @em byte @em stream. The protocol-specific parsers controls how -a byte stream is split into separate messages or if it consists of a single -message only. - -The parser engine works by separating stream into fragments, then passing -the fragment to a suitable parser. A fragment is a piece of message that is -parsed during a single step: the first line, each header, the empty line -between headers and message body, the message body. (In case of HTTP, the -message body can consists of multiple fragments known as chunks.) - -The parser starts by separating the first line (e.g., request or status -line) from the byte stream, then passing the line to the suitable parser. -After first line comes the message headers. The parser continues parsing -process by extracting headers, each on their own line, from the stream and -passing contents of each header to its parser. The message structure is -populated based on the parsing results. When an empty line - indicating end -of headers - is encountered, the control is passed to the protocol-specific -parser. Protocol-specific functions take care of extracting the possible -message body from the byte stream. - -After parsing process is completed, it can be given to the upper layers -(typically a protocol state machine). The parser continues processing the -stream and feeding the messages to protocol engine until the end of the -stream is reached. - -@image html sip-parser.gif Separating byte stream to messages -@image latex sip-parser.eps Separating byte stream to messages - -When the parsing process has completed, the first line, each header, -separator and the message body are all in their own fragment structure. The -fragments form a dual-linked list known as @e fragment @e chain as shown in -the above figure. The memory buffers for the message, the fragment chain, -and a whole lot of other stuff is held by the generic message type, #msg_t, -defined in . The internal structure of #msg_t is known only within @b -msg module and it is opaque to other modules. - -The @b msg parser engine also drives the reverse process, invoking the -encoding method of each fragment so that the whole outgoing message can be -encoded properly. - -@section msg_header_struct Message Header as a C struct - -Just separating headers from each other and from the message body is not -usually enough. When a header contains structured data, the header contents -should be converted to a form that is convenient to use from C programs. For -that purpose, the message parser needs a parsing function specific to each -individual header. This parsing function divides the contents of the header -into semantically meaningful segments and stores the result in the structure -specific to each header. - -The parser engine passes the fragment contents to the parsing function after -it has separated the fragment from the rest of the message. The parser -engine selects correct @e header @e class either by implication (in case of -first line), or it searches for the header class from the hash table using -the header name as the hash key. The @e header @e class contains a pointer -to the parsing function. The parser has also special header classes for -headers with errors and @e unknown headers, header with a name that is not -regocnized by the parser. - -For instance, the Accept header has following syntax: -@code - Accept = "Accept" ":" #( media-range [ accept-params ] ) - - media-range = ( "*" "/" "*" - | ( type "/" "*" ) - | ( type "/" subtype ) ) *( ";" parameter ) - - accept-params = ";" "q" "=" qvalue *( accept-extension ) - - accept-extension = ";" token [ "=" ( token | quoted-string ) ] -@endcode - -When an Accept header is parsed, the header parser function (msg_accept_d()) -separates the @e type, @e subtype, and each parameter in the list to -strings. The parsing result is assigned to a #msg_accept_t structure, which is -defined as follows: - -@code -typedef struct msg_accept_s -{ - msg_common_t ac_common[1]; //< Common fragment info - msg_accept_t *ac_next; //< Pointer to next Accept header - char const *ac_type; //< Pointer to type/subtype - char const *ac_subtype; //< Points after first slash in type - msg_param_t const *ac_params; //< List of parameters - msg_param_t ac_q; //< Value of q parameter -} -msg_accept_t; -@endcode - -The string containing the @e type is put into the @c ac_type field, the @e -subtype after slash in the can be found in the @c ac_subtype field, and the -list of @e accept-params (together with media-specific-parameters) is put in -the @c ac_params array. If there is a @e q parameter present, a pointer to -the @c qvalue is assigned to @c ac_q field. - -In the beginning of the header structure there are two boilerplate members. -The @c ac_common[1] contains information common to all message fragments. -The @c ac_next is a pointer to next header field with the same name, in case -a message contains multiple @b Accept headers or multiple comma-separated -header fields are located in a single line. - -@section msg_object_example Representing a Message as a C struct - -It is not enough to represent a message as a list of headers following each -other. The programmer also needs a convenient way to access certain headers -at the message level, for example, accessing directly the @b Accept header -instead of going through all headers and examining their name. The -structured view to the message is provided via a message-specific C struct. -In general, its type is msg_pub_t (it provides public view to message). The -protocol-specific type is #sip_t, #http_t or #msg_multipart_t for -SIP, HTTP and MIME, respectively. - -So, a single message is represented by two objects, first object (#msg_t) is -private to the @b msg module and opaque by an application programmer, second -(#sip_t, #http_t or #msg_multipart_t) is a public protocol-specific -structure accessible by all. - -@note The application programmer can obtain a pointer to the -protocol-specific structure from an #msg_t object using msg_public() -function. The msg_public() takes a protocol tag, a well-known identifier, as -its argument. The SIP, HTTP and MIME already define a wrapper around -msg_public(), for example, a #sip_t structure can be obtained with -sip_object() function (or macro). - -As an example, the #sip_t structure is defined as follows: -@code -typedef struct sip_s { - msg_common_t sip_common[1]; // Used with recursive inclusion - msg_pub_t *sip_next; // Ditto - void *sip_user; // Application data - unsigned sip_size; // Size of the structure with - // extension headers - int sip_flags; // Parser flags - - sip_error_t *sip_error; // Erroneous headers - - sip_request_t *sip_request; // Request line - sip_status_t *sip_status; // Status line - - sip_via_t *sip_via; // Via (v) - sip_route_t *sip_route; // Route - sip_record_route_t *sip_record_route; // Record-Route - sip_max_forwards_t *sip_max_forwards; // Max-Forwards - ... -} sip_t; -@endcode - -As you can see above, the public #sip_t structure contains the common -header members that are also found in the beginning of a header -structure. The @e sip_size indicates the size of the structure - the -application can extend the parser and #sip_t structure beyond the -original size. The @e sip_flags contains various flags used during the -parsing and printing process. They are documented in the . These -boilerplate members are followed by the pointers to various message -elements and headers. - -@section msg_parsing_example Result of Parsing Process - -Let us now show how a simple message is parsed and presented to the -applications. As an exampe, we choose a SIP request message with method BYE, -including only the mandatory fields: -@code -BYE sip:joe@example.com SIP/2.0 -Via: SIP/2.0/UDP sip.example.edu;branch=d7f2e89c.74a72681 -Via: SIP/2.0/UDP pc104.example.edu:1030;maddr=110.213.33.19 -From: Bobby Brown ;tag=77241a86 -To: Joe User ;tag=7c6276c1 -Call-ID: 4c4e911b@pc104.example.edu -CSeq: 2 -@endcode - -The figure below shows the layout of the BYE message above after parsing: - -@image html sip-parser2.gif BYE message and its representation in C -@image latex sip-parser2.eps BYE message and its representation in C - -The leftmost box represents the message of type #msg_t. Next box from -the left reprents the #sip_t structure, which contains pointers to a -header objects. The next column contains the header objects. There is -one header object for each message fragment. The rightmost box represents -the I/O buffer used when the message was received. Note that the I/O -buffer may be non-continous and composed of many separate memory areas. - -The message object has link to the public message structure (@a -m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O -buffer (@a m_buffer). The public message structure contains pointers to -the headers according to their type. If there are multiple headers of -the same type (like there are two Via headers in the above message), the -headers are put into a single-linked list. - -Each fragment has pointers to successing and preceding fragment. It also -contains pointer to the corresponding data within the I/O buffer and its -length. - -The main purpose of the fragment chain is to preserve the original order -of the headers. If there were an third Via header after CSeq in the -message, the fragment representing it would be after the CSeq header in -the fragment chain but after second Via in the header list. - -@section msg_parsing_memory Example: Parsing a Complete Message - -The following code fragment is an example of parsing a complete message. The -parsing process is more hairy when there is stream to be parsed. - -@code -msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len) -{ - msg_t *msg; - int m; - msg_iovec_t iovec[2] = {{ 0 }}; - - msg = msg_create(mclass, 0); - if (!msg) - return NULL; - - m = msg_recv_iovec(msg, iovec, 2, n, 1); - if (m < 0) { - msg_destroy(msg); - return NULL; - } - assert(m <= 2); - assert(iovec[0].mv_len + iovec[1].mv_len == n); - - memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len); - if (m == 2) - memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len); - - msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1); - - m = msg_extract(msg); - assert(m != 0); - if (m < 0) { - msg_destroy(msg); - return NULL; - } - return msg; -} -@endcode - -Let's go through this simple function, step by step. First, we get the @a -data pointer and its size in bytes, @a len. We first initialize an I/O -vector used to represent message with the parser. - -@code -msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len) -{ - msg_t *msg; - int m; - msg_iovec_t iovec[2] = {{ 0 }}; -@endcode - -The message class @a mclass (a parser driver object, #msg_mclass_t) is used -to represent a particular protocol-specific parser instance. When a message -object is created, it is given as an argument to msg_create() function: - -@code - msg = msg_create(mclass, 0); - if (!msg) - return NULL; -@endcode - -Next we obtain a memory buffer for data with msg_recv_iovec(). The memory -buffer is usually a single continous memory area, but in some cases it may -consist of two distinct areas. Therefore the @a iovec is used here to pass -the buffers around. The @a iovec is also very handly as it can be directly -passed to various system I/O calls. - -@code - m = msg_recv_iovec(msg, iovec, 2, n, 1); - if (m < 0) { - msg_destroy(msg); - return NULL; - } -@endcode - -These assumptions hold always true when you call msg_recv_iovec() first -time with a complete message: - -@code - assert(m >= 1 && m <= 2); - assert(iovec[0].mv_len + iovec[1].mv_len == n); -@endcode - -Next, we copy the data to the I/O vector and commit the copied data to the -message. Earlier with msg_recv_iovec() we allocated buffer space for data, -now calling msg_recv_commit() indicates that valid data has been copied to -the buffer. The last parameter to msg_recv_commit() indicates that the end -of stream is encountered and no more data is to be expected. - -@code - memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len); - if (m == 2) - memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len); - - msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1); -@endcode - -We call msg_extract() next; it takes care of parsing the message. A fatal -parsing error is indicated by returning -1. If the message is incomplete, -msg_extract() returns 0. When a complete message has been parsed, a positive -value is returned. We know that a message cannot be incomplete, as a call to -msg_recv_commit() indicated to the parser that the end-of-stream has been -encountered. - -@code - m = msg_extract(msg); - assert(m != 0); - if (m < 0) { - msg_destroy(msg); - return NULL; - } - return msg; -} -@endcode - - */ - -/**@class msg_s msg.h - * - * @brief Message object. - * - * The message object is used by Sofia parsers for SIP and HTTP - * protocols. The message object has an abstract, protocol-independent - * inteface type #msg_t, and a separate public protocol-specific interface - * #msg_pub_t (which is typedef'ed to #sip_t or #http_t depending - * on the protocol). - * - * The main interface to abstract messages is defined in . The - * network I/O interface used by transport protocols is defined in - * . The protocol-specific parser table, also known as message - * class, is defined in . (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. - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c deleted file mode 100644 index a015dfecd5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_auth.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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 = (msg_auth_t *)h; - - 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 = (msg_auth_t *)dst; - msg_auth_t const *o = (msg_auth_t const *)src; - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c deleted file mode 100644 index 75b729f2a8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_basic.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Fri Feb 23 19:51:55 2001 ppessi - */ - -#include "config.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#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); - - if (h) { - msg_payload_t *pl = (msg_payload_t *)h; - 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) -{ - msg_payload_t *pl = (msg_payload_t *)h; - - pl->pl_len = slen; - pl->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) -{ - msg_payload_t *pl = (msg_payload_t *)h; - size_t len = pl->pl_len; - - if (bsiz > 0) { - if (len < bsiz) - memcpy(b, pl->pl_data, len), b[len] = '\0'; - else - memcpy(b, pl->pl_data, bsiz - 1), b[bsiz - 1] = '\0'; - } - - return len; -} - -isize_t msg_payload_dup_xtra(msg_header_t const *h, isize_t offset) -{ - msg_payload_t *pl = (msg_payload_t *)h; - return offset + pl->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 = (msg_payload_t *)dst; - msg_payload_t const *o = (msg_payload_t const *)src; - - memcpy(pl->pl_data = b, o->pl_data, pl->pl_len = o->pl_len); - - dst->sh_data = pl->pl_data; - dst->sh_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); - msg_separator_t *sep = (msg_separator_t *)h; - - if (len == 0 && slen > 0) - return -1; - - memcpy(sep->sep_data, s, len); - sep->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) -{ - msg_separator_t const *sep = (msg_separator_t const *)h; - size_t n = strlen(sep->sep_data); - - if (bsiz > n) - strcpy(b, sep->sep_data); - - return (issize_t)n; -} - -msg_separator_t *msg_separator_create(su_home_t *home) -{ - msg_separator_t *sep; - - sep = (msg_separator_t *)msg_header_alloc(home, msg_separator_class, 0); - if (sep) - strcpy(sep->sep_data, CRLF); - - return sep; -} - -/* ====================================================================== */ - - diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c deleted file mode 100644 index 5a8f354fa5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_date.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Apr 11 18:57:06 2001 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/** 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. - */ -su_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 */ -su_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 , 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 (!su_casenmatch(tz, "GMT", 3) && !su_casenmatch(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 - * 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 field. - * - * The is defined as follows: - * @code - * delta-seconds = 1*DIGIT - * @endcode - * - * Note, however, that 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() "" 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() "" or - * @ref msg_delta_d() "" 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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c deleted file mode 100644 index cc34998358..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_generic.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @ingroup msg_parser - * @file msg_generic.c - * @brief Functions for generic headers - * - * @author Pekka Pessi - * - * @date Created: Thu Jan 23 20:08:00 2003 ppessi - * - */ - -#include "config.h" - -#include - -#include "sofia-sip/msg.h" -#include "sofia-sip/bnf.h" -#include "sofia-sip/msg_parser.h" -#include "sofia-sip/msg_header.h" - -#include -#include -#include -#include -#include -#include -#include - -/** - * 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) -{ - msg_generic_t *g = (msg_generic_t *)h; - g->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 = (msg_generic_t const *)h; - 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 = (msg_generic_t const *)h; - 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) -{ - msg_generic_t *g = (msg_generic_t *)dst; - msg_generic_t const *o = (msg_generic_t const *)src; - char *end = b + xtra; - MSG_STRING_DUP(b, g->g_string, o->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) -{ - msg_numeric_t *x = (msg_numeric_t *)h; - uint32_t value = 0; - issize_t retval = msg_uint32_d(&s, &value); - - assert(h->sh_class->hc_size >= sizeof *x); - - x->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) -{ - msg_numeric_t *x = (msg_numeric_t *)h; - - assert(x->x_common->h_class->hc_size >= sizeof *x); - - if (x->x_value > 0xffffffffU) - return -1; - - return snprintf(b, bsiz, "%lu", x->x_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) -{ - msg_list_t *k = (msg_list_t *)h; - return msg_commalist_d(home, &s, &k->k_items, NULL); -} - -issize_t msg_list_e(char b[], isize_t bsiz, msg_header_t const *h, int flags) -{ - msg_list_t *k = (msg_list_t *)h; - int compact = MSG_IS_COMPACT(flags); - char *b0 = b, *end = b + bsiz; - - MSG_COMMALIST_E(b, end, k->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_list_t const *k = (msg_list_t const *)h; - MSG_PARAMS_SIZE(offset, k->k_items); - return offset; -} - -char *msg_list_dup_one(msg_header_t *dst, - msg_header_t const *src, - char *b, - isize_t xtra) -{ - msg_list_t *k = (msg_list_t *)dst; - msg_list_t const *o = (msg_list_t const *)src; - char *end = b + xtra; - msg_param_t const ** items = (msg_param_t const **)&k->k_items; - - b = msg_params_dup(items, o->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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c deleted file mode 100644 index 06c75bc9f6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_copy.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include - -#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 */ -su_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 */ -su_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) -{ - size_t skip = offsetof(msg_numeric_t, x_value); /* Skip common part */ - - memcpy((char *)h + skip, (char const *)src + skip, h->sh_class->hc_size - skip); - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c deleted file mode 100644 index c2be7eadfb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_header_make.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Fri Feb 23 14:06:34 2001 ppessi - * - */ - -#include "config.h" - -#include - -#include "sofia-sip/msg.h" -#include "sofia-sip/bnf.h" -#include "sofia-sip/msg_parser.h" -#include "sofia-sip/msg_header.h" - -#include -#include -#include -#include -#include -#include -#include - -#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 - -/** 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c deleted file mode 100644 index 97cb95edaa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_inlined.c - * - * Expand inlined msg functions non-inline. - * - */ - -#include "config.h" - -#include - -#if SU_HAVE_INLINE -extern int xyzzy; -#else -#undef SU_HAVE_INLINE -#undef su_inline - -#define SU_HAVE_INLINE 1 -#define su_inline - -#include "sofia-sip/msg_header.h" -#include "sofia-sip/msg_mime_protos.h" - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h b/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h deleted file mode 100644 index 3b1ac9bb5e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_INTERNAL_H - -/**@IFILE msg_internal.h - * @brief Abstract messages - internal interface - * - * @author Pekka Pessi - * - * @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 -#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 */ -}; - - -struct hep_hdr{ - uint8_t hp_v; /* version */ - uint8_t hp_l; /* length */ - uint8_t hp_f; /* family */ - uint8_t hp_p; /* protocol */ - uint16_t hp_sport; /* source port */ - uint16_t hp_dport; /* destination port */ -}; - - -struct hep_iphdr{ - struct in_addr hp_src; - struct in_addr hp_dst; /* source and dest address */ -}; - -/* HEPv2 */ -struct hep_timehdr{ - uint32_t tv_sec; /* seconds */ - uint32_t tv_usec; /* useconds */ - uint16_t captid; /* Capture ID node */ -}; - -#if SU_HAVE_IN6 -struct hep_ip6hdr { - struct in6_addr hp6_src; /* source address */ - struct in6_addr hp6_dst; /* destination address */ -}; -#endif - -/* HEPv3 types */ - -#if (defined __SUNPRO_CC) || defined(__SUNPRO_C) || defined(_MSC_VER) -#define PACKED -#endif -#ifndef PACKED -#define PACKED __attribute__ ((__packed__)) -#endif - -#ifdef _MSC_VER -#pragma pack(push, 1) -#endif - -struct hep_chunk { - uint16_t vendor_id; - uint16_t type_id; - uint16_t length; -} PACKED; - -typedef struct hep_chunk hep_chunk_t; - -struct hep_chunk_uint8 { - hep_chunk_t chunk; - uint8_t data; -} PACKED; - -typedef struct hep_chunk_uint8 hep_chunk_uint8_t; - -struct hep_chunk_uint16 { - hep_chunk_t chunk; - uint16_t data; -} PACKED; - -typedef struct hep_chunk_uint16 hep_chunk_uint16_t; - -struct hep_chunk_uint32 { - hep_chunk_t chunk; - uint32_t data; -} PACKED; - -typedef struct hep_chunk_uint32 hep_chunk_uint32_t; - -struct hep_chunk_str { - hep_chunk_t chunk; - char *data; -} PACKED; - -typedef struct hep_chunk_str hep_chunk_str_t; - -struct hep_chunk_ip4 { - hep_chunk_t chunk; - struct in_addr data; -} PACKED; - -typedef struct hep_chunk_ip4 hep_chunk_ip4_t; - -struct hep_chunk_ip6 { - hep_chunk_t chunk; - struct in6_addr data; -} PACKED; - -typedef struct hep_chunk_ip6 hep_chunk_ip6_t; - -struct hep_chunk_payload { - hep_chunk_t chunk; - char *data; -} PACKED; - -typedef struct hep_chunk_payload hep_chunk_payload_t; - -struct hep_ctrl { - char id[4]; - uint16_t length; -} PACKED; - -typedef struct hep_ctrl hep_ctrl_t; - -struct hep_generic { - hep_ctrl_t header; - hep_chunk_uint8_t ip_family; - hep_chunk_uint8_t ip_proto; - hep_chunk_uint16_t src_port; - hep_chunk_uint16_t dst_port; - hep_chunk_uint32_t time_sec; - hep_chunk_uint32_t time_usec; - hep_chunk_uint8_t proto_t; - hep_chunk_uint32_t capt_id; -} PACKED; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif - -typedef struct hep_generic hep_generic_t; - -/** Maximum size when streaming. */ -#define MSG_SSIZE_MAX (USIZE_MAX) - -/* ---------------------------------------------------------------------- */ -/* Header-kind predicate functions. */ -su_inline int msg_is_single(msg_header_t const *h) -{ - return h->sh_class->hc_kind == msg_kind_single; -} - -su_inline int msg_is_prepend(msg_header_t const *h) -{ - return h->sh_class->hc_kind == msg_kind_prepend; -} - -su_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; -} - -su_inline int msg_is_list(msg_header_t const *h) -{ - return h->sh_class->hc_kind == msg_kind_list; -} - -su_inline int msg_is_special(msg_header_t const *h) -{ - return h->sh_class->hc_hash < 0; -} - -SOFIA_END_DECLS - -#endif /* MSG_INTERNAL_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c deleted file mode 100644 index 320ecc21b5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mclass.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Jun 5 14:34:24 2002 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#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) -{ - return msg_mclass_insert_with_mask(mc, hc, offset, 0); -} - -/**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 && su_casenmatch(s, hc->hc_name, m)) { - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c deleted file mode 100644 index 617babe04b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - * - * - */ - -#include "config.h" - -#define _GNU_SOURCE 1 - -#include -#include - -#include "msg_internal.h" -#include "sofia-sip/msg.h" -#include "sofia-sip/msg_mime.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#if !HAVE_MEMMEM -void *memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen); -#endif - -/** Protocol version of MIME */ -char const msg_mime_version_1_0[] = "MIME/1.0"; - -#include -#include - -/** 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 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 && - * su_casenmatch(sip->sip_content_type, "multipart/", 10)) { - * 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 + su_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 + su_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 *b, *end; - msg_param_t param; - - if (!pl) return NULL; - - 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 */ - - *b = '\0'; - mp->mp_common->h_len = p - b; - b += strlen(boundary) - 2; - mp->mp_common->h_data = 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 */ - *next = '\0'; - mp->mp_close_delim->pl_len = p + len - next; - next += strlen(boundary) - 2; - mp->mp_close_delim->pl_data = 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 = (unsigned)blen; /* XXX */ - - if (!(mp->mp_payload || mp->mp_separator)) continue; - - 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 = (unsigned)blen; /* XXX */ - } 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; - - for(;;) { - 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; - - msg_parse_next_field_without_recursion(); - } - -} - -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 && su_casenmatch(name, "q", 1)) { - /* 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; - - for(;;) { - 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; - - msg_parse_next_field_without_recursion(); - } - -} - -/** 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 && su_casenmatch(name, "q", 1)) { - 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") && - su_casenmatch(name, "handling", namelen)) { - cd->cd_handling = value; - cd->cd_required = su_casematch(value, "required"); - cd->cd_optional = su_casematch(value, "optional"); - } - - 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 = - * @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 = c->c_type ? strchr(c->c_type, '/') : NULL; - if (c->c_subtype) - 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; - char *text; - - for(;;) { - w = (msg_warning_t *)h; - 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; - - msg_parse_next_field_without_recursion(); - } - -} - -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in b/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in deleted file mode 100644 index e7843bd52c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_mime_table.c.in +++ /dev/null @@ -1,70 +0,0 @@ -/**@ingroup msg_mime - * @IFILE msg_mime_table.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @author Pekka Pessi - */ - -#include "config.h" - -#include -#include - -#include -#include - -#include - -#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) - - - diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c deleted file mode 100644 index 91f79bfe40..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_name_hash.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Tue Aug 20 16:27:01 EEST 2002 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk b/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk deleted file mode 100644 index 4590618eb2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.awk +++ /dev/null @@ -1,660 +0,0 @@ -#! /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 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# as published by the Free Software Foundation; either version 2.1 of -# the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -# -# -------------------------------------------------------------------- -# -# Contributor(s): Pekka.Pessi@nokia.com. -# -# Created: Fri Apr 6 12:59:59 2001 ppessi -# - -BEGIN { - "date '+%a %b %e %H:%M:%S %Y'" | getline date; - - ascii = \ - " " \ - " !\"#$%&'()*+,-./0123456789:;<=>?" \ - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \ - "`abcdefghijklmnopqrstuvwxyz{|}~"; - lower_case = "abcdefghijklmnopqrstuvwxyz"; - - N=0; - # Initialize these as arrays - split("", symbols); - split("", names); - split("", comments); - split("", hashes); - split("", NAMES); - split("", Comments); - split("", COMMENTS); - - # indexed by the C name of the header - split("", Since); # Non-NUL if extra - split("", Extra); # Offset in extra headers - - total = 0; - ordinary = 0; - basic = 0; - extra = 0; - without_experimental = 0; - - template=""; - template1=""; - template2=""; - template3=""; - prefix=""; - tprefix=""; - failed=0; - success=0; - - ERRNO="error"; -} - -function name_hash (name) -{ - hash = 0; - - len = length(name); - - for (i = 1; i <= len; i++) { - c = tolower(substr(name, i, 1)); - hash = (38501 * (hash + index(ascii, c))) % 65536; - } - - if (hash == 0) { - print "*** msg_parser.awk: calculating hash failed\n"; - exit(5); - } - - 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; - } - - expr = (without_experimental > 0 && do_hash); - if (expr) { - printf "%s is experimental\n", Comment; - } - - experimental[N] = expr; - - if (PR) { - if (expr) { - print "#if SU_HAVE_EXPERIMENTAL" > 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); - if (expr) { - print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR; - } - } -} - -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]*/, "", p); - } - - print p > PR; - } -} - -# -# Repeat each line in the footer containing the magic replacement -# pattern with an 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)#/)) { - expr = 0; - - for (j = 1; j <= N; j++) { - l = lines[i]; - if (expr != experimental[j]) { - expr = experimental[j]; - if (expr) { - print "#if SU_HAVE_EXPERIMENTAL" > PR; - } - else { - print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR; - } - } - 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; - } - - if (expr) { - print "#endif /* SU_HAVE_EXPERIMENTAL */" > 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 && /^#### DEFAULT HEADER LIST ENDS HERE ####$/ { basic=total; } -HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ { - without_experimental = total; } - -HLIST && /^[a-z]/ { protos($1, $0, 0, $2); - headers[total++] = $1; - Extra[$1] = extra++; -} -/^#### 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; total++; ordinary++; -} - -function print_parser_table(struct, scope, name, N, N_EXPERIMENTAL) -{ - if (PT) { - if (N > ordinary) { - printf("/* Ordinary %u, extra %u, experimental %u */\n", - ordinary, N - ordinary, N_EXPERIMENTAL - N) > PT; - printf("struct %s {\n", struct) > PT; - printf(" %s_t base;\n", module) > PT; - printf(" msg_header_t *extra[%u];\n", N - ordinary) > PT; - if (N != N_EXPERIMENTAL) { - print "#if SU_HAVE_EXPERIMENTAL" > PT; - printf(" msg_header_t *extra[%u];\n", N_EXPERIMENTAL - N) > PT; - print "#endif" > PT; - } - printf("};\n\n") > PT; - } - - printf("%s\n", scope) > PT; - printf("msg_mclass_t const %s[1] = \n{{\n", name) > 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; - if (N > ordinary) { - printf(" sizeof (struct %s),\n", struct) > PT; - } - else { - printf(" sizeof (%s_t),\n", module) > 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, msg_offsetof(%s_t, %s_%s) }},\n", - tprefix, unnamed[i], module, prefix, unnamed[i]) > PT; - } - if (multipart) { - printf(" {{ %s_class, msg_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, \n", MC_HASH_SIZE) > PT; - if (N != N_EXPERIMENTAL) { - print "#if SU_HAVE_EXPERIMENTAL" > PT; - printf(" %d,\n", N_EXPERIMENTAL) > PT; - print "#else" > PT; - } - printf(" %d,\n", N) > PT; - if (N != N_EXPERIMENTAL) { - print "#endif" > PT; - } - - printf(" {\n") > PT; - - for (j = 0; j < MC_HASH_SIZE; j++) { - c = (j + 1 == MC_HASH_SIZE) ? "" : ","; - if (j in header_hash) { - n = header_hash[j]; - i = index_hash[j]; - - flags = header_flags[n]; if (flags) flags = ",\n " flags; - - if (i >= N) { - print "#if SU_HAVE_EXPERIMENTAL" > PT; - } - - if (i >= ordinary) { - printf(" { %s_%s_class,\n" \ - " msg_offsetof(struct %s, extra[%u])%s }%s\n", - tprefix, n, struct, Extra[n], flags, c) > PT; - } - else { - printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n", - tprefix, n, module, prefix, n, flags, c) > PT; - } - - if (i >= N) { - printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT; - } - } - else { - printf(" { NULL, 0 }%s\n", c) > PT; - } - } - printf(" }\n}};\n\n") > PT; - - } -} - -END { - if (failed) { exit }; - - if (!NO_LAST) { - protos("unknown", "/**< Unknown headers */", -3); - protos("error", "/**< Erroneous headers */", -4); - protos("separator", "/**< Separator line between headers and body */", -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; - - sub(/.*[\/]/, "", TEMPLATE); - gsub(/#AUTO#/, auto, header); - gsub(/#DATE#/, "@date Generated: " date, header); - print header > PT; - - print "" > PT; - print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT; - print "" > 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, msg_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 (basic == 0) basic = total; - if (without_experimental == 0) without_experimental = total; - - split("", header_hash); - split("", index_hash); - - for (i = 0; i < basic; 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; - index_hash[j] = i; - } - - m = module "_mclass"; - s = "_d_" module "_t"; - - # Add basic headers - if (ordinary == basic) { - print_parser_table(s, "", m, basic, basic); - } - else if (basic < without_experimental) { - print_parser_table(s, "", m, basic, basic); - } - else { - print_parser_table(s, "", m, without_experimental, basic); - } - - if (0) { - - # Hash extra headers - for (i = basic; 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; - index_hash[j] = i; - } - - if (basic < total) { - m = module "_ext_mclass"; - s = "_e_" module "_s"; - print_parser_table(s, "static", m, without_experimental, total); - } - - printf("msg_mclass_t const * %s_extended_mclass = %s;\n\n", module, m) > PT; - - } - - if (basic < total) { - printf("msg_hclass_t * const %s_extensions[] = {\n", module) > PT; - for (i = basic; i < total; i++) { - if (i == without_experimental) { - print "#if SU_HAVE_EXPERIMENTAL" > PT; - } - printf(" %s_%s_class,\n", module, headers[i]) > PT; - } - if (total != without_experimental) - print "#endif" > PT; - print " NULL\n};\n\n" > PT; - } - } - - exit success; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c deleted file mode 100644 index 2e3a8d42af..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c +++ /dev/null @@ -1,3100 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Oct 5 14:01:24 2000 ppessi - * - */ - -/*#define NDEBUG*/ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#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); -su_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) - -su_inline int msg_is_request(msg_header_t const *h) -{ - return h->sh_class->hc_hash == msg_request_hash; -} - -su_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; -} - -su_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 = NULL, *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 */ - -su_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); -su_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); -su_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') - -su_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, (enum msg_streaming_status)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 */ -su_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; - msg_error_t *er; - - 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); - er = (msg_error_t *)h; - - if (!er) - return NULL; - - er->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; - 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; -} - -su_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_href_t const *hr; - msg_header_t *h, *h0; - msg_payload_t *pl; - char *x; - - if (msg == NULL || mo == NULL) - return -1; - - assert(!msg->m_chunk); - mc = msg->m_class; - hr = mc->mc_payload; - - 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 = (msg_payload_t*)h; - *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; - - /* 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. - */ -su_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 */ -su_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 */ -su_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 (!hc->hc_name[0] || !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 */ -su_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; - - if (bsiz < msg_min_size) { - errno = ENOMEM; - su_free(home, b); - return NULL; - } - - b2 = su_realloc(home, b, bsiz); - - if (b2 == NULL) { - errno = ENOMEM; - su_free(home, b); - return NULL; - } - - b = b2; - - continue; - } - } - - *return_len = used; - - b[used] = '\0'; /* NUL terminate */ - - return su_realloc(home, b, used + 1); -} - -/* ====================================================================== */ -/* Handling header chain */ - -su_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; -} - -su_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 */ -su_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_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); - - mc = msg->m_class; - 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; -} - -su_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_header_t **hh; - msg_header_t **separator; - msg_header_t **payload; - - assert(msg && pub && head && h); - - mc = msg->m_class; - 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. - */ -su_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) -{ - 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. */ - if (hc->hc_hash == mc->mc_request[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_request[0].hr_offset); - if (hc->hc_hash == mc->mc_status[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_status[0].hr_offset); - if (hc->hc_hash == mc->mc_separator[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_separator[0].hr_offset); - if (hc->hc_hash == mc->mc_payload[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_payload[0].hr_offset); - if (hc->hc_hash == mc->mc_unknown[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_unknown[0].hr_offset); - if (hc->hc_hash == mc->mc_error[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_error[0].hr_offset); - if (hc->hc_hash == mc->mc_multipart[0].hr_class->hc_hash) return (msg_header_t **)((char *)mo + mc->mc_multipart[0].hr_offset); - } - - return NULL; -} - -/** Append a parsed header object into the message structure */ -su_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 formatting result to message. - * - * Parse result from printf-formatted params as a given header field and add - * result to the message. - * - * @NEW_1_12_10 - */ -int msg_header_add_format(msg_t *msg, - msg_pub_t *pub, - msg_hclass_t *hc, - char const *fmt, - ...) -{ - msg_header_t *h, **hh; - va_list va; - - 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 (!fmt) - return 0; - - va_start(va, fmt); - h = msg_header_vformat(msg_home(msg), hc, fmt, va); - va_end(va); - - if (!h) - 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; - } -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c deleted file mode 100644 index 109ee60ff5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser_util.c +++ /dev/null @@ -1,2005 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Aug 28 16:26:34 2001 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#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 *stack[MSG_N_PARAMS]; - char const **list = stack, **re_list; - size_t 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 == stack || 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) { - *append_list = NULL; - return 0; - } - - if (list == stack) { - size_t size = sizeof(*list) * MSG_PARAMS_NUM(n + 1); - list = su_alloc(home, size); - if (!list) return -1; - memcpy((void *)list, stack, n * sizeof(*list)); - } - - list[n] = NULL; - *append_list = list; - return 0; - - error: - *start = NULL; - if (list != stack && 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 const **nparams = su_realloc(home, (void*)(params != stack ? params : NULL), - (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params)); - if (!nparams) { - goto error; - } - if (params == stack) - memcpy(nparams, stack, n * sizeof(*params)); - params = nparams; - } - - 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 const **nparams = su_realloc(home, (void*)(params != stack ? params : NULL), - (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params)); - if (!nparams) { - goto error; - } - if (params == stack) - memcpy(nparams, stack, n * sizeof(*params)); - params = nparams; - } - - 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 name [ "=" value]. 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, name [ "=" value ] - * @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 (su_casenmatch(maybe, param, plen) && - (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 name "=" value - * 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 (su_casenmatch(param, token, n)) { - 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 (su_casenmatch(param, token, n)) { - 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 (su_casenmatch(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 (su_casenmatch(maybe, param, n)) { - 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 && - su_casenmatch(p, d[i], nlen) - && (d[i][nlen] == '=' || d[i][nlen] == '\0')) - || - (prune == 2 && su_casematch(p, d[i])) - || - (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 - * - * - * - * - * - *
0do not prune
1prune parameters with identical names
2case-insensitive values
3case-sensitive values
- * - * @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 = su_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) -{ - isize_t e = 0; - - if (b == NULL) - bsiz = 0; - - if (0 < bsiz) - *b = '"'; - e++; - - for (;*s;) { - size_t n = strcspn(s, "\"\\"); - - if (n == 0) { - if (b && e + 2 <= bsiz) - b[e] = '\\', b[e + 1] = s[0]; - e += 2; - s++; - } - else { - if (b && (e + n <= bsiz)) - memcpy(b + e, s, n); - e += n; - s += n; - } - } - - if (b && e < bsiz) - b[e] = '"'; - e++; - - return e; -} - - -/** 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 - -/** 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); - if (msg == NULL) - return NULL; - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c deleted file mode 100644 index 061cd5ef2a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Fri Feb 23 12:46:42 2001 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#define TAG_NAMESPACE "msg" - -#include "msg_internal.h" -#include "sofia-sip/msg_header.h" -#include "sofia-sip/msg_parser.h" - -#include -#include -#include -#include "sofia-sip/msg_tag_class.h" - -#ifndef _MSC_VER -#define NONE ((void*)-1) -#else -#define NONE ((void*)(INT_PTR)-1) -#endif - -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, ""); - } -} - -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h deleted file mode 100644 index 99e9be7bea..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included */ -#define MSG_H -/**@file sofia-sip/msg.h - * - * Base message interface. - * - * @author Pekka Pessi - * - * @date Created: Fri Feb 18 08:54:48 2000 ppessi - */ - -#include -#include - -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h deleted file mode 100644 index fbeb1dea15..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_addr.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_ADDR_H - - -/**@file sofia-sip/msg_addr.h - * @brief Addressing and I/O interface for messages. - * - * @author Pekka Pessi - * - * @date Created: Thu Jun 8 19:28:55 2000 ppessi - */ - -#ifndef MSG_H -#include -#endif -#ifndef SU_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h deleted file mode 100644 index 027d3a30ed..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_buffer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_BUFFER_H - -/**@file sofia-sip/msg_buffer.h - * @brief Internal buffer management functions. - * - * @author Pekka Pessi - * - * @date Created: Fri Nov 8 12:23:00 2002 ppessi - * - */ - -#ifndef MSG_TYPES_H -#include -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h deleted file mode 100644 index 4e215c786c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_date.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Thu Jun 8 19:28:55 2000 ppessi - * - */ - -#ifndef SU_TYPES_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h deleted file mode 100644 index c633aa3632..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_HEADER_H -/**@ingroup msg_headers - * @file sofia-sip/msg_header.h - * - * @brief Message headers. - * - * @author Pekka Pessi - * - * @date Created: Mon Aug 27 15:44:27 2001 ppessi - * - */ - -#include -#include - -#ifndef SU_TYPES_H -#include -#endif -#ifndef SU_ALLOC_H -#include -#endif -#ifndef MSG_H -#include -#endif -#ifndef URL_H -#include -#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_add_format(msg_t *msg, - msg_pub_t *pub, - msg_hclass_t *hc, - char const *fmt, - ...); - -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. */ -su_inline void msg_fragment_clear(msg_common_t *h) -{ - h->h_data = NULL, h->h_len = 0; -} - -/** Pointer to header parameters. */ -su_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. */ - -#ifndef _MSC_VER -#define MSG_HEADER_NONE ((msg_header_t *)-1) -#else -#define MSG_HEADER_NONE ((msg_header_t *)(INT_PTR)-1) -#endif - -SOFIA_END_DECLS - -#ifndef MSG_PROTOS_H -#include -#endif - -#endif /** !defined(MSG_HEADER_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h deleted file mode 100644 index 473fe279c6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Mon Aug 27 15:44:27 2001 ppessi - */ - -#ifndef MSG_HEADER_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h deleted file mode 100644 index 1eba2b24d8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mclass_hash.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Tue Aug 21 16:03:45 2001 ppessi - * - */ - -#include - -#ifndef BNF_H -#include -#endif - -SOFIA_BEGIN_DECLS - -/** Hash the header name */ -#define MC_HASH(s, n) (msg_header_name_hash(s, NULL) % (unsigned)(n)) - -/** Hash header name */ -su_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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h deleted file mode 100644 index 033c551fdb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi - * - */ - -#ifndef URL_H -#include -#endif - -#ifndef MSG_TYPES_H -#include -#endif -#ifndef SU_TYPES_H -#include -#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. */ - unsigned 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 (c) */ - 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 (e) */ - 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 */ -#ifndef _MSC_VER -#define MSG_MULTIPART_PROTOCOL_TAG ((void *)0x4d494d45) /* 'MIME' */ -#else -#define MSG_MULTIPART_PROTOCOL_TAG ((void *)(UINT_PTR)0x4d494d45) /* 'MIME' */ -#endif - -SOFIA_END_DECLS - -#endif /** MSG_MIME_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in deleted file mode 100644 index 4ba204b238..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime_protos.h.in +++ /dev/null @@ -1,323 +0,0 @@ -/**@ingroup msg -*- c -*- - * @file sofia-sip/msg_mime_protos.h.in - * - * Template for . - */ - -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - */ - -#ifndef MSG_PARSER_H -#include -#endif -#ifndef MSG_MIME_H -#include -#endif -#ifndef MSG_MCLASS_H -#include -#endif -#ifndef MSG_MCLASS_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h deleted file mode 100644 index 7d784b5a61..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_parser.h +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_PARSER_H - -/**@ingroup msg_parser - * @file sofia-sip/msg_parser.h - * - * Message parser interface. - * - * @author Pekka Pessi - * - * @date Created: Tue Aug 21 16:03:45 2001 ppessi - * - */ - -#ifndef SU_ALLOC_H -#include -#endif -#ifndef MSG_HEADER_H -#include -#endif -#ifndef BNF_H -#include -#endif -#ifndef URL_H -#include -#endif - -SOFIA_BEGIN_DECLS - -/* --------------------------------------------------------------------------- - * 1) Header class definitions. - */ - -/* Do not use keywords until you fix msg_kind_foo_critical thing! */ \ -#if HAVE_STRUCT_KEYWORDS && 0 -/** 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 a header class */ -#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); - -#define msg_parse_next_field_without_recursion() { \ - msg_header_t *prev = h; \ - msg_hclass_t *hc = prev->sh_class; \ - char *end = s + slen; \ - \ - if (*s && *s != ',') \ - return -1; \ - \ - if (msg_header_update_params(prev->sh_common, 0) < 0) \ - return -1; \ - \ - while (*s == ',') \ - *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; \ - slen = end - s; \ - } - - - -/** 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,INT_MAX))\ - :((d)=NULL)) - -/* Solaris has broken memccpy - it considers last argument as signed */ - -/** 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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in deleted file mode 100644 index 43427094e2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_protos.h.in +++ /dev/null @@ -1,311 +0,0 @@ -/**@ingroup msg_headers -*- C -*- - * @file sofia-sip/msg_protos.h.in - * - * Template for . - */ - -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_PROTOS_H - -/**@ingroup msg_headers - * @file sofia-sip/msg_protos.h - * - * Prototypes for common headers - * - * #AUTO# - * - * @author Pekka Pessi - * - * @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi - */ - -#ifndef MSG_HEADER_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h deleted file mode 100644 index 089d4943be..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_tag_class.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Wed Feb 21 11:01:45 2001 ppessi - */ - -#ifndef SU_TAG_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h deleted file mode 100644 index aaf1bee42a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_types.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define MSG_TYPES_H - -/**@file sofia-sip/msg_types.h - * @brief Types for messages and common headers - * - * @author Pekka Pessi - * - * @date Created: Thu Jan 23 15:43:17 2003 ppessi - * - */ - -#ifndef SU_TYPES_H -#include -#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 value range of a 32-bit, 0..4294967295. The @a - * x_value field is unsigned long, however. - */ -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c b/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c deleted file mode 100644 index 1de4c0864e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_class.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Mar 5 11:57:20 2002 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#define TAG_NAMESPACE "tst" - -#include "test_class.h" -#include -#include -#include "test_protos.h" -#include - -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; -} - -msg_hclass_t test_numeric_class[] = - MSG_HEADER_CLASS(msg_, numeric, "Numeric", "", x_common, - single, msg_generic, msg_generic); - -msg_hclass_t test_auth_class[] = - MSG_HEADER_CLASS(msg_, auth, "Auth", "", au_params, - append, msg_auth, msg_generic); - -/** 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 -#include -#include -#include - -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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h b/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h deleted file mode 100644 index 038a665762..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_class.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define TEST_CLASS_H - -/**@ingroup test_msg - * @file test_class.h - * @brief Message and header classes for testing. - * - * @author Pekka Pessi - * - * @date Created: Thu Jun 29 15:58:06 2000 ppessi - */ - -#ifndef URL_H -#include -#endif -#ifndef MSG_H -#include -#endif -#ifndef MSG_HEADER_H -#include -#endif -#ifndef MSG_MIME_H -#include -#endif -#ifndef MSG_MCLASS_H -#include -#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 */ - - msg_auth_t *msg_auth; /**< Auth (testing) */ - msg_numeric_t *msg_numeric; /**< Numeric (testing) */ - /* === 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); - -su_inline -msg_test_t *msg_test_public(msg_t *msg) -{ - return (msg_test_t *)msg_public(msg, MSG_TEST_PROTOCOL_TAG); -} - -#define msg_auth_class test_auth_class - -#define msg_numeric_class test_numeric_class - -enum { - msg_auth_hash = 22894, - msg_numeric_hash = 24435 -}; - -extern msg_hclass_t test_auth_class[1], test_numeric_class[1]; - -SOFIA_END_DECLS - -#endif /* !defined(TEST_CLASS_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c b/libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c deleted file mode 100644 index 76e012d420..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_inlined.c - * - * Expand inlined test functions non-inline. - * - */ - -#include "config.h" - -#include - -#if SU_HAVE_INLINE -extern int xyzzy; -#else -#undef SU_HAVE_INLINE -#undef su_inline - -#define SU_HAVE_INLINE 1 -#define su_inline - -#include "test_protos.h" - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c b/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c deleted file mode 100644 index 6c85c47ad0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c +++ /dev/null @@ -1,1809 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#include -#include -#include -#include -#include - -static int test_flags = 0; -#define TSTFLAGS test_flags - -#include - -char const name[] = "test_msg"; - -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)); x->x_common->h_class = test_numeric_class; - - TEST_1(msg_numeric_d(NULL, (msg_header_t *)x, s = error1, strlen(error1)) < 0); - } - - END(); -} - -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; - } - - master = ";0"; - - 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(NULL, &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(NULL, (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); - } - - { - char b[8]; - TEST(msg_unquoted_e(NULL, 0, "\"\""), 6); - TEST(msg_unquoted_e(b, 0, "\"\""), 6); - TEST(msg_unquoted_e(b, 4, "\"\""), 6); - TEST(msg_unquoted_e(b, 6, "\"\""), 6); - TEST(memcmp(b, "\"\\\"\\\"\"", 6), 0); - TEST(msg_unquoted_e(b, 4, "\""), 4); - memset(b, 0, sizeof b); - TEST(msg_unquoted_e(b, 1, "\"kuik"), 8); - TEST(memcmp(b, "\"\0", 2), 0); - TEST(msg_unquoted_e(b, 3, "\"kuik"), 8); - TEST(memcmp(b, "\"\\\"\0", 4), 0); - TEST(msg_unquoted_e(b, 7, "\"kuik"), 8); - TEST(memcmp(b, "\"\\\"kuik\0", 8), 0); - } - - 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); - } - - msg_destroy(msg); - - /* 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); - msg_destroy(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; - char body[66 * 15 + 1]; - int i; - msg_payload_t *pl; - - /* Bug #1726034 */ - for (i = 0; i < 15; i++) - strcpy(body + i * 66, - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"); - pl = msg_payload_make(msg_home(msg), body); - - TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)pl), 0); - - 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 -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF -"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 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: " 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: " 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@localhost>" CRLF /* 12 */ - CRLF /* 13 */ -#define BODY3 "part 3" CRLF - BODY3 /* 14 */ - CRLF "--LaGqGt4BI6Ho" /* 15 */ - "c: text/html" CRLF /* 16 */ - "l: 9" CRLF /* 17 */ - "e: identity" CRLF /* 18 */ - CRLF /* 19 */ -#define BODY4 "" CRLF - BODY4 /* 20 */ - CRLF "--LaGqGt4BI6Ho--" /* 21 */ - 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" CRLF, 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); - - TEST_1(mp = mp->mp_next); - - TEST_1(mp->mp_data); - TEST_M(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len); - - TEST_1(mp->mp_content_encoding); - TEST_1(mp->mp_content_type); - - TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data); - TEST_SIZE(strlen(BODY4), pl->pl_len); - TEST(memcmp(pl->pl_data, BODY4, 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, 21); - - 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, 21); - - /* 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, 21 + 4); - -#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_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, 21 + 4); - - /* 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, 21 + 9); - - 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: " 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@localhost>" CRLF /* 12 */ - CRLF /* 13 */ -#define BODY3 "part 3" CRLF - BODY3 /* 14 */ - CRLF /* 15 */ - "--LaGqGt4BI6Ho--" CRLF; - - char const part1[] = "This is text\n"; - char const part2[] = "This is 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(); -} - -void usage(int exitcode) -{ - fprintf(stderr, "usage: %s [-v] [-a]\n", name); - exit(exitcode); -} - -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 if (strcmp(argv[i], "-a") == 0) - test_flags |= tst_abort; - else - usage(1); - } - -#if HAVE_OPEN_C - test_flags |= tst_verbatim; -#endif - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in b/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in deleted file mode 100644 index dc7da323df..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_protos.h.in +++ /dev/null @@ -1,359 +0,0 @@ -/**-*- 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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - */ - -#include -#include -#include - -#ifndef MSG_HEADER_H -#include -#endif - -#ifndef MSG_MIME_PROTOS_H -#include -#endif - -#ifndef TEST_CLASS_H -#include -#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 -su_inline tag_value_t -tsttag_header_v(msg_header_t const *v) -{ return (tag_value_t)v; } -su_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 -su_inline -tag_value_t tsttag_tst_v(msg_test_t const *v) { return (tag_value_t)v; } -su_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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in b/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in deleted file mode 100644 index 68ac0c22a7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/msg/test_table.c.in +++ /dev/null @@ -1,57 +0,0 @@ -/**@ingroup test_msg - * @IFILE test_table.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Jan 22 19:03:21 EET 2003 ppessi - */ - -#include "config.h" - -#include -#include - -#include "test_class.h" -#include "test_protos.h" -#include - -#include - - - diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog deleted file mode 100644 index 3a19236cfa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/ChangeLog +++ /dev/null @@ -1,3 +0,0 @@ -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile.in deleted file mode 100644 index 04f526e6a0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/Doxyfile.in +++ /dev/null @@ -1,22 +0,0 @@ -PROJECT_NAME = "nea" -OUTPUT_DIRECTORY = ../docs/html/nea - -INPUT = @srcdir@/nea.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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 += diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am deleted file mode 100644 index 8cc73afcdc..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/Makefile.am +++ /dev/null @@ -1,63 +0,0 @@ -# -# Makefile.am for nea module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 = nea.docs $(BUILT_SOURCES) - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea.c deleted file mode 100644 index 29afcd71c4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Feb 14 18:32:58 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#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 - -#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_urn || - 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 (su_casematch(ss->ss_substate, "terminated")) { - nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL; - nea->nea_state = nea_terminated; - - if (su_casematch(ss->ss_reason, "deactivated")) { - nea->nea_state = nea_embryonic; - nea->nea_deadline = sip_now(); - } else if (su_casematch(ss->ss_reason, "probation")) { - 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 (su_casematch(ss->ss_substate, "pending")) - nea->nea_state = nea_pending; - else if (su_casematch(ss->ss_substate, "active")) - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs b/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs deleted file mode 100644 index 04013f5ea2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea.docs +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- 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 . - * - * @CONTACT Pekka Pessi - * - * @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 - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c deleted file mode 100644 index 9128ba1c78..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - */ - -#include - -#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 , 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) }; diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h b/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h deleted file mode 100644 index 4108b2b787..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_debug.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NEA_DEBUG_H - -/**@file nea_debug.h - * @brief Debug log for @b nea module. - * - * @author Pekka Pessi - * @date Created: Thu Sep 6 19:06:40 2001 ppessi - */ - -#define SU_LOG (nea_log) -#include - -#endif /* !defined(NEA_DEBUG_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c deleted file mode 100644 index d9e0ad6cde..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_event.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @file nea_event.c - * @brief Default MIME type for certain events. - * - * @author Pekka Pessi - * - * @date Created: Thu Dec 11 20:28:46 2003 ppessi - */ - -#include "config.h" - -#include -#include - -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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c deleted file mode 100644 index 4f1fce43a1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c +++ /dev/null @@ -1,2391 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file nea_server.c - * @brief Nokia Event API - event notifier implementation. - * - * @author Pekka Pessi - * @author Martti Mela - * - * @date Created: Wed Feb 14 18:37:04 EET 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "nea_debug.h" - -#ifndef _MSC_VER -#define NONE ((void *)- 1) -#else -#define NONE ((void *)(INT_PTR)- 1) -#endif - -#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 -#include - -#include -#include -#include -#include -#include -#include -#include - -/** Number of primary views (with different MIME type or content) */ -#define NEA_VIEW_MAX (8) - -/** @internal 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; -}; - - -/** @internal 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; - -/** @internal 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; - - /** @internal 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 - - -/** @internal 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_reported :1 ; /**< Made watcher report upon un-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. */ -su_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; -} - -su_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: - *
- * - *
SIPTAG_CONTACT() or SIPTAG_CONTACT_STR() - *
The target address of the event server. - * - *
SIPTAG_ALLOW_EVENTS() - *
The initial list of events supported by eventity. This list is - * extended whenever a new event is created with nea_event_tcreate(). - * - *
SIPTAG_SERVER_STR() - *
The @b Server header for the event server. - * - *
NEATAG_MINSUB() - *
Minimum duration of a subscription. - * - *
NEATAG_THROTTLE() - *
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. - * - *
NEATAG_MINTHROTTLE() - *
Minimum allowed throttle value (by default, 5 seconds). - * - *
NEATAG_EVENTLIST() - *
If true, the subscribers must support eventlists. If SIPTAG_REQUIRE() - * is given, it must contain the "eventlist" feature. - * - *
NEATAG_DIALOG() - *
Give an optional NTA destination leg to event server. - * - *
SIPTAG_REQUIRE()/SIPTAG_REQUIRE_STR() - *
The @b Require header for the event server. The subscribers must - * indicate support the specified features. - * - *
- * - * @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" VA_NONE)); - return NULL; - } - - if (min_expires > expires || expires > max_expires) { - SU_DEBUG_5(("nea_server_create(): invalid expiration range\n" VA_NONE)); - 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", (void *)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", (void *)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", (void *)nes)); - return 100; - } - - SU_DEBUG_5(("nea_server_shutdown(%p)\n", (void *)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", (void *)nes)); - nes->nes_pending_destroy = 1; - return; - } - - SU_DEBUG_5(("nea_server_destroy(%p)\n", (void *)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: - *
- * - *
SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() - *
Updated event content. - * - *
SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR(). - *
MIME type of the content. - * - *
NEATAG_FAKE(fak) - *
If @a fake is true, 'fake' view is updated. - * - *
NEATAG_VIEW(view) - *
If included in tagged arguments, @a view is * updated. Used when - * updating secondary view. - * - *
NEATAG_VERSION(version) - *
The application-provided @a version for - * event content. After updated content has been sent to subscriber, @a - * version is copied to subscriber information structure. - * - *
NEATAG_EVMAGIC(context) - *
Application-provided @a context pointer. - * The @a context pointer is returned by nea_view_magic() function. - * - *
NEATAG_RELIABLE(reliable) - *
The @a reliable flag determines how overlapping updates are handled. - * If @a reliable is true, all updates are delivered to the subscribers. - * - *
NEATAG_THROTTLE(throttl) - *
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. - * - *
NEATAG_MINTHROTTLE() - *
Minimum allowed throttle value for updated event view. - * - *
- * - * @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 (su_casematch(cts, evv->evv_content_type->c_type)) - 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", (void *)nes, - ev->ev_event->o_type, (evv->evv_content_type ? evv->evv_content_type->c_type : "N/A"))); - - 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 (su_casematch(content_type, ev->ev_views[i]->evv_content_type->c_type)) - 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", (void *)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; - - if (nes == NULL || callback == NULL || name == NULL) - return NULL; - - /* 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, - sip_time_t now) -{ - if (!nes->nes_in_callback) { - nes->nes_in_callback = 1; - if (ev->ev_callback && !s->s_reported) { - nea_subnode_t sn[1]; - - nea_subnode_init(sn, s, now); - - if (sn->sn_expires == 0 || sn->sn_state == nea_terminated) - s->s_reported = 1; - - 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 = nea_sub_create(nes); - if (s == NULL) - return 500; - - 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 ((su_casematch(ac->ac_type, type)) || - (su_casematch(ac->ac_subtype, "*") && - su_casenmatch(ac->ac_type, type, - ac->ac_subtype - ac->ac_type))) { - 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, now) < 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 suppress = 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 (suppress && 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; - } - - suppress = (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(!suppress, - SIPTAG_CONTENT_TYPE(n_evq->evq_content_type)), - TAG_IF(!suppress, - 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, now); - } - } - 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; - sip_time_t now = sip_now(); - - 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) { - 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, now); - } - - 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 = su_casematch(reason, "rejected"); - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c deleted file mode 100644 index 928e81e780..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_tag.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Martti Mela - * - * @date Created: Tue Jul 24 22:28:34 2001 ppessi - */ - -#include "config.h" - -#include -#include - -#define TAG_NAMESPACE "nea" - -#include "sofia-sip/nea.h" -#include -#include -#include - -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h b/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h deleted file mode 100644 index f8c37e822c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NEA_H -/**@file sofia-sip/nea.h - * @brief Event API for SIP - * - * @author Pekka Pessi - * @author Martti Mela - * - * @date Created: Fri Feb 7 13:23:44 EET 2003 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif - -#include - -#ifndef NTA_H -#include -#endif - -#ifndef NEA_TAG_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h b/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h deleted file mode 100644 index c29b969505..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nea/sofia-sip/nea_tag.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NEA_TAG_H - -/**@file sofia-sip/nea_tag.h - * @brief Tags for Nokia User Agent Library - * - * @author Pekka Pessi - * @author Martti Mela - * - * @date Created: Mon Nov 28 18:54:26 EET 2005 mela - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef URL_TAG_H -#include -#endif -#ifndef SIP_TAG_H -#include -#endif -#ifndef NTA_TAG_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog deleted file mode 100644 index a37209f8af..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/ChangeLog +++ /dev/null @@ -1,102 +0,0 @@ -2005-11-08 Pekka Pessi - - * Renamed nta_test.c as test_nta.c. - -2005-10-21 Pekka Pessi - - * 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 - - * 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 - - * 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 - - * Fixed memory leak in nta_agent_create()/nta_agent_destroy(). - - M ./libsofia-sip-ua/nta/nta.c -2 +2 - -2005-10-04 Pekka Pessi - - * Added agent.pem and cafile.pem for TLS testing. - -2005-08-29 Pekka Pessi - - * nta.c (nta_agent_set_params()): Returning -1 upon an error. - -2005-08-26 Pekka Pessi - - * nta.c, nta_test.c: Fixed alias usage. - -2005-08-10 Pekka Pessi - - * Now we can start agent without any transport interfaces. - - Added flag for disabling server-side rport. - -2005-08-03 Pekka Pessi - - * Fixed running tests on IPv6. Added portbind. - -2005-07-14 Pekka Pessi - - * 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 - - * run_nta_test: Fixed portbind/bind test. - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile.in deleted file mode 100644 index 8b3ec0b511..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/Doxyfile.in +++ /dev/null @@ -1,26 +0,0 @@ -PROJECT_NAME = "nta" -OUTPUT_DIRECTORY = ../docs/html/nta - -INPUT = @srcdir@/nta.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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/nua.doxytags=../nua - -GENERATE_TAGFILE = ../docs/nta.doxytags - -EXCLUDE_PATTERNS += sl_*.h sl_*.c nta_compat.* - -ALIASES += - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../sip/sip.doxyaliases \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am deleted file mode 100644 index c450fd1a73..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/Makefile.am +++ /dev/null @@ -1,95 +0,0 @@ -# -# Makefile.am for nta module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 \ - -I$(top_srcdir)/s2check \ - -I$(srcdir)/../stun -I ../stun - -# ---------------------------------------------------------------------- -# Build targets - -noinst_LTLIBRARIES = libnta.la - -check_PROGRAMS = check_nta test_nta_api test_nta portbind -dist_noinst_SCRIPTS = run_test_nta_api run_test_nta - -TESTS = run_check_nta 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 \ - ${top_builddir}/s2check/libs2.a -lz - -test_nta_LDFLAGS = -static - -MOSTLYCLEANFILES += .test[0-9]* - -if HAVE_CHECK - -check_nta_SOURCES = check_nta.c check_nta.h \ - check_nta_api.c \ - check_nta_client.c - -check_nta_LDADD = ${LDADD} @CHECK_LIBS@ - -else -check_nta_SOURCES = exit77.c -endif - -# ---------------------------------------------------------------------- -# Install and distribution rules - -EXTRA_DIST = nta.docs sl_utils.docs \ - agent.pem cafile.pem \ - invite.msc $(BUILT_SOURCES) - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - -# Generate list of nta tags -TAG_DLL_FLAGS = LIST=nta_tag_list diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem b/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem deleted file mode 100644 index 1e92b556be..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/agent.pem +++ /dev/null @@ -1,35 +0,0 @@ ------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----- diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem b/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem deleted file mode 100644 index 083de3746a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/cafile.pem +++ /dev/null @@ -1,19 +0,0 @@ ------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----- diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.c deleted file mode 100644 index 93d635abf1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_nta.c - * @brief 2nd test Suite for Sofia SIP Transaction Engine - * - * @author Pekka Pessi - * - * @date Created: Wed Apr 30 12:48:27 EEST 2008 ppessi - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nta.h" - -#include "s2dns.h" -#include "s2base.h" -#include "s2sip.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* -- Globals -------------------------------------------------------------- */ - -struct s2nta *s2; - -/* -- main ----------------------------------------------------------------- */ - -static void usage(int exitcode) -{ - fprintf(exitcode ? stderr : stdout, - "usage: %s [--xml=logfile] case,...\n", s2_tester); - exit(exitcode); -} - -int main(int argc, char *argv[]) -{ - int i, failed = 0, selected = 0; - char const *xml = NULL; - Suite *suite; - SRunner *runner; - - s2_tester = "check_nta"; - s2_suite("NTA"); - - if (getenv("CHECK_NTA_VERBOSE")) - s2_start_stop = strtoul(getenv("CHECK_NTA_VERBOSE"), NULL, 10); - - for (i = 1; argv[i]; i++) { - if (su_strnmatch(argv[i], "--xml=", strlen("--xml="))) { - xml = argv[i] + strlen("--xml="); - } - else if (su_strmatch(argv[i], "--xml")) { - if (!(xml = argv[++i])) - usage(2); - } - else if (su_strmatch(argv[i], "-v")) { - s2_start_stop = 1; - } - else if (su_strmatch(argv[i], "-?") || - su_strmatch(argv[i], "-h") || - su_strmatch(argv[i], "--help")) - usage(0); - else { - s2_select_tests(argv[i]); - selected = 1; - } - } - - if (!selected) - s2_select_tests(getenv("CHECK_NTA_CASES")); - - suite = suite_create("Unit tests for nta (Sofia-SIP Transaction Engine)"); - - suite_add_tcase(suite, check_nta_api_1_0()); - suite_add_tcase(suite, check_nta_client_2_0()); - suite_add_tcase(suite, check_nta_client_2_1()); - suite_add_tcase(suite, check_nta_client_2_2()); - - runner = srunner_create(suite); - - if (xml) - srunner_set_xml(runner, argv[1]); - - srunner_run_all(runner, CK_ENV); - failed = srunner_ntests_failed(runner); - srunner_free(runner); - - exit(failed ? EXIT_FAILURE : EXIT_SUCCESS); -} - - -/* -- NTA callbacks -------------------------------------------------------- */ - -struct event * -s2_nta_remove_event(struct event *e) -{ - if ((*e->prev = e->next)) - e->next->prev = e->prev; - e->prev = NULL, e->next = NULL; - return e; -} - -void -s2_nta_free_event(struct event *e) -{ - if (e) { - if (e->prev) { - if ((*e->prev = e->next)) - e->next->prev = e->prev; - } - if (e->msg) - msg_destroy(e->msg); - free(e); - } -} - -void -s2_nta_flush_events(void) -{ - while (s2->events) { - s2_nta_free_event(s2->events); - } -} - -struct event * -s2_nta_next_event(void) -{ - for (;;) { - if (s2->events) - return s2_nta_remove_event(s2->events); - su_root_step(s2->root, 1); - } -} - -struct event * -s2_nta_vwait_for(enum wait_for wait_for0, - void const *value0, - va_list va0) -{ - struct event *e; - - for (;;) { - for (e = s2->events; e; e = e->next) { - va_list va; - enum wait_for wait_for; - void const *value; - - va_copy(va, va0); - - for (wait_for = wait_for0, value = value0; - wait_for; - wait_for = va_arg(va, enum wait_for), - value = va_arg(va, void const *)) { - switch (wait_for) { - case wait_for_amagic: - if (value != e->amagic) - goto next; - break; - case wait_for_omagic: - if (value != e->omagic) - goto next; - break; - case wait_for_orq: - if (value != e->orq) - goto next; - break; - case wait_for_lmagic: - if (value != e->lmagic) - goto next; - break; - case wait_for_leg: - if (value != e->leg) - goto next; - break; - case wait_for_imagic: - if (value != e->imagic) - goto next; - break; - case wait_for_irq: - if (value != e->irq) - goto next; - break; - case wait_for_method: - if ((sip_method_t)value != e->method) - goto next; - break; - case wait_for_method_name: - if (!su_strmatch(value, e->method_name)) - goto next; - break; - case wait_for_status: - if ((int)value != e->status) - goto next; - break; - case wait_for_phrase: - if (!su_casematch(value, e->phrase)) - goto next; - break; - } - } - - next: - va_end(va); - - if (!wait_for) - return s2_nta_remove_event(e); - } - su_root_step(s2->root, 1); - } -} - -struct event * -s2_nta_wait_for(enum wait_for wait_for, - void const *value, - ...) -{ - struct event *e; - va_list va; - - va_start(va, value); - e = s2_nta_vwait_for(wait_for, value, va); - va_end(va); - - return e; -} - -int -s2_nta_check_request(enum wait_for wait_for, - void const *value, - ...) -{ - struct event *e; - va_list va; - - va_start(va, value); - e = s2_nta_vwait_for(wait_for, value, va); - va_end(va); - - s2_nta_free_event(e); - return e != NULL; -} - -int -s2_nta_msg_callback(nta_agent_magic_t *magic, - nta_agent_t *nta, - msg_t *msg, - sip_t *sip) -{ - struct event *e, **prev; - - e = calloc(1, sizeof *e); - - e->amagic = magic; - e->msg = msg; - e->sip = sip; - - if (sip->sip_request) { - e->method = sip->sip_request->rq_method; - e->method_name = sip->sip_request->rq_method_name; - } - else { - e->status = sip->sip_status->st_status; - e->phrase = sip->sip_status->st_phrase; - } - - for (prev = &s2->events; *prev; prev = &(*prev)->next) - ; - *prev = e, e->prev = prev; - - return 0; -} - -int -s2_nta_orq_callback(nta_outgoing_magic_t *magic, - nta_outgoing_t *orq, - sip_t const *sip) -{ - struct event *e, **prev; - - e = calloc(1, sizeof *e); - - e->omagic = magic; - e->orq = orq; - e->msg = nta_outgoing_getresponse(orq); - e->sip = sip_object(e->msg); - - e->status = nta_outgoing_status(orq); - e->phrase = sip ? sip->sip_status->st_phrase : ""; - - for (prev = &s2->events; *prev; prev = &(*prev)->next) - ; - *prev = e, e->prev = prev; - - return 0; -} - -int -s2_nta_leg_callback(nta_leg_magic_t *magic, - nta_leg_t *leg, - nta_incoming_t *irq, - sip_t const *sip) -{ - struct event *e, **prev; - - e = calloc(1, sizeof *e); - - e->lmagic = magic; - e->leg = leg; - e->irq = irq; - - e->msg = nta_incoming_getrequest(irq); - e->sip = sip_object(e->msg); - - e->method = e->sip->sip_request->rq_method; - e->method_name = e->sip->sip_request->rq_method_name; - - for (prev = &s2->events; *prev; prev = &(*prev)->next) - ; - *prev = e, e->prev = prev; - - return 0; -} - -int -s2_nta_irq_callback(nta_incoming_magic_t *magic, - nta_incoming_t *irq, - sip_t const *sip) -{ - struct event *e, **prev; - - e = calloc(1, sizeof *e); - - e->imagic = magic; - e->irq = irq; - e->msg = nta_incoming_getrequest_ackcancel(irq); - e->sip = sip_object(e->msg); - - e->method = e->sip ? e->sip->sip_request->rq_method : 0; - e->method_name = e->sip ? e->sip->sip_request->rq_method_name : NULL; - - for (prev = &s2->events; *prev; prev = &(*prev)->next) - ; - *prev = e, e->prev = prev; - - return 0; -} - -/* ====================================================================== */ - -SOFIAPUBVAR su_log_t nta_log[]; -SOFIAPUBVAR su_log_t sresolv_log[]; -SOFIAPUBVAR su_log_t tport_log[]; -SOFIAPUBVAR su_log_t su_log_default[]; - -void -s2_nta_setup_logs(int level) -{ - su_log_soft_set_level(su_log_default, level); - su_log_soft_set_level(tport_log, level); - su_log_soft_set_level(nta_log, level); - su_log_soft_set_level(sresolv_log, level); - - if (getenv("TPORT_LOG") == NULL && getenv("S2_TPORT_LOG") == NULL) { - if (s2sip) - tport_set_params(s2sip->master, TPTAG_LOG(level > 1), TAG_END()); - } -} - -void -s2_nta_setup(char const *label, - char const * const *transports, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - s2_setup(label); - s2_nta_setup_logs(0); - s2_dns_setup(s2base->root); - ta_start(ta, tag, value); - s2_sip_setup("example.org", transports, ta_tags(ta)); - ta_end(ta); - assert(s2sip->contact); - - s2_dns_domain("example.org", 1, - "s2", 1, s2sip->udp.contact ? s2sip->udp.contact->m_url : NULL, - "s2", 1, s2sip->tcp.contact ? s2sip->tcp.contact->m_url : NULL, - "s2", 1, s2sip->tls.contact ? s2sip->tls.contact->m_url : NULL, - NULL); -} - -nta_agent_t * -s2_nta_agent_setup(url_string_t const *bind_url, - nta_message_f *callback, - nta_agent_magic_t *magic, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - assert(s2base); - - s2 = su_home_new(sizeof *s2); assert(s2); - s2->root = su_root_clone(s2base->root, s2); assert(s2->root); - fail_unless(s2->root != NULL); - - ta_start(ta, tag, value); - s2->nta = - nta_agent_create(s2->root, - bind_url ? bind_url : URL_STRING_MAKE("sip:*:*"), - callback, - magic, - /* Use internal DNS server */ - /* Force sresolv to use localhost and s2dns as DNS server */ -#if HAVE_WIN32 - SRESTAG_RESOLV_CONF("NUL"), -#else - SRESTAG_RESOLV_CONF("/dev/null"), -#endif - ta_tags(ta)); - ta_end(ta); - - assert(s2->nta); - - if (callback == NULL) - s2->default_leg = nta_leg_tcreate(s2->nta, s2_nta_leg_callback, NULL, - NTATAG_NO_DIALOG(1), - TAG_END()); - - return s2->nta; -} - -void s2_nta_teardown(void) -{ - if (s2) { - s2_nta_flush_events(); - - if (s2->default_leg) - nta_leg_destroy(s2->default_leg), s2->default_leg = NULL; - nta_agent_destroy(s2->nta), s2->nta = NULL; - su_root_destroy(s2->root), s2->root = NULL; - su_home_unref(s2->home); - s2 = NULL; - } - - s2_dns_teardown(); - s2_sip_teardown(); - s2_teardown(); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.h b/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.h deleted file mode 100644 index 362e17df1b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 CHECK_NTA_H -#define CHECK_NTA_H - -#include - -#include -#include -#include - -#include - -#include "s2sip.h" - -extern struct s2nta { - su_home_t home[1]; - - nta_agent_t *nta; - - su_root_t *root; - - nta_leg_t *default_leg; - - struct event { - struct event *next, **prev; - - nta_agent_magic_t *amagic; - - nta_outgoing_magic_t *omagic; - nta_outgoing_t *orq; - - nta_leg_magic_t *lmagic; - nta_leg_t *leg; - - nta_incoming_magic_t *imagic; - nta_incoming_t *irq; - - sip_method_t method; - char const *method_name; - - int status; - char const *phrase; - - msg_t *msg; - sip_t *sip; - } *events; -} *s2; - -struct event *s2_nta_remove_event(struct event *e); -void s2_nta_free_event(struct event *e); -void s2_nta_flush_events(void); -struct event *s2_nta_next_event(void); - -enum wait_for { - wait_for_amagic = 1, - wait_for_omagic, - wait_for_orq, - wait_for_lmagic, - wait_for_leg, - wait_for_imagic, - wait_for_irq, - wait_for_method, - wait_for_method_name, - wait_for_status, - wait_for_phrase -}; - -struct event *s2_nta_vwait_for(enum wait_for, - void const *value, - va_list va); - -struct event *s2_nta_wait_for(enum wait_for, - void const *value, - ...); - -int s2_nta_check_for(enum wait_for, - void const *value, - ...); - -int s2_nta_msg_callback(nta_agent_magic_t *magic, - nta_agent_t *nta, - msg_t *msg, - sip_t *sip); -int s2_nta_orq_callback(nta_outgoing_magic_t *magic, - nta_outgoing_t *orq, - sip_t const *sip); -int s2_nta_leg_callback(nta_leg_magic_t *magic, - nta_leg_t *leg, - nta_incoming_t *irq, - sip_t const *sip); -int s2_nta_irq_callback(nta_incoming_magic_t *magic, - nta_incoming_t *irq, - sip_t const *sip); - -void s2_nta_setup_logs(int level); -void s2_nta_setup(char const *label, - char const * const *transports, - tag_type_t tag, tag_value_t value, ...); - -nta_agent_t *s2_nta_agent_setup(url_string_t const *bind_url, - nta_message_f *callback, - nta_agent_magic_t *magic, - tag_type_t tag, tag_value_t value, ...); -void s2_nta_teardown(void); - -TCase *check_nta_api_1_0(void); -TCase *check_nta_client_2_0(void); -TCase *check_nta_client_2_1(void); -TCase *check_nta_client_2_2(void); - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_api.c b/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_api.c deleted file mode 100644 index 3f623d2117..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_api.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_nta_api.c - * - * @brief Check-driven tester for NTA API - * - * @author Pekka Pessi - * - * @copyright (C) 2009 Nokia Corporation. - */ - -#include "config.h" - -#include "check_nta.h" -#include "s2base.h" -#include "nta_internal.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#define NONE ((void *)-1) - -static void -api_setup(void) -{ - s2_nta_setup("NTA", NULL, TAG_END()); -} - -static void -api_teardown(void) -{ - mark_point(); - s2_nta_teardown(); -} - -START_TEST(api_1_0_0) -{ - su_root_t *root = s2base->root; - nta_agent_t *nta; - su_home_t home[1]; - su_nanotime_t nano; - nta_agent_magic_t *amagic = (void *)(home + 1); - nta_outgoing_magic_t *omagic = (void *)(home + 2); - msg_t *msg; - - memset(home, 0, sizeof home); home->suh_size = (sizeof home); - su_home_init(home); - - fail_unless(nta_agent_create(NULL, - (url_string_t *)"sip:*:*", - NULL, - NULL, - TAG_END()) == NULL); - - fail_unless(nta_agent_create(root, - (url_string_t *)"http://localhost:*/invalid/bind/url", - NULL, - NULL, - TAG_END()) == NULL); - - fail_unless(nta_agent_create(root, - (url_string_t *)"sip:*:*;transport=XXX", - NULL, - NULL, - TAG_END()) == NULL); - mark_point(); - nta = nta_agent_create(root, - (url_string_t *)"sip:*:*", - NULL, - NULL, - TAG_END()); - fail_unless(nta != NULL); - - mark_point(); - nta_agent_destroy(NULL); - mark_point(); - nta_agent_destroy(nta); - - mark_point(); - nta = nta_agent_create(root, - (url_string_t *)"sip:*:*", - s2_nta_msg_callback, - amagic, - TAG_END()); - fail_unless(nta != NULL); - - fail_unless(nta_agent_contact(NULL) == NULL); - fail_unless(nta_agent_via(NULL) == NULL); - fail_if(strcmp(nta_agent_version(nta), nta_agent_version(NULL))); - fail_unless(nta_agent_magic(NULL) == NULL); - fail_unless(nta_agent_magic(nta) == amagic); - fail_unless(nta_agent_add_tport(NULL, NULL, TAG_END()) == -1); - fail_unless(nta_agent_newtag(home, "tag=%s", NULL) == NULL); - fail_unless(nta_agent_newtag(home, "tag=%s", nta) != NULL); - - fail_unless(nta_msg_create(NULL, 0) == NULL); - fail_unless(nta_msg_complete(NULL) == -1); - - fail_unless((msg = nta_msg_create(nta, 0)) != NULL); - fail_unless(nta_msg_complete(msg) == -1); - fail_unless( - nta_msg_request_complete(msg, NULL, SIP_METHOD(FOO), NULL) == -1); - fail_unless(nta_is_internal_msg(NULL) == 0); - fail_unless(nta_is_internal_msg(msg) == 0); - fail_unless(msg_set_flags(msg, NTA_INTERNAL_MSG)); - fail_unless(nta_is_internal_msg(msg) == 1); - mark_point(); msg_destroy(msg); mark_point(); - - fail_unless(nta_leg_tcreate(NULL, NULL, NULL, TAG_END()) == NULL); - mark_point(); nta_leg_destroy(NULL); mark_point(); - fail_unless(nta_leg_magic(NULL, NULL) == NULL); - mark_point(); nta_leg_bind(NULL, NULL, NULL); mark_point(); - fail_unless(nta_leg_tag(NULL, "fidsafsa") == NULL); - fail_unless(nta_leg_rtag(NULL, "fidsafsa") == NULL); - fail_unless(nta_leg_get_tag(NULL) == NULL); - fail_unless(nta_leg_client_route(NULL, NULL, NULL) == -1); - fail_unless(nta_leg_client_reroute(NULL, NULL, NULL, 0) == -1); - fail_unless(nta_leg_server_route(NULL, NULL, NULL) == -1); - fail_unless(nta_leg_by_uri(NULL, NULL) == NULL); - fail_unless( - nta_leg_by_dialog(NULL, NULL, NULL, NULL, NULL, NULL, NULL) == NULL); - fail_unless( - nta_leg_by_dialog(nta, NULL, NULL, NULL, NULL, NULL, NULL) == NULL); - - fail_unless(nta_leg_make_replaces(NULL, NULL, 1) == NULL); - fail_unless(nta_leg_by_replaces(NULL, NULL) == NULL); - - fail_unless(nta_incoming_create(NULL, NULL, NULL, NULL, TAG_END()) == NULL); - fail_unless(nta_incoming_create(nta, NULL, NULL, NULL, TAG_END()) == NULL); - - mark_point(); nta_incoming_bind(NULL, NULL, NULL); mark_point(); - fail_unless(nta_incoming_magic(NULL, NULL) == NULL); - - fail_unless(nta_incoming_find(NULL, NULL, NULL) == NULL); - fail_unless(nta_incoming_find(nta, NULL, NULL) == NULL); - - fail_unless(nta_incoming_tag(NULL, NULL) == NULL); - fail_unless(nta_incoming_gettag(NULL) == NULL); - - fail_unless(nta_incoming_status(NULL) == 400); - fail_unless(nta_incoming_method(NULL) == sip_method_invalid); - fail_unless(nta_incoming_method_name(NULL) == NULL); - fail_unless(nta_incoming_url(NULL) == NULL); - fail_unless(nta_incoming_cseq(NULL) == 0); - fail_unless(nta_incoming_received(NULL, &nano) == 0); - fail_unless(nano == 0); - - fail_unless(nta_incoming_set_params(NULL, TAG_END()) == -1); - - fail_unless(nta_incoming_getrequest(NULL) == NULL); - fail_unless(nta_incoming_getrequest_ackcancel(NULL) == NULL); - fail_unless(nta_incoming_getresponse(NULL) == NULL); - - fail_unless( - nta_incoming_complete_response(NULL, NULL, 800, "foo", TAG_END()) == -1); - - fail_unless(nta_incoming_treply(NULL, SIP_200_OK, TAG_END()) == -1); - fail_unless(nta_incoming_mreply(NULL, NULL) == -1); - - mark_point(); nta_incoming_destroy(NULL); mark_point(); - - fail_unless( - nta_outgoing_tcreate(NULL, s2_nta_orq_callback, omagic, - URL_STRING_MAKE("sip:localhost"), - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:localhost"), - TAG_END()) == NULL); - - fail_unless( - nta_outgoing_mcreate(NULL, s2_nta_orq_callback, omagic, - URL_STRING_MAKE("sip:localhost"), - NULL, - TAG_END()) == NULL); - - fail_unless(nta_outgoing_default(NULL, NULL, NULL) == NULL); - - fail_unless(nta_outgoing_bind(NULL, NULL, NULL) == -1); - fail_unless(nta_outgoing_magic(NULL, NULL) == NULL); - - fail_unless(nta_outgoing_status(NULL) == 500); - fail_unless(nta_outgoing_method(NULL) == sip_method_invalid); - fail_unless(nta_outgoing_method_name(NULL) == NULL); - fail_unless(nta_outgoing_cseq(NULL) == 0); - - fail_unless(nta_outgoing_delay(NULL) == UINT_MAX); - fail_unless(nta_outgoing_request_uri(NULL) == NULL); - fail_unless(nta_outgoing_route_uri(NULL) == NULL); - - fail_unless(nta_outgoing_getresponse(NULL) == NULL); - fail_unless(nta_outgoing_getrequest(NULL) == NULL); - - fail_unless(nta_outgoing_tagged(NULL, NULL, NULL, NULL, NULL) == NULL); - fail_unless(nta_outgoing_cancel(NULL) == -1); - fail_unless(nta_outgoing_tcancel(NULL, NULL, NULL, TAG_END()) == NULL); - mark_point(); nta_outgoing_destroy(NULL); mark_point(); - - fail_unless(nta_outgoing_find(NULL, NULL, NULL, NULL) == NULL); - fail_unless(nta_outgoing_find(nta, NULL, NULL, NULL) == NULL); - - fail_unless(nta_outgoing_status(NONE) == 500); - fail_unless(nta_outgoing_method(NONE) == sip_method_invalid); - fail_unless(nta_outgoing_method_name(NONE) == NULL); - fail_unless(nta_outgoing_cseq(NONE) == 0); - - fail_unless(nta_outgoing_delay(NONE) == UINT_MAX); - fail_unless(nta_outgoing_request_uri(NONE) == NULL); - fail_unless(nta_outgoing_route_uri(NONE) == NULL); - - fail_unless(nta_outgoing_getresponse(NONE) == NULL); - fail_unless(nta_outgoing_getrequest(NONE) == NULL); - - fail_unless(nta_outgoing_tagged(NONE, NULL, NULL, NULL, NULL) == NULL); - fail_unless(nta_outgoing_cancel(NONE) == -1); - fail_unless(nta_outgoing_tcancel(NONE, NULL, NULL, TAG_END()) == NULL); - mark_point(); nta_outgoing_destroy(NONE); mark_point(); - - fail_unless(nta_reliable_treply(NULL, NULL, NULL, 0, NULL, TAG_END()) == NULL); - fail_unless(nta_reliable_mreply(NULL, NULL, NULL, NULL) == NULL); - mark_point(); nta_reliable_destroy(NULL); mark_point(); - - mark_point(); nta_agent_destroy(nta); mark_point(); - mark_point(); su_home_deinit(home); mark_point(); -} -END_TEST - -/* ---------------------------------------------------------------------- */ - -TCase *check_nta_api_1_0(void) -{ - TCase *tc = tcase_create("NTA 1 - API"); - - tcase_add_checked_fixture(tc, api_setup, api_teardown); - - tcase_set_timeout(tc, 10); - - tcase_add_test(tc, api_1_0_0); - - return tc; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_client.c b/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_client.c deleted file mode 100644 index cd29ae34c0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/check_nta_client.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_nta_client.c - * - * @brief Check-driven tester for NTA client transactions - * - * @author Pekka Pessi - * - * @copyright (C) 2009 Nokia Corporation. - */ - -#include "config.h" - -#include "check_nta.h" -#include "s2base.h" -#include "s2dns.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define NONE ((void *)-1) - -static void -client_setup(void) -{ - s2_nta_setup("NTA", NULL, TAG_END()); - s2_nta_agent_setup(URL_STRING_MAKE("sip:0.0.0.0:*"), NULL, NULL, - NTATAG_DEFAULT_PROXY("sip:example.org"), - TAG_END()); -} - -static void -client_setup_udp_only_server(void) -{ - char const * const transports[] = { "udp", NULL }; - - s2_nta_setup("NTA", transports, TAG_END()); - s2_nta_agent_setup(URL_STRING_MAKE("sip:0.0.0.0:*"), NULL, NULL, - NTATAG_DEFAULT_PROXY(s2sip->contact->m_url), - TAG_END()); -} - -static void -client_setup_tcp_only_server(void) -{ - char const * const transports[] = { "tcp", NULL }; - - s2_nta_setup("NTA", transports, TAG_END()); - s2_nta_agent_setup(URL_STRING_MAKE("sip:0.0.0.0:*"), NULL, NULL, - NTATAG_DEFAULT_PROXY(s2sip->contact->m_url), - TAG_END()); -} - -static void -client_teardown(void) -{ - mark_point(); - s2_nta_teardown(); -} - -START_TEST(client_2_0_0) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - - S2_CASE("client-2.0.0", "Send MESSAGE", - "Basic non-INVITE transaction with outbound proxy"); - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - TAG_END()); - fail_unless(orq != NULL); - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - s2_sip_respond_to(request, NULL, 200, "2.0.0", TAG_END()); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_sip_free_message(request); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -START_TEST(client_2_0_1) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - - S2_CASE("client-2.0.1", "Send MESSAGE", - "Basic non-INVITE transaction with " - "numeric per-transaction outbound proxy"); - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, - (url_string_t *)s2sip->contact->m_url, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - TAG_END()); - fail_unless(orq != NULL); - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - s2_sip_respond_to(request, NULL, 200, "OK 2.0.1", TAG_END()); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_sip_free_message(request); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -START_TEST(client_2_0_2) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - - char payload[2048]; - - S2_CASE("client-2.0.2", "Send MESSAGE", - "Basic non-INVITE transaction exceeding " - "default path MTU (1300 bytes)"); - - memset(payload, 'x', sizeof payload); - payload[(sizeof payload) - 1] = '\0'; - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - SIPTAG_PAYLOAD_STR(payload), - TAG_END()); - fail_unless(orq != NULL); - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - fail_unless(request->sip->sip_via->v_protocol == sip_transport_tcp); - - s2_sip_respond_to(request, NULL, 200, "OK 2.0.2", TAG_END()); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -/* ---------------------------------------------------------------------- */ - -TCase *check_nta_client_2_0(void) -{ - TCase *tc = tcase_create("NTA 2.0 - Client"); - - tcase_add_checked_fixture(tc, client_setup, client_teardown); - - tcase_set_timeout(tc, 2); - - tcase_add_test(tc, client_2_0_0); - tcase_add_test(tc, client_2_0_1); - tcase_add_test(tc, client_2_0_2); - - return tc; -} - -/* ---------------------------------------------------------------------- */ - -START_TEST(client_2_1_0) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - - char payload[2048]; - - S2_CASE("client-2.1.0", "Try UDP after trying with TCP", - "TCP connect() is refused"); - - memset(payload, 'x', sizeof payload); - payload[(sizeof payload) - 1] = '\0'; - - client_setup_udp_only_server(); - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - SIPTAG_PAYLOAD_STR(payload), - TAG_END()); - fail_unless(orq != NULL); - - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - fail_unless(request->sip->sip_via->v_protocol == sip_transport_udp); - s2_sip_respond_to(request, NULL, 200, "OK", TAG_END()); - s2_sip_free_message(request); - - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -#undef SU_LOG - -#include "tport_internal.h" - -tport_vtable_t hacked_tcp_vtable; - -/* Make TCP connection to 192.168.255.2:9999 */ -static tport_t * -hacked_tcp_connect(tport_primary_t *pri, - su_addrinfo_t *ai, - tp_name_t const *tpn) -{ - su_addrinfo_t fake_ai[1]; - su_sockaddr_t fake_addr[1]; - uint32_t fake_ip = htonl(0xc0a8ff02); /* 192.168.255.2 */ - - *fake_ai = *ai; - assert(ai->ai_addrlen <= (sizeof fake_addr)); - fake_ai->ai_addr = memcpy(fake_addr, ai->ai_addr, ai->ai_addrlen); - - fake_ai->ai_family = AF_INET; - fake_addr->su_family = AF_INET; - memcpy(&fake_addr->su_sin.sin_addr, &fake_ip, sizeof fake_ip); - fake_addr->su_sin.sin_port = htons(9999); - - return tport_base_connect(pri, fake_ai, ai, tpn); -} - -START_TEST(client_2_1_1) -{ - tport_t *tp; - - nta_outgoing_t *orq; - struct message *request; - struct event *response; - - char payload[2048]; - - S2_CASE("client-2.1.1", "Try UDP after trying with TCP", - "TCP connect() times out"); - - memset(payload, 'x', sizeof payload); - payload[(sizeof payload) - 1] = '\0'; - - client_setup_udp_only_server(); - - hacked_tcp_vtable = tport_tcp_vtable; - hacked_tcp_vtable.vtp_connect = hacked_tcp_connect; - fail_unless(tport_tcp_vtable.vtp_connect == NULL); - - for (tp = tport_primaries(nta_agent_tports(s2->nta)); - tp; - tp = tport_next(tp)) { - if (tport_is_tcp(tp)) { - tp->tp_pri->pri_vtable = &hacked_tcp_vtable; - break; - } - } - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, - NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - SIPTAG_PAYLOAD_STR(payload), - TAG_END()); - fail_unless(orq != NULL); - - s2_fast_forward(1, s2->root); - s2_fast_forward(1, s2->root); - s2_fast_forward(1, s2->root); - s2_fast_forward(1, s2->root); - s2_fast_forward(1, s2->root); - - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - fail_unless(request->sip->sip_via->v_protocol == sip_transport_udp); - s2_sip_respond_to(request, NULL, 200, "OK", TAG_END()); - s2_sip_free_message(request); - - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -START_TEST(client_2_1_2) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - url_t udpurl[1]; - - S2_CASE("client-2.1.2", "Send MESSAGE", - "Non-INVITE transaction to TCP-only server"); - - client_setup_tcp_only_server(); - - *udpurl = *s2sip->tcp.contact->m_url; - udpurl->url_params = "transport=udp"; - - /* Create DNS records for both UDP and TCP, resolver matches UDP */ - s2_dns_domain("udptcp.org", 1, - "s2", 1, udpurl, - "s2", 2, s2sip->tcp.contact->m_url, - NULL); - - /* Sent to tport selected by resolver */ - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, - URL_STRING_MAKE("sip:udptcp.org"), - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), - TAG_END()); - fail_unless(orq != NULL); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 503, - 0); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); - - /* Message size exceeds 1300, tries to use TCP even if NAPTR points to UDP */ - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, - URL_STRING_MAKE("sip:udptcp.org"), - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.0.example.org"), - SIPTAG_FROM_STR(""), -#define ROW "012345678901234567890123456789012345678901234\n" - SIPTAG_PAYLOAD_STR( /* > 1300 bytes */ - "0000 " ROW "0050 " ROW - "0100 " ROW "0150 " ROW - "0200 " ROW "0250 " ROW - "0300 " ROW "0350 " ROW - "0400 " ROW "0450 " ROW - "0500 " ROW "0550 " ROW - "0600 " ROW "0650 " ROW - "0700 " ROW "0750 " ROW - "0800 " ROW "0850 " ROW - "0900 " ROW "0950 " ROW - "1000 " ROW "1050 " ROW - "1100 " ROW "1150 " ROW - "1200 " ROW "1250 " ROW - ), -#undef ROW - TAG_END()); - fail_unless(orq != NULL); - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - fail_unless(request->sip->sip_via->v_protocol == sip_transport_tcp); - s2_sip_respond_to(request, NULL, 200, "2.1.2", TAG_END()); - s2_sip_free_message(request); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - - -TCase *check_nta_client_2_1(void) -{ - TCase *tc = tcase_create("NTA 2.1 - Client"); - - tcase_add_checked_fixture(tc, NULL, client_teardown); - - tcase_set_timeout(tc, 20); - - tcase_add_test(tc, client_2_1_0); - tcase_add_test(tc, client_2_1_1); - tcase_add_test(tc, client_2_1_2); - - return tc; -} - -/* ---------------------------------------------------------------------- */ - -#include - -START_TEST(client_2_2_0) -{ - nta_outgoing_t *orq; - struct message *request; - struct event *response; - static tp_name_t const tpn[1] = {{ "*", "*", "*", "5060", NULL, NULL }}; - static char const * const default_protocols[] = { "udp", "tcp", NULL }; - - char proxy[] = "sip:cname.example.org:0000000"; - - S2_CASE("client-2.2.0", "Send MESSAGE", - "Basic non-INVITE transaction with target using CNAME"); - /* Test for sf.net bug #2531152 */ - - s2_nta_setup("NTA", NULL, TAG_END()); - - fail_unless(s2sip->udp.contact != NULL); - - if (s2sip->udp.contact->m_url->url_port == NULL || - tport_tbind(s2sip->master, tpn, default_protocols, - TPTAG_SERVER(1), - TAG_END()) == -1) { - snprintf(proxy, sizeof proxy, "sip:cname.example.org:%s", - s2sip->udp.contact->m_url->url_port); - } - else { - strcpy(proxy, "sip:cname.example.org"); - } - - s2_dns_default("example.org."); - - s2_dns_record("cname.example.org.", sres_type_a, - "", sres_type_cname, "a.example.org.", - "a", sres_type_a, s2sip->udp.contact->m_url->url_host, - NULL); - - s2_dns_record("cname.example.org.", sres_type_naptr, - "", sres_type_cname, "a.example.org.", - NULL); - - s2_dns_record("cname.example.org.", sres_type_aaaa, - "", sres_type_cname, "a.example.org.", - NULL); - - s2_dns_record("a.example.org.", sres_type_a, - "", sres_type_a, s2sip->udp.contact->m_url->url_host, - NULL); - - - s2_nta_agent_setup(URL_STRING_MAKE("sip:0.0.0.0:*"), NULL, NULL, - NTATAG_DEFAULT_PROXY(proxy), - TAG_END()); - - orq = nta_outgoing_tcreate(s2->default_leg, - s2_nta_orq_callback, NULL, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:test2.2.example.org"), - SIPTAG_FROM_STR(""), - TAG_END()); - fail_unless(orq != NULL); - request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); - fail_unless(request != NULL); - s2_sip_respond_to(request, NULL, 200, "2.2.0", TAG_END()); - response = s2_nta_wait_for(wait_for_orq, orq, - wait_for_status, 200, - 0); - s2_sip_free_message(request); - s2_nta_free_event(response); - nta_outgoing_destroy(orq); -} -END_TEST - -TCase * -check_nta_client_2_2(void) -{ - TCase *tc = tcase_create("NTA 2.2 - Client"); - - tcase_add_checked_fixture(tc, NULL, client_teardown); - - tcase_set_timeout(tc, 2); - - tcase_add_test(tc, client_2_2_0); - - return tc; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/exit77.c b/libs/sofia-sip/libsofia-sip-ua/nta/exit77.c deleted file mode 100644 index ec66ec0b56..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/exit77.c +++ /dev/null @@ -1,4 +0,0 @@ -int main(int argc, char *argv[]) -{ - return 77; /* exit code indicating make check that test has been SKIPped */ -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc b/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc deleted file mode 100644 index 1a83c856f1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/invite.msc +++ /dev/null @@ -1,159 +0,0 @@ -# -# 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c deleted file mode 100644 index d4ed20ed78..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ /dev/null @@ -1,12020 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 and message utility functions - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - * - * @sa - * @RFC3261, @RFC4320 - */ - -#include "config.h" -#ifdef HAVE_ZLIB_COMPRESS -#include -#endif -#include - -/** @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 -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* 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 "nta_internal.h" - -#include -#include -#include -#include -#include -#include -#include - -/* 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 - -#ifndef _MSC_VER -#define NONE ((void *)-1) -#else -#define NONE ((void *)(INT_PTR)-1) -#endif -/* ------------------------------------------------------------------------- */ - -/** 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; - -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; - - nta_update_magic_t *sa_update_magic; - nta_update_tport_f *sa_update_tport; - - nta_error_magic_t *sa_error_magic; - nta_error_tport_f *sa_error_tport; - - uint32_t sa_next; /**< Timestamp for next agent_timer. */ - - msg_mclass_t const *sa_mclass; - uint32_t sa_flags; /**< SIP message flags */ - unsigned sa_preload; /**< Memory preload for SIP messages. */ - - tport_t *sa_tports; - 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; /**< Generator for branch parameters */ - uint64_t sa_tags; /**< Generator for tag parameters */ - -#if HAVE_SOFIA_SRESOLV - sres_resolver_t *sa_resolver; /**< DNS resolver */ - enum nta_res_order_e sa_res_order; /** Resolving order (AAAA/A) */ -#endif - - url_t *sa_default_proxy; /**< Default outbound proxy */ - unsigned sa_bad_req_mask; /**< Request error mask */ - unsigned sa_bad_resp_mask; /**< Response error mask */ - usize_t sa_maxsize; /**< Maximum size of incoming messages */ - usize_t sa_max_proceeding; /**< Maximum size of proceeding queue */ - - unsigned sa_udp_mtu; /**< Maximum size of outgoing UDP requests */ - - unsigned sa_t1; /**< SIP T1 - initial retransmit interval (500 ms) */ - unsigned sa_t2; /**< SIP T2 - maximum retransmit interval (4000 ms) */ - unsigned sa_t4; /**< SIP T4 - clear message time (5000 ms) */ - - - unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */ - - unsigned sa_progress; /**< Progress timer. - Interval between retransmitting - provisional responses. */ - - unsigned sa_timer_c; /**< SIP timer C. - Maximum interval between receiving - provisional responses. */ - - unsigned sa_graylist; /**< Graylisting period */ - unsigned sa_blacklist; /**< Blacklisting period */ - - unsigned sa_drop_prob : 10; /**< NTA is used to test packet drop */ - unsigned sa_is_a_uas : 1; /**< NTA is acting as an User Agent server */ - unsigned sa_is_stateless : 1; /**< Process requests statelessly - * unless they match existing dialog. - */ - unsigned sa_user_via:1; /**< Let application provide @Via headers */ - unsigned sa_extra_100:1; /**< Allow NTA to return "100 Trying" response - * even if application has not responded. - */ - unsigned sa_pass_100:1; /**< Pass the "100 Trying" - * provisional responses to the application - */ - unsigned sa_timeout_408:1; /**< A "408 Request Timeout" message - * is generated when outgoing request expires. - */ - unsigned sa_pass_408:1; /**< A "408 Request Timeout" responses - * are passed to client. - */ - unsigned sa_merge_482 : 1; /**< A "482 Request Merged" response is returned - * to merged requests. - */ - unsigned sa_cancel_2543 : 1; /**< Send a CANCEL to an INVITE without - * waiting for an provisional response. - */ - unsigned sa_cancel_487 : 1; /**< Return 487 response automatically when - * a CANCEL is received. - */ - - unsigned sa_invite_100rel:1; /**< Include 100rel in INVITE requests. */ - unsigned sa_timestamp : 1; /**< Insert @Timestamp in requests. */ - - unsigned sa_tport_ip4 : 1; /**< Transports support IPv4. */ - unsigned sa_tport_ip6 : 1; /**< Transports support IPv6. */ - unsigned sa_tport_udp : 1; /**< Transports support UDP. */ - unsigned sa_tport_tcp : 1; /**< Transports support TCP. */ - unsigned sa_tport_sctp : 1; /**< Transports support SCTP. */ - unsigned sa_tport_tls : 1; /**< Transports support TLS. */ - unsigned sa_tport_ws : 1; /**< Transports support WS. */ - unsigned sa_tport_wss : 1; /**< Transports support WSS. */ - - unsigned sa_use_naptr : 1; /**< Use NAPTR lookup */ - unsigned sa_use_srv : 1; /**< Use SRV lookup */ - - unsigned sa_srv_503 : 1; /**< SRV: choice another destination on 503 RFC 3263 */ - - unsigned sa_tport_threadpool:1; /**< Transports use threadpool */ - - unsigned sa_rport:1; /**< Use rport at client */ - unsigned sa_server_rport:2; /**< Use rport at server */ - unsigned sa_tcp_rport:1; /**< Use rport with tcp, too */ - unsigned sa_tls_rport:1; /**< Use rport with tls, too */ - - unsigned sa_auto_comp:1; /**< Automatically create compartments */ - unsigned sa_in_timer:1; /**< Set when executing timers */ - unsigned sa_use_timer_c:1; /**< Application has set value for timer C */ - - unsigned :0; - -#if HAVE_SMIME - sm_object_t *sa_smime; -#else - void *sa_smime; -#endif - - /** @MaxForwards */ - sip_max_forwards_t sa_max_forwards[1]; - - /** 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; - - /* Statistics */ - struct { - usize_t as_recv_msg; - usize_t as_recv_request; - usize_t as_recv_response; - usize_t as_bad_message; - usize_t as_bad_request; - usize_t as_bad_response; - usize_t as_drop_request; - usize_t as_drop_response; - usize_t as_client_tr; - usize_t as_server_tr; - usize_t as_dialog_tr; - usize_t as_acked_tr; - usize_t as_canceled_tr; - usize_t as_trless_request; - usize_t as_trless_to_tr; - usize_t as_trless_response; - usize_t as_trless_200; - usize_t as_merged_request; - usize_t as_sent_msg; - usize_t as_sent_request; - usize_t as_sent_response; - usize_t as_retry_request; - usize_t as_retry_response; - usize_t as_recv_retry; - usize_t as_tout_request; - usize_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 / Timer 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]; /* Timer C */ - 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; /**< Length of sa_in.re_list */ - - 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_route_set : 1; /**< Route set has been saved */ - unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */ - unsigned leg_tagged : 1; /**< Tagged after creation. - * - * Request missing @To tag matches - * a tagged leg even after tagging. - */ - unsigned leg_compressed:1; - unsigned:0; - nta_request_f *leg_callback; - nta_leg_magic_t *leg_magic; - nta_agent_t *leg_agent; - - url_t const *leg_url; /**< Match incoming requests. */ - char const *leg_method; /**< Match incoming requests. */ - - 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). */ -}; - -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; - - uint32_t irq_timeout; /**< Timer H, I, J */ - uint32_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_extra_100:1; /**< 100 Trying should be sent */ - unsigned irq_tag_set:1; /**< Tag is not from request */ - unsigned irq_compressed:1; - 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; - url_t const *orq_url; /**< Original RequestURI */ - - sip_from_t const *orq_from; - sip_to_t const *orq_to; - char const *orq_tag; /**< Tag from final response. */ - - sip_cseq_t const *orq_cseq; - sip_call_id_t const *orq_call_id; - - msg_t *orq_request; - msg_t *orq_response; - - su_time_t orq_sent; /**< When request was sent? */ - unsigned orq_delay; /**< RTT estimate */ - - uint32_t orq_retry; /**< Timer A, E */ - uint32_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_via_added:1; - unsigned orq_prepared:1; - unsigned orq_canceled:1; - unsigned orq_terminated:1; - unsigned orq_destroyed:1; - unsigned orq_completed:1; - unsigned orq_delayed:1; - unsigned orq_user_tport:1; /**< Application provided tport - don't retry */ - unsigned orq_try_tcp_instead:1; - unsigned orq_try_udp_instead:1; - unsigned orq_reliable:1; /**< Transport is reliable */ - - unsigned orq_forked:1; /**< Tagged fork */ - - /* Attributes */ - unsigned orq_sips:1; - unsigned orq_uas:1; /**< Running this transaction as UAS */ - 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 orq_100rel:1; /**< Support 100rel */ - unsigned:0; /* pad */ - -#if HAVE_SOFIA_SRESOLV - sipdns_resolver_t *orq_resolver; -#endif - url_t *orq_route; /**< Route URL */ - tp_name_t orq_tpn[1]; /**< Where to send request */ - - tport_t *orq_tport; - struct sigcomp_compartment *orq_cc; - tagi_t *orq_tags; /**< Tport tag items */ - - char const *orq_branch; /**< Transaction branch */ - char const *orq_via_branch; /**< @Via branch */ - - int *orq_status2b; /**< Delayed response */ - - nta_outgoing_t *orq_cancel; /**< Delayed CANCEL transaction */ - - nta_outgoing_t *orq_forking; /**< Untagged transaction */ - nta_outgoing_t *orq_forks; /**< Tagged transactions */ - uint32_t orq_rseq; /**< Latest incoming rseq */ - int orq_pending; /**< Request is pending in tport */ -}; - -/* ------------------------------------------------------------------------- */ - -/* 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 *request); - -static int mreply(nta_agent_t *agent, - msg_t *reply, - int status, char const *phrase, - msg_t *req_msg, - tport_t *tport, - int incomplete, - int sdwn_after, - char const *to_tag, - tag_type_t tag, tag_value_t value, ...); - -#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc) TAG_IF(cc && cc != NONE, 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) - -#ifndef UINT32_MAX -#define UINT32_MAX (0xffffffffU) -#endif - -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, - char const *to_tag); -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); -su_inline void incoming_cut_off(nta_incoming_t *irq); -su_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 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, - nta_incoming_t **cancel); -static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip); -su_inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, - tport_t *tport); -su_inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, - tport_t *tport); -su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, - tport_t *tport); -static void request_merge(nta_agent_t *, - msg_t *msg, sip_t *sip, tport_t *tport, - char const *to_tag); -su_inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *); -static void _nta_incoming_timer(nta_agent_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 nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *); -static int reliable_recv(nta_reliable_t *rel, 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); -su_inline void outgoing_cut_off(nta_outgoing_t *orq); -su_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 void _nta_outgoing_timer(nta_agent_t *); -static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip); - -/* Internal message passing */ -union sm_arg_u { - 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_log_global, #SOFIA_DEBUG - */ -#ifdef DOXYGEN -extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */ -#endif - -#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. - * - * Create 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 @e url is @c NONE (iow, (void*)-1), no server sockets are bound. - * @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,... tagged arguments - * - * @TAGS - * NTATAG_ALIASES(), - * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), - * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), - * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), - * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), - * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() - * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), - * NTATAG_REL100(), - * NTATAG_SERVER_RPORT(), - * NTATAG_SIPFLAGS(), - * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), - * NTATAG_STATELESS(), - * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), - * NTATAG_TLS_RPORT(), - * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), - * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), - * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). - * - * @note The value from following tags are stored, but they currently do nothing: - * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() - * - * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url. - * In that case, no server sockets are bound. - * - * @retval handle to the agent when successful, - * @retval NULL upon an error. - * - * @sa NUTAG_ - */ -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)))) { - unsigned timer_c = 0, timer_d = 32000; - - 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 = - /* - * Bit-wise not of these - what is left is suitable for UAs with - * 100rel, timer, events, publish - */ - (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar | - sip_mask_pref | sip_mask_privacy); - agent->sa_bad_resp_mask = - (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar | - sip_mask_pref | sip_mask_privacy); - 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_timer_c = 185 * 1000; - agent->sa_graylist = 600; - 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_srv_503 = 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; - - if (agent->sa_use_timer_c || !agent->sa_is_a_uas) - timer_c = agent->sa_timer_c; - if (timer_d < agent->sa_t1x64) - timer_d = agent->sa_t1x64; - - 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, timer_c); /* C */ - outgoing_queue_init(agent->sa_out.inv_completed, timer_d); /* 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%s client transaction to <" - URL_PRINT_FORMAT ">\n", - __func__, - (orq->orq_forking || orq->orq_forks) ? "forked " : "forking", - orq->orq_method_name, - URL_PRINT_ARGS(orq->orq_to->a_url))); - - orq->orq_forks = NULL, orq->orq_forking = NULL; - 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. - * - * Get a @Contact header, which can be used to reach @a agent. - * - * @param agent NTA agent object - * - * 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 - * - * @return A sip_contact_t object corresponding to the @a agent. - */ -sip_contact_t *nta_agent_contact(nta_agent_t const *agent) -{ - return agent ? agent->sa_contact : NULL; -} - -/** Return a list of @Via headers. - * - * Get @Via headers for all activated transport. - * - * @param agent NTA agent object - * - * @return 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. - * - * Get public @Via headers for all activated transports. - * - * @param agent NTA agent object - * - * @return 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; -} - -/** Match a @Via header @a v with @Via headers in @a agent. - * - */ -static -sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via) -{ - sip_via_t const *v; - - for (v = agent->sa_public_vias; v; v = v->v_next) { - if (!su_casematch(via->v_host, v->v_host)) - continue; - if (!su_strmatch(via->v_port, v->v_port)) - continue; - if (!su_casematch(via->v_protocol, v->v_protocol)) - continue; - return (sip_via_t *)v; - } - - for (v = agent->sa_vias; v; v = v->v_next) { - if (!su_casematch(via->v_host, v->v_host)) - continue; - if (!su_strmatch(via->v_port, v->v_port)) - continue; - if (!su_casematch(via->v_protocol, v->v_protocol)) - continue; - return (sip_via_t *)v; - } - - return NULL; -} - -/** Return @UserAgent header. - * - * Get @UserAgent information with NTA version. - * - * @param agent NTA agent object (may be NULL) - * - * @return 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 = su_random(); - - 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 * (uint64_t)su_nanotime(NULL); - 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) -{ - agent->sa_timer = su_timer_create(su_root_task(agent->sa_root), - NTA_SIP_T1 / 8); -#if 0 - return su_timer_set(agent->sa_timer, - agent_timer, - agent); -#endif - return -(agent->sa_timer == NULL); -} - -/** - * Agent timer routine. - */ -static -void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent) -{ - su_time_t stamp = su_now(); - uint32_t now = su_time_ms(stamp), next, latest; - - now += now == 0; - - agent->sa_next = 0; - - agent->sa_in_timer = 1; - - - _nta_outgoing_timer(agent); - _nta_incoming_timer(agent); - - agent->sa_in_timer = 0; - - /* Calculate next timeout */ - next = latest = now + NTA_TIME_MAX + 1; - -#define NEXT_TIMEOUT(next, p, f, now) \ - (void)(p && (int32_t)(p->f - (next)) < 0 && \ - ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now)))) - - NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now); - NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now); - if (agent->sa_out.inv_proceeding->q_timeout) - NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now); - - NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now); - NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now); - - if (agent->sa_next) - NEXT_TIMEOUT(next, agent, sa_next, now); - -#undef NEXT_TIMEOUT - - if (next == latest) { - /* Do not set timer? */ - /* check it there are still things queued, if there are, that means everything scheduled is > 15 days in the future */ - /* in this case, we had a large time shift, we should schedule for 15 days in the future (which is probably still before now) */ - /* and this should sort itself out on the next run through */ - if ( !agent->sa_out.completed->q_head && !agent->sa_out.trying->q_head && !agent->sa_out.inv_calling->q_head && - !agent->sa_out.re_list && !agent->sa_in.inv_confirmed->q_head && !agent->sa_in.preliminary->q_head && - !agent->sa_in.completed->q_head && !agent->sa_in.inv_completed->q_head && !agent->sa_in.re_list ) { - SU_DEBUG_9(("nta: timer not set\n" VA_NONE)); - return; - } - } - - if (next == now) if (++next == 0) ++next; - - SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set next", (long)(next - now))); - - agent->sa_next = next; - - su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now)); -} - -/** Add uin32_t milliseconds to the time. */ -static su_time_t add_milliseconds(su_time_t t0, uint32_t ms) -{ - unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000; - - t0.tv_usec += usec; - t0.tv_sec += sec; - - if (t0.tv_usec >= 1000000) { - t0.tv_sec += 1; - t0.tv_usec -= 1000000; - } - - return t0; -} - -/** Calculate nonzero value for timeout. - * - * Sets or adjusts agent timer when needed. - * - * @retval 0 if offset is 0 - * @retval timeout (millisecond counter) otherwise - */ -static -uint32_t set_timeout(nta_agent_t *agent, uint32_t offset) -{ - su_time_t now; - uint32_t next, ms; - - if (offset == 0) - return 0; - - now = su_now(); - ms = su_time_ms(now); - - next = ms + offset; - - if (next == 0) next = 1; - - if (agent->sa_in_timer) /* Currently executing timer */ - return next; - - if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) { - /* Set timer */ - if (agent->sa_next) - SU_DEBUG_9(("nta: timer %s to %ld ms\n", "shortened", (long)offset)); - else - SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set", (long)offset)); - - su_timer_set_at(agent->sa_timer, agent_timer, agent, - add_milliseconds(now, offset)); - agent->sa_next = next; - } - - return next; -} - - -/** Return current timeval. */ -static -su_time_t agent_now(nta_agent_t const *agent) -{ - return 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_MAX_PROCEEDING(), - * 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_BLACKLIST(), - * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), - * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), - * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), - * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() - * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), - * NTATAG_REL100(), - * NTATAG_SERVER_RPORT(), - * NTATAG_SIPFLAGS(), - * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(), - * NTATAG_STATELESS(), - * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(), - * NTATAG_TLS_RPORT(), - * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(), - * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(), - * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP(). - * - * @note The value from following tags are stored, but they currently do nothing: - * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME() - */ -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, nC, 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; - usize_t max_proceeding = agent->sa_max_proceeding; - unsigned max_forwards = agent->sa_max_forwards->mf_count; - unsigned 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 timer_c = agent->sa_timer_c; - unsigned timer_d = 32000; - unsigned graylist = agent->sa_graylist; - 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; - int srv_503 = agent->sa_srv_503; - 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; - int tls_rport = agent->sa_tls_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 const *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_ALIASES_REF(aliases), - NTATAG_BAD_REQ_MASK_REF(bad_req_mask), - NTATAG_BAD_RESP_MASK_REF(bad_resp_mask), - NTATAG_BLACKLIST_REF(blacklist), - NTATAG_CANCEL_2543_REF(cancel_2543), - NTATAG_CANCEL_487_REF(cancel_487), - NTATAG_DEBUG_DROP_PROB_REF(drop_prob), - NTATAG_DEFAULT_PROXY_REF(proxy), - NTATAG_EXTRA_100_REF(extra_100), - NTATAG_GRAYLIST_REF(graylist), - NTATAG_MAXSIZE_REF(maxsize), - NTATAG_MAX_PROCEEDING_REF(max_proceeding), - NTATAG_MAX_FORWARDS_REF(max_forwards), - NTATAG_MCLASS_REF(mclass), - NTATAG_MERGE_482_REF(merge_482), - NTATAG_PASS_100_REF(pass_100), - NTATAG_PASS_408_REF(pass_408), - NTATAG_PRELOAD_REF(preload), - NTATAG_PROGRESS_REF(progress), - NTATAG_REL100_REF(invite_100rel), - NTATAG_RPORT_REF(rport), - NTATAG_SERVER_RPORT_REF(server_rport), - NTATAG_SIGCOMP_ALGORITHM_REF(algorithm), - NTATAG_SIGCOMP_OPTIONS_REF(sigcomp), - NTATAG_SIPFLAGS_REF(flags), - NTATAG_SIP_T1X64_REF(sip_t1x64), - NTATAG_SIP_T1_REF(sip_t1), - NTATAG_SIP_T2_REF(sip_t2), - NTATAG_SIP_T4_REF(sip_t4), -#if HAVE_SOFIA_SMIME - NTATAG_SMIME_REF(smime), -#endif - NTATAG_STATELESS_REF(stateless), - NTATAG_TCP_RPORT_REF(tcp_rport), - NTATAG_TLS_RPORT_REF(tls_rport), - NTATAG_TIMEOUT_408_REF(timeout_408), - NTATAG_UA_REF(ua), - NTATAG_UDP_MTU_REF(udp_mtu), - NTATAG_USER_VIA_REF(user_via), - NTATAG_USE_NAPTR_REF(use_naptr), - NTATAG_USE_SRV_REF(use_srv), - NTATAG_USE_TIMESTAMP_REF(use_timestamp), -#ifdef TPTAG_THRPSIZE - /* If threadpool is enabled, start a separate "reaper thread" */ - TPTAG_THRPSIZE_REF(threadpool), -#endif - NTATAG_SRV_503_REF(srv_503), - TAG_END()); - nC = tl_gets(tags, - NTATAG_TIMER_C_REF(timer_c), - TAG_END()); - n += nC; - - if (mclass != NONE) - agent->sa_mclass = mclass ? mclass : sip_default_mclass(); - - m = 0; - for (tport = agent->sa_tports; tport; tport = tport_next(tport)) { - int m0 = tport_set_params(tport, TAG_NEXT(tags)); - if (m0 < 0) - return m0; - if (m0 > m) - m = m0; - } - - 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 || dp->url_type == url_urn) { - 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 (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) { - msg_param_t 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 > UINT32_MAX) maxsize = UINT32_MAX; - agent->sa_maxsize = maxsize; - - if (max_proceeding == 0) max_proceeding = USIZE_MAX; - agent->sa_max_proceeding = max_proceeding; - - 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; - if (nC == 1) { - agent->sa_use_timer_c = 1; - if (timer_c == 0) - timer_c = 185 * 1000; - agent->sa_timer_c = timer_c; - outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c); - } - if (timer_d < sip_t1x64) - timer_d = sip_t1x64; - outgoing_queue_adjust(agent, agent->sa_out.inv_completed, timer_d); - - if (graylist > 24 * 60 * 60) - graylist = 24 * 60 * 60; - agent->sa_graylist = graylist; - - if (blacklist > 24 * 60 * 60) - blacklist = 24 * 60 * 60; - agent->sa_blacklist = blacklist; - - if (progress == 0) - progress = 60 * 1000; - agent->sa_progress = progress; - - if (server_rport > 3) - server_rport = 1; - else if (server_rport < 0) - server_rport = 1; - agent->sa_server_rport = server_rport; - - 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_srv_503 = srv_503 != 0; - agent->sa_smime = smime; - agent->sa_flags = flags & MSG_FLG_USERMASK; - agent->sa_rport = rport != 0; - agent->sa_tcp_rport = tcp_rport != 0; - agent->sa_tls_rport = tls_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_BLACKLIST_REF(), - * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(), - * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(), - * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(), - * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(), - * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(), - * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(), - * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(), - * NTATAG_PROGRESS_REF(), - * NTATAG_REL100_REF(), - * NTATAG_SERVER_RPORT_REF(), - * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(), - * NTATAG_SIPFLAGS_REF(), - * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(), - * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(), - * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(), - * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(), - * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_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); - return n; - } - - su_seterrno(EINVAL); - return -1; -} - -/** Get NTA parameters */ -static -int agent_get_params(nta_agent_t *agent, tagi_t *tags) -{ - return - tl_tgets(tags, - NTATAG_ALIASES(agent->sa_aliases), - NTATAG_BLACKLIST(agent->sa_blacklist), - NTATAG_CANCEL_2543(agent->sa_cancel_2543), - NTATAG_CANCEL_487(agent->sa_cancel_487), - NTATAG_CLIENT_RPORT(agent->sa_rport), - NTATAG_CONTACT(agent->sa_contact), - NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob), - NTATAG_DEFAULT_PROXY(agent->sa_default_proxy), - NTATAG_EXTRA_100(agent->sa_extra_100), - NTATAG_GRAYLIST(agent->sa_graylist), - NTATAG_MAXSIZE(agent->sa_maxsize), - NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding), - NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count), - NTATAG_MCLASS(agent->sa_mclass), - NTATAG_MERGE_482(agent->sa_merge_482), - NTATAG_PASS_100(agent->sa_pass_100), - NTATAG_PASS_408(agent->sa_pass_408), - NTATAG_PRELOAD(agent->sa_preload), - NTATAG_PROGRESS(agent->sa_progress), - NTATAG_REL100(agent->sa_invite_100rel), - NTATAG_SERVER_RPORT((int)(agent->sa_server_rport)), - NTATAG_SIGCOMP_ALGORITHM(agent->sa_algorithm), - NTATAG_SIGCOMP_OPTIONS(agent->sa_sigcomp_options ? - agent->sa_sigcomp_options : - "sip"), - NTATAG_SIPFLAGS(agent->sa_flags), - NTATAG_SIP_T1(agent->sa_t1), - NTATAG_SIP_T1X64(agent->sa_t1x64), - NTATAG_SIP_T2(agent->sa_t2), - NTATAG_SIP_T4(agent->sa_t4), -#if HAVE_SOFIA_SMIME - NTATAG_SMIME(agent->sa_smime), -#else - NTATAG_SMIME(NULL), -#endif - NTATAG_STATELESS(agent->sa_is_stateless), - NTATAG_TAG_3261(1), - NTATAG_TIMEOUT_408(agent->sa_timeout_408), - NTATAG_TIMER_C(agent->sa_timer_c), - NTATAG_UA(agent->sa_is_a_uas), - NTATAG_UDP_MTU(agent->sa_udp_mtu), - NTATAG_USER_VIA(agent->sa_user_via), - NTATAG_USE_NAPTR(agent->sa_use_naptr), - NTATAG_USE_SRV(agent->sa_use_srv), - NTATAG_USE_TIMESTAMP(agent->sa_timestamp), - NTATAG_SRV_503(agent->sa_srv_503), - TAG_END()); -} - -/**Get NTA statistics. - * - * The nta_agent_get_stats() function retrieves the stack statistics. - * - * @TAGS - * NTATAG_S_ACKED_TR_REF(), - * NTATAG_S_BAD_MESSAGE_REF(), - * NTATAG_S_BAD_REQUEST_REF(), - * NTATAG_S_BAD_RESPONSE_REF(), - * NTATAG_S_CANCELED_TR_REF(), - * NTATAG_S_CLIENT_TR_REF(), - * NTATAG_S_DIALOG_TR_REF(), - * NTATAG_S_DROP_REQUEST_REF(), - * NTATAG_S_DROP_RESPONSE_REF(), - * NTATAG_S_IRQ_HASH_REF(), - * NTATAG_S_IRQ_HASH_USED_REF(), - * NTATAG_S_LEG_HASH_REF(), - * NTATAG_S_LEG_HASH_USED_REF(), - * NTATAG_S_MERGED_REQUEST_REF(), - * NTATAG_S_ORQ_HASH_REF(), - * NTATAG_S_ORQ_HASH_USED_REF(), - * NTATAG_S_RECV_MSG_REF(), - * NTATAG_S_RECV_REQUEST_REF(), - * NTATAG_S_RECV_RESPONSE_REF(), - * NTATAG_S_RECV_RETRY_REF(), - * NTATAG_S_RETRY_REQUEST_REF(), - * NTATAG_S_RETRY_RESPONSE_REF(), - * NTATAG_S_SENT_MSG_REF(), - * NTATAG_S_SENT_REQUEST_REF(), - * NTATAG_S_SENT_RESPONSE_REF(), - * NTATAG_S_SERVER_TR_REF(), - * NTATAG_S_TOUT_REQUEST_REF(), - * NTATAG_S_TOUT_RESPONSE_REF(), - * NTATAG_S_TRLESS_200_REF(), - * NTATAG_S_TRLESS_REQUEST_REF(), - * NTATAG_S_TRLESS_RESPONSE_REF(), and - * NTATAG_S_TRLESS_TO_TR_REF(), - */ -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 - -/** - * 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 (6) -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" }, - { "ws", "5080", "_sips._ws.", "SIP+D2W" }, - { "wss", "5081", "_sips._wss.", "SIPS+D2W" }, -}; - -static char const * const tports_sip[] = - { - "udp", "tcp", "sctp", "ws", NULL - }; - -static char const * const tports_sips[] = - { - "tls", "wss", "ws", 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. - * - * 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 :[:] @endcode - * where may be - * @code - * ;transport= - * ;maddr= - * ;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 @endcode 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; - char *tps[9] = {0}; - - 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 && url->url_type != url_urn)) { - 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" VA_NONE)); - 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 || url->url_type == url_urn) { - 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; - - /* 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 || - !su_casematch(tpn->tpn_comp, nta_compressor_vtable->ncv_name))) { - SU_DEBUG_1(("nta(%p): comp=%s not supported for " URL_PRINT_FORMAT "\n", - (void *)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" VA_NONE)); - goto error; - } - else - SU_DEBUG_9(("nta: Via fields initialized\n" VA_NONE)); - - if ((agent_init_contact(self)) < 0) { - error = su_errno(); - SU_DEBUG_1(("nta: cannot create Contact header\n" VA_NONE)); - goto error; - } - else - SU_DEBUG_9(("nta: Contact header created\n" VA_NONE)); - - 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_IDLE(1800000), - TAG_NEXT(tags)); - - if (!self->sa_tports) - return -1; - - SU_DEBUG_9(("nta: master transport created\n" VA_NONE)); - - 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; - self->sa_tport_ws = 0; - self->sa_tport_wss = 0; - - /* Set via fields for the tports */ - for (tp = primaries; tp; tp = tport_next(tp)) { - int maddr; - 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 (su_casematch(tpn->tpn_proto, "udp")) - self->sa_tport_udp = 1; - else if (su_casematch(tpn->tpn_proto, "tcp")) - self->sa_tport_tcp = 1; - else if (su_casematch(tpn->tpn_proto, "sctp")) - self->sa_tport_sctp = 1; - else if (su_casematch(tpn->tpn_proto, "ws")) - self->sa_tport_ws = 1; - else if (su_casematch(tpn->tpn_proto, "wss")) - self->sa_tport_wss = 1; - - if (tport_has_tls(tp)) self->sa_tport_tls = 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) { - su_inet_ntop(su->su_family, SU_ADDR(su), host, sizeof host); - maddr = use_maddr && !su_casematch(canon, host); - port = ntohs(su->su_port); - } - else { - msg_random_token(host, 16, NULL, 0); - canon = strcat(host, ".is.invalid"); - maddr = 0; - port = 0; - } - - if (su_casenmatch(tpn->tpn_proto, "tls", 3) - ? port == SIPS_DEFAULT_PORT - : port == SIP_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; - } - } - - if (!via) { - SU_DEBUG_9(("nta: agent_init_via failed\n" VA_NONE)); - goto error; - } - - /* 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; - - for (v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; - v1; - v1 = v1->v_next) { - if (host_is_ip_address(v1->v_host)) { - if (!host_is_local(v1->v_host)) - break; - } - else if (!host_has_domain_invalid(v1->v_host)) { - break; - } - } - - if (v1 == NULL) - v1 = self->sa_vias ? self->sa_vias : self->sa_public_vias; - - if (!v1) - return -1; - - tp = strrchr(v1->v_protocol, '/'); - if (!tp++) - return -1; - - v2 = v1->v_next; - - if (v2 && - su_casematch(v1->v_host, v2->v_host) && - su_casematch(v1->v_port, v2->v_port)) { - char const *p1 = v1->v_protocol, *p2 = v2->v_protocol; - - if (!su_casematch(p1, sip_transport_udp)) - p1 = v2->v_protocol, p2 = v1->v_protocol; - - if (su_casematch(p1, sip_transport_udp) && - su_casematch(p2, sip_transport_tcp)) - /* 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; - - agent_tag_init(self); - - 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 already = orq->orq_user_via || orq->orq_via_added; - int user_via = orq->orq_user_via; - sip_via_t *v; - int clear = 0; - - assert(sip); assert(via); - - if (already && sip->sip_via) { - /* Use existing @Via */ - v = sip->sip_via; - } - else if (msg && via && sip->sip_request && - (v = sip_via_copy(msg_home(msg), via))) { - if (msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)v) < 0) - return -1; - orq->orq_via_added = 1; - } - 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) || - (self->sa_tls_rport && v->v_protocol == sip_transport_tls))) - 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 || !su_casematch(bvalue, v->v_branch)) - msg_header_replace_param(msg_home(msg), v->v_common, branch); - } - - if (!su_casematch(via->v_protocol, v->v_protocol)) - clear = 1, v->v_protocol = via->v_protocol; - - /* XXX - should we do this? */ - if ((!user_via || !v->v_host) && - !su_strmatch(via->v_host, v->v_host)) - clear = 1, v->v_host = via->v_host; - - if ((!user_via || !v->v_port || - /* Replace port in user Via only if we use udp and no rport */ - (v->v_protocol == sip_transport_udp && !v->v_rport && - !orq->orq_stateless)) && - !su_strmatch(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 is not UDP. - * If 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. */ -static 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_urn && - 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; - - tpn->tpn_proto = NULL; - 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 && su_casenmatch(b, "transport=", 10)) - tpn->tpn_proto = b + 10; - else if (n > 5 && su_casenmatch(b, "comp=", 5)) - tpn->tpn_comp = b + 5; - else if (n > 6 && su_casenmatch(b, "maddr=", 6)) - 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; - - if (tpn->tpn_proto) { - if (su_casematch(url->url_scheme, "sips") && su_casematch(tpn->tpn_proto, "ws")) { - tpn->tpn_proto = "wss"; - } - return 1; - } - - if (su_casematch(url->url_scheme, "sips")) - tpn->tpn_proto = "tls"; - else - tpn->tpn_proto = "*"; - - 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)); - - if (agent->sa_error_tport) { - agent->sa_error_tport(agent->sa_error_magic, agent, tport); - } -} - -/** 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(("%s(%p): %s\n", "nta", (void *)self, - "transport address updated")); - } -} - -/* ====================================================================== */ -/* 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*); - -#if HAVE_SOFIA_SRESOLV -static void outgoing_resolve(nta_outgoing_t *orq, - int explicit_transport, - enum nta_res_order_e order); -su_inline void outgoing_cancel_resolver(nta_outgoing_t *orq); -su_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 - -/** 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); - - 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); - } -} - -#ifdef HAVE_ZLIB_COMPRESS -int sip_content_encoding_Xflate(msg_t *msg, sip_t *sip, int inflate, int check) -{ - char const *method_name; - unsigned cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; - int ok = !check; - - if (!sip->sip_payload) { - return 0; - } - - if (sip->sip_request) { - method_name = sip->sip_request->rq_method_name; - } else if (sip->sip_cseq) { - method_name = sip->sip_cseq->cs_method_name; - } else { - method_name = "Unknown"; - } - - if (!ok) { - if (sip->sip_content_encoding && sip->sip_content_encoding->k_items) { - const char *val = sip->sip_content_encoding->k_items[0]; - if (val && (!strcasecmp(val, "gzip") || !strcasecmp(val, "deflate"))) { - ok = 1; - } - } - } - - if (ok) { - unsigned long n = 0; - void *decoded = NULL; - const char *id = "N/A"; - const char *orig_payload = sip->sip_payload->pl_data; - - n = sip->sip_payload->pl_len * 10; - - decoded = su_alloc(msg_home(msg), n); - assert(decoded); - - if (inflate) { - uncompress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); - } else { - compress(decoded, &n, (void *)sip->sip_payload->pl_data, (unsigned long)sip->sip_payload->pl_len); - } - - sip->sip_payload = sip_payload_create(msg_home(msg), decoded, n); - sip->sip_content_encoding = sip_content_encoding_make(msg_home(msg), "deflate"); - - if (sip->sip_call_id) { - id = sip->sip_call_id->i_id; - } - - if (inflate) { - SU_DEBUG_1(("nta: %s (%u) (%s) Inflating compressed body:\n%s\n", method_name, cseq, id, (char *)decoded)); - } else { - SU_DEBUG_1(("nta: %s (%u) (%s) Deflating compressed body:\n%s\n", method_name, cseq, id, orig_payload)); - } - - return 1; - } - - return 0; -} -#endif - -/** @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, *cancel = 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; - unsigned compressed = 0; - - 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)); - - if (agent->sa_drop_prob && !tport_is_reliable(tport)) { - if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { - SU_DEBUG_5(("nta: %s (%u) is %s\n", - method_name, cseq, "dropped simulating packet loss")); - agent->sa_stats->as_drop_request++; - msg_destroy(msg); - return; - } - } - - 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++; - mreply(agent, NULL, SIP_413_REQUEST_TOO_LARGE, msg, - tport, 1, stream, NULL, - 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); - - agent_check_request_via(agent, msg, sip, sip->sip_via, tport); - - if (badname && reply) - 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)); - - mreply(agent, reply, 400, phrase, msg, - tport, 1, stream, NULL, - TAG_END()); - } - else { - msg_destroy(msg); - if (stream) /* Send FIN */ - tport_shutdown(tport, 1); - } - - return; - } - - if (!su_casematch(sip->sip_request->rq_version, sip_version_2_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)); - - mreply(agent, NULL, SIP_505_VERSION_NOT_SUPPORTED, msg, - tport, 0, stream, NULL, - 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; - } - -#ifdef HAVE_ZLIB_COMPRESS - compressed = sip_content_encoding_Xflate(msg, sip, 1, 1); -#endif - - /* First, try existing incoming requests */ - irq = incoming_find(agent, sip, sip->sip_via, - agent->sa_merge_482 && - !sip->sip_to->a_tag && - method != sip_method_ack - ? &merge - : NULL, - method == sip_method_ack ? &ack : NULL, - method == sip_method_cancel ? &cancel : NULL); - - 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) { - SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", - method_name, cseq, - ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq)); - if (incoming_ack(ack, msg, sip, tport) >= 0) - return; - } - else if (cancel) { - SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", - method_name, cseq, - cancel->irq_cseq->cs_method_name, cancel->irq_cseq->cs_seq)); - if (incoming_cancel(cancel, msg, sip, tport) >= 0) - return; - } - else if (merge) { - SU_DEBUG_5(("nta: %s (%u) %s\n", - method_name, cseq, "is a merged request")); - request_merge(agent, msg, sip, tport, merge->irq_tag); - return; - } - - if (method == sip_method_prack && sip->sip_rack) { - nta_reliable_t *rel = reliable_find(agent, sip); - if (rel) { - SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", - method_name, cseq, - rel->rel_irq->irq_cseq->cs_method_name, - rel->rel_irq->irq_cseq->cs_seq)); - reliable_recv(rel, msg, sip, tport); - return; - } - } - - *url = *sip->sip_request->rq_url; - url->url_params = NULL; - agent_aliases(agent, url, tport); /* canonize urls */ - - if (method != sip_method_subscribe && (leg = leg_find(agent, - method_name, url, - sip->sip_call_id, - sip->sip_from->a_tag, - sip->sip_to->a_tag))) { - /* Try existing dialog */ - SU_DEBUG_5(("nta: %s (%u) %s\n", - method_name, cseq, "going to existing leg")); - leg->leg_compressed = compressed; - 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->leg_compressed = compressed; - leg_recv(leg, msg, sip, tport); - } - else if (!agent->sa_is_stateless && (leg = agent->sa_default_leg)) { - if (method == sip_method_invite && - agent->sa_in.proceeding->q_length >= agent->sa_max_proceeding) { - SU_DEBUG_5(("nta: proceeding queue full for %s (%u)\n", - method_name, cseq)); - mreply(agent, NULL, SIP_503_SERVICE_UNAVAILABLE, msg, - tport, 0, 0, NULL, - TAG_END()); - return; - } - else { - SU_DEBUG_5(("nta: %s (%u) %s\n", - method_name, cseq, "going to a default leg")); - leg->leg_compressed = compressed; - 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) %s\n", - method_name, cseq, - "not processed by application: returning 501")); - if (method != sip_method_ack) - mreply(agent, NULL, SIP_501_NOT_IMPLEMENTED, msg, - tport, 0, 0, NULL, - 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 (!su_strmatch(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 (!su_casematch(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); - } - else if (agent->sa_server_rport == 2 || - (agent->sa_server_rport == 3 && sip && sip->sip_user_agent && - sip->sip_user_agent->g_string && - (!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || - !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20) || - !strncasecmp(sip->sip_user_agent->g_string, "ADTRAN_Total_Access", 19)))) { - 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 (su_strmatch(url->url_port, url_port_default((enum url_type_e)url->url_type)) || - su_strmatch(url->url_port, "")) - /* Remove default or empty 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 : ""; - uint32_t cseq = sip->sip_cseq ? sip->sip_cseq->cs_seq : 0; - nta_outgoing_t *orq; - su_home_t *home; - char const *branch = NONE; - - - 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_drop_prob && !tport_is_reliable(tport)) { - if ((unsigned)su_randint(0, 1000) < agent->sa_drop_prob) { - SU_DEBUG_5(("nta: %03d %s %s\n", - status, phrase, "dropped simulating packet loss")); - agent->sa_stats->as_drop_response++; - msg_destroy(msg); - return; - } - } - - 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 %s\n", status, phrase, - errors - ? "has fatal syntax errors" - : "failed sanity check")); - - 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 (!su_casematch(sip->sip_status->st_version, sip_version_2_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 && 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 %s\n", status, phrase, "is response to ACK")); - msg_destroy(msg); - return; - } - - /* XXX - should check if msg should be discarded based on via? */ - -#ifdef HAVE_ZLIB_COMPRESS - sip_content_encoding_Xflate(msg, sip, 1, 1); -#endif - - if ((orq = outgoing_find(agent, msg, sip, sip->sip_via))) { - SU_DEBUG_5(("nta: %03d %s %s\n", - status, phrase, "is going to a transaction")); - /* RFC3263 4.3 "503 error response" */ - if(agent->sa_srv_503 && status == 503 && outgoing_other_destinations(orq)) { - SU_DEBUG_5(("%s(%p): <%03d> for <%s>, %s\n", "nta", (void *)orq, status, method, "try next after timeout")); - home = msg_home(msg); - if (agent->sa_is_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; - outgoing_try_another(orq); - return; - } - - 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 %s\n", status, phrase, - "to the default transaction")); - outgoing_default_recv(orq, status, msg, sip); - return; - } - else if (agent->sa_callback) { - SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "to message callback")); - /* - * 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 - /* Exactly one Via header, belonging to us */ - && sip->sip_via && !sip->sip_via->v_next - && agent_has_via(agent, sip->sip_via)) { - agent->sa_stats->as_trless_200++; - } - - SU_DEBUG_5(("nta: %03d %s %s\n", status, phrase, "was discarded")); - 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 headers are from response generated locally by NTA. */ -int nta_sip_is_internal(sip_t const *sip) -{ - return - sip == NULL /* No message generated */ - || (sip->sip_flags & NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG; -} - -/** Check if the message is internally generated by NTA. */ -int nta_msg_is_internal(msg_t const *msg) -{ - return msg_get_flags(msg, NTA_INTERNAL_MSG) == NTA_INTERNAL_MSG; -} - -/** Check if the message is internally generated by NTA. - * - * @deprecated Use nta_msg_is_internal() instead - */ -int nta_is_internal_msg(msg_t const *msg) { return nta_msg_is_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 = mreply(agent, NULL, status, phrase, req_msg, - NULL, 0, 0, NULL, - 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, ...) -{ - int retval = -1; - ta_list ta; - - ta_start(ta, tag, value); - - retval = mreply(agent, reply, status, phrase, req_msg, - NULL, 0, 0, NULL, - ta_tags(ta)); - ta_end(ta); - - return retval; -} - -static -int mreply(nta_agent_t *agent, - msg_t *reply, - int status, char const *phrase, - msg_t *req_msg, - tport_t *tport, - int incomplete, - int sdwn_after, - char const *to_tag, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - sip_t *sip; - int *use_rport = NULL; - int retry_without_rport = 0; - tp_name_t tpn[1]; - int retval = -1; - - 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), TAG_END()); - - if (reply == NULL) { - reply = nta_msg_create(agent, 0); - } - sip = sip_object(reply); - - if (!sip) { - SU_DEBUG_3(("%s: cannot create response 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 && - (to_tag == NONE ? 0 : - to_tag != NULL - ? sip_to_tag(msg_home(reply), sip->sip_to, to_tag) < 0 - : 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 { - struct sigcomp_compartment *cc = NONE; - - 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) { - tl_gets(ta_args(ta), TPTAG_COMPARTMENT_REF(cc), - /* XXX - should also check ntatag_sigcomp_close() */ - TAG_END()); - 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), - TPTAG_SDWN_AFTER(sdwn_after), - 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 *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 client request after the - * client transactions has been terminated. In that case, the UAC can not - * really accept the call. This function was used to accept and immediately - * terminate such a call. - * - * @deprecated This was a bad idea: see sf.net bug #1750691. It can be used - * to amplify DoS attacks. Let UAS take care of retransmission timeout and - * let it terminate the session. As of @VERSION_1_12_7, this function just - * returns -1. - */ -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(bmsg); - msg_destroy(amsg); - - return -1; -} - -/**Complete a request with values from dialog. - * - * Complete 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; - uint32_t seq; - url_t reg_url[1]; - url_string_t const *original = request_uri; - - if (!leg || !msg || !sip) - 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 - || !su_strmatch(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_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 || - !su_casematch(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 (!leg->leg_id && sip->sip_cseq) - seq = sip->sip_cseq->cs_seq; - else if (method == sip_method_ack || method == sip_method_cancel) - /* Dangerous - we may do PRACK/UPDATE meanwhile */ - 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_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_cseq || - seq != sip->sip_cseq->cs_seq || - method != sip->sip_cseq->cs_method || - !su_strmatch(method_name, sip->sip_cseq->cs_method_name)) { - sip_cseq_t *cseq = sip_cseq_create(home, seq, method, method_name); - if (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, - int reroute); -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) - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -HTABLE_BODIES_WITH(leg_htable, lht, nta_leg_t, HTABLE_HASH_LEG, size_t, hash_value_t); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -su_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. - * - * Creates a leg object, which 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; - char const *what = NULL; - - 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(NULL, 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), leg->leg_route_set = 1; - - 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) { - what = "cannot duplicate local address"; - goto err; - } - else if (to && to != NONE && leg->leg_remote == NULL) { - what = "cannot duplicate remote address"; - goto err; - } - else if (route && route != NONE && leg->leg_route == NULL) { - what = "cannot duplicate route"; - goto err; - } - else if (contact && contact != NONE && leg->leg_target == NULL) { - what = "cannot duplicate target"; - goto err; - } - else if (url_string && leg->leg_url == NULL) { - what = "cannot duplicate local destination"; - goto err; - } - - if (!no_dialog) { - if (!leg->leg_local || !leg->leg_remote) { - /* To and/or From header missing */ - if (leg->leg_remote) - what = "Missing local dialog address"; - else if (leg->leg_local) - what = "Missing remote dialog address"; - else - what = "Missing dialog addresses"; - 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) { - what = "cannot create Call-ID"; - 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(("%s(): %s\n", "nta_leg_tcreate", "tried to create second default leg")); - 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(("%s(%p)\n", "nta_leg_tcreate", (void *)leg)); - - return leg; - - err: - if (what) - SU_DEBUG_9(("%s(): %s\n", "nta_leg_tcreate", what)); - - 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", (void *)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); - su_home_unref((su_home_t *)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. - * - * Change the callback function 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 == NULL || su_casematch(tag, leg->leg_local->a_tag)) - return leg->leg_local->a_tag; - else - return NULL; - } - - if (tag) { - if (sip_to_tag(leg->leg_home, leg->leg_local, tag) < 0) - return NULL; - leg->leg_tagged = 1; - 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; - - leg->leg_tagged = 1; - - 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; -} - -/** Get local request sequence number. */ -uint32_t nta_leg_get_seq(nta_leg_t const *leg) -{ - return leg ? leg->leg_seq : 0; -} - -/** Get remote request sequence number. */ -uint32_t nta_leg_get_rseq(nta_leg_t const *leg) -{ - return leg ? leg->leg_rseq : 0; -} - -/** Save target and route set at UAC side. - * - * @sa nta_leg_client_reroute(), nta_leg_server_route(), @RFC3261 section 12.1.2 - * - * @bug Allows modifying the route set after initial transaction, if initial - * transaction had no @RecordRoute headers. - * - * @deprecated Use nta_leg_client_reroute() instead. - */ -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, 0); -} - -/** Save target and route set at UAC side. - * - * If @a initial is true, the route set is modified even if it has been set - * earlier. - * - * @param leg pointer to dialog leg - * @param route @RecordRoute headers from response - * @param contact @Contact header from response - * @param initial true if response to initial transaction - * - * @sa nta_leg_client_route(), nta_leg_server_route(), @RFC3261 section 12.1.2 - * - * @NEW_1_12_11 - */ -int nta_leg_client_reroute(nta_leg_t *leg, - sip_record_route_t const *route, - sip_contact_t const *contact, - int initial) -{ - return leg_route(leg, NULL, route, contact, initial ? 2 : 1); -} - -/** Save target and route set at UAS side. - * - * @param leg pointer to dialog leg - * @param route @RecordRoute headers from request - * @param contact @Contact header from request - * - * @sa nta_leg_client_reroute(), @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, 1); -} - -/** 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. - */ -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. - */ -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, to_tag); - - if (leg == NULL && strcmp(from_tag, "0") == 0) - leg = leg_find(sa, NULL, NULL, id, NULL, to_tag); - if (leg == NULL && strcmp(to_tag, "0") == 0) - leg = leg_find(sa, NULL, NULL, id, from_tag, NULL); - } - - return leg; -} - -/**@internal - * Find a leg corresponding to the request message. - * - */ -static nta_leg_t * -leg_find_call_id(nta_agent_t const *sa, - sip_call_id_t const *i) -{ - hash_value_t hash = i->i_hash; - leg_htable_t const *lht = sa->sa_dialogs; - nta_leg_t **ll, *leg = 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; - - if (leg->leg_hash != hash) - continue; - if (strcmp(leg_i->i_id, i->i_id) != 0) - continue; - - return leg; - } - - return leg; -} - -/** Get dialog leg by @CallID. - * - * @note Usually there should be only single dialog per @CallID on - * User-Agents. However, proxies may fork requests initiating the dialog and - * result in multiple calls per @CallID. - * - * @since New in @VERSION_1_12_9. - */ -nta_leg_t * -nta_leg_by_call_id(nta_agent_t *sa, const char *call_id) -{ - nta_leg_t *leg = NULL; - - if (call_id) { - sip_call_id_t id[1]; - sip_call_id_init(id); - - id->i_hash = msg_hash_string(id->i_id = call_id); - - leg = leg_find_call_id(sa, id); - } - - return leg; -} - -/** Calculate a simple case-insensitive hash over a string */ -su_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) { - mreply(agent, NULL, 481, "No such response", msg, - tport, 0, 0, NULL, - 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", - (void *)leg, method_name)); - mreply(agent, NULL, SIP_500_INTERNAL_SERVER_ERROR, msg, - tport, 0, 0, NULL, - TAG_END()); - return; - } - - irq->irq_compressed = leg->leg_compressed; - 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", - (void *)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", - (void *)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); -} - -#if 0 -/**Compare two SIP from/to fields. - * - * @retval nonzero if matching. - * @retval zero if not matching. - */ -su_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) || - su_strcmp(a->url_port, b->url_port) || - su_strcmp(a->url_user, b->url_user); -} -#endif - -/** Get a leg by dialog. - * - * Search 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 ignored - * @param local_tag if non-NULL and there is local tag associated with leg, - * it must math - * @param local_uri ignored - * - * @note - * If @a remote_tag or @a local_tag is an empty string (""), the tag is - * ignored when matching legs. - */ -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; - 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_tag && remote_tag[0] == '\0') - remote_tag = NULL; - if (local_tag && local_tag[0] == '\0') - local_tag = NULL; - - leg = leg_find(agent, - NULL, url, - call_id, - remote_tag, - local_tag); - - if (to_be_freed) su_free(NULL, to_be_freed); - - 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"-tag, and "From"-tag 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, - char const *to_tag) -{ - 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; - char const *remote_tag = leg->leg_remote->a_tag; - 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 To has no tag and we have local tag - * and the tag has been there from the beginning. - */ - if (local_tag && !to_tag && !leg->leg_tagged) - 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 && !su_casematch(local_tag, to_tag) && to_tag[0]) - continue; - if (remote_tag && from_tag && !su_casematch(remote_tag, from_tag) && from_tag[0]) - continue; - - if (leg_url && request_uri && url_cmp(leg_url, request_uri)) - continue; - if (leg_method && method_name && !su_casematch(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 = NULL; - - if (!agent) - return NULL; - - if (!us) - return agent->sa_default_leg; - - url = url_hdup(NULL, us->us_url); - - if (url) { - agent_aliases(agent, url, NULL); - leg = dst_find(agent, url, 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 (!su_casematch(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. - * - * Sets the leg route and contact using the @RecordRoute and @Contact - * headers. - * - * @param reroute - allow rerouting - * - if 1, follow @RFC3261 semantics - * - if 2, response to initial transaction) - */ -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, - int reroute) -{ - su_home_t *home = leg->leg_home; - sip_route_t *r, r0[1], *old; - int route_is_set; - - if (!leg) - return -1; - - if (route == NULL && reverse == NULL && contact == NULL) - return 0; - - sip_route_init(r0); - - route_is_set = reroute ? leg->leg_route_set : leg->leg_route != NULL; - - if (route_is_set && reroute <= 1) { - 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 - - old = leg->leg_route; - leg->leg_route = r; - - if (old && old != r) - msg_header_free(leg->leg_home, (msg_header_t *)old); - - leg->leg_route_set = 1; - - 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); - -su_inline int incoming_is_queued(nta_incoming_t const *irq); -su_inline void incoming_queue(incoming_queue_t *queue, nta_incoming_t *); -su_inline void incoming_remove(nta_incoming_t *irq); -su_inline void incoming_set_timer(nta_incoming_t *, uint32_t interval); -su_inline void incoming_reset_timer(nta_incoming_t *); -su_inline size_t incoming_mass_destroy(nta_agent_t *, incoming_queue_t *); - -static int incoming_set_params(nta_incoming_t *irq, tagi_t const *tags); -su_inline -int incoming_set_compartment(nta_incoming_t *irq, tport_t *tport, msg_t *msg, - int create_if_needed); - -su_inline nta_incoming_t - *incoming_call_callback(nta_incoming_t *, msg_t *, sip_t *); -su_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. - * - * Create 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); /* Timestamp originally from tport */ - - 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 = sip->sip_via->v_branch; - irq->irq_reliable_tp = tport_is_reliable(tport); - irq->irq_extra_100 = 0; /* Sending extra 100 trying false by default */ - - 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); - irq->irq_tag = irq->irq_to->a_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; - /* RFC 4320 (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", - (void *)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, - uint32_t timeout) -{ - nta_incoming_t *irq; - uint32_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 ((int32_t)(irq->irq_timeout - latest) > 0) - irq->irq_timeout = latest; - } -} - -/** @internal - * Test if an incoming transaction is in a queue. - */ -su_inline -int incoming_is_queued(nta_incoming_t const *irq) -{ - return irq && irq->irq_queue; -} - -/** @internal - * Insert an incoming transaction into a queue. - * - * Insert a server transaction into a queue, and sets the corresponding - * timeout at the same time. - */ -su_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); - - irq->irq_timeout = set_timeout(irq->irq_agent, queue->q_timeout); - - 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. - */ -su_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; -} - -su_inline -void incoming_set_timer(nta_incoming_t *irq, uint32_t 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) || (int32_t)((*rq)->irq_retry - irq->irq_retry) > 0) - rq = &irq->irq_agent->sa_in.re_list; - - while (*rq && (int32_t)((*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; -} - -su_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", (void *)irq)); - - incoming_cut_off(irq); - incoming_reclaim(irq); -} - -/** Remove references to the irq */ -su_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 */ -su_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 */ -su_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", - (void *)rm, (void *)msg, (void *)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 - * - * Set the callback function 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 && !su_casematch(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 application context for a server transaction. - * - * @param irq server transaction - * @param callback callback pointer - * - * Return the application context bound to the server transaction. If the @a - * callback function pointer is given, return application context only if - * the callback matches with the callback bound to the server transaction. - * - */ -nta_incoming_magic_t *nta_incoming_magic(nta_incoming_t *irq, - nta_ack_cancel_f *callback) -{ - return irq && (callback == NULL || irq->irq_callback == callback) - ? irq->irq_magic : NULL; -} - -/** When received. - * - * Return timestamp from the reception of the initial request. - * - * @NEW_1_12_7. - */ -sip_time_t nta_incoming_received(nta_incoming_t *irq, - su_nanotime_t *return_nano) -{ - su_time_t tv = { 0, 0 }; - - if (irq) - tv = irq->irq_received; - - if (return_nano) - *return_nano = (su_nanotime_t)tv.tv_sec * 1000000000 + tv.tv_usec * 1000; - - return tv.tv_sec; -} - -/** 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, NULL); - else - return NULL; -} - -/** Find a matching server transaction object. - * - * Check also for requests to merge, to ACK, or to CANCEL. - */ -static nta_incoming_t *incoming_find(nta_agent_t const *agent, - sip_t const *sip, - sip_via_t const *v, - nta_incoming_t **return_merge, - nta_incoming_t **return_ack, - nta_incoming_t **return_cancel) -{ - 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; - incoming_htable_t const *iht = agent->sa_incoming; - hash_value_t hash = NTA_HASH(i, cseq->cs_seq); - char const *magic_branch; - - nta_incoming_t **ii, *irq; - - int is_uas_ack = return_ack && agent->sa_is_a_uas; - - if (v->v_branch && su_casenmatch(v->v_branch, "z9hG4bK", 7)) - magic_branch = v->v_branch + 7; - else - magic_branch = NULL; - - for (ii = incoming_htable_hash(iht, hash); - (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 (su_strcasecmp(irq->irq_from->a_tag, from->a_tag)) - continue; - - if (is_uas_ack && - irq->irq_method == sip_method_invite && - 200 <= irq->irq_status && irq->irq_status < 300 && - su_casematch(irq->irq_tag, to->a_tag)) { - *return_ack = irq; - return NULL; - } - - if (magic_branch) { - /* RFC3261 17.2.3: - * - * The request matches a transaction if branch and sent-by in topmost - * the method of the request matches the one that created the - * transaction, except for ACK, where the method of the request - * that created the transaction is INVITE. - */ - if (irq->irq_via->v_branch && - su_casematch(irq->irq_via->v_branch + 7, magic_branch) && - su_casematch(irq->irq_via->v_host, v->v_host) && - su_strmatch(irq->irq_via->v_port, v->v_port)) { - if (irq->irq_method == cseq->cs_method && - strcmp(irq->irq_cseq->cs_method_name, - cseq->cs_method_name) == 0) - return irq; - if (return_ack && irq->irq_method == sip_method_invite) - return *return_ack = irq, NULL; - if (return_cancel && irq->irq_method != sip_method_ack) - return *return_cancel = irq, NULL; - } - } - else { - /* No magic branch */ - - /* INVITE request matches a transaction if - the Request-URI, To tag, From tag, Call-ID, CSeq, and - top Via header match */ - - /* From tag, Call-ID, and CSeq number has been matched above */ - - /* Match top Via header field */ - if (!su_casematch(irq->irq_via->v_branch, v->v_branch) || - !su_casematch(irq->irq_via->v_host, v->v_host) || - !su_strmatch(irq->irq_via->v_port, v->v_port)) - ; - /* Match Request-URI */ - else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url)) - ; - else { - /* Match CSeq */ - if (irq->irq_method == cseq->cs_method && - su_strmatch(irq->irq_cseq->cs_method_name, cseq->cs_method_name)) { - /* Match To tag */ - if (!su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) - return irq; /* found */ - } - else if ( - /* Tag set by UAS */ - su_strcasecmp(irq->irq_tag, to->a_tag) && - /* Original tag */ - su_strcasecmp(irq->irq_to->a_tag, to->a_tag)) - ; - else if (return_ack && irq->irq_method == sip_method_invite) - return *return_ack = irq, NULL; - else if (return_cancel && irq->irq_method != sip_method_ack) - return *return_cancel = irq, NULL; - } - } - - /* RFC3261 - section 8.2.2.2 Merged Requests */ - if (return_merge) { - if (irq->irq_cseq->cs_method == cseq->cs_method && - strcmp(irq->irq_cseq->cs_method_name, - cseq->cs_method_name) == 0) - *return_merge = irq, return_merge = NULL; - } - } - - return NULL; -} - -/** Process retransmitted requests. */ -su_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 && - irq->irq_extra_100) { - /* Agent and Irq configured to 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; -} - -su_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; -} - -/** Respond to the CANCEL. */ -su_inline -int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, - tport_t *tport) -{ - nta_agent_t *agent = irq->irq_agent; - - /* According to the RFC 3261, this INVITE has been destroyed */ - if (irq->irq_method == sip_method_invite && - 200 <= irq->irq_status && irq->irq_status < 300) { - mreply(agent, NULL, SIP_481_NO_TRANSACTION, msg, - tport, 0, 0, NULL, - TAG_END()); - return 0; - } - - /* UAS MUST use same tag in final response to CANCEL and INVITE */ - if (agent->sa_is_a_uas && irq->irq_tag == NULL) { - nta_incoming_tag(irq, NULL); - } - - mreply(agent, NULL, SIP_200_OK, msg_ref_create(msg), - tport, 0, 0, irq->irq_tag, - TAG_END()); - - /* We have already sent final response */ - 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; -} - -/** Merge request */ -static -void request_merge(nta_agent_t *agent, - msg_t *msg, sip_t *sip, tport_t *tport, - char const *to_tag) -{ - nta_incoming_t *irq; - - agent->sa_stats->as_merged_request++; - - irq = incoming_create(agent, msg, sip, tport, to_tag); - - if (irq) { - nta_incoming_treply(irq, 482, "Request merged", TAG_END()); - nta_incoming_destroy(irq); - } else { - SU_DEBUG_3(("nta: request_merge(): cannot create transaction for %s\n", - sip->sip_request->rq_method_name)); - mreply(agent, NULL, 482, "Request merged", msg, - tport, 0, 0, NULL, - TAG_END()); - } -} - -/**@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 */ -su_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. Among others, parameters determine the way - * the SigComp compression is handled. - * - * @TAGS - * NTATAG_COMP(), NTATAG_SIGCOMP_CLOSE() and NTATAG_EXTRA_100(). - * - * @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++; - - else if (ntatag_extra_100 == tt) - irq->irq_extra_100 = t->t_value != 0, 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; -} - -su_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; -} - -/** Add essential headers to the response message */ -static int nta_incoming_response_headers(nta_incoming_t *irq, - msg_t *msg, - sip_t *sip) -{ - int clone = 0; - su_home_t *home = msg_home(msg); - - if (!sip->sip_from) - clone = 1, sip->sip_from = sip_from_copy(home, irq->irq_from); - if (!sip->sip_to) - clone = 1, sip->sip_to = sip_to_copy(home, irq->irq_to); - 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; - /* 100 responses are not forwarded by proxies, so only include the topmost Via header */ - if (sip->sip_status && sip->sip_status->st_status == 100) - sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via); - else - sip->sip_via = sip_via_copy(home, irq->irq_via); - } - - if (clone) - msg_set_parent(msg, (msg_t *)irq->irq_home); - - if (!sip->sip_from || !sip->sip_to || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via) - return -1; - - 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 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 (status != 0 && !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 (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 (nta_incoming_response_headers(irq, msg, sip) < 0) - return -1; - - if (sip->sip_status && sip->sip_status->st_status > 100 && - irq->irq_tag && sip->sip_to && !sip->sip_to->a_tag) - if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0) - return -1; - - if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route) - if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0) - return -1; - - return sip_complete_message(msg); -} - - -/** Create a response message for request. - * - * @NEW_1_12_5. - */ -msg_t *nta_incoming_create_response(nta_incoming_t *irq, - int status, char const *phrase) -{ - msg_t *msg = NULL; - sip_t *sip; - - if (irq) { - msg = nta_msg_create(irq->irq_agent, 0); - sip = sip_object(msg); - - if (sip) { - if (status != 0) - sip->sip_status = sip_status_create(msg_home(msg), status, phrase, NULL); - - if (nta_incoming_response_headers(irq, msg, sip) < 0) - msg_destroy(msg), msg = NULL; - } - } - - return 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 || sip == 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; - } - -#ifdef HAVE_ZLIB_COMPRESS - if (irq->irq_compressed) { - sip_content_encoding_Xflate(msg, sip, 0, 0); - } -#endif - - 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) { - /* RFC 4320 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. - */ -su_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_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 void -_nta_incoming_timer(nta_agent_t *sa) -{ - uint32_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)) { - - now = su_time_ms(su_now()); - - if ((int32_t)(irq->irq_retry - now) > 0) - break; - if (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 */ - incoming_reset_timer(irq); - - if(irq->irq_extra_100) { - SU_DEBUG_5(("nta: timer N1 fired, sending %u %s\n", SIP_100_TRYING)); - nta_incoming_treply(irq, SIP_100_TRYING, TAG_END()); - } - else { - SU_DEBUG_5(("nta: timer N1 fired, but avoided sending %u %s\n", - SIP_100_TRYING)); - } - } - } - - 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); - - now = su_time_ms(su_now()); - - if ((int32_t)(irq->irq_timeout - now) > 0) - break; - if (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); - - now = su_time_ms(su_now()); - - if ((int32_t)(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); - - now = su_time_ms(su_now()); - - if ((int32_t)(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); - - now = su_time_ms(su_now()); - - if ((int32_t)(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)); -} - -/** Mass destroy server transactions */ -su_inline -size_t 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) - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -HTABLE_BODIES_WITH(outgoing_htable, oht, nta_outgoing_t, HTABLE_HASH_ORQ, - size_t, hash_value_t); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -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_via(nta_outgoing_t *orq, tport_t *tp); -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, int timeout); -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); -su_inline int outgoing_is_queued(nta_outgoing_t const *orq); -su_inline void outgoing_queue(outgoing_queue_t *queue, - nta_outgoing_t *orq); -su_inline void outgoing_remove(nta_outgoing_t *orq); -su_inline void outgoing_set_timer(nta_outgoing_t *orq, uint32_t interval); -static void outgoing_reset_timer(nta_outgoing_t *orq); -static size_t outgoing_timer_dk(outgoing_queue_t *q, - char const *timer, - uint32_t now); -static size_t outgoing_timer_bf(outgoing_queue_t *q, - char const *timer, - uint32_t now); -static size_t outgoing_timer_c(outgoing_queue_t *q, - char const *timer, - uint32_t now); - -static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip); -static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *, - tag_type_t tag, tag_value_t value, ...); -static void outgoing_retransmit(nta_outgoing_t *orq); -static void outgoing_trying(nta_outgoing_t *orq); -static void outgoing_timeout(nta_outgoing_t *orq, uint32_t now); -static int outgoing_complete(nta_outgoing_t *orq); -static void outgoing_terminate_invite(nta_outgoing_t *); -static void outgoing_remove_fork(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); - - -/** 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. - * - * Create a request message and pass 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 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; - tagi_t const *tagi; - - 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); - - tagi = ta_args(ta); - - if (sip_add_tagis(msg, sip, &tagi) < 0) { - if (tagi && tagi->t_tag) { - tag_type_t t = tagi->t_tag; - SU_DEBUG_5(("%s(): bad tag %s::%s\n", __func__, - t->tt_ns ? t->tt_ns : "", t->tt_name ? t->tt_name : "")); - } - } - 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(), 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 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_forking) - orq = orq->orq_forking; - - 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) { - outgoing_destroy_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_tags(ta)); - else - msg = NULL; - - ta_end(ta); - - if ((cancel_2543 || cancel_408) && !orq->orq_stateless) - 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) { - if (!delay_sending) - outgoing_complete(orq); - return cancel; - } - - msg_destroy(msg); - } - - return NULL; -} - -/**Bind callback and application context to a client transaction. - * - * @param orq outgoing client transaction - * @param callback callback function (may be NULL) - * @param magic application context pointer - * (given as argument to @a callback) - * - * @NEW_1_12_9 - */ -int -nta_outgoing_bind(nta_outgoing_t *orq, - nta_response_f *callback, - nta_outgoing_magic_t *magic) -{ - if (orq && !orq->orq_destroyed) { - if (callback == NULL) - callback = outgoing_default_cb; - orq->orq_callback = callback; - orq->orq_magic = magic; - return 0; - } - return -1; -} - -/**Get application context bound to a client transaction. - * - * @param orq outgoing client transaction - * @param callback callback function (may be NULL) - * - * Return the application context bound to a client transaction. If the @a - * callback function pointer is given, return application context only if - * the callback matches with the callback bound to the client transaction. - * - * @NEW_1_12_11 - */ -nta_outgoing_magic_t * -nta_outgoing_magic(nta_outgoing_t const *orq, - nta_response_f *callback) -{ - if (orq && (callback == NULL || callback == orq->orq_callback)) - return orq->orq_magic; - else - 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(("%s(%p): %s\n", "nta_outgoing_destroy", (void *)orq, - "already destroyed")); - 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 the branch parameter. @NEW_1_12_7. */ -char const *nta_outgoing_branch(nta_outgoing_t const *orq) -{ - return orq != NULL && orq != NONE && orq->orq_branch - ? orq->orq_branch + strlen("branch=") - : NULL; -} - -/**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. - * - * Create an outgoing transaction object and send 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 = 0, stateless = 0, user_via = agent->sa_user_via; - int invite_100rel = agent->sa_invite_100rel; - int explicit_transport = 1; - - tagi_t const *t; - tport_t *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); - -#ifdef HAVE_ZLIB_COMPRESS - sip_content_encoding_Xflate(msg, sip_object(msg), 0, 1); -#endif - - if (!sip->sip_request || sip_complete_message(msg) < 0) { - SU_DEBUG_3(("nta: outgoing_create: incomplete request\n" VA_NONE)); - 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; - } - else if (ntatag_rel100 == tt) { - invite_100rel = t->t_value != 0; - } - } - - 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_timestamp = use_timestamp; - orq->orq_delay = UINT_MAX; - orq->orq_stateless = stateless != 0; - orq->orq_user_via = user_via != 0 && sip->sip_via; - orq->orq_100rel = invite_100rel; - orq->orq_uas = !stateless && agent->sa_is_a_uas; - - 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 */ - if (tport_is_secondary(override_tport)) { - tpn = tport_name(override_tport); - orq->orq_user_tport = 1; - } - } - - if (tpn) { - /* CANCEL or ACK to [3456]XX */ - invalid = tport_name_dup(home, orq->orq_tpn, tpn); -#if 0 //HAVE_SOFIA_SRESOLV - /* We send ACK or CANCEL only if original request was really sent */ - 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); - } - else if (route_url && !orq->orq_user_tport) { - invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, route_url); - if (invalid >= 0) { - explicit_transport = invalid > 0; - if (override_tport) { /* Use transport protocol name from transport */ - if (strcmp(orq->orq_tpn->tpn_proto, "*") == 0) - orq->orq_tpn->tpn_proto = tport_name(override_tport)->tpn_proto; - } - - 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 { - invalid = nta_tpn_by_url(home, orq->orq_tpn, &scheme, &port, - (url_string_t *)sip->sip_request->rq_url); - if (invalid >= 0) { - explicit_transport = invalid > 0; - resolved = tport_name_is_resolved(orq->orq_tpn); - sip_fragment_clear(sip->sip_request->rq_common); - } - orq->orq_url = url_hdup(home, sip->sip_request->rq_url); - } - - if (!override_tport) - orq->orq_tpn->tpn_ident = tp_ident; - else - orq->orq_tpn->tpn_ident = tport_name(override_tport)->tpn_ident; - - if (comp == NULL) - orq->orq_tpn->tpn_comp = comp; - - if (orq->orq_user_via && su_strmatch(orq->orq_tpn->tpn_proto, "*")) { - char const *proto = sip_via_transport(sip->sip_via); - if (proto) orq->orq_tpn->tpn_proto = proto; - } - - if (branch && branch != NONE) { - if (su_casenmatch(branch, "branch=", 7)) - branch = su_strdup(home, branch); - else - branch = su_sprintf(home, "branch=%s", branch); - } - else if (orq->orq_user_via && sip->sip_via->v_branch && orq->orq_method != sip_method_invite ) - 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) { - /* Find the original INVITE which we are ACKing */ - if (ack_branch != NULL && ack_branch != NONE) { - if (su_casenmatch(ack_branch, "branch=", 7)) - orq->orq_branch = su_strdup(home, ack_branch); - else - orq->orq_branch = su_sprintf(home, "branch=%s", ack_branch); - } - else if (orq->orq_uas) { - /* - * ACK redirects 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" VA_NONE)); - 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_sips = su_casematch(scheme, "sips"); - - 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 (orq->orq_user_tport) - outgoing_send_via(orq, override_tport); - else if (resolved) - outgoing_prepare_send(orq); -#if HAVE_SOFIA_SRESOLV - else - outgoing_resolve(orq, explicit_transport, res_order); -#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; - - /* Select transport by scheme */ - if (orq->orq_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); - - if (tpn->tpn_port[0] == '\0') { - if (orq->orq_sips || tport_has_tls(tp)) - tpn->tpn_port = "5061"; - else - tpn->tpn_port = "5060"; - } - - if (tp) { - outgoing_send_via(orq, tp); - } - else if (orq->orq_sips) { - SU_DEBUG_3(("nta outgoing create: no secure transport\n" VA_NONE)); - outgoing_reply(orq, SIP_416_UNSUPPORTED_URI, 1); - } - else { - SU_DEBUG_3(("nta outgoing create: no transport protocol\n" VA_NONE)); - outgoing_reply(orq, 503, "No transport", 1); - } -} - -/** Send request using given transport */ -static void -outgoing_send_via(nta_outgoing_t *orq, tport_t *tp) -{ - tport_t *old_tp = orq->orq_tport; - - orq->orq_tport = tport_ref(tp); - - if (orq->orq_pending && tp != old_tp) { - tport_release(old_tp, orq->orq_pending, - orq->orq_request, NULL, orq, 0); - orq->orq_pending = 0; - } - - if (old_tp) tport_unref(old_tp); - - if (outgoing_insert_via(orq, agent_tport_via(tp)) < 0) { - SU_DEBUG_3(("nta outgoing create: cannot insert Via line\n" VA_NONE)); - outgoing_reply(orq, 503, "Cannot insert Via", 1); - return; - } - -#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(orq->orq_agent->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 (orq->orq_user_tport && !tport_is_clear_to_send(orq->orq_tport)) { - outgoing_tport_error(agent, orq, NULL, orq->orq_request, EPIPE); - 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; - - if (orq->orq_pending) { - tport_release(orq->orq_tport, orq->orq_pending, - orq->orq_request, NULL, orq, 0); - orq->orq_pending = 0; - } - - 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); - - if (orq->orq_user_tport) - /* No retries */; - /* RFC3261, 18.1.1 */ - else if (err == EMSGSIZE && !orq->orq_try_tcp_instead) { - if (su_casematch(tpn->tpn_proto, "udp") || - su_casematch(tpn->tpn_proto, "*")) { - outgoing_try_tcp_instead(orq); - continue; - } - } - else if (err == ECONNREFUSED && orq->orq_try_tcp_instead) { - if (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { - outgoing_try_udp_instead(orq, 0); - continue; - } - } - else if (err == EPIPE) { - /* Connection was closed */ - if (!once++) { - orq->orq_retries++; - continue; - } - } - - 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; - - outgoing_trying(orq); /* Timer B / F */ - - if (orq->orq_method == sip_method_ack) - ; - else if (!orq->orq_reliable) { - /* race condition on initial t1 timer timeout, set minimum initial timeout to 1000ms */ - unsigned t1_timer = agent->sa_t1; - if (t1_timer < 1000) t1_timer = 1000; - outgoing_set_timer(orq, t1_timer); /* 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]; - - assert(orq->orq_pending == 0); - - *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; - } - - /* No TCP - try again with UDP without SIP MTU limit */ - 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) { - 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, int timeout) -{ - tport_t *tp; - tp_name_t tpn[1]; - - if (orq->orq_pending) { - tport_release(orq->orq_tport, orq->orq_pending, - orq->orq_request, NULL, orq, 0); - orq->orq_pending = 0; - } - - *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 %s, trying UDP\n", - orq->orq_method_name, orq->orq_cseq->cs_seq, - timeout ? "times out" : "refused")); - - 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 (su_casematch(tpn->tpn_proto, "tcp") && msg_size(msg) <= 65535) { - outgoing_print_tport_error(orq, 5, "retrying with UDP after ", - tpn, msg, error); - outgoing_try_udp_instead(orq, 0); - outgoing_remove(orq); /* Reset state - this is no resend! */ - outgoing_send(orq, 0); /* Send */ - return; - } - } - else if (error == 0) { - /* - * Server closed connection. RFC3261: - * "there is no coupling between TCP connection state and SIP - * processing." - */ - 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, - su_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 require_100rel = sip_has_feature(sip->sip_require, "100rel"); - - if (require_100rel) { - orq->orq_must_100rel = 1; - orq->orq_100rel = 1; - } - else if (sip_has_feature(sip->sip_supported, "100rel")) { - orq->orq_100rel = 1; - } - else if (orq->orq_100rel) { - supported[i++] = "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; - uint32_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 == 0 || - (int32_t)(orq->orq_timeout - latest) > 0) - orq->orq_timeout = latest; - } -} - -/** @internal - * Test if an outgoing transaction is in a queue. - */ -su_inline int -outgoing_is_queued(nta_outgoing_t const *orq) -{ - return orq && orq->orq_queue; -} - -/** @internal - * Insert an outgoing transaction into a queue. - * - * Insert a client transaction into a queue and set the corresponding - * timeout at the same time. - */ -static void -outgoing_queue(outgoing_queue_t *queue, - nta_outgoing_t *orq) -{ - if (orq->orq_queue == queue) { - //assert(queue->q_timeout == 0); - return; - } - - assert(!orq->orq_forked); - - if (outgoing_is_queued(orq)) - outgoing_remove(orq); - - 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. - */ -su_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; - - 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). - * - * Set the retry timer (B/D) on the outgoing request (client transaction). - */ -su_inline -void outgoing_set_timer(nta_outgoing_t *orq, uint32_t 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); - - /* Shortcut into queue at SIP T1 */ - rq = orq->orq_agent->sa_out.re_t1; - - if (!(*rq) || (int32_t)((*rq)->orq_retry - orq->orq_retry) > 0) - rq = &orq->orq_agent->sa_out.re_list; - - while (*rq && (int32_t)((*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 -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", (void *)orq)); - assert(orq->orq_forks == NULL && orq->orq_forking == NULL); - outgoing_cut_off(orq); - outgoing_reclaim(orq); -} - -/** Remove outgoing request from hash tables */ -su_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); - -#if 0 - if (orq->orq_forked) - outgoing_remove_fork(orq); -#endif - - 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 */ -su_inline -void outgoing_reclaim(nta_outgoing_t *orq) -{ - if (orq->orq_status2b) - *orq->orq_status2b = -1; - - 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 */ -su_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", - (void *)rm, (void *)msg, (void *)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) { - if (!orq->orq_forking && !orq->orq_forks) { - outgoing_free(orq); - return; - } - } - /* Application is expected to handle 200 OK statelessly - => kill transaction immediately */ - else if (orq->orq_method == sip_method_invite && !orq->orq_completed - /* (unless transaction has been canceled) */ - && !orq->orq_canceled - /* or it has been forked */ - && !orq->orq_forking && !orq->orq_forks) { - orq->orq_destroyed = 1; - outgoing_terminate(orq); - return; - } - - orq->orq_destroyed = 1; - orq->orq_callback = outgoing_default_cb; - orq->orq_magic = NULL; -} - -/** @internal Outgoing transaction timer routine. - * - */ -static void -_nta_outgoing_timer(nta_agent_t *sa) -{ - uint32_t now = su_time_ms(su_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)) { - - now = su_time_ms(su_now()); - - if ((int32_t)(orq->orq_retry - now) > 0) - break; - if (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 for", - orq->orq_method_name, orq->orq_cseq->cs_seq)); - outgoing_try_udp_instead(orq, 1); - outgoing_remove(orq); /* Reset state - this is no resend! */ - outgoing_send(orq, 0); /* Send */ - } - 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_c(sa->sa_out.inv_proceeding, "C", 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)); - } -} - -/** @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_forked) - ; - else if (orq->orq_method == sip_method_invite) { - if (!orq->orq_completed) { - outgoing_queue(orq->orq_agent->sa_out.inv_calling, orq); - } else { - SU_DEBUG_5(("nta(%p): completed request can not be put into inv_calling queue (%u)\n", (void *)orq, orq->orq_cseq->cs_seq)); - if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) { - /* Put back into inv_completed if it's not there by any reason */ - outgoing_queue(orq->orq_agent->sa_out.inv_completed, orq); /* Timer D */ - } - } - } - 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, - uint32_t now) -{ - nta_outgoing_t *orq; - size_t timeout = 0; - - while ((orq = q->q_head)) { - if ((int32_t)(orq->orq_timeout - now) > 0 || - timeout >= timer_max_timeout) - break; - - timeout++; - - SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", - timer, - orq->orq_method != sip_method_ack ? "timeout" : "terminating", - orq->orq_method_name, orq->orq_cseq->cs_seq)); - - if (orq->orq_method != sip_method_ack) - outgoing_timeout(orq, now); - else - outgoing_terminate(orq); - - assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0); - } - - return timeout; -} - -/** Handle timer C */ -static -size_t outgoing_timer_c(outgoing_queue_t *q, - char const *timer, - uint32_t now) -{ - nta_outgoing_t *orq; - size_t timeout = 0; - - if (q->q_timeout == 0) - return 0; - - while ((orq = q->q_head)) { - if ((int32_t)(orq->orq_timeout - now) > 0 || timeout >= timer_max_timeout) - break; - - timeout++; - - SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", - timer, "CANCEL and timeout", - orq->orq_method_name, orq->orq_cseq->cs_seq)); - /* - * If the client transaction has received a provisional response, the - * proxy MUST generate a CANCEL request matching that transaction. - */ - nta_outgoing_tcancel(orq, NULL, NULL, TAG_NULL()); - } - - return timeout; -} - -/** @internal Signal transaction timeout to the application. */ -void outgoing_timeout(nta_outgoing_t *orq, uint32_t now) -{ - nta_outgoing_t *cancel = NULL; - - if (orq->orq_status || orq->orq_canceled) - ; - else if (outgoing_other_destinations(orq)) { - SU_DEBUG_5(("%s(%p): %s\n", "nta", (void *)orq, - "try next after timeout")); - 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 / Timer E */ - - if (orq->orq_stateless) - return outgoing_terminate(orq); - - if (orq->orq_forked) { - outgoing_remove_fork(orq); - return outgoing_terminate(orq); - } - - if (orq->orq_reliable) { - if (orq->orq_method != sip_method_invite || !orq->orq_uas) - return outgoing_terminate(orq); - } - - if (orq->orq_method == sip_method_invite) { - if (orq->orq_queue != orq->orq_agent->sa_out.inv_completed) - 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, - uint32_t now) -{ - nta_outgoing_t *orq; - size_t terminated = 0; - - while ((orq = q->q_head)) { - if ((int32_t)(orq->orq_timeout - now) > 0 || - terminated >= timer_max_terminate) - break; - - terminated++; - - SU_DEBUG_5(("nta: timer %s fired, %s %s (%u)\n", timer, - "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq)); - - if (orq->orq_method == sip_method_invite) - outgoing_terminate_invite(orq); - else - outgoing_terminate(orq); - } - - return terminated; -} - - -/** Terminate an INVITE client transaction. */ -static void -outgoing_terminate_invite(nta_outgoing_t *original) -{ - nta_outgoing_t *orq = original; - - while (original->orq_forks) { - orq = original->orq_forks; - original->orq_forks = orq->orq_forks; - - assert(orq->orq_forking == original); - - SU_DEBUG_5(("nta: timer %s fired, %s %s (%u);tag=%s\n", "D", - "terminate", orq->orq_method_name, orq->orq_cseq->cs_seq, - orq->orq_tag)); - - orq->orq_forking = NULL, orq->orq_forks = NULL, orq->orq_forked = 0; - - if (outgoing_terminate(orq)) - continue; - - if (orq->orq_status < 200) { - /* Fork has timed out */ - orq->orq_agent->sa_stats->as_tout_request++; - outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT, 0); - } - } - - if (outgoing_terminate(orq = original)) - return; - - if (orq->orq_status < 200) { - /* Original INVITE has timed out */ - orq->orq_agent->sa_stats->as_tout_request++; - outgoing_reply(orq, SIP_408_REQUEST_TIMEOUT, 0); - } -} - -static void -outgoing_remove_fork(nta_outgoing_t *orq) -{ - nta_outgoing_t **slot; - - for (slot = &orq->orq_forking->orq_forks; - slot && *slot; - slot = &(*slot)->orq_forks) { - if (orq == *slot) { - *slot = orq->orq_forks; - orq->orq_forks = NULL; - orq->orq_forking = NULL; - orq->orq_forked = 0; - } - } - - assert(orq == NULL); -} - -/** 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 && 200 <= status && status < 300 && 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 (su_strcasecmp(orq->orq_from->a_tag, sip->sip_from->a_tag)) - continue; - if (orq->orq_to->a_tag && - su_strcasecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)) - continue; - - if (orq->orq_method == sip_method_ack && 300 <= status) - continue; - - if (v && !su_casematch(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_outgoing_t *orq = _orq->orq_forking ? _orq->orq_forking : _orq; - nta_agent_t *sa = orq->orq_agent; - int internal = sip == NULL || (sip->sip_flags & NTA_INTERNAL_MSG) != 0; - - assert(!internal || status >= 300); - assert(orq == _orq || orq->orq_method == sip_method_invite); - - if (status < 100) status = 100; - - if (!internal && 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); - outgoing_complete(orq); - } - 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) { - nta_outgoing_t *original = orq; - - orq = _orq; - - if (orq->orq_destroyed && 200 <= status && status < 300) { - if (orq->orq_uas && su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) != 0) { - /* Orphan 200 Ok to INVITE. ACK and BYE it */ - SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE %p\n", (void *)orq)); - return nta_msg_ackbye(sa, msg); - } - return -1; /* Proxy statelessly (RFC3261 section 16.11) */ - } - - outgoing_reset_timer(original); /* Retransmission */ - - if (status < 200) { - if (original->orq_status < 200) - original->orq_status = status; - if (orq->orq_status < 200) - orq->orq_status = status; - - if (original->orq_queue == sa->sa_out.inv_calling) { - outgoing_queue(sa->sa_out.inv_proceeding, original); - } - else if (original->orq_queue == sa->sa_out.inv_proceeding) { - if (sa->sa_out.inv_proceeding->q_timeout) { - outgoing_remove(original); - outgoing_queue(sa->sa_out.inv_proceeding, original); - } - } - - /* 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 && !internal) - outgoing_ack(original, sip); - - if (!original->orq_completed) { - if (outgoing_complete(original)) - return 0; - - if (orq->orq_uas && sip && orq == original) { - /* - * We silently discard duplicate final responses to INVITE below - * with outgoing_duplicate() - */ - 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 if (orq->orq_status >= 200) { - /* Once 2xx has been received, non-2xx will not be forwarded */ - if (status >= 300) - return outgoing_duplicate(orq, msg, sip); - - if (orq->orq_uas) { - if (su_strcasecmp(sip->sip_to->a_tag, orq->orq_tag) == 0) - /* Catch retransmission */ - return outgoing_duplicate(orq, msg, sip); - - /* Orphan 200 Ok to INVITE. ACK and BYE it */ - SU_DEBUG_5(("nta: Orphan 200 Ok send ACK&BYE" VA_NONE)); - return nta_msg_ackbye(sa, msg); - } - } - - orq->orq_status = status; - } - } - else if (orq->orq_method != sip_method_ack) { - /* Non-INVITE */ - if (orq->orq_queue == sa->sa_out.trying || - orq->orq_queue == sa->sa_out.resolving) { - /* hacked by freeswitch, this is being hit by options 404 status with 404 orq->orq_status and orq_destroyed = 1, orq_completed = 1 */ - /* assert(orq->orq_status < 200); */ - if (orq->orq_status >= 200) {msg_destroy(msg); return 0;} - - if (status < 200) { - /* @RFC3261 17.1.2.1: - * retransmissions continue for unreliable transports, - * but at an interval of T2. - * - * @RFC4321 1.2: - * Note that Timer E is not altered during the transition - * to Proceeding. - */ - if (!orq->orq_reliable) - orq->orq_interval = 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 (100 >= status + orq->orq_pass_100) { - msg_destroy(msg); - return 0; - } - - if (orq->orq_destroyed) { - msg_destroy(msg); - return 0; - } - - if (orq->orq_response) - msg_destroy(orq->orq_response); - orq->orq_response = msg; - /* Call callback */ - orq->orq_callback(orq->orq_magic, orq, sip); - 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, sip_t *sip) -{ - msg_t *ackmsg; - - 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, SIPTAG_TO(sip->sip_to), TAG_END()); - if (!ackmsg) - return; - - if (!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())) - msg_destroy(ackmsg); -} - -/** Generate messages for hop-by-hop ACK or CANCEL. - */ -msg_t *outgoing_ackmsg(nta_outgoing_t *orq, sip_method_t m, char const *mname, - tag_type_t tag, tag_value_t value, ...) -{ - 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; - - if (tag) { - ta_list ta; - - ta_start(ta, tag, value); - - sip_add_tl(msg, sip, ta_tags(ta)); - /* Bug sf.net # 173323: - * Ensure that request-URI, topmost Via, From, To, Call-ID, CSeq, - * Max-Forward, Route, Accept-Contact, Reject-Contact and - * Request-Disposition are copied from original request - */ - if (sip->sip_from) - sip_header_remove(msg, sip, (void *)sip->sip_from); - if (sip->sip_to && m != sip_method_ack) - sip_header_remove(msg, sip, (void *)sip->sip_to); - if (sip->sip_call_id) - sip_header_remove(msg, sip, (void *)sip->sip_call_id); - while (sip->sip_route) - sip_header_remove(msg, sip, (void *)sip->sip_route); - while (sip->sip_accept_contact) - sip_header_remove(msg, sip, (void *)sip->sip_accept_contact); - while (sip->sip_reject_contact) - sip_header_remove(msg, sip, (void *)sip->sip_reject_contact); - if (sip->sip_request_disposition) - sip_header_remove(msg, sip, (void *)sip->sip_request_disposition); - while (sip->sip_via) - sip_header_remove(msg, sip, (void *)sip->sip_via); - if (sip->sip_max_forwards) - sip_header_remove(msg, sip, (void *)sip->sip_max_forwards); - - ta_end(ta); - } - - sip->sip_request = - sip_request_create(home, m, mname, (url_string_t *)orq->orq_url, NULL); - - if (sip->sip_to == 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); - sip_add_dup(msg, sip, (sip_header_t *)old->sip_max_forwards); - - 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 (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", - (void *)orq, status, phrase)); - orq->orq_status = status; - if (orq->orq_queue == NULL) - outgoing_trying(orq); /* Timer F */ - return 0; - } - - if (orq->orq_destroyed) { - if (orq->orq_status < 200) - orq->orq_status = status; - outgoing_complete(orq); /* Timer D / Timer 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_method != sip_method_invite && - !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; - - orq->orq_status2b = &a->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 (a->status > 0) { - a->orq->orq_status2b = 0; - if (outgoing_recv(a->orq, a->status, a->msg, a->sip) >= 0) - return; - } - - 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 */ - - struct sipdns_tport const *sr_tport; /**< Selected transport */ - - /** 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_otype; /* origin type of query data (0 means request) */ - uint16_t sq_type; /* query type */ - uint16_t sq_priority; /* priority or preference */ - uint16_t sq_weight; /* preference or weight */ - uint16_t sq_grayish; /* candidate for graylisting */ -}; - -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 void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq); -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[]); -struct sipdns_tport const *outgoing_naptr_tport(nta_outgoing_t *orq, - 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[]); - -#ifdef __clang_analyzer__ -#define FUNC_ATTR_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) -#else -#define FUNC_ATTR_NONNULL(...) -#endif - -static void outgoing_query_results(nta_outgoing_t *orq, - struct sipdns_query *sq, - char *results[], - size_t rlen) FUNC_ATTR_NONNULL(3); - - -#define SIPDNS_503_ERROR 503, "DNS Error" - -/** Resolve a request destination */ -static void -outgoing_resolve(nta_outgoing_t *orq, - int explicit_transport, - enum nta_res_order_e res_order) -{ - struct sipdns_resolver *sr = NULL; - char const *tpname = orq->orq_tpn->tpn_proto; - int tport_known = strcmp(tpname, "*") != 0; - - 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, - */ - if (explicit_transport) - sr->sr_use_naptr = 0; - - { - /* 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 (tport_known && !su_casematch(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 (su_casematch(tpn->tpn_proto, sipdns_tports[j].name)) - 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 (tport_known) /* Looking for only one transport */ { - sr->sr_tport = sipdns_tports + j; - break; - } - } - - /* Nothing found */ - if (!sr->sr_tports[0]) { - SU_DEBUG_3(("nta(%p): transport %s is not supported%s%s\n", (void *)orq, - tpname, ident ? " by interface " : "", ident ? ident : "")); - outgoing_resolving_error(orq, SIPDNS_503_ERROR); - return; - } - } - - switch (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); - - if (orq->orq_status > 0) - /* PP: don't hack priority if a preliminary response has been received */ - ; - else if (orq->orq_agent->sa_graylist == 0) - /* PP: priority hacking disabled */ - ; - /* NetModule hack: - * Move server that did not work to end of queue in sres cache - * - * the next request does not try to use the server that is currently down - * - * @TODO: fix cases with only A or AAAA answering, or all servers down. - */ - else if (sr && sr->sr_target) { - struct sipdns_query *sq; - - /* find latest A/AAAA record */ - sq = sr->sr_head; - if (sq && sq->sq_type == sr->sr_a_aaaa2 && sr->sr_a_aaaa1 != sr->sr_a_aaaa2) { - sq->sq_grayish = 1; - } - else { - outgoing_graylist(orq, sr->sr_done); - } - } - - return outgoing_resolve_next(orq); -} - -/** Graylist SRV records */ -static void outgoing_graylist(nta_outgoing_t *orq, struct sipdns_query *sq) -{ - struct sipdns_resolver *sr = orq->orq_resolver; - char const *target = sq->sq_domain, *proto = sq->sq_proto; - unsigned prio = sq->sq_priority, maxprio = prio; - - /* Don't know how to graylist but SRV records */ - if (sq->sq_otype != sres_type_srv) - return; - - SU_DEBUG_5(("nta: graylisting %s:%s;transport=%s\n", target, sq->sq_port, proto)); - - for (sq = sr->sr_head; sq; sq = sq->sq_next) - if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) - maxprio = sq->sq_priority; - - for (sq = sr->sr_done; sq; sq = sq->sq_next) - if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) - maxprio = sq->sq_priority; - - for (sq = sr->sr_done; sq; sq = sq->sq_next) { - int modified; - - if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto)) - continue; - - /* modify the SRV record(s) corresponding to the latest A/AAAA record */ - modified = sres_set_cached_srv_priority( - orq->orq_agent->sa_resolver, - sq->sq_domain, - target, - sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL, 10) : 0, - orq->orq_agent->sa_graylist, - maxprio + 1); - - if (modified >= 0) - SU_DEBUG_3(("nta: reduced priority of %d %s SRV records (increase value to %u)\n", - modified, sq->sq_domain, maxprio + 1)); - else - SU_DEBUG_3(("nta: failed to reduce %s SRV priority\n", sq->sq_domain)); - } -} - -/** Cancel resolver query */ -su_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 */ -su_inline void outgoing_destroy_resolver(nta_outgoing_t *orq) -{ - struct sipdns_resolver *sr = orq->orq_resolver; - - assert(orq->orq_resolver); - - outgoing_cancel_resolver(orq); - - 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, *prefix; - int i; - size_t hlen, plen; - - sr->sr_use_srv = 0; - - host = sr->sr_tpn->tpn_host; - hlen = strlen(host) + 1; - - for (i = 0; sr->sr_tports[i]; i++) { - if (sr->sr_tport && sr->sr_tports[i] != sr->sr_tport) - continue; - - prefix = sr->sr_tports[i]->prefix; - 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, order = -1; - size_t rlen; - su_home_t *home = msg_home(orq->orq_request); - 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); - - if (sr->sr_tport == NULL) - sr->sr_tport = outgoing_naptr_tport(orq, answers); - - for (i = 0; answers && answers[i]; i++) { - sres_naptr_record_t const *na = answers[i]->sr_naptr; - uint16_t type; - int valid_tport; - - if (na->na_record->r_status) - continue; - if (na->na_record->r_type != sres_type_naptr) - continue; - - /* Check if NAPTR matches our target */ - if (!su_casenmatch(na->na_services, "SIP+", 4) && - !su_casenmatch(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; - - valid_tport = sr->sr_tport && - su_casematch(na->na_services, sr->sr_tport->service); - - 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, - order >= 0 && order != na->na_order ? " (out of order)" : - valid_tport ? "" : " (tport not used)")); - - /* 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) - continue; - if (!valid_tport) - 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); - - if (sq == NULL) - continue; - - *tail = sq, tail = &sq->sq_next; - sq->sq_otype = sres_type_naptr; - sq->sq_priority = na->na_prefer; - sq->sq_weight = 1; - sq->sq_type = type; - sq->sq_domain = memcpy(sq + 1, na->na_replace, rlen); - sq->sq_proto = sr->sr_tport->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); -} - -/* Find first supported protocol in order and preference */ -struct sipdns_tport const * -outgoing_naptr_tport(nta_outgoing_t *orq, sres_record_t *answers[]) -{ - int i, j, order, pref; - int orders[SIPDNS_TRANSPORTS] = {0}, prefs[SIPDNS_TRANSPORTS] = {0}; - struct sipdns_tport const *tport; - - struct sipdns_resolver *sr = orq->orq_resolver; - - prefs[0] = 0; - for (j = 0; sr->sr_tports[j]; j++) { - tport = sr->sr_tports[j]; - - orders[j] = 65536, prefs[j] = 65536; - - /* Find transport order */ - for (i = 0; answers && answers[i]; i++) { - sres_naptr_record_t const *na = answers[i]->sr_naptr; - if (na->na_record->r_status) - continue; - if (na->na_record->r_type != sres_type_naptr) - continue; - /* Check if NAPTR matches transport */ - if (!su_casematch(na->na_services, tport->service)) - continue; - orders[j] = na->na_order; - prefs[j] = na->na_prefer; - break; - } - } - - tport = sr->sr_tports[0], order = orders[0], pref = prefs[0]; - - for (j = 1; sr->sr_tports[j]; j++) { - if (orders[j] <= order && prefs[j] < pref) { - tport = sr->sr_tports[j], order = orders[j], pref = prefs[j]; - } - } - - return tport; -} - - -/* 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_otype = sres_type_srv; - 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 (*tail && rand >= (*tail)->sq_weight) { - rand -= (*tail)->sq_weight; - tail = &(*tail)->sq_next; - } - } - - /* Remove selected */ - if (*tail) { - 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 */ - - su_inet_ntop(AF_INET6, &aaaa->aaaa_addr, addr, sizeof(addr)); - - if (j == 0) - SU_DEBUG_5(("nta(%p): %s IN AAAA %s\n", (void *)orq, - aaaa->aaaa_record->r_name, addr)); - else - SU_DEBUG_5(("nta(%p): AAAA %s\n", (void *)orq, addr)); - - assert(j < found); - results[j++] = su_strdup(home, addr); - } - - sres_free_answers(orq->orq_agent->sa_resolver, answers); - - if (results) - 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 */ - - su_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", (void *)orq, addr)); - - assert(j < found); - results[j++] = su_strdup(home, addr); - } - - sres_free_answers(orq->orq_agent->sa_resolver, answers); - - if (results) - outgoing_query_results(orq, sq, results, found); - else if (!q) - outgoing_resolving_error(orq, SIPDNS_503_ERROR); -} - -/** 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", (void *)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 == 0 && sq->sq_grayish) - outgoing_graylist(orq, 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. - */ -su_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; -} - -/* Find un-PRACKed responses */ -static -nta_reliable_t *reliable_find(nta_agent_t const *agent, - sip_t const *sip) -{ - incoming_htable_t const *iht = agent->sa_incoming; - nta_incoming_t *irq, **ii; - sip_call_id_t const *i = sip->sip_call_id; - sip_rack_t const *rack = sip->sip_rack; - hash_value_t hash = NTA_HASH(i, rack->ra_cseq); - - /* XXX - add own hash table for 100rel */ - - for (ii = incoming_htable_hash(iht, hash); - (irq = *ii); - ii = incoming_htable_next(iht, ii)) { - - if (hash == irq->irq_hash && - irq->irq_call_id->i_hash == i->i_hash && - irq->irq_cseq->cs_seq == rack->ra_cseq && - irq->irq_method == sip_method_invite && - strcmp(irq->irq_call_id->i_id, i->i_id) == 0 && - (irq->irq_to->a_tag == NULL || - su_casematch(irq->irq_to->a_tag, sip->sip_to->a_tag)) && - su_casematch(irq->irq_from->a_tag, sip->sip_from->a_tag)) { - - nta_reliable_t const *rel; - - /* Found matching INVITE */ - for (rel = irq->irq_reliable; rel; rel = rel->rel_next) - if (rel->rel_rseq == rack->ra_response) - return (nta_reliable_t *)rel; - - } - } - - return NULL; -} - -/** Process incoming PRACK with matching @RAck field */ -static -int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp) -{ - nta_incoming_t *irq = rel->rel_irq; - nta_incoming_t *pr_irq; - int status; - - 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) { - mreply(irq->irq_agent, NULL, - SIP_500_INTERNAL_SERVER_ERROR, msg, - tp, 0, 0, NULL, - 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_completed) { /* Already sent final response */ - if (pr_irq->irq_terminated && pr_irq->irq_destroyed) - 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 (!timeout) - return; - - if (irq->irq_completed && irq->irq_destroyed) - incoming_free(irq), irq = NULL; - else if (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_to->a_tag))) { - /* 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. - * - * Mark a reliable response object for destroyal and free 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): %s\n", __func__, (void *)rel, "already destroyed")); - - 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): %s\n", __func__, (void *)rel, "not linked")); - 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 - * - * @bug Fix the memory leak - either one of the requests is left unreleased - * for ever. - */ -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 (CSeq: %s %u) already in dialog\n", __func__, - (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)); - return NULL; - } - if (orq->orq_method != sip_method_invite) { - SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) cannot be tagged\n", __func__, - (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)); - return NULL; - } - if (orq->orq_status < 100) { - SU_DEBUG_1(("%s: transaction %p (CSeq: %s %u) still calling\n", __func__, - (void *)orq, orq->orq_cseq->cs_method_name, orq->orq_cseq->cs_seq)); - return NULL; - } - - assert(orq->orq_agent); assert(orq->orq_request); - - agent = orq->orq_agent; - tagged = su_zalloc(agent->sa_home, sizeof(*tagged)); - - home = msg_home((msg_t *)orq->orq_request); - - tagged->orq_hash = orq->orq_hash; - tagged->orq_agent = orq->orq_agent; - tagged->orq_callback = callback; - tagged->orq_magic = magic; - - tagged->orq_method = orq->orq_method; - tagged->orq_method_name = orq->orq_method_name; - tagged->orq_url = orq->orq_url; - tagged->orq_from = orq->orq_from; - - sip_to_tag(home, to = sip_to_copy(home, orq->orq_to), to_tag); - - tagged->orq_to = to; - tagged->orq_tag = to->a_tag; - tagged->orq_cseq = orq->orq_cseq; - tagged->orq_call_id = orq->orq_call_id; - - tagged->orq_request = msg_ref_create(orq->orq_request); - tagged->orq_response = msg_ref_create(orq->orq_response); - - tagged->orq_status = orq->orq_status; - tagged->orq_via_added = orq->orq_via_added; - tagged->orq_prepared = orq->orq_prepared; - tagged->orq_reliable = orq->orq_reliable; - tagged->orq_sips = orq->orq_sips; - tagged->orq_uas = orq->orq_uas; - tagged->orq_pass_100 = orq->orq_pass_100; - tagged->orq_must_100rel = orq->orq_must_100rel; - tagged->orq_100rel = orq->orq_100rel; - tagged->orq_route = orq->orq_route; - *tagged->orq_tpn = *orq->orq_tpn; - tagged->orq_tport = tport_ref(orq->orq_tport); - if (orq->orq_cc) - tagged->orq_cc = nta_compartment_ref(orq->orq_cc); - tagged->orq_branch = orq->orq_branch; - tagged->orq_via_branch = orq->orq_via_branch; - - if (tagged->orq_uas) { - tagged->orq_forking = orq; - tagged->orq_forks = orq->orq_forks; - tagged->orq_forked = 1; - orq->orq_forks = tagged; - } - - outgoing_insert(agent, tagged); - - return tagged; -} - -/**PRACK a provisional response. - * - * Create and send 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, return 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 (su_strcasecmp(resp->sip_to->a_tag, leg->leg_remote->a_tag) || - su_strcasecmp(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 = oorq->orq_cseq->cs_seq; - rack->ra_method = oorq->orq_cseq->cs_method; - rack->ra_method_name = oorq->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 - -/** Return the master transport for the agent. - * - * @NEW_1_12_11 - */ -tport_t * -nta_agent_tports(nta_agent_t *agent) -{ - return agent ? agent->sa_tports : NULL; -} - -su_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; -} - - -/** Return a new reference to the transaction transport. - * - * @note The referenced transport must be unreferenced with tport_unref() - */ -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; -} - -/** Bind transport error callback */ -int nta_agent_bind_tport_error(nta_agent_t *agent, - nta_error_magic_t *magic, - nta_error_tport_f *callback) -{ - if (!agent) - return su_seterrno(EFAULT), -1; - agent->sa_error_magic = magic; - agent->sa_error_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) -{ - assert(orq); - -#if HAVE_SOFIA_STUN - return tport_keepalive(orq->orq_tport, msg_addrinfo(orq->orq_request), - TAG_END()); -#else - return -1; -#endif -} - -/** Close all transports. @since Experimental in @VERSION_1_12_2. */ -int nta_agent_close_tports(nta_agent_t *agent) -{ - size_t 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs b/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs deleted file mode 100644 index f3fe03c723..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.docs +++ /dev/null @@ -1,573 +0,0 @@ -/* -*- 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 , but tag parameters are - * defined in . - * - * @CONTACT Pekka Pessi - * - * @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 and , - * respectively. The various SIP headers are also defined in - * . - * - * @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
100rel 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. - * - * - * @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; - } - - ... -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c deleted file mode 100644 index d3c8094821..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_check.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 16:35:05 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -/* ======================================================================== */ -/* 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 || su_casematch(cd->cd_type, "session")) { - 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 && - su_casenmatch(sip->sip_payload->pl_data, "v=0", 3)) - /* 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 (su_casematch(c_type, ab->ac_type)) - 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] || - !strcasecmp(sip->sip_content_encoding->k_items[0], "gzip") || - !strcasecmp(sip->sip_content_encoding->k_items[0], "deflate")) - 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 (su_casematch(application_sdp, ab->ac_type)) { - 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 (su_casematch(ac->ac_type, ab->ac_type)) { - 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 shortest - * acceptable 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, ...) -{ - unsigned long min_se = my_min_se; - - if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta) - min_se = sip->sip_min_se->min_delta; - - if (sip->sip_session_expires->x_delta >= min_se) - return 0; - - if (irq) { - ta_list ta; - sip_min_se_t min_se0[1]; - - ta_start(ta, tag, value); - - sip_min_se_init(min_se0)->min_delta = min_se; - - nta_incoming_treply(irq, - SIP_422_SESSION_TIMER_TOO_SMALL, - SIPTAG_MIN_SE(min_se0), - ta_tags(ta)); - ta_end(ta); - } - - return 422; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c deleted file mode 100644 index 37a23ade00..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jul 24 22:28:34 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include - -#include "sofia-sip/nta.h" -#include "nta_compat.h" -#include "nta_internal.h" - -#include -#include - -/** 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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h b/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h deleted file mode 100644 index b7178c202b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_compat.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_COMPAT_H; - -/**@file nta_compat.h - * @brief Deprecated NTA functions and types. - * - * @author Pekka Pessi - * - * @date Created: Tue Sep 4 15:54:57 2001 ppessi - */ - -#ifndef NTA_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h b/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h deleted file mode 100644 index 38378dfc1e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_INTERNAL_H - -/**@internal @file nta_internal.h - * - * @brief NTA internal interfaces. - * - * @author Pekka Pessi - * - * @date Created: Tue Jul 18 09:18:32 2000 ppessi - */ - -SOFIA_BEGIN_DECLS - -/** A sip_flag telling that this message is internally generated. */ -#define NTA_INTERNAL_MSG (1<<15) - -#include -#include -#include -#include -#if HAVE_SOFIA_SRESOLV -#include -#endif - -typedef struct nta_compressor nta_compressor_t; - -/* 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; - -SOFIAPUBVAR 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 included directly. -#endif -#include -SOFIAPUBVAR su_log_t nta_log[]; - -SOFIA_END_DECLS - -#endif /* NTA_INTERNAL_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c deleted file mode 100644 index d6e7a2e18c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c +++ /dev/null @@ -1,1937 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jul 24 22:28:34 2001 ppessi - */ - -#include "config.h" - -#include -#include - -#define TAG_NAMESPACE "nta" - -#include "sofia-sip/nta_tag.h" -#include -#include -#include - -#include - -tag_typedef_t ntatag_any = NSTAG_TYPEDEF(*); - -/**@def NTATAG_MCLASS(x) - * - * Message class used by NTA. - * - * The nta can use a custom or extended parser created with - * msg_mclass_clone(). - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * pointer to #msg_mclass_t. - * - * @par Values - * - custom or extended parser created with msg_mclass_clone() - * - NULL - use default parser - * - * @par Default Value - * - Value returned by sip_default_mclass() - * - * @sa NTATAG_SIPFLAGS() - */ -tag_typedef_t ntatag_mclass = PTRTAG_TYPEDEF(mclass); - -/**@def NTATAG_BAD_REQ_MASK(x) - * - * 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 mask ~0U (all bits set) is specified, all requests with any bad header - * are dropped. By default only the requests with bad headers essential for - * request processing or proxying are dropped. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - bitwise or of enum #sip_bad_mask values - * - * @par Default Value - * - sip_mask_response | sip_mask_ua | sip_mask_100rel |
- * sip_mask_events | sip_mask_timer | sip_mask_publish - * The following headers are considered essential by default: - * - @ref sip_request \"request line\"", @From, @To, @CSeq, @CallID, - * @ContentLength, @Via, @ContentType, @ContentDisposition, - * @ContentEncoding, @Supported, @Contact, @Require, @RecordRoute, @RAck, - * @RSeq, @Event, @Expires, @SubscriptionState, @SessionExpires, - * @MinSE, @SIPETag, and @SIPIfMatch. - * - * @sa enum #sip_bad_mask, NTATAG_BAD_RESP_MASK() - */ -tag_typedef_t ntatag_bad_req_mask = UINTTAG_TYPEDEF(bad_req_mask); - -/**@def NTATAG_BAD_RESP_MASK(x) - * - * Mask for bad response messages. - * - * If an incoming response has erroneous headers matching with the mask, nta - * drops the response message. - * - * If mask ~0U (all bits set) is specified, all responses with any bad header - * are dropped. By default only the responses with bad headers essential for - * response processing or proxying are dropped. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - bitwise or of enum #sip_bad_mask values - * - * @sa enum #sip_bad_mask, NTATAG_BAD_REQ_MASK() - * - * @par Default Value - * - sip_mask_response | sip_mask_ua | sip_mask_100rel |
- * sip_mask_events | sip_mask_timer | sip_mask_publish - * The following headers are considered essential by default: - * - @ref sip_status \"status line\"", @From, @To, @CSeq, @CallID, - * @ContentLength, @Via, @ContentType, @ContentDisposition, - * @ContentEncoding, @Supported, @Contact, @Require, @RecordRoute, @RAck, - * @RSeq, @Event, @Expires, @SubscriptionState, @SessionExpires, - * @MinSE, @SIPETag, and @SIPIfMatch. - */ -tag_typedef_t ntatag_bad_resp_mask = UINTTAG_TYPEDEF(bad_resp_mask); - -/**@def NTATAG_DEFAULT_PROXY(x) - * - * URL for (default) proxy. - * - * The requests are sent towards the default outbound proxy regardless - * the values of request-URI or @Route headers in the request. The URL of - * the default proxy is not added to the request in the @Route header or in - * the request-URI (against the recommendation of @RFC3261 section 8.1.2). - * - * The outbound proxy set by NTATAG_DEFAULT_PROXY() is used even if the - * dialog had an established route set or registration provided User-Agent - * with a @ServiceRoute set. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack(), nta_msg_tsend() - * - * @par Parameter type - * Pointer to a url_t structure or a string containg a SIP or SIPS URI - * - * @par Values - * - Valid SIP or SIPS URI - */ -tag_typedef_t ntatag_default_proxy = URLTAG_TYPEDEF(default_proxy); - -/**@def NTATAG_CONTACT(x) - * - * Contact used by NTA. - */ -tag_typedef_t ntatag_contact = SIPHDRTAG_NAMED_TYPEDEF(contact, contact); - -/** @def NTATAG_TARGET(x) - * - * Dialog target (contact) used by NTA. - */ -tag_typedef_t ntatag_target = SIPHDRTAG_NAMED_TYPEDEF(target, contact); - -/** @def NTATAG_ALIASES(x) - * - * Aliases used by NTA. - * @deprecated - */ -tag_typedef_t ntatag_aliases = SIPHDRTAG_NAMED_TYPEDEF(aliases, contact); - -/**@def NTATAG_METHOD(x) - * - * Method name. - * - * Create a dialogless #nta_leg_t object matching only requests with - * the specified method. - * - * @par Used with - * nta_leg_tcreate() - * - * @par Parameter type - * String containing method name. - * - * @par Values - * - A SIP method name (e.g., "SUBSCRIBE"). - * - * @par Default Value - * - None (i.e., all requests methods match with the leg) - * - */ -tag_typedef_t ntatag_method = STRTAG_TYPEDEF(method); - -/**@def NTATAG_BRANCH_KEY(x) - * - * Branch ID to the topmost @Via header. - * - * The NTA generates a random branch ID for the topmost @Via header by default. - * The application can the branch by itself, for intance, if it wants to - * create a @RFC2543-era transaction. - * - * Note that according to @RFC3261 the branch ID must start with "z9hG4bK". - * - * @par Used with - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack(), nta_msg_tsend() - * - * @par Parameter type - * string - * - * @par Value - * - The "branch" ID to to insert into topmost @Via header of the - * request to be sent - * - * @par Default Value - * - A token is generated, either by random when a client transaction is - * created or by hashing the headers and contents of the request when - * request is sent statelessly - * - * @sa @RFC3261 section 8.1.1.7 - */ -tag_typedef_t ntatag_branch_key = STRTAG_TYPEDEF(branch_key); - -/**@def NTATAG_ACK_BRANCH(x) - * - * Branch of the transaction to ACK. - * - * When creating a ACK transaction, the application should provide the - * branch parameter from the original transaction to the stack. The ACK - * transaction object then receives all the retransmitted 2XX responses to - * the original INVITE transaction. - * - * @par Used with - * nta_outgoing_mcreate(), nta_outgoing_tcreate() - * - * @par Parameter type - * string - * - * @par Value - * - "branch" ID used to store the ACK transaction in the nta hash - * table for outgoing client transaction - * - * @par Default Value - * - The INVITE transaction is looked from the hash table using the @CallID, - * @CSeq, @From and @To tags and its branch ID is used - */ -tag_typedef_t ntatag_ack_branch = STRTAG_TYPEDEF(ack_branch); - -/**@def NTATAG_COMP(x) - * - * Compression algorithm. - * - * Set compression algorithm for request as described in @RFC3486. - * - * @note This tag is has no effect without a compression plugin. - * - * @par Used with - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack(), nta_msg_tsend() - * - * @par - * Note that NTATAG_COMP(NULL) can be used with nta_incoming_set_params() - * and nta_incoming_treply(), too. It indicates that the response is sent - * uncompressed, no matter what the client has in @a comp parameter of @Via - * header. - * - * @par Parameter type - * string - * - * @par Values - * - name of the compression algorithm - * - * @par Default Value - * - "sigcomp" - * - * @sa @RFC3320, @RFC3486, TPTAG_COMPARTMENT(), - * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_AWARE(), - * NTATAG_SIGCOMP_CLOSE(), NTATAG_SIGCOMP_OPTIONS() - */ -tag_typedef_t ntatag_comp = CSTRTAG_TYPEDEF(comp); - -/**@def NTATAG_MSG(x) - * - * Pass a SIP message to treply()/tcreate() functions. - * - * @par Used with - * nta_outgoing_tcreate(), nta_incoming_treply() - * - * @par Parameter type - * #msg_t - * - * @par Values - * - A message object which will be completed, serialized and encoded. - * Note that the functions modify directly the message. - * - * @par Default Value - * - A new message object is created and populated by the function call. - * - * @sa msg_copy(), msg_dup(), msg_create(), sip_default_mclass() - */ -tag_typedef_t ntatag_msg = PTRTAG_TYPEDEF(msg); - -/**@def NTATAG_TPORT(x) - * - * Pass a transport object. The transport object is used to send the request - * or response message(s). - * - * @par Used with - * nta_outgoing_tcreate(), nta_outgoing_mcreate(), nta_outgoing_tcancel(), - * nta_incoming_create(), nta_msg_tsend(), nta_msg_mreply() - * - * @par Parameter type - * - #tport_t - * - * @par Values - * - A pointer to the transport object. Note that a new reference to the transport - * is created. - * - * @par Default Value - * - The transport is selected by resolving the outbound URI (specified with - * NTATAG_DEFAULT_PROXY(), the topmost @Route URI or Request-URI. - */ -tag_typedef_t ntatag_tport = PTRTAG_TYPEDEF(tport); - -/**@def NTATAG_SMIME(x) - * - * Provide S/MIME context to NTA. - * - * @todo S/MIME is not implemented. - */ -tag_typedef_t ntatag_smime = PTRTAG_TYPEDEF(smime); - -/**@def NTATAG_REMOTE_CSEQ(x) - * - * Remote CSeq number. - * - * Specify remote command sequence number for a #nta_leg_t dialog object. If - * an request is received matching with the dialog but with @CSeq number - * less than the remote sequence number associated with the dialog, a 500 - * Internal Server Error response is automatically returned to the client. - * - * @par Used with - * nta_leg_tcreate() - * - * @par Parameter type - * - uint32_t - * - * @par Values - * - Remote command sequence number - * - * @par Default Value - * - Initially 0, then determined by the received requests - * - */ -tag_typedef_t ntatag_remote_cseq = UINTTAG_TYPEDEF(remote_cseq); - -/**@def NTATAG_MAXSIZE(x) - * - * Maximum size of incoming message. - * - * If the size of an incoming request message would exceed the - * given limit, the stack will automatically respond with 413 Request - * Entity Too Large. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * - #usize_t - * - * @par Values - * - Maximum acceptable size of an incoming request message. - * - * @par Default Value - * - 2097152 (bytes or 2 megabytes) - * - * @sa msg_maxsize(), NTATAG_UDP_MTU() - */ -tag_typedef_t ntatag_maxsize = USIZETAG_TYPEDEF(maxsize); - -/**@def NTATAG_MAX_PROCEEDING(x) - * - * Maximum size of proceeding queue. - * - * If the size of the proceedng message queue would exceed the - * given limit, the stack will automatically respond with 503 - * Service Unavailable. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * - #usize_t - * - * @par Values - * - Maximum acceptable size of a queue (size_t). - * - * @NEW_1_12_9 - */ -tag_typedef_t ntatag_max_proceeding = USIZETAG_TYPEDEF(max_proceeding); - -/**@def NTATAG_UDP_MTU(x) - * - * Maximum size of outgoing UDP request. - * - * The maximum UDP request size is used to control use of UDP with overtly - * large messages. The IETF requires that the SIP requests over 1300 bytes - * are sent over congestion-controlled transport such as TCP. If a SIP - * message size exceeds the UDP MTU, the TCP is tried instead of UDP. (If - * the TCP connection is refused, the stack reverts back to UDP). - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * - unsigned - * - * @par Values - * - Maximum size of an outgoing UDP request - * - * @par Default Value - * - 1300 (bytes) - * - * @sa @RFC3261 section 18.1.1, NTATAG_MAXSIZE() - */ -tag_typedef_t ntatag_udp_mtu = UINTTAG_TYPEDEF(udp_mtu); - -/**@def NTATAG_MAX_FORWARDS(x) - * - * Default value for @MaxForwards header. - * - * The default value of @MaxForwards header added to the requests. The - * initial value recommended by @RFC3261 is 70, but usually SIP proxies use - * much lower default value, such as 24. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned - * - * @par Values - * - Default value added to the @MaxForwards header in the sent requests - * - * @par Default Value - * - 70 (hops) - * - * @since New in @VERSION_1_12_2. - */ -tag_typedef_t ntatag_max_forwards = UINTTAG_TYPEDEF(max_forwards); - -/**@def NTATAG_SIP_T1(x) - * - * Initial retransmission interval (in milliseconds) - * - * Set the T1 retransmission interval used by the SIP transaction engine. The - * T1 is the initial duration used by request retransmission timers A and E - * (UDP) as well as response retransmission timer G. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Value of SIP T1 in milliseconds - * - * @par Default Value - * - #NTA_SIP_T1 or 500 (milliseconds) - * - * @sa @RFC3261 appendix A, #NTA_SIP_T1, NTATAG_SIP_T1X4(), NTATAG_SIP_T1(), NTATAG_SIP_T4() - */ -tag_typedef_t ntatag_sip_t1 = UINTTAG_TYPEDEF(sip_t1); - -/**@def NTATAG_SIP_T1X64(x) - * - * Transaction timeout (defaults to T1 * 64). - * - * Set the T1x64 timeout value used by the SIP transaction engine. The T1x64 is - * duration used for timers B, F, H, and J (UDP) by the SIP transaction engine. - * The timeout value T1x64 can be adjusted separately from the initial - * retransmission interval T1, which is set with NTATAG_SIP_T1(). - * - * The default value for T1x64 is 64 times value of T1, or 32000 milliseconds. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Value of T1x64 in milliseconds - * - * @par Default Value - * - 64 * #NTA_SIP_T1 or 32000 (milliseconds) - * - * @sa @RFC3261 appendix A, #NTA_SIP_T1, NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() - * - */ -tag_typedef_t ntatag_sip_t1x64 = UINTTAG_TYPEDEF(sip_t1x64); - -/**@def NTATAG_SIP_T2(x) - * - * Maximum retransmission interval (in milliseconds) - * - * Set the maximum retransmission interval used by the SIP transaction - * engine. The T2 is the maximum duration used for the timers E (UDP) and G - * by the SIP transaction engine. Note that the timer A is not capped by T2. - * Retransmission interval of INVITE requests grows exponentially until the - * timer B fires. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Value of SIP T2 in milliseconds - * - * @par Default Value - * - #NTA_SIP_T2 or 4000 (milliseconds) - * - * @sa @RFC3261 appendix A, #NTA_SIP_T2, NTATAG_SIP_T1(), NTATAG_SIP_T1X4(), NTATAG_SIP_T4() - */ -tag_typedef_t ntatag_sip_t2 = UINTTAG_TYPEDEF(sip_t2); - -/**@def NTATAG_SIP_T4(x) - * - * Transaction lifetime (in milliseconds) - * - * Set the lifetime for completed transactions used by the SIP transaction - * engine. A completed transaction is kept around for the duration of T4 in - * order to catch late responses. The T4 is the maximum duration for the - * messages to stay in the network and the duration of SIP timer K. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Value of SIP T4 in milliseconds - * - * @par Default Value - * - #NTA_SIP_T4 or 4000 (milliseconds) - * - * @sa @RFC3261 appendix A, #NTA_SIP_T4, NTATAG_SIP_T1(), NTATAG_SIP_T1X4(), NTATAG_SIP_T2() - */ -tag_typedef_t ntatag_sip_t4 = UINTTAG_TYPEDEF(sip_t4); - -/**@def NTATAG_PROGRESS(x) - * - * Progress timer for User-Agents (interval for retranmitting 1XXs). - * - * The UAS should retransmit preliminary responses to the INVITE - * transactions every minute in order to re-set the timer C within the - * intermediate proxies. - * - * The default value for the progress timer is 60000. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * Value of progress timer in milliseconds. - * - * @par Default Value - * - 90000 (milliseconds, 1.5 minutes) - * - * @sa @RFC3261 sections 13.3.1.1, 16.7 and 16.8, NTATAG_TIMER_C(), - * NTATAG_SIP_T1(), NTATAG_SIP_T1X4(), NTATAG_SIP_T2(), NTATAG_SIP_T4() - */ -tag_typedef_t ntatag_progress = UINTTAG_TYPEDEF(progress); - -/**@def NTATAG_TIMER_C(x) - * - * Value for timer C in milliseconds. - * - * By default the INVITE transaction will not timeout after a preliminary - * response has been received. However, an intermediate proxy can timeout - * the transaction using timer C. Timer C is reset every time a response - * belonging to the transaction is received. - * - * The default value for the timer C is 185000 milliseconds (3 minutes and 5 - * seconds). By default, timer C is not run on user agents (if NTATAG_UA(1) - * without NTATAG_TIMER_C() is given). - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * Value of SIP timer C in milliseconds. The default value is used - * instead if NTATAG_TIMER_C(0) is given. - * - * @par Default Value - * - 185000 (milliseconds, 3 minutes) - * - * @sa @RFC3261 sections 13.3.1.1, 16.7 and 16.8, - * NTATAG_UA(1), NTATAG_TIMER_C(), - * NTATAG_SIP_T1(), NTATAG_SIP_T1X4(), NTATAG_SIP_T2(), NTATAG_SIP_T4() - * - * @NEW_1_12_7. - */ -tag_typedef_t ntatag_timer_c = UINTTAG_TYPEDEF(timer_c); - -/**@def NTATAG_GRAYLIST(x) - * - * Avoid failed servers. - * - * The NTATAG_GRAYLIST() provides the time that the servers are avoided - * after a request sent to them has been failed. Avoiding means that if a - * domain provides multiple servers, the failed servers are tried last. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Number of seconds that server is kept in graylist, from 0 to 86400. - * - * @par Default Value - * - 600 (graylist server for 10 minutes) - * - * @sa NTATAG_BLACKLIST(), NTATAG_TIMEOUT_408() - * - * @NEW_1_12_8 - */ -tag_typedef_t ntatag_graylist = UINTTAG_TYPEDEF(graylist); - -/**@def NTATAG_BLACKLIST(x) - * - * Add Retry-After header to error responses returned to application. - * - * The NTATAG_BLACKLIST() provides a default value for @RetryAfter header - * added to the internally generated responses such as 503 DNS Error - * or 408 Timeout. The idea is that the application can retain its - * current state and retry the operation after a while. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Value of @a delta-seconds in @RetryAfter header, from 0 to 86400 - * - * @par Default Value - * - 0 (no @RetryAfter header is included) - * - * @sa NTATAG_TIMEOUT_408() - */ -tag_typedef_t ntatag_blacklist = UINTTAG_TYPEDEF(blacklist); - -/**@def NTATAG_DEBUG_DROP_PROB(x) - * - * Packet drop probability for debugging. - * - * The packet drop probability parameter is useful mainly for debugging - * purposes. The stack drops an incoming message received over an unreliable - * transport (such as UDP) with the given probability. The range is in 0 .. - * 1000, 500 means p=0.5. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned integer - * - * @par Values - * - Valid values are in range 0 ... 1000 - * - Probablity to drop a given message is value / 1000. - * - * @par Default Value - * - 0 (no packets are dropped) - * - * @sa TPTAG_DEBUG_DROP() - */ -tag_typedef_t ntatag_debug_drop_prob = UINTTAG_TYPEDEF(debug_drop_prob); - -/**@def NTATAG_SIGCOMP_OPTIONS(x) - * - * Semicolon-separated SigComp options. - * - * @note This tag is has no effect without a SigComp plugin. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_agent_add_tport() - * - * @par Parameter type - * string - * - * @par Values - * - semicolon-separated parameter-value pairs, passed to the SigComp plugin - * - * @sa NTATAG_COMP(), NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_AWARE(), - * NTATAG_SIGCOMP_CLOSE(), @RFC3320 - */ -tag_typedef_t ntatag_sigcomp_options = STRTAG_TYPEDEF(sigcomp_options); - -/**@def NTATAG_SIGCOMP_CLOSE(x) - * - * Close SigComp compartment after completing transaction. - * - * @note This tag is has no effect without a SigComp plugin. - * - * @par Used with - * nta_incoming_set_params(), nta_incoming_treply() - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tmcreate(), nta_outgoing_tcancel(), - * nta_outgoing_prack(), nta_msg_tsend(), nta_msg_treply() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - application takes care of compartment management - * - false - stack manages compartments - * - * @sa NTATAG_COMP(), TPTAG_COMPARTMENT(), - * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_AWARE(), - * NTATAG_SIGCOMP_OPTIONS(), @RFC3320 - */ -tag_typedef_t ntatag_sigcomp_close = BOOLTAG_TYPEDEF(sigcomp_close); - -/**@def NTATAG_SIGCOMP_AWARE(x) - * - * Indicate that the application is SigComp-aware. - * - * @note This tag is has no effect without a SigComp plugin. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - application takes care of compartment management - * - false - stack manages compartments - * - * @sa NTATAG_COMP(), NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_CLOSE(), - * NTATAG_SIGCOMP_OPTIONS(), @RFC3320 - */ -tag_typedef_t ntatag_sigcomp_aware = BOOLTAG_TYPEDEF(sigcomp_aware); - -/**@def NTATAG_SIGCOMP_ALGORITHM(x) - * - * Specify SigComp algorithm. - * - * @note This tag is has no effect without a SigComp plugin. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_agent_add_tport() - * - * @par Parameter type - * string - * - * @par Values - * - opaque string passed to the SigComp plugin - * - * @sa NTATAG_COMP(), NTATAG_SIGCOMP_AWARE(), NTATAG_SIGCOMP_CLOSE(), - * NTATAG_SIGCOMP_OPTIONS(), @RFC3320 - */ -tag_typedef_t ntatag_sigcomp_algorithm = STRTAG_TYPEDEF(sigcomp_algorithm); - -/**@def NTATAG_UA(x) - * - * If true, NTA acts as User Agent Server or Client by default. - * - * When acting as an UA, the NTA stack will - * - respond with 481 to a PRACK request with no matching "100rel" response - * - check for out-of-order CSeq headers for each #nta_leg_t dialog object - * - if NTATAG_MERGE_482(1) is also used, return 482 Request Merged to - * a duplicate request with same @CallID, @CSeq, @From tag but different - * topmost @Via header (see @RFC3261 section 8.2.2.2 Merged Requests) - * - silently discard duplicate final responses to INVITE - * - retransmit preliminary responses (101..199) to INVITE request in regular - * intervals ("timer N2") - * - retransmit 2XX response to INVITE request with exponential intervals - * - handle ACK sent in 2XX response to an INVITE using the - * #nta_ack_cancel_f callback bound to #nta_incoming_t with - * nta_incoming_bind() - * - not use timer C unless its value has been explicitly set - * - * @note This NUTAG_UA(1) is set internally by nua_create() - * - * @par Used with - * nta_agent_create() \n - * nta_agent_set_params() \n - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - act as an UA - * - false - act as an proxy - * - * @par Default Value - * - 0 (false) - * - * @sa NTATAG_MERGE_482() - */ -tag_typedef_t ntatag_ua = BOOLTAG_TYPEDEF(ua); - -/**@def NTATAG_STATELESS(x) - * - * Enable stateless processing. - * - * @par Server side - * The incoming requests are processed statefully if there is a default leg - * (created with nta_leg_default()). This option is provided for proxies or - * other server elements that process requests statelessly. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Values - * - true - do not pass incoming requests to default leg - * - false - pass incoming requests to default leg, if it exists - * - * @par Default Value - * - 0 (false, pass incoming requests to default leg) - * - * @par Client side - * The outgoing requests can be sent statelessly, too, if the - * NTATAG_STATELESS(1) is included in the tag list of nta_outgoing_tcreate(). - * - * @par Used with - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - create only a transient #nta_outgoing_t transaction object - * - false - create an ordinary client transaction object - * - * @par Default Value - * - 0 (false, create client transaction) - * - * @sa NTATAG_IS_UA(), nta_incoming_default(), nta_outgoing_default(), - * nta_leg_default() - */ -tag_typedef_t ntatag_stateless = BOOLTAG_TYPEDEF(stateless); - -/**@def NTATAG_USER_VIA(x) - * - * Allow application to insert Via headers. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack(), nta_msg_tsend() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - do not add @Via header to the request (if it has one) - * - false - always add a @Via header - * - * @par Default Value - * - 0 (false, always add a @Via header) - * - * @sa NTATAG_BRANCH(), NTATAG_TPORT() - */ -tag_typedef_t ntatag_user_via = BOOLTAG_TYPEDEF(user_via); - -/**@def NTATAG_PASS_100(x) - * - * Pass "100 Trying" provisional answers to the application. - * - * By default, the stack silently processes the 100 Trying responses - * from the server. Usually the 100 Trying responses are not - * important to the application but rather sent by the outgoing proxy - * immediately after it has received the request. However, the application - * can ask nta for them by setting NTATAG_PASS_100(1) if, for instance, the - * 100 Trying responses are needed for user feedback. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), nta_outgoing_prack(), nta_msg_tsend() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - pass 100 Trying to application - * - false - silently process 100 Trying responses - * - * @par Default Value - * - 0 (false, save application from seeing 100 Trying) - * - * @sa NTATAG_EXTRA_100(), NTATAG_DEFAULT_PROXY() - */ -tag_typedef_t ntatag_pass_100 = BOOLTAG_TYPEDEF(pass_100); - -/**@def NTATAG_EXTRA_100(x) - * - * Respond with "100 Trying" if application has not responded. - * - * As per recommended by @RFC4320, the stack can generate a 100 Trying - * response to the non-INVITE requests if the application has not responded - * to a request within half of the SIP T2 (the default value for T2 is 4000 - * milliseconds, so the extra 100 Trying would be sent after 2 seconds). - * - * At agent level, this option applies to retransmissions of both non-INVITE - * and INVITE transactions. - * - * At incoming request level, this option can disable sending the 100 Trying for - * both retransmissions (if set at agent level) and N1 firings, for just a given - * incoming request. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params(), - * nta_incoming_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - send extra 100 Trying if application does not respond - * - false - do not send 100 Trying - * - * @par Default Value at Agent level - * - 0 (false, do not respond with 100 Trying to retransmissions) - * - * @par Default Value at incoming transaction level - * - 1 (true, respond with 100 Trying to retransmissions and when N1 fired) - * - * @sa @RFC4320, NTATAG_PASS_408(), NTATAG_TIMEOUT_408() - */ -tag_typedef_t ntatag_extra_100 = BOOLTAG_TYPEDEF(extra_100); - -/**@def NTATAG_TIMEOUT_408(x) - * - * Generate "408 Request Timeout" response when request times out. - * - * This tag is used to prevent stack from generating extra 408 response - * messages to non-INVITE requests upon timeout. As per recommended by - * @RFC4320, the 408 Request Timeout responses to non-INVITE - * transaction are not sent over the network to the client by default. The - * application can ask stack to pass the 408 responses with - * NTATAG_PASS_408(1). - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - generate 408 response - * - false - invoke #nta_response_f callback with NULL sip pointer - * when a non-INVITE transaction times out - * - * @sa @RFC4320, NTATAG_PASS_408(), NTATAG_EXTRA_100(), - */ -tag_typedef_t ntatag_timeout_408 = BOOLTAG_TYPEDEF(timeout_408); - -/**@def NTATAG_PASS_408(x) - * - * Pass "408 Request Timeout" responses to the client. - * - * As per recommended by @RFC4320, the 408 Request Timeout responses - * to non-INVITE transaction are not sent over the network to the client by - * default. The application can ask stack to pass the 408 responses with - * NTATAG_PASS_408(1). - * - * Note that unlike NTATAG_PASS_100(), this tags changes the way server side - * works. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - pass superfluous 408 responses - * - false - discard superfluous 408 responses - * - * @sa @RFC4320, NTATAG_EXTRA_100(), NTATAG_TIMEOUT_408() - * - */ -tag_typedef_t ntatag_pass_408 = BOOLTAG_TYPEDEF(pass_408); - -/**@def NTATAG_MERGE_482(x) - * - * Merge requests, send 482 to other requests. - * - * If an User-Agent receives a duplicate request with same @CallID, @CSeq, - * @From tag but different topmost @Via header (see @RFC3261 section 8.2.2.2 - * Merged Requests), it should return 482 Request Merged response to - * the duplicate request. Such a duplicate request has been originally - * generated by a forking proxy and usually routed via different route to - * the User-Agent. The User-Agent should only respond meaningfully to the - * first request and return the 482 response to the following forked - * requests. - * - * Note that also NTATAG_UA(1) should be set before nta detects merges and - * responds with 482 to them. - * - * @note If your application is an multi-lined user-agent, you may consider - * disabling request merging. However, you have to somehow handle merging - * within a single line. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - detect duplicate requests and respond with 482 to them - * - false - process duplicate requests separately - * - * @sa NTATAG_UA(1) - */ -tag_typedef_t ntatag_merge_482 = BOOLTAG_TYPEDEF(merge_482); - -/**@def NTATAG_CANCEL_2543(x) - * - *Follow @RFC2543 semantics with CANCEL. - * - * By default, the nta follows "@RFC3261" semantics when CANCELing a - * request. The CANCEL does not terminate transaction, rather, it is just a - * hint to the server that it should respond immediately (with 487 - * Request Terminated if it has no better response). Also, if the - * original request was sent over unreliable transport such as UDP, the - * CANCEL is delayed until the server has sent a preliminary response to the - * original request. - * - * If NTATAG_CANCEL_2543(1) is given, the transaction is canceled - * immediately internally (a 487 response is generated locally) and the - * CANCEL request is sent without waiting for an provisional response. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * nta_outgoing_tcancel() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - follow "RFC 2543" semantics with CANCEL - * - false - follow "RFC 3261" semantics with CANCEL - * - * @sa NTATAG_CANCEL_408() - */ -tag_typedef_t ntatag_cancel_2543 = BOOLTAG_TYPEDEF(cancel_2543); - -/**@def NTATAG_CANCEL_408(x) - * - * Do not send a CANCEL but just timeout the request. - * - * Calling nta_outgoing_tcancel() with this tag set marks request as - * canceled but does not actually send a CANCEL request. If - * NTATAG_CANCEL_2543(1) is also included, a 487 response is generated - * internally. - * - * @par Used with - * nta_outgoing_tcancel() \n - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - do not send CANCEL - * - false - let request to timeout - * - * @sa NTATAG_CANCEL_2543() - */ -tag_typedef_t ntatag_cancel_408 = BOOLTAG_TYPEDEF(cancel_408); - -/**@def NTATAG_CANCEL_487(x) - * - * When a CANCEL is received, automatically return 487 response to original request. - * - * When the CANCEL is received for an ongoing server transaction - * #nta_incoming_t, the stack will automatically return a 487 Request - * Terminated response to the client after returning from the - * #nta_incoming_f callback bound to the transaction with - * nta_incoming_bind() - * - * The application can delay sending the response to the original request - * when NTATAG_CANCEL_408(0) is used. This is useful, for instance, with a - * proxy that forwards the CANCEL downstream and the forwards the response - * back to upstream. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - respond automatically to the CANCELed transaction - * - false - application takes care of responding - * - * @sa NTATAG_CANCEL_2543(), nta_incoming_bind() - */ -tag_typedef_t ntatag_cancel_487 = BOOLTAG_TYPEDEF(cancel_487); - -/**@def NTATAG_TAG_3261(x) - * - * When responding to requests, use unique tags. - * - * If set the UA would generate an unique @From/@To tag for all dialogs. If - * unset UA would reuse same tag in order to make it easier to re-establish - * dialog state after a reboot. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - use different tag for each dialog - * - false - use same tag for all dialogs - * - * @sa @RFC3261 section 12.2.2 - */ -tag_typedef_t ntatag_tag_3261 = BOOLTAG_TYPEDEF(tag_3261); - -/**@def NTATAG_REL100(x) - * - * Include rel100 in INVITE requests. - * - * Include feature tag "100rel" in @Supported header of the INVITE requests. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - include "100rel" - * - false - do not include "100rel" - * - * @sa nta_outgoing_prack(), nta_reliable_treply(), nta_reliable_mreply() - */ -tag_typedef_t ntatag_rel100 = BOOLTAG_TYPEDEF(rel100); - -/**@def NTATAG_NO_DIALOG(x) - * - * Create a leg without dialog. */ -tag_typedef_t ntatag_no_dialog = BOOLTAG_TYPEDEF(no_dialog); - -/**@def NTATAG_USE_TIMESTAMP(x) - * - * Use @Timestamp header. - * - * If set, a @Timestamp header would be added to stateful requests. The - * header can be used to calculate the roundtrip transport latency between - * client and server. - * - * @par Used with - * nua_create(), - * nta_agent_create(), - * nta_agent_set_params(), - * nta_outgoing_mcreate(), nta_outgoing_tcreate(), - * nta_outgoing_tcancel(), and nta_outgoing_prack(). - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - Add @Timestamp header - * - false - do not add @Timestamp header - * - * @sa @RFC3261 section 8.2.6 - */ -tag_typedef_t ntatag_use_timestamp = BOOLTAG_TYPEDEF(use_timestamp); - -/**@def NTATAG_SIPFLAGS(x) - * - * Set SIP parser flags. - * - * The SIP parser flags affect how the messages are parsed and the result - * presented to the application. They also control encoding of messages. - * The most important flags are as follows: - * - MSG_FLG_COMPACT - use compact form - * (single-letter header names, minimum whitespace) - * - MSG_FLG_EXTRACT_COPY - cache printable copy of headers when parsing. - * Using this flag can speed up proxy processing considerably. It is - * implied when the parsed messages are logged (because #TPORT_LOG - * environment variable is set, or TPTAG_LOG() is used. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - Bitwise OR of SIP parser flags (enum #msg_flg_user) - * - * @sa NTATAG_PRELOAD(), enum #msg_flg_user, sip_s::sip_flags - */ -tag_typedef_t ntatag_sipflags = UINTTAG_TYPEDEF(sipflags); - -/**@def NTATAG_CLIENT_RPORT(x) - * - * Enable client-side "rport". - * - * This tag controls @RFC3581 support on client side. The "rport" parameter - * is used when the response has to be routed symmetrically through a NAT box. - * - * The client-side support involves just adding the "rport" parameter to the topmost - * @Via header before the request is sent. - * - * @note By default, the client "rport" is disabled when nta is used, and - * enabled when nua is used. - * - * @par Used with - * nua_create() (nua uses NTATAG_CLIENT_RPORT(1) by default) \n - * nta_agent_create() \n - * nta_agent_set_params() \n - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - add "rport" parameter - * - false - do not add "rport" parameter - * - * @note The NTATAG_RPORT() is a synonym for this. - * - * @sa @RFC3581, NTATAG_SERVER_RPORT(), NTATAG_TCP_RPORT(), NTATAG_TLS_RPORT(), @Via - */ -tag_typedef_t ntatag_client_rport = BOOLTAG_TYPEDEF(client_rport); - -/**@def NTATAG_SERVER_RPORT(x) - * - * Use rport parameter at server. - * - * This tag controls @RFC3581 support on server side. The "rport" parameter - * is used when the response has to be routed symmetrically through a NAT - * box. - * - * If the topmost @Via header has an "rport" parameter, the server stores - * the port number from which the request was sent in it. When sending the - * response back to the client, the server uses the port number in the - * "rport" parameter rather than the client-supplied port number in @Via - * header. - * - * Note that on server-side the port number is stored regardless of the - * transport protocol. (It is assumed that client supports rport if it - * includes "rport" parameter in @Via field). - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - 2 - add "rport" parameter even if was not present in request - * - 1 - use "rport" parameter (default) - * - 0 - do not use "rport" parameter - * - * @sa @RFC3581, NTATAG_CLIENT_RPORT(), NTATAG_TCP_RPORT(), NTATAG_TLS_RPORT(), @Via - * - * @since Tag type and NTATAG_SERVER_RPORT(2) was added in @VERSION_1_12_9. - */ -tag_typedef_t ntatag_server_rport = INTTAG_TYPEDEF(server_rport); - - -/**@def NTATAG_TCP_RPORT(x) - * - * Use rport with TCP, too. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - include rport parameter in the TCP via line on client side - * - false - do not include rport parameter in the TCP via line on client side - * - * @sa @RFC3581, NTATAG_CLIENT_RPORT(), NTATAG_SERVER_RPORT(), @Via - */ -tag_typedef_t ntatag_tcp_rport = BOOLTAG_TYPEDEF(tcp_rport); - -/**@def NTATAG_TLS_RPORT(x) - * - * Use rport with TLS, too. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - include rport parameter in the TLS via line on client side - * - false - do not include rport parameter in the TLS via line - * on client side - * - * @sa @RFC3581, NTATAG_CLIENT_RPORT(), NTATAG_SERVER_RPORT(), @Via - * - * @NEW_1_12_10 - */ -tag_typedef_t ntatag_tls_rport = BOOLTAG_TYPEDEF(tls_rport); - -/**@def NTATAG_PRELOAD(x) - * - * Preload by N bytes. - * - * When the memory block is allocated for an incoming request by the stack, - * the stack can allocate some extra memory for the parser in addition to - * the memory used by the actual message contents. - * - * While wasting some memory, this can speed up parsing considerably. - * Recommended amount of preloading per packet is 1500 bytes. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * unsigned - * - * @par Values - * Amount of extra per-message memory allocated for parser. - * - * @sa NTATAG_SIPFLAGS() and #MSG_FLG_EXTRACT_COPY - */ -tag_typedef_t ntatag_preload = UINTTAG_TYPEDEF(preload); - -/**@def NTATAG_USE_NAPTR(x) - * - * If true, try to use NAPTR records when resolving. - * - * The application can disable NTA from using NAPTR records when resolving - * SIP URIs. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - enable NAPTR resolving - * - false - disable NAPTR resolving - * - * @bug NAPTRs are not used with SIPS URIs in any case. - * - * @sa @RFC3263, NTATAG_USE_SRV() - */ -tag_typedef_t ntatag_use_naptr = BOOLTAG_TYPEDEF(naptr); - -/**@def NTATAG_USE_SRV(x) - * - * If true, try to use SRV records when resolving. - * - * The application can disable NTA from using SRV records when resolving - * SIP URIs. - * - * @par Used with - * nua_create(), nua_set_params(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - enable SRV resolving - * - false - disable SRV resolving - * - * @sa @RFC3263, NTATAG_USE_NAPTR() - */ -tag_typedef_t ntatag_use_srv = BOOLTAG_TYPEDEF(srv); - -/**@def NTATAG_SRV_503(x) - * - * If true, try to use another destination from SRV records on 503 response. RFC3263 - * - * The application can disable NTA from using a new route after 503 - * - * @par Used with - * nua_create(), nua_set_params(), agent_recv_response(), - * nta_agent_create(), nta_agent_set_params() - * - * @par Parameter type - * boolean: true (non-zero or non-NULL pointer) - * or false (zero or NULL pointer) - * - * @par Values - * - true - enable new destination on 503 - * - false - still use the same destination after timeout - * - * @sa @RFC3263 - */ -tag_typedef_t ntatag_srv_503 = BOOLTAG_TYPEDEF(srv_503); - - -/**@def NTATAG_RSEQ(x) - * - * @RSeq value for nta_outgoing_prack(). - * - * @par Used with - * nta_outgoing_prack() - * - * @par Parameter type - * @c unsigned @c int - * - * @par Values - * Response sequence number from the @RSeq header. -*/ -tag_typedef_t ntatag_rseq = UINTTAG_TYPEDEF(rseq); - -/* Status */ - -/**@def NTATAG_S_IRQ_HASH_REF(x) - * - * Get size of hash table for server-side transactions. - * - * Return number of transactions that fit in the hash table for server-side - * transactions. - * - * @sa nta_agent_get_stats(), NTATAG_S_IRQ_HASH_USED_REF(), - * NTATAG_S_ORQ_HASH_REFxs(), NTATAG_S_LEG_HASH_REF() - */ -tag_typedef_t ntatag_s_irq_hash = USIZETAG_TYPEDEF(s_irq_hash); - -/**@def NTATAG_S_ORQ_HASH_REF(x) - * - * Get size of hash table for client-side transactions. - * - * Return number of transactions that fit in the hash table for client-side - * transactions. - * - * @sa nta_agent_get_stats(), NTATAG_S_ORQ_HASH_USED_REF(), - * NTATAG_S_IRQ_HASH_REF(), NTATAG_S_LEG_HASH_REF() - */ -tag_typedef_t ntatag_s_orq_hash = USIZETAG_TYPEDEF(s_orq_hash); - -/**@def NTATAG_S_LEG_HASH_REF(x) - * - * Get size of hash table for dialogs. - * - * Return number of dialog objects that fit in the hash table for dialogs. - * - * @sa nta_agent_get_stats(), NTATAG_S_LEG_HASH_USED_REF(), - * NTATAG_S_IRQ_HASH_REF(), NTATAG_S_ORQ_HASH_REF() - */ -tag_typedef_t ntatag_s_leg_hash = USIZETAG_TYPEDEF(s_leg_hash); - -/**@def NTATAG_S_IRQ_HASH_USED_REF(x) - * - * Get number of server-side transactions in the hash table. - * - * Return number of server-side transactions objects in the hash table. The - * number includes all transactions destroyed by the application which have - * not expired yet. - * - * @sa nta_agent_get_stats(), NTATAG_S_IRQ_HASH_REF(), - * NTATAG_S_ORQ_HASH_USED_REF(), NTATAG_S_LEG_HASH_USED_REF() - */ -/**@def NTATAG_S_IRQ_HASH_USED_REF(x) - * - * Get number of server-side transactions in the hash table. - * - * Return number of server-side transactions objects in the hash table. The - * number includes all transactions destroyed by the application which have - * not expired yet. - * - * @sa nta_agent_get_stats(), NTATAG_S_IRQ_HASH_REF(), - * NTATAG_S_ORQ_HASH_USED_REF(), NTATAG_S_LEG_HASH_USED_REF() - */ -tag_typedef_t ntatag_s_irq_hash_used = USIZETAG_TYPEDEF(s_irq_hash_used); - -/**@def NTATAG_S_ORQ_HASH_USED_REF(x) - * - * Get number of client-side transactions in the hash table. - * - * Return number of client-side transactions objects in the hash table. The - * number includes all transactions destroyed by the application which have - * not expired yet. - * - * @sa nta_agent_get_stats(), NTATAG_S_ORQ_HASH_REF(), - * NTATAG_S_IRQ_HASH_USED_REF(), NTATAG_S_LEG_HASH_USED_REF() - */ -tag_typedef_t ntatag_s_orq_hash_used = USIZETAG_TYPEDEF(s_orq_hash_used); - -/**@def NTATAG_S_LEG_HASH_USED_REF(x) - * - * Get number of dialogs in the hash table. - * - * Return number of dialog objects in the hash table. Note that the - * nta_leg_t objects created with NTATAG_NO_DIALOG(1) and this not - * corresponding to a dialog are not included in the number. - * - * @sa nta_agent_get_stats(), NTATAG_S_LEG_HASH_REF(), - * NTATAG_S_IRQ_HASH_USED_REF(), NTATAG_S_ORQ_HASH_USED_REF() - */ -tag_typedef_t ntatag_s_leg_hash_used = USIZETAG_TYPEDEF(s_leg_hash_used); - -/**@def NTATAG_S_RECV_MSG_REF(x) - * - * Get number of SIP messages received. - * - * Return number SIP messages that has been received. The number includes - * also bad and unparsable messages. - * - * @sa nta_agent_get_stats(), NTATAG_S_BAD_MESSAGE_REF(), - * NTATAG_S_RECV_REQUEST_REF(), NTATAG_S_RECV_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_recv_msg = USIZETAG_TYPEDEF(s_recv_msg); - -/**@def NTATAG_S_RECV_REQUEST_REF(x) - * - * Get number of SIP requests received. - * - * Return number SIP requests that has been received. The number includes - * also number of bad requests available with NTATAG_S_BAD_REQUEST_REF(). - * - * @sa nta_agent_get_stats(), NTATAG_S_BAD_REQUEST_REF(), - * NTATAG_S_RECV_MSG_REF(), NTATAG_S_RECV_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_recv_request = USIZETAG_TYPEDEF(s_recv_request); - -/**@def NTATAG_S_RECV_RESPONSE_REF(x) - * - * Get number of SIP responses received. - * - * Return number SIP responses that has been received. The number includes - * also number of bad and unusable responses available with - * NTATAG_S_BAD_RESPONSE_REF(). - * - * @sa nta_agent_get_stats(), NTATAG_S_BAD_RESPONSE_REF(), - * NTATAG_S_RECV_MSG_REF(), NTATAG_S_RECV_REQUEST_REF() - */ -tag_typedef_t ntatag_s_recv_response = USIZETAG_TYPEDEF(s_recv_response); - -/**@def NTATAG_S_BAD_MESSAGE_REF(x) - * - * Get number of bad SIP messages received. - * - * Return number of bad SIP messages that has been received. - * - * @sa nta_agent_get_stats(), NTATAG_S_RECV_MSG_REF(), - * NTATAG_S_BAD_REQUEST_REF(), NTATAG_S_BAD_RESPONSE_REF(). - */ -tag_typedef_t ntatag_s_bad_message = USIZETAG_TYPEDEF(s_bad_message); - -/**@def NTATAG_S_BAD_REQUEST_REF(x) - * - * Get number of bad SIP requests received. - * - * Return number of bad SIP requests that has been received. - * - * @sa nta_agent_get_stats(), NTATAG_S_BAD_MESSAGE_REF(), - * NTATAG_S_BAD_RESPONSE_REF(). - */ -tag_typedef_t ntatag_s_bad_request = USIZETAG_TYPEDEF(s_bad_request); - -/**@def NTATAG_S_BAD_RESPONSE_REF(x) - * - * Get number of bad SIP responses received. - * - * Return number of bad SIP responses that has been received. - * - * @sa nta_agent_get_stats(), NTATAG_S_BAD_MESSAGE_REF(), - * NTATAG_S_BAD_REQUEST_REF() - */ -tag_typedef_t ntatag_s_bad_response = USIZETAG_TYPEDEF(s_bad_response); - -/**@def NTATAG_S_DROP_REQUEST_REF(x) - * - * Get number of SIP requests dropped. - * - * Return number of SIP requests that has been randomly dropped after - * receiving them because of NTATAG_DEBUG_DROP_PROB() has been set. - * - * @sa nta_agent_get_stats(), NTATAG_DEBUG_DROP_PROB(), - * NTATAG_S_DROP_RESPONSE_REF() - * - * @note The value was not calculated before @VERSION_1_12_7. - */ -tag_typedef_t ntatag_s_drop_request = USIZETAG_TYPEDEF(s_drop_request); - -/**@def NTATAG_S_DROP_RESPONSE_REF(x) - * - * Get number of SIP responses dropped. - * - * Return number of SIP responses that has been randomly dropped after - * receiving them because of NTATAG_DEBUG_DROP_PROB() has been set. - * - * @sa nta_agent_get_stats(), NTATAG_DEBUG_DROP_PROB(), - * NTATAG_S_DROP_REQUEST_REF() - * - * @note The value was not calculated before @VERSION_1_12_7. - */ -tag_typedef_t ntatag_s_drop_response = USIZETAG_TYPEDEF(s_drop_response); - -/**@def NTATAG_S_CLIENT_TR_REF(x) - * - * Get number of client transactions created. - * - * Return number of client transactions created. The number also includes - * client transactions with which stack failed to send the request because - * the DNS resolving failed or the transport failed. - * - * @note The number include stateless requests sent with nta_msg_tsend(), - * too. - * - * @sa nta_agent_get_stats(), NTATAG_S_SENT_REQUEST_REF(), - * NTATAG_S_SERVER_TR_REF(). - */ -tag_typedef_t ntatag_s_client_tr = USIZETAG_TYPEDEF(s_client_tr); - -/**@def NTATAG_S_SERVER_TR_REF(x) - * - * Get number of server transactions created. - * - * Return number of server transactions created. - * - * @sa nta_agent_get_stats(), NTATAG_S_RECV_RESPONSE_REF(), - * NTATAG_S_CLIENT_TR_REF(), NTATAG_S_DIALOG_TR_REF(), - */ -tag_typedef_t ntatag_s_server_tr = USIZETAG_TYPEDEF(s_server_tr); - -/**@def NTATAG_S_DIALOG_TR_REF(x) - * - * Get number of in-dialog server transactions created. - * - * Return number of in-dialog server transactions created. The number - * includes only those transactions that were correlated with a dialog - * object. - * - * @sa nta_agent_get_stats(), NTATAG_S_SERVER_TR_REF(), - * NTATAG_S_CLIENT_TR_REF(), NTATAG_S_RECV_RESPONSE_REF(). - */ -tag_typedef_t ntatag_s_dialog_tr = USIZETAG_TYPEDEF(s_dialog_tr); - -/**@def NTATAG_S_ACKED_TR_REF(x) - * - * Get number of server transactions that have received ACK. - * - * Return number of INVITE server transactions for which an ACK request has - * been received. - * - * @sa nta_agent_get_stats(), NTATAG_S_SERVER_TR_REF(), - * NTATAG_S_CANCELED_TR_REF() - */ -tag_typedef_t ntatag_s_acked_tr = USIZETAG_TYPEDEF(s_acked_tr); - -/**@def NTATAG_S_CANCELED_TR_REF(x) - * - * Get number of server transactions that have been CANCELed. - * - * Return number of server transactions for which an CANCEL request has been - * received. Currently, the count includes only INVITE server transactions - * that have been CANCELed. - * - * @sa nta_agent_get_stats(), NTATAG_S_SERVER_TR_REF(), - * NTATAG_S_ACKED_TR_REF(). - */ -tag_typedef_t ntatag_s_canceled_tr = USIZETAG_TYPEDEF(s_canceled_tr); - -/**@def NTATAG_S_TRLESS_REQUEST_REF(x) - * - * Get number of requests that were processed stateless. - * - * Return number of received requests that were processed statelessly, - * either with #nta_message_f message callback given with the - * nta_agent_create() or, missing the callback, by returning a 501 Not - * Implemented response to the request. - * - * @sa nta_agent_get_stats(), , - * nta_agent_create(), #nta_message_f, NTATAG_S_TRLESS_TO_TR_REF(), - * NTATAG_S_TRLESS_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_trless_request = USIZETAG_TYPEDEF(s_trless_request); - -/**@def NTATAG_S_TRLESS_TO_TR_REF(x) - * - * Get number of requests converted to transactions by message callback. - * - * Return number of requests that were converted to a server transaction - * with nta_incoming_create(). - * - * @sa nta_agent_get_stats(), nta_incoming_create(), nta_agent_create(), - * #nta_message_f, NTATAG_S_TRLESS_REQUEST_REF() - */ -tag_typedef_t ntatag_s_trless_to_tr = USIZETAG_TYPEDEF(s_trless_to_tr); - -/**@def NTATAG_S_TRLESS_RESPONSE_REF(x) - * - * Get number of responses without matching request. - * - * Return number of received responses for which no matching client - * transaction was found. Such responses are processed either by the - * client transaction created with nta_outgoing_default(), the - * #nta_message_f message callback given to nta_agent_create(), or, missing - * both the default client transaction and message callback, they are - * silently discarded. - * - * The NTATAG_S_TRLESS_200_REF() counter counts those successful 2XX - * responses to the INVITE without client transaction which are silently - * discarded. - * - * @sa nta_agent_get_stats(), nta_outgoing_default(), nta_agent_create(), - * , #nta_message_f, nta_msg_ackbye(), - * NTATAG_S_TRLESS_REQUEST_REF(), NTATAG_S_TRLESS_200_REF(). - */ -tag_typedef_t ntatag_s_trless_response = USIZETAG_TYPEDEF(s_trless_response); - -/**@def NTATAG_S_TRLESS_200_REF(x) - * - * Get number of successful responses missing INVITE client transaction. - * - * Return number of received 2XX responses to INVITE transaction for which - * no matching client transaction was found nor which were processed by a - * default client transaction created with nta_outgoing_default() or - * #nta_message_f message callback given to nta_agent_create(). - * - * @sa nta_agent_get_stats(), nta_outgoing_default(), nta_agent_create(), - * , #nta_message_f, nta_msg_ackbye(), - * NTATAG_S_TRLESS_RESPONSE_REF(). - */ -tag_typedef_t ntatag_s_trless_200 = USIZETAG_TYPEDEF(s_trless_200); - -/**@def NTATAG_S_MERGED_REQUEST_REF(x) - * - * Get number of requests merged by UAS. - * - * Return number of requests for which UAS already has returned a response - * and which were merged (that is, returned a 482 Request Merged - * response). - * - * @sa nta_agent_get_stats(), NTATAG_UA(1), @RFC3261 section 8.2.2.2 - */ -tag_typedef_t ntatag_s_merged_request = USIZETAG_TYPEDEF(s_merged_request); - -/**@def NTATAG_S_SENT_MSG_REF(x) - * - * Get number of SIP messages sent by stack. - * - * Return number of SIP messages given to the transport layer for - * transmission by the SIP stack. The number includes also messages which - * the transport layer failed to send for different reasons. - * - * @sa nta_agent_get_stats(), NTATAG_S_RECV_MSG_REF(), - * NTATAG_S_SENT_REQUEST_REF(), NTATAG_S_SENT_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_sent_msg = USIZETAG_TYPEDEF(s_sent_msg); - -/**@def NTATAG_S_SENT_REQUEST_REF(x) - * - * Get number of SIP requests sent by stack. - * - * Return number of SIP requests given to the transport layer for - * transmission by the SIP stack. The number includes retransmissions and - * messages which the transport layer failed to send for different reasons. - * - * @sa nta_agent_get_stats(), NTATAG_S_RECV_REQUEST_REF(), - * NTATAG_S_SENT_MSG_REF(), NTATAG_S_SENT_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_sent_request = USIZETAG_TYPEDEF(s_sent_request); - -/**@def NTATAG_S_SENT_RESPONSE_REF(x) - * - * Get number of SIP responses sent by stack. - * - * Return number of SIP responses given to the transport layer for - * transmission by the SIP stack. The number includes retransmissions and - * messages which the transport layer failed to send for different reasons. - * - * @sa nta_agent_get_stats(), NTATAG_S_RECV_RESPONSE_REF(), - * NTATAG_S_SENT_MSG_REF(), NTATAG_S_SENT_REQUEST_REF() - */ -tag_typedef_t ntatag_s_sent_response = USIZETAG_TYPEDEF(s_sent_response); - -/**@def NTATAG_S_RETRY_REQUEST_REF(x) - * - * Get number of SIP requests retransmitted by stack. - * - * Return number of SIP requests given to the transport layer for - * retransmission by the SIP stack. The number includes messages which the - * transport layer failed to send for different reasons. - * - * @sa nta_agent_get_stats(), NTATAG_S_SENT_MSG_REF(), - * NTATAG_S_SENT_REQUEST_REF(), NTATAG_S_RETRY_RESPONSE_REF() - */ -tag_typedef_t ntatag_s_retry_request = USIZETAG_TYPEDEF(s_retry_request); - -/**@def NTATAG_S_RETRY_RESPONSE_REF(x) - * - * Get number of SIP responses retransmitted by stack. - * - * Return number of SIP responses given to the transport layer for - * retransmission by the SIP stack. The number includes messages which the - * transport layer failed to send for different reasons. - * - * @sa nta_agent_get_stats(), NTATAG_S_SENT_MSG_REF(), - * NTATAG_S_SENT_REQUEST_REF(), NTATAG_S_RETRY_REQUEST_REF() - */ -tag_typedef_t ntatag_s_retry_response = USIZETAG_TYPEDEF(s_retry_response); - -/**@def NTATAG_S_RECV_RETRY_REF(x) - * - * Get number of retransmitted SIP requests received by stack. - * - * Return number of SIP requests received by the stack. This number only - * includes retransmission for which a matching server transaction object - * was found. - * - * @sa nta_agent_get_stats(), NTATAG_S_RETRY_REQUEST_REF(). - */ -tag_typedef_t ntatag_s_recv_retry = USIZETAG_TYPEDEF(s_recv_retry); - -/**@def NTATAG_S_TOUT_REQUEST_REF(x) - * - * Get number of SIP client transactions that has timeout. - * - * Return number of SIP client transactions that has timeout. - * - * @sa nta_agent_get_stats(), NTATAG_S_TOUT_RESPONSE_REF(). - */ -tag_typedef_t ntatag_s_tout_request = USIZETAG_TYPEDEF(s_tout_request); - -/**@def NTATAG_S_TOUT_RESPONSE_REF(x) - * - * Get number of SIP server transactions that has timeout. - * - * Return number of SIP server transactions that has timeout. The number - * includes only the INVITE transactions for which the stack has received no - * ACK requests. - * - * @sa nta_agent_get_stats(), NTATAG_S_TOUT_REQUEST_REF(). - */ -tag_typedef_t ntatag_s_tout_response = USIZETAG_TYPEDEF(s_tout_response); - -/* Internal */ -tag_typedef_t ntatag_delay_sending = BOOLTAG_TYPEDEF(delay_sending); -tag_typedef_t ntatag_incomplete = BOOLTAG_TYPEDEF(incomplete); diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c b/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c deleted file mode 100644 index 1e14eb6323..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/portbind.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file portbind.c - * @brief Bind a socket to an UDP/TCP port and return the port number - * - * @author Pekka Pessi - * - * @date Created: Thu Mar 25 12:12:25 2004 ppessi - */ - -#include "config.h" - -char const name[] = "portbind"; -#include -#include -#include -#include -#include -#include - -#if HAVE_SYS_SOCKET_T -#include -#endif - -#if HAVE_NETINET_IN_H -#include -#endif - -#if HAVE_NETDB_H -#include -#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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/run_check_nta b/libs/sofia-sip/libsofia-sip-ua/nta/run_check_nta deleted file mode 100755 index 772cd95c4c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/run_check_nta +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -$VALGRIND exec ./check_nta "$@" \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta b/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta deleted file mode 100755 index 06329e91ee..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta +++ /dev/null @@ -1,222 +0,0 @@ -#! /bin/sh -# -# 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 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# as published by the Free Software Foundation; either version 2.1 of -# the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# 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 . -# - -#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 2>&1 ; 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 2>&1 ; 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 2>&1 && ./portbind --help > /dev/null 2>&1 -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 -port=$(./portbind $v6flag $((port + 1))) sips=$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 < $namedfile < $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 $sips me -_sip._tcp SRV 2 100 $contact me - -_sip._udp.srv SRV 1 100 $contact a -_sips._tcp.srv SRV 3 100 $sips 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 - -; First SIP SRV is not found -nosrv NAPTR 20 1 "s" "SIP+D2U" "" _sip._udp.nosrv - NAPTR 20 2 "s" "SIP+D2T" "" _sip._tcp.nosrv - NAPTR 20 3 "s" "SIP+D2U" "" _sip._udp.srv - NAPTR 20 4 "s" "SIP+D2T" "" _sip._tcp.srv - -; Redirect with TLS - - -; 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 $! 2>/dev/null -do - sleep 1 -done - -if test -r $pidfile ; then -# export SOFIA_DEBUG=9 - sink=$sink down=$down \ - ipv6=$ipv6 \ - SIPCONTACT="sip:*:$contact;comp=sigcomp" \ - SIPSCONTACT="sips:*:$sips;comp=sigcomp" \ - TEST_NTA_CERTDIR=$srcdir/../tport/ \ - $VALGRIND ./test_nta "$@" - $resolvfile - exit=$? - kill $(cat $pidfile) - rm $pidfile $zonefile $resolvfile $namedfile 2>/dev/null - exit $exit -else - echo "$0: cannot start named (check apparmor/selinux)" - ipv6=$ipv6 $VALGRIND exec ./test_nta "$@" -fi - -else # not having BIND and portbind - ipv6=$ipv6 $VALGRIND exec ./test_nta "$@" -fi - diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api b/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api deleted file mode 100755 index 73369c73d7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/run_test_nta_api +++ /dev/null @@ -1,39 +0,0 @@ -#! /bin/sh -# -# Run test_nta_api -# -# -------------------------------------------------------------------- -# -# This file is part of the Sofia-SIP package -# -# Copyright (C) 2005 Nokia Corporation. -# -# Contact: Pekka Pessi -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# as published by the Free Software Foundation; either version 2.1 of -# the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# 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 . -# - -#set -x - -s=${0%/*} - -exec $VALGRIND ./test_nta_api "$@" - - diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c b/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c deleted file mode 100644 index 4385e08f63..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sl_read_payload.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Sep 5 00:44:34 2002 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include - -/** 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 = ""; - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs b/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs deleted file mode 100644 index 6511aa6156..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils.docs +++ /dev/null @@ -1,9 +0,0 @@ -/* -*- 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. - * - */ - diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c b/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c deleted file mode 100644 index 35cc972a42..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_log.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Oct 5 15:38:39 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include -#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 = ""; - - 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 = su_strncspn(s, end - s, "\r\n"); - size_t crlf = su_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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c b/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c deleted file mode 100644 index a9ace69da2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sl_utils_print.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Oct 5 15:38:39 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#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 = su_strncspn(s, end - s, "\r\n"); - crlf = su_strnspn(s + n, end - s - n, "\r\n"); - if (prefix) - fputs(prefix, stream), total += strlen(prefix); - if (fwrite(s, 1, n + crlf, stream) < n + crlf) - return (issize_t)-1; - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h deleted file mode 100644 index c3139b65a5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta.h +++ /dev/null @@ -1,505 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_H - -/**@file sofia-sip/nta.h @brief Nokia Transaction API for SIP - * - * @author Pekka Pessi - * - * @date Created: Tue Jul 18 09:18:32 2000 ppessi - */ - -#ifndef SU_WAIT_H -#include -#endif - -#ifndef SIP_H -#include -#endif - -#ifndef NTA_TAG_H -#include -#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 - * . */ -#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 - * . */ -#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 - * . */ -#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 - * . */ -#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_msg_is_internal(msg_t const *msg); -SOFIAPUBFUN int nta_sip_is_internal(sip_t const *sip); - -/* ---------------------------------------------------------------------- - * 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); - -/** Get local request sequence number. @NEW_1_12_9 */ -SOFIAPUBFUN uint32_t nta_leg_get_seq(nta_leg_t const *leg); - -/** Get remote request sequence number. @NEW_1_12_9 */ -SOFIAPUBFUN uint32_t nta_leg_get_rseq(nta_leg_t const *leg); - -SOFIAPUBFUN int nta_leg_client_route(nta_leg_t *leg, - sip_record_route_t const *route, - sip_contact_t const *contact); - -SOFIAPUBFUN int nta_leg_client_reroute(nta_leg_t *leg, - sip_record_route_t const *route, - sip_contact_t const *contact, - int initial); - -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 *); - -/** Get dialog leg by CallID */ -SOFIAPUBFUN -nta_leg_t *nta_leg_by_call_id(nta_agent_t *sa, const char *call_id); - -/* ---------------------------------------------------------------------- - * 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 sip_time_t nta_incoming_received(nta_incoming_t *irq, su_nanotime_t *nano); - -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 -msg_t *nta_incoming_create_response(nta_incoming_t *irq, int status, char const *phrase); - -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_bind(nta_outgoing_t *orq, - nta_response_f *callback, - nta_outgoing_magic_t *magic); -SOFIAPUBFUN nta_outgoing_magic_t *nta_outgoing_magic(nta_outgoing_t const *orq, - nta_response_f *callback); -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 char const *nta_outgoing_branch(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 preliminary responses. - * Application may define this to appropriate type before including - * . */ -#define NTA_RELIABLE_MAGIC_T struct nta_reliable_magic_s -#endif - -/** Application context for reliable preliminary responses. */ -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); - -SOFIAPUBFUN int nta_is_internal_msg(msg_t const *msg); - -SOFIA_END_DECLS - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h deleted file mode 100644 index 48ee525275..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_stateless.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_STATELESS_H - -/**@file sofia-sip/nta_stateless.h - * @brief NTA functions for stateless SIP processing. - * - * @author Pekka Pessi - * - * @date Created: Tue Sep 4 15:54:57 2001 ppessi - */ - -#ifndef NTA_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h deleted file mode 100644 index c385362fa5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h +++ /dev/null @@ -1,605 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_TAG_H - -/**@file sofia-sip/nta_tag.h - * @brief NTA tags - * - * @author Pekka Pessi - * - * @date Created: Tue Sep 4 15:54:57 2001 ppessi - */ - -#ifndef SU_TAG_H -#include -#endif - -#ifndef SIP_TAG_H -#include -#endif - -#ifndef URL_TAG_H -#include -#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; -#define NTATAG_MCLASS(x) ntatag_mclass, tag_cptr_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_mclass_ref; -#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_cptr_vr(&(x), (x)) - -NTA_DLL extern tag_typedef_t ntatag_bad_req_mask; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#define NTATAG_UDP_MTU(x) ntatag_udp_mtu, tag_uint_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_udp_mtu_ref; -#define NTATAG_UDP_MTU_REF(x) ntatag_udp_mtu_ref, tag_uint_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_max_proceeding; -#define NTATAG_MAX_PROCEEDING(x) ntatag_max_proceeding, tag_usize_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_max_proceeding_ref; -#define NTATAG_MAX_PROCEEDING_REF(x) ntatag_max_proceeding_ref, tag_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_max_forwards; -#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; -#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; -#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; -#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; -#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; -#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_timer_c; -#define NTATAG_TIMER_C(x) ntatag_timer_c, tag_uint_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_timer_c_ref; -#define NTATAG_TIMER_C_REF(x) ntatag_timer_c_ref, tag_uint_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_graylist; -#define NTATAG_GRAYLIST(x) ntatag_graylist, tag_uint_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_graylist_ref; -#define NTATAG_GRAYLIST_REF(x) ntatag_graylist_ref, tag_uint_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_blacklist; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#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; -#define NTATAG_SERVER_RPORT(x) ntatag_server_rport, tag_int_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_server_rport_ref; -#define NTATAG_SERVER_RPORT_REF(x) ntatag_server_rport_ref, tag_int_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_tcp_rport; -#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_tls_rport; -#define NTATAG_TLS_RPORT(x) ntatag_tls_rport, tag_bool_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_tls_rport_ref; -#define NTATAG_TLS_RPORT_REF(x) ntatag_tls_rport_ref, tag_bool_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_preload; -#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; -#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; -#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_srv_503; -#define NTATAG_SRV_503(x) ntatag_srv_503, tag_bool_v((x)) - -NTA_DLL extern tag_typedef_t ntatag_srv_503_ref; -#define NTATAG_SRV_503_REF(x) ntatag_srv_503_ref, tag_bool_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_rseq; -#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_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_orq_hash; -#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_leg_hash; -#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_usize_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_usize_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_usize_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_usize_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_usize_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_usize_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_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_recv_msg; -#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_recv_request; -#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_recv_response; -#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_bad_message; -#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_bad_request; -#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_bad_response; -#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_drop_request; -#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_drop_response; -#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_client_tr; -#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_server_tr; -#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr; -#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_acked_tr; -#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr; -#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_trless_request; -#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_usize_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_usize_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_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_trless_response; -#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_trless_200; -#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_merged_request; -#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_sent_msg; -#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_sent_request; -#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_sent_response; -#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_retry_request; -#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_retry_response; -#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_recv_retry; -#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_tout_request; -#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_usize_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_usize_vr(&(x)) - -NTA_DLL extern tag_typedef_t ntatag_s_tout_response; -#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_usize_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_usize_vr(&(x)) - -SOFIA_END_DECLS - -#endif /* !defined(nta_tag_h) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h deleted file mode 100644 index 6dafbb55a0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tport.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTA_TPORT_H - -/** - * @file sofia-sip/nta_tport.h - * @brief Transport and SigComp handling - * - * @author Pekka Pessi - * - * @date Created: Thu Oct 7 20:04:39 2004 ppessi - * - */ - -#ifndef NTA_H -#include -#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; - -#ifndef NTA_ERROR_MAGIC_T -#define NTA_ERROR_MAGIC_T void -#endif -typedef NTA_ERROR_MAGIC_T nta_error_magic_t; - -struct sigcomp_compartment; -struct sigcomp_udvm; - -#define nta_transport nta_incoming_transport - -SOFIAPUBFUN tport_t *nta_agent_tports(nta_agent_t *agent); - -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 *); - -typedef void nta_error_tport_f(nta_error_magic_t *, nta_agent_t *, tport_t *); - -SOFIAPUBFUN -int nta_agent_bind_tport_update(nta_agent_t *agent, - nta_update_magic_t *magic, - nta_update_tport_f *); - -SOFIAPUBFUN -int nta_agent_bind_tport_error(nta_agent_t *agent, - nta_error_magic_t *magic, - nta_error_tport_f *callback); - -SOFIA_END_DECLS - -#endif /* !defined NTA_TPORT_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h deleted file mode 100644 index 9ddafe46a2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/sl_utils.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * - * @date Created: Thu Oct 5 15:38:39 2000 ppessi - */ - -#include - -#ifndef STRING0_H -#include -#endif - -#ifndef SIP_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c deleted file mode 100644 index 1d92314645..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c +++ /dev/null @@ -1,4003 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Aug 21 15:18:26 2001 ppessi - */ - -#include "config.h" - -typedef struct agent_t agent_t; -typedef struct client_t client_t; - -#define SU_ROOT_MAGIC_T agent_t - -#include - -#include - -#define NTA_AGENT_MAGIC_T agent_t -#define NTA_LEG_MAGIC_T agent_t -#define NTA_OUTGOING_MAGIC_T client_t -#define NTA_INCOMING_MAGIC_T agent_t -#define NTA_RELIABLE_MAGIC_T agent_t - -#include "sofia-sip/nta.h" -#include "sofia-sip/nta_tport.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "s2util.h" - -#if HAVE_OPEN_C -#include -#endif - -SOFIAPUBVAR su_log_t nta_log[]; -SOFIAPUBVAR su_log_t tport_log[]; - -int tstflags = 0; -#define TSTFLAGS tstflags - -#include - -#if HAVE_FUNC -#elif HAVE_FUNCTION -#define __func__ __FUNCTION__ -#else -#define __func__ name -#endif - -#define NONE ((void *)-1) - -int expensive_checks, test_nta_sips; - -#define EXPENSIVE_CHECKS (expensive_checks) - -struct sigcomp_compartment; - -char const name[] = "test_nta"; - -typedef struct invite_client_t invite_client_t; - -typedef int client_check_f(client_t *, nta_outgoing_t *, sip_t const *); -typedef int client_deinit_f(client_t *); - -struct client_t { - agent_t *c_ag; - char const *c_name; - client_check_f * c_check; - client_check_f * const * c_checks; - client_deinit_f * c_deinit; - void *c_extra; - nta_outgoing_t *c_orq; - int c_status; - int c_final; - int c_errors; -}; - -struct invite_client_t { - client_t ic_client[1]; - nta_outgoing_t *ic_orq; /* Original INVITE transaction */ - int ic_tag_status; /* Status for current branch */ - char *ic_tag; -}; - -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; - unsigned ag_running :1, ag_canceled:1, ag_acked:1, :0; - - 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_reliable_t *ag_reliable; - - 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; - - su_sockaddr_t ag_su_nta[1]; - socklen_t ag_su_nta_len; - - /* Dummy servers */ - char const *ag_sink_port; - su_socket_t ag_sink_socket, ag_down_socket; - su_wait_t ag_sink_wait[1]; -}; - -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); - -static int wait_for_ack_or_cancel(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 new_leg_callback_180(agent_t *ag, - nta_leg_t *leg, - nta_incoming_t *irq, - sip_t const *sip) -{ - int status = new_leg_callback_200(ag, leg, irq, sip); - if (status == 200) { - ag->ag_irq = irq; - status = 180; - } - return status; -} - - -static client_check_f client_check_to_tag; - -static client_check_f * const default_checks[] = { - client_check_to_tag, - NULL -}; - -static client_check_f * const no_default_checks[] = { - NULL -}; - -/** Callback from client transaction */ -int outgoing_callback(client_t *ctx, - nta_outgoing_t *orq, - sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = nta_outgoing_status(orq); - client_check_f * const *checks; - - if (tstflags & tst_verbatim) { - if (sip) - printf("%s: %s: response %s %03d %s\n", name, ctx->c_name, - sip->sip_status->st_version, - sip->sip_status->st_status, - sip->sip_status->st_phrase); - else - printf("%s: %s: callback %03d\n", name, ctx->c_name, - status); - } - - if (status >= 200 && ag->ag_comp) { /* XXX */ - nta_compartment_decref(&ag->ag_client_compartment); - ag->ag_client_compartment = nta_outgoing_compartment(ctx->c_orq); - } - - if (status > ctx->c_status) - ctx->c_status = status; - if (status >= 200) - ctx->c_final = 1; - - if (ctx->c_check && ctx->c_check(ctx, orq, sip)) - ctx->c_errors++; - - checks = ctx->c_checks; - - for (checks = checks ? checks : default_checks; *checks; checks++) - if ((*checks)(ctx, ctx->c_orq, sip)) - ctx->c_errors++; - - return 0; -} - -/** Deinit client. Return nonzero if client checks failed. */ -static -int client_deinit(client_t *c) -{ - int errors = c->c_errors; - - if (c->c_deinit && c->c_deinit(c)) - errors++; - - if (c->c_orq) nta_outgoing_destroy(c->c_orq), c->c_orq = NULL; - - c->c_errors = 0; - c->c_status = 0; - - return errors; -} - - -static -void nta_test_run(agent_t *ag) -{ - for (ag->ag_running = 1; ag->ag_running;) { - if (tstflags & tst_verbatim) { - fputs(".", stdout); fflush(stdout); - } - su_root_step(ag->ag_root, 500L); - } -} - - -/** Run client test. Return nonzero if client checks failed. */ -static -int client_run_with(client_t *c, int expected, void (*runner)(client_t *c)) -{ - int resulting; - - TEST_1(c->c_orq != NULL); - - runner(c); - - resulting = c->c_status; - - if (client_deinit(c)) - return 1; - - if (expected) - TEST(resulting, expected); - - return 0; -} - -static -void until_final_received(client_t *c) -{ - for (c->c_final = 0; !c->c_final; ) { - if (tstflags & tst_verbatim) { - fputs(".", stdout); fflush(stdout); - } - su_root_step(c->c_ag->ag_root, 500L); - } -} - -static -void fast_final_received(client_t *c) -{ - for (c->c_final = 0; !c->c_final; ) { - if (tstflags & tst_verbatim) { - fputs(".", stdout); fflush(stdout); - } - s2_fast_forward(500, c->c_ag->ag_root); - } -} - -static -int client_run(client_t *c, int expected) -{ - return client_run_with(c, expected, until_final_received); -} - -static -void until_server_acked(client_t *c) -{ - agent_t *ag = c->c_ag; - - for (ag->ag_acked = 0; !ag->ag_acked;) { - if (tstflags & tst_verbatim) { - fputs(".", stdout); fflush(stdout); - } - su_root_step(ag->ag_root, 500L); - } -} - -static -int client_run_until_acked(client_t *c, int expected) -{ - return client_run_with(c, expected, until_server_acked); -} - -void -until_server_canceled(client_t *c) -{ - agent_t *ag = c->c_ag; - - for (ag->ag_canceled = 0; !ag->ag_canceled || c->c_status < 200;) { - if (tstflags & tst_verbatim) { - fputs(".", stdout); fflush(stdout); - } - su_root_step(ag->ag_root, 500L); - } -} - -static -int client_run_until_canceled(client_t *c, int expected) -{ - return client_run_with(c, expected, until_server_canceled); -} - - -#include - -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, err = -1; - - BEGIN(); - - ag->ag_root = su_root_create(ag); - TEST_1(ag->ag_root); - - ag->ag_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0); - TEST_1(ag->ag_mclass); - -#if SU_HAVE_IN6 - if (su_strmatch(getenv("ipv6"), "true")) { - 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 = su_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_socket = s; - su_wait_init(ag->ag_sink_wait); - su_wait_create(ag->ag_sink_wait, ag->ag_sink_socket, SU_WAIT_IN); - - ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port)); - - /* Down server */ - s = su_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 */ - 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()); - TEST_1(ag->ag_agent); - - contact = getenv("SIPSCONTACT"); - if (contact) { - if (nta_agent_add_tport(ag->ag_agent, URL_STRING_MAKE(contact), - TPTAG_CERTIFICATE(getenv("TEST_NTA_CERTDIR")), - TPTAG_TLS_VERIFY_POLICY(TPTLS_VERIFY_NONE), - TAG_END()) == 0) - test_nta_sips = 1; - } - - { - /* Initialize our headers */ - sip_from_t from[1]; - sip_to_t to[1]; - sip_contact_t m[1]; - - su_sockaddr_t *su = ag->ag_su_nta; - - 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; - - if (host_is_ip4_address(m->m_url->url_host)) { - su_inet_pton(su->su_family = AF_INET, - m->m_url->url_host, - &su->su_sin.sin_addr); - ag->ag_su_nta_len = (sizeof su->su_sin); - } - else { - TEST_1(host_is_ip_address(m->m_url->url_host)); - su_inet_pton(su->su_family = AF_INET6, - m->m_url->url_host, - &su->su_sin6.sin6_addr); - ag->ag_su_nta_len = (sizeof su->su_sin6); - } - - su->su_port = htons(5060); - if (m->m_url->url_port && strlen(m->m_url->url_port)) { - unsigned long port = strtoul(m->m_url->url_port, NULL, 10); - su->su_port = htons(port); - } - TEST_1(su->su_port != 0); - - 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; - - err = nta_agent_set_params(ag->ag_agent, - NTATAG_ALIASES(ag->ag_aliases), - NTATAG_REL100(1), - NTATAG_UA(1), - NTATAG_MERGE_482(1), - NTATAG_USE_NAPTR(1), - NTATAG_USE_SRV(1), - NTATAG_MAX_FORWARDS(20), - TAG_END()); - TEST(err, 7); - - err = nta_agent_set_params(ag->ag_agent, - NTATAG_ALIASES(ag->ag_aliases), - NTATAG_DEFAULT_PROXY("sip:127.0.0.1"), - TAG_END()); - TEST(err, 2); - - err = nta_agent_set_params(ag->ag_agent, - NTATAG_ALIASES(ag->ag_aliases), - NTATAG_DEFAULT_PROXY(NULL), - TAG_END()); - TEST(err, 2); - - err = nta_agent_set_params(ag->ag_agent, - NTATAG_DEFAULT_PROXY("tel:+35878008000"), - TAG_END()); - TEST(err, -1); - - } - - { - url_t url[1]; - - /* Create the server leg */ - *url = *ag->ag_aliases->m_url; - url->url_user = "%"; - ag->ag_server_leg = nta_leg_tcreate(ag->ag_agent, - leg_callback_200, - ag, - NTATAG_NO_DIALOG(1), - URLTAG_URL(url), - TAG_END()); - TEST_1(ag->ag_server_leg); - } - - 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); - - if (ag->ag_sink_port) { - su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL; - su_wait_destroy(ag->ag_sink_wait); - su_close(ag->ag_sink_socket); - } - - 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 (int)len; -} - -#if HAVE_DIRENT_H -#include -#endif - -static int test_bad_messages(agent_t *ag) -{ - BEGIN(); - -#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); - } - - offset = strlen(name); - - 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 = ai->ai_addrlen); - 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 = dir ? readdir(dir) : NULL; 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); - fclose(f); - 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); - } - - TEST_SIZE(su_sendto(s, "\r\n\r\n", 4, 0, (void *)ai->ai_addr, ai->ai_addrlen), 4); - - su_root_step(ag->ag_root, 1); - - TEST_SIZE(su_sendto(s, "", 0, 0, ai->ai_addr, ai->ai_addrlen), 0); - - 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; - - if (dir) - closedir(dir); - -#endif /* HAVE_DIRENT_H */ - - END(); -} - -static unsigned char const code[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -#include - -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; -} - -static -int client_check_to_tag(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip) - TEST_1(sip->sip_to && sip->sip_to->a_tag); - return 0; -} - -static -int check_magic_branch(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip) { - TEST_1(sip->sip_via); - TEST_S(sip->sip_via->v_branch, "MagicalBranch"); - } - return 0; -} - -static -int check_via_with_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip && sip->sip_via) { - TEST_S(sip->sip_via->v_comp, "sigcomp"); - } - return 0; -} - -static -int check_via_without_sigcomp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip && sip->sip_via) { - TEST_1(sip->sip_via->v_comp == NULL); - } - return 0; -} - -static -int check_via_with_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip && sip->sip_via) { - TEST_S(sip->sip_via->v_protocol, "SIP/2.0/TCP"); - } - return 0; -} - -static -int check_via_with_sctp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip && sip->sip_via) { - TEST_S(sip->sip_via->v_protocol, "SIP/2.0/SCTP"); - } - return 0; -} - -static -int check_via_with_udp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (sip && sip->sip_via) { - TEST_S(sip->sip_via->v_protocol, "SIP/2.0/UDP"); - } - return 0; -} - -static -int save_and_check_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - if (ctx->c_status >= 200 && ctx->c_extra) { - tport_t *tport = nta_outgoing_transport(orq); - TEST_1(tport); - *(tport_t **)ctx->c_extra = tport; - } - - return check_via_with_tcp(ctx, orq, sip); -} - - - - -/* 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; - tport_t *tcp_tport = NULL; - - url_t url[1]; - - BEGIN(); - - nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); - - *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 (su_casematch(v->v_protocol, sip_transport_udp)) { - if (udp) - v_udp_only = v; - udp = 1; - if (udp_comp == NULL) - udp_comp = v->v_comp; - } - else if (su_casematch(v->v_protocol, sip_transport_tcp)) { - tcp = 1; - if (tcp_comp == NULL) - tcp_comp = v->v_comp; - } - else if (su_casematch(v->v_protocol, sip_transport_sctp)) { - sctp = 1; - } - else if (su_casematch(v->v_protocol, sip_transport_tls)) { - 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]; - client_t ctx[1] = {{ ag, "Test 0.1", check_via_without_sigcomp }}; - - *url = *ag->ag_contact->m_url; - url->url_params = NULL; - ag->ag_expect_leg = ag->ag_default_leg; - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_HEADER_STR(p_acid), - TAG_END()); - - TEST_1(!client_run(ctx, 200)); - - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - - TEST_1(ag->ag_request); - msg_destroy(ag->ag_request), ag->ag_request = 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; - client_t ctx[1] = {{ ag, "Test 0.1.2", check_via_without_sigcomp }}; - - *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; - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - - 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"); - - 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; - client_t ctx[1] = {{ ag, "Test 0.1.3", check_via_with_sigcomp }}; - - *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; - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - NTATAG_COMP("sigcomp"), - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - - TEST_1(!client_run(ctx, 200)); - - TEST_1(ag->ag_client_compartment); - nta_compartment_decref(&ag->ag_client_compartment); - TEST_P(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) { - client_t ctx[1] = {{ ag, "Test 0.2", save_and_check_tcp, }}; - url_t url[1]; - sip_payload_t *pl; - usize_t size = 512 * 1024; - - ctx->c_extra = &tcp_tport; - - *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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - TEST_1(!client_run(ctx, 200)); - TEST_1(tcp_tport); - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - if (tcp_tport) { - /* Test 0.2.1 - always use transport connection from NTATAG_TPORT() - * - * Test bug reported by geaaru - * - NTATAG_TPORT() is not used if NTATAG_DEFAULT_PROXY() is given - */ - client_t ctx[1] = {{ ag, "Test 0.2.1", save_and_check_tcp }}; - url_t url[1]; - sip_payload_t *pl; - tport_t *used_tport = NULL; - - ctx->c_extra = &used_tport; - - *url = *ag->ag_aliases->m_url; - url->url_user = "alice"; - - TEST(tport_shutdown(tcp_tport, 1), 0); /* Not going to send anymore */ - - TEST_1(pl = test_payload(ag->ag_home, 512)); - - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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), - NTATAG_TPORT(tcp_tport), - TAG_END()); - su_free(ag->ag_home, pl); - TEST_1(!client_run(ctx, 503)); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - - TEST_1(used_tport == tcp_tport); - - tport_unref(tcp_tport), tcp_tport = NULL; - - if (v_udp_only) /* Prepare for next test */ - TEST_1(tcp_tport = tport_ref(tport_parent(used_tport))); - tport_unref(used_tport); - } - - if (tcp_tport) { - /* test 0.2.2 - select transport protocol using NTATAG_TPORT() - * - * Use primary NTATAG_TPORT() to select transport - */ - client_t ctx[1] = {{ ag, "Test 0.2.2", save_and_check_tcp }}; - url_t url[1]; - sip_payload_t *pl; - tport_t *used_tport = NULL; - - ctx->c_extra = &used_tport; - TEST_1(tport_is_primary(tcp_tport)); - - TEST_1(pl = test_payload(ag->ag_home, 512)); - - *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 */ - - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - (url_string_t *)url, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_bob), - SIPTAG_TO(ag->ag_alice), - SIPTAG_CONTACT(ag->ag_m_bob), - SIPTAG_PAYLOAD(pl), - NTATAG_TPORT(tcp_tport), - TAG_END()); - su_free(ag->ag_home, pl); - TEST_1(!client_run(ctx, 503)); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - - TEST_1(used_tport); - TEST_1(tport_is_tcp(used_tport)); - tport_unref(used_tport); - tport_unref(tcp_tport), tcp_tport = NULL; - } - - /* 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) { - client_t ctx[1] = {{ ag, "Test 0.3" }}; - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - TEST_1(!client_run(ctx, 200)); - 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. - */ - { - client_t ctx[1] = {{ ag, "Test 0.4.1", check_via_with_tcp }}; - 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)); - - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - - TEST_1(!client_run(ctx, 200)); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - 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) { - client_t ctx[1] = {{ ag, "Test 0.4.2", check_via_with_udp }}; - 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; - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - - TEST_1(!client_run(ctx, 200)); - - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - - TEST_1(ag->ag_in_via); - TEST_1(su_casematch(ag->ag_in_via->v_protocol, "SIP/2.0/UDP")); - 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) { - client_t ctx[1] = {{ ag, "Test 0.5", check_via_with_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)); - - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - - TEST_1(!client_run(ctx, 200)); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - if (udp) { - /* Test 0.6 - * Send a message from default leg to server leg - * using a prefilled Via header - */ - client_t ctx[1] = {{ ag, "Test 0.6", check_magic_branch }}; - - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_VIA(via), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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; - client_t ctx[1] = {{ ag, "Test 0.7", check_via_with_sctp }}; - - *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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - TEST_1(!client_run(ctx, 200)); - 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; - client_t ctx[1] = {{ ag, "Test 0.8" }}; - - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - 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); - TEST_1(!client_run(ctx, 413)); - 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]; - client_t ctx[1] = {{ ag, "Test 0.9" }}; - - nta_agent_set_params(ag->ag_agent, - NTATAG_TIMEOUT_408(1), - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_bob), - SIPTAG_TO(ag->ag_alice), - SIPTAG_CONTACT(ag->ag_m_bob), - TAG_END()); - - TEST_1(!client_run_with(ctx, 408, fast_final_received)); - TEST_P(ag->ag_latest_leg, NULL); - - nta_agent_set_params(ag->ag_agent, - 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_running = 0; - - return 0; -} - - -int test_destroy_incoming(agent_t *ag) -{ - BEGIN(); - - url_t url[1]; - - *url = *ag->ag_contact->m_url; - - { - client_t ctx[1] = {{ ag, "Test 3.1" }}; - - /* 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); - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - TAG_END()); - TEST_1(!client_run(ctx, 500)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - { - /* Test 3.2 - * Check that when an incoming request is destroyed, a 500 response is sent - */ - client_t ctx[1] = {{ ag, "Test 3.2" }}; - - nta_leg_bind(ag->ag_default_leg, leg_callback_save, ag); - - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - TAG_END()); - TEST_1(ctx->c_orq); - nta_test_run(ag); - TEST(ctx->c_status, 0); - TEST_1(ag->ag_irq); - TEST_1(ctx->c_orq); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - - nta_incoming_destroy(ag->ag_irq), ag->ag_irq = NULL; - - TEST_1(!client_run(ctx, 500)); - } - - 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 (su_casematch(v->v_protocol, sip_transport_udp)) - udp = 1; - else if (su_casematch(v->v_protocol, sip_transport_tcp)) - tcp = 1; - else if (su_casematch(v->v_protocol, sip_transport_sctp)) - sctp = 1; - else if (su_casematch(v->v_protocol, sip_transport_tls)) - 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 - */ - client_t ctx[1] = {{ ag, "Test 1.1" }}; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - { - /* Test 1.2 - * Send a message to sip:srv.example.org - */ - client_t ctx[1] = {{ ag, "Test 1.2" }}; - url->url_host = "srv.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - { - /* Test 1.3 - * Send a message to sip:ipv.example.org - */ - client_t ctx[1] = {{ ag, "Test 1.3" }}; - url->url_host = "ipv.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - { - /* Test 1.4.1 - * Send a message to sip:down.example.org - */ - client_t ctx[1] = {{ ag, "Test 1.4.1" }}; - url->url_host = "down.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - - } - - { - /* Test 1.4.2 - * Send a message to sip:na503.example.org - */ - client_t ctx[1] = {{ ag, "Test 1.4.2" }}; - url->url_host = "na503.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 503)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - { - /* Test 1.4.3 - * Send a message to sip:nona.example.org - */ - client_t ctx[1] = {{ ag, "Test 1.4.3" }}; - url->url_host = "nona.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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 - */ - client_t ctx[1] = {{ ag, "Test 1.4.4" }}; - url->url_host = "nosrv.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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() - */ - client_t ctx[1] = {{ ag, "Test 1.5.1: outgoing_make_srv_query()" }}; - url->url_host = "srv.example.org"; - url->url_params = "transport=tcp"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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() - */ - client_t ctx[1] = {{ ag, "Test 1.5.2: outgoing_make_srv_query()" }}; - - url->url_host = "srv.example.org"; - url->url_params = "transport=udp"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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() - */ - client_t ctx[1] = {{ ag, "Test 1.5: outgoing_query_srv_a()" }}; - - url->url_host = "srv2.example.org"; - url->url_params = "transport=udp"; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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() - */ - client_t ctx[1] = {{ ag, "Test 1.6.1: 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 503)); - 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() - */ - client_t ctx[1] = {{ ag, "Test 1.6.2: 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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 - */ - client_t ctx[1] = {{ ag, "Test 1.6c" }}; - - url->url_host = "na.example.org"; - ag->ag_expect_leg = ag->ag_default_leg; - TEST_1(ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END())); - TEST_1(!client_run(ctx, 503)); - 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. - */ - client_t ctx[1] = {{ ag, "Test 1.7: outgoing_make_a_aaaa_query()" }}; - - url->url_host = "down2.example.org"; - url->url_port = ag->ag_contact->m_url->url_port; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - url->url_params = NULL; - } - - if (test_nta_sips) { - /* Test 1.8 - Send a message to sips:example.org - * - * Tests sf.net bug #1292657 (SIPS resolving with NAPTR). - */ - client_t ctx[1] = {{ ag, "Test 1.8" }}; - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)"sips:example.org", - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_default_leg); - } - - 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]; - client_t ctx[1] = {{ ag, "Test 1.2" }}; - - *url2 = *url; - url2->url_port = "9"; /* discard service */ - - ag->ag_expect_leg = ag->ag_default_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - (url_string_t *)url, - SIP_METHOD_MESSAGE, - (url_string_t *)url2, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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. - */ - - 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(ag->ag_alice_leg); - TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); - - { - client_t ctx[1] = {{ ag, "Test 2.1" }}; - - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_MESSAGE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - TEST_1(ag->ag_bob_leg != NULL); - } - - { - /* Send message from Bob to Alice */ - client_t ctx[1] = {{ ag, "Test 2.2" }}; - - nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); - - - ag->ag_expect_leg = ag->ag_alice_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_MESSAGE, - (url_string_t *)ag->ag_m_alice->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_alice_leg); - } - - { - /* Send again message from Alice to Bob */ - client_t ctx[1] = {{ ag, "Test 2.3" }}; - ag->ag_expect_leg = ag->ag_bob_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_alice_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_MESSAGE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_bob_leg); - } - - { - /* Send message from Bob to Alice - * This time, however, specify request URI - */ - client_t ctx[1] = {{ ag, "Test 2.4" }}; - ag->ag_expect_leg = ag->ag_alice_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_MESSAGE, - (url_string_t *)ag->ag_m_alice->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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(); -} - -#ifndef MSG_TRUNC -#define MSG_TRUNC 0 -#endif - -static ssize_t recv_udp(agent_t *ag, void *b, size_t size) -{ - ssize_t n; - - memset(b, 0, size); - - for (;;) { - su_root_step(ag->ag_root, 10L); - if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { - n = su_recv(ag->ag_sink_socket, b, size, MSG_TRUNC); - if (n > 0) - return n; - } - } -} - -/* Test merging */ -int test_merging(agent_t *ag) -{ - BEGIN(); - - /* - * Test merging: send two messages with same - * from tag/call-id/cseq number to nta, - * expect 200 and 408. - */ - - char const rfc3261prefix[] = "z9hG4bK"; - - char const template[] = - "%s " URL_PRINT_FORMAT " SIP/2.0\r\n" - "Via: SIP/2.0/UDP 127.0.0.1:%s;branch=%s.%p\r\n" - "Via: SIP/2.0/TCP fake.address.for.via.example.net;branch=z9hG4bK.%p\r\n" - "CSeq: %u %s\r\n" - "Call-ID: dfsjfhsduifhsjfsfjkfsd.%p@dfsdhfsjkhsdjk\r\n" - "From: Evil Forker ;tag=test_nta-%s\r\n" - "To: Bob the Builder %s\r\n" - "Content-Length: 0\r\n" - "\r\n"; - - url_t u1[1], u2[2]; - - char m1[1024], m2[1024]; - char r1[1024], r2[1024]; - - size_t len, l1, l2; - su_sockaddr_t *su = ag->ag_su_nta; - socklen_t sulen = ag->ag_su_nta_len; - - /* Empty sink socket */ - su_setblocking(ag->ag_sink_socket, 0); - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - su_wait(ag->ag_sink_wait, 1, 0); - su_wait(ag->ag_sink_wait, 1, 0); - - { - /* RFC 3261 8.2.2.2 Merged Requests: - - If the request has no tag in the To header field, the UAS core MUST - check the request against ongoing transactions. If the From tag, - Call-ID, and CSeq exactly match those associated with an ongoing - transaction, but the request does not match that transaction (based - on the matching rules in Section 17.2.3), the UAS core SHOULD - generate a 482 (Loop Detected) response and pass it to the server - transaction. - */ - nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); - ag->ag_expect_leg = ag->ag_server_leg; - ag->ag_latest_leg = NULL; - - *u1 = *ag->ag_m_bob->m_url; - snprintf(m1, sizeof m1, - template, - "MESSAGE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, - /* 2nd Via */ (void *)ag, - /* CSeq */ 13, "MESSAGE", - /* Call-ID */ (void *)ag, - /* From tag */ "2.5.1", - /* To tag */ ""); - l1 = strlen(m1); - - *u2 = *ag->ag_m_bob->m_url; - - snprintf(m2, sizeof m2, - template, - "MESSAGE", URL_PRINT_ARGS(u2), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, - /* 2nd Via */ (void *)ag, - /* CSeq */ 13, "MESSAGE", - /* Call-ID */ (void *)ag, - /* From tag */ "2.5.1", - /* To tag */ ""); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - len = strlen("SIP/2.0 200 "); - TEST_1(memcmp(r1, "SIP/2.0 200 ", len) == 0); - TEST_1(memcmp(r2, "SIP/2.0 482 ", len) == 0); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - { - /* - * Check that request with same call-id, cseq and from-tag - * are not merged if the method is different. - */ - nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); - ag->ag_expect_leg = ag->ag_server_leg; - ag->ag_latest_leg = NULL; - - *u1 = *ag->ag_m_bob->m_url; - snprintf(m1, sizeof m1, - template, - "MESSAGE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, - /* 2nd Via */ (void *)ag, - /* CSeq */ 14, "MESSAGE", - /* Call-ID */ (void *)ag, - /* From tag */ "2.5.2", - /* To tag */ ""); - l1 = strlen(m1); - - *u2 = *ag->ag_m_bob->m_url; - - snprintf(m2, sizeof m2, - template, - "OPTIONS", URL_PRINT_ARGS(u2), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, - /* 2nd Via */ (void *)ag, - /* CSeq */ 14, "OPTIONS", - /* Call-ID */ (void *)ag, - /* From tag */ "2.5.2", - /* To tag */ ""); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - len = strlen("SIP/2.0 200 "); - TEST_1(memcmp(r1, "SIP/2.0 200 ", len) == 0); - TEST_1(memcmp(r2, "SIP/2.0 482 ", len) != 0); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - { - /* test with rfc2543 */ - - snprintf(m1, sizeof m1, - template, - "MASSAGE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, "0.", (void *)0, - /* 2nd Via */ (void *)ag, - /* CSeq */ 14, "MASSAGE", - /* Call-ID */ (void *)(ag + 1), - /* From tag */ "2.5.3", - /* To tag */ ""); - l1 = strlen(m1); - - u2->url_user = "bob+2"; - - snprintf(m2, sizeof m2, - template, - "MASSAGE", URL_PRINT_ARGS(u2), - /* Via */ ag->ag_sink_port, "0.", (void *)0, - /* 2nd Via */ (void *)ag, - /* CSeq */ 14, "MASSAGE", - /* Call-ID */ (void *)(ag + 1), - /* From tag */ "2.5.3", - /* To tag */ ""); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - l1 = strlen("SIP/2.0 200 "); - TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); - TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) == 0); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - { - /* test with to-tag */ - - snprintf(m1, sizeof m1, - template, - "MESSAGE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, - /* 2nd Via */ (void *)ag, - /* CSeq */ 15, "MESSAGE", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.5.4", - /* To tag */ ";tag=in-dialog"); - l1 = strlen(m1); - - u2->url_user = "bob+2"; - - snprintf(m2, sizeof m2, - template, - "MESSAGE", URL_PRINT_ARGS(u2), - /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, - /* 2nd Via */ (void *)ag, - /* CSeq */ 15, "MESSAGE", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.5.4", - /* To tag */ ";tag=in-dialog"); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - l1 = strlen("SIP/2.0 200 "); - TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); - TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) != 0); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - { - /* test with rfc2543 and to-tag */ - - snprintf(m1, sizeof m1, - template, - "MESSAGE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, "0.", (void *)0, - /* 2nd Via */ (void *)ag, - /* CSeq */ 15, "MESSAGE", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.5.5", - /* To tag */ ";tag=in-dialog"); - l1 = strlen(m1); - - snprintf(m2, sizeof m2, - template, - "MESSAGE", URL_PRINT_ARGS(u2), - /* Via */ ag->ag_sink_port, "0.", (void *)0, - /* 2nd Via */ (void *)ag, - /* CSeq */ 15, "MESSAGE", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.5.5", - /* To tag */ ";tag=in-dialog"); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - l1 = strlen("SIP/2.0 200 "); - TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); - TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) != 0); - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - { - /* test INVITE/CANCEL with rfc2543 */ - char const template2[] = - "%s " URL_PRINT_FORMAT " SIP/2.0\r\n" - "Via: SIP/2.0/UDP 127.0.0.1:%s;x-kuik=%p\r\n" - "CSeq: %u %s\r\n" - "Call-ID: %p.dfsdhfsjkhsdjk.dfsjfhsduifhsjfsfjkfsd\r\n" - "From: Evil Forker ;tag=test_nta-%s\r\n" - "To: Bob the Builder %s\r\n" - "Content-Length: 0\r\n" - "\r\n"; - - nta_leg_bind(ag->ag_server_leg, new_leg_callback_180, ag); - - snprintf(m1, sizeof m1, - template2, - "INVITE", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, m1, - /* CSeq */ 15, "INVITE", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.6.1", - /* To tag */ ""); - l1 = strlen(m1); - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); - recv_udp(ag, r1, sizeof r1); - - l1 = strlen("SIP/2.0 180 "); - TEST_1(memcmp(r1, "SIP/2.0 180 ", l1) == 0); - - TEST_1(ag->ag_irq); - nta_incoming_bind(ag->ag_irq, wait_for_ack_or_cancel, ag); - - snprintf(m2, sizeof m2, - template2, - "CANCEL", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, m1, - /* CSeq */ 15, "CANCEL", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.6.1", - /* To tag */ ""); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - recv_udp(ag, r1, sizeof r1); - recv_udp(ag, r2, sizeof r2); - - l1 = strlen("SIP/2.0 200 "); - TEST_1(strstr(r1, "15 CANCEL")); - TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); - - TEST_1(strstr(r2, "15 INVITE")); - TEST_1(memcmp(r2, "SIP/2.0 487 ", l1) == 0); - - TEST_1(nta_incoming_status(ag->ag_irq) == 487); - - snprintf(m2, sizeof m2, - template2, - "ACK", URL_PRINT_ARGS(u1), - /* Via */ ag->ag_sink_port, m1, - /* CSeq */ 15, "ACK", - /* Call-ID */ (void *)(ag + 2), - /* From tag */ "2.6.1", - /* To tag */ ""); - l2 = strlen(m2); - - TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); - - nta_leg_destroy(ag->ag_bob_leg); ag->ag_bob_leg = NULL; - } - - while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0) - ; - - END(); -} - -static -int wait_for_ack_or_cancel(agent_t *ag, - nta_incoming_t *irq, - sip_t const *sip) -{ - sip_method_t method; - - method = sip ? sip->sip_request->rq_method : sip_method_unknown; - - if (method == sip_method_cancel) { - nta_incoming_treply(ag->ag_irq, SIP_487_REQUEST_CANCELLED, TAG_END()); - } - else if (method == sip_method_ack) { - nta_incoming_destroy(irq); - ag->ag_irq = NULL; - ag->ag_running = 0; - } - else { /* Timeout */ - nta_incoming_destroy(irq); - ag->ag_irq = NULL; - ag->ag_running = 0; - } - - return 0; -} - - -/* ---------------------------------------------------------------------- */ -/* 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_running = 0; - - 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(); -} - -static -int invite_client_deinit(client_t *c) -{ - agent_t *ag = c->c_ag; - invite_client_t *ic = (invite_client_t *)c; - - if (ic->ic_orq) nta_outgoing_destroy(ic->ic_orq), ic->ic_orq = NULL; - if (ic->ic_tag) su_free(ag->ag_home, ic->ic_tag), ic->ic_tag = NULL; - - return 0; -} - -static -int check_prack_sending(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = ctx->c_status; - - if (100 < status && status < 200) { - if (sip->sip_require && sip_has_feature(sip->sip_require, "100rel")) { - nta_outgoing_t *prack = NULL; - - TEST_1(sip->sip_rseq); - - prack = nta_outgoing_prack(ag->ag_call_leg, orq, NULL, NULL, - NULL, - sip, - TAG_END()); - nta_outgoing_destroy(prack); - TEST_1(prack != NULL); - } - } - return 0; -} - - -static -int check_leg_tagging(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = ctx->c_status; - - if (200 <= status && status < 300) { - 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); - } - - return 0; -} - - -static -int check_tu_ack(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = ctx->c_status; - - if (200 <= status && status < 300) { - nta_outgoing_t *ack; - ack = nta_outgoing_tcreate(ag->ag_call_leg, NULL, NULL, - NULL, - SIP_METHOD_ACK, - NULL, - SIPTAG_CSEQ(sip->sip_cseq), - TAG_END()); - nta_outgoing_destroy(ack); - TEST_1(ack); - } - - return 0; -} - - -static -int check_final_error(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = ctx->c_status; - - if (status >= 300) - ag->ag_call_leg = NULL; - - return 0; -} - - -/** Cancel call after receiving 1XX response */ -static -int cancel_invite(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip) -{ - int status = ctx->c_status; - - if (100 < status && status < 200) { - nta_outgoing_cancel(orq); - ctx->c_status = 0; - } - else if (status >= 200) { - TEST_1(status == 487 || status == 504); - } - - return 0; -} - -static client_check_f * const checks_for_invite[] = { - client_check_to_tag, - check_leg_tagging, - check_tu_ack, - check_final_error, - NULL, -}; - -static client_check_f * const checks_for_reinvite[] = { - client_check_to_tag, - check_prack_sending, - check_leg_tagging, - check_tu_ack, - NULL, -}; - -int test_call(agent_t *ag) -{ - sip_content_type_t *ct = ag->ag_content_type; - sip_payload_t *sdp = ag->ag_payload; - nta_leg_t *old_leg; - sip_replaces_t *r1, *r2; - - BEGIN(); - - { - invite_client_t ic[1] = - {{{{ ag, "Call 1", NULL, checks_for_invite, invite_client_deinit }}}}; - client_t *ctx = ic->ic_client; - - /* - * Test establishing a call - * - * Alice sends a INVITE to Bob, then Bob sends 200 Ok. - */ - 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(ag->ag_alice_leg); - - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_ACCEPT_CONTACT_STR("*;audio"), - SIPTAG_PAYLOAD(sdp), - NTATAG_USE_TIMESTAMP(1), - NTATAG_PASS_100(1), - TAG_END()); - TEST_1(ctx->c_orq); - /* Try to CANCEL it immediately */ - TEST_1(nta_outgoing_cancel(ctx->c_orq) == 0); - /* As Bob immediately answers INVITE with 200 Ok, - cancel should be answered with 481 and 200 Ok is returned to INVITE. */ - TEST_1(!client_run(ctx, 200)); - - 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)); - - { - invite_client_t ic[1] = - {{{{ - ag, "Re-INVITE in Call 1", - NULL, checks_for_reinvite, invite_client_deinit - }}}}; - client_t *ctx = ic->ic_client; - - /* 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_bob_leg, - outgoing_callback, ctx, - NULL, - SIP_METHOD_INVITE, - NULL, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_bob), - SIPTAG_SUPPORTED_STR("foo"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - TEST_P(ag->ag_latest_leg, ag->ag_alice_leg); - } - - { - client_t ctx[1] = {{ ag, "Hangup" }}; - - 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_BYE, - NULL, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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_acked = 1; - } - else if (method == sip_method_cancel) { - nta_incoming_treply(irq, SIP_487_REQUEST_CANCELLED, TAG_END()); - ag->ag_canceled = 1; - } - 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; - } - - 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(); -} - -/** Fork the original INVITE. */ -static -int check_orq_tagging(client_t *ctx, - nta_outgoing_t *orq, - sip_t const *sip) -{ - agent_t *ag = ctx->c_ag; - int status = ctx->c_status; - invite_client_t *ic = (invite_client_t *)ctx; - - if (100 < status && status < 200) { - TEST_1(sip->sip_rseq); - TEST_1(sip->sip_to->a_tag); - - TEST_1(orq == ctx->c_orq); - - TEST_1(ic); TEST_1(ic->ic_orq == NULL); - TEST_1(ic->ic_tag == NULL); - - ic->ic_orq = orq; - ic->ic_tag = su_strdup(ag->ag_home, sip->sip_to->a_tag); TEST_1(ic->ic_tag); - ic->ic_tag_status = status; - - TEST_S(nta_leg_rtag(ag->ag_call_leg, ic->ic_tag), ic->ic_tag); - - TEST(nta_leg_client_route(ag->ag_call_leg, - sip->sip_record_route, - sip->sip_contact), 0); - - orq = nta_outgoing_tagged(orq, - outgoing_callback, - ctx, - ic->ic_tag, - sip->sip_rseq); - TEST_1(orq); - if (ic->ic_orq != ctx->c_orq) - nta_outgoing_destroy(ctx->c_orq); - ctx->c_orq = orq; - - TEST_1(ctx->c_checks && ctx->c_checks[0] == check_orq_tagging); - - ctx->c_checks++; - } - - return 0; -} - -static client_check_f * const checks_for_100rel[] = { - check_orq_tagging, - client_check_to_tag, - check_prack_sending, - check_leg_tagging, - check_tu_ack, - NULL, -}; - - - -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 (irq) { - return 200; - } - else if (ag->ag_irq) { - nta_incoming_treply(ag->ag_irq, - 504, "Reliable Response Timeout", - TAG_END()); - nta_incoming_destroy(ag->ag_irq); - return 487; - } - - return 487; -} - -/* respond with 183 when receiving invite */ -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(); -} - - -/* - * 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) -{ - BEGIN(); - - sip_content_type_t *ct = ag->ag_content_type; - sip_payload_t *sdp = ag->ag_payload; - nta_leg_t *old_leg; - - { - /* Send a PRACK from default leg, NTA responds to it with error */ - url_t url[1]; - client_t ctx[1] = {{ ag, "Test 1.1" }}; - - *url = *ag->ag_aliases->m_url; - url->url_user = "bob"; - - ag->ag_expect_leg = ag->ag_server_leg; - ag->ag_latest_leg = NULL; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_default_leg, outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_PRACK, - (url_string_t *)url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_RACK_STR("1432432 42332432 INVITE"), - TAG_END()); - TEST_1(!client_run(ctx, 481)); - TEST_P(ag->ag_latest_leg, NULL); - } - - 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(ag->ag_alice_leg); - - TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); - - /* Send INVITE */ - { - invite_client_t ic[1] = - {{{{ ag, "Call 2", NULL, checks_for_100rel, invite_client_deinit }}}}; - client_t *ctx = ic->ic_client; - - nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag); - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - - TEST_1(!client_run_until_acked(ctx, 200)); - - /*TEST(ic->ic_tag_status, 183); */ - - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - TEST_1(ag->ag_bob_leg != NULL); - } - - { - client_t ctx[1] = {{ ag, "Hangup" }}; - - /* Send BYE from Bob to Alice */ - old_leg = ag->ag_expect_leg = ag->ag_alice_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_BYE, - NULL, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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 receiving 100rel response */ - 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(ag->ag_alice_leg); - - TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); - - { - invite_client_t ic[1] = - {{{{ - ag, "Call 2b", - cancel_invite, checks_for_invite, invite_client_deinit - }}}}; - client_t *ctx = ic->ic_client; - - /* Send INVITE */ - nta_leg_bind(ag->ag_server_leg, bob_leg_callback3, ag); - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(!client_run(ctx, 0)); - } - - 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 (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); - - 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(ag->ag_alice_leg); - - TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); - - { - invite_client_t ic[1] = - {{{{ ag, "Call 3", NULL, checks_for_invite, invite_client_deinit }}}}; - client_t *ctx = ic->ic_client; - - /* 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; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ctx, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(ctx->c_orq); - - nta_test_run(ag); - TEST(ctx->c_status, 503); - TEST_P(ctx->c_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); - } - - if (EXPENSIVE_CHECKS || 1) { - /* - * client sends INVITE, - * server sends provisional response, - * client PRACKs it, - * client timeouts after timer C - */ - - invite_client_t ic[1] = - {{{{ ag, "Call 4", NULL, checks_for_100rel, invite_client_deinit }}}}; - client_t *ctx = ic->ic_client; - - printf("%s: starting timer C, test will complete in 1 seconds\n", - name); - - TEST(nta_agent_set_params(ag->ag_agent, - NTATAG_TIMER_C(1000), - TAG_END()), 1); - - 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_callback3, ag); - ag->ag_expect_leg = ag->ag_server_leg; - TEST_1(ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ic->ic_client, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END())); - - /* Run until 1) server gets CANCEL and 2) client gets 487 */ - /* Note: this has been changed in 1.12.11 */ - TEST_1(!client_run_until_canceled(ctx, 487)); - - TEST_1(ag->ag_canceled != 0); - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - TEST_1(ag->ag_bob_leg); - nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; - - TEST(nta_agent_set_params(ag->ag_agent, - NTATAG_TIMER_C(185 * 1000), - TAG_END()), 1); - - nta_leg_destroy(ag->ag_bob_leg), ag->ag_bob_leg = NULL; - ag->ag_latest_leg = NULL; - ag->ag_call_leg = NULL; - } - - END(); -} - -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 *ct = ag->ag_content_type; - sip_payload_t *sdp = ag->ag_payload; - nta_leg_t *old_leg; - - BEGIN(); - - 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(ag->ag_alice_leg); - - TEST_1(nta_leg_tag(ag->ag_alice_leg, NULL)); - ag->ag_bob_leg = NULL; - - { - invite_client_t ic[1] = - {{{{ ag, "Call 5", NULL, checks_for_100rel, invite_client_deinit }}}}; - client_t *ctx = ic->ic_client; - - /* Send INVITE */ - nta_leg_bind(ag->ag_server_leg, bob_leg_callback2, ag); - ag->ag_expect_leg = ag->ag_server_leg; - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_call_leg = ag->ag_alice_leg, - outgoing_callback, ic->ic_client, - ag->ag_obp, - SIP_METHOD_INVITE, - (url_string_t *)ag->ag_m_bob->m_url, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - - TEST_1(!client_run(ctx, 200)); - - /*TEST(ag->ag_tag_status, 183);*/ - TEST_P(ag->ag_latest_leg, ag->ag_server_leg); - TEST_1(ag->ag_bob_leg != NULL); - } - - old_leg = ag->ag_expect_leg = ag->ag_alice_leg; - - { - client_t ctx[1] = {{ ag, "Hangup" }}; - - /* Send BYE from Bob to Alice */ - ctx->c_orq = - nta_outgoing_tcreate(ag->ag_bob_leg, outgoing_callback, ctx, - NULL, - SIP_METHOD_BYE, - NULL, - SIPTAG_SUBJECT_STR(ctx->c_name), - SIPTAG_FROM(ag->ag_alice), - SIPTAG_TO(ag->ag_bob), - SIPTAG_CONTACT(ag->ag_m_alice), - SIPTAG_CONTENT_TYPE(ct), - SIPTAG_PAYLOAD(sdp), - TAG_END()); - TEST_1(!client_run(ctx, 200)); - 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 -#include - -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" - " -a | --abort abort() on error\n" - " -q | --quiet be quiet\n" - " --expensive run expensive tests, too\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(int exitcode) -{ - fprintf(stderr, nta_test_usage, name); - exit(exitcode); -} - -#if HAVE_OPEN_C -int posix_main(int argc, char *argv[]); - -int main(int argc, char *argv[]) -{ - int retval; - - tstflags |= tst_verbatim; - - su_log_set_level(su_log_default, 9); - su_log_set_level(nta_log, 9); - su_log_set_level(tport_log, 9); - - retval = posix_main(argc, argv); - - sleep(7); - - return retval; -} - -#define main posix_main -#endif - -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 }}; - - expensive_checks = getenv("EXPENSIVE_CHECKS") != 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], "-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; - else if (strcmp(argv[i], "--expensive") == 0) - expensive_checks = 1; - 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(1); - - 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(1); - } - 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(1); - } - 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(1); - } - - if (o_attach) { - char line[10], *got; - printf("nua_test: pid %u\n", getpid()); - printf("\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_merging(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(); - } - - s2_fast_forward(64000, ag->ag_root); - - retval |= test_deinit(ag); fflush(stdout); - - su_home_deinit(ag->ag_home); - - su_deinit(); - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c b/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c deleted file mode 100644 index 818ffb6e94..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta_api.c +++ /dev/null @@ -1,1521 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 - -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -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 - -#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 ;methods=;events= */ - - 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(); -} - -static int api_test_destroy(agent_t *ag) -{ - nta_agent_t *nta; - su_root_t *root; - su_home_t home[1]; - nta_outgoing_t *orq; - nta_leg_t *leg; - int i; - - BEGIN(); - - memset(home, 0, sizeof home); - home->suh_size = sizeof home; - su_home_init(home); - - TEST_1(root = su_root_create(NULL)); - - for (i = 0; i < 2; i++) { - TEST_1(nta = nta_agent_create(root, - (url_string_t *)"sip:*:*", - NULL, - NULL, - TAG_END())); - TEST_1(leg = nta_leg_tcreate(nta, NULL, NULL, - NTATAG_NO_DIALOG(1), - TAG_END())); - /* This creates a delayed response message */ - orq = nta_outgoing_tcreate(leg, outgoing_callback, ag, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:foo.bar;transport=none"), - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - TAG_END()); - TEST_1(orq); - - TEST_VOID(nta_outgoing_destroy(orq)); - TEST_VOID(nta_leg_destroy(leg)); - TEST_VOID(nta_agent_destroy(nta)); - } - - TEST_VOID(su_root_destroy(root)); - TEST_VOID(su_home_deinit(home)); - - 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; - sip_contact_t const *contact = (void *)-1; - url_string_t const *default_proxy = (void *)-1; - void *smime = (void *)-1; - - unsigned blacklist = -1; - unsigned debug_drop_prob = -1; - unsigned max_forwards = -1; - usize_t maxsize = -1; - unsigned preload = -1; - unsigned progress = -1; - unsigned sip_t1 = -1; - unsigned sip_t2 = -1; - unsigned sip_t4 = -1; - unsigned timer_c = -1; - unsigned udp_mtu = -1; - - int cancel_2543 = -1; - int cancel_487 = -1; - int client_rport = -1; - int extra_100 = -1; - int merge_482 = -1; - int pass_100 = -1; - int pass_408 = -1; - int rel100 = -1; - int server_rport = -1; - int stateless = -1; - int tag_3261 = -1; - int timeout_408 = -1; - int ua = -1; - int use_naptr = -1; - int use_srv = -1; - int use_timestamp = -1; - int user_via = -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_ALIASES_REF(aliases), - NTATAG_BLACKLIST_REF(blacklist), - NTATAG_CANCEL_2543_REF(cancel_2543), - NTATAG_CANCEL_487_REF(cancel_487), - NTATAG_CLIENT_RPORT_REF(client_rport), - NTATAG_CONTACT_REF(contact), - NTATAG_DEBUG_DROP_PROB_REF(debug_drop_prob), - NTATAG_DEFAULT_PROXY_REF(default_proxy), - NTATAG_EXTRA_100_REF(extra_100), - NTATAG_MAXSIZE_REF(maxsize), - NTATAG_MAX_FORWARDS_REF(max_forwards), - NTATAG_MCLASS_REF(mclass), - NTATAG_MERGE_482_REF(merge_482), - NTATAG_PASS_100_REF(pass_100), - NTATAG_PASS_408_REF(pass_408), - NTATAG_PRELOAD_REF(preload), - NTATAG_PROGRESS_REF(progress), - NTATAG_REL100_REF(rel100), - NTATAG_SERVER_RPORT_REF(server_rport), - NTATAG_SIP_T1_REF(sip_t1), - NTATAG_SIP_T2_REF(sip_t2), - NTATAG_SIP_T4_REF(sip_t4), - NTATAG_SMIME_REF(smime), - NTATAG_STATELESS_REF(stateless), - NTATAG_TAG_3261_REF(tag_3261), - NTATAG_TIMEOUT_408_REF(timeout_408), - NTATAG_TIMER_C_REF(timer_c), - NTATAG_UA_REF(ua), - NTATAG_UDP_MTU_REF(udp_mtu), - NTATAG_USER_VIA_REF(user_via), - NTATAG_USE_NAPTR_REF(use_naptr), - NTATAG_USE_SRV_REF(use_srv), - NTATAG_USE_TIMESTAMP_REF(use_timestamp), - TAG_END()), - /* Number of parameters */ 33); - - TEST_P(mclass, sip_default_mclass()); - TEST_P(aliases, NULL); - TEST_1(contact != (void *)-1 && contact != NULL); - TEST_1(default_proxy == NULL); - TEST_1(smime == NULL); - - TEST_1(blacklist != (unsigned)-1); - TEST(debug_drop_prob, 0); - TEST_1(max_forwards >= 20); - TEST_1(maxsize >= 65536); - TEST_1(preload != (unsigned)-1); - TEST_1(progress <= 60 * 1000); - TEST(sip_t1, NTA_SIP_T1); - TEST(sip_t2, NTA_SIP_T2); - TEST(sip_t4, NTA_SIP_T4); - TEST_1(timer_c > 180 * 1000); - TEST(udp_mtu, 1300); - - TEST_1(cancel_2543 != -1); - TEST_1(cancel_487 != -1); - TEST_1(client_rport != -1); - TEST_1(extra_100 != -1); - TEST_1(merge_482 != -1); - TEST_1(pass_100 != -1); - TEST_1(pass_408 != -1); - TEST_1(rel100 != -1); - TEST_1(server_rport != -1); - TEST_1(stateless == 0); - TEST_1(timeout_408 != -1); - TEST_1(ua == 0); - TEST_1(use_naptr != -1); - TEST_1(use_srv != -1); - TEST_1(use_timestamp != -1); - TEST_1(user_via == 0); - - 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; - - usize_t irq_hash = -1, orq_hash = -1, leg_hash = -1; - usize_t recv_msg = -1, sent_msg = -1; - usize_t recv_request = -1, recv_response = -1; - usize_t bad_message = -1, bad_request = -1, bad_response = -1; - usize_t drop_request = -1, drop_response = -1; - usize_t client_tr = -1, server_tr = -1, dialog_tr = -1; - usize_t acked_tr = -1, canceled_tr = -1; - usize_t trless_request = -1, trless_to_tr = -1, trless_response = -1; - usize_t trless_200 = -1, merged_request = -1; - usize_t sent_request = -1, sent_response = -1; - usize_t retry_request = -1, retry_response = -1, recv_retry = -1; - usize_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(!su_casematch(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(!su_casematch(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(!su_casematch(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(!su_casematch(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(!su_casematch(v->v_protocol, sip_transport_tcp), 0); - TEST_1(v = v->v_next); - TEST(!su_casematch(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(!su_casematch(v->v_protocol, sip_transport_udp), 0); - TEST_1(v = v->v_next); - TEST(!su_casematch(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(); -} - - -/* Test that NULL host and/or port fields of user supplied Via header are - filled in automatically */ -int api_test_user_via_fillin(agent_t *ag) -{ - su_home_t home[1]; - su_root_t *root; - nta_agent_t *nta; - nta_leg_t *leg; - nta_outgoing_t *orq0, *orq1; - msg_t *msg0, *msg1; - sip_t *sip0, *sip1; - sip_via_t *via0, *via1; - sip_via_t via[1]; - static char *via_params[] = { "param1=value1", "param2=value2" }; - size_t i; - - BEGIN(); - - memset(home, 0, 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(leg = nta_leg_tcreate(nta, NULL, NULL, - NTATAG_NO_DIALOG(1), - TAG_END())); - - /* This creates a delayed response message */ - orq0 = nta_outgoing_tcreate(leg, outgoing_callback, ag, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:foo.bar;transport=none"), - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - TAG_END()); - TEST_1(orq0); - TEST_1(msg0 = nta_outgoing_getrequest(orq0)); - TEST_1(sip0 = sip_object(msg0)); - TEST_1(via0 = sip0->sip_via); - - /* create user Via template to be filled in by NTA */ - sip_via_init(via); - via->v_protocol = "*"; - for (i = 0; i < sizeof(via_params) / sizeof(via_params[0]); i++) - sip_via_add_param(home, via, via_params[i]); /* add param to the template */ - - /* This creates a delayed response message */ - orq1 = nta_outgoing_tcreate(leg, outgoing_callback, ag, NULL, - SIP_METHOD_MESSAGE, - URL_STRING_MAKE("sip:foo.bar;transport=none"), - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - NTATAG_USER_VIA(1), - SIPTAG_VIA(via), - TAG_END()); - TEST_1(orq1); - TEST_1(msg1 = nta_outgoing_getrequest(orq1)); - TEST_1(sip1 = sip_object(msg1)); - TEST_1(via1 = sip1->sip_via); - - /* check that template has been filled correctly */ - TEST_S(via0->v_protocol, via1->v_protocol); - TEST_S(via0->v_host, via1->v_host); - TEST_S(via0->v_port, via1->v_port); - /* check that the parameter has been preserved */ - for (i = 0; i < sizeof(via_params)/sizeof(via_params[0]); i++) - TEST_S(via1->v_params[i], via_params[i]); - - TEST_VOID(nta_outgoing_destroy(orq0)); - TEST_VOID(nta_outgoing_destroy(orq1)); - TEST_VOID(nta_leg_destroy(leg)); - TEST_VOID(nta_agent_destroy(nta)); - - TEST_VOID(su_root_destroy(root)); - TEST_VOID(su_home_deinit(home)); - - 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]; - su_nanotime_t nano; - - 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_received(irq, &nano), nano / 1000000000); - - 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 ;tag=aiojcidscd0i"), - SIPTAG_TO_STR("Jaska ;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]; - su_nanotime_t nano; - - 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_received(NULL, &nano), 0); - TEST64(nano, 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)); - - TEST_P(nta_reliable_treply(NULL, NULL, NULL, 0, NULL, TAG_END()), NULL); - TEST_P(nta_reliable_mreply(NULL, NULL, NULL, NULL), NULL); - TEST_VOID(nta_reliable_destroy(NULL)); - - 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@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(";tag=foo"), - /* remote */ - SIPTAG_TO_STR(""), - TAG_END())); - - TEST_1(a1 = sip_from_make(home, ";tag=foo")); - TEST_1(a2 = sip_from_make(home, ";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); -#if nomore - /* 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); -#endif - 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 */ /* XXX - not really */ - 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 -#include - -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" - " -a | --abort abort() on error\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(int exitcode) -{ - fprintf(stderr, nta_test_api_usage, name); - exit(exitcode); -} - -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], "-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; - 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(1); - - 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(1); - } - - if (o_attach) { - char *response, line[10]; - printf("nua_test: pid %lu\n", (unsigned long)getpid()); - printf("\n"); - response = 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_destroy(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_user_via_fillin(ag); SINGLE_FAILURE_CHECK(); - } - retval |= api_test_deinit(ag); fflush(stdout); - - su_home_deinit(ag->ag_home); - - su_deinit(); - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog deleted file mode 100644 index f4f3b3390e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/ChangeLog +++ /dev/null @@ -1,7 +0,0 @@ -2005-08-10 Pekka Pessi - - * Added agent.pem and cafile.pem. - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile.in deleted file mode 100644 index 5c84f05e0e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/Doxyfile.in +++ /dev/null @@ -1,19 +0,0 @@ -PROJECT_NAME = "nth" -OUTPUT_DIRECTORY = ../docs/html/nth - -INPUT = @srcdir@/nth.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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 += diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am deleted file mode 100644 index 0ac4b9f39c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/Makefile.am +++ /dev/null @@ -1,66 +0,0 @@ -# -# Makefile.am for nth module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 = nth.docs $(BUILT_SOURCES) \ - agent.pem cafile.pem - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem b/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem deleted file mode 100644 index 1e92b556be..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/agent.pem +++ /dev/null @@ -1,35 +0,0 @@ ------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----- diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem b/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem deleted file mode 100644 index 083de3746a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/cafile.pem +++ /dev/null @@ -1,19 +0,0 @@ ------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----- diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c b/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c deleted file mode 100644 index 39add225fa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/http-client.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 - * - * http-client [OPTIONS] url - * - * @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: - *
- *
--method=name
- *
Specify the request method name (GET by default). - *
- *
--proxy=url
- *
Specifies the proxy via which the request will be sent. - *
- *
--ua=value
- *
Specifies the User-Agent header field. - *
- *
--mf=n
- *
Specify the initial Max-Forwards count. - *
- *
--pipe
- *
Use pipelining (do not shutdown client connection after request). - *
- *
--extra
- *
Insert standard input to the requests. - *
- *
- * - * @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 - * - *
- */ - -#include -#include -#include -#include -#include - -typedef struct context_s context_t; -#define NTH_CLIENT_MAGIC_T context_t - -#include -#include -#include -#include -#include - -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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c b/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c deleted file mode 100644 index db359db234..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/http-server.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Sat Oct 19 02:56:23 2002 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#if HAVE_SIGNAL -#include -#endif - -typedef struct context_s context_t; -#define NTH_SITE_MAGIC_T context_t -#define SU_ROOT_MAGIC_T context_t - -#include -#include -#include - -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; - -#if HAVE_SIGNAL -static RETSIGTYPE server_intr_handler(int signum); -#endif -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); - -#if HAVE_SIGNAL - signal(SIGINT, server_intr_handler); -#if HAVE_SIGQUIT - signal(SIGQUIT, server_intr_handler); - signal(SIGHUP, server_intr_handler); -#endif -#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 = ""; - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs b/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs deleted file mode 100644 index 9a51506596..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/nth.docs +++ /dev/null @@ -1,21 +0,0 @@ -/* -*- 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 , tags controlling the options in - * . - * - * @CONTACT Pekka Pessi - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - * - * @author Pekka Pessi . - * - */ - diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c b/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c deleted file mode 100644 index 8b8d856ae3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/nth_client.c +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include - -/** @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 -#include -#include - -#include - -#include -#include - -#include - -/* 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 -#endif -#include - -#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 included directly. -#endif -#include - -/**@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 , 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) - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -HTABLE_BODIES_WITH(hc_htable, hct, nth_client_t, HTABLE_HASH_CLIENT, - uintptr_t, size_t); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -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 char const *const he_no_tls_tports[] = { "tcp", 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; - - if (tport_tbind(he->he_tports, he_name, he_tports, - TPTAG_SERVER(0), TAG_NEXT(tags)) >= 0) - return 0; - - return tport_tbind(he->he_tports, he_name, he_no_tls_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((enum url_type_e)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((enum url_type_e)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) || - su_strcmp(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 && !su_casematch(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" VA_NONE)); - 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, - su_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", (void *)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, (enum msg_streaming_status)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, (enum msg_streaming_status)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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c b/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c deleted file mode 100644 index 5fcb15a5c6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/nth_server.c +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file nth_server.c - * @brief HTTP server. - * - * @author Pekka Pessi - * - * @date Created: Sat Oct 19 01:37:36 2002 ppessi - */ - -#include "config.h" - -#include -#include - -typedef struct server_s server_t; - -/** @internal SU timer argument pointer type */ -#define SU_TIMER_ARG_T server_t - -#include -#include -#include - -#include "sofia-sip/nth.h" - -#include -#include -#include - -#include - -/* We are customer of tport_t */ -#define TP_STACK_T server_t -#define TP_MAGIC_T void - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#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 included directly. -#endif -#include - -/**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 , 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 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, (enum url_type_e)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, (enum url_type_e)parent->site_url->url_type); - url0->url_host = s; - address = (url_string_t*)url0; - } - else { - /* looks like a path */ - url_init(url0, (enum url_type_e)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" VA_NONE)); - errno = EINVAL; - goto error; - } - - if (!parent && !is_host) { - SU_DEBUG_3(("nth_site_create(): host is required\n" VA_NONE)); - errno = EINVAL; - goto error; - } - - if (parent) { - if (!parent->site_isdir) { - SU_DEBUG_3(("nth_site_create(): invalid parent resource \n" VA_NONE)); - 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; - - if (!path) { - SU_DEBUG_3(("nth_site_create(): invalid url\n" VA_NONE)); - errno = EINVAL; - goto error; - } - - 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 && - su_strcmp(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 char const * const http_no_tls_tports[] = { "tcp", 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 const *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((enum url_type_e)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 || - tport_tbind(srv->srv_tports, tpn, http_no_tls_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); -} - -/** 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, (enum msg_streaming_status)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 if (site) - site->site_access = now; - - if (site && 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((enum url_type_e)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), - "\n" - "%u %s\n" - "

%u %s

\n" - "\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" VA_NONE)); - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c b/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c deleted file mode 100644 index 745bf89f05..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/nth_tag.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jul 24 22:28:34 2001 ppessi - */ - -#include "config.h" - -#include -#include - -#define TAG_NAMESPACE "nth" - -#include "sofia-sip/nth_tag.h" -#include -#include -#include - -#include - -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); diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h b/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h deleted file mode 100644 index 63e105a4a2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 - * . */ -#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 - * . */ -#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 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 -#include -#include -#include - -#ifndef NTH_TAG_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h b/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h deleted file mode 100644 index 3f9a07d739..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NTH_TAG_H - -/**@file sofia-sip/nth_tag.h - * @brief Tags for @b nth, HTTP engine module. - * - * @author Pekka Pessi - * - * @date Created: Sun Oct 13 22:23:48 2002 ppessi - */ - -#ifndef SU_TAG_H -#include -#endif - -#ifndef URL_TAG_H -#include -#endif - -#ifndef HTTP_TAG_H -#include -#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_INLINE_TAG_CAST -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_INLINE_TAG_CAST -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c b/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c deleted file mode 100644 index 3b6859e415..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c +++ /dev/null @@ -1,963 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Oct 22 20:52:37 2002 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#if HAVE_ALARM -#include -#include -#endif - -typedef struct tester tester_t; -typedef struct site site_t; -typedef struct client client_t; - -#define SU_ROOT_MAGIC_T tester_t - -#include -#include - -#define NTH_CLIENT_MAGIC_T client_t -#define NTH_SITE_MAGIC_T site_t - -#include "sofia-sip/nth.h" -#include -#include -#include -#include - -int tstflags = 0; - -#define TSTFLAGS tstflags - -#include - -#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(su_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("Hello\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 - ("sub/sub\n"), - TAG_END())); - - TEST_1(site_create(t, m, "/sub/", - HTTP_200_OK, - HTTPTAG_CONTENT_TYPE_STR("text/html"), - HTTPTAG_PAYLOAD_STR("sub/\n"), - TAG_END())); - - TEST_1(site_create(t, m, "/sub/sub/", - HTTP_200_OK, - HTTPTAG_CONTENT_TYPE_STR("text/html"), - HTTPTAG_PAYLOAD_STR - ("sub/sub/\n"), - TAG_END())); - - TEST_1(sub2 = - site_create(t, m, "/sub2/", - HTTP_200_OK, - HTTPTAG_CONTENT_TYPE_STR("text/html"), - HTTPTAG_PAYLOAD_STR("sub2/\n"), - TAG_END())); - - TEST_1(site_create(t, sub2, "sub/", - HTTP_200_OK, - HTTPTAG_CONTENT_TYPE_STR("text/html"), - HTTPTAG_PAYLOAD_STR - ("sub2/sub/\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 - ("auth/\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 - ("auth/\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(su_setblocking(c, 1) != -1); - 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, "sub/")); - 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, "sub2/")); - 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, "sub2/")); - 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, "sub2/sub/")); - 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, "sub/sub")); - 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, ""); - } - - 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[] = - ""; - - 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(int exitcode) -{ - fprintf(stderr, "usage: %s [-v|-q] [-a] [-p proxy-uri]\n", name); - exit(exitcode); -} - -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], "-a") == 0) - tstflags |= tst_abort; - 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(1); - } - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog deleted file mode 100644 index 376f915580..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/ChangeLog +++ /dev/null @@ -1,480 +0,0 @@ -2005-11-15 Kai Vehmanen - - * Removed obsolete NUTAG_MEDIA* tags. - -2005-11-03 Pekka Pessi - - * Indicate the response status with the nua_i_. - - Now returning the status of the returned response in - nua_i_ 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 - - * 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 - - * 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 - - * 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 - - * 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 - - * Fixed logging options. Allow multithreaded, unsynchronised execution. - - M ./libsofia-sip-ua/nua/test_nua.c -115 +162 - -2005-10-12 Pekka Pessi - - * 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 - - * 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 - - * 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 - - * nua.h (nua_invite_respond): Removed, no implementation - available. - -2005-10-04 Pekka Pessi - - * Fixed soa_set_params() in respond_to_invite(). - - M ./libsofia-sip-ua/nua/nua_stack.c -1 +1 - -2005-10-03 Pekka Pessi - - * 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 - - * 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 - - * Including in . - - 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 - - * nua_stack.c: Fix delivering nua_i_active. - -2005-09-22 Kai Vehmanen - - * 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 - - * 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 - - * 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 - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile.in deleted file mode 100644 index 06eba441cb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/Doxyfile.in +++ /dev/null @@ -1,39 +0,0 @@ -PROJECT_NAME = "nua" -OUTPUT_DIRECTORY = ../docs/html/nua - -INPUT = @srcdir@/nua.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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  " - -ALIASES += \ - NUA_HPARAM_CALLS="nua_method(), nua_respond(), nua_invite(), nua_ack(), nua_cancel(), nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(), nua_message(), nua_register(), nua_unregister(), nua_publish(), nua_refer(), nua_subscribe(), nua_unsubscribe(), nua_notify(), nua_notifier()" - -VERBATIM_HEADERS = NO - -@INCLUDE = ../sip/sip.doxyaliases diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am deleted file mode 100644 index 6b6dfaa211..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/Makefile.am +++ /dev/null @@ -1,86 +0,0 @@ -# -# Makefile.am for nua module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -# ---------------------------------------------------------------------- -# Build targets - -noinst_LTLIBRARIES = libnua.la - -check_PROGRAMS = -TESTS = - -if HAVE_CHECK -check_PROGRAMS += check_nua -TESTS += check_nua -endif - -# ---------------------------------------------------------------------- -# 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_server.h nua_server.c \ - nua_client.h nua_client.c \ - nua_extension.c nua_types.h \ - 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) - -# ---------------------------------------------------------------------- - -check_nua_SOURCES = check_nua.c check_nua.h \ - check_session.c check_register.c \ - check_etsi.c check_simple.c - -check_nua_LDADD = $(nua_libs) ${top_builddir}/s2check/libs2.a \ - @CHECK_LIBS@ -lz - -nua_libs = 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 - -# ---------------------------------------------------------------------- -# Install and distribution rules - -EXTRA_DIST = nua.docs $(BUILT_SOURCES) - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - -AM_CPPFLAGS = ${INTERNAL_INCLUDES} -I$(top_srcdir)/s2check - -TAG_DLL_FLAGS = LIST=nua_tag_list diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c deleted file mode 100644 index 24c8b51570..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_etsi.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_etsi.c - * - * @brief ETSI test cases - * - * @author Pekka Pessi - * @author Paulo Pizarro - * - * @copyright (C) 2008 Nokia Corporation. - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nua.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* ====================================================================== */ - -/* define XXX as 1 in order to see all failing test cases */ -#ifndef XXX -#define XXX (0) -#endif - -/* ====================================================================== */ - -static nua_t *nua; -static soa_session_t *soa = NULL; -static struct dialog *d1 = NULL; -static struct dialog *d2 = NULL; - -#define CRLF "\r\n" - -static void etsi_setup(void) -{ - nua = s2_nua_setup("ETSI", - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - - soa = soa_create(NULL, s2base->root, NULL); - - fail_if(!soa); - - soa_set_params(soa, - SOATAG_USER_SDP_STR("m=audio 5008 RTP/AVP 8 0" CRLF - "m=video 5010 RTP/AVP 34" CRLF), - TAG_END()); - - d1 = su_home_new(sizeof *d1); fail_if(!d1); - d2 = su_home_new(sizeof *d2); fail_if(!d2); -} - -static void etsi_thread_setup(void) -{ - s2_nua_thread = 1; - etsi_setup(); -} - -static void etsi_threadless_setup(void) -{ - s2_nua_thread = 0; - etsi_setup(); -} - -static void etsi_teardown(void) -{ - s2_teardown_started("ETSI"); - - mark_point(); - - nua_shutdown(nua); - fail_unless_event(nua_r_shutdown, 200); - - s2_nua_teardown(); -} - -static void save_sdp_to_soa(struct message *message) -{ - sip_payload_t *pl; - char const *body; - isize_t bodylen; - - fail_if(!message); - - fail_if(!message->sip->sip_content_length); - fail_if(!message->sip->sip_content_type); - fail_if(strcmp(message->sip->sip_content_type->c_type, - "application/sdp")); - - fail_if(!message->sip->sip_payload); - pl = message->sip->sip_payload; - body = pl->pl_data, bodylen = pl->pl_len; - - fail_if(soa_set_remote_sdp(soa, NULL, body, (issize_t)bodylen) < 0); -} - -static void process_offer(struct message *message) -{ - save_sdp_to_soa(message); - fail_if(soa_generate_answer(soa, NULL) < 0); -} - -static void -respond_with_sdp(struct message *request, - struct dialog *dialog, - int status, char const *phrase, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - char const *body; - isize_t bodylen; - - fail_if(soa_get_local_sdp(soa, NULL, &body, &bodylen) != 1); - - ta_start(ta, tag, value); - s2_sip_respond_to(request, dialog, status, phrase, - SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR(body), - SIPTAG_CONTENT_DISPOSITION_STR("session"), - ta_tags(ta)); - ta_end(ta); -} - -static struct message * -invite_sent_by_nua(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - ta_start(ta, tag, value); - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - ta_tags(ta)); - ta_end(ta); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - return s2_sip_wait_for_request(SIP_METHOD_INVITE); -} - -static void -bye_by_nua(struct dialog *dialog, nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct message *bye; - - ta_start(ta, tag, value); - nua_bye(nh, ta_tags(ta)); - ta_end(ta); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); -} - -/* ====================================================================== */ -/* 6 - ETSI cases */ - -/* 6.1 Call Control - Originating Endpoint - Call Establishment */ - -START_TEST(SIP_CC_OE_CE_V_019) -{ - nua_handle_t *nh; - struct message *invite; - struct message *bye; - - S2_CASE("6.1.1", "SIP_CC_OE_CE_V_019", - "Ensure that the IUT when an INVITE client transaction " - "is in the Calling state, on receipt of Success (200 OK) " - "responses differing only on the tag in the To header, " - "sends an ACK request with a To header identical to the " - "received one for each received Success (200 OK) responses."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - - process_offer(invite); - - respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); - - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - respond_with_sdp(invite, d2, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, d2, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - bye_by_nua(d1, nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(SIP_CC_OE_CE_TI_008) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("6.1.2", "SIP_CC_OE_CE_TI_008", - "If an unreliable transport is used, ensure that " - "the IUT, when an INVITE client transaction is in " - "the Completed state, on receipt of final responses " - "that matches the transaction, still answer with an " - "ACK request until timer D set to at least 32 second expires."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - - s2_sip_respond_to(invite, d1, 404, "First not found", TAG_END()); - fail_unless_event(nua_r_invite, 404); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(5, s2base->root); - - s2_sip_respond_to(invite, d1, 404, "Not found after 5 seconds", TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(5, s2base->root); - - s2_sip_respond_to(invite, d1, 404, "Not found after 10 seconds", TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(21, s2base->root); - - s2_sip_respond_to(invite, d1, 404, "Not found after 31 seconds", TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(5, s2base->root); - - /* Wake up nua thread and let it time out INVITE transaction */ - nua_set_params(s2->nua, TAG_END()); - fail_unless_event(nua_r_set_params, 0); - - s2_sip_respond_to(invite, d1, 404, "Not found after 32 seconds", TAG_END()); - s2_sip_free_message(invite); - fail_if(s2_sip_check_request_timeout(SIP_METHOD_ACK, 3)); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(SIP_CC_OE_CE_TI_011_012) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("6.1.2", "SIP_CC_OE_CE_TI_011_012", - "Ensure that the IUT, when an INVITE client transaction " - "has been in the Terminated state, on receipt of a " - "retransmitted Success (200 OK) responses sends an ACK " - "request until 64*T1 duration expires, after this, " - "on receipt of a retransmitted Success (200 OK) " - "responses does not send an ACK request."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - - process_offer(invite); - - respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); - - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(5, s2base->root); - respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(5, s2base->root); - respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - s2_nua_fast_forward(20, s2base->root); - respond_with_sdp(invite, d1, SIP_200_OK, TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - /* Stack times out the INVITE transaction */ - s2_nua_fast_forward(5, s2base->root); - - respond_with_sdp(invite, d1, SIP_200_OK, - SIPTAG_SUBJECT_STR("Stray 200 OK"), - TAG_END()); - s2_sip_free_message(invite); - mark_point(); - fail_if(s2_sip_check_request_timeout(SIP_METHOD_ACK, 3)); - - bye_by_nua(d1, nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *sip_cc_oe_ce_tcase(int threading) -{ - TCase *tc = tcase_create("6.1 - ETSI CC OE - Call Establishment"); - - void (*setup)(void) = threading ? etsi_thread_setup : etsi_threadless_setup; - - tcase_add_checked_fixture(tc, setup, etsi_teardown); - { - tcase_add_test(tc, SIP_CC_OE_CE_V_019); - tcase_add_test(tc, SIP_CC_OE_CE_TI_008); - tcase_add_test(tc, SIP_CC_OE_CE_TI_011_012); - } - return tc; -} - -/* ====================================================================== */ - -void check_etsi_cases(Suite *suite, int threading) -{ - suite_add_tcase(suite, sip_cc_oe_ce_tcase(threading)); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.c deleted file mode 100644 index 60a6ee6c4b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_nua.c - * - * @brief Check-driven tester for Sofia SIP User Agent library - * - * @author Pekka Pessi - * - * @copyright (C) 2007 Nokia Corporation. - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nua.h" -#include "s2dns.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static void usage(int exitcode) -{ - fprintf(exitcode ? stderr : stdout, - "usage: %s [--xml=logfile] case,...\n", s2_tester); - exit(exitcode); -} - -int main(int argc, char *argv[]) -{ - int i, failed = 0, selected = 0; - int threading, single_thread, multi_thread; - char const *xml = NULL; - Suite *suite = suite_create("Unit tests for Sofia-SIP UA Engine"); - SRunner *runner; - - s2_tester = "check_nua"; - - s2_suite("N2"); - - if (getenv("CHECK_NUA_VERBOSE")) - s2_start_stop = strtoul(getenv("CHECK_NUA_VERBOSE"), NULL, 10); - - for (i = 1; argv[i]; i++) { - if (su_strnmatch(argv[i], "--xml=", strlen("--xml="))) { - xml = argv[i] + strlen("--xml="); - } - else if (su_strmatch(argv[i], "--xml")) { - if (!(xml = argv[++i])) - usage(2); - } - else if (su_strmatch(argv[i], "-v")) { - s2_start_stop = 1; - } - else if (su_strmatch(argv[i], "-?") || - su_strmatch(argv[i], "-h") || - su_strmatch(argv[i], "--help")) - usage(0); - else { - s2_select_tests(argv[i]); - selected = 1; - } - } - - if (!selected) - s2_select_tests(getenv("CHECK_NUA_CASES")); - - if (getenv("CHECK_NUA_THREADING")) { - single_thread = strcmp(getenv("CHECK_NUA_THREADING"), "no"); - multi_thread = !single_thread; - } - else { - single_thread = multi_thread = 1; - } - - if (single_thread) { - check_register_cases(suite, threading = 0); - check_simple_cases(suite, threading = 0); - check_session_cases(suite, threading = 0); - check_etsi_cases(suite, threading = 0); - } - - if (multi_thread) { - check_register_cases(suite, threading = 1); - check_session_cases(suite, threading = 1); - check_etsi_cases(suite, threading = 1); - check_simple_cases(suite, threading = 1); - } - - runner = srunner_create(suite); - - if (xml) - srunner_set_xml(runner, argv[1]); - - srunner_run_all(runner, CK_ENV); - failed = srunner_ntests_failed(runner); - srunner_free(runner); - - exit(failed ? EXIT_FAILURE : EXIT_SUCCESS); -} - -/* ---------------------------------------------------------------------- */ - -/* -- Globals -------------------------------------------------------------- */ - -struct s2nua *s2; - -int s2_nua_thread = 0; - -unsigned s2_default_registration_duration = 3600; - -char const s2_auth_digest_str[] = - "Digest realm=\"s2test\", " - "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " - "qop=\"auth\", " - "algorithm=\"MD5\""; - -char const s2_auth_credentials[] = "Digest:\"s2test\":abc:abc"; - -char const s2_auth2_digest_str[] = - "Digest realm=\"s2test2\", " - "nonce=\"fb0c093dcd98b7102dd2f0e8b11d0f600b\", " - "qop=\"auth\", " - "algorithm=\"MD5\""; - -char const s2_auth2_credentials[] = "Digest:\"s2test2\":abc:abc"; - -char const s2_auth3_digest_str[] = - "Digest realm=\"s2test3\", " - "nonce=\"e8b11d0f600bfb0c093dcd98b7102dd2f0\", " - "qop=\"auth-int\", " - "algorithm=\"MD5-sess\""; - -char const s2_auth3_credentials[] = "Digest:\"s2test3\":abc:abc"; - -/* -- NUA events -------------------------------------------------------- */ - -struct event *s2_remove_event(struct event *e) -{ - if ((*e->prev = e->next)) - e->next->prev = e->prev; - - e->prev = NULL, e->next = NULL; - - return e; -} - -void s2_free_event(struct event *e) -{ - if (e) { - if (e->prev) { - if ((*e->prev = e->next)) - e->next->prev = e->prev; - } - nua_destroy_event(e->event); - nua_handle_unref(e->nh); - free(e); - } -} - -void s2_flush_events(void) -{ - while (s2->events) { - s2_free_event(s2->events); - } -} - -struct event *s2_next_event(void) -{ - for (;;) { - if (s2->events) - return s2_remove_event(s2->events); - - su_root_step(s2base->root, 100); - } -} - -struct event *s2_wait_for_event(nua_event_t event, int status) -{ - struct event *e; - - for (;;) { - for (e = s2->events; e; e = e->next) { - if (event != nua_i_none && event != e->data->e_event) - continue; - if (status && e->data->e_status != status) - continue; - return s2_remove_event(e); - } - - su_root_step(s2base->root, 100); - } -} - -int s2_check_event(nua_event_t event, int status) -{ - struct event *e = s2_wait_for_event(event, status); - s2_free_event(e); - return e != NULL; -} - -int s2_check_callstate(enum nua_callstate state) -{ - int retval = 0; - tagi_t const *tagi; - struct event *e; - - e = s2_wait_for_event(nua_i_state, 0); - if (e) { - tagi = tl_find(e->data->e_tags, nutag_callstate); - if (tagi) { - retval = (tag_value_t)state == tagi->t_value; - } - } - s2_free_event(e); - return retval; -} - -int s2_check_substate(struct event *e, enum nua_substate state) -{ - int retval = 0; - tagi_t const *tagi; - - tagi = tl_find(e->data->e_tags, nutag_substate); - if (tagi) { - retval = (tag_value_t)state == tagi->t_value; - } - - return retval; -} - -static void -s2_nua_callback(nua_event_t event, - int status, char const *phrase, - nua_t *nua, nua_magic_t *_t, - nua_handle_t *nh, nua_hmagic_t *hmagic, - sip_t const *sip, - tagi_t tags[]) -{ - struct event *e, **prev; - - if (event == nua_i_active || event == nua_i_terminated) - return; - - e = calloc(1, sizeof *e); - nua_save_event(nua, e->event); - e->nh = nua_handle_ref(nh); - e->data = nua_event_data(e->event); - - for (prev = &s2->events; *prev; prev = &(*prev)->next) - ; - - *prev = e, e->prev = prev; -} - - -/* ====================================================================== */ - -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[]; - -void -s2_setup_logs(int level) -{ - su_log_soft_set_level(nua_log, level); - su_log_soft_set_level(soa_log, level); - su_log_soft_set_level(su_log_default, 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 (getenv("TPORT_LOG") == NULL && getenv("S2_TPORT_LOG") == NULL) { - if (s2sip) - tport_set_params(s2sip->master, TPTAG_LOG(level > 1), TAG_END()); - } -} - -nua_t *s2_nua_setup(char const *label, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - s2_setup(label); - - s2 = su_home_new(sizeof *s2); - - s2_dns_setup(s2base->root); - - s2_setup_logs(0); - s2_sip_setup("example.org", NULL, TAG_END()); - assert(s2sip->contact); - - s2_dns_domain("example.org", 1, - "s2", 1, s2sip->udp.contact->m_url, - "s2", 1, s2sip->tcp.contact->m_url, - NULL); - - /* enable/disable multithreading */ - su_root_threading(s2base->root, s2_nua_thread); - - ta_start(ta, tag, value); - s2->nua = - nua_create(s2base->root, - s2_nua_callback, - s2, - SIPTAG_FROM_STR("Alice "), - /* NUTAG_PROXY((url_string_t *)s2sip->contact->m_url), */ - /* Use internal DNS server */ - NUTAG_PROXY("sip:example.org"), - /* Force sresolv to use localhost and s2dns as DNS server */ -#if HAVE_WIN32 - SRESTAG_RESOLV_CONF("NUL"), -#else - SRESTAG_RESOLV_CONF("/dev/null"), -#endif - ta_tags(ta)); - ta_end(ta); - - return s2->nua; -} - -void -s2_nua_fast_forward(unsigned long seconds, - su_root_t *steproot) -{ - s2_fast_forward(seconds, NULL); - - if (s2_nua_thread) - /* Wake up nua thread */ - nua_handle_by_call_id(s2->nua, NULL); - - if (steproot) - su_root_step(steproot, 0); -} - -void s2_nua_teardown(void) -{ - if (s2) { - struct s2nua *zap = s2; - nua_destroy(s2->nua), s2->nua = NULL; - s2 = NULL; - su_home_unref(zap->home); - } - - s2_dns_teardown(); - s2_sip_teardown(); - s2_teardown(); - -} - -/* ====================================================================== */ - -/** Register NUA user. - * - *
- *  A                  B
- *  |-----REGISTER---->|
- *  |<-----200 OK------|
- *  |                  |
- * 
- */ -void s2_register_setup(void) -{ - nua_handle_t *nh; - struct message *m; - - assert(s2 && s2->nua); - assert(!s2->registration->nh); - - nh = nua_handle(s2->nua, NULL, TAG_END()); - - nua_register(nh, TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - assert(m); - - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - TAG_END()); - s2_sip_free_message(m); - - assert(s2->registration->contact != NULL); - fail_unless_event(nua_r_register, 200); - - s2->registration->nh = nh; -} - -/** Un-register NUA user. - * - *
- *  A                  B
- *  |-----REGISTER---->|
- *  |<-----200 OK------|
- *  |                  |
- * 
- */ -void s2_register_teardown(void) -{ - if (s2 && s2->registration->nh) { - nua_handle_t *nh = s2->registration->nh; - struct message *m; - - nua_unregister(nh, TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); assert(m); - s2_save_register(m); - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - TAG_END()); - assert(s2->registration->contact == NULL); - - s2_sip_free_message(m); - - fail_unless_event(nua_r_unregister, 200); - - nua_handle_destroy(nh); - s2->registration->nh = NULL; - } -} - -int -s2_save_register(struct message *rm) -{ - sip_contact_t *contact, *m, **m_prev; - sip_expires_t const *ex; - sip_date_t const *date; - sip_time_t now = rm->when.tv_sec, expires; - - msg_header_free_all(s2->home, (msg_header_t *)s2->registration->aor); - msg_header_free_all(s2->home, (msg_header_t *)s2->registration->contact); - tport_unref(s2->registration->tport); - - s2->registration->aor = NULL; - s2->registration->contact = NULL; - s2->registration->tport = NULL; - - if (rm == NULL) - return 0; - - assert(rm && rm->sip && rm->sip->sip_request); - assert(rm->sip->sip_request->rq_method == sip_method_register); - - ex = rm->sip->sip_expires; - date = rm->sip->sip_date; - - contact = sip_contact_dup(s2->home, rm->sip->sip_contact); - - for (m_prev = &contact; *m_prev;) { - m = *m_prev; - - expires = sip_contact_expires(m, ex, date, - s2_default_registration_duration, - now); - if (expires) { - char *p = su_sprintf(s2->home, "expires=%lu", (unsigned long)expires); - msg_header_add_param(s2->home, m->m_common, p); - m_prev = &m->m_next; - } - else { - *m_prev = m->m_next; - m->m_next = NULL; - msg_header_free(s2->home, (msg_header_t *)m); - } - } - - if (contact == NULL) - return 0; - - s2->registration->aor = sip_to_dup(s2->home, rm->sip->sip_to); - s2->registration->contact = contact; - s2->registration->tport = tport_ref(rm->tport); - - s2sip->sut.aor = s2->registration->aor; - s2sip->sut.contact = s2->registration->contact; - s2sip->sut.tport = s2->registration->tport; - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.h b/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.h deleted file mode 100644 index 4bac975a73..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_nua.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 CHECK_NUA_H - -#include -#include -#include -#include -#include - -#include "s2base.h" -#include "s2util.h" -#include "s2sip.h" - -struct s2nua -{ - su_home_t home[1]; - - nua_t *nua; - - int shutdown; - - struct event { - struct event *next, **prev; - nua_saved_event_t event[1]; - nua_handle_t *nh; - nua_event_data_t const *data; - su_time_t when; - } *events; - - struct { - nua_handle_t *nh; - sip_to_t *aor; - sip_contact_t *contact; - tport_t *tport; - } registration[1]; -}; - -extern unsigned s2_default_registration_duration; -extern char const s2_auth_digest_str[]; -extern char const s2_auth_credentials[]; - -extern char const s2_auth2_digest_str[]; -extern char const s2_auth2_credentials[]; - -extern char const s2_auth3_digest_str[]; -extern char const s2_auth3_credentials[]; - -extern int s2_nua_thread; - -extern struct s2nua *s2; - -void s2_setup_logs(int level); - -struct event *s2_remove_event(struct event *); -void s2_free_event(struct event *); -void s2_flush_events(void); - -struct event *s2_next_event(void); -struct event *s2_wait_for_event(nua_event_t event, int status); -int s2_check_event(nua_event_t event, int status); -int s2_check_callstate(enum nua_callstate state); -int s2_check_substate(struct event *e, enum nua_substate state); - -#define fail_unless_event(event, status) \ - fail_unless(s2_check_event(event, status)) - -#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL - -void s2_flush_all(void); - -nua_t *s2_nua_setup(char const *label, tag_type_t tag, tag_value_t value, ...); - -void s2_nua_teardown(void); - -void s2_nua_fast_forward(unsigned long seconds, - su_root_t *steproot); - -int s2_save_register(struct message *m); - -void s2_register_setup(void); -void s2_register_teardown(void); - -#include - -void check_session_cases(Suite *suite, int threading); -void check_register_cases(Suite *suite, int threading); -void check_etsi_cases(Suite *suite, int threading); -void check_simple_cases(Suite *suite, int threading); - -#endif - diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c deleted file mode 100644 index 2372c9c2fc..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_register.c - * - * @brief Check-driven tester for Sofia SIP User Agent library - * - * @author Pekka Pessi - * - * @copyright (C) 2008 Nokia Corporation. - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nua.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -SOFIAPUBVAR su_log_t tport_log[]; - -static nua_t *nua; - -static void register_setup(void) -{ - nua = s2_nua_setup("register", TAG_END()); -} - -static void register_thread_setup(void) -{ - s2_nua_thread = 1; - register_setup(); -} - -static void register_threadless_setup(void) -{ - s2_nua_thread = 1; - register_setup(); -} - -static void pingpong_setup(void) -{ - nua = s2_nua_setup("register with pingpong", - TPTAG_PINGPONG(20000), - TPTAG_KEEPALIVE(10000), - TAG_END()); - tport_set_params(s2sip->tcp.tport, TPTAG_PONG2PING(1), TAG_END()); -} - -static void pingpong_thread_setup(void) -{ - s2_nua_thread = 1; - pingpong_setup(); -} - -static void pingpong_threadless_setup(void) -{ - s2_nua_thread = 0; - pingpong_setup(); -} - -static void register_teardown(void) -{ - s2_teardown_started("register"); - nua_shutdown(nua); - fail_unless_event(nua_r_shutdown, 200); - s2_nua_teardown(); -} - -static void add_register_fixtures(TCase *tc, int threading, int pingpong) -{ - void (*setup)(void); - - if (pingpong) - setup = threading ? pingpong_thread_setup : pingpong_threadless_setup; - else - setup = threading ? register_thread_setup : register_threadless_setup; - - tcase_add_checked_fixture(tc, setup, register_teardown); -} - -/* ---------------------------------------------------------------------- */ - -START_TEST(register_1_0_1) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - - S2_CASE("1.0.1", "Failed Register", "REGISTER returned 403 response"); - - nua_register(nh, TAG_END()); - - fail_unless((m = s2_sip_wait_for_request(SIP_METHOD_REGISTER)) != NULL, NULL); - - s2_sip_respond_to(m, NULL, - SIP_403_FORBIDDEN, - TAG_END()); - s2_sip_free_message(m); - - nua_handle_destroy(nh); - -} END_TEST - - -START_TEST(register_1_1_1) -{ - S2_CASE("1.1.1", "Basic Register", "REGISTER returning 200 OK"); - - s2_register_setup(); - - s2_register_teardown(); - -} END_TEST - - -START_TEST(register_1_1_2) -{ - nua_handle_t *nh; - struct message *m; - - S2_CASE("1.1.2", "Register with dual authentication", - "Register, authenticate"); - - nh = nua_handle(nua, NULL, TAG_END()); - - nua_register(nh, TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); fail_if(!m); - s2_sip_respond_to(m, NULL, - SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(m); - fail_unless_event(nua_r_register, 407); - - nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); fail_if(!m); - s2_sip_respond_to(m, NULL, - SIP_401_UNAUTHORIZED, - SIPTAG_WWW_AUTHENTICATE_STR(s2_auth2_digest_str), - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(m); - fail_unless_event(nua_r_register, 401); - - nua_authenticate(nh, NUTAG_AUTH(s2_auth2_credentials), TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_proxy_authorization); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - TAG_END()); - s2_sip_free_message(m); - - assert(s2->registration->contact != NULL); - fail_unless_event(nua_r_register, 200); - - s2->registration->nh = nh; - - s2_register_teardown(); - -} END_TEST - -/* ---------------------------------------------------------------------- */ - -static char const receive_natted[] = "received=4.255.255.9"; -static char const receive_natted2[] = "received=4.255.255.10"; - -/* Return Via that looks very natted */ -static sip_via_t *natted_via(struct message *m, const char *receive_natted) -{ - su_home_t *h; - sip_via_t *via; - - h = msg_home(m->msg); - via = sip_via_dup(h, m->sip->sip_via); - msg_header_replace_param(h, via->v_common, receive_natted); - - if (via->v_protocol == sip_transport_udp) - msg_header_replace_param(h, via->v_common, "rport=9"); - - if (via->v_protocol == sip_transport_tcp && via->v_rport) { - tp_name_t const *tpn = tport_name(m->tport); - char *rport = su_sprintf(h, "rport=%s", tpn->tpn_port); - msg_header_replace_param(h, via->v_common, rport); - } - - return via; -} - -/* ---------------------------------------------------------------------- */ - -START_TEST(register_1_2_1) { - nua_handle_t *nh; - struct message *m; - - S2_CASE("1.2.1", "Register behind NAT", - "Register through NAT, detect NAT, re-REGISTER"); - - nh = nua_handle(nua, NULL, TAG_END()); - - nua_register(nh, TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_contact || m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - assert(s2->registration->contact != NULL); - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - fail_unless_event(nua_r_register, 200); - - s2->registration->nh = nh; - - s2_register_teardown(); - -} END_TEST - - -static nua_handle_t *make_auth_natted_register( - nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - struct message *m; - - ta_list ta; - ta_start(ta, tag, value); - nua_register(nh, ta_tags(ta)); - ta_end(ta); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); fail_if(!m); - s2_sip_respond_to(m, NULL, - SIP_401_UNAUTHORIZED, - SIPTAG_WWW_AUTHENTICATE_STR(s2_auth_digest_str), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 401); - - nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_authorization); - /* should not unregister the previous contact - * as it has not been successfully registered */ - fail_if(!m->sip->sip_contact); - fail_if(m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - assert(s2->registration->contact != NULL); - fail_unless_event(nua_r_register, 200); - - return nh; -} - -START_TEST(register_1_2_2_1) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - - S2_CASE("1.2.2.1", "Register behind NAT", - "Authenticate, outbound activated"); - - mark_point(); - make_auth_natted_register(nh, TAG_END()); - s2->registration->nh = nh; - s2_register_teardown(); -} -END_TEST - -START_TEST(register_1_2_2_2) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - - S2_CASE("1.2.2.2", "Register behind NAT", - "Authenticate, outbound activated, " - "authenticate OPTIONS probe, " - "NAT binding change"); - - mark_point(); - make_auth_natted_register(nh, TAG_END()); - s2->registration->nh = nh; - - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_OPTIONS); - fail_if(!m); - s2_sip_respond_to(m, NULL, - SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_VIA(natted_via(m, receive_natted)), - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(m); - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_OPTIONS); - fail_if(!m); fail_if(!m->sip->sip_proxy_authorization); - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - su_root_step(s2base->root, 20); su_root_step(s2base->root, 20); - s2_nua_fast_forward(120, s2base->root); /* Default keepalive interval */ - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_OPTIONS); - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - su_root_step(s2base->root, 20); su_root_step(s2base->root, 20); - s2_nua_fast_forward(120, s2base->root); /* Default keepalive interval */ - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_OPTIONS); - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_VIA(natted_via(m, receive_natted2)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_i_outbound, 0); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted2)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 200); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - - s2_register_teardown(); - -} END_TEST - - -START_TEST(register_1_2_2_3) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - - S2_CASE("1.2.2.3", "Register behind NAT", - "Authenticate, outbound activated, " - "detect NAT binding change when re-REGISTERing"); - - mark_point(); - - make_auth_natted_register(nh, - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - s2->registration->nh = nh; - - s2_nua_fast_forward(3600, s2base->root); - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted2)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted2)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - - fail_unless_event(nua_r_register, 200); - - s2_register_teardown(); - -} END_TEST - - -START_TEST(register_1_2_3) { - nua_handle_t *nh; - struct message *m; - - S2_CASE("1.2.3", "Register behind NAT", - "Outbound activated by error response"); - - nh = nua_handle(nua, NULL, TAG_END()); - nua_register(nh, TAG_END()); - - mark_point(); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_contact || m->sip->sip_contact->m_next); - - s2_sip_respond_to(m, NULL, - 400, "Bad Contact", - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - fail_unless_event(nua_r_register, 200); - - s2->registration->nh = nh; - - s2_register_teardown(); - -} END_TEST - - -/* ---------------------------------------------------------------------- */ - -START_TEST(register_1_3_1) -{ - nua_handle_t *nh; - struct message *m; - - S2_CASE("1.3.1", "Register over TCP via NAT", - "REGISTER via TCP, detect NTA, re-REGISTER"); - - nh = nua_handle(nua, NULL, TAG_END()); - - nua_register(nh, NUTAG_PROXY(s2sip->tcp.contact->m_url), TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_contact || m->sip->sip_contact->m_next); - fail_if(!tport_is_tcp(m->tport)); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - assert(s2->registration->contact != NULL); - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - fail_unless( - url_has_param(s2->registration->contact->m_url, "transport=tcp")); - fail_unless_event(nua_r_register, 200); - - s2->registration->nh = nh; - - s2_register_teardown(); - -} END_TEST - - -START_TEST(register_1_3_2_1) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - - S2_CASE("1.3.2.1", "Register behind NAT", - "Authenticate, outbound activated"); - - mark_point(); - s2->registration->nh = nh; - make_auth_natted_register(nh, NUTAG_PROXY(s2sip->tcp.contact->m_url), TAG_END()); - fail_if(!tport_is_tcp(s2->registration->tport)); - s2_register_teardown(); -} -END_TEST - - -START_TEST(register_1_3_2_2) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - - S2_CASE("1.3.2.2", "Register behind NAT with TCP", - "Detect NAT over TCP using rport. " - "Authenticate, detect NAT, " - "close TCP at server, wait for re-REGISTERs."); - - nua_set_params(nua, NTATAG_TCP_RPORT(1), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - mark_point(); - s2->registration->nh = nh; - make_auth_natted_register( - nh, NUTAG_PROXY(s2sip->tcp.contact->m_url), - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - fail_if(!tport_is_tcp(s2->registration->tport)); - tport_shutdown(s2->registration->tport, 2); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - /* The "NAT binding" changed when new TCP connection is established */ - /* => NUA re-REGISTERs with newly detected contact */ - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 200); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - - s2_register_teardown(); -} -END_TEST - -#if nomore -START_TEST(register_1_3_3_1) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - tport_t *tcp; - - S2_CASE("1.3.3.1", "Register behind NAT with UDP and TCP", - "Register with UDP, UDP time-outing, then w/ TCP using rport. "); - - nua_set_params(nua, NTATAG_TCP_RPORT(1), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - mark_point(); - s2->registration->nh = nh; - - nua_register(nh, - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - - /* NTA tries with UDP, we drop them */ - for (;;) { - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); fail_if(!m); - if (!tport_is_udp(m->tport)) /* Drop UDP */ - break; - s2_sip_free_message(m); - s2_nua_fast_forward(4, s2base->root); - } - - tcp = tport_ref(m->tport); - - /* Respond to request over TCP */ - s2_sip_respond_to(m, NULL, - SIP_401_UNAUTHORIZED, - SIPTAG_WWW_AUTHENTICATE_STR(s2_auth_digest_str), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - fail_unless_event(nua_r_register, 401); - nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); - - /* Turn off pong */ - tport_set_params(tcp, TPTAG_PONG2PING(0), TAG_END()); - - /* Now request over UDP ... registering TCP contact! */ - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - s2_save_register(m); - fail_unless( - url_has_param(s2->registration->contact->m_url, "transport=tcp")); - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - /* NUA detects oops... re-registers UDP */ - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact || !m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 200); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - - /* Wait until ping-pong failure closes the TCP connection */ - { - int i; - for (i = 0; i < 5; i++) { - su_root_step(s2base->root, 5); - su_root_step(s2base->root, 5); - su_root_step(s2base->root, 5); - s2_nua_fast_forward(5, s2base->root); - } - } - - s2_register_teardown(); -} -END_TEST -#endif - -START_TEST(register_1_3_3_2) -{ - nua_handle_t *nh = nua_handle(nua, NULL, TAG_END()); - struct message *m; - tport_t *tcp; - int i; - - S2_CASE("1.3.3.2", "Register behind NAT with TCP", - "Register w/ TCP using rport, pingpong. "); - - nua_set_params(nua, NTATAG_TCP_RPORT(1), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - mark_point(); - s2->registration->nh = nh; - - nua_register(nh, - NUTAG_PROXY(s2sip->tcp.contact->m_url), - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); fail_if(!m); - - fail_unless(tport_is_tcp(m->tport)); - - tcp = tport_ref(m->tport); - - /* Respond to request over TCP */ - s2_sip_respond_to(m, NULL, - SIP_401_UNAUTHORIZED, - SIPTAG_WWW_AUTHENTICATE_STR(s2_auth_digest_str), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - fail_unless_event(nua_r_register, 401); - nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 200); - - fail_unless(s2->registration->contact != NULL); - fail_if(s2->registration->contact->m_next != NULL); - - /* Turn off pong */ - tport_set_params(tcp, TPTAG_PONG2PING(0), TAG_END()); - - /* Wait until ping-pong failure closes the TCP connection */ - for (i = 0; i < 100; i++) { - s2_nua_fast_forward(5, s2base->root); - if (tport_is_closed(tcp)) - break; - } - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_unless(tport_is_tcp(m->tport)); - fail_unless(tcp != m->tport); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - tport_unref(tcp); - - /* Contact changed */ - fail_unless_event(nua_r_register, 100); - - m = s2_sip_wait_for_request(SIP_METHOD_REGISTER); - fail_if(!m); fail_if(!m->sip->sip_authorization); - fail_if(!m->sip->sip_contact); - fail_if(!m->sip->sip_contact->m_next); - s2_save_register(m); - - s2_sip_respond_to(m, NULL, - SIP_200_OK, - SIPTAG_CONTACT(s2->registration->contact), - SIPTAG_VIA(natted_via(m, receive_natted)), - TAG_END()); - s2_sip_free_message(m); - - fail_unless_event(nua_r_register, 200); - - s2_register_teardown(); -} -END_TEST - -/* ---------------------------------------------------------------------- */ - -TCase *register_tcase(int threading) -{ - TCase *tc = tcase_create("1 - REGISTER"); - - add_register_fixtures(tc, threading, 0); - - { - tcase_add_test(tc, register_1_0_1); - tcase_add_test(tc, register_1_1_1); - tcase_add_test(tc, register_1_1_2); - tcase_add_test(tc, register_1_2_1); - tcase_add_test(tc, register_1_2_2_1); - tcase_add_test(tc, register_1_2_2_2); - tcase_add_test(tc, register_1_2_2_3); - tcase_add_test(tc, register_1_2_3); - tcase_add_test(tc, register_1_3_1); - tcase_add_test(tc, register_1_3_2_1); - tcase_add_test(tc, register_1_3_2_2); - } - tcase_set_timeout(tc, 10); - return tc; -} - -TCase *pingpong_tcase(int threading) -{ - TCase *tc = tcase_create("1 - REGISTER (with PingPong)"); - - add_register_fixtures(tc, threading, 1); - - { - tcase_add_test(tc, register_1_3_3_2); - } - - tcase_set_timeout(tc, 10); - return tc; -} - -/* ---------------------------------------------------------------------- */ - -static struct dialog *dialog = NULL; - -static void registrar_setup(void) -{ - struct event *event; - tagi_t const *t; - sip_contact_t *m; - - dialog = su_home_new(sizeof *dialog); fail_if(!dialog); - - nua = s2_nua_setup("register", - NUTAG_APPL_METHOD("REGISTER"), - NUTAG_ALLOW("REGISTER"), - NUTAG_PROXY(SIP_NONE), - TAG_END()); - - nua_get_params(nua, TAG_ANY(), TAG_END()); - event = s2_wait_for_event(nua_r_get_params, 200); - fail_unless(event != NULL); - - t = tl_find(event->data->e_tags, ntatag_contact); - fail_unless(t != NULL); - m = sip_contact_dup(dialog->home, (sip_contact_t *)t->t_value); - fail_unless(m != NULL); - - s2sip->sut.contact = m; -} - -static void registrar_thread_setup(void) -{ - s2_nua_thread = 1; - registrar_setup(); -} - -static void registrar_threadless_setup(void) -{ - s2_nua_thread = 1; - registrar_setup(); -} - -static void registrar_teardown(void) -{ - s2_teardown_started("registrar"); - nua_shutdown(nua); - fail_unless_event(nua_r_shutdown, 200); - s2_nua_teardown(); -} - -static void add_registrar_fixtures(TCase *tc, int threading) -{ - void (*setup)(void); - - if (threading) - setup = registrar_thread_setup; - else - setup = registrar_threadless_setup; - - tcase_add_checked_fixture(tc, setup, registrar_teardown); -} - -START_TEST(registrar_1_4_0) -{ - struct event *event; - nua_handle_t *nh; - struct message *response; - - S2_CASE("1.4.0", "Registrar", "Test receiving a REGISTER"); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, NULL, - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - TAG_END())); - - event = s2_wait_for_event(nua_i_register, 100); - fail_unless(event != NULL); - nh = event->nh; fail_if(!nh); - - nua_respond(nh, 200, "Ok", - NUTAG_WITH_SAVED(event->event), - TAG_END()); - - response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(registrar_1_4_1) -{ - struct event *event; - nua_handle_t *nh; - struct message *response; - - S2_CASE("1.4.1", "Registrar", "Test receiving a REGISTER via TCP"); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, s2sip->tcp.tport, - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - TAG_END())); - - event = s2_wait_for_event(nua_i_register, 100); - fail_if(!event); - nh = event->nh; fail_if(!nh); - - nua_respond(nh, 200, "Ok", - NUTAG_WITH_SAVED(event->event), - TAG_END()); - - response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); - fail_if(!response); - tport_shutdown(response->tport, 2); - s2_sip_free_message(response); - - event = s2_wait_for_event(nua_i_media_error, 0); - fail_if(!event); - nua_handle_destroy(nh); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, s2sip->tcp.tport, - SIPTAG_FROM_STR(""), - SIPTAG_TO_STR(""), - TAG_END())); - - event = s2_wait_for_event(nua_i_register, 100); - fail_if(!event); - nh = event->nh; fail_if(!nh); - - nua_respond(nh, 200, "Ok", - NUTAG_WITH_SAVED(event->event), - TAG_END()); - - response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); - fail_if(!response); - nua_handle_destroy(nh); - - s2_step(); - s2_step(); - s2_step(); - - tport_shutdown(response->tport, 2); - s2_sip_free_message(response); -} -END_TEST - -TCase *registrar_tcase(int threading) -{ - TCase *tc = tcase_create("1.4 - REGISTER server"); - - add_registrar_fixtures(tc, threading); - - tcase_add_test(tc, registrar_1_4_0); - tcase_add_test(tc, registrar_1_4_1); - - tcase_set_timeout(tc, 10); - - return tc; -} - -void check_register_cases(Suite *suite, int threading) -{ - suite_add_tcase(suite, register_tcase(threading)); - suite_add_tcase(suite, pingpong_tcase(threading)); - suite_add_tcase(suite, registrar_tcase(threading)); -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c deleted file mode 100644 index ed1f575017..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_session.c +++ /dev/null @@ -1,3670 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_session.c - * - * @brief NUA module tests for SIP session handling - * - * @author Pekka Pessi - * - * @copyright (C) 2008 Nokia Corporation. - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nua.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* define XXX as 1 in order to see all failing test cases */ -#ifndef XXX -#define XXX (0) -#endif - -/* ====================================================================== */ - -static nua_t *nua; -static soa_session_t *soa = NULL; -static struct dialog *dialog = NULL; - -#define CRLF "\r\n" - -static void call_setup(void) -{ - nua = s2_nua_setup("call", - SIPTAG_ORGANIZATION_STR("Pussy Galore's Flying Circus"), - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - - soa = soa_create(NULL, s2base->root, NULL); - - fail_if(!soa); - - soa_set_params(soa, - SOATAG_USER_SDP_STR("m=audio 5008 RTP/AVP 8 0" CRLF - "m=video 5010 RTP/AVP 34" CRLF), - TAG_END()); - - dialog = su_home_new(sizeof *dialog); fail_if(!dialog); - - s2_register_setup(); -} - -static void call_thread_setup(void) -{ - s2_nua_thread = 1; - call_setup(); -} - -static void call_teardown(void) -{ - s2_teardown_started("call"); - - mark_point(); - - s2_register_teardown(); - - if (s2->shutdown == 0) { - mark_point(); - nua_shutdown(nua); - fail_unless_event(nua_r_shutdown, 200); - } - - mark_point(); - - s2_nua_teardown(); -} - -static void -add_call_fixtures(TCase *tc, int threading) -{ - if (threading) - tcase_add_checked_fixture(tc, call_thread_setup, call_teardown); - else - tcase_add_checked_fixture(tc, call_setup, call_teardown); -} - -static void save_sdp_to_soa(struct message *message) -{ - sip_payload_t *pl; - char const *body; - isize_t bodylen; - - fail_if(!message); - - fail_if(!message->sip->sip_content_length); - fail_if(!message->sip->sip_content_type); - fail_if(strcmp(message->sip->sip_content_type->c_type, - "application/sdp")); - - fail_if(!message->sip->sip_payload); - pl = message->sip->sip_payload; - body = pl->pl_data, bodylen = pl->pl_len; - - fail_if(soa_set_remote_sdp(soa, NULL, body, (issize_t)bodylen) < 0); -} - -static void process_offer(struct message *message) -{ - save_sdp_to_soa(message); - fail_if(soa_generate_answer(soa, NULL) < 0); -} - -static void process_answer(struct message *message) -{ - save_sdp_to_soa(message); - fail_if(soa_process_answer(soa, NULL) < 0); -} - -static void -respond_with_sdp(struct message *request, - struct dialog *dialog, - int status, char const *phrase, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - char const *body; - isize_t bodylen; - - fail_if(soa_get_local_sdp(soa, NULL, &body, &bodylen) != 1); - - ta_start(ta, tag, value); - s2_sip_respond_to(request, dialog, status, phrase, - SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR(body), - SIPTAG_CONTENT_DISPOSITION_STR("session"), - ta_tags(ta)); - ta_end(ta); -} - -static void -request_with_sdp(struct dialog *dialog, - sip_method_t method, char const *name, - tport_t *tport, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - char const *body; - isize_t bodylen; - - fail_if(soa_get_local_sdp(soa, NULL, &body, &bodylen) != 1); - - ta_start(ta, tag, value); - fail_if( - s2_sip_request_to(dialog, method, name, tport, - SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR(body), - ta_tags(ta))); - ta_end(ta); -} - -static struct message * -invite_sent_by_nua(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - ta_start(ta, tag, value); - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - ta_tags(ta)); - ta_end(ta); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - return s2_sip_wait_for_request(SIP_METHOD_INVITE); -} - -static uint32_t s2_rseq; - -static struct message * -respond_with_100rel(struct message *invite, - struct dialog *d, - int with_sdp, - int status, char const *phrase, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - sip_rseq_t rs[1]; - - assert(100 < status && status < 200); - - sip_rseq_init(rs); - rs->rs_response = ++s2_rseq; - - ta_start(ta, tag, value); - - if (with_sdp) { - respond_with_sdp( - invite, dialog, status, phrase, - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_RSEQ(rs), - ta_tags(ta)); - } - else { - s2_sip_respond_to( - invite, dialog, status, phrase, - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_RSEQ(rs), - ta_tags(ta)); - } - ta_end(ta); - - fail_unless_event(nua_r_invite, status); - - return s2_sip_wait_for_request(SIP_METHOD_PRACK); -} - -static void -invite_by_nua(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - struct message *invite; - ta_list ta; - - ta_start(ta, tag, value); - invite = invite_sent_by_nua(nh, ta_tags(ta)); - ta_end(ta); - - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); -} - -static nua_handle_t * -invite_to_nua(tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct event *invite; - struct message *response; - nua_handle_t *nh; - - soa_generate_offer(soa, 1, NULL); - - ta_start(ta, tag, value); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, ta_tags(ta)); - ta_end(ta); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; - fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - - nua_respond(nh, SIP_180_RINGING, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_early)); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_200_OK, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - - fail_if(!response); - s2_sip_update_dialog(dialog, response); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - return nh; -} - -static void -bye_by_nua(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct message *bye; - - ta_start(ta, tag, value); - nua_bye(nh, ta_tags(ta)); - ta_end(ta); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); -} - -static void -bye_by_nua_challenged(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct message *bye; - - s2_flush_events(); - - ta_start(ta, tag, value); - nua_bye(nh, ta_tags(ta)); - ta_end(ta); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 407); - - nua_authenticate(nh, NUTAG_AUTH("Digest:\"s2test\":abc:abc"), TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_if(s2->events); -} - - -static void -cancel_by_nua(nua_handle_t *nh, - struct message *invite, - struct dialog *dialog, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct message *cancel; - - ta_start(ta, tag, value); - nua_cancel(nh, ta_tags(ta)); - ta_end(ta); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); - fail_unless_event(nua_r_cancel, 200); - - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - fail_unless_event(nua_r_invite, 487); -} - -static void -bye_to_nua(nua_handle_t *nh, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - - ta_start(ta, tag, value); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, ta_tags(ta))); - ta_end(ta); - - fail_unless_event(nua_i_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); -} - -/* ====================================================================== */ -/* 2 - Call cases */ - -/* 2.1 - Basic call cases */ - -START_TEST(call_2_1_1) -{ - nua_handle_t *nh; - - S2_CASE("2.1.1", "Basic call", - "NUA sends INVITE, NUA sends BYE"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite_by_nua(nh, TAG_END()); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_2_1) -{ - nua_handle_t *nh; - - S2_CASE("2.1.2.1", "Basic call", - "NUA sends INVITE, NUA receives BYE"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite_by_nua(nh, TAG_END()); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_1_2_2) -{ - nua_handle_t *nh; - - S2_CASE("2.1.2.2", "Basic call over TCP", - "NUA sends INVITE, NUA receives BYE"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - TAG_END()); - - invite_by_nua(nh, - NUTAG_PROXY(s2sip->tcp.contact->m_url), - TAG_END()); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_3_1) -{ - nua_handle_t *nh; - - S2_CASE("2.1.3.1", "Incoming call", - "NUA receives INVITE and BYE"); - - nh = invite_to_nua(TAG_END()); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_3_2) -{ - nua_handle_t *nh; - - S2_CASE("2.1.3.2", "Incoming call over TCP", - "NUA receives INVITE and BYE"); - - dialog->tport = s2sip->tcp.tport; - - nh = invite_to_nua(TAG_END()); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_4) -{ - nua_handle_t *nh; - - S2_CASE("2.1.4", "Incoming call", - "NUA receives INVITE and sends BYE"); - - nh = invite_to_nua(TAG_END()); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_5) -{ - nua_handle_t *nh; - - S2_CASE("2.1.5", "Incoming call", - "NUA receives INVITE and sends BYE, BYE is challenged"); - - nh = invite_to_nua(TAG_END()); - - bye_by_nua_challenged(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_6) -{ - nua_handle_t *nh; - struct message *bye; - struct event *invite; - struct message *response; - - S2_CASE("2.1.6", "Basic call", - "NUA received INVITE, " - "NUA responds (and saves proxy for dialog), " - "NUA sends BYE"); - - soa_generate_offer(soa, 1, NULL); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; - fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - - nua_respond(nh, SIP_180_RINGING, - /* Dialog-specific proxy is saved */ - NUTAG_PROXY(s2sip->tcp.contact->m_url), - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_early)); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_200_OK, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - - fail_if(!response); - s2_sip_update_dialog(dialog, response); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - nua_bye(nh, TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - /* Check that NUA used dialog-specific proxy with BYE */ - fail_unless(tport_is_tcp(bye->tport)); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_7) -{ - nua_handle_t *nh, *nh2; - sip_replaces_t *replaces; - - S2_CASE("2.1.7", "Call lookup", - "Test dialog and call-id lookup"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite_by_nua(nh, TAG_END()); - - nh2 = nua_handle_by_call_id(nua, dialog->call_id->i_id); - fail_if(!nh2); fail_if(nh != nh2); nua_handle_unref(nh2); - - replaces = sip_replaces_format(NULL, "%s;from-tag=%s;to-tag=%s", - dialog->call_id->i_id, - dialog->local->a_tag, - dialog->remote->a_tag); - fail_if(!replaces); - - nh2 = nua_handle_by_replaces(nua, replaces); - fail_if(!nh2); fail_if(nh != nh2); nua_handle_unref(nh2); - - msg_header_free_all(NULL, (msg_header_t *)replaces); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_2_1_8) -{ - nua_handle_t *nh; - struct message *invite, *ack; - - S2_CASE("2.1.8", "Call using NUTAG_PROXY()", - "Test handle-specific NUTAG_PROXY()."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - NUTAG_PROXY(s2sip->tcp.contact->m_url), TAG_END()); - - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_unless(ack && tport_is_tcp(ack->tport)); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -TCase *invite_tcase(int threading) -{ - TCase *tc = tcase_create("2.1 - Basic INVITE"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_2_1_1); - tcase_add_test(tc, call_2_1_2_1); - tcase_add_test(tc, call_2_1_2_2); - tcase_add_test(tc, call_2_1_3_1); - tcase_add_test(tc, call_2_1_3_2); - tcase_add_test(tc, call_2_1_4); - tcase_add_test(tc, call_2_1_5); - tcase_add_test(tc, call_2_1_6); - tcase_add_test(tc, call_2_1_7); - tcase_add_test(tc, call_2_1_8); - } - return tc; -} - -/* ---------------------------------------------------------------------- */ -/* 2.2 - Call CANCEL cases */ - -START_TEST(cancel_2_2_1) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("2.2.1", "Cancel call", - "NUA is caller, NUA sends CANCEL immediately"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - nua_cancel(nh, TAG_END()); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - fail_if(s2sip->received != NULL); - s2_sip_respond_to(invite, dialog, SIP_100_TRYING, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - fail_unless_event(nua_r_invite, 487); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless_event(nua_r_cancel, 200); - fail_if(s2->events != NULL); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_2) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("2.2.2", "Canceled call", - "NUA is caller, NUA sends CANCEL after receiving 100"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_100_TRYING, TAG_END()); - - cancel_by_nua(nh, invite, dialog, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_3) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("2.2.3", "Canceled call", - "NUA is caller, NUA sends CANCEL after receiving 180"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - cancel_by_nua(nh, invite, dialog, TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_4) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("2.2.4", "Cancel and 200 OK glare", - "NUA is caller, NUA sends CANCEL after receiving 180 " - "but UAS already sent 200 OK."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_cancel(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - - s2_sip_respond_to(cancel, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - s2_sip_free_message(cancel); - fail_unless_event(nua_r_cancel, 481); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_5) -{ - nua_handle_t *nh; - struct message *invite, *cancel, *bye; - - S2_CASE( - "2.2.5", "Cancel and 200 OK glare", - "NUA is caller, " - "NUA uses nua_bye() to send CANCEL after receiving 180\n" - "but UAS already sent 200 OK.\n" - "Test case checks that NUA really sends BYE after nua_bye() is called\n"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - NUTAG_AUTOACK(0), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_bye(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - - s2_sip_respond_to(cancel, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - s2_sip_free_message(cancel); - fail_unless_event(nua_r_cancel, 481); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - fail_unless(s2_check_callstate(nua_callstate_terminating)); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_6) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response; - - S2_CASE("2.2.6", "Cancel call", - "NUA is callee, sends 100, 180, INVITE gets canceled"); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - - nua_respond(nh, SIP_180_RINGING, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_early)); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_CANCEL, NULL, TAG_END())); - fail_unless_event(nua_i_cancel, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_CANCEL); - fail_if(!response); - s2_sip_free_message(response); - - response = s2_sip_wait_for_response(487, SIP_METHOD_INVITE); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_7) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response; - char const *via = "SIP/2.0/UDP host.in.invalid;rport"; - - S2_CASE("2.2.7", "Call gets canceled", - "NUA is callee, sends 100, 180, INVITE gets canceled. " - "Using RFC 2543 dialog and transaction matching."); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, - SIPTAG_VIA_STR(via), - TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - - nua_respond(nh, SIP_180_RINGING, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_early)); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_CANCEL, NULL, TAG_END())); - fail_unless_event(nua_i_cancel, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_CANCEL); - fail_if(!response); - s2_sip_free_message(response); - - response = s2_sip_wait_for_response(487, SIP_METHOD_INVITE); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(cancel_2_2_8) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - int timeout; - - S2_CASE("2.2.8", "CANCEL and INVITE times out", - "NUA is caller, NUA sends CANCEL after receiving 180 " - "but UAS never responds."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_cancel(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - s2_sip_free_message(cancel); - fail_if(!cancel); - - /* Now, time out both CANCEL and INVITE */ - for (timeout = 0; timeout < 34; timeout++) { - s2_nua_fast_forward(1, s2base->root); - cancel = s2_sip_next_request(SIP_METHOD_CANCEL); - if (cancel) - s2_sip_free_message(cancel); - } - - fail_unless_event(nua_r_cancel, 408); - fail_unless_event(nua_r_invite, 408); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(cancel_2_2_9) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - int timeout; - - S2_CASE("2.2.9", "CANCEL a RFC2543 UA", - "NUA is caller, NUA sends CANCEL after receiving 180, " - "UAS sends 200 OK to CANCEL but no response to INVITE."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_cancel(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); - - /* Time out INVITE */ - for (timeout = 0; timeout < 34; timeout++) { - s2_nua_fast_forward(1, s2base->root); - } - - fail_unless_event(nua_r_invite, 408); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(cancel_2_2_10) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - struct event *event; - int timeout; - - S2_CASE("2.2.10", "CANCEL and INVITE times out", - "NUA is caller, NUA sends CANCEL after receiving 180 " - "but UAS never responds."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_cancel(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - s2_sip_free_message(cancel); - fail_if(!cancel); - - nua_cancel(nh, TAG_END()); - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); - - /* emulate network gone bad below - zap registration handle here - so that s2_register_teardown() does not hang - */ - s2->registration->nh = NULL; - - nua_set_params(s2->nua, NUTAG_SHUTDOWN_EVENTS(1), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - nua_shutdown(s2->nua); - event = s2_wait_for_event(nua_r_shutdown, 100); - fail_unless(event != NULL); - s2_free_event(event); - - /* Time out */ - for (timeout = 0; timeout < 34; timeout++) { - s2_nua_fast_forward(5, s2base->root); - nua_shutdown(s2->nua); - event = s2_wait_for_event(nua_r_shutdown, 0); - fail_unless(event != NULL); - if (event->data->e_status >= 200) - break; - } - - s2->shutdown = 200; -} -END_TEST - - - -TCase *cancel_tcase(int threading) -{ - TCase *tc = tcase_create("2.2 - CANCEL"); - add_call_fixtures(tc, threading); - - tcase_add_test(tc, cancel_2_2_1); - tcase_add_test(tc, cancel_2_2_2); - tcase_add_test(tc, cancel_2_2_3); - tcase_add_test(tc, cancel_2_2_4); - if (XXX) tcase_add_test(tc, cancel_2_2_5); - tcase_add_test(tc, cancel_2_2_6); - tcase_add_test(tc, cancel_2_2_7); - tcase_add_test(tc, cancel_2_2_8); - tcase_add_test(tc, cancel_2_2_9); - tcase_add_test(tc, cancel_2_2_10); - - return tc; -} - - -/* ---------------------------------------------------------------------- */ -/* 2.3 - Session timers */ - -/* Wait for invite from NUA */ -static struct message * -invite_timer_round(nua_handle_t *nh, - char const *session_expires, - sip_record_route_t *rr) -{ - struct message *invite, *ack; - - fail_unless(s2_check_callstate(nua_callstate_calling)); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - /* Check that INVITE contains Session-Expires header with refresher=uac */ - fail_unless(invite->sip->sip_session_expires != NULL); - fail_unless(su_casematch(invite->sip->sip_session_expires->x_refresher, "uac")); - respond_with_sdp( - invite, dialog, SIP_200_OK, - SIPTAG_SESSION_EXPIRES_STR(session_expires), - SIPTAG_REQUIRE_STR("timer"), - SIPTAG_RECORD_ROUTE(rr), - TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - if (rr == NULL) - s2_sip_free_message(ack); - return ack; -} - -START_TEST(call_2_3_1) -{ - nua_handle_t *nh; - sip_record_route_t rr[1]; - struct message *ack; - - sip_record_route_init(rr); - *rr->r_url = *s2sip->contact->m_url; - rr->r_url->url_user = "record"; - rr->r_url->url_params = "lr"; - - S2_CASE("2.3.1", "Incoming call with call timers", - "NUA receives INVITE, " - "activates call timers, " - "sends re-INVITE twice, " - "sends BYE."); - - nh = invite_to_nua( - SIPTAG_SESSION_EXPIRES_STR("300;refresher=uas"), - SIPTAG_REQUIRE_STR("timer"), - TAG_END()); - - s2_nua_fast_forward(300, s2base->root); - ack = invite_timer_round(nh, "300;refresher=uac", rr); - fail_if(ack->sip->sip_route && - su_strmatch(ack->sip->sip_route->r_url->url_user, "record")); - s2_nua_fast_forward(300, s2base->root); - invite_timer_round(nh, "300;refresher=uac", NULL); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_3_2) -{ - nua_handle_t *nh; - - S2_CASE("2.3.2", "Incoming call with call timers", - "NUA receives INVITE, " - "activates call timers, " - "sends re-INVITE, " - "sends BYE."); - - nh = invite_to_nua( - SIPTAG_SESSION_EXPIRES_STR("300;refresher=uas"), - SIPTAG_REQUIRE_STR("timer"), - TAG_END()); - - s2_nua_fast_forward(300, s2base->root); - invite_timer_round(nh, "300;refresher=uac", NULL); - s2_nua_fast_forward(300, s2base->root); - invite_timer_round(nh, "300;refresher=uac", NULL); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - - - -TCase *session_timer_tcase(int threading) -{ - TCase *tc = tcase_create("2.3 - Session timers"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_2_3_1); - tcase_add_test(tc, call_2_3_2); - } - return tc; -} - -/* ====================================================================== */ -/* 2.4 - 100rel */ - -START_TEST(call_2_4_1) -{ - nua_handle_t *nh; - struct message *invite, *prack, *ack; - int with_sdp; - sip_record_route_t rr[1]; - - S2_CASE("2.4.1", "Call with 100rel", - "NUA sends INVITE, " - "receives 183, sends PRACK, receives 200 for it, " - "receives 180, sends PRACK, receives 200 for it, " - "receives 200, send ACK."); - - sip_record_route_init(rr); - *rr->r_url = *s2sip->contact->m_url; - rr->r_url->url_user = "record"; - rr->r_url->url_params = "lr"; - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - process_offer(invite); - - prack = respond_with_100rel(invite, dialog, with_sdp = 1, - SIP_183_SESSION_PROGRESS, - SIPTAG_RECORD_ROUTE(rr), - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_180_RINGING, - TAG_END()); - fail_unless(prack->sip->sip_route != NULL); - fail_unless(su_strmatch(prack->sip->sip_route->r_url->url_user, "record")); - - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - /* Change the record-route */ - rr->r_url->url_user = "record2"; - s2_sip_respond_to(invite, dialog, SIP_200_OK, - SIPTAG_RECORD_ROUTE(rr), - TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - fail_unless(su_strmatch(ack->sip->sip_route->r_url->url_user, "record2")); - s2_sip_free_message(ack); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_4_2) -{ - nua_handle_t *nh; - struct message *invite, *prack; - int with_sdp; - - S2_CASE("2.4.2", "Call with 100rel", - "NUA sends INVITE, " - "receives 183, sends PRACK, receives 200 for it, " - "receives 180, sends PRACK, receives 200 for it, " - "receives 200, send ACK."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, - NUTAG_MEDIA_ENABLE(0), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR( - "v=0" CRLF - "o=- 6805647540234172778 5821668777690722690 IN IP4 127.0.0.1" CRLF - "s=-" CRLF - "c=IN IP4 127.0.0.1" CRLF - "m=audio 5004 RTP/AVP 0 8" CRLF), - TAG_END()); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_183_SESSION_PROGRESS, - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_180_RINGING, - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - s2_sip_respond_to(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_4_3) -{ - struct message *response; - - S2_CASE("2.4.3", "Call without 100rel", - "NUA receives INVITE with Required: 100rel, " - "rejects it with 420"); - - nua_set_params(s2->nua, - SIPTAG_SUPPORTED(SIP_NONE), - SIPTAG_SUPPORTED_STR("timer"), - TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, - SIPTAG_REQUIRE_STR("100rel"), - TAG_END()); - - response = s2_sip_wait_for_response(420, SIP_METHOD_INVITE); - fail_if(!response); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); -} -END_TEST - -START_TEST(call_2_4_4) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response; - - S2_CASE("2.4.3", "Call without 100rel", - "NUA receives INVITE with Supported: 100rel, " - "proceeds normally"); - - nua_set_params(s2->nua, - SIPTAG_SUPPORTED(SIP_NONE), - SIPTAG_SUPPORTED_STR("timer"), - TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, - SIPTAG_SUPPORTED_STR("100rel"), - TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - - nua_respond(nh, SIP_183_SESSION_PROGRESS, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_early)); - - response = s2_sip_wait_for_response(183, SIP_METHOD_INVITE); - fail_if(!response); - fail_if(response->sip->sip_require); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_200_OK, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_4_5) -{ - nua_handle_t *nh; - struct message *invite, *prack, *cancel; - int i; - int with_sdp; - sip_from_t *branch1, *branch2; - - /* Testcase for bug FSCORE-338 - - forked transactions getting canceled and terminated properly. */ - - S2_CASE("2.4.5", "Destroy proceeding call with 100rel", - "NUA sends INVITE, " - "receives 183, sends PRACK, receives 200 for it, " - "receives 180, sends PRACK, receives 200 for it, " - "handle is destroyed."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, - NUTAG_PROXY(s2sip->tcp.contact->m_url), - NUTAG_MEDIA_ENABLE(0), - NUTAG_AUTOACK(0), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR( - "v=0" CRLF - "o=- 6805647540234172778 5821668777690722690 IN IP4 127.0.0.1" CRLF - "s=-" CRLF - "c=IN IP4 127.0.0.1" CRLF - "m=audio 5004 RTP/AVP 0 8" CRLF), - TAG_END()); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_183_SESSION_PROGRESS, - SIPTAG_CONTACT(s2sip->tcp.contact), - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_180_RINGING, - SIPTAG_CONTACT(s2sip->tcp.contact), - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - branch1 = dialog->local; - branch2 = dialog->local = sip_from_dup(dialog->home, invite->sip->sip_to); - sip_from_tag(dialog->home, dialog->local, s2_sip_generate_tag(dialog->home)); - - nua_handle_destroy(nh), nh = NULL; - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - - for (i = 1; i < 4; i++) { - s2_nua_fast_forward(1, s2base->root); - } - - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - /* Time out requests */ - for (i = 1; i < 128; i++) { - s2_nua_fast_forward(1, s2base->root); - } -} -END_TEST - -TCase *invite_100rel_tcase(int threading) -{ - TCase *tc = tcase_create("2.4 - INVITE with 100rel"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_2_4_1); - tcase_add_test(tc, call_2_4_2); - tcase_add_test(tc, call_2_4_3); - tcase_add_test(tc, call_2_4_4); - tcase_add_test(tc, call_2_4_5); - } - return tc; -} - -/* ====================================================================== */ -/* 2.5 - Call with preconditions */ - -START_TEST(call_2_5_1) -{ - nua_handle_t *nh; - struct message *invite, *prack, *update; - int with_sdp; - - S2_CASE("2.5.1", "Call with preconditions", - "NUA sends INVITE, " - "receives 183, sends PRACK, receives 200 for it, " - "sends UPDATE, receives 200 for it, " - "receives 180, sends PRACK, receives 200 for it, " - "receives 200, send ACK."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - SIPTAG_REQUIRE_STR("precondition"), - TAG_END()); - process_offer(invite); - - prack = respond_with_100rel(invite, dialog, with_sdp = 1, - SIP_183_SESSION_PROGRESS, - TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - process_offer(prack); - respond_with_sdp( - prack, dialog, SIP_200_OK, - SIPTAG_REQUIRE_STR("100rel"), - TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless_event(nua_r_prack, 200); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - update = s2_sip_wait_for_request(SIP_METHOD_UPDATE); - /* UPDATE sent by stack, stack sends event for it */ - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - process_offer(update); - respond_with_sdp( - update, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(update), update = NULL; - - fail_unless_event(nua_r_update, 200); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - prack = respond_with_100rel(invite, dialog, with_sdp = 0, - SIP_180_RINGING, - TAG_END()); - s2_sip_respond_to(prack, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - fail_unless_event(nua_r_prack, 200); - - s2_sip_respond_to(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_5_2) -{ - nua_handle_t *nh; - struct message *invite, *prack, *update; - sip_rseq_t rs[1]; - sip_rack_t rack[1]; - - S2_CASE("2.5.2", "Call with preconditions - send 200 w/ ongoing PRACK ", - "NUA sends INVITE, " - "receives 183, sends PRACK, " - "receives 200 to INVITE, " - "receives 200 to PRACK, " - "sends ACK, " - "sends UPDATE, " - "receives 200 to UPDATE."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - SIPTAG_REQUIRE_STR("precondition"), - NUTAG_APPL_METHOD("PRACK"), - TAG_END()); - process_offer(invite); - - sip_rseq_init(rs)->rs_response = ++s2_rseq; - respond_with_sdp( - invite, dialog, SIP_183_SESSION_PROGRESS, - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_RSEQ(rs), - TAG_END()); - fail_unless_event(nua_r_invite, 183); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - sip_rack_init(rack)->ra_response = s2_rseq; - rack->ra_cseq = invite->sip->sip_cseq->cs_seq; - rack->ra_method = invite->sip->sip_cseq->cs_method; - rack->ra_method_name = invite->sip->sip_cseq->cs_method_name; - - nua_prack(nh, SIPTAG_RACK(rack), TAG_END()); - prack = s2_sip_wait_for_request(SIP_METHOD_PRACK); - process_offer(prack); - - s2_sip_respond_to(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - respond_with_sdp( - prack, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless_event(nua_r_prack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - update = s2_sip_wait_for_request(SIP_METHOD_UPDATE); - /* UPDATE sent by stack, stack sends event for it */ - fail_unless(s2_check_callstate(nua_callstate_calling)); - - process_offer(update); - respond_with_sdp( - update, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(update), update = NULL; - - fail_unless_event(nua_r_update, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_5_3) -{ - nua_handle_t *nh; - struct message *invite, *prack, *update; - sip_rseq_t rs[1]; - sip_rack_t rack[1]; - - S2_CASE("2.5.3", "Call with preconditions - send 200 w/ ongoing UPDATE ", - "NUA sends INVITE, " - "receives 183, sends PRACK, receives 200 to PRACK, " - "sends UPDATE, " - "receives 200 to INVITE, " - "receives 200 to UPDATE, " - "sends ACK."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua( - nh, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - SIPTAG_REQUIRE_STR("precondition"), - NUTAG_APPL_METHOD("PRACK"), - TAG_END()); - process_offer(invite); - - sip_rseq_init(rs)->rs_response = ++s2_rseq; - respond_with_sdp( - invite, dialog, SIP_183_SESSION_PROGRESS, - SIPTAG_REQUIRE_STR("100rel"), - SIPTAG_RSEQ(rs), - TAG_END()); - fail_unless_event(nua_r_invite, 183); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - sip_rack_init(rack)->ra_response = s2_rseq; - rack->ra_cseq = invite->sip->sip_cseq->cs_seq; - rack->ra_method = invite->sip->sip_cseq->cs_method; - rack->ra_method_name = invite->sip->sip_cseq->cs_method_name; - - nua_prack(nh, SIPTAG_RACK(rack), TAG_END()); - prack = s2_sip_wait_for_request(SIP_METHOD_PRACK); - process_offer(prack); - respond_with_sdp( - prack, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(prack), prack = NULL; - fail_unless_event(nua_r_prack, 200); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - update = s2_sip_wait_for_request(SIP_METHOD_UPDATE); - /* UPDATE sent by stack, stack sends event for it */ - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - s2_sip_respond_to(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - process_offer(update); - respond_with_sdp( - update, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(update), update = NULL; - - fail_unless_event(nua_r_update, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - bye_to_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *invite_precondition_tcase(int threading) -{ - TCase *tc = tcase_create("2.5 - Call with preconditions"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_2_5_1); - tcase_add_test(tc, call_2_5_2); - tcase_add_test(tc, call_2_5_3); - } - return tc; -} - -/* ====================================================================== */ -/* 2.6 - Re-INVITEs */ - -START_TEST(call_2_6_1) -{ - nua_handle_t *nh; - struct message *invite, *ack; - int i; - - S2_CASE("2.6.1", "Queued re-INVITEs", - "NUA receives INVITE, " - "sends re-INVITE twice, " - "sends BYE."); - - nh = invite_to_nua(TAG_END()); - - nua_invite(nh, TAG_END()); - nua_invite(nh, TAG_END()); - - for (i = 0; i < 2; i++) { - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - process_offer(invite); - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - } - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_6_2) -{ - nua_handle_t *nh; - struct message *invite, *ack, *response; - - S2_CASE("2.6.2", "Re-INVITE glare", - "NUA sends re-INVITE and then receives re-INVITE, " - "sends BYE."); - - nh = invite_to_nua(TAG_END()); - - nua_invite(nh, TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, dialog, SIP_500_INTERNAL_SERVER_ERROR, - SIPTAG_RETRY_AFTER_STR("8"), - TAG_END()); - s2_sip_free_message(invite); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - response = s2_sip_wait_for_response(491, SIP_METHOD_INVITE); - fail_if(!response); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - s2_sip_free_message(response); - fail_if(soa_process_reject(soa, NULL) < 0); - - /* We get nua_r_invite with 100 trying (and 500 in sip->sip_status) */ - fail_unless_event(nua_r_invite, 100); - - s2_nua_fast_forward(10, s2base->root); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_6_3) -{ - nua_handle_t *nh; - struct message *response; - - S2_CASE("2.6.3", "Handling re-INVITE without SDP gracefully", - "NUA receives INVITE, " - "re-INVITE without SDP (w/o NUTAG_REFRESH_WITHOUT_SDP(), " - "re-INVITE without SDP (using NUTAG_REFRESH_WITHOUT_SDP(), " - "sends BYE."); - - nh = invite_to_nua( - TAG_END()); - - s2_sip_request_to(dialog, SIP_METHOD_INVITE, NULL, - SIPTAG_USER_AGENT_STR("evil (evil) evil"), - TAG_END()); - - nua_respond(nh, SIP_200_OK, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - - fail_if(!response); - s2_sip_update_dialog(dialog, response); - fail_if(!response->sip->sip_content_type); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - s2_nua_fast_forward(10, s2base->root); - - nua_set_hparams(nh, NUTAG_REFRESH_WITHOUT_SDP(1), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_sip_request_to(dialog, SIP_METHOD_INVITE, NULL, - SIPTAG_USER_AGENT_STR("evil (evil) evil"), - TAG_END()); - - nua_respond(nh, SIP_200_OK, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - - fail_if(!response); - s2_sip_update_dialog(dialog, response); - fail_if(response->sip->sip_content_type); - s2_sip_free_message(response); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_6_4) -{ - nua_handle_t *nh; - struct message *invite, *ack; - - S2_CASE("2.6.4", "re-INVITEs w/o SDP", - "NUA sends re-INVITE w/o SDP, " - "receives SDP w/ offer, " - "sends ACK w/ answer, " - "sends BYE."); - - /* Bug reported by Liu Yang 2009-01-11 */ - nh = invite_to_nua(TAG_END()); - - nua_invite(nh, SIPTAG_PAYLOAD_STR(""), TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - fail_if(invite->sip->sip_content_type); - soa_generate_offer(soa, 1, NULL); - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - process_answer(ack); - s2_sip_free_message(ack); - - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_2_6_5) -{ - nua_handle_t *nh; - struct event *reinvite; - struct message *invite, *ack, *response; - - /* Test case for FreeSwitch bugs #SFSIP-135, #SFSIP-137 */ - - S2_CASE("2.6.5", "Re-INVITE glare and 500 Retry-After", - "NUA receives re-INVITE, replies with 200, " - "sends re-INVITE, gets 500, gets ACK, retrys INVITE," - "sends BYE."); - - nh = invite_to_nua(TAG_END()); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - reinvite = s2_wait_for_event(nua_i_invite, 200); fail_unless(reinvite != NULL); - fail_unless(s2_check_callstate(nua_callstate_completed)); - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_update_dialog(dialog, response); - process_answer(response); - s2_sip_free_message(response); - - nua_invite(nh, TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_calling)); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, dialog, SIP_500_INTERNAL_SERVER_ERROR, - SIPTAG_RETRY_AFTER_STR("7"), - TAG_END()); - s2_sip_free_message(invite); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - /* We get nua_r_invite with 100 trying (and 500 in sip->sip_status) */ - fail_unless_event(nua_r_invite, 100); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, TAG_END())); - fail_unless_event(nua_i_ack, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - - s2_nua_fast_forward(10, s2base->root); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - process_offer(invite); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *reinvite_tcase(int threading) -{ - TCase *tc = tcase_create("2.6 - re-INVITEs"); - - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_2_6_1); - tcase_add_test(tc, call_2_6_2); - tcase_add_test(tc, call_2_6_3); - tcase_add_test(tc, call_2_6_4); - tcase_add_test(tc, call_2_6_5); - } - return tc; -} - - -/* ====================================================================== */ -/* 3.1 - Call error cases */ - -START_TEST(call_3_1_1) -{ - nua_handle_t *nh; - struct message *invite, *ack; - - S2_CASE("3.1.1", "Call failure", "Call fails with 403 response"); - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, NULL, SIP_403_FORBIDDEN, - SIPTAG_TO_STR("UAS Changed "), - TAG_END()); - s2_sip_free_message(invite); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - fail_if(strcmp(ack->sip->sip_to->a_display, "UAS Changed")); - s2_sip_free_message(ack); - fail_unless_event(nua_r_invite, 403); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_3_1_2) -{ - nua_handle_t *nh; - struct message *invite; - int i; - - S2_CASE("3.1.2", "Call fails after too many retries", - "Call fails after 4 times 500 Retry-After"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - NUTAG_RETRY_COUNT(3), - TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - - for (i = 0;; i++) { - fail_unless(s2_check_callstate(nua_callstate_calling)); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, NULL, SIP_500_INTERNAL_SERVER_ERROR, - SIPTAG_RETRY_AFTER_STR("5"), - TAG_END()); - s2_sip_free_message(invite); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - if (i == 3) - break; - fail_unless_event(nua_r_invite, 100); - s2_nua_fast_forward(5, s2base->root); - } - - fail_unless_event(nua_r_invite, 500); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(call_3_2_1) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("3.2.1", "Re-INVITE failure", "Re-INVITE fails with 403 response"); - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - TAG_END()); - - invite_by_nua(nh, TAG_END()); - - nua_invite(nh, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, NULL, SIP_403_FORBIDDEN, TAG_END()); - s2_sip_free_message(invite); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - fail_unless_event(nua_r_invite, 403); - /* Return to previous state */ - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_by_nua(nh, TAG_END()); -} -END_TEST - - -START_TEST(call_3_2_2) -{ - nua_handle_t *nh; - struct message *invite, *bye; - int i; - - S2_CASE("3.2.2", "Re-INVITE fails after too many retries", - "Call fails after 4 times 500 Retry-After"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - NUTAG_RETRY_COUNT(3), - TAG_END()); - - invite_by_nua(nh, TAG_END()); - - nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - - for (i = 0;; i++) { - fail_unless(s2_check_callstate(nua_callstate_calling)); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, NULL, SIP_500_INTERNAL_SERVER_ERROR, - SIPTAG_RETRY_AFTER_STR("5"), - TAG_END()); - s2_sip_free_message(invite); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - if (i == 3) - break; - fail_unless_event(nua_r_invite, 100); - s2_nua_fast_forward(5, s2base->root); - } - - fail_unless_event(nua_r_invite, 500); - /* Graceful termination */ - fail_unless(s2_check_callstate(nua_callstate_terminating)); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(call_3_2_3) -{ - nua_handle_t *nh; - struct message *invite; - - S2_CASE("3.2.3", "Re-INVITE failure", "Re-INVITE fails with 491 response"); - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), - TAG_END()); - - invite_by_nua(nh, TAG_END()); - - nua_invite(nh, TAG_END()); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, NULL, SIP_491_REQUEST_PENDING, TAG_END()); - s2_sip_free_message(invite); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - fail_unless_event(nua_r_invite, 491); - /* Return to previous state */ - fail_unless(s2_check_callstate(nua_callstate_ready)); - - bye_by_nua(nh, TAG_END()); -} -END_TEST - - -TCase *invite_error_tcase(int threading) -{ - TCase *tc = tcase_create("3 - Call Errors"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, call_3_1_1); - tcase_add_test(tc, call_3_1_2); - tcase_add_test(tc, call_3_2_1); - tcase_add_test(tc, call_3_2_2); - tcase_add_test(tc, call_3_2_3); - tcase_set_timeout(tc, 5); - } - return tc; -} - - -/* ====================================================================== */ -/* Weird call termination cases */ - -START_TEST(bye_4_1_1) -{ - nua_handle_t *nh; - struct message *bye, *r481; - - S2_CASE("4.1.1", "Re-INVITE while terminating", - "NUA sends BYE, " - "BYE is challenged, " - "and NUA is re-INVITEd at the same time."); - - nh = invite_to_nua(TAG_END()); - - s2_flush_events(); - - nua_bye(nh, TAG_END()); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 407); - - soa_generate_offer(soa, 1, NULL); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - do { - r481 = s2_sip_wait_for_response(0, SIP_METHOD_INVITE); - } - while (r481->sip->sip_status->st_status < 200); - - s2_sip_update_dialog(dialog, r481); /* send ACK */ - - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(bye_4_1_2) -{ - nua_handle_t *nh; - struct message *bye, *r481; - - S2_CASE("4.1.2", "Re-INVITE while terminating", - "NUA sends BYE, and gets re-INVITEd at same time"); - - nh = invite_to_nua(TAG_END()); - - s2_flush_events(); - - nua_bye(nh, TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - do { - r481 = s2_sip_wait_for_response(0, SIP_METHOD_INVITE); - } - while (r481->sip->sip_status->st_status < 200); - - s2_sip_update_dialog(dialog, r481); /* send ACK */ - - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - s2_sip_respond_to(bye, dialog, SIP_200_OK, - TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(bye_4_1_3) -{ - nua_handle_t *nh; - struct message *bye; - struct event *i_bye; - - S2_CASE("4.1.3", "BYE while terminating", - "NUA sends BYE and receives BYE"); - - nh = invite_to_nua(TAG_END()); - - mark_point(); - - nua_set_hparams(nh, NUTAG_APPL_METHOD("BYE"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_flush_events(); - - nua_bye(nh, TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 100); - fail_if(!i_bye); - - nua_respond(nh, 200, "OKOK", NUTAG_WITH(i_bye->data->e_msg), TAG_END()); - - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(bye_4_1_4) -{ - nua_handle_t *nh; - struct message *bye; - struct event *i_bye; - - S2_CASE("4.1.4", "Send BYE after BYE has been received", - "NUA receives BYE, tries to send BYE at same time"); - - nh = invite_to_nua(TAG_END()); - - mark_point(); - nua_set_hparams(nh, NUTAG_APPL_METHOD("BYE"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - s2_flush_events(); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 100); - fail_if(!i_bye); - - nua_bye(nh, TAG_END()); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_respond(nh, 200, "OKOK", NUTAG_WITH(i_bye->data->e_msg), TAG_END()); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(bye_4_1_5) -{ - nua_handle_t *nh; - struct message *bye; - struct event *i_bye; - - S2_CASE("4.1.5", "Send BYE after BYE has been received", - "NUA receives BYE, tries to send BYE at same time"); - - nh = invite_to_nua(TAG_END()); - - mark_point(); - nua_set_hparams(nh, NUTAG_APPL_METHOD("BYE"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - s2_flush_events(); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 100); - fail_if(!i_bye); - - nua_bye(nh, TAG_END()); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - - nua_handle_destroy(nh); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); -} -END_TEST - - -START_TEST(bye_4_1_6) -{ - nua_handle_t *nh; - struct message *bye, *r486; - - S2_CASE("4.1.6", "Send BYE after INVITE has been received", - "NUA receives INVITE, sends BYE at same time"); - - nh = invite_to_nua(TAG_END()); - - nua_set_hparams(nh, NUTAG_AUTOANSWER(0), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_flush_events(); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - fail_unless(s2_sip_check_response(100, SIP_METHOD_INVITE)); - nua_bye(nh, TAG_END()); - fail_unless_event(nua_i_invite, 100); - fail_unless(s2_check_callstate(nua_callstate_received)); - - do { - r486 = s2_sip_wait_for_response(0, SIP_METHOD_INVITE); - } - while (r486->sip->sip_status->st_status < 200); - s2_sip_update_dialog(dialog, r486); /* send ACK */ - fail_unless(r486->sip->sip_status->st_status == 486); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(bye_4_1_7) -{ - nua_handle_t *nh; - struct message *bye, *r486; - - S2_CASE("4.1.7", "Send BYE after INVITE has been received", - "NUA receives INVITE, sends BYE at same time"); - - nh = invite_to_nua(TAG_END()); - - nua_set_hparams(nh, NUTAG_AUTOANSWER(0), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_flush_events(); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - fail_unless(s2_sip_check_response(100, SIP_METHOD_INVITE)); - nua_bye(nh, TAG_END()); - fail_unless_event(nua_i_invite, 100); - fail_unless(s2_check_callstate(nua_callstate_received)); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - do { - r486 = s2_sip_wait_for_response(0, SIP_METHOD_INVITE); - } - while (r486->sip->sip_status->st_status < 200); - s2_sip_update_dialog(dialog, r486); /* send ACK */ - fail_unless(r486->sip->sip_status->st_status == 486); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(bye_4_1_8) -{ - nua_handle_t *nh; - struct message *bye, *r486; - - S2_CASE("4.1.8", "BYE followed by response to INVITE", - "NUA receives INVITE, sends BYE at same time"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite_by_nua(nh, NUTAG_AUTOANSWER(0), TAG_END()); - - s2_flush_events(); - - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - fail_unless(s2_sip_check_response(100, SIP_METHOD_INVITE)); - nua_bye(nh, TAG_END()); - fail_unless_event(nua_i_invite, 100); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nua_respond(nh, SIP_486_BUSY_HERE, TAG_END()); - - do { - r486 = s2_sip_wait_for_response(0, SIP_METHOD_INVITE); - } - while (r486->sip->sip_status->st_status < 200); - s2_sip_update_dialog(dialog, r486); /* send ACK */ - fail_unless(r486->sip->sip_status->st_status == 486); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - nua_handle_destroy(nh); -} -END_TEST - - -START_TEST(bye_4_1_9) -{ - nua_handle_t *nh; - struct message *bye; - struct event *i_bye; - - S2_CASE("4.1.6", "Send BYE, receive BYE, destroy", - "NUA sends BYE, receives BYE and handle gets destroyed"); - - nh = invite_to_nua(TAG_END()); - - mark_point(); - - s2_flush_events(); - - nua_bye(nh, TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 200); - fail_if(!i_bye); - s2_free_event(i_bye), i_bye = NULL; - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); - nua_handle_destroy(nh); - mark_point(); - - su_root_step(s2base->root, 10); - su_root_step(s2base->root, 10); - su_root_step(s2base->root, 10); - - mark_point(); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - mark_point(); - while (su_home_check_alloc((su_home_t *)nua, (void *)nh)) { - su_root_step(s2base->root, 10); - } -} -END_TEST - - -START_TEST(bye_4_1_10) -{ - nua_handle_t *nh; - struct message *invite, *bye; - struct event *i_bye; - - S2_CASE("4.1.6", "Send auto-BYE upon receiving 501, receive BYE, destroy", - "NUA sends BYE, receives BYE and handle gets destroyed"); - - nh = invite_to_nua(TAG_END()); - - mark_point(); - - s2_flush_events(); - - nua_invite(nh, TAG_END()); - invite = s2_sip_wait_for_request(SIP_METHOD_INVITE); - fail_if(!invite); - s2_sip_respond_to(invite, dialog, SIP_501_NOT_IMPLEMENTED, TAG_END()); - s2_sip_free_message(invite); - - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - - fail_unless(s2_check_callstate(nua_callstate_calling)); - fail_unless_event(nua_r_invite, 501); - fail_unless(s2_check_callstate(nua_callstate_terminating)); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 200); - fail_if(!i_bye); - s2_free_event(i_bye), i_bye = NULL; - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); - nua_handle_destroy(nh); - - su_root_step(s2base->root, 10); - su_root_step(s2base->root, 10); - su_root_step(s2base->root, 10); - - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - while (su_home_check_alloc((su_home_t *)nua, (void *)nh)) { - su_root_step(s2base->root, 10); - } -} -END_TEST - -START_TEST(bye_4_1_11) -{ - nua_handle_t *nh; - struct message *invite, *ack; - struct event *i_bye; - - S2_CASE("4.1.11", "Receive BYE in completing state", - "NUA sends INVITE, receives 200, receives BYE."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, NUTAG_AUTOACK(0), TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - s2_sip_request_to(dialog, SIP_METHOD_BYE, NULL, TAG_END()); - i_bye = s2_wait_for_event(nua_i_bye, 200); - fail_if(!i_bye); - s2_free_event(i_bye), i_bye = NULL; - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_unless(s2_sip_check_response(200, SIP_METHOD_BYE)); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(bye_4_2_1) -{ - nua_handle_t *nh; - struct message *bye; - - S2_CASE("4.2.1", "BYE in progress while call timer expires", - "NUA receives INVITE, " - "activates call timers, " - "sends BYE, BYE challenged, " - "waits until session expires."); - - nh = invite_to_nua( - SIPTAG_SESSION_EXPIRES_STR("300;refresher=uas"), - SIPTAG_REQUIRE_STR("timer"), - TAG_END()); - - s2_nua_fast_forward(300, s2base->root); - invite_timer_round(nh, "300", NULL); - - nua_bye(nh, TAG_END()); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 407); - - s2_nua_fast_forward(300, s2base->root); - - nua_authenticate(nh, NUTAG_AUTH("Digest:\"s2test\":abc:abc"), TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_if(s2->events); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(bye_4_2_2) -{ - nua_handle_t *nh; - struct message *bye; - - S2_CASE("4.2.2", "BYE in progress while call timer expires", - "NUA receives INVITE, " - "activates call timers, " - "sends BYE, BYE challenged, " - "waits until session expires."); - - nh = invite_to_nua( - SIPTAG_SESSION_EXPIRES_STR("300;refresher=uas"), - SIPTAG_REQUIRE_STR("timer"), - TAG_END()); - - s2_nua_fast_forward(300, s2base->root); - invite_timer_round(nh, "300", NULL); - - s2_nua_fast_forward(140, s2base->root); - - nua_bye(nh, TAG_END()); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_407_PROXY_AUTH_REQUIRED, - SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), - TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 407); - - s2_nua_fast_forward(160, s2base->root); - - nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - fail_unless_event(nua_r_bye, 200); - fail_unless(s2_check_callstate(nua_callstate_terminated)); - fail_if(s2->events); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *termination_tcase(int threading) -{ - TCase *tc = tcase_create("4 - Call Termination"); - add_call_fixtures(tc, threading); - { - tcase_add_test(tc, bye_4_1_1); - tcase_add_test(tc, bye_4_1_2); - tcase_add_test(tc, bye_4_1_3); - tcase_add_test(tc, bye_4_1_4); - tcase_add_test(tc, bye_4_1_5); - tcase_add_test(tc, bye_4_1_6); - tcase_add_test(tc, bye_4_1_7); - tcase_add_test(tc, bye_4_1_8); - tcase_add_test(tc, bye_4_1_9); - tcase_add_test(tc, bye_4_1_10); - tcase_add_test(tc, bye_4_1_11); - tcase_add_test(tc, bye_4_2_1); - tcase_add_test(tc, bye_4_2_2); - tcase_set_timeout(tc, 5); - } - return tc; -} - -/* ====================================================================== */ - -START_TEST(destroy_4_3_1) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("4.3.1", "Destroy handle after INVITE sent", - "NUA sends INVITE, handle gets destroyed."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - - nua_handle_destroy(nh); - - s2_sip_respond_to(invite, dialog, SIP_100_TRYING, TAG_END()); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - s2_sip_free_message(invite); - - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); -} -END_TEST - - -START_TEST(destroy_4_3_2) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("4.3.2", "Destroy handle in calling state", - "NUA sends INVITE, receives 180, handle gets destroyed."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_handle_destroy(nh); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - s2_sip_free_message(invite); - - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); -} -END_TEST - -START_TEST(destroy_4_3_3) -{ - nua_handle_t *nh; - struct message *invite, *ack, *bye; - - S2_CASE("4.3.3", "Destroy handle in completing state", - "NUA sends INVITE, receives 200, handle gets destroyed."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, NUTAG_AUTOACK(0), TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - nua_handle_destroy(nh); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - s2_sip_free_message(invite); -} -END_TEST - - -START_TEST(destroy_4_3_4) -{ - nua_handle_t *nh; - struct message *invite, *ack, *bye; - - S2_CASE("4.3.3", "Destroy handle in ready state ", - "NUA sends INVITE, receives 200, handle gets destroyed."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, NUTAG_AUTOACK(0), TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - nua_ack(nh, TAG_END()); - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - fail_unless(s2_check_callstate(nua_callstate_ready)); - - nua_handle_destroy(nh); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - s2_sip_free_message(invite); -} -END_TEST - - -START_TEST(destroy_4_3_5) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("4.3.5", "Destroy handle in re-INVITE calling state", - "NUA sends re-INVITE, handle gets destroyed."); - - nh = invite_to_nua(TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - - nua_handle_destroy(nh); - - s2_sip_respond_to(invite, dialog, SIP_100_TRYING, TAG_END()); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - s2_sip_free_message(invite); - - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); -} -END_TEST - - -START_TEST(destroy_4_3_6) -{ - nua_handle_t *nh; - struct message *invite, *cancel; - - S2_CASE("4.3.6", "Destroy handle in calling state of re-INVITE", - "NUA sends re-INVITE, receives 180, handle gets destroyed."); - - nh = invite_to_nua(TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_handle_destroy(nh); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(invite, dialog, SIP_487_REQUEST_CANCELLED, TAG_END()); - s2_sip_free_message(invite); - - s2_sip_respond_to(cancel, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(cancel); -} -END_TEST - - -START_TEST(destroy_4_3_7) -{ - nua_handle_t *nh; - struct message *invite, *ack, *bye; - - S2_CASE("4.3.7", "Destroy handle in completing state of re-INVITE", - "NUA sends INVITE, receives 200, handle gets destroyed."); - - nh = invite_to_nua(TAG_END()); - - invite = invite_sent_by_nua(nh, NUTAG_AUTOACK(0), TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_completing)); - - nua_handle_destroy(nh); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - s2_sip_free_message(invite); -} -END_TEST - - -START_TEST(destroy_4_3_8) -{ - nua_handle_t *nh; - struct message *invite, *ack, *bye; - - S2_CASE("4.3.8", "Destroy handle after INVITE sent", - "NUA sends INVITE, handle gets destroyed, " - "but remote end returns 200 OK. " - "Make sure nua tries to release call properly."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - - nua_handle_destroy(nh); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); -} -END_TEST - - -START_TEST(destroy_4_3_9) -{ - nua_handle_t *nh; - struct message *invite, *cancel, *ack, *bye; - - S2_CASE("4.3.9", "Destroy handle in calling state", - "NUA sends INVITE, receives 180, handle gets destroyed, " - "but remote end returns 200 OK. " - "Make sure nua tries to release call properly."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - - invite = invite_sent_by_nua(nh, TAG_END()); - process_offer(invite); - s2_sip_respond_to(invite, dialog, SIP_180_RINGING, TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - nua_handle_destroy(nh); - - cancel = s2_sip_wait_for_request(SIP_METHOD_CANCEL); - fail_if(!cancel); - s2_sip_respond_to(cancel, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - s2_sip_free_message(cancel); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - - ack = s2_sip_wait_for_request(SIP_METHOD_ACK); - fail_if(!ack); - s2_sip_free_message(ack); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); -} -END_TEST - - -START_TEST(destroy_4_4_1) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response; - - S2_CASE("4.4.1", "Destroy handle while call is on-going", - "NUA is callee, sends 100, destroys handle"); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); - - response = s2_sip_wait_for_response(480, SIP_METHOD_INVITE); - fail_if(!response); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - s2_sip_free_message(response); -} -END_TEST - - -START_TEST(destroy_4_4_2) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response; - - S2_CASE("4.4.1", "Destroy handle while call is on-going", - "NUA is callee, sends 180, destroys handle"); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_180_RINGING, TAG_END()); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); - - response = s2_sip_wait_for_response(480, SIP_METHOD_INVITE); - fail_if(!response); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - s2_sip_free_message(response); -} -END_TEST - - -START_TEST(destroy_4_4_3_1) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response, *bye; - - S2_CASE("4.4.3.1", "Destroy handle while call is on-going", - "NUA is callee, sends 200, destroys handle"); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_180_RINGING, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - fail_unless(s2_check_callstate(nua_callstate_early)); - - nua_respond(nh, SIP_200_OK, TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - fail_if(!response); - - nua_handle_destroy(nh); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - s2_sip_free_message(response); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); -} -END_TEST - - -START_TEST(destroy_4_4_3_2) -{ - nua_handle_t *nh; - struct event *invite; - struct message *response, *bye; - - S2_CASE("4.4.3.1", "Destroy handle while call is on-going", - "NUA is callee, sends 200, destroys handle"); - - soa_generate_offer(soa, 1, NULL); - request_with_sdp(dialog, SIP_METHOD_INVITE, NULL, TAG_END()); - - invite = s2_wait_for_event(nua_i_invite, 100); fail_unless(invite != NULL); - fail_unless(s2_check_callstate(nua_callstate_received)); - - nh = invite->nh; fail_if(!nh); - - s2_free_event(invite); - - response = s2_sip_wait_for_response(100, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - nua_respond(nh, SIP_180_RINGING, - SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"), - TAG_END()); - - response = s2_sip_wait_for_response(180, SIP_METHOD_INVITE); - fail_if(!response); - s2_sip_free_message(response); - - fail_unless(s2_check_callstate(nua_callstate_early)); - - nua_respond(nh, SIP_200_OK, TAG_END()); - fail_unless(s2_check_callstate(nua_callstate_completed)); - - response = s2_sip_wait_for_response(200, SIP_METHOD_INVITE); - fail_if(!response); - - nua_handle_destroy(nh); - - bye = s2_sip_wait_for_request(SIP_METHOD_BYE); - fail_if(!bye); - s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(bye); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_ACK, NULL, - SIPTAG_VIA(sip_object(dialog->invite)->sip_via), - TAG_END())); - s2_sip_free_message(response); -} -END_TEST - -static TCase *destroy_tcase(int threading) -{ - TCase *tc = tcase_create("4.3 - Destroying Handle"); - - add_call_fixtures(tc, threading); - - { - tcase_add_test(tc, destroy_4_3_1); - tcase_add_test(tc, destroy_4_3_2); - tcase_add_test(tc, destroy_4_3_3); - tcase_add_test(tc, destroy_4_3_4); - tcase_add_test(tc, destroy_4_3_5); - tcase_add_test(tc, destroy_4_3_6); - tcase_add_test(tc, destroy_4_3_7); - if (XXX) { - tcase_add_test(tc, destroy_4_3_8); - tcase_add_test(tc, destroy_4_3_9); - } - - tcase_add_test(tc, destroy_4_4_1); - tcase_add_test(tc, destroy_4_4_2); - tcase_add_test(tc, destroy_4_4_3_1); - tcase_add_test(tc, destroy_4_4_3_2); - - tcase_set_timeout(tc, 5); - } - return tc; -} - -/* ====================================================================== */ - -static void options_setup(void), options_teardown(void); - -START_TEST(options_5_1_1) -{ - struct event *options; - nua_handle_t *nh; - struct message *response; - - S2_CASE("5.1.1", "Test nua_respond() API", - "Test nua_respond() API with OPTIONS."); - - s2_sip_request_to(dialog, SIP_METHOD_OPTIONS, NULL, TAG_END()); - - options = s2_wait_for_event(nua_i_options, 200); - fail_unless(options != NULL); - nh = options->nh; fail_if(!nh); - - response = s2_sip_wait_for_response(200, SIP_METHOD_OPTIONS); - - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); - - nua_set_params(nua, NUTAG_APPL_METHOD("OPTIONS"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_sip_request_to(dialog, SIP_METHOD_OPTIONS, NULL, TAG_END()); - - options = s2_wait_for_event(nua_i_options, 100); - fail_unless(options != NULL); - nh = options->nh; fail_if(!nh); - - nua_respond(nh, 202, "okok", NUTAG_WITH_SAVED(options->event), TAG_END()); - - response = s2_sip_wait_for_response(202, SIP_METHOD_OPTIONS); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); -} -END_TEST - - -#if HAVE_LIBPTHREAD -#include - -void *respond_to_options(void *arg) -{ - struct event *options = (struct event *)arg; - - nua_respond(options->nh, 202, "ok ok", - NUTAG_WITH_SAVED(options->event), - TAG_END()); - - pthread_exit(arg); - return NULL; -} - -START_TEST(options_5_1_2) -{ - struct event *options; - nua_handle_t *nh; - struct message *response; - pthread_t tid; - void *thread_return = NULL; - - S2_CASE("5.1.2", "Test nua_respond() API with another thread", - "Test multithreading nua_respond() API with OPTIONS."); - - nua_set_params(nua, NUTAG_APPL_METHOD("OPTIONS"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_sip_request_to(dialog, SIP_METHOD_OPTIONS, NULL, TAG_END()); - - options = s2_wait_for_event(nua_i_options, 100); - fail_unless(options != NULL); - nh = options->nh; fail_if(!nh); - - fail_if(pthread_create(&tid, NULL, respond_to_options, (void *)options)); - pthread_join(tid, &thread_return); - fail_unless(thread_return == (void *)options); - - response = s2_sip_wait_for_response(202, SIP_METHOD_OPTIONS); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); -} -END_TEST -#else -START_TEST(options_5_1_2) -{ -} -END_TEST -#endif - -TCase *options_tcase(int threading) -{ - TCase *tc = tcase_create("5 - OPTIONS, etc"); - - tcase_add_checked_fixture(tc, options_setup, options_teardown); - - tcase_add_test(tc, options_5_1_1); - tcase_add_test(tc, options_5_1_2); - - return tc; -} - -static void options_setup(void) -{ - s2_nua_thread = 1; - call_setup(); -} - -static void options_teardown(void) -{ - s2_teardown_started("options"); - call_teardown(); -} - -/* ====================================================================== */ -/* Test cases for REFER */ - -START_TEST(refer_5_2_1) -{ - nua_handle_t *nh; - sip_refer_to_t r[1]; - struct event *refer; - struct message *notify; - - S2_CASE("5.2.1", "Receive REFER", - "Make a call, receive REFER."); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - invite_by_nua(nh, TAG_END()); - - *sip_refer_to_init(r)->r_url = *s2sip->aor->a_url; - r->r_url->url_user = "bob2"; - - s2_sip_request_to(dialog, SIP_METHOD_REFER, NULL, - SIPTAG_REFER_TO(r), - TAG_END()); - refer = s2_wait_for_event(nua_i_refer, 202); - - bye_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); - - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); -} -END_TEST - - -START_TEST(refer_5_2_2) -{ - nua_handle_t *nh, *nh2; - sip_refer_to_t r[1]; - sip_referred_by_t by[1]; - struct event *refer, *notified; - sip_t const *sip; - sip_event_t const *refer_event = NULL; - sip_subscription_state_t const *ss; - struct message *invite; - struct message *notify0, *notify1, *notify2; - struct dialog *dialog1, *dialog2; - - S2_CASE("5.2.2", "Receive REFER", - "Make a call, receive REFER, " - "make another call with automatic NOTIFYs"); - - dialog2 = su_home_new(sizeof *dialog2); fail_unless(dialog2 != NULL); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - invite_by_nua(nh, TAG_END()); - - *sip_refer_to_init(r)->r_url = *s2sip->aor->a_url; - r->r_url->url_user = "bob2"; - - s2_sip_request_to(dialog, SIP_METHOD_REFER, NULL, - SIPTAG_REFER_TO(r), - TAG_END()); - refer = s2_wait_for_event(nua_i_refer, 202); - sip = sip_object(refer->data->e_msg); - fail_unless(sip && sip->sip_refer_to); - - bye_by_nua(nh, TAG_END()); - - dialog1 = dialog, dialog = dialog2; - - *sip_referred_by_init(by)->b_url = - *sip->sip_from->a_url; - - fail_unless(tl_gets(refer->data->e_tags, - NUTAG_REFER_EVENT_REF(refer_event), - TAG_END()) == 1); - - nua_notify(nh, - SIPTAG_EVENT(refer_event), - SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"), - NUTAG_SUBSTATE(nua_substate_active), - TAG_END()); - notify0 = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless((ss = notify0->sip->sip_subscription_state) != NULL); - fail_unless(su_casematch("active", ss->ss_substate)); - s2_sip_respond_to(notify0, dialog1, SIP_200_OK, TAG_END()); - notified = s2_wait_for_event(nua_r_notify, 200); - - nh2 = nua_handle(nua, NULL, NUTAG_URL(r->r_url), TAG_END()); - - invite = invite_sent_by_nua(nh2, - NUTAG_REFER_EVENT(refer_event), - NUTAG_NOTIFY_REFER(nh), - SIPTAG_REFERRED_BY(by), - TAG_END()); - process_offer(invite); - - respond_with_sdp( - invite, dialog, SIP_180_RINGING, - SIPTAG_CONTENT_DISPOSITION_STR("session;handling=optional"), - TAG_END()); - fail_unless_event(nua_r_invite, 180); - fail_unless(s2_check_callstate(nua_callstate_proceeding)); - - notify1 = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - s2_sip_respond_to(notify1, dialog1, SIP_200_OK, TAG_END()); - - respond_with_sdp(invite, dialog, SIP_200_OK, TAG_END()); - s2_sip_free_message(invite); - fail_unless_event(nua_r_invite, 200); - fail_unless(s2_check_callstate(nua_callstate_ready)); - fail_unless(s2_sip_check_request(SIP_METHOD_ACK)); - - notify2 = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - s2_sip_respond_to(notify2, dialog1, SIP_200_OK, TAG_END()); - fail_unless((ss = notify2->sip->sip_subscription_state) != NULL); - fail_unless(su_casematch("terminated", ss->ss_substate)); - - nua_handle_destroy(nh); - bye_by_nua(nh2, TAG_END()); - nua_handle_destroy(nh2); -} -END_TEST - -TCase *refer_tcase(int threading) -{ - TCase *tc = tcase_create("5.2 - Call Transfer"); - - add_call_fixtures(tc, threading); - - tcase_add_test(tc, refer_5_2_1); - tcase_add_test(tc, refer_5_2_2); - - return tc; -} - -/* ====================================================================== */ - -/* Test case template */ - -START_TEST(empty) -{ - S2_CASE("0.0.0", "Empty test case", - "Detailed explanation for empty test case."); - - tport_set_params(s2sip->master, TPTAG_LOG(1), TAG_END()); - s2_setup_logs(7); - s2_setup_logs(0); - tport_set_params(s2sip->master, TPTAG_LOG(0), TAG_END()); -} -END_TEST - -TCase *empty_tcase(int threading) -{ - TCase *tc = tcase_create("0 - Empty"); - - add_call_fixtures(tc, threading); - - tcase_add_test(tc, empty); - - return tc; -} - -/* ====================================================================== */ - -void check_session_cases(Suite *suite, int threading) -{ - suite_add_tcase(suite, invite_tcase(threading)); - suite_add_tcase(suite, cancel_tcase(threading)); - suite_add_tcase(suite, session_timer_tcase(threading)); - suite_add_tcase(suite, invite_100rel_tcase(threading)); - suite_add_tcase(suite, invite_precondition_tcase(threading)); - suite_add_tcase(suite, reinvite_tcase(threading)); - suite_add_tcase(suite, invite_error_tcase(threading)); - suite_add_tcase(suite, termination_tcase(threading)); - suite_add_tcase(suite, destroy_tcase(threading)); - suite_add_tcase(suite, options_tcase(threading)); - suite_add_tcase(suite, refer_tcase(threading)); - - if (0) /* Template */ - suite_add_tcase(suite, empty_tcase(threading)); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c deleted file mode 100644 index 66b497a2c1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_simple.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_events.c - * - * @brief NUA module tests for SIP events - * - * @author Pekka Pessi - * - * @copyright (C) 2008 Nokia Corporation. - */ - -#include "config.h" - -#undef NDEBUG - -#include "check_nua.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* define XXX as 1 in order to see all failing test cases */ -#ifndef XXX -#define XXX (0) -#endif - -/* ====================================================================== */ - -static nua_t *nua; -static struct dialog *dialog = NULL; - -#define CRLF "\r\n" - -void s2_dialog_setup(void) -{ - nua = s2_nua_setup("simple", - SIPTAG_ORGANIZATION_STR("Pussy Galore's Flying Circus"), - NUTAG_OUTBOUND("no-options-keepalive, no-validate"), - TAG_END()); - - dialog = su_home_new(sizeof *dialog); fail_if(!dialog); - - s2_register_setup(); -} - -void s2_dialog_teardown(void) -{ - s2_teardown_started("simple"); - - s2_register_teardown(); - - nua_shutdown(nua); - - fail_unless_event(nua_r_shutdown, 200); - - s2_nua_teardown(); -} - -static void simple_thread_setup(void) -{ - s2_nua_thread = 1; - s2_dialog_setup(); -} - -static void simple_threadless_setup(void) -{ - s2_nua_thread = 0; - s2_dialog_setup(); -} - -static void simple_teardown(void) -{ - s2_dialog_teardown(); -} - -static char const presence_open[] = - "\n" - "\n" - " \n" - " open\n" - " sip:bob@example.org\n" - " \n" - "\n"; - -static char const presence_closed[] = - "\n" - "\n" - " \n" - " closed\n" - " \n" - "\n"; - -static char const *event_type = "presence"; -static char const *event_mime_type = "application/pidf+xml"; -static char const *event_state = presence_open; -static char const *subscription_state = "active;expires=600"; - -static struct event * -respond_to_subscribe(struct message *subscribe, - nua_event_t expect_event, - enum nua_substate expect_substate, - int status, char const *phrase, - tag_type_t tag, tag_value_t value, ...) -{ - struct event *event; - ta_list ta; - - ta_start(ta, tag, value); - s2_sip_respond_to(subscribe, dialog, status, phrase, - ta_tags(ta)); - ta_end(ta); - - event = s2_wait_for_event(expect_event, status); fail_if(!event); - fail_unless(s2_check_substate(event, expect_substate)); - return event; -} - -static struct event * -notify_to_nua(enum nua_substate expect_substate, - tag_type_t tag, tag_value_t value, ...) -{ - struct event *event; - struct message *response; - ta_list ta; - - ta_start(ta, tag, value); - fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL, - SIPTAG_CONTENT_TYPE_STR(event_mime_type), - SIPTAG_PAYLOAD_STR(event_state), - ta_tags(ta))); - ta_end(ta); - - response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY); - fail_if(!response); - s2_sip_free_message(response); - - event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event); - fail_unless(s2_check_substate(event, expect_substate)); - - return event; -} - -static int send_notify_before_response = 0; - -static struct event * -subscription_by_nua(nua_handle_t *nh, - enum nua_substate current, - tag_type_t tag, tag_value_t value, ...) -{ - struct message *subscribe; - struct event *notify, *event; - ta_list ta; - enum nua_substate substate = nua_substate_active; - char const *substate_str = subscription_state; - char const *expires = "600"; - - subscribe = s2_sip_wait_for_request(SIP_METHOD_SUBSCRIBE); - if (event_type) - fail_if(!subscribe->sip->sip_event || - strcmp(event_type, subscribe->sip->sip_event->o_type)); - - if (subscribe->sip->sip_expires && subscribe->sip->sip_expires->ex_delta == 0) { - substate = nua_substate_terminated; - substate_str = "terminated;reason=timeout"; - expires = "0"; - } - - ta_start(ta, tag, value); - - if (send_notify_before_response) { - s2_sip_save_uas_dialog(dialog, subscribe->sip); - notify = notify_to_nua(substate, - SIPTAG_EVENT(subscribe->sip->sip_event), - SIPTAG_SUBSCRIPTION_STATE_STR(substate_str), - ta_tags(ta)); - event = respond_to_subscribe(subscribe, nua_r_subscribe, substate, - SIP_200_OK, - SIPTAG_EXPIRES_STR(expires), - TAG_END()); - s2_free_event(event); - } - else { - event = respond_to_subscribe(subscribe, nua_r_subscribe, current, - SIP_202_ACCEPTED, - SIPTAG_EXPIRES_STR(expires), - TAG_END()); - s2_free_event(event); - notify = notify_to_nua(substate, - SIPTAG_EVENT(subscribe->sip->sip_event), - SIPTAG_SUBSCRIPTION_STATE_STR(substate_str), - ta_tags(ta)); - } - - s2_sip_free_message(subscribe); - - return notify; -} - -static void -unsubscribe_by_nua(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...) -{ - struct message *subscribe, *response; - struct event *event; - - nua_unsubscribe(nh, TAG_END()); - subscribe = s2_sip_wait_for_request(SIP_METHOD_SUBSCRIBE); - - s2_sip_respond_to(subscribe, dialog, SIP_200_OK, SIPTAG_EXPIRES_STR("0"), TAG_END()); - - event = s2_wait_for_event(nua_r_unsubscribe, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_active)); - s2_free_event(event); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL, - SIPTAG_EVENT(subscribe->sip->sip_event), - SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=tiemout"), - SIPTAG_CONTENT_TYPE_STR(event_mime_type), - SIPTAG_PAYLOAD_STR(event_state), - TAG_END())); - - event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_terminated)); - s2_free_event(event); - - response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY); - fail_if(!response); - s2_sip_free_message(response); s2_sip_free_message(subscribe); -} - -/* ====================================================================== */ -/* 6 - Subscribe/notify */ - -START_TEST(subscribe_6_1_1) -{ - nua_handle_t *nh; - struct event *notify; - S2_CASE("6.1.1", "Basic subscription", - "NUA sends SUBSCRIBE, waits for NOTIFY, sends un-SUBSCRIBE"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_free_event(notify); - unsubscribe_by_nua(nh, TAG_END()); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(subscribe_6_1_2) -{ - nua_handle_t *nh; - struct message *subscribe, *response; - struct event *notify, *event; - - S2_CASE("6.1.2", "Basic subscription with refresh", - "NUA sends SUBSCRIBE, waits for NOTIFY, " - "sends re-SUBSCRIBE, waits for NOTIFY, " - "sends un-SUBSCRIBE"); - - send_notify_before_response = 1; - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_free_event(notify); - - /* Wait for refresh */ - s2_nua_fast_forward(600, s2base->root); - subscribe = s2_sip_wait_for_request(SIP_METHOD_SUBSCRIBE); - s2_sip_respond_to(subscribe, dialog, SIP_200_OK, - SIPTAG_EXPIRES_STR("600"), - TAG_END()); - - event = s2_wait_for_event(nua_r_subscribe, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_active)); - s2_free_event(event); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL, - SIPTAG_EVENT(subscribe->sip->sip_event), - SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=600"), - SIPTAG_CONTENT_TYPE_STR(event_mime_type), - SIPTAG_PAYLOAD_STR(event_state), - TAG_END())); - event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_active)); - s2_free_event(event); - response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY); - fail_if(!response); - s2_sip_free_message(response); - - unsubscribe_by_nua(nh, TAG_END()); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(subscribe_6_1_3) -{ - nua_handle_t *nh; - struct message *response; - struct event *notify, *event; - - S2_CASE("6.1.3", "Subscription terminated by notifier", - "NUA sends SUBSCRIBE, waits for NOTIFY, " - "gets NOTIFY terminating the subscription,"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_free_event(notify); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL, - SIPTAG_EVENT_STR(event_type), - SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - TAG_END())); - event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_terminated)); - s2_free_event(event); - response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY); - fail_if(!response); - s2_sip_free_message(response); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(subscribe_6_1_4) -{ - nua_handle_t *nh; - struct message *response; - struct event *notify, *event; - - S2_CASE("6.1.4", "Subscription terminated by notifier, re-established", - "NUA sends SUBSCRIBE, waits for NOTIFY, " - "gets NOTIFY terminating the subscription,"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_free_event(notify); - - fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL, - SIPTAG_EVENT_STR(event_type), - SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=deactivated"), - TAG_END())); - event = s2_wait_for_event(nua_i_notify, 200); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_embryonic)); - s2_free_event(event); - response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY); - fail_if(!response); - s2_sip_free_message(response); - - su_home_unref((void *)dialog), dialog = su_home_new(sizeof *dialog); fail_if(!dialog); - - s2_nua_fast_forward(5, s2base->root); - /* nua re-establishes the subscription */ - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_free_event(notify); - - /* Unsubscribe with nua_subscribe() Expires: 0 */ - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_active, TAG_END()); - s2_free_event(notify); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *subscribe_tcase(int threading) -{ - TCase *tc = tcase_create("6.1 - Basic SUBSCRIBE_"); - void (*simple_setup)(void); - - simple_setup = threading ? simple_thread_setup : simple_threadless_setup; - tcase_add_checked_fixture(tc, simple_setup, simple_teardown); - - { - tcase_add_test(tc, subscribe_6_1_1); - tcase_add_test(tc, subscribe_6_1_2); - tcase_add_test(tc, subscribe_6_1_3); - tcase_add_test(tc, subscribe_6_1_4); - } - return tc; -} - -START_TEST(fetch_6_2_1) -{ - nua_handle_t *nh; - struct event *notify; - - S2_CASE("6.2.1", "Event fetch - NOTIFY after 202", - "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_check_substate(notify, nua_substate_terminated); - s2_free_event(notify); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(fetch_6_2_2) -{ - nua_handle_t *nh; - struct event *notify; - - S2_CASE("6.2.2", "Event fetch - NOTIFY before 200", - "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY"); - - send_notify_before_response = 1; - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END()); - notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END()); - s2_check_substate(notify, nua_substate_terminated); - s2_free_event(notify); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(fetch_6_2_3) -{ - nua_handle_t *nh; - struct message *subscribe; - struct event *event; - - S2_CASE("6.2.3", "Event fetch - no NOTIFY", - "NUA sends SUBSCRIBE with Expires 0, waits for NOTIFY, times out"); - - nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); - nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END()); - subscribe = s2_sip_wait_for_request(SIP_METHOD_SUBSCRIBE); - s2_sip_respond_to(subscribe, dialog, SIP_202_ACCEPTED, - SIPTAG_EXPIRES_STR("0"), TAG_END()); - s2_sip_free_message(subscribe); - - event = s2_wait_for_event(nua_r_subscribe, 202); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_embryonic)); - s2_free_event(event); - - s2_nua_fast_forward(600, s2base->root); - - event = s2_wait_for_event(nua_i_notify, 408); fail_if(!event); - fail_unless(s2_check_substate(event, nua_substate_terminated)); - s2_free_event(event); - - nua_handle_destroy(nh); -} -END_TEST - - -TCase *fetch_tcase(int threading) -{ - TCase *tc = tcase_create("6.2 - Event fetch"); - void (*simple_setup)(void); - - simple_setup = threading ? simple_thread_setup : simple_threadless_setup; - tcase_add_checked_fixture(tc, simple_setup, simple_teardown); - - { - tcase_add_test(tc, fetch_6_2_1); - tcase_add_test(tc, fetch_6_2_2); - tcase_add_test(tc, fetch_6_2_3); - } - return tc; -} - -nua_handle_t * -subscribe_to_nua(char const *event, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - struct event *subscribe; - struct message *response; - nua_handle_t *nh; - - nua_set_params(nua, NUTAG_APPL_METHOD("SUBSCRIBE"), - SIPTAG_ALLOW_EVENTS_STR(event), - TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - ta_start(ta, tag, value); - s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, - SIPTAG_EVENT_STR(event), - ta_tags(ta)); - ta_end(ta); - - subscribe = s2_wait_for_event(nua_i_subscribe, 100); - nh = subscribe->nh; - nua_respond(nh, SIP_202_ACCEPTED, - NUTAG_WITH_SAVED(subscribe->event), - TAG_END()); - s2_free_event(subscribe); - - response = s2_sip_wait_for_response(202, SIP_METHOD_SUBSCRIBE); - s2_sip_update_dialog(dialog, response); - fail_unless(response->sip->sip_expires != NULL); - s2_sip_free_message(response); - - return nh; -} - -START_TEST(notify_6_3_1) -{ - nua_handle_t *nh; - struct event *subscribe; - struct message *notify, *response; - sip_t *sip; - - S2_CASE("6.3.1", "Basic NOTIFY server", - "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " - "First NOTIFY terminates subscription. "); - - s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, - SIPTAG_EVENT_STR("presence"), - TAG_END()); - /* 489 Bad Event by default */ - s2_sip_check_response(489, SIP_METHOD_SUBSCRIBE); - - nua_set_params(nua, NUTAG_APPL_METHOD("SUBSCRIBE"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, - SIPTAG_EVENT_STR("presence"), - TAG_END()); - s2_sip_check_response(489, SIP_METHOD_SUBSCRIBE); - - nua_set_params(nua, SIPTAG_ALLOW_EVENTS_STR("presence"), TAG_END()); - fail_unless_event(nua_r_set_params, 200); - - s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, - SIPTAG_EVENT_STR("presence"), - TAG_END()); - subscribe = s2_wait_for_event(nua_i_subscribe, 100); - nh = subscribe->nh; - nua_respond(nh, SIP_403_FORBIDDEN, - NUTAG_WITH_SAVED(subscribe->event), - TAG_END()); - s2_free_event(subscribe); - - s2_sip_check_response(403, SIP_METHOD_SUBSCRIBE); - - nua_handle_destroy(nh); - - s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, - SIPTAG_EVENT_STR("presence"), - TAG_END()); - subscribe = s2_wait_for_event(nua_i_subscribe, 100); - nh = subscribe->nh; - nua_respond(nh, SIP_202_ACCEPTED, - NUTAG_WITH_SAVED(subscribe->event), - TAG_END()); - s2_free_event(subscribe); - - response = s2_sip_wait_for_response(202, SIP_METHOD_SUBSCRIBE); - s2_sip_update_dialog(dialog, response); - fail_unless(response->sip->sip_expires != NULL); - s2_sip_free_message(response); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "terminated")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - - fail_unless_event(nua_r_notify, 200); - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(notify_6_3_2) -{ - nua_handle_t *nh; - struct message *notify; - sip_t *sip; - - S2_CASE("6.3.2", "NOTIFY server - automatic subscription termination", - "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " - "The subscription terminates with timeout. "); - - nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_notify, 200); - - s2_nua_fast_forward(300, s2base->root); - - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "terminated")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_notify, 200); - - nua_handle_destroy(nh); -} -END_TEST - -static int -s2_event_substate(struct event *event) -{ - if (event) { - tagi_t const *t = tl_find(event->data->e_tags, nutag_substate); - if (t) - return t->t_value; - } - return -1; -} - -START_TEST(notify_6_3_3) -{ - nua_handle_t *nh; - struct message *notify; - struct event *response; - sip_t *sip; - - S2_CASE("6.3.3", "NOTIFY server - terminate with error response to NOTIFY", - "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " - "The subscription terminates when watcher " - "returns 481 to second NOTIFY."); - - nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_notify, 200); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - response = s2_wait_for_event(nua_r_notify, 481); - fail_unless(s2_event_substate(response) == nua_substate_terminated); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(notify_6_3_4) -{ - nua_handle_t *nh; - struct message *notify; - struct event *response; - sip_t *sip; - - S2_CASE("6.3.4", "NOTIFY server - terminate with error response to NOTIFY", - "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " - "The subscription terminates when watcher " - "returns 481 to second NOTIFY. The queued 3rd NOTIFY gets " - "responded by stack."); - - nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_notify, 200); - - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_open), - TAG_END()); - nua_notify(nh, - NUTAG_SUBSTATE(nua_substate_active), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - response = s2_wait_for_event(nua_r_notify, 481); - fail_unless(s2_event_substate(response) == nua_substate_terminated); - response = s2_wait_for_event(nua_r_notify, 481); - fail_unless(s2_event_substate(response) == nua_substate_terminated); - - nua_handle_destroy(nh); -} -END_TEST - -START_TEST(notify_6_3_5) -{ - nua_handle_t *nh; - struct message *notify; - struct event *response; - sip_t *sip; - - S2_CASE("6.3.4", "NOTIFY server - terminate with error response to NOTIFY", - "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " - "The subscription terminates when watcher " - "returns 481 to NOTIFY."); - - nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); - - nua_notify(nh, - SIPTAG_SUBSCRIPTION_STATE_STR("active"), - SIPTAG_PAYLOAD_STR(presence_closed), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); - fail_unless_event(nua_r_notify, 200); - - nua_notify(nh, - SIPTAG_SUBSCRIPTION_STATE_STR("active"), - SIPTAG_PAYLOAD_STR(presence_open), - TAG_END()); - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - fail_unless(notify != NULL); - sip = notify->sip; - fail_unless(sip->sip_subscription_state != NULL); - fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, - "active")); - - nua_notify(nh, - NUTAG_NEWSUB(1), - SIPTAG_SUBSCRIPTION_STATE_STR("active"), - SIPTAG_PAYLOAD_STR(presence_open), - TAG_END()); - - s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - response = s2_wait_for_event(nua_r_notify, 481); - fail_unless(s2_event_substate(response) == nua_substate_terminated); - - notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); - s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); - response = s2_wait_for_event(nua_r_notify, 481); - fail_unless(s2_event_substate(response) == nua_substate_terminated); - - nua_handle_destroy(nh); -} -END_TEST - -TCase *notifier_tcase(int threading) -{ - TCase *tc = tcase_create("6.3 - Basic event server with NOTIFY "); - void (*simple_setup)(void); - - simple_setup = threading ? simple_thread_setup : simple_threadless_setup; - tcase_add_checked_fixture(tc, simple_setup, simple_teardown); - - { - tcase_add_test(tc, notify_6_3_1); - tcase_add_test(tc, notify_6_3_2); - tcase_add_test(tc, notify_6_3_3); - tcase_add_test(tc, notify_6_3_4); - tcase_add_test(tc, notify_6_3_5); - } - return tc; -} - -/* ====================================================================== */ - -/* Test case template */ - -START_TEST(empty) -{ - S2_CASE("0.0.0", "Empty test case", - "Detailed explanation for empty test case."); - - tport_set_params(s2sip->master, TPTAG_LOG(1), TAG_END()); - s2_setup_logs(7); - s2_setup_logs(0); - tport_set_params(s2sip->master, TPTAG_LOG(0), TAG_END()); -} - -END_TEST - -static TCase *empty_tcase(int threading) -{ - TCase *tc = tcase_create("0 - Empty"); - void (*simple_setup)(void); - - simple_setup = threading ? simple_thread_setup : simple_threadless_setup; - tcase_add_checked_fixture(tc, simple_setup, simple_teardown); - - tcase_add_test(tc, empty); - - return tc; -} - -/* ====================================================================== */ - -void check_simple_cases(Suite *suite, int threading) -{ - suite_add_tcase(suite, subscribe_tcase(threading)); - suite_add_tcase(suite, fetch_tcase(threading)); - suite_add_tcase(suite, notifier_tcase(threading)); - - if (0) /* Template */ - suite_add_tcase(suite, empty_tcase(threading)); -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua.c deleted file mode 100644 index fdeac3cad9..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file nua.c High-Level User Agent Library - "nua" Implementation. - * - * @author Pekka Pessi - * @author Kai Vehmanen - * @author Pasi Rinne-Rahkola - * - * @date Created: Wed Feb 14 18:32:58 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include - -#define SU_LOG (nua_log) -#include - -#define SU_ROOT_MAGIC_T struct nua_s - -#include -#include -#include - -#include "sofia-sip/nua.h" -#include "sofia-sip/nua_tag.h" -#include "nua_stack.h" - -#include -#include -#include -#include -#include - -/* 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 , 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 - * @retval NULL upon an error - * - * @par Related tags: - * - NUTAG_PROXY(), giving the URI of the outbound proxy - * (but see also NUTAG_INITIAL_ROUTE()). - * - NUTAG_URL() (and NUTAG_SIPS_URL(), listing URIs describing - * transports) - * - NUTAG_CERTIFICATE_DIR(), specifying the location of the - * root and client/server certificate files - * - NUTAG_SIP_PARSER(), providing customized parser used to - * parse received SIP messages - * - All parameter tags, listed with nua_set_params() - * - All NTATAG_* are passed to NTA documented in : - * see NTATAG_EXTRA_100(), - * - All tport tags are passed to tport. - * They are documented in - * - All SOATAG_* are passed to the default SOA (media session) object which - * is created by nua_create() unless NUTAG_MEDIA_ENABLE(0) is included in - * the tag list - * - STUN tags STUNTAG_DOMAIN(), STUNTAG_SERVER(). - * STUN is deprecated, however. - * - * @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(), nta_agent_create(). - */ -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, 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", - (void *)nua)); - assert(nua->nua_shutdown); - return; - } - - nua->nua_callback = NULL; - - 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 */ - nua_unref(nua); - } -} - -void nua_unref(nua_t *nua) { - if (nua) 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, 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, 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, event, 0, NULL, ta_tags(ta)); \ - ta_end(ta); \ - } \ - else { \ - SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", (void *)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, nua_r_respond, - status, phrase, ta_tags(ta)); - ta_end(ta); - } - else { - SU_DEBUG_1(("nua: respond with invalid handle %p\n", (void *)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, nua_r_destroy, 0, NULL, TAG_END()); - } -} - -/* ---------------------------------------------------------------------- */ - -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. - * - * A @Replaces header contains the @CallID value, @From and @To tags - * corresponding to SIP dialog associated with handle @a nh. Note that the - * @Replaces matches with dialog of the remote peer, - * nua_handle_by_replaces() does not return same handle (unless you swap - * rp_from_tag and rp_to_tag in @Replaces header). - * - * A @Replaces header is used in attended transfer, among other things. - * - * @param nh pointer to operation handle - * @param home memory home used to allocate the header - * @param early_only if true, include "early-only" parameter in @Replaces, too - * - * @return A newly created @Replaces header. - * - * @since New in @VERSION_1_12_4. - * - * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, @RFC3515, nua_refer(), - * #nua_i_refer(), @ReferTo, nta_leg_make_replaces(), - * sip_headers_as_url_query() - */ -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) { -#if HAVE_OPEN_C - struct nua_stack_handle_make_replaces_args a = { NULL, NULL, NULL, 0 }; - a.nh = nh; - a.home = home; - a.early_only = early_only; -#else - struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only }; -#endif - - 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; -} - -struct nua_stack_handle_by_call_id_args { - nua_handle_t *retval; - nua_t *nua; - const char *call_id; -}; - -static int nua_stack_handle_by_call_id_call(void *arg) -{ - struct nua_stack_handle_by_call_id_args *a = arg; - - a->retval = nua_stack_handle_by_call_id(a->nua, a->call_id); - - 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 the 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) { -#if HAVE_OPEN_C - struct nua_stack_handle_by_replaces_args a; - a.retval = NULL; - a.nua = nua; - a.r = r; -#else - struct nua_stack_handle_by_replaces_args a = { NULL, nua, r }; -#endif - - 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; -} - -/** Obtain a new reference to an existing handle based on @CallID. - * - * @since New in @VERSION_1_12_9. - * - * @note - * You should release the reference with nua_handle_unref() when you are - * done with the handle. - * - * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(), - * #nua_i_refer, @ReferTo, nta_leg_by_replaces() - */ -nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id) -{ - if (nua) { -#if HAVE_OPEN_C - struct nua_stack_handle_by_call_id_args a; - a.retval = NULL; - a.nua = nua; - a.call_id = call_id; -#else - struct nua_stack_handle_by_call_id_args a = { NULL, nua, call_id }; -#endif - - if (su_task_execute(nua->nua_server, - nua_stack_handle_by_call_id_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; -} - -/** Get leg from dialog. */ -const nta_leg_t *nua_get_dialog_state_leg(nua_handle_t *nh) -{ - if (nh && nh->nh_ds) - return nh->nh_ds->ds_leg; - else - return NULL; -} - -/** Get su_home_t from nua handle. */ -su_home_t *nua_handle_get_home(nua_handle_t *nh) -{ - if (nh && nh->nh_home) - return nh->nh_home; - else - return NULL; -} - -/** Get su_home_t from nua. */ -su_home_t *nua_get_home(nua_t *nua) -{ - if (nua && nua->nua_home) - return nua->nua_home; - else - return NULL; -} - -/** Get nta_agent_t from nua. */ -nta_agent_t *nua_get_agent(nua_t *nua) -{ - if (nua && nua->nua_nta) - return nua->nua_nta; - else - return NULL; -} - -/** Set has invite of a nua handle */ -void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val) -{ - if (nh) - nh->nh_has_invite = val; -} - -/** Check if nua handle is destroyed */ -unsigned nua_handle_is_destroyed(nua_handle_t *nh) -{ - assert(nh); - return nh->nh_destroyed; -} - -void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh, - unsigned min, unsigned max) { - if (nh && nh->nh_ds && nh->nh_ds->ds_usage) { - nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, min, max); - } -} \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs b/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs deleted file mode 100644 index d633c9d57e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua.docs +++ /dev/null @@ -1,2285 +0,0 @@ -/* -*- text -*- */ - -/**@MODULEPAGE "nua" - High-Level User Agent Module - -@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. - -@CONTACT Pekka Pessi - -@STATUS @SofiaSIP Core library - -@LICENSE LGPL - -@par Contributor(s): -- Pekka Pessi -- Pasi Rinne-Rahkola -- Kai Vehmanen -- Martti Mela - -@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 -nta module. -With NUA it is possible to create different kind of SIP 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. The protocol engine communicates with the application -using @ref nua_event_e "events", delivered to the application with a a -callback function. The callback function is called within the thread context -of the application, represented with a #su_root_t object. - -@section nua_concepts_user Sofia Concepts for NUA User - -@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 (su) 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 [su] for more detailed -description of the SU services. - -@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 @ref nua_event_e "NUA 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 and for more information -of root object. - -See section #nua_event_e for more information of the callback function. - -@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. - -@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 for more information of memory -management services. - -@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: - -@code -tag_type_t tag, -tag_value_t value, -...); -@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_ \n -which takes a value parameter and \n -NUTAG__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__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: -@code -nua_unregister(op->op_handle, - TAG_IF(use_registrar, NUTAG_REGISTRAR(registrar)), - SIPTAG_CONTACT_STR("*"), - SIPTAG_EXPIRES_STR("0"), - TAG_NULL()); -@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 for more information of tags and the -module-specific documentation of each Sofia module for information of -tags specific for that module. - -@subsection nua_debugandlogging Debugging and Logging - -The modules of Sofia stack contain configurable debugging and logging -functionality based on the services defined in . 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 for more information of debugging and -logging services. - -@section nua_concepts NUA Concepts - -@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. - -@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. - -@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. - -@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_() takes a parsed value as parameter. -- SIPTAG__STR() takes an unparsed string as parameter. -- SIPTAG__REF() takes a reference as parameter, is used - with tl_gets() function to retrieve tag values from tag list. -- SIPTAG___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: - -@code - nua_subscribe(nh, - SIPTAG_EVENT_STR("presence"), - SIPTAG_ACCEPT(accept1), - SIPTAG_ACCEPT(accept2), - TAG_END()); -@endcode - -- fetching tag values when processing nua_r_subscribe event: - -@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()); -@endcode - -@section nua_tutorial SIP/NUA tutorial - -This section describes basic usage scenarios of NUA/Sofia stack using -message sequence charts. - -@subsection nua_outgoingcall Outgoing Call - -@image latex SIP_outgoing_call.eps - -@image html SIP_outgoing_call.gif - - -@subsection nua_incomingcall Incoming Call - -@image latex SIP_incoming_call.eps - -@image html SIP_incoming_call.gif - -@subsection nua_basicoutgoingoperation Basic Outgoing Operation - -@image latex SIP_basic_outgoing_operation.eps - -@image html SIP_basic_outgoing_operation.gif - - -@subsection nua_basicincomingoperation Basic Incoming Operation - -@image latex SIP_basic_incoming_operation.eps - -@image html SIP_basic_incoming_operation.gif - - -@subsection nua_outgoingoperationwithauth Outgoing Operation with Authentication - -@image latex SIP_outgoing_operation_with_auth.eps - -@image html SIP_outgoing_operation_with_auth.gif - -@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. - -On sourceforge.net there is available an example application - -sofisip_cli.c that can be studied for more complete example. - -@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. - -@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 -@endcode - -The information area contents themselves can be defined as -C structures or unions: - -@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; -@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. - -@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()). - -@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(); -@endcode - -@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. - -@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 */ -@endcode - -@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. - -@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 */ -@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. - -@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 */ -@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"). - -@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 */ -@endcode - -@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. - -@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 */ -@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. - -@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 */ -@endcode - -@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. - -@code -void terminate_call(void) -{ - nua_bye(op->handle, TAG_END()); - -} /* terminate call */ -@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. - -@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 */ -@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. - -@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 */ -@endcode - -@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. - -@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 */ -@endcode - -The app_r_message() function is called by the callback function when -answer to the MESSAGE is received. - -@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 */ -@endcode - -@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. - -@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 */ -@endcode - -@subsection nua_notifier Creating a Presence Server - -@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()); -@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. - -@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; -} - - -@endcode - - -@subsection nua_shutting_down Shutdown - -The following functions show an example of how application terminates -the NUA stack. - -The shutdown() function starts the termination. - -@code -void shutdown(void) -{ - nua_shutdown(appl->nua); - -} /* shutdown */ -@endcode - -The app_r_shutdown() function is called by the callback function when NUA -stack termination is either finished or failed. - -@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 */ -@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. - -@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 |<--------------+ - +---------------+ -@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 (Trying) response. Label "2XX" means any -200-series response, e.g., 200 OK or 202 Accepted). 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 (Ringing) or 183 (Session Progress). - -@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. - -@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 :-------+ | | - + - - -: : | | | - : + - - - - - -+ | | | - : | | | | - : | | | | - :or nua_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 |<-------------------------------------+ - +------------+ -@endcode - -The detailed description of state transitions on the client side is as -follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#Previous stateInputOutputNext stateOffer/ AnswerDescription
C1 init nua_invite() INVITE calling Generate offer - 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. -
C2calling18X-proceeding(Save answer) - 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. -
C3acalling2XX-completingSave answer - Client receives a 2XX response (usually 200 OK) 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. -
C3bproceeding
C4completingnua_ack() or
@ref NUTAG_AUTOACK() "auto-ack"
ACKreadyProcess answer - 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. -
C5completingnua_ack() or
@ref NUTAG_AUTOACK() "auto-ack" and
media error
ACK
BYE
terminatingProcess answer - If there was a failure in SDP negotiation or other failure with media, - the stack will automatically terminate the call. The BYE follows - immediately after the ACK. -
C6acalling3XX 4XX
5XX 6XX
ACK*terminated- - 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. -
C6bproceeding
C7acallingnua_cancel()CANCELcalling- - 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 487 - Request Terminated 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(). -
C7bproceedingproceeding
C8aproceedingnua_bye()CANCELterminating*- - The call cannot be terminated with BYE before the dialog is established - with a non-100 preliminary response. So, instead of a @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. -
C8bproceedingnua_bye()BYE - 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. -
C9completingnua_bye()ACK
BYE
terminating- - If the stack is in @b completing state (it has already - received 2XX response), it will have to @b ACK the final response, too. -
C10terminating*2XX
to INVITE
BYEterminating- - 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. -
C11terminating*3XX 4XX
5XX 6XX
to INVITE
BYEterminating- - The @b INVITE transaction is completed without a call being created. The - call state transitions to normal terminating state. -
C12terminating3XX 4XX
5XX 6XX
to BYE
-terminated- - Call is terminated when the final response to the BYE is received. -
- -@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. - -@code - - +----------------------------------+ - | INIT | - +----------------------------------+ - | : : - | : : - (1) INVITE/100 (2b) INVITE/18X (3c) INVITE/2XX - | : : - | : : - V : : - +------------+ : : - +--------------------| | : : - | | RECEIVED |--------------+ : - | +---------------| | : | : - | | +------------+ : | : - | | | : | : - | | nua_respond/18X (2a) : | : - | | | : | : - | | 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 | - +-------------+ -@endcode - -The detailed description of state transitions on the server side is as -follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#Previous stateInputOutputNext stateOffer/ AnswerDescription
S1 init INVITE 100 Trying received Save offer - 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 100 Trying - 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. -
S2a received nua_respond() 18X early (Generate early answer) - 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. -
S2b init INVITE and - @ref NUTAG_AUTOALERT() "auto-alert"180 Ringing Save offer (and - generate early answer) - When @ref NUTAG_AUTOALERT() "auto-alert" option is enabled, stack sends - 180 Ringing immediately after receiving INVITE and enters @b early state. -
S3a received nua_respond() 2XX completed Generate answer - 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. -
S3b early
S3c init INVITE and @ref NUTAG_AUTOANSWER() "auto-answer" - 200 OK Save offer and -
generate answer
- When @ref NUTAG_AUTOANSWER() "auto-answer" option is enabled, stack send - 200 OK immediately after receiving INVITE and enters @b completed state. -
S4 completed ACK - ready - - 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. -
S5td> - completed timeout BYE terminating - - 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. -
S6a received nua_respond() 3XX 4XX
5XX 6XX
terminated - - 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. -
S6b early
S7a received CANCEL 487 Request terminatedterminated - - The client can cancel the call attempt before it is completed with a @b - CANCEL request. Server returns a 200 OK response to @b CANCEL and - a 487 Request Terminated response to the @b INVITE transaction and - the call is terminated. -
S7b early
S8 early BYE 487 to INVITE
- 200 to BYE
terminated - - 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 200 OK response to @b BYE and a 487 Request - Terminated response to the @b INVITE transaction. -
S9 completed BYE 200 to BYE terminated - - The client can terminate a completed dialog with a @b BYE request. Server - terminates call immediately, returns a 200 OK response to @b BYE - and lets the underlying transaction engine to take care of consuming @b - ACK. -
- -@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. - -@code - A C B - | | | - |<-------INVITE---------| | - | | | - | | | - |------200 (offer)----->| | - | |----INVITE (offer)---->| - | | | - | | | - | |<-----200 (answer)-----| - |<-----ACK (answer)-----| | - | | | - | |----------ACK--------->| - | | | -@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: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#Previous stateInputOutputNext stateOffer/ AnswerDescription
S1' init INVITE 100 Trying received - - There is no SDP to save. -
S2b' init INVITE and - @ref NUTAG_AUTOALERT() "auto-alert"180 Ringing early - - There is no SDP to save. -
S3a' early nua_respond() 2XX completed Generate offer - The offer is sent in 200 OK. -
S3b' received
S3c' init INVITE and - @ref NUTAG_AUTOANSWER() "auto-answer"200 OK
S4' completed ACK - ready Save and process answer - The answer is processed and media activated after receiving @b ACK. -
S9b' completed ACK and O/A error BYE terminating Save and process answer - 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. -
- - -@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. - -@code - +-------------------------------------------------------------+ - | READY | - +-------------------------------------------------------------+ - | | | | - | | | | - (1) BYE/200 (2) nua_bye/BYE (4) graceful/BYE (5) fatal/- - | | | | - | V V | - | +-----------------------------+ | - | | TERMINATING | | - | +-----------------------------+ | - | | | - | (3) [23456]XX/- | - | | | - V V V - +-------------------------------------------------------------+ - | TERMINATED | - +-------------------------------------------------------------+ -@endcode - -The detailed description of state transitions while call is terminated is as -follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#Previous stateInputOutputNext stateDescription
T1 ready BYE 200 OK terminated - 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.) -
T2 ready nua_bye BYE terminating - The application terminates the session by calling nua_bye(). All the - call-related requests on the dialog are rejected while in - terminating state with 487 No Such Call response. -
T3 terminating 2XX 3XX 4XX 5XX 6XX - terminated - The session is finally terminated when a final response to @b BYE is - received. Note that nua stack does retry @b BYE requests. -
T4 ready "graceful" response BYE terminating - 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. -
T5 ready "fatal" response - terminated - 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. -
- -@sa http://www.ietf.org/internet-drafts/draft-sparks-sipping-dialogusage-01.txt -@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. - -@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. - -@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 <- | | | - | | | -@endcode - -@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 200 OK -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. - -@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------| | - | | | -@endcode - - - -@section nua_event_diagram_call_transfer Call Transfer - -This is the unattended call transfer case. - -1st MSC showing Alice's end: - -@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------->| | - | | | -@endcode - -2nd MSC showing Bobs's end: - -@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 - | | -@endcode - -Bob includes nh1 in nua_invite()/25 as NUTAG_NOTIFY_REFER() parameter. - -Open Issue 1: - -- how Bob know when to destroy nh1? - - -@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. - -@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 - | | -@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 Headers in parsed incoming message. May be NULL. - * See also nua_current_request(). - * @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 Status or Error Indications: - * #nua_i_active \n - * #nua_i_error \n - * #nua_i_fork \n - * #nua_i_media_error \n - * #nua_i_subscription \n - * #nua_i_state \n - * #nua_i_terminated - * - * @par SIP requests: - * #nua_i_ack \n - * #nua_i_bye \n - * #nua_i_cancel \n - * #nua_i_chat \n - * #nua_i_info \n - * #nua_i_invite \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_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 - * - * @sa nua_event_is_incoming_request(), nua_event_name() - */ - -/** @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 2XX series - * 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 and 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() */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.c deleted file mode 100644 index a3e692dea7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_client.c - * @brief Client transaction handling - * - * @author Pekka Pessi - * - * @date Created: Tue Feb 3 16:10:45 EET 2009 - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#define SU_MSG_ARG_T struct nua_ee_data -#define SU_TIMER_ARG_T struct nua_client_request - -#define NUA_SAVED_EVENT_T su_msg_t * -#define NUA_SAVED_SIGNAL_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_client_request - -#include "nua_stack.h" -#include "nua_dialog.h" -#include "nua_client.h" - -#include - -#if 0 -su_inline int can_redirect(sip_contact_t const *m, sip_method_t method); -#endif - -/**@internal - * - * @class nua_client_request - * - * Each handle has a queue of client-side requests; if a request is pending, - * a new request from API is added to the queue. After the request is - * complete, it is removed from the queue and destroyed by the default. The - * exception is the client requests bound to a dialog usage: they are saved - * and re-used when the dialog usage is refreshed (and sometimes when the - * usage is terminated). - * - * The client request is subclassed and its behaviour modified using virtual - * function table in #nua_client_methods_t. - * - * The first three methods (crm_template(), crm_init(), crm_send()) are - * called when the request is sent first time. - * - * The crm_template() is called if a template request message is needed (for - * example, in case of unregister, unsubscribe and unpublish, the template - * message is taken from the request establishing the usage). - * - * The crm_init() is called when the template message and dialog leg has - * been created and populated by the tags procided by the application. Its - * parameters msg and sip are pointer to the template request message that - * is saved in the nua_client_request::cr_msg field. - * - * The crm_send() is called with a copy of the template message that has - * been populated with all the fields included in the request, including - * @CSeq and @MaxForwards. The crm_send() function, such as - * nua_publish_client_request(), usually calls nua_base_client_trequest() that - * then creates the nta-level transaction. - * - * The response to the request is processed by crm_check_restart(), which - * modifies and restarts the request when needed (e.g., when negotiating - * expiration time). After the request has been suitably modified, e.g., the - * expiration time has been increased, the restart function calls - * nua_client_restart(), which restarts the request and relays the - * intermediate response to the application with nua_client_restart() and - * crm_report(). - * - * The final responses are processed by crm_recv() and and preliminary ones - * by crm_preliminary(). All virtual functions should call - * nua_base_client_response() beside method-specific processing. - * - * The nua_base_client_response() relays the response to the application with - * nua_client_restart() and crm_report(). - * - * @par Terminating Dialog Usages and Dialogs - * - * The response is marked as terminating with nua_client_set_terminating(). - * When a terminating request completes the dialog usage is removed and the - * dialog is destroyed (unless there is an another active usage). - */ -static void nua_client_request_destroy(nua_client_request_t *cr); -static int nua_client_init_request0(nua_client_request_t *cr); -static int nua_client_request_try(nua_client_request_t *cr); -static int nua_client_request_sendmsg(nua_client_request_t *cr); -static void nua_client_restart_after(su_root_magic_t *magic, - su_timer_t *timer, - nua_client_request_t *cr); - -/**Create a client request. - * - * @retval 0 if request is pending - * @retval > 0 if error event has been sent - * @retval < 0 upon an error - */ -int nua_client_create(nua_handle_t *nh, - int event, - nua_client_methods_t const *methods, - tagi_t const * const tags) -{ - su_home_t *home = nh->nh_home; - nua_client_request_t *cr; - sip_method_t method; - char const *name; - - method = methods->crm_method, name = methods->crm_method_name; - if (!name) { - tagi_t const *t = tl_find_last(tags, nutag_method); - if (t) - name = (char const *)t->t_value; - } - - cr = su_zalloc(home, sizeof *cr + methods->crm_extra); - if (!cr) { - return nua_stack_event(nh->nh_nua, nh, - NULL, - (enum nua_event_e)event, - NUA_ERROR_AT(__FILE__, __LINE__), - NULL); - } - - cr->cr_methods = methods; - cr->cr_event = event; - cr->cr_method = method; - cr->cr_method_name = name; - cr->cr_contactize = methods->crm_flags.target_refresh; - cr->cr_dialog = methods->crm_flags.create_dialog; - cr->cr_auto = 1; - - if (su_msg_is_non_null(nh->nh_nua->nua_signal)) { - nua_event_data_t *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data; - - if (tags == e->e_tags && event == e->e_event) { - cr->cr_auto = 0; - - if (tags) { - nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal); - if (cr->cr_signal[0]) { - /* Steal reference from signal */ - cr->cr_owner = e->e_nh, e->e_nh = NULL; - cr->cr_tags = tags; - } - } - } - } - - if (cr->cr_owner == NULL) - cr->cr_owner = nua_handle_ref(nh); - - if (tags && cr->cr_tags == NULL) - cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags)); - -#if HAVE_MEMLEAK_LOG - SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); -#endif - - if (nua_client_request_queue(cr)) - return 0; - - return nua_client_init_request(cr); -} - -int nua_client_tcreate(nua_handle_t *nh, - int event, - nua_client_methods_t const *methods, - tag_type_t tag, tag_value_t value, ...) -{ - int retval; - ta_list ta; - ta_start(ta, tag, value); - retval = nua_client_create(nh, event, methods, ta_args(ta)); - ta_end(ta); - return retval; -} - -#if HAVE_MEMLEAK_LOG -nua_client_request_t * -nua_client_request_ref_by(nua_client_request_t *cr, - char const *where, unsigned line, char const *who) -{ - SU_DEBUG_0(("%p ref %s to %u by %s:%u: %s()\n", - cr, cr->cr_methods->crm_method_name, - ++(cr->cr_refs), where, line, who)); - return cr; -} - -int nua_client_request_unref_by(nua_client_request_t *cr, - char const *where, unsigned line, char const *who) -{ - SU_DEBUG_0(("%p unref %s to %u by %s:%u: %s()\n", - cr, cr->cr_methods->crm_method_name, - cr->cr_refs - 1, where, line, who)); - - if (cr->cr_refs > 1) { - cr->cr_refs--; - return 0; - } - else { - cr->cr_refs = 0; - nua_client_request_destroy(cr); - return 1; - } -} -#else -nua_client_request_t *nua_client_request_ref(nua_client_request_t *cr) -{ - cr->cr_refs++; - return cr; -} - -int nua_client_request_unref(nua_client_request_t *cr) -{ - if (cr->cr_refs > 1) { - cr->cr_refs--; - return 0; - } - else { - cr->cr_refs = 0; - nua_client_request_destroy(cr); - return 1; - } -} -#endif - -int nua_client_request_queue(nua_client_request_t *cr) -{ - int queued = 0; - nua_client_request_t **queue = &cr->cr_owner->nh_ds->ds_cr; - - assert(cr->cr_prev == NULL && cr->cr_next == NULL); - - cr->cr_status = 0; - - nua_client_request_ref(cr); - - if (cr->cr_method != sip_method_invite && - cr->cr_method != sip_method_cancel) { - while (*queue) { - if ((*queue)->cr_method == sip_method_invite || - (*queue)->cr_method == sip_method_cancel) - break; - queue = &(*queue)->cr_next; - queued = 1; - } - } - else { - while (*queue) { - queue = &(*queue)->cr_next; - if (cr->cr_method == sip_method_invite) - queued = 1; - } - } - - if ((cr->cr_next = *queue)) - cr->cr_next->cr_prev = &cr->cr_next; - - cr->cr_prev = queue, *queue = cr; - - return queued; -} - -int -nua_client_request_remove(nua_client_request_t *cr) -{ - int retval = 0; - int in_queue = cr->cr_prev != NULL; - - if (in_queue) { - if ((*cr->cr_prev = cr->cr_next)) - cr->cr_next->cr_prev = cr->cr_prev; - } - cr->cr_prev = NULL, cr->cr_next = NULL; - - if (cr->cr_timer) { - su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL; - retval = nua_client_request_unref(cr); - } - - if (!in_queue) - return retval; - - return nua_client_request_unref(cr); -} - -int -nua_client_request_clean(nua_client_request_t *cr) -{ - if (cr->cr_orq) { - nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0; - return nua_client_request_unref(cr); - } - return 0; -} - -int -nua_client_request_complete(nua_client_request_t *cr) -{ - if (cr->cr_orq) { - nua_client_request_ref(cr); - if (cr->cr_methods->crm_complete) - /* Calls nua_invite_client_complete() */ - cr->cr_methods->crm_complete(cr); - nua_client_request_clean(cr); - if (nua_client_request_unref(cr)) - return 1; - } - - return nua_client_request_remove(cr); -} - -static void -nua_client_request_destroy(nua_client_request_t *cr) -{ - nua_handle_t *nh; - - if (cr == NULL) - return; - - /* Possible references: */ - assert(cr->cr_prev == NULL); /* queue */ - assert(cr->cr_orq == NULL); /* transaction callback */ - assert(cr->cr_timer == NULL); /* timer callback */ - - nh = cr->cr_owner; - - nua_destroy_signal(cr->cr_signal); - - nua_client_bind(cr, NULL); - -#if HAVE_MEMLEAK_LOG - SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); -#endif - - if (cr->cr_msg) - msg_destroy(cr->cr_msg); - cr->cr_msg = NULL, cr->cr_sip = NULL; - - if (cr->cr_orq) - nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; - - if (cr->cr_target) - su_free(nh->nh_home, cr->cr_target); - - su_free(nh->nh_home, cr); - - nua_handle_unref(nh); -} - -/** Bind client request to a dialog usage */ -int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du) -{ - assert(cr); - if (cr == NULL) - return -1; - - if (du == NULL) { - du = cr->cr_usage; - cr->cr_usage = NULL; - if (du && du->du_cr == cr) { - du->du_cr = NULL; - nua_client_request_unref(cr); - } - return 0; - } - - if (du->du_cr && cr == du->du_cr) - return 0; - - if (du->du_cr) { - nua_client_bind(du->du_cr, NULL); - } - - du->du_cr = nua_client_request_ref(cr), cr->cr_usage = du; - - return 0; -} - -/** Check if client request is in progress. - * - * A client request is in progress, if - * 1) it has actual transaction going on - * 2) it is waiting credentials from application - * 3) it is waiting for Retry-After timer - */ -int -nua_client_request_in_progress(nua_client_request_t const *cr) -{ - return cr && - (cr->cr_orq || cr->cr_wait_for_cred || cr->cr_timer); -} - -/**Initialize client request for sending. - * - * This function is called when the request is taken from queue and sent. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - */ -int nua_client_init_request(nua_client_request_t *cr) -{ - int retval; - nua_client_request_ref(cr); - retval = nua_client_init_request0(cr); - nua_client_request_unref(cr); - return retval; -} - -/**Initialize client request for sending. - * - * This function is called when the request is taken from queue and sent. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - */ -static -int nua_client_init_request0(nua_client_request_t *cr) -{ - nua_handle_t *nh = cr->cr_owner; - nua_t *nua = nh->nh_nua; - nua_dialog_state_t *ds = nh->nh_ds; - msg_t *msg = NULL; - sip_t *sip; - url_string_t const *url = NULL; - tagi_t const *t; - int has_contact = 0; - int error = 0; - - if (!cr->cr_method_name) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL); - - if (cr->cr_msg) - return nua_client_request_try(cr); - - cr->cr_answer_recv = 0, cr->cr_offer_sent = 0; - cr->cr_offer_recv = 0, cr->cr_answer_sent = 0; - cr->cr_terminated = 0, cr->cr_graceful = 0; - - nua_stack_init_handle(nua, nh, cr->cr_tags); - - if (cr->cr_method == sip_method_cancel) { - if (cr->cr_methods->crm_init) { - error = cr->cr_methods->crm_init(cr, NULL, NULL, cr->cr_tags); - if (error) - return error; - } - - if (cr->cr_methods->crm_send) - return cr->cr_methods->crm_send(cr, NULL, NULL, cr->cr_tags); - else - return nua_base_client_request(cr, NULL, NULL, cr->cr_tags); - } - - if (!cr->cr_methods->crm_template || - cr->cr_methods->crm_template(cr, &msg, cr->cr_tags) == 0) - msg = nua_client_request_template(cr); - - sip = sip_object(msg); - if (!sip) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - - if (nh->nh_tags) { - for (t = nh->nh_tags; 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; - } - } - - /**@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. - */ - for (t = cr->cr_tags; 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_dialog) { - cr->cr_dialog = t->t_value > 1; - cr->cr_contactize = t->t_value >= 1; - } - else if (t->t_tag == nutag_auth && t->t_value) { - /* XXX ignoring errors */ - if (nh->nh_auth) - auc_credentials(&nh->nh_auth, nh->nh_home, (char *)t->t_value); - } - } - - if (cr->cr_method == sip_method_register && url == NULL) - url = (url_string_t const *)NH_PGET(nh, registrar); - - if ((t = cr->cr_tags)) { - if (sip_add_tagis(msg, sip, &t) < 0) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - } - - /** - * 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) { - if (ds->ds_remote_tag && ds->ds_remote_tag[0] && - sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - - if (sip->sip_from == NULL && - sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - - if (sip->sip_to == NULL && cr->cr_method == sip_method_register && - sip_add_dup_as(msg, sip, sip_to_class, - (sip_header_t *)sip->sip_from) < 0) { - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - } - } - else { - if (ds->ds_route) - url = NULL; - } - - if (url && nua_client_set_target(cr, (url_t *)url) < 0) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - - cr->cr_has_contact = has_contact; - - if (cr->cr_methods->crm_init) { - error = cr->cr_methods->crm_init(cr, msg, sip, cr->cr_tags); - if (error < -1) - msg = NULL; - if (error < 0) - return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg); - if (error != 0) - return error; - } - - cr->cr_msg = msg; - cr->cr_sip = sip; - - return nua_client_request_try(cr); -} - -msg_t *nua_client_request_template(nua_client_request_t *cr) -{ - nua_handle_t *nh = cr->cr_owner; - nua_t *nua = nh->nh_nua; - nua_dialog_state_t *ds = nh->nh_ds; - - msg_t *msg = nta_msg_create(nua->nua_nta, 0); - sip_t *sip = sip_object(msg); - - if (!sip) - return NULL; - - if (nh->nh_tags) { - tagi_t const *t = nh->nh_tags; - - /* Use the From header from the dialog. - If From is set, it is always first tag in the handle */ - if (ds->ds_leg && t->t_tag == siptag_from) - t++; - - /* When the INVITE message (or any other SIP message) is - * created, the tagged values saved with nua_handle() are used first. */ - sip_add_tagis(msg, sip, &t); - } - - return msg; -} - - -/** Restart the request message. - * - * A restarted request has not been completed successfully. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - */ -int nua_client_restart_request(nua_client_request_t *cr, - int terminating, - tagi_t const *tags) -{ - if (cr) { - assert(nua_client_is_queued(cr)); - - if (tags && cr->cr_msg) - if (sip_add_tagis(cr->cr_msg, NULL, &tags) < 0) - /* XXX */; - - nua_client_set_terminating(cr, terminating); - - return nua_client_request_try(cr); - } - - return 0; -} - -/** Resend the request message. - * - * A resent request has completed once successfully - restarted has not. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - */ -int nua_client_resend_request(nua_client_request_t *cr, - int terminating) -{ - if (cr) { - cr->cr_retry_count = 0; - cr->cr_challenged = 0; - - if (nua_client_is_queued(cr)) { - if (terminating) - cr->cr_graceful = 1; - return 0; - } - - if (terminating) - nua_client_set_terminating(cr, terminating); - - if (nua_client_request_queue(cr)) - return 0; - - if (nua_dialog_is_reporting(cr->cr_owner->nh_ds)) - return 0; - - return nua_client_request_try(cr); - } - return 0; -} - - -/** Send a request message. - * - * If an error occurs, send error event to the application. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - */ -static -int nua_client_request_try(nua_client_request_t *cr) -{ - int error = nua_client_request_sendmsg(cr); - - if (error < 0) - error = nua_client_response(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL); - - return error; -} - -/**Send a request message. - * - * @retval 0 if request is pending - * @retval >=1 if error event has been sent - * @retval < 0 if no error event has been sent - */ -static -int nua_client_request_sendmsg(nua_client_request_t *cr) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - sip_method_t method = cr->cr_method; - char const *name = cr->cr_method_name; - url_string_t const *url = (url_string_t *)cr->cr_target; - nta_leg_t *leg; - msg_t *msg; - sip_t *sip; - int error; - - assert(cr->cr_orq == NULL); - - cr->cr_offer_sent = cr->cr_answer_recv = 0; - cr->cr_offer_recv = cr->cr_answer_sent = 0; - - if (!ds->ds_leg && cr->cr_dialog) { - ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta, - nua_stack_process_request, nh, - SIPTAG_CALL_ID(cr->cr_sip->sip_call_id), - SIPTAG_FROM(cr->cr_sip->sip_from), - SIPTAG_TO(cr->cr_sip->sip_to), - SIPTAG_CSEQ(cr->cr_sip->sip_cseq), - TAG_END()); - if (!ds->ds_leg) - return -1; - } - - if (cr->cr_sip->sip_from && ds->ds_leg) { - if (cr->cr_sip->sip_from->a_tag == NULL) { - if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from, - nta_leg_tag(ds->ds_leg, NULL)) < 0) { - return -1; - } - } - } - - cr->cr_retry_count++; - - if (ds->ds_leg) - leg = ds->ds_leg; - else - leg = nh->nh_nua->nua_dhandle->nh_ds->ds_leg; /* Default leg */ - - msg = msg_copy(cr->cr_msg), sip = sip_object(msg); - - if (msg == NULL) - return -1; - - if (nua_dialog_is_established(ds)) { - while (sip->sip_route) - sip_route_remove(msg, sip); - } - else if (!ds->ds_route) { - sip_route_t *initial_route = NH_PGET(nh, initial_route); - - if (initial_route) { - initial_route = sip_route_dup(msg_home(msg), initial_route); - if (!initial_route) return -1; - msg_header_prepend(msg, (msg_pub_t*)sip, - /* This should be - (msg_header_t **)&sip->sip_route - * but directly casting pointer &sip->sip_route gives - * spurious type-punning warning */ - (msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)), - (msg_header_t *)initial_route); - } - } - - - /** - * 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. - * - * 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, leg, method, name, url) < 0) { - msg_destroy(msg); - return -1; - } - - /**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is - * also added now, if it does not exist. - */ - - 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); - - /** - * Next, values previously set with nua_set_params() or nua_set_hparams() - * are used: @Allow, @Supported, @Organization, @UserAgent and - * @AllowEvents headers are added to the request if they are not already - * set. - */ - if (!sip->sip_allow) - 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_make(msg, sip, sip_organization_class, 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)); - - if (!sip->sip_via && NH_PGET(nh, via)) - sip_add_make(msg, sip, sip_via_class, NH_PGET(nh, via)); - - /** Any node implementing one or more event packages SHOULD include an - * appropriate @AllowEvents header indicating all supported events in - * all methods which initiate dialogs and their responses (such as - * INVITE) and OPTIONS responses. - */ - if (!sip->sip_allow_events && - NH_PGET(nh, allow_events) && - (method == sip_method_notify || /* Always in NOTIFY */ - (!ds->ds_remote_tag && /* And in initial requests */ - (method == sip_method_subscribe || method == sip_method_refer || - method == sip_method_options || - method == sip_method_invite)))) - sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)); - - /** - * 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. - */ - - /**For the initial requests, @ServiceRoute set that was received from the - * registrar is also added to the request message. - */ - if (cr->cr_method != sip_method_register) { - if (cr->cr_contactize && cr->cr_has_contact) { - sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact); - if (ds->ds_ltarget) - msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget); - ds->ds_ltarget = ltarget; - } - - if (ds->ds_ltarget && !cr->cr_has_contact) - sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget); - - /* - FS-4102 - It was decided to comment out this code because it does not appear to make sense - Dec 22, 2016 - - if (nua_registration_add_contact_to_request(nh, msg, sip, - cr->cr_contactize && - !cr->cr_has_contact && - !ds->ds_ltarget, - !ds->ds_route) < 0) { - msg_destroy(msg); - return -1; - } - */ - - } - - cr->cr_wait_for_cred = 0; - - if (cr->cr_methods->crm_send) - error = cr->cr_methods->crm_send(cr, msg, sip, NULL); - else - error = nua_base_client_request(cr, msg, sip, NULL); - - if (error == -1) - msg_destroy(msg); - - return error; -} - -/**Add tags to request message and send it, - * - * @retval 0 success - * @retval -1 if error occurred, but event has not been sent - * @retval -2 if error occurred, event has not been sent, - * and @a msg has been destroyed - * @retval >=1 if error event has been sent - */ -int nua_base_client_trequest(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tag_type_t tag, tag_value_t value, ...) -{ - int retval; - ta_list ta; - ta_start(ta, tag, value); - retval = nua_base_client_request(cr, msg, sip, ta_args(ta)); - ta_end(ta); - return retval; -} - -/** Send request. - * - * @retval 0 success - * @retval -1 if error occurred, but event has not been sent, - * and caller has to destroy request message @ msg - * @retval -2 if error occurred, event has not been sent - * @retval >=1 if error event has been sent - */ -int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - int proxy_is_set = NH_PISSET(nh, proxy); - url_string_t * proxy = NH_PGET(nh, proxy); - - if (nh->nh_auth) { - if (cr->cr_challenged || - NH_PGET(nh, auth_cache) == nua_auth_cache_dialog) { - if (auc_authorize(&nh->nh_auth, msg, sip) < 0) - return nua_client_return(cr, 900, "Cannot add credentials", msg); - } - } - - cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */ - - assert(cr->cr_orq == NULL); - - cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta, - nua_client_orq_response, - nua_client_request_ref(cr), - NULL, - msg, - TAG_IF(proxy_is_set, - NTATAG_DEFAULT_PROXY(proxy)), - TAG_NEXT(tags)); - - if (cr->cr_orq == NULL) { - nua_client_request_unref(cr); - return -1; - } - - return 0; -} - -/** Callback for nta client transaction */ -int -nua_client_orq_response(nua_client_request_t *cr, - nta_outgoing_t *orq, - sip_t const *sip) -{ - int status; - char const *phrase; - - if (sip && sip->sip_status) { - status = sip->sip_status->st_status; - phrase = sip->sip_status->st_phrase; - } - else { - status = nta_outgoing_status(orq); - phrase = ""; - } - - nua_client_response(cr, status, phrase, sip); - - return 0; -} - -/**Return response to the client request. - * - * Return a response generated by the stack. This function is used to return - * a error response within @a nua_client_methods_t#crm_init or @a - * nua_client_methods_t#crm_send functions. It takes care of disposing the @a - * to_be_destroyed that cannot be sent. - * - * @retval 0 if response event was preliminary - * @retval 1 if response event was final - * @retval 2 if response event destroyed the handle, too. - */ -int nua_client_return(nua_client_request_t *cr, - int status, - char const *phrase, - msg_t *to_be_destroyed) -{ - if (to_be_destroyed) - msg_destroy(to_be_destroyed); - nua_client_response(cr, status, phrase, NULL); - return 1; -} - -/** Process response to the client request. - * - * The response can be generated by the stack (@a sip is NULL) or - * returned by the remote server. - * - * @retval 0 if response event was preliminary - * @retval 1 if response event was final - * @retval 2 if response event destroyed the handle, too. - */ -int nua_client_response(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - int retval = 0; - - if (cr->cr_restarting) - return 0; - - if (cr->cr_status == 200 && status < 200) { // ignore 183 follows 200 - return 0; - } - - nua_client_request_ref(cr); - - cr->cr_status = status; - cr->cr_phrase = phrase; - - if (status < 200) { - /* Xyzzy */ - } - else if (sip && nua_client_check_restart(cr, status, phrase, sip)) { - nua_client_request_unref(cr); - return 0; - } - else if (status < 300) { - if (cr->cr_terminating) { - cr->cr_terminated = 1; - } - else { - if (sip) { - if (cr->cr_contactize) - nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, cr->cr_initial); - nua_dialog_store_peer_info(nh, nh->nh_ds, sip); - } - - if (du && du->du_cr == cr) - du->du_ready = 1; - } - } - else { - sip_method_t method = cr->cr_method; - int terminated, graceful = 1; - - if (status < 700) { - terminated = sip_response_terminates_dialog(status, method, &graceful); - if (terminated && !cr->cr_initial) { - terminated = 0, graceful = 1; - } - } else { - /* XXX - terminate usage by all internal error responses */ - terminated = 0, graceful = 1; - } - - if (terminated < 0) - cr->cr_terminated = terminated; - else if (cr->cr_terminating || terminated) - cr->cr_terminated = 1; - else if (graceful) - cr->cr_graceful = 1; - } - - if (status < 200) { - if (cr->cr_methods->crm_preliminary) - cr->cr_methods->crm_preliminary(cr, status, phrase, sip); - else - nua_base_client_response(cr, status, phrase, sip, NULL); - cr->cr_phrase = NULL; - } - else { - if (cr->cr_methods->crm_recv) - retval = cr->cr_methods->crm_recv(cr, status, phrase, sip); - else - retval = nua_base_client_response(cr, status, phrase, sip, NULL); - } - - nua_client_request_unref(cr); - - return retval; -} - -/** Check if request should be restarted. - * - * @retval 1 if restarted or waiting for restart - * @retval 0 otherwise - */ -int nua_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh; - - assert(cr && status >= 200 && phrase && sip); - - nh = cr->cr_owner; - - if (cr->cr_retry_count > NH_PGET(nh, retry_count)) - return 0; - - if (cr->cr_methods->crm_check_restart) - return cr->cr_methods->crm_check_restart(cr, status, phrase, sip); - else - return nua_base_client_check_restart(cr, status, phrase, sip); -} - -int nua_base_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nta_outgoing_t *orq; -#if 0 - if (status == 302 || status == 305) { - sip_route_t r[1]; - - if (!can_redirect(sip->sip_contact, cr->cr_method)) - return 0; - - switch (status) { - case 302: - if (nua_dialog_zap(nh, nh->nh_ds) == 0 && - nua_client_set_target(cr, sip->sip_contact->m_url) >= 0) - return nua_client_restart(cr, 100, "Redirected"); - break; - - case 305: - sip_route_init(r); - *r->r_url = *sip->sip_contact->m_url; - if (nua_dialog_zap(nh, nh->nh_ds) == 0 && - sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0) - return nua_client_restart(cr, 100, "Redirected via a proxy"); - break; - - default: - break; - } - } -#endif - - if (status == 423) { - unsigned my_expires = 0; - - if (cr->cr_sip->sip_expires) - my_expires = cr->cr_sip->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; - - if (sip_add_dup(cr->cr_msg, NULL, (sip_header_t *)ex) < 0) - return 0; - - return nua_client_restart(cr, 100, "Re-Negotiating Expiration"); - } - } - - if (status == 403) { - if (nh->nh_auth) { - /* Bad username/password */ - SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh)); - auc_clear_credentials(&nh->nh_auth, NULL, NULL); - } - } - - if ((status == 401 && sip->sip_www_authenticate) || - (status == 407 && sip->sip_proxy_authenticate)) { - 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) { - int invalid = cr->cr_challenged && server + proxy == 0; - - cr->cr_challenged = 1; - - if (invalid) { - /* Bad username/password */ - SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh)); - auc_clear_credentials(&nh->nh_auth, NULL, NULL); - } else if (auc_has_authorization(&nh->nh_auth)) { - return nua_client_restart(cr, 100, "Request Authorized by Cache"); - } - - orq = cr->cr_orq, cr->cr_orq = NULL; - - cr->cr_waiting = cr->cr_wait_for_cred = 1; - nua_client_report(cr, status, phrase, NULL, orq, NULL); - nta_outgoing_destroy(orq); - cr->cr_status = 0, cr->cr_phrase = NULL; - nua_client_request_unref(cr); - - return 1; - } - } - /* GriGiu : RFC-3261 status supported Retry-After */ - if ( (status == 404 || status == 413 || status == 480 || status == 486 || - status == 500 || status == 503 || - status == 600 || status == 603) && - sip->sip_retry_after && - NH_PGET(nh, retry_after_enable) && - sip->sip_retry_after->af_delta < 3200) { - su_timer_t *timer; - char phrase[18]; /* Retry After XXXX\0 */ - - timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0); - - if (su_timer_set_interval(timer, nua_client_restart_after, cr, - sip->sip_retry_after->af_delta * 1000) < 0) { - su_timer_destroy(timer); - return 0; /* Too bad */ - } - - cr->cr_timer = timer; /* This takes over cr reference from orq */ - - snprintf(phrase, sizeof phrase, "Retry After %u", - (unsigned)sip->sip_retry_after->af_delta); - - orq = cr->cr_orq, cr->cr_orq = NULL; - cr->cr_waiting = 1; - nua_client_report(cr, 100, phrase, NULL, orq, NULL); - nta_outgoing_destroy(orq); - cr->cr_status = 0, cr->cr_phrase = NULL; - - return 1; - } - - return 0; /* This was a final response that cannot be restarted. */ -} - -#if 0 -su_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 = (enum url_type_e)m->m_url->url_type; - return - type == url_sip || - type == url_urn || - 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; -} -#endif - -/** @internal Add authorization data */ -static 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; -} - -/** @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: - * - 202 No operation to restart:\n - * The authenticator associated with the handle was updated, but there was - * no operation to retry with the new credentials. - * - 900 Cannot add credentials:\n - * There was internal problem updating authenticator. - * - 904 No matching challenge:\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) -{ - nua_client_request_t *cr = nh->nh_ds->ds_cr; - int status = nh_authorize(nh, TAG_NEXT(tags)); - - if (status > 0) { - if (cr && cr->cr_wait_for_cred) { - cr->cr_waiting = cr->cr_wait_for_cred = 0; - nua_client_restart_request(cr, cr->cr_terminating, tags); - } - else { - nua_stack_event(nua, nh, NULL, e, - 202, "No operation to restart", - NULL); - } - } - else if (cr && cr->cr_wait_for_cred) { - cr->cr_waiting = cr->cr_wait_for_cred = 0; - - if (status < 0) - nua_client_response(cr, 900, "Operation cannot add credentials", NULL); - else - nua_client_response(cr, 904, "Operation has no matching challenge ", NULL); - } - else if (status < 0) { - nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL); - } - else { - nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", NULL); - } -} - -/** Request restarted by timer */ -static void -nua_client_restart_after(su_root_magic_t *magic, - su_timer_t *timer, - nua_client_request_t *cr) -{ - cr->cr_waiting = 0; - su_timer_destroy(cr->cr_timer), cr->cr_timer = NULL; - nua_client_restart_request(cr, cr->cr_terminating, NULL); - nua_client_request_unref(cr); -} - -/** Restart request. - * - * @retval 1 if restarted - * @retval 0 otherwise - */ -int nua_client_restart(nua_client_request_t *cr, - int status, char const *phrase) -{ - nua_handle_t *nh = cr->cr_owner; - nta_outgoing_t *orq; - int error = -1, terminated, graceful; - - if (cr->cr_retry_count > NH_PGET(nh, retry_count)) - return 0; - - orq = cr->cr_orq, cr->cr_orq = NULL; assert(orq); - terminated = cr->cr_terminated, cr->cr_terminated = 0; - graceful = cr->cr_graceful, cr->cr_graceful = 0; - - cr->cr_restarting = 1; - error = nua_client_request_sendmsg(cr); - cr->cr_restarting = 0; - - if (error) { - cr->cr_graceful = graceful; - cr->cr_terminated = terminated; - assert(cr->cr_orq == NULL); - cr->cr_orq = orq; - return 0; - } - - nua_client_report(cr, status, phrase, NULL, orq, NULL); - - nta_outgoing_destroy(orq); - nua_client_request_unref(cr); /* ... reference used by old orq */ - - return 1; -} - -int nua_client_set_target(nua_client_request_t *cr, url_t const *target) -{ - url_t *new_target, *old_target = cr->cr_target; - - if (!target || target == old_target) - return 0; - - new_target = url_hdup(cr->cr_owner->nh_home, (url_t *)target); - if (!new_target) - return -1; - cr->cr_target = new_target; - if (old_target) - su_free(cr->cr_owner->nh_home, old_target); - - return 0; -} - -/**@internal - * Relay response event to the application. - * - * @todo - * If handle has already been marked as destroyed by nua_handle_destroy(), - * release the handle with nh_destroy(). - * - * @retval 0 if event was preliminary - * @retval 1 if event was final - * @retval 2 if event destroyed the handle, too. - */ -int nua_base_client_tresponse(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - tag_type_t tag, tag_value_t value, ...) -{ - ta_list ta; - int retval; - - if (cr->cr_event == nua_r_destroy) - return nua_base_client_response(cr, status, phrase, sip, NULL); - - ta_start(ta, tag, value); - retval = nua_base_client_response(cr, status, phrase, sip, ta_args(ta)); - ta_end(ta); - - return retval; -} - -/**@internal - * Relay response event to the application. - * - * @todo - * If handle has already been marked as destroyed by nua_handle_destroy(), - * release the handle with nh_destroy(). - * - * @retval 0 if event was preliminary - * @retval 1 if event was final - * @retval 2 if event destroyed the handle, too. - */ -int nua_base_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - sip_method_t method = cr->cr_method; - nua_dialog_usage_t *du; - - cr->cr_reporting = 1, nh->nh_ds->ds_reporting = 1; - - if (nh->nh_auth && sip && - (sip->sip_authentication_info || sip->sip_proxy_authentication_info)) { - /* Collect nextnonce */ - if (sip->sip_authentication_info) - auc_info(&nh->nh_auth, - sip->sip_authentication_info, - sip_authorization_class); - if (sip->sip_proxy_authentication_info) - auc_info(&nh->nh_auth, - sip->sip_proxy_authentication_info, - sip_proxy_authorization_class); - } - - if ((method != sip_method_invite && status >= 200) || status >= 300) - nua_client_request_remove(cr); - - nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags); - - if (status < 200 || - /* Un-ACKed 2XX response to INVITE */ - (method == sip_method_invite && status < 300 && !cr->cr_acked)) { - cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0; - return 1; - } - - nua_client_request_clean(cr); - - du = cr->cr_usage; - - if (cr->cr_terminated < 0) { - /* XXX - dialog has been terminated */; - nua_dialog_deinit(nh, nh->nh_ds), cr->cr_usage = NULL; - } - else if (du) { - if (cr->cr_terminated || - (!du->du_ready && status >= 300 && nua_client_is_bound(cr))) { - /* Usage has been destroyed */ - nua_dialog_usage_remove(nh, nh->nh_ds, du, cr, NULL), cr->cr_usage = NULL; - } - else if (cr->cr_graceful) { - /* Terminate usage gracefully */ - if (nua_dialog_usage_shutdown(nh, nh->nh_ds, du) > 0) - cr->cr_usage = NULL; - } - } - else if (cr->cr_terminated) { - if (nh->nh_ds->ds_usage == NULL) - nua_dialog_remove(nh, nh->nh_ds, NULL), cr->cr_usage = NULL; - } - - cr->cr_phrase = NULL; - cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0; - - if (method == sip_method_cancel) - return 1; - - return nua_client_next_request(nh->nh_ds->ds_cr, method == sip_method_invite); -} - -/** Send event, zap transaction but leave cr in list */ -int nua_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh; - - if (cr->cr_event == nua_r_destroy) - return 1; - - if (cr->cr_methods->crm_report) - return cr->cr_methods->crm_report(cr, status, phrase, sip, orq, tags); - - nh = cr->cr_owner; - - nua_stack_event(nh->nh_nua, nh, - nta_outgoing_getresponse(orq), - (enum nua_event_e)cr->cr_event, - status, phrase, - tags); - return 1; -} - -int nua_client_treport(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tag_type_t tag, tag_value_t value, ...) -{ - int retval; - ta_list ta; - ta_start(ta, tag, value); - retval = nua_client_report(cr, status, phrase, sip, orq, ta_args(ta)); - ta_end(ta); - return retval; -} - -int nua_client_next_request(nua_client_request_t *cr, int invite) -{ - for (; cr; cr = cr->cr_next) { - if (cr->cr_method == sip_method_cancel) - continue; - break; - } - - if (cr && !nua_client_request_in_progress(cr)) { - nua_client_init_request(cr); - } - - return 1; -} - -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; -} - -/**@internal - * Save handle parameters and initial authentication info. - * - * @retval -1 upon an error - * @retval 0 when successful - */ -int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags) -{ - int retval = 0; - - if (nh == NULL) - return -1; - - assert(nh != nua->nua_dhandle); - - if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0) - retval = -1; - - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.h deleted file mode 100644 index 2c18dca5f5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_client.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006, 2009 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_CLIENT_H -/** Defined when has been included. */ -#define NUA_CLIENT_H - -/**@IFILE nua_client.h - * @brief Client requests - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Tue Feb 3 15:50:35 EET 2009 ppessi - */ - -#include - -/* Methods for client request. @internal */ -typedef struct { - sip_method_t crm_method; - char const *crm_method_name; - size_t crm_extra; /**< Size of private data */ - - struct { - unsigned create_dialog:1, in_dialog:1, target_refresh:1; - unsigned:0; - } crm_flags; - - /** Generate a request message. - * - * @retval 1 when request message has been created - * @retval 0 when request message should be created in normal fashion - * @retval -1 upon an error - */ - int (*crm_template)(nua_client_request_t *cr, - msg_t **return_msg, - tagi_t const *tags); - - /**@a crm_init is called when a client request is sent first time. - * - * @retval 1 when request has been responded - * @retval 0 when request should be sent in normal fashion - * @retval -1 upon an error - */ - int (*crm_init)(nua_client_request_t *, msg_t *msg, sip_t *sip, - tagi_t const *tags); - - /** @a crm_send is called each time when a client request is sent. - * - * @retval 1 when request has been responded - * @retval 0 when request has been sent - * @retval -1 upon an error (but request message has not been destroyed) - * @retval -2 upon an error - */ - int (*crm_send)(nua_client_request_t *, - msg_t *msg, sip_t *sip, - tagi_t const *tags); - - /** @a crm_check_restart is called each time when a response is received. - * - * It is used to restart request after responses with method-specific - * status code or method-specific way of restarting the request. - * - * @retval 1 when request has been restarted - * @retval 0 when response should be processed normally - */ - int (*crm_check_restart)(nua_client_request_t *, - int status, char const *phrase, - sip_t const *sip); - - /** @a crm_recv is called each time a final response is received. - * - * A final response is in range 200 .. 699 (or internal response) and it - * cannot be restarted. - * - * crm_recv() should call nua_base_client_response() or - * nua_base_client_tresponse(). The return values below are documented with - * nua_base_client_response(), too. - * - * @retval 0 if response was preliminary - * @retval 1 if response was final - * @retval 2 if response destroyed the handle, too. - */ - int (*crm_recv)(nua_client_request_t *, - int status, char const *phrase, - sip_t const *sip); - - /** @a crm_preliminary is called each time a preliminary response is received. - * - * A preliminary response is in range 101 .. 199. - * - * crm_preliminary() should call nua_base_client_response() or - * nua_base_client_tresponse(). - * - * @retval 0 if response was preliminary - * @retval 1 if response was final - * @retval 2 if response destroyed the handle, too. - */ - int (*crm_preliminary)(nua_client_request_t *, - int status, char const *phrase, - sip_t const *sip); - - /** @a crm_report is called each time a response is received and it is - * reported to the application. - * - * The status and phrase may be different from the status and phrase - * received from the network, e.g., when the request is restarted. - * - * @return The return value should be 0. It is currently ignored. - */ - int (*crm_report)(nua_client_request_t *, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - - /** @a crm_complete is called when a client-side request is destroyed. - * - * @return The return value should be 0. It is currently ignored. - */ - int (*crm_complete)(nua_client_request_t *); - -} nua_client_methods_t; - -/* Client-side request. Documented by nua_client_create() */ -struct nua_client_request -{ - nua_client_request_t *cr_next, **cr_prev; /**< Linked list of requests */ - nua_owner_t *cr_owner; - nua_dialog_usage_t *cr_usage; - - nua_saved_signal_t cr_signal[1]; - tagi_t const *cr_tags; - - nua_client_methods_t const *cr_methods; - - msg_t *cr_msg; - sip_t *cr_sip; - - nta_outgoing_t *cr_orq; - - su_timer_t *cr_timer; /**< Expires or retry timer */ - - /*nua_event_t*/ int cr_event; /**< Request event */ - sip_method_t cr_method; - char const *cr_method_name; - - url_t *cr_target; - - char const *cr_phrase; /**< Latest status phrase */ - unsigned short cr_status; /**< Latest status */ - unsigned short cr_retry_count; /**< Retry count for this request */ - - uint32_t cr_seq; - - unsigned cr_refs; /**< References to client 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 */ - - /* Flags with usage */ - unsigned cr_neutral:1; /**< No effect on session or other usage */ - - /* Lifelong flags? */ - unsigned cr_auto:1; /**< Request was generated by stack */ - unsigned cr_has_contact:1; /**< Request has user Contact */ - unsigned cr_contactize:1; /**< Request needs Contact */ - unsigned cr_dialog:1; /**< Request can initiate dialog */ - - /* Current state */ - unsigned cr_initial:1; /**< Initial request of a dialog */ - unsigned cr_acked:1; /**< Final response to the request has been ACKed */ - unsigned cr_waiting:1; /**< Request is waiting */ - unsigned cr_challenged:1; /**< Request was challenged */ - unsigned cr_wait_for_cred:1; /**< Request is pending authentication */ - unsigned cr_restarting:1; /**< Request is being restarted */ - unsigned cr_reporting:1; /**< Reporting in progress */ - unsigned cr_terminating:1; /**< Request terminates the usage */ - signed int cr_terminated:2; /**< Response terminated usage (1) or - whole dialog (-1) */ - unsigned cr_graceful:1; /**< Graceful termination required */ -}; - -int nua_client_create(nua_owner_t *owner, - int event, - nua_client_methods_t const *methods, - tagi_t const *tags); - -int nua_client_tcreate(nua_owner_t *nh, - int event, - nua_client_methods_t const *methods, - tag_type_t tag, tag_value_t value, ...); - -su_inline -void *nua_private_client_request(nua_client_request_t const *cr) -{ - return (void *)(cr + 1); -} - -nua_client_request_t *nua_client_request_ref(nua_client_request_t *); -int nua_client_request_unref(nua_client_request_t *); - -#if HAVE_MEMLEAK_LOG - -#define nua_client_request_ref(cr) \ - nua_client_request_ref_by((cr), __FILE__, __LINE__, __func__) -#define nua_client_request_unref(cr) \ - nua_client_request_unref_by((cr), __FILE__, __LINE__, __func__) - -nua_client_request_t *nua_client_request_ref_by(nua_client_request_t *, - char const *file, unsigned line, - char const *who); -int nua_client_request_unref_by(nua_client_request_t *, - char const *file, unsigned line, char const *who); - -#endif - -int nua_client_request_queue(nua_client_request_t *cr); - -su_inline int nua_client_is_queued(nua_client_request_t const *cr) -{ - return cr && cr->cr_prev; -} - -int nua_client_request_in_progress(nua_client_request_t const *cr); - -int nua_client_request_complete(nua_client_request_t *cr); -int nua_client_request_remove(nua_client_request_t *cr); -int nua_client_request_clean(nua_client_request_t *cr); -int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du); - -su_inline int nua_client_is_bound(nua_client_request_t const *cr) -{ - return cr && cr->cr_usage && cr->cr_usage->du_cr == cr; -} - -su_inline int nua_client_is_reporting(nua_client_request_t const *cr) -{ - return cr && cr->cr_reporting; -} - -/** Mark client request as a terminating one */ -su_inline void nua_client_set_terminating(nua_client_request_t *cr, int value) -{ - cr->cr_terminating = value != 0; -} - -int nua_client_init_request(nua_client_request_t *cr); - -msg_t *nua_client_request_template(nua_client_request_t *cr); - -int nua_client_restart_request(nua_client_request_t *cr, - int terminating, - tagi_t const *tags); - -int nua_client_resend_request(nua_client_request_t *cr, - int terminating); - -int nua_base_client_request(nua_client_request_t *cr, - msg_t *msg, - sip_t *sip, - tagi_t const *tags); - -int nua_base_client_trequest(nua_client_request_t *cr, - msg_t *msg, - sip_t *sip, - tag_type_t tag, tag_value_t value, ...); - -extern nta_response_f nua_client_orq_response; - -int nua_client_return(nua_client_request_t *cr, - int status, - char const *phrase, - msg_t *to_be_destroyed); - -int nua_client_response(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip); - -int nua_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip); - -int nua_base_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip); - -int nua_client_restart(nua_client_request_t *cr, - int status, char const *phrase); - -int nua_base_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - tagi_t const *tags); - -int nua_base_client_tresponse(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - tag_type_t tag, tag_value_t value, ...); - -int nua_client_set_target(nua_client_request_t *cr, url_t const *target); - -int nua_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - -nua_client_request_t *nua_client_request_pending(nua_client_request_t const *); - -int nua_client_next_request(nua_client_request_t *cr, int invite); - -#endif /* NUA_CLIENT_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c deleted file mode 100644 index 661a18b1d2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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@nokia.com - * - * @date Created: Tue Apr 26 13:23:17 2005 ppessi - * - */ - -#include "config.h" - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -#include - -#define SU_LOG (nua_log) -#include - -#define SU_ROOT_MAGIC_T struct nua_s - -#include - -#include -#include - -#include "sofia-sip/nua.h" -#include "sofia-sip/nua_tag.h" - -#include -#include -#include - -#include -#if HAVE_SMIME /* Start NRC Boston */ -#include "smimec.h" -#endif /* End NRC Boston */ - -#include - -#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)))) { - if ((nh = su_home_new(sizeof(*nh)))) { - nh->nh_valid = nua_valid_handle_cookie; - nh->nh_nua = nua; - nh->nh_magic = hmagic; - nh->nh_prefs = nua->nua_dhandle->nh_prefs; - nh->nh_ds->ds_owner = nh; - - if (nua_handle_save_tags(nh, tags) < 0) { - SU_DEBUG_5(("nua(%p): creating handle %p failed\n", - (void *)nua, (void *)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", (void *)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", (void *)nh)); -} - -#if HAVE_MEMLEAK_LOG - -nua_handle_t * -_nua_handle_ref_by(nua_handle_t *nh, - char const *file, unsigned line, - char const *function) -{ - -#if (HAVE_MEMLEAK_LOG == 1) - if (nh) - SU_DEBUG_0(("%p - nua_handle_ref() => "MOD_ZU" by %s:%u: %s()\n", - nh, su_home_refcount((su_home_t *)nh) + 1, file, line, function)); - return (nua_handle_t *)su_home_ref((su_home_t *)nh); -#else - - return (nua_handle_t *)_su_home_ref_by((su_home_t *)nh, file, line, function); -#endif -} - -int -_nua_handle_unref_by(nua_handle_t *nh, - char const *file, unsigned line, - char const *function) -{ - -#if (HAVE_MEMLEAK_LOG == 1) - - if (nh) { - size_t refcount = su_home_refcount((su_home_t *)nh) - 1; - int freed = su_home_unref((su_home_t *)nh); - - if (freed) refcount = 0; - SU_DEBUG_0(("%p - nua_handle_unref() => "MOD_ZU" by %s:%u: %s()\n", - nh, refcount, file, line, function)); - return freed; - } - - return 0; -#else - return _su_home_unref_by((su_home_t *)nh, file, line, function); -#endif -} - -#else - -/** 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); -} - -#endif - -/** 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); -} - -/** Check if event is a request that can be responded with nua_respond(). - * - * Note that if event status is 200 or greater, it already has been - * responded. This function is provided for compatibility with future - * versions of nua. An unknown event can always be handled in the event - * callback like this: - * @code - * switch (event) { - * ... - * default: - * if (status < 200 && nua_event_is_incoming_request(event)) - * nua_respond(nh, SIP_501_NOT_IMPLEMENTED, - * NUTAG_WITH_THIS(nua), TAG_END()); - * if (hmagic == NULL) - * nua_handle_destroy(nh); - * return; - * ... - * @endcode - * - * @sa nua_respond(), #nua_event_e, #nua_event_t, nua_event_name() - * - * @NEW_1_12_6. - */ -int nua_event_is_incoming_request(nua_event_t event) -{ - switch (event) { - case nua_i_invite: return 1; - case nua_i_cancel: return 1; - case nua_i_register: return 1; - case nua_i_bye: return 1; - case nua_i_options: return 1; - case nua_i_refer: return 1; - case nua_i_publish: return 1; - case nua_i_prack: return 1; - case nua_i_info: return 1; - case nua_i_update: return 1; - case nua_i_message: return 1; - case nua_i_subscribe: return 1; - case nua_i_notify: return 1; - case nua_i_method: return 1; - default: return 0; - } -} - -/** Get name for a NUA event. - * - * @sa #nua_event_e, #nua_event_t, nua_callstate_name(), nua_substate_name() - */ -char const *nua_event_name(nua_event_t event) -{ - switch (event) { - case nua_i_none: return "nua_i_none"; - - 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. - * - * @sa enum #nua_callstate, nua_event_name(), nua_substate_name() - */ -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"; - } -} - -/** Return name of subscription state. @NEW_1_12_5. - * - * @sa enum #nua_substate, nua_event_name(), nua_callstate_name() - */ -char const *nua_substate_name(enum nua_substate substate) -{ - switch (substate) { - case nua_substate_embryonic: - /*FALLTHROUGH*/ - case nua_substate_pending: - return "pending"; - case nua_substate_terminated: - return "terminated"; - case nua_substate_active: - /*FALLTHROUGH*/ - default: - return "active"; - } -} - -/** Convert string to enum nua_substate. @NEW_1_12_5. */ -enum nua_substate nua_substate_make(char const *sip_substate) -{ - if (sip_substate == NULL) - return nua_substate_active; - else if (su_casematch(sip_substate, "terminated")) - return nua_substate_terminated; - else if (su_casematch(sip_substate, "pending")) - return nua_substate_pending; - else /* if (su_casematch(sip_substate, "active")) */ - return nua_substate_active; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c deleted file mode 100644 index 019691b611..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#define NUA_OWNER_T su_home_t - -#include "nua_dialog.h" - -#define SU_LOG (nua_log) -#include - -#ifndef NONE - -#ifndef _MSC_VER -#define NONE ((void *)-1) -#else -#define NONE ((void *)(INT_PTR)-1) -#endif -#endif - -/* ======================================================================== */ -/* Dialog handling */ - -static void nua_dialog_usage_remove_at(nua_owner_t*, nua_dialog_state_t*, - nua_dialog_usage_t**, - nua_client_request_t *cr, - nua_server_request_t *sr); -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 - * @param initial if true, @a sip is response to initial transaction - */ -void nua_dialog_uac_route(nua_owner_t *own, - nua_dialog_state_t *ds, - sip_t const *sip, - int rtag, - int initial) -{ - int established = nua_dialog_is_established(ds); - int status = sip->sip_status->st_status; - - 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; - - if (initial && status >= 200) - nta_leg_client_reroute(ds->ds_leg, sip->sip_record_route, sip->sip_contact, 1); - else - nta_leg_client_reroute(ds->ds_leg, sip->sip_record_route, sip->sip_contact, 0); - - 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_dialog_peer_info_t *nr = ds->ds_remote_ua; - nua_dialog_usage_t *du; - nua_dialog_peer_info_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_via = NULL, su_free(own, old->nr_via); - 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_via) { - nr->nr_via = sip_via_dup(own, sip->sip_via); - su_free(own, old->nr_via); - } - - 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 information. */ -int nua_dialog_zap(nua_owner_t *own, - nua_dialog_state_t *ds) -{ - /* zap peer info */ - nua_dialog_store_peer_info(own, ds, NULL); - /* Local Contact */ - msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL; - /* Leg */ - nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL; - /* Remote tag */ - su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL; - /* Ready to set route/remote target */ - ds->ds_route = 0; - - return 0; -} - -/** 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)) { - return nua_dialog_zap(own, ds); - } - 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 (!su_strmatch(event->o_type, o->o_type)) - continue; - if (!su_casematch(event->o_id, o->o_id)) { - if (event->o_id || !su_strmatch(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 ""; - 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", - (void *)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) { - su_home_ref(own); - du->du_dialog = ds; - 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", - (void *)own, nua_dialog_usage_name(du), - o ? " with event " : "", o ? o->o_type :"")); - - 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_client_request_t *cr, - nua_server_request_t *sr) -{ - 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, cr, sr); -} - -/** @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, - nua_client_request_t *cr0, - nua_server_request_t *sr0) -{ - int unref = 0; - nua_dialog_usage_t *du = NULL; - - if (*at) { - sip_event_t const *o = NULL; - nua_client_request_t *cr, *cr_next; - nua_server_request_t *sr, *sr_next; - du = *at; - - *at = du->du_next; - - o = du->du_event; - - SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n", - (void *)own, nua_dialog_usage_name(du), - o ? " with event " : "", o ? o->o_type :"")); - du->du_class->usage_remove(own, ds, du, cr0, sr0); - - /* Clean reference to saved client request */ - if (du->du_cr) - nua_client_bind(du->du_cr, NULL); - - /* Clean references from queued client requests */ - for (cr = ds->ds_cr; cr; cr = cr_next) { - cr_next = cr->cr_next; - if (cr->cr_usage == du) - cr->cr_usage = NULL; - } - - /* Clean references from queued server requests */ - for (sr = ds->ds_sr; sr; sr = sr_next) { - sr_next = sr->sr_next; - if (sr->sr_usage == du) { - sr->sr_usage = NULL; - if (sr != sr0) - nua_server_request_destroy(sr); - } - } - - unref = 1; - } - - /* Zap dialog if there are no more usages */ - if (ds->ds_terminating) - ; - else if (ds->ds_usage == NULL) { - nua_dialog_remove(own, ds, NULL); - ds->ds_has_events = 0; - if (unref) { - su_home_unref(own); - su_free(own, du); - } - return; - } - else { - nua_dialog_log_usage(own, ds); - } - - if (unref) { - su_home_unref(own); - su_free(own, du); - } -} - -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", (void *)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) -{ - ds->ds_terminating = 1; - - while (ds->ds_usage) { - nua_dialog_usage_remove_at(own, ds, &ds->ds_usage, NULL, NULL); - } - - nua_dialog_remove(own, ds, NULL); - - ds->ds_has_events = 0; - ds->ds_terminating = 0; -} - -void nua_dialog_update_params(nua_dialog_state_t *ds, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *params, - nua_handle_preferences_t const *defaults) -{ - nua_dialog_usage_t *usage; - - for (usage = ds->ds_usage; usage; usage = usage->du_next) { - usage->du_class->usage_update_params(usage, changed, params, defaults); - } -} - -void nua_base_usage_update_params(nua_dialog_usage_t const *du, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *params, - nua_handle_preferences_t const *defaults) -{ - (void)du, (void)changed, (void)params, (void)defaults; -} - -/**@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 dialog usage is never refreshed. - */ -void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta) -{ - if (delta == 0) - nua_dialog_usage_reset_refresh(du); - else if (delta > 90 && delta < 5 * 60) - /* refresh 30..60 seconds before deadline */ - nua_dialog_usage_set_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_set_refresh_range(du, min, max); - } -} - -/**@internal Set refresh in range min..max seconds in the future. */ -void nua_dialog_usage_set_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_refquested = now; - - du->du_refresh = target; -} - -/** Set absolute refresh time */ -void nua_dialog_usage_set_refresh_at(nua_dialog_usage_t *du, - sip_time_t target) -{ - SU_DEBUG_7(("nua(): refresh %s after %lu seconds\n", - nua_dialog_usage_name(du), target - sip_now())); - du->du_refresh = target; -} - -/**@internal Do not refresh. */ -void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du) -{ - if (du) { - du->du_refquested = sip_now(); - du->du_refresh = 0; - } -} - -/** @internal Refresh usage. */ -void nua_dialog_usage_refresh(nua_owner_t *owner, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - sip_time_t now) -{ - assert(du && du->du_class->usage_refresh); - du->du_class->usage_refresh(owner, ds, du, now); -} - -/** Terminate all dialog usages gracefully. */ -int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds) -{ - nua_dialog_usage_t *du; - - ds->ds_terminating = 1; - - do { - for (du = ds->ds_usage; du; du = du->du_next) { - if (!du->du_shutdown) { - nua_dialog_usage_shutdown(owner, ds, du); - break; - } - } - } while (du); - - return 1; -} - -/** Shutdown (gracefully terminate) usage. - * - * @retval >0 shutdown done - * @retval 0 shutdown in progress - * @retval <0 try again later - */ -int nua_dialog_usage_shutdown(nua_owner_t *owner, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) -{ - if (du) { - nua_dialog_usage_reset_refresh(du); - du->du_shutdown = 1; - assert(du->du_class->usage_shutdown); - return du->du_class->usage_shutdown(owner, ds, du); - } - else - return 200; -} - -/** Repeat shutdown of all usages. - * - * @note Caller must have a reference to nh - */ -int nua_dialog_repeat_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds) -{ - nua_dialog_usage_t *du; - nua_server_request_t *sr, *sr_next; - - for (sr = ds->ds_sr; sr; sr = sr_next) { - sr_next = sr->sr_next; - - if (nua_server_request_is_pending(sr)) { - SR_STATUS1(sr, SIP_410_GONE); /* 410 terminates dialog */ - nua_server_respond(sr, NULL); - nua_server_report(sr); - } - } - - for (du = ds->ds_usage; du ;) { - nua_dialog_usage_t *du_next = du->du_next; - - nua_dialog_usage_shutdown(owner, ds, du); - - if (du_next == NULL) - break; - - for (du = ds->ds_usage; du; du = du->du_next) { - if (du == du_next) - break; - else if (!du->du_shutdown) - break; - } - } - - return ds->ds_usage != NULL; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h deleted file mode 100644 index 707e6a60ec..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NUA_DIALOG_H - -/**@IFILE nua_dialog.h - * @brief Dialog and dialog usage handling - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Wed Mar 8 11:38:18 EET 2006 ppessi - */ - -#include - -#ifndef NTA_H -#include -#endif - -struct nua_dialog_state -{ - /** Dialog owner */ - nua_owner_t *ds_owner; - - /** Dialog usages. */ - nua_dialog_usage_t *ds_usage; - - /** Client requests */ - nua_client_request_t *ds_cr; - /** Server requests */ - nua_server_request_t *ds_sr; - - /* Dialog and subscription state */ - unsigned ds_reporting:1; /**< We are reporting */ - - unsigned ds_route:1; /**< We have route */ - unsigned ds_terminating: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_got_session:1; /**< We have (or have had) session */ - unsigned ds_got_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; - sip_contact_t *ds_ltarget; /**< Local target */ - char const *ds_remote_tag; /**< Remote tag (if any). - * Should be non-NULL - * if dialog is established. - */ - - struct nua_dialog_peer_info { - sip_via_t *nr_via; - 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]; -}; - -/* 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, - nua_client_request_t *cr, - nua_server_request_t *sr); - char const *(*usage_name)(nua_dialog_usage_t const *du); - void (*usage_update_params)(nua_dialog_usage_t const *du, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *params, - nua_handle_preferences_t const *defaults); - 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; - nua_dialog_state_t *du_dialog; - nua_client_request_t *du_cr; /**< Client request bound with usage */ - sip_time_t du_refquested; /**< When refreshed was requested */ - sip_time_t du_refresh; /**< When to refresh */ - - 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_event_t const *du_event; /**< Event of usage */ - -}; - -void nua_dialog_uac_route(nua_owner_t *, nua_dialog_state_t *ds, - sip_t const *sip, int rtag, int initial); -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_zap(nua_owner_t *own, - nua_dialog_state_t *ds); -int nua_dialog_remove(nua_owner_t *own, - nua_dialog_state_t *ds, - nua_dialog_usage_t *usage); - -su_inline int nua_dialog_is_reporting(nua_dialog_state_t const *ds) -{ - return ds && ds->ds_reporting; -} - -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, - nua_client_request_t *cr, - nua_server_request_t *sr); - -void nua_dialog_update_params(nua_dialog_state_t *ds, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *params, - nua_handle_preferences_t const *defaults); - -void nua_base_usage_update_params(nua_dialog_usage_t const *du, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *params, - nua_handle_preferences_t const *defaults); - -void nua_dialog_deinit(nua_owner_t *own, - nua_dialog_state_t *ds); - -int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds); - -int nua_dialog_repeat_shutdown(nua_owner_t *owner, - nua_dialog_state_t *ds); - -void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta); - -void nua_dialog_usage_set_refresh_range(nua_dialog_usage_t *du, - unsigned min, unsigned max); - -void nua_dialog_usage_set_refresh_at(nua_dialog_usage_t *du, - sip_time_t target); - -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); - -int nua_dialog_usage_shutdown(nua_owner_t *owner, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du); - -su_inline -int nua_dialog_is_established(nua_dialog_state_t const *ds) -{ - return ds->ds_remote_tag != NULL; -} - -#if 0 -su_inline -void *nua_dialog_usage_private(nua_dialog_usage_t const *du) -{ - return du ? (void *)(du + 1) : NULL; -} - -su_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 - -#define NUA_DIALOG_USAGE_PRIVATE(du) ((void *)((du) + 1)) -#define NUA_DIALOG_USAGE_PUBLIC(pu) ((void *)((nua_dialog_usage_t *)(pu) - 1)) - -#include "nua_client.h" -#include "nua_server.h" - -#endif /* NUA_DIALOG_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c deleted file mode 100644 index 0ddecd95f3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_event_server.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#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, 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_tevent(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, NULL); - - 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, *o_subtype; - char *temp = NULL; - - o_type = su_strdup(home, event->o_type); - if (o_type == NULL) - return NULL; - 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 = temp = 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); - - su_free(home, temp); - su_free(home, o_type); - } - - 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_STATUS(200, 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_STATUS(403, sip_403_Forbidden); - } - else if (substate == nua_substate_pending) { - what = "pending"; SET_STATUS(202, sip_202_Accepted); - } - else { - what = "active"; - } - - SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, what)); - nea_sub_auth(sn->sn_subscriber, (nea_state_t)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", - (void *)nh, "watcher is removed")); - } - - nua_stack_tevent(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, (nea_state_t)state, TAG_NEXT(tags)); - nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL); - } - else { - nua_stack_event(nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), NULL); - } -} - -/** @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, NULL); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c deleted file mode 100644 index f32fabf4fb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Mon Nov 13 15:18:54 EET 2006 - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "nua_stack.h" - -/**Send a request message with an extension method. - * - * Send a request message with the request method specified with - * NUTAG_METHOD(). - * - * @param nh Pointer to operation handle - * @param tag, value, ... List of tagged parameters - * - * @return - * nothing - * - * Note that it is possible to send a request with any method (except - * perhaps @b INVITE, @b ACK or @b CANCEL) using this function. - * - * @par Related Tags: - * NUTAG_METHOD() \n - * NUTAG_URL() \n - * Tags of nua_set_hparams() \n - * Header tags defined in - * - * @par Events: - * #nua_r_method - * - * @sa SIP_METHOD_UNKNOWN(), #nua_r_method, #nua_i_method - * - * @since New in @VERSION_1_12_4. - */ - -static nua_client_methods_t const nua_method_client_methods = { - SIP_METHOD_UNKNOWN, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 0, - /* target_refresh */ 1, - }, - NULL, /* crm_template */ - NULL, /* crm_init */ - NULL, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int -nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_method_client_methods, tags); -} - -/** @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 - */ - -/** @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 headers in incoming request (see also nua_current_request()) - * @param tags NUTAG_METHOD() - * - * The extension method name is in sip->sip_request->rq_method_name, too. - * - * @note If the @a status is < 200, it is up to application to respond to - * the request with nua_respond(). If the handle is destroyed, the stack - * returns a 500 Internal Server Error response to any unresponded - * request. - * - * @sa nua_method(), #nua_r_method, NUTAG_ALLOW(), NUTAG_APPL_METHOD(), - * nua_respond(), NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_ - * - * @END_NUA_EVENT - */ - -nua_server_methods_t const nua_extension_server_methods = - { - SIP_METHOD_UNKNOWN, - nua_i_method, /* Event */ - { - 1, /* Do create dialog */ - 0, /* Can be an initial request */ - 1, /* Perhaps a target refresh request? */ - 1, /* Add a contact? */ - }, - nua_base_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_base_server_report, - }; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c deleted file mode 100644 index fb39f9ac1b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 17:01:22 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "nua_stack.h" - -/* ======================================================================== */ -/* MESSAGE */ - -/**@fn void nua_message( \ - * nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); - * - * 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 - * Header tags defined in - * - * @par Events: - * #nua_r_message - * - * @sa #nua_i_message, @RFC3428 - */ - -static int nua_message_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); - -static nua_client_methods_t const nua_message_client_methods = { - SIP_METHOD_MESSAGE, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 0, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - nua_message_client_init, /* crm_init */ - NULL, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ - -}; - -int -nua_stack_message(nua_t *nua, - nua_handle_t *nh, - nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_message_client_methods, tags); -} - -static int nua_message_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - if (NH_PGET(cr->cr_owner, win_messenger_enable)) - cr->cr_contactize = 1; - return 0; -} - -/** @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 - */ - -/** @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_message_server_init(nua_server_request_t *sr); -int nua_message_server_params(nua_server_request_t *, tagi_t const *); - -nua_server_methods_t const nua_message_server_methods = - { - SIP_METHOD_MESSAGE, - nua_i_message, /* Event */ - { - 0, /* Do not create dialog */ - 0, /* Can be initial request */ - 0, /* Perhaps a target refresh request? */ - 0, /* Do not add contact by default */ - }, - nua_message_server_init, - nua_base_server_preprocess, - nua_message_server_params, - nua_base_server_respond, - nua_base_server_report, - }; - -int nua_message_server_init(nua_server_request_t *sr) -{ - if (!NH_PGET(sr->sr_owner, message_enable)) - return SR_STATUS1(sr, SIP_403_FORBIDDEN); - - return 0; -} - -int nua_message_server_params(nua_server_request_t *sr, - tagi_t const *tags) -{ - if (NH_PGET(sr->sr_owner, win_messenger_enable)) - sr->sr_add_contact = 1; - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c deleted file mode 100644 index 97247f9d6d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 15:10:08 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nua_stack.h" - -/* ---------------------------------------------------------------------- */ -/* Notifier event usage */ - -struct notifier_usage -{ - enum nua_substate nu_substate; /**< Subscription state */ - sip_time_t nu_expires; /**< Expiration time */ - sip_time_t nu_requested; /**< Requested expiration time */ -#if SU_HAVE_EXPERIMENTAL - char *nu_tag; /**< @ETag in last NOTIFY */ - unsigned nu_etags:1; /**< Subscriber supports etags */ - unsigned nu_appl_etags:1; /**< Application generates etags */ - unsigned nu_no_body:1; /**< Suppress body */ -#endif -}; - -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, - nua_client_request_t *cr, - nua_server_request_t *sr); -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, - nua_base_usage_update_params, - 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, - nua_client_request_t *cr, - nua_server_request_t *sr) -{ - ds->ds_has_events--; - ds->ds_has_notifys--; -} - -/* ====================================================================== */ -/* SUBSCRIBE server */ - -/** @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. - * - * @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() - * - * Initial SUBSCRIBE requests are dropped with 489 Bad Event - * 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()). - * - * If the event has been allowed 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_THIS()/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 by an intermediate proxy - * because it had forked the SUBSCRIBE request. - * - * SUBSCRIBE requests modifying (usually refreshing or terminating) an - * existing event subscription are accepted by default and a 200 OK - * response along with a copy of previously sent NOTIFY is sent - * automatically to the subscriber. - * - * 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. - * - * @par Subscription Lifetime and Terminating Subscriptions - * - * Accepting the SUBSCRIBE request creates a dialog with a notifier - * dialog usage on the handle. The dialog usage is active, until the - * subscriber terminates the subscription, it times out or the application - * terminates the usage with nua_notify() call containing the tag - * NUTAG_SUBSTATE(nua_substate_terminated) or @SubscriptionState header with - * state "terminated" and/or expiration time 0. - * - * When the subscriber terminates the subscription, the application is - * notified of an termination by a #nua_i_subscribe event with - * NUTAG_SUBSTATE(nua_substate_terminated) tag. When the subscription times - * out, nua automatically initiates a NOTIFY transaction. When it is - * terminated, the application is sent a #nua_r_notify event with - * NUTAG_SUBSTATE(nua_substate_terminated) tag. - * - * @sa @RFC3265, nua_notify(), NUTAG_SUBSTATE(), @SubscriptionState, - * @Event, nua_subscribe(), #nua_r_subscribe, #nua_i_refer, nua_refer() - * - * @END_NUA_EVENT - */ - -static int nua_subscribe_server_init(nua_server_request_t *sr); -static int nua_subscribe_server_preprocess(nua_server_request_t *sr); -static int nua_subscribe_server_respond(nua_server_request_t*, tagi_t const *); -static int nua_subscribe_server_report(nua_server_request_t*, tagi_t const *); - -nua_server_methods_t const nua_subscribe_server_methods = - { - SIP_METHOD_SUBSCRIBE, - nua_i_subscribe, /* Event */ - { - 1, /* Create dialog */ - 0, /* Initial request */ - 1, /* Target refresh request */ - 1, /* Add Contact */ - }, - nua_subscribe_server_init, - nua_subscribe_server_preprocess, - nua_base_server_params, - nua_subscribe_server_respond, - nua_subscribe_server_report, - }; - -int nua_subscribe_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - sip_allow_events_t const *allow_events = NH_PGET(nh, allow_events); - sip_t const *sip = sr->sr_request.sip; - sip_event_t *o = sip->sip_event; - char const *event = o ? o->o_type : NULL; - - if (sr->sr_initial || !nua_dialog_usage_get(ds, nua_notify_usage, o)) { - if (su_strmatch(event, "refer")) - /* refer event subscription should be initiated with REFER */ - return SR_STATUS1(sr, SIP_403_FORBIDDEN); - - /* XXX - event is case-sensitive, should use msg_header_find_item() */ - if (!event || !msg_header_find_param(allow_events->k_common, event)) - return SR_STATUS1(sr, SIP_489_BAD_EVENT); - } - - return 0; -} - -int nua_subscribe_server_preprocess(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - nua_dialog_usage_t *du; - struct notifier_usage *nu; - sip_t const *sip = sr->sr_request.sip; - sip_event_t *o = sip->sip_event; - char const *event = o ? o->o_type : NULL; - /* Maximum expiration time */ - unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600; - sip_time_t now = sip_now(); - - assert(nh && nh->nh_nua->nua_dhandle != nh); - - du = nua_dialog_usage_get(ds, nua_notify_usage, o); - - if (du == NULL) { - /* Create a new subscription */ - du = nua_dialog_usage_add(nh, ds, nua_notify_usage, o); - if (du == NULL) - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - else { - /* Refresh existing subscription */ - if (su_strmatch(event, "refer")){ - expires = NH_PGET(nh, refer_expires); - - SR_STATUS1(sr, SIP_200_OK);} - } - - nu = nua_dialog_usage_private(du); - - if (now + expires >= now) - nu->nu_requested = now + expires; - else - nu->nu_requested = SIP_TIME_MAX - 1; - -#if SU_HAVE_EXPERIMENTAL - nu->nu_etags = - sip_suppress_body_if_match(sip) || - sip_suppress_notify_if_match(sip) || - sip_has_feature(sr->sr_request.sip->sip_supported, "etags"); -#endif - - sr->sr_usage = du; - - return sr->sr_status <= 100 ? 0 : sr->sr_status; -} - -/** @internal Respond to a SUBSCRIBE request. - * - */ -static -int nua_subscribe_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage); - - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - if (200 <= sr->sr_status && sr->sr_status < 300) { - sip_expires_t ex[1]; - - sip_expires_init(ex); - - if (nu) { - sip_time_t now = sip_now(); - - if (nu->nu_requested) { - if (sip->sip_expires) { - /* Expires in response can only shorten the expiration time */ - if (nu->nu_requested > now + sip->sip_expires->ex_delta) - nu->nu_requested = now + sip->sip_expires->ex_delta; - } - else { - unsigned sub_expires = NH_PGET(sr->sr_owner, sub_expires); - if (nu->nu_requested > now + sub_expires) - nu->nu_requested = now + sub_expires; - } - - if (nu->nu_requested >= now) - nu->nu_expires = nu->nu_requested; - else - nu->nu_expires = now; - - if (nu->nu_expires <= now) - nu->nu_substate = nua_substate_terminated; - } - - if (nu->nu_expires > now) - ex->ex_delta = nu->nu_expires - now; - } - else { - /* Always add header Expires: 0 */ - } - - if (!sip->sip_expires || sip->sip_expires->ex_delta > ex->ex_delta) - sip_add_dup(msg, sip, (sip_header_t *)ex); - } - - return nua_base_server_respond(sr, tags); -} - -static -int nua_subscribe_server_report(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_dialog_usage_t *du = sr->sr_usage; - struct notifier_usage *nu = nua_dialog_usage_private(du); - enum nua_substate substate = nua_substate_terminated; - int notify = 0; - int retval; - - if (nu && !sr->sr_terminating) { - substate = nu->nu_substate; - } - - /* nu_requested is set by SUBSCRIBE and cleared when NOTIFY is sent */ - if (nu && nu->nu_requested && substate != nua_substate_embryonic) { -#if SU_HAVE_EXPERIMENTAL - sip_t const *sip = sr->sr_request.sip; - sip_suppress_notify_if_match_t *snim = sip_suppress_notify_if_match(sip); - sip_suppress_body_if_match_t *sbim = sip_suppress_body_if_match(sip); - - if (!nu->nu_tag) - notify = 1; - else if (snim && su_casematch(snim->snim_tag, nu->nu_tag)) - notify = 0; - else if (sbim && su_casematch(snim->snim_tag, nu->nu_tag)) - notify = 1, nu->nu_no_body = 1; - else -#endif - notify = 1; - - notify = notify && du->du_cr != NULL; - } - - retval = nua_base_server_treport(sr, NUTAG_SUBSTATE(substate), TAG_END()); - - if (retval >= 2 || du == NULL) - return retval; - - if (notify) { - /* Send NOTIFY (and terminate subscription, when needed) */ - nua_dialog_usage_refresh(nh, ds, du, sip_now()); - } - - return retval; -} - -/* ======================================================================== */ -/* NOTIFY client */ - -/**@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. The subscription state can be modified - * with NUTAG_SUBSTATE(), however, its effect is overriden by - * @SubscriptionState header included in the nua_notify() tags. - * - * @bug If the @Event is not given by application, stack uses the @Event - * header from the first subscription usage on handle. - * - * If there is no active notifier dialog usage or no notifier dialog - * usage matches the @Event header given by the application the nua_notify() - * request is rejected locally by the stack with status code 481. The local - * rejection can be bypassed if NUTAG_NEWSUB(1) is included in tags. - * - * Please note that including NUTAG_NEWSUB(1) in nua_notify() tags if there - * is a valid subscription may lead to an extra NOTIFY sent to subscriber if - * the subscription had been terminated by the subscriber or by a timeout - * before the nua_notify() is processed. - * - * @param nh Pointer to operation handle - * @param tag, value, ... List of tagged parameters - * - * @return - * nothing - * - * @par Related Tags: - * NUTAG_SUBSTATE() \n - * NUTAG_NEWSUB() \n - * Tags of nua_set_hparams() \n - * Header tags defined in - * - * @par Events: - * #nua_r_notify - * - * @sa @RFC3265, #nua_i_subscribe, #nua_i_refer, NUTAG_ALLOW_EVENTS() - */ - -#if 0 -static int nua_notify_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); - - -static int nua_notify_client_init_etag(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); - -static int nua_notify_client_request(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_notify_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); -#endif -#if 0 -static nua_client_methods_t const nua_notify_client_methods = { - SIP_METHOD_NOTIFY, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - nua_notify_client_init, /* crm_init */ - nua_notify_client_request, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - nua_notify_client_report, /* crm_report */ - NULL, /* crm_complete */ -}; -#endif - -nua_client_methods_t const nua_notify_client_methods = { - SIP_METHOD_NOTIFY, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - NULL, /* crm_init */ - NULL, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -/**@internal Send NOTIFY. */ -int nua_stack_notify(nua_t *nua, - nua_handle_t *nh, - nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_notify_client_methods, tags); -} -#if 0 -static int nua_notify_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du; - struct notifier_usage *nu; - sip_event_t const *o = sip->sip_event; - sip_subscription_state_t *ss = sip->sip_subscription_state; - sip_time_t now = sip_now(); - - if (o == NULL && nh->nh_ds->ds_has_notifys == 1) - o = NONE; - - du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o); - - if (!du) { - tagi_t const *newsub = tl_find_last(tags, nutag_newsub); - - if (!newsub || !newsub->t_value) - return 0; /* Rejected eventually by nua_notify_client_request() */ - - /* Create new notifier */ - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o); - if (du == NULL) - return -1; - - nu = nua_dialog_usage_private(du); - nu->nu_expires = now; - } - else - nu = nua_dialog_usage_private(du); - - - if (nu->nu_substate == nua_substate_terminated) { - /*Xyzzy*/; - } - else if (ss != NULL) { - /* SIPTAG_SUBSCRIPTION_STATE() overrides NUTAG_SUBSTATE() */ - nu->nu_substate = nua_substate_make(ss->ss_substate); - - if (ss->ss_expires) { - unsigned long expires = strtoul(ss->ss_expires, NULL, 10); - if (now + expires < now) - expires = SIP_TIME_MAX - now - 1; - - /* We can change the lifetime of unsolicited subscription at will */ - if (nu->nu_requested == 0) - nu->nu_expires = nu->nu_requested = now + expires; - /* Notifier can only shorten the subscribed time */ - else if (nu->nu_requested >= now + expires) - nu->nu_expires = nu->nu_requested = now + expires; - } - else { - if (nu->nu_requested >= nu->nu_expires) - nu->nu_expires = nu->nu_requested; - } - - } - else { - enum nua_substate substate = nu->nu_substate; - - if (nu->nu_requested >= nu->nu_expires) - nu->nu_expires = nu->nu_requested; - - if (nu->nu_expires > now) { - tagi_t const *t = tl_find_last(tags, nutag_substate); - if (t) - substate = (enum nua_substate)t->t_value; - } - else - substate = nua_substate_terminated; - - switch (substate) { - case nua_substate_embryonic: - /*FALLTHROUGH*/ - case nua_substate_pending: - nu->nu_substate = nua_substate_pending; - break; - case nua_substate_active: - default: - nu->nu_substate = nua_substate_active; - break; - case nua_substate_terminated: - nu->nu_substate = nua_substate_terminated; - break; - } - } - - cr->cr_usage = du; - - return nua_notify_client_init_etag(cr, msg, sip, tags); -} - -static int nua_notify_client_init_etag(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ -#if SU_HAVE_EXPERIMENTAL - nua_handle_t *nh = cr->cr_owner; - struct notifier_usage *nu = nua_dialog_usage_private(cr->cr_usage); - nua_server_request_t *sr; - - if (nu->nu_tag) - su_free(nh->nh_home, nu->nu_tag), nu->nu_tag = NULL; - nu->nu_no_body = 0; - - if (sip->sip_etag) { - nu->nu_appl_etags = 1; - nu->nu_tag = su_strdup(nh->nh_home, sip->sip_etag->g_string); - } - else if (!nu->nu_appl_etags && nu->nu_etags) { - su_md5_t md5[1]; - unsigned char digest[SU_MD5_DIGEST_SIZE]; - sip_payload_t pl[1] = { SIP_PAYLOAD_INIT() }; - char token[2 * 16]; - - su_md5_init(md5); - - if (sip->sip_payload) *pl = *sip->sip_payload; - - if (pl->pl_len) - su_md5_update(md5, pl->pl_data, pl->pl_len); - su_md5_update(md5, &pl->pl_len, sizeof(pl->pl_len)); - - if (sip->sip_content_type) - su_md5_striupdate(md5, sip->sip_content_type->c_type); - - su_md5_digest(md5, digest); - token64_e(token, sizeof token, digest, sizeof digest); - token[(sizeof token) - 1] = '\0'; - nu->nu_tag = su_strdup(nh->nh_home, token); - } - - if (!nu->nu_requested || !nu->nu_tag) - return 0; - - /* Check if SUBSCRIBE had matching suppression */ - for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) - if (sr->sr_usage == cr->cr_usage && sr->sr_method == sip_method_subscribe) - break; - - if (sr) { - sip_t const *sip = sr->sr_request.sip; - - sip_suppress_body_if_match_t *sbim; - sip_suppress_notify_if_match_t *snim; - - if (cr->cr_usage->du_ready) { - snim = sip_suppress_notify_if_match(sip); - - if (snim && su_casematch(snim->snim_tag, nu->nu_tag)) { - if (nu->nu_requested > nu->nu_expires) - nu->nu_expires = nu->nu_requested; - nu->nu_requested = 0; - return nua_client_return(cr, 202, "NOTIFY Suppressed", msg); - } - } - - sbim = sip_suppress_body_if_match(sip); - if (sbim && su_casematch(sbim->sbim_tag, nu->nu_tag)) - nu->nu_no_body = 1; - } -#endif - - return 0; -} - -static -int nua_notify_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_dialog_usage_t *du = cr->cr_usage; - struct notifier_usage *nu = nua_dialog_usage_private(du); - su_home_t *home = msg_home(msg); - sip_time_t now = sip_now(); - sip_subscription_state_t *ss = sip->sip_subscription_state; - char const *expires; - - if (du == NULL) /* Subscription has been terminated */ - return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); - - assert(du && nu); - - if (du && nua_client_bind(cr, du) < 0) - return -1; - - if (nu->nu_requested) - nu->nu_expires = nu->nu_requested; - nu->nu_requested = 0; - - if (nu->nu_expires <= now || du->du_shutdown) { - nu->nu_substate = nua_substate_terminated; - expires = "expires=0"; - } - else { - expires = su_sprintf(home, "expires=%lu", nu->nu_expires - now); - } - - if (ss == NULL || nua_substate_make(ss->ss_substate) != nu->nu_substate) { - if (nu->nu_substate == nua_substate_terminated) - expires = nu->nu_expires > now ? "reason=noresource" : "reason=timeout"; - - ss = sip_subscription_state_format(home, "%s;%s", - nua_substate_name(nu->nu_substate), - expires); - - msg_header_insert(msg, (void *)sip, (void *)ss); - } - else if (nu->nu_substate != nua_substate_terminated) { - msg_header_replace_param(home, ss->ss_common, expires); - } - -#if SU_HAVE_EXPERIMENTAL - if (nu->nu_tag && !sip->sip_etag) - msg_header_add_make(msg, (void *)sip, sip_etag_class, nu->nu_tag); - - if (nu->nu_no_body) { - nu->nu_no_body = 0; - msg_header_remove(msg, (void *)sip, (void *)sip->sip_payload); - msg_header_remove(msg, (void *)sip, (void *)sip->sip_content_length); - } -#endif - - if (nu->nu_substate == nua_substate_terminated) - nua_client_set_terminating(cr, 1); - - if (cr->cr_terminating) { - nua_server_request_t *sr; - for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) { - if (sr->sr_usage == du) { - /* If subscribe has not been responded, don't terminate usage by NOTIFY */ - sr->sr_terminating = 1; - // nua_client_set_terminating(cr, 0); - break; - } - } - } - - if (du->du_event && !sip->sip_event) - sip_add_dup(cr->cr_msg, sip, (sip_header_t *)du->du_event); - - return nua_base_client_request(cr, msg, sip, tags); -} -#endif -/** @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). - * - * The current subscription state is included in NUTAG_SUBSTATE() tag. The - * nua_substate_terminated indicates that the subscription is terminated, - * the notifier usage has been removed and when there was no other usages of - * the dialog the dialog state is also removed. - * - * @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 - * SIPTAG_EVENT() indicating subscription event - * - * @sa nua_notify(), @RFC3265, #nua_i_subscribe, #nua_i_refer, NUTAG_SUBSTATE() - * - * @END_NUA_EVENT - */ -#if 0 -static int nua_notify_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - struct notifier_usage *nu = nua_dialog_usage_private(du); - enum nua_substate substate = nua_substate_terminated; - - if (nu && !cr->cr_terminated) - substate = nu->nu_substate; - - nua_stack_tevent(nh->nh_nua, nh, - nta_outgoing_getresponse(orq), - (enum nua_event_e)cr->cr_event, - status, phrase, - NUTAG_SUBSTATE(substate), - SIPTAG_EVENT(du ? du->du_event : NULL), - TAG_NEXT(tags)); - - if (du && du->du_cr == cr && !cr->cr_terminated) { - if (nu->nu_requested) { - /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */ - nua_client_resend_request(cr, 0); - } - else if (nu->nu_expires) { - nua_dialog_usage_set_refresh_at(du, nu->nu_expires); - } - } - - return 0; -} -#endif - -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); - nua_client_request_t *cr = du->du_cr; - nua_event_t e = nua_r_notify; - - if (cr) { - int terminating = 0; - - if (nu->nu_expires && nu->nu_expires <= now) - terminating = 1; - else if (nu->nu_requested && nu->nu_requested <= now) - terminating = 1; - - if (nua_client_resend_request(cr, terminating) >= 0) - return; - } - else { - if (nua_client_create(nh, e, &nua_notify_client_methods, NULL) >= 0) - return; - } - - nua_stack_tevent(nh->nh_nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), - NUTAG_SUBSTATE(nua_substate_terminated), - TAG_END()); - - nua_dialog_usage_remove(nh, ds, du, NULL, 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) -{ - struct notifier_usage *nu = nua_dialog_usage_private(du); - //nua_client_request_t *cr = du->du_cr; - - if (!nu) - return -1; - - nu->nu_substate = nua_substate_terminated; -#if 0 - if (cr) { - SU_DEBUG_5(("%s(%p, %p, %p): using existing cr=%p\n", - "nua_notify_usage_shutdown", - (void *)nh, (void *)ds, (void *)du, (void *)cr)); - - if (nua_client_resend_request(cr, 1) >= 0) - return 0; - } - else { - SU_DEBUG_5(("%s(%p, %p, %p): new NOTIFY cr for %s\n", - "nua_notify_usage_shutdown", - (void *)nh, (void *)ds, (void *)du, - du->du_event ? du->du_event->o_type : "")); - - if (nua_client_tcreate(nh, nua_r_notify, - &nua_notify_client_methods, - SIPTAG_EVENT(du->du_event), - NUTAG_SUBSTATE(nua_substate_terminated), - TAG_END()) >= 0) - return 0; - } -#endif - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - return 200; -} - -/* ======================================================================== */ -/* REFER */ -/* RFC 3515 */ - -static int nua_refer_server_init(nua_server_request_t *sr); -static int nua_refer_server_preprocess(nua_server_request_t *sr); -static int nua_refer_server_respond(nua_server_request_t*, tagi_t const *); -static int nua_refer_server_report(nua_server_request_t*, tagi_t const *); - -nua_server_methods_t const nua_refer_server_methods = - { - SIP_METHOD_REFER, - nua_i_refer, /* Event */ - { - 1, /* Create dialog */ - 0, /* Initial request */ - 1, /* Target refresh request */ - 1, /* Add Contact */ - }, - nua_refer_server_init, - nua_refer_server_preprocess, - nua_base_server_params, - nua_refer_server_respond, - nua_refer_server_report, - }; - -static int nua_refer_server_init(nua_server_request_t *sr) -{ - return 0; -} - -static int nua_refer_server_preprocess(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - sip_t const *sip = sr->sr_request.sip; - struct notifier_usage *nu; - sip_event_t *o; - - if (nh->nh_ds->ds_got_referrals || NH_PGET(nh, refer_with_id)) - o = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq); - else - o = sip_event_make(nh->nh_home, "refer"); - - if (o) { - sr->sr_usage = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o); - msg_header_free(nh->nh_home, (msg_header_t *)o); - } - - if (!sr->sr_usage) - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - - nu = nua_dialog_usage_private(sr->sr_usage); - nu->nu_requested = sip_now() + NH_PGET(nh, refer_expires); - - return 0; -} - -static -int nua_refer_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage); - sip_refer_sub_t const *rs = sip_refer_sub(sr->sr_response.sip); - - if (sr->sr_status < 200 || nu == NULL) { - } - else if (sr->sr_status < 300 && - /* No subscription if Refer-Sub: false in response */ - (rs == NULL || !su_casematch(rs->rs_value, "false"))) { - sr->sr_usage->du_ready = 1; - - nu->nu_expires = sip_now() + NH_PGET(nh, refer_expires); - - if (sr->sr_application) /* Application responded to REFER */ - nu->nu_substate = nua_substate_active; - } - else { - /* Destroy the implicit subscription usage */ - sr->sr_terminating = 1; - } - - return nua_base_server_respond(sr, tags); -} - - -/** @NUA_EVENT nua_i_refer - * - * Incoming @b REFER request used to transfer calls. The tag list will - * contain tag NUTAG_REFER_EVENT() with the @Event header constructed from - * the REFER request. It will also contain the SIPTAG_REFERRED_BY() tag with - * the @ReferredBy header containing the identity of the party sending the - * REFER. The @ReferredBy structure contained in the tag is constructed from - * the @From header if the @ReferredBy header was not present in the REFER - * request. - * - * The application can let the nua to send NOTIFYs from the call it - * initiates with nua_invite() if it includes in the nua_invite() arguments - * both the NUTAG_NOTIFY_REFER() with the handle with which nua_i_refer was - * received and the NUTAG_REFER_EVENT() from #nua_i_refer event tags. - * - * @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 - */ - -static -int nua_refer_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - //nua_handle_t *nh = sr->sr_owner; - struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage); - sip_t const *sip = sr->sr_request.sip; - sip_referred_by_t *by = sip->sip_referred_by, default_by[1]; - sip_event_t const *o = sr->sr_usage->du_event; - enum nua_substate substate = nua_substate_terminated; - //int initial = sr->sr_initial, retval; - int retval; - - if (nu) { - if (!sr->sr_terminating) - substate = nu->nu_substate; - } - - if (by == NULL) { - by = sip_referred_by_init(default_by); - - by->b_display = sip->sip_from->a_display; - *by->b_url = *sip->sip_from->a_url; - } - - retval = nua_base_server_treport(sr, - NUTAG_SUBSTATE(substate), - NUTAG_REFER_EVENT(o), - TAG_IF(by, SIPTAG_REFERRED_BY(by)), - TAG_END()); - - if (retval >= 2 || nu == NULL) - return retval; - -#if 0 - if (initial) - nua_stack_post_signal(nh, - nua_r_notify, - SIPTAG_EVENT(o), - SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"), - TAG_END()); -#endif - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c deleted file mode 100644 index 0615d9c626..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 17:02:19 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#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: - * Header tags defined in - * - * @par Events: - * #nua_r_options - * - * @sa #nua_i_options, @RFC3261 section 10 - */ - -/** @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 nua_client_methods_t const nua_options_client_methods = { - SIP_METHOD_OPTIONS, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 0, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - NULL, /* crm_init */ - NULL, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int nua_stack_options(nua_t *nua, - nua_handle_t *nh, - nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_options_client_methods, tags); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c deleted file mode 100644 index 2140eff7da..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c +++ /dev/null @@ -1,1783 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "nua_stack.h" - -#include -#include -#include -#include - -#include - -/* ====================================================================== */ -/* 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) -{ - memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set)); - - /* Bitwise or of bitfields, casted to unsigned */ - a->nhp_set_.set_unsigned[0] |= b->nhp_set_.set_unsigned[0]; - a->nhp_set_.set_unsigned[1] |= b->nhp_set_.set_unsigned[1]; -} - -static int nhp_set_tags(su_home_t *home, - nua_handle_preferences_t *nhp, - nua_global_preferences_t *ngp, - 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 int nhp_save_params(nua_handle_t *nh, - su_home_t *tmphome, - nua_global_preferences_t *gsrc, - nua_handle_preferences_t *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 su_casenmatch(s, pn + 1, pnlen) || su_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, timer_autorequire, 1); - NHP_SET(nhp, invite_timeout, 120); - - nhp->nhp_session_timer = 1800; - nhp->nhp_refresher = nua_no_refresher; - - NHP_SET(nhp, min_se, 120); - 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, retry_after_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, sub_expires, 3600); - - 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, auto_invite_100, 1); - - 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]; - int set; - - tl_gets(tags, - /* By nua_stack_set_from() */ - SIPTAG_FROM_REF(from), - SIPTAG_FROM_STR_REF(str), - TAG_END()); - - 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); - set = 1; - } - else if (str && str != NONE) { - f = sip_from_make(nua->nua_home, str); - if (f) - *f0 = *f, f = f0, f->a_params = NULL; - set = 1; - } - 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); - } - set = 0; - } - - if (!f) - return -1; - - nua->nua_from_is_set = set; - *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_INITIAL_ROUTE() \n - * NUTAG_INITIAL_ROUTE_STR() \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_RETRY_AFTER_ENABLE() \n - * NUTAG_PROXY() (aka NTATAG_DEFAULT_PROXY()) \n - * NUTAG_REFER_EXPIRES() \n - * NUTAG_REFER_WITH_ID() \n - * NUTAG_REFRESH_WITHOUT_SDP() \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_SUB_EXPIRES() \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 - * , and nta tags, defined in . - * - * @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 SUBSCRIBE and the - * header @Organization will have value The Phone Company. - * - */ - -/**@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_AUTH_CACHE() \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_INITIAL_ROUTE() \n - * NUTAG_INITIAL_ROUTE_STR() \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_RETRY_AFTER_ENABLE() \n - * NUTAG_PROXY() (aka NTATAG_DEFAULT_PROXY()) \n - * NUTAG_REFER_EXPIRES() \n - * NUTAG_REFER_WITH_ID() \n - * NUTAG_REFRESH_WITHOUT_SDP() \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_SUB_EXPIRES() \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 . - * - * 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; - - int status; - char const *phrase; - - nua_handle_preferences_t tmp[1]; - int any_changes = 0; - - enter; - - { - su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) }; - nua_handle_preferences_t *nhp = nh->nh_prefs; - nua_handle_preferences_t const *dnhp = dnh->nh_prefs; - nua_global_preferences_t gtmp[1], *ngp = NULL; - - *tmp = *nhp; NHP_UNSET_ALL(tmp); - - /* - * Supported features, allowed methods and events are merged - * with previous or default settings. - * - * Here we just copy pointers from default settings. However when saving - * settings we have to be extra careful so that we - * 1) zero the pointers if the setting has not been modified - * 2) do not free pointer if the setting has been modified - * See NHP_ZAP_OVERRIDEN() below for gorier details. - */ - if (!NHP_ISSET(nhp, supported)) - tmp->nhp_supported = dnhp->nhp_supported; - if (!NHP_ISSET(nhp, allow)) - tmp->nhp_allow = dnhp->nhp_allow; - if (!NHP_ISSET(nhp, allow_events)) - tmp->nhp_allow_events = dnhp->nhp_allow_events; - if (!NHP_ISSET(nhp, appl_method)) - tmp->nhp_appl_method = dnhp->nhp_appl_method; - - if (nh == dnh) /* nua_set_params() call, save stack-wide params, too */ - ngp = gtmp, *gtmp = *nua->nua_prefs; - - /* Set and save parameters to tmp */ - if (!nh->nh_used_ptags && - nhp_set_tags(tmphome, tmp, NULL, nh->nh_ptags) < 0) - status = 900, phrase = "Error storing default handle parameters"; - else if (nhp_set_tags(tmphome, tmp, ngp, tags) < 0) - status = 900, phrase = "Error storing parameters"; - else if ((any_changes = nhp_save_params(nh, tmphome, ngp, tmp)) < 0) - status = 900, phrase = su_strerror(ENOMEM); - else - status = 200, phrase = "OK", nh->nh_used_ptags = 1; - - su_home_deinit(tmphome); - } - - if (status == 200) { - nua_handle_preferences_t const *nhp = nh->nh_prefs; - nua_handle_preferences_t const *dnhp = dnh->nh_prefs; - - 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); - - if (!nh->nh_soa) - status = 900, phrase = "Error Creating SOA Object"; - else if (soa_set_params(nh->nh_soa, TAG_NEXT(nh->nh_ptags)) < 0) - status = 900, phrase = "Error Setting SOA Parameters"; - } - 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 (status == 200 && tags && nh->nh_soa && - soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0) - status = 900, phrase = "Error Setting SOA Parameters"; - } - - if (status == 200 && nh == dnh) { - /* Set stack-specific things below */ - if (nua_stack_set_smime_params(nua, tags) < 0) { - status = 900, phrase = "Error setting S/MIME parameters"; - } - else if (nua->nua_nta && - nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) { - status = 900, phrase = "Error setting NTA parameters"; - } - else { - nua_stack_set_from(nua, 0, tags); - - if (nua->nua_prefs->ngp_detect_network_updates) - nua_stack_launch_network_change_detector(nua); - } - } - - if (status != 200) { - if (e == nua_i_none) - SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase)); - return UA_EVENT2(e, status, phrase), -1; - } - else { - if (e == nua_r_set_params) - UA_EVENT2(e, status, phrase); - - if (any_changes) { - nua_handle_preferences_t changed[1]; - - *changed = *nh->nh_prefs; - memcpy(&changed->nhp_set_, &tmp->nhp_set_, sizeof changed->nhp_set_); - - nua_dialog_update_params(nh->nh_ds, - changed, - nh->nh_prefs, - dnh->nh_prefs); - } - return 0; - } -} - - -/** Parse parameters from tags to @a nhp or @a ngp. - * - * @param home allocate new values from @a home - * @param nhp structure to store handle preferences - * @param ngp structure to store global preferences - * @param tags list of tags to parse - */ -static int nhp_set_tags(su_home_t *home, - nua_handle_preferences_t *nhp, - nua_global_preferences_t *ngp, - 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, type, name, v) \ - if ((v) != (tag_value_t)-1) { \ - url_t const *_value = (url_t const *)(v); \ - type *_new = (type *)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, hdr, v) \ - if ((v) != 0) { \ - sip_##hdr##_t const *_value = (sip_##hdr##_t const *)(v); \ - sip_##hdr##_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, hdr, v) \ - if ((v) != 0) { \ - char const *_value = (char const *)(v); \ - sip_##hdr##_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; \ - } - -/* Append copy of header to handle pref structure */ -#define NHP_APPEND_HEADER(nhp, name, hdr, is_str, next, v) \ - { \ - sip_##hdr##_t const *_value = (sip_##hdr##_t const *)(v); \ - char const *_str = (char const *)(v); \ - sip_##hdr##_t *_new = NULL; \ - sip_##hdr##_t **_end = &nhp->nhp_##name; \ - if (_value != SIP_NONE && _value != NULL) { \ - _new = (is_str) \ - ? sip_##hdr##_make(home, _str) \ - : sip_##hdr##_dup(home, _value); \ - if (_new == NULL) return -1; \ - } \ - if (NHP_ISSET(nhp, name)) \ - while(*_end) \ - _end = next(*_end); \ - nhp->nhp_set.nhb_##name = 1; \ - *_end = _new; \ - } - -/* 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_TIMER_AUTOREQUIRE(timer_autorequire) */ - else if (tag == nutag_timer_autorequire) { - NHP_SET(nhp, timer_autorequire, 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, (enum nua_session_refresher)refresher); - } - /* NUTAG_UPDATE_REFRESH(update_refresh) */ - else if (tag == nutag_update_refresh) { - NHP_SET(nhp, update_refresh, value != 0); - } - /* NUTAG_REFRESH_WITHOUT_SDP(refresh_without_sdp) */ - else if (tag == nutag_refresh_without_sdp) { - NHP_SET(nhp, refresh_without_sdp, 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); - } - /* 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_RETRY_AFTER_ENABLE(retry_after_enable) */ - else if (tag == nutag_retry_after_enable) { - NHP_SET(nhp, retry_after_enable, value != 0); - } - /* NUTAG_AUTH_CACHE(auth_cache) */ - else if (tag == nutag_auth_cache) { - if (value >= 0 && value < (tag_value_t)_nua_auth_cache_invalid) - NHP_SET(nhp, auth_cache, (int)value); - } - /* 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_SUB_EXPIRES(sub_expires) */ - else if (tag == nutag_sub_expires) { - NHP_SET(nhp, sub_expires, 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, - /* already set by tags? */ - NHP_ISSET(nhp, appl_method), - 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); - } - } - else if (tag == nutag_initial_route || - tag == nutag_initial_route_str) { -#define next_route(r) (&(r)->r_next) - NHP_APPEND_HEADER(nhp, initial_route, route, - (tag == nutag_initial_route_str), - next_route, - t->t_value); - sip_route_fix(nhp->nhp_initial_route); - } - /* 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); - } - /* SIPTAG_VIA(via) */ - else if (tag == siptag_via) { - NHP_SET_STR_BY_HEADER(nhp, via, value); - } - /* SIPTAG_VIA_STR(via_str) */ - else if (tag == siptag_via_str) { - if (value == -1) - value = 0; - NHP_SET_STR(nhp, via, value); - } - /* NUTAG_REGISTRAR(registrar) */ - else if (tag == nutag_registrar) { - NHP_SET_STR_BY_URL(nhp, char, registrar, value); - if (NHP_ISSET(nhp, registrar) && su_strmatch(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_PROXY() (aka NTATAG_DEFAULT_PROXY()) */ - else if (tag == ntatag_default_proxy) { - NHP_SET_STR_BY_URL(nhp, url_string_t, proxy, value); - } - /* NUTAG_AUTO_INVITE_100() */ - else if (tag == nutag_auto_invite_100) { - NHP_SET(nhp, auto_invite_100, value != 0); - } - /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */ - else if (ngp && 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; - - ngp->ngp_detect_network_updates = detector; - ngp->ngp_set.ngp_detect_network_updates = 1; - } - /* NUTAG_SHUTDOWN_EVENTS() */ - else if (ngp && tag == nutag_shutdown_events) { - ngp->ngp_shutdown_events = value != 0; - ngp->ngp_set.ngp_shutdown_events = 1; - } - } - - 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; -} - -/** Save parameters in @a gtmp and @a tmp. - * - * @retval 1 - parameters were changed - * @retval 0 - no changes in parameters - * @retval -1 - an error - */ -static -int nhp_save_params(nua_handle_t *nh, - su_home_t *tmphome, - nua_global_preferences_t *gsrc, - nua_handle_preferences_t *src) -{ - su_home_t *home = nh->nh_home; - nua_t *nua = nh->nh_nua; - nua_handle_t *dnh = nua->nua_dhandle; - nua_handle_preferences_t *dst, old[1]; - - if (gsrc) { - *nua->nua_prefs = *gsrc; /* No pointers this far */ - } - - if (!NHP_IS_ANY_SET(src)) - return 0; - - if (nh == dnh || nh->nh_prefs != dnh->nh_prefs) { - dst = nh->nh_prefs, *old = *dst; - } - else { - dst = su_zalloc(home, sizeof *dst), memset(old, 0, sizeof *old); - if (!dst) - return -1; - } - - /* Move allocations from tmphome to home */ - su_home_move(nh->nh_home, tmphome); - - /* Copy parameters that are set from src to dst */ - nhp_or_set(dst, src); - - /* Handle pointer items. Free changed ones and zap unset ones. */ - /* Note that pointer items where !NHP_ISSET(old, pref) are not freed - (because they were just on loan from the default preference set) */ -#define NHP_ZAP_OVERRIDEN(old, dst, free, pref) \ - (((NHP_ISSET(old, pref) && \ - (old)->nhp_##pref && (old)->nhp_##pref != (dst)->nhp_##pref) \ - ? (free)(home, (void *)(old)->nhp_##pref) : (void)0), \ - (void)(!(dst)->nhp_set.nhb_##pref ? (dst)->nhp_##pref = NULL : NULL)) - - NHP_ZAP_OVERRIDEN(old, dst, su_free, soa_name); - NHP_ZAP_OVERRIDEN(old, dst, su_free, registrar); - NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow); - NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, supported); - NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow_events); - NHP_ZAP_OVERRIDEN(old, dst, su_free, user_agent); - NHP_ZAP_OVERRIDEN(old, dst, su_free, organization); - NHP_ZAP_OVERRIDEN(old, dst, su_free, via); - NHP_ZAP_OVERRIDEN(old, dst, su_free, m_display); - NHP_ZAP_OVERRIDEN(old, dst, su_free, m_username); - NHP_ZAP_OVERRIDEN(old, dst, su_free, m_params); - NHP_ZAP_OVERRIDEN(old, dst, su_free, m_features); - NHP_ZAP_OVERRIDEN(old, dst, su_free, instance); - NHP_ZAP_OVERRIDEN(old, dst, su_free, outbound); - NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, appl_method); - NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, initial_route); - - nh->nh_prefs = dst; - - return memcmp(dst, old, sizeof *dst) != 0; -} - -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) -{ - /* Initialization parameters */ - url_string_t const *url = NULL; - sip_to_t const *p_to = NULL; - char const *to_str = NULL; - 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; - -#if HAVE_OPEN_C - /* Nice. An old symbian compiler */ - tagi_t tagfilter[2]; - tagi_t paramfilter[2]; - - tagfilter[0].t_tag = tag_filter; - tagfilter[0].t_value = tag_filter_v(nua_handle_tags_filter); - tagfilter[1].t_tag = (tag_type_t)0; - tagfilter[1].t_value = (tag_value_t)0; - - paramfilter[0].t_tag = tag_filter; - paramfilter[0].t_value = tag_filter_v(nua_handle_param_filter); - paramfilter[1].t_tag = (tag_type_t)0; - paramfilter[1].t_value = (tag_value_t)0; - -#else - tagi_t const tagfilter[] = { - { TAG_FILTER(nua_handle_tags_filter) }, - { TAG_NULL() } - }; - tagi_t const paramfilter[] = { - { TAG_FILTER(nua_handle_param_filter) }, - { TAG_NULL() } - }; -#endif - - 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_sips_url) { - url = (url_string_t *)t->t_value; - } - /* NUTAG_WS_URL_REF(url) */ - else if (t->t_tag == nutag_ws_url) { - url = (url_string_t *)t->t_value; - } - /* NUTAG_WSS_URL_REF(url) */ - else if (t->t_tag == nutag_wss_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 - p_from = SIP_NONE; - - 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, - TAG_IF(p_from != SIP_NONE, SIPTAG_FROM(p_from)), - TAG_IF(p_from != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)), - TAG_IF(p_to != SIP_NONE, SIPTAG_TO(p_to)), - TAG_IF(p_to != SIP_NONE, 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_ws_url || - t->t_tag == nutag_wss_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_APPL_METHOD() \n - * NUTAG_AUTH_CACHE() \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_INITIAL_ROUTE() \n - * NUTAG_INITIAL_ROUTE_STR() \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_RETRY_AFTER_ENABLE() \n - * NUTAG_REFER_EXPIRES() \n - * NUTAG_REFER_WITH_ID() \n - * NUTAG_REFRESH_WITHOUT_SDP() \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_SUB_EXPIRES() \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_global_preferences_t const *ngp = nua->nua_prefs; - nua_handle_preferences_t const *nhp = nh->nh_prefs; - nua_handle_preferences_t const nhp_zero[1] = {{ 0 }}; - tagi_t *lst; - - int has_from; - sip_from_t from[1]; - - sip_contact_t const *m; - - /* nta */ - unsigned udp_mtu = 0; - usize_t max_proceeding = 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; - - if (nh == dnh) - nta_agent_get_params(nua->nua_nta, - NTATAG_UDP_MTU_REF(udp_mtu), - NTATAG_MAX_PROCEEDING_REF(max_proceeding), - 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 /* if (nua->nua_from_is_set) */ - has_from = 1, *from = *nua->nua_from; - - 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 tag in the list returned to user - * if it has been earlier set (by user) - * but always include in the default parameters */ -#define TIFD(TAG, pref) \ - TAG_IF(nh == dnh || 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)) - - if (nh != dnh && nhp == dnh->nh_prefs) - nhp = nhp_zero; - - su_home_auto(tmphome, sizeof(tmphome)); - - 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_TIMER_AUTOREQUIRE, timer_autorequire), - TIF(NUTAG_INVITE_TIMER, invite_timeout), - - TIFD(NUTAG_SESSION_TIMER, session_timer), - TIF(NUTAG_MIN_SE, min_se), - TIFD(NUTAG_SESSION_REFRESHER, refresher), - TIF(NUTAG_UPDATE_REFRESH, update_refresh), - TIF(NUTAG_REFRESH_WITHOUT_SDP, refresh_without_sdp), - - 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_RETRY_AFTER_ENABLE, retry_after_enable), - TIF(NUTAG_AUTH_CACHE, auth_cache), - TIF(NUTAG_REFER_EXPIRES, refer_expires), - TIF(NUTAG_REFER_WITH_ID, refer_with_id), - - TIF(NUTAG_SUBSTATE, substate), - TIF(NUTAG_SUB_EXPIRES, sub_expires), - - TIF(SIPTAG_SUPPORTED, supported), - TIF_STR(SIPTAG_SUPPORTED_STR, supported), - TIF(SIPTAG_ALLOW, allow), - TIF_STR(SIPTAG_ALLOW_STR, allow), - TIF_STR(NUTAG_APPL_METHOD, appl_method), - 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_SIP(SIPTAG_VIA, via), - TIF(SIPTAG_VIA_STR, via), - - TIF(NUTAG_INITIAL_ROUTE, initial_route), - TIF_STR(NUTAG_INITIAL_ROUTE_STR, initial_route), - - 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), - - /* Handle-specific proxy */ - TAG_IF(nh != dnh && nhp->nhp_set.nhb_proxy, - NUTAG_PROXY(nhp->nhp_proxy)), - - /* Skip user-agent-level parameters if parameters are for handle only */ - TAG_IF(nh != dnh, TAG_NEXT(media_params)), - - /* Include tag in the list returned to user - * if it has been earlier set (by user) */ -#define GIF(TAG, pref) \ - TAG_IF(ngp->ngp_set.ngp_##pref, TAG(ngp->ngp_##pref)) - - GIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates), - GIF(NUTAG_SHUTDOWN_EVENTS, shutdown_events), - - 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_MAX_PROCEEDING(max_proceeding), - 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), - /* Stack-wide proxy */ - 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, lst); - - su_home_deinit(tmphome); - - tl_vfree(media_params); - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h deleted file mode 100644 index d48ceca155..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NUA_PARAMS_H - -/**@internal @file nua_params.h - * @brief Parameters and their handling - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Wed Mar 8 11:38:18 EET 2006 ppessi - */ - -#include - -#ifndef NUA_TAG_H -#include -#endif - -/**@internal @brief 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() - */ -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 */ - - /**< Accept refreshes without SDP */ - unsigned nhp_refresh_without_sdp:1; - - /* 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; - /** Authentication cache policy */ - unsigned nhp_auth_cache:1; - - /** Always include id with Event: refer */ - unsigned nhp_refer_with_id:1; - - unsigned nhp_timer_autorequire:1; - - /** Enable Retry-After */ - unsigned nhp_retry_after_enable:1; - - /** Enable/Disable automatic 100 Trying when receiving INVITE */ - unsigned nhp_auto_invite_100: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; - unsigned nhp_sub_expires; - - /* 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_via; - - 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; - - sip_allow_t *nhp_appl_method; - - /** Initial route set */ - sip_route_t *nhp_initial_route; - - /** Next hop URI (used instead of route). */ - url_string_t *nhp_proxy; - - union { struct { - /* A bit for each feature set by application */ - /* NOTE: - Some compilers behave weird if there are bitfields - together with width > 32 - So there should be a padding field (unsigned:0;) - every 32 bits. - */ - 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_refresh_without_sdp: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_auth_cache:1; - unsigned nhb_refer_with_id:1; - unsigned nhb_refer_expires:1; - unsigned nhb_substate:1; - unsigned nhb_sub_expires:1; - unsigned nhb_keepalive:1; - unsigned nhb_keepalive_stream:1; - unsigned nhb_registrar:1; - unsigned :0; /* at most 32 bits before this point */ - - unsigned nhb_allow:1; - unsigned nhb_supported:1; - - unsigned nhb_allow_events:1; - unsigned nhb_user_agent:1; - unsigned nhb_organization:1; - unsigned nhb_via: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_appl_method:1; - unsigned nhb_initial_route:1; - unsigned nhb_proxy:1; - unsigned nhb_timer_autorequire:1; - unsigned nhb_retry_after_enable:1; - unsigned nhb_auto_invite_100:1; - unsigned :0; - } set_bits; - unsigned set_unsigned[2]; - } nhp_set_; -}; - -#define nhp_set nhp_set_.set_bits - -/** Global preferences for nua. */ -struct nua_global_preferences { - /** Network detection: NONE, INFORMAL, TRY_FULL */ - signed int ngp_detect_network_updates:3; - /** Pass events during shutdown, too */ - int ngp_shutdown_events:1; - - unsigned :0; /* pad */ - union { struct { - /* A bit for each feature set by application */ - unsigned ngp_detect_network_updates:1; - unsigned ngp_shutdown_events:1; - unsigned :0; - } set_bits; - unsigned set_unsigned[2]; - } ngp_set_; -}; - -#define ngp_set ngp_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_dprefs, 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) - -/* Check if preference has been set by application */ -#define NUA_PISSET(nua, nh, pref) \ - (NHP_ISSET((nua)->nua_dhandle->nh_prefs, pref) || \ - ((nh) && NHP_ISSET((nh)->nh_prefs, pref))) - -#endif /* NUA_PARAMS_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c deleted file mode 100644 index 2a55c345a7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 17:01:32 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "nua_stack.h" - -/* ====================================================================== */ -/* Publish usage */ - -struct publish_usage { - sip_etag_t *pu_etag; - int pu_published; -}; - -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, - nua_client_request_t *cr, - nua_server_request_t *sr); -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, - nua_base_usage_update_params, - 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, - nua_client_request_t *cr, - nua_server_request_t *sr -) -{ - 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 */ - -/**@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 - * Header tags defined in - * - * @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 - * Other header tags defined in except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR() - * - * @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 - */ - -static int nua_publish_client_template(nua_client_request_t *cr, - msg_t **return_msg, - tagi_t const *tags); -static int nua_publish_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_publish_client_request(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_publish_client_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_publish_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); - -static nua_client_methods_t const nua_publish_client_methods = { - SIP_METHOD_PUBLISH, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 0, - /* target refresh */ 0 - }, - nua_publish_client_template, /* crm_template */ - nua_publish_client_init, /* crm_init */ - nua_publish_client_request, /* crm_send */ - nua_publish_client_check_restart, /* crm_check_restart */ - nua_publish_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -/**@internal Send PUBLISH. */ -int nua_stack_publish(nua_t *nua, - nua_handle_t *nh, - nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_publish_client_methods, tags); -} - -static int nua_publish_client_template(nua_client_request_t *cr, - msg_t **return_msg, - tagi_t const *tags) -{ - nua_dialog_usage_t *du; - - if (cr->cr_event == nua_r_publish) - return 0; - - du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_publish_usage, NULL); - if (du && du->du_cr) { - if (nua_client_set_target(cr, du->du_cr->cr_target) < 0) - return -1; - *return_msg = msg_copy(du->du_cr->cr_msg); - return 1; - } - - return 0; -} - -static int nua_publish_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du; - struct publish_usage *pu; - - if (cr->cr_event == nua_r_publish) { - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL); - if (!du) - return -1; - pu = nua_dialog_usage_private(du); - pu->pu_published = 0; - if (sip->sip_if_match) { - pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_if_match); - if (!pu->pu_etag) - return -1; - sip_header_remove(msg, sip, (sip_header_t *)sip->sip_if_match); - } - } - else - du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL); - - cr->cr_usage = du; - - return 0; -} - -static -int nua_publish_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_dialog_usage_t *du = cr->cr_usage; - int un, done; - sip_etag_t const *etag = NULL; - - un = cr->cr_terminating || - cr->cr_event != nua_r_publish || - (du && du->du_shutdown) || - (sip->sip_expires && sip->sip_expires->ex_delta == 0); - nua_client_set_terminating(cr, un); - done = un; - - if (du) { - struct publish_usage *pu = nua_dialog_usage_private(du); - - if (nua_client_bind(cr, du) < 0) - return -1; - if (pu->pu_published) - done = 1; - etag = pu->pu_etag; - } - - return nua_base_client_trequest(cr, msg, sip, - SIPTAG_IF_MATCH(etag), - TAG_IF(done, SIPTAG_PAYLOAD(NONE)), - TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)), - TAG_IF(un, SIPTAG_EXPIRES_STR("0")), - TAG_NEXT(tags)); -} - -static int nua_publish_client_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - char const *restarting = NULL; - - if (cr->cr_terminating || !cr->cr_usage) - ; - else if (status == 412) - restarting = phrase; - else if (200 <= status && status < 300 && - sip->sip_expires && sip->sip_expires->ex_delta == 0) - restarting = "Immediate re-PUBLISH"; - - if (restarting) { - struct publish_usage *pu = nua_dialog_usage_private(cr->cr_usage); - - if (pu) { - pu->pu_published = 0; - su_free(cr->cr_owner->nh_home, pu->pu_etag), pu->pu_etag = NULL; - if (nua_client_restart(cr, 100, restarting)) - return 0; - } - } - - return nua_base_client_check_restart(cr, status, phrase, sip); -} - -static int nua_publish_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - - if (!cr->cr_terminated && du && sip) { - struct publish_usage *pu = nua_dialog_usage_private(du); - sip_expires_t const *ex = sip->sip_expires; - - /* Reset state */ - pu->pu_published = 0; - if (pu->pu_etag) - su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL; - - if (status < 300) { - pu->pu_published = 1; - pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_etag); - - if (!ex || ex->ex_delta == 0 || !pu->pu_etag) { - cr->cr_terminated = 1; - - if (!ex || ex->ex_delta == 0) - SET_STATUS(900, "Received Invalid Expiration Time"); - else - SET_STATUS(900, _NUA_INTERNAL_ERROR_AT(__FILE__, __LINE__)); - } - else - nua_dialog_usage_set_refresh(du, ex->ex_delta); - } - } - - return nua_base_client_response(cr, status, phrase, sip, NULL); -} - -static void nua_publish_usage_refresh(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - sip_time_t now) -{ - nua_client_request_t *cr = du->du_cr; - - if (cr) { - if (nua_client_resend_request(cr, 0) >= 0) - return; - } - - nua_stack_event(nh->nh_nua, nh, NULL, - nua_r_publish, NUA_ERROR_AT(__FILE__, __LINE__), - NULL); - - nua_dialog_usage_remove(nh, ds, du, NULL, 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 = du->du_cr; - - if (cr) { - if (nua_client_resend_request(cr, 1) >= 0) - return 0; - } - - /* XXX - report to user */ - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - return 200; -} - -/* ---------------------------------------------------------------------- */ -/* Server side */ - -/** @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_THIS()/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_publish_server_init(nua_server_request_t *sr); - -nua_server_methods_t const nua_publish_server_methods = - { - SIP_METHOD_PUBLISH, - nua_i_publish, /* Event */ - { - 0, /* Do not create dialog */ - 0, /* Initial request */ - 0, /* Not a target refresh request */ - 1, /* Add Contact */ - }, - nua_publish_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_base_server_report, - }; - -int nua_publish_server_init(nua_server_request_t *sr) -{ - sip_allow_events_t *allow_events = NH_PGET(sr->sr_owner, allow_events); - sip_event_t *o = sr->sr_request.sip->sip_event; - char const *event = o ? o->o_type : NULL; - - if (!allow_events) - return SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED); - else if (!event || !msg_header_find_param(allow_events->k_common, event)) - return SR_STATUS1(sr, SIP_489_BAD_EVENT); - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c deleted file mode 100644 index 5c2fa1a33b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c +++ /dev/null @@ -1,2167 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Martti Mela - * @author Kai Vehmanen - * - * @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 - -#define TP_CLIENT_T struct register_usage - -#include -#include -#include -#include - -#include -#include -#include - -#define NTA_UPDATE_MAGIC_T struct nua_s -#define NTA_ERROR_MAGIC_T struct nua_s - -#include "nua_stack.h" - -#include -#include -#include -#include - -#define OUTBOUND_OWNER_T struct nua_handle_s - -#include "outbound.h" - -#if HAVE_SIGCOMP -#include -#endif - -#include -#include -#include -#include - -#include - -/* ======================================================================== */ -/* 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, - nua_client_request_t *cr, - nua_server_request_t *sr); -static void nua_register_usage_update_params(nua_dialog_usage_t const *du, - nua_handle_preferences_t const *, - nua_handle_preferences_t const *, - nua_handle_preferences_t const *); -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 *); - -/** @internal @brief 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_contact_t nr_dcontact[1]; /**< Contact in dialog */ - sip_via_t *nr_via; /**< Corresponding Via headers */ - - unsigned long nr_min_expires; /**< Value from 423 negotiation */ - - /** 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; - - unsigned:0; - - int nr_error_report_id; /**< ID used to ask for error reports from tport */ - - 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_update_params, - 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_client_request_t *cr, - nua_server_request_t *sr) -{ - 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 - - if (nr->nr_error_report_id) - tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0); - - if (nr->nr_tport) - tport_unref(nr->nr_tport), nr->nr_tport = NULL; - - 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 nua_register_connection_closed(tp_stack_t *sip_stack, - nua_registration_t *nr, - tport_t *tport, - msg_t *msg, - int error); - -/* Interface towards outbound_t */ -sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh, - su_home_t *home, - int in_dialog, - sip_via_t const *v, - char const *transport, - char const *m_param, - ...); - -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, - /* oo_contact */ nua_handle_contact_by_via, - /* oo_refresh */ nua_stack_outbound_refresh, - /* oo_status */ nua_stack_outbound_status, - /* oo_probe_error */ nua_stack_outbound_failed, - /* oo_keepalive_error */ nua_stack_outbound_failed, - /* oo_credentials */ 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 - * ;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@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 - * - * draft-lennox-sip-reg-payload-01.txt. - * - * 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. - * - * As alternative to OPTIONS/STUN keepalives, the client can propose - * a more frequent registration refresh interval with - * NUTAG_M_FEATURES() (e.g. NUTAG_M_FEATURES("expires=120") given as - * parameter to nua_register()). - * - * @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 - * Header tags defined in 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 - */ - -static int nua_register_client_template(nua_client_request_t *cr, - msg_t **return_msg, - tagi_t const *tags); -static int nua_register_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_register_client_request(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_register_client_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_register_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); - -static nua_client_methods_t const nua_register_client_methods = { - SIP_METHOD_REGISTER, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 0, - /* target refresh */ 0 - }, - nua_register_client_template, /* crm_template */ - nua_register_client_init, /* crm_init */ - nua_register_client_request, /* crm_send */ - nua_register_client_check_restart, /* crm_check_restart */ - nua_register_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -/**@internal Send REGISTER. */ -int nua_stack_register(nua_t *nua, - nua_handle_t *nh, - nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_register_client_methods, tags); -} - -static int nua_register_client_template(nua_client_request_t *cr, - msg_t **return_msg, - tagi_t const *tags) -{ - nua_dialog_usage_t *du; - - if (cr->cr_event == nua_r_register) - return 0; - - /* Use a copy of REGISTER message as the template for un-REGISTER */ - du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_register_usage, NULL); - if (du && du->du_cr) { - if (nua_client_set_target(cr, du->du_cr->cr_target) < 0) - return -1; - *return_msg = msg_copy(du->du_cr->cr_msg); - return 1; - } - - return 0; -} - -static int nua_register_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du; - nua_registration_t *nr; - sip_to_t const *aor = sip->sip_to; - - int unreg; - - /* Explicit empty (NULL) contact - used for CPL store/remove? */ - if (!sip->sip_contact && cr->cr_has_contact) - /* Do not create any usage */ - return 0; - - unreg = cr->cr_event != nua_r_register || - (sip->sip_expires && sip->sip_expires->ex_delta == 0); - if (unreg) - nua_client_set_terminating(cr, 1); - - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_register_usage, NULL); - if (du == NULL) - return -1; - nr = nua_dialog_usage_private(du); - - if (nua_client_bind(cr, du) < 0) - return -1; - - if (!nr->nr_list) { - nua_registration_add(&nh->nh_nua->nua_registrations, nr); - - if (aor == NULL) - aor = sip->sip_from; - if (aor == NULL) - aor = nh->nh_nua->nua_from; - - if (nua_registration_set_aor(nh->nh_home, nr, aor) < 0) - return -1; - } - - if (nua_registration_set_contact(nh, nr, sip->sip_contact, unreg) < 0) - return -1; - - if (!nr->nr_ob && (NH_PGET(nh, outbound) || NH_PGET(nh, instance))) { - nr->nr_ob = outbound_new(nh, &nua_stack_outbound_callbacks, - nh->nh_nua->nua_root, - nh->nh_nua->nua_nta, - NH_PGET(nh, instance)); - if (!nr->nr_ob) - return nua_client_return(cr, 900, "Cannot create outbound", msg); - - nua_register_usage_update_params(du, - NULL, - nh->nh_prefs, - nh->nh_dprefs); - } - - if (nr->nr_ob) { - outbound_t *ob = nr->nr_ob; - sip_contact_t *m; - - if (!unreg && sip->sip_contact) { - for (m = sip->sip_contact; m; m = m->m_next) - if (!m->m_expires || strtoul(m->m_expires, NULL, 10) != 0) - break; - - if (m == NULL) - unreg = 1; /* All contacts have expires=0 */ - } - - if (outbound_set_contact(ob, sip->sip_contact, nr->nr_via, unreg) < 0) - return nua_client_return(cr, 900, "Cannot set outbound contact", msg); - } - - return 0; -} - -static -int nua_register_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_registration_t *nr; - sip_contact_t *m, *contacts = sip->sip_contact; - char const *min_expires = NULL; - int unreg; - tport_t *tport = NULL; - - (void)nh; - - /* Explicit empty (NULL) contact - used for CPL store/remove? */ - if (!contacts && cr->cr_has_contact) - return nua_base_client_request(cr, msg, sip, tags); - - if ((du && du->du_shutdown) || - (sip->sip_expires && sip->sip_expires->ex_delta == 0)) - nua_client_set_terminating(cr, 1); - - if (contacts) { - if (!cr->cr_terminating) { - for (m = contacts; m; m = m->m_next) - if (!m->m_expires || strtoul(m->m_expires, NULL, 10) != 0) - break; - /* All contacts have expires=0 */ - if (m == NULL) - nua_client_set_terminating(cr, 1); - } - } - - unreg = cr->cr_terminating; - - nr = nua_dialog_usage_private(du); - - if (nr) { - if (nr->nr_ob) { - outbound_stop_keepalive(nr->nr_ob); - outbound_start_registering(nr->nr_ob); - } - - if (nr->nr_by_stack) { - sip_contact_t *m = nr->nr_contact, *previous = NULL; - - outbound_get_contacts(nr->nr_ob, &m, &previous); - - sip_add_dup(msg, sip, (sip_header_t *)m); - /* previous is an outdated contact generated by stack - * and it is now unregistered */ - if (previous) - sip_add_dup(msg, sip, (sip_header_t *)previous); - } - - tport = nr->nr_tport; - } - - for (m = sip->sip_contact; m; m = m->m_next) { - if (m->m_url->url_type == url_any) { - /* If there is a '*' in contact list, remove everything else */ - while (m != sip->sip_contact) - sip_header_remove(msg, sip, (sip_header_t *)sip->sip_contact); - while (m->m_next) - sip_header_remove(msg, sip, (sip_header_t *)m->m_next); - break; - } - - if (!m->m_expires) - continue; - if (unreg) { - /* Remove the expire parameters from contacts */ - msg_header_remove_param(m->m_common, "expires"); - } - else if (nr && nr->nr_min_expires && - strtoul(m->m_expires, 0, 10) < nr->nr_min_expires) { - if (min_expires == NULL) - min_expires = su_sprintf(msg_home(msg), "expires=%lu", - nr->nr_min_expires); - msg_header_replace_param(msg_home(msg), m->m_common, min_expires); - } - } - - return nua_base_client_trequest(cr, msg, sip, - TAG_IF(unreg, SIPTAG_EXPIRES_STR("0")), -#if 0 - TAG_IF(unreg, NTATAG_SIGCOMP_CLOSE(1)), - TAG_IF(!unreg, NTATAG_COMP("sigcomp")), -#endif - NTATAG_TPORT(tport), - TAG_NEXT(tags)); -} - -static int nua_register_client_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_registration_t *nr = nua_dialog_usage_private(cr->cr_usage); - unsigned short retry_count = cr->cr_retry_count; - int restart = 0, retry; - - if (nr && nr->nr_ob) { - msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq); - sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg); - - retry = outbound_register_response(nr->nr_ob, cr->cr_terminating, - req, sip); - - restart = retry >= ob_reregister_now; - - if (retry == ob_reregister) - /* outbound restarts REGISTER later */; - - if (retry < 0) - /* XXX - report an error? */; - } - - if (nr && status == 423) { - if (sip->sip_min_expires) - nr->nr_min_expires = sip->sip_min_expires->me_delta; - } - - /* Check for status-specific reasons to retry */ - if (nua_base_client_check_restart(cr, status, phrase, sip)) - return 1; - - /* Restart only if nua_base_client_check_restart() did not try to restart */ - if (restart && retry_count == cr->cr_retry_count) - return nua_client_restart(cr, 100, "Outbound NAT Detected"); - - return 0; -} - -static int nua_register_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_registration_t *nr = nua_dialog_usage_private(du); - int ready; - - ready = du && !cr->cr_terminated && status < 300; - - if (ready) { - sip_time_t mindelta = 0; - sip_time_t now = sip_now(), delta, reqdelta, mdelta; - - sip_contact_t const *m, *sent; - - msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq); - sip_t *req = sip_object(_reqmsg); - - tport_t *tport; - - msg_destroy(_reqmsg); - - assert(nr); assert(sip); assert(req); - -#if HAVE_SIGCOMP - { - struct sigcomp_compartment *cc; - cc = nta_outgoing_compartment(cr->cr_orq); - sigcomp_compartment_unref(nr->nr_compartment); - nr->nr_compartment = cc; - } -#endif - - /* XXX - if store/remove, remove - Content-Disposition - Content-Type - body - */ - - /** 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_urn && - 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)) - continue; - - if (sent->m_expires) - mdelta = strtoul(sent->m_expires, NULL, 10); - else - mdelta = reqdelta; - - 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_refresh(du, mindelta); - - /* 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. - - */ - su_free(nh->nh_home, nr->nr_route); - nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route); - - { - /* 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 (sip->sip_to->a_url->url_type == url_sips) - nr->nr_secure = 1; - - if (nr->nr_ob) { - outbound_gruuize(nr->nr_ob, sip); - outbound_start_keepalive(nr->nr_ob, cr->cr_orq); - } - - tport = nta_outgoing_transport (cr->cr_orq); - - /* cache persistant connection for registration */ - if (tport && tport != nr->nr_tport) { - if (nr->nr_error_report_id) { - if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0) - SU_DEBUG_1(("nua_register: tport_release() failed\n" VA_NONE)); - nr->nr_error_report_id = 0; - } - tport_unref(nr->nr_tport); - nr->nr_tport = tport; - - if (tport_is_secondary(tport)) { - tport_set_params(tport, TPTAG_SDWN_ERROR(1), TAG_END()); - nr->nr_error_report_id = - tport_pend(tport, NULL, nua_register_connection_closed, nr); - } - } - else - tport_unref(tport); /* note: nta_outgoing_transport() makes a ref */ - - nua_registration_set_ready(nr, 1); - } - else if (du) { - nua_dialog_usage_reset_refresh(du); - - su_free(nh->nh_home, nr->nr_route); - nr->nr_route = NULL; - - outbound_stop_keepalive(nr->nr_ob); - - /* release the persistant transport for registration */ - if (nr->nr_tport) { - if (nr->nr_error_report_id) { - if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0) - SU_DEBUG_1(("nua_register: tport_release() failed\n" VA_NONE)); - nr->nr_error_report_id = 0; - } - - tport_unref(nr->nr_tport), nr->nr_tport = NULL; - } - nua_registration_set_ready(nr, 0); - } - - - return nua_base_client_response(cr, status, phrase, sip, NULL); -} - -static -void nua_register_connection_closed(tp_stack_t *sip_stack, - nua_registration_t *nr, - tport_t *tport, - msg_t *msg, - int error) -{ - nua_dialog_usage_t *du; - tp_name_t const *tpn; - int pending; - - assert(nr && tport == nr->nr_tport); - if (nr == NULL || tport != nr->nr_tport) - return; - - du = NUA_DIALOG_USAGE_PUBLIC(nr); - pending = nr->nr_error_report_id; - - if (tport_release(tport, pending, NULL, NULL, nr, 0) < 0) - SU_DEBUG_1(("nua_register: tport_release() failed\n" VA_NONE)); - nr->nr_error_report_id = 0; - - tpn = tport_name(nr->nr_tport); - - SU_DEBUG_5(("nua_register(%p): tport to %s/%s:%s%s%s closed %s\n", - (void *)du->du_dialog->ds_owner, - tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port, - tpn->tpn_comp ? ";comp=" : "", - tpn->tpn_comp ? tpn->tpn_comp : "", - error != 0 ? su_strerror(error) : "")); - - tport_unref(nr->nr_tport), nr->nr_tport = NULL; - - /* Schedule re-REGISTER immediately */ - nua_dialog_usage_set_refresh_range(du, 0, 0); -} - -static void -nua_register_usage_update_params(nua_dialog_usage_t const *du, - nua_handle_preferences_t const *changed, - nua_handle_preferences_t const *nhp, - nua_handle_preferences_t const *dnhp) -{ - nua_registration_t *nr = nua_dialog_usage_private(du); - outbound_t *ob = nr->nr_ob; - - if (!ob) - return; - - if (!changed || - NHP_ISSET(changed, outbound) || - NHP_ISSET(changed, keepalive) || - NHP_ISSET(changed, keepalive_stream)) { - char const *outbound = - NHP_ISSET(nhp, outbound) ? nhp->nhp_outbound - : dnhp->nhp_outbound; - unsigned keepalive = - NHP_ISSET(nhp, keepalive) ? nhp->nhp_keepalive - : dnhp->nhp_keepalive; - unsigned keepalive_stream = - NHP_ISSET(nhp, keepalive_stream) ? nhp->nhp_keepalive_stream - : NHP_ISSET(dnhp, keepalive_stream) ? nhp->nhp_keepalive_stream - : keepalive; - - outbound_set_options(ob, outbound, keepalive, keepalive_stream); - } - - if (!changed || NHP_ISSET(changed, proxy)) { - if (NHP_ISSET(nhp, proxy)) - outbound_set_proxy(ob, nhp->nhp_proxy); - } -} - - -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 = du->du_cr; - - if (cr) { - if (nua_client_resend_request(cr, 0) >= 0) - return; - } - - /* Report that we have de-registered */ - nua_stack_event(nua, nh, NULL, nua_r_register, NUA_ERROR_AT(__FILE__, __LINE__), NULL); - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); -} - -/** @interal Shut down REGISTER usage. - * - * @retval >0 shutdown done - * @retval 0 shutdown in progress - * @retval <0 try again later - */ -static int nua_register_usage_shutdown(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) -{ - nua_client_request_t *cr = du->du_cr; - nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du); - - if (cr) { - if (nua_client_is_queued(cr)) /* Already registering. */ - return -1; - cr->cr_event = nua_r_unregister; - if (nua_client_resend_request(cr, 1) >= 0) - return 0; - } - - /* release the persistant transport for registration */ - if (nr->nr_tport) - tport_decref(&nr->nr_tport), nr->nr_tport = NULL; - - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - return 200; -} - -/* ---------------------------------------------------------------------- */ -/* nua_registration_t interface */ - -#if HAVE_SOFIA_STUN -#include -#endif - -static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta); -static void nua_stack_tport_error(nua_t *nua, nta_agent_t *nta, tport_t *tport); -static int nua_registration_add_contact_and_route(nua_handle_t *nh, - 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; - url_string_t const *contact3 = NULL, *contact4 = NULL; - char const *name1 = "sip", *name2 = "sip"; - char const *name3 = "sip", *name4 = "sip"; - char const *certificate_dir = NULL; - - tl_gets(tags, - NUTAG_URL_REF(contact1), - NUTAG_SIPS_URL_REF(contact2), - NUTAG_WS_URL_REF(contact3), - NUTAG_WSS_URL_REF(contact4), - NUTAG_CERTIFICATE_DIR_REF(certificate_dir), - TAG_END()); - - if (!contact1 && contact2) - contact1 = contact2, contact2 = NULL; - - if (contact1 && - (url_is_string(contact1) - ? su_casenmatch(contact1->us_str, "sips:", 5) - : contact1->us_url->url_type == url_sips)) - name1 = "sips"; - - if (contact2 && - (url_is_string(contact2) - ? su_casenmatch(contact2->us_str, "sips:", 5) - : contact2->us_url->url_type == url_sips)) - name2 = "sips"; - - if (contact3 && - (url_is_string(contact3) - ? su_casenmatch(contact3->us_str, "sips:", 5) - : contact3->us_url->url_type == url_sips)) - name3 = "sips"; - - if (contact4 && - (url_is_string(contact4) - ? su_casenmatch(contact4->us_str, "sips:", 5) - : contact4->us_url->url_type == url_sips)) - name4 = "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" VA_NONE)); - } -#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 (contact3 && - nta_agent_add_tport(nua->nua_nta, contact3, - TPTAG_IDENT(name3), - TPTAG_CERTIFICATE(certificate_dir), - TAG_NEXT(nua->nua_args)) < 0) - return -1; - - if (contact4 && - nta_agent_add_tport(nua->nua_nta, contact4, - TPTAG_IDENT(name4), - 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; - - nw_updates = nua->nua_prefs->ngp_detect_network_updates; - - switch (nw_updates) { - case NUA_NW_DETECT_ONLY_INFO: - nua_stack_event(nua, NULL, NULL, nua_i_network_changed, SIP_200_OK, NULL); - 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", NULL); - else - nua_stack_event(nua, NULL, NULL, nua_i_network_changed, - SIP_200_OK, NULL); - - 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_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, (nta_update_magic_t *)nua, nua_stack_tport_update); - nta_agent_bind_tport_error(nua->nua_nta, (nta_error_magic_t *)nua, nua_stack_tport_error); - - 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 (!su_casematch(protocol, (*prev)->v_protocol)) - continue; - if (!su_casematch(v->v_host, (*prev)->v_host)) - continue; - if (!su_strmatch(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; - - contact = nua_handle_contact_by_via(nh, home, 0, v2, protocol, NULL); - - 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_dcontact = *contact, nr->nr_dcontact->m_params = NULL; - 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_error(nua_t *nua, nta_agent_t *nta, tport_t *tport) -{ - return; -} - -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 *registered = 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 (!registered && nr->nr_aor) - registered = nr; - if (!public && nr->nr_public) - public = nr; - if (!any) - any = nr; - } - if (registered) - return (nua_registration_t *)registered; - 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); - alt_aor->a_url->url_type = url_sips; - alt_aor->a_url->url_scheme = "sips"; - } - - 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; - } - - if (!sipswise && ((sips_aor || sips_uri) ? - nr->nr_secure : !nr->nr_secure)) - sipswise = nr; - if (!registered) - registered = 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; - if (registered) - return (nua_registration_t *)registered; - - /* 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; - } - - if (nr->nr_contact) - return nr->nr_dcontact; - else - return NULL; -} - -/** 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 ? nr->nr_dcontact : 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(nh, nr, msg, sip, - add_contact, - add_service_route); -} - -/** Add a Contact header to response. - * - * @param nh - * @param msg response message - * @param sip headers in response message - * @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(nh, nr, msg, sip, - 1, - 0); -} - -/** Add a Contact (and Route) header to request */ -static -int nua_registration_add_contact_and_route(nua_handle_t *nh, - 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 = NULL; - char const *m_display; - char const *m_username; - char const *m_params; - url_t const *u; - - if (nr->nr_by_stack && nr->nr_ob) { - m = outbound_dialog_gruu(nr->nr_ob); - - if (m) - return msg_header_add_dup(msg, (msg_pub_t *)sip, (void const *)m); - - m = outbound_dialog_contact(nr->nr_ob); - } - - if (m == NULL) - m = nr->nr_contact; - - if (!m) - return -1; - - u = m->m_url; - - if (NH_PISSET(nh, m_display)) - m_display = NH_PGET(nh, m_display); - else - m_display = m->m_display; - - if (NH_PISSET(nh, m_username)) - m_username = NH_PGET(nh, m_username); - else - m_username = m->m_url->url_user; - - if (NH_PISSET(nh, m_params)) { - m_params = NH_PGET(nh, m_params); - - if (u->url_params && m_params && strstr(u->url_params, m_params) == 0) - m_params = NULL; - } - else - m_params = NULL; - - m = sip_contact_format(msg_home(msg), - "%s<%s:%s%s%s%s%s%s%s%s%s>", - m_display ? m_display : "", - u->url_scheme, - m_username ? m_username : "", - m_username ? "@" : "", - u->url_host, - u->url_port ? ":" : "", - u->url_port ? u->url_port : "", - u->url_params ? ";" : "", - u->url_params ? u->url_params : "", - m_params ? ";" : "", - m_params ? m_params : ""); - - if (msg_header_insert(msg, (msg_pub_t *)sip, (void *)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, 0, - nr0->nr_via, tport, NULL); - } - } - - if (!m) - return -1; - - nr->nr_contact = m; - *nr->nr_dcontact = *m, nr->nr_dcontact->m_params = NULL; - 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) -{ - if (nr) { - 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 */ -} - -/** 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_args(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_args(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 -#include - -/** @internal Generate a @Contact header. */ -sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh, - su_home_t *home, - int in_dialog, - sip_via_t const *v, - char const *transport, - char const *m_param, - ...) -{ - su_strlst_t *l; - char const *s; - char const *host, *port, *maddr, *comp; - int one = 1; - char _transport[16]; - va_list va; - sip_contact_t *m; - url_t url; - - url_init(&url, url_sip); - - 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)) { - url.url_type = url_sips; - url.url_scheme = url_scheme(url_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 (su_casenmatch(transport, "SIP/2.0/", 8)) - transport += 8; - - /* Make transport parameter lowercase */ - if (strlen(transport) < (sizeof _transport)) { - char *s; - short c; - - strcpy(_transport, transport); - for (s = _transport; (c = *s) && c != ';'; s++) - if (isupper(c)) - *s = tolower(c); - - transport = _transport; - } - } - - s = NH_PGET(nh, m_username); - if (s) - url.url_user = s; - url.url_host = host; - url.url_port = port; - url.url_params = su_strdup(home, NH_PGET(nh, m_params)); - if (transport) { - url.url_params = url_strip_param_string((char*)url.url_params, "transport"); - url_param_add(home, &url, su_sprintf(home, "transport=%s", transport)); - } - if (maddr) { - url.url_params = url_strip_param_string((char*)url.url_params, "maddr"); - url_param_add(home, &url, su_sprintf(home, "maddr=%s", maddr)); - } - if (comp) { - url.url_params = url_strip_param_string((char*)url.url_params, "comp"); - url_param_add(home, &url, su_sprintf(home, "comp=%s", comp)); - } - - 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, url_as_string(home, &url)); - 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); - - if (!in_dialog) { - s = NH_PGET(nh, m_features); - if (s) - s[0] == ';' ? "" : su_strlst_append(l, ";"), su_strlst_append(l, s); - - if (NH_PGET(nh, callee_caps)) { - sip_allow_t const *allow = NH_PGET(nh, allow); - - if (allow) { - su_strlst_append(l, ";methods=\""); - 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++); - } - } - } - } - - m = sip_contact_make(home, su_strlst_join(l, su_strlst_home(l), "")); - - su_strlst_destroy(l); - - return m; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c deleted file mode 100644 index a57b511005..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 -#include -#include -#include - -#include - -#define TP_CLIENT_T struct nua_handle_s -#define TP_STACK_T struct nta_agent_s - -#include -#include -#include -#include - -#define NTA_INCOMING_MAGIC_T struct nua_handle_s -#define NTA_RELIABLE_MAGIC_T struct nua_handle_s - -#include "nua_stack.h" - -#include -#include - -/* ---------------------------------------------------------------------- */ -/* Registrar usage */ - -struct registrar_usage -{ - tport_t *tport; /**< */ - int pending; /**< Waiting for tport to close */ -}; - -static char const *nua_registrar_usage_name(nua_dialog_usage_t const *du) -{ - return "registrar"; -} - -static int nua_registrar_usage_add(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) -{ - return 0; -} - -static void nua_registrar_usage_remove(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - nua_client_request_t *cr, - nua_server_request_t *sr) -{ - struct registrar_usage *ru; - - ru = nua_dialog_usage_private(du); - - if (!ru) - return; - - if (ru->pending) - tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; - - tport_unref(ru->tport), ru->tport = NULL; -} - -static void nua_registrar_usage_refresh(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - sip_time_t now) -{ -} - -/** Terminate registration usage. - * - * @retval >0 shutdown done - * @retval 0 shutdown in progress - * @retval <0 try again later - */ -static int nua_registrar_usage_shutdown(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) -{ - return 1; -} - -static nua_usage_class const nua_registrar_usage[1] = { - { - sizeof (struct registrar_usage), sizeof nua_registrar_usage, - nua_registrar_usage_add, - nua_registrar_usage_remove, - nua_registrar_usage_name, - nua_base_usage_update_params, - NULL, - nua_registrar_usage_refresh, - nua_registrar_usage_shutdown - }}; - - -/* ======================================================================== */ -/* 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, e.g., - * @verbatim - * nua_set_params(nua; - * NUTAG_APPL_METHOD("REGISTER"), - * NUTAG_ALLOW("REGISTER"), - * TAG_END()); - * @endverbatim - * - * The nua_response() call responding to a REGISTER request must include - * NUTAG_WITH() (or NUTAG_WITH_THIS()/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 - */ - -static int nua_registrar_server_preprocess(nua_server_request_t *sr); -static int nua_registrar_server_report(nua_server_request_t *, tagi_t const *); - -nua_server_methods_t const nua_register_server_methods = - { - SIP_METHOD_REGISTER, - nua_i_register, /* Event */ - { - 0, /* Do not create dialog */ - 0, /* Initial request */ - 0, /* Not a target refresh request */ - 0, /* Do not add Contact */ - }, - nua_base_server_init, - nua_registrar_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_registrar_server_report, - }; - -static void -registrar_tport_error(nta_agent_t *nta, nua_handle_t *nh, - tport_t *tp, msg_t *msg, int error) -{ - nua_dialog_state_t *ds = nh->nh_ds; - nua_dialog_usage_t *du; - struct registrar_usage *ru; - - SU_DEBUG_3(("tport error %d: %s\n", error, su_strerror(error))); - - du = nua_dialog_usage_get(ds, nua_registrar_usage, NULL); - - if (du == NULL) - return; - - ru = nua_dialog_usage_private(du); - if (ru->tport) { - tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; - tport_unref(ru->tport), ru->tport = NULL; - } - - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_media_error, 500, "Transport error detected", - NULL); -} - -static int -nua_registrar_server_preprocess(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_state_t *ds = sr->sr_owner->nh_ds; - nua_dialog_usage_t *du; - struct registrar_usage *ru; - tport_t *tport; - - tport = nta_incoming_transport(nh->nh_nua->nua_nta, sr->sr_irq, sr->sr_request.msg); - - if (!tport_is_tcp(tport)) { - tport_unref(tport); - return 0; - } - - du = nua_dialog_usage_get(ds, nua_registrar_usage, NULL); - if (du == NULL) - du = nua_dialog_usage_add(nh, ds, nua_registrar_usage, NULL); - - if (du == NULL) - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - - ru = nua_dialog_usage_private(du); - - if (ru->tport && ru->tport != tport) { - tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; - tport_unref(ru->tport), ru->tport = NULL; - } - - ru->tport = tport; - ru->pending = tport_pend(tport, NULL, registrar_tport_error, nh); - - tport_set_params(tport, - TPTAG_SDWN_ERROR(1), - TAG_END()); - - return 0; -} - -static int -nua_registrar_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - return nua_base_server_report(sr, tags); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c deleted file mode 100644 index 0acfba5a87..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_server.c - * @brief Server transaction handling - * - * @author Pekka Pessi - * - * @date Created: Tue Feb 3 16:10:45 EET 2009 - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include - -#define NUA_SAVED_EVENT_T su_msg_t * -#define NUA_SAVED_SIGNAL_T su_msg_t * - -#include - -#include "nua_stack.h" -#include "nua_dialog.h" -#include "nua_server.h" -#include "nua_params.h" - -/* ======================================================================== */ -/* - * Process incoming requests - */ - -nua_server_methods_t const *nua_server_methods[] = { - /* These must be in same order as in sip_method_t */ - &nua_extension_server_methods, - &nua_invite_server_methods, /**< INVITE */ - NULL, /**< ACK */ - NULL, /**< CANCEL */ - &nua_bye_server_methods, /**< BYE */ - &nua_options_server_methods, /**< OPTIONS */ - &nua_register_server_methods, /**< REGISTER */ - &nua_info_server_methods, /**< INFO */ - &nua_prack_server_methods, /**< PRACK */ - &nua_update_server_methods, /**< UPDATE */ - &nua_message_server_methods, /**< MESSAGE */ - &nua_subscribe_server_methods,/**< SUBSCRIBE */ - &nua_notify_server_methods, /**< NOTIFY */ - &nua_refer_server_methods, /**< REFER */ - &nua_publish_server_methods, /**< PUBLISH */ - NULL -}; - - -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 *name = sip->sip_request->rq_method_name; - nua_server_methods_t const *sm; - nua_server_request_t *sr, sr0[1]; - int status, initial = 1; - int create_dialog; - - 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 (method == sip_method_cancel) - return 481; - - /* Hook to outbound */ - if (method == sip_method_options) { - status = nua_registration_process_request(nua->nua_registrations, - irq, sip); - if (status) - return status; - } - - 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_urn: - case url_sips: - case url_im: - case url_pres: - case url_tel: - break; - default: - nta_incoming_treply(irq, status = SIP_416_UNSUPPORTED_URI, - SIPTAG_ALLOW(allow), - SIPTAG_SUPPORTED(supported), - SIPTAG_USER_AGENT_STR(user_agent), - TAG_END()); - return status; - } - - if (nta_check_required(irq, sip, supported, - SIPTAG_ALLOW(allow), - SIPTAG_USER_AGENT_STR(user_agent), - TAG_END())) - return 420; - - if (method > sip_method_unknown && method <= sip_method_publish) - sm = nua_server_methods[method]; - else - sm = nua_server_methods[0]; - - initial = nh == nua->nua_dhandle; - - if (sm == NULL) { - SU_DEBUG_1(("nua(%p): strange %s from <" URL_PRINT_FORMAT ">\n", - (void *)nh, sip->sip_request->rq_method_name, - URL_PRINT_ARGS(sip->sip_from->a_url))); - } - else if (initial && sm->sm_flags.in_dialog) { - /* These must be in-dialog */ - sm = NULL; - } - else if (initial && sip->sip_to->a_tag && method != sip_method_subscribe) { - /* 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. - */ /* we allow this on subscribes because we have disabled the built-in notify server and we need those messages in the application layer */ - - if (method == sip_method_info) - /* accept out-of-dialog info */; else - if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable)) - sm = NULL; - } - - if (!sm) { - nta_incoming_treply(irq, - status = 481, "Call Does Not Exist", - SIPTAG_ALLOW(allow), - SIPTAG_SUPPORTED(supported), - SIPTAG_USER_AGENT_STR(user_agent), - TAG_END()); - return 481; - } - - create_dialog = sm->sm_flags.create_dialog; - if (method == sip_method_message && NH_PGET(nh, win_messenger_enable)) - create_dialog = 1; - sr = memset(sr0, 0, (sizeof sr0)); - - sr->sr_methods = sm; - sr->sr_method = method = sip->sip_request->rq_method; - sr->sr_add_contact = sm->sm_flags.add_contact; - sr->sr_target_refresh = sm->sm_flags.target_refresh; - - sr->sr_owner = nh; - sr->sr_initial = initial; - - sr->sr_irq = irq; - - SR_STATUS1(sr, SIP_100_TRYING); - - sr->sr_request.msg = nta_incoming_getrequest(irq); - sr->sr_request.sip = sip; - assert(sr->sr_request.msg); - - sr->sr_response.msg = nta_incoming_create_response(irq, 0, NULL); - sr->sr_response.sip = sip_object(sr->sr_response.msg); - - if (sr->sr_response.msg == NULL) { - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - else if (sm->sm_init && sm->sm_init(sr)) { - if (sr->sr_status < 200) /* Init may have set response status */ - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - /* Create handle if request does not fail */ - else if (initial && sr->sr_status < 300) { - if ((nh = nua_stack_incoming_handle(nua, irq, sip, create_dialog))) - sr->sr_owner = nh; - else - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - if (sr->sr_status < 300 && sm->sm_preprocess && sm->sm_preprocess(sr)) { - if (sr->sr_status < 200) /* Set response status if preprocess did not */ - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - if (sr->sr_status < 300) { - if (sr->sr_target_refresh) - nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */ - nua_dialog_store_peer_info(nh, nh->nh_ds, sip); - } - - if (sr->sr_status == 100 && method != sip_method_unknown && - !sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), method, name)) { - if (method == sip_method_refer || method == sip_method_subscribe) - SR_STATUS1(sr, SIP_202_ACCEPTED); - else - SR_STATUS1(sr, SIP_200_OK); - } - - /* INVITE server request is not finalized after 2XX response */ - if (sr->sr_status < (method == sip_method_invite ? 300 : 200)) { - sr = su_alloc(nh->nh_home, (sizeof *sr)); - - if (sr) { - *sr = *sr0; - - 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; - } - else { - sr = sr0; - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - } - - if (sr->sr_status <= 100) { - SR_STATUS1(sr, SIP_100_TRYING); - if ((method == sip_method_invite && nh->nh_prefs->nhp_auto_invite_100) || - sip->sip_timestamp) { - nta_incoming_treply(irq, SIP_100_TRYING, - SIPTAG_USER_AGENT_STR(user_agent), - TAG_END()); - - } - } - else { - /* Note that this may change the sr->sr_status */ - nua_server_respond(sr, NULL); - } - - if (nua_server_report(sr) == 0) - return 0; - - return 501; -} - -#undef nua_base_server_init -#undef nua_base_server_preprocess - -int nua_base_server_init(nua_server_request_t *sr) -{ - return 0; -} - -int nua_base_server_preprocess(nua_server_request_t *sr) -{ - return 0; -} - -void nua_server_request_destroy(nua_server_request_t *sr) -{ - nua_server_request_t *sr0 = NULL; - - if (sr == NULL) - return; - - if (SR_HAS_SAVED_SIGNAL(sr)) - nua_destroy_signal(sr->sr_signal); - - if (sr->sr_prev) { - /* Allocated from heap */ - if ((*sr->sr_prev = sr->sr_next)) - sr->sr_next->sr_prev = sr->sr_prev; - sr0 = sr; - } - - if (sr->sr_irq) { - nta_incoming_t *irq = sr->sr_irq; - if (sr->sr_method == sip_method_bye && sr->sr_status < 200) { - nta_incoming_treply(sr->sr_irq, SIP_200_OK, TAG_END()); - } - sr->sr_irq = NULL; - nta_incoming_destroy(irq); - } - - if (sr->sr_request.msg) { - msg_t *msg = sr->sr_request.msg; - sr->sr_request.msg = NULL; - msg_destroy(msg); - } - - if (sr->sr_response.msg) { - msg_t *msg = sr->sr_response.msg; - sr->sr_response.msg = NULL; - msg_destroy(msg); - } - - if (sr0) su_free(sr->sr_owner->nh_home, sr0); -} - -/**@fn void nua_respond(nua_handle_t *nh, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...); - * - * Respond to a request with given status code and phrase. - * - * The stack returns a SIP response message with given status code and - * phrase to the client. The tagged parameter list can specify extra headers - * to include with the response message and other stack parameters. The SIP - * session or other protocol state associated with the handle is updated - * accordingly (for instance, if an initial INVITE is responded with 200, a - * SIP session is established.) - * - * 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. - * - * @param nh Pointer to operation handle - * @param status SIP response status code (see RFCs of SIP) - * @param phrase free text (default response phrase is used if NULL) - * @param tag, value, ... List of tagged parameters - * - * @return - * nothing - * - * @par Responses by Protocol Engine - * - * When nua protocol engine receives an incoming SIP request, it can either - * respond to the request automatically or let application to respond to the - * request. The automatic response is returned to the client if the request - * fails syntax check, or the method, SIP extension or content negotiation - * fails. - * - * When the @ref nua_handlingevents "request event" is delivered to the - * application, the application should examine the @a status parameter. The - * @a status parameter is 200 or greater if the request has been already - * responded automatically by the stack. - * - * 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 405 Not Allowed. - * - * In order to simplify the simple applications, most requests are responded - * automatically. The BYE and CANCEL requests are always responded by the - * stack. Likewise, the NOTIFY requests associated with an event - * subscription are responded by the stack. - * - * 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 the stack if there - * is no ongoing INVITE transaction corresponding to them. - * - * @par Related Tags: - * NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_WITH_SAVED() \n - * NUTAG_EARLY_ANSWER() \n - * SOATAG_ADDRESS() \n - * SOATAG_AF() \n - * SOATAG_HOLD() \n - * Tags used with nua_set_hparams() \n - * Header tags defined in . - * - * @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_request.msg == request) - break; - /* nua_respond() to INVITE can be used without NUTAG_WITH() */ - if (!t && sr->sr_method == sip_method_invite) - break; - } - - if (sr == NULL) { - nua_stack_event(nua, nh, NULL, nua_i_error, - 500, "Responding to a Non-Existing Request", NULL); - return; - } - else if (!nua_server_request_is_pending(sr)) { - nua_stack_event(nua, nh, NULL, nua_i_error, - 500, "Already Sent Final Response", NULL); - return; - } - else if (sr->sr_100rel && !sr->sr_pracked && 200 <= status && status < 300) { - /* Save signal until we have received PRACK */ - if (tags && nua_stack_set_params(nua, nh, nua_i_none, tags) < 0) { - sr->sr_application = status; - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - else { - su_msg_save(sr->sr_signal, nh->nh_nua->nua_signal); - return; - } - } - else { - sr->sr_application = status; - if (tags && nua_stack_set_params(nua, nh, nua_i_none, tags) < 0) - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - else { - sr->sr_status = status, sr->sr_phrase = phrase; - } - } - - nua_server_params(sr, tags); - nua_server_respond(sr, tags); - - if (!(sr->sr_method == sip_method_invite && status == 100)) { - /* Since we don't change state, do not notify application when - we send 100 Trying for INVITE */ - nua_server_report(sr); - } -} - -int nua_server_params(nua_server_request_t *sr, tagi_t const *tags) -{ - if (sr->sr_methods->sm_params) - return sr->sr_methods->sm_params(sr, tags); - return 0; -} - -#undef nua_base_server_params - -int nua_base_server_params(nua_server_request_t *sr, tagi_t const *tags) -{ - return 0; -} - -/** Return the response to the client. - * - * @retval 0 when successfully sent - * @retval -1 upon an error - */ -int nua_server_trespond(nua_server_request_t *sr, - tag_type_t tag, tag_value_t value, ...) -{ - int retval; - ta_list ta; - ta_start(ta, tag, value); - retval = nua_server_respond(sr, ta_args(ta)); - ta_end(ta); - return retval; -} - -/** Return the response to the client. - * - * @retval 0 when successfully sent - * @retval -1 upon an error - */ -int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - sip_method_t method = sr->sr_method; - struct { msg_t *msg; sip_t *sip; } next = { NULL, NULL }; - int retval, user_contact = 1; -#if HAVE_OPEN_C - /* Nice. And old arm symbian compiler; see below. */ - tagi_t next_tags[2]; -#else - tagi_t next_tags[2] = {{ SIPTAG_END() }, { TAG_NEXT(tags) }}; -#endif - - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - sip_contact_t *m = sr->sr_request.sip->sip_contact; - -#if HAVE_OPEN_C - next_tags[0].t_tag = siptag_end; - next_tags[0].t_value = (tag_value_t)0; - next_tags[1].t_tag = tag_next; - next_tags[1].t_value = (tag_value_t)(tags); -#endif - - if (sr->sr_response.msg == NULL) { - //assert(sr->sr_status == 500); - SU_DEBUG_0(("sr without msg, sr_status=%u", sr->sr_status)); - goto internal_error; - } - - if (sr->sr_status == 100) { - return nta_incoming_treply(sr->sr_irq, SIP_100_TRYING, - SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)), - TAG_END()); - return 0; - } - - if (sr->sr_status < 200) { - next.msg = nta_incoming_create_response(sr->sr_irq, 0, NULL); - next.sip = sip_object(next.msg); - if (next.sip == NULL) - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - if (nta_incoming_complete_response(sr->sr_irq, msg, - sr->sr_status, - sr->sr_phrase, - TAG_NEXT(tags)) < 0) - ; - else if (!sip->sip_supported && NH_PGET(nh, supported) && - sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)) < 0) - ; - 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) - ; - else if (!sip->sip_organization && NH_PGET(nh, organization) && - sip_add_make(msg, sip, sip_organization_class, - NH_PGET(nh, organization)) < 0) - ; - else if (!sip->sip_via && NH_PGET(nh, via) && - sip_add_make(msg, sip, sip_via_class, - NH_PGET(nh, via)) < 0) - ; - else if (!sip->sip_allow && NH_PGET(nh, allow) && - sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow)) < 0) - ; - else if (!sip->sip_allow_events && - NH_PGET(nh, allow_events) && - (method == sip_method_publish || method == sip_method_subscribe || - method == sip_method_options || method == sip_method_refer || - (sr->sr_initial && - (method == sip_method_invite || - method == sip_method_notify))) && - sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)) < 0) - ; - else if (!sip->sip_contact && sr->sr_status < 300 && sr->sr_add_contact && - (user_contact = 0, - ds->ds_ltarget - ? sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget) - : nua_registration_add_contact_to_response(nh, msg, sip, NULL, m)) - < 0) - ; - else { - int term; - sip_contact_t *ltarget = NULL; - - term = sip_response_terminates_dialog(sr->sr_status, sr->sr_method, NULL); - - sr->sr_terminating = (term < 0) ? -1 : (term > 0 || sr->sr_terminating); - - if (sr->sr_target_refresh && sr->sr_status < 300 && !sr->sr_terminating && - user_contact && sip->sip_contact) { - /* Save Contact given by application */ - ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact); - } - - retval = sr->sr_methods->sm_respond(sr, next_tags); - - if (sr->sr_status < 200) - sr->sr_response.msg = next.msg, sr->sr_response.sip = next.sip; - else if (next.msg) - msg_destroy(next.msg); - - assert(sr->sr_status >= 200 || sr->sr_response.msg); - - if (ltarget) { - if (sr->sr_status < 300) { - nua_dialog_state_t *ds = nh->nh_ds; - msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget); - ds->ds_ltarget = ltarget; - } - else - msg_header_free(nh->nh_home, (msg_header_t *)ltarget); - } - - return retval; - } - - if (next.msg) - msg_destroy(next.msg); - - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - - msg_destroy(msg); - - internal_error: - sr->sr_response.msg = NULL, sr->sr_response.sip = NULL; - nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END()); - - return 0; -} - -/** Return the response to the client. - * - * @retval 0 when successfully sent - * @retval -1 upon an error - */ -int nua_base_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - msg_t *response = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - sr->sr_response.msg = NULL, sr->sr_response.sip = NULL; - - if (sr->sr_status != sip->sip_status->st_status) { - msg_header_remove(response, (msg_pub_t *)sip, - (msg_header_t *)sip->sip_status); - nta_incoming_complete_response(sr->sr_irq, response, - sr->sr_status, - sr->sr_phrase, - TAG_END()); - } - - if (sr->sr_status != sip->sip_status->st_status) { - msg_destroy(response); - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END()); - return 0; - } - - return nta_incoming_mreply(sr->sr_irq, response); -} - -int nua_server_report(nua_server_request_t *sr) -{ - if (sr) - return sr->sr_methods->sm_report(sr, NULL); - else - return 1; -} - -int nua_base_server_treport(nua_server_request_t *sr, - tag_type_t tag, tag_value_t value, - ...) -{ - int retval; - ta_list ta; - ta_start(ta, tag, value); - retval = nua_base_server_report(sr, ta_args(ta)); - ta_end(ta); - return retval; -} - -/**Report request event to the application. - * - * @retval 0 request lives - * @retval 1 request was destroyed - * @retval 2 request and its usage was destroyed - * @retval 3 request, all usages and dialog was destroyed - * @retval 4 request, all usages, dialog, and handle was destroyed - */ -int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_t *nua = nh->nh_nua; - nua_dialog_usage_t *usage = sr->sr_usage; - int initial = sr->sr_initial; - int status = sr->sr_status; - char const *phrase = sr->sr_phrase; - - int terminated; - int handle_can_be_terminated = initial && !sr->sr_event; - - if (sr->sr_application) { - /* There was an error sending response */ - if (sr->sr_application != sr->sr_status) - nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, tags); - sr->sr_application = 0; - } - else if (status < 300 && !sr->sr_event) { - msg_t *msg = msg_ref_create(sr->sr_request.msg); - nua_event_t e = (enum nua_event_e)sr->sr_methods->sm_event; - sr->sr_event = 1; - nua_stack_event(nua, nh, msg, e, status, phrase, tags); - } - - if (status < 200) - return 0; /* sr lives on until final response is sent */ - - if (sr->sr_method == sip_method_invite && status < 300) - return 0; /* INVITE lives on until ACK is received */ - - if (initial && 300 <= status) - terminated = 1; - else if (sr->sr_terminating && status < 300) - terminated = 1; - else - terminated = sip_response_terminates_dialog(status, sr->sr_method, NULL); - - if (usage && terminated) - nua_dialog_usage_remove(nh, nh->nh_ds, usage, NULL, sr); - - nua_server_request_destroy(sr); - - if (!terminated) - return 1; - - if (!initial) { - if (terminated > 0) - return 2; - - /* Remove all usages of the dialog */ - nua_dialog_deinit(nh, nh->nh_ds); - - return 3; - } - else if (!handle_can_be_terminated) { - return 3; - } - else { - if (nh != nh->nh_nua->nua_dhandle) - nh_destroy(nh->nh_nua, nh); - - return 4; - } -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.h deleted file mode 100644 index 5682616161..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_SERVER_H -/** Defined when has been included. */ -#define NUA_SERVER_H - -/**@IFILE nua_server.h - * @brief Dialog and dialog usage handling - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Wed Mar 8 11:38:18 EET 2006 ppessi - */ - -#include - -#ifndef NTA_H -#include -#endif - -typedef struct { - sip_method_t sm_method; - char const *sm_method_name; - - int sm_event; - - struct { - unsigned create_dialog:1, in_dialog:1, target_refresh:1, add_contact:1; - unsigned :0; - } sm_flags; - - /** Initialize server-side request. */ - int (*sm_init)(nua_server_request_t *sr); - - /** Preprocess server-side request (after handle has been created). */ - int (*sm_preprocess)(nua_server_request_t *sr); - - /** Update server-side request parameters */ - int (*sm_params)(nua_server_request_t *sr, tagi_t const *tags); - - /** Respond to server-side request. */ - int (*sm_respond)(nua_server_request_t *sr, tagi_t const *tags); - - /** Report server-side request to application. */ - int (*sm_report)(nua_server_request_t *sr, tagi_t const *tags); - -} nua_server_methods_t; - -/* Server side transaction */ -struct nua_server_request { - struct nua_server_request *sr_next, **sr_prev; - - nua_server_methods_t const *sr_methods; - - nua_owner_t *sr_owner; /**< Backpointer to handle */ - nua_dialog_usage_t *sr_usage; /**< Backpointer to usage */ - - nta_incoming_t *sr_irq; /**< Server transaction object */ - - struct { - msg_t *msg; /**< Request message */ - sip_t const *sip; /**< Headers in request message */ - } sr_request; - - struct { - msg_t *msg; /**< Response message */ - sip_t *sip; /**< Headers in response message */ - } sr_response; - - sip_method_t sr_method; /**< Request method */ - - int sr_application; /**< Status by application */ - - int sr_status; /**< Status code */ - char const *sr_phrase; /**< Status phrase */ - - unsigned sr_event:1; /**< Reported to application */ - unsigned sr_initial:1; /**< Handle was created by this request */ - unsigned sr_add_contact:1; /**< Add Contact header to the response */ - unsigned sr_target_refresh:1; /**< Refresh target */ - unsigned sr_terminating:1; /**< Terminate usage after final response */ - unsigned sr_gracefully:1; /**< Terminate usage gracefully */ - - unsigned sr_neutral:1; /**< No effect on session or other usage */ - - /* Flags used with 100rel */ - unsigned sr_100rel:1, sr_pracked:1; - - /* 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:2; /**< We have offered SDP (reliably, if >1) */ - unsigned sr_answer_recv:1; /**< We have received SDP answer */ - - unsigned :0; - - char const *sr_sdp; /**< SDP received from client */ - size_t sr_sdp_len; /**< SDP length */ - - /**< Save 200 OK nua_respond() signal until PRACK has been received */ - nua_saved_signal_t sr_signal[1]; -}; - -#define SR_STATUS(sr, status, phrase) \ - ((sr)->sr_phrase = (phrase), (sr)->sr_status = (status)) - -#define SR_STATUS1(sr, statusphrase) \ - sr_status(sr, statusphrase) - -#define SR_HAS_SAVED_SIGNAL(sr) ((sr)->sr_signal[0] != NULL) - -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); -} - -extern nua_server_methods_t const - nua_extension_server_methods, - nua_invite_server_methods, /**< INVITE */ - nua_bye_server_methods, /**< BYE */ - nua_options_server_methods, /**< OPTIONS */ - nua_register_server_methods, /**< REGISTER */ - nua_info_server_methods, /**< INFO */ - nua_prack_server_methods, /**< PRACK */ - nua_update_server_methods, /**< UPDATE */ - nua_message_server_methods, /**< MESSAGE */ - nua_subscribe_server_methods, /**< SUBSCRIBE */ - nua_notify_server_methods, /**< NOTIFY */ - nua_refer_server_methods, /**< REFER */ - nua_publish_server_methods; /**< PUBLISH */ - -/** Return true if we have not sent final response to request */ -su_inline -int nua_server_request_is_pending(nua_server_request_t const *sr) -{ - return sr && sr->sr_response.msg; -} - -su_inline -int nua_server_request_status(nua_server_request_t const *sr) -{ - return sr ? nta_incoming_status(sr->sr_irq) : 500; -} - -void nua_server_request_destroy(nua_server_request_t *sr); - -int nua_base_server_init(nua_server_request_t *sr); - -#define nua_base_server_init NULL - -int nua_base_server_preprocess(nua_server_request_t *sr); - -#define nua_base_server_preprocess NULL - -int nua_server_params(nua_server_request_t *sr, tagi_t const *tags); - -int nua_base_server_params(nua_server_request_t *sr, tagi_t const *tags); - -#define nua_base_server_params NULL - -int nua_server_trespond(nua_server_request_t *sr, - tag_type_t tag, tag_value_t value, ...); -int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags); - -int nua_base_server_trespond(nua_server_request_t *sr, - tag_type_t tag, tag_value_t value, ...); -int nua_base_server_respond(nua_server_request_t *sr, - tagi_t const *tags); - -int nua_server_report(nua_server_request_t *sr); - -int nua_base_server_treport(nua_server_request_t *sr, - tag_type_t tag, tag_value_t value, ...); -int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags); - -#endif /* NUA_SERVER_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c deleted file mode 100644 index 08bc8b6926..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ /dev/null @@ -1,4791 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 16:17:27 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#define NTA_INCOMING_MAGIC_T struct nua_server_request -#define NTA_OUTGOING_MAGIC_T struct nua_client_request -#define NTA_RELIABLE_MAGIC_T struct nua_server_request - -#include "nua_stack.h" -#include - -#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(). - -@sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite - -@par Session State Diagram - -@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 | - | | - +----------+ -@endcode -*/ - -/* ---------------------------------------------------------------------- */ -/* Session event usage */ - -/** @internal @brief Session-related state. */ -typedef struct nua_session_usage -{ - enum nua_callstate ss_state; /**< 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_reporting:1; /**< True if reporting state */ - unsigned : 0; - - struct session_timer { - unsigned interval; /**< Negotiated expiration time */ - enum nua_session_refresher refresher; /**< Our Negotiated role */ - - struct { - unsigned expires, defaults; /**< Value of Session-Expires (delta) */ - unsigned min_se; /**< Minimum session expires */ - /** none, local or remote */ - enum nua_session_refresher refresher; - unsigned supported:1, require:1, :0; - } local, remote; - - unsigned timer_set:1; /**< We have active session timer. */ - } ss_timer[1]; - - char const *ss_reason; /**< Reason for termination. */ - - /* Offer-Answer status */ - char const *ss_oa_recv, *ss_oa_sent; - - /**< Version of user SDP from latest successful O/A */ - int ss_sdp_version; -} nua_session_usage_t; - -static char const Offer[] = "offer", Answer[] = "answer"; - -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, - nua_client_request_t *cr, - nua_server_request_t *sr); -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 void signal_call_state_change(nua_handle_t *nh, - nua_session_usage_t *ss, - int status, char const *phrase, - enum nua_callstate next_state); - -static int nua_invite_client_should_ack(nua_client_request_t const *cr); -static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags); -static int nua_invite_client_complete(nua_client_request_t *cr); - -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, - nua_base_usage_update_params, - 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; - ds->ds_got_session = 1; - - ss->ss_timer->local.refresher = nua_any_refresher; - ss->ss_timer->remote.refresher = nua_any_refresher; - - return 0; -} - -static -void nua_session_usage_remove(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - nua_client_request_t *cr0, - nua_server_request_t *sr0) -{ - nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); - nua_client_request_t *cr, *cr_next; - nua_server_request_t *sr; - - /* Destroy queued INVITE transactions */ - for (cr = ds->ds_cr; cr; cr = cr_next) { - cr_next = cr->cr_next; - - if (cr->cr_method != sip_method_invite) - continue; - - if (cr == cr0) - continue; - - nua_client_request_ref(cr); - - if (nua_invite_client_should_ack(cr)) { - ss->ss_reporting = 1; - nua_invite_client_ack(cr, NULL); - ss->ss_reporting = 0; - } - - if (cr == du->du_cr && cr->cr_orq) { - nua_client_request_unref(cr); - continue; - } - - if (cr->cr_status < 200) { - nua_stack_event(nh->nh_nua, nh, - NULL, - (enum nua_event_e)cr->cr_event, - SIP_481_NO_TRANSACTION, - NULL); - } - - nua_client_request_remove(cr); - - nua_client_request_unref(cr); - - cr_next = ds->ds_cr; - } - - if (ss->ss_state != nua_callstate_terminated && - ss->ss_state != nua_callstate_init && - !ss->ss_reporting) { - int status = 0; char const *phrase = "Terminated"; - - if (cr0) - status = cr0->cr_status, phrase = cr0->cr_phrase ? cr0->cr_phrase : phrase; - else if (sr0) - status = sr0->sr_status, phrase = sr0->sr_phrase; - - signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated); - } - - /* Application can respond to BYE after the session usage has terminated */ - for (sr = ds->ds_sr; sr; sr = sr->sr_next) { - if (sr->sr_usage == du && sr->sr_method == sip_method_bye) - sr->sr_usage = NULL; - } - - ds->ds_has_session = 0; - 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; -} - -static -nua_dialog_usage_t *nua_dialog_usage_for_session(nua_dialog_state_t const *ds) -{ - if (ds == ((nua_handle_t *)NULL)->nh_ds) - return NULL; - - return nua_dialog_usage_get(ds, nua_session_usage, NULL); -} - -static -nua_session_usage_t *nua_session_usage_for_dialog(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); -} - -/** Zap the session associated with the handle */ -static -void nua_session_usage_destroy(nua_handle_t *nh, - nua_session_usage_t *ss) -{ - /* Remove usage */ - nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss), NULL, NULL); - - SU_DEBUG_5(("nua: terminated session %p\n", (void *)nh)); -} - -/* ======================================================================== */ -/* INVITE and call (session) processing */ - -static int session_timer_is_supported(struct session_timer const *t); - -static void session_timer_preferences(struct session_timer *t, - sip_t const *sip, - sip_supported_t const *supported, - unsigned expires, int isset, - enum nua_session_refresher refresher, - unsigned min_se); - -static void session_timer_store(struct session_timer *t, - sip_t const *sip); - -static int session_timer_check_min_se(msg_t *msg, sip_t *sip, - sip_t const *request, - unsigned long min_se); - -static int session_timer_add_headers(struct session_timer *t, - int initial, - msg_t *msg, sip_t *sip, - nua_handle_t *nh); - -static void session_timer_negotiate(struct session_timer *t, int uas); - -static void session_timer_set(nua_session_usage_t *ss, int uas); - -static int session_timer_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); - -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 -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 nua_server_retry_after(nua_server_request_t *sr, - 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 @b INVITE method. - * - * The INVITE method is used to initiate a call between two parties. The - * call is also known as SIP session. - * - * At SIP level the session is represented as @e Dialog, which is a - * peer-to-peer association between two SIP User-Agents. The dialog is - * established by a successful 2XX response to the INVITE. The dialog is - * terminated by BYE transaction, which application can initiate with - * nua_bye() call. - * - * An @e early @e dialog is established by an preliminary response - * (101..199), such as 180 Ringing. An early dialog is terminated - * with an error response with response code in range 300...699. - * - * The media session belonging to the SIP session is usually represented by - * SDP, Session Description Protocol. The media session it is usually - * established during the call set-up with procedure known as SDP - * Offer/Answer exchange, defined by @RFC3264. See Media Session - * Handling below for details. - * - * @param nh Pointer to operation handle - * @param tag, value, ... List of tagged parameters - * - * @return - * nothing - * - * @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 Tags: - * NUTAG_AUTH_CACHE() \n - * NUTAG_AUTOACK() \n - * NUTAG_AUTOANSWER() \n - * NUTAG_EARLY_MEDIA() \n - * NUTAG_ENABLEINVITE() \n - * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR() \n - * NUTAG_INVITE_TIMER() \n - * NUTAG_MEDIA_ENABLE() \n - * NUTAG_MEDIA_FEATURES() \n - * NUTAG_MIN_SE() \n - * NUTAG_RETRY_COUNT() \n - * NUTAG_SERVICE_ROUTE_ENABLE() \n - * NUTAG_SESSION_REFRESHER() \n - * NUTAG_SESSION_TIMER() \n - * NUTAG_SOA_NAME() \n - * NUTAG_UPDATE_REFRESH() \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 an unique tag is added to @From - * header. - * - * @par - * For the initial INVITE requests, the @Route headers specified by - * SIPTAG_ROUTE()/SIPTAG_ROUTER_STR() tags in nua_handle() and nua_invite() - * calls are inserted to the request. Next the initial route set specified - * by NUTAG_INITIAL_ROUTE()/NUTAG_INITIAL_ROUTE_STR() tags is prepended to - * the route. Finally (unless NUTAG_SERVICE_ROUTE_ENABLE(0) is used) the - * @ServiceRoute set received from the registrar is also appended to the - * route set of the initial request message. - * - * @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 a registration active, the @Contact header used with registration is - * used. Otherwise, the @Contact header is generated from the local IP - * address and port number, taking also the values from NUTAG_M_DISPLAY(), - * NUTAG_M_FEATURES(), NUTAG_M_PARAMS(), and NUTAG_M_USERNAME(). - * - * @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 - * 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 Tags Related to SIP Headers and Request-URI - * NUTAG_URL(), SIPTAG_REQUEST(), SIPTAG_REQUEST_STR() \n - * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(), - * SIPTAG_ROUTE(), SIPTAG_ROUTE_STR(), - * NUTAG_SERVICE_ROUTE_ENABLE() \n - * SIPTAG_MAX_FORWARDS(), SIPTAG_MAX_FORWARDS_STR() \n - * SIPTAG_PROXY_REQUIRE(), SIPTAG_PROXY_REQUIRE_STR() \n - * SIPTAG_FROM(), SIPTAG_FROM_STR() \n - * SIPTAG_TO(), SIPTAG_TO_STR() \n - * SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR() \n - * SIPTAG_CSEQ(), SIPTAG_CSEQ_STR() - * (note that @CSeq value is incremented if request gets retried)\n - * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR() \n - * SIPTAG_REQUEST_DISPOSITION(), SIPTAG_REQUEST_DISPOSITION_STR() \n - * SIPTAG_ACCEPT_CONTACT(), SIPTAG_ACCEPT_CONTACT_STR() \n - * SIPTAG_REJECT_CONTACT(), SIPTAG_REJECT_CONTACT_STR() \n - * SIPTAG_EXPIRES(), SIPTAG_EXPIRES_STR() \n - * SIPTAG_DATE(), SIPTAG_DATE_STR() \n - * SIPTAG_TIMESTAMP(), SIPTAG_TIMESTAMP_STR() \n - * SIPTAG_SUBJECT(), SIPTAG_SUBJECT_STR() \n - * SIPTAG_PRIORITY(), SIPTAG_PRIORITY_STR() \n - * SIPTAG_CALL_INFO(), SIPTAG_CALL_INFO_STR() \n - * SIPTAG_ORGANIZATION(), SIPTAG_ORGANIZATION_STR() \n - * NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n - * SIPTAG_IN_REPLY_TO(), SIPTAG_IN_REPLY_TO_STR() \n - * SIPTAG_ACCEPT(), SIPTAG_ACCEPT_STR() \n - * SIPTAG_ACCEPT_ENCODING(), SIPTAG_ACCEPT_ENCODING_STR() \n - * SIPTAG_ACCEPT_LANGUAGE(), SIPTAG_ACCEPT_LANGUAGE_STR() \n - * NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n - * NUTAG_EARLY_MEDIA(), SIPTAG_REQUIRE(), and SIPTAG_REQUIRE_STR() \n - * NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n - * SIPTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS_STR() \n - * SIPTAG_PROXY_AUTHORIZATION(), SIPTAG_PROXY_AUTHORIZATION_STR() \n - * SIPTAG_AUTHORIZATION(), SIPTAG_AUTHORIZATION_STR() \n - * SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR() \n - * SIPTAG_REPLACES(), SIPTAG_REPLACES_STR() \n - * NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(), - * SIPTAG_SESSION_EXPIRES(), SIPTAG_SESSION_EXPIRES_STR() \n - * NUTAG_MIN_SE(), SIPTAG_MIN_SE(), SIPTAG_MIN_SE_STR() \n - * SIPTAG_SECURITY_CLIENT(), SIPTAG_SECURITY_CLIENT_STR() \n - * SIPTAG_SECURITY_VERIFY(), SIPTAG_SECURITY_VERIFY_STR() \n - * SIPTAG_PRIVACY(), SIPTAG_PRIVACY_STR() \n - * SIPTAG_MIME_VERSION(), SIPTAG_MIME_VERSION_STR() \n - * SIPTAG_CONTENT_TYPE(), SIPTAG_CONTENT_TYPE_STR() \n - * SIPTAG_CONTENT_ENCODING(), SIPTAG_CONTENT_ENCODING_STR() \n - * SIPTAG_CONTENT_LANGUAGE(), SIPTAG_CONTENT_LANGUAGE_STR() \n - * SIPTAG_CONTENT_DISPOSITION(), SIPTAG_CONTENT_DISPOSITION_STR() \n - * SIPTAG_HEADER(), SIPTAG_HEADER_STR() \n - * SIPTAG_PAYLOAD(), SIPTAG_PAYLOAD_STR() \n - * - * @par SDP Handling - * By default the nua_invite() uses an @ref soa_session_t "SOA media - * session" object to take care of the Offer/Answer exchange. The SOA can - * be disabled with tag NUTAG_MEDIA_ENABLE(0). - * - * @par - * The SDP description of the - * @ref soa_session_t "soa media session" is included in the INVITE request - * as a message body. - * The SDP in the message body of the 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 Tags Related to SDP Management and Offer/Answer Model: - * NUTAG_MEDIA_ENABLE(), \n - * NUTAG_INCLUDE_EXTRA_SDP(), \n - * SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(), - * SOATAG_ORDERED_USER(), SOATAG_REUSE_REJECTED(), - * SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(), - * SOATAG_AUDIO_AUX(), \n - * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n - * - * @par Alternative Call Models - * In addition to the basic SIP call model described in @RFC3261 and - * @RFC3264, the early media model described in @RFC3262 is available. The - * use of 100rel and early media can be use can be forced with - * NUTAG_EARLY_MEDIA(1). - * - * Also, the "precondition" call model described in @RFC3312 is supported at - * SIP level, that is, the SIP PRACK and UPDATE requests are sent if - * "precondition" is added to the @Require header in the INVITE request. - * - * 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 - * - * @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 the - * stored 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 - */ - -static int nua_invite_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_invite_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_invite_client_preliminary(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_invite_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_session_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_invite_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - -nua_client_methods_t const nua_invite_client_methods = { - SIP_METHOD_INVITE, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - nua_invite_client_init, /* crm_init */ - nua_invite_client_request, /* crm_send */ - session_timer_check_restart, /* crm_check_restart */ - nua_invite_client_response, /* crm_recv */ - nua_invite_client_preliminary, /* crm_preliminary */ - nua_invite_client_report, /* crm_report */ - nua_invite_client_complete, /* crm_complete */ -}; - -extern nua_client_methods_t const nua_bye_client_methods; -extern nua_client_methods_t const nua_cancel_client_methods; -extern nua_client_methods_t const nua_update_client_methods; -extern nua_client_methods_t const nua_prack_client_methods; - -int nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_invite_client_methods, tags); -} - -static int nua_invite_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du; - nua_session_usage_t *ss; - - cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds); - /* Errors returned by nua_invite_client_init() - do not change the session state */ - cr->cr_neutral = 1; - - if (nh_is_special(nh) || - nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error)) - return nua_client_return(cr, 900, "Invalid handle for INVITE", msg); - else if (nh_referral_check(nh, tags) < 0) - return nua_client_return(cr, 900, "Invalid referral", msg); - - if (du) { - nua_server_request_t *sr; - for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) - /* INVITE in progress? */ - if (sr->sr_usage == du && sr->sr_method == sip_method_invite && - nua_server_request_is_pending(sr)) - return nua_client_return(cr, SIP_491_REQUEST_PENDING, msg); - cr->cr_initial = 0; - } - else { - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL); - cr->cr_initial = 1; - } - - if (!du) - return -1; - - ss = nua_dialog_usage_private(du); - - if (ss->ss_state >= nua_callstate_terminating) - return nua_client_return(cr, 900, "Session is terminating", msg); - - if (nua_client_bind(cr, du) < 0) - return nua_client_return(cr, 900, "INVITE already in progress", msg); - - cr->cr_neutral = 0; - - session_timer_preferences(ss->ss_timer, - sip, - NH_PGET(nh, supported), - NH_PGET(nh, session_timer), - NUA_PISSET(nh->nh_nua, nh, session_timer), - NH_PGET(nh, refresher), - NH_PGET(nh, min_se)); - - return 0; -} - -static int nua_invite_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss; - int offer_sent = 0, retval; - - if (du == NULL) /* Call terminated */ - return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); - - ss = NUA_DIALOG_USAGE_PRIVATE(du); - - if (ss->ss_state >= nua_callstate_terminating) - return nua_client_return(cr, 900, "Session is terminating", msg); - - nua_dialog_usage_reset_refresh(du); - - /* Add session timer headers */ - if (session_timer_is_supported(ss->ss_timer)) - session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init, - msg, sip, nh); - - 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 (nh->nh_soa) { - soa_init_offer_answer(nh->nh_soa); - - if (sip->sip_payload) - offer_sent = 0; /* XXX - kludge */ - else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0) - return -1; - else - offer_sent = 1; - - if (offer_sent > 0 && - session_include_description(nh->nh_soa, 1, msg, sip) < 0) - return nua_client_return(cr, 900, "Internal media error", msg); - - if (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); - } - } - } - else { - offer_sent = session_get_description(sip, NULL, NULL); - } - - retval = nua_base_client_trequest(cr, msg, sip, - NTATAG_REL100(ss->ss_100rel), - TAG_NEXT(tags)); - if (retval == 0) { - if ((cr->cr_offer_sent = offer_sent)) - ss->ss_oa_sent = Offer; - - if (!cr->cr_restarting) /* Restart logic calls nua_invite_client_report */ - signal_call_state_change(nh, ss, 0, "INVITE sent", - nua_callstate_calling); - } - - return retval; -} - -static int nua_invite_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - int uas; - - if (ss == NULL || sip == NULL) { - /* Xyzzy */ - } - else if (status < 300) { - du->du_ready = 1; - - if (session_timer_is_supported(ss->ss_timer)) - session_timer_store(ss->ss_timer, sip); - - session_timer_set(ss, uas = 0); - } - - return nua_session_client_response(cr, status, phrase, sip); -} - -static int nua_invite_client_preliminary(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - assert(sip); - - if (ss && sip && sip->sip_rseq) { - /* Handle 100rel responses */ - sip_rseq_t *rseq = sip->sip_rseq; - - /* Establish early dialog - we should fork here */ - if (!nua_dialog_is_established(nh->nh_ds)) { - nta_outgoing_t *tagged; - - nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, 1); - nua_dialog_store_peer_info(nh, nh->nh_ds, sip); - - /* Tag the INVITE request */ - tagged = nta_outgoing_tagged(cr->cr_orq, - nua_client_orq_response, cr, - sip->sip_to->a_tag, sip->sip_rseq); - if (tagged) { - nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = tagged; - } - else { - cr->cr_graceful = 1; - ss->ss_reason = "SIP;cause=500;text=\"Cannot Create Early Dialog\""; - } - } - - if (!rseq) { - SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", (void *)nh)); - } - else if (nta_outgoing_rseq(cr->cr_orq) > rseq->rs_response) { - SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", (void *)nh, - (unsigned)rseq->rs_response, - nta_outgoing_rseq(cr->cr_orq))); - return 1; /* Do not send event */ - } - else if (nta_outgoing_setrseq(cr->cr_orq, rseq->rs_response) < 0) { - SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", (void *)nh, - (unsigned)rseq->rs_response)); - cr->cr_graceful = 1; - ss->ss_reason = "SIP;cause=400;text=\"Bad RSeq\""; - } - } - - return nua_session_client_response(cr, status, phrase, sip); -} - -/** Process response to a session request (INVITE, PRACK, UPDATE) */ -static int nua_session_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - char const *sdp = NULL; - size_t len; - char const *received = NULL; - -#define LOG3(m) \ - SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s (%u)\n", \ - (void *)nh, cr->cr_method_name, (m), \ - received ? received : "SDP", status, phrase, cr->cr_answer_recv)) -#define LOG5(m) \ - SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s (%u)\n", \ - (void *)nh, cr->cr_method_name, (m), received, status, phrase, cr->cr_answer_recv)) - - retry: - - if (!ss || !sip || 300 <= status) - /* Xyzzy */; - else if (!session_get_description(sip, &sdp, &len)) - /* No SDP */; - else if (cr->cr_answer_recv) { - if (cr->cr_answer_recv > status) { - LOG3("status is older than previous answer, ignoring"); - sdp = NULL; - return 0; - } else { - // we need to make sure its *actually* a dup, so we can't assume for now. - LOG3("multiple answers received, processing"); - cr->cr_answer_recv = 0; - goto retry; - } - } - else if (cr->cr_offer_sent) { - /* case 1: answer to our offer */ - cr->cr_answer_recv = status; - received = Answer; - - if (nh->nh_soa == NULL) - LOG5("got SDP"); - else if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) { - LOG3("error parsing SDP"); - sdp = NULL; - cr->cr_graceful = 1; - ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\""; - } - else if (soa_process_answer(nh->nh_soa, NULL) < 0) { - LOG5("error processing SDP"); - /* XXX */ - sdp = NULL; - } - else if (soa_activate(nh->nh_soa, NULL) < 0) { - /* XXX - what about errors? */ - LOG3("error activating media after"); - } - else { - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - LOG5("processed SDP"); - } - } - else if (cr->cr_method != sip_method_invite) { - /* If non-invite request did not have offer, ignore SDP in response */ - LOG3("ignoring extra"); - sdp = NULL; - } - else { - /* case 2: new offer */ - cr->cr_offer_recv = 1, cr->cr_answer_sent = 0; - received = Offer; - - if (nh->nh_soa && soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) { - LOG3("error parsing SDP"); - sdp = NULL; - cr->cr_graceful = 1; - ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\""; - } - else - LOG5("got SDP"); - } - - if (ss && received) - ss->ss_oa_recv = received; - - if (sdp && nh->nh_soa) - return nua_base_client_tresponse(cr, status, phrase, sip, - NH_REMOTE_MEDIA_TAGS(1, nh->nh_soa), - TAG_END()); - else - return nua_base_client_response(cr, status, phrase, sip, NULL); -} - -static int nua_invite_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - msg_t *response = nta_outgoing_getresponse(orq); - unsigned next_state; - int error; - - nh_referral_respond(nh, status, phrase); /* XXX - restarting after 401/407 */ - - nua_stack_event(nh->nh_nua, nh, - response, - (enum nua_event_e)cr->cr_event, - status, phrase, - tags); - - if (cr->cr_waiting) - /* Do not report call state change if waiting for restart */ - return 1; - - if (ss == NULL) { - signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated); - return 1; - } - - ss->ss_reporting = 1; - - if (cr->cr_neutral) { - signal_call_state_change(nh, ss, status, phrase, ss->ss_state); - ss->ss_reporting = 0; - return 1; - } - - response = msg_ref_create(response); /* Keep reference to contents of sip */ - - if (orq != cr->cr_orq && cr->cr_orq) { /* Being restarted */ - next_state = nua_callstate_calling; - } - else if (status == 100) { - next_state = nua_callstate_calling; - } - else if (status < 300 && cr->cr_graceful) { - next_state = nua_callstate_terminating; - if (200 <= status) { - nua_invite_client_ack(cr, NULL); - } - } - else if (status < 200) { - next_state = nua_callstate_proceeding; - - if (sip && sip->sip_rseq && - !SIP_IS_ALLOWED(NH_PGET(nh, appl_method), sip_method_prack)) { - sip_rack_t rack[1]; - - 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; - - error = nua_client_tcreate(nh, nua_r_prack, &nua_prack_client_methods, - SIPTAG_RACK(rack), - TAG_END()); - if (error < 0) { - cr->cr_graceful = 1; - next_state = nua_callstate_terminating; - } - } - } - else if (status < 300) { - next_state = nua_callstate_completing; - } - else if (cr->cr_terminated) { - next_state = nua_callstate_terminated; - } - else if (cr->cr_graceful && ss->ss_state >= nua_callstate_completing) { - next_state = nua_callstate_terminating; - } - else { - next_state = nua_callstate_init; - } - - if (next_state == nua_callstate_calling) { - if (sip && sip->sip_status && sip->sip_status->st_status == 100) { - ss->ss_reporting = 0; - return 1; - } - } - - if (next_state == nua_callstate_completing) { - if (NH_PGET(nh, auto_ack) || - /* Auto-ACK response to re-INVITE when media is enabled - and auto_ack is not set to 0 on handle */ - (ss->ss_state == nua_callstate_ready && nh->nh_soa && - !NH_PISSET(nh, auto_ack))) { - nua_client_request_t *cru; - - for (cru = ds->ds_cr; cru; cru = cru->cr_next) { - if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv) - break; - } - - if (cru) - /* A final response to UPDATE or PRACK with answer on its way? */; - else if (nua_invite_client_ack(cr, NULL) > 0) - next_state = nua_callstate_ready; - else - next_state = nua_callstate_terminating; - } - } - - if (next_state == nua_callstate_terminating) { - /* Send BYE or CANCEL */ - /* XXX - Forking - send BYE to early dialog?? */ - if (ss->ss_state > nua_callstate_proceeding || status >= 200) - error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); - else - error = nua_client_create(nh, nua_r_cancel, - &nua_cancel_client_methods, tags); - - if (error) { - next_state = nua_callstate_terminated; - cr->cr_terminated = 1; - } - cr->cr_graceful = 0; - } - - ss->ss_reporting = 0; - - signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state); - - msg_destroy(response); - - return 1; -} - -/**@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 needed 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: - * Header tags defined in - * - * @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_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - nua_session_usage_t *ss = nua_dialog_usage_private(du); - nua_client_request_t *cr = du ? du->du_cr : NULL; - int error; - - if (!cr || cr->cr_orq == NULL || cr->cr_status < 200) { - UA_EVENT2(nua_i_error, 900, "No response to ACK"); - return 1; - } - - if (tags) - nua_stack_set_params(nua, nh, nua_i_error, tags); - - nua_client_request_ref(cr); - error = nua_invite_client_ack(cr, tags); - - if (error < 0) { - if (ss->ss_reason == NULL) - ss->ss_reason = "SIP;cause=500;text=\"Internal Error\""; - ss->ss_reporting = 1; /* We report terminated state here if BYE fails */ - error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); - ss->ss_reporting = 0; - signal_call_state_change(nh, ss, 500, "Internal Error", - error - ? nua_callstate_terminated - : nua_callstate_terminating); - } - else if (ss) - signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready); - - nua_client_request_unref(cr); - - return 0; -} - -/** Send ACK, destroy INVITE transaction. - * - * @retval 1 if successful - * @retval < 0 if an error occurred - */ -static -int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); - - msg_t *msg; - sip_t *sip; - int error = -1; - sip_authorization_t *wa; - sip_proxy_authorization_t *pa; - sip_cseq_t *cseq; - int proxy_is_set; - url_string_t *proxy; - nta_outgoing_t *ack; - int status = 200; - char const *phrase = "OK", *reason = NULL; - char const *invite_branch; - char const *pl_s = NULL; - - assert(cr->cr_orq); - assert(cr->cr_method == sip_method_invite); - - cr->cr_initial = 0; - - if (!ds->ds_leg) { - /* XXX - fix nua_dialog_usage_remove_at() instead! */ - goto error; - } - - tl_gets(tags, - SIPTAG_PAYLOAD_STR_REF(pl_s), - TAG_END()); - - - assert(ds->ds_leg); - - msg = nta_outgoing_getrequest(cr->cr_orq); - sip = sip_object(msg); - if (!msg) - goto error; - invite_branch = nta_outgoing_branch(cr->cr_orq); - - wa = sip_authorization(sip); - pa = sip_proxy_authorization(sip); - - msg_destroy(msg); - - msg = nta_msg_create(nh->nh_nua->nua_nta, 0); - sip = sip_object(msg); - if (!msg) - goto error; - - cseq = sip_cseq_create(msg_home(msg), cr->cr_seq, SIP_METHOD_ACK); - - if (!cseq) - ; - else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)) < 0) - ; - else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)) < 0) - ; - else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0) - ; - else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0) - ; - else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0) - ; - else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACK, NULL) < 0) - ; - else { - /* Remove extra headers */ - 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); - - if (ss == NULL || ss->ss_state > nua_callstate_ready || pl_s) - ; - else if (cr->cr_offer_recv && !cr->cr_answer_sent) { - if (nh->nh_soa == NULL) { - if (session_get_description(sip, NULL, NULL)) - cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer; - } - else if (soa_generate_answer(nh->nh_soa, NULL) < 0 || - session_include_description(nh->nh_soa, 1, msg, sip) < 0) { - status = 900, phrase = "Internal media error"; - reason = "SIP;cause=500;text=\"Internal media error\""; - /* reason = soa_error_as_sip_reason(nh->nh_soa); */ - } - else { - cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer; - } - } - - if (ss == NULL || ss->ss_state > nua_callstate_ready || reason) - ; - else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) { - /* signal SOA that O/A round(s) is (are) complete */ - if (soa_activate(nh->nh_soa, NULL) >= 0) { - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - } - else if (nh->nh_soa == NULL - /* NUA does not necessarily know dirty details */ - /* && !(cr->cr_offer_sent && !cr->cr_answer_recv) */) { - ; - } - else { - nua_client_request_t *cru; - - /* Final response to UPDATE or PRACK may be on its way ... */ - for (cru = ds->ds_cr; cru; cru = cru->cr_next) { - if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv) - break; - } - - if (cru == NULL) { - /* No SDP answer -> terminate call */ - status = 988, phrase = "Incomplete offer/answer"; - reason = "SIP;cause=488;text=\"Incomplete offer/answer\""; - } - } - - proxy_is_set = NH_PISSET(nh, proxy); - proxy = NH_PGET(nh, proxy); - - if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL, - msg, - NTATAG_ACK_BRANCH(invite_branch), - TAG_IF(proxy_is_set, - NTATAG_DEFAULT_PROXY(proxy)), - SIPTAG_END(), - TAG_NEXT(tags)))) { - /* TR engine keeps this around for T2 so it catches all 2XX retransmissions */ - nta_outgoing_destroy(ack); - - if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready) - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_media_error, status, phrase, - NULL); - } - else if (!reason) { - status = 900, phrase = "Cannot send ACK"; - reason = "SIP;cause=500;text=\"Internal Error\""; - } - - if (ss && reason) - ss->ss_reason = reason; - - if (status < 300) - error = 1; - else - error = -2; - } - - if (error == -1) - msg_destroy(msg); - - error: - cr->cr_acked = 1; /* ... or we have at least tried */ - - nua_client_request_remove(cr); - nua_client_request_clean(cr); - - return error; -} - -static int -nua_invite_client_should_ack(nua_client_request_t const *cr) -{ - return - cr && cr->cr_orq && !cr->cr_acked && - 200 <= cr->cr_status && cr->cr_status < 300; -} - -/** Complete client request */ -static int nua_invite_client_complete(nua_client_request_t *cr) -{ - if (cr->cr_orq == NULL) - /* Xyzzy */; - else if (cr->cr_status < 200) - nta_outgoing_cancel(cr->cr_orq); - else if (cr->cr_status < 300 && !cr->cr_acked) - nua_invite_client_ack(cr, NULL); - - return 0; -} - -/**@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: - * Header tags defined in - * - * @par Events: - * #nua_r_cancel, #nua_i_state (#nua_i_active, #nua_i_terminated) - * - * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel - */ - -static int nua_cancel_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_cancel_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip); - -nua_client_methods_t const nua_cancel_client_methods = { - SIP_METHOD_CANCEL, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 1, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - NULL, /* crm_init */ - nua_cancel_client_request, /* .. not really crm_send */ - nua_cancel_client_check_restart, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_cancel_client_methods, tags); -} - -static int nua_cancel_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - - if (!du || !du->du_cr || !du->du_cr->cr_orq || - nta_outgoing_status(du->du_cr->cr_orq) >= 200) { - return nua_client_return(cr, 481, "No transaction to CANCEL", msg); - } - - assert(cr->cr_orq == NULL); - - cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq, - nua_client_orq_response, - nua_client_request_ref(cr), - TAG_NEXT(tags)); - - if (cr->cr_orq == NULL) { - nua_client_request_unref(cr); - return -1; - } - - return 0; -} - -static int -nua_cancel_client_check_restart(nua_client_request_t *cr, - int status, - char const *phrase, - sip_t const *sip) -{ - /* We cannot really restart CANCEL */ - 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 void nua_session_usage_refresh(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du, - sip_time_t now) -{ - nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du); - nua_client_request_t const *cr = du->du_cr; - nua_server_request_t const *sr; - - if (ss->ss_state >= nua_callstate_terminating || - /* INVITE is in progress or being authenticated */ - nua_client_request_in_progress(cr)) - return; - - if (ds->ds_cr) return; /* request queued */ - - /* UPDATE has been queued */ - //for (cr = ds->ds_cr; cr; cr = cr->cr_next) - //if (cr->cr_method == sip_method_update) - // return; - - /* INVITE or UPDATE in progress on server side */ - 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)) - return; - - if (ss->ss_timer->refresher == nua_remote_refresher) { - SU_DEBUG_3(("nua(%p): session almost expired, sending BYE before timeout.\n", (void *)nh)); - ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; - nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); - return; - } - else if (NH_PGET(nh, update_refresh)) { - nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); - } - else if (du->du_cr) { - nua_client_resend_request(du->du_cr, 0); - } - else { - nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); - } -} - -/** @interal Shut down session usage. - * - * @retval >0 shutdown done - * @retval 0 shutdown in progress - * @retval <0 try again later - */ -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_server_request_t *sr, *sr_next; - nua_client_request_t *cri; - - assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); - - /* 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 (nua_server_request_is_pending(sr)) { - SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE); - nua_server_respond(sr, NULL); - if (nua_server_report(sr) >= 2) - return 480; - } - else - nua_server_request_destroy(sr); - } - } - - cri = du->du_cr; - - switch (ss->ss_state) { - case nua_callstate_calling: - case nua_callstate_proceeding: - return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL); - - case nua_callstate_completing: - case nua_callstate_completed: - case nua_callstate_ready: - if (cri && cri->cr_orq) { - if (cri->cr_status < 200) { - nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL); - } - else if (cri->cr_status < 300 && !cri->cr_acked) { - nua_invite_client_ack(cri, NULL); - } - } - if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL) != 0) - break; - - signal_call_state_change(nh, ss, 487, "BYE sent", - nua_callstate_terminating); - return 0; - - case nua_callstate_terminating: - case nua_callstate_terminated: /* XXX */ - return 0; - - default: - break; - } - - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - - return 200; -} - -/**@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 , . - * - * @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 - */ - -static int nua_prack_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_prack_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_prack_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_prack_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - -nua_client_methods_t const nua_prack_client_methods = { - SIP_METHOD_PRACK, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 1, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - nua_prack_client_init, /* crm_init */ - nua_prack_client_request, /* crm_send */ - NULL, /* crm_check_restart */ - nua_prack_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - nua_prack_client_report, /* crm_report */ - NULL, /* crm_complete */ -}; - -int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_prack_client_methods, tags); -} - -static int nua_prack_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - - cr->cr_usage = du; - - return 0; -} - -static int nua_prack_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss; - nua_client_request_t *cri; - int offer_sent = 0, answer_sent = 0, retval; - int status = 0; char const *phrase = "PRACK Sent"; - //uint32_t rseq = 0; - - if (du == NULL) /* Call terminated */ - return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); - - ss = NUA_DIALOG_USAGE_PRIVATE(du); - if (ss->ss_state >= nua_callstate_terminating) - return nua_client_return(cr, 900, "Session is terminating", msg); - - cri = du->du_cr; - -// if (sip->sip_rack) -// rseq = sip->sip_rack->ra_response; - - if (cri->cr_offer_recv && !cri->cr_answer_sent) { - if (nh->nh_soa == NULL) - /* It is up to application to handle SDP */ - answer_sent = session_get_description(sip, NULL, NULL); - else if (sip->sip_payload) - /* XXX - we should just do MIME in session_include_description() */; - else 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): local response to PRACK: %d %s\n", - (void *)nh, status, phrase)); - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_media_error, status, phrase, - NULL); - return nua_client_return(cr, status, phrase, msg); - } - else { - answer_sent = 1; - if (soa_activate(nh->nh_soa, NULL) >= 0) { - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - } - } - else if (nh->nh_soa == NULL) { - offer_sent = session_get_description(sip, NULL, NULL); - } - else { - /* When 100rel response status was 183 do support for preconditions */ - int send_offer = ss->ss_precondition && - cri->cr_status == 183 && cri->cr_offer_sent && cri->cr_answer_recv; - - if (!send_offer) { - tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp); - send_offer = t && t->t_value; - } - - if (!send_offer) { - } - else if (soa_generate_offer(nh->nh_soa, 0, NULL) >= 0 && - session_include_description(nh->nh_soa, 1, msg, sip) >= 0) { - offer_sent = 1; - } - else { - status = soa_error_as_sip_response(nh->nh_soa, &phrase); - SU_DEBUG_3(("nua(%p): PRACK offer: %d %s\n", (void *)nh, - status, phrase)); - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_media_error, status, phrase, NULL); - return nua_client_return(cr, status, phrase, msg); - } - } - - retval = nua_base_client_request(cr, msg, sip, NULL); - - if (retval == 0) { - cr->cr_offer_sent = offer_sent; - cr->cr_answer_sent = answer_sent; - - if (offer_sent) - ss->ss_oa_sent = Offer; - else if (answer_sent) - ss->ss_oa_sent = Answer; - - if (cr->cr_restarting) - /* Restart logic calls nua_prack_client_report */; - else if (!cr->cr_auto && (!offer_sent || !answer_sent)) - /* Suppose application know it called nua_prack() */; - else - signal_call_state_change(nh, ss, status, phrase, ss->ss_state); - } - - return retval; -} - -static int nua_prack_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - /* XXX - fatal error cases? */ - - return nua_session_client_response(cr, status, phrase, sip); -} - -static int nua_prack_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - int acked = 0; - - nua_stack_event(nh->nh_nua, nh, - nta_outgoing_getresponse(orq), - (enum nua_event_e)cr->cr_event, - status, phrase, - tags); - - if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting) - return 1; - - if (cr->cr_offer_sent || cr->cr_answer_sent) { - unsigned next_state = ss->ss_state; - - if (status < 200) - ; - else if (nua_invite_client_should_ack(du->du_cr)) { - /* There is an un-ACK-ed INVITE there */ - assert(du->du_cr->cr_method == sip_method_invite); - if (NH_PGET(nh, auto_ack) || - /* Auto-ACK response to re-INVITE when media is enabled - and auto_ack is not set to 0 on handle */ - (ss->ss_state == nua_callstate_ready && nh->nh_soa && - !NH_PISSET(nh, auto_ack))) { - /* There should be no UPDATE with offer/answer - if PRACK with offer/answer was ongoing! */ - if (nua_invite_client_ack(du->du_cr, NULL) > 0) - next_state = nua_callstate_ready; - else - next_state = nua_callstate_terminating; - - acked = 1; - } - } - - signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state); - } - - if (acked && - nua_client_is_queued(du->du_cr) && - du->du_cr->cr_method == sip_method_invite) { - /* New INVITE was queued - do not send UPDATE */ - } - else if (ss->ss_update_needed && 200 <= status && status < 300 && - !SIP_IS_ALLOWED(NH_PGET(nh, appl_method), sip_method_update)) - nua_client_create(nh, nua_r_update, &nua_update_client_methods, NULL); - - return 1; -} - -/* ---------------------------------------------------------------------- */ -/* UAS side of INVITE */ - -/** @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 - * @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 415 Unsupported Media Type 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 the response message using SIPTAG_PAYLOAD() or - * SIPTAG_PAYLOAD_STR(). Also, the @ContentType should be set using - * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR(). - * - * @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 - * NUTAG_EARLY_ANSWER(1), 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_ANSWER(), NUTAG_EARLY_MEDIA(), - * NUTAG_ONLY183_100REL(), - * NUTAG_INCLUDE_EXTRA_SDP(), - * #nua_i_prack, #nua_i_update, nua_update(), - * nua_invite(), #nua_r_invite - * - * @par - * @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 - */ - -static int nua_invite_server_init(nua_server_request_t *sr); -static int nua_session_server_init(nua_server_request_t *sr); -static int nua_invite_server_preprocess(nua_server_request_t *sr); -static int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *); -static int nua_invite_server_is_100rel(nua_server_request_t *, tagi_t const *); -static int nua_invite_server_report(nua_server_request_t *sr, tagi_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_ack_error(nua_server_request_t *sr, msg_t *ackmsg, - int status, char const *phrase, char const *reason), - process_cancel(nua_server_request_t *, nta_incoming_t *, sip_t const *), - process_timeout(nua_server_request_t *, nta_incoming_t *), - process_prack(nua_server_request_t *, - nta_reliable_t *rel, - nta_incoming_t *irq, - sip_t const *sip); - -nua_server_methods_t const nua_invite_server_methods = - { - SIP_METHOD_INVITE, - nua_i_invite, /* Event */ - { - 1, /* Create dialog */ - 0, /* Initial request */ - 1, /* Target refresh request */ - 1, /* Add Contact */ - }, - nua_invite_server_init, - nua_invite_server_preprocess, - nua_base_server_params, - nua_invite_server_respond, - nua_invite_server_report, - }; - - -/** @internal Preprocess incoming invite - sure we have a valid request. - * - * @return 0 if request is valid, or error statuscode otherwise - */ -static int -nua_invite_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_t *nua = nh->nh_nua; - nua_session_usage_t *ss; - - sr->sr_neutral = 1; - - if (!NUA_PGET(nua, nh, invite_enable)) - return SR_STATUS1(sr, SIP_403_FORBIDDEN); - - if (nua_session_server_init(sr)) - return sr->sr_status; - - if (sr->sr_usage) { - /* Existing session - check for overlap and glare */ - - nua_server_request_t const *sr0; - nua_client_request_t const *cr; - - for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) { - /* Previous INVITE has not been ACKed */ - if (sr0->sr_method == sip_method_invite) - break; - /* Or we have sent offer but have not received an answer */ - if (sr->sr_sdp && sr0->sr_offer_sent && !sr0->sr_answer_recv) - break; - /* Or we have received request with offer but not sent an answer */ - if (sr->sr_sdp && sr0->sr_offer_recv && !sr0->sr_answer_sent) - break; - } - - if (sr0) { - /* Overlapping invites - RFC 3261 14.2 */ - return nua_server_retry_after(sr, 500, "Overlapping Requests", 0, 10); - } - - for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next) { - if (cr->cr_usage == sr->sr_usage && cr->cr_orq && cr->cr_offer_sent) - /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */ - return SR_STATUS1(sr, SIP_491_REQUEST_PENDING); - } - - ss = nua_dialog_usage_private(sr->sr_usage); - - if (ss->ss_state < nua_callstate_ready && - ss->ss_state != nua_callstate_init) { - return nua_server_retry_after(sr, 500, "Overlapping Requests 2", 0, 10); - } - } - - sr->sr_neutral = 0; - - return 0; -} - -/** Initialize session server request. - * - * Ensure that the request is valid. - */ -static int -nua_session_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_t *nua = nh->nh_nua; - - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - sip_t *request = (sip_t *) sr->sr_request.sip; - - if (!sr->sr_initial) - sr->sr_usage = nua_dialog_usage_get(nh->nh_ds, nua_session_usage, NULL); - - if (sr->sr_method != sip_method_invite && sr->sr_usage == NULL) { - /* UPDATE/PRACK sent within an existing dialog? */ - return SR_STATUS(sr, 481, "Call Does Not Exist"); - } - else if (sr->sr_usage) { - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - if (ss->ss_state >= nua_callstate_terminating) - return SR_STATUS(sr, 481, "Call is being terminated"); - } - - if (nh->nh_soa) { - sip_accept_t *a = nua->nua_invite_accept; - - /* XXX - soa should know what it supports */ - sip_add_dup(msg, sip, (sip_header_t *)a); - - /* if we see there is a multipart content-type, - parse it into the sip structre and find the SDP and replace it - into the request as the requested content */ - if (request->sip_content_type && - su_casenmatch(request->sip_content_type->c_type, "multipart/", 10)) { - msg_multipart_t *mp, *mpp; - - if (request->sip_multipart) { - mp = request->sip_multipart; - } else { - mp = msg_multipart_parse(nua_handle_home(nh), - request->sip_content_type, - (sip_payload_t *)request->sip_payload); - request->sip_multipart = mp; - } - - if (mp) { - int sdp = 0; - - /* extract the SDP and set the primary content-type and payload to that SDP as if it was the only content so SOA will work */ - for(mpp = mp; mpp; mpp = mpp->mp_next) { - if (mpp->mp_content_type && mpp->mp_content_type->c_type && - mpp->mp_payload && mpp->mp_payload->pl_data && - su_casenmatch(mpp->mp_content_type->c_type, "application/sdp", 15)) { - - request->sip_content_type = msg_content_type_dup(nua_handle_home(nh), mpp->mp_content_type); - - if (request->sip_content_length) { - request->sip_content_length->l_length = mpp->mp_payload->pl_len; - } - - request->sip_payload->pl_data = su_strdup(nua_handle_home(nh), mpp->mp_payload->pl_data); - request->sip_payload->pl_len = mpp->mp_payload->pl_len; - - sdp++; - - break; - } - } - - /* insist on the existance of a SDP in the content or refuse the request */ - if (!sdp) { - return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE); - } - } - } - - - /* Make sure caller uses application/sdp without compression */ - if (nta_check_session_content(NULL, request, a, TAG_END())) { - sip_add_make(msg, sip, sip_accept_encoding_class, ""); - return SR_STATUS1(sr, SIP_415_UNSUPPORTED_MEDIA); - } - - /* Make sure caller accepts application/sdp */ - if (nta_check_accept(NULL, request, a, NULL, TAG_END())) { - sip_add_make(msg, sip, sip_accept_encoding_class, ""); - return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE); - } - } - - if (request->sip_session_expires && - sip_has_feature(NH_PGET(nh, supported), "timer") && - session_timer_check_min_se(msg, sip, request, NH_PGET(nh, min_se))) { - if (sip->sip_min_se) - return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL); - else - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - session_get_description(request, &sr->sr_sdp, &sr->sr_sdp_len); - - return 0; -} - -/** Preprocess INVITE. - * - * This is called after a handle has been created for an incoming INVITE. - */ -int nua_invite_server_preprocess(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_state_t *ds = nh->nh_ds; - nua_session_usage_t *ss; - - sip_t const *request = sr->sr_request.sip; - - assert(sr->sr_status == 100); - assert(nh != nh->nh_nua->nua_dhandle); - - if (sr->sr_status > 100) - return sr->sr_status; - - if (nh->nh_soa) - soa_init_offer_answer(nh->nh_soa); - - if (sr->sr_sdp) { - if (nh->nh_soa && - soa_set_remote_sdp(nh->nh_soa, NULL, sr->sr_sdp, sr->sr_sdp_len) < 0) { - SU_DEBUG_5(("nua(%p): %s server: error parsing SDP\n", (void *)nh, - "INVITE")); - return SR_STATUS(sr, 400, "Bad Session Description"); - } - else - sr->sr_offer_recv = 1; - } - - /* Add the session usage */ - if (sr->sr_usage == NULL) { - sr->sr_usage = nua_dialog_usage_add(nh, ds, nua_session_usage, NULL); - if (sr->sr_usage == NULL) - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - ss = nua_dialog_usage_private(sr->sr_usage); - - if (sr->sr_offer_recv) - ss->ss_oa_recv = Offer; - - ss->ss_100rel = NH_PGET(nh, early_media); - ss->ss_precondition = sip_has_feature(request->sip_require, "precondition"); - if (ss->ss_precondition) - ss->ss_100rel = 1; - - session_timer_store(ss->ss_timer, request); - -#if 0 /* The glare and overlap tests should take care of this. */ - assert(ss->ss_state >= nua_callstate_completed || - ss->ss_state == nua_callstate_init); -#endif - - 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))) { - SR_STATUS1(sr, SIP_200_OK); - } - else if (NH_PGET(nh, auto_alert)) { - if (ss->ss_100rel && - (sip_has_feature(request->sip_supported, "100rel") || - sip_has_feature(request->sip_require, "100rel"))) { - SR_STATUS1(sr, SIP_183_SESSION_PROGRESS); - } - else { - SR_STATUS1(sr, SIP_180_RINGING); - } - } - - return 0; -} - - -/** @internal Respond to an INVITE request. - * - */ -static -int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = sr->sr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - int reliable = 0, maybe_answer = 0, offer = 0, answer = 0, extra = 0; - - enter; - - if (du == NULL) { - if (sr->sr_status < 300) - sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR); - return nua_base_server_respond(sr, tags); - } - - if (200 <= sr->sr_status && sr->sr_status < 300) { - reliable = 1, maybe_answer = 1; - } - else if (nua_invite_server_is_100rel(sr, tags)) { - reliable = 1, maybe_answer = 1; - } - else if (!nh->nh_soa || sr->sr_status >= 300) { - if (sr->sr_neutral) - return nua_base_server_respond(sr, tags); - } - else if (tags && 100 < sr->sr_status && sr->sr_status < 200 && - !NHP_ISSET(nh->nh_prefs, early_answer)) { - 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()); - - maybe_answer = user_sdp || user_sdp_str; - } - else { - maybe_answer = NH_PGET(nh, early_answer); - } - - if (!nh->nh_soa) { - if (session_get_description(sip, NULL, NULL)) { - if (sr->sr_offer_recv) - answer = 1; - else if (sr->sr_offer_sent < 2) - offer = 1; - } - } - else if (sr->sr_status >= 300) { - soa_clear_remote_sdp(nh->nh_soa); - } - else 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 && maybe_answer) { - /* Generate answer */ - if (soa_generate_answer(nh->nh_soa, NULL) >= 0 && - soa_activate(nh->nh_soa, NULL) >= 0) { - answer = 1; /* signal that O/A answer sent (answer to invite) */ - /* ss_sdp_version is updated only after answer is sent reliably */ - } - /* We have an error! */ - else if (sr->sr_status >= 200) { - sip_warning_t *warning = NULL; - int wcode; - char const *text; - char const *host = "invalid."; - - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_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); - sip_header_insert(msg, sip, (sip_header_t *)warning); - } - } - else { - /* 1xx - we don't have to send answer */ - } - } - else if (sr->sr_offer_recv && sr->sr_answer_sent == 1 && maybe_answer) { - /* The answer was sent unreliably, keep sending it */ - answer = 1; - } - else if (!sr->sr_offer_recv && !sr->sr_offer_sent && reliable) { - if (200 <= sr->sr_status && nua_callstate_ready <= ss->ss_state && - NH_PGET(nh, refresh_without_sdp)) - /* This is a re-INVITE without SDP - do not try to send offer in 200 */; - else - /* Generate offer */ - if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0) - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase); - else - offer = 1; - } - - if (sr->sr_status < 300 && (offer || answer || extra)) { - if (nh->nh_soa && session_include_description(nh->nh_soa, 1, msg, sip) < 0) - SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - else if (offer) - sr->sr_offer_sent = 1 + reliable, ss->ss_oa_sent = Offer; - else if (answer) - sr->sr_answer_sent = 1 + reliable, ss->ss_oa_sent = Answer; - - if (answer && reliable && nh->nh_soa) { - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - } - - if (reliable && sr->sr_status < 200) { - sr->sr_response.msg = NULL, sr->sr_response.sip = NULL; - if (nta_reliable_mreply(sr->sr_irq, process_prack, sr, msg) == NULL) - return -1; - sr->sr_100rel = 1; - return 0; - } - - if (200 <= sr->sr_status && sr->sr_status < 300) { - session_timer_preferences(ss->ss_timer, - sip, - NH_PGET(nh, supported), - NH_PGET(nh, session_timer), - NUA_PISSET(nh->nh_nua, nh, session_timer), - NH_PGET(nh, refresher), - NH_PGET(nh, min_se)); - - if (session_timer_is_supported(ss->ss_timer)) - session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh); - } - - return nua_base_server_respond(sr, tags); -} - -/** Check if the response should be sent reliably. - * XXX - use tags to indicate when to use reliable responses ??? - */ -static -int nua_invite_server_is_100rel(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - sip_require_t *require = sr->sr_request.sip->sip_require; - sip_supported_t *supported = sr->sr_request.sip->sip_supported; - - if (sr->sr_status >= 200) - return 0; - else if (sr->sr_status == 100) - return 0; - - if (sip_has_feature(sr->sr_response.sip->sip_require, "100rel")) - return 1; - - if (require == NULL && supported == NULL) - return 0; - - if (!sip_has_feature(NH_PGET(nh, supported), "100rel")) - return 0; - if (sip_has_feature(require, "100rel")) - return 1; - if (!sip_has_feature(supported, "100rel")) - return 0; - if (sr->sr_status == 183) - return 1; - - if (NH_PGET(nh, early_media) && !NH_PGET(nh, only183_100rel)) - return 1; - - if (sip_has_feature(require, "precondition")) { - if (!NH_PGET(nh, only183_100rel)) - return 1; - if (sr->sr_offer_recv && !sr->sr_answer_sent) - return 1; - } - - return 0; -} - - -int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = sr->sr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - int initial = sr->sr_initial && !sr->sr_event; - int neutral = sr->sr_neutral; - int application = sr->sr_application; - int status = sr->sr_status; char const *phrase = sr->sr_phrase; - int retval; - - if (!sr->sr_event && status < 300) { /* Not reported yet */ - nta_incoming_bind(sr->sr_irq, process_ack_or_cancel, sr); - } - - retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */ - - if (retval >= 2 || ss == NULL) { - /* Session has been terminated. */ - if (!initial && !neutral) { -#if 0 - signal_call_state_change(nh, NULL, status, phrase, - nua_callstate_terminated); -#endif - } - return retval; - } - - /* Update session state */ - if (status < 300 || application != 0) { - 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 - : status > 100 - ? nua_callstate_early - : nua_callstate_received); - } - - if (status == 180) - ss->ss_alerting = 1; - else if (status >= 200) - ss->ss_alerting = 0; - - if (200 <= status && status < 300) { - du->du_ready = 1; - } - else if (300 <= status && !neutral) { - 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 retval; -} - -/** @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_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 - */ -static -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; - int uas; - - if (ss == NULL) - return 0; - - if (sr->sr_offer_sent && !sr->sr_answer_recv) { - char const *sdp; - size_t len; - - if (session_get_description(sip, &sdp, &len)) - recv = Answer; - - if (recv) { - assert(ss->ss_oa_recv == NULL); - ss->ss_oa_recv = recv; - } - - if (nh->nh_soa == NULL) - ; - else if (recv == NULL ) { - if (ss->ss_state >= nua_callstate_ready && - soa_get_user_version(nh->nh_soa) == ss->ss_sdp_version && - soa_process_reject(nh->nh_soa, NULL) >= 0) { - url_t const *m; - - /* The re-INVITE was a refresh and re-INVITEr ignored our offer */ - ss->ss_oa_sent = NULL; - - if (sr->sr_request.sip->sip_contact) - m = sr->sr_request.sip->sip_contact->m_url; - else - m = sr->sr_request.sip->sip_from->a_url; - - SU_DEBUG_3(("nua(%p): re-INVITEr ignored offer in our %u response " - "(Contact: <" URL_PRINT_FORMAT ">)\n", - (void *)nh, sr->sr_status, URL_PRINT_ARGS(m))); - if (sr->sr_request.sip->sip_user_agent) - SU_DEBUG_3(("nua(%p): re-INVITE: \"User-Agent: %s\"\n", (void *)nh, - sr->sr_request.sip->sip_user_agent->g_string)); - } - else - return process_ack_error(sr, msg, 488, "Offer-Answer error", - "SIP;cause=488;text=\"No answer to offer\""); - } - else if (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) >= 0) { - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - else { - 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); - - return process_ack_error(sr, msg, status, phrase, reason); - } - } - - if (nh->nh_soa) - soa_clear_remote_sdp(nh->nh_soa); - - nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, NULL); - signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready); - session_timer_set(ss, uas = 1); - - nua_server_request_destroy(sr); - - return 0; -} - -static int -process_ack_error(nua_server_request_t *sr, - msg_t *ackmsg, - int status, - char const *phrase, - char const *reason) -{ - nua_handle_t *nh = sr->sr_owner; - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - int error; - - nua_stack_event(nh->nh_nua, nh, ackmsg, - nua_i_ack, status, phrase, NULL); - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_media_error, status, phrase, NULL); - - if (reason) ss->ss_reason = reason; - ss->ss_reporting = 1; - error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); - ss->ss_reporting = 0; - - signal_call_state_change(nh, ss, - 488, "Offer-Answer Error", - /* We report terminated state if BYE failed */ - error - ? nua_callstate_terminated - : nua_callstate_terminating); - - 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(ss); assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); (void)ss; - - assert(nta_incoming_status(irq) < 200); - - nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK, NULL); - sr->sr_application = SR_STATUS1(sr, SIP_487_REQUEST_TERMINATED); - nua_server_respond(sr, NULL); - nua_server_report(sr); - - 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); - char const *phrase = "ACK Timeout"; - char const *reason = "SIP;cause=408;text=\"ACK Timeout\""; - int error; - - assert(ss); assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); - - if (nua_server_request_is_pending(sr)) { - phrase = "PRACK Timeout"; - reason = "SIP;cause=504;text=\"PRACK Timeout\""; - } - - nua_stack_event(nh->nh_nua, nh, 0, nua_i_error, 408, phrase, NULL); - - if (nua_server_request_is_pending(sr)) { - /* PRACK timeout */ - SR_STATUS1(sr, SIP_504_GATEWAY_TIME_OUT); - nua_server_trespond(sr, - SIPTAG_REASON_STR(reason), - TAG_END()); - if (nua_server_report(sr) >= 2) - return 0; /* Done */ - sr = NULL; - } - - /* send BYE, too, if 200 OK (or 183 to re-INVITE) timeouts */ - ss->ss_reason = reason; - - ss->ss_reporting = 1; /* We report terminated state here if BYE fails */ - error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); - ss->ss_reporting = 0; - - signal_call_state_change(nh, ss, 0, phrase, - error - ? nua_callstate_terminated - : nua_callstate_terminating); - - if (sr) - nua_server_request_destroy(sr); - - return 0; -} - - -/** @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 PRACK request - * @param tags empty - * - * @sa nua_prack(), #nua_r_prack, @RFC3262, NUTAG_EARLY_MEDIA() - * - * @END_NUA_EVENT - */ - -int nua_prack_server_init(nua_server_request_t *sr); -int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags); -int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags); - -nua_server_methods_t const nua_prack_server_methods = - { - SIP_METHOD_PRACK, - nua_i_prack, /* Event */ - { - 0, /* Do not create dialog */ - 1, /* In-dialog request */ - 1, /* Target refresh request */ - 1, /* Add Contact */ - }, - nua_prack_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_prack_server_respond, - nua_prack_server_report, - }; - -/** @internal Process reliable response PRACK or (timeout from 100rel) */ -static int process_prack(nua_server_request_t *sr, - nta_reliable_t *rel, - nta_incoming_t *irq, - sip_t const *sip) -{ - nua_handle_t *nh; - - nta_reliable_destroy(rel); - - if (irq == NULL) - /* Final response interrupted 100rel, we did not actually receive PRACK */ - return 200; - - sr->sr_pracked = 1; - - if (!nua_server_request_is_pending(sr)) /* There is no INVITE anymore */ - return 481; - - nh = sr->sr_owner; - - if (nh->nh_ds->ds_leg == NULL) - return 500; - - if (sip == NULL) { - /* 100rel timeout */ - SR_STATUS(sr, 504, "Reliable Response Timeout"); - nua_stack_event(nh->nh_nua, nh, NULL, nua_i_error, - sr->sr_status, sr->sr_phrase, - NULL); - nua_server_trespond(sr, - SIPTAG_REASON_STR("SIP;cause=504;" - "text=\"PRACK Timeout\""), - TAG_END()); - nua_server_report(sr); - return 504; - } - - nta_incoming_bind(irq, NULL, (void *)sr); - - return nua_stack_process_request(nh, nh->nh_ds->ds_leg, irq, sip); -} - - -int nua_prack_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL); - - if (sri == NULL) - return SR_STATUS(sr, 481, "No Such Preliminary Response"); - - if (nua_session_server_init(sr)) - return sr->sr_status; - - if (sr->sr_sdp) { - nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(sr->sr_usage); - char const *offeranswer; - - /* XXX - check for overlap? */ - - if (sri->sr_offer_sent && !sri->sr_answer_recv) - sr->sr_answer_recv = 1, sri->sr_answer_recv = 1, offeranswer = Answer; - else - sr->sr_offer_recv = 1, offeranswer = Offer; - - ss->ss_oa_recv = offeranswer; - - if (nh->nh_soa && - soa_set_remote_sdp(nh->nh_soa, NULL, sr->sr_sdp, sr->sr_sdp_len) < 0) { - SU_DEBUG_5(("nua(%p): %s server: error parsing %s\n", (void *)nh, - "PRACK", offeranswer)); - return - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase); - } - } - - return 0; -} - -int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - - if (sr->sr_status < 200 || 300 <= sr->sr_status) - return nua_base_server_respond(sr, tags); - - if (sr->sr_sdp) { - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - if (nh->nh_soa == NULL) { - if (sr->sr_offer_recv && session_get_description(sip, NULL, NULL)) - sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer; - } - else if ((sr->sr_offer_recv && soa_generate_answer(nh->nh_soa, NULL) < 0) || - (sr->sr_answer_recv && soa_process_answer(nh->nh_soa, NULL) < 0)) { - SU_DEBUG_5(("nua(%p): %s server: %s %s\n", - (void *)nh, "PRACK", - "error processing", - sr->sr_offer_recv ? Offer : Answer)); - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase); - } - else if (sr->sr_offer_recv) { - if (session_include_description(nh->nh_soa, 1, msg, sip) < 0) - sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR); - else - sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer; - } - } - - return nua_base_server_respond(sr, tags); -} - -int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL); - int status = sr->sr_status; char const *phrase = sr->sr_phrase; - int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent || sr->sr_offer_sent || sr->sr_answer_recv; - int retval; - - retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */ - - if (retval >= 2 || ss == NULL) { -#if 0 - signal_call_state_change(nh, NULL, - status, phrase, - nua_callstate_terminated); -#endif - return retval; - } - - if (offer_recv_or_answer_sent) { - /* signal offer received, answer sent */ - signal_call_state_change(nh, ss, - status, phrase, - ss->ss_state); - if (nh->nh_soa) { - soa_activate(nh->nh_soa, NULL); - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - } - - if (status < 200 || 300 <= status) - return retval; - - assert(sri); - - if (sri == NULL) { - - } - else if (SR_HAS_SAVED_SIGNAL(sri)) { - nua_signal_data_t const *e; - - e = nua_signal_data(sri->sr_signal); - - sri->sr_application = SR_STATUS(sri, e->e_status, e->e_phrase); - - nua_server_params(sri, e->e_tags); - nua_server_respond(sri, e->e_tags); - nua_server_report(sri); - } - else if (ss->ss_state < nua_callstate_ready - && !ss->ss_alerting - && !ss->ss_precondition - && NH_PGET(nh, auto_alert)) { - SR_STATUS1(sri, SIP_180_RINGING); - nua_server_respond(sri, NULL); - nua_server_report(sri); - } - - return retval; -} - -/* ---------------------------------------------------------------------- */ -/* 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" VA_NONE)); - return -1; - } - else if (!ref->ref_event) { - SU_DEBUG_3(("nua: NOTIFY event missing\n" VA_NONE)); - 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", - (void *)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; -} - -/* ======================================================================== */ -/* INFO */ - -/**@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: - * Header tags defined in . - * - * @par Events: - * #nua_r_info - * - * @sa #nua_i_info - */ - -nua_client_methods_t const nua_info_client_methods = { - SIP_METHOD_INFO, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 1, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - NULL, /* crm_init */ - NULL, /* crm_send */ - NULL, /* crm_check_restart */ - NULL, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int -nua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_info_client_methods, 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 - */ - -/** @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 - */ - -nua_server_methods_t const nua_info_server_methods = - { - SIP_METHOD_INFO, - nua_i_info, /* Event */ - { - 0, /* Do not create dialog */ - 0, /* Allow outside dialog, too */ - 0, /* Not a target refresh request */ - 0, /* Do not add Contact */ - }, - nua_base_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_base_server_report, - }; - -/* ======================================================================== */ -/* UPDATE */ - -/**@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 - */ - -static int nua_update_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_update_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_update_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_update_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - -nua_client_methods_t const nua_update_client_methods = { - SIP_METHOD_UPDATE, /* crm_method, crm_method_name */ - 0, /* crm_extrasize of private data */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - nua_update_client_init, /* crm_init */ - nua_update_client_request, /* crm_send */ - session_timer_check_restart, /* crm_check_restart */ - nua_update_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - nua_update_client_report, /* crm_report */ - NULL, /* crm_complete */ -}; - -int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_update_client_methods, tags); -} - -static int nua_update_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - - cr->cr_usage = du; - - return 0; -} - -static int nua_update_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss; - nua_server_request_t *sr; - nua_client_request_t *cri; - int offer_sent = 0, retval; - - if (du == NULL) /* Call terminated */ - return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); - - ss = NUA_DIALOG_USAGE_PRIVATE(du); - if (ss->ss_state >= nua_callstate_terminating) - return nua_client_return(cr, 900, "Session is terminating", msg); - - cri = du->du_cr; - - for (sr = nh->nh_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 == NULL) { - offer_sent = session_get_description(sip, NULL, NULL); - } - else if (sr || - (cri && cri->cr_offer_sent && !cri->cr_answer_recv) || - (cri && cri->cr_offer_recv && !cri->cr_answer_sent)) { - if (session_get_description(sip, NULL, NULL)) - return nua_client_return(cr, 500, "Overlapping Offer/Answer", msg); - } - else if (!sip->sip_payload) { - 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 - use soa_error_as_sip_reason(nh->nh_soa) */ - cr->cr_graceful = 1; - ss->ss_reason = "SIP;cause=400;text=\"Local media failure\""; - } - return nua_client_return(cr, 900, "Local media failed", msg); - } - offer_sent = 1; - } - - /* Add session timer headers */ - session_timer_preferences(ss->ss_timer, - sip, - NH_PGET(nh, supported), - NH_PGET(nh, session_timer), - NUA_PISSET(nh->nh_nua, nh, session_timer), - NH_PGET(nh, refresher), - NH_PGET(nh, min_se)); - - if (session_timer_is_supported(ss->ss_timer)) - session_timer_add_headers(ss->ss_timer, ss->ss_state < nua_callstate_ready, - msg, sip, nh); - - retval = nua_base_client_request(cr, msg, sip, NULL); - - if (retval == 0) { - enum nua_callstate state = ss->ss_state; - cr->cr_offer_sent = offer_sent; - ss->ss_update_needed = 0; - - if (state == nua_callstate_ready) - state = nua_callstate_calling; /* XXX */ - - if (offer_sent) - ss->ss_oa_sent = Offer; - - if (!cr->cr_restarting) /* Restart logic calls nua_update_client_report */ - signal_call_state_change(nh, ss, 0, "UPDATE sent", state); - } - - return retval; -} - -static int nua_update_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - int uas; - - assert(200 <= status); - - if (ss && sip && status < 300) { - if (session_timer_is_supported(ss->ss_timer)) { - nua_server_request_t *sr; - - for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) - if (sr->sr_method == sip_method_invite || - sr->sr_method == sip_method_update) - break; - - if (!sr && (!du->du_cr || !du->du_cr->cr_orq)) { - session_timer_store(ss->ss_timer, sip); - session_timer_set(ss, uas = 0); - } - } - } - - return nua_session_client_response(cr, status, phrase, sip); -} - -/** @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 nua_update_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - nua_stack_event(nh->nh_nua, nh, - nta_outgoing_getresponse(orq), - (enum nua_event_e)cr->cr_event, - status, phrase, - tags); - - if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting) - return 1; - - if (cr->cr_offer_sent) { - unsigned next_state = ss->ss_state; - - if (status < 200) - ; - else if (nua_invite_client_should_ack(du->du_cr)) { - /* There is an un-ACK-ed INVITE there */ - assert(du->du_cr->cr_method == sip_method_invite); - - if (NH_PGET(nh, auto_ack) || - /* Auto-ACK response to re-INVITE when media is enabled - and auto_ack is not set to 0 on handle */ - (ss->ss_state == nua_callstate_ready && nh->nh_soa && - !NH_PISSET(nh, auto_ack))) { - if (nua_invite_client_ack(du->du_cr, NULL) > 0) - next_state = nua_callstate_ready; - else - next_state = nua_callstate_terminating; - } - } - - signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state); - } - - return 1; -} - -/* ---------------------------------------------------------------------- */ -/* UPDATE server */ - -int nua_update_server_init(nua_server_request_t *sr); -int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags); -int nua_update_server_report(nua_server_request_t *, tagi_t const *); - -nua_server_methods_t const nua_update_server_methods = - { - SIP_METHOD_UPDATE, - nua_i_update, /* Event */ - { - 0, /* Do not create dialog */ - 1, /* In-dialog request */ - 1, /* Target refresh request */ - 1, /* Add Contact */ - }, - nua_update_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_update_server_respond, - nua_update_server_report, - }; - -int nua_update_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_session_usage_t *ss; - - sip_t const *request = sr->sr_request.sip; - - if (nua_session_server_init(sr)) - return sr->sr_status; - - ss = nua_dialog_usage_private(sr->sr_usage); - - /* Do session timer negotiation */ - if (request->sip_session_expires) - session_timer_store(ss->ss_timer, request); - - if (sr->sr_sdp) { /* Check for overlap */ - nua_client_request_t *cr; - nua_server_request_t *sr0; - 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 = nh->nh_ds->ds_cr; cr; cr = cr->cr_next) - if ((overlap = cr->cr_offer_sent && !cr->cr_answer_recv)) - break; - - if (!overlap) - for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) - if ((overlap = sr0->sr_offer_recv && !sr0->sr_answer_sent)) - break; - - if (nh->nh_soa && overlap) { - return nua_server_retry_after(sr, 500, "Overlapping Offer/Answer", 1, 9); - } - - if (nh->nh_soa && - soa_set_remote_sdp(nh->nh_soa, NULL, sr->sr_sdp, sr->sr_sdp_len) < 0) { - SU_DEBUG_5(("nua(%p): %s server: error parsing %s\n", (void *)nh, - "UPDATE", Offer)); - return - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase); - } - - sr->sr_offer_recv = 1; - ss ? ss->ss_oa_recv = Offer : Offer; - } - - return 0; -} - -/** @internal Respond to an UPDATE request. - * - */ -int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - if (200 <= sr->sr_status && sr->sr_status < 300 && sr->sr_sdp) { - if (nh->nh_soa == NULL) { - sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer; - } - else if (soa_generate_answer(nh->nh_soa, NULL) < 0) { - SU_DEBUG_5(("nua(%p): %s server: %s %s\n", - (void *)nh, "UPDATE", "error processing", Offer)); - sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase); - } - else if (soa_activate(nh->nh_soa, NULL) < 0) { - SU_DEBUG_5(("nua(%p): %s server: error activating media\n", - (void *)nh, "UPDATE")); - /* XXX */ - } - else if (session_include_description(nh->nh_soa, 1, msg, sip) < 0) { - sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - else { - sr->sr_answer_sent = 1; - if (ss) { - ss->ss_oa_sent = Answer; - ss->ss_sdp_version = soa_get_user_version(nh->nh_soa); - } - } - } - - if (ss && 200 <= sr->sr_status && sr->sr_status < 300) { - session_timer_preferences(ss->ss_timer, - sip, - NH_PGET(nh, supported), - NH_PGET(nh, session_timer), - NUA_PISSET(nh->nh_nua, nh, session_timer), - NH_PGET(nh, refresher), - NH_PGET(nh, min_se)); - - if (session_timer_is_supported(ss->ss_timer)) { - nua_server_request_t *sr0; - int uas; - - session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh); - - for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) - if (sr0->sr_method == sip_method_invite) - break; - - if (!sr0 && (!sr->sr_usage->du_cr || !sr->sr_usage->du_cr->cr_orq)) - session_timer_set(ss, uas = 1); - } - } - - return nua_base_server_respond(sr, tags); -} - -/** @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 - */ - -int nua_update_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = sr->sr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - int status = sr->sr_status; char const *phrase = sr->sr_phrase; - int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent; - int retval; - - retval = nua_base_server_report(sr, tags), sr = NULL; /* destroys sr */ - - if (retval >= 2 || ss == NULL) { -#if 0 - signal_call_state_change(nh, NULL, status, phrase, - nua_callstate_terminated); -#endif - return retval; - } - - if (offer_recv_or_answer_sent) { - /* signal offer received, answer sent */ - enum nua_callstate state = ss->ss_state; - - if (state == nua_callstate_ready && status < 200) - state = nua_callstate_received; - - signal_call_state_change(nh, ss, status, phrase, state); - } - - if (200 <= status && status < 300 - && ss->ss_state < nua_callstate_ready - && ss->ss_precondition - && !ss->ss_alerting - && NH_PGET(nh, auto_alert)) { - nua_server_request_t *sri; - - for (sri = nh->nh_ds->ds_sr; sri; sri = sri->sr_next) - if (sri->sr_method == sip_method_invite && - nua_server_request_is_pending(sri)) - break; - - if (sri) { - SR_STATUS1(sri, SIP_180_RINGING); - nua_server_respond(sri, NULL); - nua_server_report(sri); - } - } - - return retval; -} - -/* ======================================================================== */ -/* BYE */ - -/**@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 - */ - -static int nua_bye_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_bye_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); -static int nua_bye_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); -static int nua_bye_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags); - -nua_client_methods_t const nua_bye_client_methods = { - SIP_METHOD_BYE, /* crm_method, crm_method_name */ - 0, /* crm_extrasize */ - { /* crm_flags */ - /* create_dialog */ 0, - /* in_dialog */ 1, - /* target refresh */ 0 - }, - NULL, /* crm_template */ - nua_bye_client_init, /* crm_init */ - nua_bye_client_request, /* crm_send */ - NULL, /* crm_check_restart */ - nua_bye_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - nua_bye_client_report, /* crm_report */ - NULL, /* crm_complete */ -}; - -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_session_usage_for_dialog(nh->nh_ds); - - if (ss && - nua_callstate_calling <= ss->ss_state && - ss->ss_state <= nua_callstate_proceeding) - return nua_client_create(nh, e, &nua_cancel_client_methods, tags); - else - return nua_client_create(nh, e, &nua_bye_client_methods, tags); -} - -static int nua_bye_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - if (!ss || (ss->ss_state >= nua_callstate_terminating && !cr->cr_auto)) - return nua_client_return(cr, 900, "Invalid handle for BYE", msg); - - if (!cr->cr_auto) - /* Implicit state transition by nua_bye() */ - ss->ss_state = nua_callstate_terminating; - - if (nh->nh_soa) - soa_terminate(nh->nh_soa, 0); - - nua_client_bind(cr, du); - - return 0; -} - -static int nua_bye_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss; - char const *reason = NULL; - - int error; - nua_server_request_t *sr; - - if (du == NULL) - return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); - - ss = nua_dialog_usage_private(du); - reason = ss->ss_reason; - - error = nua_base_client_trequest(cr, msg, sip, - SIPTAG_REASON_STR(reason), - TAG_NEXT(tags)); - - if (error == 0) { - nua_dialog_usage_reset_refresh(du); - ss->ss_timer->timer_set = 0; - - /* Terminate server transactions associated with session, too. */ - for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) { - if (sr->sr_usage == du && nua_server_request_is_pending(sr) && - sr->sr_method != sip_method_bye) { - sr_status(sr, SIP_486_BUSY_HERE); - nua_server_respond(sr, 0); - } - } - } - - return error; -} -static int nua_bye_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) { - - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - if (ss && ss->ss_reporting && status >= 900) - return 1; - - return nua_base_client_response(cr, status, phrase, sip, NULL); -} - -/** @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 nua_bye_client_report(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip, - nta_outgoing_t *orq, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - - nua_stack_event(nh->nh_nua, nh, - nta_outgoing_getresponse(orq), - (enum nua_event_e)cr->cr_event, - status, phrase, - tags); - - if (du == NULL) { - /* No more session */ - } - else if (status < 200) { - /* Preliminary */ - } - else { - nua_session_usage_t *ss = nua_dialog_usage_private(du); - nua_client_request_t *cri; - - if (ss->ss_reporting) { - return 1; /* Somebody else's problem */ - } - else if (cr->cr_waiting) { - return 1; /* Application problem */ - } - - nua_client_bind(cr, NULL); - - signal_call_state_change(nh, ss, status, "to BYE", - nua_callstate_terminated); - - for (cri = du->du_dialog->ds_cr; cri; cri = cri->cr_next) { - if (cri->cr_method == sip_method_invite) - break; - } - - if (!cri || cri->cr_status >= 200) { - /* INVITE is completed, we can zap the session... */; - nua_session_usage_destroy(nh, ss); - } - } - - return 1; -} - -/** @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_bye_server_init(nua_server_request_t *sr); -int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags); - -nua_server_methods_t const nua_bye_server_methods = - { - SIP_METHOD_BYE, - nua_i_bye, /* Event */ - { - 0, /* Do not create dialog */ - 1, /* In-dialog request */ - 0, /* Not a target refresh request */ - 0, /* Do not add Contact */ - }, - nua_bye_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_bye_server_report, - }; - - -int nua_bye_server_init(nua_server_request_t *sr) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); - - sr->sr_terminating = 1; - - if (du) - sr->sr_usage = du; - else - return SR_STATUS(sr, 481, "No Such Call"); - - return 0; -} - -int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = sr->sr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - int early = 0, retval; - - if (sr->sr_status < 200) - return nua_base_server_report(sr, tags); - - if (ss) { - nua_server_request_t *sr0 = NULL, *sr_next; - char const *phrase; - - early = ss->ss_state < nua_callstate_ready; - phrase = early ? "Early Session Terminated" : "Session Terminated"; - -#if 0 - sr->sr_usage = NULL; -#endif - - for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr_next) { - sr_next = sr0->sr_next; - - if (sr == sr0 || sr0->sr_usage != sr->sr_usage) - continue; - - if (nua_server_request_is_pending(sr0)) { - SR_STATUS(sr0, 487, phrase); - nua_server_respond(sr0, NULL); - } - nua_server_request_destroy(sr0); - } - - sr->sr_phrase = phrase; - } - - retval = nua_base_server_report(sr, tags); - - //assert(2 <= retval && retval < 4); - -#if 0 - if (ss) { - signal_call_state_change(nh, ss, 200, - early ? "Received early BYE" : "Received BYE", - nua_callstate_terminated); - nua_dialog_usage_remove(nh, nh->nh_ds, du); - } -#endif - - return retval; -} - -/* ---------------------------------------------------------------------- */ - -/** @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. The tags NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV() indicate - * whether the remote SDP that was received was considered as an offer or an - * answer. Tags NUTAG_OFFER_SENT() or NUTAG_ANSWER_SENT() indicate whether - * the local SDP which was sent was considered as an offer or answer. - * - * If the @b soa SDP negotiation is enabled (by default or with - * NUTAG_MEDIA_ENABLE(1)), the received remote SDP is included in tags - * SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR(). The SDP negotiation - * result from @b soa is included in the tags SOATAG_LOCAL_SDP() and - * SOATAG_LOCAL_SDP_STR(). - * - * 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 the information relayed in call - * establisment (#nua_i_active) and termination (#nua_i_terminated) events. - * - * @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_MEDIA_ENABLE(), - * 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 - * - * @par History - * Prior @VERSION_1_12_6 the tags NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(), - * NUTAG_ANSWER_SENT(), NUTAG_OFFER_SENT() were not included with - * nua_i_state eventif media was disabled. - * - * @END_NUA_EVENT - */ - -/** - * 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) -{ - enum nua_callstate ss_state = nua_callstate_init; - enum nua_callstate invite_state = next_state; - - char const *oa_recv = NULL; - char const *oa_sent = NULL; - - int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0; - - if (ss) { - if (ss->ss_reporting) - return; - - ss_state = ss->ss_state; - oa_recv = ss->ss_oa_recv, ss->ss_oa_recv = NULL; - oa_sent = ss->ss_oa_sent, ss->ss_oa_sent = NULL; - - assert(oa_sent == Offer || oa_sent == Answer || oa_sent == NULL); - assert(oa_recv == Offer || oa_recv == Answer || oa_recv == NULL); - - if (oa_recv) { - offer_recv = oa_recv == Offer; - answer_recv = oa_recv == Answer; - } - - if (oa_sent) { - offer_sent = oa_sent == Offer; - answer_sent = oa_sent == Answer; - } - } - - 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", - (void *)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", - (void *)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 (next_state == nua_callstate_terminating && - ss_state >= nua_callstate_terminating) - return; - - if (ss) { - /* Update state variables */ - if (next_state == nua_callstate_init) { - if (ss_state < nua_callstate_ready) - ss->ss_state = next_state; - else if (ss->ss_state == nua_callstate_ready) - next_state = ss->ss_state; - else if (ss->ss_state == nua_callstate_terminating) - return; - else - ss->ss_state = next_state = nua_callstate_terminated; - } - else if (next_state > ss_state) - ss->ss_state = next_state; - } - - if (next_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"; - - { - 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; - - if (nh->nh_soa) { - if (oa_recv) - soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0); - if (oa_sent) - soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0); - - if (answer_recv || answer_sent) { /* Update nh_hold_remote */ - char const *held = NULL; - soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held), TAG_END()); - nh->nh_hold_remote = held && strlen(held) > 0; - } - } - else - oa_recv = NULL, oa_sent = NULL; - - nua_stack_tevent(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()); - } - - if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) { - nua_stack_tevent(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()); - } - - else if (next_state == nua_callstate_terminated) { - nua_stack_event(nh->nh_nua, nh, NULL, - nua_i_terminated, status, phrase, - NULL); - } - - if (invite_state == nua_callstate_ready) { - /* Start next INVITE request, if queued */ - nua_client_next_request(nh->nh_ds->ds_cr, 1); - } -} - -/** @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 - */ - -/** @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 - */ - - -/* ======================================================================== */ - -static -int nua_server_retry_after(nua_server_request_t *sr, - 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; - - sip_add_dup(sr->sr_response.msg, sr->sr_response.sip, (sip_header_t *)af); - - return sr_status(sr, status, phrase); -} - -/* ======================================================================== */ -/* Session timer - RFC 4028 */ - -static int session_timer_is_supported(struct session_timer const *t) -{ - return t->local.supported; -} - -/** Set session timer preferences */ -static -void session_timer_preferences(struct session_timer *t, - sip_t const *sip, - sip_supported_t const *supported, - unsigned expires, - int isset, - enum nua_session_refresher refresher, - unsigned min_se) -{ - memset(&t->local, 0, sizeof t->local); - - t->local.require = sip_has_feature(sip->sip_require, "timer"); - t->local.supported = - sip_has_feature(supported, "timer") || - sip_has_feature(sip->sip_supported, "timer"); - if (isset || refresher != nua_no_refresher) - t->local.expires = expires; - else - t->local.defaults = expires; - t->local.min_se = min_se; - t->local.refresher = refresher; -} - -static int session_timer_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - if (status == 422) { - nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); - - if (ss && session_timer_is_supported(ss->ss_timer)) { - struct session_timer *t = ss->ss_timer; - - if (sip->sip_min_se && t->local.min_se < sip->sip_min_se->min_delta) - t->local.min_se = sip->sip_min_se->min_delta; - if (t->local.expires != 0 && t->local.min_se > t->local.expires) - t->local.expires = t->local.min_se; - - return nua_client_restart(cr, 100, "Re-Negotiating Session Timer"); - } - } - - return nua_base_client_check_restart(cr, status, phrase, sip); -} - -/** Check that received Session-Expires is longer than Min-SE */ -static -int session_timer_check_min_se(msg_t *msg, - sip_t *sip, - sip_t const *request, - unsigned long min) -{ - if (min == 0) - min = 1; - - /* - If an incoming request contains a Supported header field with a value - 'timer' and a Session Expires header field, the UAS MAY reject the - INVITE request with a 422 (Session Interval Too Small) response if - the session interval in the Session-Expires header field is smaller - than the minimum interval defined by the UAS' local policy. When - sending the 422 response, the UAS MUST include a Min-SE header field - with the value of its minimum interval. This minimum interval MUST - NOT be lower than 90 seconds. - */ - if (request->sip_session_expires && - sip_has_feature(request->sip_supported, "timer") && - request->sip_session_expires->x_delta < min) { - sip_min_se_t min_se[1]; - - if (min < 90) - min = 90; - - sip_min_se_init(min_se)->min_delta = min; - - /* Include extension parameters, if any */ - if (request->sip_min_se) - min_se->min_params = request->sip_min_se->min_params; - - sip_add_dup(msg, sip, (sip_header_t *)min_se); - - return 422; - } - - return 0; -} - -/** Store session timer parameters in request from uac / response from uas */ -static -void session_timer_store(struct session_timer *t, - sip_t const *sip) -{ - sip_require_t const *require = sip->sip_require; - sip_supported_t const *supported = sip->sip_supported; - sip_session_expires_t const *x = sip->sip_session_expires; - - t->remote.require = require && sip_has_feature(require, "timer"); - t->remote.supported = - t->remote.supported || (supported && sip_has_feature(supported, "timer")); - - t->remote.expires = 0; - t->remote.refresher = nua_any_refresher; - t->remote.min_se = 0; - - if (x) { - t->remote.expires = x->x_delta; - - if (x->x_refresher) { - int uas = sip->sip_request != NULL; - - if (su_casenmatch(x->x_refresher, "uac", (sizeof "uac"))) - t->remote.refresher = uas ? nua_remote_refresher : nua_local_refresher; - else if (su_casenmatch(x->x_refresher, "uas", (sizeof "uas"))) - t->remote.refresher = uas ? nua_local_refresher : nua_remote_refresher; - } - else if (t->remote.require) { - /* Require: timer but no refresher parameter in Session-Expires header */ - t->remote.refresher = nua_local_refresher; - } - } - - if (sip->sip_min_se) - t->remote.min_se = sip->sip_min_se->min_delta; -} - -/** Add timer feature and Session-Expires/Min-SE headers to request/response - * - */ -static int -session_timer_add_headers(struct session_timer *t, - int initial, - msg_t *msg, - sip_t *sip, - nua_handle_t *nh) -{ - unsigned long expires, min; - sip_min_se_t min_se[1]; - sip_session_expires_t x[1]; - int uas; - int autorequire = 1; - - enum nua_session_refresher refresher = nua_any_refresher; - - static sip_param_t const x_params_uac[] = {"refresher=uac", NULL}; - static sip_param_t const x_params_uas[] = {"refresher=uas", NULL}; - - if ( !NH_PGET(nh, timer_autorequire) && NH_PISSET(nh, timer_autorequire)) { - autorequire = 0; - } - - if (!t->local.supported) - return 0; - - uas = sip->sip_status != NULL; - - min = t->local.min_se; - if (min < t->remote.min_se) - min = t->remote.min_se; - - if (uas) { - session_timer_negotiate(t, uas = 1); - - refresher = t->refresher; - expires = t->interval; - } - else { - /* RFC 4028: - * The UAC MAY include the refresher parameter with value 'uac' if it - * wants to perform the refreshes. However, it is RECOMMENDED that the - * parameter be omitted so that it can be selected by the negotiation - * mechanisms described below. - */ - if (t->local.refresher == nua_local_refresher) - refresher = nua_local_refresher; - else if (!initial) - refresher = t->refresher; - - expires = t->local.expires; - if (expires != 0 && expires < min) - expires = min; - - if (expires == 0 && !initial && t->interval) - expires = t->interval; - } - - sip_min_se_init(min_se)->min_delta = min; - - sip_session_expires_init(x)->x_delta = expires; - if (refresher == nua_remote_refresher) - x->x_params = uas ? x_params_uac : x_params_uas; - else if (refresher == nua_local_refresher) - x->x_params = uas ? x_params_uas : x_params_uac; - - if (expires == 0 && t->remote.min_se == 0) - /* Session timer is not used, do not add headers */ - return 1; - - sip_add_tl(msg, sip, - TAG_IF(expires != 0, SIPTAG_SESSION_EXPIRES(x)), - TAG_IF((!uas || sip->sip_status->st_status == 422) && (min != 0 - /* Min-SE: 0 is optional with initial INVITE */ - || !initial), - SIPTAG_MIN_SE(min_se)), - TAG_IF(autorequire && refresher == nua_remote_refresher && expires != 0, SIPTAG_REQUIRE_STR("timer")), - TAG_END()); - - return 1; -} - -static void -session_timer_negotiate(struct session_timer *t, int uas) -{ - if (!t->local.supported) - t->refresher = nua_no_refresher; - else if (!t->remote.supported) - t->refresher = nua_local_refresher; - else if (t->remote.refresher == nua_local_refresher) - t->refresher = nua_local_refresher; - else if (t->remote.refresher == nua_remote_refresher) - t->refresher = nua_remote_refresher; - else if (uas) - /* UAS defaults UAC to refreshing */ - t->refresher = nua_remote_refresher; - else - /* UAC refreshes by itself */ - t->refresher = nua_local_refresher; - - t->interval = t->remote.expires; - if (t->interval == 0) - t->interval = t->local.expires; - if (t->local.expires != 0 && t->interval > t->local.expires) - t->interval = t->local.expires; - if (t->local.defaults != 0 && t->interval > t->local.defaults) - t->interval = t->local.defaults; - - if (t->interval != 0) { - if (t->interval < t->local.min_se) - t->interval = t->local.min_se; - if (t->interval < t->remote.min_se) - t->interval = t->remote.min_se; - } - - if (t->interval == 0) - t->refresher = nua_no_refresher; -} - -static void -session_timer_set(nua_session_usage_t *ss, int uas) -{ - nua_dialog_usage_t *du = nua_dialog_usage_public(ss); - struct session_timer *t; - - if (ss == NULL) - return; - - t = ss->ss_timer; - - session_timer_negotiate(t, uas); - - if (t->refresher == nua_local_refresher) { - unsigned low = t->interval / 2, high = t->interval / 2; - - if (t->interval >= 90) - low -=5, high += 5; - - nua_dialog_usage_set_refresh_range(du, low, high); - t->timer_set = 1; - } - else if (t->refresher == nua_remote_refresher) { - /* RFC 4028 10.3 and 10.4: Send BYE before the session expires. - Increased interval from 2/3 to 9/10 of session expiration delay - because some endpoints won't UPDATE early enough with very short - sessions (e.g. 120). */ - - unsigned interval = t->interval; - - interval -= 32 > interval / 10 ? interval / 10 : 32; - - nua_dialog_usage_set_refresh_range(du, interval, interval); - t->timer_set = 1; - } - else { - nua_dialog_usage_reset_refresh(du); - t->timer_set = 0; - } -} - -/* ======================================================================== */ - -/** Get SDP from a SIP message. - * - * @retval 1 if message contains SDP - * @retval 0 if message does not contain valid SDP - */ -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 (!su_casematch(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 || !su_casenmatch(pl->pl_data, "v=0", 3)) - return 0; - } - - if (return_sdp && return_len) { - *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_ct) - return -1; - - if (session && !*return_cd) - return -1; - } - - return retval; -} - -/* ====================================================================== */ - -/** @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_options_server_respond(nua_server_request_t *sr, tagi_t const *tags); - -nua_server_methods_t const nua_options_server_methods = - { - SIP_METHOD_OPTIONS, - nua_i_options, /* Event */ - { - 0, /* Do not create dialog */ - 0, /* Initial request */ - 0, /* Not a target refresh request */ - 1, /* Add Contact */ - }, - nua_base_server_init, - nua_base_server_preprocess, - nua_base_server_params, - nua_options_server_respond, - nua_base_server_report, - }; - -/** @internal Respond to an OPTIONS request. - * - */ -int nua_options_server_respond(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_t *nua = nh->nh_nua; - - if (200 <= sr->sr_status && sr->sr_status < 300) { - msg_t *msg = sr->sr_response.msg; - sip_t *sip = sr->sr_response.sip; - - sip_add_tl(msg, sip, SIPTAG_ACCEPT(nua->nua_invite_accept), TAG_END()); - - 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); - } - } - - return nua_base_server_respond(sr, tags); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c deleted file mode 100644 index 4c8a8379ce..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * @author Martti Mela - * @author Remeres Jacobs - * @author Tat Chan - * - * @date Created: Wed Feb 14 18:32:58 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#define SU_ROOT_MAGIC_T struct nua_s -#define SU_MSG_ARG_T struct nua_ee_data - -#define NUA_SAVED_EVENT_T su_msg_t * -#define NUA_SAVED_SIGNAL_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_client_request - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "sofia-sip/nua.h" -#include "sofia-sip/nua_tag.h" -#include "nua_stack.h" - -#include -#include -#include -#include -#include - -#include - -/* ======================================================================== - * - * Protocol stack side - * - * ======================================================================== */ - -/* ---------------------------------------------------------------------- */ -/* Internal types */ - -/** @internal Linked stack frames from nua event callback */ -struct nua_event_frame_s { - nua_event_frame_t *nf_next; - nua_saved_event_t nf_saved[1]; -}; - - -static void nua_event_deinit(nua_ee_data_t *ee); -static void nua_application_event(nua_t *, su_msg_r, nua_ee_data_t *ee); -static void nua_stack_signal(nua_t *nua, su_msg_r, nua_ee_data_t *ee); - -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 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_valid_handle_cookie; - 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" VA_NONE)); - return -1; - } - - if (nua_stack_set_from(nua, 1, nua->nua_args) < 0) - return -1; - - if (nua->nua_prefs->ngp_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, ...); - -int nua_stack_tevent(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, ...) -{ - ta_list ta; - int retval; - ta_start(ta, tag, value); - retval = nua_stack_event(nua, nh, msg, event, status, phrase, ta_args(ta)); - ta_end(ta); - return retval; -} - -/** @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, - tagi_t const *tags) -{ - su_msg_r sumsg = SU_MSG_R_INIT; - size_t e_len, len, xtra, p_len; - - if (event == nua_r_ack || event == nua_i_none) - return event; - - if (nh == nua->nua_dhandle) - nh = NULL; - - 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): event %s %s\n", (void *)nh, name, p)); - else - SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)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 && - !nua->nua_prefs->ngp_shutdown_events)) { - if (msg) - msg_destroy(msg); - return event; - } - - if (tags) { - e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags); - len = tl_len(tags); - xtra = tl_xtra(tags, len); - } - else { - e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0; - } - p_len = phrase ? strlen(phrase) + 1 : 1; - - if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) { - nua_ee_data_t *ee = su_msg_data(sumsg); - nua_event_data_t *e = ee->ee_data; - void *p; - - if (tags) { - 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, tags, &b); p = b; - assert(t == t_end); assert(b == end); (void)end; - } - else - p = ee + 1; - - ee->ee_nua = nua_stack_ref(nua); - e->e_event = event; - e->e_nh = nh ? nua_handle_ref(nh) : NULL; - e->e_status = status; - e->e_phrase = strcpy(p, phrase ? phrase : ""); - if (msg) - e->e_msg = msg, su_home_threadsafe(msg_home(msg)); - - su_msg_deinitializer(sumsg, nua_event_deinit); - - su_msg_send_to(sumsg, nua->nua_client, nua_application_event); - } - - return event; -} - -static -void nua_event_deinit(nua_ee_data_t *ee) -{ - nua_t *nua = ee->ee_nua; - nua_event_data_t *e = ee->ee_data; - nua_handle_t *nh = e->e_nh; - - if (e->e_msg) - msg_destroy(e->e_msg), e->e_msg = NULL; - - if (nh) - nua_handle_unref(nh), e->e_nh = NULL; - - if (nua) - nua_stack_unref(nua), ee->ee_nua = NULL; -} - -/*# Receive event from protocol machine and hand it over to application */ -static -void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee) -{ - nua_t *nua = ee->ee_nua; - nua_event_data_t *e = ee->ee_data; - nua_handle_t *nh = e->e_nh; - - enter; - - ee->ee_nua = NULL; - e->e_nh = NULL; - - if (nh == NULL) { - /* Xyzzy */ - } - else if (nh->nh_valid) { - if (!nh->nh_ref_by_user) { - /* Application must now call nua_handle_destroy() */ - nh->nh_ref_by_user = 1; - nua_handle_ref(nh); - } - } - else if (!nh->nh_valid) { /* Handle has been destroyed */ - if (nua_log->log_level >= 7) { - char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4; - SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name)); - } - nua_handle_unref(nh); - nua_stack_unref(nua); - return; - } - - if (e->e_event == nua_r_shutdown && e->e_status >= 200) - nua->nua_shutdown_final = 1; - - if (nua->nua_callback) { - nua_event_frame_t frame[1]; - - su_msg_save(frame->nf_saved, sumsg); - frame->nf_next = nua->nua_current, nua->nua_current = frame; - - nua->nua_callback((enum nua_event_e)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 (su_msg_is_non_null(frame->nf_saved)) { - su_msg_destroy(frame->nf_saved); - } - nua->nua_current = frame->nf_next; - } - - nua_handle_unref(nh); - nua_stack_unref(nua); -} - -/** Get current request message. @NEW_1_12_4. - * - * @note A response message is returned when processing response message. - * - * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT() - */ -msg_t *nua_current_request(nua_t const *nua) -{ - if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) - return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg; - return NULL; -} - - -su_msg_t *nua_current_msg(nua_t const *nua, int clear) -{ - if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) { - su_msg_t *r = nua->nua_current->nf_saved[0]; - if (clear) { - nua->nua_current->nf_saved[0] = NULL; - } - return r; - //return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg; - - } - - return NULL; -} - - -/** Get request message from saved nua event. @NEW_1_12_4. - * - * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(), - */ -msg_t *nua_saved_event_request(nua_saved_event_t const *saved) -{ - return saved && saved[0] ? su_msg_data(saved)->ee_data->e_msg : NULL; -} - -/** Save nua event and its arguments. - * - * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event() - */ -int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1]) -{ - if (return_saved) { - if (nua && nua->nua_current) { - su_msg_save(return_saved, nua->nua_current->nf_saved); - return su_msg_is_non_null(return_saved); - } - else - *return_saved = NULL; - } - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -/** @internal - * 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, event, 0, NULL, ta_tags(ta)); - ta_end(ta); -} - - -/*# Send a request to the protocol thread */ -int nua_signal(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; - size_t len, xtra, ee_len, l_len = 0, l_xtra = 0; - ta_list ta; - int retval = -1; - - if (nua == NULL) - return -1; - - if (nua->nua_shutdown_started && event != nua_r_shutdown) - return -1; - - ta_start(ta, tag, value); - - ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags); - len = tl_len(ta_args(ta)); - xtra = tl_xtra(ta_args(ta), len); - - if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) { - nua_ee_data_t *ee = su_msg_data(sumsg); - nua_event_data_t *e = ee->ee_data; - 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 = event == nua_r_destroy || event == nua_r_shutdown; - e->e_event = event; - e->e_nh = nh ? nua_handle_ref(nh) : NULL; - e->e_status = status; - e->e_phrase = phrase; - - su_msg_deinitializer(sumsg, nua_event_deinit); - - retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal); - - if (retval == 0){ - SU_DEBUG_7(("nua(%p): %s signal %s\n", (void *)nh, - "sent", nua_event_name(event) + 4)); - } - else { - SU_DEBUG_0(("nua(%p): %s signal %s\n", (void *)nh, - "FAILED TO SEND", nua_event_name(event) + 4)); - - } - } - - ta_end(ta); - - return retval; -} - -/* ---------------------------------------------------------------------- - * Receiving events from client - */ -static -void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee) -{ - nua_event_data_t *e = ee->ee_data; - nua_handle_t *nh = e->e_nh; - tagi_t *tags = e->e_tags; - nua_event_t event; - int error = 0; - - 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((enum nua_event_e)e->e_event); - - if (e->e_status == 0) - SU_DEBUG_5(("nua(%p): %s signal %s\n", (void *)nh, "recv", name + 4)); - else - SU_DEBUG_5(("nua(%p): recv signal %s %u %s\n", - (void *)nh, name + 4, - e->e_status, e->e_phrase ? e->e_phrase : "")); - } - - su_msg_save(nua->nua_signal, msg); - - event = (enum nua_event_e)e->e_event; - - if (nua->nua_shutdown && !e->e_always) { - /* Shutting down */ - nua_stack_event(nua, nh, NULL, event, - 901, "Stack is going down", - NULL); - } - else switch (event) { - case nua_r_get_params: - nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags); - break; - case nua_r_set_params: - nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, 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, event, tags); - break; - case nua_r_invite: - error = nua_stack_invite(nua, nh, event, tags); - break; - case nua_r_cancel: - error = nua_stack_cancel(nua, nh, event, tags); - break; - case nua_r_bye: - error = nua_stack_bye(nua, nh, event, tags); - break; - case nua_r_options: - error = nua_stack_options(nua, nh, event, tags); - break; - case nua_r_refer: - error = nua_stack_refer(nua, nh, event, tags); - break; - case nua_r_publish: - case nua_r_unpublish: - error = nua_stack_publish(nua, nh, event, tags); - break; - case nua_r_info: - error = nua_stack_info(nua, nh, event, tags); - break; - case nua_r_prack: - error = nua_stack_prack(nua, nh, event, tags); - break; - case nua_r_update: - error = nua_stack_update(nua, nh, event, tags); - break; - case nua_r_message: - error = nua_stack_message(nua, nh, event, tags); - break; - case nua_r_subscribe: - case nua_r_unsubscribe: - error = nua_stack_subscribe(nua, nh, event, tags); - break; - case nua_r_notify: - error = nua_stack_notify(nua, nh, event, tags); - break; - case nua_r_notifier: - nua_stack_notifier(nua, nh, event, tags); - break; - case nua_r_terminate: - nua_stack_terminate(nua, nh, event, tags); - break; - case nua_r_method: - error = nua_stack_method(nua, nh, event, tags); - break; - case nua_r_authenticate: - nua_stack_authenticate(nua, nh, event, tags); - break; - case nua_r_authorize: - nua_stack_authorize(nua, nh, event, tags); - break; - case nua_r_ack: - error = nua_stack_ack(nua, nh, event, tags); - break; - case nua_r_respond: - nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags); - break; - case nua_r_destroy: - if (nh && !nh->nh_destroyed) { - nua_stack_destroy_handle(nua, nh, tags); - su_msg_destroy(nua->nua_signal); - } - return; - default: - break; - } - - if (error < 0) { - if (nh) { - nua_stack_event(nh->nh_nua, nh, NULL, event, - NUA_ERROR_AT(__FILE__, __LINE__), NULL); - } - } - - su_msg_destroy(nua->nua_signal); -} - -/* ====================================================================== */ -/* Signal and event handling */ - -/** Get event data. - * - * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event(). - */ -nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1]) -{ - return saved && saved[0] ? su_msg_data(saved)->ee_data : NULL; -} - -/** Destroy saved event. - * - * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request(). - */ -void nua_destroy_event(nua_saved_event_t saved[1]) -{ - if (saved && saved[0]) su_msg_destroy(saved); -} - -/** @internal Move signal. */ -void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]) -{ - su_msg_save(a, b); -} - -void nua_destroy_signal(nua_saved_signal_t saved[1]) -{ - if (saved) su_msg_destroy(saved); -} - -nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]) -{ - return nua_event_data(saved); -} - -/* ====================================================================== */ - -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; - - nh_next = nh->nh_next; - - busy += nua_dialog_repeat_shutdown(nh, ds); - - 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->ds_usage) { - nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage, NULL, NULL); - } - } - 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, NULL); -} - -/* ---------------------------------------------------------------------- */ - -/** @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 a 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) -{ - if (nh->nh_destroyed) { - return; - } - - if (nh->nh_notifier) - nua_stack_terminate(nua, nh, (enum nua_event_e)0, NULL); - - nua_dialog_shutdown(nh, nh->nh_ds); - - if (nh->nh_ref_by_user) { - nh->nh_ref_by_user = 0; - nua_handle_unref(nh); - } - - 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); - - if (nh->nh_destroyed) { - return; - } - - nh->nh_destroyed = 1; - - if (nh->nh_notifier) - nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL; - - while (nh->nh_ds->ds_cr) - nua_client_request_complete(nh->nh_ds->ds_cr); - - while (nh->nh_ds->ds_sr) - nua_server_request_destroy(nh->nh_ds->ds_sr); - - 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 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 (nh && nua_stack_init_handle(nua, nh, NULL) < 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->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; -} - -nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id) -{ - if (nua) { - nta_leg_t *leg = nta_leg_by_call_id(nua->nua_nta, call_id); - if (leg) - return nta_leg_magic(leg, nua_stack_process_request); - } - return NULL; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h deleted file mode 100644 index ba2d69a53d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h +++ /dev/null @@ -1,452 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NUA_STACK_H -/**@IFILE nua_stack.h - * @brief Sofia-SIP User Agent Engine - internal stack interface - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Wed Feb 14 17:09:44 2001 ppessi - */ - -#ifndef SU_CONFIG_H -#include -#endif - -#ifndef SU_OS_NW_H -#include -#endif -#ifndef SOA_H -#include "sofia-sip/soa.h" -#endif -#ifndef NTA_H -#include -#endif -#ifndef AUTH_CLIENT_H -#include -#endif -#ifndef NEA_H -#include -#endif -#ifndef NUA_H -#include -#endif - -#define SU_LOG (nua_log) -#include - -#ifndef NUA_DIALOG_H -#define NUA_OWNER_T struct nua_handle_s -#include "nua_dialog.h" -#endif - -SOFIA_BEGIN_DECLS - -#if HAVE_SIGCOMP -#include -#endif - -#ifndef NUA_PARAMS_H -#include "nua_params.h" -#endif - -typedef struct event_s event_t, nua_signal_data_t; - -/** Extended event data. */ -typedef struct nua_ee_data { - nua_t *ee_nua; - nua_event_data_t ee_data[1]; -} nua_ee_data_t; - -#ifndef _MSC_VER -#define NONE ((void *)-1) -#else -#define NONE ((void *)(INT_PTR)-1) -#endif - -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))) - -/** @internal @brief 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; /**< Cookie */ -#define nua_valid_handle_cookie ((void *)(intptr_t)nua_handle) - 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 */ -#define nh_dprefs nh_nua->nua_dhandle->nh_prefs - - /* 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 nh_destroyed:1; /**< nh_destroy already called */ - 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 == nua_valid_handle_cookie) - -#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) - -su_inline -int nh_is_special(nua_handle_t *nh) -{ - return nh == NULL || nh->nh_special; -} - -typedef struct nua_event_frame_s nua_event_frame_t; - -extern char const nua_internal_error[]; - -#define NUA_INTERNAL_ERROR 900, nua_internal_error -#define _NUA_INTERNAL_ERROR_AT(file, line) "Internal error at " file ":" #line -#define NUA_ERROR_AT(file, line) 900, _NUA_INTERNAL_ERROR_AT(file, line) - -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; - - nua_callback_f nua_callback; - nua_magic_t *nua_magic; - - nua_event_frame_t *nua_current; - nua_saved_event_t nua_signal[1]; - - /**< Used by stop-and-wait args calls */ - tagi_t const *nua_args; - - /* Engine state flags */ - sip_time_t nua_shutdown; - - unsigned nua_shutdown_started:1; /**< Shutdown initiated */ - unsigned nua_shutdown_final:1; /**< Shutdown is complete */ - - unsigned nua_from_is_set; - unsigned :0; - - /**< Local SIP address. Contents are kept around for ever. */ - sip_from_t nua_from[1]; - - /* ---------------------------------------------------------------------- */ - - /* Protocol (server) side */ - su_network_changed_t *nua_nw_changed; - - 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; - - /* User-agent parameters */ - nua_global_preferences_t nua_prefs[1]; - - 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 - -#if HAVE_MEMLEAK_LOG - -#define nua_handle_ref(nh) \ - _nua_handle_ref_by((nh), __FILE__, __LINE__, __func__) -#define nua_handle_unref(nh) \ - _nua_handle_unref_by((nh), __FILE__, __LINE__, __func__) - -nua_handle_t *_nua_handle_ref_by( - nua_handle_t *nh, char const *file, unsigned line, char const *by); -int _nua_handle_unref_by( - nua_handle_t *nh, char const *file, unsigned line, char const *by); - -#endif - -su_inline nua_t *nua_stack_ref(nua_t *nua) -{ - return (nua_t *)su_home_ref(nua->nua_home); -} - -su_inline void nua_stack_unref(nua_t *nua) -{ - su_home_unref(nua->nua_home); -} - -/* Internal prototypes */ -int nua_stack_init(su_root_t *root, nua_t *nua); -void nua_stack_deinit(su_root_t *root, nua_t *nua); - -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 *); - -void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]); -nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]); -void nua_destroy_signal(nua_saved_signal_t saved[1]); - -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_prack, - 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, NULL) - -#define UA_EVENT2(e, status, phrase) \ - nua_stack_event(nua, nh, NULL, e, status, phrase, NULL) - -#define UA_EVENT3(e, status, phrase, tag) \ - nua_stack_event(nua, nh, NULL, e, status, phrase, tag, NULL) - -int nua_stack_tevent(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, ...); - -int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg, - nua_event_t event, int status, char const *phrase, - tagi_t const *tags); - -su_msg_t *nua_current_msg(nua_t const *nua, int clear); - -void nua_move_event(nua_saved_event_t a[1], nua_saved_event_t b[1]); - -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); - -int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags); - -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); - -nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id); - - -/* ---------------------------------------------------------------------- */ - -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_launch_network_change_detector(nua_t *nua); - -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); - -/* ---------------------------------------------------------------------- */ - -#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 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 num, str. - * @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 */ - -int nua_signal(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, ...); - -SOFIA_END_DECLS - -#endif /* NUA_STACK_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c deleted file mode 100644 index e41d0bb09d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c +++ /dev/null @@ -1,929 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Mar 8 15:10:08 EET 2006 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "nua_stack.h" - -/* ---------------------------------------------------------------------- */ -/* Subcriber event usage */ - -struct event_usage -{ - enum nua_substate eu_substate; /**< Subscription state */ - unsigned eu_delta; /**< Proposed expiration */ - sip_time_t eu_expires; /**< Absolute expiration time */ - unsigned eu_notified; /**< Number of NOTIFYs received */ - unsigned eu_unsolicited:1; /**< Not SUBSCRIBEd or REFERed */ - unsigned eu_refer:1; /**< Implied subscription by refer */ - 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, - nua_client_request_t *cr, - nua_server_request_t *sr); -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, - nua_base_usage_update_params, - 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, - nua_client_request_t *cr, - nua_server_request_t *sr) -{ - ds->ds_has_events--; - ds->ds_has_subscribes--; -} - -/* ====================================================================== */ -/* SUBSCRIBE */ - -/**@fn void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); - * - * 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() - * Header tags defined in - * - * @par Events: - * #nua_r_subscribe \n - * #nua_i_notify - * - * @sa NUTAG_SUBSTATE(), @RFC3265 - */ - -/**@fn void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); - * - * 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 - * Header tags defined in except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR() - * - * @par Events: - * #nua_r_unsubscribe - * - * @sa NUTAG_SUBSTATE(), @RFC3265 - */ - -static int nua_subscribe_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_subscribe_client_request(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_subscribe_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); - -static nua_client_methods_t const nua_subscribe_client_methods = { - SIP_METHOD_SUBSCRIBE, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - nua_subscribe_client_init, /* crm_init */ - nua_subscribe_client_request, /* crm_send */ - NULL, /* crm_check_restart */ - nua_subscribe_client_response, /* crm_recv */ - NULL, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int -nua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_subscribe_client_methods, tags); -} - -static int nua_subscribe_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du; - 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); - - if (du) { - if (du->du_event && o == NULL) - /* Add Event header */ - sip_add_dup(msg, sip, (sip_header_t *)du->du_event); - } - else if (cr->cr_event == nua_r_subscribe) { - /* Create dialog usage */ - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o); - /* Note that we allow SUBSCRIBE without event */ - } - - cr->cr_usage = du; - - return 0; -} - -static int nua_subscribe_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_dialog_usage_t *du = cr->cr_usage; - sip_time_t expires = 0; - - if (cr->cr_event == nua_r_destroy || !du || du->du_shutdown) - nua_client_set_terminating(cr, 1); - - if (du) { - struct event_usage *eu = nua_dialog_usage_private(du); - sip_event_t *o = sip->sip_event; - - if (nua_client_bind(cr, du) < 0) - return -1; - - if (eu->eu_no_id && o && o->o_id) { - /* Notifier does not handle id properly, remove it */ - msg_header_remove_param(o->o_common, "id"); - } - -#if 0 - if (cr->cr_terminating) { - /* Already terminated subscription? */ - if (eu->eu_substate == nua_substate_terminated || - eu->eu_substate == nua_substate_embryonic) { - return nua_client_return(cr, SIP_200_OK, msg); - } - } -#endif - - nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */ - - if (cr->cr_terminating || cr->cr_event != nua_r_subscribe) - expires = eu->eu_delta = 0; - else if (sip->sip_expires) - /* Use value specified by application or negotiated with Min-Expires */ - expires = eu->eu_delta = 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. */ - expires = eu->eu_delta = 3600; - - eu->eu_final_wait = 0; - - if (eu->eu_substate == nua_substate_terminated) - eu->eu_substate = nua_substate_embryonic; - } - - if (!sip->sip_expires || sip->sip_expires->ex_delta != expires) { - sip_expires_t ex[1]; - sip_expires_init(ex)->ex_delta = expires; - sip_add_dup(msg, sip, (sip_header_t *)ex); - } - - return nua_base_client_request(cr, msg, sip, 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 nua_subscribe_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - struct event_usage *eu = nua_dialog_usage_private(du); - enum nua_substate substate; - - if (eu == NULL || cr->cr_terminated) - substate = nua_substate_terminated; - else if (status >= 300) - substate = eu->eu_substate; - else { - int win_messenger_enable = NH_PGET(nh, win_messenger_enable); - sip_time_t delta, now = sip_now(); - - du->du_ready = 1; - - if (eu->eu_substate != nua_substate_terminated) - /* If there is no @Expires header, - use default value stored in eu_delta */ - delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, - eu->eu_delta, now); - else - delta = 0; - - if (delta > eu->eu_delta) - delta = eu->eu_delta; - - 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, ""); - } - - if (delta > 0) { - nua_dialog_usage_set_refresh(du, delta); - eu->eu_expires = du->du_refquested + delta; - } - else { - if (eu->eu_substate == nua_substate_terminated) { - if (!eu->eu_notified) - eu->eu_substate = nua_substate_embryonic; - } - - if (eu->eu_substate != nua_substate_terminated) { - /* Wait 32 seconds for NOTIFY. */ - delta = 64 * NTA_SIP_T1 / 1000; - - eu->eu_final_wait = 1; - - if (!eu->eu_notified && win_messenger_enable) - delta = 4 * 60; /* Wait 4 minutes for NOTIFY from Messenger */ - - nua_dialog_usage_set_refresh_range(du, delta, delta); - } - else { - nua_dialog_usage_reset_refresh(du); - } - - eu->eu_expires = du->du_refquested; - } - - substate = eu->eu_substate; - - if (substate == nua_substate_terminated) - /* let nua_base_client_tresponse to remove usage */ - cr->cr_terminated = 1; - } - - return nua_base_client_tresponse(cr, status, phrase, sip, - NUTAG_SUBSTATE(substate), - SIPTAG_EVENT(du ? du->du_event : NULL), - TAG_END()); -} - -/** 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_client_request_t *cr = du->du_cr; - struct event_usage *eu = nua_dialog_usage_private(du); - - 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): event %s%s%s fetch timeouts\n", - (void *)nh, o ? o->o_type : "(empty)", - id ? "; id=" : "", id ? id : "")); - - nua_stack_tevent(nh->nh_nua, nh, NULL, - nua_i_notify, 408, "Fetch Timeouts without NOTIFY", - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_EVENT(du->du_event), - TAG_END()); - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - - return; - } - - if (cr) { - if (nua_client_resend_request(cr, 0) >= 0) - return; - } - else if (eu->eu_refer) { - /* - * XXX - If we have received a NOTIFY, we should try to terminate - * subscription - */ - } - - if (!eu->eu_unsolicited) - nua_stack_tevent(nh->nh_nua, nh, NULL, - nua_i_notify, NUA_ERROR_AT(__FILE__, __LINE__), - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_EVENT(du->du_event), - TAG_END()); - - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); -} - -/** Terminate subscription. - * - * @retval >0 shutdown done - * @retval 0 shutdown in progress - * @retval <0 try again later - */ -static int nua_subscribe_usage_shutdown(nua_handle_t *nh, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) -{ - struct event_usage *eu = nua_dialog_usage_private(du); - nua_client_request_t *cr = du->du_cr; - - assert(eu); (void)eu; - - if (cr) { - if (nua_client_resend_request(cr, 1) >= 0) - return 0; - } - - nua_dialog_usage_remove(nh, ds, du, NULL, NULL); - 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 - */ - -int nua_notify_server_init(nua_server_request_t *sr); -int nua_notify_server_preprocess(nua_server_request_t *sr); -int nua_notify_server_report(nua_server_request_t *, tagi_t const *); - -nua_server_methods_t const nua_notify_server_methods = - { - SIP_METHOD_NOTIFY, - nua_i_notify, /* Event */ - { - /* create_dialog: */ 1, /* Do create dialog */ - /* in_dialog: */ 0, /* Not always in-dialog request */ - /* target_refresh: */ 1, /* Target refresh request */ - /* add_contact: */ 1, /* Add Contact to response */ - }, - nua_notify_server_init, - nua_notify_server_preprocess, - nua_base_server_params, - nua_base_server_respond, - nua_notify_server_report, - }; - - -int nua_notify_server_init(nua_server_request_t *sr) -{ - if (!sr->sr_initial) { - nua_dialog_state_t *ds = sr->sr_owner->nh_ds; - - /* Check for forked subscription. */ - if (ds->ds_remote_tag && ds->ds_remote_tag[0] && - su_strcasecmp(ds->ds_remote_tag, - sr->sr_request.sip->sip_from->a_tag)) { - sip_contact_t const *m = NULL; - - m = nua_stack_get_contact(sr->sr_owner->nh_nua->nua_registrations); - - if (m) { - sip_warning_t w[1]; - - sip_warning_init(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"; - - sip_add_dup(sr->sr_response.msg, NULL, (sip_header_t*)w); - } - - return SR_STATUS(sr, 481, "Subscription Does Not Exist"); - } - } - - return 0; -} - -int nua_notify_server_preprocess(nua_server_request_t *sr) -{ - nua_dialog_state_t *ds = sr->sr_owner->nh_ds; - nua_dialog_usage_t *du; - struct event_usage *eu; - sip_t const *sip = sr->sr_request.sip; - sip_event_t *o = sip->sip_event; - enum nua_substate substate = nua_substate_terminated; - sip_subscription_state_t *subs = sip->sip_subscription_state; - char const *what = "", *reason = NULL; - int solicited = 1; - - du = nua_dialog_usage_get(ds, nua_subscribe_usage, o); - - if (du == NULL) { - if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), SIP_METHOD_NOTIFY)) - return SR_STATUS(sr, 481, "Subscription Does Not Exist"); - - solicited = 0; /* Let application to handle unsolicited NOTIFY */ - du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o); - if (!du) - return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); - } - - sr->sr_usage = du; - eu = nua_dialog_usage_private(du); assert(eu); - eu->eu_notified++; - if (!o || !o->o_id) - eu->eu_no_id = 1; - - if (subs == NULL) { - /* Compatibility */ - unsigned long delta = eu->eu_delta; - if (sip->sip_expires) - delta = sip->sip_expires->ex_delta; - - if (delta == 0) - substate = nua_substate_terminated, what = "terminated"; - else - substate = nua_substate_active, what = "active"; - } - else if (su_casematch(subs->ss_substate, what = "terminated")) { - substate = nua_substate_terminated; - reason = subs->ss_reason; - - if (su_casematch(reason, "deactivated") || - su_casematch(reason, "probation")) - substate = nua_substate_embryonic; - } - else if (su_casematch(subs->ss_substate, what = "pending")) { - substate = nua_substate_pending; - } - else /* if (su_casematch(subs->ss_substate, what = "active")) */ { - /* Any extended state is considered as active */ - what = subs->ss_substate; - substate = nua_substate_active; - } - - eu->eu_substate = substate; - if (!solicited) - eu->eu_unsolicited = 1; - - SU_DEBUG_5(("nua(%p): %s: %s (%s)\n", - (void *)sr->sr_owner, "nua_notify_server_preprocess", - what, reason ? reason : "")); - - if (solicited) - return SR_STATUS1(sr, SIP_200_OK); - - return 0; -} - - -int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags) -{ - nua_handle_t *nh = sr->sr_owner; - nua_dialog_usage_t *du = sr->sr_usage; - struct event_usage *eu = nua_dialog_usage_private(du); - sip_t const *sip = sr->sr_request.sip; - enum nua_substate substate = nua_substate_terminated; - sip_time_t delta = SIP_TIME_MAX; - sip_event_t const *o = sip->sip_event; - int retry = -1; - int retval; - - if (eu) { - sip_subscription_state_t *subs = sip->sip_subscription_state; - - substate = eu->eu_substate; - - if (substate == nua_substate_active || substate == nua_substate_pending) { - if (subs && subs->ss_expires) { - sip_time_t now = sip_now(); - sip_time_t delta0 = strtoul(subs->ss_expires, NULL, 10); - if (now + delta0 <= eu->eu_expires) - delta = delta0; - } - } - else if (substate == nua_substate_embryonic) { - if (subs && subs->ss_reason) { - if (su_casematch(subs->ss_reason, "deactivated")) { - retry = 0; /* retry immediately */ - } - else if (su_casematch(subs->ss_reason, "probation")) { - retry = 30; - if (subs->ss_retry_after) - retry = strtoul(subs->ss_retry_after, NULL, 10); - if (retry > 3600) - retry = 3600; - } - } - } - else if (substate == nua_substate_terminated) { - sr->sr_terminating = 1; - } - } - - retval = nua_base_server_treport(sr, /* can destroy sr */ - NUTAG_SUBSTATE(substate), - SIPTAG_EVENT(o), - TAG_NEXT(tags)); - - if (retval != 1 || du == NULL) - return retval; - - if (eu->eu_unsolicited) { - /* Xyzzy */; - } - else if (retry >= 0) { /* Try to subscribe again */ - /* XXX - this needs through testing */ - nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */ - nua_dialog_usage_set_refresh_range(du, retry, retry + 5); - } - else { - if (delta < SIP_TIME_MAX) { - nua_dialog_usage_set_refresh(du, delta); - eu->eu_expires = du->du_refquested + delta; - } - } - - return retval; -} - - -/* ======================================================================== */ -/* REFER */ - -/**@fn void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); - * - * 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 - * Header tags defined in - * - * @par Events: - * #nua_r_refer \n - * #nua_i_notify - * - * @sa #nua_r_refer, NUTAG_SUBSTATE(), NUTAG_REFER_EVENT(),#nua_i_refer, - * @RFC3515, @ReferTo, SIPTAG_REFER_TO(), SIPTAG_REFER_TO_STR(), - * @RFC3892, @ReferredBy, SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR(), - * @RFC3891, @Replaces, SIPTAG_REPLACES(), SIPTAG_REPLACES_STR(), - * @RFC4488, @ReferSub, SIPTAG_REFER_SUB(), SIPTAG_REFER_SUB_STR() - */ - -/**@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, @RFC4488, @ReferSub - * - * @END_NUA_EVENT - */ - -static int nua_refer_client_init(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_refer_client_request(nua_client_request_t *cr, - msg_t *, sip_t *, - tagi_t const *tags); -static int nua_refer_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip); - -static nua_client_methods_t const nua_refer_client_methods = { - SIP_METHOD_REFER, /* crm_method, crm_method_name */ - 0, /* crm_extra */ - { /* crm_flags */ - /* create_dialog */ 1, - /* in_dialog */ 1, - /* target refresh */ 1 - }, - NULL, /* crm_template */ - nua_refer_client_init, /* crm_init */ - nua_refer_client_request, /* crm_send */ - NULL, /* crm_check_restart */ - nua_refer_client_response, /* crm_recv */ - nua_refer_client_response, /* crm_preliminary */ - NULL, /* crm_report */ - NULL, /* crm_complete */ -}; - -int -nua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, - tagi_t const *tags) -{ - return nua_client_create(nh, e, &nua_refer_client_methods, tags); -} - -static int nua_refer_client_init(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - - if (sip->sip_referred_by == NULL) { - sip_from_t *a = sip->sip_from; - sip_referred_by_t by[1]; - - sip_referred_by_init(by); - - if (a == NULL) - a = nh->nh_nua->nua_from; - by->b_display = a->a_display; - *by->b_url = *a->a_url; - - sip_add_dup(msg, sip, (sip_header_t *)by); - } - - if (sip->sip_event) - sip_header_remove(msg, sip, (sip_header_t *)sip->sip_event); - - return 0; -} - -static int nua_refer_client_request(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du, *du0 = cr->cr_usage; - struct event_usage *eu; - sip_event_t *event; - int error; - - cr->cr_usage = NULL; - - event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq); - if (!event) - return -1; - - if (du0 == NULL || - du0->du_event == NULL || - du0->du_event->o_id == NULL || - strcmp(du0->du_event->o_id, event->o_id)) { - du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event); - if (!du) - return -1; - } - else { - du = du0, du0 = NULL; - } - - if (du0) - nua_dialog_usage_remove(nh, nh->nh_ds, du0, NULL, NULL); - - eu = nua_dialog_usage_private(cr->cr_usage = du); - eu ->eu_refer = 1; - - error = nua_base_client_request(cr, msg, sip, tags); - - if (!error) { - /* Give application an Event header for matching NOTIFYs with REFER */ - nua_stack_tevent(nh->nh_nua, nh, NULL, - (enum nua_event_e)cr->cr_event, SIP_100_TRYING, - NUTAG_REFER_EVENT(event), - SIPTAG_EVENT(event), - TAG_END()); - su_free(nh->nh_home, event); - } - - return error; -} - -static int nua_refer_client_response(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - nua_dialog_usage_t *du = cr->cr_usage; - enum nua_substate substate = nua_substate_terminated; - - if (du) { - struct event_usage *eu = nua_dialog_usage_private(du); - - if (status < 200) { - substate = eu->eu_substate; - } - else if (status < 300) { - sip_refer_sub_t const *rs = sip_refer_sub(sip); - - if (rs && su_casematch("false", rs->rs_value)) - cr->cr_terminated = 1; - - if (!cr->cr_terminated) - substate = eu->eu_substate; - } - } - - return nua_base_client_tresponse(cr, status, phrase, sip, - NUTAG_SUBSTATE(substate), - SIPTAG_EVENT(du ? du->du_event : NULL), - TAG_END()); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c deleted file mode 100644 index 21dede4343..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c +++ /dev/null @@ -1,3006 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Martti Mela - * - * @date Created: Wed Feb 21 10:13:29 2001 ppessi - */ - -#include "config.h" - -#define TAG_NAMESPACE "nua" - -#include "sofia-sip/nua_tag.h" - -#include -#include -#include -#include -#include - -/** @page nua_api_overview NUA API Overview - * - * This page shortly overviews the NUA API: different functions, tags, and - * where and how they affect the working of NUA engine. - * - * The application and the NUA engine can pass various parameters between - * them using tagged arguments. Tagged arguments can be used like named - * arguments in higher-lever language. - * - * @par NUA Agent - * - * The NUA agent object is created with nua_create(). The nua_create() also - * creates the transports and binds the transport sockets used by the SIP - * stack. - * - * The special tags controlling the transports are - * - NUTAG_URL(), NUTAG_SIPS_URL(), NUTAG_CERTIFICATE_DIR(), NUTAG_SIP_PARSER() - * - * See nta_agent_add_tport() for discussion about magic URIs used to - * initialize transports. - * - * The agent-wide parameter can be later modified or obtained with - * nua_set_params() and nua_get_params(), respectively. - * - * The #su_root_t mainloop integration uses - * - su_root_create(), su_root_threading(), - * su_root_poll(), su_root_run(), su_root_break() - * - * @par NUA Handles - * - nua_handle(), nua_get_hparams(), nua_set_hparams() - * - nua_handle_home(), nua_handle_has_invite(), nua_handle_has_subscribe(), - * nua_handle_has_register(), nua_handle_has_active_call(), - * nua_handle_has_call_on_hold(), nua_handle_has_events(), - * nua_handle_has_registrations(), nua_handle_remote(), and - * nua_handle_local(). - * - Settings: - * See nua_set_hparams(). There are a few "sticky" headers that are used - * on subsequent requests if given on any handle-specific call: - * - @Contact, @UserAgent, @Supported, @Allow, @Organization - * - * @par Client Generating SIP Requests - * - nua_register(), nua_unregister(), nua_invite(), nua_cancel(), - * nua_ack(), nua_bye(), nua_options(), nua_refer(), nua_publish(), - * nua_unpublish(), nua_prack(), nua_info(), nua_update(), nua_message(), - * nua_subscribe(), nua_unsubscribe(), nua_notify(), nua_method() - * - NUTAG_URL() - * Settings: - * - NUTAG_RETRY_COUNT(), NUTAG_PROXY(), - * NUTAG_INITIAL_ROUTE() and NUTAG_INITIAL_ROUTE_STR() - * - NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() - * - NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() - * - NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() - * - SIPTAG_ORGANIZATION() and SIPTAG_ORGANIZATION_STR() - * - * @par Client Authenticating Requests - * - nua_authenticate(), #nua_r_authenticate - * - NUTAG_AUTH(), NUTAG_AUTH_CACHE() - * - * @par Server Processing Received SIP Requests - * - nua_respond(), NUTAG_WITH_THIS(), NUTAG_WITH_SAVED(), NUTAG_WITH() - * - #nua_i_invite, #nua_i_cancel, #nua_i_ack, #nua_i_bye, - * #nua_i_options, #nua_i_refer, #nua_i_publish, #nua_i_prack, - * #nua_i_info, #nua_i_update, #nua_i_message, #nua_i_subscribe, - * #nua_i_notify, #nua_i_method, #nua_i_register - * Settings: - * - NUTAG_APPL_METHOD(), NUTAG_PROXY() - * - NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() - * - NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() - * - * @par Registrations and Contact Header Generation - * - nua_register(), #nua_r_register(), #nua_i_outbound, - * nua_unregister(), and #nua_r_unregister - * Settings: - * - NUTAG_CALLEE_CAPS() - * - NUTAG_DETECT_NETWORK_UPDATES() - * - NUTAG_INSTANCE() - * - NUTAG_KEEPALIVE() - * - NUTAG_KEEPALIVE_STREAM() - * - NUTAG_M_DISPLAY() - * - NUTAG_M_FEATURES() - * - NUTAG_M_PARAMS() - * - NUTAG_M_USERNAME() - * - NUTAG_OUTBOUND() - * - NUTAG_PATH_ENABLE() - * - NUTAG_RETRY_AFTER_ENABLE() - * - NUTAG_SERVICE_ROUTE_ENABLE() - * Specifications: - * - @RFC3261 section 10, @RFC3327, @RFC3608, @RFC3680, @RFC3840, - * draft-ietf-sip-outbound, draft-ietf-sip-gruu-14 - * - * @par INVITE Sessions and Call Model - * - nua_invite(), #nua_r_invite, #nua_i_invite - * - nua_handle_has_active_call(), nua_handle_has_call_on_hold(), - * nua_handle_has_invite() - * - nua_cancel(), #nua_r_cancel, #nua_i_cancel - * - nua_ack(), #nua_i_ack - * - nua_bye(), #nua_r_bye, #nua_i_bye - * - #nua_i_state, NUTAG_CALLSTATE(), - * NUTAG_OFFER_SENT(), NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(), and - * NUTAG_ANSWER_SENT(), SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(), - * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR() - * Settings: - * - NUTAG_AUTOACK(), NUTAG_AUTOALERT(), NUTAG_AUTOANSWER(), - * NUTAG_ENABLEINVITE(), NUTAG_INVITE_TIMER(), NUTAG_MEDIA_ENABLE(), - * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), SOATAG_CAPS_SDP(), - * SOATAG_CAPS_SDP_STR() - * Specifications: - * - @RFC3261, @RFC3264 - * - * @par In-Session Information requests - * - nua_info() #nua_r_info, #nua_i_info - * Settings: - * - NUTAG_ALLOW("INFO"), NUTAG_APPL_METHOD("INFO") - * - * @par SDP Processing - * - #nua_i_state, SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(), - * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT(), - * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(), - * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR() - * Settings: - * - NUTAG_MEDIA_ENABLE(), NUTAG_SOA_NAME(), NUTAG_EARLY_ANSWER(), - * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), SOATAG_CAPS_SDP(), - * SOATAG_CAPS_SDP_STR() - * Specifications: - * - @RFC3264 - * - * @par Call Model Extensions ("100rel" and "precondition") - * Early - * - nua_prack(), #nua_r_prack, #nua_i_prack - * - nua_update() #nua_r_update, #nua_i_update - * Settings: - * - NUTAG_EARLY_MEDIA(), NUTAG_ONLY183_100REL() - * - "100rel" or "precondition" in NUTAG_SUPPORTED()/SIPTAG_SUPPORTED() - * Specifications: - * - @RFC3262, @RFC3311, @RFC3312 - * - * @par SIP Session Timers ("timer") - * Periodic refresh of SIP Session initiated with INVITE with re-INVITE or - * UPDATE requests. - * Settings: - * - NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(), - * NUTAG_SESSION_TIMER(), NUTAG_UPDATE_REFRESH(), - * NUTAG_REFRESH_WITHOUT_SDP(), - * - "timer" in NUTAG_SUPPORTED()/SIPTAG_SUPPORTED() - * Specifications: - * - @RFC4028 - * - * @par Caller Preferences and Callee Caps - * - Caller preferences in @AcceptContact header in a INVITE requests - * - Callee caps contained in @Contact header in a REGISTER request - * Settings: - * - NUTAG_CALLEE_CAPS(), NUTAG_MEDIA_FEATURES(), - * NUTAG_M_FEATURES() - * Specifications: - * - @RFC3840, @RFC3841 - * - * @par Instant Messaging - * - nua_message(), #nua_r_message, #nua_i_message - * Settings: - * - NUTAG_APPL_METHOD("MESSAGE"), - * NUTAG_ENABLEMESSAGE(), NUTAG_ENABLEMESSENGER() - * Specifications: - * - @RFC3428 - * - * @par Call Transfer - * - nua_refer(), #nua_r_refer, #nua_i_notify, SIPTAG_EVENT(), - * @ReferTo, SIPTAG_REFER_TO(), @ReferredBy, SIPTAG_REFERRED_BY(), - * nua_handle_make_replaces(), @Replaces, SIPTAG_REPLACES(), - * @ReferSub, SIPTAG_REFER_SUB() - * - #nua_i_refer, nua_notify(), #nua_r_notify, - * nua_handle_by_replaces() - * - nua_invite() with NUTAG_NOTIFY_REFER() and NUTAG_REFER_EVENT() - * Settings: - * - NUTAG_REFER_EXPIRES(), NUTAG_REFER_WITH_ID() - * Specifications: - * - @RFC3515 (@ReferTo), @RFC3892 (@ReferredBy), @RFC3891 (@Replaces), - * @RFC4488, @ReferSub - * - * @par Internal SIP Event Server - * - nua_notifier(), #nua_r_notifier, #nua_i_subscription, - * nua_authorize(), #nua_r_authorize, nua_terminate(), #nua_r_terminate - * - SIPTAG_EVENT(), SIPTAG_CONTENT_TYPE(), SIPTAG_PAYLOAD(), - * NUTAG_SUBSTATE() - * @par Settings - * - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and - * SIPTAG_ALLOW_EVENTS_STR() - * - NUTAG_MAX_SUBSCRIPTIONS() - * - NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES() - * @par Specifications - * - @RFC3265 - * - * @par SIP Event Subscriber - * - nua_subscribe(), #nua_r_subscribe, #nua_i_notify, NUTAG_SUBSTATE(), - * SIPTAG_EVENT(), SIPTAG_EXPIRES() - * - nua_unsubscribe(), #nua_r_unsubscribe() - * @par Specifications - * - @RFC3265 - * - * @par SIP Event Notifier - * - #nua_i_subscribe(), nua_notify(), #nua_r_notify, - * NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES(), SIPTAG_EVENT() - * Settings: - * - NUTAG_SUB_EXPIRES() - * - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and - * SIPTAG_ALLOW_EVENTS_STR() - * - NUTAG_ALLOW("SUBSCRIBE"), NUTAG_APPL_METHOD("SUBSCRIBE") - * @par Specifications - * - @RFC3265 - * - * @par SIP Event Publisher - * - nua_publish(), #nua_r_publish(), nua_unpublish(), nua_r_unpublish() - * - @SIPETag, SIPTAG_ETAG(), @SIPIfMatch, SIPTAG_IF_MATCH() - * @par Specifications - * - @RFC3903 - * - * @par SIP Event State Compositor (PUBLISH Server) - * - #nua_i_publish, @SIPETag, @SIPIfMatch - * @par Settings - * - NUTAG_ALLOW("PUBLISH"), NUTAG_APPL_METHOD("PUBLISH") - * @par Specifications - * - @RFC3903 - * - * @par Non-Standard Extension Methods - * - nua_method(), NUTAG_METHOD(), #nua_r_method, NUTAG_DIALOG() - * - #nua_i_method, nua_respond() - * Settings: - * - NUTAG_ALLOW(x), NUTAG_APPL_METHOD(x) - * - * @par Server Shutdown - * - nua_shutdown(), NUTAG_SHUTDOWN_EVENTS(), nua_destroy(). - */ - -/* @par S/MIME - * - NUTAG_SMIME_ENABLE() - * - NUTAG_SMIME_KEY_ENCRYPTION() - * - NUTAG_SMIME_MESSAGE_DIGEST() - * - NUTAG_SMIME_MESSAGE_ENCRYPTION() - * - NUTAG_SMIME_OPT() - * - NUTAG_SMIME_PROTECTION_MODE() - * - NUTAG_SMIME_SIGNATURE() - */ - -tag_typedef_t nutag_any = NSTAG_TYPEDEF(*); - -/**@def NUTAG_URL() - * - * 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 * or url_t * or url_string_t * - * - * @par Values - * #url_string_t, which is either a pointer to #url_t or NULL terminated - * character string representing URL - * - * 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(). It can be specified multiple times when used with - * nua_create(). - * - * @sa SIPTAG_TO() - * - * Corresponding tag taking reference parameter is NUTAG_URL_REF() - */ -tag_typedef_t nutag_url = URLTAG_TYPEDEF(url); - - -/**@def NUTAG_METHOD(x) - * - * 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. - */ -tag_typedef_t nutag_method = STRTAG_TYPEDEF(method); - -/**@def NUTAG_METHOD_REF(x) - * Reference tag for NUTAG_METHOD(). - */ - - -/*#@def NUTAG_UICC(x) - * - * Intentionally undocumented. - */ -tag_typedef_t nutag_uicc = STRTAG_TYPEDEF(uicc); - -/*#@def NUTAG_UICC_REF(x) - * Reference tag for NUTAG_UICC(). - */ - - -/**@def NUTAG_MEDIA_FEATURES() - * - * Add media tags from our offer to Accept-Contact headers. - * - * Automatically generate @AcceptContact headers for caller - * preference processing according to the media capabilities in @a soa. - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_invite() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Do not add @AcceptContact - * - 1 (true) - Add @AcceptContact with media tags - * - * Corresponding tag taking reference parameter is NUTAG_MEDIA_FEATURES_REF() - * - * @sa nua_invite(), @AcceptContact, @RFC3841, @RFC3840, SOATAG_USER_SDP(), - * SIPTAG_ACCEPT_CONTACT(), NUTAG_CALLEE_CAPS() - */ -tag_typedef_t nutag_media_features = BOOLTAG_TYPEDEF(media_features); - -/**@def NUTAG_MEDIA_FEATURES_REF(x) - * Reference tag for NUTAG_MEDIA_FEATURES(). - */ - - -/**@def NUTAG_CALLEE_CAPS(x) - * - * Add methods parameter and media feature parameter to the @Contact headers - * generated for REGISTER request. - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_register() - * - * @par Parameter type - * int - * - * @par Values - * - 0 (false) - Do not include methods and media feature parameters - * - 1 (true) - Include media tags in @Contact - * - * Corresponding tag taking reference parameter is NUTAG_MEDIA_FEATURES_REF(). - * - * @sa nua_register(), @Contact, NUTAG_M_FEATURES(), @RFC3840, @RFC3841, - * SOATAG_USER_SDP(), NUTAG_MEDIA_FEATURES() - */ -tag_typedef_t nutag_callee_caps = BOOLTAG_TYPEDEF(callee_caps); - -/**@def NUTAG_CALLEE_CAPS_REF(x) - * Reference tag for NUTAG_CALLEE_CAPS(). - */ - - -/**@def NUTAG_EARLY_MEDIA(x) - * - * Establish early media session using 100rel, 183 responses and PRACK. - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_invite(), nua_respond() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - do not try to use early media - * - 1 (true) - try to use early media - * - * @sa NUTAG_EARLY_ANSWER() - * - * Corresponding tag taking reference parameter is NUTAG_EARLY_MEDIA_REF(). - */ -tag_typedef_t nutag_early_media = BOOLTAG_TYPEDEF(early_media); - -/**@def NUTAG_EARLY_MEDIA_REF(x) - * Reference tag for NUTAG_EARLY_MEDIA(). - */ - - -/**@def NUTAG_ONLY183_100REL(x) - * - * Require 100rel extension and PRACK only with 183 response. - * - * When NUTAG_EARLY_MEDIA() is set, and if this parameter is set, stack - * includes feature tag "100rel" in the @Require header only with 183: - * otherwise, all 1XX responses (except 100 Trying) require 100rel. - * - * @par Used with - * nua_set_params() \n - * nua_get_params() \n - * nua_handle() \n - * nua_set_hparams() \n - * nua_get_hparams() \n - * nua_invite() \n - * nua_respond() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - include 100rel in all preliminary responses - * - 1 (true) - include 100rel only in 183 responses - * - * @note - * This tag takes only effect when NUTAG_EARLY_MEDIA(1) has been used, too. - * - * Corresponding tag taking reference parameter is NUTAG_ONLY183_100REL_REF(). - * - * @sa - */ -tag_typedef_t nutag_only183_100rel = BOOLTAG_TYPEDEF(only183_100rel); - -/**@def NUTAG_ONLY183_100REL_REF(x) - * Reference tag for NUTAG_ONLY183_100REL(). - */ - - -/**@def NUTAG_EARLY_ANSWER(x) - * - * 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: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - do not include SDP in non-100rel 1XX responses - * - 1 (true) - try to include SDP in preliminary responses - * - * 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. - */ -tag_typedef_t nutag_early_answer = BOOLTAG_TYPEDEF(early_answer); - -/**@def NUTAG_EARLY_ANSWER_REF(x) - * Reference tag for NUTAG_EARLY_ANSWER(). - */ - - -/**@def NUTAG_INCLUDE_EXTRA_SDP(x) - * - * 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: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - do not include extra SDP on 200 OK - * - 1 (true) - include SDP in 200 OK even if it has been sent - * a 100rel response, too - * - * 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. - */ -tag_typedef_t nutag_include_extra_sdp = BOOLTAG_TYPEDEF(include_extra_sdp); - -/**@def NUTAG_INCLUDE_EXTRA_SDP_REF(x) - * Reference tag for NUTAG_INCLUDE_EXTRA_SDP(). - */ - - -/**@def NUTAG_MEDIA_ENABLE() - * - * 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 - * - 0 (false) - do not use soa - * - 1 (true) - use soa with SDP O/A - * - * Corresponding tag taking reference parameter is NUTAG_MEDIA_ENABLE_REF() - */ -tag_typedef_t nutag_media_enable = BOOLTAG_TYPEDEF(media_enable); - -/**@def NUTAG_MEDIA_ENABLE_REF(x) - * Reference tag for NUTAG_MEDIA_ENABLE(). - */ - - - -/**@def NUTAG_SOA_NAME(x) - * - * 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_NAME_REF(). - */ -tag_typedef_t nutag_soa_name = STRTAG_TYPEDEF(soa_name); - -/**@def NUTAG_SOA_NAME_REF(x) - * Reference tag for NUTAG_SOA_NAME(). - */ - - -/**@def NUTAG_RETRY_COUNT(x) - * - * Set request retry count. - * - * Retry count determines how many times stack will automatically retry - * after an recoverable error response, like 302, 401 or 407. - * - * Note that the first request does not count as retry. - * - * @par Used with - * nua_create(), nua_set_params(), nua_handle(), nua_set_hparams(), - * nua_get_params(), nua_get_hparams(), - * nua_register(), nua_unregister(), - * nua_options(), nua_invite(), nua_ack(), nua_cancel(), nua_bye(), - * nua_prack(), nua_update(), nua_info(), - * nua_message(), nua_publish(), nua_unpublish(), nua_notifier(), - * nua_subscribe(), nua_unsubscribe(), nua_notify(), nua_refer(), - * nua_method(), nua_respond() - * nua_authenticate(). - * - * @par Parameter type - * unsigned - * - * @par Values - * - 0 - Never retry automatically - * - Otherwise, number of extra transactions initiated after initial - * transaction failed with recoverable error response - * - * @NEW_1_12_4. - * - * Corresponding tag taking reference parameter is NUTAG_RETRY_COUNT_REF(). - */ -tag_typedef_t nutag_retry_count = UINTTAG_TYPEDEF(retry_count); - -/**@def NUTAG_RETRY_COUNT_REF(x) - * - * Reference tag for NUTAG_RETRY_COUNT(). - */ - - -/**@def NUTAG_MAX_SUBSCRIPTIONS(x) - * - * 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 int - * - * @par Values - * - 0 (zero) - do not allow any subscriptions - * - * @sa nua_notifier(), nua_authorize() - * - * Corresponding tag taking reference parameter is - * NUTAG_MAX_SUBSCRIPTIONS_REF(). - */ -tag_typedef_t nutag_max_subscriptions = UINTTAG_TYPEDEF(max_subscriptions); - -/**@def NUTAG_MAX_SUBSCRIPTIONS_REF(x) - * Reference tag for NUTAG_MAX_SUBSCRIPTIONS(). - */ - - -/**@def NUTAG_CALLSTATE() - * - * 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(). - */ -tag_typedef_t nutag_callstate = INTTAG_TYPEDEF(callstate); - -/**@def NUTAG_CALLSTATE_REF(x) - * Reference tag for NUTAG_CALLSTATE(). - */ - - -/**@def NUTAG_OFFER_RECV() - * - * Indicate that SDP offer has been received. - * - * @par Used with - * #nua_i_state - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * Corresponding tag taking reference parameter is NUTAG_OFFER_RECV_REF(). - */ -tag_typedef_t nutag_offer_recv = BOOLTAG_TYPEDEF(offer_recv); - -/**@def NUTAG_OFFER_RECV_REF(x) - * Reference tag for NUTAG_OFFER_RECV(). - */ - - -/**@def NUTAG_ANSWER_RECV() - * - * Indicate that SDP answer has been received. - * - * @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_RECV_REF(). - */ -tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv); - -/**@def NUTAG_ANSWER_RECV_REF(x) - * Reference tag for NUTAG_ANSWER_RECV(). - */ - - -/**@def NUTAG_OFFER_SENT() - * - * Indicate that SDP offer 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_OFFER_SENT_REF(). - */ -tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent); - -/**@def NUTAG_OFFER_SENT_REF(x) - * Reference tag for NUTAG_OFFER_SENT(). - */ - - -/**@def NUTAG_ANSWER_SENT() - * - * 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(). - */ -tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent); - -/**@def NUTAG_ANSWER_SENT_REF(x) - * Reference tag for NUTAG_ANSWER_SENT(). - */ - - -/**@def NUTAG_SUBSTATE() - * - * Subscription state. - * - * @par Used with - * - with nua_create(), nua_set_params(), nua_get_params(), - * nua_handle(), nua_set_hparams(), nua_get_hparams(), and - * nua_notifier() to change the default subscription state returned by - * the internal event server - * - with nua_notify() and nua_respond() to SUBSCRIBE to determine the - * subscription state (if application include @SubscriptionState - * header in the tag list, the NUTAG_SUBSTATE() value is ignored) - * - with #nua_r_subscribe, #nua_i_notify, #nua_i_subscribe, and #nua_r_notify - * to indicate the current subscription state - * - * @par Parameter type - * int - * - * @par Values - * - #nua_substate_embryonic (0) - * - #nua_substate_pending (1) - * - #nua_substate_active (2) - * - #nua_substate_terminated (3) - * - * Note that the @SubscriptionState or @Expires headers specified by - * application with the nua_notify() or nua_respond() to SUBSCRIBE overrides - * the subscription state specified by NUTAG_SUBSTATE(). - * Application can terminate subscription by including - * NUTAG_SUBSTATE(nua_substate_terminated), @SubscriptionState with value - * "terminated" or @Expires header with value 0 in the NOTIFY request sent - * by nua_notify(). - * - * @sa @RFC3265, @SubscriptionState, SIPTAG_SUBSCRIPTION_STATE(), - * SIPTAG_SUBSCRIPTION_STATE_STR(), nua_notifier(), #nua_r_subscribe, - * #nua_i_subscribe, #nua_i_refer, #nua_r_notify, #nua_i_notify. - * - * Corresponding tag taking reference parameter is NUTAG_SUBSTATE_REF(). - */ -tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate); - -/**@def NUTAG_SUBSTATE_REF(x) - * Reference tag for NUTAG_SUBSTATE(). - */ - - -/**@def NUTAG_SUB_EXPIRES() - * - * Default expiration time of subscriptions. - * - * @par Used with - * - with nua_create(), nua_set_params(), nua_get_params(), nua_handle(), - * nua_set_hparams(), nua_get_hparams(), nua_respond(), nua_notify(), and - * nua_notifier() to change the default expiration time of subscriptions - * - * @par Parameter type - * unsigned int - * - * @par Values - * - default expiration time in seconds - * - * Note that the expires parameter in @SubscriptionState or @Expires header - * in the nua_response() to the SUBSCRIBE overrides the default subscription - * expiration specified by NUTAG_SUB_EXPIRES(). - * - * @sa @RFC3265, NUTAG_REFER_EXPIRES(), @Expires, SIPTAG_EXPIRES(), - * SIPTAG_EXPIRES_STR(), @SubscriptionState, nua_respond(), nua_notifier(), - * #nua_r_subscribe, #nua_i_subscribe, #nua_r_refer, #nua_r_notify, - * #nua_i_notify. - * - * Corresponding tag taking reference parameter is NUTAG_SUB_EXPIRES_REF(). - * - * @NEW_1_12_9. - */ -tag_typedef_t nutag_sub_expires = UINTTAG_TYPEDEF(substate); - -/**@def NUTAG_SUB_EXPIRES_REF(x) - * Reference tag for NUTAG_SUB_EXPIRES(). - */ - - -/**@def NUTAG_NEWSUB() - * - * Send unsolicited NOTIFY request. - * - * Some applications may require sending unsolicited NOTIFY requests, that - * is, NOTIFY without SUBSCRIBE or REFER request sent by event watcher. - * However, sending NOTIFY request requires an existing dialog usage by - * default. If the nua_notify() tags include NUTAG_NEWSUB(1), the usage - * is created by nua_notify() itself. - * - * If you want to create a subscription that does not terminate immediately - * include SIPTAG_SUBSCRIPTION_STATE()/SIPTAG_SUBSCRIPTION_STATE_STR() with - * an "expires" parameter in the argument list, too. - * - * @par Used with - * nua_notify() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 - false (default) - do not create new subscription - * but reject NOTIFY with 481 locally - * - 1 - true - create a subscription if it does not exist - * - * Corresponding tag taking reference parameter is NUTAG_NEWSUB_REF(). - * - * @NEW_1_12_5. - */ -tag_typedef_t nutag_newsub = BOOLTAG_TYPEDEF(newsub); - -/**@def NUTAG_NEWSUB_REF(x) - * Reference tag for NUTAG_NEWSUB(). - */ - - -/**@def NUTAG_INVITE_TIMER(x) - * - * 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(), nua_set_hparams(), - * nua_get_params(), nua_get_hparams() - * - * @par Parameter type - * int (enum nua_af) - * - * @par Values - * - 0 no timer - * - >0 timer in seconds - * - * Corresponding tag taking reference parameter is NUTAG_INVITE_TIMER_REF(). - */ -tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer); - -/**@def NUTAG_INVITE_TIMER_REF(x) - * Reference tag for NUTAG_INVITE_TIMER(). - */ - - -/**@def NUTAG_SESSION_TIMER(x) - * - * Default session timer in seconds. - * - * Set default value for session timer in seconds when the session timer - * extension is used. The tag value is the proposed session expiration time - * in seconds, the session is refreshed twice during the expiration time. - * - * @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 422 Session Timer Too - * Small. In that case, @b nua increases the value of @SessionExpires - * header and retries the request automatically. - * - * @par Returning a 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 request 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 422 Session Timer Too Small. - * - * @par Refreshes - * - * After the initial INVITE request, the SIP session is refreshed at the - * intervals indicated by the @SessionExpires header returned in the 2XX - * response. The party indicated with the "refresher" parameter of the - * @SessionExpires header sends a re-INVITE requests (or an UPDATE - * request if NUTAG_UPDATE_REFRESH(1) parameter tag has been set). - * - * Some SIP user-agents use INVITE without SDP offer to refresh session. - * By default, NUA sends an offer in 200 OK to such an INVITE and expects - * an answer back in ACK. If NUTAG_REFRESH_WITHOUT_SDP(1) tag is used, - * no SDP offer is sent in 200 OK if re-INVITE was received without SDP. - * - * @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() or NUTAG_SESSION_REFRESHER() - * 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. - * - * @note The session timer extension is used only if the feature - * tag "timer" is listed in the @Supported header, set by NUTAG_SUPPORTED(), - * SIPTAG_SUPPORTED(), or SIPTAG_SUPPORTED_STR() tags. - * - * @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 - * - 0 disable - * - >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_respond(), - * nua_update(), #nua_r_update, #nua_i_update, - * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE - */ -tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer); - -/**@def NUTAG_SESSION_TIMER_REF(x) - * Reference tag for NUTAG_SESSION_TIMER(). - */ - - -/**@def NUTAG_MIN_SE(x) - * - * 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 - */ -tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se); - -/**@def NUTAG_MIN_SE_REF(x) - * Reference tag for NUTAG_MIN_SE(). - */ - - -/**@def NUTAG_SESSION_REFRESHER(x) - * - * 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 - * - nua_no_refresher (session timers are disabled) - * - nua_local_refresher - * - nua_remote_refresher - * - nua_any_refresher (default) - * - * Corresponding tag taking reference parameter is - * NUTAG_SESSION_REFRESHER_REF(). - * - * @sa NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(), - * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE - */ -tag_typedef_t nutag_session_refresher = INTTAG_TYPEDEF(session_refresher); - -/**@def NUTAG_SESSION_REFRESHER_REF(x) - * Reference tag for NUTAG_SESSION_REFRESHER(). - */ - - - - -/**@def NUTAG_UPDATE_REFRESH(x) - * - * 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 - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 1 (true, use UPDATE) - * - 0 (false, use INVITE) - * - * Corresponding tag taking reference parameter is NUTAG_UPDATE_REFRESH_REF(). - * - * @sa #nua_r_update, NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(), - * NUTAG_SESSION_REFRESHER(), @RFC4028, @SessionExpires, @MinSE - */ -tag_typedef_t nutag_update_refresh = BOOLTAG_TYPEDEF(update_refresh); - -/**@def NUTAG_UPDATE_REFRESH_REF(x) - * Reference tag for NUTAG_UPDATE_REFRESH(). - */ - - -/**@def NUTAG_REFRESH_WITHOUT_SDP(x) - * - * Do not send offer in response if re-INVITE was received without SDP. - * - * Some SIP user-agents use INVITE without SDP offer to refresh session. - * By default, NUA sends an offer in 200 OK to such an INVITE and expects - * an answer back in ACK. - * - * If NUTAG_REFRESH_WITHOUT_SDP(1) tag is used, no SDP offer is sent in 200 - * OK if re-INVITE was received without SDP. - * - * @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 - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 1 (true, do not try to send offer in response to re-INVITE) - * - 0 (false, always use SDP offer-answer in re-INVITEs) - * - * Corresponding tag taking reference parameter is NUTAG_REFRESH_WITHOUT_SDP_REF(). - * - * @sa #nua_r_update, NUTAG_SESSION_TIMER(), NUTAG_MIN_SE_REF(), - * NUTAG_SESSION_REFRESHER(), NUTAG_UPDATE_REFRESH(), @RFC4028, - * @SessionExpires, @MinSE - * - * @NEW_1_12_10 - */ -tag_typedef_t nutag_refresh_without_sdp = BOOLTAG_TYPEDEF(refresh_without_sdp); - -/**@def NUTAG_REFRESH_WITHOUT_SDP_REF(x) - * Reference tag for NUTAG_REFRESH_WITHOUT_SDP_REF(). - */ - - -/**@def NUTAG_REFER_EXPIRES() - * - * Default lifetime for implicit subscriptions created by REFER. - * - * Default expiration time in seconds for implicit subscriptions created by - * REFER. - * - * @par Used with - * nua_handle(), nua_respond() \n - * nua_set_params() or nua_set_hparams() \n - * nua_get_params() or nua_get_hparams() - * - * @par Parameter type - * unsigned int - * - * @par Values - * - default interval in seconds - * - * @sa NUTAG_SUB_EXPIRES() - * - * Corresponding tag taking reference parameter is NUTAG_REFER_EXPIRES_REF(). - */ -tag_typedef_t nutag_refer_expires = UINTTAG_TYPEDEF(refer_expires); - -/**@def NUTAG_REFER_EXPIRES_REF(x) - * Reference tag for NUTAG_REFER_EXPIRES(). - */ - - -/**@def NUTAG_REFER_WITH_ID() - * - * 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: nonzero is true, zero is false) - * - * @par Values - * - 0 (false, do not use id with subscription created with first REFER request) - * - 1 (true, use id with all subscriptions created with REFER request) - * - * Corresponding tag taking reference parameter is NUTAG_REFER_WITH_ID_REF(). - * - * @since New in @VERSION_1_12_2. - */ -tag_typedef_t nutag_refer_with_id = BOOLTAG_TYPEDEF(refer_with_id); - -/**@def NUTAG_REFER_WITH_ID_REF(x) - * Reference tag for NUTAG_REFER_WITH_ID(). - */ - -/**@def NUTAG_AUTOALERT(x) - * - * Send alerting (180 Ringing) automatically (instead of 100 Trying). If the - * early media has been enabled with NUTAG_EARLY_MEDIA(1), the stack will - * send 183, wait for PRACK and then return 180 Ringing. - * - * @par Used with - * nua_set_params() \n - * nua_get_params() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - no automatic sending of "180 Ringing" - * - 1 (true) - "180 Ringing" sent automatically - * - * Corresponding tag taking reference parameter is NUTAG_AUTOALERT_REF(). - */ -tag_typedef_t nutag_autoalert = BOOLTAG_TYPEDEF(autoAlert); - -/**@def NUTAG_AUTOALERT_REF(x) - * Reference tag for NUTAG_AUTOALERT(). - */ - - -/**@def NUTAG_AUTOANSWER(x) - * - * 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: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - No automatic sending of "200 Ok" - * - 1 (true) - "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(). - */ -tag_typedef_t nutag_autoanswer = BOOLTAG_TYPEDEF(autoAnswer); - -/**@def NUTAG_AUTOANSWER_REF(x) - * Reference tag for NUTAG_AUTOANSWER(). - */ - - -/**@def NUTAG_AUTOACK(x) - * - * 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 (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - No automatic sending of ACK - * - 1 (true) - ACK sent automatically - * - * Default value is NUTAG_AUTOACK(1). - * - * @par Auto ACK with Re-INVITE requests - * By default, NUA tries to auto-ACK the final response to re-INVITE used to - * refresh the session when the media is enabled. Set NUTAG_AUTOACK(0) on - * the call handle (e.g., include the tag with nua_invite() or - * nua_respond()) in order to disable the auto ACK with re-INVITE. - * - * Corresponding tag taking reference parameter is NUTAG_AUTOACK_REF(). - */ -tag_typedef_t nutag_autoack = BOOLTAG_TYPEDEF(autoACK); - -tag_typedef_t nutag_timer_autorequire = BOOLTAG_TYPEDEF(timerAutorequire); - -/**@def NUTAG_AUTOACK_REF(x) - * Reference tag for NUTAG_AUTOACK(). - */ - - -/**@def NUTAG_ENABLEINVITE(x) - * - * Enable incoming INVITE. - * - * - * @par Used with - * nua_set_params() \n - * nua_get_params() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Incoming INVITE not enabled. NUA answers 403 Forbidden - * - 1 (true) - Incoming INVITE enabled - * - * Corresponding tag taking reference parameter is NUTAG_ENABLEINVITE_REF(). - */ -tag_typedef_t nutag_enableinvite = BOOLTAG_TYPEDEF(enableInvite); - -/**@def NUTAG_ENABLEINVITE_REF(x) - * Reference tag for NUTAG_ENABLEINVITE(). - */ - - - -/**@def NUTAG_ENABLEMESSAGE(x) - * - * Enable incoming MESSAGE - * - * @par Used with - * nua_set_params() \n - * nua_get_params() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Incoming MESSAGE not enabled. NUA answers 403 Forbidden - * - 1 (true) - Incoming MESSAGE enabled - * - * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSAGE_REF(). - */ -tag_typedef_t nutag_enablemessage = BOOLTAG_TYPEDEF(enableMessage); - -/**@def NUTAG_ENABLEMESSAGE_REF(x) - * Reference tag for NUTAG_ENABLEMESSAGE(). - */ - - - -/**@def NUTAG_ENABLEMESSENGER(x) - * - * Enable incoming MESSAGE with To tag. - * - * Set this parameter true if you want to chat with Windows Messenger. When - * it is set, stack will accept MESSAGE requests with To tag outside - * existing dialogs. - * - * @par Used with - * nua_set_params() \n - * nua_get_params() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - disable Windows-Messenger-specific features - * - 1 (true) - enable Windows-Messenger-specific features - * - * Corresponding tag taking reference parameter is NUTAG_ENABLEMESSENGER_REF(). - */ -tag_typedef_t nutag_enablemessenger = BOOLTAG_TYPEDEF(enableMessenger); - -/**@def NUTAG_ENABLEMESSENGER_REF(x) - * Reference tag for NUTAG_ENABLEMESSENGER(). - */ - - -/**@def NUTAG_SMIME_ENABLE(x) - * - * Enable S/MIME - * - * @par Used with - * nua_create() \n - * nua_set_params() \n - * nua_get_params() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - S/MIME is Disabled - * - 1 (true) - S/MIME is Enabled - * - * Corresponding tag taking reference parameter is NUTAG_SMIME_ENABLE_REF(). - */ -tag_typedef_t nutag_smime_enable = BOOLTAG_TYPEDEF(smime_enable); - -/**@def NUTAG_SMIME_ENABLE_REF(x) - * Reference tag for NUTAG_SMIME_ENABLE(). - */ - - -/**@def NUTAG_SMIME_OPT(x) - * - * 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 - * - -1 (SM_ID_NULL) No security service needed - * - 0 (SM_ID_CLEAR_SIGN) Clear signing - * - 1 (SM_ID_SIGN) S/MIME signing - * - 2 (SM_ID_ENCRYPT) S/MIME encryption - * - * Corresponding tag taking reference parameter is NUTAG_SMIME_OPT_REF(). - */ -tag_typedef_t nutag_smime_opt = INTTAG_TYPEDEF(smime_opt); - -/**@def NUTAG_SMIME_OPT_REF(x) - * Reference tag for NUTAG_SMIME_OPT(). - */ - - -/**@def NUTAG_SMIME_PROTECTION_MODE(x) - * - * 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 - * - -1 (SM_MODE_NULL) Unspecified - * - 0 (SM_MODE_PAYLOAD_ONLY) SIP payload only - * - 1 (SM_MODE_TUNNEL) SIP tunneling mode - * - 2 (SM_MODE_SIPFRAG) SIPfrag protection - * - * Corresponding tag taking reference parameter is NUTAG_SMIME_PROTECTION_MODE_REF(). - */ -tag_typedef_t nutag_smime_protection_mode = - INTTAG_TYPEDEF(smime_protection_mode); - -/**@def NUTAG_SMIME_PROTECTION_MODE_REF(x) - * Reference tag for NUTAG_SMIME_PROTECTION_MODE(). - */ - - -/**@def NUTAG_SMIME_MESSAGE_DIGEST(x) - * - * 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(). - */ -tag_typedef_t nutag_smime_message_digest = - STRTAG_TYPEDEF(smime_message_digest); - -/**@def NUTAG_SMIME_MESSAGE_DIGEST_REF(x) - * Reference tag for NUTAG_SMIME_MESSAGE_DIGEST(). - */ - - -/**@def NUTAG_SMIME_SIGNATURE(x) - * - * 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(). - */ -tag_typedef_t nutag_smime_signature = - STRTAG_TYPEDEF(smime_signature); - -/**@def NUTAG_SMIME_SIGNATURE_REF(x) - * Reference tag for NUTAG_SMIME_SIGNATURE(). - */ - - -/**@def NUTAG_SMIME_KEY_ENCRYPTION(x) - * - * 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(). - */ -tag_typedef_t nutag_smime_key_encryption = - STRTAG_TYPEDEF(smime_key_encryption); - -/**@def NUTAG_SMIME_KEY_ENCRYPTION_REF(x) - * Reference tag for NUTAG_SMIME_KEY_ENCRYPTION(). - */ - - -/**@def NUTAG_SMIME_MESSAGE_ENCRYPTION(x) - * - * 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(). - */ -tag_typedef_t nutag_smime_message_encryption = - STRTAG_TYPEDEF(smime_message_encryption); - -/**@def NUTAG_SMIME_MESSAGE_ENCRYPTION_REF(x) - * Reference tag for NUTAG_SMIME_MESSAGE_ENCRYPTION(). - */ - - -/**@def NUTAG_SIPS_URL(x) - * - * 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(). - */ -tag_typedef_t nutag_sips_url = URLTAG_TYPEDEF(sips_url); - -/**@def NUTAG_SIPS_URL_REF(x) - * Reference tag for NUTAG_SIPS_URL(). - */ - -/**@def NUTAG_WS_URL(x) - * - * Local WS url. - * - * The application can specify an alternative local address for - * NUA user agent engine. Usually the alternative address is a - * SIP URI (WS) used with websocket transport. - * - * @par Used with - * nua_create() - * - * @par Parameter type - * char const * - * - * @par Values - * - * Corresponding tag taking reference parameter is NUTAG_WS_URL_REF(). - */ -tag_typedef_t nutag_ws_url = URLTAG_TYPEDEF(ws_url); - -/**@def NUTAG_WS_URL_REF(x) - * Reference tag for NUTAG_WS_URL(). - */ - - -/**@def NUTAG_WSS_URL(x) - * - * Local WSS url. - * - * The application can specify an alternative local address for - * NUA user agent engine. Usually the alternative address is a - * secure SIP URI (WSS) used with secure websocket transport. - * - * @par Used with - * nua_create() - * - * @par Parameter type - * char const * - * - * @par Values - * - * Corresponding tag taking reference parameter is NUTAG_WSS_URL_REF(). - */ -tag_typedef_t nutag_wss_url = URLTAG_TYPEDEF(wss_url); - -/**@def NUTAG_WSS_URL_REF(x) - * Reference tag for NUTAG_WSS_URL(). - */ - - -/**@def NUTAG_CERTIFICATE_DIR(x) - * - * 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(). - */ -tag_typedef_t nutag_certificate_dir = STRTAG_TYPEDEF(certificate_dir); - -/**@def NUTAG_CERTIFICATE_DIR_REF(x) - * Reference tag for NUTAG_CERTIFICATE_DIR(). - */ - - -/**@def NUTAG_CERTIFICATE_PHRASE(x) - * - * 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(). - */ -tag_typedef_t nutag_certificate_phrase = STRTAG_TYPEDEF(certificate_phrase); - -/**@def NUTAG_CERTIFICATE_PHRASE_REF(x) - * Reference tag for NUTAG_CERTIFICATE_PHRASE(). - */ - -extern msg_hclass_t sip_route_class[]; - -/**@def NUTAG_INITIAL_ROUTE(x) - * - * Specify initial route set. - * - * The initial route set is used instead or or in addition to the outbound - * proxy URL given by NUTAG_PROXY(). The NUTAG_INITIAL_ROUTE() accepts a - * list of parsed @Route header structures, NUTAG_INITIAL_ROUTE_STR() an - * unparsed string. - * - * If a tag list contains multiple NUTAG_INITIAL_ROUTE() or - * NUTAG_INITIAL_ROUTE_STR() tags, the route set is constructed from them - * all. - * - * The initial route is inserted into request message before the route - * entries set with SIPTAG_ROUTE() or SIPTAG_ROUTE_STR(). - * - * @par Used with - * nua_set_params() \n - * nua_set_hparams() \n - * any handle-specific nua call - * - * @par Parameter type - * sip_route_t const * - * - * @par Values - * Linked list of #sip_route_t structures - * - * Corresponding tag taking reference parameter is NUTAG_INITIAL_ROUTE_REF(). - * - * @NEW_1_12_7. - */ -tag_typedef_t nutag_initial_route = SIPEXTHDRTAG_TYPEDEF(initial_route, route); - -/**@def NUTAG_INITIAL_ROUTE_REF(x) - * Reference tag for NUTAG_INITIAL_ROUTE(). - */ - - -/**@def NUTAG_INITIAL_ROUTE_STR(x) - * - * Specify initial route set. - * - * The initial route set is used instead or or in addition to the outbound - * proxy URL given by NUTAG_PROXY(). The NUTAG_INITIAL_ROUTE() accepts a - * list of parsed @Route header structures, NUTAG_INITIAL_ROUTE_STR() a - * unparsed string containing route URIs, quoted with <> and separated by - * commas. - * - * Please note that the syntax requires <> around the @Route URIs if they - * contain parameters, e.g., "lr". - * - * If a tag list contains multiple NUTAG_INITIAL_ROUTE() or - * NUTAG_INITIAL_ROUTE_STR() tags, the route set is constructed from them - * all. - * - * The initial route set can be reset with NUTAG_INITIAL_ROUTE(NULL). - * - * If a tag list of a request contains SIPTAG_ROUTE() or - * SIPTAG_ROUTE_STR() tags, the resulting route set will contain first the - * initial route entries followed by the route URIs given with the - * SIPTAG_ROUTE()/SIPTAG_ROUTE_STR() tags. - * - * @par Used with - * nua_set_params() \n - * nua_set_hparams() \n - * any handle-specific nua call - * - * @par Parameter type - * sip_route_t const * - * - * @par Values - * Linked list of #sip_route_t structures - * - * Corresponding tag taking reference parameter is NUTAG_INITIAL_ROUTE_STR_REF(). - * - * @NEW_1_12_7. - */ -tag_typedef_t nutag_initial_route_str = STRTAG_TYPEDEF(inital_route_str); - -/**@def NUTAG_INITIAL_ROUTE_STR_REF(x) - * Reference tag for NUTAG_INITIAL_ROUTE_STR(). - */ - - -/**@def NUTAG_REGISTRAR(x) - * - * 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(). - */ -tag_typedef_t nutag_registrar = URLTAG_TYPEDEF(registrar); - -/**@def NUTAG_REGISTRAR_REF(x) - * Reference tag for NUTAG_REGISTRAR(). - */ - - -/**@def NUTAG_IDENTITY(x) - * - * 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(). - */ -tag_typedef_t nutag_identity = PTRTAG_TYPEDEF(identity); - -/**@def NUTAG_IDENTITY_REF(x) - * Reference tag for NUTAG_IDENTITY(). - */ - - -/**@def NUTAG_M_DISPLAY(x) - * - * Display name for @Contact. - * - * Specify display name for the Contact header URI generated for - * registration request and dialog-creating requests/responses. - * - * Note that the display name is not included the request-URI when proxy - * forwards the request towards the user-agent. - * - * @par Used with - * nua_register(), nua_set_hparams(), nua_set_params(). - * nua_invite(), nua_respond(), nua_subscribe(), nua_notify() - * - * @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. - */ -tag_typedef_t nutag_m_display = STRTAG_TYPEDEF(m_display); - -/**@def NUTAG_M_DISPLAY_REF(x) - * Reference tag for NUTAG_M_DISPLAY(). - */ - - -/**@def NUTAG_M_USERNAME(x) - * - * 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(). - * nua_invite(), nua_respond(), nua_subscribe(), nua_notify() - * - * @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. - */ -tag_typedef_t nutag_m_username = STRTAG_TYPEDEF(m_username); - -/**@def NUTAG_M_USERNAME_REF(x) - * Reference tag for NUTAG_M_USERNAME(). - */ - - -/**@def NUTAG_M_PARAMS(x) - * - * 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(), - * nua_invite(), nua_respond(), nua_subscribe(), nua_notify() - * - * @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. - */ -tag_typedef_t nutag_m_params = STRTAG_TYPEDEF(m_params); - -/**@def NUTAG_M_PARAMS_REF(x) - * Reference tag for NUTAG_M_PARAMS(). - */ - - -/**@def NUTAG_M_FEATURES(x) - * - * Header parameters for @Contact used in registration. - * - * 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. - */ -tag_typedef_t nutag_m_features = STRTAG_TYPEDEF(m_features); - -/**@def NUTAG_M_FEATURES_REF(x) - * Reference tag for NUTAG_M_FEATURES(). - */ - - -/**@def NUTAG_INSTANCE(x) - * - * 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(). - */ -tag_typedef_t nutag_instance = STRTAG_TYPEDEF(instance); - -/**@def NUTAG_INSTANCE_REF(x) - * Reference tag for NUTAG_INSTANCE(). - */ - - -/**@def NUTAG_OUTBOUND(x) - * - * 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 contact from REGISTER response - * - "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"). - * - * An empty string can be passed to let the stack choose the - * default values for outbound usage (in the 1.12.5 release, the - * defaults are: "gruuize no-outbound validate use-port 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(). - */ -tag_typedef_t nutag_outbound = STRTAG_TYPEDEF(outbound); - -/**@def NUTAG_OUTBOUND_REF(x) - * Reference tag for NUTAG_OUTBOUND(). - */ - - -/*#@def NUTAG_OUTBOUND_SET1(x) - * - * 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(). - */ -tag_typedef_t nutag_outbound_set1 = STRTAG_TYPEDEF(outbound_set1); - -/*#@def NUTAG_OUTBOUND_SET1_REF(x) - * Reference tag for NUTAG_OUTBOUND_SET1(). - */ - - -/*#@def NUTAG_OUTBOUND_SET2(x) - * - * 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(). - */ -tag_typedef_t nutag_outbound_set2 = STRTAG_TYPEDEF(outbound_set2); - -/*#@def NUTAG_OUTBOUND_SET2_REF(x) - * Reference tag for NUTAG_OUTBOUND_SET2(). - */ - - -/*#@def NUTAG_OUTBOUND_SET3(x) - * - * 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(). - */ -tag_typedef_t nutag_outbound_set3 = STRTAG_TYPEDEF(outbound_set3); - -/*#@def NUTAG_OUTBOUND_SET3_REF(x) - * Reference tag for NUTAG_OUTBOUND_SET3(). - */ - - -/*#@def NUTAG_OUTBOUND_SET4(x) - * - * 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(). - */ -tag_typedef_t nutag_outbound_set4 = STRTAG_TYPEDEF(outbound_set4); - -/*#@def NUTAG_OUTBOUND_SET4_REF(x) - * Reference tag for NUTAG_OUTBOUND_SET4(). - */ - - - -/**@def NUTAG_KEEPALIVE(x) - * - * Keepalive interval in milliseconds. - * - * This setting applies to OPTIONS/STUN keepalives. See documentation - * for nua_register() for more detailed information. - * - * @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(). - */ -tag_typedef_t nutag_keepalive = UINTTAG_TYPEDEF(keepalive); - -/**@def NUTAG_KEEPALIVE_REF(x) - * Reference tag for NUTAG_KEEPALIVE(). - */ - - -/**@def NUTAG_KEEPALIVE_STREAM(x) - * - * Transport-level keepalive interval for streams. - * - * See documentation for nua_register() for more detailed information. - * - * @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. - */ -tag_typedef_t nutag_keepalive_stream = UINTTAG_TYPEDEF(keepalive_stream); - -/**@def NUTAG_KEEPALIVE_STREAM_REF(x) - * Reference tag for NUTAG_KEEPALIVE_STREAM(). - */ - - - -/**@def NUTAG_USE_DIALOG(x) - * - * Ask NUA to create dialog for this handle - * - * @par Used with nua calls that send a SIP request - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - do not create a dialog - * - 1 (true) - store dialog info - * - * Corresponding tag taking reference parameter is NUTAG_USE_DIALOG_REF(). - */ -tag_typedef_t nutag_use_dialog = BOOLTAG_TYPEDEF(use_dialog); - -/**@def NUTAG_USE_DIALOG_REF(x) - * Reference tag for NUTAG_USE_DIALOG(). - */ - - -/**@def NUTAG_AUTH(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(). - */ -tag_typedef_t nutag_auth = STRTAG_TYPEDEF(auth); - -/**@def NUTAG_AUTH_REF(x) - * Reference tag for NUTAG_AUTH(). - */ - - -/**@def NUTAG_AUTHTIME(x) - * - * Lifetime of authentication data in seconds. - * - * @par Used with - * Currently not processed by NUA - * - * @par Parameter type - * unsigned int - * - * @par Values - * - 0 (zero) - Use authentication data only for this handle - * - nonzero - Lifetime of authentication data in seconds - * - * @todo - * - * Corresponding tag taking reference parameter is NUTAG_AUTHTIME_REF(). - */ -tag_typedef_t nutag_authtime = INTTAG_TYPEDEF(authtime); - -/**@def NUTAG_AUTHTIME_REF(x) - * Reference tag for NUTAG_AUTHTIME(). - */ - - - -/**@def NUTAG_EVENT(x) - * - * NUA event. - * - * @deprecated - * - * @par Parameter type - * enum nua_event_e - * - * @par Values - * - * Corresponding tag taking reference parameter is NUTAG_EVENT_REF(). - */ -tag_typedef_t nutag_event = INTTAG_TYPEDEF(event); - -/**@def NUTAG_EVENT_REF(x) - * Reference tag for NUTAG_EVENT(). - */ - - -/**@def NUTAG_STATUS(x) - * - * Response status code - * - * @deprecated - * - * @par Parameter type - * unsigned int - * - * @par Values - * - 100 - preliminary response, request is being processed by next hop - * - 1XX - preliminary response, request is being processed by UAS - * - 2XX - successful final response - * - 3XX - redirection error response - * - 4XX - client error response - * - 5XX - server error response - * - 6XX - global error response - * - * Corresponding tag taking reference parameter is NUTAG_STATUS_REF(). - */ -tag_typedef_t nutag_status = INTTAG_TYPEDEF(status); - -/**@def NUTAG_STATUS_REF(x) - * Reference tag for NUTAG_STATUS(). - */ - - -/**@def NUTAG_PHRASE(x) - * - * Response phrase - * - * @deprecated - * - * @par Parameter type - * char const * - * - * @par Values. - * - * Corresponding tag taking reference parameter is NUTAG_PHRASE_REF(). - */ -tag_typedef_t nutag_phrase = STRTAG_TYPEDEF(phrase); - -/**@def NUTAG_PHRASE_REF(x) - * Reference tag for NUTAG_PHRASE(). - */ - - -/**@def NUTAG_HANDLE(x) - * - * NUA Handle - * - * @deprecated - * - * @par Parameter type - * nua_handle_t * - * - * @par Values - * - * Corresponding tag taking reference parameter is NUTAG_HANDLE_REF(). - */ -tag_typedef_t nutag_handle = PTRTAG_TYPEDEF(handle); - -/**@def NUTAG_HANDLE_REF(x) - * Reference tag for NUTAG_HANDLE(). - */ - - -/**@def NUTAG_NOTIFY_REFER(x) - * - * 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(). - */ -tag_typedef_t nutag_notify_refer = PTRTAG_TYPEDEF(notify_refer); - -/**@def NUTAG_NOTIFY_REFER_REF(x) - * Reference tag for NUTAG_NOTIFY_REFER(). - */ - -/**@def NUTAG_REFER_EVENT(x) - * - * 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(). - */ -tag_typedef_t nutag_refer_event = SIPHDRTAG_NAMED_TYPEDEF(refer_event, event); - -/**@def NUTAG_REFER_EVENT_REF(x) - * Reference tag for NUTAG_REFER_EVENT(). - */ - - -/**@def NUTAG_REFER_PAUSE() - * - * 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 (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - do not pause referring call - * - 1 (true) - pause referring call - * - * Corresponding tag taking reference parameter is NUTAG_REFER_PAUSE_REF(). - * - * @deprecated Not implemented. - */ -tag_typedef_t nutag_refer_pause = BOOLTAG_TYPEDEF(refer_pause); - -/**@def NUTAG_REFER_PAUSE_REF(x) - * Reference tag for NUTAG_REFER_PAUSE(). - */ - - -/**@def NUTAG_USER_AGENT() - * - * 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(). - */ -tag_typedef_t nutag_user_agent = STRTAG_TYPEDEF(user_agent); - -/**@def NUTAG_USER_AGENT_REF(x) - * Reference tag for NUTAG_USER_AGENT(). - */ - - -/**@def NUTAG_VIA() - * - * Via string. - * - * Indicate the Via header used by the stack. - * - * @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 - * - * Corresponding tag taking reference parameter is NUTAG_VIA_REF(). - */ -tag_typedef_t nutag_via = STRTAG_TYPEDEF(via); - -/**@def NUTAG_VIA_REF(x) - * Reference tag for NUTAG_VIA(). - */ - -/**@def NUTAG_ALLOW() - * - * 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 405 - * Method Not Allowed 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(). - */ -tag_typedef_t nutag_allow = STRTAG_TYPEDEF(allow); - -/**@def NUTAG_ALLOW_REF(x) - * Reference tag for NUTAG_ALLOW(). - */ - - -/**@def NUTAG_ALLOW_EVENTS() - * - * 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 489 Bad Event 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(). - */ -tag_typedef_t nutag_allow_events = STRTAG_TYPEDEF(allow_events); - -/**@def NUTAG_ALLOW_EVENTS_REF(x) - * Reference tag for NUTAG_ALLOW_EVENTS(). - */ - - -/**@def NUTAG_APPL_METHOD() - * - * 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. Handling of client-side PRACK and - * UPDATE was fixed in @VERSION_1_12_6. - */ -tag_typedef_t nutag_appl_method = STRTAG_TYPEDEF(appl_method); - -/**@def NUTAG_APPL_METHOD_REF(x) - * Reference tag for NUTAG_APPL_METHOD(). - */ - - -/**@def NUTAG_SUPPORTED() - * - * 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 - * 420 Bad Extension 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. - */ -tag_typedef_t nutag_supported = STRTAG_TYPEDEF(supported); - -/**@def NUTAG_SUPPORTED_REF(x) - * Reference tag for NUTAG_SUPPORTED(). - */ - - -/**@def NUTAG_PATH_ENABLE(x) - * - * If true, add "path" to @Supported in REGISTER. - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_register() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Do not include "path" to @Supported header - * - 1 (true) - Include "path" to @Supported header - * - * @sa NUTAG_SERVICE_ROUTE_ENABLE(), NUTAG_SUPPORTED(), - * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(), @RFC3327 - * "SIP Extension Header Field for Registering Non-Adjacent Contacts", - * D. Willis, B. Hoeneisen, - * December 2002. - */ -tag_typedef_t nutag_path_enable = BOOLTAG_TYPEDEF(path_enable); - -/**@def NUTAG_PATH_ENABLE_REF(x) - * Reference tag for NUTAG_PATH_ENABLE(). - */ - -/**@def NUTAG_RETRY_AFTER_ENABLE(x) - * - * If true, support RFC 3261 Retry-After - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_register() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Do not honor Retry-After - * - 1 (true) - honor Retry-After - * - */ -tag_typedef_t nutag_retry_after_enable = BOOLTAG_TYPEDEF(retry_after_enable); - -/**@def NUTAG_RETRY_AFTER_ENABLE_REF(x) - * Reference tag for NUTAG_RETRY_AFTER_ENABLE(). - */ - - - -/**@def NUTAG_SERVICE_ROUTE_ENABLE(x) - * - * Use route taken from the @ServiceRoute header in the 200 class response - * to REGISTER. - * - * @par Used with - * - nua_create(), nua_set_params(), nua_get_params() - * - nua_handle(), nua_set_hparams(), nua_get_hparams() - * - nua_register() - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - Do not use @ServiceRoute - * - 1 (true) - Use @ServiceRoute - * - * Corresponding tag taking reference parameter is NUTAG_SERVICE_ROUTE_ENABLE_REF(). - * - * @sa NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(), @RFC3608 - * - * @todo - */ -tag_typedef_t nutag_service_route_enable = - BOOLTAG_TYPEDEF(service_route_enable); - -/**@def NUTAG_SERVICE_ROUTE_ENABLE_REF(x) - * Reference tag for NUTAG_SERVICE_ROUTE_ENABLE(). - */ - - -/**@def NUTAG_AUTH_CACHE(x) - * - * Authentication caching policy - * - * @par Used with - * nua_set_params(), nua_set_hparams() \n - * nua_get_params(), nua_get_hparams() \n - * @NUA_HPARAM_CALLS - * - * @par Parameter type - * enum nua_auth_cache - * - * @par Values - * - nua_auth_cache_dialog (0) - include credentials within dialog - * - nua_auth_cache_challenged (1) - include credentials only when - * challenged - * - * Corresponding tag taking reference parameter is NUTAG_AUTH_CACHE_REF(). - * - * @NEW_1_12_6. - */ -tag_typedef_t nutag_auth_cache = INTTAG_TYPEDEF(auth_cache); - -/**@def NUTAG_AUTH_CACHE_REF(x) - * Reference tag for NUTAG_AUTH_CACHE(). - */ - -/**@def NUTAG_AUTO_INVITE_100(x) - */ -tag_typedef_t nutag_auto_invite_100 = INTTAG_TYPEDEF(auto_invite_100); - -/**@def NUTAG_AUTO_INVITE_100(x) - * Reference tag for NUTAG_AUTO_INVITE_100(). - */ - -/**@def NUTAG_DETECT_NETWORK_UPDATES(x) - * - * 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. - */ -tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates); - -/**@def NUTAG_DETECT_NETWORK_UPDATES_REF(x) - * Reference tag for NUTAG_DETECT_NETWORK_UPDATES(). - */ - - -/**@def NUTAG_WITH_THIS(nua) - * - * 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 NUTAG_WITH(), NUTAG_WITH_SAVED() - */ - -/**@def NUTAG_WITH(msg) - * - * 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 nua_save_event(), NUTAG_WITH_THIS(), NUTAG_WITH_SAVED() - */ - -/**@def NUTAG_WITH_SAVED(event) - * - * Specify request to respond to. - * - * @par Used with - * nua_respond() - * - * @par Parameter type - * nua_saved_event_t * - * - * @par Values - * Pointer to a saved event. - * - * @NEW_1_12_4. - * - * @sa nua_save_event(), NUTAG_WITH(), NUTAG_WITH_THIS() - */ - -tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with); - - -/**@def NUTAG_DIALOG(x) - * - * An (extension) method is used to create dialog or refresh target. - * - * @par Used with - * nua_method() - * - * @par Parameter type - * unsigned int (0, 1, 2) - * - * @par Values - * - 0 if dialog target is not refreshed - * - 1 if dialog target is refreshed - * - > 1 if dialog is to be created - * - * @NEW_1_12_6. - * - * @sa nua_method(), #nua_i_method - */ -tag_typedef_t nutag_dialog = UINTTAG_TYPEDEF(dialog); - - -/**@def NUTAG_PROXY(x) - * - * Outbound proxy URL. - * - * Same tag as NTATAG_DEFAULT_PROXY() - * - * @par Used with - * nua_set_params() \n - * nua_get_params() \n - * nua_create() - * @note - * Since @VERSION_1_12_9, NUTAG_PROXY()/NTATAG_DEFAULT_PROXY() can be used - * to set handle-specific outbound route. The route is set with \n - * nua_set_hparams(), \n - * nua_invite(), nua_prack(), nua_ack(), nua_update(), nua_respond(), \n - * nua_info(), nua_cancel(), nua_bye(), \n - * nua_register(), nua_unregister(), nua_publish(), nua_unpublish(), \n - * nua_subscribe(), nua_unsubscribe(), nua_refer(), nua_notify(), \n - * nua_options(), nua_message(), nua_method() - * - * @par Parameter type - * url_string_t const * (either char const * or url_t *) - * - * @par Values - * NULL implies routing based on request-URI or Route header. - * Non-NULL is used as invisible routing URI, ie., routing URI that is - * not included in the request. - * - * Corresponding tag taking reference parameter is NUTAG_PROXY_REF(). - */ - -/**@def NUTAG_PROXY_REF(x) - * Reference tag for NUTAG_PROXY(). - */ - -/**@def NUTAG_SIP_PARSER(x) - * - * Pointer to SIP parser structure - * - * @par Used with - * nua_create() - * - * @par Parameter type - * msg_mclass_t const * - * - * @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(). - */ - -/**@def NUTAG_SIP_PARSER_REF(x) - * Reference tag for NUTAG_SIP_PARSER(). - */ - - -/**@def NUTAG_SHUTDOWN_EVENTS(x) - * - * Allow passing of normal events when stack is being shut down. - * - * By default, only #nua_r_shutdown events are passed to application after - * calling nua_shutdown(). If application is interested in nua events during - * shutdown, it should give NUTAG_SHUTDOWN_EVENTS(1) to nua_create() or - * nua_set_params() called before nua_shutdown(). - * - * @par Used with - * nua_create(), nua_set_params(). - * - * @par Parameter type - * int (boolean: nonzero is true, zero is false) - * - * @par Values - * - 0 (false) - pass only #nua_r_shutdown events to application during shutdown - * - 1 (true) - pass all events to application during shutdown - * - * Corresponding tag taking reference parameter is NUTAG_SHUTDOWN_EVENTS_REF(). - * - * @sa nua_shutdown(), nua_destroy(). - * - * @NEW_1_12_9. - */ -tag_typedef_t nutag_shutdown_events = BOOLTAG_TYPEDEF(shutdown_events); - -/**@def NUTAG_SHUTDOWN_EVENTS_REF(x) - * Reference tag for NUTAG_SHUTDOWN_EVENTS(). - */ - - -/* ---------------------------------------------------------------------- */ - -tag_typedef_t nutag_soa_session = PTRTAG_TYPEDEF(soa_session); -tag_typedef_t nutag_hold = BOOLTAG_TYPEDEF(hold); -tag_typedef_t nutag_address = STRTAG_TYPEDEF(address); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_types.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_types.h deleted file mode 100644 index 18fb05a625..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_types.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2008 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_TYPES_H -/** Defined when has been included. */ -#define NUA_TYPES_H - -/**@internal @file nua_types.h - * @brief Internal types for nua. - * - * @author Pekka Pessi - */ - -typedef struct nua_handle_preferences nua_handle_preferences_t; -typedef struct nua_global_preferences nua_global_preferences_t; - -#ifndef NUA_OWNER_T -#define NUA_OWNER_T struct nua_owner_s -#endif -typedef NUA_OWNER_T nua_owner_t; - -typedef struct nua_dialog_state nua_dialog_state_t; -typedef struct nua_dialog_usage nua_dialog_usage_t; -typedef struct nua_server_request nua_server_request_t; -typedef struct nua_client_request nua_client_request_t; -typedef struct nua_dialog_peer_info nua_dialog_peer_info_t; - -#ifndef NUA_SAVED_SIGNAL_T -#define NUA_SAVED_SIGNAL_T struct nua_saved_signal * -#endif - -typedef NUA_SAVED_SIGNAL_T nua_saved_signal_t; - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c b/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c deleted file mode 100644 index ff3d20591d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c +++ /dev/null @@ -1,1291 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * @author Martti Mela - * - * @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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SU_LOG (nua_log) -#include - -#include -#include -#include -#include -#include - -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 */ - signed okeepalive:2; /**< 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; - - /* The registration state machine. */ - /** Initial REGISTER containing ob_rcontact has been sent */ - unsigned ob_registering:1; - /** 2XX response to REGISTER containing 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 ob_proxy_override:1; /**< Override stack default proxy */ - unsigned :0; - - url_string_t *ob_proxy; /**< Outbound-specific proxy */ - char const *ob_instance; /**< Our instance ID */ - int32_t ob_reg_id; /**< Flow-id */ - 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_sprintf(ob->ob_home, "+sip.instance=\"<%s>\"", instance); - ob->ob_reg_id = 0; - - outbound_peer_info(ob, NULL); - - /* Generate a random 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 - -/** 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 *s, *options = su_strdup(NULL, _options); - int invalid; - - prefs->interval = interval; - prefs->stream_interval = stream_interval; - -#define MATCH(v) (len == sizeof(#v) - 1 && su_casenmatch(#v, s, len)) - - if (options) { - for (s = options; s[0]; s++) if (s[0] == '-') s[0] = '_'; - } - - prefs->gruuize = 1; - prefs->outbound = 0; - prefs->natify = 1; - prefs->okeepalive = -1; - prefs->validate = 1; - prefs->use_rport = 1; - - for (s = options; s && s[0]; ) { - size_t len = span_token(s); - int value = 1; - - if (len > 3 && su_casenmatch(s, "no_", 3)) - value = 0, s += 3, len -= 3; - else if (len > 4 && su_casenmatch(s, "not_", 4)) - 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(use_connect)) prefs->use_connect = value; - else if (MATCH(use_rport)) prefs->use_rport = value; - else if (MATCH(use_socks)) prefs->use_socks = value; - else if (MATCH(use_upnp)) prefs->use_upnp = value; - else if (MATCH(use_stun)) prefs->use_stun = value; - else - SU_DEBUG_1(("outbound(%p): unknown option \"%.*s\"\n", - (void *)ob->ob_owner, (int)len, s)); - - s += len; - len = strspn(s, " \t\n\r,;"); - if (len == 0) - break; - s += len; - } - - invalid = s && s[0]; - if (invalid) - SU_DEBUG_1(("outbound(%p): invalid options \"%s\"\n", - (void *)ob->ob_owner, options)); - su_free(NULL, options); - if (invalid) - 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", - (void *)ob->ob_owner)); - } - - ob->ob_prefs = *prefs; - ob->ob_reg_id = prefs->outbound ? 1 : 0; - - return 0; -} - -/** Override stack default proxy for outbound */ -int outbound_set_proxy(outbound_t *ob, - url_string_t *proxy) -{ - url_string_t *new_proxy = NULL, *old_proxy = ob->ob_proxy; - - if (proxy) - new_proxy = (url_string_t *)url_as_string(ob->ob_home, proxy->us_url); - - if (proxy == NULL || new_proxy != NULL) { - ob->ob_proxy_override = 1; - ob->ob_proxy = new_proxy; - su_free(ob->ob_home, old_proxy); - return 0; - } - - return -1; -} - -/* ---------------------------------------------------------------------- */ - -/** Obtain contacts for REGISTER */ -int outbound_get_contacts(outbound_t *ob, - sip_contact_t **return_current_contact, - sip_contact_t **return_previous_contact) -{ - if (ob) { - if (ob->ob_contacts) - *return_current_contact = ob->ob_rcontact; - *return_previous_contact = ob->ob_previous; - } - return 0; -} - -/** REGISTER request has been sent */ -int outbound_start_registering(outbound_t *ob) -{ - if (ob) - ob->ob_registering = 1; - return 0; -} - -/** 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; - - if (terminating) { - ob->ob_registering = ob->ob_registered = 0; - return 0; /* Cleanup is done separately */ - } - - if (!response || !request) - return 0; - - assert(request->sip_request); assert(response->sip_status); - - status = response->sip_status->st_status; - - if (status < 300) { - if (request->sip_contact && response->sip_contact) { - if (ob->ob_rcontact != NULL) - msg_header_free(ob->ob_home, (msg_header_t *)ob->ob_rcontact); - ob->ob_rcontact = sip_contact_dup(ob->ob_home, request->sip_contact); - ob->ob_registered = ob->ob_registering; - } else - ob->ob_registered = 0; - } - - reregister = outbound_check_for_nat(ob, request, response); - if (reregister) - return reregister; - - if (ob->ob_previous && status < 300) { - 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. - * - * @retval -1 upon an error - * @retval #ob_register_ok (0) if the registration was OK - * @retval #ob_reregister (1) if client needs to re-register - * @retval #ob_reregister_now (2) if client needs to re-register immediately - */ -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 ob_reregister; - } - else if (ob->ob_upnp) { - /* Use UPnP */ - return ob_reregister; - } - else { - if (outbound_contacts_from_via(ob, response->sip_via) < 0) - return -1; - } - - return ob_reregister_now; - } - - 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", - (void *)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 && su_casematch(rport, nat_port)) - return 1; - if (!v->v_rport || !v->v_rport[0]) - return 1; - } - - if (!nat_detected) { - SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n", - (void *)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_5(("outbound(%p): NAT binding changed: " - "[%s]:%s != [%s]:%s\n", - (void *)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, "pub-gruu="); - - if (gruu == NULL || gruu[0] == '\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 int process_response_to_keepalive_options(outbound_t *ob, - nta_outgoing_t *orq, - sip_t const *sip, - int status, - char const *phrase); - -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, udp; - - if (!ob) - return; - - udp = ob->ob_via && ob->ob_via->v_protocol == sip_transport_udp; - - if (/* ob->ob_prefs.natify && */ - /* On UDP, use OPTIONS keepalive by default */ - (udp ? ob->ob_prefs.okeepalive != 0 - /* Otherwise, only if requested */ - : ob->ob_prefs.okeepalive > 0)) - interval = ob->ob_prefs.interval; - need_to_validate = ob->ob_prefs.validate && !ob->ob_validated; - - if (!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) { - su_duration_t max_defer; - - max_defer = su_root_get_max_defer(ob->ob_root); - if ((su_duration_t)interval >= max_defer) { - interval -= max_defer - 100; - } - - ob->ob_keepalive.timer = - su_timer_create(su_root_task(ob->ob_root), interval); - - su_timer_deferrable(ob->ob_keepalive.timer, 1); - } - - 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_contact_t *m = ob->ob_rcontact; - - unsigned d = ob->ob_keepalive.interval; - - if (msg == NULL) - return -1; - - assert(regsip); assert(regsip->sip_request); - - if (m && m->m_params) { - sip_accept_contact_t *ac; - size_t i; - int features = 0; - - ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit"); - - for (i = 0; m->m_params[i]; i++) { - char const *s = m->m_params[i]; - if (!sip_is_callerpref(s)) - continue; - features++; - s = su_strdup(msg_home(msg), s); - msg_header_add_param(msg_home(msg), ac->cp_common, s); - } - - if (features) - msg_header_insert(msg, NULL, (void *)ac); - else - msg_header_free(msg_home(msg), (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_IF(ob->ob_proxy_override, - NTATAG_DEFAULT_PROXY(ob->ob_proxy)), - 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; - - 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) { - if (orq == ob->ob_keepalive.orq) - ob->ob_keepalive.orq = NULL; - process_response_to_keepalive_options(ob, orq, sip, status, phrase); - nta_outgoing_destroy(orq); - } - - return 0; -} - -static int process_response_to_keepalive_options(outbound_t *ob, - nta_outgoing_t *orq, - sip_t const *sip, - int status, - char const *phrase) -{ - 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 == NULL) { - SU_DEBUG_3(("outbound(%p): keepalive %u %s\n", (void *)ob->ob_owner, - status, phrase)); - ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END()); - 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 (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; - - if (loglevel >= SU_LOG->log_level) { - sip_contact_t const *m = ob->ob_rcontact; - - if (m) - su_llog(SU_LOG, loglevel, - "outbound(%p): %s <" URL_PRINT_FORMAT ">\n", - (void *)ob->ob_owner, - failed ? "FAILED to validate" : "validated", - URL_PRINT_ARGS(m->m_url)); - else - su_llog(SU_LOG, loglevel, - "outbound(%p): %s registration\n", - (void *)ob->ob_owner, - failed ? "FAILED to validate" : "validated"); - - if (failed) - su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n", - (void *)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_3(("outbound(%p): keepalive timeout\n", (void *)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, - TAG_IF(ob->ob_proxy_override, - NTATAG_DEFAULT_PROXY(ob->ob_proxy)), - 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 && - su_casematch(sip->sip_accept->ac_type, outbound_content_type); -} - -/** 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_5(("outbound(%p): registration check OPTIONS received\n", - (void *)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; - 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, 1, - 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, 0, - v, v->v_protocol, - ob->ob_instance, reg_id_param, NULL); - - 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_registered - /* && (ob->ob_reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported) - * XXX - multiple connections not yet 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_by_stack && application_contact == NULL) - return 0; - - if (ob->ob_contacts) - previous = ob->ob_rcontact; - } - else if (application_contact) { - rcontact = sip_contact_dup(home, 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 (ob->ob_by_stack) { - return 0; /* Xyzzy - nothing happens */ - } - 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, 1, - 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, 0, - v, v->v_protocol, - 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_contacts = rcontact != 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; -} - -sip_contact_t const *outbound_dialog_gruu(outbound_t const *ob) -{ - return ob ? ob->ob_gruu : NULL; -} - -/* ---------------------------------------------------------------------- */ - - -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 (enum outbound_feature)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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h b/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h deleted file mode 100644 index 2a239c5b29..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define OUTBOUND_H -/**@IFILE outbound.h - * - * @brief Interface to SIP NAT traversal and outbound - * - * @author Pekka Pessi - * - * @date Created: Wed May 10 12:01:38 EEST 2006 ppessi - */ - -#ifndef SU_CONFIG_H -#include -#endif -#ifndef NTA_H -#include -#endif -#ifndef AUTH_CLIENT_H -#include -#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_proxy(outbound_t *ob, - url_string_t *proxy); - -int outbound_get_contacts(outbound_t *ob, - sip_contact_t **return_current_contact, - sip_contact_t **return_previous_contact); - -int outbound_start_registering(outbound_t *ob); - -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); - -sip_contact_t const *outbound_dialog_gruu(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, - int used_in_dialog, - 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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h deleted file mode 100644 index 5a698359cb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h +++ /dev/null @@ -1,405 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Feb 14 17:09:44 2001 ppessi - */ - -#ifndef NUA_H -/** Defined when has been included. */ -#define NUA_H - -#ifndef SU_WAIT_H -#include -#endif - - -#ifndef URL_H -#include -#endif - -#ifndef SIP_H -#include -#endif - -#ifndef NTA_H -#include -#endif - -#ifndef NUA_TAG_H -#include -#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 of NUA event callback. */ -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); - -/** Return name of subscription state. @NEW_1_12_5. */ -SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate); - -/** Convert string to enum nua_substate. @NEW_1_12_5. */ -SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate); - -/** 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, ...); - -/** Send a request message with an extension method. */ -SOFIAPUBFUN void nua_method(nua_handle_t *, tag_type_t, tag_value_t, ...); - -/** Respond to a request with given status code and phrase. */ -SOFIAPUBFUN void nua_respond(nua_handle_t *nh, - int status, char const *phrase, - tag_type_t, tag_value_t, - ...); - -/** Check if event can be responded with nua_respond() */ -SOFIAPUBFUN int nua_event_is_incoming_request(nua_event_t e); - -/** Cast a #nua_handle_t pointer to a #su_home_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); - -nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id); - -SOFIAPUBFUN const nta_leg_t *nua_get_dialog_state_leg(nua_handle_t *nh); -SOFIAPUBFUN su_home_t *nua_handle_get_home(nua_handle_t *nh); -SOFIAPUBFUN void nua_unref(nua_t *nua); -SOFIAPUBFUN su_home_t *nua_get_home(nua_t *nua); -SOFIAPUBFUN nta_agent_t *nua_get_agent(nua_t *nua); -SOFIAPUBFUN void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val); -SOFIAPUBFUN unsigned nua_handle_is_destroyed(nua_handle_t *nh); -SOFIAPUBFUN void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh, - unsigned min, unsigned max); - -SOFIA_END_DECLS - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h deleted file mode 100644 index 3a3f96e02b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h +++ /dev/null @@ -1,684 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define NUA_TAG_H - -/**@file sofia-sip/nua_tag.h - * @brief Tags for Sofia-SIP User Agent Library - * - * @author Pekka Pessi - * @author Martti Mela - * - * @date Created: Mon Feb 19 18:54:26 EET 2001 ppessi - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SDP_TAG_H -#include -#endif -#ifndef URL_TAG_H -#include -#endif -#ifndef SIP_TAG_H -#include -#endif -#ifndef NTA_TAG_H -#include -#endif -#ifndef NEA_TAG_H -#include -#endif -#ifndef SOA_TAG_H -#include -#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; - -#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; - -#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; - -#define NUTAG_WITH(x) nutag_with, tag_ptr_v(x) -SOFIAPUBVAR tag_typedef_t nutag_with; - -#define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua))) -#define NUTAG_WITH_CURRENT(nua) \ - nutag_with, tag_ptr_v(nua_current_request((nua))) -#define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e))) - -#define NUTAG_DIALOG(b) nutag_dialog, tag_uint_v((b)) -SOFIAPUBVAR tag_typedef_t nutag_dialog; - -#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; - -#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; - -#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; - -#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() */ - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -/** Enumeration type of NUTAG_SESSION_REFRESHER(). */ -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). */ -}; - -#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; - -#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; - -#define NUTAG_REFRESH_WITHOUT_SDP(x) nutag_refresh_without_sdp, tag_bool_v((x)) -SOFIAPUBVAR tag_typedef_t nutag_refresh_without_sdp; -#define NUTAG_REFRESH_WITHOUT_SDP_REF(x) \ - nutag_refresh_without_sdp_ref, tag_bool_vr((&(x))) -SOFIAPUBVAR tag_typedef_t nutag_refresh_without_sdp_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; - -#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; - -#define NUTAG_TIMER_AUTOREQUIRE(x) nutag_timer_autorequire, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t nutag_timer_autorequire; -#define NUTAG_TIMER_AUTOREQUIRE_REF(x) nutag_timer_autorequire_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_timer_autorequire_ref; - -#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; - -#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; - -#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; - -#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 */ - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -/* End NRC Boston */ - -#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; - -#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; - -#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; - -#define NUTAG_WS_URL(x) nutag_ws_url, urltag_url_v(x) -SOFIAPUBVAR tag_typedef_t nutag_ws_url; -#define NUTAG_WS_URL_REF(x) nutag_ws_url_ref, urltag_url_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_ws_url_ref; - -#define NUTAG_WSS_URL(x) nutag_wss_url, urltag_url_v(x) -SOFIAPUBVAR tag_typedef_t nutag_wss_url; -#define NUTAG_WSS_URL_REF(x) nutag_wss_url_ref, urltag_url_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_wss_url_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 - -#define NUTAG_INITIAL_ROUTE(x) nutag_initial_route, siptag_route_v(x) -SOFIAPUBVAR tag_typedef_t nutag_initial_route; -#define NUTAG_INITIAL_ROUTE_REF(x) nutag_initial_route_ref, siptag_route_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_initial_route_ref; - -#define NUTAG_INITIAL_ROUTE_STR(x) nutag_initial_route_str, tag_str_v(x) -SOFIAPUBVAR tag_typedef_t nutag_initial_route_str; -#define NUTAG_INITIAL_ROUTE_STR_REF(x) nutag_initial_route_str_ref, tag_str_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_initial_route_str_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; - -#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 - -#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; - -#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; - -#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; - -#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 */ - -#define NUTAG_SIP_PARSER(x) NTATAG_MCLASS(x) -#define NUTAG_SIP_PARSER_REF(x) NTATAG_MCLASS_REF(x) - -#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; - -#define NUTAG_AUTH_CACHE(x) nutag_auth_cache, tag_int_v(x) -SOFIAPUBVAR tag_typedef_t nutag_auth_cache; -#define NUTAG_AUTH_CACHE_REF(x) nutag_auth_cache_ref, tag_int_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_auth_cache_ref; - -/** Authentication caching policy. @NEW_1_12_6. */ -enum nua_auth_cache { - /** Include credentials within dialog (default) */ - nua_auth_cache_dialog = 0, - /** Include credentials only when challenged */ - nua_auth_cache_challenged = 1, - _nua_auth_cache_invalid -}; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#define NUTAG_VIA(x) nutag_via, tag_str_v(x) -SOFIAPUBVAR tag_typedef_t nutag_via; -#define NUTAG_VIA_REF(x) nutag_via_ref, tag_str_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_via_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; - - -#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; - - -#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; - -#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; - -#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); - -#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 */ -}; - -/** Return name of subscription state. @NEW_1_12_5. */ -SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate); - -/** Convert string to enum nua_substate. @NEW_1_12_5. */ -SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate); - -#define NUTAG_SUB_EXPIRES(x) nutag_sub_expires, tag_uint_v(x) -SOFIAPUBVAR tag_typedef_t nutag_sub_expires; -#define NUTAG_SUB_EXPIRES_REF(x) nutag_sub_expires_ref, tag_uint_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_sub_expires_ref; - -#define NUTAG_NEWSUB(x) nutag_newsub, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t nutag_newsub; -#define NUTAG_NEWSUB_REF(x) nutag_newsub_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_newsub_ref; - -#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; - -#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; - -#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; - -#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; - -#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; - -#define NUTAG_RETRY_AFTER_ENABLE(x) nutag_retry_after_enable, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t nutag_retry_after_enable; -#define NUTAG_RETRY_AFTER_ENABLE_REF(x) nutag_retry_after_enable_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_retry_after_enable_ref; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#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; - -#define NUTAG_SHUTDOWN_EVENTS(x) \ - nutag_shutdown_events, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t nutag_shutdown_events; -#define NUTAG_SHUTDOWN_EVENTS_REF(x) \ - nutag_shutdown_events_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_shutdown_events_ref; - -#define NUTAG_AUTO_INVITE_100(x) \ - nutag_auto_invite_100, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100; -#define NUTAG_AUTO_INVITE_100_REF(x) \ - nutag_auto_invite_100_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100_ref; - -/* Pass nua handle as tagged argument */ -#if SU_INLINE_TAG_CAST -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog deleted file mode 100644 index 5274ed3866..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/ChangeLog +++ /dev/null @@ -1,55 +0,0 @@ -2005-10-17 Pekka Pessi - - * 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 - - * 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 - - * sdp_print.c (sdp_printing_error): Fixed return - for success to be NULL as defined in function - documentation. - -2005-09-29 Pekka Pessi - - * Added SDPTAG_TYPEDEF(). - - M ./libsofia-sip-ua/sdp/sdp_tag.h +3 - - * Not including . - - M ./libsofia-sip-ua/sdp/sdp_tag.h -7 +12 - -2005-09-28 Pekka Pessi - - * 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 - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile.in deleted file mode 100644 index 169419e269..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/Doxyfile.in +++ /dev/null @@ -1,12 +0,0 @@ -PROJECT_NAME = "sdp" -OUTPUT_DIRECTORY = ../docs/html/sdp - -INPUT = @srcdir@/sdp.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf - -TAGFILES += ../docs/su.doxytags=../su -GENERATE_TAGFILE = ../docs/sdp.doxytags - -ALIASES += diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am deleted file mode 100644 index 1e06912dd7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/Makefile.am +++ /dev/null @@ -1,63 +0,0 @@ -# -# Makefile.am for sdp module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 = 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 \ - tests/message-11.sdp - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/README b/libs/sofia-sip/libsofia-sip-ua/sdp/README deleted file mode 100644 index f9199be7ff..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/README +++ /dev/null @@ -1,11 +0,0 @@ -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. diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/errata b/libs/sofia-sip/libsofia-sip-ua/sdp/errata deleted file mode 100644 index 900493935d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/errata +++ /dev/null @@ -1,14 +0,0 @@ -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. diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt b/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt deleted file mode 100644 index de840c1af6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/rfc2327.txt +++ /dev/null @@ -1,2355 +0,0 @@ - - - - - - -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@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 = is always exactly one character and is - case-significant. is a structured text string whose format - depends on . It also will be case-significant unless a - specific field defines otherwise. Whitespace is not permitted either - side of the `=' sign. In general 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@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=
-
- - 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. - - is the user's login on the originating host, or it is "-" - if the originating host does not support the concept of user ids. - must not contain spaces. is a numeric string - such that the tuple of , , , -
and
form a globally unique identifier for - the session. - - The method of 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]. - - 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 is increased when a modification - is made to the session data. Again, it is recommended (but not - mandatory) that an NTP timestamp is used. - - is a text string giving the type of network. - Initially "IN" is defined to have the meaning "Internet".
is a text string giving the type of the address that follows. - Initially "IP4" and "IP6" are defined.
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= - - 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= - - 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= - - 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= - p= - - 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@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 - - 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=
- - 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
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: - - // - - 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=: - - o This specifies the proposed bandwidth to be used by the session or - media, and is optional. - - o is in kilobits per second - - o 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= - - 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= - - 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 in the - corresponding "t=" field would be the NTP representation of 10am on - the first Monday, the would be 1 week, the - 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= .... - - 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= - k=: - - 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: - The encryption key (as described in [3] for RTP media streams - under the AV profile) is included untransformed in this key - field. - - k=base64: - 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: - 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= - a=: - - 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=". 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=:". 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= - - 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= / - - 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: /[/] - - For audio streams, 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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: - 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 - "." are allowed. It is a media attribute, is - only defined for video media, and is not dependent on charset. - - a=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: - 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@isi.edu - - Van Jacobson - MS 46a-1121 - Lawrence Berkeley Laboratory - Berkeley, CA 94720 - United States - electronic mail: van@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] - diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp deleted file mode 100755 index b6cd00a344..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/sh -# -# Run the sdp tests -# -# usage: run_test_sdp [test_program] [test-directory] -# - -test_sdp="${1:-./test_sdp}" -sdp_path=`dirname $0` -tests="${2:-${sdp_path}/tests}" - -if test -r $tests/message-1.sdp ; then - -for n in 1 2 3 4 5 6 7 8 9 10 11; -do - echo -n "$n: " - "$test_sdp" < "$tests/message-$n.sdp" && echo OK -done - -else - echo "sdp run-tests: no tests found in $tests, skipping." - exit 77 -fi diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf deleted file mode 100644 index 42281c1ec2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.bnf +++ /dev/null @@ -1,249 +0,0 @@ - ; 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" or "text" - - 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c deleted file mode 100644 index 8ed84ff357..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c +++ /dev/null @@ -1,1930 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Fri Feb 18 10:25:08 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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); \ - ((*(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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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) a list of - * SDP connection description @a c allocating memory using memory @a home. - * - * @param h Memory home - * @param c SDP connection description to be duplicated - * - * @note The duplicated list is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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) a list of SDP - * bandwidth descriptions @a b allocating memory using memory @a home. - * - * @param h Memory home - * @param b SDP bandwidth description to be duplicated - * - * @note The duplicated list is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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) a list of SDP time - * descriptions @a t allocating memory using memory @a home. - * - * @param h Memory home - * @param t SDP time description to be duplicated - * - * @note The duplicated list is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated list is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - * - * @note The duplicated structure is allocated using a single call to - * su_alloc() and it can be freed with su_free(). - * - * @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 - -size_t sdptag_session_xtra(tagi_t const *t, size_t offset) -{ - sdp_session_t const *sdp = (sdp_session_t *)t->t_value; - - if (sdp) - return STRUCT_ALIGN(offset) + session_xtra(sdp); - else - return 0; -} - -tagi_t *sdptag_session_dup(tagi_t *dst, tagi_t const *src, void **bb) -{ - sdp_session_t *sdp; - sdp_session_t const *srcsdp; - char *b; - - assert(src); assert(*bb); - - b = *bb; - b += STRUCT_ALIGN(b); - srcsdp = (sdp_session_t *)src->t_value; - - sdp = srcsdp ? session_dup(&b, srcsdp) : NULL; - - dst->t_tag = src->t_tag; - dst->t_value = (tag_value_t)sdp; - - *bb = b; - - return dst + 1; -} - -int sdptag_session_snprintf(tagi_t const *t, char b[], size_t size) -{ - sdp_session_t const *sdp; - sdp_printer_t *print; - size_t retval; - - assert(t); - - if (!t || !t->t_value) { - if (size && b) b[0] = 0; - return 0; - } - - sdp = (sdp_session_t const *)t->t_value; - - print = sdp_print(NULL, sdp, b, size, 0); - - retval = sdp_message_size(print); - - sdp_printer_free(print); - - return (int)retval; -} - -/** Tag class for SDP tags. @HIDE */ -tag_class_t sdptag_session_class[1] = - {{ - sizeof(sdptag_session_class), - /* tc_next */ NULL, - /* tc_len */ NULL, - /* tc_move */ NULL, - /* tc_xtra */ sdptag_session_xtra, - /* tc_dup */ sdptag_session_dup, - /* tc_free */ NULL, - /* tc_find */ NULL, - /* tc_snprintf */ sdptag_session_snprintf, - /* tc_filter */ NULL /* msgtag_str_filter */, - /* tc_ref_set */ t_ptr_ref_set, - }}; - - -/* ---------------------------------------------------------------------- */ - -/** Compare two 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 = su_strcmp(a->sdp_subject, b->sdp_subject))) - return rv; - if ((rv = su_strcmp(a->sdp_information, b->sdp_information))) - return rv; - if ((rv = su_strcmp(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 ? ab->b_next : NULL), bb = (bb ? bb->b_next : NULL)) - if ((rv = sdp_bandwidth_cmp(ab, bb))) - 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 || ba; - aa = (aa ? aa->a_next : NULL), ba = (ba ? ba->a_next : NULL)) - if ((rv = sdp_attribute_cmp(aa, ba))) - return rv; - - for (am = a->sdp_media, bm = b->sdp_media; - am || bm; - am = (am ? am->m_next : NULL), bm = (bm ? bm->m_next : NULL)) - 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 = su_strcasecmp(a->o_username, b->o_username))) - return rv; - if ((rv = su_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 || !b) - return -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) - return -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 || !b) - return -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; - - if (!a || !b) - return -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 || !b) - return -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 = su_strcmp(a->k_method_name, b->k_method_name))) - return rv; - return su_strcmp(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 = su_strcmp(a->a_name, b->a_name))) - return rv; - return su_strcmp(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 || !b) - return -1; - - if (a->rm_pt != b->rm_pt) - return a->rm_pt < b->rm_pt ? -1 : 1; - - /* Case insensitive encoding */ - if ((rv = su_strcmp(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 = su_strcasecmp(a_param, b_param); - - if (rv) - return rv; - } - - return su_strcasecmp(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 = su_strcmp(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 || !b) - return -1; - - 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 = su_strcmp(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_proto_x) - if ((rv = su_strcmp(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 ? arm->rm_next : NULL), brm = (brm ? brm->rm_next : NULL)) - if ((rv = sdp_rtpmap_cmp(arm, brm))) - return rv; - - if ((rv = sdp_list_cmp(a->m_format, b->m_format))) - return rv; - - if ((rv = su_strcmp(a->m_information, b->m_information))) - return rv; - - for (ac = a->m_connections, bc = b->m_connections; - ac || bc; - ac = (ac ? ac->c_next : NULL), bc = (bc ? bc->c_next : NULL)) - if ((rv = sdp_connection_cmp(ac, bc))) - return rv; - - for (ab = a->m_bandwidths, bb = b->m_bandwidths; - ab || bb; - ab = (ab ? ab->b_next : NULL), bb = (bb ? bb->b_next : NULL)) - if ((rv = sdp_bandwidth_cmp(ab, bb))) - 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 || ba; - aa = (aa ? aa->a_next : NULL), ba = (ba ? ba->a_next : NULL)) - 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 (su_casematch(a->a_name, name)) - 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 (su_casematch(a->a_name, name)) - break; - } - - if (a == 0) - for (a = a2; a; a = a->a_next) { - if (su_casematch(a->a_name, name)) - 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 (su_casematch(a->a_name, "sendrecv")) - return sdp_sendrecv; - if (su_casematch(a->a_name, "inactive")) - return sdp_inactive; - if (su_casematch(a->a_name, "recvonly")) - return sdp_recvonly; - if (su_casematch(a->a_name, "sendonly")) - 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=: ' 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 (su_casematch((*list)->a_name, a->a_name)) - 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 (su_casematch(name, a->a_name)) - 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 && !su_casematch(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 && !su_casematch(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 - && !su_casematch(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 - && !su_casematch(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_extended_srtp || - (m->m_proto == sdp_proto_x && m->m_proto_name && - su_casenmatch(m->m_proto_name, "RTP/", 4))); -} - -/** 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 (!su_casematch(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 (!su_casematch(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; - sdp_rtpmap_t const *cp_list = NULL; - - if (rm == NULL) - return NULL; - - for (; list; list = list->rm_next) { - if (rm->rm_rate != list->rm_rate) - continue; - - if (!su_casematch(rm->rm_encoding, list->rm_encoding)) - continue; - - lparam = rm->rm_params; rparam = list->rm_params; - - if (lparam == rparam) { - cp_list = list; - if (rm->rm_pt != list->rm_pt) continue; - break; - } - - if (!lparam) lparam = "1"; - - if (!rparam) rparam = "1"; - - if (!su_casematch(lparam, rparam)) - continue; - - break; - } - - return cp_list ? (sdp_rtpmap_t *) cp_list : (sdp_rtpmap_t *)list; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs deleted file mode 100644 index 582db48ccd..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.docs +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- c -*- */ - -/**@MODULEPAGE "sdp" - SDP Module - -@section sdp_meta Module Meta Information - -The @b sdp module provides a simple "C" parser interface for SDP [@RFC2327], -Session Description Protocol. 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. - -@CONTACT Pekka Pessi - -@STATUS @SofiaSIP Core library - -@LICENSE LGPL - -Contributor(s): -- Pekka Pessi -- Jari Selin - -@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: - -@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); -@endcode - Act upon session description, then free the parser: -@code - } - sdp_parser_free(parser); -@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. - -@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: -@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); -@endcode - -At this point, application can use the SDP message contents, e.g., it can -send them to network, and then free the message: -@code - } - else { - show_critical_error(sdp_printing_error(printer)); - } - sdp_printer_free(printer); -@endcode - -@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 -@a buf. - -@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(parser)); - } - - sdp_parser_free(parser); - - su_home_deinit(home); - - return retval; -} -@endcode - -*/ diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c deleted file mode 100644 index bb9221f109..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c +++ /dev/null @@ -1,1931 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Fri Feb 18 10:25:08 2000 ppessi - * - * @sa @RFC4566, @RFC2327. - */ - -#include "config.h" - -#include -#include - -#include "sofia-sip/sdp.h" - -#include -#include -#include -#include -#include -#include -#include - -/** @typedef struct sdp_parser_s sdp_parser_t; - * - * SDP parser handle. - * - * The SDP parser handle returned by sdp_parse() contains either - * a successfully parsed 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(), @RFC4566, - * @RFC2327. - */ - -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 - -#ifdef _MSC_VER -#undef STRICT -#endif -#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 int 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. - * - * @sa sdp_session(), sdp_parsing_error(), sdp_sanity_check(), - * sdp_parser_home(), sdp_parser_free(), @RFC4566, @RFC2327. - */ -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" -#define TOKEN ALPHA DIGIT "-!#$%&'*+.^_`{|}~" - -/* ========================================================================= */ -/* 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 = ""; - - p->pr_ok = 1; - p->pr_session->sdp_size = sizeof(p->pr_session); - - /* Require that version comes first */ - record = next(&message, CRLF, strip); - - if (!su_strmatch(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); -} -#ifdef SOFIA_AUTO_CORRECT_INADDR_ANY -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 && su_strmatch(c->c_address, "0.0.0.0")) || - (c->c_addrtype == sdp_addr_ip6 && su_strmatch(c->c_address, "::"))); -} -#endif - -/**Postprocess session description. - * - * Postprocessing includes setting the session backpointer for each media, - * doing sanity checks and setting rejected and mode flags. - */ -static void post_session(sdp_parser_t *p, sdp_session_t *sdp) -{ - sdp_media_t *m; -#ifdef SOFIA_AUTO_CORRECT_INADDR_ANY - sdp_connection_t const *c; -#endif - - 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; - } - -#ifdef SOFIA_AUTO_CORRECT_INADDR_ANY - c = sdp_media_connections(m); - - - if (p->pr_mode_0000 && sdp_connection_is_inaddr_any(c)) { - /* Reset recvonly flag */ - m->m_mode &= ~sdp_recvonly; - } -#endif - } - - 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) - return -1; - else if (sdp->sdp_version[0] != 0) - return parsing_error(p, "Incorrect version"); - else if (!sdp->sdp_origin) - return parsing_error(p, "No o= present"); - else if (p->pr_strict && !sdp->sdp_subject) - return parsing_error(p, "No s= present"); - else if (p->pr_strict && !sdp->sdp_time) - return parsing_error(p, "No t= present"); - - /* 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 (su_casenmatch(r, "IN", 2)) { - 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 (su_casematch(s, "IP4")) - c->c_addrtype = sdp_addr_ip4; - else if (su_casematch(s, "IP6")) - 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 = token - bandwidth = 1*(DIGIT) - */ - /* NOTE: bwtype can also be like X-barf */ - sdp_bandwidth_e modifier; - char *name; - unsigned long value; - - name = token(&r, ":", TOKEN, SPACE TAB); - - if (name == NULL || parse_ul(p, &r, &value, 0)) { - parsing_error(p, "invalid bandwidth"); - return; - } - - if (su_casematch(name, "CT")) - modifier = sdp_bw_ct, name = "CT"; - else if (su_casematch(name, "TIAS") == 1) - modifier = sdp_bw_tias, name = "TIAS"; - else if (su_casematch(name, "AS") == 1) - modifier = sdp_bw_as, name = "AS"; - else - modifier = sdp_bw_x, name = "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 SP stop-time - *(CRLF repeat-fields) CRLF) - [zone-adjustments CRLF] - - start-time = time / "0" - - stop-time = time / "0" - - time = POS-DIGIT 9*DIGIT - ; Decimal representation of NTP time in - ; seconds since 1900. The representation - ; of NTP time is an unbounded length field - ; containing at least 10 digits. Unlike the - ; 64-bit representation used elsewhere, time - ; in SDP does not wrap in the year 2036. - */ - 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 = %x72 "=" repeat-interval 2*(SP typed-time) - - repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit] - - typed-time = 1*DIGIT [fixed-len-time-unit] - - fixed-len-time-unit = %x64 / %x68 / %x6d / %x73 ; "d" | "h" | "m" | "s" - */ - - unsigned long tt, *interval; - size_t i; - int n, N; - char *s; - sdp_repeat_t *r; - int strict = STRICT(p); - - /** Count number of intervals */ - for (N = 0, s = d; *s; ) { - if (!(is_posdigit(*s) || (!strict && (*s) == '0'))) - break; - do { s++; } while (is_digit(*s)); - if (*s && strchr(strict ? "dhms" : "dhmsDHMS", *s)) - s++; - N++; - if (!(i = strict ? 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': case 'D': tt *= 24; - case 'h': case 'H': tt *= 60; - case 'm': case 'M': tt *= 60; - case 's': 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, ":", TOKEN, SPACE TAB); - if (!s) { - parsing_error(p, "invalid key method"); - return; - } - - { - PARSE_ALLOC(p, sdp_key_t, k); - *result = k; - - /* These are defined as key-sensitive in RFC 4566 */ -#define MATCH(s, tok) \ - (STRICT(p) ? su_strmatch((s), (tok)) : su_casematch((s), (tok))) - - if (MATCH(s, "clear")) - k->k_method = sdp_key_clear, k->k_method_name = "clear"; - else if (MATCH(s, "base64")) - k->k_method = sdp_key_base64, k->k_method_name = "base64"; - else if (MATCH(s, "uri")) - k->k_method = sdp_key_uri, k->k_method_name = "uri"; - else if (MATCH(s, "prompt")) - k->k_method = sdp_key_prompt, k->k_method_name = "prompt"; - else if (!STRICT(p)) - k->k_method = sdp_key_x, k->k_method_name = s; - else { - parsing_error(p, "invalid key method"); - return; - } - - 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 = token - - att-value = byte-string - */ - - char *name = NULL, *value = NULL; - - if (!(name = token(&r, ":", TOKEN, SPACE TAB))) { - parsing_error(p,"invalid attribute name"); - return; - } - - if (*r) - value = r; - else - PARSE_CHECK_REST(p, r, "a"); - - if (su_casematch(name, "charset")) { - p->pr_session->sdp_charset = value; - return; - } - - if (p->pr_mode_manual) - ; - else if (su_casematch(name, "inactive")) - p->pr_session_mode = sdp_inactive; - else if (su_casematch(name, "sendonly")) - p->pr_session_mode = sdp_sendonly; - else if (su_casematch(name, "recvonly")) - p->pr_session_mode = sdp_recvonly; - else if (su_casematch(name, "sendrecv")) - 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 = token - ;typically "audio", "video", "application" - ;or "data" or "text" - - fmt = token - ;typically an RTP payload type for audio - ;and video media - - proto = token *("/" token) - ;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, TOKEN, 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; - } - - s = token(&r, SPACE, "/" TOKEN, SPACE); - if (s == NULL) { - parsing_error(p, "m= missing protocol"); - return; - } - - if (!STRICT(p) && su_casematch(s, "RTP")) - 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 = token(&r, SPACE TAB, TOKEN, SPACE TAB); - fmt = &l->l_next; - } - } -} - -/** Set media type */ -void sdp_media_type(sdp_media_t *m, char const *s) -{ - if (su_strmatch(s, "*")) - m->m_type = sdp_media_any, m->m_type_name = "*"; - else if (su_casematch(s, "audio")) - m->m_type = sdp_media_audio, m->m_type_name = "audio"; - else if (su_casematch(s, "video")) - m->m_type = sdp_media_video, m->m_type_name = "video"; - else if (su_casematch(s, "application")) - m->m_type = sdp_media_application, m->m_type_name = "application"; - else if (su_casematch(s, "data")) - m->m_type = sdp_media_data, m->m_type_name = "data"; - else if (su_casematch(s, "control")) - m->m_type = sdp_media_control, m->m_type_name = "control"; - else if (su_casematch(s, "message")) - m->m_type = sdp_media_message, m->m_type_name = "message"; - else if (su_casematch(s, "image")) - m->m_type = sdp_media_image, m->m_type_name = "image"; - else if (su_casematch(s, "red")) - m->m_type = sdp_media_red, m->m_type_name = "red"; - else if (su_casematch(s, "text")) - m->m_type = sdp_media_text, m->m_type_name = "text"; - else - m->m_type = sdp_media_x, m->m_type_name = s; -} - -/** Set transport protocol. - * - * Set the @m->m_proto to a well-known protocol type as - * well as canonize case of @a m_proto_name. - */ -void sdp_media_transport(sdp_media_t *m, char const *s) -{ - if (m == NULL || s == NULL) - ; - else if (su_strmatch(s, "*")) - m->m_proto = sdp_proto_any, m->m_proto_name = "*"; - else if (su_casematch(s, "RTP/AVP")) - m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP"; - else if (su_casematch(s, "RTP/SAVP")) - m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP"; - else if (su_casematch(s, "UDP/TLS/RTP/SAVP")) - m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP"; - else if (su_casematch(s, "RTP/SAVPF")) - m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "RTP/SAVPF"; - else if (su_casematch(s, "UDP/TLS/RTP/SAVPF")) - m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "UDP/TLS/RTP/SAVPF"; - else if (su_casematch(s, "RTP/AVPF")) - m->m_proto = sdp_proto_extended_rtp, m->m_proto_name = "RTP/AVPF"; - else if (su_casematch(s, "UDP/RTP/AVPF")) - m->m_proto = sdp_proto_extended_rtp, m->m_proto_name = "UDP/RTP/AVPF"; - else if (su_casematch(s, "udptl")) - /* Lower case - be compatible with people living by T.38 examples */ - m->m_proto = sdp_proto_udptl, m->m_proto_name = "udptl"; - else if (su_casematch(s, "TCP/MSRP")) - m->m_proto = sdp_proto_msrp, m->m_proto_name = "TCP/MSRP"; - else if (su_casematch(s, "TCP/TLS/MSRP")) - m->m_proto = sdp_proto_msrps, m->m_proto_name = "TCP/TLS/MSRP"; - else if (su_casematch(s, "UDP")) - m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP"; - else if (su_casematch(s, "TCP")) - m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP"; - else if (su_casematch(s, "TLS")) - 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 || m->m_proto == sdp_proto_extended_srtp || m->m_proto == sdp_proto_extended_rtp); -} - -#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; - - 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 = token - - att-value = byte-string - - a=rtpmap: /[/] - a=fmtp: - */ - int rtp = sdp_media_has_rtp(m); - char *name = NULL, *value = NULL; - int n; - - if (!(name = token(&r, ":", TOKEN, 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 (m->m_port == 0 || su_casematch(name, "inactive")) { - m->m_mode = sdp_inactive; - return; - } - else if (su_casematch(name, "sendonly")) { - m->m_mode = sdp_sendonly; - return; - } - else if (su_casematch(name, "recvonly")) { - m->m_mode = sdp_recvonly; - return; - } - else if (su_casematch(name, "sendrecv")) { - m->m_mode = sdp_sendrecv; - return; - } - - if (rtp && su_casematch(name, "rtpmap")) { - if ((n = parse_rtpmap(p, r, m)) == 0 || n < -1) - return; - } - else if (rtp && su_casematch(name, "fmtp")) { - 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: /[/] - */ -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, "/", TOKEN, NULL); - if (!r) { - parsing_error(p, "a=rtpmap:%lu: missing ", pt); - return -2; - } - if (parse_ul(p, &r, &rate, 0)) { - parsing_error(p, "a=rtpmap:%lu %s: invalid ", 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: - */ -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 = ""; - - 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 -#if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800)) -unsigned long long strtoull(char const *string, char **return_end, int base); -#endif -#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 long long 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[0]) - 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 int parsing_error(sdp_parser_t *p, char const *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - memset(p->pr_error, 0, sizeof(p->pr_error)); - vsnprintf(p->pr_error, sizeof(p->pr_error), fmt, ap); - va_end(ap); - - p->pr_ok = 0; - - return -1; -} - -static void parse_alloc_error(sdp_parser_t *p, const char *typename) -{ - parsing_error(p, "memory exhausted (while allocating memory for %s)", - typename); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c deleted file mode 100644 index 767556d7ac..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Fri Feb 18 10:25:08 2000 ppessi - */ - -#include "config.h" - -#include -#include - -#include "sofia-sip/sdp.h" - -#include -#include -#include -#include -#include -#include - -/* ========================================================================= */ -/* 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); -static void printing_error(sdp_printer_t *p, const char *fmt, ...); - -/** 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; - - if (session) - print_session(p, session); - else - printing_error(p, "NULL session description"); - - 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 print_session(sdp_printer_t *p, sdp_session_t const *sdp) -{ - p->pr_ok = 1; - - if (p->pr_ok) - 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; - } - - if (nettype && addrtype) - sdp_printf(p, "%s%s%s", nettype, addrtype, c->c_address); - else if (nettype) - sdp_printf(p, "%s%s%s", nettype, c->c_address); - else - sdp_printf(p, "%s", 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; - case sdp_bw_tias: name = "TIAS"; 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 (su_casematch(name, "inactive") || - su_casematch(name, "sendonly") || - su_casematch(name, "recvonly") || - su_casematch(name, "sendrecv")) - 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; - case sdp_media_text : media = "text"; 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_extended_srtp: proto = "RTP/SAVPF"; break; - case sdp_proto_udptl: proto = "udptl"; break; - case sdp_proto_msrp: proto = "TCP/MSRP"; break; - case sdp_proto_msrps: proto = "TCP/TLS/MSRP"; 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 syntax requires at least one format. */ - /* defaults to "19", or "t38" for image */ - if (m->m_type == sdp_media_image) sdp_printf(p, " t38"); - else sdp_printf(p, " 19"); - } - - - 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_encoding && *rm->rm_encoding && (!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; - - if (p->pr_ok) { - va_start(ap, fmt); - vsnprintf(p->pr_buffer, p->pr_bsiz, fmt, ap); - va_end(ap); - } - - p->pr_ok = 0; -} - -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"; - } - } -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c deleted file mode 100644 index 2b3ce8c002..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_tag.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @file sdp_tag.c - * @brief SDP Tags - * - * @author Pekka Pessi - * - * @date Created: Mon May 12 12:11:30 2003 ppessi - * - */ - -#include "config.h" - -#include - -#define TAG_NAMESPACE "sdp" - -#include - -tag_typedef_t sdptag_any = NSTAG_TYPEDEF(*); - -tag_typedef_t sdptag_session = {{ - TAG_NAMESPACE, "session", sdptag_session_class -}}; diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h deleted file mode 100644 index bf0741e044..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h +++ /dev/null @@ -1,570 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Fri Feb 18 08:54:48 2000 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif -#ifndef SU_TYPES_H -#include -#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_bw_tias, /**< 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, - * e.g., JPIP or T.38. */ - sdp_media_red, /**< Redundancy. @NEW_1_12_4. */ - sdp_media_text, /**< Realtime Text */ -} 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_msrp = 259, /**< TCP/MSRP @NEW_MSRP*/ - sdp_proto_msrps = 260, /**< TCP/TLS/MSRP @NEW_MSRP*/ - sdp_proto_extended_srtp = 261, /** WEBRTC SAVPF */ - sdp_proto_extended_rtp = 262, /** WEBRTC AVPF */ - 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 */ - unsigned :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 *, sdp_connection_t const *); - -/** Duplicate an SDP bandwidth structure. */ -SOFIAPUBFUN -sdp_bandwidth_t *sdp_bandwidth_dup(su_home_t *, sdp_bandwidth_t const *); - -/** Duplicate an SDP time structure. */ -SOFIAPUBFUN -sdp_time_t *sdp_time_dup(su_home_t *, sdp_time_t const *); - -/** Duplicate an SDP repeat structure. */ -SOFIAPUBFUN -sdp_repeat_t *sdp_repeat_dup(su_home_t *, sdp_repeat_t const *); - -/** Duplicate an SDP timezone structure. */ -SOFIAPUBFUN -sdp_zone_t *sdp_zone_dup(su_home_t *, sdp_zone_t const *); - -/** Duplicate an SDP key structure. */ -SOFIAPUBFUN -sdp_key_t *sdp_key_dup(su_home_t *, sdp_key_t const *); - -/** Duplicate an SDP attribute structure. */ -SOFIAPUBFUN -sdp_attribute_t *sdp_attribute_dup(su_home_t *, 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 *, sdp_list_t const *); - -/** Duplicate an rtpmap structure. */ -SOFIAPUBFUN -sdp_rtpmap_t *sdp_rtpmap_dup(su_home_t *, 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 *, - 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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h deleted file mode 100644 index 098064e0d7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp_tag.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SDP_TAG_H - -/**@file sofia-sip/sdp_tag.h - * @brief SDP tags - * - * @author Pekka Pessi - * - * @date Created: Mon May 12 12:06:20 EEST 2003 ppessi - * @{ - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SU_TAG_CLASS_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c b/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c deleted file mode 100644 index 98cac4c908..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/test_sdp.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created : Fri Feb 18 10:25:08 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp deleted file mode 100644 index 7697aae23d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-1.sdp +++ /dev/null @@ -1 +0,0 @@ -v=1 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp deleted file mode 100644 index 82f7544296..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-10.sdp +++ /dev/null @@ -1,32 +0,0 @@ -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@isi.edu (Mark Handley) -e=mjh@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-11.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-11.sdp deleted file mode 100644 index 27f92f1004..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-11.sdp +++ /dev/null @@ -1,34 +0,0 @@ -v=0 -o=- 3250588766 0 IN IP4 77.75.1.10 -s=- -c=IN IP4 77.75.1.10 -t=0 0 -m=audio 54424 RTP/AVP 18 99 101 102 103 15 104 4 105 106 107 108 125 109 100 8 0 -a=rtpmap:18 G729/8000 -a=fmtp:18 annexb=no -a=rtpmap:99 G.729a/8000 -a=rtpmap:101 G.726-16/8000 -a=rtpmap:102 G.726-24/8000 -a=rtpmap:103 G.726-32/8000 -a=rtpmap:15 G728/8000 -a=rtpmap:104 G.723.1-H/8000 -a=rtpmap:4 G723/8000 -a=rtpmap:105 G.723.1-L/8000 -a=rtpmap:106 G.729b/8000 -a=rtpmap:107 G.723.1a-H/8000 -a=rtpmap:108 G.723.1a-L/8000 -a=rtpmap:125 G.nX64/8000 -a=rtpmap:109 AMR/8000 -a=rtpmap:100 X-NSE/8000 -a=fmtp:100 192-194,200-202 -a=rtpmap:8 PCMA/8000 -a=rtpmap:0 PCMU/8000 -a=maxptime:20 -a=maxptime:30 -a=ptime:20 -a=ptime:30 -a=X-cap: 1 audio RTP/AVP 100 -a=X-cap: 2 image udptl t38 -a=X-sqn:0 -a=X-cpar: a=rtpmap:100 X-NSE/8000 -a=X-cpar: a=fmtp:100 192-194,200-202 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp deleted file mode 100644 index bd63b47d2b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-2.sdp +++ /dev/null @@ -1,13 +0,0 @@ -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@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp deleted file mode 100644 index 78c7efa734..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-3.sdp +++ /dev/null @@ -1,8 +0,0 @@ -v=0 -o=user1 53655765 2353687637 IN IP4 128.3.4.5 -s=Mbone Audio -i=Discussion of Mbone Engineering Issues -e=mbone@somewhere.com -c=IN IP4 224.2.0.1/127 -t=0 0 -m=audio 3456 RTP/AVP 0 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp deleted file mode 100644 index 2675d0ab4d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-4.sdp +++ /dev/null @@ -1,4 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp deleted file mode 100644 index bf973eb1c0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-5.sdp +++ /dev/null @@ -1,5 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp deleted file mode 100644 index affb3a0931..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-6.sdp +++ /dev/null @@ -1,6 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp deleted file mode 100644 index bac7b03fc6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-7.sdp +++ /dev/null @@ -1,10 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp deleted file mode 100644 index 432023cff8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-8.sdp +++ /dev/null @@ -1,10 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp b/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp deleted file mode 100644 index 9bfe7ac203..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/tests/message-9.sdp +++ /dev/null @@ -1,25 +0,0 @@ -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@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c b/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c deleted file mode 100644 index f29ac7f762..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/torture_sdp.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Kai Vehmanen - * - * @date Created: Tue Mar 6 18:33:42 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#define TSTFLAGS tstflags - -#include - -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 s0_cmp_msg[] = -"v=0\n" -"s=/sdp_torture\n" -"o=sdp_torture 0 0 IN IP4 0.0.0.0\n" -"b=AS:64\n" -"b=CRASH:32\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 char const s1_cmp_msg[] = -"v=0\n" -"s=/sdp_torture\n" -"o=sdp_torture 0 0 IN IP4 0.0.0.0\n" -"b=AS:64\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_sdp_session_cmp(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, *parser2; - - BEGIN(); - - su_home_check(home); - TEST_1(home); - - su_home_check(home2); - TEST_1(home2); - - TEST_1((parser = sdp_parse(home, s0_cmp_msg, sizeof(s0_cmp_msg), sdp_f_config))); - TEST_1((sdp_src = sdp_session(parser))); - - TEST_1((parser2 = sdp_parse(home2, s1_cmp_msg, sizeof(s1_cmp_msg), sdp_f_config))); - TEST_1((sdp_target = sdp_session(parser2))); - - /* Check comparing */ - TEST(sdp_session_cmp(sdp_src, sdp_target), 1); - - /* 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); - - /* frees all data created by the parser including 'sdp_target' */ - sdp_parser_free(parser2); - - /* 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(s3_msg) - 1, 0))); - - TEST_1(sdp_sanity_check(parser) == 0); - - su_home_unref(home); - - END(); -} - -static char const pint_msg[] = - "v=0\r\n" - "o=- 2353687640 2353687640 IN IP4 128.3.4.5\r\n" - "s=marketing\r\n" - "e=john.jones.3@chinet.net\r\n" - "c=TN RFC2543 +1-201-406-4090\r\n" - "t=2353687640 0\r\n" - "m=audio 1 voice -\r\n" - ; - -static char const pint_torture_msg[] = - "v=0\r\n" - "o=- 2353687640 2353687640 IN IP4 128.3.4.5\r\n" - "s=marketing\r\n" - - "c= TN RFC2543 123\r\n" - "a=phone-context:+97252\r\n" - "t=2353687640 0\r\n" - "m= text 1 fax plain\r\n" - "a=fmtp:plain spr:fi6MeoclEjaF3EDfYHlkqx1zn8A1lMoiJFUHpQ5Xo\r\n" - ; - -static int test_pint(void) -{ - su_home_t *home = su_home_create(); - sdp_parser_t *parser; - sdp_session_t *sdp; - sdp_printer_t *printer; - char const *m; - - BEGIN(); - - su_home_check(home); TEST_1(home); - - TEST_1((parser = sdp_parse(home, pint_msg, sizeof(pint_msg) - 1, sdp_f_anynet))); - TEST_1((sdp = sdp_session(parser))); - - TEST_1((printer = sdp_print(home, sdp, NULL, -1, 0))); - TEST_1((m = sdp_message(printer))); - TEST_S(m, pint_msg); - TEST(sdp_message_size(printer), sizeof(pint_msg) - 1); - - TEST_1((parser = sdp_parse(home, pint_torture_msg, sizeof(pint_torture_msg) - 1, - sdp_f_anynet))); - TEST_1((sdp = sdp_session(parser))); - - su_home_check(home); - 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 -#include - -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(int exitcode) -{ - fprintf(stderr, "usage: %s [-v] [-a]\n", name); - exit(exitcode); -} - -int main(int argc, char *argv[]) -{ - int retval = 0; - int i; - - for (i = 1; argv[i]; i++) { - if (su_strmatch(argv[i], "-v")) - tstflags |= tst_verbatim; - else if (su_strmatch(argv[i], "-a")) - tstflags |= tst_abort; - else - usage(1); - } - - null = fopen("/dev/null", "ab"); - - retval |= test_error(); fflush(stdout); - retval |= test_sdp_session_cmp(); fflush(stdout); - retval |= test_session(); fflush(stdout); - retval |= test_session2(); fflush(stdout); - retval |= test_pint(); 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER b/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER deleted file mode 100644 index 5458021d04..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/ADD-A-HEADER +++ /dev/null @@ -1,152 +0,0 @@ -Adding a SIP Header to Sofia SIP -================================ - -by Pekka Pessi (2002-08-16, last updated 2007-09-19) - -There are two recommended ways to extend the Sofia SIP parser, including a -standard header in extra headers or putting the extension headers into a -separate library. - -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 , add: - - - Add typedef to the header structure. - - 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 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. */ - }; - - * Add entry to sip_extra_headers.txt: - - In this case: - example @NEW_2_0 /* Example header */ - - The first is the base C name used for functions and types related to - the type. The AWK script msg_parser.awk automatically creates the - default prototypes and tags for the newly created header. It will - complain about mismatches between header name and the base name. - - - If the entry is before #### DEFAULT HEADER LIST ENDS HERE #### - the new header is added to the default parser - - If after, the new header is added only to the extended parser. - - - The extended parser will be used after call to - sip_update_default_mclass(NULL) - - * 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 COMPLETELY NON-STANDARD -------------------------------------------- - - * Add a separate library package for them - - - 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 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 . - */ - -#ifndef SIP_EXAMPLE_H -/** Defined when has been included. */ -#define SIP_EXAMPLE_H - -/**@file sip_example.h -* - * @brief Example header. - * - * #AUTO# - * - * @author Pekka Pessi . - * - * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi - */ - -#ifndef SIP_H -#include -#endif -#ifndef SIP_HEADER_H -#include -#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--- diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog deleted file mode 100644 index 93f094cdae..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/ChangeLog +++ /dev/null @@ -1,58 +0,0 @@ -2006-01-25 Kai Vehmanen - - * 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 - - * Doxyfile: References to removed files sip_internal.h - and sip_extensions.h caused fatal doxygen error. - -2005-10-21 Pekka Pessi - - * 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 - - * 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 - - * 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 - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile.in deleted file mode 100644 index 10e1379854..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/Doxyfile.in +++ /dev/null @@ -1,31 +0,0 @@ -PROJECT_NAME = "sip" -OUTPUT_DIRECTORY = ../docs/html/sip - -INPUT = @srcdir@/sofia-sip sofia-sip @srcdir@/sip.docs @srcdir@/sip_parser.docs @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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@defgroup" \ - "SIP_PARSER=\n" - -@INCLUDE = sip.doxyaliases - -PREDEFINED += SU_HAVE_EXPERIMENTAL=1 - -IMAGE_PATH += @srcdir@/images diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR b/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR deleted file mode 100644 index 9052f13b76..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/GRAMMAR +++ /dev/null @@ -1,537 +0,0 @@ -/* 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am deleted file mode 100644 index 19fa9b545d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/Makefile.am +++ /dev/null @@ -1,152 +0,0 @@ -# -# Makefile.am for sip module -# - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 \ - test_sip_msg validator test_date - -# ---------------------------------------------------------------------- -# 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_parser_table.c - -BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C) sip_tag_ref.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 sip_inlined.c \ - $(BUILT_SOURCES) - -COVERAGE_INPUT = $(libsip_la_SOURCES) $(include_sofia_HEADERS) - -LDADD = libsip.la \ - ../msg/libmsg.la \ - ../bnf/libbnf.la \ - ../url/liburl.la \ - ../ipt/libipt.la \ - ../su/libsu.la - -torture_sip_LDFLAGS = -static -test_sip_msg_LDFLAGS = -static -test_date_LDFLAGS = -static - -# ---------------------------------------------------------------------- -# Install and distribution rules - -# note: srcdir needs to be specified, otherwise -# breaks make distcheck target - -EXTRA_DIST = 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_test_sip_msg run_test_date - -dist_noinst_SCRIPTS = run_test_sip_msg run_test_date - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - -MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk - -AWK_SIP_AWK = LC_ALL=C $(AWK) -f $(MSG_PARSER_AWK) module=sip - -SS_SIP_H = ${srcdir}/sofia-sip/sip.h - -EXTRA = ${srcdir}/sip_extra_headers.txt - -${GENERATED_H} ${GENERATED_C}: ${SS_SIP_H} ${MSG_PARSER_AWK} - -sofia-sip/sip_hclasses.h: ${srcdir}/sofia-sip/sip_hclasses.h.in - @-mkdir sofia-sip 2>/dev/null || true - ${AWK_SIP_AWK} PR=$@ TEMPLATE=${srcdir}/sofia-sip/sip_hclasses.h.in \ - ${SS_SIP_H} - -sofia-sip/sip_protos.h: ${srcdir}/sofia-sip/sip_protos.h.in - @-mkdir sofia-sip 2>/dev/null || true - ${AWK_SIP_AWK} PR=$@ TEMPLATE=${srcdir}/sofia-sip/sip_protos.h.in \ - ${SS_SIP_H} - -sofia-sip/sip_tag.h: ${srcdir}/sofia-sip/sip_tag.h.in - @-mkdir sofia-sip 2>/dev/null || true - ${AWK_SIP_AWK} PR=$@ TEMPLATE=${srcdir}/sofia-sip/sip_tag.h.in \ - ${SS_SIP_H} - -sip_tag.c: ${srcdir}/sip_tag.c.in ${EXTRA} - ${AWK_SIP_AWK} PR=$@ TEMPLATE=${srcdir}/sip_tag.c.in \ - ${SS_SIP_H} ${EXTRA} - -# Note: sip_bad_mask is used by nta to weed out bad messages - -sip_parser_table.c: ${srcdir}/sip_parser_table.c.in ${EXTRA} sip_bad_mask - ${AWK_SIP_AWK} PT=$@ TEMPLATE=${srcdir}/sip_parser_table.c.in \ - FLAGFILE=${srcdir}/sip_bad_mask \ - MC_HASH_SIZE=127 MC_SHORT_SIZE=26 \ - ${SS_SIP_H} ${EXTRA} - -sofia-sip/sip_extra.h: ${srcdir}/sofia-sip/sip_extra.h.in ${EXTRA} - @-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 \ - TEMPLATE3=${srcdir}/sofia-sip/sip_tag.h.in \ - TEMPLATE=${srcdir}/sofia-sip/sip_extra.h.in ${EXTRA} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser.eps deleted file mode 100644 index 998e836f8da56f5fcd2ce54f1ffbc6013798537c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165734 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

AErePAI|; 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 NdhCt_m8Spz06X)yC|m#l diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.eps deleted file mode 100644 index a000e75c4cd645c38e99b1dda8c15e640e6908b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 223408 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 U@7)sK3;9m>H?QcmKP$igf2|JtoB#j- diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser2.gif deleted file mode 100644 index d56ae564bf0b3f51f05d28dc884257526f22ef28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16927 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.eps deleted file mode 100644 index fd0d958f5f05cae7c17426c7953cf7e40f9d7f90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235727 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 O)+spr%W1ml-~T@>54B$a diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser3.gif deleted file mode 100644 index 0386f66c3726bcaff02014ff2f6944b546624e3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14550 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 A9smFU diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.eps deleted file mode 100644 index 21085ad32991919c86d9e71b90a684c39853d018..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154295 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

_R9f)4BpO~;ainz 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif b/libs/sofia-sip/libsofia-sip-ua/sip/images/sip-parser4.gif deleted file mode 100644 index df70af900ec2eb5ec311da4deea7a497fa11f945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4272 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 S#9WoPNlb%<$;8=I0028@(mF)| diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt b/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt deleted file mode 100644 index fb9d785ef1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/rfc2543.txt +++ /dev/null @@ -1,8564 +0,0 @@ - - - - - - -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@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@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@lab : - : 2| 3| : - : | | : - : henning | : -+.. cs.tu-berlin.de ..+ 1: INVITE : | | : -: : henning@cs.col: | \/ 4: INVITE 5: ring : -: cz@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@lab : - : 2| 3| : - : | | : - : henning| : -+.. cs.tu-berlin.de ..+ 1: INVITE : | | : -: : henning@cs.col: | \/ : -: cz@cs.tu-berlin.de =======================>(~~~~~~) : -: | ^ | <.......................( ) : -: | . | : 4: 302 Moved : ( ) : -: | . | : hgs@lab : ( work ) : -: | . | : : ( ) : -: | . | : 5: ACK : ( ) : -: | . | =======================>(~~~~~~) : -: | . | : : : -+.......|...|.........+ : : - | . | : : - | . | : : - | . | : : - | . | : : - | . | 6: INVITE hgs@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@big.com using multicast to 239.255.255.1 - with a ttl of 15, the following URL would be used: - - - sip:j.doe@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@big.com - sip:j.doe:secret@big.com;transport=tcp - sip:j.doe@big.com?subject=project - sip:+1-212-555-1212:1234@gateway.com;user=phone - sip:1212@gateway.com - sip:alice@10.1.2.3 - sip:alice@example.com - sip:alice%40example.com@gateway.com - sip:alice@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@example.com and SIP:J.Doe@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@domain" - rather than "user@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@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@acme.com is proxied to the particular person, e.g., - sip:bob@ny.acme.com , with the To field remaining as - sip:sales@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@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 = * - - - 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@foo.bar.com - - - or - - i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6@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" - ;q=0.7; expires=3600, - "Mr. Watson" ;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@boston.bell-telephone.com SIP/2.0 - Via: SIP/2.0/UDP 169.130.12.5 - From: - To: T. A. Watson - Call-ID: 187602141351@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" - From: sip:+12125551212@server.phone2net.com - From: Anonymous - - - - 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: , - - - - - - - - -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@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 ;tag=287447 - To: sip:+12125551212@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@example.com : - - 485 Ambiguous SIP/2.0 - Contact: Carol Lee - - - - -Handley, et al. Standards Track [Page 81] - -RFC 2543 SIP: Session Initiation Protocol March 1999 - - - Contact: Ping Lee - Contact: Lee M. Foote - - - - 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@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@isi.edu - t:sip:schooler@cs.caltech.edu - i:62729-27@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@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<* ** *>INVITE : -|;status>* failure *>status<-* success *: - ! ! 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@boston.bell-telephone.com SIP/2.0$ - Via: SIP/2.0/UDP 169.130.12.5$ - To: T. A. Watson $ - From: A. Bell $ - Encryption: PGP version=5.0$ - Content-Length: 224$ - Call-ID: 187602141351@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@boston.bell-telephone.com SIP/2.0$ - Via: SIP/2.0/UDP 169.130.12.5$ - To: T. A. Watson $ - From: A. Bell $ - 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@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 - To: T. A. Watson - Call-ID: 187602141351@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 - To: T. A. Watson - Call-ID: 187602141351@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@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@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@bell-tel.com - To: sip:watson@bell-tel.com - Call-ID: 70710@saturn.bell-tel.com - CSeq: 1 REGISTER - Contact: - Expires: 7200 - - - - The registration expires after two hours. Any future invitations for - watson@bell-tel.com arriving at sip.bell-tel.com will now be - redirected to watson@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@bell-tel.com - To: sip:watson@bell-tel.com - Call-ID: 70710@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@bell-tel.com - To: sip:watson@bell-tel.com - Call-ID: 70710@saturn.bell-tel.com - CSeq: 3 REGISTER - Contact: sip:tawatson@example.com - - - - Now, the server will forward any request for Watson to the server at - example.com, using the Request-URI tawatson@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@bell-tel.com - To: sip:watson@bell-tel.com - Call-ID: 17320@pluto.bell-tel.com - CSeq: 1 REGISTER - Contact: sip:tawatson@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@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@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 - To: Eve Schooler - Call-ID: 2963313058@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@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@isi.edu and addressed to schooler@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@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 - To: Eve Schooler ;tag=9883472 - Call-ID: 2963313058@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 - To: Eve Schooler ;tag=9883472 - Call-ID: 2963313058@north.east.isi.edu - CSeq: 1 INVITE - Contact: sip:es@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@jove.cs.caltech.edu SIP/2.0 - Via: SIP/2.0/UDP north.east.isi.edu - From: Mark Handley - To: Eve Schooler ;tag=9883472 - Call-ID: 2963313058@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@boston.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP kton.bell-tel.com - From: A. Bell - To: T. Watson - Call-ID: 3298420296@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 - To: T. Watson ;tag=37462311 - Call-ID: 3298420296@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 - To: T. Watson ;tag=37462311 - Call-ID: 3298420296@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 - To: T. Watson ;tag=37462311 - Call-ID: 3298420296@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 - To: T. Watson ;tag=37462311 - Call-ID: 3298420296@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 - To: ;tag=37462311 - Call-ID: 3298420296@kton.bell-tel.com - CSeq: 1 INVITE - Contact: sip:watson@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@boston.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP kton.bell-tel.com - From: A. Bell - To: T. Watson ;tag=37462311 - Call-ID: 3298420296@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@boston.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP kton.bell-tel.com - From: A. Bell - To: T. A. Watson ;tag=37462311 - Call-ID: 3298420296@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@bell-tel.com) (C), currently seated - at host c.bell-tel.com wants to call Watson (t.watson@ieee.org). At - the time of the call, Watson is logged in at two workstations, - t.watson@x.bell-tel.com (X) and watson@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@h.bell-tel.com (H), as well as a permanent registration at - watson@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@ieee.org SIP/2.0 - Via: SIP/2.0/UDP c.bell-tel.com - From: A. Bell - To: T. Watson - Call-ID: 31415@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@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 - To: T. Watson - Call-ID: 31415@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 - To: T. Watson ;tag=87454273 - - - -Handley, et al. Standards Track [Page 126] - -RFC 2543 SIP: Session Initiation Protocol March 1999 - - - Call-ID: 31415@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@h.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP sip.ieee.org ;branch=1 - From: A. Bell - To: T. Watson ;tag=87454273 - Call-ID: 31415@c.bell-tel.com - CSeq: 1 ACK - - - - Also, P attempts to reach Watson through the ACM server: - - P->A: INVITE sip:watson@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 - To: T. Watson - Call-ID: 31415@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@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 - To: T. Watson - Call-ID: 31415@c.bell-tel.com - CSeq: 1 INVITE - - P->Y: INVITE sip:watson@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 - To: T. Watson - Call-ID: 31415@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 - To: T. Watson ;tag=192137601 - Call-ID: 31415@c.bell-tel.com - CSeq: 1 INVITE - Contact: sip:t.watson@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@y.bell-tel.com - From: A. Bell - To: T. Watson ;tag=35253448 - Call-ID: 31415@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@acm.org SIP/2.0 - Via: SIP/2.0/UDP sip.ieee.org ;branch=2 - From: A. Bell - To: T. Watson - Call-ID: 31415@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 - To: T. Watson - - - -Handley, et al. Standards Track [Page 128] - -RFC 2543 SIP: Session Initiation Protocol March 1999 - - - Call-ID: 31415@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@x.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP c.bell-tel.com - From: A. Bell - To: T. Watson ;tag=192137601 - Call-ID: 31415@c.bell-tel.com - CSeq: 1 ACK - - C->Y: ACK sip:watson@y.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP c.bell-tel.com - From: A. Bell - To: T. Watson ;tag=35253448 - Call-ID: 31415@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@y.bell-tel.com SIP/2.0 - Via: SIP/2.0/UDP c.bell-tel.com - From: A. Bell - To: T. Watson ;tag=35253448 - Call-ID: 31415@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 - To: T. Watson ;tag=35253448 - Call-ID: 31415@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 - To: T. Watson ;tag=72538263 - Call-ID: 31415@c.bell-tel.com - CSeq: 1 INVITE - Contact: sip:watson@h.bell-tel.com, - sip:watson@acm.org, sip:t.watson@x.bell-tel.com, - sip:watson@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 - To: Alice ;tag=2332462 - Call-ID: 27182@caller.com - Contact: sip:bob@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@anywhere.com SIP/2.0 - From: sip:charlie@caller.com - To: sip:alice@anywhere.com - Call-ID: 27182@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@anywhere.com SIP/2.0 - From: sip:charlie@caller.com - To: Alice - Call-ID: 27182@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@caller.com - To: Alice - Call-ID: 27182@caller.com - CSeq: 1 INVITE - Contact: - - - - 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@anywhere.com SIP/2.0 - From: sip:charlie@caller.com - To: Alice - Call-ID: 27182@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@isi.edu - To: ;tag=7434264 - Call-ID: 14142@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@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@example.com SIP/2.0 - From: Alice - To: Bob - Call-ID: 6378@host.anywhere.org - CSeq: 1 OPTIONS - Accept: application/sdp - - S->C: SIP/2.0 200 OK - From: Alice - To: Bob ;tag=376364382 - - - -Handley, et al. Standards Track [Page 132] - -RFC 2543 SIP: Session Initiation Protocol March 1999 - - - Call-ID: 6378@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 "*element" indicating at least and at most - 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: "(element)" is equivalent to - "*(element)"; that is, exactly 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 "# element" indicating at least - and at most 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 = - CHAR = - 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 = - 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 = - - - 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 = > - - - 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@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@aciri.org - - Henning Schulzrinne - Dept. of Computer Science - Columbia University - 1214 Amsterdam Avenue - New York, NY 10027 - USA - Email: schulzrinne@cs.columbia.edu - - Eve Schooler - Computer Science Department 256-80 - California Institute of Technology - Pasadena, CA 91125 - USA - Email: schooler@cs.caltech.edu - - Jonathan Rosenberg - Lucent Technologies, Bell Laboratories - Rm. 4C-526 - 101 Crawfords Corner Road - Holmdel, NJ 07733 - USA - Email: jdrosen@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] diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/run-tests b/libs/sofia-sip/libsofia-sip-ua/sip/run-tests deleted file mode 100755 index ac6c41b592..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/run-tests +++ /dev/null @@ -1,47 +0,0 @@ -#! /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 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# as published by the Free Software Foundation; either version 2.1 of -# the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/run_test_date b/libs/sofia-sip/libsofia-sip-ua/sip/run_test_date deleted file mode 100755 index f92bb64b0a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/run_test_date +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -./test_date "Sun, 18 Mar 2001 23:01:00 GMT" diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/run_test_sip_msg b/libs/sofia-sip/libsofia-sip-ua/sip/run_test_sip_msg deleted file mode 100755 index 0ca2c88915..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/run_test_sip_msg +++ /dev/null @@ -1,88 +0,0 @@ -#! /bin/sh -# -# Run the parser tests -# -# usage: env srcdir=dir run_sip_test_msg -# -# -------------------------------------------------------------------- -# -# This file is part of the Sofia-SIP package -# -# Copyright (C) 2005 Nokia Corporation. -# -# Contact: Pekka Pessi -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public License -# as published by the Free Software Foundation; either version 2.1 of -# the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -# -# -------------------------------------------------------------------- -# - -rc=0 - -if test ! -d "${srcdir:=.}/tests" -then - echo Please set environment variable srcdir - exit 77 -fi - -test=./test_sip_msg - -# These are messages that the parser should pass -good="-t test1.txt test2.txt test3.txt test4.txt - -u test5.txt -t test6.txt test7.txt -u test8.txt -t test9.txt - test14.txt test20.txt test23.txt test24.txt test31.txt - own1.txt own2.txt own3.txt own4.txt own5.txt own6.txt" -# These are messages that the parser should fail -bad="test10.txt test11.txt test12.txt test13.txt test15.txt - test16.txt test17.txt test18.txt test19.txt - test21.txt test22.txt - test26.txt test29.txt test33.txt - test35.txt - test40.txt" -# These are ugly messages that parser should pass -ugly="-t test25.txt -u test27.txt test28.txt -t test30.txt - -u test32.txt test34.txt -t test36.txt -u test37.txt - test38.txt test39.txt test41.txt test42.txt" - -# These are messages that parser should pass, but it does not -goodish="" -# These are messages that parser should not pass, but it does -baddish="" - -flag=-t -for n in $good $ugly; -do - if test $n = -t ; then - flag=$n - elif test $n = -u ; then - flag= - elif "$test" $flag < "$srcdir/tests/$n" > /dev/null ; then - echo "PASS: $n" - else - echo "ERROR: $n"; rc=1 - fi -done - -for n in $bad; -do - if "$test" -t < "$srcdir/tests/$n" > /dev/null 2>/dev/null ; then - echo "ERROR: $n (no error detected)"; rc=1 - else - echo "PASS: $n" - fi -done - -exit $rc diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs b/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs deleted file mode 100644 index 3e73b0384a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip.docs +++ /dev/null @@ -1,608 +0,0 @@ -/* -*- 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 - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - * - * @section sip_overview Overview - * - * The structure of each header is defined in @b . 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 - * . For header @c X, there are types, functions, - * macros and header class declared in and - * . 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 . 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 . 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@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 ;tag=77241a86 - * To: Joe User ;tag=7c6276c1 - * Call-ID: 4c4e911b@pc104.example.edu - * CSeq: 2 - * @endcode - * - * The figure below shows the layout of the BYE message above after parsing: - * - * @image html sip-parser2.gif BYE message and its representation in C - * @image latex sip-parser2.eps BYE message and its representation in C - * - * The leftmost box represents the message of type #msg_t. Next box from - * the left reprents the #sip_t structure, which contains pointers to a - * header objects. The next column contains the header objects. There is - * one header object for each message fragment. The rightmost box represents - * the I/O buffer used when the message was received. Note that the I/O - * buffer may be non-continous and composed of many separate memory areas. - * - * The message object has link to the public message structure (@a - * m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O - * buffer (@a m_buffer). The public message 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 and 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 . - */ - -/**@defgroup sip_tag SIP Tags - * - * SIP headers in tag item lists and tagged argument lists. - * - * The include file 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". - * - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases b/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases deleted file mode 100644 index 9acd3f00f3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip.doxyaliases +++ /dev/null @@ -1,74 +0,0 @@ -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\"" \ - "AlertInfo=@ref sip_alert_info \"Alert-Info\"" \ - "ReplyTo=@ref sip_reply_to \"Reply-To\"" \ - "SuppressBodyIfMatch=@ref sip_suppress_body_if_match \"Suppress-Body-If-Match\"" \ - "SuppressNotifyIfMatch=@ref sip_suppress_notify_if_match \"Suppress-Notify-If-Match\"" \ - "RemotePartyID=@ref sip_remote_party_id \"Remote-Party-ID\"" \ - "PAssertedIdentity=@ref sip_p_asserted_identity \"P-Asserted-Identity\"" \ - "PPreferredIdentity=@ref sip_p_preferred_identity \"P-Preferred-Identity\"" \ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask b/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask deleted file mode 100644 index 1d3eefa160..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_bad_mask +++ /dev/null @@ -1,102 +0,0 @@ -# -# nta has an error 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 for definition of mask values. -# -# The error flags for a particular header 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(). -# - -# -# When updating this file, please update -# NTATAG_BAD_RESP_MASK()/NTATAG_BAD_REQ_MASK() documentation, too. -# - -# -# 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 -# -Contact = sip_mask_ua | sip_mask_proxy | sip_mask_registrar -Require = sip_mask_ua | sip_mask_registrar | sip_mask_timer -Record-Route = sip_mask_ua | sip_mask_proxy - -Expires = sip_mask_registrar | sip_mask_events - -# Nothing bad can happen if something looks like it is not Supported -# Supported = sip_mask_ua | sip_mask_proxy | sip_mask_registrar - -# -# 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c deleted file mode 100644 index 0dc57fd680..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c +++ /dev/null @@ -1,2914 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include - -#include "sofia-sip/sip_parser.h" -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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 = (sip_request_t *)h; - 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 = (sip_request_t *)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 sip_request_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_request_t const *rq = (sip_request_t *)h; - - 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 = (sip_request_t *)dst; - sip_request_t const *o = (sip_request_t *)src; - 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_request_t *)sip_header_alloc(home, sip_request_class, xtra); - - 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 = (sip_status_t *)h; - 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) -{ - sip_status_t const *st = (sip_status_t *)h; - int status; - - assert(sip_is_status(h)); - - 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 #sip_status_t object. */ -isize_t sip_status_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_status_t const *st = (sip_status_t *)h; - 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 = (sip_status_t *)dst; - sip_status_t const *o = (sip_status_t *)src; - 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_status_t *)sip_header_alloc(home, sip_status_class, 0))) { - 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 = (sip_payload_t *)h; - - 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_separator_t *) - sip_header_alloc(home, sip_separator_class, 0); - - 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 ( name-addr | addr-spec ) 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 */ - /* Do not accept an empty URL */ - if (addr_spec[0] == '\0') - return -1; - 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; -} - -/** Calculate the extra size needed to duplicate a name-addr-params construct. - * - * @param display display name (may be NULL) - * @param addr pointer to URL structure - * @param params pointer to parameter list (may be NULL) - * @param offset base offset - * - * @retval Size of duplicated name-addr-params construct, including base offset. - * - * @NEW_1_12_7. - */ -isize_t sip_name_addr_xtra(char const *display, url_t const *addr, - msg_param_t const params[], - isize_t offset) -{ - SIP_PARAMS_SIZE(offset, params); - offset += SIP_STRING_SIZE(display); - offset += url_xtra(addr); - return offset; -} - -/**Duplicate a name-addr-params construct. - * - * @param d_display value-result parameter for copied @e name (may be NULL) - * @param display display name (may be NULL) - * @param d_addr value-result parameter for copied @e address - * @param addr pointer to URL address structure - * @param d_params value-result parameter for copied parameters (may be NULL) - * @param params pointer to parameter list (may be NULL) - * @param b pointer to memory pool - * @param xtra size of the memory pool - * - * @retval End of the memory area used. - * - * @NEW_1_12_7. - */ -char *sip_name_addr_dup(char const **d_display, char const *display, - url_t *d_addr, url_t const *addr, - msg_param_t const **d_params, msg_param_t const params[], - char *b, isize_t xtra) -{ - char *end = b + xtra; - - if (d_params) - b = msg_params_dup(d_params, params, b, xtra); - - URL_DUP(b, end, d_addr, addr); - - if (d_display) - MSG_STRING_DUP(b, *d_display, display); - - assert(b <= end); - - return b; -} - - -/** Parse @To or @From headers */ -static 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; - - return sip_name_addr_xtra(a->a_display, - a->a_url, - a->a_params, - 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; - - return sip_name_addr_dup(&a->a_display, o->a_display, - a->a_url, o->a_url, - &a->a_params, o->a_params, - b, xtra); -} - -/** 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") && su_casenmatch(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, hc, n); - - if (h) { - sip_addr_t *a = (sip_to_t *)h; - 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 (su_casematch(a->a_tag, value)) - 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 = (sip_call_id_t *)h; - - 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) -{ - sip_call_id_t const *i = (sip_call_id_t *)h; - size_t n = strlen(i->i_id); - - if (bsiz > n) - strcpy(b, i->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 = (sip_call_id_t *)h; - 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 = (sip_call_id_t *)dst; - sip_call_id_t const *o = (sip_call_id_t *)src; - 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_call_id_t *)sip_header_alloc(home, sip_call_id_class, xtra); - - 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 = (sip_cseq_t *)h; - - 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) -{ - sip_cseq_t const *cs = (sip_cseq_t *)h; - - assert(sip_is_cseq(h)); - - return snprintf(b, bsiz, "%u %s", cs->cs_seq, cs->cs_method_name); -} - -isize_t sip_cseq_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_cseq_t const *cs = (sip_cseq_t *)h; - 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 = (sip_cseq_t *)dst; - sip_cseq_t const *o = (sip_cseq_t *)src; - 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((sip_method_t)method, method_name); - - if (method_name == NULL) - return NULL; - - xtra = (method ? 0 : (strlen(method_name) + 1)); - - cs = (sip_cseq_t *)sip_header_alloc(home, sip_cseq_class, xtra); - - if (cs) { - cs->cs_seq = seq; - cs->cs_method = (sip_method_t)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 . 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 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; - - assert(h); - for(;;) { - - m = (sip_contact_t *)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; - - msg_parse_next_field_without_recursion(); - } - -} - - -issize_t sip_contact_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - sip_contact_t const *m = (sip_contact_t *)h; - 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 = (sip_contact_t *)h; - - return sip_name_addr_xtra(m->m_display, - m->m_url, - m->m_params, - offset) - + MSG_STRING_SIZE(m->m_comment); -} - -char *sip_contact_dup_one(sip_header_t *dst, sip_header_t const *src, - char *b, isize_t xtra) -{ - sip_contact_t *m = (sip_contact_t *)dst; - sip_contact_t const *o = (sip_contact_t *)src; - - b = sip_name_addr_dup(&m->m_display, o->m_display, - m->m_url, o->m_url, - &m->m_params, o->m_params, - b, xtra); - MSG_STRING_DUP(b, m->m_comment, o->m_comment); - 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 && su_casenmatch(name, "q", 1)) { - /* XXX - check for invalid value? */ - m->m_q = value; - } - else if (namelen == strlen("expires") && - su_casenmatch(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) -{ - sip_content_length_t *l = (sip_content_length_t *)h; - issize_t retval = msg_uint32_d(&s, &l->l_length); - if (*s) - retval = -1; - return retval; -} - -issize_t sip_content_length_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - sip_content_length_t const *l = (sip_content_length_t const *)h; - assert(sip_is_content_length(h)); - return snprintf(b, bsiz, "%lu", (unsigned long)l->l_length); -} - -/**@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_content_length_t *) - sip_header_alloc(home, sip_content_length_class, 0); - - 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 = (sip_date_t *)h; - - 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 = (sip_date_t *)h; - - 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_date_t *d = (sip_date_t *)sip_header_alloc(home, sip_date_class, 0); - - if (d) { - if (date == 0) - date = sip_now(); - d->d_time = date; - } - - return d; -} - -/* ====================================================================== */ - -/**@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 = (sip_expires_t *)h; - - 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 = (sip_expires_t *)h; - - 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_expires_t *ex = (sip_expires_t *) - sip_header_alloc(home, sip_expires_class, 0); - - if (ex) - ex->ex_delta = delta; - - return ex; -} - -/* ====================================================================== */ - -/**@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 = (sip_retry_after_t *)h; - - 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 = (sip_retry_after_t *)h; - 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 = (sip_retry_after_t *)h; - - 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 = (sip_retry_after_t *)dst; - sip_retry_after_t const *o = (sip_retry_after_t *)src; - 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") && - su_casenmatch(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; - - - assert(h); - for (;;) { - r = (sip_route_t *)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; - } - - msg_parse_next_field_without_recursion(); - } - -} - -issize_t sip_any_route_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - sip_route_t const *r = (sip_route_t *)h; - - 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 = (sip_route_t *)h; - return sip_name_addr_xtra(r->r_display, - r->r_url, - r->r_params, - 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 = (sip_route_t *)dst; - sip_route_t const *o = (sip_route_t *)src; - return sip_name_addr_dup(&r->r_display, o->r_display, - r->r_url, o->r_url, - &r->r_params, o->r_params, - b, xtra); -} - -#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 = (sip_record_route_t *)h)) { - 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 - * 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 . 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; - - assert(h); - for (;;) { - v = (sip_via_t *)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; - - msg_parse_next_field_without_recursion(); - } -} - -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 = (sip_via_t *)h; - - 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 = (sip_via_t *)h; - - 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 = (sip_via_t *)dst; - sip_via_t const *o = (sip_via_t *)src; - 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) && su_casenmatch(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 = (sip_via_t *)msg_header_dup_as(home, sip_via_class, (sip_header_t *)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 is not UDP. - * If 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 || - su_casematch(v->v_protocol, sip_transport_udp)) - 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 */ -} - -/**@SIP_HEADER sip_identity Identity Header - * - * The Identity header field specifies the "logical" recipient of the - * request. It is defined in @RFC8224 with semantics shown below, - * though for now it's parsed to a single 'value' field. - * - * @code - * Identity = "Identity" HCOLON signed-identity-digest SEMI - * ident-info *( SEMI ident-info-params ) - * signed-identity-digest = 1*(base64-char / ".") - * ident-info = "info" EQUAL ident-info-uri - * ident-info-uri = LAQUOT absoluteURI RAQUOT - * ident-info-params = ident-info-alg / ident-type / - * ident-info-extension - * ident-info-alg = "alg" EQUAL token - * ident-type = "ppt" EQUAL token - * ident-info-extension = generic-param - * - * base64-char = ALPHA / DIGIT / "/" / "+" - * @endcode - * - * The parsed Identity header is stored in #sip_identity_t structure. - */ - -/**@ingroup sip_identity - * @typedef typedef struct sip_identity_s sip_identity_t; - * - * The structure #sip_identity_t contains representation of @Identity header. - * - * The #sip_identity_t is defined as follows: - * @code - * typedef struct { - * sip_common_t id_common[1]; // Common fragment info - * sip_error_t *id_next; // Link to next (dummy) - * char const *id_value; // Identity - * char const *id_info; // Info param containing URL of the cert, with no '<','>' - * } sip_identity_t; - * @endcode - * - */ - -static msg_xtra_f sip_identity_dup_xtra; -static msg_dup_f sip_identity_dup_one; -static msg_update_f sip_identity_update; - -msg_hclass_t sip_identity_class[] = -SIP_HEADER_CLASS(identity, "Identity", "", id_common, single, identity); - -issize_t sip_identity_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) -{ - sip_identity_t *id = (sip_identity_t *)h; - char const *p = NULL, *pp = NULL, *ppp = NULL, *ie = NULL; - char *result = NULL; - size_t len = 0; - - id->id_value = strdup(s); - id->id_info = NULL; - - p = strstr(s, "info="); - if (p) { - - ie = strchr(p, ';'); - pp = strchr(p, '<'); - ppp = strchr(p, '>'); - - // allow for a spaces between "info=" and opening '<' - // extract URI from inside "<>" but allow empty - let the higher level app decide what to do about it - if (ie && pp && ppp && (pp < ppp) && (ppp < ie)) { - - len = ppp - pp; - if ((result = malloc(len))) { - memcpy(result, pp + 1, len - 1); - result[len - 1] = '\0'; - id->id_info = result; - } - } - } - - return 0; -} - -issize_t sip_identity_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - sip_identity_t const *id = (sip_identity_t *)h; - - return snprintf(b, bsiz, "%s", id->id_value); -} - -isize_t sip_identity_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_identity_t const *id = (sip_identity_t *)h; - return offset + MSG_STRING_SIZE(id->id_value); -} - -char *sip_identity_dup_one(sip_header_t *dst, sip_header_t const *src, - char *b, isize_t xtra) -{ - sip_identity_t *id = (sip_identity_t *)dst; - sip_identity_t const *o = (sip_identity_t *)src; - - MSG_STRING_DUP(b, id->id_value, o->id_value); - - return b; -} - -static int sip_identity_update(msg_common_t *h, - char const *name, isize_t namelen, - char const *value) -{ - sip_identity_t *id = (sip_identity_t *)h; - - id->id_value = strdup(value); - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c deleted file mode 100644 index b2dc3d8e50..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_caller_prefs.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @author Pekka Pessi - * - * @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 -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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) -{ - for(;;) { - 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 (su_casenmatch(s, "*,", 2)) - 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; */ - msg_parse_next_field_without_recursion(); - } - -} - -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) && su_casenmatch(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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c deleted file mode 100644 index 1d1304b646..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_event.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include -#include -#include - -#include - -/* ====================================================================== */ - -/**@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") && su_casenmatch(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) && su_casenmatch(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); - -su_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; -} - -su_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 (su_casenmatch(pub->pub_params[i], "stream=", strlen("stream="))) - pub->pub_stream = pub->pub_params[i] + strlen("stream="); - else if (su_casenmatch(pub->pub_params[i], "type=", strlen("type="))) - 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c deleted file mode 100644 index 109bea84f2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 "../su/sofia-sip/su_alloc.h" - -#include -#include -#include -#include -#include -# -#include - -/* ====================================================================== */ - -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") && - su_casenmatch(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_alert_info Alert-Info Header - * - * When present in an INVITE request, the Alert-Info header field - * specifies an alternative ring tone to the UAS. When present in a 180 - * (Ringing) response, the Alert-Info header field specifies an - * alternative ringback tone to the UAC. A typical usage is for a proxy - * to insert this header field to provide a distinctive ring feature. - * - * @code - * Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param) - * alert-param = LAQUOT absoluteURI RAQUOT *(SEMI generic-param) - * @endcode - * - * The parsed Alert-Info header is stored in #sip_alert_info_t structure. - * - * @NEW_1_12_7. In order to use @b Alert-Info header, initialize the SIP - * parser before calling nta_agent_create() or nua_create() with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * The #sip_t structure does not contain a @a sip_alert_info field, but - * sip_alert_info() function should be used for accessing the @b Alert-Info - * header structure. - */ - -/**@ingroup sip_alert_info - * @typedef struct sip_alert_info_s sip_alert_info_t; - * - * The structure #sip_alert_info_t contains representation of an - * @AlertInfo header. - * - * The #sip_alert_info_t is defined as follows: - * @code - * struct sip_alert_info_s - * { - * sip_common_t ai_common[1]; // Common fragment info - * sip_alert_info_t *ai_next; // Link to next @AlertInfo - * url_t ai_url[1]; // URI to alert info - * msg_param_t const *ai_params; // List of optional parameters - * }; - * @endcode - * - * @NEW_1_12_7. - */ - -msg_hclass_t sip_alert_info_class[] = -SIP_HEADER_CLASS(alert_info, "Alert-Info", "", - ai_params, append, info); - -issize_t sip_alert_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_alert_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f) -{ - sip_alert_info_t *ai = (sip_alert_info_t *)h; - return sip_name_addr_e(b, bsiz, f, NULL, 1, ai->ai_url, ai->ai_params, NULL); -} - -/* ====================================================================== */ - -/**@SIP_HEADER sip_reply_to Reply-To Header - * - * The @b Reply-To header field contains a logical return URI that may be - * different from the @From header field. For example, the URI MAY be used to - * return missed calls or unestablished sessions. If the user wished to - * remain anonymous, the header field SHOULD either be omitted from the - * request or populated in such a way that does not reveal any private - * information. Its syntax is defined in @RFC3261 as follows: - * - * @code - * Reply-To = "Reply-To" HCOLON rplyto-spec - * rplyto-spec = ( name-addr / addr-spec ) - * *( SEMI rplyto-param ) - * rplyto-param = generic-param - * @endcode - * - * The parsed Reply-To header is stored in #sip_reply_to_t structure. - * - * @sa sip_update_default_mclass() - * - * @NEW_1_12_7. In order to use @b Reply-To header, - * initialize the SIP parser before calling nta_agent_create() or - * nua_create() with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t structure does not contain a @a sip_reply_to field, but - * sip_reply_to() function should be used for accessing the @b Reply-To - * header structure. - */ - -/**@ingroup sip_reply_to - * @typedef struct msg_list_s sip_reply_to_t; - * - * The structure #sip_reply_to_t contains representation of SIP - * @ReplyTo header. - * - * The #sip_reply_to_t is defined as follows: - * @code - * struct sip_reply_to_s - * { - * sip_common_t rplyto_common[1]; // Common fragment info - - * sip_reply_to_t *rplyto_next; // Dummy link to next header - * char const *rplyto_display; // Display name - * url_t rplyto_url[1]; // Return URI - * msg_param_t const *rplyto_params; // List of optional parameters - * }; - * @endcode - */ - -static isize_t sip_reply_to_dup_xtra(sip_header_t const *h, isize_t offset); -static char *sip_reply_to_dup_one(sip_header_t *dst, - sip_header_t const *src, - char *b, - isize_t xtra); -#define sip_reply_to_update NULL - -msg_hclass_t sip_reply_to_class[] = - SIP_HEADER_CLASS(reply_to, "Reply-To", "", rplyto_params, single, reply_to); - -issize_t sip_reply_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen) -{ - sip_reply_to_t *rplyto = (sip_reply_to_t *)h; - - return sip_name_addr_d(home, - &s, - &rplyto->rplyto_display, - rplyto->rplyto_url, - &rplyto->rplyto_params, - NULL); -} - -issize_t sip_reply_to_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - sip_reply_to_t *rplyto = (sip_reply_to_t *)h; - - return sip_name_addr_e(b, bsiz, - flags, - rplyto->rplyto_display, - MSG_IS_CANONIC(flags), rplyto->rplyto_url, - rplyto->rplyto_params, - NULL); -} - -static isize_t sip_reply_to_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_reply_to_t const *rplyto = (sip_reply_to_t const *)h; - - return sip_name_addr_xtra(rplyto->rplyto_display, - rplyto->rplyto_url, - rplyto->rplyto_params, - offset); -} - -/**@internal Duplicate one sip_reply_to_t object. */ -static char *sip_reply_to_dup_one(sip_header_t *dst, sip_header_t const *src, - char *b, isize_t xtra) -{ - sip_reply_to_t *rplyto = (sip_reply_to_t *)dst; - sip_reply_to_t const *o = (sip_reply_to_t *)src; - - return sip_name_addr_dup(&rplyto->rplyto_display, o->rplyto_display, - rplyto->rplyto_url, o->rplyto_url, - &rplyto->rplyto_params, o->rplyto_params, - b, xtra); -} - -/* ====================================================================== */ - -/**@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_in_reply_to_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; - char *end; - - for(;;) { - ci = h->sh_call_info; - end = s + slen; - - 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; - - slen = end - s; - msg_parse_next_field_without_recursion(); - } -} - -isize_t sip_info_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_call_info_t const *ci = h->sh_call_info; - - return sip_name_addr_xtra(NULL, - ci->ci_url, - ci->ci_params, - 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; - - return sip_name_addr_dup(NULL, NULL, - ci->ci_url, o->ci_url, - &ci->ci_params, o->ci_params, - b, xtra); -} - -/* ====================================================================== */ - -#if SU_HAVE_EXPERIMENTAL - -/**@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 - * - * @EXP_1_12_5. - * In order to use @b Suppress-Body-If-Match header, - * initialize the SIP parser with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t structure does not contain a @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 - * - * @EXP_1_12_5. - * In order to use @b Suppress-Notify-If-Match header, - * initialize the SIP parser with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t struct 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); -} - -#endif - -#if SIP_HAVE_REMOTE_PARTY_ID - -/**@SIP_HEADER sip_remote_party_id Remote-Party-ID Header - * - * The syntax of the Remote-Party-ID header is described as follows: - * @code - * Remote-Party-ID = "Remote-Party-ID" HCOLON rpid *(COMMA rpid) - * - * rpid = [display-name] LAQUOT addr-spec RAQUOT - * *(SEMI rpi-token) - * - * rpi-token = rpi-screen / rpi-pty-type / - * rpi-id-type / rpi-privacy / other-rpi-token - * - * rpi-screen = "screen" EQUAL ("no" / "yes") - * - * rpi-pty-type = "party" EQUAL ("calling" / "called" / token) - * - * rpi-id-type = "id-type" EQUAL ("subscriber" / "user" / - * "term" / token) - * - * rpi-privacy = "privacy" EQUAL - * ( rpi-priv-element - * / (LDQUOT rpi-priv-element - * *(COMMA rpi-priv-element) RDQUOT) ) - * - * rpi-priv-element = ("full" / "name" / "uri" / "off" / token) - * ["-" ( "network" / token )] - * - * other-rpi-token = ["-"] token [EQUAL (token / quoted-string)] - * - * @endcode - * - * @sa sip_update_default_mclass(), draft-ietf-sip-privacy-04.txt, @RFC3325 - * - * @NEW_1_12_7. In order to use @b Remote-Party-ID header, - * initialize the SIP parser before calling nta_agent_create() or - * nua_create() with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t structure does not contain @a sip_remote_party_id field, but - * sip_remote_party_id() function should be used for accessing the @b - * Remote-Party-ID header structure. - */ - -/**@ingroup sip_remote_party_id - * @typedef typedef struct sip_remote_party_id_s sip_remote_party_id_t; - * - * The structure #sip_remote_party_id_t contains representation of SIP - * @RemotePartyID header. - * - * The #sip_remote_party_id_t is defined as follows: - * @code - * typedef struct sip_remote_party_id_s { - * sip_common_t rpid_common[1]; // Common fragment info - * sip_remote_party_id_t *rpid_next; // Link to next - * char const *rpid_display; // Display name - * url_t rpid_url[1]; // URL - * sip_param_t const *rpid_params; // Parameters - * // Shortcuts to screen, party, id-type and privacy parameters - * char const *rpid_screen, *rpid_party, *rpid_id_type, *rpid_privacy; - * } sip_remote_party_id_t; - * @endcode - */ - -extern msg_xtra_f sip_remote_party_id_dup_xtra; -extern msg_dup_f sip_remote_party_id_dup_one; - -static msg_update_f sip_remote_party_id_update; - -msg_hclass_t sip_remote_party_id_class[] = -SIP_HEADER_CLASS(remote_party_id, "Remote-Party-ID", "", - rpid_params, append, remote_party_id); - -issize_t sip_remote_party_id_d(su_home_t *home, sip_header_t *h, - char *s, isize_t slen) -{ - sip_remote_party_id_t *rpid; - - for(;;) { - rpid = (sip_remote_party_id_t *)h; - - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; - - if (sip_name_addr_d(home, &s, - &rpid->rpid_display, - rpid->rpid_url, - &rpid->rpid_params, NULL) == -1) - return -1; - - msg_parse_next_field_without_recursion(); - } - -} - -issize_t sip_remote_party_id_e(char b[], isize_t bsiz, - sip_header_t const *h, int f) -{ - sip_remote_party_id_t const *rpid = (sip_remote_party_id_t *)h; - - return sip_name_addr_e(b, bsiz, f, - rpid->rpid_display, 1, - rpid->rpid_url, - rpid->rpid_params, - NULL); -} - -/** Calculate size of extra data required for duplicating one - * sip_remote_party_id_t header. - */ -isize_t sip_remote_party_id_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_remote_party_id_t const *rpid = (sip_remote_party_id_t *)h; - return sip_name_addr_xtra(rpid->rpid_display, - rpid->rpid_url, - rpid->rpid_params, - offset); -} - -/** Duplicate one sip_remote_party_id_t object */ -char *sip_remote_party_id_dup_one(sip_header_t *dst, - sip_header_t const *src, - char *b, isize_t xtra) -{ - sip_remote_party_id_t *rpid = (sip_remote_party_id_t *)dst; - sip_remote_party_id_t const *o = (sip_remote_party_id_t const *)src; - - return sip_name_addr_dup(&rpid->rpid_display, o->rpid_display, - rpid->rpid_url, o->rpid_url, - &rpid->rpid_params, o->rpid_params, - b, xtra); -} - -static int sip_remote_party_id_update(msg_common_t *h, - char const *name, isize_t namelen, - char const *value) -{ - sip_remote_party_id_t *rpid = (sip_remote_party_id_t *)h; - - if (name == NULL) { - rpid->rpid_screen = NULL; - rpid->rpid_party = NULL; - rpid->rpid_id_type = NULL; - rpid->rpid_privacy = NULL; - } - -#define MATCH(s) (namelen == strlen(#s) && su_casenmatch(name, #s, strlen(#s))) - - else if (MATCH(screen)) - rpid->rpid_screen = value; - else if (MATCH(party)) - rpid->rpid_party = value; - else if (MATCH(id-type)) - rpid->rpid_id_type = value; - else if (MATCH(privacy)) - rpid->rpid_privacy = value; - -#undef MATCH - - return 0; -} - -#endif - -#if SIP_HAVE_P_ASSERTED_IDENTITY - -/**@SIP_HEADER sip_p_asserted_identity P-Asserted-Identity Header - * - * The P-Asserted-Identity header is used used among trusted SIP entities - * (typically intermediaries) to carry the identity of the user sending a - * SIP message as it was verified by authentication. It is "defined" in - * @RFC3325 section 9.1 as follows: - * - * @code - * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value - * *(COMMA PAssertedID-value) - * PAssertedID-value = name-addr / addr-spec - * @endcode - * - * @sa @RFC3325, @PPreferredIdentity - * - * @NEW_1_12_7. In order to use @b P-Asserted-Identity header, - * initialize the SIP parser before calling nta_agent_create() or - * nua_create() with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t structure does not contain @a sip_p_asserted_identity field, - * but sip_p_asserted_identity() function should be used for accessing the - * @b P-Asserted-Identity header structure. - */ - -/**@ingroup sip_p_asserted_identity - * @typedef typedef struct sip_p_asserted_identity_s sip_p_asserted_identity_t; - * - * The structure #sip_p_asserted_identity_t contains representation of SIP - * @PAssertedIdentity header. - * - * The #sip_p_asserted_identity_t is defined as follows: - * @code - * typedef struct sip_p_asserted_identity_s { - * sip_common_t paid_common[1]; // Common fragment info - * sip_p_asserted_identity_t *paid_next; // Link to next - * char const *paid_display; // Display name - * url_t paid_url[1]; // URL - * } sip_p_asserted_identity_t; - * @endcode - */ - -static msg_xtra_f sip_p_asserted_identity_dup_xtra; -static msg_dup_f sip_p_asserted_identity_dup_one; - -#define sip_p_asserted_identity_update NULL - -msg_hclass_t sip_p_asserted_identity_class[] = -SIP_HEADER_CLASS(p_asserted_identity, "P-Asserted-Identity", "", - paid_common, append, p_asserted_identity); - -issize_t sip_p_asserted_identity_d(su_home_t *home, sip_header_t *h, - char *s, isize_t slen) -{ - sip_p_asserted_identity_t *paid; - - for(;;) { - paid = (sip_p_asserted_identity_t *)h; - while (*s == ',') /* Ignore empty entries (comma-whitespace) */ - *s = '\0', s += span_lws(s + 1) + 1; - - if (sip_name_addr_d(home, &s, - &paid->paid_display, - paid->paid_url, - NULL, NULL) == -1) - return -1; - - msg_parse_next_field_without_recursion(); - } - -} - -issize_t sip_p_asserted_identity_e(char b[], isize_t bsiz, - sip_header_t const *h, int f) -{ - sip_p_asserted_identity_t const *paid = (sip_p_asserted_identity_t *)h; - - return sip_name_addr_e(b, bsiz, f, - paid->paid_display, MSG_IS_CANONIC(f), - paid->paid_url, - NULL, - NULL); -} - -isize_t sip_p_asserted_identity_dup_xtra(sip_header_t const *h, isize_t offset) -{ - sip_p_asserted_identity_t const *paid = (sip_p_asserted_identity_t *)h; - - return sip_name_addr_xtra(paid->paid_display, - paid->paid_url, - NULL, - offset); -} - -/** Duplicate one sip_p_asserted_identity_t object */ -char *sip_p_asserted_identity_dup_one(sip_header_t *dst, - sip_header_t const *src, - char *b, isize_t xtra) -{ - sip_p_asserted_identity_t *paid = (sip_p_asserted_identity_t *)dst; - sip_p_asserted_identity_t const *o = (sip_p_asserted_identity_t *)src; - - return sip_name_addr_dup(&paid->paid_display, o->paid_display, - paid->paid_url, o->paid_url, - NULL, NULL, - b, xtra); -} - -#endif - -#if SIP_HAVE_P_PREFERRED_IDENTITY - -/**@SIP_HEADER sip_p_preferred_identity P-Preferred-Identity Header - * - * The P-Preferred-Identity header is used used among trusted SIP entities - * (typically intermediaries) to carry the identity of the user sending a - * SIP message as it was verified by authentication. It is "defined" in - * @RFC3325 section 9.1 as follows: - * - * @code - * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value - * *(COMMA PPreferredID-value) - * PPreferredID-value = name-addr / addr-spec - * @endcode - * - * @sa @RFC3325, @PAssertedIdentity - * - * @NEW_1_12_7. In order to use @b P-Preferred-Identity header, - * initialize the SIP parser before calling nta_agent_create() or - * nua_create() with, e.g., - * sip_update_default_mclass(sip_extend_mclass(NULL)). - * - * @note - * The #sip_t structure does not contain @a sip_p_preferred_identity field, - * but sip_p_preferred_identity() function should be used for accessing the - * @b P-Preferred-Identity header structure. - */ - -/**@ingroup sip_p_preferred_identity - * @typedef typedef struct sip_p_preferred_identity_s sip_p_preferred_identity_t; - * - * The structure #sip_p_preferred_identity_t contains representation of SIP - * @PPreferredIdentity header. - * - * The #sip_p_preferred_identity_t is defined as follows: - * @code - * typedef struct sip_p_preferred_identity_s { - * sip_common_t ppid_common[1]; // Common fragment info - * sip_p_preferred_identity_t *ppid_next; // Link to next - * char const *ppid_display; // Display name - * url_t ppid_url[1]; // URL - * } sip_p_preferred_identity_t; - * @endcode - */ - - -msg_hclass_t sip_p_preferred_identity_class[] = -SIP_HEADER_CLASS(p_preferred_identity, "P-Preferred-Identity", "", - ppid_common, append, p_asserted_identity); - -issize_t sip_p_preferred_identity_d(su_home_t *home, sip_header_t *h, - char *s, isize_t slen) -{ - return sip_p_asserted_identity_d(home, h, s, slen); -} - -issize_t sip_p_preferred_identity_e(char b[], isize_t bsiz, - sip_header_t const *h, int f) -{ - return sip_p_asserted_identity_e(b, bsiz, h, f); -} - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt b/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt deleted file mode 100644 index b20e6f4511..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_extra_headers.txt +++ /dev/null @@ -1,34 +0,0 @@ -# -# This file specifies extra SIP headers not included in sip_t structure -# -# The parsed headers are accessed with function (or macro) like sip_refer_sub() -# e.g., sip_refer_sub_t *rsub = sip_refer_sub(sip); -# -# The line format is: -# C-name @SINCE sip_t-like-comment -# -# Put all experimental things after EXPERIMENTAL HEADER LIST STARTS HERE... -# -#### EXTRA HEADER LIST STARTS HERE #### - -refer_sub @NEW_1_12_5 /**< Refer-Sub header */ - -#### DEFAULT HEADER LIST ENDS HERE #### - -# -# These headers are added to the extended parser, installed -# as default with sip_update_default_mclass(NULL) -# - -alert_info @NEW_1_12_7 /**< Alert-Info header */ -reply_to @NEW_1_12_7 /**< Reply-To header */ -remote_party_id @NEW_1_12_7 /**< Remote-Party-ID header */ -p_asserted_identity @NEW_1_12_7 /** - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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 { - int method = (int)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) -{ - int meth = method; - - if (meth < sip_method_unknown || !allow) - return 0; - - if (sip_method_unknown < meth && meth < 32) - /* Well-known method */ - return (allow->k_bitmap & (1 << meth)) != 0; - - if (meth == 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 not 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 not 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); -} - - -/** Check if required features are not 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 (su_casematch(feature, slist[j])) { - feature = NULL; - break; - } - - if (feature) - for (j = 0; rlist[j]; j++) - if (su_casematch(feature, rlist[j])) { - feature = NULL; - break; - } - - if (feature) - for (j = 0; prlist[j]; j++) - if (su_casematch(feature, prlist[j])) { - 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 (su_casematch(feature, supported->k_items[i])) - 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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c deleted file mode 100644 index 66100a9d3e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_header.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include "sofia-sip/sip_parser.h" -#include - -#include -#include -#include -#include -#include -#include - -#include - -/** 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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_inlined.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_inlined.c deleted file mode 100644 index 55ec8d6d12..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_inlined.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2007 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_inlined.c - * - * Expand inlined sip functions non-inline. - * - */ - -#include "config.h" - -#include - -#if SU_HAVE_INLINE -extern int xyzzy; -#else -#include "sofia-sip/msg_header.h" -#include "sofia-sip/su_tag.h" - -#undef SU_HAVE_INLINE -#undef su_inline - -#define SU_HAVE_INLINE 1 -#define su_inline - -#include "sofia-sip/sip_protos.h" -#include "sofia-sip/sip_extra.h" - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c deleted file mode 100644 index 62286bc0fa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_mime.c +++ /dev/null @@ -1,686 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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; - - assert(h); - - for(;;) { - ad = (sip_accept_disposition_t *)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++; - - msg_parse_next_field_without_recursion(); - } - -} - -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 - * 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) -{ - return msg_content_type_d(home, (msg_header_t *)h, s, slen); -} - -issize_t sip_content_type_e(char b[], isize_t bsiz, sip_header_t const *h, int flags) -{ - return msg_content_type_e(b, bsiz, (msg_header_t const *)h, flags); -} - -static -isize_t sip_content_type_dup_xtra(sip_header_t const *h, isize_t offset) -{ - return msg_content_type_dup_xtra((msg_header_t *)h, 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) -{ - return msg_content_type_dup_one((msg_header_t *)dst, - (msg_header_t const *)src, - b, xtra); -} - -/* ====================================================================== */ - -/**@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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c deleted file mode 100644 index 8f1b0d4110..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include "sofia-sip/sip_parser.h" -#include - -#include -#include -#include -#include -#include -#include - -#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[]; - -static msg_mclass_t const *_default = sip_mclass; -static msg_mclass_t *_default_parser_cloned = NULL; - -/** Return a built-in SIP parser object. */ -msg_mclass_t const *sip_default_mclass(void) -{ - return _default; -} - -/** Release SIP parser object if it was cloned. */ -void sip_cloned_parser_destroy(void) -{ - if (_default_parser_cloned) { - free(_default_parser_cloned); - _default_parser_cloned = NULL; - } -} - -/** Update the default SIP parser. - * - * Use the extended SIP parser as default one. - * - * If the applications want to use headers added after @VERSION_1_12_5, - * they should call this function before doing any other initialization, e.g., - * @code - * su_init(); - * if (sip_update_default_mclass(sip_extend_mclass(NULL)) < 0) { - * su_deinit(); - * exit(2); - * } - * @endcode - * - * The default parser is not extended because it may break the old - * applications looking for extension headers from sip_unknown list. - * - * @retval 0 when successful - * @retval -1 upon an error - * - * @sa sip_extend_mclass() - * - * @NEW_1_12_7. - */ -int sip_update_default_mclass(msg_mclass_t const *mclass) -{ - if (mclass == NULL) - return -1; - _default = mclass; - return 0; -} - -/**Extend SIP parser class with extension headers. - * - * Extend given SIP parser class with extension headers. If the given parser - * (message class) is the default one or NULL, make a clone of default - * parser before extending it. - * - * @param input pointer to a SIP message class (may be NULL) - * - * @return Pointer to extended mclass, or NULL upon an error. - * - * @sa - * @AlertInfo, - * @ReplyTo, - * @RemotePartyId, - * @PAssertedIdentity, - * @PPreferredIdentity, - * @SuppressBodyIfMatch, - * @SuppressNotifyIfMatch - * - * @NEW_1_12_7. - */ -msg_mclass_t *sip_extend_mclass(msg_mclass_t *input) -{ - msg_mclass_t *mclass; - - if (input == NULL || input == _default) { - _default_parser_cloned = msg_mclass_clone(_default, 0, 0); - mclass = _default_parser_cloned; - } else { - mclass = input; - } - - if (mclass) { - extern msg_hclass_t * const sip_extensions[]; - int i; - - for (i = 0; sip_extensions[i]; i++) { - msg_hclass_t *hclass = sip_extensions[i]; - if (mclass->mc_unknown != msg_find_hclass(mclass, hclass->hc_name, NULL)) - continue; - - if (msg_mclass_insert_header(mclass, hclass, 0) < 0) { - if (input != mclass) { - free(mclass); - _default_parser_cloned = NULL; - } - return mclass = NULL; - } - } - } - - return 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 (su_casenmatch(s, sip_version_2_0, version_size) && - !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 (su_casematch(s, sip_version_2_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[] = { - "", - 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 (sip_method_t)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_ws[] = "SIP/2.0/WS"; -char const sip_transport_wss[] = "SIP/2.0/WSS"; -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) \ - (su_casenmatch(s + 7, t + 7, (sizeof t) - 8) && \ - (!s[sizeof(t) - 1] || IS_LWS(s[sizeof(t) - 1])) \ - && (transport = t, s += sizeof(t) - 1)) - - if (!su_casenmatch(s, "SIP/2.0", 7) || - (!TRANSPORT_MATCH(sip_transport_udp) && - !TRANSPORT_MATCH(sip_transport_tcp) && - !TRANSPORT_MATCH(sip_transport_sctp) && - !TRANSPORT_MATCH(sip_transport_ws) && - !TRANSPORT_MATCH(sip_transport_wss) && - !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 (su_casematch(transport, sip_transport_udp)) - transport = sip_transport_udp; - else if (su_casematch(transport, sip_transport_tcp)) - transport = sip_transport_tcp; - else if (su_casematch(transport, sip_transport_sctp)) - transport = sip_transport_sctp; - else if (su_casematch(transport, sip_transport_ws)) - transport = sip_transport_ws; - else if (su_casematch(transport, sip_transport_wss)) - transport = sip_transport_wss; - else if (su_casematch(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_ws || - transport == sip_transport_wss || - transport == sip_transport_tls || - su_casematch(transport, sip_transport_udp) || - su_casematch(transport, sip_transport_tcp) || - su_casematch(transport, sip_transport_sctp) || - su_casematch(transport, sip_transport_ws) || - su_casematch(transport, sip_transport_wss) || - su_casematch(transport, sip_transport_tls)) - 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 (s == sip_transport_ws) - *dd = s; - else if (s == sip_transport_wss) - *dd = s; - else if (su_casematch(s, sip_transport_udp)) - *dd = sip_transport_udp; - else if (su_casematch(s, sip_transport_tcp)) - *dd = sip_transport_tcp; - else if (su_casematch(s, sip_transport_sctp)) - *dd = sip_transport_sctp; - else if (su_casematch(s, sip_transport_tls)) - *dd = sip_transport_tls; - else if (su_casematch(s, sip_transport_ws)) - *dd = sip_transport_ws; - else if (su_casematch(s, sip_transport_wss)) - *dd = sip_transport_wss; - else - MSG_STRING_DUP(*pp, *dd, s); -} - -/** Parse SIP 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs b/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs deleted file mode 100644 index 576b3f51b2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser.docs +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- 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 . - */ - -#ifndef SIP_EXAMPLE_H -/** Defined when has been included. */ -#define SIP_EXAMPLE_H - -/**@file sofia-sip/sip_example.h -* - * @brief Example header. - * - * #AUTO# - * - * @author Pekka Pessi . - * - * @date Created: Fri May 27 18:40:38 EEST 2005 ppessi - */ - -#ifndef SIP_H -#include -#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 - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in b/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in deleted file mode 100644 index 05ffd745b8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_parser_table.c.in +++ /dev/null @@ -1,56 +0,0 @@ -/**@IFILE sip_parser_table.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Tue Oct 1 20:28:59 2002 ppessi - */ - -#include "config.h" - -#include -#include - -/* 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 -#include -#include - - - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c deleted file mode 100644 index 5226ee4d4d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_prack.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c deleted file mode 100644 index 0535e36bc7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_pref_util.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Tue Nov 2 16:39:33 EET 2004 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "sofia-sip/sip_parser.h" -#include -#include -#include - -static double parse_number(char const *str, char **return_end); - -/** 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' || - su_casematch(s, "TRUE") || - su_casematch(s, "\"TRUE\"")) { - /* 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 (su_casematch(s, "FALSE") || - su_casematch(s, "\"FALSE\"")) { - /* 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 = parse_number(s = s + 1, &e); - else if (s0 == '<' && s[1] == '=') - sp->sp_type = sp_range, n1 = -DBL_MAX, n2 = parse_number(s = s + 2, &e); - else if (s0 == '>' && s[1] == '=') - sp->sp_type = sp_range, n1 = parse_number(s = s + 2, &e), n2 = DBL_MAX; - else if (((n1 = parse_number(s, &e)) != 0.0 || s != e) && e[0] == ':') - sp->sp_type = sp_range, n2 = parse_number(s = e + 1, &e); - else - /* Error in conversion */ - sp->sp_type = sp_error, n1 = DBL_MAX, n2 = -DBL_MAX; - - 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; -} - -/** Parse number: - * number = [ "+" / "-" ] 1*DIGIT ["." 0*DIGIT] - */ -static double parse_number(char const *str, char **return_end) -{ - double value = 0.0; - double decimal = 0.1; - char d, sign = '+'; - - if (return_end) - *return_end = (char *)str; - - d = *str; - - if (d == '+' || d == '-') - sign = d, d = *++str; - - if (!('0' <= d && d <= '9')) - return value; - - for (; '0' <= d && d <= '9'; d = *++str) - value = value * 10 + (d - '0'); - - if (d == '.') for (d = *++str; '0' <= d && d <= '9'; d = *++str) { - value += (d - '0') * decimal; decimal *= 0.1; - } - - if (value > DBL_MAX) - value = DBL_MAX; - - if (sign == '-') - value = -value; - - if (return_end) - *return_end = (char *)str; - - return value; -} - - -/** 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 && - su_casenmatch(a->sp_literal.spl_value, b->sp_literal.spl_value, - a->sp_literal.spl_length); - 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) \ - (su_casenmatch(¶m[1], &s[1], strlen(s) - 1) && \ - (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 @RFC3841 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(), - * @RFC3841, @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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c deleted file mode 100644 index 995fd8c816..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_reason.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - */ - -#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 -#include -#include -#include -#include - -#include - -/**@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 - * 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; - size_t n; - for (;;) { - re = (sip_reason_t *)h; - - 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; - - msg_parse_next_field_without_recursion(); - } - - -} - -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) && su_casenmatch(name, #s, strlen(#s))) - - else if (MATCH(cause)) { - re->re_cause = value; - } - else if (MATCH(text)) { - re->re_text = value; - } - -#undef MATCH - - return 0; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c deleted file mode 100644 index a55c9eb1cd..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_refer.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#include -#include -#include -#include - -#include - -/* ====================================================================== */ - -/**@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") && su_casenmatch(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 and exactly - * one , 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 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) && su_casenmatch(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 (!su_casematch(rs->rs_value, "false") && - !su_casematch(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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c deleted file mode 100644 index 69cddff252..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_security.c +++ /dev/null @@ -1,846 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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", append); - -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 \. - * - * 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", append); - -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) -{ - - for (;;) { - 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; - - msg_parse_next_field_without_recursion(); - } - -} - -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) && su_casenmatch(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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c deleted file mode 100644 index 046bb182bf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_session.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 - -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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") && - su_casenmatch(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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c deleted file mode 100644 index 2ea82963e6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Fri Aug 11 18:03:33 2000 ppessi - */ - -#include "config.h" - -#include -#include - -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_607_Unwanted[] = "Unwanted", - 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 607: return sip_607_Unwanted; - case 687: return sip_687_Dialog_terminated; - } - - return ""; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in b/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in deleted file mode 100644 index 7ba015894a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag.c.in +++ /dev/null @@ -1,94 +0,0 @@ -/**@IFILE sip_tag.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Fri Feb 23 12:46:42 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include - -#define TAG_NAMESPACE "sip" - -#include "sofia-sip/sip_parser.h" -#include - -#include -#include -#include - -#include - -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 -}; diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c deleted file mode 100644 index 3fc69e36db..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Fri Feb 23 12:46:42 2001 ppessi - */ - -#include "config.h" - -#include "sofia-sip/sip_parser.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/** Tag class for tags containing SIP headers. @HIDE - * - * Tags in this class are not automatically added to the message with - * sip_add_tl() or sip_add_tagis(). - */ -tag_class_t sipexthdrtag_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 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 (hh == NULL || - (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); - if (hh != NULL && - (char *)hh < ((char *)sip + sip->sip_size) && - (char *)hh >= (char *)&sip->sip_request) { - 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 - * 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(*(const unsigned char *)n)) - *n = tolower(*(const unsigned char *)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 = hnv ? strcspn(hnv, "=") : 0; - if (n == 0) - break; - - if (n == 4 && su_casenmatch(hnv, "body", 4)) - 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 && su_casenmatch(hnv, hc->hc_short, 1)) - break; - else if (n == (size_t)hc->hc_len && - su_casenmatch(hnv, hc->hc_name, n)) - 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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c deleted file mode 100644 index 77fababe6b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_time.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Wed Apr 11 18:57:06 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "sofia-sip/sip_parser.h" -#include -#include -#include - -/** 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c deleted file mode 100644 index a581791574..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @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 -#include -#include - -#include "sofia-sip/sip_parser.h" -#include -#include -#include - -#include -#include - - -#include -#include -#include -#include -#include -#include -#include -#include - -/**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 || - su_casematch(a->a_tag, b->a_tag)) - && - su_casematch(a->a_host, b->a_host) - && - su_strmatch(a->a_user, b->a_user) - && - su_strmatch(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 and 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 || - su_casematch(tp, sip_transport_udp)) /* 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 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 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 && strcmp(port, SIP_DEFAULT_SERV) == 0 && - (host_is_ip_address(host) || host_has_domain_invalid(host))) { - port = NULL; - } - - if (su_casenmatch(transport, "SIP/2.0/", 8)) - transport += 8; - - /* Make transport parameter lowercase */ - if (transport && strlen(transport) < (sizeof _transport)) { - char *s; - short c; - - strcpy(_transport, transport); - - for (s = _transport; (c = *s) && c != ';'; s++) - if (isupper(c)) - *s = tolower(c); - - 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 - su_casenmatch(transport_name, "TLS", 3) || - su_casenmatch(transport_name, sip_transport_tls, 11); -} - -/**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 && - !su_strmatch(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) -{ - 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'; - - assert(SIP_HDR_TEST(h)); - - 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[256]; - ssize_t n; - - 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)) { - memset(rv,0,len); - n = sip_header_field_e(rv, len, 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 ("1" | "." 1,3DIGIT) - * - * @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->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 = su_strcmp(s->sa_mec, v->sa_mec))) - return retval; - - digest = su_casematch(s->sa_mec, "Digest"); - - 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] && - su_casenmatch(v_params[j], "d-ver=", 6)) { - if (return_d_ver) - *return_d_ver = v_params[j] + strlen("d-ver="); - j++; - } - - retval = su_strcmp(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 (su_strmatch(s->sa_mec, c->sa_mec)) - 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. - * - * @RFC5057 - */ -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. - */ - - 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. - */ - - 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. */ - - 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 */ - /** @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. - - Asterisk (v 1.2.7.1) does response with 484 if a client does send a refer - with a @ReferTo header to an unknown number. This is therefore not - fundamentally wrong and the dialog should not be destroyed! - */ - if (method == sip_method_refer) - { - *return_graceful_terminate_usage = 0; - return 0; - } - - case 485: /* Ambiguous */ - - 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; - - case 607: /** @par 607 Unwanted - - This response is similar to 603, except it informs the caller - that the call is unwanted and may be blacklisted. Added by - RFC-8197 - */ - *return_graceful_terminate_usage = 0; - return 0; - } - - /* Do not change graceful_terminate */ - - return 0; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h deleted file mode 100644 index aef7baae0f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h +++ /dev/null @@ -1,943 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_H - -/**@file sofia-sip/sip.h - * - * SIP objects. - * - * @author Pekka Pessi . - * - * @date Created : Thu Jun 8 19:28:55 2000 ppessi - */ - -#ifndef MSG_TYPES_H -#include -#endif -#ifndef MSG_MIME_H -#include -#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 */ -#ifndef _MSC_VER -#define SIP_NONE ((void const *)-1L) -#else -#define SIP_NONE ((void const *)(INT_PTR)-1L) -#endif - -/** SIP protocol identifier @HIDE */ -#ifndef _MSC_VER -#define SIP_PROTOCOL_TAG ((void *)0x53495020) /* 'SIP'20 */ -#else -#define SIP_PROTOCOL_TAG ((void *)(UINT_PTR)0x53495020) /* 'SIP'20 */ -#endif - -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) - -/** Structure for accessing parsed SIP headers. */ -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; - -/* SIP Identity Header, e.g. STIR-Shaken SIP Identity Header, RFC 8224 */ -typedef struct sip_identity_s sip_identity_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_identity_t *sip_identity; /**< Identity */ - 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_identity - * @brief Structure for @Identity SIP header. - */ -struct sip_identity_s -{ - sip_common_t id_common[1]; /**< Common fragment info */ - sip_error_t *id_next; /**< Link to next (dummy) */ - char const *id_value; /**< Identity text as shown in SIP Header */ - char const *id_info; /**< Info param containing URL of the cert */ -}; - -/**@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 @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]; - sip_identity_t sh_identity[1]; -}; - -SOFIA_END_DECLS - -#endif /* !defined(SIP_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in deleted file mode 100644 index 1c79acd5e7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_extra.h.in +++ /dev/null @@ -1,176 +0,0 @@ -`/**@file sofia-sip/sip_extra.h.in - * -*- C -*- - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_EXTRA_H - -/**@file sofia-sip/sip_extra.h -* - * @brief Extension headers for SIP. - * - * #AUTO# - * - * @author Pekka Pessi . - */ - -#ifndef SIP_H -#include -#endif - -#ifndef SIP_HEADER_H -#include -#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_alert_info_s sip_alert_info_t; - -/**@ingroup sip_alert_info - * @brief Structure for @AlertInfo header. - */ -struct sip_alert_info_s -{ - sip_common_t ai_common[1]; /**< Common fragment info */ - sip_alert_info_t *ai_next; /**< Link to next @AlertInfo */ - url_t ai_url[1]; /**< URI to alert info */ - msg_param_t const *ai_params; /**< List of optional parameters */ -}; - -typedef struct sip_reply_to_s sip_reply_to_t; - -/**@ingroup sip_reply_to - * @brief Structure for @ReplyTo header. - */ -struct sip_reply_to_s -{ - sip_common_t rplyto_common[1]; /**< Common fragment info */ - sip_reply_to_t *rplyto_next; /**< Dummy link to next header */ - char const *rplyto_display; /**< Display name */ - url_t rplyto_url[1]; /**< Return URI */ - msg_param_t const *rplyto_params; /**< List of optional 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 */ -}; - -typedef struct sip_p_asserted_identity_s sip_p_asserted_identity_t; - -/**@ingroup sip_p_asserted_identity - * @brief Structure for @PAssertedIdentity header. - */ -struct sip_p_asserted_identity_s -{ - sip_common_t paid_common[1];/**< Common fragment info */ - sip_p_asserted_identity_t - *paid_next; /**< Link to next identity */ - char const *paid_display; /**< Display name */ - url_t paid_url[1]; /**< SIP, SIPS or TEL URL */ -}; - -typedef struct sip_p_preferred_identity_s sip_p_preferred_identity_t; - -/**@ingroup sip_p_preferred_identity - * @brief Structure for @PPreferredIdentity header. - */ -struct sip_p_preferred_identity_s -{ - sip_common_t ppid_common[1];/**< Common fragment info */ - sip_p_preferred_identity_t - *ppid_next; /**< Link to next identity */ - char const *ppid_display; /**< Display name */ - url_t ppid_url[1]; /**< SIP, SIPS or TEL URL */ -}; - - -int sip_p_initialize_remote_party_id_headers(msg_mclass_t *mclass); - -typedef struct sip_remote_party_id_s sip_remote_party_id_t; - -/**@ingroup sip_remote_party_id - * @brief Structure for @RemotePartyID header. - */ -struct sip_remote_party_id_s -{ - sip_common_t rpid_common[1];/**< Common fragment info */ - sip_remote_party_id_t - *rpid_next; /**< Link to next identity */ - char const *rpid_display; /**< Display name */ - url_t rpid_url[1]; /**< URL */ - sip_param_t const *rpid_params; /**< Parameters */ - /** Shortcuts to screen, party, id-type and privacy parameters */ - char const *rpid_screen, *rpid_party, *rpid_id_type, *rpid_privacy; -}; - - - -/** Defined as 1 if the @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" is supported */ -#define SIP_HAVE_#XXXXXX# 1 - - -SOFIA_END_DECLS - -#endif /** !defined(SIP_EXTRA_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in deleted file mode 100644 index e710a73e26..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_hclasses.h.in +++ /dev/null @@ -1,78 +0,0 @@ -/** -*- C -*- - * - * @file sofia-sip/sip_hclasses.h.in - * - * Template for . - */ - -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_HCLASSES_H - -/**@file sofia-sip/sip_hclasses.h - * @brief Declarations of SIP header classes. - * - * #AUTO# - * - * @author Pekka Pessi - * - * @date Created: Thu Jan 23 19:26:31 2003 ppessi - */ - -#ifndef MSG_TYPES_H -#include -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h deleted file mode 100644 index 9271878459..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_header.h +++ /dev/null @@ -1,524 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included.*/ -#define SIP_HEADER_H - -/**@file sofia-sip/sip_header.h - * - * SIP parser library prototypes. - * - * @author Pekka Pessi . - * - * @date Created: Tue Jun 13 02:58:26 2000 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif - -#ifndef SU_TAG_H -#include -#endif - -#ifndef SIP_H -#include -#endif - -#ifndef MSG_HEADER_H -#include -#endif - -#ifndef _STRING_H -#include -#endif - -SOFIA_BEGIN_DECLS - -/** Return a built-in SIP parser object. */ -SOFIAPUBFUN msg_mclass_t const *sip_default_mclass(void); - -/** Release SIP parser object if it was cloned. */ -SOFIAPUBFUN void sip_cloned_parser_destroy(void); - -SOFIAPUBFUN int sip_update_default_mclass(msg_mclass_t const *mclass); -SOFIAPUBFUN msg_mclass_t *sip_extend_mclass(msg_mclass_t *input); - -/** Check that sip_t is a SIP header structure (not MIME or HTTP). @HIDE */ -#define sip_is_sip(sip) ((sip) && (sip)->sip_ident == SIP_PROTOCOL_TAG) - -/** Initializer for a SIP header structure. @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 WS transport version string. */ -SOFIAPUBVAR char const sip_transport_ws[]; -/** @internal WSS transport version string. */ -SOFIAPUBVAR char const sip_transport_wss[]; -/** @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 -#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 @Identity header object. */ -SOFIAPUBFUN sip_identity_t *sip_identity_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); - -/** Return true if the method is listed in @Allow header. */ -SOFIAPUBFUN int sip_is_allowed(sip_allow_t const *allow, - sip_method_t method, char const *name); - -/** Check if the well-known method is listed in @Allow header. @NEW_1_12_6. */ -#define SIP_IS_ALLOWED(allow, method) \ - (sip_method_unknown < (method) && (method) < 32 && \ - (allow) && ((allow)->k_bitmap & (1 << (method))) != 0) - -/** - * Bitmasks for header classifications. - * - * If parsing of a particular header fails, the error bits in #msg_t are - * updated. The error bits can be obtained via msg_extract_errors() after - * parsing. The header-specific bits are stored along with the - * @ref msg_hclass_t "header class" in the #msg_href_t structure, found in - * the parser tables of the #msg_mclass_t object. - * - * @sa NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), - * #msg_mclass_t, struct #msg_mclass_s, msg_mclass_clone(), - * msg_mclass_insert_with_mask(), - * #msg_href_t, struct #msg_href_s, msg_mclass_insert(). - */ -enum sip_bad_mask { - /** Bit marking essential headers in a request message. - * - * @ref sip_request \"request line\"", @From, @To, @CSeq, @CallID, - * @ContentLength, @Via - */ - sip_mask_request = (1 << 0), - - /** Bit marking essential headers in a response message. - * - * @ref sip_status \"status line\"", @From, @To, @CSeq, @CallID, - * @ContentLength, @Via - */ - sip_mask_response = (1 << 1), - - /** Bit marking essential headers for User-Agent. - * - * @ContentType, @ContentDisposition, @ContentEncoding, @Supported, - * @Contact, @Require, and @RecordRoute. - */ - sip_mask_ua = (1 << 2), - - /** Bit marking essential headers for proxy server. - * - * @Route, @MaxForwards, @ProxyRequire, @ProxyAuthorization, @Supported, - * @Contact, and @RecordRoute. - */ - sip_mask_proxy = (1 << 3), - - /** Bit marking essential headers for registrar server. - * - * @MinExpires, @Authorization, @Path, @Supported, @Contact, @Require, and - * @Expires. - * - */ - sip_mask_registrar = (1 << 4), - - /** Bit marking essential headers for 100rel extension. - * - * @RAck and @RSeq. - * - * @sa @RFC3262. - */ - sip_mask_100rel = (1 << 5), - - /** Bit marking essential headers for SIP events. - * - * @Event, @Expires, and @SubscriptionState. - * - * @sa @RFC3265. - */ - sip_mask_events = (1 << 6), - - /** Bit marking essential headers for session timer extension. - * - * @SessionExpires, and @MinSE. - * - * @RFC4028 - */ - sip_mask_timer = (1 << 7), - - /** Bit marking essential headers for privacy extension. - * - * @Privacy. - * - * @sa @RFC3323 - */ - sip_mask_privacy = (1 << 8), - - /** Bit marking essential headers for caller preference extension. - * - * @RequestDisposition, @AcceptContact, and @RejectContact. - * - * @sa @RFC3841. - */ - sip_mask_pref = (1 << 9), - - /** Bit marking essential headers for PUBLISH servers and clients. - * - * @SIPETag, and @SIPIfMatch. - * - * @sa @RFC3903. - */ - sip_mask_publish = (1 << 10) - - /* NOTE: - * When adding bits, please update nta_agent_create() and - * NTATAG_BAD_RESP_MASK()/NTATAG_BAD_REQ_MASK() documentation. - */ -}; - -/* ------------------------------------------------------------------------- */ - -/* 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h deleted file mode 100644 index 68aaff9ded..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_parser.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 . - * - * @date Created: Thu Mar 8 15:13:11 2001 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif - -#ifndef MSG_H -#include -#endif - -#ifndef MSG_PARSER_H -#include -#endif - -#ifndef SIP_H -#include -#endif - -#ifndef SIP_HEADER_H -#include -#endif - -#ifndef SOFIA_SIP_SU_STRING_H -#include -#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); - -SOFIAPUBFUN isize_t sip_name_addr_xtra(char const *display, url_t const *addr, - msg_param_t const params[], - isize_t offset); - -SOFIAPUBFUN char *sip_name_addr_dup(char const **d_display, char const *display, - url_t *d_addr, url_t const *addr, - msg_param_t const **d_params, - msg_param_t const params[], - char *b, isize_t xtra); - - -/* --------------------------------------------------------------------------- - * 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 - -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in deleted file mode 100644 index 5734ffc3a0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_protos.h.in +++ /dev/null @@ -1,367 +0,0 @@ -/**@file sofia-sip/sip_protos.h.in - * - * Template for . - */ - -/* -*- C -*- - * - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_PROTOS_H - -/**@file sofia-sip/sip_protos.h - * - * SIP prototypes and macros for each header. - * - * #AUTO# - * - * @author Pekka Pessi . - * - */ - -#include - -#ifndef SIP_HEADER_H -#include -#endif - -#ifndef SIP_HCLASSES_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h deleted file mode 100644 index b10d165e3a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 . - * - * @date Created: Tue Jun 6 17:43:46 2000 ppessi - */ - -#include - -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 -/** 607 Unwanted @HIDE */ -#define SIP_607_UNWANTED 607, sip_607_Unwanted -/** 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_607_Unwanted[]; -SOFIAPUBVAR char const sip_687_Dialog_terminated[]; - -SOFIA_END_DECLS - -#endif /** @} !defined(SIP_STATUS_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in deleted file mode 100644 index 55abfbe87a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in +++ /dev/null @@ -1,256 +0,0 @@ -/**@file sofia-sip/sip_tag.h.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_TAG_H - -/**@file sofia-sip/sip_tag.h - * @brief Tag class for SIP headers - * - * #AUTO# - * - * @author Pekka Pessi . - * - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SU_TAG_CLASS_H -#include -#endif - -#ifndef SIP_H -#include -#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_INLINE_TAG_CAST -su_inline -tag_value_t siptag_sip_v(sip_t const *v) { return (tag_value_t)v; } -su_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_INLINE_TAG_CAST -su_inline tag_value_t -siptag_header_v(sip_header_t const *v) -{ return (tag_value_t)v; } -su_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("P-Alternative-URL: <+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_INLINE_TAG_CAST -su_inline tag_value_t -siptag_#xxxxxx#_v(sip_#xxxxxx#_t const *v) -{ return (tag_value_t)v; } -su_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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h deleted file mode 100644 index 32df99a5f6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag_class.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 . - * - * @date Created: Wed Feb 21 11:01:45 2001 ppessi - */ - -#ifndef SU_TAG_CLASS_H -#include -#endif - -#ifndef MSG_TAG_CLASS_H -#include -#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 }} - -/** 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]; - -/** Define a named tag type using structure of SIP header @a t. */ -#define SIPEXTHDRTAG_TYPEDEF(n, t) \ -{{ TAG_NAMESPACE, #n, sipexthdrtag_class, \ - (tag_value_t)sip_##t##_class }} - -/** Tag class using SIP header structure */ -SOFIAPUBVAR tag_class_t sipexthdrtag_class[1]; - - -/**@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h deleted file mode 100644 index cbd12a3b4f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_util.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SIP_UTIL_H - -/**@file sofia-sip/sip_util.h - * @brief SIP utility functions - * - * @author Pekka Pessi . - * - * @date Created: Thu Jun 8 19:28:55 2000 ppessi - */ - -#ifndef SIP_H -#include -#endif - -#ifndef STRING0_H -#include -#endif - -#ifndef MSG_HEADER_H -#include -#endif - -SOFIA_BEGIN_DECLS - -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>"). */ /* (tag="") */ - 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; /**< Lower limit. Lowest value is -DBL_MAX. */ - double spr_upper; /**< Upper limit. Highest value is DBL_MAX. */ - } 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); - -/* Compatibility stuff */ - -#define sip_params_add msg_params_add -#define sip_params_cmp msg_params_cmp -#define sip_params_replace msg_params_replace -#define sip_params_find msg_params_find - -SOFIA_END_DECLS - -#endif /** !defined(SIP_UTIL_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/test_date.c b/libs/sofia-sip/libsofia-sip-ua/sip/test_date.c deleted file mode 100644 index c89d58a017..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/test_date.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_date.c - * - * Tester for SIP date parser - * - * @author Pekka Pessi . - * - * @date Wed Mar 21 19:12:13 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include -#include - -void usage(int exitcode) -{ - fprintf(stderr, - "usage: test_date [SIP-date] " - "[YYYYy][DDd][HHh][MMm][SS[s]]\n"); - exit(exitcode); -} - -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 (su_strmatch(av[1], "-v")) - verbatim = 1, av++; - - if ((s = av[1])) { - if (msg_date_d(&s, &t) < 0) { - fprintf(stderr, "test_date: %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, "test_date: %s is not valid time offset\n" , av[2]); - usage(1); - 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, "test_date: decoding %s failed\n", buf); - retval = 1; - break; - } - else if (t2 != t) { - fprintf(stderr, "test_date: %lu != %lu\n", t, t2); - retval = 1; - break; - } - t += delta; - } - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/test_sip_msg.c b/libs/sofia-sip/libsofia-sip-ua/sip/test_sip_msg.c deleted file mode 100644 index 2dd9168677..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/test_sip_msg.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_PARSER - * - * @file test_sip_msg.c Simple SIP message parser/printer tester. - * - * @author Pekka Pessi . - * - * @date Created: Fri Feb 18 10:25:08 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_mclass.h" -#include "sofia-sip/msg_mclass_hash.h" -#include -#include -#include - -#include -#include -#include -#include -#include - -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 test_msg_class(msg_mclass_t const *mc) -{ - int i, j, N; - - N = mc->mc_hash_size; - - /* Check parser table sanity */ - for (i = 0; i < N; i++) { - /* Verify each header entry */ - msg_hclass_t *hc = mc->mc_hash[i].hr_class; - - if (hc == NULL) - continue; - - /* Short form */ - if (hc->hc_short[0]) - assert(mc->mc_short[hc->hc_short[0] - 'a'].hr_class == hc); - - /* Long form */ - for (j = MC_HASH(hc->hc_name, N); j != i; j = (j + 1) % N) - assert(mc->mc_hash[j].hr_class); - } - - return 0; -} - -char * url_print(url_t *url, char buf[1024]) -{ - url_e(buf, 1024, url); - - return buf; -} - -void print_contact(FILE *f, sip_contact_t *m) -{ - char const * const *p; - char buf[1024]; - const char *sep = "\tContact: "; - - for (;m; m = m->m_next) { - int quoted_url = 0; - fputs(sep, f); sep = ", "; - - if (m->m_display) { - quoted_url = 1; - fprintf(f, "\"%s\" <", m->m_display); - } - url_print(m->m_url, buf); - if (!quoted_url && strpbrk(buf, ",;?")) { - fputs("<", f); - } - fputs(buf, f); - if (quoted_url) fputs(">", f); - - if (m->m_params) - for (p = m->m_params; *p; p++) - fprintf(f, " ;%s", *p); - - if (m->m_comment) - fprintf(f, " (%s)", m->m_comment); - } - - fputs("\n", f); -} - -void print_via(FILE *f, sip_via_t *v) -{ - char const * const *p; - char const * sep = "\tVia: "; - - for (;v; v = v->v_next) { - fputs(sep, f); sep = ", "; - - fprintf(f, "%s %s", v->v_protocol, v->v_host); - if (v->v_port) - fprintf(f, ":%s", v->v_port); - - if (v->v_params) - for (p = v->v_params; *p; p++) - fprintf(f, " ;%s", *p); - if (v->v_comment) - fprintf(f, " (%s)", v->v_comment); - } - - fputs("\n", f); -} - -int main(int argc, char *argv[]) -{ - char urlbuf[1024]; - size_t n; - int m, tcp; - sip_t *sip; - int exitcode = 0; - msg_mclass_t const *sip_mclass = sip_default_mclass(); - msg_t *msg = msg_create(sip_mclass, MSG_FLG_EXTRACT_COPY); - msg_iovec_t iovec[1]; - - tcp = argv[1] && strcmp(argv[1], "-t") == 0; - - test_msg_class(sip_mclass); - - for (n = 0, m = 0;;) { - if (msg_recv_iovec(msg, iovec, 1, 1, 0) < 0) { - perror("msg_recv_iovec"); - exit(1); - } - assert(iovec->mv_len >= 1); - - n = read(0, iovec->mv_base, 1); - - if (n < 0) { - perror("test_sip_msg read"); - exit(1); - } - - msg_recv_commit(msg, n, n == 0); - - if (tcp) - m = msg_extract(msg); - - if (n == 0 || m < 0) - break; - } - - if (!tcp) - m = msg_extract(msg); - - sip = msg_object(msg); - if (sip) - fprintf(stdout, "sip flags = %x\n", sip->sip_flags); - - if (m < 0) { - fprintf(stderr, "test_sip_msg: parsing error ("MOD_ZD")\n", n); - exit(1); - } - - if (sip->sip_flags & MSG_FLG_TRUNC) { - fprintf(stderr, "test_sip_msg: message truncated\n"); - exit(1); - } - - if (msg_next(msg)) { - fprintf(stderr, "test_sip_msg: stuff after message\n"); - exit(1); - } - -#if 0 - fprintf(stderr, "test_sip_msg: %d headers (%d short ones), %d unknown\n", - msg->mh_n_headers, msg->mh_n_short, msg->mh_n_unknown); - - if (msg->mh_payload) { - fprintf(stderr, "\twith payload of %d bytes\n", - msg->mh_payload->pl_len); - } -#endif - - if (MSG_HAS_ERROR(sip->sip_flags) || sip->sip_error) { - fprintf(stderr, "test_sip_msg: parsing error\n"); - exit(1); - } - else if (sip_sanity_check(sip) < 0) { - fprintf(stderr, "test_sip_msg: message failed sanity check\n"); - exit(1); - } - - if (sip->sip_request) { - fprintf(stdout, "\trequest %s (%d) %s %s\n", - sip->sip_request->rq_method_name, - sip->sip_request->rq_method, - url_print(sip->sip_request->rq_url, urlbuf), - sip->sip_request->rq_version); - if (sip->sip_request->rq_url->url_type == url_unknown) { - exitcode = 1; - fprintf(stderr, "test_sip_msg: invalid request URI\n"); - } - } - - if (sip->sip_status) - fprintf(stdout, "\tstatus %s %03d %s\n", - sip->sip_status->st_version, - sip->sip_status->st_status, - sip->sip_status->st_phrase); - - if (sip->sip_cseq) - fprintf(stdout, "\tCSeq: %u %s (%d)\n", - sip->sip_cseq->cs_seq, - sip->sip_cseq->cs_method_name, - sip->sip_cseq->cs_method); - - if (sip->sip_call_id) - fprintf(stdout, "\tCall-ID: %s (%x)\n", - sip->sip_call_id->i_id, - sip->sip_call_id->i_hash); - - if (sip->sip_from) - fprintf(stdout, "\tFrom: %s@%s%s%s\n", - sip->sip_from->a_user ? sip->sip_from->a_user : "[nobody]", - sip->sip_from->a_host ? sip->sip_from->a_host : "[nowhere]", - sip->sip_from->a_tag ? " ;tag=" : "", - sip->sip_from->a_tag ? sip->sip_from->a_tag : ""); - - if (sip->sip_to) - fprintf(stdout, "\tTo: %s@%s%s%s\n", - sip->sip_to->a_user ? sip->sip_to->a_user : "[nobody]", - sip->sip_to->a_host ? sip->sip_to->a_host : "[nowhere]", - sip->sip_to->a_tag ? " ;tag=" : "", - sip->sip_to->a_tag ? sip->sip_to->a_tag : ""); - - if (sip->sip_contact) - print_contact(stdout, sip->sip_contact); - if (sip->sip_via) - print_via(stdout, sip->sip_via); - - if (sip->sip_content_length) { - fprintf(stdout, "\tcontent length %u\n", - sip->sip_content_length->l_length); - } - - if (msg_next(msg)) { - fprintf(stderr, "test_sip_msg: extra stuff after valid message\n"); - exit(1); - } - - return exitcode; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/10052.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/10052.txt deleted file mode 100644 index 1d9708a414..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/10052.txt +++ /dev/null @@ -1,20 +0,0 @@ -INVITE sip:1234@10.50.71.28 SIP/2.0 -To: -From: "Displayname" ;tag=10052 -Via: SIP/2.0/UDP 10.50.71.29:5060;branch=z9hG4bK10052t1174659568681 -Call-ID: s0c00010052i0t1174659568681@10.50.71.29 -Contact: "999" -Content-Length: 180 -Content-Type: application/sdp -CSeq: 1 INVITE -Max-Forwards: 70 - -v=0 -o=999 1 1 IN IP4 10.50.71.29 -s=Codenomicon SIP UAS Test Tool 3.0.2 (http://www.codenomicon.com/) -c=IN IP4 10.50.71.29 -t=0 0 -m=audio 49152 RTP/AVP 0 -a=rtpmap:0 PCMU/8000 \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt deleted file mode 100644 index bc64fdfd64..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own0.txt +++ /dev/null @@ -1,45 +0,0 @@ -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: ;foo=bar -Record-Route: -Hide: route -Max-Forwards: 15 -From: sip:digest@garage.sr.ntc.nokia.com -To: sip:digest@garage.sr.ntc.nokia.com -Contact: sip:digest@172.21.9.155 -Call-ID: 982773899-reg@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@garage.sr.ntc.nokia.com -Call-Info: ;purpose=icon -Organization: Fuzzy Felines, Inc. -Server: please -User-Agent: Nokia Universal Killer Internet Application/2.0 (NUUKIA) -In-Reply-To: 982773898-reg@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: -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt deleted file mode 100644 index fdd43df5d0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own1.txt +++ /dev/null @@ -1,18 +0,0 @@ -INVITE sip:John_Smith@tct.hut.fi SIP/2.0 -To: John Smith - ; tag = deadbeef -From: http://www.cs.columbia.edu -Call-ID: 0ha0isndaksdj@10.1.2.3 -CSeq : 8 INVITE -Via: SIP/2.0/UDP 135.180.130.133 -Content-Type: application/sdp -Contact: Joe Bob Briggs ; bar="foo baa", sip:kuik@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt deleted file mode 100644 index 28d879dd0d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own2.txt +++ /dev/null @@ -1,12 +0,0 @@ -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: -From: sip:digest@garage.sr.ntc.nokia.com -To: sip:digest@garage.sr.ntc.nokia.com -Call-ID: 982773899-reg@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt deleted file mode 100644 index da194c3083..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own3.txt +++ /dev/null @@ -1,19 +0,0 @@ -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: -From: sip:digest@garage.sr.ntc.nokia.com -To: sip:digest@garage.sr.ntc.nokia.com -Call-Id: 982773899-reg@172.21.9.155 -Cseq: 2 REGISTER -Contact: sip:digest@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt deleted file mode 100644 index ff098ee717..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own4.txt +++ /dev/null @@ -1,19 +0,0 @@ -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: -From: sip:digest@garage.sr.ntc.nokia.com -To: sip:digest@garage.sr.ntc.nokia.com -Call-Id: 982773899-reg@172.21.9.155 -Cseq: 2 REGISTER -Contact: sip:digest@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt deleted file mode 100644 index a1f5a5fe01..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own5.txt +++ /dev/null @@ -1,27 +0,0 @@ -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: - ;tag=ud6a29947 -To: -Call-ID: f89fa68e-5109-11d6-0581-0010A48D6A46 -CSeq: 2 INVITE -Contact: -Call-Info: - ;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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt deleted file mode 100644 index 9c4f012f2f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own6.txt +++ /dev/null @@ -1,16 +0,0 @@ -OPTIONS sip:bob@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: -Record-Route: -From: ;tag=ud6a29947 -To: -Call-ID: f3359e42-5109-11d6-998d-0010a47e1c0f -CSeq: 1 OPTIONS -Contact: -Content-Length: 0 -Accept: -Allow: diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt deleted file mode 100644 index ac5af8ae86..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/own8.txt +++ /dev/null @@ -1,2 +0,0 @@ -JUNK * SIP/1.0 - \ No newline at end of file diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt deleted file mode 100644 index 05d2c763ad..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test-ack-1.txt +++ /dev/null @@ -1,8 +0,0 @@ -ACK sip:company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:j.user@company.com -Call-ID: 0ha0isndaksdj@10.0.2.2 -Contact: sip:j.user@host.company.com -CSeq: 8 NEWMETHOD -Via: SIP/2.0/UDP 135.180.130.133 -Content-Length: 0 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt deleted file mode 100644 index 0af721c16b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1.txt +++ /dev/null @@ -1,22 +0,0 @@ -INVITE sip:vivekg@chair.dnrc.bell-labs.com SIP/2.0 - To : - sip:vivekg@chair.dnrc.bell-labs.com ; tag = 1a1b1f1H33n -From : "J Rosenberg \\\"" - ; - tag = 98asjd8 -CaLl-Id - : 0ha0isndaksdj@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 \"\"" ; newparam = newvalue ; - secondparam = secondvalue ; q = 0.33 - (((nested comments) and (more))) , - tel:4443322 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt deleted file mode 100644 index 55291c053d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10.txt +++ /dev/null @@ -1,27 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:j.user@company.com -Call-ID: 0ha0isndaksdj@10.0.2.2 -Contact: sip:j.user@host.company.com -CSeq: 8 REGISTER -Via: SIP/2.0/UDP 135.180.130.133 -Content-Length: 0 - - - -INVITE sip:joe@company.com SIP/3.0 -To: sip:joe@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isnda977644900765@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 - - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt deleted file mode 100644 index 16a1a2d7f3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10b.txt +++ /dev/null @@ -1,8 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:j.user@COMPANY.COM;maddr=135.180.130.133;tag=foo -From: sip:j.user@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@10.0.2.2 -Contact: * -CSeq: 9 REGISTER -Via: SIP/2.0/UDP 135.180.130.133 -Content-Length: 0 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt deleted file mode 100644 index 2eb450b49b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test10c.txt +++ /dev/null @@ -1,9 +0,0 @@ -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@COMPANY.COM;maddr=135.180.130.133;tag=foo -From: sip:j.user@COMPANY.COM;tag=bar -Call-ID: 0ha0isndaksdj@10.0.2.2 -Contact: * -CSeq: 9 REGISTER -Content-Length: 0 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt deleted file mode 100644 index deb2afacdf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test11.txt +++ /dev/null @@ -1,11 +0,0 @@ -INVITE sip:user@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt deleted file mode 100644 index 4a302ce5c4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test12.txt +++ /dev/null @@ -1,18 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -Via: SIP/2.0/UDP 135.180.130.133 -CSeq: 0 INVITE -Call-ID: 98asdh@10.1.1.1 -Call-ID: 98asdh@10.1.1.2 -From: sip:caller@university.edu -From: sip:caller@organization.org -To: sip:user@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt deleted file mode 100644 index 190a0d7ea0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test13.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -Via: SIP/2.0/UDP 135.180.130.133 -CSeq: 0 INVITE -Call-ID: 98asdh@10.1.1.2 -Expires: Thu, 44 Dec 19999 16:00:00 EDT -From: sip:caller@university.edu -To: sip:user@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt deleted file mode 100644 index 8a76b83a64..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14-req.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@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@10.1.1.1 -CSeq: 0 INVITE -To: sip:user@company.com -From: sip:user@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt deleted file mode 100644 index f91ebd6957..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test14.txt +++ /dev/null @@ -1,16 +0,0 @@ -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@10.1.1.1 -CSeq: 0 INVITE -From: sip:user@company.com -To: sip:user@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt deleted file mode 100644 index b1e29063dd..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test15.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: ;tag=23444 -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@10.0.0.1 -CSeq: 8 INVITE -Via: SIP/2.0/UDP 135.180.130.133;;,; -Contact: "" <> ;,"Joe" ;;,,;; -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt deleted file mode 100644 index 59f34ff353..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test16.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt deleted file mode 100644 index 47033aaf8a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test17.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt deleted file mode 100644 index 6aff0e3025..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test18.txt +++ /dev/null @@ -1,19 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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''...'';;;; - - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt deleted file mode 100644 index e14b284604..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test19.txt +++ /dev/null @@ -1,15 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: "Mr. J. User -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt deleted file mode 100644 index 8b7d17a691..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test1a.txt +++ /dev/null @@ -1,21 +0,0 @@ -INVITE sip:vivekg@chair.dnrc.bell-labs.com SIP/2.0 - To : - sip:vivekg@chair.dnrc.bell-labs.com ; tag = 1a1b1f1H33n -From : "J Rosenberg \\\"" - ; - tag = 98asjd8 -CaLl-Id - : 0ha0isndaksdj@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 \"\"" ; newparam = newvalue ; - secondparam = secondvalue ; q = 0.33 - (((nested comments) and (more))) , - tel:4443322 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt deleted file mode 100644 index e36b9b77a4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test2.txt +++ /dev/null @@ -1,10 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:j_user@company.com -From: sip:caller@university.edu;tag=242etr -Max-Forward: 6 -Call-ID: 0ha0isndaksdj@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt deleted file mode 100644 index fe3201e5c6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test20.txt +++ /dev/null @@ -1,9 +0,0 @@ -INVITE sip:user;par=u%40h.com@company.com SIP/2.0 -To: sip:j_user@company.com -From: sip:caller@university.edu;tag=33242 -Max-Forwards: 3 -Call-ID: 0ha0isndaksdj@10.1.1.1 -CSeq: 8 INVITE -Via: SIP/2.0/UDP 135.180.130.133;branch=z9hG4bKkdjuw -Content-Length: 0 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt deleted file mode 100644 index 82abf35069..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test21.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 1@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt deleted file mode 100644 index ef9fe4694f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test22.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE sip:user@company.com; transport=udp SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 2@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt deleted file mode 100644 index f119d1f023..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test23.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 3@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt deleted file mode 100644 index 12244cce6b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test24.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE sip:sip%3Auser%40example.com@company.com;other-param=summit SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 4@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt deleted file mode 100644 index 6f80e96c1a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test25.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE sip:user@company.com?Route=%3Csip:sip.example.com%3E SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 5@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt deleted file mode 100644 index aeaa09770f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test26.txt +++ /dev/null @@ -1,17 +0,0 @@ -INVITE name:user SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 6@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt deleted file mode 100644 index ba97e673af..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test27.txt +++ /dev/null @@ -1,6 +0,0 @@ -OPTIONS sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: "caller" -Call-ID: 1234abcd@10.0.0.1 -CSeq: 1 OPTIONS -Via: SIP/2.0/UDP 135.180.130.133 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt deleted file mode 100644 index 9907805344..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test28.txt +++ /dev/null @@ -1,6 +0,0 @@ -OPTIONS sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: "caller" -Call-ID: 1234abcd@10.0.0.1 -CSeq: 2 OPTIONS -Via: SIP/2.0/UDP 135.180.130.133 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt deleted file mode 100644 index 50b62ad8fa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test29.txt +++ /dev/null @@ -1,18 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 7@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt deleted file mode 100644 index 384d5dd816..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test3.txt +++ /dev/null @@ -1,16 +0,0 @@ -INVITE sip:John_Smith@tct.hut.fi SIP/2.0 -To: isbn:2983792873 -From: http://www.cs.columbia.edu -Call-ID: 0ha0isndaksdj@10.1.2.3 -CSeq : 8 INVITE -Via: SIP/2.0/UDP 135.180.130.133 -Content-Type: application/sdp -Contact: Joe Bob Briggs -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt deleted file mode 100644 index df007b2b17..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test30.txt +++ /dev/null @@ -1,18 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 8@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt deleted file mode 100644 index ee5413d601..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test31.txt +++ /dev/null @@ -1,18 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:user@company.com -From: sip:caller@university.edu -Call-ID: 9@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt deleted file mode 100644 index f83b653162..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test32.txt +++ /dev/null @@ -1,8 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:user@company.com -From: sip:user@company.com -Contact: sip:user@host.company.com -Call-ID: k345asrl3fdbv@10.0.0.1 -CSeq: 1 REGISTER -Via: SIP/2.0/UDP 135.180.130.133 -Contact: diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt deleted file mode 100644 index 95de6f4fed..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test33.txt +++ /dev/null @@ -1,8 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:user@company.com -From: sip:user@company.com -Contact: sip:user@host.company.com -Call-ID: k345asrl3fdbv@10.0.0.1 -CSeq: 1 REGISTER -Via: SIP/2.0/UDP 135.180.130.133 -Contact: sip:user@example.com?Route=%3Csip:sip.example.com%3E diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt deleted file mode 100644 index 4dd5483704..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test34.txt +++ /dev/null @@ -1,50 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: "I have a user name of extreme proportion" -From: sip:caller@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt deleted file mode 100644 index 1694777660..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test35.txt +++ /dev/null @@ -1,14 +0,0 @@ -OPTIONS sip:135.180.130.133 SIP/2.0 -Via: SIP/2.0/UDP company.com:5604 -From: sip:iuser@company.com -To: sip:user@135.180.130.133 -Call-ID: 1804928587@company.com -CSeq: 1 OPTIONS -Expires: 0 0l@company.com -To: sip:user@135.180.130.133 -Call-ID: 1804928587@company.com -CSeq: 1 OPTIONS -Contact: sip:host.company.com -Expires: 0xpires: 0sip:host.company.com -Expires: 0 -Contact: sip:host.company.com diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt deleted file mode 100644 index 34c63f84b2..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test36.txt +++ /dev/null @@ -1,23 +0,0 @@ -INVITE sip:+1-972-555-2222;phone-context=name%40domain;new=user?%22Route%3a%20X%40Y%3bZ=W%22@gw1.wcom.com;user=phone SIP/2.0 -Via: SIP/2.0/UDP iftgw.there.com:5060 -From: sip:+1-303-555-1111@ift.here.com;user=phone -To: sip:+1-650-555-2222@ss1.wcom.com;user=phone -Call-ID: 1717@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt deleted file mode 100644 index 96deefaa76..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test37.txt +++ /dev/null @@ -1,7 +0,0 @@ -REGISTER sip:bell-tel.com SIP/2.0 -Via: SIP/2.0/UDP saturn.bell-tel.com -From: sip:watson@bell-tel.com -To: sip:watson@bell-tel.com -Call-ID: 70710@saturn.bell-tel.com -CSeq: 2 REGISTER -Contact: sip:+1-972-555-2222@gw1.wcom.com;user=phone diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt deleted file mode 100644 index a3946de226..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test38.txt +++ /dev/null @@ -1,7 +0,0 @@ -REGISTER sip:bell-tel.com SIP/2.0 -Via: SIP/2.0/UDP saturn.bell-tel.com -From: sip:watson@bell-tel.com -To: sip:watson@bell-tel.com -Call-ID: 70710@saturn.bell-tel.com -CSeq: 3 REGISTER -Contact: diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt deleted file mode 100644 index e9ac9ecba0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test39.txt +++ /dev/null @@ -1,6 +0,0 @@ -INVITE sip:t.watson@ieee.org SIP/2.0 -Via: SIP/2.0/UDP c.bell-tel.com -From: A. Bell -To: T. Watson -Call-ID: 31414@c.bell-tel.com -CSeq: 1 INVITE diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt deleted file mode 100644 index 093e1d7015..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test4.txt +++ /dev/null @@ -1,9 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:user@company.com -From: sip:user@company.com -Contact: sip:user@host.company.com -Call-ID: 0ha0isndaksdj@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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt deleted file mode 100644 index 566ad8b57b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test40.txt +++ /dev/null @@ -1,6 +0,0 @@ -INVITE sip:t.watson@ieee.org SIP/2.0 -Via: SIP/2.0/UDP c.bell-tel.com -From: Bell, Alexander -To: Watson, Thomas -Call-ID: 31415@c.bell-tel.com -CSeq: 1 INVITE diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt deleted file mode 100644 index 0246e18a52..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test41.txt +++ /dev/null @@ -1,7 +0,0 @@ -INVITE sip:t.watson@ieee.org SIP/7.0 -Max-Forwards: 70 -Via: SIP/2.0/UDP c.bell-tel.com -From: A. Bell -To: T. Watson -Call-ID: 31416@c.bell-tel.com -CSeq: 1 INVITE diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt deleted file mode 100644 index d3003322c5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test42.txt +++ /dev/null @@ -1,6 +0,0 @@ -INVITE sip:t.watson@ieee.org SIP/7.0 -Via: SIP/2.0/UDP c.bell-tel.com -From: A. Bell -To: T. Watson -Call-ID: 31417@c.bell-tel.com -CSeq: 1 INVITE diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt deleted file mode 100644 index bd957cbfeb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test5.txt +++ /dev/null @@ -1,16 +0,0 @@ -INVITE sip:user@company.com SIP/2.0 -To: sip:j_user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt deleted file mode 100644 index afd1114fdb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test6.txt +++ /dev/null @@ -1,12 +0,0 @@ -INVITE sip:user@comapny.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@10.0.0.1 -CSeq: 8 INVITE -Via: SIP/2.0/UDP 135.180.130.133 -Content-Type: application/newformat -Content-Length: 37 - - diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt deleted file mode 100644 index 9125d090eb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test7.txt +++ /dev/null @@ -1,15 +0,0 @@ -NEWMETHOD sip:user@comapny.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt deleted file mode 100644 index 2c54bdf02f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test8.txt +++ /dev/null @@ -1,15 +0,0 @@ -NEWMETHOD sip:user@comapny.com SIP/2.0 -To: sip:j.user@company.com -From: sip:caller@university.edu;tag=34525 -Max-Forwards: 6 -Call-ID: 0ha0isndaksdj@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt b/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt deleted file mode 100644 index 46760854d3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/tests/test9.txt +++ /dev/null @@ -1,7 +0,0 @@ -REGISTER sip:company.com SIP/2.0 -To: sip:j.user@company.com -From: sip:j.user@company.com -Call-ID: 0ha0isndaksdj@10.0.1.1 -CSeq: 8 REGISTER -Via: SIP/2.0/UDP 135.180.130.133 -Authorization: Super-PGP ajsohdaosdh0asyhdaind08yasdknasd09asidhas0d8 diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c b/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c deleted file mode 100644 index 00514fbd2c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c +++ /dev/null @@ -1,3671 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Tue Mar 6 18:33:42 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -/* 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 - -#include -#include -#include - -#include "sofia-sip/sip_parser.h" -#include -#include - -#include -#include -#include -#include -#include - -#include - -int tstflags; - -#define TSTFLAGS tstflags - -#include - -char const *name = "torture_sip.c"; - -msg_mclass_t *test_mclass = NULL; - -static msg_t *read_message(int flags, char const string[]); - -static int test_identity(void) -{ - su_home_t *home; - sip_alert_info_t *ai; - sip_reply_to_t *rplyto; - sip_remote_party_id_t *rpid; - sip_p_asserted_identity_t *paid; - sip_p_preferred_identity_t *ppid; - - msg_t *msg; - sip_t *sip; - - BEGIN(); - - msg_href_t const *href; - msg_mclass_t const *def0, *def1, *ext; - - def0 = sip_default_mclass(); - - /* Check that Refer-Sub has been added to our parser */ - TEST_1(href = msg_find_hclass(def0, "Refer-Sub", NULL)); - TEST_P(href->hr_class, sip_refer_sub_class); - /* Check that Reply-To is not there */ - TEST_P(msg_find_hclass(def0, "Reply-To", NULL), def0->mc_unknown); - - TEST_1(ext = sip_extend_mclass(NULL)); - /* Update default parser */ - TEST_1(sip_update_default_mclass(ext) == 0); - def1 = sip_default_mclass(); - TEST_1(def0 != def1); - TEST_1(ext == def1); - - TEST_1(href = msg_find_hclass(def1, "Reply-To", NULL)); - TEST_P(href->hr_class, sip_reply_to_class); - - TEST_1(test_mclass = msg_mclass_clone(def0, 0, 0)); - - msg = read_message(MSG_DO_EXTRACT_COPY, - "BYE sip:foo@bar SIP/2.0\r\n" - "To: ;tag=deadbeef\r\n" - "From: ;\r\n" - "Call-ID: 0ha0isndaksdj@10.1.2.3\r\n" - "CSeq: 8 SUBSCRIBE\r\n" - "Via: SIP/2.0/UDP 135.180.130.133\r\n" - "Alert-Info: ;walz, \r\n" - "Reply-To: Arska ;humppa\r\n" - "P-Asserted-Identity: \r\n" - "P-Preferred-Identity: , \r\n" - "Remote-Party-ID: \r\n" - "Content-Length: 0\r\n" - "\r\n"); - - sip = sip_object(msg); - - TEST_1(sip); - TEST_1(!sip_alert_info(sip)); - TEST_1(!sip_reply_to(sip)); - TEST_1(!sip_p_asserted_identity(sip)); - TEST_1(!sip_p_preferred_identity(sip)); - TEST_1(!sip_remote_party_id(sip)); - - msg_destroy(msg); - - TEST_1(msg_mclass_insert_header(test_mclass, - sip_p_asserted_identity_class, 0) > 0); - TEST_1(msg_mclass_insert_header(test_mclass, - sip_p_preferred_identity_class, 0) > 0); - - msg = read_message(MSG_DO_EXTRACT_COPY, - "BYE sip:foo@bar SIP/2.0\r\n" - "To: ;tag=deadbeef\r\n" - "From: ;\r\n" - "Call-ID: 0ha0isndaksdj@10.1.2.3\r\n" - "CSeq: 8 SUBSCRIBE\r\n" - "Via: SIP/2.0/UDP 135.180.130.133\r\n" - "Alert-Info: ;walz, \r\n" - "Reply-To: Arska ;humppa\r\n" - "P-Asserted-Identity: \r\n" - "P-Preferred-Identity: , \r\n" - "Remote-Party-ID: \r\n" - "Content-Length: 0\r\n" - "\r\n"); - - sip = sip_object(msg); - - TEST_1(!sip_alert_info(sip)); - TEST_1(!sip_reply_to(sip)); - TEST_1(sip_p_asserted_identity(sip)); - TEST_1(sip_p_preferred_identity(sip)); - TEST_1(!sip_remote_party_id(sip)); - - TEST_1(home = msg_home(msg)); - - TEST_1((paid = sip_p_asserted_identity_make(home, "sip:joe@example.com"))); - TEST_1((paid = sip_p_asserted_identity_make - (home, "Jaska , Helmi "))); - TEST_1(paid->paid_next); - TEST_1((ppid = sip_p_preferred_identity_make(home, "sip:joe@example.com"))); - TEST_1((ppid = sip_p_preferred_identity_make - (home, "Jaska , Helmi "))); - - msg_destroy(msg); - - /* Now with extensions */ - TEST_1(test_mclass = msg_mclass_clone(def1, 0, 0)); - - msg = read_message(MSG_DO_EXTRACT_COPY, - "BYE sip:foo@bar SIP/2.0\r\n" - "To: ;tag=deadbeef\r\n" - "From: ;\r\n" - "Call-ID: 0ha0isndaksdj@10.1.2.3\r\n" - "CSeq: 8 SUBSCRIBE\r\n" - "Via: SIP/2.0/UDP 135.180.130.133\r\n" - "Alert-Info: ;walz, \r\n" - "Reply-To: Arska ;humppa\r\n" - "P-Asserted-Identity: \r\n" - "P-Preferred-Identity: , \r\n" - "Remote-Party-ID: \r\n" - "Content-Length: 0\r\n" - "\r\n"); - - sip = sip_object(msg); - - TEST_1(ai = sip_alert_info(sip)); - TEST_S(ai->ai_url->url_host, "test.com"); - TEST_1(rplyto = sip_reply_to(sip)); - TEST_S(rplyto->rplyto_url->url_host, "gov.ca.us"); - TEST_1(paid = sip_p_asserted_identity(sip)); - TEST_1(ppid = sip_p_preferred_identity(sip)); - TEST_1(rpid = sip_remote_party_id(sip)); - TEST_S(rpid->rpid_url->url_host, "test.domain.com"); - - msg_destroy(msg); - - { - su_home_t *home = su_home_clone(NULL, sizeof *home); - - char *s; - char const canonic[] = - "\"Jaska Jokunen\" ;" - "screen=yes;party=called;id-type=user;privacy=\"name,uri-network\""; - char const canonic2[] = - "Jaska Jokunen ;" - "screen=yes;party=called;id-type=user;privacy=\"name,uri-network\""; - - sip_remote_party_id_t *rpid, *d; - - TEST_1(rpid = sip_remote_party_id_make(home, canonic)); - TEST_S(rpid->rpid_display, "\"Jaska Jokunen\""); - TEST_S(rpid->rpid_url->url_user, "jaska.jokunen"); - TEST_S(rpid->rpid_params[0], "screen=yes"); - TEST_S(rpid->rpid_screen, "yes"); - TEST_S(rpid->rpid_party, "called"); - TEST_S(rpid->rpid_id_type, "user"); - TEST_S(rpid->rpid_privacy, "\"name,uri-network\""); - TEST_1(s = sip_header_as_string(home, (void*)rpid)); - TEST_S(s, canonic); - TEST_1(d = sip_remote_party_id_dup(home, rpid)); - TEST_S(d->rpid_display, rpid->rpid_display); - TEST_S(d->rpid_params[0], rpid->rpid_params[0]); - - TEST_1(rpid = sip_remote_party_id_make(home, canonic2)); - TEST_S(rpid->rpid_display, "Jaska Jokunen"); - TEST_1(s = sip_header_as_string(home, (void*)rpid)); - TEST_S(s, canonic2); - TEST_1(d = sip_remote_party_id_dup(home, rpid)); - TEST_S(d->rpid_display, rpid->rpid_display); - - su_home_check(home); - - su_home_zap(home); - } - - END(); -} - -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; - sip_refer_sub_t rs[1]; - - TEST_1(home = su_home_new(sizeof *home)); - - sip_refer_sub_init(rs)->rs_value = "false"; - - s = sip_headers_as_url_query - (home, - SIPTAG_SUBJECT_STR("kuik"), - SIPTAG_REFER_SUB(rs), - TAG_END()); - - TEST_1(s); - TEST_S(s, "subject=kuik&refer-sub=false"); - - s = sip_headers_as_url_query - (home, - SIPTAG_TO_STR("\"Joe\" ;tag=foofaa"), - SIPTAG_SUBJECT_STR("foo"), - TAG_END()); - - TEST_1(s); - TEST_S(s, "to=%22Joe%22%20%3Csip%3Ajoe@example.com%3E%3Btag%3Dfoofaa" - "&subject=foo"); - - url = url_format(home, "sip:test@example.net?%s", s); TEST_1(url); - - TEST_S(url->url_headers, s); - - s = sip_headers_as_url_query - (home, - SIPTAG_FROM_STR(""), - SIPTAG_ACCEPT_STR(""), - SIPTAG_PAYLOAD_STR("hello"), - SIPTAG_ACCEPT_STR(""), - TAG_END()); - - TEST_S(s, "from=%3Csip%3Ajoe@example.com%3Buser%3Dip%3E" - "&accept=" - "&body=hello" - "&accept="); - - d = url_query_as_header_string(home, s); - TEST_S(d, "from:\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@bar SIP/2.0\r\n" - "To: Joe User \r\n" - "From: \"Bar Owner\" ;tag=foobar\r\n" - "Call-ID: 0ha0isndaksdj@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 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@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@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@example.com", NULL)); - TEST_1(rq = sip_request_create(home, sip_method_unknown, "invite", - (void *)"sip:joe@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@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@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]; - msg_param_t const *params; - char const *comment; - char const na[] = "Raaka Arska ;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@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(!sip_from_make(home, (void *)"tester <>;tag=fasjfuios")); - - TEST_1(f = sip_from_make(home, (void *)"sip:joe@bar (foo)")); - su_free(home, f); - - TEST_1(f = sip_from_make(home, (void *)" (joe)")); - TEST_1(sip_from_tag(home, f, "tag=jxahudsf") == 0); - su_free(home, f); - - TEST_1(f = sip_from_create(home, (void *)" (joe)")); - TEST_1(sip_is_from((sip_header_t*)f)); - su_free(home, f); - - TEST_1(t = sip_to_create(home, (void *)" (joe)")); - TEST_1(sip_is_to((sip_header_t*)t)); - 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@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, ""); - 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, ""); - su_free(home, v), su_free(home, s); - } - - { - char *input; - char const *output = NULL; - char udp[] = "sip/2.0/udp"; - char tcp[] = "sip/2.0/tCp "; - char sctp[] = "sip/2.0/sctp\t"; - char tls[] = "sip/2.0/tls\r"; - - input = udp; - TEST(sip_transport_d(&input, &output), 0); - TEST_S(output, "SIP/2.0/UDP"); - - input = tcp; - TEST(sip_transport_d(&input, &output), 0); - TEST_S(output, "SIP/2.0/TCP"); - - input = sctp; - TEST(sip_transport_d(&input, &output), 0); - TEST_S(output, "SIP/2.0/SCTP"); - - input = tls; - TEST(sip_transport_d(&input, &output), 0); - TEST_S(output, "SIP/2.0/TLS"); - } - - { - 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, ";lr")); - TEST_1(r = sip_route_make(home, ";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, ";lr")); - TEST_1(!sip_record_route_make(home, ";lr bar, sip:foo")); - TEST_1(r = sip_record_route_make(home, ";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, - ";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); - } - - { - sip_alert_info_t *ai, *ai0; - - TEST_1(ai = sip_alert_info_make(home, ";x-format=mp3")); - TEST_1(ai0 = sip_alert_info_dup(home, ai)); - - TEST(msg_header_remove_param(ai->ai_common, "x-format"), 1); - TEST(msg_header_remove_param(ai0->ai_common, "x-format"), 1); - - su_free(home, ai); - su_free(home, ai0); - } - - { - sip_reply_to_t *rplyto, *rplyto0; - - TEST_1(rplyto = sip_reply_to_make(home, "sip:joe@bar")); - TEST_1(msg_header_add_param(home, (msg_common_t *)rplyto, "x-extra=extra") == 0); - while (rplyto->rplyto_params && rplyto->rplyto_params[0]) - msg_header_remove_param(rplyto->rplyto_common, rplyto->rplyto_params[0]); - su_free(home, rplyto); - - TEST_1(!sip_reply_to_make(home, (void *)"sip:joe@[baa")); - - TEST_1(rplyto = sip_reply_to_make(home, (void *)"sip:joe@bar")); - su_free(home, rplyto); - - TEST_1(rplyto = sip_reply_to_make(home, (void *)"Joe ;x-extra=extra")); - TEST_1(rplyto0 = sip_reply_to_dup(home, rplyto)); - su_free(home, rplyto); - su_free(home, rplyto0); - } - - - 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(); -} - -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@bar SIP/2.0\r\n" - "To: Joe User \r\n" - "From: \"Bar Owner\" ;tag=foobar\r\n" - "P-Asserted-Identity: \r\n" - "P-Preferred-Identity: \r\n" - "Call-ID: 0ha0isndaksdj@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: \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: \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: \r\n" - "Replaces: 12345601@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 ;tag=deadbeef\r\n" - "From: sip:bar@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: ;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: \r\n" - "Event: presence;id=1\r\n" - "Allow-Events: presence, presence.winfo\r\n" - "Subscription-State: active;expires=1800\r\n" - "Call-Info: ;purpose=xcap\r\n" - "Error-Info: ;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: \r\n" - "Alert-Info: \r\n" - "Reply-To: Bob \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 ;tag=deadbeef\r\n" - "From: sip:bar@foo;tag=foobar\r\n" - "Call-ID: {0h!a0i\"sndaksdj}@[kjsafi3]\r\n" - "CSeq: 8912734 SUBSCRIBE\r\n" - "Record-Route: \r\n" - "Record-Route: \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;tag=deadbeef\r\n", c->h_len); - - TEST_1(c = sip->sip_from->a_common); - TEST_M(c->h_data, "f:sip:bar@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:,\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@example.com SIP/2.0"); - sip_to_t *to = sip_to_make(home, - "Joe User " - ";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@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 ;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: \r\n" -"From: sip:digest@garage.sr.ntc.nokia.com\r\n" -"To: sip:digest@garage.sr.ntc.nokia.com\r\n" -"Call-ID: 982773899-reg@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 }, - { SIP_607_UNWANTED }, - { 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@tct.hut.fi SIP/2.0\r\n" - "To: John Smith \r\n" - " ; tag = deadbeef\r\n" - "From: http://www.cs.columbia.edu\r\n" - "Call-ID: 0ha0isndaksdj@10.1.2.3\r\n" - "CSeq : 8 INVITE\r\n" - "Via: SIP/2.0/UDP 135.180.130.133\r\n" - "Route: , sip:2@b;lr=2, \r\n" - "Route: \r\n" - "Route: sip:2@e;lr=5, \r\n" - "Route: , ;lr=8\r\n" - "Content-Type: application/sdp\r\n" - "Contact: Joe Bob Briggs ; bar=\"foo baa\", sip:kuik@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_alert_info_class->hc_params, - offsetof(sip_alert_info_t, ai_params)); - TEST_SIZE(sip_reply_to_class->hc_params, - offsetof(sip_reply_to_t, rplyto_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@tct.hut.fi SIP/2.0\r\n" - "To: John Smith \r\n" - " ; tag = deadbeef\r\n" - "From:h\r\n" - "Call-ID: 0ha0isndaksdj@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 ; bar=\042foo baa\042, , sip:barf\r\n" - "Via: SIP/2.0/UDP [aa:bb::1]:5061\r\n" - "Record-Route: Test Element ;param=12+1\r\n" - "Record-Route: sip:135.180.130.133,,\r\n" - "\t,Test Element ;param=12+1\r\n" - "Path: Test \r\n" - "Service-Route: Test \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); -#if SU_HAVE_EXPERIMENTAL - TEST(count(sip->sip_unknown->un_common), 2); -#else - TEST(count(sip->sip_unknown->un_common), 4); -#endif - 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); - -#if SU_HAVE_EXPERIMENTAL - { - 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)); - } -#endif - - 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(""), - 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(""), - 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(""), - SIPTAG_END(), - SIPTAG_REFER_TO_STR(""), - 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, "") == 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, - "") == 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/2.0\r\n" - "To: John Smith \r\n" - " ; tag = deadbeef\r\n" - "From:h\r\n" - "Call-ID: 0ha0isndaksdj@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 ; bar=\042foo baa\042, sip:kuik@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@tct.hut.fi SIP/2.0\r\n" - "To: John Smith \r\n" - "From: ;tag=foobar\r\n" - "Call-ID: 0ha0isndaksdj@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 ; bar=\042foo baa\042, , 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) -{ - 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(); -} - - -static int test_content_type(void) -{ - sip_content_type_t *c; - sip_content_type_t c0[1]; - su_home_t *home; - - BEGIN(); - - TEST_1(home = su_home_create()); - TEST_1(c = sip_content_type_make(home, "application/sdp ; charset = utf-8")); - TEST_S(c->c_type, "application/sdp"); - TEST_S(c->c_subtype, "sdp"); - TEST_1(c->c_params && c->c_params[0] && !c->c_params[1]); - TEST_S(c->c_params[0], "charset=utf-8"); - TEST_P(c->c_params[1], NULL); - - sip_content_type_init(c0); - c = sip_content_type_dup(home, c0); - TEST_P(c->c_type, NULL); - TEST_P(c->c_subtype, NULL); - - c0->c_type = "text"; - c = sip_content_type_dup(home, c0); - TEST_S(c->c_type, "text"); - TEST_P(c->c_subtype, NULL); - - su_home_unref(home); - END(); -} - - -static int test_www_authenticate(void) -{ - sip_www_authenticate_t *www; - su_home_t *home; - char const *s; - msg_t *msg; sip_t *sip; - - BEGIN(); - - TEST_1(home = su_home_create()); - TEST_1(www = sip_www_authenticate_make - (home, "Digest realm=\"Registered_Subscribers\",\n" - "domain=\"sip:206.229.26.61\",\n" - "nonce=\"20dfb7e5a77abee7a02dbe53efe42cdd\", " - "opaque=\"423767123y723742376423762376423784623782a794e58\",\n" - "stale=FALSE,algorithm=MD5")); - TEST_S(www->au_scheme, "Digest"); - TEST_1(www->au_params && www->au_params[0] && www->au_params[1] && www->au_params[2] && - www->au_params[3] && www->au_params[4] && www->au_params[5] && - !www->au_params[6]); - TEST_1(s = sip_header_as_string(home, (sip_header_t *)www)); - TEST_1(strlen(s) >= 128); - - su_home_unref(home); - - TEST_1( - msg = read_message( - MSG_DO_EXTRACT_COPY, - "SIP/2.0 401 Unauthorized" "\r\n" - "Date: Wed, 07 Jan 2009 22:24:39 GMT" "\r\n" - "WWW-Authenticate: Kerberos realm=\"SIP Communications Service\", targetname=\"sip/OCS1.flux.local\", version=3" "\r\n" - "WWW-Authenticate: NTLM realm=\"SIP Communications Service\", targetname=\"OCS1.flux.local\", version=3" "\r\n" - "From: ;epid=1234567890;tag=48BXgr379e85j" "\r\n" - "To: ;transport=tls;tag=B57737091022903031FF204696B79CC4" "\r\n" - "Call-ID: cf12f708-57ac-122c-ad90-6f23d7babf4f" "\r\n" - "CSeq: 109565202 REGISTER" "\r\n" - "Via: SIP/2.0/TLS 192.168.43.1:5069;branch=z9hG4bK47ZUrFK0v5eQa;received=192.168.43.1;ms-received-port=54059;ms-received-cid=E500" "\r\n" - "Content-Length: 0" "\r\n")); - TEST_1(sip = sip_object(msg)); - - TEST_1(www = sip->sip_www_authenticate); - TEST_S(www->au_scheme, "Kerberos"); - TEST_1(www = www->au_next); - TEST_S(www->au_scheme, "NTLM"); - - msg_destroy(msg); - - 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\" ;tag=5AA04E0-66CFC37F\r\n" - "To: ;user=phone;tag=j6Fg9y7t8KNrF\r\n" - "CSeq: 4 REFER\r\n" - "Call-ID: a14822a4-5932e3ea-d7f37191@10.3.3.8\r\n" - "Contact: \r\n" - "User-Agent: PolycomSoundPointIP-SPIP_500-UA/1.4.1\r\n" - "Refer-To: \r\n" - "Referred-By: \"Anthony Minessale\" \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 now 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 = "")); - 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 ;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@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@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@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 " - ";cid=\"foo@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: ;tag=deadbeef\r\n" - "From: ;\r\n" - "Call-ID: 0ha0isndaksdj@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, ""))); - TEST_P(r0->r_params, NULL); - TEST_1(r0->r_url->url_params); - - TEST_1((r1 = sip_record_route_make(home, ""))); - 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, ";lr")); - TEST_1(p = sip_path_make(home, ";lr")); - TEST_1(p0 = sip_path_dup(home, p)); - - su_free(home, p); - su_free(home, p0); - - TEST_1(!sip_service_route_make(home, ";lr")); - TEST_1(!sip_service_route_make(home, - ";lr bar, sip:foo")); - - TEST_1(sr = sip_service_route_make(home, ";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 -#include - -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 = "\" ! , \""; - 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_MAX); - 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_MAX); - 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); - - /* Numeric */ - s = "\" !#=" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111." - - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111," - " #<=-16" - "\""; - - 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, DBL_MAX); - TEST_D(sp->sp_range.spr_upper, DBL_MAX); - TEST_1(sip_prefs_match(sp, sp)); - TEST_1(negate); - - TEST_1(sip_prefs_parse(sp, &s, &negate)); - TEST(sp->sp_type, sp_range); - TEST_D(sp->sp_range.spr_lower, -DBL_MAX); - TEST_D(sp->sp_range.spr_upper, -16.0); - TEST_1(sip_prefs_match(sp, sp)); - TEST_1(!negate); - - 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("\"!\"", "\"\"", &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("\",\"", - "\",\"", &error)); - TEST_1(!sip_prefs_matching("\",\"", "\"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\"", "\",\"", &error)); - TEST(error, 12); - - error = 12; - TEST_1(!sip_prefs_matching("\",#=1\"", "\",\"", &error)); - TEST(error, -1); - - error = 12; - TEST_1(!sip_prefs_matching("\",\"", "\",#=1\"", &error)); - TEST(error, -1); - - error = 12; - TEST_1(!sip_prefs_matching("\",bar\"", "\",\"", &error)); - TEST(error, -1); - - error = 12; - TEST_1(!sip_prefs_matching("\",\"", "\",#12:12\"", &error)); - TEST(error, -1); - - { - char const *params[] = { - "methods=\"INVITE,MESSAGE,SUBSCRIBE\"", - "events=\"presence,presence.winfo\"", - "description=\"\"", - "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, - ";video;audio;type=\"RFC 3264. - -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. - -@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 preconditions is defined -RFC 3312. -Another example of two-phase negotiation is presented in RFC -3264 section 10.2, showing how a single codec can be selected. - -@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. - -@section soa_with_sip Using SDP Offer/Answer with SIP - -Using SDP Offer/Answer with SIP is specified in -RFC 3261, -RFC 3262 (100rel and PRACK), and -RFC 3311 (UPDATE). - -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). - -@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 - -@subsection soa_uc_basic_out Basic Call Out - -This is the "basic" outbound call model. - -

-       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	|		|		|			|
-        |		|		|			|
-
- -@subsection soa_uc_basic_in Basic Call In - -This is the "basic" inbound call model. - -
-       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	|		|		|			|
-	|		|		|			|
-
- -@subsection soa_uc_basic_3p 3rd Party Call In - -The 3rd-party call model just reverses the O/A roles of callee and caller. - -
- 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      |		|		|			|
-        |		|		|			|
-
- -@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. - -
- 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	|		|		|			|
-	|		|		|			|
-
- -@subsection soa_uc_early_in Call In Establishing Early Media - -The mirror of the previous scenario: - -
- 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      |		|		|			|
-	|		|		|			|
-
-Note 1: 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). - -@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. - -
- 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	|		|		|			|
-	|		|		|			|
-
- -@subsection soa_uc_100rel_in Call In with PRACK - -The mirror of the previous scenario: - -
- 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      |		|		|			|
-        |		|		|			|
-
- -Note 1: 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. - -*/ - -/** -@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. - -@section soa_use_case_1 Case #1: Basic Call - -This is the basic SIP call model with the most simple offer-answer exchange. - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|			|
-	|< - - 180 Ringing - - -|
-	|			|
-	|			|
-	|<----200 (answer)------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- -@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...": - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|			|
-	|<----180 (answer)------|
-	|			|
-	|			|
-	|<----200 (answer')-----|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- -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. - -@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. - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|<----183 (answer)------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|<---------180----------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|			|
-	|			|
-	|<---------200----------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- -@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": - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|			|
-	|<----183 (answer)------|
-	|--------PRACK--------->|
-	|<-----200/PRACK--------|
-	|			|
-	|			|
-	|----UPDATE (offer2)--->|
-	|<-200/UPDATE (answer2)-|
-	|			|
-	|<---------180----------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|			|
-	|<---------200----------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- - -@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": - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|<----183 (answer)------|
-	|-----PRACK(offer2)---->|
-	|<--200/PRACK(answer2)--|
-	|			|
-	|			|
-	|<---------180----------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|			|
-	|<---------200----------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- - -@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: - -
-	A		        B
-	|			|
-	|----INVITE (offer)---->|
-	|			|
-	|<----183 (answer)------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|			|
-	|<---UPDATE (offer2)----|
-	|-200/UPDATE (answer2)->|
-	|			|
-	|<---------180----------|
-	|--------PRACK--------->|
-	|<-----200/PRACK------->|
-	|			|
-	|			|
-	|<---------200----------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- - -@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: - -
-        	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--------->|
-        	|			|
-        	|			|
-
- - -@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: - -
-	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----------------------------------------->|
-	|			|		|		|
-	|			|		|		|
-
- -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). - -@section soa_use_case_9 Case #9: 3rd Party Call Control - -Now something different: 3rd party call model, where "C" -establishes the call: - -
-	A		        C		        B
-	|			|			|
-	|<-------INVITE---------|			|
-	|			|			|
-	|			|			|
-	|------200 (offer)----->|  	  		|
-	|			|----INVITE (offer)---->|
-	|			|			|
-	|			|			|
-	|			|<-----200 (answer)-----|
-	|<-----ACK (answer)-----|			|
-	|			|     			|
-	|			|----------ACK--------->|
-	|			|			|
-
- -@section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE - -The session is upgraded: a new media is added to the session. - -
-	A		        B
-	|			|
-	|----INVITE (offer1)--->|
-	|			|
-	|			|
-	|< - - 180 Ringing - - -|
-	|			|
-	|			|
-	|<----200 (answer2)-----|
-	|----------ACK--------->|
-	|			|
-	|			|
-	|			|
-	|			|
-	|----INVITE (offer2)--->|
-	|			|
-	|<----200 (answer2)-----|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- -@section soa_use_case_10 Case #10: Upgrade Session with Re-INVITE - -The session upgraded is rejected. - -
-	A		        B
-	|			|
-	|----INVITE (offer1)--->|
-	|			|
-	|			|
-	|< - - 180 Ringing - - -|
-	|			|
-	|			|
-	|<----200 (answer2)-----|
-	|----------ACK--------->|
-	|			|
-	|			|
-	|			|
-	|			|
-	|----INVITE (offer2)--->|
-	|			|
-	|<---------488----------|
-	|----------ACK--------->|
-	|			|
-	|			|
-
- - -*/ - -/** @typedef struct soa_session soa_session_t; - -@brief "soa" session object. - -The @soa session object is responsible for -@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. - -@par Functions used to create, copy and destroy "soa" session objects: -@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 *); -@endcode - -@par Functions used to set and get parameters for "soa" session objects: -@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, ...); -@endcode - -@par Functions used to obtain status information from "soa" session objects: -@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); -@endcode - - -@par Functions used to store and retrieve SDP descriptions: -@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); -@endcode - - -@par Functions for executing Offer/Answer negotiation steps: -@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); -@endcode - -@par Functions for signaling events of session signaling: -@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); -@endcode -These functions are used to activate actions taken by @soa, for instance, -a COMEDIA connection is established with soa_activate(). - -@par Functions for Checking Activated Media: -@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); -@endcode - -*/ diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c deleted file mode 100644 index 48917d14d0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_asynch.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Aug 16 17:06:06 EEST 2005 - */ - -#include "config.h" - -#include -#include -#include - -#include - -struct soa_asynch_complete; - -#define SU_MSG_ARG_T struct soa_asynch_completed - -#include -#include -#include -#include -#include - -#include "sofia-sip/soa.h" -#include -#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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c deleted file mode 100644 index c80d45ce36..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#include -#include - -#include - -struct soa_static_complete; - -#define SU_MSG_ARG_T struct soa_static_completed - -#include -#include -#include -#include -#include -#include -#include - -#include "sofia-sip/soa.h" -#include -#include "sofia-sip/soa_session.h" - -#define NONE ((void *)-1) -#define XXX assert(!"implemented") - -typedef struct soa_static_session -{ - soa_session_t sss_session[1]; - char *sss_audio_aux; - int sss_ordered_user; /**< User SDP is ordered */ - int sss_reuse_rejected; /**< Try to reuse rejected media line slots */ - - /** Mapping from user SDP m= lines to session SDP m= lines */ - int *sss_u2s; - /** Mapping from session SDP m= lines to user SDP m= lines */ - int *sss_s2u; - - /** State kept from SDP before current offer */ - struct { - int *u2s, *s2u; - } sss_previous; - - /** Our latest offer or answer */ - sdp_session_t *sss_latest; -} -soa_static_session_t; - -#define U2S_NOT_USED (-1) -#define U2S_SENTINEL (-2) - -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 ordered_user = sss->sss_ordered_user; - int reuse_rejected = sss->sss_reuse_rejected; - int n, m; - - n = tl_gets(tags, - SOATAG_AUDIO_AUX_REF(audio_aux), - SOATAG_ORDERED_USER_REF(ordered_user), - SOATAG_REUSE_REJECTED_REF(reuse_rejected), - TAG_END()); - - if (n > 0 && !su_casematch(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); - } - - sss->sss_ordered_user = ordered_user != 0; - sss->sss_reuse_rejected = reuse_rejected != 0; - - 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), - SOATAG_ORDERED_USER(sss->sss_ordered_user), - SOATAG_REUSE_REJECTED(sss->sss_reuse_rejected), - 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_IF(sss->sss_ordered_user, - SOATAG_ORDERED_USER(1)), - TAG_IF(sss->sss_reuse_rejected, - SOATAG_REUSE_REJECTED(1)), - 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 */ -static -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) { - if (m->m_rtpmaps) { - rejected->m_rtpmaps = m->m_rtpmaps; - } - else if (m->m_format) { - rejected->m_format = m->m_format; - } - } - - rejected->m_rejected = 1; - - return sdp_media_dup(home, rejected, sdp); -} - -/** Expand a @a truncated SDP. - */ -static -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 */ -static -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 = su_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; -} - -static -sdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from, - sdp_rtpmap_t const *anylist, - char const *auxiliary) -{ - sdp_rtpmap_t const *rm; - - for (rm = anylist; rm; rm = rm->rm_next) { - /* Ignore auxiliary codecs */ - if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary)) - continue; - - if (sdp_rtpmap_find_matching(from, rm)) - return (sdp_rtpmap_t *)rm; - } - - return NULL; -} - -#ifndef _MSC_VER -#define SDP_MEDIA_NONE ((sdp_media_t *)-1) -#else -#define SDP_MEDIA_NONE ((sdp_media_t *)(INT_PTR)-1) -#endif - -/** Find first matching media in table @a mm. - * - * - if allow_rtp_mismatch == 0, search for a matching codec - * - if allow_rtp_mismatch == 1, prefer m=line with matching codec - * - if allow_rtp_mismatch > 1, ignore codecs - */ -static -int soa_sdp_matching_mindex(soa_session_t *ss, - sdp_media_t *mm[], - sdp_media_t const *with, - int *return_codec_mismatch) -{ - int i, j = -1; - soa_static_session_t *sss = (soa_static_session_t *)ss; - int rtp = sdp_media_uses_rtp(with), dummy; - char const *auxiliary = NULL; - - if (return_codec_mismatch == NULL) - return_codec_mismatch = &dummy; - - if (with->m_type == sdp_media_audio) { - auxiliary = sss->sss_audio_aux; - /* Looking for a single codec */ - if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL) - auxiliary = NULL; - } - - for (i = 0; mm[i]; i++) { - if (mm[i] == SDP_MEDIA_NONE) - continue; - - if (!sdp_media_match_with(mm[i], with)) - continue; - - if (!rtp) - break; - - if (soa_sdp_media_matching_rtpmap(with->m_rtpmaps, - mm[i]->m_rtpmaps, - auxiliary)) - break; - - if (j == -1) - j = i; - } - - if (mm[i]) - return *return_codec_mismatch = 0, i; - else - return *return_codec_mismatch = 1, j; -} - -/** Set payload types in @a l_m according to the values in @a r_m. - * - * @retval number of common codecs - */ -static -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) { -#if 0 - /* Use same payload type as remote */ - if (lrm->rm_pt != rrm->rm_pt) { - lrm->rm_predef = 0; - lrm->rm_pt = rrm->rm_pt; - - } -#endif - 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 - */ -static -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 - */ -static -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 */ -static -int soa_sdp_media_upgrade_rtpmaps(soa_session_t *ss, - sdp_media_t *sm, - sdp_media_t const *rm) -{ - soa_static_session_t *sss = (soa_static_session_t *)ss; - char const *auxiliary = NULL; - int common_codecs; - - common_codecs = soa_sdp_set_rtpmap_pt(sm, rm); - - if (rm->m_type == sdp_media_audio) - auxiliary = sss->sss_audio_aux; - - 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 common_codecs; -} - - -/** Sort and select rtpmaps within session */ -static -int soa_sdp_session_upgrade_rtpmaps(soa_session_t *ss, - sdp_session_t *session, - sdp_session_t const *remote) -{ - 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 && sdp_media_uses_rtp(sm)) - soa_sdp_media_upgrade_rtpmaps(ss, sm, rm); - } - - return 0; -} - -/** Upgrade m= lines within session */ -static -int soa_sdp_upgrade(soa_session_t *ss, - su_home_t *home, - sdp_session_t *session, - sdp_session_t const *user, - sdp_session_t const *remote, - int **return_u2s, - int **return_s2u) -{ - soa_static_session_t *sss = (soa_static_session_t *)ss; - - int Ns, Nu, Nr, Nmax, n, i, j; - sdp_media_t *m, **mm, *um; - sdp_media_t **s_media, **o_media, **u_media; - sdp_media_t const *rm, **r_media; - int *u2s = NULL, *s2u = NULL; - - if (session == NULL || user == NULL) - return (errno = EFAULT), -1; - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-literal-null-conversion" -#endif - - Ns = sdp_media_count(session, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0); - Nu = sdp_media_count(user, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0); - Nr = sdp_media_count(remote, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - - if (remote == NULL) - Nmax = Ns + Nu; - else if (Ns < Nr) - Nmax = Nr; - else - Nmax = Ns; - - s_media = su_zalloc(home, (Nmax + 1) * (sizeof *s_media)); - o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media)); - u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media)); - r_media = su_zalloc(home, (Nr + 1) * (sizeof *r_media)); - if (!s_media || !o_media || !u_media || !r_media) - return -1; - - um = sdp_media_dup_all(home, user->sdp_media, session); - if (!um && user->sdp_media) - return -1; - - u2s = su_alloc(home, (Nu + 1) * sizeof(*u2s)); - s2u = su_alloc(home, (Nmax + 1) * sizeof(*s2u)); - if (!u2s || !s2u) - return -1; - - for (i = 0; i < Nu; i++) - u2s[i] = U2S_NOT_USED; - u2s[Nu] = U2S_SENTINEL; - - for (i = 0; i < Nmax; i++) - s2u[i] = U2S_NOT_USED; - s2u[Nmax] = U2S_SENTINEL; - - 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 = um; m && i < Nu; m = m->m_next) - u_media[i++] = m; - assert(i == Nu); - m = remote ? remote->sdp_media : NULL; - for (i = 0; m && i < Nr; m = m->m_next) - r_media[i++] = m; - assert(i == Nr); - - if (sss->sss_ordered_user && sss->sss_u2s) { /* User SDP is ordered */ - for (j = 0; sss->sss_u2s[j] != U2S_SENTINEL; j++) { - i = sss->sss_u2s[j]; - if (i == U2S_NOT_USED) - continue; - if (j >= Nu) /* lines removed from user SDP */ - continue; - if (i >= Ns) /* I should never be called but somehow i and Ns are 0 here sometimes */ - continue; - s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE; - u2s[j] = i, s2u[i] = j; - } - } - - if (remote) { - /* Update session according to remote */ - for (i = 0; i < Nr; i++) { - rm = r_media[i]; - m = s_media[i]; - - if (!m) { - int codec_mismatch = 0; - - if (!rm->m_rejected) - j = soa_sdp_matching_mindex(ss, u_media, rm, &codec_mismatch); - else - j = -1; - - if (j == -1) { - s_media[i] = soa_sdp_make_rejected_media(home, rm, session, 0); - continue; - } - else if (codec_mismatch && !ss->ss_rtp_mismatch) { - m = soa_sdp_make_rejected_media(home, u_media[j], session, 1); - soa_sdp_set_rtpmap_pt(s_media[i] = m, rm); - continue; - } - - s_media[i] = m = u_media[j]; u_media[j] = SDP_MEDIA_NONE; - u2s[j] = i, s2u[i] = j; - } - - if (sdp_media_uses_rtp(rm)) - soa_sdp_media_upgrade_rtpmaps(ss, m, rm); - } - } - else { - - if (sss->sss_ordered_user) { - /* Update session with unused media in u_media */ - - if (!sss->sss_reuse_rejected) { - /* Mark previously used slots */ - for (i = 0; i < Ns; i++) { - if (s_media[i]) - continue; - s_media[i] = - soa_sdp_make_rejected_media(home, o_media[i], session, 0); - } - } - - for (j = 0; j < Nu; j++) { - if (u_media[j] == SDP_MEDIA_NONE) - continue; - - for (i = 0; i < Nmax; i++) { - if (s_media[i] == NULL) { - s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE; - u2s[j] = i, s2u[i] = j; - break; - } - } - - assert(i != Nmax); - } - } - - /* Match unused user media by media types with the existing session */ - for (i = 0; i < Ns; i++) { - if (s_media[i]) - continue; - - j = soa_sdp_matching_mindex(ss, u_media, o_media[i], NULL); - if (j == -1) { - s_media[i] = soa_sdp_make_rejected_media(home, o_media[i], session, 0); - continue; - } - - s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE; - u2s[j] = i, s2u[i] = j; - } - - /* Here we just append new media at the end */ - for (j = 0; j < Nu; j++) { - if (u_media[j] != SDP_MEDIA_NONE) { - s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE; - u2s[j] = i, s2u[i] = j; - i++; - } - } - assert(i <= Nmax); - } - - mm = &session->sdp_media; - for (i = 0; s_media[i]; i++) { - m = s_media[i]; *mm = m; mm = &m->m_next; - } - *mm = NULL; - - s2u[n = i] = U2S_SENTINEL; - *return_u2s = u2s; - *return_s2u = s2u; - -#ifndef NDEBUG /* X check */ - for (j = 0; j < Nu; j++) { - i = u2s[j]; - assert(i == U2S_NOT_USED || s2u[i] == j); - } - for (i = 0; i < n; i++) { - j = s2u[i]; - assert(j == U2S_NOT_USED || u2s[j] == i); - } -#endif - - return 0; -} - -static -int *u2s_alloc(su_home_t *home, int const *u2s) -{ - if (u2s) { - int i, *a; - for (i = 0; u2s[i] != U2S_SENTINEL; i++) - ; - a = su_alloc(home, (i + 1) * (sizeof *u2s)); - if (a) - memcpy(a, u2s, (i + 1) * (sizeof *u2s)); - return a; - } - - return NULL; -} - -/** Check if @a session contains media that are rejected by @a remote. */ -static -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 */ -static -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; -} - - -/** Update mode within session. - * - * @sa soatag_hold - * - * @retval 1 if session was changed (or to be changed, if @a dryrun is nonzero) - */ -static -int soa_sdp_mode_set(sdp_session_t const *user, - int const *s2u, - sdp_session_t *session, - sdp_session_t const *remote, - char const *hold, - int dryrun) -{ - sdp_media_t *sm; - sdp_media_t const *rm, *rm_next, *um; - int retval = 0, i, j; - int hold_all; - int inactive_all; - char const *hold_media = NULL; - sdp_mode_t send_mode, recv_mode; - - SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n", - (void *)session, (void *)remote, hold ? hold : "")); - - if (!session || !session->sdp_media) - return 0; - - rm = remote ? remote->sdp_media : NULL, rm_next = NULL; - - hold_all = su_strmatch(hold, "*"); - inactive_all = su_strmatch(hold, "#"); - - i = 0; - - for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) { - rm_next = rm ? rm->m_next : NULL; - - if (sm->m_rejected) - continue; - - assert(s2u); - - for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++) { - if (!um) break; - } - - if (um == NULL) { - if (dryrun) - return 1; - else - retval = 1; - sm->m_rejected = 1; - sm->m_mode = sdp_inactive; - sm->m_port = 0; - continue; - } - - if (um->m_mode) { /* when its inactive, keep it inactive */ - send_mode = (sdp_mode_t)(um->m_mode & sdp_sendonly); - if (rm) - send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; - } else send_mode = um->m_mode; - - recv_mode = (sdp_mode_t)(um->m_mode & sdp_recvonly); - - if (rm && rm->m_mode == sdp_inactive) { - send_mode = recv_mode = (sdp_mode_t)0; - } - else if (inactive_all) { - send_mode = recv_mode = (sdp_mode_t)0; - } - else if (hold_all) { - recv_mode = (sdp_mode_t)0; - } - else if (hold && (hold_media = su_strcasestr(hold, sm->m_type_name))) { - recv_mode = (sdp_mode_t)0; - hold_media += strlen(sm->m_type_name); - hold_media += strspn(hold_media, " \t"); - if (hold_media[0] == '=') { - hold_media += strspn(hold, " \t"); - if (su_casenmatch(hold_media, "inactive", strlen("inactive"))) - recv_mode = send_mode = (sdp_mode_t)0; - } - } - - if (sm->m_mode != (unsigned)(recv_mode | send_mode)) { - if (dryrun) - return 1; - else - retval = 1; - sm->m_mode = recv_mode | send_mode; - } - } - - return retval; -} - -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) -{ - soa_static_session_t *sss = (soa_static_session_t *)ss; - - 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; - - int fresh = 0; - - sdp_origin_t o[1] = {{ sizeof(o) }}; - sdp_connection_t *c, c0[1] = {{ sizeof(c0) }}; - char c0_buffer[64]; - - sdp_time_t t[1] = {{ sizeof(t) }}; - - int *u2s = NULL, *s2u = NULL, *tbf; - - sdp_session_t *latest = NULL, *previous = NULL; - - 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", - (void *)ss, by)); - - if (user == NULL) - return soa_set_status(ss, 500, "No session set by user"); - - if (action == generate_offer) - remote = NULL; - else if (remote == NULL) - return soa_set_status(ss, 500, "No remote SDP"); - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-literal-null-conversion" -#endif - - /* 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, "*", (sdp_proto_e)0, (sdp_text_t)0) < - sdp_media_count(local, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)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); - if (remote == NULL) - return soa_set_status(ss, 500, "Cannot expand remote session"); - } - default: - break; - } - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - - - /* 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): %s\n", (void *)ss, by, - "generating local description")); - - fresh = 1; - local = local0; - *local = *user, local->sdp_media = NULL; - - o->o_username = "-"; - o->o_address = c0; - c0->c_address = c0_buffer; - - if (!local->sdp_origin) - local->sdp_origin = o; - 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", (void *)ss, by, - "upgrade with local description")); - if (soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u) < 0) - goto internal_error; - 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", (void *)ss, by, - "upgrade with remote description")); - if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0) - goto internal_error; - } - 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): %s\n", (void *)ss, by, - "marking rejected media")); - soa_sdp_reject(tmphome, local, remote); - } - break; - default: - break; - } - - /* Step D: Set media mode bits */ - switch (action) { - int const *s2u_; - - case generate_offer: - case generate_answer: - case process_answer: - s2u_ = s2u; - - if (!s2u_) s2u_ = sss->sss_s2u; - - if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) { - if (local != local0) { - *local0 = *local, local = local0; - DUP_LOCAL(local); - } - - soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0); - } - 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", (void *)ss, by, - "upgrade codecs with remote description")); - if (local != local0) { - *local0 = *local, local = local0; - DUP_LOCAL(local); - } - soa_sdp_session_upgrade_rtpmaps(ss, local, remote); - } - break; - case generate_offer: - case generate_answer: - default: - break; - } - - /* Step F0: Initialize o= line */ - if (fresh) { - if (user->sdp_origin) { - o->o_username = user->sdp_origin->o_username; - - if (user->sdp_origin->o_address) - o->o_address = user->sdp_origin->o_address; - - if (user->sdp_origin->o_id) - o->o_id = user->sdp_origin->o_id; - - if (user->sdp_origin->o_version && user->sdp_origin->o_version != o->o_version) { - o->o_version = user->sdp_origin->o_version; - o->o_version--; - } - } - - if (soa_init_sdp_origin_with_session(ss, o, c0_buffer, local) < 0) { - phrase = "Cannot Get IP Address for Session Description"; - goto internal_error; - } - - local->sdp_origin = o; - } - - /* Step F: Update c= line(s) */ - switch (action) { - sdp_connection_t *user_c, *local_c; - - case generate_offer: - case generate_answer: - user_c = user->sdp_connection; - if (!soa_check_sdp_connection(user_c)) - user_c = NULL; - - local_c = local->sdp_connection; - if (!soa_check_sdp_connection(local_c)) - local_c = NULL; - - if (ss->ss_local_user_version != user_version || - local_c == NULL || - (user_c != NULL && sdp_connection_cmp(local_c, user_c))) { - sdp_media_t *m; - - if (user_c) - c = user_c; - else - c = local->sdp_origin->o_address; - - /* Every m= line (even rejected one) must have a c= line - * or there must be a c= line at session level - */ - 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); - su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; - su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; - - if (u2s) { - u2s = u2s_alloc(ss->ss_home, u2s); - s2u = u2s_alloc(ss->ss_home, s2u); - if (!u2s || !s2u) - goto internal_error; - } - - if (ss->ss_local->ssd_sdp != local && - sdp_session_cmp(ss->ss_local->ssd_sdp, local)) { - int bump; - - switch (action) { - case generate_offer: - bump = sdp_session_cmp(local, sss->sss_latest); - break; - case generate_answer: - bump = 1; - break; - case process_answer: - default: - bump = 0; - break; - } - - if (bump) { - /* Upgrade the version number */ - 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 */ - int *previous_u2s = u2s_alloc(ss->ss_home, sss->sss_u2s); - int *previous_s2u = u2s_alloc(ss->ss_home, sss->sss_s2u); - - if ((sss->sss_u2s && !previous_u2s) || (sss->sss_s2u && !previous_s2u)) - goto internal_error; - - *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; - sss->sss_previous.u2s = previous_u2s; - sss->sss_previous.s2u = previous_s2u; - } - - SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by, - "storing local description")); - - /* Update the unparsed and pretty-printed descriptions */ - if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) { - if (action == generate_offer) { - /* Remove 2nd reference to local session state */ - memset(ss->ss_previous, 0, (sizeof *ss->ss_previous)); - ss->ss_previous_user_version = 0; - ss->ss_previous_remote_version = 0; - su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; - su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; - } - - su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u); - - goto internal_error; - } - - if (bump) { - latest = sdp_session_dup(ss->ss_home, ss->ss_local->ssd_sdp); - previous = sss->sss_latest; - } - } - - if (u2s) { - tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf); - tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf); - } - - /* Update version numbers */ - switch (action) { - case generate_offer: - ss->ss_local_user_version = user_version; - sss->sss_latest = latest; - break; - case generate_answer: - ss->ss_local_user_version = user_version; - ss->ss_local_remote_version = remote_version; - sss->sss_latest = latest; - break; - case process_answer: - ss->ss_local_remote_version = remote_version; - default: - break; - } - - if (previous) - su_free(ss->ss_home, previous); - - 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) -{ - soa_static_session_t *sss = (soa_static_session_t *)ss; - struct soa_description d[1]; - - soa_base_process_reject(ss, NULL); - - *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); - su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; - su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; - ss->ss_previous_user_version = 0; - ss->ss_previous_remote_version = 0; - - su_free(ss->ss_home, sss->sss_latest), sss->sss_latest = NULL; - - return 0; -} - -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_static_session_t *sss = (soa_static_session_t *)ss; - - soa_description_free(ss, ss->ss_local); - su_free(ss->ss_home, sss->sss_u2s), sss->sss_u2s = NULL; - su_free(ss->ss_home, sss->sss_s2u), sss->sss_s2u = NULL; - - soa_description_free(ss, ss->ss_previous); - ss->ss_previous_user_version = 0; - ss->ss_previous_remote_version = 0; - su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL; - su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL; - - su_free(ss->ss_home, sss->sss_latest), sss->sss_latest = NULL; - - soa_base_terminate(ss, option); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c deleted file mode 100644 index b251035cab..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Aug 3 20:28:17 EEST 2005 - */ - -#include "config.h" - -#include - -#if 1 -#define TAG_NAMESPACE soa_tag_namespace -#else -/* Definition used by tag_dll.awk */ -#define TAG_NAMESPACE "soa" -#endif - -#include -#include - -#include -#include - -#include - -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. - * - * The hold media stream will have the attribute a=sendonly (meaning that - * some hold announcements or pause music is sent to the held party but that - * the held party should not generate any media) or a=inactive (meaning that - * no media is sent). - * - * When putting a SIP session on hold with sendonly, 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 - * using inactive instead, the application should use "#" or - * "audio=inactive" instead. When resuming the session, application should - * include the tag 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); - - -/**@def SOATAG_ORDERED_USER(x) - * - * Take account strict ordering of user SDP m=lines. If user SDP has been - * updated, the new media lines replace old ones even if the media type has - * been changed. This allows the application to replace @b m=audio with - * @b m=image/t38, for instance. - * - * @par Used with - * soa_set_params(), soa_get_params(), soa_get_paramlist() \n - * - * @par Parameter type - * boolean - * - * @par Values - * - false (0) - update session with user SDP based on media type - * - true (1) - update session with m= line in user SDP based on their order - * - * The default value is false and session are updated based on media types. - * - * - * Corresponding tag taking a reference parameter is SOATAG_RTP_SELECT_REF(). - * - * @sa @RFC3264 section 8.3.3, T.38 - * - * @NEW_1_12_7. - */ -tag_typedef_t soatag_ordered_user = BOOLTAG_TYPEDEF(ordered_user); - -tag_typedef_t soatag_reuse_rejected = BOOLTAG_TYPEDEF(reuse_rejected); diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h deleted file mode 100644 index 9330005ff7..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define SOA_H -/**@file sofia-sip/soa.h SDP Offer/Answer (RFC 3264) Interface. - * - * @author Pekka Pessi - * @author Kai Vehmanen - * - * @date Created: Fri Jul 15 15:43:53 EEST 2005 ppessi - */ - -#ifndef SU_WAIT_H -#include -#endif -#ifndef SU_TAG_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h deleted file mode 100644 index fd7856250a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_add.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi - */ - -#include - -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h deleted file mode 100644 index 8691156dff..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#endif -#ifndef SU_STRLST_H -#include -#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 - { - unsigned ma_audio:4; /**< Audio activity (send/recv) */ - unsigned ma_video:4; /**< Video activity (send/recv) */ - unsigned ma_image:4; /**< Image activity (send/recv) for JPIP */ - unsigned 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); - -enum soa_activity { - soa_activity_local, - soa_activity_remote, - soa_activity_session -}; - -SOFIAPUBFUN void soa_set_activity(soa_session_t *ss, - sdp_media_t const *m, - enum soa_activity activity); - -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_origin_with_session(soa_session_t *ss, - sdp_origin_t *o, - char buffer[64], - sdp_session_t const *sdp); -SOFIAPUBFUN int soa_check_sdp_connection(sdp_connection_t const *c); -SOFIAPUBFUN int soa_init_sdp_connection(soa_session_t *, - sdp_connection_t *, char buf[64]); -SOFIAPUBFUN int soa_init_sdp_connection_with_session(soa_session_t *, - sdp_connection_t *, char buf[64], - sdp_session_t const *sdp); - -SOFIAPUBFUN sdp_connection_t *soa_find_local_sdp_connection(sdp_session_t const*); - -/* ====================================================================== */ -/* Debug log settings */ - -#define SU_LOG soa_log - -#ifdef SU_DEBUG_H -#error included directly. -#endif -#include -SOFIAPUBVAR su_log_t soa_log[]; - -SOFIA_END_DECLS - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h deleted file mode 100644 index 7c31ac0ab4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Mon Aug 1 15:43:53 EEST 2005 ppessi - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SDP_TAG_H -#include -#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; - -#define SOATAG_ORDERED_USER(x) soatag_ordered_user, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t soatag_ordered_user; - -#define SOATAG_ORDERED_USER_REF(x) \ - soatag_ordered_user_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t soatag_ordered_user_ref; - -#define SOATAG_REUSE_REJECTED(x) soatag_reuse_rejected, tag_bool_v(x) -SOFIAPUBVAR tag_typedef_t soatag_reuse_rejected; - -#define SOATAG_REUSE_REJECTED_REF(x) \ - soatag_reuse_rejected_ref, tag_bool_vr(&(x)) -SOFIAPUBVAR tag_typedef_t soatag_reuse_rejected_ref; - -SOFIA_END_DECLS - -#endif /* SOA_TAG_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c b/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c deleted file mode 100644 index 281b16496e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c +++ /dev/null @@ -1,2729 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include - -#if HAVE_ALARM -#include -#include -#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 - -#include -#include - -#include - -S2_LOCALINFO_STUBS(); - -extern su_log_t soa_log[]; - -char const name[] = "test_soa"; -int tstflags = 0; -#define TSTFLAGS tstflags - -#include - -#if HAVE_FUNC -#elif HAVE_FUNCTION -#define __func__ __FUNCTION__ -#else -#define __func__ name -#endif - -#define NONE ((void*)-1) - -static char const *test_ifaces1[] = { - "eth0\0" "11.12.13.14\0" "2001:1508:1003::21a:a0ff:fe71:813\0" "fe80::21a:a0ff:fe71:813\0", - "eth1\0" "12.13.14.15\0" "2001:1508:1004::21a:a0ff:fe71:814\0" "fe80::21a:a0ff:fe71:814\0", - "eth2\0" "192.168.2.15\0" "fec0::21a:a0ff:fe71:815\0" "fe80::21a:a0ff:fe71:815\0", - "lo0\0" "127.0.0.1\0" "::1\0", - NULL -}; - -int test_localinfo_replacement(void) -{ - BEGIN(); - su_localinfo_t *res, *li, hints[1]; - int error, n; - struct results { - struct afresult { unsigned global, site, link, host; } ip6[1], ip4[1]; - } results[1]; - - s2_localinfo_ifaces(test_ifaces1); - - error = su_getlocalinfo(NULL, &res); - TEST(error, ELI_NOERROR); - TEST_1(res != NULL); - memset(results, 0, sizeof results); - for (li = res, n = 0; li; li = li->li_next) { - struct afresult *afr; - TEST_1(li->li_family == AF_INET || li->li_family == AF_INET6); - if (li->li_family == AF_INET) - afr = results->ip4; - else - afr = results->ip6; - - if (li->li_scope == LI_SCOPE_GLOBAL) - afr->global++; - else if (li->li_scope == LI_SCOPE_SITE) - afr->site++; - else if (li->li_scope == LI_SCOPE_LINK) - afr->link++; - else if (li->li_scope == LI_SCOPE_HOST) - afr->host++; - n++; - } - TEST(n, 11); - TEST(results->ip4->global, 2); - TEST(results->ip4->site, 1); - TEST(results->ip4->link, 0); - TEST(results->ip4->host, 1); -#if SU_HAVE_IN6 - TEST(results->ip6->global, 2); - TEST(results->ip6->site, 1); - TEST(results->ip6->link, 3); - TEST(results->ip6->host, 1); -#endif - su_freelocalinfo(res); - - error = su_getlocalinfo(memset(hints, 0, sizeof hints), &res); - TEST(error, ELI_NOERROR); - TEST_1(res != NULL); - for (li = res, n = 0; li; li = li->li_next) - n++; - TEST(n, 11); - su_freelocalinfo(res); - - hints->li_flags = LI_CANONNAME; - - error = su_getlocalinfo(hints, &res); - TEST(error, ELI_NOERROR); - TEST_1(res != NULL); - for (li = res, n = 0; li; li = li->li_next) { - TEST_1(li->li_canonname != NULL); - n++; - } - TEST(n, 11); - su_freelocalinfo(res); - - hints->li_flags = LI_IFNAME | LI_CANONNAME; - hints->li_ifname = "eth1"; - - error = su_getlocalinfo(hints, &res); - TEST(error, ELI_NOERROR); - TEST_1(res != NULL); - for (li = res, n = 0; li; li = li->li_next) { - TEST_1(li->li_canonname != NULL); - TEST_S(li->li_ifname, "eth1"); - n++; - } - TEST(n, 3); - su_freelocalinfo(res); - - END(); -} -/* ========================================================================= */ - -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 = (isize_t)-1; - isize_t offerlen = (isize_t)-1; - isize_t answerlen = (isize_t)-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 put call inactive */ - 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=inactive")); - 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=inactive")); - 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_INACTIVE); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); - - /* B will send an offer to A, but there is no change in O/A status */ - 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, "a=inactive")); - /* printf("offer:\n%s", offer); */ - TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - TEST(soa_generate_answer(a, test_completed), 0); - TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); - 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, "a=inactive")); - /* printf("answer:\n%s", answer); */ - 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(b), SOA_ACTIVE_INACTIVE); - TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_INACTIVE); - - /* '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") && !strstr(offer, "a=inactive")); - 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") && !strstr(answer, "a=inactive")); - 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 5008 RTP/AVP 0 8\r\ni=x\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 = (isize_t)-1, answerlen = (isize_t)-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 reusing 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_media_mode(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1; - isize_t answerlen = (isize_t)-1; - - su_home_t home[1] = { SU_HOME_INIT(home) }; - - char const a_caps[] = "m=audio 5008 RTP/AVP 0 8\r\n"; - char const b_caps[] = "m=audio 5004 RTP/AVP 8 0\n"; - - TEST_1(a = soa_clone(ctx->a, ctx->root, ctx)); - TEST_1(b = soa_clone(ctx->b, ctx->root, ctx)); - - TEST(soa_set_user_sdp(a, 0, a_caps, -1), 1); - TEST(soa_set_user_sdp(b, 0, b_caps, -1), 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_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); - - 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_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - - /* '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_user_sdp(b, 0, - "m=audio 5004 RTP/AVP 8 0\n" - "a=inactive\n", -1), 1); - 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=inactive")); - 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_INACTIVE); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); - - /* 'A' will retrieve call, 'B' will keep call on hold */ - offer = NONE; - 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_user_sdp(b, 0, - "m=audio 5004 RTP/AVP 8 0\n" - "a=sendonly\n", -1), 1); - 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=sendonly")); - 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_RECVONLY); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_RECVONLY); - - TEST_VOID(soa_terminate(a, NULL)); - TEST_VOID(soa_terminate(b, NULL)); - - TEST_VOID(soa_destroy(a)); - TEST_VOID(soa_destroy(b)); - - su_home_deinit(home); - - END(); -} - -int test_media_replace(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1; - - sdp_session_t const *a_sdp, *b_sdp; - sdp_media_t const *m; - - 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\r\n" - ; - - char const b_caps[] = - "m=audio 5004 RTP/AVP 0 8\n" - "a=rtpmap:96 G7231/8000\n" - "a=rtpmap:97 G729/8000\n" - "m=image 5556 UDPTL t38\r\n" - "a=T38FaxVersion:0\r\n" - "a=T38MaxBitRate:9600\r\n" - "a=T38FaxFillBitRemoval:0\r\n" - "a=T38FaxTranscodingMMR:0\r\n" - "a=T38FaxTranscodingJBIG:0\r\n" - "a=T38FaxRateManagement:transferredTCF\r\n" - "a=T38FaxMaxDatagram:400\r\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); - - 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_SENDRECV); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - - /* ---------------------------------------------------------------------- */ - - /* Re-O/A: replace media stream */ - - /* Accept media without common codecs */ - TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0), - SOATAG_ORDERED_USER(1), - 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=image 16384 UDPTL t38\r\n" - "a=T38FaxVersion:0\r\n" - "a=T38MaxBitRate:9600\r\n" - "a=T38FaxFillBitRemoval:0\r\n" - "a=T38FaxTranscodingMMR:0\r\n" - "a=T38FaxTranscodingJBIG:0\r\n" - "a=T38FaxRateManagement:transferredTCF\r\n" - "a=T38FaxMaxDatagram:400\r\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); - 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_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected); - TEST(m->m_type, sdp_media_image); - TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); - TEST_S(m->m_format->l_text, "t38"); - - TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected); - TEST(m->m_type, sdp_media_image); - TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); - TEST_S(m->m_format->l_text, "t38"); - - TEST(soa_is_audio_active(a), SOA_ACTIVE_DISABLED); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_DISABLED); - - 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_media_removal(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1; - - sdp_session_t const *a_sdp, *b_sdp; - sdp_media_t const *m; - - 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\r\n" - ; - - char const b_caps[] = - "v=0\n" - "m=audio 5004 RTP/AVP 0 8\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_1(soa_set_params(b, SOATAG_RTP_MISMATCH(0), - SOATAG_ORDERED_USER(1), - TAG_END())); - - 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_SENDRECV); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - - /* ---------------------------------------------------------------------- */ - /* Re-O/A: remove media stream */ - TEST(soa_set_user_sdp(b, 0, "v=0", -1), 1); - - 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(m = b_sdp->sdp_media); TEST_1(m->m_rejected); - 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(m = a_sdp->sdp_media); TEST_1(m->m_rejected); - - 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_VOID(soa_terminate(a, NULL)); - TEST_VOID(soa_terminate(b, NULL)); - - TEST_VOID(soa_destroy(a)); - TEST_VOID(soa_destroy(b)); - - /* ---------------------------------------------------------------------- */ - - 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); - - 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_SENDRECV); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - - /* ---------------------------------------------------------------------- */ - /* Re-O/A: offerer remove media stream from user sdp */ - TEST(soa_set_user_sdp(a, 0, "v=0", -1), 1); - - 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(m = a_sdp->sdp_media); TEST_1(m->m_rejected); - 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(m = b_sdp->sdp_media); TEST_1(m->m_rejected); - 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(m = a_sdp->sdp_media); TEST_1(m->m_rejected); - - 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_VOID(soa_terminate(a, NULL)); - TEST_VOID(soa_terminate(b, NULL)); - - TEST_VOID(soa_destroy(a)); - TEST_VOID(soa_destroy(b)); - - END(); -} - - -int test_media_reject(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1; - - sdp_session_t const *b_sdp; - - 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 0 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); - - 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_VOID(soa_terminate(a, NULL)); - TEST_VOID(soa_terminate(b, NULL)); - - TEST_VOID(soa_destroy(a)); - TEST_VOID(soa_destroy(b)); - - END(); -} - - -int test_media_replace2(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1; - - sdp_session_t const *a_sdp, *b_sdp; - sdp_media_t const *m; - - char const a_caps[] = - "v=0\r\n" - "o=a 432432423423 2 IN IP4 127.0.0.2\r\n" - "c=IN IP4 127.0.0.2\r\n" - "m=image 5556 UDPTL t38\r\n" - "a=T38FaxVersion:0\r\n" - "a=T38MaxBitRate:9600\r\n" - "a=T38FaxFillBitRemoval:0\r\n" - "a=T38FaxTranscodingMMR:0\r\n" - "a=T38FaxTranscodingJBIG:0\r\n" - "a=T38FaxRateManagement:transferredTCF\r\n" - "a=T38FaxMaxDatagram:400\r\n" - "m=audio 5004 RTP/AVP 0 8\n" - "a=rtpmap:96 G7231/8000\n" - "a=rtpmap:97 G729/8000\n"; - - char const a_caps2[] = - "v=0\r\n" - "o=a 432432423423 2 IN IP4 127.0.0.2\r\n" - "c=IN IP4 127.0.0.2\r\n" - "m=image 0 UDPTL t38\r\n" - "m=image 5004 UDPTL t38\r\n" - "a=T38FaxVersion:0\r\n" - "a=T38MaxBitRate:9600\r\n" - "a=T38FaxFillBitRemoval:0\r\n" - "a=T38FaxTranscodingMMR:0\r\n" - "a=T38FaxTranscodingJBIG:0\r\n" - "a=T38FaxRateManagement:transferredTCF\r\n" - "a=T38FaxMaxDatagram:400\r\n"; - - char const b_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\r\n" - ; - - char const b_caps2[] = - "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=image 5008 UDPTL t38\r\n" - ; - - TEST_1(a = soa_create("static", ctx->root, ctx)); - TEST_1(b = soa_create("static", ctx->root, ctx)); - - TEST_1(soa_set_params(a, SOATAG_ORDERED_USER(1), - SOATAG_REUSE_REJECTED(1), - TAG_END()) > 0); - TEST_1(soa_set_params(b, SOATAG_ORDERED_USER(1), - SOATAG_REUSE_REJECTED(1), - TAG_END()) > 0); - - 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); - - 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); - - 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(a_sdp->sdp_media); - TEST_1(a_sdp->sdp_media->m_type == sdp_media_image); - TEST_1(a_sdp->sdp_media->m_next); - TEST_1(a_sdp->sdp_media->m_next->m_type == sdp_media_audio); - - /* ---------------------------------------------------------------------- */ - - /* Re-O/A: replace media stream */ - - /* Do not accept media without common codecs */ - TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(0), - SOATAG_USER_SDP_STR(b_caps2), - TAG_END()) > 0); - - n = soa_generate_offer(b, 1, test_completed); TEST(n, 0); - n = soa_get_local_sdp(b, &b_sdp, &offer, &offerlen); TEST(n, 1); - TEST_1(offer != NULL && offer != NONE); - n = soa_set_remote_sdp(a, 0, offer, offerlen); TEST(n, 1); - TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0), - SOATAG_USER_SDP_STR(a_caps2), - TAG_END()) > 0); - - n = soa_generate_answer(a, test_completed); TEST(n, 0); - n = soa_get_local_sdp(a, &a_sdp, &answer, &answerlen); TEST(n, 1); - TEST_1(answer != NULL && answer != NONE); - n = soa_set_remote_sdp(b, 0, answer, -1); TEST(n, 1); - n = soa_process_answer(b, test_completed); TEST(n, 0); - n = soa_get_local_sdp(b, &b_sdp, NULL, NULL); TEST(n, 1); - - TEST_1(soa_is_complete(a)); - TEST(soa_activate(a, NULL), 0); - - TEST_1(soa_is_complete(b)); - TEST(soa_activate(b, NULL), 0); - - TEST_1(m = a_sdp->sdp_media); TEST_1(m->m_rejected); - TEST_1(m = m->m_next); - TEST(m->m_type, sdp_media_image); - TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); - TEST_S(m->m_format->l_text, "t38"); - - TEST_1(m = b_sdp->sdp_media); TEST_1(m->m_rejected); - TEST_1(m = m->m_next); - TEST(m->m_type, sdp_media_image); - TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); - TEST_S(m->m_format->l_text, "t38"); - - TEST(soa_is_audio_active(a), SOA_ACTIVE_DISABLED); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_DISABLED); - - 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_large_sessions(struct context *ctx) -{ - BEGIN(); - int n; - - soa_session_t *a, *b; - - char const *offer = NONE, *answer = NONE; - isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1; - - sdp_session_t const *a_sdp, *b_sdp; - sdp_media_t const *m; - - char const a_caps[] = - "v=0\r\n" - "o=a 432432423423 2 IN IP4 127.0.0.2\r\n" - "c=IN IP4 127.0.0.2\r\n" - "m=image 5556 UDPTL t38\r\n" - "m=audio 5004 RTP/AVP 0 8\n" - ; - - char const a_caps2[] = - "v=0\r\n" - "o=a 432432423423 2 IN IP4 127.0.0.2\r\n" - "c=IN IP4 127.0.0.2\r\n" - "m=image 5556 UDPTL t38\r\n" - "m=audio 5004 RTP/AVP 0\n" - "m=audio1 5006 RTP/AVP 8\n" - "m=audio2 5008 RTP/AVP 3\n" - "m=audio3 5010 RTP/AVP 9\n" - "m=audio4 5010 RTP/AVP 15\n" - ; - - char const b_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\r\n" - ; - - char const b_caps2[] = - "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\r\n" - "m=image 5008 UDPTL t38\r\n" - "m=audio00 5008 RTP/AVP 0 8\r\n" - "m=audio01 5006 RTP/AVP 8\n" - "m=audio02 5008 RTP/AVP 3\n" - "m=audio03 5010 RTP/AVP 9\n" - "m=audio04 5010 RTP/AVP 15\n" - ; - - TEST_1(a = soa_create("static", ctx->root, ctx)); - TEST_1(b = soa_create("static", ctx->root, ctx)); - - TEST_1(soa_set_params(a, SOATAG_ORDERED_USER(1), - TAG_END()) > 0); - TEST_1(soa_set_params(b, SOATAG_ORDERED_USER(1), - TAG_END()) > 0); - - 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); - - 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); - /* printf("offer1: %s\n", offer); */ - 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); - /* printf("answer1: %s\n", answer); */ - 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(a_sdp->sdp_media); - TEST_1(a_sdp->sdp_media->m_type == sdp_media_image); - TEST_1(a_sdp->sdp_media->m_next); - TEST_1(a_sdp->sdp_media->m_next->m_type == sdp_media_audio); - - /* ---------------------------------------------------------------------- */ - /* Re-O/A - activate image, add incompatible m= lines */ - - TEST_1(soa_set_params(b, SOATAG_RTP_MISMATCH(0), - SOATAG_USER_SDP_STR(b_caps2), - SOATAG_REUSE_REJECTED(1), - TAG_END()) > 0); - - n = soa_generate_offer(b, 1, test_completed); TEST(n, 0); - n = soa_get_local_sdp(b, &b_sdp, &offer, &offerlen); TEST(n, 1); - TEST_1(offer != NULL && offer != NONE); - n = soa_set_remote_sdp(a, 0, offer, offerlen); TEST(n, 1); - /* printf("offer2: %s\n", offer); */ - - n = soa_generate_answer(a, test_completed); TEST(n, 0); - n = soa_get_local_sdp(a, &a_sdp, &answer, &answerlen); TEST(n, 1); - TEST_1(answer != NULL && answer != NONE); - /* printf("answer2: %s\n", answer); */ - n = soa_set_remote_sdp(b, 0, answer, -1); TEST(n, 1); - n = soa_process_answer(b, test_completed); TEST(n, 0); - n = soa_get_local_sdp(b, &b_sdp, NULL, NULL); TEST(n, 1); - - TEST_1(soa_is_complete(a)); - TEST(soa_activate(a, NULL), 0); - - TEST_1(soa_is_complete(b)); - TEST(soa_activate(b, NULL), 0); - - TEST_1(m = a_sdp->sdp_media); - TEST(m->m_type, sdp_media_image); TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); TEST_S(m->m_format->l_text, "t38"); - - TEST_1(m = b_sdp->sdp_media); - TEST(m->m_type, sdp_media_image); TEST(m->m_proto, sdp_proto_udptl); - TEST_1(m->m_format); TEST_S(m->m_format->l_text, "t38"); - - TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - - /* 2nd re-offer */ - /* Add even more incompatible lines */ - TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0), - SOATAG_USER_SDP_STR(a_caps2), - TAG_END()) > 0); - - 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); - /* printf("offer3: %s\n", offer); */ - n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1); - n = soa_get_local_sdp(b, NULL, &answer, &answerlen); 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); - /* printf("answer3: %s\n", answer); */ - 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_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 /* This has never been implemented */ - 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(); -} - -#define TEST_OC_ADDRESS(s, address, ip) \ - TEST(test_address_in_offer(s, address, sdp_addr_ ## ip, address, sdp_addr_ ## ip), 0); - -static int -test_address_in_offer(soa_session_t *ss, - char const *o_address, - int o_addrtype, - char const *c_address, - int c_addrtype) -{ - sdp_session_t const *sdp = NULL; - sdp_connection_t const *c; - - TEST(soa_get_local_sdp(ss, &sdp, NULL, NULL), 1); - TEST_1(sdp != NULL); - TEST_1(c = sdp->sdp_connection); - TEST(c->c_nettype, sdp_net_in); - if (c_addrtype) TEST(c->c_addrtype, c_addrtype); - if (c_address) TEST_S(c->c_address, c_address); - - TEST_1(c = sdp->sdp_origin->o_address); - TEST(c->c_nettype, sdp_net_in); - if (o_addrtype) TEST(c->c_addrtype, o_addrtype); - if (o_address) TEST_S(c->c_address, o_address); - - return 0; -} - -/** This tests the IP address selection logic. - * - * The IP address is selected based on the SOATAG_AF() preference, - * SOATAG_ADDRESS(), and locally obtained address list. - */ -int test_address_selection(struct context *ctx) -{ - BEGIN(); - int n; - - static char const *ifaces1[] = { - "eth2\0" "192.168.2.15\0" "fec0::21a:a0ff:fe71:815\0" "fe80::21a:a0ff:fe71:815\0", - "eth0\0" "11.12.13.14\0" "2001:1508:1003::21a:a0ff:fe71:813\0" "fe80::21a:a0ff:fe71:813\0", - "eth1\0" "12.13.14.15\0" "2001:1508:1004::21a:a0ff:fe71:814\0" "fe80::21a:a0ff:fe71:814\0", - "lo0\0" "127.0.0.1\0" "::1\0", - NULL - }; - - static char const *ifaces_ip6only[] = { - "eth2\0" "fec0::21a:a0ff:fe71:815\0" "fe80::21a:a0ff:fe71:815\0", - "eth0\0" "2001:1508:1003::21a:a0ff:fe71:813\0" "fe80::21a:a0ff:fe71:813\0", - "eth1\0" "2001:1508:1004::21a:a0ff:fe71:814\0" "fe80::21a:a0ff:fe71:814\0", - "lo0\0" "127.0.0.1\0" "::1\0", - NULL - }; - - static char const *ifaces_ip4only[] = { - "eth2\0" "192.168.2.15\0" "fe80::21a:a0ff:fe71:815\0", - "eth0\0" "11.12.13.14\0" "fe80::21a:a0ff:fe71:813\0", - "eth1\0" "12.13.14.15\0" "fe80::21a:a0ff:fe71:814\0", - "lo0\0" "127.0.0.1\0" "::1\0", - NULL - }; - - soa_session_t *a, *b; - sdp_origin_t *o; - - su_home_t home[1] = { SU_HOME_INIT(home) }; - - s2_localinfo_ifaces(ifaces1); - - TEST_1(a = soa_clone(ctx->a, ctx->root, ctx)); - - /* SOATAG_AF(SOA_AF_IP4_ONLY) => select IP4 address */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_ONLY), TAG_END()); - n = soa_set_user_sdp(a, 0, "m=audio 5008 RTP/AVP 0 8", -1); TEST(n, 1); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "11.12.13.14", ip4); - /* Should flush the session */ - TEST_VOID(soa_process_reject(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP6_ONLY) => select IP6 address */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP6_ONLY), TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "2001:1508:1003::21a:a0ff:fe71:813", ip6); - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_IP6) => select IP4 address */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_IP6), TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "11.12.13.14", ip4); - TEST_VOID(soa_process_reject(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP6_IP4) => select IP6 address */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP6_IP4), TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "2001:1508:1003::21a:a0ff:fe71:813", ip6); - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_IP6) but session mentions IP6 => select IP6 */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_IP6), TAG_END()); - n = soa_set_user_sdp(a, 0, "c=IN IP6 ::\r\nm=audio 5008 RTP/AVP 0 8", -1); TEST(n, 1); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "2001:1508:1003::21a:a0ff:fe71:813", ip6); - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_IP6), o= mentions IP6 => select IP4 */ - n = soa_set_user_sdp(a, 0, "o=- 1 1 IN IP6 ::\r\n" - "m=audio 5008 RTP/AVP 0 8", -1); TEST(n, 1); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "11.12.13.14", ip4); - TEST_VOID(soa_process_reject(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_IP6), c= uses non-local IP6 - => select local IP6 on o= */ - n = soa_set_user_sdp(a, 0, - "c=IN IP6 2001:1508:1004::21a:a0ff:fe71:819\r\n" - "m=audio 5008 RTP/AVP 0 8", -1); - TEST(n, 1); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST(test_address_in_offer(a, - /* o= has local address */ - "2001:1508:1003::21a:a0ff:fe71:813", sdp_addr_ip6, - /* c= has sdp-provided address */ - "2001:1508:1004::21a:a0ff:fe71:819", sdp_addr_ip6), 0); - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_ONLY), no IP4 addresses */ - s2_localinfo_ifaces(ifaces_ip6only); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_ONLY), TAG_END()); - n = soa_set_user_sdp(a, 0, "m=audio 5008 RTP/AVP 0 8", -1); - TEST(soa_generate_offer(a, 1, test_completed), -1); - - /* Retry with IP6 enabled */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_IP6), TAG_END()); - TEST(soa_generate_offer(a, 1, test_completed), 0); - TEST_OC_ADDRESS(a, "2001:1508:1003::21a:a0ff:fe71:813", ip6); - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP6_ONLY), no IP6 addresses */ - s2_localinfo_ifaces(ifaces_ip4only); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP6_ONLY), TAG_END()); - TEST(soa_generate_offer(a, 1, test_completed), -1); /* should fail */ - TEST_VOID(soa_terminate(a, NULL)); - - /* SOATAG_AF(SOA_AF_IP4_ONLY), no IP4 addresses */ - s2_localinfo_ifaces(ifaces_ip6only); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_ONLY), TAG_END()); - TEST(soa_generate_offer(a, 1, test_completed), -1); /* should fail */ - TEST_VOID(soa_terminate(a, NULL)); - - /* Select locally available address from the SOATAG_ADDRESS() list */ - s2_localinfo_ifaces(ifaces1); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_IP6), - SOATAG_ADDRESS("test.com 17.18.19.20 12.13.14.15"), - TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "12.13.14.15", ip4); - TEST_VOID(soa_process_reject(a, NULL)); - - /* Select locally available IP6 address from the SOATAG_ADDRESS() list */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP6_IP4), - SOATAG_ADDRESS("test.com 12.13.14.15 fec0::21a:a0ff:fe71:815"), - TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "fec0::21a:a0ff:fe71:815", ip6); - TEST_VOID(soa_process_reject(a, NULL)); - - /* Select first available address from the SOATAG_ADDRESS() list */ - n = soa_set_params(a, SOATAG_AF(SOA_AF_ANY), - SOATAG_ADDRESS("test.com 12.13.14.15 fec0::21a:a0ff:fe71:815"), - TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "12.13.14.15", ip4); - TEST_VOID(soa_process_reject(a, NULL)); - - /* Select preferred address from the SOATAG_ADDRESS() list */ - s2_localinfo_ifaces(ifaces1); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP4_IP6), - SOATAG_ADDRESS("test.com fec0::22a:a0ff:fe71:815 19.18.19.20"), - TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "19.18.19.20", ip4); - TEST_VOID(soa_process_reject(a, NULL)); - - /* Select preferred address from the SOATAG_ADDRESS() list */ - s2_localinfo_ifaces(ifaces1); - n = soa_set_params(a, SOATAG_AF(SOA_AF_IP6_IP4), - SOATAG_ADDRESS("test.com 19.18.19.20 fec0::22a:a0ff:fe71:815 fec0::22a:a0ff:fe71:819"), - TAG_END()); - n = soa_generate_offer(a, 1, test_completed); TEST(n, 0); - TEST_OC_ADDRESS(a, "fec0::22a:a0ff:fe71:815", ip6); - TEST_VOID(soa_process_reject(a, NULL)); - - TEST_VOID(soa_destroy(a)); - - (void)b; (void)o; -#if 0 - TEST_1(b = soa_clone(ctx->b, ctx->root, ctx)); - - 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 put call inactive */ - 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=inactive")); - 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=inactive")); - 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_INACTIVE); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); - - /* B will send an offer to A, but there is no change in O/A status */ - 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, "a=inactive")); - /* printf("offer:\n%s", offer); */ - TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); - TEST(soa_generate_answer(a, test_completed), 0); - TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE); - TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); - 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, "a=inactive")); - /* printf("answer:\n%s", answer); */ - 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(b), SOA_ACTIVE_INACTIVE); - TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_INACTIVE); - - /* '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") && !strstr(offer, "a=inactive")); - 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") && !strstr(answer, "a=inactive")); - 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 5008 RTP/AVP 0 8\r\ni=x\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)); -#endif - su_home_deinit(home); - - END(); -} - -int test_deinit(struct context *ctx) -{ - BEGIN(); - - su_root_destroy(ctx->root), ctx->root = NULL; - soa_destroy(ctx->a); - soa_destroy(ctx->b); - - END(); -} - -#if HAVE_ALARM -static RETSIGTYPE sig_alarm(int s) -{ - fprintf(stderr, "%s: FAIL! test timeout!\n", name); - exit(1); -} -#endif - -void usage(int exitcode) -{ - fprintf(stderr, - "usage: %s [-v|-q] [-a] [-l level] [-p outbound-proxy-uri]\n", - name); - exit(exitcode); -} - -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], "-a") == 0) - tstflags |= tst_abort; - 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(1); - - 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(1); - } - -#if HAVE_OPEN_C - tstflags |= tst_verbatim; -#endif - - if (o_attach) { - char line[10], *cr; - printf("%s: pid %u\n", name, getpid()); - printf("\n"); - cr = fgets(line, sizeof line, stdin); - (void)cr; - } -#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_localinfo_replacement(); SINGLE_FAILURE_CHECK(); - - 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_address_selection(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_large_sessions(ctx); SINGLE_FAILURE_CHECK(); - 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_media_replace(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_media_removal(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_media_reject(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_media_replace2(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_media_mode(ctx); SINGLE_FAILURE_CHECK(); - - retval |= test_asynch_offer_answer(ctx); SINGLE_FAILURE_CHECK(); - } - retval |= test_deinit(ctx); SINGLE_FAILURE_CHECK(); - - su_deinit(); - -#if HAVE_OPEN_C - sleep(5); -#endif - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sofia.am b/libs/sofia-sip/libsofia-sip-ua/sofia.am deleted file mode 100644 index a7d8c346d6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sofia.am +++ /dev/null @@ -1,58 +0,0 @@ -# common Makefile targets for libsofia-sip-ua modules -# --------------------------------------------------- - -AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) $(SOFIA_COVERAGE) $(SOFIA_PLAT_CFLAGS) - -# Use with --enable-ndebug -if NDEBUG -AM_CFLAGS += -DNDEBUG -endif - -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone b/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone deleted file mode 100644 index 2dd92e46ca..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/127.zone +++ /dev/null @@ -1,13 +0,0 @@ -$TTL 86400 -@ IN SOA localhost. root.localhost ( - 1 ; serial - 28800 ; refresh - 7200 ; retry - 604800 ; expire - 86400 ; ttk - ) - - -@ IN NS localhost. - -1 IN PTR localhost. diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188 b/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188 deleted file mode 100644 index 46e5f4098c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/194.2.188 +++ /dev/null @@ -1,14 +0,0 @@ -$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. - diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 b/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 deleted file mode 100644 index c923d57608..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0 +++ /dev/null @@ -1,13 +0,0 @@ -$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. diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa b/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa deleted file mode 100644 index e48ecffe6f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/3.f.f.e.1.2.0.0.3.0.1.2.c.0.0.0.arpa +++ /dev/null @@ -1,13 +0,0 @@ -$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. diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog deleted file mode 100644 index ea00912a0b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/ChangeLog +++ /dev/null @@ -1,10 +0,0 @@ -2006-05-03 Kai Vehmanen - - * 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 - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile.in deleted file mode 100644 index e5b55b7f0f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/Doxyfile.in +++ /dev/null @@ -1,16 +0,0 @@ -PROJECT_NAME = "sresolv" -OUTPUT_DIRECTORY = ../docs/html/sresolv - -INPUT = @srcdir@/sofia-sip @srcdir@/sofia-resolv @srcdir@/sresolv.docs @srcdir@ - -EXCLUDE = resolve_sip.c - -@INCLUDE_PATH = . @srcdir@ -@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am deleted file mode 100644 index b80ec5863c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/Makefile.am +++ /dev/null @@ -1,72 +0,0 @@ -# -# Makefile.am for sresolv module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -I$(srcdir)/../url -I../url \ - -I$(srcdir)/../bnf -I../bnf \ - -I$(srcdir)/../su -I../su - -# ---------------------------------------------------------------------- -# Build targets - -noinst_LTLIBRARIES = libsresolv.la - -check_PROGRAMS = torture_sresolv test_sresolv - -TESTS = - -check_PROGRAMS += check_sres_sip -TESTS += check_sres_sip -check_sres_sip_LDADD = $(LDADD) ${top_builddir}/s2check/libs2.a @CHECK_LIBS@ -AM_CPPFLAGS += -I${top_srcdir}/s2check - -TESTS += torture_sresolv run_test_sresolv - -CLEANFILES = resolv.conf error.conf named.conf.tmp \ - .test_sresolv.api.conf.?????? \ - named.run - -LDADD = libsresolv.la \ - ../url/liburl.la ../bnf/libbnf.la \ - ../su/libsu.la - -test_sresolv_LDFLAGS = -static - -# ---------------------------------------------------------------------- -# Rules for building the targets - -nobase_include_sofia_HEADERS = \ - sofia-sip/sresolv.h \ - sofia-sip/sres_sip.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 sres_sip.c - -COVERAGE_INPUT = $(libsresolv_la_SOURCES) $(include_sofia_HEADERS) - -# ---------------------------------------------------------------------- -# Distribution - -EXTRA_DIST = 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 $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/check_sres_sip.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/check_sres_sip.c deleted file mode 100644 index ea392f0324..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/check_sres_sip.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2009 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 check_sres_sip.c - * - * @brief Check-driven tester for SIP URI resolver - * - * @author Pekka Pessi - * - * @copyright (C) 2009 Nokia Corporation. - */ - -#include "config.h" - -#define SRES_SIP_MAGIC_T void - -#include - -#include "s2check.h" -#include "s2dns.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include - -SOFIAPUBVAR su_log_t sresolv_log[]; - -static void -setup_logs(int level) -{ - su_log_soft_set_level(sresolv_log, level); -} - -/* */ -struct context { - su_root_t *root; - sres_resolver_t *sres; -} x[1]; - -static su_addrinfo_t hint_udp_tcp[2]; -static su_addrinfo_t hint_udp_tcp_tls[2]; -static su_addrinfo_t hint_udp_tcp_ip4[2]; -static su_addrinfo_t hint_tls[1]; -static su_addrinfo_t hint_tls_udp_tcp[1]; - -static void -resolver_setup(void) -{ - x->root = su_root_create(NULL); - assert(x->root); - s2_dns_setup(x->root); - - s2_dns_record("test.example.com.", sres_type_a, - "test.example.com.", sres_type_a, "12.13.14.25", - NULL); - - x->sres = sres_resolver_create( - x->root, NULL, -#if HAVE_WIN32 - SRESTAG_RESOLV_CONF("NUL"), -#else - SRESTAG_RESOLV_CONF("/dev/null"), -#endif - TAG_END()); - - hint_udp_tcp[0].ai_protocol = TPPROTO_UDP; - hint_udp_tcp[0].ai_next = &hint_udp_tcp[1]; - hint_udp_tcp[1].ai_protocol = TPPROTO_TCP; - - hint_udp_tcp_ip4[0].ai_protocol = TPPROTO_UDP; - hint_udp_tcp_ip4[0].ai_family = AF_INET; - hint_udp_tcp_ip4[0].ai_next = &hint_udp_tcp_ip4[1]; - hint_udp_tcp_ip4[1].ai_protocol = TPPROTO_TCP; - hint_udp_tcp_ip4[1].ai_family = AF_INET; - - hint_tls[0].ai_protocol = TPPROTO_TLS; - - hint_tls_udp_tcp[0].ai_protocol = TPPROTO_TLS; - hint_tls_udp_tcp[0].ai_next = hint_udp_tcp; - - hint_udp_tcp_tls[0].ai_protocol = TPPROTO_UDP; - hint_udp_tcp_tls[0].ai_next = &hint_udp_tcp_tls[1]; - hint_udp_tcp_tls[1].ai_protocol = TPPROTO_TCP; - hint_udp_tcp_tls[1].ai_next = &hint_udp_tcp_tls[2]; - hint_udp_tcp_tls[2].ai_protocol = TPPROTO_TLS; - hint_udp_tcp_tls[2].ai_next = NULL; - - setup_logs(0); -} - -static void -resolver_teardown(void) -{ - sres_resolver_unref(x->sres), x->sres = NULL; - s2_dns_teardown(); -} - -/* ---------------------------------------------------------------------- */ - -static uint16_t -ai_port(su_addrinfo_t const *ai) -{ - return ai && ai->ai_addr ? - ntohs(((struct sockaddr_in *)ai->ai_addr)->sin_port) : 0; -} - -static int -ai_ip4_match(su_addrinfo_t const *ai, - char const *addr, - uint16_t port) -{ - struct in_addr in, in_in_ai; - - if (ai_port(ai) != port) - return 0; - - if (ai->ai_family != AF_INET) - return 0; - - if (su_inet_pton(AF_INET, addr, &in) <= 0) - return 0; - - in_in_ai = ((struct sockaddr_in *)ai->ai_addr)->sin_addr; - - return memcmp(&in, &in_in_ai, (sizeof in)) == 0; -} - -/* ---------------------------------------------------------------------- */ - -START_TEST(invalid) -{ - sres_sip_t *srs; - -#if 0 - S2_CASE("1.0", "Check invalid input values", - "Detailed explanation for empty test case."); -#endif - - srs = sres_sip_new(NULL, (void *)"sip:test.example.com.", NULL, - 1, 1, - NULL, NULL); - fail_if(srs != NULL); - - srs = sres_sip_new(x->sres, NULL, NULL, - 1, 1, - NULL, NULL); - - fail_if(srs != NULL); - - srs = sres_sip_new(x->sres, (void *)"tilu.liu.", NULL, 1, 1, NULL, NULL); - fail_unless(srs != NULL); - fail_if(sres_sip_error(srs) != SRES_SIP_ERR_BAD_URI); - fail_if(sres_sip_next_step(srs)); - fail_if(sres_sip_results(srs) != NULL); - sres_sip_unref(srs); -} -END_TEST - -static void -resolver_callback(void *userdata, - sres_sip_t *srs, - int final) -{ - if (final) - su_root_break((su_root_t *)userdata); -} - -START_TEST(not_found) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - - srs = sres_sip_new(x->sres, (void *)"sip:notfound.example.net", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - fail_if(ai != NULL); - - fail_if(sres_sip_error(srs) != SRES_SIP_ERR_NO_NAME); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(failure) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - - /* there is no server at all */ - s2_dns_teardown(); - - srs = sres_sip_new(x->sres, (void *)"sip:timeout.example.net", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - fail_if(ai != NULL); - - fail_if(sres_sip_error(srs) != SRES_SIP_ERR_AGAIN); - - sres_sip_unref(srs); -} -END_TEST - -/* time() replacement */ -static time_t offset; - -time_t -time(time_t *return_time) -{ - su_time_t tv; - time_t now; - - su_time(&tv); - - now = tv.tv_sec + offset - 2208988800UL; /* NTP_EPOCH */ - - if (return_time) - *return_time = now; - - return now; -} - -/* Drop packet */ -static int drop(void *data, size_t len, void *userdata) -{ - return 0; -} - -/* Fast forward time, call resolver timer */ -static void wakeup(su_root_magic_t *magic, - su_timer_t *timer, - su_timer_arg_t *extra) -{ - offset++; - sres_resolver_timer(x->sres, 0); -} - -START_TEST(timeout) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - su_timer_t *faster = su_timer_create(su_root_task(x->root), 10); - - su_timer_run(faster, wakeup, NULL); - - s2_dns_set_filter(drop, NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:timeout.example.net", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - fail_if(ai != NULL); - - fail_if(sres_sip_error(srs) != SRES_SIP_ERR_AGAIN); - - sres_sip_unref(srs); - - s2_dns_set_filter(NULL, NULL); - - su_timer_destroy(faster); -} -END_TEST - -START_TEST(found_a) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - - srs = sres_sip_new(x->sres, (void *)"sip:test.example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_ip) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - url_string_t *uri; - - srs = sres_sip_new(x->sres, (void *)"sip:127.21.50.37", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - - srs = sres_sip_new(x->sres, (void *)"sip:127.21.50.37:", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - -#if SU_HAVE_IN6 - - uri = (void *)"sip:[3ff0:0010:3012:c000:02c0:95ff:fee2:4b78]"; - - srs = sres_sip_new(x->sres, uri, NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - -#endif -} -END_TEST - -START_TEST(found_maddr_a) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - url_string_t *uri; - - s2_dns_record("maddr.example.com", sres_type_a, - "", sres_type_a, "11.12.13.14", - NULL); - - uri = (void *)"sip:test.example.com;lr=1;maddr=maddr.example.com;more"; - - srs = sres_sip_new(x->sres, uri, NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai_ip4_match(ai, "11.12.13.14", 5060)); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_cname) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - url_string_t *uri; - - s2_dns_default("example.com."); - - s2_dns_record("cname1.example.com.", sres_type_a, - "", sres_type_cname, "a.example.com.", - "a", sres_type_a, "11.12.13.14", - NULL); - - s2_dns_record("cname1.example.com.", sres_type_naptr, - "", sres_type_cname, "a.example.com.", - NULL); - - s2_dns_record("cname1.example.com.", sres_type_aaaa, - "", sres_type_cname, "a.example.com.", - NULL); - - s2_dns_record("a.example.com.", sres_type_a, - "", sres_type_a, "11.12.13.14", - NULL); - - s2_dns_record("cname2.example.com.", sres_type_a, - "", sres_type_cname, "a.example.com.", - "test.example.com.", sres_type_a, "11.12.13.14", - NULL); - - uri = (void *)"sip:cname1.example.com"; - - srs = sres_sip_new(x->sres, uri, NULL, 1, 1, resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai_ip4_match(ai, "11.12.13.14", 5060)); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_maddr_ip) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - url_string_t *uri; - - uri = (void *)"sip:not.existing.net;maddr=127.21.50.37"; - - srs = sres_sip_new(x->sres, uri, NULL, 1, 1, resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - -#if SU_HAVE_IN6 - - uri = (void *)"sip:test.example.com:" - ";maddr=3ff0:0010:3012:c000:02c0:95ff:fee2:4b78"; - - srs = sres_sip_new(x->sres, uri, NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - - uri = (void *)"sip:test.example.com:" - ";maddr=[3ff0:0010:3012:c000:02c0:95ff:fee2:4b78]"; - - srs = sres_sip_new(x->sres, uri, NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - fail_if(sres_sip_next_step(srs)); - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); - -#endif -} -END_TEST - -START_TEST(found_a_aaaa) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - - s2_dns_default("example.com."); - - s2_dns_record("ip6ip4.example.com.", sres_type_a, - "", sres_type_a, "12.13.14.25", - "", sres_type_aaaa, "3ff0:0010:3012:c000:02c0:95ff:fee2:4b78", - NULL); - - s2_dns_record("ip6ip4", sres_type_aaaa, - "", sres_type_aaaa, "3ff0:0010:3012:c000:02c0:95ff:fee2:4b78", - "", sres_type_a, "12.13.14.25", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:ip6ip4.example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - assert(ai != NULL); -#if SU_HAVE_IN6 - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai->ai_family == AF_INET6); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET6); - fail_if(!(ai = ai->ai_next)); -#endif - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_naptr) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - d, sres_type_naptr, 20, 50, "s", "SIP+D2T", "", "_sip._tcp", - /* priority weight port target */ - "_sip._tcp", sres_type_srv, 2, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.15", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_naptr_nohint) -{ - sres_sip_t *srs; - char const *d; - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - d, sres_type_naptr, 20, 50, "s", "SIP+D2Z", "", "_sip._tilulilu", - /* priority weight port target */ - "_sip._tilulilu", sres_type_srv, 2, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.15", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - fail_unless(sres_sip_results(srs) == NULL); - fail_unless(sres_sip_error(srs) == SRES_SIP_ERR_NO_TPORT); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_bad_naptr) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - d, sres_type_naptr, 20, 50, "s", "ZIP+D2T", "", "_zip._tcp", - NULL); - - s2_dns_record(d, sres_type_a, - "", sres_type_a, "11.12.13.14", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_run(x->root); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_if((ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(ignore_naptr) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - d, sres_type_naptr, 20, 50, "s", "SIP+D2T", "", "_sip._tcp", - /* priority weight port target */ - "_sip._tcp", sres_type_srv, 2, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.15", - NULL); - - s2_dns_record(d, sres_type_a, - "", sres_type_a, "13.14.15.16", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com:5060", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - ai = ai->ai_next; assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - ai = ai->ai_next; assert(ai == NULL); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_naptr2) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - /* Test case without caching, two A addresses */ - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - "", sres_type_naptr, 20, 50, "s", "SIP+D2T", "", "_sip._tcp", - NULL); - - s2_dns_record("_sip._tcp", sres_type_srv, - /* priority weight port target */ - "", sres_type_srv, 2, 100, 5060, "sip00", - NULL); - - s2_dns_record("sip00", sres_type_a, - "", sres_type_a, "12.13.14.15", - "", sres_type_a, "12.13.14.16", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_naptr3) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - /* Check that sip: resolves only to TLS */ - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - d, sres_type_naptr, 30, 50, "s", "SIP+D2T", "", "_sip._tcp.srv00", - d, sres_type_naptr, 20, 50, "s", "SIPS+D2T", "", "_sips._tcp.srv00", - /* priority weight port target */ - "_sips._tcp.srv00", sres_type_srv, 2, 100, 5061, "sips00", - "sips00", sres_type_a, "12.13.14.15", - "_sip._tcp.srv00", sres_type_srv, 2, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.16", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); - - /* Hint no support for TLS */ - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hint_udp_tcp, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_naptr_with_a) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - int i; - - s2_dns_default(d = "example.com."); - - s2_dns_record(d, sres_type_naptr, - /* order priority flags services regexp target */ - "", sres_type_naptr, 20, 50, "a", "SIP+D2U", "", "sip00", - "", sres_type_naptr, 20, 50, "a", "SIP+D2T", "", "sip00", - "", sres_type_naptr, 20, 50, "a", "SIPS+D2T", "", "sip00", - "sip00", sres_type_a, "12.13.14.15", - NULL); - - /* Check that cache does not change ordering */ - for (i = 0; i < 3; i++) { - srs = sres_sip_new(x->sres, (void *)"sip:example.com", NULL, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - - if (i == 0) { - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - } - else { - fail_if(sres_sip_next_step(srs)); - } - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai->ai_family == AF_INET); - - ai = ai->ai_next; - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - - ai = ai->ai_next; - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - - fail_if(ai->ai_next); - - sres_sip_unref(srs); - } -} -END_TEST - -START_TEST(found_srv) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - - /* Check that hints are followed: */ - - s2_dns_default(d = "example.com."); - - s2_dns_record("_sips._tcp", sres_type_srv, - "", sres_type_srv, 2, 100, 5061, "sips00", - "sips00", sres_type_a, "12.13.14.15", - NULL); - s2_dns_record("_sip._tcp", sres_type_srv, - "", sres_type_srv, 2, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.16", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hint_udp_tcp, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); - - /* Hints prefer TLS */ - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hint_tls_udp_tcp, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); - - /* Hints support TLS, prefer TCP */ - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hint_udp_tcp_tls, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); - sres_resolver_unref(x->sres); - - x->sres = sres_resolver_create( - x->root, NULL, -#if HAVE_WIN32 - SRESTAG_RESOLV_CONF("NUL"), -#else - SRESTAG_RESOLV_CONF("/dev/null"), -#endif - TAG_END()); - - /* Add UDP record */ - s2_dns_record("_sip._udp", sres_type_srv, - "", sres_type_srv, 1, 100, 5060, "sip00", - "sip00", sres_type_a, "12.13.14.16", - NULL); - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hint_udp_tcp_tls, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_if(!(ai = ai->ai_next)); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - fail_unless(!(ai = ai->ai_next)); - - sres_sip_unref(srs); -} -END_TEST - -START_TEST(found_multi_srv) -{ - sres_sip_t *srs; - su_addrinfo_t const *ai; - char const *d; - int i; - su_addrinfo_t hints[1]; - - /* Check that srv records are selected correctly by priority and weight */ - - s2_dns_default(d = "example.com."); - - s2_dns_record("_sips._tcp", sres_type_srv, - "", sres_type_srv, 2, 100, 5061, "sips00", - "", sres_type_srv, 2, 100, 5061, "sips01", - "", sres_type_srv, 2, 200, 5061, "sips02", - "sips00", sres_type_a, "12.13.0.10", - "sips01", sres_type_a, "12.13.1.10", - "sips02", sres_type_a, "12.13.2.10", - NULL); - - mark_point(); - - s2_dns_record("_sip._tcp", sres_type_srv, - "", sres_type_srv, 4, 1, 5060, "sip00", - "", sres_type_srv, 3, 100, 5060, "sip01", - "", sres_type_srv, 3, 10, 5060, "sip02", - "sip00", sres_type_a, "12.13.0.1", - "sip00", sres_type_a, "12.13.0.2", - "sip01", sres_type_a, "12.13.1.2", - "sip01", sres_type_a, "12.13.1.1", - "sip02", sres_type_a, "12.13.2.1", - "sip02", sres_type_a, "12.13.2.2", - NULL); - mark_point(); - - s2_dns_record("_sip._udp", sres_type_srv, - "", sres_type_srv, 10, 100, 5060, "sip00", - "", sres_type_srv, 10, 0, 5060, "sip01", - "", sres_type_srv, 1, 100, 5060, "sip02", - "sip00", sres_type_a, "12.13.0.1", - "sip00", sres_type_a, "12.13.0.2", - "sip01", sres_type_a, "12.13.1.2", - "sip01", sres_type_a, "12.13.1.1", - "sip02", sres_type_a, "12.13.2.1", - "sip02", sres_type_a, "12.13.2.2", - NULL); - - mark_point(); - - /* Ask resolver to return canonic names */ - *hints = *hint_udp_tcp_tls, hints->ai_flags |= AI_CANONNAME; - - srs = sres_sip_new(x->sres, (void *)"sip:example.com", hints, - 1, 1, - resolver_callback, x->root); - fail_if(srs == NULL); - - while (sres_sip_next_step(srs)) - su_root_step(x->root, 1000); - - ai = sres_sip_results(srs); - - for (i = 0; i < 6; i++) { - static char const * const names[] = { - "sip02.", "sip02.", /* Selected because priority */ - "sip00.", "sip00.", /* Because of sip01 has weight=0 */ - "sip01.", "sip01." - }; - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_UDP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(ai_port(ai) == 5060); - fail_if(memcmp(ai->ai_canonname, names[i], strlen(names[i])) != 0); - ai = ai->ai_next; - } - - for (i = 0; i < 6; i++) { - static char const * const names[] = { - "sip", "sip", - "sip", "sip", - "sip00.", "sip00." - }; - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TCP); - fail_unless(ai->ai_family == AF_INET); - fail_unless(ai_port(ai) == 5060); - fail_if(memcmp(ai->ai_canonname, names[i], strlen(names[i])) != 0); - ai = ai->ai_next; - } - - for (i = 0; i < 3; i++) { - assert(ai != NULL); - fail_if(ai->ai_protocol != TPPROTO_TLS); - fail_unless(ai->ai_family == AF_INET); - fail_unless(ai_port(ai) == 5061); - ai = ai->ai_next; - } - - sres_sip_unref(srs); -} -END_TEST - -TCase *api_tcase(void) -{ - TCase *tc = tcase_create("1 - Test simple resolving"); - - tcase_add_checked_fixture(tc, resolver_setup, resolver_teardown); - - tcase_add_test(tc, invalid); - tcase_add_test(tc, not_found); - tcase_add_test(tc, failure); - tcase_add_test(tc, timeout); - tcase_add_test(tc, found_a); - tcase_add_test(tc, found_cname); - tcase_add_test(tc, found_ip); - tcase_add_test(tc, found_maddr_a); - tcase_add_test(tc, found_maddr_ip); - tcase_add_test(tc, found_a_aaaa); - tcase_add_test(tc, found_naptr); - tcase_add_test(tc, found_bad_naptr); - tcase_add_test(tc, found_naptr_nohint); - tcase_add_test(tc, found_naptr2); - tcase_add_test(tc, found_naptr3); - tcase_add_test(tc, found_naptr_with_a); - tcase_add_test(tc, ignore_naptr); - tcase_add_test(tc, found_srv); - tcase_add_test(tc, found_multi_srv); - - return tc; -} - -/* ---------------------------------------------------------------------- */ - -static void usage(int exitcode) -{ - fprintf(exitcode ? stderr : stdout, - "usage: check_sres_sip [--xml=logfile] case,...\n"); - exit(exitcode); -} - -int main(int argc, char *argv[]) -{ - int i, failed = 0; - - Suite *suite = suite_create("Unit tests for SIP URI resolver"); - SRunner *runner; - char const *xml = NULL; - - s2_select_tests(getenv("CHECK_CASES")); - - for (i = 1; argv[i]; i++) { - if (su_strnmatch(argv[i], "--xml=", strlen("--xml="))) { - xml = argv[i] + strlen("--xml="); - } - else if (su_strmatch(argv[i], "--xml")) { - if (!(xml = argv[++i])) - usage(2); - } - else if (su_strmatch(argv[i], "-?") || - su_strmatch(argv[i], "-h") || - su_strmatch(argv[i], "--help")) - usage(0); - else - s2_select_tests(argv[i]); - } - - suite_add_tcase(suite, api_tcase()); - - runner = srunner_create(suite); - if (xml) - srunner_set_xml(runner, xml); - srunner_run_all(runner, CK_ENV); - failed = srunner_ntests_failed(runner); - srunner_free(runner); - - exit(failed ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com b/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com deleted file mode 100644 index d1c424acd3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/example.com +++ /dev/null @@ -1,93 +0,0 @@ -; -; 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 - -cloop CNAME cloop0 -cloop0 CNAME cloop1 -cloop1 CNAME cloop2 -cloop2 CNAME cloop0 - -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf b/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf deleted file mode 100644 index 52b46b57ca..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/named.conf +++ /dev/null @@ -1,33 +0,0 @@ -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"; -}; diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf b/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf deleted file mode 100644 index 05be2c8e09..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/resolv_timeout.conf +++ /dev/null @@ -1,5 +0,0 @@ -foo bar foobar -nameserver 137.0.0.1 -nameserver 182.21.40.170 -#nameserver 127.0.0.1 - diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c deleted file mode 100644 index 978f4cef85..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/resolve_sip.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2006 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @par Created: Tue Jul 16 18:50:14 2002 ppessi - * - * - */ - -#include -#include -#include - -/* Typesafe */ -#define SRES_CONTEXT_T struct context - -#include "sofia-sip/sresolv.h" -#include "sofia-sip/su_string.h" - -char const name[] = "sip_resolve"; - -#include -#include -#include -#include -#include - -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 (!su_casenmatch("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 (!su_casenmatch("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 */ - - su_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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt b/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt deleted file mode 100644 index 55cdb21fe6..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/rfc1034.txt +++ /dev/null @@ -1,3077 +0,0 @@ -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 @ is mapped into a domain name by -converting into a single label (regardles of dots it -contains), converting 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@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). - - ::= | " " - - ::=

mY8X3vncdN>C7{6d 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 UY_1lxB?C(amJBQzm_7slKOgU}*#H0l diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.gif deleted file mode 100644 index dde6c679544790c57698c1df39c707d1435971b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10413 zcmbukWl-F)yEgo*7h0e=UEG}(7MHe^;#S-#4hu_hm*TQmad)>x7S}@2Wr5=E?!^m* z-M8nQd7gRa%zxf5Z$4y_dy?F_k~`NmNu*_^1ci+C9)5aw4FDJn2Kevve+&Op{g3(o zYV$wU|7HA-9si^8|7Z9AIOhKt|JRiMKOB860DM}3$Z;Tj7bwF3^%%M?%qJAaVg?ho zfhjx2pzy%}ND-j30NDKia4H~*06w7r#ce|p0!1}*c20$1P7z0+sC|Y1F{4jp0m{bG?f%>oZ_<$k^u%H9{*nw0q zfDi>xpMY&e0HZ;Pu@c63YhhwsF!^zqhAIpag;@f?bbuT;VDtfSQwE|9fr76w3I%L$|J!&<3`Q7( z(ZXO{Fqk+DrV4{W{R;*V7-0Df2-pIWFhIQoFzE#x)&V~ZC=vrs#V8hGED#vKPE0Ba zgP6mhw*LjsKfoFQ;06Gx0MH5mOaIW4l43YHF`qtR^z<+e4w$eoOm;S=z8-@@VL$+w z2~Y$B79RjVMIcoNKv)1MCt%wTz(iAGGKDeaT9_6W%s?DwrV6u-!hiv=BA{piSoi^c zsX!_MK%fBBHt^5!e+Ka1+r?x7fc=0EsemE^&_Mwf+kg}19|p>3jBqAKs~qFff{7cz zRL%SYKzsA}U(C<}9RC$L|8*ulJVyf$o>RzF=X3==CuGwfsLuTv`ifpIL#8ILH-Zdo zy*N;l-ycIG0lOnJDi{o4R4xljaV+dlA~J5tc&%C_p3eJb9X060I07*GKc&P5tW@%( zpMdz%oFQ_>im^QAx^=}mykG`bfp6>@wm7Vm4%@QG4yZoEucX z**%d`sw6}!THChTx+a@)h1O>g{K`(*8`)jzt1j%iS_UAiYBJ|&s zZmxdsf#lWR41t8Mj_Q7*4-#<=uP;tE#BJVm+=%XVIhDdI*|pL0e=ird?QRW4uTi^+ zma2Xj+fS>I1C3|oQqQnUQorGJY#N#47YV2ak24AqhLEHc(YlX0^sNQqMeXV+F`ZrI zn$YqvOh)jsO0SzS!vr@%xOtM+gOmnmXCp!@we^hOE$^yE03g=!Xn1|`W}E`^Vbqi>55p-?76JnzO*ER}tJV zd~g^r`c;R}Vd55PQ`WATepE`ZTt{u>9xXy0+n~|9o4aIqSsA_0)eN^gL55hH1y2vz zw%J5u(c7mZkyYh~$K`Py@wja>oq8l5)!kuq5ht?GpUJcQ6cZASO(9P9eABh|5v8w4 z=0^H9x&ijmu8UBw%rX4KSNVg%*^s+4$U}O;3YX-*3vh#9 zbW&(t5D@Kiz5U)TS$~(~$Okg){a(hdcsLJ!Jx$?tRFl`ze_Yp^@-$Vbd8<$0CeZC6 zcBOrXz)9Od-FlSE*r=ABPc4GpS7c_=@vV60imr(Qae=%SO_{l2{}QU)R92y~7Cy`8jr-xgv~S<{LLW zN3e*iL|Q52+n12>^OVJUGCo`)2MZPp1^kM#ugizSS%k%IPh%atNFk#Gq9Y3!u%5TSb&Zn96T)5f)duT4HD=M2*DVqC z^dn(fM?wxuxcl%5fPU=v!~gLM5D^(oZg=oYa$)c1+<86W&)9X_!npJMqKF^a-#zCs z6OW;L7RM3JQ;1A_s_bfpg(w(G;kB9H6eP_32)uBKQz)4z?$7$*f3_$z&hjZh$WB;8 zh;UD(@ROTr{jC$rc$PxFob4_CVQ+<0vFFr2f>9Uoae>NZ=xwP)yq&ZOk=OUb!7|A~ zq^(RN$3$_^iqnMHD26?cu05PUx4Ohm*ewBs{s6Uf1tW zXRTLdhC%kt(H0Temh<;#ib+eiggy@~h_dXq zj2jKT7Pv#x{VT;?jI8H4|D*-rlUS_zeK$za3e5HhTlAlSXstR?)F$Pc#uTzphLMf; ztjp173Fd~djQ?46r(Sm_i*UlX`Vu3mxlIA(#udu2kVXcXLFMmz$0O1AvzyUG%i3EZ zIh?P}lioVq6ebJJH-S&tTm*xZ zry^z1C3y)gY^;?HO4#gPytOUsm2Yma4~v?U`pP3Sp4za~B2_KQs+$^g4+~piEftA@ z`yl00%h>+THRn4{F}EFBlgEnT*Ng~}$=ukt7PHz4w&y1)FE zCrQ_6FRskYK6Cx98~zAJ1cvFR+QcDMs?r{RrQH69jUmT;C1EQwW6A5lq2C!*jtV)k z;%QnAo#A;Xoxz&!=T2#LKKfY+bMN?g8hK1#(6;+M88#X!`KphIORH@=vsYvmaBfhE zvE=Rdl9VzZPr4E{n95T+a!S*&IodQAOK-hM-qECFUD%JUylS#M{{wdaN_FsNapo9Z z(OA@3IGeQqIgxW4cba+Ow)BdWi@o=(ec`y}@Jge2O5i;ek#Br!`HZ*A{k(2X0DBg6 z#GVSbdb(uc$bR{JpL}Z|K+EILzU5g`*-@$5z<#`1^pabs@WzGnZ!!{UlCuwPk7@k8 z9kYbCtW|LHprC%J_tpHl53P6Ln@*oU>kG{b&MO-tzPJ0NnXA89D&ehFr^W9vw_FQ& z#It_{+P-1%otB!^Zem=2Oe`N-JN{q}f8yy9OSKI@6G4AChG4U=0>$PZPF`;LJaC?V zQZv(@pDXW%`ZEZ5%L_Ks}25-$<)I z-ggSHlpDI5*^)j%q>9*Wc?Ri{V87`8si4*4Ija8kR{LIAN6BUaEqjFc?ctV6_+5Tw z!mfn0oMW89x(=Cm<0lbS$M_8WjA)CJIwhE6LMjCT17mZFTAZqkM}#i_f#fV$@nXNZ)(cHeTOgb?UOV|}t3-m$vgFEz=71NZ zxS~_=&)ps_a?o`5YU6hE(~nf-LT6@uZy!+?MQG5j3`K~0g}m?tFHExhZ6O)FcIlq2 zrR?M|m~cH>LR6kv+=#dJZ z6>7@#?-wsIR3V9*q7D|2WuXWKy*1Bd9Ho9dwb_q&Y`?3@*1FW7}SyL8ysKQ$`OKvqx zcR%P!n%r6jB$}7qyFHG##I3#siz5cS@3|M&32UgR2}TNXxak>Sv(+|PL$=ELpRya) zeMy>CLo7cj-HG4&%J?-QANznaW2ScgIMzB`GE-yPH}$K##YgfJwaJd86Bw-5**Nym zwar*ZA|2GE=>=H7sDW%7LfK=DjjZZjY$5uMAc6>@p-ru`3ux=o7P%WMIHxyBITpQB$Q_%Aej5F$W+70#=9YZR&{zZ)( z;5uArDr1h9rn8INFXj-wZ?8+ezSJ&Th2Smt@1!Yn+`cWx6J2j!dC~c0syK$?Z>n+@ z;{=wy-{UsiyOitpABwh~QfcX!SHukr;zw4`HZ}I1U!`P<{{8}&r#bRXeoqW}YvapC z8_f}zKe-yLgiir_c=JpGd%G$al282zGSEfVXA?+emVuLajqbj|8Z#4R$m+rl>tRTP z2mB?cL+T6ujE#NF=iID{e?a)Dba2F1g(%G#Iw@4>qN1xfnTObS?KN9dj$|%aCcB&w zr<{jHQ0K49YyRmGh~th{g0A3vxpuVS`e0()Br9B2 z1m2%cD8VRnGb#Uj?X#!OWqG?U318e?=KZ*7LWzx(VKqpR1jGlNt(Wc-olunI3u;`3ye;SS&L@v#S{ zPg_m$-mwnnk?MTb$pLLC*p1J z!YN3rotjwZgYuyM71FKadtQ~#NyN%s(sBFkQPsD>eq~EGhaZorR=M)y4**bT~}@d7t9ozm!==q1fvf5@tR&Vv{4U zCfaVCnQWY1m|ILiz)6D&)75glGuz64;P~>nI%1+4gtb#Ojp^0U_Z4Zl#lOHoiVX3s z>_+OBFU)wB3#>8vP1Nr_#{S)*VzSv+NCkAi1dpV<9I)=mKB^k`>w!iw_n9jaKBhqf zk8v5af31oKVG(ng&Hge5!X8j46=;vGO9HRBRVSOqHl)AP;z%X1jBm;&uxh}~=Ek>% z0vL=()OF&v6*FGbZ*R^`>?r4m2Rj}LUKACm8cZ@E(%T2sg;u_TWrlw z9cWb>lq(tNCX}P9AyaVkg`|qPEIt1`7rmKdgEo)MXv%@)GR;omM+c1hv%igdc!!Xb zvW>JGz0riqMf!7RTM=;{)_sx5V3~Br{^+EEggQu9o(uL%v8MBb7W-b4U>yEho9GJp z>)`=C-tm=o9l}MiHdBXxlKJMktgX^%d#q5o82z2+Vt=mQt|~IK+UjI&BX{@Y=1TN}ZTTGhTQ-#PK9#9LvLg zM1~X2%c|xtpFSUn?NZiT{Jc^%F^rFWCQ7f>`ia+B`E0)GP#&j@>*{=+^-{OuYprAb z7~7p?^OVM~sx=&gvW1Gxq^JSucJA9w$c0CM3DQ1huyizjn3=iPLLd9UGX!k)Vn zwzY1K2OMG*!hAN9m0BY8w=MNH4f%XXDeP9)^`#D%QGN;$-rs8_>>?Z^B7$}s-QQ;T zaa$W5e@zxjN(W{9A`C)(j-B&`eDuXv7g>h4<0wl5B z@?kE8ESiZI2COr6|fidXp*1 z-J*{vQ+-~CI-6+^vYZ{*=faYwi#1h}4^q7-DTr5v#hWCW$W7#>%MI@3oUpc7mDqXe zvdQMB>8e|^kEB>jm0+WvmY1g^g>6!$yBiBDJ&)!gRh?4UhgK1k;RWz+DM6dcfw*Q4 zL;%S_g5OA1BYXWQD7~~{!EvFo@gEVxn>OO~;LSTqpvuJAhpxnN8V2OWrKhz+Z0&e14(AAjORNsxHoSV1iU&z>Oaj#?t)OydpG9frXN6!>F4ANw4C zip7{;e7gP!+ZnqnnmhkOaE@}$(r_A9pB&aC=a|r9=d7L9b31a@`cf|BQp+vR(x9uO z3kAoEoZnu}TcRg81X2RAaIB`4Tjld2H`+_|g3qEX*WypxX9deM*2KtGTnq26d;IYX z?YA4kcg(!pCRj{ko*QbL?RVU?WG?GBD;{L}+EIy^Fcr&aM}HJ{6G$LJH<^5=<0+yI zZehOn)NJ@R|Hk~MW5@Lw;)O!P8O@jDwyRNckk8PH%~zK(HSkHX7Ioq`^}}VS=Jug! zt!U?~I<*t@FT&0{kN)4v@RK{p%&4z#S}Fn_gm`pp=Kbey_Iy(@ky4GFd2t%S!b9Ts z81A=rDe0?iH2h^3^>XUw=ekehLpzFChm1l^445F@X( zaTAuGuW!+jI>IlFEM*>jq`4Y(dIvRF33KcbJWn9d6s`TYM>v5THlAj~}%r>4kYj?Y=9LCZeLkKL@QGdx-ps0vvgDL zUKES=--j|YAM7cbpJHW)WLRDvx|92-y;6F9luObos~iYo)1a;+$8Tm;RK6n2!{?kz zdwC%^$;su-y=W;knp#4M#5Me+yZDuY`NJ1OqLk5E13}W;A)T`UvEBuU{9f^Bx^Ruj zSWxkEd~>zPZA2P4Dsd7vKPmFCK2qM?`a{&MdP$#i+zCaJhJlPaZ`@>V_d`p$D!DG* z5RFp4MKzsa>~`qSrL(tqs~ zL7SazkJW32kh@QzE!D*P*6r-7M~;^@czkd85FqtMUDx(Q#$vBR|#w+DBu>Q4o8A5ock;FZ=$GHC~TG9JIL)EIn59pCUX3OeiPwdU8y-3=Gv z3=Q2kPGRHy33^)fSVUBF7pB$oKEpm7>&}FFeWJyH@$@zO;bOMjbxyZ=4Y6{Wo@~Qx z-5vwae5AJ-gMiMUk@;C=#+_LOoyx%6qJ7M3)I6uwoE6a)y?2QI3Jr5ZONN1lsRzvr z4dbP=^!RvUbZpD&HF5@Z)H)Wg?b-C_)1ElA{2X)=x&5Z*3rz*;?KqW?W{z*$`#KGRgd zXz{N-OIkr=9|Iv7(xAqg zP~)$}zAjXOG@!6mt3j8PTwkVJxAm~%W)@oIB4f=(Ptp;xw6Hz=#tpxOwcWYzgL}^l zzP`P+QVo~EuFHucfNvam?2k~bjc*5}Hi)dRYO=awAspMxkhI}7F@rTbSBOOQi zTamfHL{BKnVhy%MoyTN`7Mwk3UXaa=FRNm?eA6-&q78_fxf=SC+pMK7l%9HT9H9j|yK;@P zVih1AyO#R(-JgTcvinW&)9TacK1cx^=B^6AwmDO1yBWD_~+|Wl>I}PxK5cWbgpvwjX_o6IGsFOd?nR?=yaD1;@H8alJ7=d(?#ThhbTuj*>&siPinQLp z)_k9J;V!Jctv!Kc2~|A{V%Ip3(%7#zwIG7K@)Zlvx*<_FzboA?r`~l5BYCDRzE7F1 z0HNw4YxprWb~o&1ooPAkpgR7emI8L#6yopvui{UQb!6y=WDv(u0S14qlnKJ-o^_A= zKQ^;H*hk;WkHcKe6M8qE+3Jb7>m)Q%x7pgNVJ*fP*VrcJv6K1}>+9D}<@0ze`+ZLz z$C69V`q``YG~O|Jf5fGEf03T(a&8epWz{Sr_QtmBwc(%UspcuDnafU*;cWfe&!?B{ zh6fRv=b5myt0gAy%ZT#RvsWGg?M!|s4N+wKbxbV+%4nWg(kV7seFc8|h_m_K94*vr zrqU#kVrcDSAAxi~V+~O;t8@=;aMBB?EfY1%iq-aBZR!#ORIDvF1_bWmA91h{AUD-X z+e>Aa%CfMBt?EXb~@HYL~ChL%@`<+W>Je`~A6ZloVe$uH%rpM+apC+Q=fG0Aa z-P8z#@7|K|5t1G?ZS+|AICEBv%&$gg=bjB`)JchWw!>ow(?QxEa&_XFXt68#Yzj`@ zq2>E5&G6({{!2!yT@95YB*WOV+joz*V!aL08z!uA{HWfESIn96w{6IN}KEBp+<*Ct3D--Z&rT z!=X2|ravX=Eej)Wz`MU-)GsdEQtNgn%d`lkeAK}56BU*d@TK|RBSp=O$9>Ni_<&kpIsmu+*__du&>xy0d^s{>>4#{yT)uEEo%c-iv4}RTmEj8KQ`%uq`@WuG{_<-=}46>#hR6h4j&cV*)xc;ubO) z-z7ni^zcQ>W`_6_Mvs|zML8ixeU)`{#zYbY=ZM$O+}^wDo=-%<=dx!>1v4aO$)ksUP34>?k}U)`B?a8%@NHf zwtcDX{OVSgMf?j6dc&6v_)>^QdT(jF@>}%c7kk zXW{*_QYF))F0Yy8qgmu}J*=Y(Eqv}8;^lp!i_Y5l0Uy;6EnXrRwcgp#?esi6kisyY zpbUM9=UQW`-o)(`cXV7FjUJ2K=_I|Gx=NpUzqNY*m%0gsX8!Tuoz=IeqN~Xd9|9u( E5BzL*!~g&Q diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/autotools.vsd deleted file mode 100644 index 7e692d59991877a22657b90b04f1c83d270316b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51200 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 A2><{9 diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps b/libs/sofia-sip/libsofia-sip-ua/docs/pictures/nta-receiving-message.eps deleted file mode 100644 index f74a8b6bef05f01e0f312ba6420a7e497cdf6146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108850 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 -Sofia-SIP @VERSION@ - -Copyright (C) 2006 Nokia Corporation. All rights reserved. -Licensed under the terms of the GNU Lesser General Public License. diff --git a/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog deleted file mode 100644 index 17d4af632d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/ChangeLog +++ /dev/null @@ -1,32 +0,0 @@ -2005-10-27 Pekka Pessi - - * 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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile.in deleted file mode 100644 index ad72360a20..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/Doxyfile.in +++ /dev/null @@ -1,23 +0,0 @@ -PROJECT_NAME = "features" -OUTPUT_DIRECTORY = ../docs/html/features - -INPUT = @srcdir@/features.docs @srcdir@/sofia-sip sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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 += diff --git a/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am deleted file mode 100644 index bbc1c78517..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -# -# Makefile.am for sofia features module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = $(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 = features.docs - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/features/features.c b/libs/sofia-sip/libsofia-sip-ua/features/features.c deleted file mode 100644 index 1e90d1db65..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/features.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Mon Oct 24 14:51:32 2005 ppessi - */ - -#include "config.h" - -#include - -#include -#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 -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/features/features.docs b/libs/sofia-sip/libsofia-sip-ua/features/features.docs deleted file mode 100644 index 9bde692e9c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/features.docs +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- text -*- */ - -/**@MODULEPAGE "features" Module - -@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. - -@CONTACT Pekka Pessi - -@STATUS @SofiaSIP Core library - -@LICENSE LGPL - -@par Contributor(s): -- Pekka Pessi - -@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in b/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in deleted file mode 100644 index 9688377f07..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/features/sofia-sip/sofia_features.h.in +++ /dev/null @@ -1,67 +0,0 @@ -/* This -*- C -*- file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Feb 14 17:09:44 2001 ppessi - */ - -#ifndef SOFIA_SIP_FEATURES_H -/** Defined when 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@-@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 diff --git a/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog deleted file mode 100644 index 4c0129b1a5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/ChangeLog +++ /dev/null @@ -1,7 +0,0 @@ -2005-11-08 Pekka Pessi - - * Renamed http_test.c as test_http.c - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile.in deleted file mode 100644 index 8ba200bd29..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/Doxyfile.in +++ /dev/null @@ -1,19 +0,0 @@ -PROJECT_NAME = "http" -OUTPUT_DIRECTORY = ../docs/html/http - -INPUT = @srcdir@/http.docs @srcdir@/sofia-sip sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@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@defgroup" \ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am deleted file mode 100644 index 0e56d800c1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/Makefile.am +++ /dev/null @@ -1,93 +0,0 @@ -# -# Makefile.am for http module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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_parser_table.c - -BUILT_SOURCES = $(BUILT_H) $(BUILT_C) http_tag_ref.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_inlined.c \ - http_status.c http_tag_class.c \ - $(BUILT_SOURCES) - -COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS) - -LDADD = libhttp.la \ - ../bnf/libbnf.la \ - ../msg/libmsg.la \ - ../url/liburl.la \ - ../ipt/libipt.la \ - ../su/libsu.la - -test_http_LDFLAGS = -static - -# ---------------------------------------------------------------------- -# Install and distribution rules - -EXTRA_DIST = 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 $(top_srcdir)/rules/sofia.am - -TAG_DLL_FLAGS = DLLREF=1 - -MSG_PARSER_AWK = ${srcdir}/../msg/msg_parser.awk - -AWK_HTTP_AWK = LC_ALL=C ${AWK} -f ${MSG_PARSER_AWK} module=http - -SS_HTTP_H = ${srcdir}/sofia-sip/http.h - -${BUILT_H} ${BUILT_C}: ${srcdir}/sofia-sip/http.h ${MSG_PARSER_AWK} - -sofia-sip/http_protos.h: ${srcdir}/sofia-sip/http_protos.h.in - @-mkdir sofia-sip 2>/dev/null || true - ${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/sofia-sip/http_protos.h.in ${SS_HTTP_H} - -sofia-sip/http_tag.h: ${srcdir}/sofia-sip/http_tag.h.in - @-mkdir sofia-sip 2>/dev/null || true - ${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/sofia-sip/http_tag.h.in ${SS_HTTP_H} - -http_tag.c: ${srcdir}/http_tag.c.in - ${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/http_tag.c.in ${SS_HTTP_H} - -http_parser_table.c: ${srcdir}/http_parser_table.c.in - ${AWK_HTTP_AWK} PT=$@ TEMPLATE=${srcdir}/http_parser_table.c.in \ - MC_HASH_SIZE=127 ${SS_HTTP_H} diff --git a/libs/sofia-sip/libsofia-sip-ua/http/headers b/libs/sofia-sip/libsofia-sip-ua/http/headers deleted file mode 100644 index bd19d10196..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/headers +++ /dev/null @@ -1,48 +0,0 @@ -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http.def.in b/libs/sofia-sip/libsofia-sip-ua/http/http.def.in deleted file mode 100644 index ecdcfc1003..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http.def.in +++ /dev/null @@ -1,17 +0,0 @@ -; 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 - diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http.docs b/libs/sofia-sip/libsofia-sip-ua/http/http.docs deleted file mode 100644 index 06dc46785e..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http.docs +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- 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 - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - * - * @section http_overview Overview - * - * Each HTTP header has a structure defined for it in . All the - * variables, objects and functions related to a particular HTTP header are - * documented in a submodule 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 - * 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 SIP Parser module. - * The parser provider interface makes it possible to extend HTTP parser with - * new headers or extend existing ones. - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c b/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c deleted file mode 100644 index 55312c2893..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_basic.c +++ /dev/null @@ -1,1667 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -/* ====================================================================== */ - -/**@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_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 (!su_casenmatch(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] == '"' || su_casenmatch(s, "W/\"", 3)) { - 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((msg_param_t 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 - */ - -su_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_sec_websocket_key Sec-WebSocket-Key header. */ - -#define http_sec_websocket_key_d msg_generic_d -#define http_sec_websocket_key_e msg_generic_e -msg_hclass_t http_sec_websocket_key_class[] = -HTTP_HEADER_CLASS_G(sec_websocket_key, "Sec-WebSocket-Key", single); - -/* ====================================================================== */ -/**@HTTP_HEADER http_sec_websocket_protocol Sec-WebSocket-Protocol header. */ - -#define http_sec_websocket_protocol_d msg_generic_d -#define http_sec_websocket_protocol_e msg_generic_e -msg_hclass_t http_sec_websocket_protocol_class[] = -HTTP_HEADER_CLASS_G(sec_websocket_protocol, "Sec-WebSocket-Protocol", single); - -/* ====================================================================== */ -/**@HTTP_HEADER http_sec_websocket_version Sec-WebSocket-Version header. */ - -#define http_sec_websocket_version_d msg_generic_d -#define http_sec_websocket_version_e msg_generic_e -msg_hclass_t http_sec_websocket_version_class[] = -HTTP_HEADER_CLASS_G(sec_websocket_version, "Sec-WebSocket-Version", single); - -/* ====================================================================== */ -/**@HTTP_HEADER http_origin Origin header. */ - -#define http_origin_d msg_generic_d -#define http_origin_e msg_generic_e -msg_hclass_t http_origin_class[] = -HTTP_HEADER_CLASS_G(origin, "Origin", single); - -/* ====================================================================== */ -/**@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. - */ - diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c b/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c deleted file mode 100644 index ff6bef2caa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_extra.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - */ - -#include "config.h" - -#include - -/* 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 -#include -#include -#include -#include - -/* ========================================================================== */ - -/**@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 - */ -su_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 - */ -su_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 - -/* Scan a cookie parameter */ -static issize_t set_cookie_scanner(char *s) -{ - char *rest; - -#define LOOKING_AT(s, what) \ - (su_casenmatch((s), what, strlen(what)) && (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); diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_header.c b/libs/sofia-sip/libsofia-sip-ua/http/http_header.c deleted file mode 100644 index 4ae0159832..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_header.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Jun 13 02:57:51 2000 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* 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 -#include - -#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; -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c b/libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c deleted file mode 100644 index eb4bd47d50..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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_inlined.c - * - * Expand inlined http functions non-inline. - * - */ - -#include "config.h" - -#include - -#if SU_HAVE_INLINE - -extern int xyzzy; - -#else - -#include "sofia-sip/msg_header.h" -#include "sofia-sip/su_tag.h" - -#undef SU_HAVE_INLINE -#undef su_inline - -#define SU_HAVE_INLINE 1 -#define su_inline - -#include "sofia-sip/http_header.h" - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c b/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c deleted file mode 100644 index 09dd4d21d0..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_parser.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 -#include -#include "sofia-sip/http_parser.h" -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -/** 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 const *http_default_mclass(void) -{ - extern msg_mclass_t const 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] && - !su_casematch(http->http_transfer_encoding->k_items[0], "identity")) { - 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 && - su_casematch(http->http_content_type->c_type, "multipart/byteranges")) - 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 (su_casenmatch(s, http_version_1_1, version_size) && - !IS_TOKEN(s[version_size])) { - result = http_version_1_1; - s += version_size; - } - else if (su_casenmatch(s, http_version_1_0, version_size) && - !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 (su_casematch(s, http_version_1_1)) - result = http_version_1_1; - else if (su_casematch(s, http_version_1_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[] = { - "", - 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) (su_casenmatch(s, m, n = sizeof(m) - 1)) - - 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 (http_method_t)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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in b/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in deleted file mode 100644 index d5ffdb05b1..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_parser_table.c.in +++ /dev/null @@ -1,59 +0,0 @@ -/** -*- C -*- - * @IFILE http_parser_table.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Oct 1 20:37:52 2002 ppessi - */ - -#include "config.h" - -#include -#include - -/* 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 -#include - -#define HTTP_PARSER_FLAGS (MSG_FLG_CHUNKING) - - - diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_status.c b/libs/sofia-sip/libsofia-sip-ua/http/http_status.c deleted file mode 100644 index aef456d293..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_status.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Sep 18 18:58:21 2001 ppessi - */ - -#include "config.h" - -#include -#include - -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 " "; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in b/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in deleted file mode 100644 index 531a2c4e71..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_tag.c.in +++ /dev/null @@ -1,68 +0,0 @@ -/**@HTTP - * @IFILE http_tag.c.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file http_tag.c HTTP Tag classes - * - * This file is autogenerated from . - * - * #AUTO# - * - * @author Pekka Pessi - */ - -#include "config.h" - -#define TAG_NAMESPACE "http" - -#include -#include -#include - -#include - -#include -#include -#include -#include - -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#); - diff --git a/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c b/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c deleted file mode 100644 index f69ff0cdaa..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/http_tag_class.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Fri Feb 23 12:46:42 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include - -/* 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 - -#include -#include -#include -#include -#include - -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; - if (http == NULL) - return dst; - - mc = (void *)http->http_common->h_class; - hh = (void *)msg_hclass_offset(mc, http, hc); - - if (hh == 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h deleted file mode 100644 index f5a9d6dd1b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define HTTP_H - -/**@file sofia-sip/http.h - * - * HTTP message, methods, headers. - * - * @sa RFC 2616 - * - * @author Pekka Pessi . - * - * @date Created : Thu Jun 8 19:28:55 2000 ppessi - */ - -#ifndef MSG_H -#include -#endif -#ifndef URL_H -#include -#endif -#ifndef MSG_MIME_H -#include -#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 */ -#ifndef _MSC_VER -#define HTTP_PROTOCOL_TAG ((void *)0x48545450) /* 'HTTP' */ -#else -#define HTTP_PROTOCOL_TAG ((void *)(UINT_PTR)0x48545450) /* 'HTTP' */ -#endif - -/** 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 msg_generic_t http_sec_websocket_key_t; -typedef msg_generic_t http_origin_t; -typedef msg_generic_t http_sec_websocket_protocol_t; -typedef msg_generic_t http_sec_websocket_version_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;/** - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define HTTP_HCLASSES_H - -/**@file sofia-sip/http_hclasses.h - * @brief HTTP header classes. - * - * @author Pekka Pessi - * - */ - -#ifndef MSG_TYPES_H -#include -#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 -#undef HTTP_HCLASSES_ONLY -#endif - -#endif /* !defined HTTP_HCLASSES_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h deleted file mode 100644 index ba34a60510..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_header.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included.*/ -#define HTTP_HEADER_H - -/**@file sofia-sip/http_header.h - * - * HTTP library prototypes. - * - * @author Pekka Pessi - * - * @date Created: Tue Jun 13 02:58:26 2000 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif - -#ifndef SU_TAG_H -#include -#endif - -#ifndef HTTP_H -#include -#endif - -#ifndef MSG_HEADER_H -#include -#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 const *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 -#endif - -#endif /* !defined(HTTP_HEADER_H) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h deleted file mode 100644 index 22790772e5..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_parser.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included.*/ -#define HTTP_PARSER_H -/**@file sofia-sip/http_parser.h - * @brief Typedefs and prototypes used by HTTP parser. - * - * @author Pekka Pessi - * - * @date Created: Tue Jun 13 02:58:26 2000 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#endif - -#ifndef MSG_H -#include -#endif - -#ifndef MSG_PARSER_H -#include -#endif - -#ifndef HTTP_H -#include -#endif - -#ifndef HTTP_HEADER_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in deleted file mode 100644 index b91774acb8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_protos.h.in +++ /dev/null @@ -1,311 +0,0 @@ -/** -*- C -*- - * @file sofia-sip/http_protos.h.in - * - * Template for . - */ - -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define HTTP_PROTOS_H - -/**@file sofia-sip/http_protos.h - * - * Macros for each HTTP header. - * - * #AUTO# - * - * @author Pekka Pessi - */ - -#include - -#ifndef HTTP_HEADER_H -#include -#endif -#ifndef HTTP_HCLASSES_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h deleted file mode 100644 index 5893b185b4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_status.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Sep 18 18:55:09 2001 ppessi - */ - -#include - -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in deleted file mode 100644 index c6bd61b8e3..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in +++ /dev/null @@ -1,236 +0,0 @@ -/**@file sofia-sip/http_tag.h.in - * - * Template for . - * - * @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 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define HTTP_TAG_H - -/**@file sofia-sip/http_tag.h - * @brief Tag class for HTTP headers - * - * #AUTO# - * - * @author Pekka Pessi - * - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SU_TAG_CLASS_H -#include -#endif -#ifndef SU_TAG_CLASS_H -#include -#endif - -#ifndef HTTP_H -#include -#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_INLINE_TAG_CAST -su_inline -tag_value_t httptag_http_v(http_t const *v) { return (tag_value_t)v; } -su_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_INLINE_TAG_CAST -su_inline tag_value_t -httptag_header_v(http_header_t const *v) -{ return (tag_value_t)v; } -su_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_INLINE_TAG_CAST -su_inline tag_value_t -httptag_#xxxxxx#_v(http_#xxxxxx#_t const *v) -{ return (tag_value_t)v; } -su_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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h deleted file mode 100644 index 34c29cf656..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag_class.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Feb 21 11:01:45 2001 ppessi - */ - -#ifndef SU_TAG_CLASS_H -#include -#endif - -#ifndef MSG_TAG_CLASS_H -#include -#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) */ diff --git a/libs/sofia-sip/libsofia-sip-ua/http/test_http.c b/libs/sofia-sip/libsofia-sip-ua/http/test_http.c deleted file mode 100644 index c9e698eb1a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/http/test_http.c +++ /dev/null @@ -1,1524 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 - -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#define TSTFLAGS tstflags - -#include - -#include -#include -#include -#include -#include - -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 const *test_mclass = NULL; - -char *lastpart(char *path) -{ - if (strchr(path, '/')) - return strrchr(path, '/') + 1; - else - return path; -} - -int tstflags; - -void usage(int exitcode) -{ - fprintf(stderr, - "usage: %s [-v] [-a]\n", - name); - exit(exitcode); -} - -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 if (strcmp(argv[i], "-a") == 0) - tstflags |= tst_abort; - else - usage(1); - } - -#if HAVE_OPEN_C - tstflags |= tst_verbatim; -#endif - - 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); - -#if HAVE_OPEN_C - sleep(5); -#endif - - 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@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" - "\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" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n9\r\n" - "\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@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" - "Heippa!Heippa!" - "\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" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n9\r\n" - "\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" - "\n" - "\n" - "\n" - "\n" - "\n8\n" - "\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" - "\r" - "\r" - "\r" - "\r" - "\r8\r" - "\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(); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog deleted file mode 100644 index f67c275652..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/ChangeLog +++ /dev/null @@ -1,14 +0,0 @@ -2005-10-27 Pekka Pessi - - * 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 - - * sha1.c: Added RFC 3174 copyright notice. - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile.in deleted file mode 100644 index a39768d673..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/Doxyfile.in +++ /dev/null @@ -1,15 +0,0 @@ -PROJECT_NAME = "ipt" -OUTPUT_DIRECTORY = ../docs/html/ipt - -INPUT = @srcdir@/ipt.docs -INPUT += @srcdir@/sofia-sip/base64.h @srcdir@/base64.c -INPUT += @srcdir@/sofia-sip/token64.h @srcdir@/token64.c - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf - -TAGFILES += ../docs/su.doxytags=../su -GENERATE_TAGFILE = ../docs/ipt.doxytags - -ALIASES += - diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am deleted file mode 100644 index 69f2f15a55..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/Makefile.am +++ /dev/null @@ -1,55 +0,0 @@ -# -# Makefile.am for ipt module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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/base64.h \ - sofia-sip/token64.h \ - sofia-sip/uniqueid.h - -libipt_la_SOURCES = base64.c token64.c - -EXTRA_DIST = sofia-sip/utf8.h \ - sofia-sip/rc4.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 += ipt.docs - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c b/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c deleted file mode 100644 index c61be09fcc..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/base64.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - */ - -#include "config.h" - -#include -#include -#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 RFC 2045, - * "Multipurpose Internet Mail Extensions (MIME) Part One: - * Format of Internet Message Bodies", - * 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 RFC 2045, - * "Multipurpose Internet Mail Extensions (MIME) Part One: - * Format of Internet Message Bodies", - * 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs b/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs deleted file mode 100644 index 1dddd7d099..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/ipt.docs +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- c -*- */ - -/**@MODULEPAGE "ipt" - Utility Module - * - * @section ipt_meta Module Meta Information - * - * Utility library for IP Telephony applications. - * - * @CONTACT Pekka Pessi - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - * - * @section ipt_overview Overview - * - * This module contain some routines useful for IPT applications, like - * - BASE64 encoding/decoding, and - * - encoding/decoding binary as SIP/HTTP token. - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c b/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c deleted file mode 100644 index a343c13041..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/rc4.c +++ /dev/null @@ -1,264 +0,0 @@ -/**@CFILE rc4.c Arcfour pseudorandom generator. - * - * @author Pekka Pessi - * - * 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 - -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 diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h b/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h deleted file mode 100644 index 296b1a8647..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/base64.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 RFC 2045, - * "Multipurpose Internet Mail Extensions (MIME) Part One: - * Format of Internet Message Bodies", - * N. Freed, N. Borenstein, - * November 1996. - * - * @author Pekka Pessi - */ - -#ifndef SU_TYPES_H -#include -#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) - -/** Calculate size of n bytes encoded in base64 sans trailing =. @NEW_1_12_5. */ -#define BASE64_MINSIZE(n) ((n * 4 + 2) / 3) - -SOFIA_END_DECLS - -#endif /* !BASE_64 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h b/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h deleted file mode 100644 index 1edbfd663b..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/rc4.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define RC4_H - -/**@file sofia-sip/rc4.h - * @brief Arcfour random number generator. - * - * @author Pekka Pessi - * - * @date Created: Sun Jun 9 14:32:58 1996 ppessi - */ - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef SU_TYPES_H -#include -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h b/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h deleted file mode 100644 index 59747b9fce..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/token64.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h b/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h deleted file mode 100644 index 6f9a1c0133..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/uniqueid.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define UNIQUEID_H - -/**@file sofia-sip/uniqueid.h - * - * Compatibility functions to handle GloballyUniqueID. - * - * This file just includes . - * - * @author Pekka Pessi - * - * @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 - - -#endif diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h b/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h deleted file mode 100644 index fa85605d83..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/sofia-sip/utf8.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Apr 21 15:32:38 1998 pessi - - * @sa RFC 2279, - * "UTF-8, a transformation format of ISO 10646", - * F. Yergeau. January 1998. - * - */ - -#ifndef UTF8_H -/** Defined when has been included */ -#define UTF8_H - -#ifndef SU_TYPES_H -#include -#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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c b/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c deleted file mode 100644 index 0bf6c5c739..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/token64.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file token64.c - * - * Token encoding. - * - * @author Pekka Pessi - * - * @date Created: Wed Apr 3 10:45:47 2002 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include "sofia-sip/token64.h" - -static const char code[65] = -"0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/** Encode data as a SIP/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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c b/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c deleted file mode 100644 index c61db6261d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/torture_base64.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 \n - * - * @date Created: Tue Feb 1 13:29:09 EET 2005 ppessi - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "sofia-sip/base64.h" - -int tstflags = 0; -#define TSTFLAGS tstflags - -char const *name = "torture_base64"; - -#include - -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(int exitcode) -{ - fprintf(stderr, - "usage: %s [-v] [-a]\n", - name); - exit(exitcode); -} - -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 if (strcmp(argv[i], "-a") == 0) - tstflags |= tst_abort; - else - usage(1); - } - - retval |= test_encoding(); fflush(stdout); - retval |= test_decoding(); fflush(stdout); - - return retval; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c b/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c deleted file mode 100644 index 328604fd50..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/ucs2.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Apr 21 15:32:02 1998 pessi - * - */ - -#include "config.h" - -#include -#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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c b/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c deleted file mode 100644 index 1c6eafcaea..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/ucs4.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Apr 21 15:32:02 1998 pessi - */ - -#include "config.h" - -#include -#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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c b/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c deleted file mode 100644 index 715f3b8459..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Apr 21 15:32:02 1998 pessi - */ - -#include "config.h" - -#include -#include "utf8internal.h" - -#ifndef _WIN32 -#include -#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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h b/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h deleted file mode 100644 index 730ddaf2ef..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8internal.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c b/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c deleted file mode 100644 index cf2fde6e0d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/ipt/utf8test.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Tue Apr 21 15:32:38 1998 pessi - */ - -#include "config.h" - -#include -#include -#include - -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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog b/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog deleted file mode 100644 index 422d76b2eb..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/ChangeLog +++ /dev/null @@ -1,24 +0,0 @@ -2005-11-08 Pekka Pessi - - * Renamed auth_digest_test.c as test_auth_digest.c. - -2005-10-21 Pekka Pessi - - * Generate opaque only if opaque parameter has value "*". - - M ./libsofia-sip-ua/iptsec/auth_module.c -14 +20 - -2005-09-06 Pekka Pessi - - * 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 - - * auth_module.c: Using unsigned as type of hash! - -2005-07-18 Kai Vehmanen - - * Initial import of the module to Sofia-SIP tree. diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile.in b/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile.in deleted file mode 100644 index 098099f12f..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile.in +++ /dev/null @@ -1,26 +0,0 @@ -PROJECT_NAME = "iptsec" -OUTPUT_DIRECTORY = ../docs/html/iptsec - -INPUT = @srcdir@/iptsec.docs @srcdir@/sofia-sip @srcdir@ . - -@INCLUDE_PATH = . @srcdir@ -@INCLUDE = ../docs/Doxyfile.conf -@INCLUDE = ../sip/sip.doxyaliases - -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/http.doxytags=../http -TAGFILES += ../docs/sresolv.doxytags=../sresolv -TAGFILES += ../docs/tport.doxytags=../tport -TAGFILES += ../docs/nta.doxytags=../nta - -GENERATE_TAGFILE = ../docs/iptsec.doxytags - -ALIASES += "iptsec=@ref index \"iptsec\"" - -PREDEFINED += SOFIA_EXTEND_AUTH_CLIENT=1 - diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am deleted file mode 100644 index ff10add512..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/Makefile.am +++ /dev/null @@ -1,87 +0,0 @@ -# -# Makefile.am for iptsec module -# -# Copyright (C) 2005,2006 Nokia Corporation -# Contact: Pekka Pessi -# Licensed under LGPL. See file COPYING. - -# ---------------------------------------------------------------------- -# Header paths - -AM_CPPFLAGS = -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 - -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_sip.c \ - iptsec_debug.c - -COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS) - -LDADD = libiptsec.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 - -if HAVE_NTLM -nobase_include_sofia_HEADERS += $(NTLM_HEADER) -libiptsec_la_SOURCES += $(NTLM_SOURCE) -endif - -if HAVE_NTH -libiptsec_la_SOURCES += $(HTTP_SOURCE) -LDADD += ../http/libhttp.la -endif - -HTTP_SOURCE = auth_module_http.c - -NTLM_HEADER = sofia-sip/auth_ntlm.h -NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c - -EXTRA_libiptsec_la_SOURCES = \ - $(NTLM_HEADER) $(NTLM_SOURCE) $(HTTP_SOURCE) - -# ---------------------------------------------------------------------- -# Install and distribution rules - -EXTRA_DIST = iptsec.docs testpasswd $(BUILT_SOURCES) - -# ---------------------------------------------------------------------- -# Sofia specific rules - -include $(top_srcdir)/rules/sofia.am - diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c deleted file mode 100644 index a2e2c19220..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed Feb 14 18:32:58 2001 ppessi - */ - -#include "config.h" - -#define SOFIA_EXTEND_AUTH_CLIENT 1 - -#include -#include - -#include "sofia-sip/auth_common.h" -#include "sofia-sip/auth_client.h" -#include "sofia-sip/auth_client_plugin.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -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); - -static int ca_has_authorization(auth_client_t const *ca); - - -/** 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 at least one 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 (*cca == NULL) { - return -1; - } - else if (ca_challenge((*cca), ch, crcl, scheme, realm) < 0) { - ca_destroy(home, *cca), *cca = NULL; - return -1; - } - /* XXX - case w/ unknown authentication scheme */ - else - 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 (!su_casematch(ca->ca_scheme, scheme)) - return 0; - if (!su_strmatch(ca->ca_realm, realm)) - return 0; - - if (ca->ca_credential_class && - ca->ca_credential_class != credential_class) - return 0; - - if (!ca->ca_auc) { - ca->ca_credential_class = credential_class; - return 1; - } - - if (ca->ca_auc->auc_challenge) - stale = ca->ca_auc->auc_challenge(ca, ch); - - if (AUTH_CLIENT_IS_EXTENDED(ca)) - ca->ca_clear = 0; - - if (stale < 0) - return -1; - - if (!ca->ca_credential_class) - stale = 2, ca->ca_credential_class = credential_class; - - return stale > 1 ? 2 : 1; -} - -/** Store authentication info to authenticators. - * - * The function auc_info() feeds the authentication data from the @b - * Authentication-Info header @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 header to be processed - * @param[in] credential_class corresponding credential class - * - * The authentication info can be in either @AuthenticationInfo or in - * @ProxyAuthenticationInfo headers. If the header is @AuthenticationInfo, - * the @a credential_class should be #sip_authorization_class or - * #http_authorization_class. Likewise, If the header is - * @ProxyAuthenticationInfo, the @a credential_class should be - * #sip_proxy_authorization_class or #http_proxy_authorization_class. - - * The authentication into header usually contains next nonce or mutual - * authentication information. Currently, only the nextnonce parameter is - * processed. - * - * @bug - * In principle, SIP allows more than one challenge for a single request. - * For example, there can be multiple proxies that each challenge the - * client. The result of storing authentication info can be quite unexpected - * if there are more than one authenticator with the given type (specified - * by @a credential_class). - * - * @retval number of challenges to updated - * @retval 0 when there was no challenge to update - * @retval -1 upon an error - * - * @NEW_1_12_5. - */ -int auc_info(auth_client_t **auc_list, - msg_auth_info_t const *info, - 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, info, 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 *info, - msg_hclass_t *credential_class) -{ - assert(ca); assert(info); - - if (!ca || !info) - 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, info); -} - - -/**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 0 if not authenticator matched with @a data - * @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" - or "Basic:\"[fe80::204:23ff:fea7:d60a]\":user1:secret" (IPv6) - or "Basic:\"Use \\\"interesting\\\" username and password here:\":user1:secret" - */ - if (s && (s = strchr(scheme = s, ':'))) - *s++ = 0; - if (s) { - if (*s == '"') { - realm = s; - s += span_quoted(s); - if (*s == ':') - *s++ = 0; - else - realm = NULL, s = NULL; - } - else - s = NULL; - } - 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 - * - * @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 >0 or number of updated clients when successful - * @retval 0 when no client was updated - * @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) -{ - char *new_user, *new_pass; - char *old_user, *old_pass; - - assert(ca); - - if (!ca || !ca->ca_scheme || !ca->ca_realm) - return -1; - - if ((scheme != NULL && !su_casematch(scheme, ca->ca_scheme)) || - (realm != NULL && !su_strmatch(realm, ca->ca_realm))) - return 0; - - old_user = ca->ca_user, old_pass = ca->ca_pass; - - if (su_strmatch(user, old_user) && su_strmatch(pass, old_pass)) - return 0; - - new_user = su_strdup(ca->ca_home, user); - new_pass = su_strdup(ca->ca_home, pass); - - if (!new_user || !new_pass) - return -1; - - ca->ca_user = new_user, ca->ca_pass = new_pass; - if (AUTH_CLIENT_IS_EXTENDED(ca)) - ca->ca_clear = 0; - - su_free(ca->ca_home, old_user); - su_free(ca->ca_home, old_pass); - - 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 (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear) - continue; - if (!ca->ca_scheme[0] || !su_casematch(ca->ca_scheme, d->ca_scheme)) - continue; - if (!ca->ca_realm || !su_strmatch(ca->ca_realm, d->ca_realm)) - continue; - - if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) && - su_strmatch(d->ca_user, ca->ca_user) && - su_strmatch(d->ca_pass, ca->ca_pass)) { - 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; - if (AUTH_CLIENT_IS_EXTENDED(d)) - d->ca_clear = 0; - - 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; - int match; - - for (; *auc_list; auc_list = &(*auc_list)->ca_next) { - auth_client_t *ca = *auc_list; - - if (!AUTH_CLIENT_IS_EXTENDED(ca)) - continue; - - if ((scheme != NULL && !su_casematch(scheme, ca->ca_scheme)) || - (realm != NULL && !su_strmatch(realm, ca->ca_realm))) - continue; - - match = ca->ca_auc->auc_clear(*auc_list); - - if (match < 0) { - retval = -1; - break; - } - if (match) - retval++; - } - - return retval; -} - -static -int ca_clear_credentials(auth_client_t *ca) -{ - assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca)); - - if (!ca) - return -1; - - ca->ca_clear = 1; - - return 1; -} - -/** Check if there are credentials for all challenges. - * - * @retval 1 when authorization can proceed - * @retval 0 when there is not enough credentials - * - * @NEW_1_12_5. - */ -int auc_has_authorization(auth_client_t **auc_list) -{ - auth_client_t const *ca, *other; - - if (auc_list == NULL) - return 0; - - for (ca = *auc_list; ca; ca = ca->ca_next) { - if (!ca_has_authorization(ca)) { - /* - * Check if we have another challenge with same realm but different - * scheme - */ - for (other = *auc_list; other; other = other->ca_next) { - if (ca == other) { - continue; - } - - if (ca->ca_credential_class == other->ca_credential_class && - su_strcmp(ca->ca_realm, other->ca_realm) == 0 && - ca_has_authorization(other)) - break; - } - - if (!other) - return 0; - } - } - - return 1; -} - -static int -ca_has_authorization(auth_client_t const *ca) -{ - return ca->ca_credential_class && - ca->ca_auc && - ca->ca_user && ca->ca_pass && - !(AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear); -} - -/**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 credential headers */ - 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 credential headers */ - 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_has_authorization(ca)) - continue; - - if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0) - return -1; - if (h == NULL) - continue; - if (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_has_authorization(ca)) - 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 **); - -static 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, - /* auc_clear: */ ca_clear_credentials -}; - -/**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; - - if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear) - return 0; - - 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); - - if (basic == NULL) - return -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 *info); - -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, - /* auc_clear: */ ca_clear_credentials -}; - -/** Store a digest authorization challenge. - * - * @retval 2 if credentials need to be (re)sent - * @retval 1 if challenge was updated - * @retval -1 upon an error - */ -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 || cda->cda_ac->ac_nonce == NULL; - - if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale || ca->ca_clear )) { - su_guid_t guid[1]; - char *cnonce; - size_t b64len = BASE64_MINSIZE(sizeof(guid)) + 1; - 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, b64len); - base64_e(cnonce, b64len, 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 *info) -{ - 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, info->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. - * - * @retval 1 when authorization headers has been created - * @retval 0 when there is no credentials - * @retval -1 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; - void const *data = body ? body->pl_data : ""; - usize_t dlen = body ? body->pl_len : 0; - char *uri; - - msg_header_t *h; - auth_hexmd5_t sessionkey, response; - auth_response_t ar[1] = {{ 0 }}; - char ncount[17]; - - if (!user || !pass || (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)) - return 0; - - 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 = url_as_string(home, url); - - if (ar->ar_uri == NULL) - return -1; - - /* 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 || - su_strmatch(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 || su_casematch(auc->auc_name, scheme)) - break; - } - - /* XXX - should report error if the auth scheme is not known? */ - - 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 - -/**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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c deleted file mode 100644 index 8b2b155f11..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client_ntlm.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Wed May 24 21:44:39 EEST 2006 - */ - -#include "config.h" - -#include -#include - -#include "sofia-sip/auth_ntlm.h" -#include "sofia-sip/auth_client.h" -#include "sofia-sip/auth_client_plugin.h" - -#include - -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c deleted file mode 100644 index 54dbaf74ee..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_common.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @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 - -#include -#include -#include -#include - -su_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 (su_casematch(p, fmt)) { - /* Matched the whole parameter with fmt name=expected */ - value = p; - break; - } - else if (!su_casenmatch(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 (su_casematch(p, expected)) { - /* 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 (!su_casenmatch(p, fmt, len)) - continue; - - if (p[len] == '"') - value = msg_unquote_dup(home, p + len); - else - value = su_strdup(home, p + len); - - if (value == NULL) { - va_end(ap); - 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; -} - -su_inline int has_token(char const *qstring, char const *token) -{ - size_t n = strlen(token); - char const *q; - - q = su_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; - } -} - diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c deleted file mode 100644 index cae56f166d..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_digest.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Feb 22 12:10:37 2001 ppessi - */ - -#include "config.h" - -#include -#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 -#include -#include -#include -#include - -/**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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c deleted file mode 100644 index 8d121faeec..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module.c +++ /dev/null @@ -1,1553 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Wed Apr 11 15:14:03 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "iptsec_debug.h" - -#if HAVE_FUNC -#elif HAVE_FUNCTION -#define __func__ __FUNCTION__ -#else -static char const __func__[] = "auth_mod"; -#endif - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#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_call_scheme_destructor(void *); -static void auth_md5_hmac_key(auth_mod_t *am); - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#endif - -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); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -/**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; - su_home_destructor(am->am_home, auth_call_scheme_destructor); - } - - 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 max_ncount = 0; - 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_MAX_NCOUNT_REF(max_ncount), - 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_max_ncount = max_ncount; - 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 || su_casematch(algorithm, "MD5"); - 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) -{ - su_home_unref(am->am_home); -} - -/** Call scheme-specific destructor function. */ -static void auth_call_scheme_destructor(void *arg) -{ - auth_mod_t *am = arg; - am->am_scheme->asch_destroy(am); -} - -/** 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) -{ - return (auth_mod_t *)su_home_ref(am->am_home); -} - -/** Destroy a reference to an authentication module. */ -void auth_mod_unref(auth_mod_t *am) -{ - su_home_unref(am->am_home); -} - -/** Get authenticatin module name. @NEW_1_12_4. */ -char const *auth_mod_name(auth_mod_t *am) -{ - return am ? am->am_scheme->asch_method : ""; -} - -/** 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: - * - as->as_status == 0 authentication is successful - * - as->as_status == 100 authentication is pending - * - as->as_status >= 400 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 >= upsize) { - void *b = realloc(userpass == buffer ? NULL : userpass, upsize = n + 1); - if (b == NULL) - break; - base64_d(userpass = b, 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_MINSIZE(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; - } - -#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 && - !su_casematch(ar->ar_qop, "auth") && - !su_casematch(ar->ar_qop, "\"auth\"")) || - (ar->ar_auth_int && - !su_casematch(ar->ar_qop, "auth-int") && - !su_casematch(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" VA_NONE)); - - 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" VA_NONE)); - - 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 */ - -su_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 -#endif - -/* This is just a magic value */ -#define auth_apw_local ((void *)(intptr_t)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; - ssize_t slen; - 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 */ - - slen = 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 (slen < 0) - return -1; - len = (size_t)slen; - - /* 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) { - size_t size = (N * 5 + 3) / 4; - if (auth_htable_resize(am->am_home, am->am_users, size) < 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; - - if ((realm = strchr(pass, ':'))) - *realm++ = '\0'; - else - realm = ""; - - if ((ident = strchr(realm, ':'))) - *ident++ = '\0'; - else - ident = ""; - - 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 local user */ -su_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 (ssize_t)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 (!su_casematch(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 (!su_casematch(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" VA_NONE)); - return -1; - } - if (base64_d((void*)nonce, (sizeof nonce), ar->ar_nonce) != (sizeof nonce)) { - SU_DEBUG_5(("auth_method_digest: too short nonce\n" VA_NONE)); - 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" VA_NONE)); - 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; - } - - if (am->am_max_ncount && ar->ar_nc) { - unsigned long nc = strtoul(ar->ar_nc, NULL, 10); - - if (nc == 0 || nc > am->am_max_ncount) { - SU_DEBUG_5(("auth_method_digest: nonce used %s times, max %u\n", - ar->ar_nc, am->am_max_ncount)); - 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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c deleted file mode 100644 index 98a63e4b26..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_http.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @file auth_module_http.c - * @brief Authenticate HTTP request - * - * @author Pekka Pessi - * @author Jari Urpalainen - * - * @date Created: Thu Jan 15 17:23:21 2004 ppessi - */ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include - -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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c deleted file mode 100644 index a634cdac74..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_module_sip.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @file auth_module_sip.c - * @brief Authenticate SIP request - * - * @author Pekka Pessi - * @author Jari Urpalainen - * - * @date Created: Thu Jan 15 17:23:21 2004 ppessi - */ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include - -#include - -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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c deleted file mode 100644 index a2c659585a..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_ntlm.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Feb 22 12:10:37 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include - -#include -#include "sofia-sip/auth_digest.h" -#include "sofia-sip/auth_ntlm.h" - -#include "iptsec_debug.h" - -su_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 && !su_casematch(ac->ac_stale, "true")) - 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c deleted file mode 100644 index c7db9e19e4..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * @file auth_plugin.c - * @brief Plugin interface for authentication verification modules. - * - * @author Pekka Pessi - * - * @date Created: Tue Apr 27 15:23:31 2004 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#if HAVE_FUNC -#elif HAVE_FUNCTION -#define __func__ __FUNCTION__ -#else -static char const __func__[] = "auth_plugin"; -#endif - -#include - -#include -#include -#include -#include - -#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 (su_casematch(base, "Basic")) - bscheme = auth_scheme_basic; - else if (su_casematch(base, "Digest")) - bscheme = auth_scheme_digest; - - if (base == NULL || bscheme) { - int i; - - for (i = 0; schemes[i] && i < N; i++) { - if (su_casenmatch(schemes[i]->asch_method, method, len) && - 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; -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c deleted file mode 100644 index 4a5853f882..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_delayed.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Wed Apr 11 15:14:03 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#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 -#include - -#include -#include - -#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_cookie; - 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; -}; - -/* This is unique identifier */ -#define delayed_asp_cookie ((void const *)(intptr_t)delayed_auth_cancel) - -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_cookie = delayed_asp_cookie; - 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_cookie == delayed_asp_cookie) - 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); -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c deleted file mode 100644 index 6b8e40f417..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_plugin_ntlm.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Wed Apr 11 15:14:03 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#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 (!su_casematch(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 && - !su_casematch(ar->ar_qop, "auth") && - !su_casematch(ar->ar_qop, "\"auth\"")) || - (ar->ar_auth_int && - !su_casematch(ar->ar_qop, "auth-int") && - !su_casematch(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); - } -} diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c deleted file mode 100644 index 6d383940f8..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_tag.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 . - * - * @date Created: Wed Apr 11 15:14:03 2001 ppessi - */ - -#include "config.h" - -#define TAG_NAMESPACE "auth" - -#include "sofia-sip/auth_module.h" - -#include -#include - -/**@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 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_MAX_NCOUNT() - * - * Max nonce count value. - * - * The tag AUTHTAG_MAX_NCOUNT() specifies the maximum number of times a - * nonce should be used. - * - * @todo Count actual usages and don't trust "nc" parameter only. - */ -tag_typedef_t authtag_max_ncount = UINTTAG_TYPEDEF(max_ncount); - -/**@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); - diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs b/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs deleted file mode 100644 index 9aa0776032..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec.docs +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- 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 - * - * @STATUS @SofiaSIP Core library - * - * @LICENSE LGPL - * - * @section auth_module Server Verifying Authentication - * - * The file 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 - * . The most important parameters include: - * - * - AUTHTAG_METHOD(), - * - AUTHTAG_ALGORITHM(), - * - AUTHTAG_QOP(), and - * - AUTHTAG_REMOTE(). - * - * @section auth_client Client Authenticating User - * - * The file 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(). - */ diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c deleted file mode 100644 index 81377789e9..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 @file iptsec_debug.c - * @brief Debug log for IPTSEC module. - * - * @author Pekka Pessi - * - * @date Created: Thu Dec 19 15:55:30 2002 ppessi - */ - -#include "config.h" - -#include - -#include "iptsec_debug.h" - -#if DOXYGEN_ONLY -/** @defgroup iptsec_env Environment Variables Used by iptsec Module - * - * @brief Environment variables used by @iptsec module are listed here. - * - * The #IPTSEC_DEBUG variable sets the debug level. - */ - -/**@ingroup iptsec_env - * - * Environment variable determining the debug log level for @iptsec - * module. - * - * The IPTSEC_DEBUG environment variable is used to determine the debug - * logging level for @iptsec module. The default level is 3. - * - * @sa , #iptsec_log, #SOFIA_DEBUG - */ -extern IPTSEC_DEBUG; -#endif - -#ifndef SU_DEBUG -#define SU_DEBUG 3 -#endif - -/** Common log for client and server components. - * - * The iptsec_log is the log object used by @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) }; - diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h deleted file mode 100644 index bca87f3965..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/iptsec_debug.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define IPTSEC_DEBUG_H - -/**@internal - * @file iptsec_debug.h - * @brief Debug log for IPTSEC module. - * - * @author Pekka Pessi - * - * @date Created: Thu Dec 19 15:56:35 2002 ppessi - */ - -#include - -SOFIA_BEGIN_DECLS - -/** Common log for client and server components. */ -SOFIAPUBVAR su_log_t iptsec_log[]; - -SOFIA_END_DECLS - -#define SU_LOG (iptsec_log) - -#include - -#endif /* !defined IPTSEC_DEBUG_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h deleted file mode 100644 index f5bea7676c..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define AUTH_CLIENT_H - -/**@file sofia-sip/auth_client.h - * - * @brief Client-side authenticator library. - * - * @author Pekka Pessi - * - * @date Created: Wed Feb 14 17:09:44 2001 ppessi - */ - -#ifndef MSG_TYPES_H -#include -#endif - -#ifndef URL_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h deleted file mode 100644 index cc1d2d83cf..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define AUTH_CLIENT_PLUGIN_H - -/**@file sofia-sip/auth_client_plugin.h - * @brief Client-side plugin interface for authentication - * - * @note For extensions in 1.12.6 or later, - * you have to define SOFIA_EXTEND_AUTH_CLIENT to 1 - * before including this file. - * - * @author Pekka Pessi - * - * @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 -#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; - -#if SOFIA_EXTEND_AUTH_CLIENT - int ca_clear; -#endif -}; - -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); - -#if SOFIA_EXTEND_AUTH_CLIENT - /** Clear credentials (user/pass). @NEW_1_12_6. */ - int (*auc_clear)(auth_client_t *ca); -#endif -}; - -/** Check if authentication client has been extended. @NEW_1_12_6. */ -#define AUTH_CLIENT_IS_EXTENDED(ca) \ - ((ca)->ca_auc && \ - (ca)->ca_auc->auc_plugin_size > \ - (int)offsetof(auth_client_plugin_t, auc_clear) \ - && (ca)->ca_auc->auc_clear != NULL) - -SOFIA_END_DECLS - -#endif /* !defined AUTH_CLIENT_PLUGIN_H */ diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h deleted file mode 100644 index 638413cd77..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_common.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define AUTH_COMMON_H - -/**@file sofia-sip/auth_common.h - * - * Functions common for client/server. - * - * @author Pekka Pessi - * - * @date Created: Fri May 19 15:54:08 EEST 2006 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h deleted file mode 100644 index 0f40061392..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_digest.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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, - * "HTTP Authentication: Basic and Digest Access Authentication", - * J. Franks et al, - * June 1999. - * - * @sa @RFC3261 section 22 - * - * @author Pekka Pessi - * - * @date Created: Thu Feb 22 12:25:55 2001 ppessi - */ - -#ifndef SU_ALLOC_H -#include -#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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h deleted file mode 100644 index de4e72d579..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h +++ /dev/null @@ -1,404 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 has been included. */ -#define AUTH_MODULE_H - -/**@file sofia-sip/auth_module.h - * @brief Authentication verification interface. - * - * @author Pekka Pessi . - * - * @date Created: Mon Jul 23 19:21:24 2001 ppessi - */ - -#ifndef SU_TAG_H -#include -#endif -#ifndef SU_WAIT_H -#include -#endif -#ifndef MSG_TYPES_H -#include -#endif -#ifndef URL_H -#include -#endif -#ifndef URL_TAG_H -#include -#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_INLINE_TAG_CAST -su_inline tag_value_t authtag_module_v(auth_mod_t *v) { - return (tag_value_t)v; -} -su_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; - -/** Maximum nonce count allowed. */ -#define AUTHTAG_MAX_NCOUNT(x) authtag_max_ncount, tag_uint_v((x)) -SOFIAPUBVAR tag_typedef_t authtag_max_ncount; - -#define AUTHTAG_MAX_NCOUNT_REF(x) authtag_max_ncount_ref, tag_uint_vr((&x)) -SOFIAPUBVAR tag_typedef_t authtag_max_ncount_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; - -/** 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 diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h b/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h deleted file mode 100644 index 0176b9b8cd..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_ntlm.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 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 - * RFC 2617, - * "HTTP Authentication: Basic and Ntlm Access Authentication", - * J. Franks et al, - * June 1999. - * - * @sa Section 19 from - * -#endif - -#ifndef SU_MD5_H -#include -#endif - -#include - -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 identifier */ - - 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; /**< Not used */ - - /* 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 */ - - unsigned am_max_ncount:1; /**< If nonzero, challenge with new nonce after ncount */ -}; - -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 */ diff --git a/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c b/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c deleted file mode 100644 index d849046058..0000000000 --- a/libs/sofia-sip/libsofia-sip-ua/iptsec/test_auth_digest.c +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * This file is part of the Sofia-SIP package - * - * Copyright (C) 2005 Nokia Corporation. - * - * Contact: Pekka Pessi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 - * - * @date Created: Thu Feb 22 12:10:37 2001 ppessi - */ - -#include "config.h" - -#include -#include -#include -#include - -#if HAVE_SOFIA_SIP -#define PROTOCOL "SIP/2.0" -#include -#include -#include -#else -#define PROTOCOL "HTTP/1.1" -#include -#include -#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 -#include -#include -#include -#include - -int tstflags; -char *argv0; - -#define TSTFLAGS tstflags - -#include - -#if defined(_WIN32) -#include -#endif - -char const name[] = "test_auth_digest"; - -/* Fake su_time() implementation */ -#include - -unsigned offset; - -void offset_time(su_time_t *tv) -{ - tv->tv_sec += offset; -} - -int test_digest(void) -{ - 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@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@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@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@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@host.com", - nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", - uri="/dir/index.html", - response="e966c932a9242554e42c8ee200cec7f6", - opaque="5ccc069c403ebaf9f0171e9517f40e41" - */ - - char challenge[] = - "Digest realm=\"testrealm@host.com\", " - "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " - "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; - - char rfc2069_cred[] = - "Digest username=\"Mufasa\", " - "realm=\"testrealm@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@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)); - - { - size_t n = auth_digest_response_get(home, ar, pz->au_params); - TEST_SIZE(n, 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@194.2.188.133\", algorithm=MD5, " - "response=\"26e8b9aaacfca2d68770fab1ec04e2c7\", " - "qop=auth-int, nc=00000001"; - char data[] = - "\n" - "\n" - "\n" - "\n" - "