[asterisk-commits] dvossel: branch 1.8 r282269 - in /branches/1.8: channels/ configs/ include/as...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 13 15:04:32 CDT 2010


Author: dvossel
Date: Fri Aug 13 15:03:56 2010
New Revision: 282269

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=282269
Log:
res_stun_monitor for monitoring network changes behind a NAT device

Review: https://reviewboard.asterisk.org/r/854

Added:
    branches/1.8/configs/res_stun_monitor.conf.sample   (with props)
    branches/1.8/res/res_stun_monitor.c   (with props)
Modified:
    branches/1.8/channels/chan_iax2.c
    branches/1.8/channels/chan_sip.c
    branches/1.8/configs/iax.conf.sample
    branches/1.8/configs/sip.conf.sample
    branches/1.8/include/asterisk/event_defs.h

Modified: branches/1.8/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_iax2.c?view=diff&rev=282269&r1=282268&r2=282269
==============================================================================
--- branches/1.8/channels/chan_iax2.c (original)
+++ branches/1.8/channels/chan_iax2.c Fri Aug 13 15:03:56 2010
@@ -268,6 +268,9 @@
 static char language[MAX_LANGUAGE] = "";
 static char regcontext[AST_MAX_CONTEXT] = "";
 
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static int network_change_event_sched_id = -1;
+
 static int maxauthreq = 3;
 static int max_retries = 4;
 static int ping_time = 21;
@@ -1177,6 +1180,8 @@
 static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *datalen);
 static int iax2_transfer(struct ast_channel *c, const char *dest);
 static int iax2_write(struct ast_channel *c, struct ast_frame *f);
+static int iax2_sched_add(struct ast_sched_thread *st, int when, ast_sched_cb callback, const void *data);
+
 static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now);
 static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
@@ -1201,6 +1206,7 @@
 static struct callno_entry *get_unused_callno(int trunk, int validated);
 static int replace_callno(const void *obj);
 static void sched_delay_remove(struct sockaddr_in *sin, struct callno_entry *callno_entry);
+static void network_change_event_cb(const struct ast_event *, void *);
 
 static const struct ast_channel_tech iax2_tech = {
 	.type = "IAX2",
@@ -1236,6 +1242,47 @@
 	 * is time to send MWI, since it is only sent with a REGACK. */
 }
 
+static void network_change_event_subscribe(void)
+{
+	if (!network_change_event_subscription) {
+		network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+			network_change_event_cb,
+			"SIP Network Change ",
+			NULL,
+			AST_EVENT_IE_END);
+	}
+}
+
+static void network_change_event_unsubscribe(void)
+{
+	if (network_change_event_subscription) {
+		network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+	}
+}
+
+static int network_change_event_sched_cb(const void *data)
+{
+	struct iax2_registry *reg;
+	network_change_event_sched_id = -1;
+	AST_LIST_LOCK(&registrations);
+	AST_LIST_TRAVERSE(&registrations, reg, entry) {
+		iax2_do_register(reg);
+	}
+	AST_LIST_UNLOCK(&registrations);
+
+	return 0;
+}
+
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
+{
+	ast_debug(1, "IAX, got a network change event, renewing all IAX registrations.\n");
+	if (network_change_event_sched_id == -1) {
+		network_change_event_sched_id = iax2_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
+	}
+
+}
+
+
 /*! \brief Send manager event at call setup to link between Asterisk channel name
 	and IAX2 call identifiers */
 static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt) 
@@ -1245,7 +1292,6 @@
 		pvt->owner ? pvt->owner->name : "",
 		pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
 }
