[asterisk-commits] file: branch file/pimp_sip_nat r382482 - in /team/file/pimp_sip_nat: include/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 6 06:03:34 CST 2013
Author: file
Date: Wed Mar 6 06:03:29 2013
New Revision: 382482
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382482
Log:
Incorporate review feedback.
Modified:
team/file/pimp_sip_nat/include/asterisk/res_sip.h
team/file/pimp_sip_nat/include/asterisk/res_sip_session.h
team/file/pimp_sip_nat/res/res_sip/config_transport.c
team/file/pimp_sip_nat/res/res_sip/sip_configuration.c
team/file/pimp_sip_nat/res/res_sip/sip_distributor.c
team/file/pimp_sip_nat/res/res_sip_nat.c
team/file/pimp_sip_nat/res/res_sip_sdp_audio.c
team/file/pimp_sip_nat/res/res_sip_session.c
Modified: team/file/pimp_sip_nat/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/include/asterisk/res_sip.h?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/include/asterisk/res_sip.h (original)
+++ team/file/pimp_sip_nat/include/asterisk/res_sip.h Wed Mar 6 06:03:29 2013
@@ -118,6 +118,16 @@
struct ast_sockaddr external_address;
/*! Transport state information */
struct ast_sip_transport_state *state;
+};
+
+/*!
+ * \brief Structure for SIP nat hook information
+ */
+struct ast_sip_nat_hook {
+ /*! Sorcery object details */
+ SORCERY_OBJECT(details);
+ /*! Callback for when a message is going outside of our local network */
+ void (*outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport);
};
/*!
Modified: team/file/pimp_sip_nat/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/include/asterisk/res_sip_session.h?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/include/asterisk/res_sip_session.h (original)
+++ team/file/pimp_sip_nat/include/asterisk/res_sip_session.h Wed Mar 6 06:03:29 2013
@@ -25,6 +25,7 @@
/* Forward declarations */
struct ast_sip_endpoint;
+struct ast_sip_transport;
struct pjsip_inv_session;
struct ast_channel;
struct ast_datastore;
@@ -192,6 +193,13 @@
*/
int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct pjmedia_sdp_session *sdp);
/*!
+ * \brief Update media stream with external address if applicable
+ * \param tdata The outgoing message itself
+ * \param stream The stream on which to operate
+ * \param transport The transport the SDP is going out on
+ */
+ void (*change_outgoing_sdp_stream)(struct pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport);
+ /*!
* \brief Apply a negotiated SDP media stream
* \param session The session for which media is being applied
* \param local The entire local negotiated SDP
Modified: team/file/pimp_sip_nat/res/res_sip/config_transport.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip/config_transport.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip/config_transport.c (original)
+++ team/file/pimp_sip_nat/res/res_sip/config_transport.c Wed Mar 6 06:03:29 2013
@@ -258,14 +258,11 @@
static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
struct ast_sip_transport *transport = obj;
- struct ast_ha *ha;
int error = 0;
- if (!(ha = ast_append_ha("d", var->value, transport->localnet, &error))) {
- return -1;
- }
-
- transport->localnet = ha;
+ if (!(transport->localnet = ast_append_ha("d", var->value, transport->localnet, &error))) {
+ return -1;
+ }
return error;
}
@@ -288,7 +285,7 @@
ast_sorcery_object_field_register(sorcery, "transport", "privkey_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file));
ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
- ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, external_signaling_port));
+ ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, NULL, 0, 0);
Modified: team/file/pimp_sip_nat/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip/sip_configuration.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip/sip_configuration.c (original)
+++ team/file/pimp_sip_nat/res/res_sip/sip_configuration.c Wed Mar 6 06:03:29 2013
@@ -106,6 +106,11 @@
static void *sip_endpoint_to_location_alloc(const char *name)
{
return ao2_alloc(sizeof(struct sip_endpoint_to_location), sip_endpoint_to_location_destroy);
+}
+
+static void *sip_nat_hook_alloc(const char *name)
+{
+ return ao2_alloc(sizeof(struct ast_sip_nat_hook), NULL);
}
static int host_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
@@ -279,6 +284,8 @@
ast_sorcery_apply_default(sip_sorcery, "location_to_endpoint", "memory", NULL);
ast_sorcery_apply_default(sip_sorcery, "endpoint_to_location", "memory", NULL);
+ ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
+
if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, NULL)) {
ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
ast_sorcery_unref(sip_sorcery);
@@ -288,6 +295,8 @@
ast_sorcery_object_register(sip_sorcery, "location_to_endpoint", sip_location_to_endpoint_alloc, NULL, NULL);
ast_sorcery_object_register(sip_sorcery, "endpoint_to_location", sip_endpoint_to_location_alloc, NULL, NULL);
+
+ ast_sorcery_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
Modified: team/file/pimp_sip_nat/res/res_sip/sip_distributor.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip/sip_distributor.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip/sip_distributor.c (original)
+++ team/file/pimp_sip_nat/res/res_sip/sip_distributor.c Wed Mar 6 06:03:29 2013
@@ -35,7 +35,7 @@
static pjsip_module distributor_mod = {
.name = {"Request Distributor", 19},
- .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 20,
.on_rx_request = distributor,
.on_rx_response = distributor,
};
@@ -44,7 +44,7 @@
static pjsip_module endpoint_mod = {
.name = {"Endpoint Identifier", 19},
- .priority = PJSIP_MOD_PRIORITY_APPLICATION - 2,
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 10,
.on_rx_request = endpoint_lookup,
};
Modified: team/file/pimp_sip_nat/res/res_sip_nat.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip_nat.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip_nat.c (original)
+++ team/file/pimp_sip_nat/res/res_sip_nat.c Wed Mar 6 06:03:29 2013
@@ -33,7 +33,7 @@
static pj_bool_t nat_on_rx_request(pjsip_rx_data *rdata)
{
- RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sip_identify_endpoint(rdata), ao2_cleanup);
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
pjsip_contact_hdr *contact;
if (!endpoint) {
@@ -101,6 +101,27 @@
return pjsip_uri_get_uri(contact->uri);
}
+/*! \brief Structure which contains hook details */
+struct nat_hook_details {
+ /*! \brief Outgoing message itself */
+ pjsip_tx_data *tdata;
+ /*! \brief Chosen transport */
+ struct ast_sip_transport *transport;
+};
+
+/*! \brief Callback function for invoking hooks */
+static int nat_invoke_hook(void *obj, void *arg, int flags)
+{
+ struct ast_sip_nat_hook *hook = obj;
+ struct nat_hook_details *details = arg;
+
+ if (hook->outgoing_external_message) {
+ hook->outgoing_external_message(details->tdata, details->transport);
+ }
+
+ return 0;
+}
+
static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
{
RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
@@ -109,6 +130,7 @@
pjsip_via_hdr *via = NULL;
struct ast_sockaddr addr = { { 0, } };
pjsip_sip_uri *uri = NULL;
+ RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
/* If a transport selector is in use we know the transport or factory, so explicitly find it */
if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
@@ -175,19 +197,13 @@
}
}
- /* Update the SDP if relevant */
- if (tdata->msg->body && !pj_strcmp2(&tdata->msg->body->content_type.type, "application") &&
- !pj_strcmp2(&tdata->msg->body->content_type.subtype, "sdp") && !ast_strlen_zero(transport->external_media_address)) {
- struct pjmedia_sdp_session *sdp = tdata->msg->body->data;
- int stream;
-
- if (sdp->conn) {
- pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address);
- }
-
- for (stream = 0; stream < sdp->media_count; ++stream) {
- pj_strdup2(tdata->pool, &sdp->media[stream]->conn->addr, transport->external_media_address);
- }
+ /* Invoke any additional hooks that may be registered */
+ if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
+ struct nat_hook_details hook_details = {
+ .tdata = tdata,
+ .transport = transport,
+ };
+ ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
}
return PJ_SUCCESS;
@@ -196,7 +212,7 @@
static pjsip_module nat_module = {
.name = { "NAT", 3 },
.id = -1,
- .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER + 4,
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 5,
.on_rx_request = nat_on_rx_request,
.on_tx_request = nat_on_tx_message,
.on_tx_response = nat_on_tx_message,
Modified: team/file/pimp_sip_nat/res/res_sip_sdp_audio.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip_sdp_audio.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip_sdp_audio.c (original)
+++ team/file/pimp_sip_nat/res/res_sip_sdp_audio.c Wed Mar 6 06:03:29 2013
@@ -46,18 +46,26 @@
#include "asterisk/channel.h"
#include "asterisk/causes.h"
#include "asterisk/sched.h"
+#include "asterisk/acl.h"
#include "asterisk/res_sip.h"
#include "asterisk/res_sip_session.h"
/*! \brief Scheduler for RTCP purposes */
static struct ast_sched_context *sched;
+
+/*! \brief Address for IPv4 RTP */
+static struct ast_sockaddr address_ipv4;
+
+/*! \brief Address for IPv6 RTP */
+static struct ast_sockaddr address_ipv6;
/*! \brief Forward declarations for SDP handler functions */
static int audio_negotiate_incoming_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
static int audio_create_outgoing_sdp_stream(struct ast_sip_session *session, struct pjmedia_sdp_session *sdp);
static int audio_apply_negotiated_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream);
+static void audio_change_outgoing_sdp_stream(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport);
/*! \brief Forward declaration for session supplement functions */
static void audio_session_destroy(struct ast_sip_session *session);
@@ -68,6 +76,7 @@
.negotiate_incoming_sdp_stream = audio_negotiate_incoming_sdp_stream,
.create_outgoing_sdp_stream = audio_create_outgoing_sdp_stream,
.apply_negotiated_sdp_stream = audio_apply_negotiated_sdp_stream,
+ .change_outgoing_sdp_stream = audio_change_outgoing_sdp_stream,
};
/*! \brief Session supplement for 'audio' media stream */
@@ -78,14 +87,9 @@
/*! \brief Internal function which creates an RTP instance */
static int audio_create_rtp(struct ast_sip_session *session, unsigned int ipv6)
{
- struct ast_sockaddr tmp;
struct ast_rtp_engine_ice *ice;
- if (!ast_sockaddr_parse(&tmp, ipv6 ? "::" : "0.0.0.0", 0)) {
- return -1;
- }
-
- if (!(session->media[AST_SIP_MEDIA_AUDIO].rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
+ if (!(session->media[AST_SIP_MEDIA_AUDIO].rtp = ast_rtp_instance_new("asterisk", sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) {
return -1;
}
@@ -128,6 +132,66 @@
/* pjmedia takes care of the formats and such */
return 1;
+}
+
+/*! \brief Function which adds ICE attributes to an 'audio' stream */
+static void audio_add_ice_to_stream(struct ast_sip_session *session, pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+ struct ast_rtp_engine_ice *ice;
+ struct ao2_container *candidates;
+ const char *username, *password;
+ pj_str_t stmp;
+ pjmedia_sdp_attr *attr;
+ struct ao2_iterator it_candidates;
+ struct ast_rtp_engine_ice_candidate *candidate;
+
+ if (!session->endpoint->ice_support || !(ice = ast_rtp_instance_get_ice(session->media[AST_SIP_MEDIA_AUDIO].rtp)) ||
+ !(candidates = ice->get_local_candidates(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
+ return;
+ }
+
+ if ((username = ice->get_ufrag(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
+ attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
+ media->attr[media->attr_count++] = attr;
+ }
+
+ if ((password = ice->get_password(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
+ attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
+ media->attr[media->attr_count++] = attr;
+ }
+
+ it_candidates = ao2_iterator_init(candidates, 0);
+ for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
+ struct ast_str *attr_candidate = ast_str_create(128);
+
+ ast_str_set(&attr_candidate, -1, "%s %d %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
+ candidate->priority, ast_sockaddr_stringify_host(&candidate->address));
+ ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
+
+ switch (candidate->type) {
+ case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
+ ast_str_append(&attr_candidate, -1, "host");
+ break;
+ case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
+ ast_str_append(&attr_candidate, -1, "srflx");
+ break;
+ case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
+ ast_str_append(&attr_candidate, -1, "relay");
+ break;
+ }
+
+ if (!ast_sockaddr_isnull(&candidate->relay_address)) {
+ ast_str_append(&attr_candidate, -1, " raddr %s rport ", ast_sockaddr_stringify_host(&candidate->relay_address));
+ ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
+ }
+
+ attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
+ media->attr[media->attr_count++] = attr;
+
+ ast_free(attr_candidate);
+ }
+
+ ao2_iterator_destroy(&it_candidates);
}
/*! \brief Function which creates an outgoing 'audio' stream */
@@ -147,8 +211,6 @@
pj_str_t stmp;
pjmedia_sdp_attr *attr;
int index = 0, min_packet_size = 0, noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0;
- struct ast_rtp_engine_ice *ice;
- struct ao2_container *candidates;
if (!ast_format_cap_has_type(session->endpoint->codecs, AST_FORMAT_TYPE_AUDIO)) {
/* If no audio formats are configured don't add a stream */
@@ -186,54 +248,7 @@
media->desc.port_count = 1;
/* Add ICE attributes and candidates */
- if (session->endpoint->ice_support && (ice = ast_rtp_instance_get_ice(session->media[AST_SIP_MEDIA_AUDIO].rtp)) &&
- (candidates = ice->get_local_candidates(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
- const char *username, *password;
- struct ao2_iterator it_candidates;
- struct ast_rtp_engine_ice_candidate *candidate;
-
- if ((username = ice->get_ufrag(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
- attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
- media->attr[media->attr_count++] = attr;
- }
-
- if ((password = ice->get_password(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
- attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
- media->attr[media->attr_count++] = attr;
- }
-
- it_candidates = ao2_iterator_init(candidates, 0);
- for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
- struct ast_str *attr_candidate = ast_str_create(128);
-
- ast_str_set(&attr_candidate, -1, "%s %d %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
- candidate->priority, ast_sockaddr_stringify_host(&candidate->address));
- ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
-
- switch (candidate->type) {
- case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
- ast_str_append(&attr_candidate, -1, "host");
- break;
- case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
- ast_str_append(&attr_candidate, -1, "srflx");
- break;
- case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
- ast_str_append(&attr_candidate, -1, "relay");
- break;
- }
-
- if (!ast_sockaddr_isnull(&candidate->relay_address)) {
- ast_str_append(&attr_candidate, -1, " raddr %s rport ", ast_sockaddr_stringify_host(&candidate->relay_address));
- ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
- }
-
- attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
- media->attr[media->attr_count++] = attr;
-
- ast_free(attr_candidate);
- }
- ao2_iterator_destroy(&it_candidates);
- }
+ audio_add_ice_to_stream(session, pool, media);
/* Add formats */
for (index = 0; (index < AST_CODEC_PREF_SIZE); index++) {
@@ -312,6 +327,84 @@
sdp->media[sdp->media_count++] = media;
return 1;
+}
+
+/*! \brief Function which processes ICE attributes in an audio stream */
+static void audio_process_ice_attributes(struct ast_sip_session *session, const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
+{
+ struct ast_rtp_engine_ice *ice;
+ const pjmedia_sdp_attr *attr;
+ char attr_value[256];
+ unsigned int attr_i;
+
+ /* If ICE support is not enabled or available exit early */
+ if (!session->endpoint->ice_support || !(ice = ast_rtp_instance_get_ice(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
+ return;
+ }
+
+ if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL))) {
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+ ice->set_authentication(session->media[AST_SIP_MEDIA_AUDIO].rtp, attr_value, NULL);
+ }
+
+ if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL))) {
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+ ice->set_authentication(session->media[AST_SIP_MEDIA_AUDIO].rtp, NULL, attr_value);
+ }
+
+ if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
+ ice->ice_lite(session->media[AST_SIP_MEDIA_AUDIO].rtp);
+ }
+
+ /* Find all of the candidates */
+ for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
+ char foundation[32], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = "";
+ int port, relay_port = 0;
+ struct ast_rtp_engine_ice_candidate candidate = { 0, };
+
+ attr = remote_stream->attr[attr_i];
+
+ /* If this is not a candidate line skip it */
+ if (pj_strcmp2(&attr->name, "candidate")) {
+ continue;
+ }
+
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+
+ if (sscanf(attr_value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
+ &candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
+ /* Candidate did not parse properly */
+ continue;
+ }
+
+ candidate.foundation = foundation;
+ candidate.transport = transport;
+
+ ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&candidate.address, port);
+
+ if (!strcasecmp(cand_type, "host")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
+ } else if (!strcasecmp(cand_type, "srflx")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
+ } else if (!strcasecmp(cand_type, "relay")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
+ } else {
+ continue;
+ }
+
+ if (!ast_strlen_zero(relay_address)) {
+ ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
+ }
+
+ if (relay_port) {
+ ast_sockaddr_set_port(&candidate.relay_address, relay_port);
+ }
+
+ ice->add_remote_candidate(session->media[AST_SIP_MEDIA_AUDIO].rtp, &candidate);
+ }
+
+ ice->start(session->media[AST_SIP_MEDIA_AUDIO].rtp);
}
/*! \brief Function which applies a negotiated SDP stream */
@@ -327,7 +420,6 @@
RAII_VAR(struct ast_format_cap *, jointcap, NULL, ast_format_cap_destroy);
RAII_VAR(struct ast_format_cap *, peercap, NULL, ast_format_cap_destroy);
struct ast_format fmt;
- struct ast_rtp_engine_ice *ice;
/* Create an RTP instance if need be */
if (!session->media[AST_SIP_MEDIA_AUDIO].rtp && audio_create_rtp(session, session->endpoint->rtp_ipv6)) {
@@ -435,74 +527,7 @@
ast_channel_set_fd(session->channel, 1, ast_rtp_instance_fd(session->media[AST_SIP_MEDIA_AUDIO].rtp, 1));
/* If ICE support is enabled find all the needed attributes */
- if (session->endpoint->ice_support && (ice = ast_rtp_instance_get_ice(session->media[AST_SIP_MEDIA_AUDIO].rtp))) {
- char attr_value[256];
- unsigned int attr_i;
-
- if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL))) {
- ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
- ice->set_authentication(session->media[AST_SIP_MEDIA_AUDIO].rtp, attr_value, NULL);
- }
-
- if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL))) {
- ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
- ice->set_authentication(session->media[AST_SIP_MEDIA_AUDIO].rtp, NULL, attr_value);
- }
-
- if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
- ice->ice_lite(session->media[AST_SIP_MEDIA_AUDIO].rtp);
- }
-
- /* Find all of the candidates */
- for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
- char foundation[32], transport[4], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[46] = "";
- int port, relay_port = 0;
- struct ast_rtp_engine_ice_candidate candidate = { 0, };
-
- attr = remote_stream->attr[attr_i];
-
- /* If this is not a candidate line skip it */
- if (pj_strcmp2(&attr->name, "candidate")) {
- continue;
- }
-
- ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
-
- if (sscanf(attr_value, "%31s %30u %3s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
- &candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
- /* Candidate did not parse properly */
- continue;
- }
-
- candidate.foundation = foundation;
- candidate.transport = transport;
-
- ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
- ast_sockaddr_set_port(&candidate.address, port);
-
- if (!strcasecmp(cand_type, "host")) {
- candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
- } else if (!strcasecmp(cand_type, "srflx")) {
- candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
- } else if (!strcasecmp(cand_type, "relay")) {
- candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
- } else {
- continue;
- }
-
- if (!ast_strlen_zero(relay_address)) {
- ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
- }
-
- if (relay_port) {
- ast_sockaddr_set_port(&candidate.relay_address, relay_port);
- }
-
- ice->add_remote_candidate(session->media[AST_SIP_MEDIA_AUDIO].rtp, &candidate);
- }
-
- ice->start(session->media[AST_SIP_MEDIA_AUDIO].rtp);
- }
+ audio_process_ice_attributes(session, remote, remote_stream);
if (session->media[AST_SIP_MEDIA_AUDIO].held && (!ast_sockaddr_isnull(addrs) ||
!pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL))) {
@@ -514,6 +539,7 @@
/* The remote side has put us on hold */
ast_queue_control_data(session->channel, AST_CONTROL_HOLD, S_OR(session->endpoint->mohsuggest, NULL),
!ast_strlen_zero(session->endpoint->mohsuggest) ? strlen(session->endpoint->mohsuggest) + 1 : 0);
+ ast_rtp_instance_stop(session->media[AST_SIP_MEDIA_AUDIO].rtp);
ast_queue_frame(session->channel, &ast_null_frame);
session->media[AST_SIP_MEDIA_AUDIO].held = 1;
} else {
@@ -523,6 +549,23 @@
ast_rtp_codecs_payloads_destroy(&codecs);
return 1;
+}
+
+/*! \brief Function which updates the media stream with external media address, if applicable */
+static void audio_change_outgoing_sdp_stream(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
+{
+ char host[NI_MAXHOST];
+ struct ast_sockaddr addr = { { 0, } };
+
+ ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
+ ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
+
+ /* Is the address within the SDP inside the same network? */
+ if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) {
+ return;
+ }
+
+ pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
}
/*! \brief Function which destroys the audio RTP instance when session ends */
@@ -548,6 +591,9 @@
*/
static int load_module(void)
{
+ ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
+ ast_sockaddr_parse(&address_ipv6, "::", 0);
+
if (!(sched = ast_sched_context_create())) {
ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
goto end;
Modified: team/file/pimp_sip_nat/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pimp_sip_nat/res/res_sip_session.c?view=diff&rev=382482&r1=382481&r2=382482
==============================================================================
--- team/file/pimp_sip_nat/res/res_sip_session.c (original)
+++ team/file/pimp_sip_nat/res/res_sip_session.c Wed Mar 6 06:03:29 2013
@@ -51,6 +51,9 @@
static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata);
static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata);
+/*! \brief NAT hook for modifying outgoing messages with SDP */
+static struct ast_sip_nat_hook *nat_hook;
+
/*!
* \brief Registered SDP stream handlers
*
@@ -637,7 +640,7 @@
timer.min_se = endpoint->min_se;
timer.sess_expires = endpoint->sess_expires;
pjsip_timer_init_session(inv_session, &timer);
-
+
if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
return NULL;
@@ -758,7 +761,7 @@
}
return;
}
-
+
/* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
* so that we will be notified so we can destroy the session properly
*/
@@ -1259,9 +1262,54 @@
.on_redirected = session_inv_on_redirected,
};
+/*! \brief Hook for modifying outgoing messages with SDP to contain the proper address information */
+static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
+{
+ struct ast_sip_nat_hook *hook = tdata->mod_data[session_module.id];
+ struct pjmedia_sdp_session *sdp;
+ int stream;
+
+ /* SDP produced by us directly will never be multipart */
+ if (hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") ||
+ pj_stricmp2(&tdata->msg->body->content_type.subtype, "sdp") || ast_strlen_zero(transport->external_media_address)) {
+ return;
+ }
+
+ sdp = tdata->msg->body->data;
+
+ for (stream = 0; stream < sdp->media_count; ++stream) {
+ /* See if there are registered handlers for this media stream type */
+ char media[20];
+ struct ast_sip_session_sdp_handler *handler;
+ RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+
+ /* We need a null-terminated version of the media string */
+ ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
+
+ handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+ if (!handler_list) {
+ ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+ continue;
+ }
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler->change_outgoing_sdp_stream) {
+ handler->change_outgoing_sdp_stream(tdata, sdp->media[stream], transport);
+ }
+ }
+ }
+
+ /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
+ tdata->mod_data[session_module.id] = nat_hook;
+}
+
static int load_module(void)
{
pjsip_endpoint *endpt;
+ if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ nat_hook->outgoing_external_message = session_outgoing_nat_hook;
+ ast_sorcery_create(ast_sip_get_sorcery(), nat_hook);
sdp_handlers = ao2_container_alloc(SDP_HANDLER_BUCKETS,
sdp_handler_list_hash, sdp_handler_list_cmp);
if (!sdp_handlers) {
@@ -1282,6 +1330,10 @@
static int unload_module(void)
{
ast_sip_unregister_service(&session_module);
+ if (nat_hook) {
+ ast_sorcery_delete(ast_sip_get_sorcery(), nat_hook);
+ nat_hook = NULL;
+ }
return 0;
}
More information about the asterisk-commits
mailing list