Sat Feb 11 06:36:38 2012

Asterisk developer's documentation


res_stun_monitor.c File Reference

STUN Network Monitor. More...

#include "asterisk.h"
#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 "asterisk/acl.h"
#include <fcntl.h>

Include dependency graph for res_stun_monitor.c:

Go to the source code of this file.

Defines

#define DEFAULT_MONITOR_REFRESH   30

Functions

static void __reg_module (void)
static int __reload (int startup)
static void __unreg_module (void)
static int load_config (int startup)
static int load_module (void)
static int reload (void)
static int setup_stunaddr (const char *value)
static void stun_close_sock (void)
static int stun_monitor_request (const void *blarg)
static int stun_start_monitor (void)
static void stun_stop_monitor (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "STUN Network Monitor" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND }
struct {
   struct sockaddr_in   external_addr
   unsigned int   external_addr_known:1
   ast_mutex_t   lock
   unsigned int   monitor_enabled:1
   unsigned int   refresh
   const char *   server_hostname
   unsigned int   stun_poll_failed_gripe:1
   unsigned int   stun_port
   int   stun_sock
args
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_sched_contextsched
static const char stun_conf_file [] = "res_stun_monitor.conf"


Detailed Description

STUN Network Monitor.

Author:
David Vossel <dvossel@digium.com>

Definition in file res_stun_monitor.c.


Define Documentation

#define DEFAULT_MONITOR_REFRESH   30

Default refresh period in seconds

Definition at line 44 of file res_stun_monitor.c.

Referenced by load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 398 of file res_stun_monitor.c.

static int __reload ( int  startup  )  [static]

Definition at line 352 of file res_stun_monitor.c.

References args, ast_mutex_lock, ast_mutex_unlock, load_config(), stun_start_monitor(), and stun_stop_monitor().

Referenced by load_module(), and reload().

00353 {
00354    int res;
00355 
00356    ast_mutex_lock(&args.lock);
00357    if (!(res = load_config(startup)) && args.monitor_enabled) {
00358       res = stun_start_monitor();
00359    }
00360    ast_mutex_unlock(&args.lock);
00361 
00362    if (res < 0 || !args.monitor_enabled) {
00363       stun_stop_monitor();
00364    }
00365 
00366    return res;
00367 }

static void __unreg_module ( void   )  [static]

Definition at line 398 of file res_stun_monitor.c.

static int load_config ( int  startup  )  [static]

Definition at line 303 of file res_stun_monitor.c.

References args, ast_config_destroy(), ast_config_load2(), ast_log(), ast_set_flag, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MONITOR_REFRESH, ast_variable::lineno, LOG_WARNING, ast_variable::name, ast_variable::next, setup_stunaddr(), stun_close_sock(), and ast_variable::value.

00304 {
00305    struct ast_flags config_flags = { 0, };
00306    struct ast_config *cfg;
00307    struct ast_variable *v;
00308 
00309    if (!startup) {
00310       ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
00311    }
00312 
00313    cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags);
00314    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
00315       ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file);
00316       return -1;
00317    }
00318    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00319       return 0;
00320    }
00321 
00322    /* clean up any previous open socket */
00323    stun_close_sock();
00324    args.stun_poll_failed_gripe = 0;
00325 
00326    /* set defaults */
00327    args.monitor_enabled = 0;
00328    args.refresh = DEFAULT_MONITOR_REFRESH;
00329 
00330    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00331       if (!strcasecmp(v->name, "stunaddr")) {
00332          if (setup_stunaddr(v->value)) {
00333             ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n",
00334                v->value, v->lineno);
00335          }
00336       } else if (!strcasecmp(v->name, "stunrefresh")) {
00337          if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
00338             ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
00339             args.refresh = DEFAULT_MONITOR_REFRESH;
00340          }
00341       } else {
00342          ast_log(LOG_WARNING, "Invalid config option %s at line %d\n",
00343             v->value, v->lineno);
00344       }
00345    }
00346 
00347    ast_config_destroy(cfg);
00348 
00349    return 0;
00350 }

