Sat Jul 26 06:14:06 2008

Asterisk developer's documentation


dnsmgr.c File Reference

Background DNS update manager. More...

#include "asterisk.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <regex.h>
#include <signal.h>
#include "asterisk/dnsmgr.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/sched.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"

Include dependency graph for dnsmgr.c:

Go to the source code of this file.

Data Structures

struct  ast_dnsmgr_entry
struct  refresh_info

Defines

#define REFRESH_DEFAULT   300

Functions

int ast_dnsmgr_changed (struct ast_dnsmgr_entry *entry)
 Check is see if a dnsmgr entry has changed.
ast_dnsmgr_entryast_dnsmgr_get (const char *name, struct in_addr *result)
int ast_dnsmgr_lookup (const char *name, struct in_addr *result, struct ast_dnsmgr_entry **dnsmgr)
int ast_dnsmgr_refresh (struct ast_dnsmgr_entry *entry)
 Force a refresh of a dnsmgr entry.
void ast_dnsmgr_release (struct ast_dnsmgr_entry *entry)
static AST_LIST_HEAD_STATIC (entry_list, ast_dnsmgr_entry)
 AST_MUTEX_DEFINE_STATIC (refresh_lock)
int dnsmgr_init (void)
static int dnsmgr_refresh (struct ast_dnsmgr_entry *entry, int verbose)
int dnsmgr_reload (void)
void dnsmgr_start_refresh (void)
static void * do_refresh (void *data)
static int do_reload (int loading)
static int handle_cli_refresh (int fd, int argc, char *argv[])
static int handle_cli_reload (int fd, int argc, char *argv[])
static int handle_cli_status (int fd, int argc, char *argv[])
static int refresh_list (const void *data)

Variables

static struct ast_cli_entry cli_refresh
static struct ast_cli_entry cli_reload
static struct ast_cli_entry cli_status
static int enabled
static struct refresh_info master_refresh_info
static int refresh_interval
static int refresh_sched = -1
static pthread_t refresh_thread = AST_PTHREADT_NULL
static struct sched_contextsched


Detailed Description

Background DNS update manager.

Author:
Kevin P. Fleming <kpfleming@digium.com>

Definition in file dnsmgr.c.


Define Documentation

#define REFRESH_DEFAULT   300

Definition at line 72 of file dnsmgr.c.

Referenced by do_reload().


Function Documentation

int ast_dnsmgr_changed ( struct ast_dnsmgr_entry entry  ) 

Check is see if a dnsmgr entry has changed.

Return values:
non-zero if the dnsmgr entry has changed since the last call to this function
zero if the dnsmgr entry has not changed since the last call to this function

Definition at line 198 of file dnsmgr.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_dnsmgr_entry::changed, and ast_dnsmgr_entry::lock.

Referenced by iax2_do_register().

00199 {
00200    int changed;
00201 
00202    ast_mutex_lock(&entry->lock);
00203 
00204    changed = entry->changed;
00205    entry->changed = 0;
00206 
00207    ast_mutex_unlock(&entry->lock);
00208    
00209    return changed;
00210 }

struct ast_dnsmgr_entry* ast_dnsmgr_get ( const char *  name,
struct in_addr *  result 
)

Definition at line 89 of file dnsmgr.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_init(), ast_strlen_zero(), and ast_dnsmgr_entry::result.

Referenced by ast_dnsmgr_lookup().

00090 {
00091    struct ast_dnsmgr_entry *entry;
00092 
00093    if (!result || ast_strlen_zero(name) || !(entry = ast_calloc(1, sizeof(*entry) + strlen(name))))
00094       return NULL;
00095 
00096    entry->result = result;
00097    ast_mutex_init(&entry->lock);
00098    strcpy(entry->name, name);
00099    memcpy(&entry->last, result, sizeof(entry->last));
00100 
00101    AST_LIST_LOCK(&entry_list);
00102    AST_LIST_INSERT_HEAD(&entry_list, entry, list);
00103    AST_LIST_UNLOCK(&entry_list);
00104 
00105    return entry;
00106 }

int ast_dnsmgr_lookup ( const char *  name,
struct in_addr *  result,
struct ast_dnsmgr_entry **  dnsmgr 
)

Definition at line 123 of file dnsmgr.c.

References ahp, ast_dnsmgr_get(), ast_gethostbyname(), ast_strlen_zero(), ast_verbose(), enabled, hp, option_verbose, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_4.

Referenced by build_peer(), and iax2_register().

