]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add support for returning only reachable contacts and use it.
authorJoshua Colp <jcolp@digium.com>
Wed, 31 May 2017 15:41:45 +0000 (15:41 +0000)
committerJoshua Colp <jcolp@digium.com>
Tue, 6 Jun 2017 14:45:49 +0000 (14:45 +0000)
This introduces the ability for PJSIP code to specify filtering flags
when retrieving PJSIP contacts. The first flag for use causes the
query code to only retrieve contacts that are not unreachable. This
change has been leveraged by both the Dial() process and the
PJSIP_DIAL_CONTACTS dialplan function so they will now only attempt
calls to contacts which are not unreachable.

ASTERISK-26281

Change-Id: I8233b4faa21ba3db114f5a42e946e4b191446f6c

CHANGES
channels/pjsip/dialplan_functions.c
include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/location.c
res/res_pjsip_session.c

diff --git a/CHANGES b/CHANGES
index 94405bf4a37a8bdc3d20a4de26ed81b62e978e55..4b690247dc11cfbf56d56ce8662a065ed64c7890 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -19,6 +19,12 @@ res_agi
    EAGI provides. If not specified, it will continue to use the default signed
    linear (slin).
 
+chan_pjsip
+------------------
+ * When dialing an endpoint directly or using the PJSIP_DIAL_CONTACTS dialplan
+   function any contact which is considered unreachable due to qualify being
+   enabled will no longer be called.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.15.0 to Asterisk 13.16.0 ----------
 ------------------------------------------------------------------------------
index 652a6b7f380465c17d31dbe1e410e4543c81cc50..d11636ccc43d0f2923803bfcf22f8e46854ac8f9 100644 (file)
@@ -898,7 +898,7 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char
                if (!aor) {
                        /* If the AOR provided is not found skip it, there may be more */
                        continue;
-               } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
+               } else if (!(contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_REACHABLE))) {
                        /* No contacts are available, skip it as well */
                        continue;
                } else if (!ao2_container_count(contacts)) {
index 59122b987399e447b9a6f1e67eae21a53e1d4194..66a744d680fcf0e05e34b878c290e39a7cbdd120 100644 (file)
@@ -868,6 +868,17 @@ struct ast_sip_endpoint_identifier {
     struct ast_sip_endpoint *(*identify_endpoint)(pjsip_rx_data *rdata);
 };
 
+/*!
+ * \brief Contact retrieval filtering flags
+ */
+enum ast_sip_contact_filter {
+       /*! \brief Default filter flags */
+       AST_SIP_CONTACT_FILTER_DEFAULT = 0,
+
+       /*! \brief Return only reachable or unknown contacts */
+       AST_SIP_CONTACT_FILTER_REACHABLE = (1 << 0),
+};
+
 /*!
  * \brief Register a SIP service in Asterisk.
  *
@@ -1053,6 +1064,18 @@ struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name);
  */
 struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor);
 
+/*!
+ * \brief Retrieve the first bound contact for an AOR and filter based on flags
+ * \since 13.16.0
+ *
+ * \param aor Pointer to the AOR
+ * \param flags Filtering flags
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ */
+struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags);
+
 /*!
  * \brief Retrieve all contacts currently available for an AOR
  *
@@ -1067,6 +1090,23 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct
  */
 struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor);
 
+/*!
+ * \brief Retrieve all contacts currently available for an AOR and filter based on flags
+ * \since 13.16.0
+ *
+ * \param aor Pointer to the AOR
+ * \param flags Filtering flags
+ *
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ *
+ * \warning
+ * Since this function prunes expired contacts before returning, it holds a named write
+ * lock on the aor.  If you already hold the lock, call ast_sip_location_retrieve_aor_contacts_nolock instead.
+ */
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags);
+
 /*!
  * \brief Retrieve all contacts currently available for an AOR without locking the AOR
  * \since 13.9.0
@@ -1081,6 +1121,22 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si
  */
 struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor);
 
