Merge "res_pjsip: Symmetric transports"

changes/38/5238/1
Joshua Colp 8 years ago committed by Gerrit Code Review
commit 732367e806

@ -118,6 +118,22 @@ app_voicemail
* Added 'fromstring' field to the voicemail boxes. If set, it will override
the global 'fromstring' field on a per-mailbox basis.
res_pjsip
------------------
* A new transport parameter 'symmetric_transport' has been added.
When a request from a dynamic contact comes in on a transport with this
option set to 'yes', the transport name will be saved and used for
subsequent outgoing requests like OPTIONS, NOTIFY and INVITE. It's
saved as a contact uri parameter named 'x-ast-txp' and will display with
the contact uri in CLI, AMI, and ARI output. On the outgoing request,
if a transport wasn't explicitly set on the endpoint AND the request URI
is not a hostname, the saved transport will be used and the 'x-ast-txp'
parameter stripped from the outgoing packet. To facilitate recreation of
subscriptions on asterisk restart, a new column 'contact_uri' needed to be
added to the ps_subcsription_persistence table. Since new columns were
added to both transport and subscription_persistence, an alembic upgrade
should be run to bring the database tables up to date.
res_pjsip_transport_websocket
------------------
* Removed non-secure websocket support. Firefox and Chrome have not allowed

@ -853,6 +853,17 @@
; this option is set to 'no' (the default) changes to the
; particular transport will be ignored. If set to 'yes',
; changes (if any) will be applied.
;symmetric_transport=no ; When a request from a dynamic contact comes in on a
; transport with this option set to 'yes', the transport
; name will be saved and used for subsequent outgoing
; requests like OPTIONS, NOTIFY and INVITE. It's saved
; as a contact uri parameter named 'x-ast-txp' and will
; display with the contact uri in CLI, AMI, and ARI
; output. On the outgoing request, if a transport
; wasn't explicitly set on the endpoint AND the request
; URI is not a hostname, the saved transport will be
; used and the 'x-ast-txp' parameter stripped from the
; outgoing packet.
;==========================AOR SECTION OPTIONS=========================
;[aor]

@ -12,6 +12,7 @@ down_revision = '465e70e8c337'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
YESNO_NAME = 'yesno_values'
YESNO_VALUES = ['yes', 'no']

@ -0,0 +1,32 @@
"""symmetric_transport
Revision ID: f638dbe2eb23
Revises: 15db7b91a97a
Create Date: 2017-03-09 09:38:59.513479
"""
# revision identifiers, used by Alembic.
revision = 'f638dbe2eb23'
down_revision = '15db7b91a97a'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
YESNO_NAME = 'yesno_values'
YESNO_VALUES = ['yes', 'no']
def upgrade():
############################# Enums ##############################
# yesno_values have already been created, so use postgres enum object
# type to get around "already created" issue - works okay with mysql
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
op.add_column('ps_transports', sa.Column('symmetric_transport', yesno_values))
op.add_column('ps_subscription_persistence', sa.Column('contact_uri', sa.String(256)))
def downgrade():
op.drop_column('ps_subscription_persistence', 'contact_uri')
op.drop_column('ps_transports', 'symmetric_transport')

