Thu Jul 9 13:41:16 2009

Asterisk developer's documentation


dnsmgr.c File Reference

Background DNS update manager. More...

#include "asterisk.h"
#include "asterisk/_private.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/sched.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"

Go to the source code of this file.

Data Structures

struct  ast_dnsmgr_entry
struct  entry_list
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)
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 char * handle_cli_refresh (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int refresh_list (const void *data)

Variables

static struct ast_cli_entry cli_refresh = { .handler = handle_cli_refresh , .summary = "Performs an immediate refresh" ,__VA_ARGS__ }
static struct ast_cli_entry cli_reload = { .handler = handle_cli_reload , .summary = "Reloads the DNS manager configuration" ,__VA_ARGS__ }
static struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the DNS manager status" ,__VA_ARGS__ }
static int enabled
static struct refresh_info master_refresh_info
static int refresh_interval
static ast_mutex_t refresh_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
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>
Bug:
There is a minor race condition. In the event that an IP address of a dnsmgr managed host changes, there is the potential for the consumer of that address to access the in_addr data at the same time that the dnsmgr thread is in the middle of updating it to the new address.

Definition in file dnsmgr.c.


Define Documentation

#define REFRESH_DEFAULT   300

Definition at line 68 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 191 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().

00192 {
00193    int changed;
00194 
00195    ast_mutex_lock(&entry->lock);
00196 
00197    changed = entry->changed;
00198    entry->changed = 0;
00199 
00200    ast_mutex_unlock(&entry->lock);
00201    
00202    return changed;
00203 }

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

Definition at line 85 of file dnsmgr.c.

References ast_calloc, ast_mutex_init(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strlen_zero(), ast_dnsmgr_entry::list, and ast_dnsmgr_entry::result.

Referenced by ast_dnsmgr_lookup().

00086 {
00087    struct ast_dnsmgr_entry *entry;
00088 
00089    if (!result || ast_strlen_zero(name) || !(entry = ast_calloc(1, sizeof(*entry) + strlen(name))))
00090       return NULL;
00091 
00092    entry->result = result;
00093    ast_mutex_init(&entry->lock);
00094    strcpy(entry->name, name);
00095    memcpy(&entry->last, result, sizeof(entry->last));
00096 
00097    AST_RWLIST_WRLOCK(&entry_list);
00098    AST_RWLIST_INSERT_HEAD(&entry_list, entry, list);
00099    AST_RWLIST_UNLOCK(&entry_list);
00100 
00101    return entry;
00102 }

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

Definition at line 118 of file dnsmgr.c.

References ahp, ast_dnsmgr_get(), ast_gethostbyname(), ast_strlen_zero(), ast_verb, enabled, hp, and inet_aton().

Referenced by build_peer(), and iax2_append_register().

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

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 183 of file dnsmgr.c.

References dnsmgr_refresh().

Referenced by iax2_do_register().

00184 {
00185    return dnsmgr_refresh(entry, 0);
00186 }

void ast_dnsmgr_release ( struct ast_dnsmgr_entry entry  ) 

Definition at line 104 of file dnsmgr.c.

References ast_free, ast_mutex_destroy(), AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_dnsmgr_entry::list, ast_dnsmgr_entry::lock, and ast_dnsmgr_entry::name.

Referenced by delete_users(), peer_destructor(), and sip_destroy_peer().

00105 {
00106    if (!entry)
00107       return;
00108 
00109    AST_RWLIST_WRLOCK(&entry_list);
00110    AST_RWLIST_REMOVE(&entry_list, entry, list);
00111    AST_RWLIST_UNLOCK(&entry_list);
00112    ast_verb(4, "removing dns manager for '%s'\n", entry->name);
00113 
00114    ast_mutex_destroy(&entry->lock);
00115    ast_free(entry);
00116 }

int dnsmgr_init ( void   ) 

Provided by dnsmgr.c

Definition at line 350 of file dnsmgr.c.

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

Referenced by main().

00351 {
00352    if (!(sched = sched_context_create())) {
00353       ast_log(LOG_ERROR, "Unable to create schedule context.\n");
00354       return -1;
00355    }
00356    ast_cli_register(&cli_reload);
00357    ast_cli_register(&cli_status);
00358    ast_cli_register(&cli_refresh);
00359    return do_reload(1);
00360 }

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

Definition at line 152 of file dnsmgr.c.

References ahp, ast_copy_string(), ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, ast_dnsmgr_entry::changed, hp, ast_dnsmgr_entry::last, ast_dnsmgr_entry::lock, LOG_NOTICE, ast_dnsmgr_entry::name, and ast_dnsmgr_entry::result.

Referenced by ast_dnsmgr_refresh(), and refresh_list().

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

int dnsmgr_reload ( void   ) 

Provided by dnsmgr.c

Definition at line 362 of file dnsmgr.c.

References do_reload().

00363 {
00364    return do_reload(0);
00365 }

void dnsmgr_start_refresh ( void   ) 

Provided by dnsmgr.c

Definition at line 244 of file dnsmgr.c.

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

Referenced by main().

00245 {
00246    if (refresh_sched > -1) {
00247       AST_SCHED_DEL(sched, refresh_sched);
00248       refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00249    }
00250 }

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

Definition at line 205 of file dnsmgr.c.

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

Referenced by do_reload().

00206 {
00207    for (;;) {
00208       pthread_testcancel();
00209       usleep((ast_sched_wait(sched)*1000));
00210       pthread_testcancel();
00211       ast_sched_runq(sched);
00212    }
00213    return NULL;
00214 }

static int do_reload ( int  loading  )  [static]

Definition at line 367 of file dnsmgr.c.

References 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(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, do_refresh(), enabled, EVENT_FLAG_SYSTEM, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, master_refresh_info, REFRESH_DEFAULT, refresh_interval, refresh_list(), and sched.

00368 {
00369    struct ast_config *config;
00370    struct ast_flags config_flags = { loading ? 0 : CONFIG_FLAG_FILEUNCHANGED };
00371    const char *interval_value;
00372    const char *enabled_value;
00373    int interval;
00374    int was_enabled;
00375    int res = -1;
00376 
00377    if ((config = ast_config_load("dnsmgr.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00378       return 0;
00379 
00380    /* ensure that no refresh cycles run while the reload is in progress */
00381    ast_mutex_lock(&refresh_lock);
00382 
00383    /* reset defaults in preparation for reading config file */
00384    refresh_interval = REFRESH_DEFAULT;
00385    was_enabled = enabled;
00386    enabled = 0;
00387 
00388    AST_SCHED_DEL(sched, refresh_sched);
00389 
00390    if (config) {
00391       if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00392          enabled = ast_true(enabled_value);
00393       }
00394       if ((interval_value = ast_variable_retrieve(config, "general", "refreshinterval"))) {
00395          if (sscanf(interval_value, "%d", &interval) < 1)
00396             ast_log(LOG_WARNING, "Unable to convert '%s' to a numeric value.\n", interval_value);
00397          else if (interval < 0)
00398             ast_log(LOG_WARNING, "Invalid refresh interval '%d' specified, using default\n", interval);
00399          else
00400             refresh_interval = interval;
00401       }
00402       ast_config_destroy(config);
00403    }
00404 
00405    if (enabled && refresh_interval)
00406       ast_log(LOG_NOTICE, "Managed DNS entries will be refreshed every %d seconds.\n", refresh_interval);
00407 
00408    /* if this reload enabled the manager, create the background thread
00409       if it does not exist */
00410    if (enabled) {
00411       if (!was_enabled && (refresh_thread == AST_PTHREADT_NULL)) {
00412          if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
00413             ast_log(LOG_ERROR, "Unable to start refresh thread.\n");
00414          }
00415       }
00416       /* make a background refresh happen right away */
00417       refresh_sched = ast_sched_add_variable(sched, 100, refresh_list, &master_refresh_info, 1);
00418       res = 0;
00419    }
00420    /* if this reload disabled the manager and there is a background thread,
00421       kill it */
00422    else if (!enabled && was_enabled && (refresh_thread != AST_PTHREADT_NULL)) {
00423       /* wake up the thread so it will exit */
00424       pthread_cancel(refresh_thread);
00425       pthread_kill(refresh_thread, SIGURG);
00426       pthread_join(refresh_thread, NULL);
00427       refresh_thread = AST_PTHREADT_NULL;
00428       res = 0;
00429    }
00430    else
00431       res = 0;
00432 
00433    ast_mutex_unlock(&refresh_lock);
00434    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: DNSmgr\r\nStatus: %s\r/nMessage: DNSmgr reload Requested\r\n", enabled ? "Enabled" : "Disabled");
00435 
00436    return res;
00437 }

static char* handle_cli_refresh ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 273 of file dnsmgr.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, enabled, refresh_info::entries, ast_cli_args::fd, refresh_info::filter, refresh_list(), refresh_info::regex_present, and ast_cli_entry::usage.

00274 {
00275    struct refresh_info info = {
00276       .entries = &entry_list,
00277       .verbose = 1,
00278    };
00279    switch (cmd) {
00280    case CLI_INIT:
00281       e->command = "dnsmgr refresh";
00282       e->usage = 
00283          "Usage: dnsmgr refresh [pattern]\n"
00284          "       Peforms an immediate refresh of the managed DNS entries.\n"
00285          "       Optional regular expression pattern is used to filter the entries to refresh.\n";
00286       return NULL;
00287    case CLI_GENERATE:
00288       return NULL;   
00289    }
00290 
00291    if (!enabled) {
00292       ast_cli(a->fd, "DNS Manager is disabled.\n");
00293       return 0;
00294    }
00295 
00296    if (a->argc > 3) {
00297       return CLI_SHOWUSAGE;
00298    }
00299 
00300    if (a->argc == 3) {
00301       if (regcomp(&info.filter, a->argv[2], REG_EXTENDED | REG_NOSUB)) {
00302          return CLI_SHOWUSAGE;
00303       } else {
00304          info.regex_present = 1;
00305       }
00306    }
00307 
00308    refresh_list(&info);
00309 
00310    if (info.regex_present) {
00311       regfree(&info.filter);
00312    }
00313 
00314    return CLI_SUCCESS;
00315 }

static char* handle_cli_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 254 of file dnsmgr.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, do_reload(), and ast_cli_entry::usage.

00255 {
00256    switch (cmd) {
00257    case CLI_INIT:
00258       e->command = "dnsmgr reload";
00259       e->usage = 
00260          "Usage: dnsmgr reload\n"
00261          "       Reloads the DNS manager configuration.\n";
00262       return NULL;
00263    case CLI_GENERATE:
00264       return NULL;   
00265    }
00266    if (a->argc > 2)
00267       return CLI_SHOWUSAGE;
00268 
00269    do_reload(0);
00270    return CLI_SUCCESS;
00271 }

static char* handle_cli_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 317 of file dnsmgr.c.

References ast_cli_args::argc, ast_cli(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, enabled, ast_cli_args::fd, ast_dnsmgr_entry::list, refresh_interval, and ast_cli_entry::usage.

00318 {
00319    int count = 0;
00320    struct ast_dnsmgr_entry *entry;
00321    switch (cmd) {
00322    case CLI_INIT:
00323       e->command = "dnsmgr status";
00324       e->usage = 
00325          "Usage: dnsmgr status\n"
00326          "       Displays the DNS manager status.\n";
00327       return NULL;
00328    case CLI_GENERATE:
00329       return NULL;   
00330    }
00331 
00332    if (a->argc > 2)
00333       return CLI_SHOWUSAGE;
00334 
00335    ast_cli(a->fd, "DNS Manager: %s\n", enabled ? "enabled" : "disabled");
00336    ast_cli(a->fd, "Refresh Interval: %d seconds\n", refresh_interval);
00337    AST_RWLIST_RDLOCK(&entry_list);
00338    AST_RWLIST_TRAVERSE(&entry_list, entry, list)
00339       count++;
00340    AST_RWLIST_UNLOCK(&entry_list);
00341    ast_cli(a->fd, "Number of entries: %d\n", count);
00342 
00343    return CLI_SUCCESS;
00344 }

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

Definition at line 216 of file dnsmgr.c.

References ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_verb, dnsmgr_refresh(), refresh_info::entries, refresh_info::filter, ast_dnsmgr_entry::list, LOG_WARNING, ast_dnsmgr_entry::name, refresh_interval, refresh_info::regex_present, and refresh_info::verbose.

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

00217 {
00218    struct refresh_info *info = (struct refresh_info *)data;
00219    struct ast_dnsmgr_entry *entry;
00220 
00221    /* if a refresh or reload is already in progress, exit now */
00222    if (ast_mutex_trylock(&refresh_lock)) {
00223       if (info->verbose)
00224          ast_log(LOG_WARNING, "DNS Manager refresh already in progress.\n");
00225       return -1;
00226    }
00227 
00228    ast_verb(3, "Refreshing DNS lookups.\n");
00229    AST_RWLIST_RDLOCK(info->entries);
00230    AST_RWLIST_TRAVERSE(info->entries, entry, list) {
00231       if (info->regex_present && regexec(&info->filter, entry->name, 0, NULL, 0))
00232           continue;
00233 
00234       dnsmgr_refresh(entry, info->verbose);
00235    }
00236    AST_RWLIST_UNLOCK(info->entries);
00237 
00238    ast_mutex_unlock(&refresh_lock);
00239 
00240    /* automatically reschedule based on the interval */
00241    return refresh_interval * 1000;
00242 }


Variable Documentation

struct ast_cli_entry cli_refresh = { .handler = handle_cli_refresh , .summary = "Performs an immediate refresh" ,__VA_ARGS__ } [static]

Definition at line 347 of file dnsmgr.c.

Referenced by dnsmgr_init().

struct ast_cli_entry cli_reload = { .handler = handle_cli_reload , .summary = "Reloads the DNS manager configuration" ,__VA_ARGS__ } [static]

Definition at line 346 of file dnsmgr.c.

Referenced by dnsmgr_init().

struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the DNS manager status" ,__VA_ARGS__ } [static]

Definition at line 348 of file dnsmgr.c.

int enabled [static]

Definition at line 70 of file dnsmgr.c.

struct refresh_info master_refresh_info [static]

Initial value:

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

Definition at line 80 of file dnsmgr.c.

Referenced by dnsmgr_start_refresh(), and do_reload().

int refresh_interval [static]

Definition at line 71 of file dnsmgr.c.

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

ast_mutex_t refresh_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 66 of file dnsmgr.c.

int refresh_sched = -1 [static]

Definition at line 48 of file dnsmgr.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 49 of file dnsmgr.c.

struct sched_context* sched [static]

Definition at line 47 of file dnsmgr.c.


Generated on Thu Jul 9 13:41:16 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7