diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 18d1aafff2..b3701c0445 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -146,6 +146,8 @@ struct ast_sip_contact { AST_DECLARE_STRING_FIELDS( /*! Full URI of the contact */ AST_STRING_FIELD(uri); + /*! Outbound proxy to use for qualify */ + AST_STRING_FIELD(outbound_proxy); ); /*! Absolute time that this contact is no longer valid after */ struct timeval expiration_time; @@ -190,6 +192,8 @@ struct ast_sip_aor { AST_DECLARE_STRING_FIELDS( /*! Voicemail boxes for this AOR */ AST_STRING_FIELD(mailboxes); + /*! Outbound proxy for OPTIONS requests */ + AST_STRING_FIELD(outbound_proxy); ); /*! Minimum expiration time */ unsigned int minimum_expiration; @@ -1277,6 +1281,16 @@ int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pj */ struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata); +/*! + * \brief Set the outbound proxy for an outbound SIP message + * + * \param tdata The message to set the outbound proxy on + * \param proxy SIP uri of the proxy + * \retval 0 Success + * \retval -1 Failure + */ +int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy); + /*! * \brief Add a header to an outbound SIP message * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 08c4552429..5abb1f32fa 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -868,6 +868,13 @@ If 0 never qualify. Time in seconds. + + Outbound proxy used when sending OPTIONS request + + If set the provided URI will be used as the outbound proxy when an + OPTIONS request is sent to a contact for qualify purposes. + + The configuration for a location of an endpoint @@ -964,6 +971,13 @@ authentication is attempted before declaring the contact available. + + Outbound proxy used when sending OPTIONS request + + If set the provided URI will be used as the outbound proxy when an + OPTIONS request is sent to a contact for qualify purposes. + + Options that apply to the SIP stack as well as other system-wide settings @@ -1637,6 +1651,15 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s return -1; } + /* If an outbound proxy is specified on the endpoint apply it to this request */ + if (endpoint && !ast_strlen_zero(endpoint->outbound_proxy) && + ast_sip_set_outbound_proxy((*tdata), endpoint->outbound_proxy)) { + ast_log(LOG_ERROR, "Unable to apply outbound proxy on request %.*s to endpoint %s\n", + (int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint)); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return -1; + } + /* We can release this pool since request creation copied all the necessary * data into the outbound request's pool */ @@ -1713,6 +1736,22 @@ int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct } } +int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy) +{ + pjsip_route_hdr *route; + static const pj_str_t ROUTE_HNAME = { "Route", 5 }; + pj_str_t tmp; + + pj_strdup2_with_null(tdata->pool, &tmp, proxy); + if (!(route = pjsip_parse_hdr(tdata->pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) { + return -1; + } + + pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route); + + return 0; +} + int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value) { pj_str_t hdr_name; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 14f58552ae..ddd846123d 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -193,6 +193,10 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struc contact->qualify_frequency = aor->qualify_frequency; contact->authenticate_qualify = aor->authenticate_qualify; + if (!ast_strlen_zero(aor->outbound_proxy)) { + ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy); + } + return ast_sorcery_create(ast_sip_get_sorcery(), contact); } @@ -388,6 +392,7 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery) ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, 0, 0); ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400); + ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); @@ -399,6 +404,7 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery) ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing)); ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes)); + ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy)); ast_sip_register_endpoint_formatter(&endpoint_aor_formatter); return 0; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 8d46eb0368..0409c15575 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -258,6 +258,15 @@ static int qualify_contact(struct ast_sip_contact *contact) return -1; } + /* If an outbound proxy is specified set it on this request */ + if (!ast_strlen_zero(contact->outbound_proxy) && + ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) { + pjsip_tx_data_dec_ref(tdata); + ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n", + contact->uri); + return -1; + } + init_start_time(contact); ao2_ref(contact, +1); @@ -795,6 +804,7 @@ static int qualify_and_schedule_cb(void *obj, void *arg, int flags) struct ast_sip_aor *aor = arg; contact->qualify_frequency = aor->qualify_frequency; + qualify_and_schedule(contact); return 0;