Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 280617)
+++ channels/chan_sip.c	(working copy)
@@ -274,6 +274,7 @@
 #include "asterisk/xml.h"
 #include "sip/include/dialog.h"
 #include "sip/include/dialplan_functions.h"
+#include "sip/include/sipstun.h"
 
 
 /*** DOCUMENTATION
@@ -1155,6 +1156,8 @@
 static time_t externexpire;             /*!< Expiration counter for re-resolving external host name in dynamic DNS */
 static int externrefresh = 10;          /*!< Refresh timer for DNS-based external address (dyndns) */
 static struct sockaddr_in stunaddr;     /*!< stun server address */
+static struct sip_stun_args stun_client; /*!< stun client to send requests from */
+
 static uint16_t externtcpport;          /*!< external tcp port */ 
 static uint16_t externtlsport;          /*!< external tls port */
 
@@ -3151,7 +3154,7 @@
 		if (externexpire && time(NULL) >= externexpire) {
 			if (stunaddr.sin_addr.s_addr) {
 				ast_sockaddr_to_sin(&externaddr, &externaddr_sin);
-				ast_stun_request(sipsock, &stunaddr, NULL, &externaddr_sin);
+				sip_stun_request(&stun_client, &stunaddr, NULL, &externaddr_sin);
 			} else {
 				if (ast_sockaddr_resolve_first(&externaddr, externhost, 0)) {
 					ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
@@ -26214,6 +26217,7 @@
 
 	/* Reset IP addresses  */
 	ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
+	sip_stun_set_default_bind(&stun_client);
 	memset(&stunaddr, 0, sizeof(stunaddr));
 	memset(&internip, 0, sizeof(internip));
 
@@ -26606,6 +26610,8 @@
 				ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
 			}
 			externexpire = time(NULL);
+		} else if (!strcasecmp(v->name, "stunbindaddr")) {
+			sip_stun_set_bindaddr(&stun_client, v->value);
 		} else if (!strcasecmp(v->name, "bindaddr") || !strcasecmp(v->name, "udpbindaddr")) {
 			if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
 				ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
@@ -26906,14 +26912,18 @@
 			}
 		}
 	}
+
 	if (stunaddr.sin_addr.s_addr != 0) {
-		ast_debug(1, "stun to %s:%d\n",
-			ast_inet_ntoa(stunaddr.sin_addr) , ntohs(stunaddr.sin_port));
+		ast_debug(1, "stun to %s:%d\n", ast_inet_ntoa(stunaddr.sin_addr) , ntohs(stunaddr.sin_port));
 		ast_sockaddr_to_sin(&externaddr, &externaddr_sin);
-		ast_stun_request(sipsock, &stunaddr,
-			NULL, &externaddr_sin);
-		ast_debug(1, "STUN sees us at %s\n",
-			ast_sockaddr_stringify(&externaddr));
+		if (sip_stun_bind_socket(&stun_client) != -1) {
+			sip_stun_request(&stun_client, &stunaddr, NULL, &externaddr_sin);
+			ast_debug(1, "STUN sees us at %s\n", ast_sockaddr_stringify(&externaddr));
+		} else {
+			ast_log(LOG_WARNING, "SIP STUN Error, can not request externaddr, socket failed to open.\n");
+		}
+	} else {
+		sip_stun_close_sock(&stun_client);
 	}
 	ast_mutex_unlock(&netlock);
 
@@ -28210,6 +28220,8 @@
 	ASTOBJ_CONTAINER_INIT(&regl); /* Registry object list -- not searched for anything */
 	ASTOBJ_CONTAINER_INIT(&submwil); /* MWI subscription object list */
 
