Index: include/asterisk/res_pjsip.h =================================================================== --- include/asterisk/res_pjsip.h (revision 411010) +++ include/asterisk/res_pjsip.h (working copy) @@ -1265,13 +1265,13 @@ * they arrive. * * \param tdata The request to send - * \param dlg Optional. If specified, the dialog on which the request should be sent - * \param endpoint Optional. If specified, the request is sent out-of-dialog to the endpoint. - * \param token Data to be passed to the callback upon receipt of response - * \param callback Callback to be called upon receipt of response + * \param dlg Optional. The dialog in which the request is sent. Otherwise it is out-of-dialog. + * \param endpoint Optional. If specified, the out-of-dialog request is sent to the endpoint. + * \param token Data to be passed to the callback upon receipt of out-of-dialog response. + * \param callback Callback to be called upon receipt of out-of-dialog response. * * \retval 0 Success - * \retval -1 Failure + * \retval -1 Failure (out-of-dialog callback will not be called.) */ int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, Index: res/res_pjsip/pjsip_options.c =================================================================== --- res/res_pjsip/pjsip_options.c (revision 411010) +++ res/res_pjsip/pjsip_options.c (working copy) @@ -34,8 +34,6 @@ #define DEFAULT_ENCODING "text/plain" #define QUALIFIED_BUCKETS 211 -static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact); - /*! * \internal * \brief Create a ast_sip_contact_status object. @@ -152,12 +150,34 @@ /*! * \internal + * \brief Match a container contact object URI with the contact URI looking for. + * + * \param obj pointer to the (user-defined part) of an object. + * \param arg callback argument from ao2_callback() + * \param flags flags from ao2_callback() + * + * \return Values are a combination of enum _cb_results. + */ +static int match_contact_uri(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_contact *looking_for = arg; + + /* Do the contact URI's match? */ + return strcmp(contact->uri, looking_for->uri) ? 0 : CMP_MATCH; +} + +/*! + * \internal * \brief For an endpoint try to match on a given contact. */ static int on_endpoint(void *obj, void *arg, int flags) { struct ast_sip_endpoint *endpoint = obj; - char *aor_name, *aors; + struct ast_sip_contact *contact = arg; + struct ast_sip_contact *matching_contact; + char *aor_name; + char *aors; if (!arg || ast_strlen_zero(endpoint->aors)) { return 0; @@ -174,7 +194,9 @@ continue; } - if (ao2_find(contacts, arg, OBJ_NODATA | OBJ_POINTER)) { + matching_contact = ao2_callback(contacts, 0, match_contact_uri, contact); + if (matching_contact) { + ao2_ref(matching_contact, -1); return CMP_MATCH; } } @@ -184,14 +206,14 @@ /*! * \internal - * \brief Find endpoints associated with the given contact. + * \brief Find an endpoint associated with the given contact. */ -static struct ao2_iterator *find_endpoints(struct ast_sip_contact *contact) +static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact) { RAII_VAR(struct ao2_container *, endpoints, ast_sip_get_endpoints(), ao2_cleanup); - return ao2_callback(endpoints, OBJ_MULTIPLE, on_endpoint, contact); + return ao2_callback(endpoints, 0, on_endpoint, contact); } /*! @@ -200,7 +222,7 @@ */ static void qualify_contact_cb(void *token, pjsip_event *e) { - RAII_VAR(struct ast_sip_contact *, contact, token, ao2_cleanup); + struct ast_sip_contact *contact = token; switch(e->body.tsx_state.type) { case PJSIP_EVENT_TRANSPORT_ERROR: @@ -211,30 +233,34 @@ update_contact_status(contact, AVAILABLE); break; } + ao2_cleanup(contact); } /*! * \internal * \brief Attempt to qualify the contact * - * \detail Sends a SIP OPTIONS request to the given contact in order to make + * \details Sends a SIP OPTIONS request to the given contact in order to make * sure that contact is available. */ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact) { pjsip_tx_data *tdata; - RAII_VAR(struct ast_sip_endpoint *, endpoint_local, ao2_bump(endpoint), ao2_cleanup); + RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup); - - if (!endpoint_local && contact->authenticate_qualify) { - struct ao2_iterator *endpoint_iterator = find_endpoints(contact); - - /* try to find endpoints that are associated with the contact */ - if (endpoint_iterator) { - /* find "first" endpoint in order to authenticate - actually any - endpoint should do that matched on the contact */ - endpoint_local = ao2_iterator_next(endpoint_iterator); - ao2_iterator_destroy(endpoint_iterator); + if (contact->authenticate_qualify) { + endpoint_local = ao2_bump(endpoint); + if (!endpoint_local) { + /* + * Find the "first" endpoint to completely qualify the contact - any + * endpoint that is associated with the contact should do. + */ + endpoint_local = find_an_endpoint(contact); + if (!endpoint_local) { + ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", + contact->uri); + return -1; + } } } @@ -256,11 +282,11 @@ init_start_time(contact); ao2_ref(contact, +1); - if (ast_sip_send_request(tdata, NULL, contact->authenticate_qualify ? endpoint_local : NULL, contact, - qualify_contact_cb) != PJ_SUCCESS) { - /* The callback will be called so we don't need to drop the contact ref*/ + if (ast_sip_send_request(tdata, NULL, endpoint_local, contact, qualify_contact_cb) + != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", contact->uri); + ao2_ref(contact, -1); return -1; } @@ -793,6 +819,7 @@ struct ast_sip_aor *aor = arg; contact->qualify_frequency = aor->qualify_frequency; + contact->authenticate_qualify = aor->authenticate_qualify; qualify_and_schedule(contact); @@ -803,7 +830,7 @@ * \internal * \brief Qualify and schedule an endpoint's contacts * - * \detail For the given endpoint retrieve its list of aors, qualify all + * \details For the given endpoint retrieve its list of aors, qualify all * contacts, and schedule for checks if configured. */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) Index: res/res_pjsip.c =================================================================== --- res/res_pjsip.c (revision 411010) +++ res/res_pjsip.c (working copy) @@ -1850,10 +1850,11 @@ } AST_RWLIST_UNLOCK(&supplements); - if ((tsx->status_code == 401 || tsx->status_code == 407) && req_data->endpoint) { - if (!ast_sip_create_request_with_auth(&req_data->endpoint->outbound_auths, challenge, tsx, &tdata)) { - pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, req_data->token, req_data->callback); - } + if ((tsx->status_code == 401 || tsx->status_code == 407) + && req_data->endpoint + && !ast_sip_create_request_with_auth(&req_data->endpoint->outbound_auths, challenge, tsx, &tdata) + && pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, req_data->token, req_data->callback) + == PJ_SUCCESS) { return; } @@ -1870,6 +1871,7 @@ struct ast_sip_contact *contact = ast_sip_mod_data_get(tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT); if (!req_data) { + pjsip_tx_data_dec_ref(tdata); return -1; } @@ -1888,7 +1890,7 @@ ast_log(LOG_ERROR, "Error attempting to send outbound %.*s request to endpoint %s\n", (int) pj_strlen(&tdata->msg->line.req.method.name), pj_strbuf(&tdata->msg->line.req.method.name), - ast_sorcery_object_get_id(endpoint)); + endpoint ? ast_sorcery_object_get_id(endpoint) : ""); ao2_cleanup(req_data); return -1; }