diff options
| author | Stef Walter <stef@memberwebs.com> | 2006-04-05 05:14:43 +0000 | 
|---|---|---|
| committer | Stef Walter <stef@memberwebs.com> | 2006-04-05 05:14:43 +0000 | 
| commit | fa3cea48898b0ba5a87bd6bda0f7aab015f4a28c (patch) | |
| tree | 58a3e713e0a6a14077923183b90460e3be9011ae | |
| parent | b6044e96fe7860f20a3964b962627451b78439dc (diff) | |
Add timeouts and resends. Rework globals.
| -rw-r--r-- | tools/rrdbot-get.c | 191 | 
1 files changed, 130 insertions, 61 deletions
| diff --git a/tools/rrdbot-get.c b/tools/rrdbot-get.c index a6cc0bc..a1c904a 100644 --- a/tools/rrdbot-get.c +++ b/tools/rrdbot-get.c @@ -50,26 +50,30 @@  #include "server-mainloop.h"  #include "config-parser.h" -/* The socket to use */ -static int snmp_socket = -1; -/* Since we only deal with one packet at a time, global buffer */ -static unsigned char snmp_buffer[0x1000]; +#define RESEND_TIMEOUT      200         /* Time between SNMP resends */ +#define DEFAULT_TIMEOUT     5000        /* Default timeout for SNMP response */ +#define MAX_RETRIES         3           /* Number of SNMP packets we retry */ -/* The actual request data */ -static struct snmp_pdu snmp_data; +struct context +{ +    int socket;                         /* The socket to use */ +    unsigned char packet[0x1000];       /* The raw packet data to send */ +    struct snmp_pdu pdu;                /* The actual request data */ +    struct asn_oid oid_first;           /* The first OID we've done */ -/* The first OID we've done */ -static struct asn_oid oid_first; +    struct sockaddr_any hostaddr;       /* The remote host */ +    char* hostname;                     /* The remote host */ -/* The remote host */ -static struct sockaddr_any snmp_hostaddr; -static char* snmp_hostname = NULL; +    uint64_t lastsend;                  /* Time of last send */ +    int retries;                        /* Number of retries */ +    uint64_t timeout;                   /* Receive timeout */ -static int retries = 0; +    int recursive;                      /* Whether we're going recursive or not */ +    int numeric;                        /* Print raw data */ +}; -static int recursive = 0;   /* Whether we're going recursive or not */ -static int numeric = 0;     /* Print raw data */ +static struct context ctx;  /* -----------------------------------------------------------------------------   * DUMMY CONFIG FUNCTIONS @@ -98,17 +102,20 @@ send_req()      struct asn_buf b;      ssize_t ret; -    b.asn_ptr = snmp_buffer; -    b.asn_len = sizeof(snmp_buffer); +    b.asn_ptr = ctx.packet; +    b.asn_len = sizeof(ctx.packet); -    if(snmp_pdu_encode(&snmp_data, &b)) +    if(snmp_pdu_encode(&ctx.pdu, &b))          errx(1, "couldn't encode snmp buffer"); -    ret = sendto(snmp_socket, snmp_buffer, b.asn_ptr - snmp_buffer, 0, -                 &SANY_ADDR(snmp_hostaddr), SANY_LEN(snmp_hostaddr)); +    ret = sendto(ctx.socket, ctx.packet, b.asn_ptr - ctx.packet, 0, +                 &SANY_ADDR(ctx.hostaddr), SANY_LEN(ctx.hostaddr));      if(ret == -1) -        err(1, "couldn't send snmp packet to: %s", snmp_hostname); +        err(1, "couldn't send snmp packet to: %s", ctx.hostname); +    /* Some bookkeeping */ +    ctx.retries++; +    ctx.lastsend = server_get_time();  }  static void @@ -122,7 +129,7 @@ setup_req(char* uri)      /* Parse the SNMP URI */      copy = strdup(uri); -    msg = cfg_parse_uri(uri, &scheme, &snmp_hostname, &user, &path); +    msg = cfg_parse_uri(uri, &scheme, &ctx.hostname, &user, &path);      if(msg)          errx(2, "%s: %s", msg, copy);      free(copy); @@ -133,46 +140,52 @@ setup_req(char* uri)      if(strcmp(scheme, "snmp") != 0)          errx(2, "invalid scheme: %s", scheme); -    if(sock_any_pton(snmp_hostname, &snmp_hostaddr, +    if(sock_any_pton(ctx.hostname, &ctx.hostaddr,                       SANY_OPT_DEFPORT(161) | SANY_OPT_DEFLOCAL) == -1) -        err(1, "couldn't resolve host address (ignoring): %s", snmp_hostname); +        err(1, "couldn't resolve host address (ignoring): %s", ctx.hostname); -    memset(&snmp_data, 0, sizeof(snmp_data)); -    snmp_data.version = 1; -    snmp_data.request_id = 0; -    snmp_data.type = recursive ? SNMP_PDU_GETNEXT : SNMP_PDU_GET; -    snmp_data.error_status = 0; -    snmp_data.error_index = 0; -    strlcpy(snmp_data.community, user ? user : "public", -            sizeof(snmp_data.community)); +    memset(&ctx.pdu, 0, sizeof(ctx.pdu)); +    ctx.pdu.version = 1; +    ctx.pdu.request_id = 0; +    ctx.pdu.type = ctx.recursive ? SNMP_PDU_GETNEXT : SNMP_PDU_GET; +    ctx.pdu.error_status = 0; +    ctx.pdu.error_index = 0; +    strlcpy(ctx.pdu.community, user ? user : "public", +            sizeof(ctx.pdu.community));      /* And parse the OID */ -    snmp_data.bindings[0].syntax = 0; -    memset(&(snmp_data.bindings[0].v), 0, sizeof(snmp_data.bindings[0].v)); -    if(mib_parse(path, &(snmp_data.bindings[0].var)) == -1) +    ctx.pdu.bindings[0].syntax = 0; +    memset(&(ctx.pdu.bindings[0].v), 0, sizeof(ctx.pdu.bindings[0].v)); +    if(mib_parse(path, &(ctx.pdu.bindings[0].var)) == -1)          errx(2, "invalid MIB: %s", path);      /* Add an item to this request */ -    snmp_data.nbindings = 1; +    ctx.pdu.nbindings = 1;      /* Keep track of top for recursiveness */ -    memcpy(&oid_first, &(snmp_data.bindings[0].var), sizeof(oid_first)); +    memcpy(&ctx.oid_first, &(ctx.pdu.bindings[0].var), sizeof(ctx.oid_first)); +    /* Reset bookkeeping */ +    ctx.retries = 0; +    ctx.lastsend = 0;  }  static void  setup_next(struct snmp_value* value)  { -    snmp_data.request_id++; -    snmp_data.type = SNMP_PDU_GETNEXT; +    ctx.pdu.request_id++; +    ctx.pdu.type = SNMP_PDU_GETNEXT;      /* And parse the OID */ -    memcpy(&(snmp_data.bindings[0]), value, sizeof(struct snmp_value)); -    snmp_data.bindings[0].syntax = 0; -    snmp_data.nbindings = 1; -} +    memcpy(&(ctx.pdu.bindings[0]), value, sizeof(struct snmp_value)); +    ctx.pdu.bindings[0].syntax = 0; +    ctx.pdu.nbindings = 1; +    /* Reset bookkeeping */ +    ctx.retries = 0; +    ctx.lastsend = 0; +}  static int  print_resp(struct snmp_pdu* pdu, uint64_t when) @@ -187,11 +200,13 @@ print_resp(struct snmp_pdu* pdu, uint64_t when)      {          value = &(pdu->bindings[i]); -        if(numeric) -            printf("%s: ", asn_oid2str(&(value->var))); +        if(ctx.numeric) +            printf("%s", asn_oid2str(&(value->var)));          else              mib_format(&(value->var), stdout); +        printf(": "); +          switch(value->syntax)          {          case SNMP_SYNTAX_NULL: @@ -255,7 +270,7 @@ receive_resp(int fd, int type, void* arg)      /* Read in the packet */      SANY_LEN(from) = sizeof(from); -    len = recvfrom(snmp_socket, snmp_buffer, sizeof(snmp_buffer), 0, +    len = recvfrom(ctx.socket, ctx.packet, sizeof(ctx.packet), 0,                     &SANY_ADDR(from), &SANY_LEN(from));      if(len < 0)      { @@ -268,7 +283,7 @@ receive_resp(int fd, int type, void* arg)      /* Now parse the packet */ -    b.asn_ptr = snmp_buffer; +    b.asn_ptr = ctx.packet;      b.asn_len = len;      ret = snmp_pdu_decode(&b, &pdu, &ip); @@ -276,13 +291,12 @@ receive_resp(int fd, int type, void* arg)          errx(1, "invalid snmp packet received from: %s", hostname);      /* It needs to match something we're waiting for */ -    if(pdu.request_id != snmp_data.request_id) +    if(pdu.request_id != ctx.pdu.request_id)          return;      /* Check for errors */      if(pdu.error_status != SNMP_ERR_NOERROR)      { -        snmp_pdu_dump (&pdu);          msg = snmp_get_errmsg (pdu.error_status);          if(msg)              errx(1, "snmp error from host '%s': %s", hostname, msg); @@ -296,15 +310,15 @@ receive_resp(int fd, int type, void* arg)      if(pdu.nbindings > 0)      {          val = &(pdu.bindings[pdu.nbindings - 1]); -        subid = asn_compare_oid(&oid_first, &(val->var)) == 0 || -                asn_is_suboid(&oid_first, &(val->var)); +        subid = asn_compare_oid(&ctx.oid_first, &(val->var)) == 0 || +                asn_is_suboid(&ctx.oid_first, &(val->var));      }      /* Print the packet values */ -    if(!recursive || subid) +    if(!ctx.recursive || subid)          ret = print_resp(&pdu, server_get_time()); -    if(ret && recursive && subid) +    if(ret && ctx.recursive && subid)      {          /* If recursive, move onto next one */          setup_next(&(pdu.bindings[pdu.nbindings - 1])); @@ -315,6 +329,23 @@ receive_resp(int fd, int type, void* arg)      server_stop ();  } +static int +send_timer(uint64_t when, void* arg) +{ +    if(ctx.lastsend == 0) +        return 1; + +    /* Check for timeouts */ +    if(ctx.lastsend + ctx.timeout < when) +        errx(1, "timed out waiting for response from server"); + +    /* Resend packets when no response */ +    if(ctx.retries < MAX_RETRIES && ctx.lastsend + RESEND_TIMEOUT < when) +        send_req(); + +    return 1; +} +  /* -----------------------------------------------------------------------------   * STARTUP   */ @@ -322,7 +353,7 @@ receive_resp(int fd, int type, void* arg)  static void  usage()  { -    fprintf(stderr, "usage: rrdbot-get [-nr] snmp://community@host/oid\n"); +    fprintf(stderr, "usage: rrdbot-get [-Mnr] [-t timeout] [-m mibdir] snmp://community@host/oid\n");      fprintf(stderr, "       rrdbot-get -V\n");      exit(2);  } @@ -339,21 +370,45 @@ main(int argc, char* argv[])  {      struct sockaddr_in addr;      char ch; +    char* t; + +    /* Defaults */ +    memset(&ctx, 0, sizeof(ctx)); +    ctx.socket = -1; +    ctx.timeout = DEFAULT_TIMEOUT;      /* Parse the arguments nicely */ -    while((ch = getopt(argc, argv, "nrV")) != -1) +    while((ch = getopt(argc, argv, "m:Mnrt:V")) != -1)      {          switch(ch)          { +        /* mib directory */ +        case 'm': +            mib_directory = optarg; +            break; + +        /* MIB load warnings */ +        case 'M': +            mib_warnings = 1; +            break; +          /* Numeric output */          case 'n': -            numeric = 1; +            ctx.numeric = 1;              break;          /* SNMP walk (recursive)*/          case 'r': -            recursive = 1; +            ctx.recursive = 1; +            break; + +        /* The timeout */ +        case 't': +            ctx.timeout = strtoul(optarg, &t, 10); +            if(*t) +                errx(2, "invalid timeout: %s", optarg); +            ctx.timeout *= 1000;              break;          /* Print version number */ @@ -375,22 +430,36 @@ main(int argc, char* argv[])      if(argc != 1)          usage(); -    setup_req (argv[0]); +    server_init(); + +    setup_req(argv[0]);      /* Setup the SNMP socket */ -    snmp_socket = socket(PF_INET, SOCK_DGRAM, 0); -    if(snmp_socket < 0) +    ctx.socket = socket(PF_INET, SOCK_DGRAM, 0); +    if(ctx.socket < 0)          err(1, "couldn't open snmp socket");      memset(&addr, 0, sizeof(addr));      addr.sin_family = AF_INET; -    if(bind(snmp_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) +    if(bind(ctx.socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)          err(1, "couldn't listen on port"); -    if(server_watch(snmp_socket, SERVER_READ, receive_resp, NULL) == -1) +    if(server_watch(ctx.socket, SERVER_READ, receive_resp, NULL) == -1)          err(1, "couldn't listen on socket"); +    /* Send off first request */      send_req(); +    /* We fire off the resend timer every 1/5 second */ +    if(server_timer(RESEND_TIMEOUT, send_timer, NULL) == -1) +        err(1, "couldn't setup timer"); + +    /* Wait for responses */      server_run(); +    /* Done */ +    server_unwatch(ctx.socket); +    close(ctx.socket); + +    server_uninit(); +      return 0;  } | 
