Wed Oct 28 11:52:18 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"
#include "asterisk/acl.h"

Include dependency graph for dnsmgr.c:

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

static void __fini_entry_list (void)
static void __init_entry_list (void)
int ast_dnsmgr_changed (struct ast_dnsmgr_entry *entry)
 Check is see if a dnsmgr entry has changed.
struct ast_dnsmgr_entryast_dnsmgr_get (const char *name, struct sockaddr_in *result, const char *service)
 Allocate a new DNS manager entry.
int ast_dnsmgr_lookup (const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
 Allocate and initialize a DNS manager entry.
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)
 Free a DNS manager 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 = AST_CLI_DEFINE(handle_cli_refresh, "Performs an immediate refresh")
static struct ast_cli_entry cli_reload = AST_CLI_DEFINE(handle_cli_reload, "Reloads the DNS manager configuration")
static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the DNS manager status")
static int enabled
static struct refresh_info master_refresh_info
static int refresh_interval
static ast_mutex_t refresh_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
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 71 of file dnsmgr.c.

Referenced by do_reload().


Function Documentation

static void __fini_entry_list ( void   )  [static]

Definition at line 67 of file dnsmgr.c.

00076 {

static void __init_entry_list ( void   )  [static]

Definition at line 67 of file dnsmgr.c.

00076 {

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 sockaddr_in *  result,
const char *  service 
) [read]

Allocate a new DNS manager entry.

Parameters:
name the hostname
result where the DNS manager should store the IP address as it refreshes it. it.
This function allocates a new DNS manager entry object, and fills it with the provided hostname and IP address. This function does not force an initial lookup of the IP address. So, generally, this should be used when the initial address is already known.

Returns:
a DNS manager entry
Version:
1.6.1 result changed from struct in_addr to struct sockaddr_in to store port number

Definition at line 88 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::last, ast_dnsmgr_entry::lock, ast_dnsmgr_entry::name, ast_dnsmgr_entry::result, and ast_dnsmgr_entry::service.

Referenced by ast_dnsmgr_lookup().

00089 {
00090    struct ast_dnsmgr_entry *entry;
00091    int total_size = sizeof(*entry) + strlen(name) + (service ? strlen(service) + 1 : 0);
00092 
00093    if (!result || ast_strlen_zero(name) || !(entry = ast_calloc(1, total_size)))
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    if (service) {
00101       entry->service = ((char *) entry) + sizeof(*entry) + strlen(name);
00102       strcpy(entry->service, service);
00103    }
00104 
00105    AST_RWLIST_WRLOCK(&entry_list);
00106    AST_RWLIST_INSERT_HEAD(&entry_list, entry, list);
00107    AST_RWLIST_UNLOCK(&entry_list);
00108 
00109    return entry;
00110 }

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

Allocate and initialize a DNS manager entry.

Parameters:
name the hostname
result where to store the IP address as the DNS manager refreshes it
dnsmgr Where to store the allocate DNS manager entry
This function allocates a new DNS manager entry object, and fills it with the provided hostname and IP address. This function _does_ force an initial lookup, so it may block for some period of time.

Return values:
0 success
non-zero failure
Version:
1.6.1 result changed from struct in_addr to struct aockaddr_in to store port number

Definition at line 126 of file dnsmgr.c.

References ast_dnsmgr_get(), ast_get_ip_or_srv(), ast_strlen_zero(), ast_verb, enabled, and inet_aton().

Referenced by build_peer(), iax2_append_register(), and transmit_register().

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 it's actually an IP address and not a name,
00135       there's no need for a managed lookup */
00136    if (inet_aton(name, &result->sin_addr))
00137       return 0;
00138 
00139    ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name);
00140 
00141    /* do a lookup now but add a manager so it will automagically get updated in the background */
00142    ast_get_ip_or_srv(result, name, service);
00143    
00144    /* if dnsmgr is not enable don't bother adding an entry */
00145    if (!enabled)
00146       return 0;
00147    
00148    ast_verb(3, "adding dns manager for '%s'\n", name);
00149    *dnsmgr = ast_dnsmgr_get(name, result, service);
00150    return !*dnsmgr;
00151 }

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(), and sip_reg_timeout().

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

void ast_dnsmgr_release ( struct ast_dnsmgr_entry entry  ) 

Free a DNS manager entry.

Parameters:
entry the DNS manager entry to free
Returns:
nothing

Definition at line 112 of file dnsmgr.c.

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

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

00113 {
00114    if (!entry)
00115       return;
00116 
00117    AST_RWLIST_WRLOCK(&entry_list);
00118    AST_RWLIST_REMOVE(&entry_list, entry, list);
00119    AST_RWLIST_UNLOCK(&entry_list);
00120    ast_verb(4, "removing dns manager for '%s'\n", entry->name);
00121 
00122    ast_mutex_destroy(&entry->lock);
00123    ast_free(entry);
00124 }

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

References ast_copy_string(), ast_get_ip_or_srv(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, ast_dnsmgr_entry::changed, inaddrcmp(), ast_dnsmgr_entry::last, ast_dnsmgr_entry::lock, LOG_NOTICE, ast_dnsmgr_entry::name, ast_dnsmgr_entry::result, and ast_dnsmgr_entry::service.

Referenced by ast_dnsmgr_refresh(), and refresh_list().

00157 {
00158    char iabuf[INET_ADDRSTRLEN];
00159    char iabuf2[INET_ADDRSTRLEN];
00160    struct sockaddr_in tmp;
00161    int changed = 0;
00162         
00163    ast_mutex_lock(&entry->lock);
00164    if (verbose)
00165       ast_verb(3, "refreshing '%s'\n", entry->name);
00166 
00167    tmp.sin_port = entry->last.sin_port;
00168    
00169    if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, &entry->last)) {
00170       ast_copy_string(iabuf, ast_inet_ntoa(entry->last.sin_addr), sizeof(iabuf));
00171       ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2));
00172       ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n", 
00173          entry->name, iabuf, ntohs(entry->last.sin_port), iabuf2, ntohs(tmp.sin_port));
00174       *entry->result = tmp;
00175       entry->last = tmp;
00176       changed = entry->changed = 1;
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, and refresh_list().

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(), and ast_sched_wait().

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_load2(), 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, and refresh_list().

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_load2("dnsmgr.conf", "dnsmgr", 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, "%30d", &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, 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, 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 = AST_CLI_DEFINE(handle_cli_refresh, "Performs an immediate refresh") [static]

Definition at line 347 of file dnsmgr.c.

Referenced by dnsmgr_init().

struct ast_cli_entry cli_reload = AST_CLI_DEFINE(handle_cli_reload, "Reloads the DNS manager configuration") [static]

Definition at line 346 of file dnsmgr.c.

Referenced by dnsmgr_init().

struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the DNS manager status") [static]

Definition at line 348 of file dnsmgr.c.

int enabled [static]

Definition at line 73 of file dnsmgr.c.

Initial value:

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

Definition at line 83 of file dnsmgr.c.

Referenced by dnsmgr_start_refresh(), and do_reload().

int refresh_interval [static]

Definition at line 74 of file dnsmgr.c.

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

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

Definition at line 69 of file dnsmgr.c.

int refresh_sched = -1 [static]

Definition at line 49 of file dnsmgr.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 50 of file dnsmgr.c.

struct sched_context* sched [static]

Definition at line 48 of file dnsmgr.c.


Generated on Wed Oct 28 11:52:19 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6