00124 {
00125    struct ast_hostent ahp;
00126    struct hostent *hp;
00127 
00128    if (ast_strlen_zero(name) || !result || !dnsmgr)
00129       return -1;
00130 
00131    if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name))
00132       return 0;
00133 
00134    if (option_verbose > 3)
00135       ast_verbose(VERBOSE_PREFIX_4 "doing dnsmgr_lookup for '%s'\n", name);
00136 
00137    /* if it's actually an IP address and not a name,
00138       there's no need for a managed lookup */
00139    if (inet_aton(name, result))
00140       return 0;
00141 
00142    /* do a lookup now but add a manager so it will automagically get updated in the background */
00143    if ((hp = ast_gethostbyname(name, &ahp)))
00144       memcpy(result, hp->h_addr, sizeof(result));
00145    
00146    /* if dnsmgr is not enable don't bother adding an entry */
00147    if (!enabled)
00148       return 0;
00149    
00150    if (option_verbose > 2)
00151       ast_verbose(VERBOSE_PREFIX_2 "adding dns manager for '%s'\n", name);
00152    *dnsmgr = ast_dnsmgr_get(name, result);
00153    return !*dnsmgr;
00154 }

int ast_dnsmgr_refresh ( struct ast_dnsmgr_entry entry  ) 

Force a refresh of a dnsmgr entry.

Return values:
non-zero if the result is different than the previous result
zero if the result is the same as the previous result

Definition at line 190 of file dnsmgr.c.

References dnsmgr_refresh().

Referenced by iax2_do_register().

00191 {
00192    return dnsmgr_refresh(entry, 0);
00193 }

void ast_dnsmgr_release ( struct ast_dnsmgr_entry entry  ) 

Definition at line 108 of file dnsmgr.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_verbose(), free, ast_dnsmgr_entry::lock, option_verbose, and VERBOSE_PREFIX_4.

Referenced by delete_users(), and peer_destructor().

00109 {
00110    if (!entry)
00111       return;
00112 
00113    AST_LIST_LOCK(&entry_list);
00114    AST_LIST_REMOVE(&entry_list, entry, list);
00115    AST_LIST_UNLOCK(&entry_list);
00116    if (option_verbose > 3)
00117       ast_verbose(VERBOSE_PREFIX_4 "removing dns manager for '%s'\n", entry->name);
00118 
00119    ast_mutex_destroy(&entry->lock);
00120    free(entry);
00121 }

static AST_LIST_HEAD_STATIC ( entry_list  ,
ast_dnsmgr_entry   
) [static]

AST_MUTEX_DEFINE_STATIC ( refresh_lock   ) 

int dnsmgr_init ( void   ) 

Provided by dnsmgr.c

Definition at line 337 of file dnsmgr.c.

References ast_cli_register(), ast_log(), cli_reload, cli_status, do_reload(), LOG_ERROR, sched, and sched_context_create().

Referenced by main().

00338 {
00339    if (!(sched = sched_context_create())) {
00340       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
00341       return -1;
00342    }
00343    ast_cli_register(&cli_reload);
00344    ast_cli_register(&cli_status);
00345    return do_reload(1);
00346 }

static int dnsmgr_refresh ( struct ast_dnsmgr_entry entry,
int  verbose 
) [static]

Definition at line 159 of file dnsmgr.c.

References ahp, ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_dnsmgr_entry::changed, hp, ast_dnsmgr_entry::last, ast_dnsmgr_entry::lock, LOG_NOTICE, option_verbose, ast_dnsmgr_entry::result, and VERBOSE_PREFIX_2.

Referenced by ast_dnsmgr_refresh(), and refresh_list().

00160 {
00161    struct ast_hostent ahp;
00162    struct hostent *hp;
00163    char iabuf[INET_ADDRSTRLEN];
00164    char iabuf2[INET_ADDRSTRLEN];
00165    struct in_addr tmp;
00166    int changed = 0;
00167         
00168    ast_mutex_lock(&entry->lock);
00169    if (verbose && (option_verbose > 2))
00170       ast_verbose(VERBOSE_PREFIX_2 "refreshing '%s'\n", entry->name);
00171 
00172    if ((hp = ast_gethostbyname(entry->name, &ahp))) {
00173       /* check to see if it has changed, do callback if requested (where de callback is defined ????) */
00174       memcpy(&tmp, hp->h_addr, sizeof(tmp));
00175       if (tmp.s_addr != entry->last.s_addr) {
00176          ast_copy_string(iabuf, ast_inet_ntoa(entry->last), sizeof(iabuf));
00177          ast_copy_string(iabuf2, ast_inet_ntoa(tmp), sizeof(iabuf2));
00178          ast_log(LOG_NOTICE, "host '%s' changed from %s to %s\n", 
00179             entry->name, iabuf, iabuf2);
00180          memcpy(entry->result, hp->h_addr, sizeof(entry->result));
00181          memcpy(&entry->last, hp->h_addr, sizeof(entry->last));
00182          changed = entry->changed = 1;
00183       } 
00184       
00185    }
00186    ast_mutex_unlock(&entry->lock);
00187    return changed;
00188 }

