diff options
author | Stef Walter <stef@memberwebs.com> | 2006-08-05 20:48:58 +0000 |
---|---|---|
committer | Stef Walter <stef@memberwebs.com> | 2006-08-05 20:48:58 +0000 |
commit | 2d975d635f1903a5a5b84ff808b0311d431f9e25 (patch) | |
tree | 04dcb3842e05dadd22764e56fcadc17f0072c632 /daemon | |
parent | 2b77de36782f4906b20b45d695524bbe48c731fc (diff) |
Added asynchronous DNS resolver. See #47
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/Makefile.am | 1 | ||||
-rw-r--r-- | daemon/config.c | 53 | ||||
-rw-r--r-- | daemon/rrdbotd.c | 16 | ||||
-rw-r--r-- | daemon/rrdbotd.h | 7 | ||||
-rw-r--r-- | daemon/snmp-engine.c | 83 |
5 files changed, 139 insertions, 21 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 63f5169..28dceaf 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -8,6 +8,7 @@ rrdbotd_SOURCES = rrdbotd.c rrdbotd.h config.c \ ../common/compat.h ../common/compat.c \ ../common/hash.h ../common/hash.c \ ../common/config-parser.h ../common/config-parser.c \ + ../common/async-resolver.h ../common/async-resolver.c \ ../mib/mib-parser.h ../mib/mib-parser.c rrdbotd_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir}/bsnmp/ -I${top_srcdir} \ -DCONF_PREFIX=\"$(sysconfdir)\" -DDATA_PREFIX=\"$(datadir)\" diff --git a/daemon/config.c b/daemon/config.c index 0f68c79..3e7c534 100644 --- a/daemon/config.c +++ b/daemon/config.c @@ -196,6 +196,7 @@ parse_item(const char* field, char* uri, config_ctx *ctx) { rb_item *ritem; rb_host *rhost; + int r; const char *msg; char* copy; @@ -235,17 +236,29 @@ parse_item(const char* field, char* uri, config_ctx *ctx) rhost->version = 1; rhost->name = host; rhost->community = user ? user : "public"; + rhost->is_resolved = 1; + rhost->resolve_interval = 0; + rhost->last_resolved = 0; - /* TODO: Eventually resolving should be in a separate thread, - and done regularly */ - if(sock_any_pton(host, &(rhost->address), - SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL) == -1) + /* Try and resolve the DNS name */ + r = sock_any_pton(host, &(rhost->address), + SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL | SANY_OPT_NORESOLV); + + if(r == -1) { - rb_message(LOG_WARNING, "couldn't resolve host address (ignoring): %s", host); + rb_message(LOG_WARNING, "couldn't parse host address (ignoring): %s", host); free(rhost); return NULL; } + /* + * If we got back SANY_AF_DNS, then it needs resolving. The actual + * interval and stuff are worked out in rb_config_parse() once all + * the hosts, polls etc... have been parsed. + */ + if(r == SANY_AF_DNS) + rhost->is_resolved = 0; + /* And add it to the list */ rhost->next = g_state.hosts; g_state.hosts = rhost; @@ -346,6 +359,7 @@ void rb_config_parse() { config_ctx ctx; + rb_poller* poll; /* Setup the hash tables properly */ g_state.poll_by_key = hsh_create(); @@ -358,6 +372,35 @@ rb_config_parse() if(!g_state.polls) errx(1, "no config files found in config directory: %s", g_state.confdir); + + /* Organize the async resolve intervals */ + for(poll = g_state.polls; poll; poll = poll->next) + { + rb_item *item; + mstime resint; + + /* When less than three minutes, resolve once per minute */ + if(poll->interval <= 180000) + resint = 60000; + + /* When between 3 and 10 minutes resolve once per cycle */ + else if(poll->interval <= 600000) + resint = poll->interval; + + /* Otherwise resolve thrice per cycle */ + else + resint = poll->interval / 3; + + for(item = poll->items; item; item = item->next) + { + /* The lowest interval (since hosts can be shared by pollers) wins */ + if(!item->host->is_resolved && item->host->resolve_interval < resint) + { + rb_host* host = (rb_host*)item->host; + host->resolve_interval = resint; + } + } + } } /* ----------------------------------------------------------------------------- diff --git a/daemon/rrdbotd.c b/daemon/rrdbotd.c index a2976a5..9e81350 100644 --- a/daemon/rrdbotd.c +++ b/daemon/rrdbotd.c @@ -50,6 +50,7 @@ #include "rrdbotd.h" #include "server-mainloop.h" +#include "async-resolver.h" /* The default command line options */ #define DEFAULT_CONFIG CONF_PREFIX "/rrdbot" @@ -134,14 +135,14 @@ rb_vmessage(int level, int err, const char* msg, va_list ap) buf[MAX_MSGLEN - 1] = 0; /* Either to syslog or stderr */ - if (daemonized) - vsyslog (level, buf, ap); + if(daemonized) + vsyslog(level, buf, ap); else - vwarnx (buf, ap); + vwarnx(buf, ap); } void -rb_messagex (int level, const char* msg, ...) +rb_messagex(int level, const char* msg, ...) { va_list ap; va_start(ap, msg); @@ -150,7 +151,7 @@ rb_messagex (int level, const char* msg, ...) } void -rb_message (int level, const char* msg, ...) +rb_message(int level, const char* msg, ...) { va_list ap; va_start(ap, msg); @@ -301,6 +302,10 @@ main(int argc, char* argv[]) /* The mainloop server */ server_init(); + /* Setup the Async DNS resolver */ + if(async_resolver_init() < 0) + err(1, "couldn't initialize resolver"); + /* Parse config and setup SNMP system */ rb_config_parse(); @@ -345,6 +350,7 @@ main(int argc, char* argv[]) /* Cleanups */ rb_snmp_engine_uninit(); rb_config_free(); + async_resolver_uninit(); server_uninit(); return 0; diff --git a/daemon/rrdbotd.h b/daemon/rrdbotd.h index 061beb2..35b3912 100644 --- a/daemon/rrdbotd.h +++ b/daemon/rrdbotd.h @@ -100,8 +100,10 @@ typedef struct _rb_host /* Host resolving and book keeping */ struct sockaddr_any address; - mstime interval; + mstime resolve_interval; + mstime last_resolve_try; mstime last_resolved; + int is_resolved; /* Next in list of hosts */ struct _rb_host* next; @@ -155,6 +157,9 @@ extern rb_state g_state; * UTILITIES (rrdbotd.c) */ +typedef void (*resolve_callback)(void *context, int unused, const char *name, + const unsigned char *addr, size_t addrlen); + void rb_messagex(int level, const char* msg, ...); void rb_message(int level, const char* msg, ...); void rb_vmessage(int level, int err, const char* msg, va_list ap); diff --git a/daemon/snmp-engine.c b/daemon/snmp-engine.c index 479bc85..c2afbe9 100644 --- a/daemon/snmp-engine.c +++ b/daemon/snmp-engine.c @@ -37,16 +37,20 @@ */ #include "usuals.h" +#include <sys/types.h> +#include <sys/socket.h> #include <errno.h> #include <unistd.h> #include <syslog.h> #include <err.h> +#include <arpa/inet.h> #include <bsnmp/asn1.h> #include <bsnmp/snmp.h> #include "rrdbotd.h" #include "server-mainloop.h" +#include "async-resolver.h" /* The socket to use */ static int snmp_socket = -1; @@ -61,7 +65,6 @@ static unsigned char snmp_buffer[0x1000]; * REQUESTS */ -/* rb_request waaaaayyyyy too big */ typedef struct _rb_request { /* The SNMP request identifier */ @@ -229,6 +232,23 @@ send_req(rb_request* req, mstime when) struct asn_buf b; ssize_t ret; + /* Update our bookkeeping */ + req->sent++; + if(req->sent <= g_state.retries) + req->next_retry = when + req->interval; + else + req->next_retry = 0; + req->last_sent = when; + + /* No sending if no address */ + if(!req->host->is_resolved) + { + if(req->sent <= 1) + rb_messagex(LOG_DEBUG, "skipping snmp request: host not resolved: %s", + req->host->name); + return; + } + b.asn_ptr = snmp_buffer; b.asn_len = sizeof(snmp_buffer); @@ -243,14 +263,6 @@ send_req(rb_request* req, mstime when) else rb_messagex(LOG_DEBUG, "sent request #%d to: %s", req->id, req->host->name); } - - /* And update our bookkeeping */ - req->sent++; - if(req->sent <= g_state.retries) - req->next_retry = when + req->interval; - else - req->next_retry = 0; - req->last_sent = when; } static void @@ -272,7 +284,6 @@ timeout_req(rb_request* req, mstime when) if(it->req == req) { rb_messagex(LOG_DEBUG, "value for field '%s' timed out", it->rrdfield); - it->vtype = VALUE_UNSET; it->req = NULL; } @@ -601,6 +612,54 @@ prep_timer(mstime when, void* arg) return 0; } +static void +resolve_cb(int ecode, struct addrinfo* ai, void* arg) +{ + rb_host* host = (rb_host*)arg; + + if(ecode) + { + rb_messagex(LOG_WARNING, "couldn't resolve hostname: %s: %s", host->name, + gai_strerror(ecode)); + return; + } + + /* A successful resolve */ + memcpy(&SANY_ADDR(host->address), ai->ai_addr, ai->ai_addrlen); + SANY_LEN(host->address) = ai->ai_addrlen; + host->last_resolved = server_get_time(); + host->is_resolved = 1; + + rb_messagex(LOG_DEBUG, "resolved host: %s", host->name); +} + +static int +resolve_timer(mstime when, void* arg) +{ + rb_host* host; + + /* Go through hosts and see which ones need resolving */ + for(host = g_state.hosts; host; host = host->next) + { + /* No need to resolve? */ + if(!host->resolve_interval) + continue; + + if(when - host->resolve_interval > host->last_resolve_try) + { + /* Automatically strips port number */ + rb_messagex(LOG_DEBUG, "resolving host: %s", host->name); + async_resolver_queue(host->name, "161", resolve_cb, host); + host->last_resolve_try = when; + } + + /* When the last 3 resolves have failed, set to unresolved */ + if(when - (host->resolve_interval * 3) > host->last_resolved) + host->is_resolved = 0; + } + + return 1; +} void rb_snmp_engine_init() @@ -636,6 +695,10 @@ rb_snmp_engine_init() /* We fire off the resend timer every 1/5 second */ if(server_timer(200, resend_timer, NULL) == -1) err(1, "couldn't setup timer"); + + /* resolve timer goes once per second */ + if(server_timer(1000, resolve_timer, NULL) == -1) + err(1, "couldn't setup timer"); } void |