@ -194,6 +194,8 @@ struct ast_sip_transport {
int write_timeout;
/*! Allow reload */
int allow_reload;
/*! Automatically send requests out the same transport requests have come in on */
int symmetric_transport;
};
#define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias"
@ -765,6 +767,10 @@ struct ast_sip_endpoint {
unsigned int asymmetric_rtp_codec;
};
/*! URI parameter for symmetric transport */
#define AST_SIP_X_AST_TXP "x-ast-txp"
#define AST_SIP_X_AST_TXP_LEN 9
/*!
* \brief Initialize an auth vector with the configured values.
*
@ -1657,6 +1663,26 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
*/
pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status);
/*!
* \brief General purpose method for creating an rdata structure using specific information
* \since 13.15.0
*
* \param rdata[out] The rdata structure that will be populated
* \param packet A SIP message
* \param src_name The source IP address of the message
* \param src_port The source port of the message
* \param transport_type The type of transport the message was received on
* \param local_name The local IP address the message was received on
* \param local_port The local port the message was received on
* \param contact_uri The contact URI of the message
*
* \retval 0 success
* \retval -1 failure
*/
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet,
const char *src_name, int src_port, char *transport_type, const char *local_name,
int local_port, const char *contact_uri);
/*!
* \brief General purpose method for creating an rdata structure using specific information
*
@ -1671,8 +1697,8 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint,
* \retval 0 success
* \retval -1 failure
*/
int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type,
const char *local_name, int local_port);
int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name,
int src_port, char *transport_type, const char *local_name, int local_port);
/*!
* \brief General purpose method for creating a SIP request
@ -2709,4 +2735,54 @@ void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr,
void ast_sip_get_unidentified_request_thresholds(unsigned int *count, unsigned int *period,
unsigned int *prune_interval);
/*!
* \brief Get the transport name from an endpoint or request uri
* \since 13.15.0
*
* \param endpoint
* \param sip_uri
* \param buf Buffer to receive transport name
* \param buf_len Buffer length
*
* \retval 0 Success
* \retval -1 Failure
*
* \note
* If endpoint->transport is not NULL, it is returned in buf.
* Otherwise if sip_uri has an 'x-ast-txp' parameter AND the sip_uri host is
* an ip4 or ip6 address, its value is returned,
*/
int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint,
pjsip_sip_uri *sip_uri, char *buf, size_t buf_len);
/*!
* \brief Sets pjsip_tpselector from an endpoint or uri
* \since 13.15.0
*
* \param endpoint If endpoint->transport is set, it's used
* \param sip_uri If sip_uri contains a x-ast-txp parameter, it's used
* \param selector The selector to be populated
*
* \retval 0 success
* \retval -1 failure
*/
int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoint,
pjsip_sip_uri *sip_uri, pjsip_tpselector *selector);
/*!
* \brief Set the transport on a dialog
* \since 13.15.0
*
* \param endpoint
* \param dlg
* \param selector (optional)
*
* \note
* This API calls ast_sip_get_transport_name(endpoint, dlg->target) and if the result is
* non-NULL, calls pjsip_dlg_set_transport. If 'selector' is non-NULL, it is updated with
* the selector used.
*/
int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg,
pjsip_tpselector *selector);
#endif /* _RES_PJSIP_H */