static int load_module ( void   )  [static]

Definition at line 381 of file res_stun_monitor.c.

References __reload(), args, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_destroy, and ast_mutex_init.

00382 {
00383    ast_mutex_init(&args.lock);
00384    args.stun_sock = -1;
00385    if (__reload(1)) {
00386       ast_mutex_destroy(&args.lock);
00387       return AST_MODULE_LOAD_DECLINE;
00388    }
00389 
00390    return AST_MODULE_LOAD_SUCCESS;
00391 }

static int reload ( void   )  [static]

Definition at line 369 of file res_stun_monitor.c.

References __reload().

00370 {
00371    return __reload(0);
00372 }

static int setup_stunaddr ( const char *  value  )  [static]

Definition at line 253 of file res_stun_monitor.c.

References args, ast_free, ast_get_ip(), ast_log(), ast_sockaddr_split_hostport(), ast_strdup, ast_strdupa, ast_strlen_zero(), LOG_WARNING, ast_sockaddr::ss, and STANDARD_STUN_PORT.

Referenced by load_config().

00254 {
00255    char *val;
00256    char *host_str;
00257    char *port_str;
00258    unsigned int port;
00259    struct ast_sockaddr stun_addr;
00260 
00261    if (ast_strlen_zero(value)) {
00262       /* Setting to an empty value disables STUN monitoring. */
00263       args.monitor_enabled = 0;
00264       return 0;
00265    }
00266 
00267    val = ast_strdupa(value);
00268    if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0)
00269       || ast_strlen_zero(host_str)) {
00270       return -1;
00271    }
00272 
00273    /* Determine STUN port */
00274    if (ast_strlen_zero(port_str)
00275       || 1 != sscanf(port_str, "%30u", &port)) {
00276       port = STANDARD_STUN_PORT;
00277    }
00278 
00279    host_str = ast_strdup(host_str);
00280    if (!host_str) {
00281       return -1;
00282    }
00283 
00284    /* Lookup STUN address. */
00285    memset(&stun_addr, 0, sizeof(stun_addr));
00286    stun_addr.ss.ss_family = AF_INET;
00287    if (ast_get_ip(&stun_addr, host_str)) {
00288       ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str);
00289       ast_free(host_str);
00290       return -1;
00291    }
00292 
00293    /* Save STUN server information. */
00294    ast_free((char *) args.server_hostname);
00295    args.server_hostname = host_str;
00296    args.stun_port = port;
00297 
00298    /* Enable STUN monitor */
00299    args.monitor_enabled = 1;
00300    return 0;
00301 }

static void stun_close_sock ( void   )  [static]

Definition at line 70 of file res_stun_monitor.c.

References args.

Referenced by load_config(), stun_monitor_request(), stun_start_monitor(), and stun_stop_monitor().

00071 {
00072    if (0 <= args.stun_sock) {
00073       close(args.stun_sock);
00074       args.stun_sock = -1;
00075    }
00076 }

static int stun_monitor_request ( const void *  blarg  )  [static]

Definition at line 79 of file res_stun_monitor.c.

