Blame apps/snmpping.c

Packit fcad23
/*
Packit fcad23
 * Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply.
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * Copyright (c) 2013, Arista Networks, Inc.
Packit fcad23
 * All rights reserved.
Packit fcad23
 *
Packit fcad23
 * Redistribution and use in source and binary forms, with or without
Packit fcad23
 * modification, are permitted provided that the following conditions are
Packit fcad23
 * met:
Packit fcad23
 *
Packit fcad23
 * *  Redistributions of source code must retain the above copyright notice,
Packit fcad23
 *    this list of conditions and the following disclaimer.
Packit fcad23
 *
Packit fcad23
 * *  Redistributions in binary form must reproduce the above copyright
Packit fcad23
 *    notice, this list of conditions and the following disclaimer in the
Packit fcad23
 *    documentation and/or other materials provided with the distribution.
Packit fcad23
 *
Packit fcad23
 * *  Neither the name of Arista Networks, Inc. nor the names of its
Packit fcad23
 *    contributors may be used to endorse or promote products derived
Packit fcad23
 *    from this software without specific prior written permission.
Packit fcad23
 *
Packit fcad23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit fcad23
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit fcad23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit fcad23
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
Packit fcad23
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit fcad23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
Packit fcad23
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Packit fcad23
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
Packit fcad23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
Packit fcad23
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
Packit fcad23
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
Packit fcad23
 * DAMAGE.
Packit fcad23
 */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