+/*!
+ * \brief Retrieve all contacts currently available for an AOR without locking the AOR and filter based on flags
+ * \since 13.16.0
+ *
+ * \param aor Pointer to the AOR
+ * \param flags Filtering flags
+ *
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ *
+ * \warning
+ * This function should only be called if you already hold a named write lock on the aor.
+ */
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags);
+
 /*!
  * \brief Retrieve the first bound contact from a list of AORs
  *
@@ -1109,6 +1165,18 @@ struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const cha
  void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
        struct ast_sip_contact **contact);
 
+/*!
+ * \brief Retrieve the first bound contact AND the AOR chosen from a list of AORs and filter based on flags
+ * \since 13.16.0
+ *
+ * \param aor_list A comma-separated list of AOR names
+ * \param flags Filtering flags
+ * \param aor The chosen AOR
+ * \param contact The chosen contact
+ */
+void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags,
+       struct ast_sip_aor **aor, struct ast_sip_contact **contact);
+
 /*!
  * \brief Retrieve a named contact
  *
index d47815fec209379ecf744e1e94b33e72a641b49d..24627addfe1a286606b81f483f79cee962684cd6 100644 (file)
@@ -3030,7 +3030,7 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
        if (res != PJ_SUCCESS) {
                if (res == PJSIP_EINVALIDURI) {
                        ast_log(LOG_ERROR,
-                               "Endpoint '%s': Could not create dialog to invalid URI '%s'.  Is endpoint registered?\n",
+                               "Endpoint '%s': Could not create dialog to invalid URI '%s'.  Is endpoint registered and reachable?\n",
                                ast_sorcery_object_get_id(endpoint), uri);
                }
                return NULL;
index d8f0c58b5c901c632fe0e757b2a4f5df3188bf73..05e19f53a9af9ce17318b381e06da37bef7383be 100644 (file)
@@ -171,12 +171,36 @@ static int contact_link_static(void *obj, void *arg, int flags)
        return 0;
 }
 
+/*! \brief Internal callback function which removes any contact which is unreachable */
+static int contact_remove_unreachable(void *obj, void *arg, int flags)
+{
+       struct ast_sip_contact *contact = obj;
+       struct ast_sip_contact_status *status;
+       int unreachable;
+
+       status = ast_res_pjsip_find_or_create_contact_status(contact);
+       if (!status) {
+               return 0;
+       }
+
+       unreachable = (status->status == UNAVAILABLE);
+       ao2_ref(status, -1);
+
+       return unreachable ? CMP_MATCH : 0;
+}
+
 struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor)
+{
+       return ast_sip_location_retrieve_first_aor_contact_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
+}
+
+struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags)
 {
        struct ao2_container *contacts;
        struct ast_sip_contact *contact = NULL;
 
-       contacts = ast_sip_location_retrieve_aor_contacts(aor);
+       contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, flags);
        if (contacts && ao2_container_count(contacts)) {
                /* Get the first AOR contact in the container. */
                contact = ao2_callback(contacts, 0, NULL, NULL);
@@ -186,6 +210,12 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct
 }
 
 struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
+{
+       return ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
+}
+
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags)
 {
        /* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
        char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
@@ -205,10 +235,20 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct
                ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts);
        }
 
+       if (flags & AST_SIP_CONTACT_FILTER_REACHABLE) {
+               ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_remove_unreachable, NULL);
+       }
+
        return contacts;
 }
 
 struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
+{
+       return ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
+}
+
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor,
+       unsigned int flags)
 {
        struct ao2_container *contacts;
        struct ast_named_lock *lock;
@@ -219,15 +259,22 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si
        }
 
        ao2_lock(lock);
-       contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
+       contacts = ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, flags);
        ao2_unlock(lock);
        ast_named_lock_put(lock);
 
        return contacts;
 }
 
+
 void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
        struct ast_sip_contact **contact)
+{
+       ast_sip_location_retrieve_contact_and_aor_from_list_filtered(aor_list, AST_SIP_CONTACT_FILTER_DEFAULT, aor, contact);
+}
+
+void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags,
+       struct ast_sip_aor **aor, struct ast_sip_contact **contact)
 {
        char *aor_name;
        char *rest;
@@ -247,7 +294,7 @@ void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, s
                if (!(*aor)) {
                        continue;
                }
-               *contact = ast_sip_location_retrieve_first_aor_contact(*aor);
+               *contact = ast_sip_location_retrieve_first_aor_contact_filtered(*aor, flags);
                /* If a valid contact is available use its URI for dialing */
                if (*contact) {
                        break;
index 400eb6a8499af61e6c83d5ba82289f2ab12bd5db..1fec089f8efbdd067f8650bb94dfa3e865796c8b 100644 (file)
@@ -1717,7 +1717,8 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint
        if (location || !contact) {
                location = S_OR(location, endpoint->aors);
 
-               ast_sip_location_retrieve_contact_and_aor_from_list(location, &found_aor, &found_contact);
+               ast_sip_location_retrieve_contact_and_aor_from_list_filtered(location, AST_SIP_CONTACT_FILTER_REACHABLE,
+                       &found_aor, &found_contact);
                if (!found_contact || ast_strlen_zero(found_contact->uri)) {
                        uri = location;
                } else {