References args, ast_connect(), ast_event_destroy(), AST_EVENT_IE_END, AST_EVENT_NETWORK_CHANGE, ast_event_new(), ast_event_queue(), ast_get_ip(), ast_inet_ntoa(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_sockaddr_set_port, ast_sockaddr_stringify(), ast_strdupa, ast_stun_request(), errno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_sockaddr::ss, and stun_close_sock().

Referenced by stun_start_monitor().

00080 {
00081    int res;
00082    struct sockaddr_in answer;
00083    static const struct sockaddr_in no_addr = { 0, };
00084 
00085    ast_mutex_lock(&args.lock);
00086    if (!args.monitor_enabled) {
00087       goto monitor_request_cleanup;
00088    }
00089 
00090    if (args.stun_sock < 0) {
00091       struct ast_sockaddr stun_addr;
00092 
00093       /* STUN socket not open.  Refresh the server DNS address resolution. */
00094       if (!args.server_hostname) {
00095          /* No STUN hostname? */
00096          goto monitor_request_cleanup;
00097       }
00098 
00099       /* Lookup STUN address. */
00100       memset(&stun_addr, 0, sizeof(stun_addr));
00101       stun_addr.ss.ss_family = AF_INET;
00102       if (ast_get_ip(&stun_addr, args.server_hostname)) {
00103          /* Lookup failed. */
00104          ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n",
00105             args.server_hostname);
00106          goto monitor_request_cleanup;
00107       }
00108       ast_sockaddr_set_port(&stun_addr, args.stun_port);
00109 
00110       /* open socket binding */
00111       args.stun_sock = socket(AF_INET, SOCK_DGRAM, 0);
00112       if (args.stun_sock < 0) {
00113          ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
00114          goto monitor_request_cleanup;
00115       }
00116       if (ast_connect(args.stun_sock, &stun_addr)) {
00117          ast_log(LOG_WARNING, "STUN Failed to connect to %s: %s\n",
00118             ast_sockaddr_stringify(&stun_addr), strerror(errno));
00119          stun_close_sock();
00120          goto monitor_request_cleanup;
00121       }
00122    }
00123 
00124    res = ast_stun_request(args.stun_sock, NULL, NULL, &answer);
00125    if (res) {
00126       /*
00127        * STUN request timed out or errored.
00128        *
00129        * Refresh the server DNS address resolution next time around.
00130        */
00131       if (!args.stun_poll_failed_gripe) {
00132          args.stun_poll_failed_gripe = 1;
00133          ast_log(LOG_WARNING, "STUN poll %s. Re-evaluating STUN server address.\n",
00134             res < 0 ? "failed" : "got no response");
00135       }
00136       stun_close_sock();
00137    } else {
00138       args.stun_poll_failed_gripe = 0;
00139       if (memcmp(&no_addr, &answer, sizeof(no_addr))
00140          && memcmp(&args.external_addr, &answer, sizeof(args.external_addr))) {
00141          const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
00142          int newport = ntohs(answer.sin_port);
00143 
00144          ast_log(LOG_NOTICE, "Old external address/port %s:%d now seen as %s:%d.\n",
00145             ast_inet_ntoa(args.external_addr.sin_addr),
00146             ntohs(args.external_addr.sin_port), newaddr, newport);
00147 
00148          args.external_addr = answer;
00149 
00150          if (args.external_addr_known) {
00151             struct ast_event *event;
00152 
00153             /*
00154              * The external address was already known, and has changed...
00155              * generate event.
00156              */
00157             event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
00158             if (!event) {
00159                ast_log(LOG_ERROR, "Could not create AST_EVENT_NETWORK_CHANGE event.\n");
00160             } else if (ast_event_queue(event)) {
00161                ast_event_destroy(event);
00162                ast_log(LOG_ERROR, "Could not queue AST_EVENT_NETWORK_CHANGE event.\n");
00163             }
00164          } else {
00165             /* this was the first external address we found, do not alert listeners
00166              * until this address changes to something else. */
00167             args.external_addr_known = 1;
00168          }
00169       }
00170    }
00171 
00172 monitor_request_cleanup:
00173    /* always refresh this scheduler item.  It will be removed elsewhere when
00174     * it is supposed to go away */
00175    res = args.refresh * 1000;
00176    ast_mutex_unlock(&args.lock);
00177 
00178    return res;
00179 }

static int stun_start_monitor ( void   )  [static]

Definition at line 213 of file res_stun_monitor.c.

References args, ast_log(), ast_sched_add_variable(), ast_sched_context_create(), ast_sched_context_destroy(), ast_sched_start_thread(), LOG_ERROR, LOG_NOTICE, stun_close_sock(), and stun_monitor_request().

Referenced by __reload().