@ -1193,6 +1193,22 @@
in-progress calls.</para>
</description>
</configOption>
<configOption name="symmetric_transport" default="no">
<synopsis>Use the same transport for outgoing reqests as incoming ones.</synopsis>
<description>
<para>When a request from a dynamic contact
comes in on a transport with this option set to 'yes',
the transport name will be saved and used for subsequent
outgoing requests like OPTIONS, NOTIFY and INVITE. It's
saved as a contact uri parameter named 'x-ast-txp' and will
display with the contact uri in CLI, AMI, and ARI output.
On the outgoing request, if a transport wasn't explicitly
set on the endpoint AND the request URI is not a hostname,
the saved transport will be used and the 'x-ast-txp'
parameter stripped from the outgoing packet.
</para>
</description>
</configOption>
</configObject>
<configObject name="contact">
<synopsis>A way of creating an aliased name to a SIP URI</synopsis>
@ -2762,7 +2778,54 @@ pjsip_endpoint *ast_sip_get_pjsip_endpoint(void)
return ast_pjsip_endpoint;
}
static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const char *domain, const pj_str_t *target, pjsip_tpselector *selector)
int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint,
pjsip_sip_uri *sip_uri, char *buf, size_t buf_len)
{
char *host = NULL;
static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN };
pjsip_param *x_transport;
if (!ast_strlen_zero(endpoint->transport)) {
ast_copy_string(buf, endpoint->transport, buf_len);
return 0;
}
x_transport = pjsip_param_find(&sip_uri->other_param, &x_name);
if (!x_transport) {
return -1;
}
/* Only use x_transport if the uri host is an ip (4 or 6) address */
host = ast_alloca(sip_uri->host.slen + 1);
ast_copy_pj_str(host, &sip_uri->host, sip_uri->host.slen + 1);
if (!ast_sockaddr_parse(NULL, host, PARSE_PORT_FORBID)) {
return -1;
}
ast_copy_pj_str(buf, &x_transport->value, buf_len);
return 0;
}
int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg,
pjsip_tpselector *selector)
{
pjsip_sip_uri *uri;
pjsip_tpselector sel = { .type = PJSIP_TPSELECTOR_NONE, };
uri = pjsip_uri_get_uri(dlg->target);
if (!selector) {
selector = &sel;
}
ast_sip_set_tpselector_from_ep_or_uri(endpoint, uri, selector);
pjsip_dlg_set_transport(dlg, selector);
return 0;
}
static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user,
const char *domain, const pj_str_t *target, pjsip_tpselector *selector)
{
pj_str_t tmp, local_addr;
pjsip_uri *uri;
@ -2892,15 +2955,16 @@ int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip
return ast_sip_set_tpselector_from_transport(transport, selector);
}
static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector)
int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoint,
pjsip_sip_uri *sip_uri, pjsip_tpselector *selector)
{
const char *transport_name = endpoint->transport;
char transport_name[128];
if (ast_strlen_zero(transport_name)) {
if (ast_sip_get_transport_name(endpoint, sip_uri, transport_name, sizeof(transport_name))) {
return 0;
}
return ast_sip_set_tpselector_from_transport_name(endpoint->transport, selector);
return ast_sip_set_tpselector_from_transport_name(transport_name, selector);
}
void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri)
@ -2908,8 +2972,8 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t
pjsip_sip_uri *sip_uri;
int i = 0;
pjsip_param *param;
const pj_str_t STR_USER = { "user", 4 };
const pj_str_t STR_PHONE = { "phone", 5 };
static const pj_str_t STR_USER = { "user", 4 };
static const pj_str_t STR_PHONE = { "phone", 5 };
if (!endpoint || !endpoint->usereqphone || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
return;
@ -2942,7 +3006,8 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t
pj_list_insert_before(&sip_uri->other_param, param);
}
pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user)
pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
const char *uri, const char *request_user)
{
char enclosed_uri[PJSIP_MAX_URL_SIZE];
pj_str_t local_uri = { "sip:temp@temp", 13 }, remote_uri, target_uri;
@ -2967,12 +3032,13 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
return NULL;
}
if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
pjsip_dlg_terminate(dlg);
return NULL;
}
/* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */
dlg->sess_count++;
ast_sip_dlg_set_transport(endpoint, dlg, &selector);
if (sip_dialog_create_from(dlg->pool, &local_uri, endpoint->fromuser, endpoint->fromdomain, &remote_uri, &selector)) {
dlg->sess_count--;
pjsip_dlg_terminate(dlg);
return NULL;
}
@ -3008,11 +3074,6 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
ast_sip_add_usereqphone(endpoint, dlg->pool, dlg->target);
ast_sip_add_usereqphone(endpoint, dlg->pool, dlg->remote.info->uri);
/* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */
dlg->sess_count++;
pjsip_dlg_set_transport(dlg, &selector);
if (!ast_strlen_zero(outbound_proxy)) {
pjsip_route_hdr route_set, *route;
static const pj_str_t ROUTE_HNAME = { "Route", 5 };
@ -3081,10 +3142,13 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint,
pjsip_transport_type_e type = rdata->tp_info.transport->key.type;
pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
pjsip_transport *transport;
pjsip_contact_hdr *contact_hdr;
ast_assert(status != NULL);
if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
if (ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(contact_hdr->uri),
&selector)) {
return NULL;
}
@ -3130,8 +3194,8 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint,
return dlg;
}
int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
char *transport_type, const char *local_name, int local_port)
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
char *transport_type, const char *local_name, int local_port, const char *contact)
{
pj_str_t tmp;
@ -3155,6 +3219,16 @@ int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_nam
return -1;
}
if (!ast_strlen_zero(contact)) {
pjsip_contact_hdr *contact_hdr;
contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
if (contact_hdr) {
contact_hdr->uri = pjsip_parse_uri(rdata->tp_info.pool, (char *)contact,
strlen(contact), PJSIP_PARSE_URI_AS_NAMEADDR);
}
}
pj_strdup2(rdata->tp_info.pool, &rdata->msg_info.via->recvd_param, rdata->pkt_info.src_name);
rdata->msg_info.via->rport_param = -1;
@ -3166,6 +3240,13 @@ int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_nam
return 0;
}
int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
char *transport_type, const char *local_name, int local_port)
{
return ast_sip_create_rdata_with_contact(rdata, packet, src_name, src_port, transport_type,
local_name, local_port, NULL);
}
/* PJSIP doesn't know about the INFO method, so we have to define it ourselves */
static const pjsip_method info_method = {PJSIP_OTHER_METHOD, {"INFO", 4} };
static const pjsip_method message_method = {PJSIP_OTHER_METHOD, {"MESSAGE", 7} };
@ -3247,14 +3328,6 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
pj_cstr(&remote_uri, uri);
}
if (endpoint) {
if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport selector for endpoint %s\n",
ast_sorcery_object_get_id(endpoint));
return -1;
}
}
pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound request", 256, 256);
if (!pool) {
@ -3272,6 +3345,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
return -1;
}
ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(sip_uri), &selector);
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)) {
@ -3291,6 +3366,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
return -1;
}
pjsip_tx_data_set_transport(*tdata, &selector);
if (endpoint && !ast_strlen_zero(endpoint->contact_user)){
pjsip_contact_hdr *contact_hdr;
pjsip_sip_uri *contact_uri;
@ -3332,6 +3409,8 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
{
const pjsip_method *pmethod = get_pjsip_method(method);
ast_assert(endpoint != NULL);
if (!pmethod) {
ast_log(LOG_WARNING, "Unknown method '%s'. Cannot send request\n", method);
return -1;
@ -3596,7 +3675,6 @@ 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, };
if (!cb && token) {
/* Silly. Without a callback we cannot do anything with token. */
@ -3621,11 +3699,6 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
/* Add a reference to tdata. The wrapper destructor cleans it up. */
pjsip_tx_data_add_ref(tdata);
if (endpoint) {
sip_get_tpselector_from_endpoint(endpoint, &selector);
pjsip_tx_data_set_transport(tdata, &selector);
}
if (timeout > 0) {
pj_time_val timeout_timer_val = { timeout / 1000, timeout % 1000 };

@ -552,13 +552,20 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
}
}
if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
pj_sock_t sock;
pj_qos_params qos_params;
sock = pjsip_udp_transport_get_socket(temp_state->state->transport);
pj_sock_get_qos_params(sock, &qos_params);
set_qos(transport, &qos_params);
pj_sock_set_qos_params(sock, &qos_params);
if (res == PJ_SUCCESS) {
temp_state->state->transport->info = pj_pool_alloc(temp_state->state->transport->pool,
(AST_SIP_X_AST_TXP_LEN + strlen(transport_id) + 2));
sprintf(temp_state->state->transport->info, "%s:%s", AST_SIP_X_AST_TXP, transport_id);
if (transport->tos || transport->cos) {
pj_sock_t sock;
pj_qos_params qos_params;
sock = pjsip_udp_transport_get_socket(temp_state->state->transport);
pj_sock_get_qos_params(sock, &qos_params);
set_qos(transport, &qos_params);
pj_sock_set_qos_params(sock, &qos_params);
}
}
} else if (transport->type == AST_TRANSPORT_TCP) {
pjsip_tcp_transport_cfg cfg;
@ -1375,6 +1382,7 @@ int ast_sip_initialize_sorcery_transport(void)
ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
ast_sorcery_object_field_register(sorcery, "transport", "websocket_write_timeout", AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, write_timeout), 1, INT_MAX);
ast_sorcery_object_field_register(sorcery, "transport", "allow_reload", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, allow_reload));
ast_sorcery_object_field_register(sorcery, "transport", "symmetric_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, symmetric_transport));
internal_sip_register_endpoint_formatter(&endpoint_transport_formatter);

@ -28,6 +28,7 @@
#define MOD_DATA_RESTRICTIONS "restrictions"
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata);
static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata);
/*! \brief Outgoing message modification restrictions */
struct multihomed_message_restrictions {
@ -41,6 +42,7 @@ static pjsip_module multihomed_module = {
.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
.on_tx_request = multihomed_on_tx_message,
.on_tx_response = multihomed_on_tx_message,
.on_rx_request = multihomed_on_rx_message,
};
/*! \brief Helper function to get (or allocate if not already present) restrictions on a message */
@ -151,6 +153,44 @@ static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
return 0;
}
static void sanitize_tdata(pjsip_tx_data *tdata)
{
static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN };
pjsip_param *x_transport;
pjsip_sip_uri *uri;
pjsip_fromto_hdr *fromto;
pjsip_contact_hdr *contact;
pjsip_hdr *hdr;
if (tdata->msg->type == PJSIP_REQUEST_MSG) {
uri = pjsip_uri_get_uri(tdata->msg->line.req.uri);
x_transport = pjsip_param_find(&uri->other_param, &x_name);
if (x_transport) {
pj_list_erase(x_transport);
}
}
for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) {
if (hdr->type == PJSIP_H_TO || hdr->type == PJSIP_H_FROM) {
fromto = (pjsip_fromto_hdr *) hdr;
uri = pjsip_uri_get_uri(fromto->uri);
x_transport = pjsip_param_find(&uri->other_param, &x_name);
if (x_transport) {
pj_list_erase(x_transport);
}
} else if (hdr->type == PJSIP_H_CONTACT) {
contact = (pjsip_contact_hdr *) hdr;
uri = pjsip_uri_get_uri(contact->uri);
x_transport = pjsip_param_find(&uri->other_param, &x_name);
if (x_transport) {
pj_list_erase(x_transport);
}
}
}
pjsip_tx_data_invalidate_msg(tdata);
}
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
{
struct multihomed_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS);
@ -159,6 +199,8 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
pjsip_via_hdr *via;
pjsip_fromto_hdr *from;
sanitize_tdata(tdata);
/* Use the destination information to determine what local interface this message will go out on */
pjsip_tpmgr_fla2_param_default(&prm);
prm.tp_type = tdata->tp_info.transport->key.type;
@ -273,6 +315,47 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
return PJ_SUCCESS;
}
static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata)
{
pjsip_contact_hdr *contact;
pjsip_sip_uri *uri;
const char *transport_id;
struct ast_sip_transport *transport;
pjsip_param *x_transport;
if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) {
return PJ_FALSE;
}
contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
if (!(contact && contact->uri
&& ast_begins_with(rdata->tp_info.transport->info, AST_SIP_X_AST_TXP ":"))) {
return PJ_FALSE;
}
uri = pjsip_uri_get_uri(contact->uri);
transport_id = rdata->tp_info.transport->info + AST_SIP_X_AST_TXP_LEN + 1;
transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_id);
if (!(transport && transport->symmetric_transport)) {
return PJ_FALSE;
}
x_transport = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param);
x_transport->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_TXP);
x_transport->value = pj_strdup3(rdata->tp_info.pool, transport_id);
pj_list_insert_before(&uri->other_param, x_transport);
ast_debug(1, "Set transport '%s' on %.*s from %.*s:%d\n", transport_id,
(int)rdata->msg_info.msg->line.req.method.name.slen,
rdata->msg_info.msg->line.req.method.name.ptr,
(int)uri->host.slen, uri->host.ptr, uri->port);
return PJ_FALSE;
}
void ast_res_pjsip_cleanup_message_ip_updater(void)
{
ast_sip_unregister_service(&multihomed_module);

@ -123,6 +123,9 @@
<configOption name="expires">
<synopsis>The time at which the subscription expires</synopsis>
</configOption>
<configOption name="contact_uri">
<synopsis>The Contact URI of the dialog for the subscription</synopsis>
</configOption>
</configObject>
<configObject name="resource_list">
<synopsis>Resource list configuration parameters.</synopsis>
@ -376,6 +379,8 @@ struct subscription_persistence {
char *tag;
/*! When this subscription expires */
struct timeval expires;
/*! Contact URI */
char contact_uri[PJSIP_MAX_URL_SIZE];
};
/*!
@ -591,8 +596,8 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr
return;
}
ast_debug(3, "Updating persistence for '%s->%s'\n",
ast_sorcery_object_get_id(sub_tree->endpoint), sub_tree->root->resource);
ast_debug(3, "Updating persistence for '%s->%s'\n", sub_tree->persistence->endpoint,
sub_tree->root->resource);
dlg = sub_tree->dlg;
sub_tree->persistence->cseq = dlg->local.cseq;
@ -600,10 +605,14 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr
if (rdata) {
int expires;
pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
/* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
* message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
* will always point to the proper SIP message that is to be processed. When updating subscription
@ -1550,8 +1559,9 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags)
pj_pool_reset(pool);
rdata.tp_info.pool = pool;
if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port,
persistence->transport_key, persistence->local_name, persistence->local_port)) {
if (ast_sip_create_rdata_with_contact(&rdata, persistence->packet, persistence->src_name,
persistence->src_port, persistence->transport_key, persistence->local_name,
persistence->local_port, persistence->contact_uri)) {
ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
persistence->endpoint);
ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
@ -1703,28 +1713,6 @@ void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, co
return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
}
/*!
* \internal
* \brief Wrapper for pjsip_evsub_send_request
*
* This function (re)sets the transport before sending to catch cases
* where the transport might have changed.
*
* If pjproject gives us the ability to resend, we'll only reset the transport
* if PJSIP_ETPNOTAVAIL is returned from send.
*
* \returns pj_status_t
*/
static pj_status_t internal_pjsip_evsub_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
{
pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
ast_sip_set_tpselector_from_transport_name(sub_tree->endpoint->transport, &selector);
pjsip_dlg_set_transport(sub_tree->dlg, &selector);
return pjsip_evsub_send_request(sub_tree->evsub, tdata);
}
/* XXX This function is not used. */
struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
struct ast_sip_endpoint *endpoint, const char *resource)
@ -1772,7 +1760,7 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su
evsub = sub_tree->evsub;
if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
internal_pjsip_evsub_send_request(sub_tree, tdata);
pjsip_evsub_send_request(sub_tree->evsub, tdata);
} else {
/* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
* being called and terminating the subscription. Therefore, we don't
@ -1869,7 +1857,7 @@ static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree,
return -1;
}
res = internal_pjsip_evsub_send_request(sub_tree, tdata);
res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
subscription_persistence_update(sub_tree, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST);
@ -5283,6 +5271,8 @@ static int load_module(void)
persistence_tag_str2struct, persistence_tag_struct2str, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
CHARFLDSET(struct subscription_persistence, contact_uri));
if (apply_list_configuration(sorcery)) {
ast_sip_unregister_service(&pubsub_module);

@ -973,32 +973,10 @@ int ast_sip_session_refresh(struct ast_sip_session *session,
return 0;
}
/*!
* \internal
* \brief Wrapper for pjsip_inv_send_msg
*
* This function (re)sets the transport before sending to catch cases
* where the transport might have changed.
*
* If pjproject gives us the ability to resend, we'll only reset the transport
* if PJSIP_ETPNOTAVAIL is returned from send.
*
* \returns pj_status_t
*/
static pj_status_t internal_pjsip_inv_send_msg(pjsip_inv_session *inv, const char *transport_name, pjsip_tx_data *tdata)
{
pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
ast_sip_set_tpselector_from_transport_name(transport_name, &selector);
pjsip_dlg_set_transport(inv->dlg, &selector);
return pjsip_inv_send_msg(inv, tdata);
}
void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
{
handle_outgoing_response(session, tdata);
internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata);
pjsip_inv_send_msg(session->inv_session, tdata);
return;
}
@ -1229,7 +1207,7 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip
MOD_DATA_ON_RESPONSE, on_response);
handle_outgoing_request(session, tdata);
internal_pjsip_inv_send_msg(session->inv_session, session->endpoint->transport, tdata);
pjsip_inv_send_msg(session->inv_session, tdata);
return;
}
@ -2051,7 +2029,7 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
}
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
pjsip_inv_send_msg(inv_session, tdata);
return NULL;
}
return inv_session;
@ -2222,7 +2200,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
} else {
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
pjsip_inv_send_msg(inv_session, tdata);
}
}
return;
@ -2234,7 +2212,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
} else {
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
pjsip_inv_send_msg(inv_session, tdata);
}
#ifdef HAVE_PJSIP_INV_SESSION_REF
pjsip_inv_dec_ref(inv_session);
@ -2247,7 +2225,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
} else {
internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
pjsip_inv_send_msg(inv_session, tdata);
}
#ifdef HAVE_PJSIP_INV_SESSION_REF
pjsip_inv_dec_ref(inv_session);

Loading…
Cancel
Save