home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / nocol / part13 < prev    next >
Encoding:
Text File  |  1993-11-23  |  74.9 KB  |  2,415 lines

  1. Newsgroups: comp.sources.misc
  2. From: vikas@jvnc.net (Vikas Aggarwal)
  3. Subject: v40i143:  nocol - Network Monitoring System, Part13/26
  4. Message-ID: <1993Nov23.212613.21564@sparky.sterling.com>
  5. X-Md4-Signature: d6e039333e61328324ea1f9648f85679
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 23 Nov 1993 21:26:13 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: vikas@jvnc.net (Vikas Aggarwal)
  12. Posting-number: Volume 40, Issue 143
  13. Archive-name: nocol/part13
  14. Environment: INET, UNIX
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c
  21. #   nocol-3.0/src/cmu-snmp/include/snmp_api.c
  22. #   nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c
  23. #   nocol-3.0/src/perlnocol/idlemodemmon-confg
  24. # Wrapped by kent@sparky on Tue Nov  9 22:22:19 1993
  25. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  26. echo If this archive is complete, you will see the following message:
  27. echo '          "shar: End of archive 13 (of 26)."'
  28. if test -f 'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c'\"
  30. else
  31.   echo shar: Extracting \"'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c'\" \(11847 characters\)
  32.   sed "s/^X//" >'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c' <<'END_OF_FILE'
  33. X/***********************************************************
  34. X    Copyright 1989 by Carnegie Mellon University
  35. X
  36. X                      All Rights Reserved
  37. X
  38. XPermission to use, copy, modify, and distribute this software and its 
  39. Xdocumentation for any purpose and without fee is hereby granted, 
  40. Xprovided that the above copyright notice appear in all copies and that
  41. Xboth that copyright notice and this permission notice appear in 
  42. Xsupporting documentation, and that the name of CMU not be
  43. Xused in advertising or publicity pertaining to distribution of the
  44. Xsoftware without specific, written prior permission.  
  45. X
  46. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  47. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  48. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  49. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  50. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  51. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  52. XSOFTWARE.
  53. X******************************************************************/
  54. X/*
  55. X * Copyright (c) 1983,1988 Regents of the University of California.
  56. X * All rights reserved.
  57. X *
  58. X * Redistribution and use in source and binary forms are permitted
  59. X * provided that this notice is preserved and that due credit is given
  60. X * to the University of California at Berkeley. The name of the University
  61. X * may not be used to endorse or promote products derived from this
  62. X * software without specific prior written permission. This software
  63. X * is provided ``as is'' without express or implied warranty.
  64. X */
  65. X
  66. X#include <stdio.h>
  67. X#include <strings.h>
  68. X#include <ctype.h>
  69. X
  70. X#include <sys/param.h>
  71. X#include <sys/socket.h>
  72. X
  73. X#include <netinet/in.h>
  74. X#define    LOOPBACKNET 127
  75. X
  76. X#include <netdb.h>
  77. X#include "main.h"
  78. X#include "asn1.h"
  79. X#include "snmp.h"
  80. X#include "snmp_impl.h"
  81. X#include "snmp_api.h"
  82. X#include "snmp_client.h"
  83. X#include "mib.h"
  84. X
  85. Xextern    int nflag;
  86. Xextern    char *routename(), *netname(), *plural();
  87. Xextern    char *malloc();
  88. Xextern    struct snmp_session *Session;
  89. Xextern    struct variable_list *getvarbyname();
  90. Xextern    int print_errors;
  91. X
  92. X
  93. Xstruct route_entry {
  94. X    oid        instance[4];
  95. X    struct in_addr  destination;
  96. X    int        set_destination;
  97. X    struct in_addr  gateway;
  98. X    int        set_gateway;
  99. X    int        interface;
  100. X    int        set_interface;
  101. X    int        type;
  102. X    int        set_type;
  103. X    int        proto;
  104. X    int        set_proto;
  105. X    char    ifname[64];
  106. X    int        set_name;
  107. X};
  108. X
  109. X
  110. X
  111. X#define RTDEST        1
  112. X#define RTIFINDEX   2
  113. X#define RTNEXTHOP   7
  114. X#define RTTYPE        8
  115. X#define RTPROTO        9
  116. Xstatic oid oid_rttable[] = {1, 3, 6, 1, 2, 1, 4, 21, 1};
  117. Xstatic oid oid_rtdest[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 1};
  118. Xstatic oid oid_rtifindex[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 2};
  119. Xstatic oid oid_rtnexthop[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 7};
  120. Xstatic oid oid_rttype[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 8};
  121. Xstatic oid oid_rtproto[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 9};
  122. Xstatic oid oid_ifdescr[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 2};
  123. Xstatic oid oid_ipnoroutes[] = {1, 3, 6, 1, 2, 1, 4, 12, 0};
  124. X
  125. X
  126. X/*
  127. X * Print routing tables.
  128. X */
  129. Xroutepr()
  130. X{
  131. X    struct route_entry route, *rp = &route;
  132. X    struct snmp_pdu *request, *response;
  133. X    struct variable_list *vp;
  134. X    char name[16], *flags;
  135. X    oid *instance, type;
  136. X    int toloopback, status;
  137. X    char ch;
  138. X
  139. X    printf("Routing tables\n");
  140. X    printf("%-16.16s %-18.18s %-6.6s  %s\n",
  141. X        "Destination", "Gateway",
  142. X        "Flags", "Interface");
  143. X
  144. X
  145. X    request = snmp_pdu_create(GETNEXT_REQ_MSG);
  146. X
  147. X    snmp_add_null_var(request, oid_rtdest, sizeof(oid_rtdest)/sizeof(oid));
  148. X    snmp_add_null_var(request, oid_rtifindex, sizeof(oid_rtifindex)/sizeof(oid));
  149. X    snmp_add_null_var(request, oid_rtnexthop, sizeof(oid_rtnexthop)/sizeof(oid));
  150. X    snmp_add_null_var(request, oid_rttype, sizeof(oid_rttype)/sizeof(oid));
  151. X    snmp_add_null_var(request, oid_rtproto, sizeof(oid_rtproto)/sizeof(oid));
  152. X
  153. X    while(request){
  154. X        status = snmp_synch_response(Session, request, &response);
  155. X        if (status != STAT_SUCCESS || response->errstat != SNMP_ERR_NOERROR){
  156. X        fprintf(stderr, "SNMP request failed\n");
  157. X        break;
  158. X        }
  159. X        instance = NULL;
  160. X        request = NULL;
  161. X        rp->set_destination = 0;
  162. X        rp->set_interface = 0;
  163. X        rp->set_gateway = 0;
  164. X        rp->set_type = 0;
  165. X        rp->set_proto = 0;
  166. X        for(vp = response->variables; vp; vp = vp->next_variable){
  167. X        if (vp->name_length != 14 ||
  168. X            bcmp((char *)vp->name, (char *)oid_rttable, sizeof(oid_rttable))){
  169. X            continue;    /* if it isn't in this subtree, just continue */
  170. X        }
  171. X
  172. X        if (instance != NULL){
  173. X            oid *ip, *op;
  174. X            int count;
  175. X
  176. X            ip = instance;
  177. X            op = vp->name + 10;
  178. X            for(count = 0; count < 4; count++){
  179. X            if (*ip++ != *op++)
  180. X                break;
  181. X            }
  182. X            if (count < 4)
  183. X            continue;    /* not the right instance, ignore */
  184. X        } else {
  185. X            instance = vp->name + 10;
  186. X        }
  187. X        /*
  188. X         * At this point, this variable is known to be in the routing table
  189. X         * subtree, and is of the right instance for this transaction.
  190. X         */
  191. X
  192. X        if (request == NULL)
  193. X            request = snmp_pdu_create(GETNEXT_REQ_MSG);
  194. X        snmp_add_null_var(request, vp->name, vp->name_length);
  195. X
  196. X        type = vp->name[9];
  197. X        switch ((char)type){
  198. X            case RTDEST:
  199. X            bcopy((char *)vp->val.string, (char *)&rp->destination, sizeof(u_long));
  200. X            rp->set_destination = 1;
  201. X            break;
  202. X            case RTIFINDEX:
  203. X            rp->interface = *vp->val.integer;
  204. X            rp->set_interface = 1;
  205. X            break;
  206. X            case RTNEXTHOP:
  207. X            bcopy((char *)vp->val.string, (char *)&rp->gateway, sizeof(u_long));
  208. X            rp->set_gateway = 1;
  209. X            break;
  210. X            case RTTYPE:
  211. X            rp->type = *vp->val.integer;
  212. X            rp->set_type = 1;
  213. X            break;
  214. X            case RTPROTO:
  215. X            rp->proto = *vp->val.integer;
  216. X            rp->set_proto = 1;
  217. X            break;
  218. X        }
  219. X        }
  220. X        if (!(rp->set_destination && rp->set_gateway
  221. X        && rp->set_type && rp->set_interface)){
  222. X            if (request)
  223. X            snmp_free_pdu(request);
  224. X            request = 0;
  225. X            continue;
  226. X        }
  227. X        toloopback = *(char *)&rp->gateway == LOOPBACKNET;
  228. X        printf("%-16.16s ",
  229. X        (rp->destination.s_addr == 0) ? "default" :
  230. X        (toloopback) ?
  231. X        routename(rp->destination) : netname(rp->destination, 0L));
  232. X        printf("%-18.18s ", routename(rp->gateway));
  233. X        flags = name;
  234. X        *flags++ = 'U'; /* route is in use */
  235. X        /* this !toloopback shouldnt be necessary */
  236. X        if (!toloopback && rp->type == MIB_IPROUTETYPE_REMOTE)
  237. X        *flags++ = 'G';
  238. X        if (toloopback)
  239. X        *flags++ = 'H';
  240. X        if (rp->proto == MIB_IPROUTEPROTO_ICMP)
  241. X        *flags++ = 'D';    /* redirect */
  242. X        *flags = '\0';
  243. X        printf("%-6.6s ", name);
  244. X        get_ifname(rp->ifname, rp->interface);
  245. X        ch = rp->ifname[strlen(rp->ifname) - 1];
  246. X        ch = '5';   /* force the if statement */
  247. X        if (isdigit(ch))
  248. X        printf(" %.32s\n", rp->ifname);
  249. X        else
  250. X        printf(" %.32s%d\n", rp->ifname, rp->interface);
  251. X
  252. X    }
  253. X}
  254. X
  255. Xstruct iflist {
  256. X    int    index;
  257. X    char name[64];
  258. X    struct iflist *next;
  259. X} *Iflist = NULL;
  260. X
  261. Xget_ifname(name, index)
  262. X    char *name;
  263. X    int index;
  264. X{
  265. X    struct snmp_pdu *pdu, *response;
  266. X    struct variable_list *vp;
  267. X    struct iflist *ip;
  268. X    oid varname[32];
  269. X    int status;
  270. X
  271. X    for(ip = Iflist; ip; ip = ip->next){
  272. X    if (ip->index == index)
  273. X        break;
  274. X    }
  275. X    if (ip){
  276. X    strcpy(name, ip->name);
  277. X    return;
  278. X    }
  279. X    ip = (struct iflist *)malloc(sizeof(struct iflist));
  280. X    ip->next = Iflist;
  281. X    Iflist = ip;
  282. X    ip->index = index;
  283. X    pdu = snmp_pdu_create(GET_REQ_MSG);
  284. X    bcopy((char *)oid_ifdescr, (char *)varname, sizeof(oid_ifdescr));
  285. X    varname[10] = (oid)index;
  286. X    snmp_add_null_var(pdu, varname, sizeof(oid_ifdescr)/sizeof(oid) + 1);
  287. X    status = snmp_synch_response(Session, pdu, &response);
  288. X    if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR){
  289. X    vp = response->variables;
  290. X    bcopy((char *)vp->val.string, ip->name, vp->val_len);
  291. X    ip->name[vp->val_len] = '\0';
  292. X    } else {
  293. X    sprintf(ip->name, "if%d", index);
  294. X    }    
  295. X    strcpy(name, ip->name);
  296. X}
  297. X
  298. Xchar *
  299. Xroutename(in)
  300. X    struct in_addr in;
  301. X{
  302. X    register char *cp;
  303. X    static char line[MAXHOSTNAMELEN + 1];
  304. X    struct hostent *hp;
  305. X    static char domain[MAXHOSTNAMELEN + 1];
  306. X    static int first = 1;
  307. X    char *index();
  308. X
  309. X    if (first) {
  310. X        first = 0;
  311. X        if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
  312. X            (cp = index(domain, '.')))
  313. X            (void) strcpy(domain, cp + 1);
  314. X        else
  315. X            domain[0] = 0;
  316. X    }
  317. X    cp = 0;
  318. X    if (!nflag) {
  319. X        hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
  320. X            AF_INET);
  321. X        if (hp) {
  322. X            if ((cp = index(hp->h_name, '.')) &&
  323. X                !strcmp(cp + 1, domain))
  324. X                *cp = 0;
  325. X            cp = hp->h_name;
  326. X        }
  327. X    }
  328. X    if (cp)
  329. X        strncpy(line, cp, sizeof(line) - 1);
  330. X    else {
  331. X#define C(x)    ((x) & 0xff)
  332. X        in.s_addr = ntohl(in.s_addr);
  333. X        sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  334. X            C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
  335. X    }
  336. X    return (line);
  337. X}
  338. X
  339. X/*
  340. X * Return the name of the network whose address is given.
  341. X * The address is assumed to be that of a net or subnet, not a host.
  342. X */
  343. Xchar *
  344. Xnetname(in, mask)
  345. X    struct in_addr in;
  346. X    u_long mask;
  347. X{
  348. X    char *cp = 0;
  349. X    static char line[MAXHOSTNAMELEN + 1];
  350. X    struct netent *np = 0;
  351. X    u_long net;
  352. X    register i;
  353. X    int subnetshift;
  354. X
  355. X    i = ntohl(in.s_addr);
  356. X    if (!nflag && i) {
  357. X        if (mask == 0) {
  358. X            if (IN_CLASSA(i)) {
  359. X                mask = IN_CLASSA_NET;
  360. X                subnetshift = 8;
  361. X            } else if (IN_CLASSB(i)) {
  362. X                mask = IN_CLASSB_NET;
  363. X                subnetshift = 8;
  364. X            } else {
  365. X                mask = IN_CLASSC_NET;
  366. X                subnetshift = 4;
  367. X            }
  368. X            /*
  369. X             * If there are more bits than the standard mask
  370. X             * would suggest, subnets must be in use.
  371. X             * Guess at the subnet mask, assuming reasonable
  372. X             * width subnet fields.
  373. X             */
  374. X            while (i &~ mask)
  375. X                mask = (long)mask >> subnetshift;
  376. X        }
  377. X        net = i & mask;
  378. X        while ((mask & 1) == 0)
  379. X            mask >>= 1, net >>= 1;
  380. X        np = getnetbyaddr(net, AF_INET);
  381. X        if (np)
  382. X            cp = np->n_name;
  383. X    }    
  384. X    if (cp)
  385. X        strncpy(line, cp, sizeof(line) - 1);
  386. X    else if ((i & 0xffffff) == 0)
  387. X        sprintf(line, "%u", C(i >> 24));
  388. X    else if ((i & 0xffff) == 0)
  389. X        sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
  390. X    else if ((i & 0xff) == 0)
  391. X        sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
  392. X    else
  393. X        sprintf(line, "%u.%u.%u.%u", C(i >> 24),
  394. X            C(i >> 16), C(i >> 8), C(i));
  395. X    return (line);
  396. X}
  397. X
  398. X/*
  399. X * Print routing statistics
  400. X */
  401. Xrt_stats()
  402. X{
  403. X    struct variable_list *var;
  404. X
  405. X    printf("routing:\n");
  406. X    var = getvarbyname(Session, oid_ipnoroutes, sizeof(oid_ipnoroutes) / sizeof(oid));
  407. X    if (var){
  408. X        printf("\t%u destination%s found unreachable\n",
  409. X        *var->val.integer, plural((int)*var->val.integer));
  410. X    } else {
  411. X        printf("\tCouldn't get ipOutNoRoutes variable\n");
  412. X    }
  413. X}
  414. X
  415. X/*
  416. X * Request a variable with a GET REQUEST message on the given
  417. X * session.  The session must have been opened as a synchronous
  418. X * session (synch_setup_session()).  If the variable is found, a
  419. X * pointer to a struct variable_list object will be returned.
  420. X * Otherwise, NULL is returned.  The caller must free the returned
  421. X * variable_list object when done with it.
  422. X */
  423. Xstruct variable_list *
  424. Xgetvarbyname(sp, name, len)
  425. X    struct snmp_session *sp;
  426. X    oid    *name;
  427. X    int len;
  428. X{
  429. X    struct snmp_pdu *request, *response;
  430. X    struct variable_list *var = NULL, *vp;
  431. X    int status;
  432. X
  433. X    request = snmp_pdu_create(GET_REQ_MSG);
  434. X
  435. X    snmp_add_null_var(request, name, len);
  436. X
  437. X    status = snmp_synch_response(sp, request, &response);
  438. X
  439. X    if (status == STAT_SUCCESS){
  440. X    if (response->errstat == SNMP_ERR_NOERROR){
  441. X        for(var = response->variables; var; var = var->next_variable){
  442. X        if (var->name_length == len && !bcmp(name, var->name, len * sizeof(oid)))
  443. X            break;    /* found our match */
  444. X        }
  445. X        if (var != NULL){
  446. X        /*
  447. X         * Now unlink this var from pdu chain so it doesn't get freed.
  448. X         * The caller will free the var.
  449. X         */
  450. X        if (response->variables == var){
  451. X            response->variables = var->next_variable;
  452. X        } else {
  453. X            for(vp = response->variables; vp; vp = vp->next_variable){
  454. X            if (vp->next_variable == var){
  455. X                vp->next_variable = var->next_variable;
  456. X                break;
  457. X            }
  458. X            }
  459. X        }
  460. X        }
  461. X    }
  462. X    }
  463. X    if (response)
  464. X    snmp_free_pdu(response);
  465. X    return var;
  466. X}
  467. END_OF_FILE
  468.   if test 11847 -ne `wc -c <'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c'`; then
  469.     echo shar: \"'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c'\" unpacked with wrong size!
  470.   fi
  471.   # end of 'nocol-3.0/src/cmu-snmp/apps/snmpnetstat/route.c'
  472. fi
  473. if test -f 'nocol-3.0/src/cmu-snmp/include/snmp_api.c' -a "${1}" != "-c" ; then 
  474.   echo shar: Will not clobber existing file \"'nocol-3.0/src/cmu-snmp/include/snmp_api.c'\"
  475. else
  476.   echo shar: Extracting \"'nocol-3.0/src/cmu-snmp/include/snmp_api.c'\" \(28805 characters\)
  477.   sed "s/^X//" >'nocol-3.0/src/cmu-snmp/include/snmp_api.c' <<'END_OF_FILE'
  478. X/***********************************************************
  479. X    Copyright 1989 by Carnegie Mellon University
  480. X
  481. X                      All Rights Reserved
  482. X
  483. XPermission to use, copy, modify, and distribute this software and its 
  484. Xdocumentation for any purpose and without fee is hereby granted, 
  485. Xprovided that the above copyright notice appear in all copies and that
  486. Xboth that copyright notice and this permission notice appear in 
  487. Xsupporting documentation, and that the name of CMU not be
  488. Xused in advertising or publicity pertaining to distribution of the
  489. Xsoftware without specific, written prior permission.  
  490. X
  491. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  492. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  493. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  494. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  495. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  496. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  497. XSOFTWARE.
  498. X******************************************************************/
  499. X/*
  500. X * snmp_api.c - API for access to snmp.
  501. X */
  502. X
  503. X#include <stdio.h>
  504. X#include <sys/types.h>
  505. X#include <sys/param.h>
  506. X#include <sys/time.h>
  507. X#include <netinet/in.h>
  508. X#include <sys/socket.h>
  509. X#include <netdb.h>
  510. X#include "asn1.h"
  511. X#include "snmp.h"
  512. X#include "snmp_impl.h"
  513. X#include "snmp_api.h"
  514. X
  515. X#define PACKET_LENGTH    4500
  516. X
  517. X#ifndef BSD4_3
  518. X#define BSD4_2
  519. X#endif
  520. X
  521. X#ifndef BSD4_3
  522. X
  523. Xtypedef long    fd_mask;
  524. X#define NFDBITS    (sizeof(fd_mask) * NBBY)    /* bits per mask */
  525. X
  526. X#define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  527. X#define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  528. X#define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  529. X#define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  530. X#endif
  531. X
  532. Xoid default_enterprise[] = {1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */
  533. X
  534. X#define DEFAULT_COMMUNITY   "public"
  535. X#define DEFAULT_RETRIES        4
  536. X#define DEFAULT_TIMEOUT        1000000L
  537. X#define DEFAULT_REMPORT        SNMP_PORT
  538. X#define DEFAULT_ENTERPRISE  default_enterprise
  539. X#define DEFAULT_TIME        0
  540. X
  541. X/*
  542. X * Internal information about the state of the snmp session.
  543. X */
  544. Xstruct snmp_internal_session {
  545. X    int        sd;        /* socket descriptor for this connection */
  546. X    ipaddr  addr;    /* address of connected peer */
  547. X    struct request_list *requests;/* Info about outstanding requests */
  548. X};
  549. X
  550. X/*
  551. X * A list of all the outstanding requests for a particular session.
  552. X */
  553. Xstruct request_list {
  554. X    struct request_list *next_request;
  555. X    u_long  request_id;    /* request id */
  556. X    int        retries;    /* Number of retries */
  557. X    u_long timeout;    /* length to wait for timeout */
  558. X    struct timeval time; /* Time this request was made */
  559. X    struct timeval expire;  /* time this request is due to expire */
  560. X    struct snmp_pdu *pdu;   /* The pdu for this request (saved so it can be retransmitted */
  561. X};
  562. X
  563. X/*
  564. X * The list of active/open sessions.
  565. X */
  566. Xstruct session_list {
  567. X    struct session_list *next;
  568. X    struct snmp_session *session;
  569. X    struct snmp_internal_session *internal;
  570. X};
  571. X
  572. Xstruct session_list *Sessions = NULL;
  573. X
  574. Xu_long Reqid = 0;
  575. Xint snmp_errno = 0;
  576. X
  577. Xchar *api_errors[4] = {
  578. X    "Unknown session",
  579. X    "Unknown host",
  580. X    "Invalid local port",
  581. X    "Unknown Error"
  582. X};
  583. X
  584. Xstatic char *
  585. Xapi_errstring(snmp_errnumber)
  586. X    int    snmp_errnumber;
  587. X{
  588. X    if (snmp_errnumber <= SNMPERR_BAD_SESSION && snmp_errnumber >= SNMPERR_GENERR){
  589. X    return api_errors[snmp_errnumber + 4];
  590. X    } else {
  591. X    return "Unknown Error";
  592. X    }
  593. X}
  594. X
  595. X
  596. X/*
  597. X * Gets initial request ID for all transactions.
  598. X */
  599. Xstatic
  600. Xinit_snmp(){
  601. X    struct timeval tv;
  602. X
  603. X    gettimeofday(&tv, (struct timezone *)0);
  604. X    srandom(tv.tv_sec ^ tv.tv_usec);
  605. X    Reqid = random();
  606. X}
  607. X
  608. X/*
  609. X * Sets up the session with the snmp_session information provided
  610. X * by the user.  Then opens and binds the necessary UDP port.
  611. X * A handle to the created session is returned (this is different than
  612. X * the pointer passed to snmp_open()).  On any error, NULL is returned
  613. X * and snmp_errno is set to the appropriate error code.
  614. X */
  615. Xstruct snmp_session *
  616. Xsnmp_open(session)
  617. X    struct snmp_session *session;
  618. X{
  619. X    struct session_list *slp;
  620. X    struct snmp_internal_session *isp;
  621. X    u_char *cp;
  622. X    int sd;
  623. X    u_long addr;
  624. X    struct sockaddr_in    me;
  625. X    struct hostent *hp;
  626. X    struct servent *servp;
  627. X
  628. X
  629. X    if (Reqid == 0)
  630. X    init_snmp();
  631. X
  632. X    /* Copy session structure and link into list */
  633. X    slp = (struct session_list *)malloc(sizeof(struct session_list));
  634. X    slp->internal = isp = (struct snmp_internal_session *)malloc(sizeof(struct snmp_internal_session));
  635. X    bzero((char *)isp, sizeof(struct snmp_internal_session));
  636. X    slp->internal->sd = -1; /* mark it not set */
  637. X    slp->session = (struct snmp_session *)malloc(sizeof(struct snmp_session));
  638. X    bcopy((char *)session, (char *)slp->session, sizeof(struct snmp_session));
  639. X    session = slp->session;
  640. X    /* now link it in. */
  641. X    slp->next = Sessions;
  642. X    Sessions = slp;
  643. X    /*
  644. X     * session now points to the new structure that still contains pointers to
  645. X     * data allocated elsewhere.  Some of this data is copied to space malloc'd
  646. X     * here, and the pointer replaced with the new one.
  647. X     */
  648. X
  649. X    if (session->peername != NULL){
  650. X    cp = (u_char *)malloc((unsigned)strlen(session->peername) + 1);
  651. X    strcpy((char *)cp, session->peername);
  652. X    session->peername = (char *)cp;
  653. X    }
  654. X
  655. X    /* Fill in defaults if necessary */
  656. X    if (session->community_len != SNMP_DEFAULT_COMMUNITY_LEN){
  657. X    cp = (u_char *)malloc((unsigned)session->community_len);
  658. X    bcopy((char *)session->community, (char *)cp, session->community_len);
  659. X    } else {
  660. X    session->community_len = strlen(DEFAULT_COMMUNITY);
  661. X    cp = (u_char *)malloc((unsigned)session->community_len);
  662. X    bcopy((char *)DEFAULT_COMMUNITY, (char *)cp, session->community_len);
  663. X    }
  664. X    session->community = cp;    /* replace pointer with pointer to new data */
  665. X
  666. X    if (session->retries == SNMP_DEFAULT_RETRIES)
  667. X    session->retries = DEFAULT_RETRIES;
  668. X    if (session->timeout == SNMP_DEFAULT_TIMEOUT)
  669. X    session->timeout = DEFAULT_TIMEOUT;
  670. X    isp->requests = NULL;
  671. X
  672. X    /* Set up connections */
  673. X    sd = socket(AF_INET, SOCK_DGRAM, 0);
  674. X    if (sd < 0){
  675. X    perror("socket");
  676. X    snmp_errno = SNMPERR_GENERR;
  677. X    if (!snmp_close(session)){
  678. X        fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  679. X        exit(1);
  680. X    }
  681. X    return 0;
  682. X    }
  683. X    isp->sd = sd;
  684. X    if (session->peername != SNMP_DEFAULT_PEERNAME){
  685. X    if ((addr = inet_addr(session->peername)) != -1){
  686. X        bcopy((char *)&addr, (char *)&isp->addr.sin_addr, sizeof(isp->addr.sin_addr));
  687. X    } else {
  688. X        hp = gethostbyname(session->peername);
  689. X        if (hp == NULL){
  690. X        fprintf(stderr, "unknown host: %s\n", session->peername);
  691. X        snmp_errno = SNMPERR_BAD_ADDRESS;
  692. X        if (!snmp_close(session)){
  693. X            fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  694. X            exit(2);
  695. X        }
  696. X        return 0;
  697. X        } else {
  698. X        bcopy((char *)hp->h_addr, (char *)&isp->addr.sin_addr, hp->h_length);
  699. X        }
  700. X    }
  701. X    isp->addr.sin_family = AF_INET;
  702. X    if (session->remote_port == SNMP_DEFAULT_REMPORT){
  703. X        servp = getservbyname("snmp", "udp");
  704. X        if (servp != NULL){
  705. X        isp->addr.sin_port = servp->s_port;
  706. X        } else {
  707. X        isp->addr.sin_port = htons(SNMP_PORT);
  708. X        }
  709. X    } else {
  710. X        isp->addr.sin_port = htons(session->remote_port);
  711. X    }
  712. X    } else {
  713. X    isp->addr.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
  714. X    }
  715. X
  716. X    me.sin_family = AF_INET;
  717. X    me.sin_addr.s_addr = INADDR_ANY;
  718. X    me.sin_port = htons(session->local_port);
  719. X    if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
  720. X    perror("bind");
  721. X    snmp_errno = SNMPERR_BAD_LOCPORT;
  722. X    if (!snmp_close(session)){
  723. X        fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  724. X        exit(3);
  725. X    }
  726. X    return 0;
  727. X    }
  728. X    return session;
  729. X}
  730. X
  731. X
  732. X/*
  733. X * Free each element in the input request list.
  734. X */
  735. Xstatic
  736. Xfree_request_list(rp)
  737. X    struct request_list *rp;
  738. X{
  739. X    struct request_list *orp;
  740. X
  741. X    while(rp){
  742. X    orp = rp;
  743. X    rp = rp->next_request;
  744. X    if (orp->pdu != NULL)
  745. X        snmp_free_pdu(orp->pdu);
  746. X    free((char *)orp);
  747. X    }
  748. X}
  749. X
  750. X/*
  751. X * Close the input session.  Frees all data allocated for the session,
  752. X * dequeues any pending requests, and closes any sockets allocated for
  753. X * the session.  Returns 0 on error, 1 otherwise.
  754. X */
  755. Xint 
  756. Xsnmp_close(session)
  757. X    struct snmp_session *session;
  758. X{
  759. X    struct session_list *slp = NULL, *oslp = NULL;
  760. X
  761. X    if (Sessions->session == session){    /* If first entry */
  762. X    slp = Sessions;
  763. X    Sessions = slp->next;
  764. X    } else {
  765. X    for(slp = Sessions; slp; slp = slp->next){
  766. X        if (slp->session == session){
  767. X        if (oslp)   /* if we found entry that points here */
  768. X            oslp->next = slp->next;    /* link around this entry */
  769. X        break;
  770. X        }
  771. X        oslp = slp;
  772. X    }
  773. X    }
  774. X    /* If we found the session, free all data associated with it */
  775. X    if (slp){
  776. X    if (slp->session->community != NULL)
  777. X        free((char *)slp->session->community);
  778. X    if(slp->session->peername != NULL)
  779. X        free((char *)slp->session->peername);
  780. X    free((char *)slp->session);
  781. X    if (slp->internal->sd != -1)
  782. X        close(slp->internal->sd);
  783. X    free_request_list(slp->internal->requests);
  784. X    free((char *)slp->internal);
  785. X    free((char *)slp);
  786. X    } else {
  787. X    snmp_errno = SNMPERR_BAD_SESSION;
  788. X    return 0;
  789. X    }
  790. X    return 1;
  791. X}
  792. X
  793. X/*
  794. X * Takes a session and a pdu and serializes the ASN PDU into the area
  795. X * pointed to by packet.  out_length is the size of the data area available.
  796. X * Returns the length of the completed packet in out_length.  If any errors
  797. X * occur, -1 is returned.  If all goes well, 0 is returned.
  798. X */
  799. Xstatic int
  800. Xsnmp_build(session, pdu, packet, out_length)
  801. X    struct snmp_session    *session;
  802. X    struct snmp_pdu    *pdu;
  803. X    register u_char    *packet;
  804. X    int            *out_length;
  805. X{
  806. X    u_char  buf[PACKET_LENGTH];
  807. X    register u_char  *cp;
  808. X    struct variable_list *vp;
  809. X    int        length;
  810. X    long    zero = 0;
  811. X    int        totallength;
  812. X
  813. X    length = *out_length;
  814. X    cp = packet;
  815. X    for(vp = pdu->variables; vp; vp = vp->next_variable){
  816. X    cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type, vp->val_len, (u_char *)vp->val.string, &length);
  817. X    if (cp == NULL)
  818. X        return -1;
  819. X    }
  820. X    totallength = cp - packet;
  821. X
  822. X    length = PACKET_LENGTH;
  823. X    cp = asn_build_header(buf, &length, (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), totallength);
  824. X    if (cp == NULL)
  825. X    return -1;
  826. X    bcopy((char *)packet, (char *)cp, totallength);
  827. X    totallength += cp - buf;
  828. X
  829. X    length = *out_length;
  830. X    if (pdu->command != TRP_REQ_MSG){
  831. X    /* request id */
  832. X    cp = asn_build_int(packet, &length,
  833. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  834. X        (long *)&pdu->reqid, sizeof(pdu->reqid));
  835. X    if (cp == NULL)
  836. X        return -1;
  837. X    /* error status */
  838. X    cp = asn_build_int(cp, &length,
  839. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  840. X        (long *)&pdu->errstat, sizeof(pdu->errstat));
  841. X    if (cp == NULL)
  842. X        return -1;
  843. X    /* error index */
  844. X    cp = asn_build_int(cp, &length,
  845. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  846. X        (long *)&pdu->errindex, sizeof(pdu->errindex));
  847. X    if (cp == NULL)
  848. X        return -1;
  849. X    } else {    /* this is a trap message */
  850. X    /* enterprise */
  851. X    cp = asn_build_objid(packet, &length,
  852. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  853. X        (oid *)pdu->enterprise, pdu->enterprise_length);
  854. X    if (cp == NULL)
  855. X        return -1;
  856. X    /* agent-addr */
  857. X    cp = asn_build_string(cp, &length,
  858. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  859. X        (u_char *)&pdu->agent_addr.sin_addr.s_addr, sizeof(pdu->agent_addr.sin_addr.s_addr));
  860. X    if (cp == NULL)
  861. X        return -1;
  862. X    /* generic trap */
  863. X    cp = asn_build_int(cp, &length,
  864. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  865. X        (long *)&pdu->trap_type, sizeof(pdu->trap_type));
  866. X    if (cp == NULL)
  867. X        return -1;
  868. X    /* specific trap */
  869. X    cp = asn_build_int(cp, &length,
  870. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  871. X        (long *)&pdu->specific_type, sizeof(pdu->specific_type));
  872. X    if (cp == NULL)
  873. X        return -1;
  874. X    /* timestamp  */
  875. X    cp = asn_build_int(cp, &length,
  876. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  877. X        (long *)&pdu->time, sizeof(pdu->time));
  878. X    if (cp == NULL)
  879. X        return -1;
  880. X    }
  881. X    if (length < totallength)
  882. X    return -1;
  883. X    bcopy((char *)buf, (char *)cp, totallength);
  884. X    totallength += cp - packet;
  885. X
  886. X    length = PACKET_LENGTH;
  887. X    cp = asn_build_header(buf, &length, (u_char)pdu->command, totallength);
  888. X    if (cp == NULL)
  889. X    return -1;
  890. X    if (length < totallength)
  891. X    return -1;
  892. X    bcopy((char *)packet, (char *)cp, totallength);
  893. X    totallength += cp - buf;
  894. X
  895. X    length = *out_length;
  896. X    cp = snmp_auth_build(packet, &length, session->community, &session->community_len, &zero, totallength);
  897. X    if (cp == NULL)
  898. X    return -1;
  899. X    if ((*out_length - (cp - packet)) < totallength)
  900. X    return -1;
  901. X    bcopy((char *)buf, (char *)cp, totallength);
  902. X    totallength += cp - packet;
  903. X    *out_length = totallength;
  904. X    return 0;
  905. X}
  906. X
  907. X/*
  908. X * Parses the packet recieved on the input session, and places the data into
  909. X * the input pdu.  length is the length of the input packet.  If any errors
  910. X * are encountered, -1 is returned.  Otherwise, a 0 is returned.
  911. X */
  912. Xstatic int
  913. Xsnmp_parse(session, pdu, data, length)
  914. X    struct snmp_session *session;
  915. X    struct snmp_pdu *pdu;
  916. X    u_char  *data;
  917. X    int        length;
  918. X{
  919. X    u_char  msg_type;
  920. X    u_char  type;
  921. X    u_char  *var_val;
  922. X    long    version;
  923. X    int        len, four;
  924. X    u_char community[128];
  925. X    int community_length = 128;
  926. X    struct variable_list *vp;
  927. X    oid        objid[MAX_NAME_LEN], *op;
  928. X
  929. X    /* authenticates message and returns length if valid */
  930. X    data = snmp_auth_parse(data, &length, community, &community_length, &version);
  931. X    if (data == NULL)
  932. X    return -1;
  933. X    if (version != SNMP_VERSION_1){
  934. X    fprintf(stderr, "Wrong version: %d\n", version);
  935. X    fprintf(stderr, "Continuing anyway\n");
  936. X    }
  937. X    if (session->authenticator){
  938. X    data = session->authenticator(data, &length, community, community_length);
  939. X    if (data == NULL)
  940. X        return 0;
  941. X    }
  942. X    data = asn_parse_header(data, &length, &msg_type);
  943. X    if (data == NULL)
  944. X    return -1;
  945. X    pdu->command = msg_type;
  946. X    if (pdu->command != TRP_REQ_MSG){
  947. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->reqid, sizeof(pdu->reqid));
  948. X    if (data == NULL)
  949. X        return -1;
  950. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->errstat, sizeof(pdu->errstat));
  951. X    if (data == NULL)
  952. X        return -1;
  953. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->errindex, sizeof(pdu->errindex));
  954. X    if (data == NULL)
  955. X        return -1;
  956. X    } else {
  957. X    pdu->enterprise_length = MAX_NAME_LEN;
  958. X    data = asn_parse_objid(data, &length, &type, objid, &pdu->enterprise_length);
  959. X    if (data == NULL)
  960. X        return -1;
  961. X    pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
  962. X    bcopy((char *)objid, (char *)pdu->enterprise, pdu->enterprise_length * sizeof(oid));
  963. X
  964. X    four = 4;
  965. X    data = asn_parse_string(data, &length, &type, (u_char *)&pdu->agent_addr.sin_addr.s_addr, &four);
  966. X    if (data == NULL)
  967. X        return -1;
  968. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->trap_type, sizeof(pdu->trap_type));
  969. X    if (data == NULL)
  970. X        return -1;
  971. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->specific_type, sizeof(pdu->specific_type));
  972. X    if (data == NULL)
  973. X        return -1;
  974. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->time, sizeof(pdu->time));
  975. X    if (data == NULL)
  976. X        return -1;
  977. X    }
  978. X    data = asn_parse_header(data, &length, &type);
  979. X    if (data == NULL)
  980. X    return -1;
  981. X    if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR))
  982. X    return -1;
  983. X    while((int)length > 0){
  984. X    if (pdu->variables == NULL){
  985. X        pdu->variables = vp = (struct variable_list *)malloc(sizeof(struct variable_list));
  986. X    } else {
  987. X        vp->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
  988. X        vp = vp->next_variable;
  989. X    }
  990. X    vp->next_variable = NULL;
  991. X    vp->val.string = NULL;
  992. X    vp->name = NULL;
  993. X    vp->name_length = MAX_NAME_LEN;
  994. X    data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type, &vp->val_len, &var_val, (int *)&length);
  995. X    if (data == NULL)
  996. X        return -1;
  997. X    op = (oid *)malloc((unsigned)vp->name_length * sizeof(oid));
  998. X    bcopy((char *)objid, (char *)op, vp->name_length * sizeof(oid));
  999. X    vp->name = op;
  1000. X
  1001. X    len = PACKET_LENGTH;
  1002. X    switch((short)vp->type){
  1003. X        case ASN_INTEGER:
  1004. X        case COUNTER:
  1005. X        case GAUGE:
  1006. X        case TIMETICKS:
  1007. X        vp->val.integer = (long *)malloc(sizeof(long));
  1008. X        vp->val_len = sizeof(long);
  1009. X        asn_parse_int(var_val, &len, &vp->type, (long *)vp->val.integer, sizeof(vp->val.integer));
  1010. X        break;
  1011. X        case ASN_OCTET_STR:
  1012. X        case IPADDRESS:
  1013. X        case OPAQUE:
  1014. X        vp->val.string = (u_char *)malloc((unsigned)vp->val_len);
  1015. X        asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
  1016. X        break;
  1017. X        case ASN_OBJECT_ID:
  1018. X        vp->val_len = MAX_NAME_LEN;
  1019. X        asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
  1020. X        vp->val_len *= sizeof(oid);
  1021. X        vp->val.objid = (oid *)malloc((unsigned)vp->val_len);
  1022. X        bcopy((char *)objid, (char *)vp->val.objid, vp->val_len);
  1023. X        break;
  1024. X        case ASN_NULL:
  1025. X        break;
  1026. X        default:
  1027. X        fprintf(stderr, "bad type returned (%x)\n", vp->type);
  1028. X        break;
  1029. X    }
  1030. X    }
  1031. X    return 0;
  1032. X}
  1033. X
  1034. X/*
  1035. X * Sends the input pdu on the session after calling snmp_build to create
  1036. X * a serialized packet.  If necessary, set some of the pdu data from the
  1037. X * session defaults.  Add a request corresponding to this pdu to the list
  1038. X * of outstanding requests on this session, then send the pdu.
  1039. X * Returns the request id of the generated packet if applicable, otherwise 1.
  1040. X * On any error, 0 is returned.
  1041. X * The pdu is freed by snmp_send() unless a failure occured.
  1042. X */
  1043. Xint
  1044. Xsnmp_send(session, pdu)
  1045. X    struct snmp_session *session;
  1046. X    struct snmp_pdu    *pdu;
  1047. X{
  1048. X    struct session_list *slp;
  1049. X    struct snmp_internal_session *isp = NULL;
  1050. X    u_char  packet[PACKET_LENGTH];
  1051. X    int length = PACKET_LENGTH;
  1052. X    struct request_list *rp;
  1053. X    struct timeval tv;
  1054. X
  1055. X    for(slp = Sessions; slp; slp = slp->next){
  1056. X    if (slp->session == session){
  1057. X        isp = slp->internal;
  1058. X        break;
  1059. X    }
  1060. X    }
  1061. X    if (isp == NULL){
  1062. X    snmp_errno = SNMPERR_BAD_SESSION;
  1063. X    return 0;
  1064. X    }
  1065. X    if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
  1066. X    || pdu->command == GET_RSP_MSG || pdu->command == SET_REQ_MSG){
  1067. X    if (pdu->reqid == SNMP_DEFAULT_REQID)
  1068. X        pdu->reqid = ++Reqid;
  1069. X    if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  1070. X        pdu->errstat = 0;
  1071. X    if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  1072. X        pdu->errindex = 0;
  1073. X    } else {
  1074. X    /* fill in trap defaults */
  1075. X    pdu->reqid = 1;    /* give a bogus non-error reqid for traps */
  1076. X    if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH){
  1077. X        pdu->enterprise = (oid *)malloc(sizeof(DEFAULT_ENTERPRISE));
  1078. X        bcopy((char *)DEFAULT_ENTERPRISE, (char *)pdu->enterprise, sizeof(DEFAULT_ENTERPRISE));
  1079. X        pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
  1080. X    }
  1081. X    if (pdu->time == SNMP_DEFAULT_TIME)
  1082. X        pdu->time = DEFAULT_TIME;
  1083. X    }
  1084. X    if (pdu->address.sin_addr.s_addr == SNMP_DEFAULT_ADDRESS){
  1085. X    if (isp->addr.sin_addr.s_addr != SNMP_DEFAULT_ADDRESS){
  1086. X        bcopy((char *)&isp->addr, (char *)&pdu->address, sizeof(pdu->address));
  1087. X    } else {
  1088. X        fprintf(stderr, "No remote IP address specified\n");
  1089. X        snmp_errno = SNMPERR_BAD_ADDRESS;
  1090. X        return 0;
  1091. X    }
  1092. X    }
  1093. X    
  1094. X
  1095. X    if (snmp_build(session, pdu, packet, &length) < 0){
  1096. X    fprintf(stderr, "Error building packet\n");
  1097. X    snmp_errno = SNMPERR_GENERR;
  1098. X    return 0;
  1099. X    }
  1100. X    if (snmp_dump_packet){
  1101. X    int count;
  1102. X
  1103. X    for(count = 0; count < length; count++){
  1104. X        printf("%02X ", packet[count]);
  1105. X        if ((count % 16) == 15)
  1106. X        printf("\n");
  1107. X    }
  1108. X    printf("\n\n");
  1109. X    }
  1110. X
  1111. X    gettimeofday(&tv, (struct timezone *)0);
  1112. X    if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&pdu->address, sizeof(pdu->address)) < 0){
  1113. X    perror("sendto");
  1114. X    snmp_errno = SNMPERR_GENERR;
  1115. X    return 0;
  1116. X    }
  1117. X    if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG || pdu->command == SET_REQ_MSG){
  1118. X    /* set up to expect a response */
  1119. X    rp = (struct request_list *)malloc(sizeof(struct request_list));
  1120. X    rp->next_request = isp->requests;
  1121. X    isp->requests = rp;
  1122. X    rp->pdu = pdu;
  1123. X    rp->request_id = pdu->reqid;
  1124. X
  1125. X    rp->retries = 1;
  1126. X    rp->timeout = session->timeout;
  1127. X    rp->time = tv;
  1128. X    tv.tv_usec += rp->timeout;
  1129. X    tv.tv_sec += tv.tv_usec / 1000000L;
  1130. X    tv.tv_usec %= 1000000L;
  1131. X    rp->expire = tv;
  1132. X    }
  1133. X    return pdu->reqid;
  1134. X}
  1135. X
  1136. X/*
  1137. X * Frees the pdu and any malloc'd data associated with it.
  1138. X */
  1139. Xvoid
  1140. Xsnmp_free_pdu(pdu)
  1141. X    struct snmp_pdu *pdu;
  1142. X{
  1143. X    struct variable_list *vp, *ovp;
  1144. X
  1145. X    vp = pdu->variables;
  1146. X    while(vp){
  1147. X    if (vp->name)
  1148. X        free((char *)vp->name);
  1149. X    if (vp->val.string)
  1150. X        free((char *)vp->val.string);
  1151. X    ovp = vp;
  1152. X    vp = vp->next_variable;
  1153. X    free((char *)ovp);
  1154. X    }
  1155. X    if (pdu->enterprise)
  1156. X    free((char *)pdu->enterprise);
  1157. X    free((char *)pdu);
  1158. X}
  1159. X
  1160. X
  1161. X/*
  1162. X * Checks to see if any of the fd's set in the fdset belong to
  1163. X * snmp.  Each socket with it's fd set has a packet read from it
  1164. X * and snmp_parse is called on the packet received.  The resulting pdu
  1165. X * is passed to the callback routine for that session.  If the callback
  1166. X * routine returns successfully, the pdu and it's request are deleted.
  1167. X */
  1168. Xvoid
  1169. Xsnmp_read(fdset)
  1170. X    fd_set  *fdset;
  1171. X{
  1172. X    struct session_list *slp;
  1173. X    struct snmp_session *sp;
  1174. X    struct snmp_internal_session *isp;
  1175. X    u_char packet[PACKET_LENGTH];
  1176. X    struct sockaddr_in    from;
  1177. X    int length, fromlength;
  1178. X    struct snmp_pdu *pdu;
  1179. X    struct request_list *rp, *orp;
  1180. X
  1181. X    for(slp = Sessions; slp; slp = slp->next){
  1182. X    if (FD_ISSET(slp->internal->sd, fdset)){
  1183. X        sp = slp->session;
  1184. X        isp = slp->internal;
  1185. X        fromlength = sizeof from;
  1186. X        length = recvfrom(isp->sd, (char *)packet, PACKET_LENGTH, 0, (struct sockaddr *)&from, &fromlength);
  1187. X        if (length == -1)
  1188. X        perror("recvfrom");
  1189. X        if (snmp_dump_packet){
  1190. X        int count;
  1191. X
  1192. X        printf("recieved %d bytes from %s:\n", length, inet_ntoa(from.sin_addr));
  1193. X        for(count = 0; count < length; count++){
  1194. X            printf("%02X ", packet[count]);
  1195. X            if ((count % 16) == 15)
  1196. X            printf("\n");
  1197. X        }
  1198. X        printf("\n\n");
  1199. X        }
  1200. X
  1201. X        pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
  1202. X        pdu->address = from;
  1203. X        pdu->reqid = 0;
  1204. X        pdu->variables = NULL;
  1205. X        pdu->enterprise = NULL;
  1206. X        pdu->enterprise_length = 0;
  1207. X        if (snmp_parse(sp, pdu, packet, length) != SNMP_ERR_NOERROR){
  1208. X        fprintf(stderr, "Mangled packet\n");
  1209. X        snmp_free_pdu(pdu);
  1210. X        return;
  1211. X        }
  1212. X
  1213. X        if (pdu->command == GET_RSP_MSG){
  1214. X        for(rp = isp->requests; rp; rp = rp->next_request){
  1215. X            if (rp->request_id == pdu->reqid){
  1216. X            if (sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic) == 1){
  1217. X                /* successful, so delete request */
  1218. X                orp = rp;
  1219. X                if (isp->requests == orp){
  1220. X                /* first in list */
  1221. X                isp->requests = orp->next_request;
  1222. X                } else {
  1223. X                for(rp = isp->requests; rp; rp = rp->next_request){
  1224. X                    if (rp->next_request == orp){
  1225. X                    rp->next_request = orp->next_request;    /* link around it */
  1226. X                    break;
  1227. X                    }
  1228. X                }
  1229. X                }
  1230. X                snmp_free_pdu(orp->pdu);
  1231. X                free((char *)orp);
  1232. X                break;  /* there shouldn't be any more request with the same reqid */
  1233. X            }
  1234. X            }
  1235. X        }
  1236. X        } else if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
  1237. X            || pdu->command == TRP_REQ_MSG || pdu->command == SET_REQ_MSG){
  1238. X        sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic);
  1239. X        }
  1240. X        snmp_free_pdu(pdu);
  1241. X    }
  1242. X    }
  1243. X}
  1244. X
  1245. X/*
  1246. X * Returns info about what snmp requires from a select statement.
  1247. X * numfds is the number of fds in the list that are significant.
  1248. X * All file descriptors opened for SNMP are OR'd into the fdset.
  1249. X * If activity occurs on any of these file descriptors, snmp_read
  1250. X * should be called with that file descriptor set
  1251. X *
  1252. X * The timeout is the latest time that SNMP can wait for a timeout.  The
  1253. X * select should be done with the minimum time between timeout and any other
  1254. X * timeouts necessary.  This should be checked upon each invocation of select.
  1255. X * If a timeout is received, snmp_timeout should be called to check if the
  1256. X * timeout was for SNMP.  (snmp_timeout is idempotent)
  1257. X *
  1258. X * Block is 1 if the select is requested to block indefinitely, rather than time out.
  1259. X * If block is input as 1, the timeout value will be treated as undefined, but it must
  1260. X * be available for setting in snmp_select_info.  On return, if block is true, the value
  1261. X * of timeout will be undefined.
  1262. X *
  1263. X * snmp_select_info returns the number of open sockets.  (i.e. The number of sessions open)
  1264. X */
  1265. Xint
  1266. Xsnmp_select_info(numfds, fdset, timeout, block)
  1267. X    int        *numfds;
  1268. X    fd_set  *fdset;
  1269. X    struct timeval *timeout;
  1270. X    int        *block; /* should the select block until input arrives (i.e. no input) */
  1271. X{
  1272. X    struct session_list *slp;
  1273. X    struct snmp_internal_session *isp;
  1274. X    struct request_list *rp;
  1275. X    struct timeval now, earliest;
  1276. X    int active = 0, requests = 0;
  1277. X
  1278. X    timerclear(&earliest);
  1279. X    /*
  1280. X     * For each request outstanding, add it's socket to the fdset,
  1281. X     * and if it is the earliest timeout to expire, mark it as lowest.
  1282. X     */
  1283. X    for(slp = Sessions; slp; slp = slp->next){
  1284. X    active++;
  1285. X    isp = slp->internal;
  1286. X    if ((isp->sd + 1) > *numfds)
  1287. X        *numfds = (isp->sd + 1);
  1288. X    FD_SET(isp->sd, fdset);
  1289. X    if (isp->requests){
  1290. X        /* found another session with outstanding requests */
  1291. X        requests++;
  1292. X        for(rp = isp->requests; rp; rp = rp->next_request){
  1293. X        if (!timerisset(&earliest) || timercmp(&rp->expire, &earliest, <))
  1294. X            earliest = rp->expire;
  1295. X        }
  1296. X    }
  1297. X    }
  1298. X    if (requests == 0)    /* if none are active, skip arithmetic */
  1299. X    return active;
  1300. X
  1301. X    /*
  1302. X     * Now find out how much time until the earliest timeout.  This
  1303. X     * transforms earliest from an absolute time into a delta time, the
  1304. X     * time left until the select should timeout.
  1305. X     */
  1306. X    gettimeofday(&now, (struct timezone *)0);
  1307. X    earliest.tv_sec--;    /* adjust time to make arithmetic easier */
  1308. X    earliest.tv_usec += 1000000L;
  1309. X    earliest.tv_sec -= now.tv_sec;
  1310. X    earliest.tv_usec -= now.tv_usec;
  1311. X    while (earliest.tv_usec >= 1000000L){
  1312. X    earliest.tv_usec -= 1000000L;
  1313. X    earliest.tv_sec += 1;
  1314. X    }
  1315. X    if (earliest.tv_sec < 0){
  1316. X    earliest.tv_sec = 0;
  1317. X    earliest.tv_usec = 0;
  1318. X    }
  1319. X
  1320. X    /* if it was blocking before or our delta time is less, reset timeout */
  1321. X    if (*block == 1 || timercmp(&earliest, timeout, <)){
  1322. X    *timeout = earliest;
  1323. X    *block = 0;
  1324. X    }
  1325. X    return active;
  1326. X}
  1327. X
  1328. X/*
  1329. X * snmp_timeout should be called whenever the timeout from snmp_select_info expires,
  1330. X * but it is idempotent, so snmp_timeout can be polled (probably a cpu expensive
  1331. X * proposition).  snmp_timeout checks to see if any of the sessions have an
  1332. X * outstanding request that has timed out.  If it finds one (or more), and that
  1333. X * pdu has more retries available, a new packet is formed from the pdu and is
  1334. X * resent.  If there are no more retries available, the callback for the session
  1335. X * is used to alert the user of the timeout.
  1336. X */
  1337. Xvoid
  1338. Xsnmp_timeout(){
  1339. X    struct session_list *slp;
  1340. X    struct snmp_session *sp;
  1341. X    struct snmp_internal_session *isp;
  1342. X    struct request_list *rp, *orp, *freeme = NULL;
  1343. X    struct timeval now;
  1344. X
  1345. X    gettimeofday(&now, (struct timezone *)0);
  1346. X    /*
  1347. X     * For each request outstanding, check to see if it has expired.
  1348. X     */
  1349. X    for(slp = Sessions; slp; slp = slp->next){
  1350. X    sp = slp->session;
  1351. X    isp = slp->internal;
  1352. X    orp = NULL;
  1353. X    for(rp = isp->requests; rp; rp = rp->next_request){
  1354. X        if (freeme != NULL){    /* frees rp's after the for loop goes on to the next_request */
  1355. X        free((char *)freeme);
  1356. X        freeme = NULL;
  1357. X        }
  1358. X        if (timercmp(&rp->expire, &now, <)){
  1359. X        /* this timer has expired */
  1360. X        if (rp->retries >= sp->retries){
  1361. X            /* No more chances, delete this entry */
  1362. X            sp->callback(TIMED_OUT, sp, rp->pdu->reqid, rp->pdu, sp->callback_magic);
  1363. X            if (orp == NULL){
  1364. X            isp->requests = rp->next_request;
  1365. X            } else {
  1366. X            orp->next_request = rp->next_request;
  1367. X            }
  1368. X            snmp_free_pdu(rp->pdu);
  1369. X            freeme = rp;
  1370. X            continue;    /* don't update orp below */
  1371. X        } else {
  1372. X            u_char  packet[PACKET_LENGTH];
  1373. X            int length = PACKET_LENGTH;
  1374. X            struct timeval tv;
  1375. X
  1376. X            /* retransmit this pdu */
  1377. X            rp->retries++;
  1378. X            rp->timeout <<= 1;
  1379. X            if (snmp_build(sp, rp->pdu, packet, &length) < 0){
  1380. X            fprintf(stderr, "Error building packet\n");
  1381. X            }
  1382. X            if (snmp_dump_packet){
  1383. X            int count;
  1384. X
  1385. X            for(count = 0; count < length; count++){
  1386. X                printf("%02X ", packet[count]);
  1387. X                if ((count % 16) == 15)
  1388. X                printf("\n");
  1389. X            }
  1390. X            printf("\n\n");
  1391. X            }
  1392. X            gettimeofday(&tv, (struct timezone *)0);
  1393. X            if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&rp->pdu->address, sizeof(rp->pdu->address)) < 0){
  1394. X            perror("sendto");
  1395. X            }
  1396. X            rp->time = tv;
  1397. X            tv.tv_usec += rp->timeout;
  1398. X            tv.tv_sec += tv.tv_usec / 1000000L;
  1399. X            tv.tv_usec %= 1000000L;
  1400. X            rp->expire = tv;
  1401. X        }
  1402. X        }
  1403. X        orp = rp;
  1404. X    }
  1405. X    if (freeme != NULL){
  1406. X        free((char *)freeme);
  1407. X        freeme = NULL;
  1408. X    }
  1409. X    }
  1410. X}
  1411. END_OF_FILE
  1412.   if test 28805 -ne `wc -c <'nocol-3.0/src/cmu-snmp/include/snmp_api.c'`; then
  1413.     echo shar: \"'nocol-3.0/src/cmu-snmp/include/snmp_api.c'\" unpacked with wrong size!
  1414.   fi
  1415.   # end of 'nocol-3.0/src/cmu-snmp/include/snmp_api.c'
  1416. fi
  1417. if test -f 'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c' -a "${1}" != "-c" ; then 
  1418.   echo shar: Will not clobber existing file \"'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c'\"
  1419. else
  1420.   echo shar: Extracting \"'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c'\" \(28907 characters\)
  1421.   sed "s/^X//" >'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c' <<'END_OF_FILE'
  1422. X/***********************************************************
  1423. X    Copyright 1989 by Carnegie Mellon University
  1424. X
  1425. X                      All Rights Reserved
  1426. X
  1427. XPermission to use, copy, modify, and distribute this software and its 
  1428. Xdocumentation for any purpose and without fee is hereby granted, 
  1429. Xprovided that the above copyright notice appear in all copies and that
  1430. Xboth that copyright notice and this permission notice appear in 
  1431. Xsupporting documentation, and that the name of CMU not be
  1432. Xused in advertising or publicity pertaining to distribution of the
  1433. Xsoftware without specific, written prior permission.  
  1434. X
  1435. XCMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  1436. XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  1437. XCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  1438. XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  1439. XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  1440. XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  1441. XSOFTWARE.
  1442. X******************************************************************/
  1443. X/*
  1444. X * snmp_api.c - API for access to snmp.
  1445. X */
  1446. X
  1447. X#include <stdio.h>
  1448. X#include <sys/types.h>
  1449. X#include <sys/param.h>
  1450. X#include <sys/time.h>
  1451. X#include <netinet/in.h>
  1452. X#include <sys/socket.h>
  1453. X#include <netdb.h>
  1454. X#include "asn1.h"
  1455. X#include "snmp.h"
  1456. X#include "snmp_impl.h"
  1457. X#include "snmp_api.h"
  1458. X
  1459. X#define PACKET_LENGTH    4500
  1460. X
  1461. X#ifndef BSD4_3
  1462. X#define BSD4_2
  1463. X#endif
  1464. X
  1465. X#if defined(FD_SET)  ||  defined(BSD4_3)
  1466. X# define HAVE_FD_MACROS
  1467. X#endif
  1468. X
  1469. X#ifndef HAVE_FD_MACROS
  1470. X
  1471. Xtypedef long    fd_mask;
  1472. X#define NFDBITS    (sizeof(fd_mask) * NBBY)    /* bits per mask */
  1473. X
  1474. X#define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  1475. X#define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  1476. X#define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  1477. X#define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  1478. X#endif    /* HAVE_FD_MACROS */
  1479. X
  1480. Xoid default_enterprise[] = {1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */
  1481. X
  1482. X#define DEFAULT_COMMUNITY   "public"
  1483. X#define DEFAULT_RETRIES        4
  1484. X#define DEFAULT_TIMEOUT        1000000L
  1485. X#define DEFAULT_REMPORT        SNMP_PORT
  1486. X#define DEFAULT_ENTERPRISE  default_enterprise
  1487. X#define DEFAULT_TIME        0
  1488. X
  1489. X/*
  1490. X * Internal information about the state of the snmp session.
  1491. X */
  1492. Xstruct snmp_internal_session {
  1493. X    int        sd;        /* socket descriptor for this connection */
  1494. X    ipaddr  addr;    /* address of connected peer */
  1495. X    struct request_list *requests;/* Info about outstanding requests */
  1496. X};
  1497. X
  1498. X/*
  1499. X * A list of all the outstanding requests for a particular session.
  1500. X */
  1501. Xstruct request_list {
  1502. X    struct request_list *next_request;
  1503. X    u_long  request_id;    /* request id */
  1504. X    int        retries;    /* Number of retries */
  1505. X    u_long timeout;    /* length to wait for timeout */
  1506. X    struct timeval time; /* Time this request was made */
  1507. X    struct timeval expire;  /* time this request is due to expire */
  1508. X    struct snmp_pdu *pdu;   /* The pdu for this request (saved so it can be retransmitted */
  1509. X};
  1510. X
  1511. X/*
  1512. X * The list of active/open sessions.
  1513. X */
  1514. Xstruct session_list {
  1515. X    struct session_list *next;
  1516. X    struct snmp_session *session;
  1517. X    struct snmp_internal_session *internal;
  1518. X};
  1519. X
  1520. Xstruct session_list *Sessions = NULL;
  1521. X
  1522. Xu_long Reqid = 0;
  1523. Xint snmp_errno = 0;
  1524. X
  1525. Xchar *api_errors[4] = {
  1526. X    "Unknown session",
  1527. X    "Unknown host",
  1528. X    "Invalid local port",
  1529. X    "Unknown Error"
  1530. X};
  1531. X
  1532. Xstatic char *
  1533. Xapi_errstring(snmp_errnumber)
  1534. X    int    snmp_errnumber;
  1535. X{
  1536. X    if (snmp_errnumber <= SNMPERR_BAD_SESSION && snmp_errnumber >= SNMPERR_GENERR){
  1537. X    return api_errors[snmp_errnumber + 4];
  1538. X    } else {
  1539. X    return "Unknown Error";
  1540. X    }
  1541. X}
  1542. X
  1543. X
  1544. X/*
  1545. X * Gets initial request ID for all transactions.
  1546. X */
  1547. Xstatic
  1548. Xinit_snmp(){
  1549. X    struct timeval tv;
  1550. X
  1551. X    gettimeofday(&tv, (struct timezone *)0);
  1552. X    srandom(tv.tv_sec ^ tv.tv_usec);
  1553. X    Reqid = random();
  1554. X}
  1555. X
  1556. X/*
  1557. X * Sets up the session with the snmp_session information provided
  1558. X * by the user.  Then opens and binds the necessary UDP port.
  1559. X * A handle to the created session is returned (this is different than
  1560. X * the pointer passed to snmp_open()).  On any error, NULL is returned
  1561. X * and snmp_errno is set to the appropriate error code.
  1562. X */
  1563. Xstruct snmp_session *
  1564. Xsnmp_open(session)
  1565. X    struct snmp_session *session;
  1566. X{
  1567. X    struct session_list *slp;
  1568. X    struct snmp_internal_session *isp;
  1569. X    u_char *cp;
  1570. X    int sd;
  1571. X    u_long addr;
  1572. X    struct sockaddr_in    me;
  1573. X    struct hostent *hp;
  1574. X    struct servent *servp;
  1575. X
  1576. X
  1577. X    if (Reqid == 0)
  1578. X    init_snmp();
  1579. X
  1580. X    /* Copy session structure and link into list */
  1581. X    slp = (struct session_list *)malloc(sizeof(struct session_list));
  1582. X    slp->internal = isp = (struct snmp_internal_session *)malloc(sizeof(struct snmp_internal_session));
  1583. X    bzero((char *)isp, sizeof(struct snmp_internal_session));
  1584. X    slp->internal->sd = -1; /* mark it not set */
  1585. X    slp->session = (struct snmp_session *)malloc(sizeof(struct snmp_session));
  1586. X    bcopy((char *)session, (char *)slp->session, sizeof(struct snmp_session));
  1587. X    session = slp->session;
  1588. X    /* now link it in. */
  1589. X    slp->next = Sessions;
  1590. X    Sessions = slp;
  1591. X    /*
  1592. X     * session now points to the new structure that still contains pointers to
  1593. X     * data allocated elsewhere.  Some of this data is copied to space malloc'd
  1594. X     * here, and the pointer replaced with the new one.
  1595. X     */
  1596. X
  1597. X    if (session->peername != NULL){
  1598. X    cp = (u_char *)malloc((unsigned)strlen(session->peername) + 1);
  1599. X    strcpy((char *)cp, session->peername);
  1600. X    session->peername = (char *)cp;
  1601. X    }
  1602. X
  1603. X    /* Fill in defaults if necessary */
  1604. X    if (session->community_len != SNMP_DEFAULT_COMMUNITY_LEN){
  1605. X    cp = (u_char *)malloc((unsigned)session->community_len);
  1606. X    bcopy((char *)session->community, (char *)cp, session->community_len);
  1607. X    } else {
  1608. X    session->community_len = strlen(DEFAULT_COMMUNITY);
  1609. X    cp = (u_char *)malloc((unsigned)session->community_len);
  1610. X    bcopy((char *)DEFAULT_COMMUNITY, (char *)cp, session->community_len);
  1611. X    }
  1612. X    session->community = cp;    /* replace pointer with pointer to new data */
  1613. X
  1614. X    if (session->retries == SNMP_DEFAULT_RETRIES)
  1615. X    session->retries = DEFAULT_RETRIES;
  1616. X    if (session->timeout == SNMP_DEFAULT_TIMEOUT)
  1617. X    session->timeout = DEFAULT_TIMEOUT;
  1618. X    isp->requests = NULL;
  1619. X
  1620. X    /* Set up connections */
  1621. X    sd = socket(AF_INET, SOCK_DGRAM, 0);
  1622. X    if (sd < 0){
  1623. X    perror("socket");
  1624. X    snmp_errno = SNMPERR_GENERR;
  1625. X    if (!snmp_close(session)){
  1626. X        fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  1627. X        exit(1);
  1628. X    }
  1629. X    return 0;
  1630. X    }
  1631. X    isp->sd = sd;
  1632. X    if (session->peername != SNMP_DEFAULT_PEERNAME){
  1633. X    if ((addr = inet_addr(session->peername)) != -1){
  1634. X        bcopy((char *)&addr, (char *)&isp->addr.sin_addr, sizeof(isp->addr.sin_addr));
  1635. X    } else {
  1636. X        hp = gethostbyname(session->peername);
  1637. X        if (hp == NULL){
  1638. X        fprintf(stderr, "unknown host: %s\n", session->peername);
  1639. X        snmp_errno = SNMPERR_BAD_ADDRESS;
  1640. X        if (!snmp_close(session)){
  1641. X            fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  1642. X            exit(2);
  1643. X        }
  1644. X        return 0;
  1645. X        } else {
  1646. X        bcopy((char *)hp->h_addr, (char *)&isp->addr.sin_addr, hp->h_length);
  1647. X        }
  1648. X    }
  1649. X    isp->addr.sin_family = AF_INET;
  1650. X    if (session->remote_port == SNMP_DEFAULT_REMPORT){
  1651. X        servp = getservbyname("snmp", "udp");
  1652. X        if (servp != NULL){
  1653. X        isp->addr.sin_port = servp->s_port;
  1654. X        } else {
  1655. X        isp->addr.sin_port = htons(SNMP_PORT);
  1656. X        }
  1657. X    } else {
  1658. X        isp->addr.sin_port = htons(session->remote_port);
  1659. X    }
  1660. X    } else {
  1661. X    isp->addr.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
  1662. X    }
  1663. X
  1664. X    me.sin_family = AF_INET;
  1665. X    me.sin_addr.s_addr = INADDR_ANY;
  1666. X    me.sin_port = htons(session->local_port);
  1667. X    if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
  1668. X    perror("bind");
  1669. X    snmp_errno = SNMPERR_BAD_LOCPORT;
  1670. X    if (!snmp_close(session)){
  1671. X        fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
  1672. X        exit(3);
  1673. X    }
  1674. X    return 0;
  1675. X    }
  1676. X    return session;
  1677. X}
  1678. X
  1679. X
  1680. X/*
  1681. X * Free each element in the input request list.
  1682. X */
  1683. Xstatic
  1684. Xfree_request_list(rp)
  1685. X    struct request_list *rp;
  1686. X{
  1687. X    struct request_list *orp;
  1688. X
  1689. X    while(rp){
  1690. X    orp = rp;
  1691. X    rp = rp->next_request;
  1692. X    if (orp->pdu != NULL)
  1693. X        snmp_free_pdu(orp->pdu);
  1694. X    free((char *)orp);
  1695. X    }
  1696. X}
  1697. X
  1698. X/*
  1699. X * Close the input session.  Frees all data allocated for the session,
  1700. X * dequeues any pending requests, and closes any sockets allocated for
  1701. X * the session.  Returns 0 on error, 1 otherwise.
  1702. X */
  1703. Xint 
  1704. Xsnmp_close(session)
  1705. X    struct snmp_session *session;
  1706. X{
  1707. X    struct session_list *slp = NULL, *oslp = NULL;
  1708. X
  1709. X    if (Sessions->session == session){    /* If first entry */
  1710. X    slp = Sessions;
  1711. X    Sessions = slp->next;
  1712. X    } else {
  1713. X    for(slp = Sessions; slp; slp = slp->next){
  1714. X        if (slp->session == session){
  1715. X        if (oslp)   /* if we found entry that points here */
  1716. X            oslp->next = slp->next;    /* link around this entry */
  1717. X        break;
  1718. X        }
  1719. X        oslp = slp;
  1720. X    }
  1721. X    }
  1722. X    /* If we found the session, free all data associated with it */
  1723. X    if (slp){
  1724. X    if (slp->session->community != NULL)
  1725. X        free((char *)slp->session->community);
  1726. X    if(slp->session->peername != NULL)
  1727. X        free((char *)slp->session->peername);
  1728. X    free((char *)slp->session);
  1729. X    if (slp->internal->sd != -1)
  1730. X        close(slp->internal->sd);
  1731. X    free_request_list(slp->internal->requests);
  1732. X    free((char *)slp->internal);
  1733. X    free((char *)slp);
  1734. X    } else {
  1735. X    snmp_errno = SNMPERR_BAD_SESSION;
  1736. X    return 0;
  1737. X    }
  1738. X    return 1;
  1739. X}
  1740. X
  1741. X/*
  1742. X * Takes a session and a pdu and serializes the ASN PDU into the area
  1743. X * pointed to by packet.  out_length is the size of the data area available.
  1744. X * Returns the length of the completed packet in out_length.  If any errors
  1745. X * occur, -1 is returned.  If all goes well, 0 is returned.
  1746. X */
  1747. Xstatic int
  1748. Xsnmp_build(session, pdu, packet, out_length)
  1749. X    struct snmp_session    *session;
  1750. X    struct snmp_pdu    *pdu;
  1751. X    register u_char    *packet;
  1752. X    int            *out_length;
  1753. X{
  1754. X    u_char  buf[PACKET_LENGTH];
  1755. X    register u_char  *cp;
  1756. X    struct variable_list *vp;
  1757. X    int        length;
  1758. X    long    zero = 0;
  1759. X    int        totallength;
  1760. X
  1761. X    length = *out_length;
  1762. X    cp = packet;
  1763. X    for(vp = pdu->variables; vp; vp = vp->next_variable){
  1764. X    cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type, vp->val_len, (u_char *)vp->val.string, &length);
  1765. X    if (cp == NULL)
  1766. X        return -1;
  1767. X    }
  1768. X    totallength = cp - packet;
  1769. X
  1770. X    length = PACKET_LENGTH;
  1771. X    cp = asn_build_header(buf, &length, (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), totallength);
  1772. X    if (cp == NULL)
  1773. X    return -1;
  1774. X    bcopy((char *)packet, (char *)cp, totallength);
  1775. X    totallength += cp - buf;
  1776. X
  1777. X    length = *out_length;
  1778. X    if (pdu->command != TRP_REQ_MSG){
  1779. X    /* request id */
  1780. X    cp = asn_build_int(packet, &length,
  1781. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1782. X        (long *)&pdu->reqid, sizeof(pdu->reqid));
  1783. X    if (cp == NULL)
  1784. X        return -1;
  1785. X    /* error status */
  1786. X    cp = asn_build_int(cp, &length,
  1787. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1788. X        (long *)&pdu->errstat, sizeof(pdu->errstat));
  1789. X    if (cp == NULL)
  1790. X        return -1;
  1791. X    /* error index */
  1792. X    cp = asn_build_int(cp, &length,
  1793. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1794. X        (long *)&pdu->errindex, sizeof(pdu->errindex));
  1795. X    if (cp == NULL)
  1796. X        return -1;
  1797. X    } else {    /* this is a trap message */
  1798. X    /* enterprise */
  1799. X    cp = asn_build_objid(packet, &length,
  1800. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  1801. X        (oid *)pdu->enterprise, pdu->enterprise_length);
  1802. X    if (cp == NULL)
  1803. X        return -1;
  1804. X    /* agent-addr */
  1805. X    cp = asn_build_string(cp, &length,
  1806. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  1807. X        (u_char *)&pdu->agent_addr.sin_addr.s_addr, sizeof(pdu->agent_addr.sin_addr.s_addr));
  1808. X    if (cp == NULL)
  1809. X        return -1;
  1810. X    /* generic trap */
  1811. X    cp = asn_build_int(cp, &length,
  1812. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1813. X        (long *)&pdu->trap_type, sizeof(pdu->trap_type));
  1814. X    if (cp == NULL)
  1815. X        return -1;
  1816. X    /* specific trap */
  1817. X    cp = asn_build_int(cp, &length,
  1818. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1819. X        (long *)&pdu->specific_type, sizeof(pdu->specific_type));
  1820. X    if (cp == NULL)
  1821. X        return -1;
  1822. X    /* timestamp  */
  1823. X    cp = asn_build_int(cp, &length,
  1824. X        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  1825. X        (long *)&pdu->time, sizeof(pdu->time));
  1826. X    if (cp == NULL)
  1827. X        return -1;
  1828. X    }
  1829. X    if (length < totallength)
  1830. X    return -1;
  1831. X    bcopy((char *)buf, (char *)cp, totallength);
  1832. X    totallength += cp - packet;
  1833. X
  1834. X    length = PACKET_LENGTH;
  1835. X    cp = asn_build_header(buf, &length, (u_char)pdu->command, totallength);
  1836. X    if (cp == NULL)
  1837. X    return -1;
  1838. X    if (length < totallength)
  1839. X    return -1;
  1840. X    bcopy((char *)packet, (char *)cp, totallength);
  1841. X    totallength += cp - buf;
  1842. X
  1843. X    length = *out_length;
  1844. X    cp = snmp_auth_build(packet, &length, session->community, &session->community_len, &zero, totallength);
  1845. X    if (cp == NULL)
  1846. X    return -1;
  1847. X    if ((*out_length - (cp - packet)) < totallength)
  1848. X    return -1;
  1849. X    bcopy((char *)buf, (char *)cp, totallength);
  1850. X    totallength += cp - packet;
  1851. X    *out_length = totallength;
  1852. X    return 0;
  1853. X}
  1854. X
  1855. X/*
  1856. X * Parses the packet recieved on the input session, and places the data into
  1857. X * the input pdu.  length is the length of the input packet.  If any errors
  1858. X * are encountered, -1 is returned.  Otherwise, a 0 is returned.
  1859. X */
  1860. Xstatic int
  1861. Xsnmp_parse(session, pdu, data, length)
  1862. X    struct snmp_session *session;
  1863. X    struct snmp_pdu *pdu;
  1864. X    u_char  *data;
  1865. X    int        length;
  1866. X{
  1867. X    u_char  msg_type;
  1868. X    u_char  type;
  1869. X    u_char  *var_val;
  1870. X    long    version;
  1871. X    int        len, four;
  1872. X    u_char community[128];
  1873. X    int community_length = 128;
  1874. X    struct variable_list *vp;
  1875. X    oid        objid[MAX_NAME_LEN], *op;
  1876. X
  1877. X    /* authenticates message and returns length if valid */
  1878. X    data = snmp_auth_parse(data, &length, community, &community_length, &version);
  1879. X    if (data == NULL)
  1880. X    return -1;
  1881. X    if (version != SNMP_VERSION_1){
  1882. X    fprintf(stderr, "Wrong version: %d\n", version);
  1883. X    fprintf(stderr, "Continuing anyway\n");
  1884. X    }
  1885. X    if (session->authenticator){
  1886. X    data = session->authenticator(data, &length, community, community_length);
  1887. X    if (data == NULL)
  1888. X        return 0;
  1889. X    }
  1890. X    data = asn_parse_header(data, &length, &msg_type);
  1891. X    if (data == NULL)
  1892. X    return -1;
  1893. X    pdu->command = msg_type;
  1894. X    if (pdu->command != TRP_REQ_MSG){
  1895. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->reqid, sizeof(pdu->reqid));
  1896. X    if (data == NULL)
  1897. X        return -1;
  1898. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->errstat, sizeof(pdu->errstat));
  1899. X    if (data == NULL)
  1900. X        return -1;
  1901. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->errindex, sizeof(pdu->errindex));
  1902. X    if (data == NULL)
  1903. X        return -1;
  1904. X    } else {
  1905. X    pdu->enterprise_length = MAX_NAME_LEN;
  1906. X    data = asn_parse_objid(data, &length, &type, objid, &pdu->enterprise_length);
  1907. X    if (data == NULL)
  1908. X        return -1;
  1909. X    pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
  1910. X    bcopy((char *)objid, (char *)pdu->enterprise, pdu->enterprise_length * sizeof(oid));
  1911. X
  1912. X    four = 4;
  1913. X    data = asn_parse_string(data, &length, &type, (u_char *)&pdu->agent_addr.sin_addr.s_addr, &four);
  1914. X    if (data == NULL)
  1915. X        return -1;
  1916. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->trap_type, sizeof(pdu->trap_type));
  1917. X    if (data == NULL)
  1918. X        return -1;
  1919. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->specific_type, sizeof(pdu->specific_type));
  1920. X    if (data == NULL)
  1921. X        return -1;
  1922. X    data = asn_parse_int(data, &length, &type, (long *)&pdu->time, sizeof(pdu->time));
  1923. X    if (data == NULL)
  1924. X        return -1;
  1925. X    }
  1926. X    data = asn_parse_header(data, &length, &type);
  1927. X    if (data == NULL)
  1928. X    return -1;
  1929. X    if (type != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR))
  1930. X    return -1;
  1931. X    while((int)length > 0){
  1932. X    if (pdu->variables == NULL){
  1933. X        pdu->variables = vp = (struct variable_list *)malloc(sizeof(struct variable_list));
  1934. X    } else {
  1935. X        vp->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
  1936. X        vp = vp->next_variable;
  1937. X    }
  1938. X    vp->next_variable = NULL;
  1939. X    vp->val.string = NULL;
  1940. X    vp->name = NULL;
  1941. X    vp->name_length = MAX_NAME_LEN;
  1942. X    data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type, &vp->val_len, &var_val, (int *)&length);
  1943. X    if (data == NULL)
  1944. X        return -1;
  1945. X    op = (oid *)malloc((unsigned)vp->name_length * sizeof(oid));
  1946. X    bcopy((char *)objid, (char *)op, vp->name_length * sizeof(oid));
  1947. X    vp->name = op;
  1948. X
  1949. X    len = PACKET_LENGTH;
  1950. X    switch((short)vp->type){
  1951. X        case ASN_INTEGER:
  1952. X        case COUNTER:
  1953. X        case GAUGE:
  1954. X        case TIMETICKS:
  1955. X        vp->val.integer = (long *)malloc(sizeof(long));
  1956. X        vp->val_len = sizeof(long);
  1957. X        asn_parse_int(var_val, &len, &vp->type, (long *)vp->val.integer, sizeof(vp->val.integer));
  1958. X        break;
  1959. X        case ASN_OCTET_STR:
  1960. X        case IPADDRESS:
  1961. X        case OPAQUE:
  1962. X        vp->val.string = (u_char *)malloc((unsigned)vp->val_len);
  1963. X        asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
  1964. X        break;
  1965. X        case ASN_OBJECT_ID:
  1966. X        vp->val_len = MAX_NAME_LEN;
  1967. X        asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
  1968. X        vp->val_len *= sizeof(oid);
  1969. X        vp->val.objid = (oid *)malloc((unsigned)vp->val_len);
  1970. X        bcopy((char *)objid, (char *)vp->val.objid, vp->val_len);
  1971. X        break;
  1972. X        case ASN_NULL:
  1973. X        break;
  1974. X        default:
  1975. X        fprintf(stderr, "bad type returned (%x)\n", vp->type);
  1976. X        break;
  1977. X    }
  1978. X    }
  1979. X    return 0;
  1980. X}
  1981. X
  1982. X/*
  1983. X * Sends the input pdu on the session after calling snmp_build to create
  1984. X * a serialized packet.  If necessary, set some of the pdu data from the
  1985. X * session defaults.  Add a request corresponding to this pdu to the list
  1986. X * of outstanding requests on this session, then send the pdu.
  1987. X * Returns the request id of the generated packet if applicable, otherwise 1.
  1988. X * On any error, 0 is returned.
  1989. X * The pdu is freed by snmp_send() unless a failure occured.
  1990. X */
  1991. Xint
  1992. Xsnmp_send(session, pdu)
  1993. X    struct snmp_session *session;
  1994. X    struct snmp_pdu    *pdu;
  1995. X{
  1996. X    struct session_list *slp;
  1997. X    struct snmp_internal_session *isp = NULL;
  1998. X    u_char  packet[PACKET_LENGTH];
  1999. X    int length = PACKET_LENGTH;
  2000. X    struct request_list *rp;
  2001. X    struct timeval tv;
  2002. X
  2003. X    for(slp = Sessions; slp; slp = slp->next){
  2004. X    if (slp->session == session){
  2005. X        isp = slp->internal;
  2006. X        break;
  2007. X    }
  2008. X    }
  2009. X    if (isp == NULL){
  2010. X    snmp_errno = SNMPERR_BAD_SESSION;
  2011. X    return 0;
  2012. X    }
  2013. X    if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
  2014. X    || pdu->command == GET_RSP_MSG || pdu->command == SET_REQ_MSG){
  2015. X    if (pdu->reqid == SNMP_DEFAULT_REQID)
  2016. X        pdu->reqid = ++Reqid;
  2017. X    if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
  2018. X        pdu->errstat = 0;
  2019. X    if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
  2020. X        pdu->errindex = 0;
  2021. X    } else {
  2022. X    /* fill in trap defaults */
  2023. X    pdu->reqid = 1;    /* give a bogus non-error reqid for traps */
  2024. X    if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH){
  2025. X        pdu->enterprise = (oid *)malloc(sizeof(DEFAULT_ENTERPRISE));
  2026. X        bcopy((char *)DEFAULT_ENTERPRISE, (char *)pdu->enterprise, sizeof(DEFAULT_ENTERPRISE));
  2027. X        pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
  2028. X    }
  2029. X    if (pdu->time == SNMP_DEFAULT_TIME)
  2030. X        pdu->time = DEFAULT_TIME;
  2031. X    }
  2032. X    if (pdu->address.sin_addr.s_addr == SNMP_DEFAULT_ADDRESS){
  2033. X    if (isp->addr.sin_addr.s_addr != SNMP_DEFAULT_ADDRESS){
  2034. X        bcopy((char *)&isp->addr, (char *)&pdu->address, sizeof(pdu->address));
  2035. X    } else {
  2036. X        fprintf(stderr, "No remote IP address specified\n");
  2037. X        snmp_errno = SNMPERR_BAD_ADDRESS;
  2038. X        return 0;
  2039. X    }
  2040. X    }
  2041. X    
  2042. X
  2043. X    if (snmp_build(session, pdu, packet, &length) < 0){
  2044. X    fprintf(stderr, "Error building packet\n");
  2045. X    snmp_errno = SNMPERR_GENERR;
  2046. X    return 0;
  2047. X    }
  2048. X    if (snmp_dump_packet){
  2049. X    int count;
  2050. X
  2051. X    for(count = 0; count < length; count++){
  2052. X        printf("%02X ", packet[count]);
  2053. X        if ((count % 16) == 15)
  2054. X        printf("\n");
  2055. X    }
  2056. X    printf("\n\n");
  2057. X    }
  2058. X
  2059. X    gettimeofday(&tv, (struct timezone *)0);
  2060. X    if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&pdu->address, sizeof(pdu->address)) < 0){
  2061. X    perror("sendto");
  2062. X    snmp_errno = SNMPERR_GENERR;
  2063. X    return 0;
  2064. X    }
  2065. X    if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG || pdu->command == SET_REQ_MSG){
  2066. X    /* set up to expect a response */
  2067. X    rp = (struct request_list *)malloc(sizeof(struct request_list));
  2068. X    rp->next_request = isp->requests;
  2069. X    isp->requests = rp;
  2070. X    rp->pdu = pdu;
  2071. X    rp->request_id = pdu->reqid;
  2072. X
  2073. X    rp->retries = 1;
  2074. X    rp->timeout = session->timeout;
  2075. X    rp->time = tv;
  2076. X    tv.tv_usec += rp->timeout;
  2077. X    tv.tv_sec += tv.tv_usec / 1000000L;
  2078. X    tv.tv_usec %= 1000000L;
  2079. X    rp->expire = tv;
  2080. X    }
  2081. X    return pdu->reqid;
  2082. X}
  2083. X
  2084. X/*
  2085. X * Frees the pdu and any malloc'd data associated with it.
  2086. X */
  2087. Xvoid
  2088. Xsnmp_free_pdu(pdu)
  2089. X    struct snmp_pdu *pdu;
  2090. X{
  2091. X    struct variable_list *vp, *ovp;
  2092. X
  2093. X    vp = pdu->variables;
  2094. X    while(vp){
  2095. X    if (vp->name)
  2096. X        free((char *)vp->name);
  2097. X    if (vp->val.string)
  2098. X        free((char *)vp->val.string);
  2099. X    ovp = vp;
  2100. X    vp = vp->next_variable;
  2101. X    free((char *)ovp);
  2102. X    }
  2103. X    if (pdu->enterprise)
  2104. X    free((char *)pdu->enterprise);
  2105. X    free((char *)pdu);
  2106. X}
  2107. X
  2108. X
  2109. X/*
  2110. X * Checks to see if any of the fd's set in the fdset belong to
  2111. X * snmp.  Each socket with it's fd set has a packet read from it
  2112. X * and snmp_parse is called on the packet received.  The resulting pdu
  2113. X * is passed to the callback routine for that session.  If the callback
  2114. X * routine returns successfully, the pdu and it's request are deleted.
  2115. X */
  2116. Xvoid
  2117. Xsnmp_read(fdset)
  2118. X    fd_set  *fdset;
  2119. X{
  2120. X    struct session_list *slp;
  2121. X    struct snmp_session *sp;
  2122. X    struct snmp_internal_session *isp;
  2123. X    u_char packet[PACKET_LENGTH];
  2124. X    struct sockaddr_in    from;
  2125. X    int length, fromlength;
  2126. X    struct snmp_pdu *pdu;
  2127. X    struct request_list *rp, *orp;
  2128. X
  2129. X    for(slp = Sessions; slp; slp = slp->next){
  2130. X    if (FD_ISSET(slp->internal->sd, fdset)){
  2131. X        sp = slp->session;
  2132. X        isp = slp->internal;
  2133. X        fromlength = sizeof from;
  2134. X        length = recvfrom(isp->sd, (char *)packet, PACKET_LENGTH, 0, (struct sockaddr *)&from, &fromlength);
  2135. X        if (length == -1)
  2136. X        perror("recvfrom");
  2137. X        if (snmp_dump_packet){
  2138. X        int count;
  2139. X
  2140. X        printf("recieved %d bytes from %s:\n", length, inet_ntoa(from.sin_addr));
  2141. X        for(count = 0; count < length; count++){
  2142. X            printf("%02X ", packet[count]);
  2143. X            if ((count % 16) == 15)
  2144. X            printf("\n");
  2145. X        }
  2146. X        printf("\n\n");
  2147. X        }
  2148. X
  2149. X        pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
  2150. X        pdu->address = from;
  2151. X        pdu->reqid = 0;
  2152. X        pdu->variables = NULL;
  2153. X        pdu->enterprise = NULL;
  2154. X        pdu->enterprise_length = 0;
  2155. X        if (snmp_parse(sp, pdu, packet, length) != SNMP_ERR_NOERROR){
  2156. X        fprintf(stderr, "Mangled packet\n");
  2157. X        snmp_free_pdu(pdu);
  2158. X        return;
  2159. X        }
  2160. X
  2161. X        if (pdu->command == GET_RSP_MSG){
  2162. X        for(rp = isp->requests; rp; rp = rp->next_request){
  2163. X            if (rp->request_id == pdu->reqid){
  2164. X            if (sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic) == 1){
  2165. X                /* successful, so delete request */
  2166. X                orp = rp;
  2167. X                if (isp->requests == orp){
  2168. X                /* first in list */
  2169. X                isp->requests = orp->next_request;
  2170. X                } else {
  2171. X                for(rp = isp->requests; rp; rp = rp->next_request){
  2172. X                    if (rp->next_request == orp){
  2173. X                    rp->next_request = orp->next_request;    /* link around it */
  2174. X                    break;
  2175. X                    }
  2176. X                }
  2177. X                }
  2178. X                snmp_free_pdu(orp->pdu);
  2179. X                free((char *)orp);
  2180. X                break;  /* there shouldn't be any more request with the same reqid */
  2181. X            }
  2182. X            }
  2183. X        }
  2184. X        } else if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
  2185. X            || pdu->command == TRP_REQ_MSG || pdu->command == SET_REQ_MSG){
  2186. X        sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic);
  2187. X        }
  2188. X        snmp_free_pdu(pdu);
  2189. X    }
  2190. X    }
  2191. X}
  2192. X
  2193. X/*
  2194. X * Returns info about what snmp requires from a select statement.
  2195. X * numfds is the number of fds in the list that are significant.
  2196. X * All file descriptors opened for SNMP are OR'd into the fdset.
  2197. X * If activity occurs on any of these file descriptors, snmp_read
  2198. X * should be called with that file descriptor set
  2199. X *
  2200. X * The timeout is the latest time that SNMP can wait for a timeout.  The
  2201. X * select should be done with the minimum time between timeout and any other
  2202. X * timeouts necessary.  This should be checked upon each invocation of select.
  2203. X * If a timeout is received, snmp_timeout should be called to check if the
  2204. X * timeout was for SNMP.  (snmp_timeout is idempotent)
  2205. X *
  2206. X * Block is 1 if the select is requested to block indefinitely, rather than time out.
  2207. X * If block is input as 1, the timeout value will be treated as undefined, but it must
  2208. X * be available for setting in snmp_select_info.  On return, if block is true, the value
  2209. X * of timeout will be undefined.
  2210. X *
  2211. X * snmp_select_info returns the number of open sockets.  (i.e. The number of sessions open)
  2212. X */
  2213. Xint
  2214. Xsnmp_select_info(numfds, fdset, timeout, block)
  2215. X    int        *numfds;
  2216. X    fd_set  *fdset;
  2217. X    struct timeval *timeout;
  2218. X    int        *block; /* should the select block until input arrives (i.e. no input) */
  2219. X{
  2220. X    struct session_list *slp;
  2221. X    struct snmp_internal_session *isp;
  2222. X    struct request_list *rp;
  2223. X    struct timeval now, earliest;
  2224. X    int active = 0, requests = 0;
  2225. X
  2226. X    timerclear(&earliest);
  2227. X    /*
  2228. X     * For each request outstanding, add it's socket to the fdset,
  2229. X     * and if it is the earliest timeout to expire, mark it as lowest.
  2230. X     */
  2231. X    for(slp = Sessions; slp; slp = slp->next){
  2232. X    active++;
  2233. X    isp = slp->internal;
  2234. X    if ((isp->sd + 1) > *numfds)
  2235. X        *numfds = (isp->sd + 1);
  2236. X    FD_SET(isp->sd, fdset);
  2237. X    if (isp->requests){
  2238. X        /* found another session with outstanding requests */
  2239. X        requests++;
  2240. X        for(rp = isp->requests; rp; rp = rp->next_request){
  2241. X        if (!timerisset(&earliest) || timercmp(&rp->expire, &earliest, <))
  2242. X            earliest = rp->expire;
  2243. X        }
  2244. X    }
  2245. X    }
  2246. X    if (requests == 0)    /* if none are active, skip arithmetic */
  2247. X    return active;
  2248. X
  2249. X    /*
  2250. X     * Now find out how much time until the earliest timeout.  This
  2251. X     * transforms earliest from an absolute time into a delta time, the
  2252. X     * time left until the select should timeout.
  2253. X     */
  2254. X    gettimeofday(&now, (struct timezone *)0);
  2255. X    earliest.tv_sec--;    /* adjust time to make arithmetic easier */
  2256. X    earliest.tv_usec += 1000000L;
  2257. X    earliest.tv_sec -= now.tv_sec;
  2258. X    earliest.tv_usec -= now.tv_usec;
  2259. X    while (earliest.tv_usec >= 1000000L){
  2260. X    earliest.tv_usec -= 1000000L;
  2261. X    earliest.tv_sec += 1;
  2262. X    }
  2263. X    if (earliest.tv_sec < 0){
  2264. X    earliest.tv_sec = 0;
  2265. X    earliest.tv_usec = 0;
  2266. X    }
  2267. X
  2268. X    /* if it was blocking before or our delta time is less, reset timeout */
  2269. X    if (*block == 1 || timercmp(&earliest, timeout, <)){
  2270. X    *timeout = earliest;
  2271. X    *block = 0;
  2272. X    }
  2273. X    return active;
  2274. X}
  2275. X
  2276. X/*
  2277. X * snmp_timeout should be called whenever the timeout from snmp_select_info expires,
  2278. X * but it is idempotent, so snmp_timeout can be polled (probably a cpu expensive
  2279. X * proposition).  snmp_timeout checks to see if any of the sessions have an
  2280. X * outstanding request that has timed out.  If it finds one (or more), and that
  2281. X * pdu has more retries available, a new packet is formed from the pdu and is
  2282. X * resent.  If there are no more retries available, the callback for the session
  2283. X * is used to alert the user of the timeout.
  2284. X */
  2285. Xvoid
  2286. Xsnmp_timeout(){
  2287. X    struct session_list *slp;
  2288. X    struct snmp_session *sp;
  2289. X    struct snmp_internal_session *isp;
  2290. X    struct request_list *rp, *orp, *freeme = NULL;
  2291. X    struct timeval now;
  2292. X
  2293. X    gettimeofday(&now, (struct timezone *)0);
  2294. X    /*
  2295. X     * For each request outstanding, check to see if it has expired.
  2296. X     */
  2297. X    for(slp = Sessions; slp; slp = slp->next){
  2298. X    sp = slp->session;
  2299. X    isp = slp->internal;
  2300. X    orp = NULL;
  2301. X    for(rp = isp->requests; rp; rp = rp->next_request){
  2302. X        if (freeme != NULL){    /* frees rp's after the for loop goes on to the next_request */
  2303. X        free((char *)freeme);
  2304. X        freeme = NULL;
  2305. X        }
  2306. X        if (timercmp(&rp->expire, &now, <)){
  2307. X        /* this timer has expired */
  2308. X        if (rp->retries >= sp->retries){
  2309. X            /* No more chances, delete this entry */
  2310. X            sp->callback(TIMED_OUT, sp, rp->pdu->reqid, rp->pdu, sp->callback_magic);
  2311. X            if (orp == NULL){
  2312. X            isp->requests = rp->next_request;
  2313. X            } else {
  2314. X            orp->next_request = rp->next_request;
  2315. X            }
  2316. X            snmp_free_pdu(rp->pdu);
  2317. X            freeme = rp;
  2318. X            continue;    /* don't update orp below */
  2319. X        } else {
  2320. X            u_char  packet[PACKET_LENGTH];
  2321. X            int length = PACKET_LENGTH;
  2322. X            struct timeval tv;
  2323. X
  2324. X            /* retransmit this pdu */
  2325. X            rp->retries++;
  2326. X            rp->timeout <<= 1;
  2327. X            if (snmp_build(sp, rp->pdu, packet, &length) < 0){
  2328. X            fprintf(stderr, "Error building packet\n");
  2329. X            }
  2330. X            if (snmp_dump_packet){
  2331. X            int count;
  2332. X
  2333. X            for(count = 0; count < length; count++){
  2334. X                printf("%02X ", packet[count]);
  2335. X                if ((count % 16) == 15)
  2336. X                printf("\n");
  2337. X            }
  2338. X            printf("\n\n");
  2339. X            }
  2340. X            gettimeofday(&tv, (struct timezone *)0);
  2341. X            if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&rp->pdu->address, sizeof(rp->pdu->address)) < 0){
  2342. X            perror("sendto");
  2343. X            }
  2344. X            rp->time = tv;
  2345. X            tv.tv_usec += rp->timeout;
  2346. X            tv.tv_sec += tv.tv_usec / 1000000L;
  2347. X            tv.tv_usec %= 1000000L;
  2348. X            rp->expire = tv;
  2349. X        }
  2350. X        }
  2351. X        orp = rp;
  2352. X    }
  2353. X    if (freeme != NULL){
  2354. X        free((char *)freeme);
  2355. X        freeme = NULL;
  2356. X    }
  2357. X    }
  2358. X}
  2359. END_OF_FILE
  2360.   if test 28907 -ne `wc -c <'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c'`; then
  2361.     echo shar: \"'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c'\" unpacked with wrong size!
  2362.   fi
  2363.   # end of 'nocol-3.0/src/cmu-snmp/snmplib/snmp_api.c'
  2364. fi
  2365. if test -f 'nocol-3.0/src/perlnocol/idlemodemmon-confg' -a "${1}" != "-c" ; then 
  2366.   echo shar: Will not clobber existing file \"'nocol-3.0/src/perlnocol/idlemodemmon-confg'\"
  2367. else
  2368.   echo shar: Extracting \"'nocol-3.0/src/perlnocol/idlemodemmon-confg'\" \(750 characters\)
  2369.   sed "s/^X//" >'nocol-3.0/src/perlnocol/idlemodemmon-confg' <<'END_OF_FILE'
  2370. X## Config for modemmon-idle-monitor
  2371. X#
  2372. X# If the idle time of lines in use equal or exceed the values here, the
  2373. X# severity will be escalated to the level the value indicates.
  2374. X#
  2375. X#    15m = 900s     25m = 1500s     40m = 2400s
  2376. X## Name Address  Warning-#lines   Error-#lines   Critical-#lines
  2377. X##
  2378. Xalcatraz 192.67.247.1    900    1500    2400
  2379. Xexit14 192.67.238.1    900     1500    2400
  2380. Xfranklin 192.67.239.2    900     1500    2400
  2381. Xhancock 192.67.242.1    900     1500    2400
  2382. Xjpmorgan 192.67.241.1    900     1500    2400
  2383. Xmonument 192.67.246.1    900     1500    2400
  2384. Xmozart 161.58.1.5    900     1500    2400
  2385. Xptbarnum 192.67.243.1    900     1500    2400
  2386. Xringo  192.67.236.1    900     1500    2400
  2387. Xrocky  192.67.245.1    900     1500    2400
  2388. Xvanderbilt 192.67.240.1 900     1500    2400
  2389. X
  2390. X        
  2391. X
  2392. END_OF_FILE
  2393.   if test 750 -ne `wc -c <'nocol-3.0/src/perlnocol/idlemodemmon-confg'`; then
  2394.     echo shar: \"'nocol-3.0/src/perlnocol/idlemodemmon-confg'\" unpacked with wrong size!
  2395.   fi
  2396.   # end of 'nocol-3.0/src/perlnocol/idlemodemmon-confg'
  2397. fi
  2398. echo shar: End of archive 13 \(of 26\).
  2399. cp /dev/null ark13isdone
  2400. MISSING=""
  2401. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ; do
  2402.     if test ! -f ark${I}isdone ; then
  2403.     MISSING="${MISSING} ${I}"
  2404.     fi
  2405. done
  2406. if test "${MISSING}" = "" ; then
  2407.     echo You have unpacked all 26 archives.
  2408.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2409. else
  2410.     echo You still must unpack the following archives:
  2411.     echo "        " ${MISSING}
  2412. fi
  2413. exit 0
  2414. exit 0 # Just in case...
  2415.