Packit fcad23
#include <signal.h>
Packit fcad23
Packit fcad23
#include <ctype.h>
Packit fcad23
Packit fcad23
#if HAVE_ARPA_INET_H
Packit fcad23
#include <arpa/inet.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <sys/types.h>
Packit fcad23
#if HAVE_SYS_SOCKET_H
Packit fcad23
#include <sys/socket.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_NETDB_H
Packit fcad23
#include <netdb.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <math.h>
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
Packit fcad23
#include "inet_ntop.h"
Packit fcad23
Packit fcad23
/* XXX */
Packit fcad23
#define INETADDRESSTYPE_IPV4    1
Packit fcad23
#define INETADDRESSTYPE_IPV6    2
Packit fcad23
Packit fcad23
#define PINGCTLADMINSTATUS_ENABLED 1
Packit fcad23
Packit fcad23
/* Target info */
Packit fcad23
int targetAddrType;
Packit fcad23
u_char targetAddr[16];
Packit fcad23
int targetAddrLen;
Packit fcad23
Packit fcad23
char *targetName;
Packit fcad23
Packit fcad23
/* Parameters */
Packit fcad23
int pings = 15;
Packit fcad23
int datasize = 0;
Packit fcad23
/* todo: timeout, data fill, ownerindex, testname */
Packit fcad23
Packit fcad23
/* Control-C? */
Packit fcad23
int interrupted = 0;
Packit fcad23
Packit fcad23
void
Packit fcad23
usage(void)
Packit fcad23
{
Packit fcad23
    fprintf(stderr, "Usage: snmpping ");
Packit fcad23
    snmp_parse_args_usage(stderr);
Packit fcad23
    fprintf(stderr, " DESTINATION\n\n");
Packit fcad23
    snmp_parse_args_descriptions(stderr);
Packit fcad23
    fprintf(stderr, "\nsnmpping options:\n");
Packit fcad23
    fprintf(stderr, "\t-Cc<pings>\tSpecify the number of pings (1-15)\n");
Packit fcad23
    fprintf(stderr, "\t-Cs<size>\tSpecify the amount of extra data (0-65507)\n");
Packit fcad23
}
Packit fcad23
Packit fcad23
static void
Packit fcad23
optProc(int argc, char *const *argv, int opt)
Packit fcad23
{
Packit fcad23
    char *endptr = NULL;
Packit fcad23
Packit fcad23
    switch (opt) {
Packit fcad23
    case 'C':
Packit fcad23
        while (*optarg) {
Packit fcad23
            switch (*optarg++) {
Packit fcad23
            case 'c':
Packit fcad23
                pings = strtol(optarg, &endptr, 0);
Packit fcad23
                if (pings < 1 || pings > 15) {
Packit fcad23
                    /* out of range */
Packit fcad23
                    usage();
Packit fcad23
                    exit(1);
Packit fcad23
                }
Packit fcad23
Packit fcad23
                optarg = endptr;
Packit fcad23
                if (isspace((unsigned char)(*optarg))) {
Packit fcad23
                    return;
Packit fcad23
                }
Packit fcad23
                break;
Packit fcad23
Packit fcad23
            case 's':
Packit fcad23
                datasize = strtol(optarg, &endptr, 0);
Packit fcad23
                if (datasize < 0 || datasize > 65507) {
Packit fcad23
                    /* out of range */
Packit fcad23
                    usage();
Packit fcad23
                    exit(1);
Packit fcad23
                }
Packit fcad23
Packit fcad23
                optarg = endptr;
Packit fcad23
                if (isspace((unsigned char)(*optarg))) {
Packit fcad23
                    return;
Packit fcad23
                }
Packit fcad23
                break;
Packit fcad23
Packit fcad23
Packit fcad23
            default:
Packit fcad23
                fprintf(stderr,
Packit fcad23
                        "Unknown flag passed to -C: %c\n", optarg[-1]);
Packit fcad23
                exit(1);
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
void sigint(int sig)
Packit fcad23
{
Packit fcad23
    interrupted = 1;
Packit fcad23
    printf("[interrupted]\n");
Packit fcad23
}
Packit fcad23
Packit fcad23
struct pingResultsTable {
Packit fcad23
    int   pingResultsOperStatus;
Packit fcad23
    int   pingResultsMinRtt;
Packit fcad23
    int   pingResultsMaxRtt;
Packit fcad23
    int   pingResultsAverageRtt;
Packit fcad23
    int   pingResultsProbeResponses;
Packit fcad23
    int   pingResultsSentProbes;
Packit fcad23
    int   pingResultsRttSumOfSquares;
Packit fcad23
    char *pingResultsLastGoodProbe;
Packit fcad23
};
Packit fcad23
Packit fcad23
struct pingProbeHistoryTable {
Packit fcad23
    int   pingProbeHistoryIndex;
Packit fcad23
    int   pingProbeHistoryResponse;
Packit fcad23
    int   pingProbeHistoryStatus;
Packit fcad23
    char *pingProbeHistoryTime;
Packit fcad23
};
Packit fcad23
Packit fcad23
const char *
Packit fcad23
inetaddresstop(u_char *addr, int addrlen, int addrtype)
Packit fcad23
{
Packit fcad23
    int type;
Packit fcad23
    static char buf[INET6_ADDRSTRLEN];
Packit fcad23
Packit fcad23
    switch (addrtype) {
Packit fcad23
    case INETADDRESSTYPE_IPV4:
Packit fcad23
        type = AF_INET;
Packit fcad23
        break;
Packit fcad23
    case INETADDRESSTYPE_IPV6:
Packit fcad23
        type = AF_INET6;
Packit fcad23
        break;
Packit fcad23
    default:
Packit fcad23
        buf[0] = '?';
Packit fcad23
        buf[1] = '\0';
Packit fcad23
        return buf;
Packit fcad23
    }
Packit fcad23
    return inet_ntop(type, addr, buf, sizeof(buf));
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
add_var(netsnmp_pdu *pdu, const char *mibnodename,
Packit fcad23
    oid * index, size_t indexlen,
Packit fcad23
    u_char type, const void *value, size_t len)
Packit fcad23
{
Packit fcad23
    oid             base[MAX_OID_LEN];
Packit fcad23
    size_t          base_length = MAX_OID_LEN;
Packit fcad23
Packit fcad23
    memset(base, 0, MAX_OID_LEN * sizeof(oid));
Packit fcad23
Packit fcad23
    if (!snmp_parse_oid(mibnodename, base, &base_length)) {
Packit fcad23
        snmp_perror(mibnodename);
Packit fcad23
        fprintf(stderr, "couldn't find mib node %s, giving up\n",
Packit fcad23
                mibnodename);
Packit fcad23
        exit(1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (index && indexlen) {
Packit fcad23
        memcpy(&(base[base_length]), index, indexlen * sizeof(oid));
Packit fcad23
        base_length += indexlen;
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("add", "created: "));
Packit fcad23
    DEBUGMSGOID(("add", base, base_length));
Packit fcad23
    DEBUGMSG(("add", "\n"));
Packit fcad23
    snmp_varlist_add_variable(&pdu->variables, base, base_length,
Packit fcad23
          type, value, len);
Packit fcad23
Packit fcad23
    return base_length;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
add(netsnmp_pdu *pdu, const char *mibnodename,
Packit fcad23
    oid * index, size_t indexlen)
Packit fcad23
{
Packit fcad23
   return add_var(pdu, mibnodename, index, indexlen, ASN_NULL, NULL, 0);
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
my_synch_response(netsnmp_session *ss, netsnmp_pdu *pdu, netsnmp_pdu **response)
Packit fcad23
{
Packit fcad23
    int status;
Packit fcad23
Packit fcad23
    status = snmp_synch_response(ss, pdu, response);
Packit fcad23
    if (status == STAT_SUCCESS) {
Packit fcad23
        if (*response) {
Packit fcad23
            if ((*response)->errstat == SNMP_ERR_NOERROR) {
Packit fcad23
                return 0;
Packit fcad23
            } else {
Packit fcad23
                fprintf(stderr, "Error in packet.\nReason: %s\n",
Packit fcad23
                        snmp_errstring((*response)->errstat));
Packit fcad23
                if ((*response)->errindex != 0) {
Packit fcad23
                    int             count;
Packit fcad23
                    netsnmp_variable_list *vars;
Packit fcad23
                    fprintf(stderr, "Failed object: ");
Packit fcad23
                    for (count = 1, vars = (*response)->variables;
Packit fcad23
                         vars && count != (*response)->errindex;
Packit fcad23
                         vars = vars->next_variable, count++)
Packit fcad23
                        /*EMPTY*/;
Packit fcad23
                    if (vars)
Packit fcad23
                        fprint_objid(stderr, vars->name,
Packit fcad23
                                     vars->name_length);
Packit fcad23
                    else
Packit fcad23
                        fprintf(stderr, "??? (errindex=%ld)",
Packit fcad23
                                        (*response)->errindex);
Packit fcad23
                    fprintf(stderr, "\n");
Packit fcad23
                }
Packit fcad23
                return 2;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    } else if (status == STAT_TIMEOUT) {
Packit fcad23
        fprintf(stderr, "Timeout: No Response from %s\n",
Packit fcad23
                ss->peername);
Packit fcad23
        return 1;
Packit fcad23
    } else {                    /* status == STAT_ERROR */
Packit fcad23
        snmp_sess_perror("snmpping", ss);
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
cleanup_ctlTable(netsnmp_session *ss, oid * index, size_t indexlen)
Packit fcad23
{
Packit fcad23
    netsnmp_pdu    *pdu;
Packit fcad23
    netsnmp_pdu    *response;
Packit fcad23
    int             rowStatus;
Packit fcad23
    int             status;
Packit fcad23
Packit fcad23
    pdu = snmp_pdu_create(SNMP_MSG_SET);
Packit fcad23
    rowStatus = RS_DESTROY;
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlRowStatus", index, indexlen, ASN_INTEGER,
Packit fcad23
          &rowStatus, sizeof(rowStatus));
Packit fcad23
    status = my_synch_response(ss, pdu, &response);
Packit fcad23
    if (response)
Packit fcad23
        snmp_free_pdu(response);
Packit fcad23
    return status;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
start_ping(netsnmp_session *ss, oid * index, size_t indexlen, char *pingDest)
Packit fcad23
{
Packit fcad23
    netsnmp_pdu    *pdu;
Packit fcad23
    netsnmp_pdu    *response;
Packit fcad23
    int             adminStatus, rowStatus, storageType;
Packit fcad23
    int             status;
Packit fcad23
    struct addrinfo *dest, hints;
Packit fcad23
Packit fcad23
    memset(&hints, 0, sizeof(hints));
Packit fcad23
    hints.ai_flags = AI_CANONNAME;
Packit fcad23
    status = getaddrinfo(pingDest, NULL, &hints, &dest);
Packit fcad23
    if (status != 0) {
Packit fcad23
        fprintf(stderr, "snmpping: %s: %s\n", pingDest, gai_strerror(status));
Packit fcad23
        return 1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Destroy any previously-existing row.  We could get fancy
Packit fcad23
     * and try to reuse it, but that is way more complex.
Packit fcad23
     */
Packit fcad23
    cleanup_ctlTable(ss, index, indexlen);
Packit fcad23
Packit fcad23
    switch (dest->ai_family) {
Packit fcad23
       case AF_INET:
Packit fcad23
          targetAddrType = INETADDRESSTYPE_IPV4;
Packit fcad23
          targetAddrLen = sizeof(struct in_addr);
Packit fcad23
          memcpy(targetAddr, &((struct sockaddr_in *)dest->ai_addr)->sin_addr, targetAddrLen);
Packit fcad23
          break;
Packit fcad23
#ifdef NETSNMP_ENABLE_IPV6
Packit fcad23
       case AF_INET6:
Packit fcad23
          targetAddrType = INETADDRESSTYPE_IPV6;
Packit fcad23
          targetAddrLen = sizeof(struct in6_addr);
Packit fcad23
          memcpy(targetAddr, &((struct sockaddr_in6 *)dest->ai_addr)->sin6_addr, sizeof(struct in6_addr));
Packit fcad23
          break;
Packit fcad23
#endif
Packit fcad23
       default:
Packit fcad23
          fprintf(stderr, "Unsupported address family\n");
Packit fcad23
          return 3;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (dest->ai_canonname) {
Packit fcad23
        targetName = strdup(dest->ai_canonname);
Packit fcad23
    } else {
Packit fcad23
        targetName = strdup(pingDest);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    freeaddrinfo(dest);
Packit fcad23
Packit fcad23
    pdu = snmp_pdu_create(SNMP_MSG_SET);
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlTargetAddressType", index, indexlen, ASN_INTEGER,
Packit fcad23
          &targetAddrType, sizeof(targetAddrType));
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlTargetAddress", index, indexlen, ASN_OCTET_STR,
Packit fcad23
          &targetAddr, targetAddrLen);
Packit fcad23
    /* Rely on DEFVAL to keep the PDU small */
Packit fcad23
    if (pings != 1) {
Packit fcad23
        add_var(pdu, "DISMAN-PING-MIB::pingCtlProbeCount", index, indexlen, ASN_UNSIGNED,
Packit fcad23
              &pings, sizeof(pings));
Packit fcad23
    }
Packit fcad23
    if (datasize != 0) {
Packit fcad23
        add_var(pdu, "DISMAN-PING-MIB::pingCtlDataSize", index, indexlen, ASN_UNSIGNED,
Packit fcad23
              &datasize, sizeof(datasize));
Packit fcad23
    }
Packit fcad23
    adminStatus = PINGCTLADMINSTATUS_ENABLED;
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlAdminStatus", index, indexlen, ASN_INTEGER,
Packit fcad23
          &adminStatus, sizeof(adminStatus));
Packit fcad23
    storageType = ST_VOLATILE;  /* don't ask for this to be saved, we're only going to delete it */
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlStorageType", index, indexlen, ASN_INTEGER,
Packit fcad23
          &storageType, sizeof(storageType));
Packit fcad23
    rowStatus = RS_CREATEANDGO;
Packit fcad23
    add_var(pdu, "DISMAN-PING-MIB::pingCtlRowStatus", index, indexlen, ASN_INTEGER,
Packit fcad23
          &rowStatus, sizeof(rowStatus));
Packit fcad23
    status = my_synch_response(ss, pdu, &response);
Packit fcad23
    if (response)
Packit fcad23
        snmp_free_pdu(response);
Packit fcad23
    if (status == 0) {
Packit fcad23
        printf("PING %s (%s) from %s with %d bytes of extra data\n", targetName,
Packit fcad23
              inetaddresstop(targetAddr, targetAddrLen, targetAddrType), ss->peername,
Packit fcad23
              datasize);
Packit fcad23
    }
Packit fcad23
    return status;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
wait_for_completion(netsnmp_session *ss, oid * index, size_t indexlen)
Packit fcad23
{
Packit fcad23
    int             running = 1;
Packit fcad23
    int             status;
Packit fcad23
    int             pingStatus;
Packit fcad23
    int             sent;
Packit fcad23
    int             responses, prev_responses = 0;
Packit fcad23
    int             tries = 0;
Packit fcad23
    netsnmp_pdu    *pdu;
Packit fcad23
    netsnmp_pdu    *response;
Packit fcad23
    netsnmp_variable_list *vlp;
Packit fcad23
Packit fcad23
    while (running && !interrupted) {
Packit fcad23
        pdu = snmp_pdu_create(SNMP_MSG_GET);
Packit fcad23
        add(pdu, "DISMAN-PING-MIB::pingResultsOperStatus", index, indexlen);
Packit fcad23
        add(pdu, "DISMAN-PING-MIB::pingResultsSentProbes", index, indexlen);
Packit fcad23
        add(pdu, "DISMAN-PING-MIB::pingResultsProbeResponses", index, indexlen);
Packit fcad23
Packit fcad23
        status = snmp_synch_response(ss, pdu, &response);
Packit fcad23
        if (status != STAT_SUCCESS || !response) {
Packit fcad23
            snmp_sess_perror("snmpping", ss);
Packit fcad23
            if (status == STAT_TIMEOUT)
Packit fcad23
                goto retry;
Packit fcad23
            running = 0;
Packit fcad23
            goto out;
Packit fcad23
        }
Packit fcad23
        if (response->errstat != SNMP_ERR_NOERROR) {
Packit fcad23
            fprintf(stderr, "snmpping: Error in packet: %s\n",
Packit fcad23
                    snmp_errstring(response->errstat));
Packit fcad23
            running = 0;
Packit fcad23
            goto out;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        vlp = response->variables;
Packit fcad23
        if (vlp->type == SNMP_NOSUCHINSTANCE) {
Packit fcad23
            DEBUGMSGTL(("ping", "no-such-instance for pingResultsOperStatus\n"));
Packit fcad23
            goto retry;
Packit fcad23
        }
Packit fcad23
        pingStatus = *vlp->val.integer;
Packit fcad23
Packit fcad23
        vlp = vlp->next_variable;
Packit fcad23
        if (vlp->type == SNMP_NOSUCHINSTANCE) {
Packit fcad23
            DEBUGMSGTL(("ping", "no-such-instance for pingResultsSentProbes\n"));
Packit fcad23
            goto retry;
Packit fcad23
        }
Packit fcad23
        sent = *vlp->val.integer;
Packit fcad23
Packit fcad23
        vlp = vlp->next_variable;
Packit fcad23
        if (vlp->type == SNMP_NOSUCHINSTANCE) {
Packit fcad23
            DEBUGMSGTL(("ping", "no-such-instance for pingResultsProbeResponses\n"));
Packit fcad23
            goto retry;
Packit fcad23
        }
Packit fcad23
        responses = *vlp->val.integer;
Packit fcad23
#define PINGRESULTSOPERSTATUS_ENABLED   1 /* XXX */
Packit fcad23
#define PINGRESULTSOPERSTATUS_DISABLED  2 /* XXX */
Packit fcad23
#define PINGRESULTSOPERSTATUS_COMPLETED 3 /* XXX */
Packit fcad23
Packit fcad23
        if (responses > prev_responses || pingStatus == PINGRESULTSOPERSTATUS_COMPLETED) {
Packit fcad23
            DEBUGMSGTL(("ping", "responses %d (was %d), status %d\n", responses, prev_responses, pingStatus));
Packit fcad23
Packit fcad23
            /* collect results between prev_responses and responses by walking probeHistoryTable */
Packit fcad23
            prev_responses = responses;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * Observed behavior: before the test has run, operStatus can be
Packit fcad23
         * disabled, and then can turn to enabled, so we can't just stop
Packit fcad23
         * if it's disabled.  However, it doesn't always go to completed.
Packit fcad23
         * So, we say we're completed if it's completed, *or* if it's
Packit fcad23
         * disabled and we've sent at least one probe.
Packit fcad23
         */
Packit fcad23
        if (pingStatus == PINGRESULTSOPERSTATUS_COMPLETED ||
Packit fcad23
            (pingStatus == PINGRESULTSOPERSTATUS_DISABLED && sent > 0)) {
Packit fcad23
            running = 0;
Packit fcad23
            goto out;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /* sleep before asking again */
Packit fcad23
        sleep(1);
Packit fcad23
Packit fcad23
        if (0) {
Packit fcad23
retry:
Packit fcad23
            if (tries++ < 5) {
Packit fcad23
                /* we can try again */
Packit fcad23
                sleep(1);
Packit fcad23
            } else {
Packit fcad23
                if (status == STAT_TIMEOUT)
Packit fcad23
                    fprintf(stderr, "snmpping: too many timeouts.\n");
Packit fcad23
                else
Packit fcad23
                    fprintf(stderr, "snmpping: pingResultsTable entry never created.\n");
Packit fcad23
                running = 0;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
Packit fcad23
out:
Packit fcad23
        if (response)
Packit fcad23
            snmp_free_pdu(response);
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
overall_stats(netsnmp_session *ss, oid * index, size_t indexlen)
Packit fcad23
{
Packit fcad23
    netsnmp_pdu    *pdu;
Packit fcad23
    netsnmp_pdu    *response;
Packit fcad23
    netsnmp_variable_list *vlp;
Packit fcad23
    int status;
Packit fcad23
    struct pingResultsTable result;
Packit fcad23
Packit fcad23
    pdu = snmp_pdu_create(SNMP_MSG_GET);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsOperStatus", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsMinRtt", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsMaxRtt", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsAverageRtt", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsProbeResponses", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsSentProbes", index, indexlen);
Packit fcad23
    add(pdu, "DISMAN-PING-MIB::pingResultsRttSumOfSquares", index, indexlen);
Packit fcad23
Packit fcad23
    status = snmp_synch_response(ss, pdu, &response);
Packit fcad23
    if (status != STAT_SUCCESS || !response) {
Packit fcad23
        snmp_sess_perror("snmpping", ss);
Packit fcad23
        goto out;
Packit fcad23
    }
Packit fcad23
    if (response->errstat != SNMP_ERR_NOERROR) {
Packit fcad23
        fprintf(stderr, "snmpping: Error in packet: %s\n",
Packit fcad23
                snmp_errstring(response->errstat));
Packit fcad23
        goto out;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    vlp = response->variables;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsOperStatus = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsMinRtt = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsMaxRtt = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsAverageRtt = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsProbeResponses = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsSentProbes = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
    if (vlp->type == SNMP_NOSUCHOBJECT) goto parseerr;
Packit fcad23
    result.pingResultsRttSumOfSquares = *vlp->val.integer;
Packit fcad23
    vlp = vlp->next_variable;
Packit fcad23
Packit fcad23
    printf( "--- %s ping statistics ---\n", targetName );
Packit fcad23
    printf( "%d packets transmitted, %d received, %d%% packet loss\n",
Packit fcad23
            result.pingResultsSentProbes, result.pingResultsProbeResponses,
Packit fcad23
            result.pingResultsSentProbes ?
Packit fcad23
                ( ( result.pingResultsSentProbes -
Packit fcad23
                    result.pingResultsProbeResponses ) * 100 /
Packit fcad23
                  result.pingResultsSentProbes ) : 0 );
Packit fcad23
    if (result.pingResultsProbeResponses) {
Packit fcad23
        double stddev;
Packit fcad23
Packit fcad23
        stddev = result.pingResultsRttSumOfSquares;
Packit fcad23
        stddev /= result.pingResultsProbeResponses;
Packit fcad23
        stddev -= result.pingResultsAverageRtt * result.pingResultsAverageRtt;
Packit fcad23
        /*
Packit fcad23
         * If the RTT is less than 1.0, the sum of squares can be
Packit fcad23
         * smaller than the number of responses, resulting in a
Packit fcad23
         * negative stddev.  Clamp the stddev to 0.
Packit fcad23
         */
Packit fcad23
        if (stddev < 0)
Packit fcad23
            stddev = 0.0;
Packit fcad23
        printf( "rtt min/avg/max/stddev = %d/%d/%d/%d ms\n",
Packit fcad23
                result.pingResultsMinRtt,
Packit fcad23
                result.pingResultsAverageRtt,
Packit fcad23
                result.pingResultsMaxRtt,
Packit fcad23
                (int)sqrt( stddev ));
Packit fcad23
    }
Packit fcad23
    if (0) {
Packit fcad23
parseerr:
Packit fcad23
        fprintf(stderr, "snmpping: Error parsing response packet\n");
Packit fcad23
    }
Packit fcad23
Packit fcad23
out:
Packit fcad23
    if (response)
Packit fcad23
        snmp_free_pdu(response);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
#ifdef WIN32
Packit fcad23
/* To do: port this function to the Win32 platform. */
Packit fcad23
const char *getlogin(void)
Packit fcad23
{
Packit fcad23
    return "";
Packit fcad23
}
Packit fcad23
#endif
Packit fcad23
Packit fcad23
int main(int argc, char **argv)
Packit fcad23
{
Packit fcad23
    netsnmp_session session, *ss;
Packit fcad23
    int ret;
Packit fcad23
    int arg;
Packit fcad23
    oid index[66], *idx;
Packit fcad23
    int indexlen, i;
Packit fcad23
    int usernameLen, testnameLen;
Packit fcad23
    char username[33];
Packit fcad23
    char testname[33];
Packit fcad23
    char *p;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * get the common command line arguments 
Packit fcad23
     */
Packit fcad23
    switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
Packit fcad23
    case NETSNMP_PARSE_ARGS_ERROR:
Packit fcad23
        exit(1);
Packit fcad23
    case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
Packit fcad23
        exit(0);
Packit fcad23
    case NETSNMP_PARSE_ARGS_ERROR_USAGE:
Packit fcad23
        usage();
Packit fcad23
        exit(1);
Packit fcad23
    default:
Packit fcad23
        break;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (arg >= argc) {
Packit fcad23
        fprintf(stderr, "Please specify a destination host.\n");
Packit fcad23
        usage();
Packit fcad23
        exit(1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    SOCK_STARTUP;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * open an SNMP session 
Packit fcad23
     */
Packit fcad23
    ss = snmp_open(&session);
Packit fcad23
    if (ss == NULL) {
Packit fcad23
        /*
Packit fcad23
         * diagnose snmp_open errors with the input netsnmp_session pointer 
Packit fcad23
         */
Packit fcad23
        snmp_sess_perror("snmpping", &session);
Packit fcad23
        exit(1);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (session.securityModel == SNMP_SEC_MODEL_USM) {
Packit fcad23
        strncpy(username, session.securityName, sizeof(username) - 1);
Packit fcad23
        username[32] = '\0';
Packit fcad23
        usernameLen = strlen(username); /* TODO session.securityNameLen */
Packit fcad23
    } else {
Packit fcad23
        strncpy(username, getlogin(), sizeof(username) - 1);
Packit fcad23
        username[32] = '\0';
Packit fcad23
        usernameLen = strlen(username);
Packit fcad23
    }
Packit fcad23
    if (1 /* !have-testname-arg */) {
Packit fcad23
        snprintf(testname, sizeof(testname) - 1, "snmpping-%d", getpid());
Packit fcad23
        testname[32] = '\0';
Packit fcad23
        testnameLen = strlen(testname);
Packit fcad23
    }
Packit fcad23
    idx = index;
Packit fcad23
    *idx++ = usernameLen;
Packit fcad23
    p = username;
Packit fcad23
    for (i = 0; i < usernameLen; i++) {
Packit fcad23
        *idx++ = *p++;
Packit fcad23
    }
Packit fcad23
    *idx++ = testnameLen;
Packit fcad23
    p = testname;
Packit fcad23
    for (i = 0; i < testnameLen; i++) {
Packit fcad23
        *idx++ = *p++;
Packit fcad23
    }
Packit fcad23
    indexlen = idx - index;
Packit fcad23
    ret = start_ping( ss, index, indexlen, argv[ arg ] );
Packit fcad23
    if ( ret != 0 ) {
Packit fcad23
        return ret;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    signal(SIGINT, sigint);
Packit fcad23
Packit fcad23
    wait_for_completion( ss, index, indexlen );
Packit fcad23
    overall_stats( ss, index, indexlen );
Packit fcad23
    cleanup_ctlTable( ss, index, indexlen );
Packit fcad23
Packit fcad23
    snmp_close(ss);
Packit fcad23
    SOCK_CLEANUP;
Packit fcad23
    return 0;
Packit fcad23
}