+	sip_stun_init(&stun_client);
+
 	if (!(sched = sched_context_create())) {
 		ast_log(LOG_ERROR, "Unable to create scheduler context\n");
 		return AST_MODULE_LOAD_FAILURE;
@@ -28463,6 +28475,8 @@
 	ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
 	ast_cc_agent_unregister(&sip_cc_agent_callbacks);
 
+	sip_stun_destroy(&stun_client);
+
 	sip_reqresp_parser_exit();
 	sip_unregister_tests();
 
Index: channels/sip/include/sipstun.h
===================================================================
--- channels/sip/include/sipstun.h	(revision 0)
+++ channels/sip/include/sipstun.h	(revision 0)
@@ -0,0 +1,65 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief sip stun client header file
+ */
+
+#ifndef _SIP_STUN_H
+#define _SIP_STUN_H
+#include "asterisk/lock.h"
+#include "asterisk/netsock2.h"
+
+#define STUN_DEFAULT_PORT 3478
+struct sip_stun_args {
+	struct ast_sockaddr stunbindaddr; /*!< The stun address we bind to. */
+	ast_mutex_t lock;
+	int stunsock;
+};
+
+/*!
+ * \brief set stun bind address 
+ *
+ * \note sip_stun_bind_socket must be called before this will take effect
+ *
+ * \retval 0 success -1 failure
+ */
+int sip_stun_set_bindaddr(struct sip_stun_args *args, const char *value);
+
+/*!
+ * \brief  
+ *
+ * \retval 0 success -1 failure
+ */
+int sip_stun_request(struct sip_stun_args *args, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer);
+
+/*!
+ * \brief closes old socket, creates new socket and binds address 
+ *
+ * \retval 0 success -1 failure
+ */
+int sip_stun_bind_socket(struct sip_stun_args *args);
+
+void sip_stun_set_default_bind(struct sip_stun_args *args);
+
+void sip_stun_close_sock(struct sip_stun_args *args);
+
+void sip_stun_init(struct sip_stun_args *args);
+
+void sip_stun_destroy(struct sip_stun_args *args);
+
+#endif

Property changes on: channels/sip/include/sipstun.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Index: channels/sip/sipstun.c
===================================================================
--- channels/sip/sipstun.c	(revision 0)
+++ channels/sip/sipstun.c	(revision 0)
@@ -0,0 +1,145 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief sip stun client
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "include/sipstun.h"
+#include "asterisk/stun.h"
+#include "asterisk/config.h"
+
+
+static void stun_close_sock(struct sip_stun_args *args, int lock)
+{
+	if (lock) {
+		ast_mutex_lock(&args->lock);
+	}
+
+	if (args->stunsock < 0) {
+		close(args->stunsock);
+		args->stunsock = -1;
+	}
+
+	if (lock) {
+		ast_mutex_unlock(&args->lock);
+	}
+}
+
+void sip_stun_close_sock(struct sip_stun_args *args)
+{
+	stun_close_sock(args, 1);
+}
+
+static void stun_set_default_bind(struct sip_stun_args *args, int lock)
+{
+	if (lock) {
+		ast_mutex_lock(&args->lock);
+	}
+
+	ast_sockaddr_parse(&args->stunbindaddr, "0.0.0.0:0", 0);
+
+	if (lock) {
+		ast_mutex_unlock(&args->lock);
+	}
+
+}
+
+void sip_stun_set_default_bind(struct sip_stun_args *args)
+{
+	stun_set_default_bind(args, 1);
+}
+
+int sip_stun_request(struct sip_stun_args *args, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
+{
+	int res;
+
+	ast_mutex_lock(&args->lock);
+	if (args->stunsock < 0) {
+		res = -1;
+	} else {
+		res = ast_stun_request(args->stunsock, dst, username, answer);
+	}
+	ast_mutex_unlock(&args->lock);
+
+	return res;
+}
+
+int sip_stun_set_bindaddr(struct sip_stun_args *args, const char *value)
+{
+	int res = 0;
+	ast_mutex_lock(&args->lock);
+	if (ast_parse_arg(value, PARSE_ADDR, &args->stunbindaddr)) {
+		ast_log(LOG_WARNING, "SIP STUN. invalid address: %s\n", value);
+		stun_set_default_bind(args, 0);
+		res = -1;
+	}
+	ast_mutex_unlock(&args->lock);
+	return res;
+}
+
+int sip_stun_bind_socket(struct sip_stun_args *args)
+{
+	int res = -1;
+
+	ast_mutex_lock(&args->lock);
+
+	/* close sock if it was already open */
+	stun_close_sock(args, 0);
+
+	/* open new socket and bind addr */
+	if (!ast_sockaddr_port(&args->stunbindaddr)) {
+		ast_sockaddr_set_port(&args->stunbindaddr, STUN_DEFAULT_PORT);
+	}
+	args->stunsock = socket(ast_sockaddr_is_ipv6(&args->stunbindaddr) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
+	if (args->stunsock < 0) {
+		ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
+		goto stun_bind_cleanup;
+	} else {
+		const int reuseFlag = 1;
+		setsockopt(args->stunsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseFlag, sizeof(reuseFlag));
+
+		if (ast_bind(args->stunsock, &args->stunbindaddr) < 0) {
+			ast_log(LOG_WARNING, "SIP STUN Failed to bind to %s: %s\n", ast_sockaddr_stringify(&args->stunbindaddr), strerror(errno));
+			stun_close_sock(args, 0);
+			goto stun_bind_cleanup;
+		}
+	}
+	res = 0;
+
+stun_bind_cleanup:
+	ast_mutex_unlock(&args->lock);
+
+	return res;
+}
+
+void sip_stun_init(struct sip_stun_args *args)
+{
+	memset(args, 0, sizeof(args));
+	stun_set_default_bind(args, 0);
+	ast_mutex_init(&args->lock);
+}
+
+void sip_stun_destroy(struct sip_stun_args *args)
+{
+	stun_close_sock(args, 1);
+	ast_mutex_destroy(&args->lock);
+}

Property changes on: channels/sip/sipstun.c
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Author Date Id Revision
Added: svn:eol-style
   + native

Index: configs/sip.conf.sample
===================================================================
--- configs/sip.conf.sample	(revision 280617)
+++ configs/sip.conf.sample	(working copy)
@@ -707,6 +707,11 @@
 ;        stunaddr = foo.stun.com:3478
 ;        externrefresh = 15
 ;
+;      By default stun queries will be sent from port 3478. To bind the stun
+;      client to a different address/port use the 'stunbindaddr' option.
+;
+;        stunbindaddr = 0.0.0.0:5000 ; bind stun client address.
+;
 ;   Note that at the moment all these mechanism work only for the SIP socket.
 ;   The IP address discovered with externaddr/externhost/STUN is reused for
 ;   media sessions as well, but the port numbers are not remapped so you