-
 
 static struct ast_datastore_info iax2_variable_datastore_info = {
 	.type = "IAX2_VARIABLE",
@@ -12779,7 +12825,8 @@
 	int format;
 	int portno = IAX_DEFAULT_PORTNO;
 	int  x;
-	int mtuv; 
+	int mtuv;
+	int subscribe_network_change = 1;
 	struct iax2_user *user;
 	struct iax2_peer *peer;
 	struct ast_netsock *ns;
@@ -13097,6 +13144,14 @@
 			if (add_calltoken_ignore(v->value)) {
 				ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
 			}
+		} else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
+			if (ast_true(v->value)) {
+				subscribe_network_change = 1;
+			} else if (ast_false(v->value)) {
+				subscribe_network_change = 0;
+			} else {
+				ast_log(LOG_WARNING, "subscribe_network_change_event value %s is not valid at line %d.\n", v->value, v->lineno);
+			}
 		} else if (!strcasecmp(v->name, "shrinkcallerid")) {
 			if (ast_true(v->value)) {
 				ast_set_flag64((&globalflags), IAX_SHRINKCALLERID);
@@ -13109,7 +13164,13 @@
 		/*	ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
 		v = v->next;
 	}
-	
+
+	if (subscribe_network_change) {
+		network_change_event_subscribe();
+	} else {
+		network_change_event_unsubscribe();
+	}
+
 	if (defaultsockfd < 0) {
 		if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, qos.tos, qos.cos, socket_read, NULL))) {
 			ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
@@ -14050,6 +14111,8 @@
 	struct ast_context *con;
 	int x;
 
+	network_change_event_unsubscribe();
+
 	ast_manager_unregister("IAXpeers");
 	ast_manager_unregister("IAXpeerlist");
 	ast_manager_unregister("IAXnetstats");
@@ -14530,6 +14593,8 @@
 
 	ast_realtime_require_field("iaxpeers", "name", RQ_CHAR, 10, "ipaddr", RQ_CHAR, 15, "port", RQ_UINTEGER2, 5, "regseconds", RQ_UINTEGER2, 6, SENTINEL);
 
+	network_change_event_subscribe();
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 

Modified: branches/1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_sip.c?view=diff&rev=282269&r1=282268&r2=282269
==============================================================================
--- branches/1.8/channels/chan_sip.c (original)
+++ branches/1.8/channels/chan_sip.c Fri Aug 13 15:03:56 2010
@@ -762,6 +762,9 @@
 static struct ast_flags global_flags[3] = {{0}};  /*!< global SIP_ flags */
 static int global_t38_maxdatagram;                /*!< global T.38 FaxMaxDatagram override */
 
+static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
+static int network_change_event_sched_id = -1;
+
 static char used_context[AST_MAX_CONTEXT];        /*!< name of automatically created context for unloading */
 
 AST_MUTEX_DEFINE_STATIC(netlock);
@@ -1334,6 +1337,7 @@
 static void sip_poke_all_peers(void);
 static void sip_peer_hold(struct sip_pvt *p, int hold);
 static void mwi_event_cb(const struct ast_event *, void *);
+static void network_change_event_cb(const struct ast_event *, void *);
 
 /*--- Applications, functions, CLI and manager command helpers */
 static const char *sip_nat_mode(const struct sip_pvt *p);
@@ -13430,6 +13434,39 @@
 	ao2_lock(peer);
 	sip_send_mwi_to_peer(peer, event, 0);
 	ao2_unlock(peer);
+}
+
+static void network_change_event_subscribe(void)
+{
+	if (!network_change_event_subscription) {
+		network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
+			network_change_event_cb,
+			"SIP Network Change ",
+			NULL, AST_EVENT_IE_END);
+	}
+}
+
+static void network_change_event_unsubscribe(void)
+{
+	if (network_change_event_subscription) {
+		network_change_event_subscription = ast_event_unsubscribe(network_change_event_subscription);
+	}
+}
+
+static int network_change_event_sched_cb(const void *data)
+{
+	network_change_event_sched_id = -1;
+	sip_send_all_registers();
+	sip_send_all_mwi_subscriptions();
+	return 0;
+}
+
+static void network_change_event_cb(const struct ast_event *event, void *userdata)
+{
+	ast_debug(1, "SIP, got a network change event, renewing all SIP registrations.\n");
+	if (network_change_event_sched_id == -1) {
+		network_change_event_sched_id = ast_sched_add(sched, 1000, network_change_event_sched_cb, NULL);
+	}
 }
 
 /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
@@ -26108,6 +26145,7 @@
 	int auto_sip_domains = FALSE;
 	struct ast_sockaddr old_bindaddr = bindaddr;
 	int registry_count = 0, peer_count = 0, timerb_set = 0, timert1_set = 0;
+	int subscribe_network_change = 1;
 	time_t run_start, run_end;
 	struct sockaddr_in externaddr_sin;
 	int bindport = 0;
@@ -26811,9 +26849,23 @@
 				ast_log(LOG_WARNING, "'%s' is not a valid maxforwards value at line %d.  Using default.\n", v->value, v->lineno);
 				sip_cfg.default_max_forwards = DEFAULT_MAX_FORWARDS;
 			}
+		} else if (!strcasecmp(v->name, "subscribe_network_change_event")) {
+			if (ast_true(v->value)) {
+				subscribe_network_change = 1;
+			} else if (ast_false(v->value)) {
+				subscribe_network_change = 0;
+			} else {
+				ast_log(LOG_WARNING, "subscribe_network_change_event value %s is not valid at line %d.\n", v->value, v->lineno);
+			}
 		} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
 				ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 		}
