[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