summaryrefslogtreecommitdiff
path: root/res/res_pjsip.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_pjsip.c')
-rw-r--r--res/res_pjsip.c173
1 files changed, 128 insertions, 45 deletions
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 54a0a5f39..7b10f47f6 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -944,6 +944,16 @@
to the receiving one.
</para></description>
</configOption>
+ <configOption name="rtcp_mux" default="no">
+ <synopsis>Enable RFC 5761 RTCP multiplexing on the RTP port</synopsis>
+ <description><para>
+ With this option enabled, Asterisk will attempt to negotiate the use of the "rtcp-mux"
+ attribute on all media streams. This will result in RTP and RTCP being sent and received
+ on the same port. This shifts the demultiplexing logic to the application rather than
+ the transport layer. This option is useful when interoperating with WebRTC endpoints
+ since they mandate this option's use.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
@@ -1177,6 +1187,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>
@@ -2750,12 +2776,59 @@ 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;
pjsip_sip_uri *sip_uri;
- pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
+ pjsip_transport_type_e type;
int local_port;
char default_user[PJSIP_MAX_URL_SIZE];
@@ -2775,21 +2848,21 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u
sip_uri = pjsip_uri_get_uri(uri);
/* Determine the transport type to use */
+ type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
- type = PJSIP_TRANSPORT_TLS;
+ if (type == PJSIP_TRANSPORT_UNSPECIFIED
+ || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
+ type = PJSIP_TRANSPORT_TLS;
+ }
} else if (!sip_uri->transport_param.slen) {
type = PJSIP_TRANSPORT_UDP;
- } else {
- type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
- }
-
- if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
+ } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
return -1;
}
/* If the host is IPv6 turn the transport into an IPv6 version */
- if (pj_strchr(&sip_uri->host, ':') && type < PJSIP_TRANSPORT_START_OTHER) {
- type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ if (pj_strchr(&sip_uri->host, ':')) {
+ type |= PJSIP_TRANSPORT_IPV6;
}
if (!ast_strlen_zero(domain)) {
@@ -2813,8 +2886,8 @@ static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *u
}
/* If IPv6 was specified in the transport, set the proper type */
- if (pj_strchr(&local_addr, ':') && type < PJSIP_TRANSPORT_START_OTHER) {
- type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ if (pj_strchr(&local_addr, ':')) {
+ type |= PJSIP_TRANSPORT_IPV6;
}
from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
@@ -2880,15 +2953,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)
@@ -2896,8 +2970,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;
@@ -2930,7 +3004,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;
@@ -2955,12 +3030,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;
}
@@ -2996,11 +3072,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 };
@@ -3069,10 +3140,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;
}
@@ -3118,8 +3192,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;
@@ -3143,6 +3217,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;
@@ -3154,6 +3238,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} };
@@ -3235,14 +3326,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) {
@@ -3260,6 +3343,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)) {
@@ -3279,6 +3364,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;
@@ -3320,6 +3407,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;
@@ -3584,7 +3673,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. */
@@ -3609,11 +3697,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 };