int dnsmgr_reload ( void   ) 

Provided by dnsmgr.c

Definition at line 348 of file dnsmgr.c.

References do_reload().

00349 {
00350    return do_reload(0);
00351 }

void dnsmgr_start_refresh ( void   ) 

Provided by dnsmgr.c

Definition at line 252 of file dnsmgr.c.

References ast_sched_add_variable(), AST_SCHED_DEL, master_refresh_info, refresh_list(), and sched.

Referenced by main().

00253 {
00254    if (refresh_sched > -1) {
00255       AST_SCHED_DEL(sched, refresh_sched);
00256       refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00257    }
00258 }

static void* do_refresh ( void *  data  )  [static]

Definition at line 212 of file dnsmgr.c.

References ast_sched_runq(), ast_sched_wait(), and sched.

Referenced by do_reload().

00213 {
00214    for (;;) {
00215       pthread_testcancel();
00216       usleep((ast_sched_wait(sched)*1000));
00217       pthread_testcancel();
00218       ast_sched_runq(sched);
00219    }
00220    return NULL;
00221 }

static int do_reload ( int  loading  )  [static]

Definition at line 353 of file dnsmgr.c.

References ast_cli_register(), ast_cli_unregister(), ast_config_destroy(), ast_config_load(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_sched_add_variable(), AST_SCHED_DEL, ast_true(), ast_variable_retrieve(), cli_refresh, config, do_refresh(), enabled, LOG_ERROR, LOG_NOTICE, LOG_WARNING, master_refresh_info, REFRESH_DEFAULT, refresh_interval, refresh_list(), and sched.

00354 {
00355    struct ast_config *config;
00356    const char *interval_value;
00357    const char *enabled_value;
00358    int interval;
00359    int was_enabled;
00360    int res = -1;
00361 
00362    /* ensure that no refresh cycles run while the reload is in progress */
00363    ast_mutex_lock(&refresh_lock);
00364 
00365    /* reset defaults in preparation for reading config file */
00366    refresh_interval = REFRESH_DEFAULT;
00367    was_enabled = enabled;
00368    enabled = 0;
00369 
00370    AST_SCHED_DEL(sched, refresh_sched);
00371 
00372    if ((config = ast_config_load("dnsmgr.conf"))) {
00373       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00374          enabled = ast_true(enabled_value);
00375       }
00376       if ((interval_value = ast_variable_retrieve(config, "general", "refreshinterval"))) {
00377          if (sscanf(interval_value, "%d", &interval) < 1)
00378             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", interval_value);
00379          else if (interval < 0)
00380             ast_log(LOG_WARNING, "Invalid refresh interval '%d' specified, using default\n", interval);
00381          else
00382             refresh_interval = interval;
00383       }
00384       ast_config_destroy(config);
00385    }
00386 
00387    if (enabled && refresh_interval)
00388       ast_log(LOG_NOTICE, "Managed DNS entries will be refreshed every %d seconds.\n", refresh_interval);
00389 
00390    /* if this reload enabled the manager, create the background thread
00391       if it does not exist */
00392    if (enabled) {
00393       if (!was_enabled && (refresh_thread == AST_PTHREADT_NULL)) {
00394          if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
00395             ast_log(LOG_ERROR, "Unable to start refresh thread.\n");
00396          }
00397          ast_cli_register(&cli_refresh);
00398       }
00399       /* make a background refresh happen right away */
00400       refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00401       res = 0;
00402    }
00403    /* if this reload disabled the manager and there is a background thread,
00404       kill it */
00405    else if (!enabled && was_enabled && (refresh_thread != AST_PTHREADT_NULL)) {
00406       /* wake up the thread so it will exit */
00407       pthread_cancel(refresh_thread);
00408       pthread_kill(refresh_thread, SIGURG);
00409       pthread_join(refresh_thread, NULL);
00410       refresh_thread = AST_PTHREADT_NULL;
00411       ast_cli_unregister(&cli_refresh);
00412       res = 0;
00413    }
00414    else
00415       res = 0;
00416 
00417    ast_mutex_unlock(&refresh_lock);
00418 
00419    return res;
00420 }

static int handle_cli_refresh ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 271 of file dnsmgr.c.

