From 1583559a06297e37e611713916e8f69c3afce713 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 10 Mar 2016 18:52:14 -0700 Subject: [PATCH] res_pjsip/pjsip_options: Fix From generation on outgoing OPTIONS No one seemed to notice but every time an OPTIONS goes out, it goes out with a From of "asterisk" (or whatever the default from_user is set to), even if you specify an endpoint. The issue had several causes... qualify_contact is only called with an endpoint if called from the CLI. If the endpoint is NULL, qualify_contact only looks up the endpoint if authenticate_qualify=yes. Even then, it never passes it on to ast_sip_create_request where the From header is set. Therefore From is always "asterisk" (or whatever the default from_user is set to). Even if ast_sip_create_request were to get an endpoint, it only sets the From if endpoint->from_user is set. The fix is 4 parts... First, create_out_of_dialog_request was modified to use the endpoint id if endpoint was specified and from_user is not set. Second, qualify_contact was modified to always look up an endpoint if one wasn't specified regardless of authenticate_qualify. It then passes the endpoint on to create_out_of_dialog_request. Third (and most importantly), find_an_endpoint was modified to find an endpoint by using an "aors LIKE %contact->aor%" predicate with ast_sorcery_retrieve_by_fields. As such, this patch will only work if the sorcery realtime optimizations patch goes in. Otherwise we'd be pulling the entire endpoints database every time we send an OPTIONS. Since we already know the contact's aor, the on_endpoint callback was also modified to just check if the contact->aor is an exact match to one of the endpoint's. Finally, since we now have an endpoint for every OPTIONS request, res_pjsip/endpt_send_request (which handles out-of-dialog reqests) was updated to get the transport from the endpoint and set it on tdata. Now the correct transport is used. Change-Id: I2207e12bb435e373bd1e03ad091d82e5aba011af --- res/res_pjsip.c | 10 ++++- res/res_pjsip/pjsip_options.c | 81 ++++++++++++----------------------- 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index e84da1a45d6..0d5ded56507 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2866,6 +2866,7 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s pj_pool_t *pool; pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; pjsip_uri *sip_uri; + const char *fromuser; if (ast_strlen_zero(uri)) { if (!endpoint && (!contact || ast_strlen_zero(contact->uri))) { @@ -2912,7 +2913,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } - if (sip_dialog_create_from(pool, &from, endpoint ? endpoint->fromuser : NULL, + fromuser = endpoint ? (!ast_strlen_zero(endpoint->fromuser) ? endpoint->fromuser : ast_sorcery_object_get_id(endpoint)) : NULL; + if (sip_dialog_create_from(pool, &from, fromuser, endpoint ? endpoint->fromdomain : NULL, &remote_uri, &selector)) { ast_log(LOG_ERROR, "Unable to create From header for %.*s request to endpoint %s\n", (int) pj_strlen(&method->name), pj_strbuf(&method->name), @@ -3207,6 +3209,7 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, struct send_request_wrapper *req_wrapper; pj_status_t ret_val; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); + pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; /* Create wrapper to detect if the callback was actually called on an error. */ req_wrapper = ao2_alloc(sizeof(*req_wrapper), send_request_wrapper_destructor); @@ -3257,6 +3260,11 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, */ ao2_ref(req_wrapper, +1); + if (endpoint) { + sip_get_tpselector_from_endpoint(endpoint, &selector); + pjsip_tx_data_set_transport(tdata, &selector); + } + ret_val = pjsip_endpt_send_request(endpt, tdata, -1, req_wrapper, endpt_send_request_cb); if (ret_val != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index fa0873984b6..3a4524316ab 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -248,31 +248,12 @@ static void init_start_time(const struct ast_sip_contact *contact) /*! * \internal - * \brief Match a container contact object with the contact sorcery id 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_id(void *obj, void *arg, int flags) -{ - struct ast_sip_contact *contact = obj; - const char *looking_for = arg; - - return strcmp(ast_sorcery_object_get_id(contact), looking_for) ? 0 : CMP_MATCH; -} - -/*! - * \internal - * \brief For an endpoint try to match the given contact sorcery id. + * \brief For an endpoint try to match the given contact->aor. */ static int on_endpoint(void *obj, void *arg, int flags) { struct ast_sip_endpoint *endpoint = obj; - struct ast_sip_contact *contact; - char *looking_for = arg; + char *contact_aor = arg; char *aor_name; char *aors; @@ -282,24 +263,7 @@ static int on_endpoint(void *obj, void *arg, int flags) aors = ast_strdupa(endpoint->aors); while ((aor_name = ast_strip(strsep(&aors, ",")))) { - struct ast_sip_aor *aor; - struct ao2_container *contacts; - - aor = ast_sip_location_retrieve_aor(aor_name); - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - ao2_ref(aor, -1); - if (!contacts) { - continue; - } - - contact = ao2_callback(contacts, 0, match_contact_id, looking_for); - ao2_ref(contacts, -1); - if (contact) { - ao2_ref(contact, -1); + if (!strcmp(contact_aor, aor_name)) { return CMP_MATCH; } } @@ -313,12 +277,26 @@ static int on_endpoint(void *obj, void *arg, int flags) */ static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact) { - char *looking_for = (char *) ast_sorcery_object_get_id(contact); - struct ao2_container *endpoints = ast_sip_get_endpoints(); + struct ao2_container *endpoints; struct ast_sip_endpoint *endpoint; + struct ast_variable *var; + char *aor = ast_alloca(strlen(contact->aor) + 3); + + sprintf(aor, "%%%s%%", contact->aor); + var = ast_variable_new("aors LIKE", aor, ""); + endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var); + + ast_variables_destroy(var); - endpoint = ao2_callback(endpoints, 0, on_endpoint, looking_for); + /* + * Because aors are a string list, we have to use a pattern match but since a simple + * pattern match could return an endpoint that has an aor of "aaabccc" when searching + * for "abc", we still have to iterate over them to find an exact aor match. + */ + endpoint = ao2_callback(endpoints, 0, on_endpoint, contact->aor); ao2_ref(endpoints, -1); + return endpoint; } @@ -357,23 +335,18 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con pjsip_tx_data *tdata; RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup); - if (contact->authenticate_qualify) { + if (endpoint) { endpoint_local = ao2_bump(endpoint); + } else { + endpoint_local = find_an_endpoint(contact); 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; - } + ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n", + contact->uri); + return -1; } } - if (ast_sip_create_request("OPTIONS", NULL, NULL, NULL, contact, &tdata)) { + if (ast_sip_create_request("OPTIONS", NULL, endpoint_local, NULL, contact, &tdata)) { ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n", contact->uri); return -1;