00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 291192 $")
00029
00030 #include "asterisk/module.h"
00031 #include "asterisk/event.h"
00032 #include "asterisk/sched.h"
00033 #include "asterisk/config.h"
00034 #include "asterisk/stun.h"
00035 #include "asterisk/netsock2.h"
00036 #include "asterisk/lock.h"
00037 #include <fcntl.h>
00038
00039 static const int DEFAULT_MONITOR_REFRESH = 30;
00040
00041 static const char stun_conf_file[] = "res_stun_monitor.conf";
00042 static struct ast_sched_thread *sched;
00043
00044 static struct {
00045 struct sockaddr_in stunaddr;
00046 struct sockaddr_in externaladdr;
00047 ast_mutex_t lock;
00048 unsigned int refresh;
00049 int stunsock;
00050 unsigned int monitor_enabled:1;
00051 unsigned int externaladdr_known:1;
00052 } args;
00053
00054 static inline void stun_close_sock(void)
00055 {
00056 if (args.stunsock != -1) {
00057 close(args.stunsock);
00058 args.stunsock = -1;
00059 memset(&args.externaladdr, 0, sizeof(args.externaladdr));
00060 args.externaladdr_known = 0;
00061 }
00062 }
00063
00064
00065
00066
00067
00068
00069
00070
00071 static void stun_purge_socket(void)
00072 {
00073 int flags = fcntl(args.stunsock, F_GETFL);
00074 int res = 0;
00075 unsigned char reply_buf[1024];
00076
00077 fcntl(args.stunsock, F_SETFL, flags | O_NONBLOCK);
00078 while (res != -1) {
00079
00080 res = recv(args.stunsock, reply_buf, sizeof(reply_buf), 0);
00081 }
00082 fcntl(args.stunsock, F_SETFL, flags & ~O_NONBLOCK);
00083 }
00084
00085
00086 static int stun_monitor_request(const void *blarg)
00087 {
00088 int res;
00089 int generate_event = 0;
00090 struct sockaddr_in answer = { 0, };
00091
00092
00093
00094 ast_mutex_lock(&args.lock);
00095 if (args.stunsock == -1) {
00096 ast_log(LOG_ERROR, "STUN monitor: can not send STUN request, socket is not open\n");
00097 goto monitor_request_cleanup;
00098 }
00099
00100 stun_purge_socket();
00101
00102 if (!(ast_stun_request(args.stunsock, &args.stunaddr, NULL, &answer)) &&
00103 (memcmp(&args.externaladdr, &answer, sizeof(args.externaladdr)))) {
00104 const char *newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
00105 int newport = ntohs(answer.sin_port);
00106
00107 ast_log(LOG_NOTICE, "STUN MONITOR: Old external address/port %s:%d now seen as %s:%d \n",
00108 ast_inet_ntoa(args.externaladdr.sin_addr), ntohs(args.externaladdr.sin_port),
00109 newaddr, newport);
00110
00111 memcpy(&args.externaladdr, &answer, sizeof(args.externaladdr));
00112
00113 if (args.externaladdr_known) {
00114
00115 generate_event = 1;
00116
00117 } else {
00118
00119
00120 args.externaladdr_known = 1;
00121 }
00122 }
00123
00124 if (generate_event) {
00125 struct ast_event *event = ast_event_new(AST_EVENT_NETWORK_CHANGE, AST_EVENT_IE_END);
00126 if (!event) {
00127 ast_log(LOG_ERROR, "STUN monitor: could not create AST_EVENT_NETWORK_CHANGE event.\n");
00128 goto monitor_request_cleanup;
00129 }
00130 if (ast_event_queue(event)) {
00131 ast_event_destroy(event);
00132 event = NULL;
00133 ast_log(LOG_ERROR, "STUN monitor: could not queue AST_EVENT_NETWORK_CHANGE event.\n");
00134 goto monitor_request_cleanup;
00135 }
00136 }
00137
00138 monitor_request_cleanup:
00139
00140
00141 res = args.refresh * 1000;
00142 ast_mutex_unlock(&args.lock);
00143
00144 return res;
00145 }
00146
00147
00148
00149
00150 static void stun_stop_monitor(void)
00151 {
00152 if (sched) {
00153 sched = ast_sched_thread_destroy(sched);
00154 ast_log(LOG_NOTICE, "STUN monitor stopped\n");
00155 }
00156
00157
00158 stun_close_sock();
00159 }
00160
00161
00162
00163
00164 static int stun_start_monitor(void)
00165 {
00166 struct ast_sockaddr dst;
00167
00168 stun_close_sock();
00169
00170
00171 ast_sockaddr_from_sin(&dst, &args.stunaddr);
00172
00173
00174 args.stunsock = socket(AF_INET, SOCK_DGRAM, 0);
00175 if (args.stunsock < 0) {
00176 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
00177 return -1;
00178 }
00179
00180 if (ast_connect(args.stunsock, &dst) != 0) {
00181 ast_log(LOG_WARNING, "SIP STUN Failed to connect to %s\n", ast_sockaddr_stringify(&dst));
00182 stun_close_sock();
00183 return -1;
00184 }
00185
00186
00187 if (sched) {
00188 return 0;
00189 }
00190
00191 if (!(sched = ast_sched_thread_create())) {
00192 ast_log(LOG_ERROR, "Failed to create stun monitor scheduler thread\n");
00193 stun_close_sock();
00194 return -1;
00195 }
00196
00197 if (ast_sched_thread_add_variable(sched, (args.refresh * 1000), stun_monitor_request, NULL, 1) < 0) {
00198 ast_log(LOG_ERROR, "Unable to schedule STUN network monitor \n");
00199 sched = ast_sched_thread_destroy(sched);
00200 stun_close_sock();
00201 return -1;
00202 }
00203
00204 ast_log(LOG_NOTICE, "STUN monitor started\n");
00205 return 0;
00206 }
00207
00208 static int load_config(int startup)
00209 {
00210 struct ast_flags config_flags = { 0, };
00211 struct ast_config *cfg;
00212 struct ast_variable *v;
00213
00214 if (!startup) {
00215 ast_set_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
00216 }
00217
00218 if (!(cfg = ast_config_load2(stun_conf_file, "res_stun_monitor", config_flags)) ||
00219 cfg == CONFIG_STATUS_FILEINVALID) {
00220 ast_log(LOG_ERROR, "Unable to load config %s\n", stun_conf_file);
00221 return -1;
00222 }
00223
00224 if (cfg == CONFIG_STATUS_FILEUNCHANGED && !startup) {
00225 return 0;
00226 }
00227
00228
00229 args.monitor_enabled = 0;
00230 memset(&args.stunaddr, 0, sizeof(args.stunaddr));
00231 args.refresh = DEFAULT_MONITOR_REFRESH;
00232
00233 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00234 if (!strcasecmp(v->name, "stunaddr")) {
00235 args.stunaddr.sin_port = htons(STANDARD_STUN_PORT);
00236 if (ast_parse_arg(v->value, PARSE_INADDR, &args.stunaddr)) {
00237 ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", v->value);
00238 } else {
00239 ast_log(LOG_NOTICE, "STUN monitor enabled: %s\n", v->value);
00240 args.monitor_enabled = 1;
00241 }
00242 } else if (!strcasecmp(v->name, "stunrefresh")) {
00243 if ((sscanf(v->value, "%30u", &args.refresh) != 1) || !args.refresh) {
00244 ast_log(LOG_WARNING, "Invalid stunrefresh value '%s', must be an integer > 0 at line %d\n", v->value, v->lineno);
00245 args.refresh = DEFAULT_MONITOR_REFRESH;
00246 } else {
00247 ast_log(LOG_NOTICE, "STUN Monitor set to refresh every %d seconds\n", args.refresh);
00248 }
00249 } else {
00250 ast_log(LOG_WARNING, "SIP STUN: invalid config option %s at line %d\n", v->value, v->lineno);
00251 }
00252 }
00253
00254 ast_config_destroy(cfg);
00255
00256 return 0;
00257 }
00258
00259 static int __reload(int startup)
00260 {
00261 int res;
00262
00263 ast_mutex_lock(&args.lock);
00264 if (!(res = load_config(startup)) && args.monitor_enabled) {
00265 res = stun_start_monitor();
00266 }
00267 ast_mutex_unlock(&args.lock);
00268
00269 if ((res == -1) || !args.monitor_enabled) {
00270 args.monitor_enabled = 0;
00271 stun_stop_monitor();
00272 }
00273
00274 return res;
00275 }
00276
00277 static int reload(void)
00278 {
00279 return __reload(0);
00280 }
00281
00282 static int unload_module(void)
00283 {
00284 stun_stop_monitor();
00285 ast_mutex_destroy(&args.lock);
00286 return 0;
00287 }
00288
00289 static int load_module(void)
00290 {
00291 ast_mutex_init(&args.lock);
00292 args.stunsock = -1;
00293 memset(&args.externaladdr, 0, sizeof(args.externaladdr));
00294 args.externaladdr_known = 0;
00295 sched = NULL;
00296 if (__reload(1)) {
00297 stun_stop_monitor();
00298 ast_mutex_destroy(&args.lock);
00299 return AST_MODULE_LOAD_DECLINE;
00300 }
00301
00302 return AST_MODULE_LOAD_SUCCESS;
00303 }
00304
00305 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "STUN Network Monitor",
00306 .load = load_module,
00307 .unload = unload_module,
00308 .reload = reload,
00309 .load_pri = AST_MODPRI_CHANNEL_DEPEND
00310 );