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 | 