+	}
+
+	if (subscribe_network_change) {
+		network_change_event_subscribe();
+	} else {
+		network_change_event_unsubscribe();
 	}
 
 	if (global_t1 < global_t1min) {
@@ -28322,6 +28374,7 @@
 
 
 	sip_register_tests();
+	network_change_event_subscribe();
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
@@ -28333,6 +28386,8 @@
 	struct sip_threadinfo *th;
 	struct ast_context *con;
 	struct ao2_iterator i;
+
+	network_change_event_unsubscribe();
 
 	ast_sched_dump(sched);
 	

Modified: branches/1.8/configs/iax.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/configs/iax.conf.sample?view=diff&rev=282269&r1=282268&r2=282269
==============================================================================
--- branches/1.8/configs/iax.conf.sample (original)
+++ branches/1.8/configs/iax.conf.sample Fri Aug 13 15:03:56 2010
@@ -244,6 +244,15 @@
 ;
 ;register => FWDNumber:passwd at iax.fwdnet.net
 ;
+; Through the use of the res_stun_monitor module, Asterisk has the ability to detect when the
+; perceived external network address has changed.  When the stun_monitor is installed and
+; configured, chan_iax will renew all outbound registrations when the monitor detects any sort
+; of network change has occurred. By default this option is enabled, but only takes effect once
+; res_stun_monitor is configured.  If res_stun_monitor is enabled and you wish to not
+; generate all outbound registrations on a network change, use the option below to disable
+; this feature.
+;
+; subscribe_network_change_event = yes ; on by default
 ;
 ; You can disable authentication debugging to reduce the amount of
 ; debugging traffic.

Added: branches/1.8/configs/res_stun_monitor.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/configs/res_stun_monitor.conf.sample?view=auto&rev=282269
==============================================================================
--- branches/1.8/configs/res_stun_monitor.conf.sample (added)
+++ branches/1.8/configs/res_stun_monitor.conf.sample Fri Aug 13 15:03:56 2010
@@ -1,0 +1,22 @@
+;
+; Configuration file for the res_stun_monitor module
+;
+; The res_stun_monitor module sends STUN requests to a configured STUN server
+; periodically.  If the monitor detects a change in the external ip or port
+; provided by the STUN server an event is sent out internally within Asterisk
+; to alert all listeners to that event of the change.
+
+; The current default listeners for the netork change event include chan_sip
+; and chan_iax.  Both of these channel drivers by default react to this event
+; by renewing all outbound registrations.  This allows the endpoints Asterisk
+; is registering with to become aware of the address change and know the new
+; location.
+;
+[general]
+;
+; ---- STUN Server configuration ---
+;  Setting the 'stunaddr' option to a valid address enables the stun monitor.
+;
+; stunaddr = mystunserver.com ; address of the stun server to query.
+; stunrefresh = 30     ; number of seconds between stun refreshes. default is 30
+;

Propchange: branches/1.8/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: branches/1.8/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: branches/1.8/configs/res_stun_monitor.conf.sample
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: branches/1.8/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/configs/sip.conf.sample?view=diff&rev=282269&r1=282268&r2=282269
==============================================================================
--- branches/1.8/configs/sip.conf.sample (original)
+++ branches/1.8/configs/sip.conf.sample Fri Aug 13 15:03:56 2010
@@ -783,6 +783,16 @@
 ; can not be set per-user or per-peer.
 ;
 ; media_address = 172.16.42.1
+;
+; Through the use of the res_stun_monitor module, Asterisk has the ability to detect when the
+; perceived external network address has changed.  When the stun_monitor is installed and
+; configured, chan_sip will renew all outbound registrations when the monitor detects any sort
+; of network change has occurred. By default this option is enabled, but only takes effect once
+; res_stun_monitor is configured.  If res_stun_monitor is enabled and you wish to not
+; generate all outbound registrations on a network change, use the option below to disable
+; this feature.
+;
+; subscribe_network_change_event = yes ; on by default
 
 ;----------------------------------- MEDIA HANDLING --------------------------------
 ; By default, Asterisk tries to re-invite media streams to an optimal path. If there's

Modified: branches/1.8/include/asterisk/event_defs.h
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/include/asterisk/event_defs.h?view=diff&rev=282269&r1=282268&r2=282269
==============================================================================
--- branches/1.8/include/asterisk/event_defs.h (original)
+++ branches/1.8/include/asterisk/event_defs.h Fri Aug 13 15:03:56 2010
@@ -52,8 +52,10 @@
 	AST_EVENT_CEL                 = 0x07,
 	/*! A report of a security related event (see security_events.h) */
 	AST_EVENT_SECURITY            = 0x08,
+	/*! Used by res_stun_monitor to alert listeners to an exernal network address change. */
+	AST_EVENT_NETWORK_CHANGE      = 0x09,
 	/*! Number of event types.  This should be the last event type + 1 */
-	AST_EVENT_TOTAL               = 0x09,
+	AST_EVENT_TOTAL               = 0x0a,
 };
 
 /*! \brief Event Information Element types */

