summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2006-08-05 20:48:58 +0000
committerStef Walter <stef@memberwebs.com>2006-08-05 20:48:58 +0000
commit2d975d635f1903a5a5b84ff808b0311d431f9e25 (patch)
tree04dcb3842e05dadd22764e56fcadc17f0072c632 /daemon
parent2b77de36782f4906b20b45d695524bbe48c731fc (diff)
Added asynchronous DNS resolver. See #47
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/config.c53
-rw-r--r--daemon/rrdbotd.c16
-rw-r--r--daemon/rrdbotd.h7
-rw-r--r--daemon/snmp-engine.c83
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