chan_pjsip: Store transport info for outgoing channels

Outgoing PJSIP channels did not have transport information stored in
their session datastore when CHANNEL(pjsip,local_addr) or
CHANNEL(pjsip,remote_addr) was read. As a result, the address fields
were empty on B-leg channels even though other dialog fields such as
call-id and URIs were available.

Store the selected local transport address and destination address for
outgoing UAC session requests once the request is transmitted and the
transport information is known.

Fixes: #871
pull/2060/head
Mehrdad Seifzadeh 3 months ago committed by github-actions[bot]
parent c05ac3f232
commit 8cd58fd39d

@ -271,6 +271,102 @@ static struct ast_datastore_info transport_info = {
.destroy = transport_info_destroy,
};
/*!
* \brief Determine the local signaling address used for an outgoing request.
*
* For unreliable transports, the transport local address may be a wildcard
* address. Ask the PJSIP transport manager for the local interface selected
* for the request destination, then fall back to the transport local address
* if needed.
*/
static int set_transport_info_local_addr(struct pjsip_tx_data *tdata, pj_sockaddr *local_addr)
{
if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {
pjsip_tpmgr_fla2_param prm;
pjsip_tpmgr_fla2_param_default(&prm);
prm.tp_type = tdata->tp_info.transport->key.type;
pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
prm.local_if = PJ_TRUE;
if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
tdata->pool, &prm) == PJ_SUCCESS) {
int af = prm.tp_type & PJSIP_TRANSPORT_IPV6 ? pj_AF_INET6() : pj_AF_INET();
if (prm.tp_type == PJSIP_TRANSPORT_UDP || prm.tp_type == PJSIP_TRANSPORT_UDP6) {
prm.ret_port = tdata->tp_info.transport->local_name.port;
}
if (pj_sockaddr_init(af, local_addr, &prm.ret_addr, prm.ret_port) == PJ_SUCCESS) {
return 0;
}
}
}
pj_sockaddr_cp(local_addr, &tdata->tp_info.transport->local_addr);
return pj_sockaddr_has_addr(local_addr) ? 0 : -1;
}
/*!
* \brief Store transport information for outgoing PJSIP session requests.
*
* Incoming PJSIP channels get their transport information from the received
* request. Outgoing channels may not have this information available through
* the channel datastore, so store the selected transport addresses once the
* outgoing request has been created and a destination is known.
*/
static pj_status_t transport_info_on_tx_request(pjsip_tx_data *tdata)
{
RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
struct transport_info_data *transport_data;
pjsip_dialog *dlg;
if (!tdata->tp_info.transport
|| !pj_sockaddr_has_addr(&tdata->tp_info.dst_addr)) {
return PJ_SUCCESS;
}
dlg = pjsip_tdata_get_dlg(tdata);
if (!dlg) {
return PJ_SUCCESS;
}
session = ast_sip_dialog_get_session(dlg);
if (!session
|| !session->inv_session
|| session->inv_session->role != PJSIP_ROLE_UAC) {
return PJ_SUCCESS;
}
datastore = ast_sip_session_get_datastore(session, "transport_info");
if (datastore) {
return PJ_SUCCESS;
}
datastore = ast_sip_session_alloc_datastore(&transport_info, "transport_info");
if (!datastore) {
return PJ_SUCCESS;
}
transport_data = ast_calloc(1, sizeof(*transport_data));
if (!transport_data) {
return PJ_SUCCESS;
}
if (set_transport_info_local_addr(tdata, &transport_data->local_addr)) {
ast_free(transport_data);
return PJ_SUCCESS;
}
pj_sockaddr_cp(&transport_data->remote_addr, &tdata->tp_info.dst_addr);
datastore->data = transport_data;
ast_sip_session_add_datastore(session, datastore);
return PJ_SUCCESS;
}
static struct ast_datastore_info direct_media_mitigation_info = { };
static int direct_media_mitigate_glare(struct ast_sip_session *session)
@ -1956,10 +2052,11 @@ static void transfer_redirect(struct ast_sip_session *session, const char *targe
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
}
/*! \brief REFER Callback module, used to attach session data structure to subscription */
static pjsip_module refer_callback_module = {
.name = { "REFER Callback", 14 },
/*! \brief General PJSIP module for chan_pjsip, currently used for REFER subscription data and outgoing request callbacks */
static pjsip_module chan_pjsip_module = {
.name = { "chan_pjsip", 10 },
.id = -1,
.on_tx_request = transport_info_on_tx_request,
};
/*!
@ -1979,7 +2076,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
return;
}
chan = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
chan = pjsip_evsub_get_mod_data(sub, chan_pjsip_module.id);
if (!chan) {
return;
}
@ -2007,7 +2104,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
/* Since no subscription is desired, assume that call has been transferred successfully. */
/* Channel reference will be released at end of function */
/* Terminate subscription. */
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
pjsip_evsub_set_mod_data(sub, chan_pjsip_module.id, NULL);
pjsip_evsub_terminate(sub, PJ_TRUE);
res = -1;
}
@ -2071,7 +2168,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
}
}
/* Finished. Remove session from subscription */
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
pjsip_evsub_set_mod_data(sub, chan_pjsip_module.id, NULL);
ast_debug(3, "Transfer channel %s completed: %d %.*s (%s)\n",
ast_channel_name(chan),
status_line.code,
@ -2107,10 +2204,10 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
return;
}
/* refer_callback_module requires a reference to chan
/* chan_pjsip_module requires a reference to chan
* which will be released in xfer_client_on_evsub_state()
* when the implicit REFER subscription terminates */
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, chan);
pjsip_evsub_set_mod_data(sub, chan_pjsip_module.id, chan);
ao2_ref(chan, +1);
if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
@ -2132,7 +2229,7 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
failure:
message = AST_TRANSFER_FAILED;
ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message));
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
pjsip_evsub_set_mod_data(sub, chan_pjsip_module.id, NULL);
pjsip_evsub_terminate(sub, PJ_FALSE);
ao2_ref(chan, -1);
@ -3493,7 +3590,7 @@ static int load_module(void)
ast_manager_register_xml(app_pjsip_hangup, EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, pjsip_action_hangup);
ast_sip_register_service(&refer_callback_module);
ast_sip_register_service(&chan_pjsip_module);
ast_sip_session_register_supplement(&chan_pjsip_supplement);
ast_sip_session_register_supplement(&chan_pjsip_supplement_response);
@ -3533,7 +3630,7 @@ end:
ast_sip_session_unregister_supplement(&chan_pjsip_supplement_response);
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
ast_sip_session_unregister_supplement(&call_pickup_supplement);
ast_sip_unregister_service(&refer_callback_module);
ast_sip_unregister_service(&chan_pjsip_module);
ast_custom_function_unregister(&dtmf_mode_function);
ast_custom_function_unregister(&moh_passthrough_function);
ast_custom_function_unregister(&media_offer_function);
@ -3566,7 +3663,7 @@ static int unload_module(void)
ast_sip_session_unregister_supplement(&chan_pjsip_prack_supplement);
ast_sip_session_unregister_supplement(&call_pickup_supplement);
ast_sip_unregister_service(&refer_callback_module);
ast_sip_unregister_service(&chan_pjsip_module);
ast_custom_function_unregister(&dtmf_mode_function);
ast_custom_function_unregister(&moh_passthrough_function);

Loading…
Cancel
Save