00214 {
00215    /* if scheduler thread is not started, make sure to start it now */
00216    if (sched) {
00217       return 0; /* already started */
00218    }
00219 
00220    if (!(sched = ast_sched_context_create())) {
00221       ast_log(LOG_ERROR, "Failed to create stun monitor scheduler context\n");
00222       return -1;
00223    }
00224 
00225    if (ast_sched_start_thread(sched)) {
00226       ast_sched_context_destroy(sched);
00227       sched = NULL;
00228       stun_close_sock();
00229       return -1;
00230    }
00231 
00232    if (ast_sched_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
00233       ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
00234       ast_sched_context_destroy(sched);
00235       sched = NULL;
00236       return -1;
00237    }
00238 
00239    ast_log(LOG_NOTICE, "STUN monitor started\n");
00240 
00241    return 0;
00242 }

static void stun_stop_monitor ( void   )  [static]

Definition at line 189 of file res_stun_monitor.c.

References args, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_sched_context_destroy(), LOG_NOTICE, and stun_close_sock().

Referenced by __reload(), and unload_module().

00190 {
00191    ast_mutex_lock(&args.lock);
00192    args.monitor_enabled = 0;
00193    ast_free((char *) args.server_hostname);
00194    args.server_hostname = NULL;
00195    stun_close_sock();
00196    ast_mutex_unlock(&args.lock);
00197 
00198    if (sched) {
00199       ast_sched_context_destroy(sched);
00200       sched = NULL;
00201       ast_log(LOG_NOTICE, "STUN monitor stopped\n");
00202    }
00203 }

static int unload_module ( void   )  [static]

Definition at line 374 of file res_stun_monitor.c.

References args, ast_mutex_destroy, and stun_stop_monitor().

00375 {
00376    stun_stop_monitor();
00377    ast_mutex_destroy(&args.lock);
00378    return 0;
00379 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "STUN Network Monitor" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND } [static]

Definition at line 398 of file res_stun_monitor.c.

struct { ... } args [static]

