[svn-commits] dvossel: branch dvossel/stun_monitor r281654 - in /team/dvossel/stun_monitor:...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Aug 10 16:57:48 CDT 2010


Author: dvossel
Date: Tue Aug 10 16:57:44 2010
New Revision: 281654

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=281654
Log:
addition of the res_stun_monitor mondule and sample config

Added:
    team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample   (with props)
    team/dvossel/stun_monitor/res/res_stun_monitor.c   (with props)

Added: team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample?view=auto&rev=281654
==============================================================================
--- team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample (added)
+++ team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample Tue Aug 10 16:57:44 2010
@@ -1,0 +1,15 @@
+;
+; Configuration file for the res_stun_monitor module
+;
+[general]
+;
+; ---- STUN Server configuration ---
+; stunaddr = mystunserver.com ; address of the stun server to query
+; stunrefresh = 30     ; number of seconds between stun refreshes. default is 30
+;
+; ---- STUN Client configuration ---
+;  By default stun queries will be sent from port 3478 when a 'stunadd' is
+;  specified. To bind the stun client to a different address/port use the
+;  'stunbindaddr' option.
+;
+; stunbindaddr = 0.0.0.0:5000 ; bind stun client address.

Propchange: team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/dvossel/stun_monitor/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/dvossel/stun_monitor/res/res_stun_monitor.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/stun_monitor/res/res_stun_monitor.c?view=auto&rev=281654
==============================================================================
--- team/dvossel/stun_monitor/res/res_stun_monitor.c (added)
+++ team/dvossel/stun_monitor/res/res_stun_monitor.c Tue Aug 10 16:57:44 2010
@@ -1,0 +1,270 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2009-2010, Digium, Inc.
+ *
+ * David Vossel <dvossel at digium.com>
+ *
+ * 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 STUN Network Monitor
+ *
+ * \author David Vossel <dvossel at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/event.h"
+#include "asterisk/sched.h"
+#include "asterisk/config.h"
+#include "asterisk/stun.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/lock.h"
+
+#define STANDARD_STUN_PORT 3478
+#define DEFAULT_MONITOR_REFRESH 30
+
+static const char *stun_conf_file = "res_stun_monitor.conf";
+static struct ast_sched_thread *sched;
+
+static struct stun_monitor_args {
+	struct ast_sockaddr stunbindaddr; /*!< The stun addres we bind to */
+	struct sockaddr_in stunaddr;      /*!< The stun address we send requests to*/
+	struct sockaddr_in externaladdr;  /*!< current perceived external address. */
+	int externaladdr_known;
+	unsigned int refresh;
+	int stunsock;
+	int monitor_enabled;
+	ast_mutex_t lock;
+} args;
+
+static inline void stun_close_sock(void)
+{
+	if (args.stunsock < 0) {
+		close(args.stunsock);
+		args.stunsock = -1;
+	}
+}
+
+/* \brief called by scheduler to send STUN request */
+static int stun_monitor_request(const void *blarg)
+{
+	int res;
+	struct sockaddr_in answer = { 0, };
+
+	/* once the stun socket goes away, this scheduler item will go away as well */
+	ast_mutex_lock(&args.lock);
+	if (args.stunsock > -1) {
+		if (!(ast_stun_request(args.stunsock, &args.stunaddr, NULL, &answer)) &&
+			(memcmp(&args.externaladdr, &answer, sizeof(args.externaladdr)))) {
+			const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
+			int newport = ntohs(answer.sin_port);
+
+			ast_log(LOG_NOTICE, "STUN MONITOR: Old external address/port %s:%d now seen as %s:%d \n",
+				ast_inet_ntoa(args.externaladdr.sin_addr), ntohs(args.externaladdr.sin_port),
+				newaddr, newport);
+
+			memcpy(&args.externaladdr, &answer, sizeof(args.externaladdr));
+
+			if (args.externaladdr_known) {
+				/* todohere external addr addr is different, push event out */
+			} else {
+				/* this was the first external address we found, do not alert listeners
+				 * until this address changes to something else. */
+				args.externaladdr_known = 1;
+			}
+		}
+	} else {
+		ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
+	}
+
+	/* always refresh this scheduler item.  It will be removed elsewhere when
+	 * it is supposed to go away */
+	res = args.refresh * 1000;
+	ast_mutex_unlock(&args.lock);
+
+	return res;
+}
+
+/* \brief stops the stun monitor thread
+ * \note do not hold the args->lock while calling this
+ */
+static void stun_stop_monitor(void)
+{
+	if (sched) {
+		sched = ast_sched_thread_destroy(sched);
+		ast_log(LOG_NOTICE, "STUN monitor stopped\n");
+	}
+	/* it is only safe to destroy the socket without holding arg->lock
+	 * after the sched thread is destroyed */
+	stun_close_sock();
+}
+
+/* \brief starts the stun monitor thread
+ * \note The args->lock MUST be held when calling this function
+ */
+static int stun_start_monitor(void)
+{
+	const int reuseFlag = 1;
+
+	/* clean up any previous open socket */
+	stun_close_sock();
+
+	/* open new socket binding */
+	if (!ast_sockaddr_port(&args.stunbindaddr)) {
+		ast_sockaddr_set_port(&args.stunbindaddr, STANDARD_STUN_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));
+		return -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();
+		return -1;
+	}
+
+	/* if scheduler thread is not started, make sure to start it now */
+	if (sched) {
+		return 0; /* already started */
+	}
+
+	if (!(sched = ast_sched_thread_create())) {
+		ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
+		stun_close_sock();
+		return -1;
+	}
+
+	if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
+		ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
+		sched = ast_sched_thread_destroy(sched);
+		stun_close_sock();
+		return -1;
+	}
+
+	ast_log(LOG_NOTICE, "STUN monitor started\n");
+	return 0;
+}
+
+static int load_config(int startup)
+{
+	struct ast_flags config_flags = { 0, };
+	struct ast_config *cfg;
+	struct ast_variable *v;
+
+	if (!startup) {
+		ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+	}
+
+	if (!(cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags)) ||
+		cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_ERROR, "Unable to load config %s\n", stun_conf_file);
+		return -1;
+	}
+
+	if (cfg == CONFIG_STATUS_FILEUNCHANGED && !startup) {
+		return 0;
+	}
+
+	/* set defaults */
+	args.monitor_enabled = 0;
+	memset(&args.stunaddr, 0, sizeof(args.stunaddr));
+	ast_sockaddr_parse(&args.stunbindaddr, "0.0.0.0:0", 0);
+	args.refresh = DEFAULT_MONITOR_REFRESH;
+
+	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+		if (!strcasecmp(v->name, "stunaddr")) {
+			args.stunaddr.sin_port = htons(STANDARD_STUN_PORT);
+			if (ast_parse_arg(v->value, PARSE_INADDR, &args.stunaddr)) {
+				ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
+			} else {
+				ast_log(LOG_NOTICE, "STUN monitor enabled: %s\n", v->value);
+				args.monitor_enabled = 1;
+			}
+		} else if (!strcasecmp(v->name, "stunbindaddr")) {
+			if (ast_parse_arg(v->value, PARSE_ADDR, &args.stunbindaddr)) {
+				ast_log(LOG_WARNING, "SIP STUN. invalid address: %s\n", v->value);
+				ast_sockaddr_parse(&args.stunbindaddr, "0.0.0.0:0", 0);
+			}
+		} else if (!strcasecmp(v->name, "stunrefresh")) {
+			if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
+				ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
+				args.refresh = DEFAULT_MONITOR_REFRESH;
+			} else {
+				ast_log(LOG_NOTICE, "STUN Monitor set to refresh every %d seconds\n", args.refresh);
+			}
+		}
+	}
+
+	ast_config_destroy(cfg);
+
+	return 0;
+}
+
+static int __reload(int startup)
+{
+	int res;
+
+	ast_mutex_lock(&args.lock);
+	if (!(res = load_config(startup)) && args.monitor_enabled) {
+		res = stun_start_monitor();
+	}
+	ast_mutex_unlock(&args.lock);
+
+	if ((res == -1) || !args.monitor_enabled) {
+		args.monitor_enabled = 0;
+		stun_stop_monitor();
+	}
+
+	return res;
+}
+
+static int reload(void)
+{
+	return __reload(0);
+}
+
+static int unload_module(void)
+{
+	stun_stop_monitor();
+	ast_mutex_destroy(&args.lock);
+	return 0;
+}
+
+static int load_module(void)
+{
+	ast_mutex_init(&args.lock);
+	args.stunsock = -1;
+	memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+	args.externaladdr_known = 0;
+	sched = NULL;
+	if (__reload(1)) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_log(LOG_NOTICE, "Loaded STUN monitor\n");
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+		.load_pri = AST_MODPRI_CHANNEL_DEPEND
+	);

Propchange: team/dvossel/stun_monitor/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/dvossel/stun_monitor/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/dvossel/stun_monitor/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the svn-commits mailing list