42 #include "asterisk/stasis_system.h"
47 #define DEFAULT_MONITOR_REFRESH 30
48 #define DEFAULT_RETRIES 3
51 static const char stun_conf_file[] =
"res_stun_monitor.conf";
75 static void stun_close_sock(
void)
77 if (0 <= args.stun_sock) {
78 close(args.stun_sock);
87 struct sockaddr_in answer;
88 static const struct sockaddr_in no_addr = { 0, };
90 ast_mutex_lock(&args.lock);
91 if (!args.monitor_enabled) {
92 goto monitor_request_cleanup;
95 if (args.stun_sock < 0) {
99 if (!args.server_hostname) {
101 goto monitor_request_cleanup;
105 memset(&stun_addr, 0,
sizeof(stun_addr));
106 stun_addr.ss.ss_family = AF_INET;
107 if (
ast_get_ip(&stun_addr, args.server_hostname)) {
109 ast_log(LOG_WARNING,
"Unable to lookup STUN server '%s'\n",
110 args.server_hostname);
111 goto monitor_request_cleanup;
116 args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0);
117 if (args.stun_sock < 0) {
118 ast_log(LOG_WARNING,
"Unable to create STUN socket: %s\n", strerror(errno));
119 goto monitor_request_cleanup;
122 ast_log(LOG_WARNING,
"STUN Failed to connect to %s: %s\n",
125 goto monitor_request_cleanup;
136 if (!args.stun_poll_failed_gripe) {
137 args.stun_poll_failed_gripe = 1;
138 ast_log(LOG_WARNING,
"STUN poll %s. Re-evaluating STUN server address.\n",
139 res < 0 ?
"failed" :
"got no response");
143 args.stun_poll_failed_gripe = 0;
144 if (memcmp(&no_addr, &answer,
sizeof(no_addr))
145 && memcmp(&args.external_addr, &answer,
sizeof(args.external_addr))) {
147 int newport = ntohs(answer.sin_port);
149 ast_log(LOG_NOTICE,
"Old external address/port %s:%d now seen as %s:%d.\n",
151 ntohs(args.external_addr.sin_port), newaddr, newport);
153 args.external_addr = answer;
155 if (args.external_addr_known) {
160 if (!ast_network_change_type()) {
161 goto publish_failure;
168 goto publish_failure;
172 goto publish_failure;
181 ast_log(LOG_ERROR,
"Failed to issue network change message.\n");
186 args.external_addr_known = 1;
191 monitor_request_cleanup:
194 res = args.refresh * 1000;
195 ast_mutex_unlock(&args.lock);
206 static void stun_stop_monitor(
void)
208 ast_mutex_lock(&args.lock);
209 args.monitor_enabled = 0;
210 ast_free((
char *) args.server_hostname);
211 args.server_hostname = NULL;
213 ast_mutex_unlock(&args.lock);
218 ast_log(LOG_NOTICE,
"STUN monitor stopped\n");
228 static int stun_start_monitor(
void)
236 ast_log(LOG_ERROR,
"Failed to create stun monitor scheduler context\n");
248 ast_log(LOG_ERROR,
"Unable to schedule STUN network monitor \n");
254 ast_log(LOG_NOTICE,
"STUN monitor started\n");
269 static int setup_stunaddr(
const char *value,
int reload)
277 if (ast_strlen_zero(value)) {
279 args.monitor_enabled = 0;
285 || ast_strlen_zero(host_str)) {
290 if (ast_strlen_zero(port_str)
291 || 1 != sscanf(port_str,
"%30u", &port)) {
292 port = STANDARD_STUN_PORT;
304 ast_log(LOG_WARNING,
"Unable to lookup STUN server '%s'\n", host_str);
314 ast_free((
char *) args.server_hostname);
315 args.server_hostname = host_str;
316 args.stun_port = port;
319 args.monitor_enabled = 1;
323 static int load_config(
int startup)
334 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
335 ast_log(LOG_WARNING,
"Unable to load config %s\n", stun_conf_file);
338 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
344 args.stun_poll_failed_gripe = 0;
347 args.monitor_enabled = 0;
350 for (v = ast_variable_browse(cfg,
"general"); v; v = v->
next) {
351 if (!strcasecmp(v->
name,
"stunaddr")) {
352 if (setup_stunaddr(v->
value, !startup)) {
353 ast_log(LOG_WARNING,
"Invalid STUN server address: %s at line %d\n",
354 v->
value, v->lineno);
356 }
else if (!strcasecmp(v->
name,
"stunrefresh")) {
357 if ((sscanf(v->
value,
"%30u", &args.refresh) != 1) || !args.refresh) {
358 ast_log(LOG_WARNING,
"Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->
value, v->lineno);
362 ast_log(LOG_WARNING,
"Invalid config option %s at line %d\n",
363 v->
value, v->lineno);
377 #define DATALN "%-25s %-5u %-7u %-8d %-7s %-16s %-d\n"
378 #define HEADER "%-25s %-5s %-7s %-8s %-7s %-16s %-s\n"
381 ast_cli(fd, HEADER,
"Hostname",
"Port",
"Period",
"Retries",
"Status",
"ExternAddr",
"ExternPort");
383 if (args.stun_poll_failed_gripe) {
385 }
else if (args.external_addr_known) {
391 args.server_hostname,
397 ntohs(args.external_addr.sin_port)
408 e->
command =
"stun show status";
410 "Usage: stun show status\n"
411 " List all known STUN servers and statuses.\n";
418 return CLI_SHOWUSAGE;
426 AST_CLI_DEFINE(handle_cli_stun_show_status,
"Show STUN servers and statuses"),
429 static int __reload(
int startup)
433 ast_mutex_lock(&
args.lock);
434 if (!(res = load_config(startup)) &&
args.monitor_enabled) {
435 res = stun_start_monitor();
437 ast_mutex_unlock(&
args.lock);
439 if (res < 0 || !
args.monitor_enabled) {
446 static int reload(
void)
454 ast_mutex_destroy(&
args.lock);
464 ast_mutex_init(&
args.lock);
467 ast_mutex_destroy(&
args.lock);
477 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"STUN Network Monitor",
478 .support_level = AST_MODULE_SUPPORT_CORE,
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
struct ast_variable * next
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes. ...
#define DEFAULT_MONITOR_REFRESH
static int stun_monitor_request(const void *blarg)
called by scheduler to send STUN request
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
static void _stun_show_status(int fd)
Execute stun show status command.
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Structure for variables, used for configurations and for channel variables.
int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result
Adds a scheduled event with rescheduling support.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ast_strdup(str)
A wrapper for strdup()
Socket address structure.
int args
This gets set in ast_cli_register()
Configuration File Parser.
struct sockaddr_in external_addr
int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
Splits a string into its host and port components.
Asterisk JSON abstraction layer.
#define ast_strdupa(s)
duplicate a string in memory from the stack
int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
Generic STUN request.
Access Control of various sorts.
Scheduler Routines (derived from cheops)
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
static int load_module(void)
int ast_get_ip(struct ast_sockaddr *addr, const char *hostname)
Get the IP address given a hostname.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Module has failed to load, may be in an inconsistent state.
Structure used to handle boolean flags.
unsigned int monitor_enabled
const char * server_hostname
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Standard Command Line Interface.
unsigned int stun_poll_failed_gripe
Abstract JSON element (object, array, string, int, ...).
static int unload_module(void)
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Structure for mutex and tracking information.
unsigned int external_addr_known