References refresh_info::entries, refresh_info::filter, refresh_list(), refresh_info::regex_present, and RESULT_SHOWUSAGE.

00272 {
00273    struct refresh_info info = {
00274       .entries = &entry_list,
00275       .verbose = 1,
00276    };
00277 
00278    if (argc > 3)
00279       return RESULT_SHOWUSAGE;
00280 
00281    if (argc == 3) {
00282       if (regcomp(&info.filter, argv[2], REG_EXTENDED | REG_NOSUB))
00283          return RESULT_SHOWUSAGE;
00284       else
00285          info.regex_present = 1;
00286    }
00287 
00288    refresh_list(&info);
00289 
00290    if (info.regex_present)
00291       regfree(&info.filter);
00292 
00293    return 0;
00294 }

static int handle_cli_reload ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 262 of file dnsmgr.c.

References do_reload(), and RESULT_SHOWUSAGE.

00263 {
00264    if (argc > 2)
00265       return RESULT_SHOWUSAGE;
00266 
00267    do_reload(0);
00268    return 0;
00269 }

static int handle_cli_status ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 296 of file dnsmgr.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, enabled, refresh_interval, and RESULT_SHOWUSAGE.

00297 {
00298    int count = 0;
00299    struct ast_dnsmgr_entry *entry;
00300 
00301    if (argc > 2)
00302       return RESULT_SHOWUSAGE;
00303 
00304    ast_cli(fd, "DNS Manager: %s\n", enabled ? "enabled" : "disabled");
00305    ast_cli(fd, "Refresh Interval: %d seconds\n", refresh_interval);
00306    AST_LIST_LOCK(&entry_list);
00307    AST_LIST_TRAVERSE(&entry_list, entry, list)
00308       count++;
00309    AST_LIST_UNLOCK(&entry_list);
00310    ast_cli(fd, "Number of entries: %d\n", count);
00311 
00312    return 0;
00313 }

static int refresh_list ( const void *  data  )  [static]

Definition at line 223 of file dnsmgr.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_verbose(), dnsmgr_refresh(), refresh_info::entries, refresh_info::filter, LOG_WARNING, option_verbose, refresh_interval, refresh_info::regex_present, refresh_info::verbose, and VERBOSE_PREFIX_2.

Referenced by dnsmgr_start_refresh(), do_reload(), and handle_cli_refresh().

00224 {
00225    struct refresh_info *info = (struct refresh_info *)data;
00226    struct ast_dnsmgr_entry *entry;
00227 
00228    /* if a refresh or reload is already in progress, exit now */
00229    if (ast_mutex_trylock(&refresh_lock)) {
00230       if (info->verbose)
00231          ast_log(LOG_WARNING, "DNS Manager refresh already in progress.\n");
00232       return -1;
00233    }
00234 
00235    if (option_verbose > 2)
00236       ast_verbose(VERBOSE_PREFIX_2 "Refreshing DNS lookups.\n");
00237    AST_LIST_LOCK(info->entries);
00238    AST_LIST_TRAVERSE(info->entries, entry, list) {
00239       if (info->regex_present && regexec(&info->filter, entry->name, 0, NULL, 0))
00240           continue;
00241 
00242       dnsmgr_refresh(entry, info->verbose);
00243    }
00244    AST_LIST_UNLOCK(info->entries);
00245 
00246    ast_mutex_unlock(&refresh_lock);
00247 
00248    /* automatically reschedule based on the interval */
00249    return refresh_interval * 1000;
00250 }


Variable Documentation

struct ast_cli_entry cli_refresh [static]

Definition at line 322 of file dnsmgr.c.

Referenced by do_reload().

struct ast_cli_entry cli_reload [static]

Definition at line 315 of file dnsmgr.c.

Referenced by dnsmgr_init(), load_module(), and unload_module().

struct ast_cli_entry cli_status [static]

Definition at line 330 of file dnsmgr.c.

int enabled [static]

Definition at line 74 of file dnsmgr.c.

struct refresh_info master_refresh_info [static]

Initial value:

 {
   .entries = &entry_list,
   .verbose = 0,
}

Definition at line 84 of file dnsmgr.c.

Referenced by dnsmgr_start_refresh(), and do_reload().

int refresh_interval [static]

Definition at line 75 of file dnsmgr.c.

Referenced by do_reload(), handle_cli_status(), and refresh_list().

int refresh_sched = -1 [static]

Definition at line 52 of file dnsmgr.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 53 of file dnsmgr.c.

struct sched_context* sched [static]

Definition at line 51 of file dnsmgr.c.


Generated on Sat Jul 26 06:14:06 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1