Added: branches/1.8/res/res_stun_monitor.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/res/res_stun_monitor.c?view=auto&rev=282269
==============================================================================
--- branches/1.8/res/res_stun_monitor.c (added)
+++ branches/1.8/res/res_stun_monitor.c Fri Aug 13 15:03:56 2010
@@ -1,0 +1,311 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 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"
+#include <fcntl.h>
+
+static const int STANDARD_STUN_PORT = 3478;
+static const int DEFAULT_MONITOR_REFRESH = 30;
+
+static const char stun_conf_file[] = "res_stun_monitor.conf";
+static struct ast_sched_thread *sched;
+
+static struct {
+	struct sockaddr_in stunaddr;      /*!< The stun address we send requests to*/
+	struct sockaddr_in externaladdr;  /*!< current perceived external address. */
+	ast_mutex_t lock;
+	unsigned int refresh;
+	int stunsock;
+	unsigned int monitor_enabled:1;
+	unsigned int externaladdr_known:1;
+} args;
+
+static inline void stun_close_sock(void)
+{
+	if (args.stunsock != -1) {
+		close(args.stunsock);
+		args.stunsock = -1;
+		memset(&args.externaladdr, 0, sizeof(args.externaladdr));
+		args.externaladdr_known = 0;
+	}
+}
+
+/* \brief purge the stun socket's receive buffer before issuing a new request
+ *
+ * XXX Note that this is somewhat of a hack.  This function is essentially doing
+ * a cleanup on the socket rec buffer to handle removing any STUN responses we have not
+ * handled.  This is called before sending out a new STUN request so we don't read
+ * a latent previous response thinking it is new.
+ */
+static void stun_purge_socket(void)
+{
+	int flags = fcntl(args.stunsock, F_GETFL);
+	int res = 0;
+	unsigned char reply_buf[1024];
+
+	fcntl(args.stunsock, F_SETFL, flags | O_NONBLOCK);
+	while (res != -1) {
+		/* throw away everything in the buffer until we reach the end. */
+		res = recv(args.stunsock, reply_buf, sizeof(reply_buf), 0);
+	}
+	fcntl(args.stunsock, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+/* \brief called by scheduler to send STUN request */
+static int stun_monitor_request(const void *blarg)
+{
+	int res;
+	int generate_event = 0;
+	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) {
+		ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
+		goto monitor_request_cleanup;
+	}
+
+	stun_purge_socket();
+
+	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) {
+			/* the external address was already known, and has changed... generate event. */
+			generate_event = 1;
+
+		} else {
+			/* this was the first external address we found, do not alert listeners
+			 * until this address changes to something else. */
+			args.externaladdr_known = 1;
+		}
+	}
+
+	if (generate_event) {
+		struct ast_event *event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
+		if (!event) {
+			ast_log(LOG_ERROR, "STUN monitor: could not create AST_EVENT_NETWORK_CHANGE event.\n");
+			goto monitor_request_cleanup;
+		}
+		if (ast_event_queue(event)) {
+			ast_event_destroy(event);
+			event = NULL;
+			ast_log(LOG_ERROR, "STUN monitor: could not queue AST_EVENT_NETWORK_CHANGE event.\n");
+			goto monitor_request_cleanup;
+		}
+	}
+
+monitor_request_cleanup:
+	/* 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)
+{
+	struct ast_sockaddr dst;
+	/* clean up any previous open socket */
+	stun_close_sock();
+
+	/* create destination ast_sockaddr */
+	ast_sockaddr_from_sin(&dst, &args.stunaddr);
+
+	/* open new socket binding */
+	args.stunsock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (args.stunsock < 0) {
+		ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (ast_connect(args.stunsock, &dst) != 0) {
+		ast_log(LOG_WARNING, "SIP STUN Failed to connect to %s\n", ast_sockaddr_stringify(&dst));
+		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));
+	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, "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);
+			}
+		} else {
+			ast_log(LOG_WARNING, "SIP STUN: invalid config option %s at line %d\n", v->value, v->lineno);
+		}
+	}
+
+	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)) {
+		stun_stop_monitor();
+		ast_mutex_destroy(&args.lock);
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
+	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: branches/1.8/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: branches/1.8/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: branches/1.8/res/res_stun_monitor.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list