summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES13
-rw-r--r--autoconf/libcurl.m449
-rw-r--r--channels/chan_sip.c6
-rwxr-xr-xconfigure33
-rw-r--r--configure.ac11
-rw-r--r--contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py21
-rwxr-xr-xcontrib/scripts/install_prereq4
-rw-r--r--funcs/func_odbc.c16
-rw-r--r--include/asterisk/autoconfig.h.in12
-rw-r--r--include/asterisk/res_odbc.h5
-rw-r--r--include/asterisk/res_pjsip.h5
-rw-r--r--res/res_config_odbc.c1
-rw-r--r--res/res_odbc.c16
-rw-r--r--res/res_pjsip.c12
-rw-r--r--res/res_pjsip/pjsip_configuration.c65
-rw-r--r--res/res_pjsip/pjsip_options.c84
-rw-r--r--res/res_pjsip_exten_state.c10
-rw-r--r--res/res_sorcery_realtime.c2
-rw-r--r--tests/test_sorcery_realtime.c37
19 files changed, 280 insertions, 122 deletions
diff --git a/CHANGES b/CHANGES
index 6e6bec6d0..6a6cb6337 100644
--- a/CHANGES
+++ b/CHANGES
@@ -361,6 +361,17 @@ cdr_csv
------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ----------
+------------------------------------------------------------------------------
+
+res_pjsip
+------------------
+ * Added "subscribe_context" to endpoint.
+ If specified, incoming SUBSCRIBE requests will be searched for the matching
+ extension in the indicated context. If no "subscribe_context" is specified,
+ then the "context" setting is used.
+
+------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 -----------
------------------------------------------------------------------------------
@@ -397,8 +408,6 @@ res_pjsip
"contact_deny" - List of Contact header addresses to deny
"contact_permit" - List of Contact header addresses to permit
- * Added new status Updated to AMI event ContactStatus on update registration
-
* Added "reg_server" to contacts.
If the Asterisk system name is set in asterisk.conf, it will be stored
into the "reg_server" field in the ps_contacts table to facilitate
diff --git a/autoconf/libcurl.m4 b/autoconf/libcurl.m4
index 085ee0ea0..9a31bfc8b 100644
--- a/autoconf/libcurl.m4
+++ b/autoconf/libcurl.m4
@@ -1,3 +1,24 @@
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 2006, David Shaw <dshaw@jabberwocky.com>
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
# [ACTION-IF-YES], [ACTION-IF-NO])
# ----------------------------------------------------------
@@ -55,10 +76,14 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG],
AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
AC_SUBST(PBX_CURL)
AC_ARG_WITH(libcurl,
- AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
+ AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
[_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
if test "$_libcurl_with" != "no" ; then
@@ -72,10 +97,10 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG],
if test -d "$_libcurl_with" ; then
CURL_INCLUDE="-I$withval/include"
_libcurl_ldflags="-L$withval/lib"
- AC_PATH_PROG([_libcurl_config],[curl-config],["$withval/bin"],
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],
["$withval/bin"])
else
- AC_PATH_PROG([_libcurl_config],[curl-config])
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
fi
if test x$_libcurl_config != "x" ; then
@@ -143,18 +168,19 @@ AC_DEFUN([AST_LIBCURL_CHECK_CONFIG],
_libcurl_save_libs=$LIBS
LIBS="$CURL_LIB $LIBS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <curl/curl.h>],[
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
/* Try and use a few common options to force a failure if we are
missing symbols or can't link. */
int x;
curl_easy_setopt(NULL,CURLOPT_URL,NULL);
x=CURL_ERROR_SIZE;
x=CURLOPT_WRITEFUNCTION;
-x=CURLOPT_FILE;
+x=CURLOPT_WRITEDATA;
x=CURLOPT_ERRORBUFFER;
x=CURLOPT_STDERR;
x=CURLOPT_VERBOSE;
-])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+if (x) {;}
+]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
CPPFLAGS=$_libcurl_save_cppflags
LIBS=$_libcurl_save_libs
@@ -196,17 +222,23 @@ x=CURLOPT_VERBOSE;
# We don't have --protocols, so just assume that all
# protocols are available
- _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
if test x$libcurl_feature_SSL = xyes ; then
_libcurl_protocols="$_libcurl_protocols HTTPS"
# FTPS wasn't standards-compliant until version
- # 7.11.0
+ # 7.11.0 (0x070b00 == 461568)
if test $_libcurl_version -ge 461568; then
_libcurl_protocols="$_libcurl_protocols FTPS"
fi
fi
+
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
fi
for _libcurl_protocol in $_libcurl_protocols ; do
@@ -241,4 +273,3 @@ x=CURLOPT_VERBOSE;
unset _libcurl_with
])dnl
-
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 28379ff85..599ecd639 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -18386,7 +18386,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re
static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
const char *fromtag, struct sip_pvt **out_pvt, struct ast_channel **out_chan)
{
- struct sip_pvt *sip_pvt_ptr;
+ RAII_VAR(struct sip_pvt *, sip_pvt_ptr, NULL, ao2_cleanup);
struct sip_pvt tmp_dialog = {
.callid = callid,
};
@@ -18461,6 +18461,9 @@ static int get_sip_pvt_from_replaces(const char *callid, const char *totag,
}
}
+ /* If we're here sip_pvt_ptr has been copied to *out_pvt, prevent RAII_VAR cleanup */
+ sip_pvt_ptr = NULL;
+
return 0;
}
@@ -31095,6 +31098,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
return NULL;
}
if (!(peer->endpoint = ast_endpoint_create("SIP", name))) {
+ ao2_t_ref(peer, -1, "failed to allocate endpoint, drop peer");
return NULL;
}
if (!(peer->caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
diff --git a/configure b/configure
index 5e5667c97..2834ada58 100755
--- a/configure
+++ b/configure
@@ -2095,7 +2095,8 @@ Optional Packages:
--with-uriparser=PATH use uriparser library files in PATH
--with-kqueue=PATH use kqueue support files in PATH
--with-ldap=PATH use OpenLDAP files in PATH
- --with-libcurl=DIR look for the curl library in DIR
+ --with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers
+ in PREFIX/include
--with-libedit=PATH use NetBSD Editline library files in PATH, use
'internal' Editline otherwise
--with-libxml2=PATH use LibXML2 files in PATH
@@ -9464,6 +9465,10 @@ fi
+
+
+
+
# Check whether --with-libcurl was given.
if test "${with_libcurl+set}" = set; then :
withval=$with_libcurl; _libcurl_with=$withval
@@ -9551,7 +9556,6 @@ done
done
IFS=$as_save_IFS
- test -z "$ac_cv_path__libcurl_config" && ac_cv_path__libcurl_config=""$withval/bin""
;;
esac
fi
@@ -9701,10 +9705,11 @@ int x;
curl_easy_setopt(NULL,CURLOPT_URL,NULL);
x=CURL_ERROR_SIZE;
x=CURLOPT_WRITEFUNCTION;
-x=CURLOPT_FILE;
+x=CURLOPT_WRITEDATA;
x=CURLOPT_ERRORBUFFER;
x=CURLOPT_STDERR;
x=CURLOPT_VERBOSE;
+if (x) {;}
;
return 0;
@@ -9771,17 +9776,23 @@ _ACEOF
# We don't have --protocols, so just assume that all
# protocols are available
- _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
if test x$libcurl_feature_SSL = xyes ; then
_libcurl_protocols="$_libcurl_protocols HTTPS"
# FTPS wasn't standards-compliant until version
- # 7.11.0
+ # 7.11.0 (0x070b00 == 461568)
if test $_libcurl_version -ge 461568; then
_libcurl_protocols="$_libcurl_protocols FTPS"
fi
fi
+
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
fi
for _libcurl_protocol in $_libcurl_protocols ; do
@@ -17919,19 +17930,13 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -march=native support" >&5
$as_echo_n "checking for -march=native support... " >&6; }
if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
- if test "${CONFIG_CFLAGS}" = ""; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- AST_NATIVE_ARCH=1
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: user CFLAGS present" >&5
-$as_echo "user CFLAGS present" >&6; }
- AST_NATIVE_ARCH=
- fi
+ AST_NATIVE_ARCH=1
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- AST_NATIVE_ARCH=
+ AST_NATIVE_ARCH=0
fi
diff --git a/configure.ac b/configure.ac
index 6256ef7fb..3cb0fed05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1217,16 +1217,11 @@ AC_SUBST(AST_SHADOW_WARNINGS)
AC_MSG_CHECKING(for -march=native support)
if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
- if test "${CONFIG_CFLAGS}" = ""; then
- AC_MSG_RESULT(yes)
- AST_NATIVE_ARCH=1
- else
- AC_MSG_RESULT(user CFLAGS present)
- AST_NATIVE_ARCH=
- fi
+ AC_MSG_RESULT(yes)
+ AST_NATIVE_ARCH=1
else
AC_MSG_RESULT(no)
- AST_NATIVE_ARCH=
+ AST_NATIVE_ARCH=0
fi
AC_SUBST(AST_NATIVE_ARCH)
diff --git a/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py b/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py
new file mode 100644
index 000000000..2358fdd59
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py
@@ -0,0 +1,21 @@
+"""pjsip_add_subscribe_context
+
+Revision ID: 9deac0ae4717
+Revises: ef7efc2d3964
+Create Date: 2016-07-04 12:11:28.117788
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '9deac0ae4717'
+down_revision = 'ef7efc2d3964'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('subscribe_context', sa.String(40)))
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'subscribe_context')
diff --git a/contrib/scripts/install_prereq b/contrib/scripts/install_prereq
index bda28e9f7..fb240890b 100755
--- a/contrib/scripts/install_prereq
+++ b/contrib/scripts/install_prereq
@@ -175,7 +175,9 @@ install_unpackaged() {
cd libsrtp
git pull
fi
- ./configure CFLAGS=-fPIC && make libsrtp.a && make uninstall && make install
+ git checkout "1_5_x_throttle"
+ ./configure --disable-debug --disable-stdout --enable-openssl
+ make shared_library uninstall install
cd ..
echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf
/sbin/ldconfig
diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c
index 489f3734b..224cd7a7f 100644
--- a/funcs/func_odbc.c
+++ b/funcs/func_odbc.c
@@ -388,9 +388,25 @@ static struct odbc_obj *get_odbc_obj(const char *dsn_name, struct dsn **dsn)
static inline void release_obj_or_dsn(struct odbc_obj **obj, struct dsn **dsn)
{
if (dsn && *dsn) {
+ /* If multiple connections are not enabled then the guarantee
+ * of a single connection already exists and holding on to the
+ * connection would prevent any other user from acquiring it
+ * indefinitely.
+ */
+ if (ast_odbc_get_max_connections((*dsn)->name) < 2) {
+ ast_odbc_release_obj((*dsn)->connection);
+ (*dsn)->connection = NULL;
+ }
ao2_unlock(*dsn);
ao2_ref(*dsn, -1);
*dsn = NULL;
+ /* Some callers may provide both an obj and dsn. To ensure that
+ * the connection is not released twice we set it to NULL here if
+ * present.
+ */
+ if (obj) {
+ *obj = NULL;
+ }
} else if (obj && *obj) {
ast_odbc_release_obj(*obj);
*obj = NULL;
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 5834de77e..cdcc4d006 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -1216,9 +1216,21 @@
/* Defined if libcurl supports HTTPS */
#undef LIBCURL_PROTOCOL_HTTPS
+/* Defined if libcurl supports IMAP */
+#undef LIBCURL_PROTOCOL_IMAP
+
/* Defined if libcurl supports LDAP */
#undef LIBCURL_PROTOCOL_LDAP
+/* Defined if libcurl supports POP3 */
+#undef LIBCURL_PROTOCOL_POP3
+
+/* Defined if libcurl supports RTSP */
+#undef LIBCURL_PROTOCOL_RTSP
+
+/* Defined if libcurl supports SMTP */
+#undef LIBCURL_PROTOCOL_SMTP
+
/* Defined if libcurl supports TELNET */
#undef LIBCURL_PROTOCOL_TELNET
diff --git a/include/asterisk/res_odbc.h b/include/asterisk/res_odbc.h
index 8c7b54950..137f7d4a5 100644
--- a/include/asterisk/res_odbc.h
+++ b/include/asterisk/res_odbc.h
@@ -243,4 +243,9 @@ int ast_odbc_text2isolation(const char *txt);
*/
const char *ast_odbc_isolation2text(int iso);
+/*!
+ * \brief Return the current configured maximum number of connections for a class
+ */
+unsigned int ast_odbc_get_max_connections(const char *name);
+
#endif /* _ASTERISK_RES_ODBC_H */
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index f9f9e2037..6f5928365 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -271,7 +271,6 @@ enum ast_sip_contact_status_type {
UNKNOWN,
CREATED,
REMOVED,
- UPDATED,
};
/*!
@@ -296,6 +295,8 @@ struct ast_sip_contact_status {
int64_t rtt;
/*! Last status for a contact (default - unavailable) */
enum ast_sip_contact_status_type last_status;
+ /*! TRUE if the contact was refreshed. e.g., re-registered */
+ unsigned int refresh:1;
};
/*!
@@ -505,6 +506,8 @@ struct ast_sip_endpoint_subscription_configuration {
unsigned int minexpiry;
/*! Message waiting configuration */
struct ast_sip_mwi_configuration mwi;
+ /* Context for SUBSCRIBE requests */
+ char context[AST_MAX_CONTEXT];
};
/*!
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 37c6d3ff9..26aa17b17 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -137,6 +137,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
if (!ast_strlen_zero(cps->extra)) {
const char *newval = cps->extra;
+ ast_debug(1, "Parameter %d = '%s'\n", x, newval);
if (strchr(newval, ';') || strchr(newval, '^')) {
ENCODE_CHUNK(encodebuf, newval);
ast_string_field_set(cps, encoding[x], encodebuf);
diff --git a/res/res_odbc.c b/res/res_odbc.c
index a89c95492..bd64b9fef 100644
--- a/res/res_odbc.c
+++ b/res/res_odbc.c
@@ -744,6 +744,22 @@ static int aoro2_class_cb(void *obj, void *arg, int flags)
return 0;
}
+unsigned int ast_odbc_get_max_connections(const char *name)
+{
+ struct odbc_class *class;
+ unsigned int max_connections;
+
+ class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name);
+ if (!class) {
+ return 0;
+ }
+
+ max_connections = class->maxconnections;
+ ao2_ref(class, -1);
+
+ return max_connections;
+}
+
/*
* \brief Determine if the connection has died.
*
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index d99c1cf84..af2f93749 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -900,6 +900,15 @@
mask with a slash ('/')
</para></description>
</configOption>
+ <configOption name="subscribe_context">
+ <synopsis>Context for incoming MESSAGE requests.</synopsis>
+ <description><para>
+ If specified, incoming SUBSCRIBE requests will be searched for the matching
+ extension in the indicated context.
+ If no <replaceable>subscribe_context</replaceable> is specified,
+ then the <replaceable>context</replaceable> setting is used.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
@@ -1964,6 +1973,9 @@
<parameter name="ActiveChannels">
<para>The number of active channels associated with this endpoint.</para>
</parameter>
+ <parameter name="SubscribeContext">
+ <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='subscribe_context']/synopsis/node())"/></para>
+ </parameter>
</syntax>
</managerEventInstance>
</managerEvent>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 8a5ff416a..4d3fb6583 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi
ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint));
}
+static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact)
+{
+ struct ast_json *blob;
+ char rtt[32];
+
+ snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt);
+ blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
+ "contact_status", ast_sip_get_contact_status_label(contact->status),
+ "aor", contact->aor,
+ "uri", contact->uri,
+ "roundtrip_usec", rtt,
+ "endpoint_name", ast_endpoint_get_resource(endpoint));
+ if (blob) {
+ ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
+ ast_json_unref(blob);
+ }
+}
+
+/*! \brief Callback function for publishing the status of an endpoint */
+static int persistent_endpoint_publish_status(void *obj, void *arg, int flags)
+{
+ struct sip_persistent_endpoint *persistent = obj;
+ struct ast_endpoint *endpoint = persistent->endpoint;
+ struct ast_sip_contact_status *status = arg;
+
+ /* If the status' aor isn't one of the endpoint's, we skip */
+ if (!strstr(persistent->aors, status->aor)) {
+ return 0;
+ }
+
+ endpoint_publish_contact_status(endpoint, status);
+ return 0;
+}
+
/*! \brief Callback function for changing the state of an endpoint */
static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
{
@@ -112,30 +146,17 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
struct ast_endpoint *endpoint = persistent->endpoint;
struct ast_sip_contact_status *status = arg;
struct ao2_container *contacts;
- struct ast_json *blob;
struct ao2_iterator i;
struct ast_sip_contact *contact;
enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
- if (status) {
- char rtt[32];
-
- /* If the status' aor isn't one of the endpoint's, we skip */
- if (!strstr(persistent->aors, status->aor)) {
- return 0;
- }
-
- snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt);
- blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
- "contact_status", ast_sip_get_contact_status_label(status->status),
- "aor", status->aor,
- "uri", status->uri,
- "roundtrip_usec", rtt,
- "endpoint_name", ast_endpoint_get_resource(endpoint));
- ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
- ast_json_unref(blob);
+ /* If the status' aor isn't one of the endpoint's, we skip */
+ if (!strstr(persistent->aors, status->aor)) {
+ return 0;
}
+ endpoint_publish_contact_status(endpoint, status);
+
/* Find all the contacts for this endpoint. If ANY are available,
* mark the endpoint as ONLINE.
*/
@@ -222,6 +243,13 @@ static void persistent_endpoint_contact_status_observer(const void *object)
{
struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object;
+ if (contact_status->refresh) {
+ /* We are only re-publishing the contact status. */
+ ao2_callback(persistent_endpoints, OBJ_NODATA,
+ persistent_endpoint_publish_status, contact_status);
+ return;
+ }
+
/* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
if (contact_status->rtt_start.tv_sec > 0) {
return;
@@ -1859,6 +1887,7 @@ int ast_res_pjsip_initialize_configuration(void)
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context));
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index dc3bce06f..808ee171a 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -43,7 +43,6 @@ static const char *status_map [] = {
[UNKNOWN] = "Unknown",
[CREATED] = "Created",
[REMOVED] = "Removed",
- [UPDATED] = "Updated",
};
static const char *short_status_map [] = {
@@ -52,7 +51,6 @@ static const char *short_status_map [] = {
[UNKNOWN] = "Unknown",
[CREATED] = "Created",
[REMOVED] = "Removed",
- [UPDATED] = "Updated",
};
const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)
@@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const
* \brief Update an ast_sip_contact_status's elements.
*/
static void update_contact_status(const struct ast_sip_contact *contact,
- enum ast_sip_contact_status_type value)
+ enum ast_sip_contact_status_type value, int is_contact_refresh)
{
RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup);
@@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact,
return;
}
+ if (is_contact_refresh
+ && status->status == CREATED) {
+ /*
+ * The contact status hasn't been updated since creation
+ * and we don't want to re-send a created status.
+ */
+ if (contact->qualify_frequency
+ || status->rtt_start.tv_sec > 0) {
+ /* Ignore, the status will change soon. */
+ return;
+ }
+
+ /*
+ * Convert to a regular contact status update
+ * because the status may never change.
+ */
+ is_contact_refresh = 0;
+ value = UNKNOWN;
+ }
+
update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
ast_sorcery_object_get_id(status));
if (!update) {
@@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact,
}
ast_string_field_set(update, uri, contact->uri);
- update->last_status = status->status;
- update->status = value;
-
- /* if the contact is available calculate the rtt as
- the diff between the last start time and "now" */
- update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ?
- ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;
- update->rtt_start = ast_tv(0, 0);
-
- ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
- "Contact: %s\r\n"
- "Status: %s\r\n"
- "RTT: %" PRId64,
- ast_sorcery_object_get_id(update),
- ast_sip_get_contact_status_label(update->status),
- update->rtt);
+
+ if (is_contact_refresh) {
+ /* Copy everything just to set the refresh flag. */
+ update->status = status->status;
+ update->last_status = status->last_status;
+ update->rtt = status->rtt;
+ update->rtt_start = status->rtt_start;
+ update->refresh = 1;
+ } else {
+ update->last_status = status->status;
+ update->status = value;
+
+ /*
+ * if the contact is available calculate the rtt as
+ * the diff between the last start time and "now"
+ */
+ update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0
+ ? ast_tvdiff_us(ast_tvnow(), status->rtt_start)
+ : 0;
+ update->rtt_start = ast_tv(0, 0);
+
+ ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
+ "Contact: %s\r\n"
+ "Status: %s\r\n"
+ "RTT: %" PRId64,
+ ast_sorcery_object_get_id(update),
+ ast_sip_get_contact_status_label(update->status),
+ update->rtt);
+ }
if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
@@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e)
/* Fall through */
case PJSIP_EVENT_TRANSPORT_ERROR:
case PJSIP_EVENT_TIMER:
- update_contact_status(contact, UNAVAILABLE);
+ update_contact_status(contact, UNAVAILABLE, 0);
break;
case PJSIP_EVENT_RX_MSG:
- update_contact_status(contact, AVAILABLE);
+ update_contact_status(contact, AVAILABLE, 0);
break;
}
ao2_cleanup(contact);
@@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con
!= PJ_SUCCESS) {
ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
contact->uri);
- update_contact_status(contact, UNAVAILABLE);
+ update_contact_status(contact, UNAVAILABLE, 0);
ao2_ref(contact, -1);
return -1;
}
@@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact)
schedule_qualify(contact, contact->qualify_frequency * 1000);
} else {
- update_contact_status(contact, UNKNOWN);
+ update_contact_status(contact, UNKNOWN, 0);
}
}
@@ -544,8 +575,7 @@ static void contact_created(const void *obj)
*/
static void contact_updated(const void *obj)
{
- update_contact_status((struct ast_sip_contact *) obj, UPDATED);
- qualify_and_schedule((struct ast_sip_contact *) obj);
+ update_contact_status(obj, AVAILABLE, 1);
}
/*!
@@ -574,8 +604,8 @@ static void contact_deleted(const void *obj)
static const struct ast_sorcery_observer contact_observer = {
.created = contact_created,
+ .updated = contact_updated,
.deleted = contact_deleted,
- .updated = contact_updated
};
static pj_bool_t options_start(void)
@@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact)
if (contact->qualify_frequency) {
schedule_qualify(contact, initial_interval);
} else {
- update_contact_status(contact, UNKNOWN);
+ update_contact_status(contact, UNKNOWN, 0);
}
}
diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c
index 25b9bf1fe..9bb53bfe3 100644
--- a/res/res_pjsip_exten_state.c
+++ b/res/res_pjsip_exten_state.c
@@ -412,9 +412,11 @@ static void subscription_shutdown(struct ast_sip_subscription *sub)
static int new_subscribe(struct ast_sip_endpoint *endpoint,
const char *resource)
{
- if (!ast_exists_extension(NULL, endpoint->context, resource, PRIORITY_HINT, NULL)) {
+ const char *context = S_OR(endpoint->subscription.context, endpoint->context);
+
+ if (!ast_exists_extension(NULL, context, resource, PRIORITY_HINT, NULL)) {
ast_log(LOG_NOTICE, "Extension state subscription failed: Extension %s does not exist in context '%s' or has no associated hint\n",
- resource, endpoint->context);
+ resource, context);
return 404;
}
@@ -432,7 +434,9 @@ static int subscription_established(struct ast_sip_subscription *sip_sub)
return -1;
}
- ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
+ ast_copy_string(exten_state_sub->context,
+ S_OR(endpoint->subscription.context, endpoint->context),
+ sizeof(exten_state_sub->context));
ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten));
if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c
index abf2840fb..4023654ab 100644
--- a/res/res_sorcery_realtime.c
+++ b/res/res_sorcery_realtime.c
@@ -271,7 +271,7 @@ static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data
return -1;
}
- return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0;
+ return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0;
}
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)
diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c
index b33031e8e..033bf5d6f 100644
--- a/tests/test_sorcery_realtime.c
+++ b/tests/test_sorcery_realtime.c
@@ -711,41 +711,6 @@ AST_TEST_DEFINE(object_update)
return AST_TEST_PASS;
}
-AST_TEST_DEFINE(object_update_uncreated)
-{
- RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
- RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
-
- switch (cmd) {
- case TEST_INIT:
- info->name = "object_update_uncreated";
- info->category = "/res/sorcery_realtime/";
- info->summary = "sorcery object update unit test";
- info->description =
- "Test updating of an uncreated object in sorcery using realtime wizard";
- return AST_TEST_NOT_RUN;
- case TEST_EXECUTE:
- break;
- }
-
- if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) {
- ast_test_status_update(test, "Failed to open sorcery structure\n");
- return AST_TEST_FAIL;
- }
-
- if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
- ast_test_status_update(test, "Failed to allocate a known object type\n");
- return AST_TEST_FAIL;
- }
-
- if (!ast_sorcery_update(sorcery, obj)) {
- ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
- return AST_TEST_FAIL;
- }
-
- return AST_TEST_PASS;
-}
-
AST_TEST_DEFINE(object_delete)
{
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
@@ -942,7 +907,6 @@ static int unload_module(void)
AST_TEST_UNREGISTER(object_retrieve_regex);
AST_TEST_UNREGISTER(object_retrieve_regex_nofetch);
AST_TEST_UNREGISTER(object_update);
- AST_TEST_UNREGISTER(object_update_uncreated);
AST_TEST_UNREGISTER(object_delete);
AST_TEST_UNREGISTER(object_delete_uncreated);
AST_TEST_UNREGISTER(object_allocate_on_retrieval);
@@ -964,7 +928,6 @@ static int load_module(void)
AST_TEST_REGISTER(object_retrieve_regex);
AST_TEST_REGISTER(object_retrieve_regex_nofetch);
AST_TEST_REGISTER(object_update);
- AST_TEST_REGISTER(object_update_uncreated);
AST_TEST_REGISTER(object_delete);
AST_TEST_REGISTER(object_delete_uncreated);
AST_TEST_REGISTER(object_allocate_on_retrieval);