Referenced by __reload(), acf_curl_helper(), acf_isexten_exec(), acf_jabberreceive_read(), acf_jabberstatus_read(), acf_meetme_info(), acf_odbc_read(), acf_odbc_write(), acf_rand_exec(), acf_strftime(), acf_strptime(), acf_transaction_read(), acf_transaction_write(), acf_version_exec(), acf_vmcount_exec(), add_agent(), add_cfg_entry(), add_rt_cfg_entry(), add_rt_multi_cfg_entry(), admin_exec(), adsi_process(), aelsub_exec(), aes_helper(), agi_exec_full(), aji_join_exec(), aji_leave_exec(), aji_send_exec(), aji_sendgroup_exec(), aji_status_exec(), answer_exec_enable(), app_exec(), aqm_exec(), ast_cc_agent_status_response(), ast_cli_command_full(), ast_eivr_senddtmf(), ast_func_read(), ast_func_read2(), ast_func_write(), ast_queue_log(), asyncgoto_exec(), background_detect_exec(), bridge_exec(), build_profile(), builtin_automixmonitor(), builtin_automonitor(), calendar_query_exec(), calendar_query_result_exec(), callerid_read(), cc_do_state_change(), cc_request_state_change(), cc_status_response(), cdr_read(), cdr_write(), celgenuserevent_exec(), chanavail_exec(), channel_admin_exec(), channel_set_debug(), chanspy_exec(), cli_odbc_read(), cli_odbc_write(), conf_exec(), confbridge_exec(), config_function_read(), controlplayback_exec(), count_exec(), cut_internal(), dahdi_call(), dahdiras_exec(), determine_starting_point(), dial_exec_full(), dial_trunk(), dialgroup_write(), dictate_exec(), directory_exec(), disa_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enable_jack_hook(), enum_query_read(), enum_result_read(), exec_exec(), extenspy_exec(), festival_exec(), file_count_line(), file_read(), file_write(), filter(), find_call(), find_conf(), find_realtime_gw(), func_args(), func_confbridge_info(), func_header_read(), function_agent(), function_db_delete(), function_db_exists(), function_db_read(), function_db_write(), function_enum(), function_fieldnum_helper(), function_fieldqty_helper(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_write(), function_txtcidname(), gosubif_exec(), handle_verbose(), hint_read(), iconv_read(), import_helper(), isAnsweringMachine(), isexten_function_read(), jb_debug_output(), jb_error_output(), jb_framedata_init(), jb_warning_output(), listfilter(), load_config(), load_module(), log_exec(), login_exec(), man_do_variable_value(), manager_mixmonitor(), math(), misdn_call(), misdn_check_l2l1(), misdn_facility_exec(), misdn_request(), mixmonitor_exec(), msg_send_exec(), originate_exec(), ospauth_exec(), ospfinished_exec(), osplookup_exec(), ospnext_exec(), oss_call(), oss_request(), page_exec(), parkandannounce_exec(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_resetcdr(), pbx_builtin_setvar_multiple(), pbx_builtin_waitexten(), peek_read(), pickup_by_name_cb(), pickupchan_exec(), playback_exec(), pp_each_extension_helper(), pp_each_user_helper(), pqm_exec(), privacy_exec(), process_applicationmap_line(), ql_exec(), queue_exec(), queue_function_mem_read(), queue_function_mem_write(), queue_function_memberpenalty_read(), queue_function_memberpenalty_write(), rcvfax_exec(), realtimefield_read(), receivefax_exec(), record_exec(), reg_source_db(), regex(), reload_single_member(), replace(), retrydial_exec(), rqm_exec(), run_station(), saycountedadj_exec(), saycountednoun_exec(), sayunixtime_exec(), senddtmf_exec(), sendfax_exec(), sendurl_exec(), setup_stunaddr(), shared_read(), shared_write(), shift_pop(), sip_acf_channel_read(), sip_request_call(), sip_tcptls_client_args_destructor(), sla_trunk_exec(), smdi_msg_read(), smdi_msg_retrieve_read(), sndfax_exec(), softhangup_exec(), speech_background(), speech_load(), srv_result_read(), start_monitor_exec(), static_realtime_cb(), stop_mixmonitor_exec(), strreplace(), stun_close_sock(), stun_monitor_request(), stun_start_monitor(), stun_stop_monitor(), transfer_exec(), tryexec_exec(), unload_module(), unshift_push(), upqm_exec(), userevent_exec(), verbose_exec(), vm_box_exists(), vm_exec(), vm_execmain(), volume_write(), and zapateller_exec().

Definition at line 398 of file res_stun_monitor.c.

struct sockaddr_in external_addr

Current perceived external address.

Definition at line 53 of file res_stun_monitor.c.

unsigned int external_addr_known

TRUE if the perceived external address is valid/known.

Definition at line 65 of file res_stun_monitor.c.

STUN monitor protection lock.

Definition at line 51 of file res_stun_monitor.c.

unsigned int monitor_enabled

TRUE if the STUN monitor is enabled.

Definition at line 63 of file res_stun_monitor.c.

unsigned int refresh

Number of seconds between polls to the STUN server for the external address.

Definition at line 59 of file res_stun_monitor.c.

Referenced by iax2_ack_registry().

struct ast_sched_context* sched [static]

Definition at line 47 of file res_stun_monitor.c.

const char* server_hostname

STUN server host name.

Definition at line 55 of file res_stun_monitor.c.

const char stun_conf_file[] = "res_stun_monitor.conf" [static]

Definition at line 46 of file res_stun_monitor.c.

unsigned int stun_poll_failed_gripe

TRUE if we have already griped about a STUN poll failing.

Definition at line 67 of file res_stun_monitor.c.

unsigned int stun_port

Port of STUN server to use

Definition at line 57 of file res_stun_monitor.c.

int stun_sock

Monitoring STUN socket.

Definition at line 61 of file res_stun_monitor.c.


Generated on Sat Feb 11 06:36:38 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6