Wed Aug 7 17:15:45 2019

Asterisk developer's documentation


res_stun_monitor.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * David Vossel <dvossel@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief STUN Network Monitor
00022  *
00023  * \author David Vossel <dvossel@digium.com>
00024  */
00025 
00026 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 346700 $")
00033 
00034 #include "asterisk/module.h"
00035 #include "asterisk/event.h"
00036 #include "asterisk/sched.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/stun.h"
00039 #include "asterisk/netsock2.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/acl.h"
00042 #include <fcntl.h>
00043 
00044 #define DEFAULT_MONITOR_REFRESH 30  /*!< Default refresh period in seconds */
00045 
00046 static const char stun_conf_file[] = "res_stun_monitor.conf";
00047 static struct ast_sched_thread *sched;
00048 
00049 static struct {
00050    /*! STUN monitor protection lock. */
00051    ast_mutex_t lock;
00052    /*! Current perceived external address. */
00053    struct sockaddr_in external_addr;
00054    /*! STUN server host name. */
00055    const char *server_hostname;
00056    /*! Port of STUN server to use */
00057    unsigned int stun_port;
00058    /*! Number of seconds between polls to the STUN server for the external address. */
00059    unsigned int refresh;
00060    /*! Monitoring STUN socket. */
00061    int stun_sock;
00062    /*! TRUE if the STUN monitor is enabled. */
00063    unsigned int monitor_enabled:1;
00064    /*! TRUE if the perceived external address is valid/known. */
00065    unsigned int external_addr_known:1;
00066    /*! TRUE if we have already griped about a STUN poll failing. */
00067    unsigned int stun_poll_failed_gripe:1;
00068 } args;
00069 
00070 static void stun_close_sock(void)
00071 {
00072    if (0 <= args.stun_sock) {
00073       close(args.stun_sock);
00074       args.stun_sock = -1;
00075    }
00076 }
00077 
00078 /* \brief called by scheduler to send STUN request */
00079 static int stun_monitor_request(const void *blarg)
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 }
00180 
00181 /*!
00182  * \internal
00183  * \brief Stops the STUN monitor thread.
00184  *
00185  * \note do not hold the args->lock while calling this
00186  *
00187  * \return Nothing
00188  */
00189 static void stun_stop_monitor(void)
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       sched = ast_sched_thread_destroy(sched);
00200       ast_log(LOG_NOTICE, "STUN monitor stopped\n");
00201    }
00202 }
00203 
00204 /*!
00205  * \internal
00206  * \brief Starts the STUN monitor thread.
00207  *
00208  * \note The args->lock MUST be held when calling this function
00209  *
00210  * \return Nothing
00211  */
00212 static int stun_start_monitor(void)
00213 {
00214    /* if scheduler thread is not started, make sure to start it now */
00215    if (sched) {
00216       return 0; /* already started */
00217    }
00218 
00219    if (!(sched = ast_sched_thread_create())) {
00220       ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
00221       return -1;
00222    }
00223 
00224    if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
00225       ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
00226       sched = ast_sched_thread_destroy(sched);
00227       return -1;
00228    }
00229 
00230    ast_log(LOG_NOTICE, "STUN monitor started\n");
00231    return 0;
00232 }
00233 
00234 /*!
00235  * \internal
00236  * \brief Parse and setup the stunaddr parameter.
00237  *
00238  * \param value Configuration parameter variable value.
00239  *
00240  * \retval 0 on success.
00241  * \retval -1 on error.
00242  */
00243 static int setup_stunaddr(const char *value)
00244 {
00245    char *val;
00246    char *host_str;
00247    char *port_str;
00248    unsigned int port;
00249    struct ast_sockaddr stun_addr;
00250 
00251    if (ast_strlen_zero(value)) {
00252       /* Setting to an empty value disables STUN monitoring. */
00253       args.monitor_enabled = 0;
00254       return 0;
00255    }
00256 
00257    val = ast_strdupa(value);
00258    if (!ast_sockaddr_split_hostport(val, &host_str, &port_str, 0)
00259       || ast_strlen_zero(host_str)) {
00260       return -1;
00261    }
00262 
00263    /* Determine STUN port */
00264    if (ast_strlen_zero(port_str)
00265       || 1 != sscanf(port_str, "%30u", &port)) {
00266       port = STANDARD_STUN_PORT;
00267    }
00268 
00269    host_str = ast_strdup(host_str);
00270    if (!host_str) {
00271       return -1;
00272    }
00273 
00274    /* Lookup STUN address. */
00275    memset(&stun_addr, 0, sizeof(stun_addr));
00276    stun_addr.ss.ss_family = AF_INET;
00277    if (ast_get_ip(&stun_addr, host_str)) {
00278       ast_log(LOG_WARNING, "Unable to lookup STUN server '%s'\n", host_str);
00279       ast_free(host_str);
00280       return -1;
00281    }
00282 
00283    /* Save STUN server information. */
00284    ast_free((char *) args.server_hostname);
00285    args.server_hostname = host_str;
00286    args.stun_port = port;
00287 
00288    /* Enable STUN monitor */
00289    args.monitor_enabled = 1;
00290    return 0;
00291 }
00292 
00293 static int load_config(int startup)
00294 {
00295    struct ast_flags config_flags = { 0, };
00296    struct ast_config *cfg;
00297    struct ast_variable *v;
00298 
00299    if (!startup) {
00300       ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
00301    }
00302 
00303    cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags);
00304    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
00305       ast_log(LOG_WARNING, "Unable to load config %s\n", stun_conf_file);
00306       return -1;
00307    }
00308    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00309       return 0;
00310    }
00311 
00312    /* clean up any previous open socket */
00313    stun_close_sock();
00314    args.stun_poll_failed_gripe = 0;
00315 
00316    /* set defaults */
00317    args.monitor_enabled = 0;
00318    args.refresh = DEFAULT_MONITOR_REFRESH;
00319 
00320    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00321       if (!strcasecmp(v->name, "stunaddr")) {
00322          if (setup_stunaddr(v->value)) {
00323             ast_log(LOG_WARNING, "Invalid STUN server address: %s at line %d\n",
00324                v->value, v->lineno);
00325          }
00326       } else if (!strcasecmp(v->name, "stunrefresh")) {
00327          if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
00328             ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
00329             args.refresh = DEFAULT_MONITOR_REFRESH;
00330          }
00331       } else {
00332          ast_log(LOG_WARNING, "Invalid config option %s at line %d\n",
00333             v->value, v->lineno);
00334       }
00335    }
00336 
00337    ast_config_destroy(cfg);
00338 
00339    return 0;
00340 }
00341 
00342 static int __reload(int startup)
00343 {
00344    int res;
00345 
00346    ast_mutex_lock(&args.lock);
00347    if (!(res = load_config(startup)) && args.monitor_enabled) {
00348       res = stun_start_monitor();
00349    }
00350    ast_mutex_unlock(&args.lock);
00351 
00352    if (res < 0 || !args.monitor_enabled) {
00353       stun_stop_monitor();
00354    }
00355 
00356    return res;
00357 }
00358 
00359 static int reload(void)
00360 {
00361    return __reload(0);
00362 }
00363 
00364 static int unload_module(void)
00365 {
00366    stun_stop_monitor();
00367    ast_mutex_destroy(&args.lock);
00368    return 0;
00369 }
00370 
00371 static int load_module(void)
00372 {
00373    ast_mutex_init(&args.lock);
00374    args.stun_sock = -1;
00375    if (__reload(1)) {
00376       ast_mutex_destroy(&args.lock);
00377       return AST_MODULE_LOAD_DECLINE;
00378    }
00379 
00380    return AST_MODULE_LOAD_SUCCESS;
00381 }
00382 
00383 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
00384       .load = load_module,
00385       .unload = unload_module,
00386       .reload = reload,
00387       .load_pri = AST_MODPRI_CHANNEL_DEPEND
00388    );

Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1