summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--channels/pjsip/dialplan_functions.c2
-rw-r--r--include/asterisk/res_pjsip.h68
-rw-r--r--res/res_pjsip.c2
-rw-r--r--res/res_pjsip/location.c53
-rw-r--r--res/res_pjsip_session.c3
6 files changed, 128 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index b81ef1cde..442f59d62 100644
--- a/CHANGES
+++ b/CHANGES
@@ -28,6 +28,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 14.4.0 to Asterisk 14.5.0 ------------
------------------------------------------------------------------------------
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index 332df70b4..7b3434d40 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -896,7 +896,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)) {
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 59f1710d1..8c589ef85 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -865,6 +865,17 @@ struct ast_sip_endpoint_identifier {
};
/*!
+ * \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.
*
* This is more-or-less a wrapper around pjsip_endpt_register_module().
@@ -1050,6 +1061,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
*
* \param aor Pointer to the AOR
@@ -1064,6 +1087,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
*
@@ -1078,6 +1118,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
*
* \param aor_list A comma-separated list of AOR names
@@ -1106,6 +1162,18 @@ struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const cha
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
*
* \param contact_name Name of the contact
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 102bc3933..d994f2824 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -3040,7 +3040,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;
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 5abfcabad..6213046e3 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -177,12 +177,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);
@@ -193,6 +217,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];
struct ao2_container *contacts;
@@ -211,24 +241,41 @@ 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;
/* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */
ao2_lock((void*)aor);
- contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, flags);
ao2_unlock((void*)aor);
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;
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 9e3abf253..8447be36e 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1719,7 +1719,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 {