diff options
-rw-r--r-- | CHANGES | 13 | ||||
-rw-r--r-- | autoconf/libcurl.m4 | 49 | ||||
-rw-r--r-- | channels/chan_sip.c | 6 | ||||
-rwxr-xr-x | configure | 33 | ||||
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/9deac0ae4717_pjsip_add_subscribe_context.py | 21 | ||||
-rwxr-xr-x | contrib/scripts/install_prereq | 4 | ||||
-rw-r--r-- | funcs/func_odbc.c | 16 | ||||
-rw-r--r-- | include/asterisk/autoconfig.h.in | 12 | ||||
-rw-r--r-- | include/asterisk/res_odbc.h | 5 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 5 | ||||
-rw-r--r-- | res/res_config_odbc.c | 1 | ||||
-rw-r--r-- | res/res_odbc.c | 16 | ||||
-rw-r--r-- | res/res_pjsip.c | 12 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 65 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 84 | ||||
-rw-r--r-- | res/res_pjsip_exten_state.c | 10 | ||||
-rw-r--r-- | res/res_sorcery_realtime.c | 2 | ||||
-rw-r--r-- | tests/test_sorcery_realtime.c | 37 |
19 files changed, 280 insertions, 122 deletions
@@ -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))) { @@ -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); |