+++ /dev/null
-/* -*- C -*-
- SNMP.xs -- Perl 5 interface to the UCD SNMP toolkit
-
- written by G. S. Marzot (gmarzot@nortelnetworks.com)
-
- Copyright (c) 1995-1999 G. S. Marzot. All rights reserved.
- This program is free software; you can redistribute it and/or
- modify it under the same terms as Perl itself.
-*/
-#define WIN32SCK_IS_STDSCK
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <ctype.h>
-#ifdef I_SYS_TIME
-#include <sys/time.h>
-#endif
-#include <netdb.h>
-#include <stdlib.h>
-#include <unistd.h>
-/* XXX This is a problem if regex.h is not on the system. */
-#include <regex.h>
-
-#ifndef __P
-#define __P(x) x
-#endif
-
-#ifndef na
-#define na PL_na
-#endif
-
-#ifndef sv_undef
-#define sv_undef PL_sv_undef
-#endif
-
-#ifndef stack_base
-#define stack_base PL_stack_base
-#endif
-
-#ifndef G_VOID
-#define G_VOID G_DISCARD
-#endif
-
-#ifdef WIN32
-#define SOCK_STARTUP winsock_startup()
-#define SOCK_CLEANUP winsock_cleanup()
-#define DLL_IMPORT __declspec( dllimport )
-#define strcasecmp _stricmp
-#define strncasecmp _strnicmp
-#else
-#define SOCK_STARTUP
-#define SOCK_CLEANUP
-#define DLL_IMPORT
-#endif
-
-DLL_IMPORT extern struct tree *Mib;
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-
-#include "perlsnmp.h"
-
-#define SUCCESS 1
-#define FAILURE 0
-
-#define ZERO_BUT_TRUE "0 but true"
-
-#define VARBIND_TAG_F 0
-#define VARBIND_IID_F 1
-#define VARBIND_VAL_F 2
-#define VARBIND_TYPE_F 3
-
-#define TYPE_UNKNOWN 0
-#define MAX_TYPE_NAME_LEN 16
-#define STR_BUF_SIZE 1024
-#define ENG_ID_BUF_SIZE 32
-
-#define SYS_UPTIME_OID_LEN 9
-#define SNMP_TRAP_OID_LEN 11
-#define NO_RETRY_NOSUCH 0
-static oid sysUpTime[SYS_UPTIME_OID_LEN] = {1, 3, 6, 1, 2, 1, 1, 3, 0};
-static oid snmpTrapOID[SNMP_TRAP_OID_LEN] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
-
-/* Internal flag to determine snmp_main_loop() should return after callback */
-static int mainloop_finish = 0;
-
-/* these should be part of transform_oids.h ? */
-#define USM_AUTH_PROTO_MD5_LEN 10
-#define USM_AUTH_PROTO_SHA_LEN 10
-#define USM_PRIV_PROTO_DES_LEN 10
-
-/* why does ucd-snmp redefine sockaddr_in ??? */
-#define SIN_ADDR(snmp_addr) (((struct sockaddr_in *) &(snmp_addr))->sin_addr)
-
-typedef netsnmp_session SnmpSession;
-typedef struct tree SnmpMibNode;
-typedef struct snmp_xs_cb_data {
- SV* perl_cb;
- SV* sess_ref;
-} snmp_xs_cb_data;
-
-static void __recalc_timeout _((struct timeval*,struct timeval*,
- struct timeval*,struct timeval*, int* ));
-static in_addr_t __parse_address _((char*));
-static int __is_numeric_oid _((char*));
-static int __is_leaf _((struct tree*));
-static int __translate_appl_type _((char*));
-static int __translate_asn_type _((int));
-static int __snprint_value _((char *, size_t,
- netsnmp_variable_list*, struct tree *,
- int, int));
-static int __sprint_num_objid _((char *, oid *, int));
-static int __scan_num_objid _((char *, oid *, int *));
-static int __get_type_str _((int, char *));
-static int __get_label_iid _((char *, char **, char **, int));
-static int __oid_cmp _((oid *, int, oid *, int));
-static int __tp_sprint_num_objid _((char*,SnmpMibNode *));
-static SnmpMibNode * __get_next_mib_node _((SnmpMibNode *));
-static struct tree * __oid2tp _((oid*, int, struct tree *, int*));
-static struct tree * __tag2oid _((char *, char *, oid *, int *, int *, int));
-static int __concat_oid_str _((oid *, int *, char *));
-static int __add_var_val_str _((netsnmp_pdu *, oid *, int, char *,
- int, int));
-static int __send_sync_pdu _((netsnmp_session *, netsnmp_pdu *,
- netsnmp_pdu **, int , SV *, SV *, SV *));
-static int __snmp_xs_cb __P((int, netsnmp_session *, int,
- netsnmp_pdu *, void *));
-static int __callback_wrapper __P((int, netsnmp_session *, int,
- netsnmp_pdu *, void *));
-static SV* __push_cb_args2 _((SV * sv, SV * esv, SV * tsv));
-#define __push_cb_args(a,b) __push_cb_args2(a,b,NULL)
-static int __call_callback _((SV * sv, int flags));
-static char* __av_elem_pv _((AV * av, I32 key, char *dflt));
-static u_int compute_match _((const char *, const char *));
-
-#define USE_NUMERIC_OIDS 0x08
-#define NON_LEAF_NAME 0x04
-#define USE_LONG_NAMES 0x02
-#define FAIL_ON_NULL_IID 0x01
-#define NO_FLAGS 0x00
-
-/* Structures used by snmp_bulkwalk method to track requested OID's/subtrees. */
-typedef struct bulktbl {
- oid req_oid[MAX_OID_LEN]; /* The OID originally requested. */
- oid last_oid[MAX_OID_LEN]; /* Last-seen OID under this branch. */
- AV *vars; /* Array of Varbinds for this OID. */
- char req_len; /* Length of requested OID. */
- char last_len; /* Length of last-seen OID. */
- char norepeat; /* Is this a non-repeater OID? */
- char complete; /* Non-zero if this tree complete. */
- char ignore; /* Ignore this OID, not requested. */
-} bulktbl;
-
-/* Context for bulkwalk() sessions. Used to store state across callbacks. */
-typedef struct walk_context {
- SV *sess_ref; /* Reference to Perl SNMP session object. */
- SV *perl_cb; /* Pointer to Perl callback func or array. */
- bulktbl *req_oids; /* Pointer to bulktbl[] for requested OIDs. */
- bulktbl *repbase; /* Pointer to first repeater in req_oids[]. */
- bulktbl *reqbase; /* Pointer to start of requests req_oids[]. */
- int nreq_oids; /* Number of valid bulktbls in req_oids[]. */
- int req_remain; /* Number of outstanding requests remaining */
- int non_reps; /* Number of nonrepeater vars in req_oids[] */
- int repeaters; /* Number of repeater vars in req_oids[]. */
- int max_reps; /* Maximum repetitions of variable per PDU. */
- int exp_reqid; /* Expect a response to this request only. */
- int getlabel_f; /* Flag long/numeric names for get_label(). */
- int sprintval_f; /* Flag enum/sprint values for sprintval(). */
- int pkts_exch; /* Number of packet exchanges with agent. */
- int oid_total; /* Total number of OIDs received this walk. */
- int oid_saved; /* Total number of OIDs saved as results. */
-} walk_context;
-
-/* Prototypes for bulkwalk support functions. */
-static netsnmp_pdu *_bulkwalk_send_pdu _((walk_context *context));
-static int _bulkwalk_done _((walk_context *context));
-static int _bulkwalk_recv_pdu _((walk_context *context, netsnmp_pdu *pdu));
-static int _bulkwalk_finish _((walk_context *context, int okay));
-static int _bulkwalk_async_cb _((int op, SnmpSession *ss, int reqid,
- netsnmp_pdu *pdu, void *context_ptr));
-
-/* Structure to hold valid context sessions. */
-struct valid_contexts {
- walk_context **valid; /* Array of valid walk_context pointers. */
- int sz_valid; /* Maximum size of valid contexts array. */
- int num_valid; /* Count of valid contexts in the array. */
-};
-static struct valid_contexts *_valid_contexts = NULL;
-static int _context_add _((walk_context *context));
-static int _context_del _((walk_context *context));
-static int _context_okay _((walk_context *context));
-
-/* Wrapper around fprintf(stderr, ...) for clean and easy debug output. */
-#ifdef DEBUGGING
-static int _debug_level = 0;
-#define DBOUT PerlIO_stderr(),
-#define DBPRT(severity, otherargs) \
- do { \
- if (_debug_level && severity <= _debug_level) { \
- (void)PerlIO_fprintf(PerlIO_stderr(), otherargs); \
- } \
- } while (/*CONSTCOND*/0)
-
-char _debugx[1024]; /* Space to sprintf() into - used by sprint_objid(). */
-
-#else /* DEBUGGING */
-#define DBOUT
-#define DBPRT(severity, otherargs) /* Ignore */
-
-#endif /* DEBUGGING */
-
-void
-__libraries_init(char *appname)
- {
- static int have_inited = 0;
-
- if (have_inited)
- return;
- have_inited = 1;
-
- snmp_set_quick_print(1);
- init_snmp(appname);
-
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS, 1);
- netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 1);
-
- SOCK_STARTUP;
-
- }
-
-static void
-__recalc_timeout (tvp, ctvp, ltvp, itvp, block)
-struct timeval* tvp;
-struct timeval* ctvp;
-struct timeval* ltvp;
-struct timeval* itvp;
-int *block;
-{
- struct timeval now;
-
- if (!timerisset(itvp)) return; /* interval zero means loop forever */
- *block = 0;
- gettimeofday(&now,(struct timezone *)0);
-
- if (ctvp->tv_sec < 0) { /* first time or callback just fired */
- timersub(&now,ltvp,ctvp);
- timersub(ctvp,itvp,ctvp);
- timersub(itvp,ctvp,ctvp);
- timeradd(ltvp,itvp,ltvp);
- } else {
- timersub(&now,ltvp,ctvp);
- timersub(itvp,ctvp,ctvp);
- }
-
- /* flag is set for callback but still hasnt fired so set to something
- * small and we will service packets first if there are any ready
- * (also guard against negative timeout - should never happen?)
- */
- if (!timerisset(ctvp) || ctvp->tv_sec < 0 || ctvp->tv_usec < 0) {
- ctvp->tv_sec = 0;
- ctvp->tv_usec = 10;
- }
-
- /* if snmp timeout > callback timeout or no more requests to process */
- if (timercmp(tvp, ctvp, >) || !timerisset(tvp)) {
- *tvp = *ctvp; /* use the smaller non-zero timeout */
- timerclear(ctvp); /* used as a flag to let callback fire on timeout */
- }
-}
-
-static in_addr_t
-__parse_address(address)
-char *address;
-{
- in_addr_t addr;
- struct sockaddr_in saddr;
- struct hostent *hp;
-
- if ((addr = inet_addr(address)) != -1)
- return addr;
- hp = gethostbyname(address);
- if (hp == NULL){
- return (-1); /* error value */
- } else {
- memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
- return saddr.sin_addr.s_addr;
- }
-
-}
-
-static int
-__is_numeric_oid (oidstr)
-char* oidstr;
-{
- if (!oidstr) return 0;
- for (; *oidstr; oidstr++) {
- if (isalpha((int)*oidstr)) return 0;
- }
- return(1);
-}
-
-static int
-__is_leaf (tp)
-struct tree* tp;
-{
- char buf[MAX_TYPE_NAME_LEN];
- return (tp && __get_type_str(tp->type,buf));
-}
-
-static SnmpMibNode*
-__get_next_mib_node (tp)
-SnmpMibNode* tp;
-{
- /* printf("tp = %lX, parent = %lX, peer = %lX, child = %lX\n",
- tp, tp->parent, tp->next_peer, tp->child_list); */
- if (tp->child_list) return(tp->child_list);
- if (tp->next_peer) return(tp->next_peer);
- if (!tp->parent) return(NULL);
- for (tp = tp->parent; !tp->next_peer; tp = tp->parent) {
- if (!tp->parent) return(NULL);
- }
- return(tp->next_peer);
-}
-
-static int
-__translate_appl_type(typestr)
-char* typestr;
-{
- if (typestr == NULL || *typestr == '\0') return TYPE_UNKNOWN;
-
- if (!strncasecmp(typestr,"INTEGER32",8))
- return(TYPE_INTEGER32);
- if (!strncasecmp(typestr,"INTEGER",3))
- return(TYPE_INTEGER);
- if (!strncasecmp(typestr,"UNSIGNED32",3))
- return(TYPE_UNSIGNED32);
- if (!strcasecmp(typestr,"COUNTER")) /* check all in case counter64 */
- return(TYPE_COUNTER);
- if (!strncasecmp(typestr,"GAUGE",3))
- return(TYPE_GAUGE);
- if (!strncasecmp(typestr,"IPADDR",3))
- return(TYPE_IPADDR);
- if (!strncasecmp(typestr,"OCTETSTR",3))
- return(TYPE_OCTETSTR);
- if (!strncasecmp(typestr,"TICKS",3))
- return(TYPE_TIMETICKS);
- if (!strncasecmp(typestr,"OPAQUE",3))
- return(TYPE_OPAQUE);
- if (!strncasecmp(typestr,"OBJECTID",3))
- return(TYPE_OBJID);
- if (!strncasecmp(typestr,"NETADDR",3))
- return(TYPE_NETADDR);
- if (!strncasecmp(typestr,"COUNTER64",3))
- return(TYPE_COUNTER64);
- if (!strncasecmp(typestr,"NULL",3))
- return(TYPE_NULL);
- if (!strncasecmp(typestr,"BITS",3))
- return(TYPE_BITSTRING);
- if (!strncasecmp(typestr,"ENDOFMIBVIEW",3))
- return(SNMP_ENDOFMIBVIEW);
- if (!strncasecmp(typestr,"NOSUCHOBJECT",7))
- return(SNMP_NOSUCHOBJECT);
- if (!strncasecmp(typestr,"NOSUCHINSTANCE",7))
- return(SNMP_NOSUCHINSTANCE);
- if (!strncasecmp(typestr,"UINTEGER",3))
- return(TYPE_UINTEGER); /* historic - should not show up */
- /* but it does? */
- if (!strncasecmp(typestr, "NOTIF", 3))
- return(TYPE_NOTIFTYPE);
- if (!strncasecmp(typestr, "TRAP", 4))
- return(TYPE_TRAPTYPE);
- return(TYPE_UNKNOWN);
-}
-
-static int
-__translate_asn_type(type)
-int type;
-{
- switch (type) {
- case ASN_INTEGER:
- return(TYPE_INTEGER);
- break;
- case ASN_OCTET_STR:
- return(TYPE_OCTETSTR);
- break;
- case ASN_OPAQUE:
- return(TYPE_OPAQUE);
- break;
- case ASN_OBJECT_ID:
- return(TYPE_OBJID);
- break;
- case ASN_TIMETICKS:
- return(TYPE_TIMETICKS);
- break;
- case ASN_GAUGE:
- return(TYPE_GAUGE);
- break;
- case ASN_COUNTER:
- return(TYPE_COUNTER);
- break;
- case ASN_IPADDRESS:
- return(TYPE_IPADDR);
- break;
- case ASN_BIT_STR:
- return(TYPE_BITSTRING);
- break;
- case ASN_NULL:
- return(TYPE_NULL);
- break;
- /* no translation for these exception type values */
- case SNMP_ENDOFMIBVIEW:
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- return(type);
- break;
- case ASN_UINTEGER:
- return(TYPE_UINTEGER);
- break;
- case ASN_COUNTER64:
- return(TYPE_COUNTER64);
- break;
- default:
- warn("translate_asn_type: unhandled asn type (%d)\n",type);
- return(TYPE_OTHER);
- break;
- }
-}
-
-#define USE_BASIC 0
-#define USE_ENUMS 1
-#define USE_SPRINT_VALUE 2
-static int
-__snprint_value (buf, buf_len, var, tp, type, flag)
-char * buf;
-size_t buf_len;
-netsnmp_variable_list * var;
-struct tree * tp;
-int type;
-int flag;
-{
- int len = 0;
- u_char* ip;
- struct enum_list *ep;
-
-
- buf[0] = '\0';
- if (flag == USE_SPRINT_VALUE) {
- snprint_value(buf, buf_len, var->name, var->name_length, var);
- len = strlen(buf);
- } else {
- switch (var->type) {
- case ASN_INTEGER:
- if (flag == USE_ENUMS) {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (ep->value == *var->val.integer) {
- strcpy(buf, ep->label);
- len = strlen(buf);
- break;
- }
- }
- }
- if (!len) {
- sprintf(buf,"%ld", *var->val.integer);
- len = strlen(buf);
- }
- break;
-
- case ASN_GAUGE:
- case ASN_COUNTER:
- case ASN_TIMETICKS:
- case ASN_UINTEGER:
- sprintf(buf,"%lu", (unsigned long) *var->val.integer);
- len = strlen(buf);
- break;
-
- case ASN_OCTET_STR:
- case ASN_OPAQUE:
- memcpy(buf, (char*)var->val.string, var->val_len);
- len = var->val_len;
- break;
-
- case ASN_IPADDRESS:
- ip = (u_char*)var->val.string;
- sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
- len = strlen(buf);
- break;
-
- case ASN_NULL:
- break;
-
- case ASN_OBJECT_ID:
- __sprint_num_objid(buf, (oid *)(var->val.objid),
- var->val_len/sizeof(oid));
- len = strlen(buf);
- break;
-
- case SNMP_ENDOFMIBVIEW:
- sprintf(buf,"%s", "ENDOFMIBVIEW");
- break;
- case SNMP_NOSUCHOBJECT:
- sprintf(buf,"%s", "NOSUCHOBJECT");
- break;
- case SNMP_NOSUCHINSTANCE:
- sprintf(buf,"%s", "NOSUCHINSTANCE");
- break;
-
- case ASN_COUNTER64:
- printU64(buf,(struct counter64 *)var->val.counter64);
- len = strlen(buf);
- break;
-
- case ASN_BIT_STR:
- snprint_bitstring(buf, sizeof(buf), var, NULL, NULL, NULL);
- len = strlen(buf);
- break;
-
- case ASN_NSAP:
- default:
- warn("snprint_value: asn type not handled %d\n",var->type);
- }
- }
- return(len);
-}
-
-static int
-__sprint_num_objid (buf, objid, len)
-char *buf;
-oid *objid;
-int len;
-{
- int i;
- buf[0] = '\0';
- for (i=0; i < len; i++) {
- sprintf(buf,".%lu",*objid++);
- buf += strlen(buf);
- }
- return SUCCESS;
-}
-
-static int
-__tp_sprint_num_objid (buf, tp)
-char *buf;
-SnmpMibNode *tp;
-{
- oid newname[MAX_OID_LEN], *op;
- /* code taken from get_node in snmp_client.c */
- for (op = newname + MAX_OID_LEN - 1; op >= newname; op--) {
- *op = tp->subid;
- tp = tp->parent;
- if (tp == NULL) break;
- }
- return __sprint_num_objid(buf, op, newname + MAX_OID_LEN - op);
-}
-
-static int
-__scan_num_objid (buf, objid, len)
-char *buf;
-oid *objid;
-int *len;
-{
- char *cp;
- *len = 0;
- if (*buf == '.') buf++;
- cp = buf;
- while (*buf) {
- if (*buf++ == '.') {
- sscanf(cp, "%lu", objid++);
- /* *objid++ = atoi(cp); */
- (*len)++;
- cp = buf;
- } else {
- if (isalpha((int)*buf)) {
- return FAILURE;
- }
- }
- }
- sscanf(cp, "%lu", objid++);
- /* *objid++ = atoi(cp); */
- (*len)++;
- return SUCCESS;
-}
-
-static int
-__get_type_str (type, str)
-int type;
-char * str;
-{
- switch (type) {
- case TYPE_OBJID:
- strcpy(str, "OBJECTID");
- break;
- case TYPE_OCTETSTR:
- strcpy(str, "OCTETSTR");
- break;
- case TYPE_INTEGER:
- strcpy(str, "INTEGER");
- break;
- case TYPE_INTEGER32:
- strcpy(str, "INTEGER32");
- break;
- case TYPE_UNSIGNED32:
- strcpy(str, "UNSIGNED32");
- break;
- case TYPE_NETADDR:
- strcpy(str, "NETADDR");
- break;
- case TYPE_IPADDR:
- strcpy(str, "IPADDR");
- break;
- case TYPE_COUNTER:
- strcpy(str, "COUNTER");
- break;
- case TYPE_GAUGE:
- strcpy(str, "GAUGE");
- break;
- case TYPE_TIMETICKS:
- strcpy(str, "TICKS");
- break;
- case TYPE_OPAQUE:
- strcpy(str, "OPAQUE");
- break;
- case TYPE_COUNTER64:
- strcpy(str, "COUNTER64");
- break;
- case TYPE_NULL:
- strcpy(str, "NULL");
- break;
- case SNMP_ENDOFMIBVIEW:
- strcpy(str, "ENDOFMIBVIEW");
- break;
- case SNMP_NOSUCHOBJECT:
- strcpy(str, "NOSUCHOBJECT");
- break;
- case SNMP_NOSUCHINSTANCE:
- strcpy(str, "NOSUCHINSTANCE");
- break;
- case TYPE_UINTEGER:
- strcpy(str, "UINTEGER"); /* historic - should not show up */
- /* but it does? */
- break;
- case TYPE_NOTIFTYPE:
- strcpy(str, "NOTIF");
- break;
- case TYPE_BITSTRING:
- strcpy(str, "BITS");
- break;
- case TYPE_TRAPTYPE:
- strcpy(str, "TRAP");
- break;
- case TYPE_OTHER: /* not sure if this is a valid leaf type?? */
- case TYPE_NSAPADDRESS:
- default: /* unsupported types for now */
- strcpy(str, "");
- return(FAILURE);
- }
- return SUCCESS;
-}
-
-/* does a destructive disection of <label1>...<labeln>.<iid> returning
- <labeln> and <iid> in seperate strings (note: will destructively
- alter input string, 'name') */
-static int
-__get_label_iid (name, last_label, iid, flag)
-char * name;
-char ** last_label;
-char ** iid;
-int flag;
-{
- char *lcp;
- char *icp;
- int len = strlen(name);
- int found_label = 0;
-
- *last_label = *iid = NULL;
-
- if (len == 0) return(FAILURE);
-
- /* Handle case where numeric oid's have been requested. The input 'name'
- ** in this case should be a numeric OID -- return failure if not.
- */
- if ((flag & USE_NUMERIC_OIDS)) {
- if (!__is_numeric_oid(name))
- return(FAILURE);
-
- /* Walk backward through the string, looking for first two '.' chars */
- lcp = &(name[len]);
- icp = NULL;
- while (lcp > name) {
- if (*lcp == '.') {
-
- /* If this is the first occurence of '.', note it in icp.
- ** Otherwise, this must be the second occurrence, so break
- ** out of the loop.
- */
- if (icp == NULL)
- icp = lcp;
- else
- break;
- }
- lcp --;
- }
-
- /* Make sure we found at least a label and index. */
- if (!icp)
- return(FAILURE);
-
- /* Push forward past leading '.' chars and separate the strings. */
- lcp ++;
- *icp ++ = '\0';
-
- *last_label = (flag & USE_LONG_NAMES) ? name : lcp;
- *iid = icp;
-
- return(SUCCESS);
- }
-
- lcp = icp = &(name[len]);
-
- while (lcp > name) {
- if (*lcp == '.') {
- if (found_label) {
- lcp++;
- break;
- } else {
- icp = lcp;
- }
- }
- if (!found_label && isalpha((int)*lcp)) found_label = 1;
- lcp--;
- }
-
- if (!found_label || (!isdigit((int)*(icp+1)) && (flag & FAIL_ON_NULL_IID)))
- return(FAILURE);
-
- if (flag & NON_LEAF_NAME) { /* dont know where to start instance id */
- /* put the whole thing in label */
- icp = &(name[len]);
- flag |= USE_LONG_NAMES;
- /* special hack in case no mib loaded - object identifiers will
- * start with .iso.<num>.<num>...., in which case it is preferable
- * to make the label entirely numeric (i.e., convert "iso" => "1")
- */
- if (*lcp == '.' && lcp == name) {
- if (!strncmp(".ccitt.",lcp,7)) {
- name += 2;
- *name = '.';
- *(name+1) = '0';
- } else if (!strncmp(".iso.",lcp,5)) {
- name += 2;
- *name = '.';
- *(name+1) = '1';
- } else if (!strncmp(".joint-iso-ccitt.",lcp,17)) {
- name += 2;
- *name = '.';
- *(name+1) = '2';
- }
- }
- } else if (*icp) {
- *(icp++) = '\0';
- }
- *last_label = (flag & USE_LONG_NAMES ? name : lcp);
-
- *iid = icp;
-
- return(SUCCESS);
-}
-
-
-static int
-__oid_cmp(oida_arr, oida_arr_len, oidb_arr, oidb_arr_len)
-oid *oida_arr;
-int oida_arr_len;
-oid *oidb_arr;
-int oidb_arr_len;
-{
- for (;oida_arr_len && oidb_arr_len;
- oida_arr++, oida_arr_len--, oidb_arr++, oidb_arr_len--) {
- if (*oida_arr == *oidb_arr) continue;
- return(*oida_arr > *oidb_arr ? 1 : -1);
- }
- if (oida_arr_len == oidb_arr_len) return(0);
- return(oida_arr_len > oidb_arr_len ? 1 : -1);
-}
-
-#define MAX_BAD 0xffffff
-
-static u_int
-compute_match(search_base, key)
-const char *search_base;
-const char *key;
-{
- int rc;
- regex_t parsetree;
- regmatch_t pmatch;
-
- rc = regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED);
- if (rc == 0)
- rc = regexec(&parsetree, search_base, 1, &pmatch, 0);
- regfree(&parsetree);
- if (rc == 0) {
- return pmatch.rm_so;
- }
-
- return MAX_BAD;
-}
-
-static struct tree *
-__tag2oid(tag, iid, oid_arr, oid_arr_len, type, best_guess)
-char * tag;
-char * iid;
-oid * oid_arr;
-int * oid_arr_len;
-int * type;
-int best_guess;
-{
- struct tree *tp = NULL;
- struct tree *rtp = NULL;
- DLL_IMPORT extern struct tree *tree_head;
- oid newname[MAX_OID_LEN], *op;
- int newname_len = 0;
-
- if (type) *type = TYPE_UNKNOWN;
- if (oid_arr_len) *oid_arr_len = 0;
- if (!tag) goto done;
-
- if (best_guess) {
- tp = rtp = find_best_tree_node(tag, tree_head, NULL);
- if (tp) {
- if (type) *type = tp->type;
- if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp;
- for (op = newname + MAX_OID_LEN - 1; op >= newname; op--) {
- *op = tp->subid;
- tp = tp->parent;
- if (tp == NULL)
- break;
- }
- *oid_arr_len = newname + MAX_OID_LEN - op;
- memcpy(oid_arr, op, *oid_arr_len * sizeof(oid));
- }
- return(rtp);
- }
-
- if (strchr(tag,'.')) { /* if multi part tag */
- if (!__scan_num_objid(tag, newname, &newname_len)) { /* numeric tag */
- newname_len = MAX_OID_LEN;
- read_objid(tag, newname, &newname_len); /* long name */
- }
- if (type) *type = (tp ? tp->type : TYPE_UNKNOWN);
- if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp;
- memcpy(oid_arr,(char*)newname,newname_len*sizeof(oid));
- *oid_arr_len = newname_len;
- } else { /* else it is a leaf */
- rtp = tp = find_node(tag, Mib);
- if (tp) {
- if (type) *type = tp->type;
- if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp;
- /* code taken from get_node in snmp_client.c */
- for(op = newname + MAX_OID_LEN - 1; op >= newname; op--){
- *op = tp->subid;
- tp = tp->parent;
- if (tp == NULL)
- break;
- }
- *oid_arr_len = newname + MAX_OID_LEN - op;
- memcpy(oid_arr, op, *oid_arr_len * sizeof(oid));
- } else {
- return(rtp); /* HACK: otherwise, concat_oid_str confuses things */
- }
- }
- done:
- if (iid && *iid) __concat_oid_str(oid_arr, oid_arr_len, iid);
- return(rtp);
-}
-/* searches down the mib tree for the given oid
- returns the last found tp and its index in lastind
- */
-static struct tree *
-__oid2tp (oidp, len, subtree, lastind)
-oid* oidp;
-int len;
-struct tree * subtree;
-int* lastind;
-{
- struct tree *return_tree = NULL;
-
-
- for (; subtree; subtree = subtree->next_peer) {
- if (*oidp == subtree->subid){
- goto found;
- }
- }
- *lastind=0;
- return NULL;
-
-found:
- if (len > 1){
- return_tree =
- __oid2tp(oidp + 1, len - 1, subtree->child_list, lastind);
- (*lastind)++;
- } else {
- *lastind=1;
- }
- if (return_tree)
- return return_tree;
- else
- return subtree;
-}
-
-/* function: __concat_oid_str
- *
- * This function converts a dotted-decimal string, soid_str, to an array
- * of oid types and concatenates them on doid_arr begining at the index
- * specified by doid_arr_len.
- *
- * returns : SUCCESS, FAILURE
- */
-static int
-__concat_oid_str(doid_arr, doid_arr_len, soid_str)
-oid *doid_arr;
-int *doid_arr_len;
-char * soid_str;
-{
- char soid_buf[STR_BUF_SIZE];
- char *cp;
-
- if (!soid_str || !*soid_str) return SUCCESS;/* successfully added nothing */
- if (*soid_str == '.') soid_str++;
- strcpy(soid_buf, soid_str);
- cp = strtok(soid_buf,".");
- while (cp) {
- sscanf(cp, "%lu", &(doid_arr[(*doid_arr_len)++]));
- /* doid_arr[(*doid_arr_len)++] = atoi(cp); */
- cp = strtok(NULL,".");
- }
- return(SUCCESS);
-}
-
-/*
- * add a varbind to PDU
- */
-static int
-__add_var_val_str(pdu, name, name_length, val, len, type)
- netsnmp_pdu *pdu;
- oid *name;
- int name_length;
- char * val;
- int len;
- int type;
-{
- netsnmp_variable_list *vars;
- oid oidbuf[MAX_OID_LEN];
- int ret = SUCCESS;
- struct tree *tp;
-
- if (pdu->variables == NULL){
- pdu->variables = vars =
- (netsnmp_variable_list *)calloc(1,sizeof(netsnmp_variable_list));
- } else {
- for(vars = pdu->variables;
- vars->next_variable;
- vars = vars->next_variable)
- /*EXIT*/;
- vars->next_variable =
- (netsnmp_variable_list *)calloc(1,sizeof(netsnmp_variable_list));
- vars = vars->next_variable;
- }
-
- vars->next_variable = NULL;
- vars->name = (oid *)malloc(name_length * sizeof(oid));
- memcpy((char *)vars->name, (char *)name, name_length * sizeof(oid));
- vars->name_length = name_length;
- switch (type) {
- case TYPE_INTEGER:
- case TYPE_INTEGER32:
- vars->type = ASN_INTEGER;
- vars->val.integer = (long *)malloc(sizeof(long));
- if (val)
- *(vars->val.integer) = strtol(val,NULL,0);
- else {
- ret = FAILURE;
- *(vars->val.integer) = 0;
- }
- vars->val_len = sizeof(long);
- break;
-
- case TYPE_GAUGE:
- case TYPE_UNSIGNED32:
- vars->type = ASN_GAUGE;
- goto UINT;
- case TYPE_COUNTER:
- vars->type = ASN_COUNTER;
- goto UINT;
- case TYPE_TIMETICKS:
- vars->type = ASN_TIMETICKS;
- goto UINT;
- case TYPE_UINTEGER:
- vars->type = ASN_UINTEGER;
-UINT:
- vars->val.integer = (long *)malloc(sizeof(long));
- if (val)
- sscanf(val,"%lu",vars->val.integer);
- else {
- ret = FAILURE;
- *(vars->val.integer) = 0;
- }
- vars->val_len = sizeof(long);
- break;
-
- case TYPE_OCTETSTR:
- vars->type = ASN_OCTET_STR;
- goto OCT;
-
- case TYPE_BITSTRING:
- vars->type = ASN_OCTET_STR;
- goto OCT;
-
- case TYPE_OPAQUE:
- vars->type = ASN_OCTET_STR;
-OCT:
- vars->val.string = (u_char *)malloc(len);
- vars->val_len = len;
- if (val && len)
- memcpy((char *)vars->val.string, val, len);
- else {
- ret = FAILURE;
- vars->val.string = strdup("");
- vars->val_len = 0;
- }
- break;
-
- case TYPE_IPADDR:
- vars->type = ASN_IPADDRESS;
- vars->val.integer = (long *)malloc(sizeof(long));
- if (val)
- *(vars->val.integer) = inet_addr(val);
- else {
- ret = FAILURE;
- *(vars->val.integer) = 0;
- }
- vars->val_len = sizeof(long);
- break;
-
- case TYPE_OBJID:
- vars->type = ASN_OBJECT_ID;
- vars->val_len = MAX_OID_LEN;
- /* if (read_objid(val, oidbuf, &(vars->val_len))) { */
- /* tp = __tag2oid(val,NULL,oidbuf,&(vars->val_len),NULL,0); */
- if (!val || !snmp_parse_oid(val, oidbuf, &vars->val_len)) {
- vars->val.objid = NULL;
- ret = FAILURE;
- } else {
- vars->val_len *= sizeof(oid);
- vars->val.objid = (oid *)malloc(vars->val_len);
- memcpy((char *)vars->val.objid, (char *)oidbuf, vars->val_len);
- }
- break;
-
- default:
- vars->type = ASN_NULL;
- vars->val_len = 0;
- vars->val.string = NULL;
- ret = FAILURE;
- }
-
- return ret;
-}
-
-/* takes ss and pdu as input and updates the 'response' argument */
-/* the input 'pdu' argument will be freed */
-static int
-__send_sync_pdu(ss, pdu, response, retry_nosuch,
- err_str_sv, err_num_sv, err_ind_sv)
-netsnmp_session *ss;
-netsnmp_pdu *pdu;
-netsnmp_pdu **response;
-int retry_nosuch;
-SV * err_str_sv;
-SV * err_num_sv;
-SV * err_ind_sv;
-{
- int status;
- long command = pdu->command;
- *response = NULL;
-retry:
-
- status = snmp_synch_response(ss, pdu, response);
-
- if ((*response == NULL) && (status == STAT_SUCCESS)) status = STAT_ERROR;
-
- switch (status) {
- case STAT_SUCCESS:
- switch ((*response)->errstat) {
- case SNMP_ERR_NOERROR:
- break;
-
- case SNMP_ERR_NOSUCHNAME:
- if (retry_nosuch && (pdu = snmp_fix_pdu(*response, command))) {
- if (*response) snmp_free_pdu(*response);
- goto retry;
- }
-
- /* Pv1, SNMPsec, Pv2p, v2c, v2u, v2*, and SNMPv3 PDUs */
- case SNMP_ERR_TOOBIG:
- case SNMP_ERR_BADVALUE:
- case SNMP_ERR_READONLY:
- case SNMP_ERR_GENERR:
- /* in SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs */
- case SNMP_ERR_NOACCESS:
- case SNMP_ERR_WRONGTYPE:
- case SNMP_ERR_WRONGLENGTH:
- case SNMP_ERR_WRONGENCODING:
- case SNMP_ERR_WRONGVALUE:
- case SNMP_ERR_NOCREATION:
- case SNMP_ERR_INCONSISTENTVALUE:
- case SNMP_ERR_RESOURCEUNAVAILABLE:
- case SNMP_ERR_COMMITFAILED:
- case SNMP_ERR_UNDOFAILED:
- case SNMP_ERR_AUTHORIZATIONERROR:
- case SNMP_ERR_NOTWRITABLE:
- /* in SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs */
- case SNMP_ERR_INCONSISTENTNAME:
- default:
- sv_catpv(err_str_sv,
- (char*)snmp_errstring((*response)->errstat));
- sv_setiv(err_num_sv, (*response)->errstat);
- sv_setiv(err_ind_sv, (*response)->errindex);
- status = (*response)->errstat;
- break;
- }
- break;
-
- case STAT_TIMEOUT:
- case STAT_ERROR:
- sv_catpv(err_str_sv, (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(err_num_sv, ss->s_snmp_errno);
- break;
-
- default:
- sv_catpv(err_str_sv, "send_sync_pdu: unknown status");
- sv_setiv(err_num_sv, ss->s_snmp_errno);
- break;
- }
-
- return(status);
-}
-
-static int
-__callback_wrapper (op, ss, reqid, pdu, cb_data)
-int op;
-netsnmp_session *ss;
-int reqid;
-netsnmp_pdu *pdu;
-void *cb_data;
-{
- /* we should probably just increment the reference counter... */
- /* sv_inc(cb_data); */
- return __snmp_xs_cb(op, ss, reqid, pdu, newSVsv(cb_data));
-}
-
-
-static int
-__snmp_xs_cb (op, ss, reqid, pdu, cb_data)
-int op;
-netsnmp_session *ss;
-int reqid;
-netsnmp_pdu *pdu;
-void *cb_data;
-{
- SV *varlist_ref;
- AV *varlist;
- SV *varbind_ref;
- AV *varbind;
- SV *traplist_ref = NULL;
- AV *traplist = NULL;
- netsnmp_variable_list *vars;
- struct tree *tp;
- int len;
- SV *tmp_sv;
- int type;
- char tmp_type_str[MAX_TYPE_NAME_LEN];
- u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf;
- size_t str_buf_len = sizeof(str_buf);
- size_t out_len = 0;
- int buf_over = 0;
- char *label;
- char *iid;
- char *cp;
- int getlabel_flag = NO_FLAGS;
- int sprintval_flag = USE_BASIC;
- netsnmp_pdu *reply_pdu;
- int old_numeric, old_printfull;
- netsnmp_transport *transport = NULL;
-
- SV* cb = ((struct snmp_xs_cb_data*)cb_data)->perl_cb;
- SV* sess_ref = ((struct snmp_xs_cb_data*)cb_data)->sess_ref;
- SV **err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- SV **err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- SV **err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
-
- dSP;
- ENTER;
- SAVETMPS;
-
- free(cb_data);
-
- sv_setpv(*err_str_svp, (char*)snmp_errstring(pdu->errstat));
- sv_setiv(*err_num_svp, pdu->errstat);
- sv_setiv(*err_ind_svp, pdu->errindex);
-
- varlist_ref = &sv_undef; /* Prevent unintialized use below. */
-
- switch (op) {
- case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
- traplist_ref = NULL;
- switch (pdu->command) {
- case SNMP_MSG_INFORM:
- /*
- * Ideally, we would use the return value from the callback to
- * decide what response, if any, we send, and what the error status
- * and error index should be.
- */
- reply_pdu = snmp_clone_pdu(pdu);
- if (reply_pdu) {
- reply_pdu->command = SNMP_MSG_RESPONSE;
- reply_pdu->reqid = pdu->reqid;
- reply_pdu->errstat = reply_pdu->errindex = 0;
- snmp_send(ss, reply_pdu);
- } else {
- warn("Couldn't clone PDU for inform response");
- }
- /* FALLTHRU */
- case SNMP_MSG_TRAP2:
- traplist = newAV();
- traplist_ref = newRV_noinc((SV*)traplist);
-#if 0
- /* of dubious utility... */
- av_push(traplist, newSViv(pdu->command));
-#endif
- av_push(traplist, newSViv(pdu->reqid));
- if ((transport = snmp_sess_transport(snmp_sess_pointer(ss))) != NULL) {
- cp = transport->f_fmtaddr(transport, pdu->transport_data,
- pdu->transport_data_length);
- av_push(traplist, newSVpv(cp, strlen(cp)));
- free(cp);
- } else {
- /* This shouldn't ever happen; every session has a transport. */
- av_push(traplist, newSVpv("", 0));
- }
- av_push(traplist, newSVpv((char*) pdu->community, pdu->community_len));
- /* FALLTHRU */
- case SNMP_MSG_RESPONSE:
- {
- varlist = newAV();
- varlist_ref = newRV_noinc((SV*)varlist);
-
- /*
- ** Set up for numeric OID's, if necessary. Save the old values
- ** so that they can be restored when we finish -- these are
- ** library-wide globals, and have to be set/restored for each
- ** session.
- */
- old_numeric = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS);
- old_printfull = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID);
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
- getlabel_flag |= USE_NUMERIC_OIDS;
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1);
- }
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1))) {
- getlabel_flag |= USE_LONG_NAMES;
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1);
- }
-
- sv_bless(varlist_ref, gv_stashpv("SNMP::VarList",0));
- for(vars = (pdu?pdu->variables:NULL); vars; vars = vars->next_variable) {
- varbind = newAV();
- varbind_ref = newRV_noinc((SV*)varbind);
- sv_bless(varbind_ref, gv_stashpv("SNMP::Varbind",0));
- av_push(varlist, varbind_ref);
- *str_buf = '.';
- *(str_buf+1) = '\0';
- out_len = 0;
- tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len,
- &out_len, 0, &buf_over,
- vars->name,vars->name_length);
- str_buf[sizeof(str_buf)-1] = '\0';
- if (__is_leaf(tp)) {
- type = tp->type;
- } else {
- getlabel_flag |= NON_LEAF_NAME;
- type = __translate_asn_type(vars->type);
- }
- __get_label_iid(str_buf,&label,&iid,getlabel_flag);
- av_store(varbind, VARBIND_TAG_F,
- newSVpv(label, strlen(label)));
- av_store(varbind, VARBIND_IID_F,
- newSVpv(iid, strlen(iid)));
- __get_type_str(type, tmp_type_str);
- tmp_sv = newSVpv(tmp_type_str, strlen(tmp_type_str));
- av_store(varbind, VARBIND_TYPE_F, tmp_sv);
- len = __snprint_value(str_buf, sizeof(str_buf),
- vars, tp, type, sprintval_flag);
- tmp_sv = newSVpv((char*)str_buf, len);
- av_store(varbind, VARBIND_VAL_F, tmp_sv);
- } /* for */
-
- /* Reset the library's behavior for numeric/symbolic OID's. */
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, old_numeric );
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, old_printfull);
-
- } /* case SNMP_MSG_RESPONSE */
- break;
- default:;
- } /* switch pdu->command */
- break;
-
- case NETSNMP_CALLBACK_OP_TIMED_OUT:
- varlist_ref = &sv_undef;
- break;
- default:;
- } /* switch op */
- sv_2mortal(cb);
- cb = __push_cb_args2(cb,
- (SvTRUE(varlist_ref) ? sv_2mortal(varlist_ref):varlist_ref),
- (SvTRUE(traplist_ref) ? sv_2mortal(traplist_ref):traplist_ref));
- __call_callback(cb, G_DISCARD);
-
- FREETMPS;
- LEAVE;
- sv_2mortal(sess_ref);
- return 1;
-}
-
-static SV *
-__push_cb_args2(sv,esv,tsv)
-SV *sv;
-SV *esv;
-SV *tsv;
-{
- dSP;
- if (SvTYPE(SvRV(sv)) != SVt_PVCV) sv = SvRV(sv);
-
- PUSHMARK(sp);
- if (SvTYPE(sv) == SVt_PVAV) {
- AV *av = (AV *) sv;
- int n = av_len(av) + 1;
- SV **x = av_fetch(av, 0, 0);
- if (x) {
- int i = 1;
- sv = *x;
-
- for (i = 1; i < n; i++) {
- x = av_fetch(av, i, 0);
- if (x) {
- SV *arg = *x;
- XPUSHs(sv_mortalcopy(arg));
- } else {
- XPUSHs(&sv_undef);
- }
- }
- } else {
- sv = &sv_undef;
- }
- }
- if (esv) XPUSHs(sv_mortalcopy(esv));
- if (tsv) XPUSHs(sv_mortalcopy(tsv));
- PUTBACK;
- return sv;
-}
-
-static int
-__call_callback(sv, flags)
-SV *sv;
-int flags;
-{
- dSP;
- I32 myframe = TOPMARK;
- I32 count;
- ENTER;
- if (SvTYPE(sv) == SVt_PVCV)
- {
- count = perl_call_sv(sv, flags);
- }
- else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)
- {
- count = perl_call_sv(SvRV(sv), flags);
- }
- else
- {
-
- SV **top = stack_base + myframe + 1;
- SV *obj = *top;
- if (SvPOK(sv) && SvROK(obj) && SvOBJECT(SvRV(obj)))
- {
- count = perl_call_method(SvPV(sv, na), flags);
- }
- else if (SvPOK(obj) && SvROK(sv) && SvOBJECT(SvRV(sv)))
- {
- /* We have obj method ...
- Used to be used instead of LangMethodCall()
- */
- *top = sv;
- count = perl_call_method(SvPV(obj, na), flags);
- }
- else
- {
- count = perl_call_sv(sv, flags);
- }
- }
- LEAVE;
- return count;
-}
-
-/* Bulkwalk support routines */
-
-/* Add a context pointer to the list of valid pointers. Place it in the first
-** NULL slot in the array.
-*/
-static int
-_context_add(walk_context *context)
-{
- int i, j, new_sz;
-
- if ((i = _context_okay(context)) != 0) /* Already exists? Okay. */
- return i;
-
- /* Initialize the array if necessary. */
- if (_valid_contexts == NULL) {
-
- /* Create the _valid_contexts structure. */
- Newz(0, _valid_contexts, 1, struct valid_contexts);
- assert(_valid_contexts != NULL);
-
- /* Populate the original valid contexts array. */
- Newz(0, _valid_contexts->valid, 4, walk_context *);
- assert(_valid_contexts->valid != NULL);
-
- /* Computer number of slots in the array. */
- _valid_contexts->sz_valid = sizeof(*_valid_contexts->valid) /
- sizeof(walk_context *);
-
- for (i = 0; i < _valid_contexts->sz_valid; i++)
- _valid_contexts->valid[i] = NULL;
-
- DBPRT(3, (DBOUT "Created valid_context array 0x%p (%d slots)\n",
- _valid_contexts->valid, _valid_contexts->sz_valid));
- }
-
- /* Search through the list, looking for NULL's -- unused slots. */
- for (i = 0; i < _valid_contexts->sz_valid; i++)
- if (_valid_contexts->valid[i] == NULL)
- break;
-
- /* Did we walk off the end of the list? Need to grow the list. Double
- ** it for now.
- */
- if (i == _valid_contexts->sz_valid) {
- new_sz = _valid_contexts->sz_valid * 2;
-
- Renew(_valid_contexts->valid, new_sz, walk_context *);
- assert(_valid_contexts->valid != NULL);
-
- DBPRT(3, (DBOUT "Resized valid_context array 0x%p from %d to %d slots\n",
- _valid_contexts->valid, _valid_contexts->sz_valid, new_sz));
-
- _valid_contexts->sz_valid = new_sz;
-
- /* Initialize the new half of the resized array. */
- for (j = i; j < new_sz; j++)
- _valid_contexts->valid[j] = NULL;
- }
-
- /* Store the context pointer in the array and return 0 (success). */
- _valid_contexts->valid[i] = context;
- DBPRT(3,( "Add context 0x%p to valid context list\n", context));
- return 0;
-}
-
-/* Remove a context pointer from the valid list. Replace the pointer with
-** NULL in the valid pointer list.
-*/
-static int
-_context_del(walk_context *context)
-{
- int i;
-
- if (_valid_contexts == NULL) /* Make sure it was initialized. */
- return 1;
-
- for (i = 0; i < _valid_contexts->sz_valid; i++) {
- if (_valid_contexts->valid[i] == context) {
- DBPRT(3,( "Remove context 0x%p from valid context list\n", context));
- _valid_contexts->valid[i] = NULL; /* Remove it from the list. */
- return 0; /* Return successful status. */
- }
- }
- return 1;
-}
-
-/* Check if a specific context pointer is in the valid list. Return true (1)
-** if the context is still in the valid list, or 0 if not (or context is NULL).
-*/
-static int
-_context_okay(walk_context *context)
-{
- int i;
-
- if (_valid_contexts == NULL) /* Make sure it was initialized. */
- return 0;
-
- if (context == NULL) /* Asked about a NULL context? Fail. */
- return 0;
-
- for (i = 0; i < _valid_contexts->sz_valid; i++)
- if (_valid_contexts->valid[i] == context)
- return 1; /* Found it! */
-
- return 0; /* No match -- return failure. */
-}
-
-/* Check if the walk is completed, based upon the context. Also set the
-** ignore flag on any completed variables -- this prevents them from being
-** being sent in later packets.
-*/
-static int
-_bulkwalk_done(walk_context *context)
-{
- int is_done = 1;
- int i;
- bulktbl *bt_entry; /* bulktbl requested OID entry */
-
- /* Don't consider walk done until at least one packet has been exchanged. */
- if (context->pkts_exch == 0)
- return 0;
-
- /* Fix up any requests that have completed. If the complete flag is set,
- ** or it is a non-repeater OID, set the ignore flag so that it will not
- ** be considered further. Assume we are done with the walk, and note
- ** otherwise if we aren't. Return 1 if all requests are complete, or 0
- ** if there's more to do.
- */
- for (i = 0; i < context->nreq_oids; i ++) {
- bt_entry = &context->req_oids[i];
-
- if (bt_entry->complete || bt_entry->norepeat) {
-
- /* This request is complete. Remove it from list of
- ** walks still in progress.
- */
- DBPRT(1, (DBOUT "Ignoring %s request oid %s\n",
- bt_entry->norepeat? "nonrepeater" : "completed",
- snprint_objid(_debugx, sizeof(_debugx), bt_entry->req_oid,
- bt_entry->req_len)));
-
- /* Ignore this OID in any further packets. */
- bt_entry->ignore = 1;
- }
-
- /* If any OID is not being ignored, the walk is not done. Must loop
- ** through all requests to do the fixup -- no early return possible.
- */
- if (!bt_entry->ignore)
- is_done = 0;
- }
-
- return is_done; /* Did the walk complete? */
-}
-
-/* Callback registered with SNMP. Return 1 from this callback to cause the
-** current request to be deleted from the retransmit queue.
-*/
-static int
-_bulkwalk_async_cb(int op,
- SnmpSession *ss,
- int reqid,
- netsnmp_pdu *pdu,
- void *context_ptr)
-{
- walk_context *context;
- int done = 0;
- int npushed;
- SV **err_str_svp;
- SV **err_num_svp;
-
- /* Handle callback request for asynchronous bulkwalk. If the bulkwalk has
- ** not completed, and has not timed out, send the next request packet in
- ** the walk.
- **
- ** Return 0 to indicate success (caller ignores return value).
- */
-
- DBPRT(2, (DBOUT "bulkwalk_async_cb(op %d, reqid 0x%08X, context 0x%p)\n",
- op, reqid, context_ptr));
-
- context = (walk_context *)context_ptr;
-
- /* Make certain this is a valid context pointer. This pdu may
- ** have been retransmitted after the bulkwalk was completed
- ** (and the context was destroyed). If so, just return.
- */
- if (!_context_okay(context)) {
- DBPRT(2,( "Ignoring PDU for dead context 0x%p...\n", context));
- return 1;
- }
-
- /* Is this a retransmission of a request we've already seen or some
- ** unexpected request id? If so, just ignore it.
- */
- if (reqid != context->exp_reqid) {
- DBPRT(2,
- ("Got reqid 0x%08X, expected reqid 0x%08X. Ignoring...\n", reqid,
- context->exp_reqid));
- return 1;
- }
- /* Ignore any future packets for this reqid. */
- context->exp_reqid = -1;
-
- err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);
-
- switch (op) {
- case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
- {
- DBPRT(1,( "Received message for reqid 0x%08X ...\n", reqid));
-
- switch (pdu->command)
- {
- case SNMP_MSG_RESPONSE:
- {
- DBPRT(2, (DBOUT "Calling bulkwalk_recv_pdu(context 0x%p, pdu 0x%p)\n",
- context_ptr, pdu));
-
- /* Handle the response PDU. If an error occurs or there were
- ** no variables in the response, consider the walk done. If
- ** the response was okay, check if we have any more to do after
- ** this response.
- */
- if (_bulkwalk_recv_pdu(context, pdu) <= 0)
- done = 1;
- else
- done = _bulkwalk_done(context); /* Also set req ignore flags */
- break;
- }
- default:
- {
- DBPRT(1,( "unexpected pdu->command %d\n", pdu->command));
- done = 1; /* "This can't happen!", so bail out when it does. */
- break;
- }
- }
-
- break;
- }
-
- case NETSNMP_CALLBACK_OP_TIMED_OUT:
- {
- DBPRT(1,( "\n*** Timeout for reqid 0x%08X\n\n", reqid));
-
- sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_TIMEOUT));
- sv_setiv(*err_num_svp, SNMPERR_TIMEOUT);
-
- /* Timeout means something bad has happened. Return a not-okay
- ** result to the async callback.
- */
- npushed = _bulkwalk_finish(context, 0 /* NOT OKAY */);
- return 1;
- }
-
- default:
- {
- DBPRT(1,( "unexpected callback op %d\n", op));
- sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_GENERR));
- sv_setiv(*err_num_svp, SNMPERR_GENERR);
- npushed = _bulkwalk_finish(context, 0 /* NOT OKAY */);
- return 1;
- }
- }
-
- /* We have either timed out, or received and parsed in a response. Now,
- ** if we have more variables to test, call bulkwalk_send_pdu() to enqueue
- ** another async packet, and return.
- **
- ** If, however, the bulkwalk has completed (or an error has occurred that
- ** cuts the walk short), call bulkwalk_finish() to push the results onto
- ** the Perl call stack. Then explicitly call the Perl callback that was
- ** passed in by the user oh-so-long-ago.
- */
- if (!done) {
- DBPRT(1,( "bulkwalk not complete -- send next pdu from callback\n"));
-
- if (_bulkwalk_send_pdu(context) != NULL)
- return 1;
-
- DBPRT(1,( "send_pdu() failed!\n"));
- /* Fall through and return what we have so far. */
- }
-
- /* Call the perl callback with the return values and we're done. */
- npushed = _bulkwalk_finish(context, 1 /* OKAY */);
-
- return 1;
-}
-
-static netsnmp_pdu *
-_bulkwalk_send_pdu(walk_context *context)
-{
- netsnmp_pdu *pdu = NULL;
- netsnmp_pdu *response = NULL;
- struct bulktbl *bt_entry;
- int nvars = 0;
- int reqid;
- int status;
- int i;
-
- /* Send a pdu requesting any remaining variables in the context.
- **
- ** In synchronous mode, returns a pointer to the response packet.
- **
- ** In asynchronous mode, it returns the request ID, cast to a struct snmp *,
- ** not a valid SNMP response packet. The async code should not be trying
- ** to get variables out of this "response".
- **
- ** In either case, return a NULL pointer on error or failure.
- */
-
- SV **sess_ptr_sv = hv_fetch((HV*)SvRV(context->sess_ref), "SessPtr", 7, 1);
- netsnmp_session *ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- SV **err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);
- SV **err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);
- SV **err_ind_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorInd", 8, 1);
-
- /* Create a new PDU and send the remaining set of requests to the agent. */
- pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
- if (pdu == NULL) {
- sv_setpv(*err_str_svp, "snmp_pdu_create(GETBULK) failed: ");
- sv_catpv(*err_str_svp, strerror(errno));
- sv_setiv(*err_num_svp, SNMPERR_MALLOC);
- goto err;
- }
-
- /* Request non-repeater variables only in the first packet exchange. */
- pdu->errstat = (context->pkts_exch == 0) ? context->non_reps : 0;
- pdu->errindex = context->max_reps;
-
- for (i = 0; i < context->nreq_oids; i++) {
- bt_entry = &context->req_oids[i];
- if (bt_entry->ignore)
- continue;
-
- assert(bt_entry->complete == 0);
-
- if (!snmp_add_null_var(pdu, bt_entry->last_oid, bt_entry->last_len)) {
- sv_setpv(*err_str_svp, "snmp_add_null_var() failed");
- sv_setiv(*err_num_svp, SNMPERR_GENERR);
- sv_setiv(*err_ind_svp, i);
- goto err;
- }
-
- nvars ++;
-
- DBPRT(1, (DBOUT " Add %srepeater %s\n", bt_entry->norepeat ? "non" : "",
- snprint_objid(_debugx, sizeof(_debugx), bt_entry->last_oid, bt_entry->last_len)));
- }
-
- /* Make sure variables are actually being requested in the packet. */
- assert (nvars != 0);
-
- context->pkts_exch ++;
-
- DBPRT(1, (DBOUT "Sending %ssynchronous request %d...\n",
- SvTRUE(context->perl_cb) ? "a" : "", context->pkts_exch));
-
- /* We handle the asynchronous and synchronous requests differently here.
- ** For async, we simply enqueue the packet with a callback to handle the
- ** returned response, then return. Note that this we call the bulkwalk
- ** callback, and hand it the walk_context, not the Perl callback. The
- ** snmp_async_send() function returns the reqid on success, 0 on failure.
- */
- if (SvTRUE(context->perl_cb)) {
- reqid = snmp_async_send(ss, pdu, _bulkwalk_async_cb, (void *)context);
-
- DBPRT(2,( "bulkwalk_send_pdu(): snmp_async_send => 0x%08X\n", reqid));
-
- if (reqid == 0) {
- sv_setpv(*err_str_svp, (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- goto err;
- }
-
- /* Make a note of the request we expect to be answered. */
- context->exp_reqid = reqid;
-
- /* Callbacks take care of the rest. Let the caller know how many vars
- ** we sent in this request. Note that this is not a valid SNMP PDU,
- ** but that's because a response has not yet been received.
- */
- return (netsnmp_pdu *)reqid;
- }
-
- /* This code is for synchronous mode support.
- **
- ** Send the PDU and block awaiting the response. Return the response
- ** packet back to the caller. Note that snmp_sess_read() frees the pdu.
- */
- status = __send_sync_pdu(ss, pdu, &response, NO_RETRY_NOSUCH,
- *err_str_svp, *err_num_svp, *err_ind_svp);
-
- pdu = NULL;
-
- /* Check for a failed request. __send_sync_pdu() will set the appropriate
- ** values in the error string and number SV's.
- */
- if (status != STAT_SUCCESS) {
- DBPRT(1,( "__send_sync_pdu() -> %d\n",(int)status));
- goto err;
- }
-
- DBPRT(1, (DBOUT "%d packets exchanged, response 0x%p\n", context->pkts_exch,
- response));
- return response;
-
-
- err:
- if (pdu)
- snmp_free_pdu(pdu);
- return NULL;
-}
-
-/* Handle an incoming GETBULK response PDU. This function just pulls the
-** variables off of the PDU and builds up the arrays of returned values
-** that are stored in the context.
-**
-** Returns the number of variables found in this packet, or -1 on error.
-** Note that the caller is expected to free the pdu.
-*/
-static int
-_bulkwalk_recv_pdu(walk_context *context, netsnmp_pdu *pdu)
-{
- netsnmp_variable_list *vars;
- struct tree *tp;
- char type_str[MAX_TYPE_NAME_LEN];
- u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf;
- size_t str_buf_len = sizeof(str_buf);
- size_t out_len = 0;
- int buf_over = 0;
- char *label;
- char *iid;
- bulktbl *expect = NULL;
- int old_numeric;
- int old_printfull;
- int old_format;
- int getlabel_flag;
- int type;
- int pix;
- int len;
- int i;
- AV *varbind;
- SV *rv;
- SV **sess_ptr_sv = hv_fetch((HV*)SvRV(context->sess_ref), "SessPtr", 7, 1);
- SV **err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);
- SV **err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);
- SV **err_ind_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorInd", 8, 1);
-
- DBPRT(3, (DBOUT "bulkwalk: sess_ref = 0x%p, sess_ptr_sv = 0x%p\n",
- context->sess_ref, sess_ptr_sv));
-
- /* Set up for numeric OID's, if necessary. Save the old values
- ** so that they can be restored when we finish -- these are
- ** library-wide globals, and have to be set/restored for each
- ** session.
- */
- old_numeric = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS);
- old_printfull = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID);
- old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
- if (context->getlabel_f & USE_NUMERIC_OIDS) {
- DBPRT(2,( "Using numeric oid's\n"));
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1);
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1);
- netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_NUMERIC);
- }
-
- /* Parse through the list of variables returned, adding each return to
- ** the appropriate array (as a VarBind). Also keep track of which
- ** repeated OID we're expecting to see, and check if that tree walk has
- ** been completed (i.e. we've walked past the root of our request). If
- ** so, mark the request complete so that we don't send it again in any
- ** subsequent request packets.
- */
- if (context->pkts_exch == 1)
- context->reqbase = context->req_oids; /* Request with non-repeaters */
- else
- context->reqbase = context->repbase; /* Request only repeater vars */
-
- /* Note the first variable we expect to see. Should be reqbase. */
- expect = context->reqbase;
-
- for (vars = pdu->variables, pix = 0;
- vars != NULL;
- vars = vars->next_variable, pix ++)
- {
-
- /* If no outstanding requests remain, we're done. This works, but it
- ** causes the reported total variable count to be wrong (since the
- ** remaining vars on the last packet are not counted). In practice
- ** this is probably worth the win, but for debugging it's not.
- */
- if (context->req_remain == 0) {
- DBPRT(2,( "No outstanding requests remain. Terminating processing.\n"));
- while (vars) {
- pix ++;
- vars = vars->next_variable;
- }
- break;
- }
-
- /* Determine which OID we expect to see next. We assert that the OID's
- ** must be returned in the expected order. The first nreq_oids returns
- ** should match the req_oids array, after that, we must cycle through
- ** the repeaters in order. Non-repeaters are not included in later
- ** packets, so cannot have the "ignore" flag set.
- */
-
- if (context->oid_saved < context->non_reps) {
- assert(context->pkts_exch == 1);
-
- expect = context->reqbase ++;
- assert(expect->norepeat);
-
- } else {
- /* Must be a repeater. Look for the first one that is not being
- ** ignored. Make sure we don't loop around to where we started.
- ** If we get here but everything is being ignored, there's a problem.
- **
- ** Note that we *do* accept completed but not ignored OID's -- these
- ** are OID's for trees that have been completed sometime in this
- ** response, but must be looked at to maintain ordering.
- */
-
- if (pix == 0) {
- /* Special case code for no non-repeater case. This
- ** is necessary because expect normally points to the
- ** last non-repeater upon entry to this code (so the
- ** '++expect' below increments it into the repeaters
- ** section of the req_oids[] array).
- ** If there are no non-repeaters, the expect pointer
- ** is never initialized. This addresses this problem.
- */
- expect = context->reqbase;
-
- } else {
-
- /* Find the repeater OID we expect to see. Ignore any
- ** OID's marked 'ignore' -- these have been completed
- ** and were not requested in this iteration.
- */
- for (i = 0; i < context->repeaters; i++) {
-
- /* Loop around to first repeater if we hit the end. */
- if (++ expect == &context->req_oids[context->nreq_oids])
- expect = context->reqbase = context->repbase;
-
- /* Stop if this OID is not being ignored. */
- if (!expect->ignore)
- break;
- }
-
- /* Make sure we did find an expected OID. */
- assert(i <= context->repeaters);
- }
- }
-
- DBPRT(2, (DBOUT "Var %03d request %s\n", pix, snprint_objid(_debugx, sizeof(_debugx),
- expect->req_oid, expect->req_len)));
-
- /* Did we receive an error condition for this variable?
- ** If it's a repeated variable, mark it as complete and
- ** fall through to the block below.
- */
- if ((vars->type == SNMP_ENDOFMIBVIEW) ||
- (vars->type == SNMP_NOSUCHOBJECT) ||
- (vars->type == SNMP_NOSUCHINSTANCE))
- {
- DBPRT(2,( "error type %d\n", (int)vars->type));
-
- /* ENDOFMIBVIEW should be okay for a repeater - just walked off the
- ** end of the tree. Mark the request as complete, and go on to the
- ** next one.
- */
- if ((context->oid_saved >= context->non_reps) &&
- (vars->type == SNMP_ENDOFMIBVIEW))
- {
- expect->complete = 1;
- DBPRT(2, (DBOUT "Ran out of tree for oid %s\n",
- snprint_objid(_debugx, sizeof(_debugx), vars->name,vars->name_length)));
-
- context->req_remain --;
-
- /* Go on to the next variable. */
- continue;
-
- }
- sv_setpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- sv_setiv(*err_ind_svp, pix);
- goto err;
- }
-
- /* If this is not the first packet, skip any duplicated OID values, if
- ** present. These should be the seed values copied from the last OID's
- ** of the previous packet. In practice we don't see this, but it is
- ** easy enough to do, and will avoid confusion for the caller from mis-
- ** behaving agents (badly misbehaving... ;^).
- */
- if ((context->pkts_exch > 1) && (pix < context->repeaters)) {
- if (__oid_cmp(vars->name, vars->name_length,
- context->reqbase[pix].last_oid,
- context->reqbase[pix].last_len) == 0)
- {
- DBPRT(2, (DBOUT "Ignoring repeat oid: %s\n",
- snprint_objid(_debugx, sizeof(_debugx), vars->name,vars->name_length)));
-
- continue;
- }
- }
-
- context->oid_total ++; /* Count each variable received. */
-
- /* If this is a non-repeater, handle it. Otherwise, if it is a
- ** repeater, has the walk wandered off of the requested tree? If so,
- ** this request is complete, so mark it as such. Ignore any other
- ** variables in a completed request. In order to maintain the correct
- ** ordering of which variables we expect to see in this packet, we must
- ** not set the ignore flags immediately. It is done in bulkwalk_done().
- ** XXX Can we use 'expect' instead of 'context->req_oids[pix]'?
- */
- if (context->oid_saved < context->non_reps) {
- DBPRT(2, (DBOUT " expected var %s (nonrepeater %d/%d)\n",
- snprint_objid(_debugx, sizeof(_debugx), context->req_oids[pix].req_oid,
- context->req_oids[pix].req_len),
- pix, context->non_reps));
- DBPRT(2, (DBOUT " received var %s\n",
- snprint_objid(_debugx, sizeof(_debugx), vars->name, vars->name_length)));
-
- /* This non-repeater has now been seen, so mark the sub-tree as
- ** completed. Note that this may not be the same oid as requested,
- ** since non-repeaters act like GETNEXT requests, not GET's. <sigh>
- */
- context->req_oids[pix].complete = 1;
- context->req_remain --;
-
- } else { /* Must be a repeater variable. */
-
- DBPRT(2, (DBOUT " received oid %s\n",
- snprint_objid(_debugx, sizeof(_debugx), vars->name, vars->name_length)));
-
- /* Are we already done with this tree? If so, just ignore this
- ** variable and move on to the next expected variable.
- */
- if (expect->complete) {
- DBPRT(2,( " this branch is complete - ignoring.\n"));
- continue;
- }
-
- /* If the base oid of this variable doesn't match the expected oid,
- ** assume that we've walked past the end of the subtree. Set this
- ** subtree to be completed, and go on to the next variable.
- */
- if ((vars->name_length < expect->req_len) ||
- (memcmp(vars->name, expect->req_oid, expect->req_len*sizeof(oid))))
- {
- DBPRT(2,( " walked off branch - marking subtree as complete.\n"));
- expect->complete = 1;
- context->req_remain --;
- continue;
- }
-
- /* Still interested in the tree -- we need to keep track of the
- ** last-seen value in case we need to send an additional request
- ** packet.
- */
- (void)memcpy(expect->last_oid, vars->name,
- vars->name_length * sizeof(oid));
- expect->last_len = vars->name_length;
-
- }
-
- /* Create a new Varbind and populate it with the parsed information
- ** returned by the agent. This Varbind is then pushed onto the arrays
- ** maintained for each request OID in the context. These varbinds are
- ** collected into a return array by bulkwalk_finish().
- */
- varbind = (AV*) newAV();
- if (varbind == NULL) {
- sv_setpv(*err_str_svp, "newAV() failed: ");
- sv_catpv(*err_str_svp, (char*)strerror(errno));
- sv_setiv(*err_num_svp, SNMPERR_MALLOC);
- goto err;
- }
-
- *str_buf = '.';
- *(str_buf+1) = '\0';
- out_len = 0;
- tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len,
- &out_len, 0, &buf_over,
- vars->name,vars->name_length);
- str_buf[sizeof(str_buf)-1] = '\0';
-
- getlabel_flag = context->getlabel_f;
-
- if (__is_leaf(tp)) {
- type = tp->type;
- } else {
- getlabel_flag |= NON_LEAF_NAME;
- type = __translate_asn_type(vars->type);
- }
- if (__get_label_iid(str_buf, &label, &iid, getlabel_flag) == FAILURE) {
- label = str_buf;
- iid = label + strlen(label);
- }
-
- DBPRT(2,( " save var %s.%s = ", label, iid));
-
- av_store(varbind, VARBIND_TAG_F, newSVpv(label, strlen(label)));
- av_store(varbind, VARBIND_IID_F, newSVpv(iid, strlen(iid)));
-
- __get_type_str(type, type_str);
- av_store(varbind, VARBIND_TYPE_F, newSVpv(type_str, strlen(type_str)));
-
- len=__snprint_value(str_buf, sizeof(str_buf),
- vars, tp, type, context->sprintval_f);
- av_store(varbind, VARBIND_VAL_F, newSVpv((char*)str_buf, len));
-
- str_buf[len] = '\0';
- DBPRT(3,( "'%s' (%s)\n", str_buf, type_str));
-
-#if 0
- /* huh? */
- /* If necessary, store a timestamp as the semi-documented 5th element. */
- if (sv_timestamp)
- av_store(varbind, VARBIND_TIME_F, SvREFCNT_inc(sv_timestamp));
-#endif
-
- /* Push ref to the varbind onto the list of vars for OID. */
- rv = newRV_noinc((SV *)varbind);
- sv_bless(rv, gv_stashpv("SNMP::Varbind", 0));
- av_push(expect->vars, rv);
-
- context->oid_saved ++; /* Count this as a saved variable. */
-
- } /* next variable in response packet */
-
- DBPRT(1, (DBOUT "-- pkt %d saw %d vars, total %d (%d saved)\n", context->pkts_exch,
- pix, context->oid_total, context->oid_saved));
-
- /* We assert that all non-repeaters must be returned in
- ** the initial response (they are not repeated in additional
- ** packets, so would be dropped). If nonrepeaters still
- ** exist, consider it a fatal error.
- */
- if ((context->pkts_exch == 1) && (context->oid_saved < context->non_reps)) {
- /* Re-use space from the value string for error message. */
- sprintf(str_buf, "%d non-repeaters went unanswered", context->non_reps);
- sv_setpv(*err_str_svp, str_buf);
- sv_setiv(*err_num_svp, SNMPERR_GENERR);
- sv_setiv(*err_num_svp, context->oid_saved);
- goto err;
- }
-
- /* Reset the library's behavior for numeric/symbolic OID's. */
- if (context->getlabel_f & USE_NUMERIC_OIDS) {
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, old_numeric);
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, old_printfull);
- netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, old_format);
- }
-
- return pix;
-
- err:
- if (pdu)
- snmp_free_pdu(pdu);
- return -1;
-
-}
-
-/* Once the bulkwalk has completed, extend the stack and push references to
-** each of the arrays of SNMP::Varbind's onto the stack. Return the number
-** of arrays pushed on the stack. The caller should return to Perl, or call
-** the Perl callback function.
-**
-** Note that this function free()'s the walk_context and request bulktbl's.
-*/
-static int
-_bulkwalk_finish(walk_context *context, int okay)
-{
- int npushed = 0;
- int i;
- int async = 0;
- bulktbl *bt_entry;
- AV *ary = NULL;
- SV *rv;
- SV *perl_cb;
-
- SV **err_str_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorStr", 8, 1);
- SV **err_num_svp = hv_fetch((HV*)SvRV(context->sess_ref), "ErrorNum", 8, 1);
-
- dXSARGS;
-
- async = SvTRUE(context->perl_cb);
-
- /* Successfully completed the bulkwalk. For synchronous calls, push each
- ** of the request value arrays onto the stack, and return the number of
- ** items pushed onto the stack. For async, create a new array and push
- ** the references onto it. The array is then passed to the Perl callback.
- */
- if (!async)
- SP -= items;
-
- DBPRT(1, (DBOUT "Bulwalk %s (saved %d/%d), ", okay ? "completed" : "had error",
- context->oid_saved, context->oid_total));
-
- if (okay) {
- DBPRT(1, (DBOUT "%s %d varbind refs %s\n",
- async ? "pass ref to array of" : "return",
- context->nreq_oids,
- async ? "to callback" : "on stack to caller"));
-
- /* Create the array to hold the responses for the asynchronous callback,
- ** or pre-extend the stack enough to hold responses for synch return.
- */
- if (async) {
- ary = (AV *)newAV();
- if (ary == NULL) {
- sv_setpv(*err_str_svp, "newAV(): ");
- sv_catpv(*err_str_svp, (char *)strerror(errno));
- sv_setiv(*err_num_svp, errno);
- }
-
- /* NULL ary pointer is okay -- we'll handle it below... */
-
- } else {
- EXTEND(sp, context->nreq_oids);
-
- }
-
- /* Push a reference to each array of varbinds onto the stack, in
- ** the order requested. Note that these arrays may be empty.
- */
- for (i = 0; i < context->nreq_oids; i++) {
- bt_entry = &context->req_oids[i];
-
- DBPRT(2, (DBOUT " %sreq #%d (%s) => %d var%s\n",
- bt_entry->complete ? "" : "incomplete ", i,
- snprint_objid(_debugx, sizeof(_debugx), bt_entry->req_oid, bt_entry->req_len),
- (int)av_len(bt_entry->vars) + 1,
- (int)av_len(bt_entry->vars) > 0 ? "s" : ""));
-
- if (async && ary == NULL) {
- DBPRT(2,( " [dropped due to newAV() failure]\n"));
- continue;
- }
-
- /* Get a reference to the varlist, and push it onto array or stack */
- rv = newRV_noinc((SV *)bt_entry->vars);
- sv_bless(rv, gv_stashpv("SNMP::VarList",0));
-
- if (async)
- av_push(ary, rv);
- else
- PUSHs(sv_2mortal((SV *)rv));
-
- npushed ++;
- }
-
- } else { /* Not okay -- push a single undef on the stack if not async */
-
- if (!async) {
- XPUSHs(&sv_undef);
- npushed = 1;
- }
- }
-
- /* XXX Future enhancement -- make statistics (pkts exchanged, vars
- ** saved vs. received, total time, etc) available to caller so they
- ** can adjust their request parameters and/or re-order requests.
- */
-
- PUTBACK;
-
- if (async) {
- /* Asynchronous callback. Push the caller's arglist onto the stack,
- ** and follow it with the contents of the array (or undef if newAV()
- ** failed or the session had an error). Then mortalize the Perl
- ** callback pointer, and call the callback.
- */
- if (!okay || ary == NULL)
- rv = &sv_undef;
- else
- rv = newRV_noinc((SV *)ary);
-
- sv_2mortal(perl_cb = context->perl_cb);
- perl_cb = __push_cb_args(perl_cb, (SvTRUE(rv) ? sv_2mortal(rv) : rv));
-
- __call_callback(perl_cb, G_DISCARD);
- }
- sv_2mortal(context->sess_ref);
-
- /* Free the allocated space for the request states and return number of
- ** variables found. Remove the context from the valid context list.
- */
- _context_del(context);
- DBPRT(2,( "Free() context->req_oids\n"));
- Safefree(context->req_oids);
- DBPRT(2,( "Free() context 0x%p\n", context));
- Safefree(context);
- return npushed;
-}
-
-/* End of bulkwalk support routines */
-
-static char *
-__av_elem_pv(AV *av, I32 key, char *dflt)
-{
- SV **elem = av_fetch(av, key, 0);
-
- return (elem && SvOK(*elem)) ? SvPV(*elem, na) : dflt;
-}
-
-static int
-not_here(s)
-char *s;
-{
- croak("%s not implemented on this architecture", s);
- return -1;
-}
-
-static double
-constant(name, arg)
-char *name;
-int arg;
-{
- errno = 0;
- switch (*name) {
- case 'R':
- if (strEQ(name, "NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE"))
-#ifdef NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE
- return NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE;
-#else
- goto not_there;
-#endif
- break;
- case 'S':
- if (strEQ(name, "SNMPERR_BAD_ADDRESS"))
-#ifdef SNMPERR_BAD_ADDRESS
- return SNMPERR_BAD_ADDRESS;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMPERR_BAD_LOCPORT"))
-#ifdef SNMPERR_BAD_LOCPORT
- return SNMPERR_BAD_LOCPORT;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMPERR_BAD_SESSION"))
-#ifdef SNMPERR_BAD_SESSION
- return SNMPERR_BAD_SESSION;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMPERR_GENERR"))
-#ifdef SNMPERR_GENERR
- return SNMPERR_GENERR;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMPERR_TOO_LONG"))
-#ifdef SNMPERR_TOO_LONG
- return SNMPERR_TOO_LONG;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_ADDRESS"))
-#ifdef SNMP_DEFAULT_ADDRESS
- return SNMP_DEFAULT_ADDRESS;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_COMMUNITY_LEN"))
-#ifdef SNMP_DEFAULT_COMMUNITY_LEN
- return SNMP_DEFAULT_COMMUNITY_LEN;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_ENTERPRISE_LENGTH"))
-#ifdef SNMP_DEFAULT_ENTERPRISE_LENGTH
- return SNMP_DEFAULT_ENTERPRISE_LENGTH;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_ERRINDEX"))
-#ifdef SNMP_DEFAULT_ERRINDEX
- return SNMP_DEFAULT_ERRINDEX;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_ERRSTAT"))
-#ifdef SNMP_DEFAULT_ERRSTAT
- return SNMP_DEFAULT_ERRSTAT;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_PEERNAME"))
-#ifdef SNMP_DEFAULT_PEERNAME
- return 0;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_REMPORT"))
-#ifdef SNMP_DEFAULT_REMPORT
- return SNMP_DEFAULT_REMPORT;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_REQID"))
-#ifdef SNMP_DEFAULT_REQID
- return SNMP_DEFAULT_REQID;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_RETRIES"))
-#ifdef SNMP_DEFAULT_RETRIES
- return SNMP_DEFAULT_RETRIES;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_TIME"))
-#ifdef SNMP_DEFAULT_TIME
- return SNMP_DEFAULT_TIME;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_TIMEOUT"))
-#ifdef SNMP_DEFAULT_TIMEOUT
- return SNMP_DEFAULT_TIMEOUT;
-#else
- goto not_there;
-#endif
- if (strEQ(name, "SNMP_DEFAULT_VERSION"))
-#ifdef DEFAULT_SNMP_VERSION
- return DEFAULT_SNMP_VERSION;
-#else
-#ifdef SNMP_DEFAULT_VERSION
- return SNMP_DEFAULT_VERSION;
-#else
- goto not_there;
-#endif
-#endif
- break;
- case 'T':
- if (strEQ(name, "NETSNMP_CALLBACK_OP_TIMED_OUT"))
-#ifdef NETSNMP_CALLBACK_OP_TIMED_OUT
- return NETSNMP_CALLBACK_OP_TIMED_OUT;
-#else
- goto not_there;
-#endif
- break;
- default:
- break;
- }
- errno = EINVAL;
- return 0;
-
-#ifndef NETSNMP_CALLBACK_OP_TIMED_OUT
-not_there:
-#endif
- errno = ENOENT;
- return 0;
-}
-
-
-MODULE = SNMP PACKAGE = SNMP PREFIX = snmp
-
-BOOT:
-# first blank line terminates bootstrap code
- Mib = 0;
-
-
-double
-constant(name,arg)
- char * name
- int arg
-
-long
-snmp_sys_uptime()
- CODE:
- RETVAL = get_uptime();
- OUTPUT:
- RETVAL
-
-void
-init_snmp(appname)
- char *appname
- CODE:
- __libraries_init(appname);
-
-
-SnmpSession *
-snmp_new_session(version, community, peer, lport, retries, timeout)
- char * version
- char * community
- char * peer
- int lport
- int retries
- int timeout
- CODE:
- {
- SnmpSession session = {0};
- SnmpSession *ss = NULL;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- __libraries_init("perl");
-
- if (!strcmp(version, "1")) {
- session.version = SNMP_VERSION_1;
- } else if ((!strcmp(version, "2")) || (!strcmp(version, "2c"))) {
- session.version = SNMP_VERSION_2c;
- } else if (!strcmp(version, "3")) {
- session.version = SNMP_VERSION_3;
- } else {
- if (verbose)
- warn("error:snmp_new_session:Unsupported SNMP version (%s)\n", version);
- goto end;
- }
-
- session.community_len = strlen((char *)community);
- session.community = (u_char *)community;
- session.peername = peer;
- session.local_port = lport;
- session.retries = retries; /* 5 */
- session.timeout = timeout; /* 1000000L */
- session.authenticator = NULL;
-
- ss = snmp_open(&session);
-
- if (ss == NULL) {
- if (verbose) warn("error:snmp_new_session: Couldn't open SNMP session");
- }
- end:
- RETVAL = ss;
- }
- OUTPUT:
- RETVAL
-
-SnmpSession *
-snmp_new_v3_session(version, peer, retries, timeout, sec_name, sec_level, sec_eng_id, context_eng_id, context, auth_proto, auth_pass, priv_proto, priv_pass, eng_boots, eng_time)
- int version
- char * peer
- int retries
- int timeout
- char * sec_name
- int sec_level
- char * sec_eng_id
- char * context_eng_id
- char * context
- char * auth_proto
- char * auth_pass
- char * priv_proto
- char * priv_pass
- int eng_boots
- int eng_time
- CODE:
- {
-/* u_char sec_eng_id_buf[ENG_ID_BUF_SIZE]; */
-/* u_char context_eng_id_buf[ENG_ID_BUF_SIZE]; */
- SnmpSession session = {0};
- SnmpSession *ss = NULL;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- __libraries_init("perl");
-
- if (version == 3) {
- session.version = SNMP_VERSION_3;
- } else {
- if (verbose)
- warn("error:snmp_new_v3_session:Unsupported SNMP version (%d)\n", version);
- goto end;
- }
-
- session.peername = strdup(peer);
- session.retries = retries; /* 5 */
- session.timeout = timeout; /* 1000000L */
- session.authenticator = NULL;
- session.contextNameLen = strlen(context);
- session.contextName = context;
- session.securityNameLen = strlen(sec_name);
- session.securityName = sec_name;
- session.securityLevel = sec_level;
- session.securityModel = USM_SEC_MODEL_NUMBER;
- /* session.securityEngineID = sec_eng_id_buf;*/
- session.securityEngineIDLen =
- hex_to_binary2(sec_eng_id, strlen(sec_eng_id),
- (char **) &session.securityEngineID);
- /* session.contextEngineID = context_eng_id_buf; */
- session.contextEngineIDLen =
- hex_to_binary2(sec_eng_id, strlen(sec_eng_id),
- (char **) &session.contextEngineID);
- session.engineBoots = eng_boots;
- session.engineTime = eng_time;
- if (!strcmp(auth_proto, "MD5")) {
- session.securityAuthProto =
- snmp_duplicate_objid(usmHMACMD5AuthProtocol,
- USM_AUTH_PROTO_MD5_LEN);
- session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
- } else if (!strcmp(auth_proto, "SHA")) {
- session.securityAuthProto =
- snmp_duplicate_objid(usmHMACSHA1AuthProtocol,
- USM_AUTH_PROTO_SHA_LEN);
- session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
- } else {
- if (verbose)
- warn("error:snmp_new_v3_session:Unsupported authentication protocol(%s)\n", auth_proto);
- goto end;
- }
- if (session.securityLevel >= SNMP_SEC_LEVEL_AUTHNOPRIV) {
- session.securityAuthKeyLen = USM_AUTH_KU_LEN;
- if (generate_Ku(session.securityAuthProto,
- session.securityAuthProtoLen,
- (u_char *)auth_pass, strlen(auth_pass),
- session.securityAuthKey,
- &session.securityAuthKeyLen) != SNMPERR_SUCCESS) {
- if (verbose)
- warn("error:snmp_new_v3_session:Error generating Ku from authentication password.\n");
- goto end;
- }
- }
- if (!strcmp(priv_proto, "DES")) {
- session.securityPrivProto =
- snmp_duplicate_objid(usmDESPrivProtocol,
- USM_PRIV_PROTO_DES_LEN);
- session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
- } else {
- if (verbose)
- warn("error:snmp_new_v3_session:Unsupported privacy protocol(%s)\n", priv_proto);
- goto end;
- }
- if (session.securityLevel >= SNMP_SEC_LEVEL_AUTHPRIV) {
- session.securityPrivKeyLen = USM_PRIV_KU_LEN;
- if (generate_Ku(session.securityAuthProto,
- session.securityAuthProtoLen,
- (u_char *)priv_pass, strlen(priv_pass),
- session.securityPrivKey,
- &session.securityPrivKeyLen) != SNMPERR_SUCCESS) {
- if (verbose)
- warn("error:snmp_new_v3_session:Error generating Ku from privacy pass phrase.\n");
- goto end;
- }
- }
-
- ss = snmp_open(&session);
-
- if (ss == NULL) {
- if (verbose) warn("error:snmp_new_v3_session:Couldn't open SNMP session");
- }
- end:
- RETVAL = ss;
- free (session.contextEngineID);
- }
- OUTPUT:
- RETVAL
-
-
-SnmpSession *
-snmp_update_session(sess_ref, version, community, peer, lport, retries, timeout)
- SV * sess_ref
- char * version
- char * community
- char * peer
- int lport
- int retries
- int timeout
- CODE:
- {
- SV **sess_ptr_sv;
- SnmpSession *ss;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
-
- if (!ss) goto update_end;
-
- if (!strcmp(version, "1")) {
- ss->version = SNMP_VERSION_1;
- } else if (!strcmp(version, "2") || !strcmp(version, "2c")) {
- ss->version = SNMP_VERSION_2c;
- } else if (!strcmp(version, "3")) {
- ss->version = SNMP_VERSION_3;
- } else {
- if (verbose)
- warn("Unsupported SNMP version (%s)\n", version);
- goto update_end;
- }
- /* WARNING LEAKAGE but I cant free lib memory under win32 */
- ss->community_len = strlen((char *)community);
- ss->community = (u_char *)strdup(community);
- ss->peername = strdup(peer);
- ss->local_port = lport;
- ss->retries = retries; /* 5 */
- ss->timeout = timeout; /* 1000000L */
- ss->authenticator = NULL;
-
- update_end:
- RETVAL = ss;
- }
- OUTPUT:
- RETVAL
-
-int
-snmp_add_mib_dir(mib_dir,force=0)
- char * mib_dir
- int force
- CODE:
- {
- int result = 0; /* Avoid use of uninitialized variable below. */
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- if (mib_dir && *mib_dir) {
- result = add_mibdir(mib_dir);
- }
- if (result) {
- if (verbose) warn("Added mib dir %s\n", mib_dir);
- } else {
- if (verbose) warn("Failed to add %s\n", mib_dir);
- }
- RETVAL = (I32)result;
- }
- OUTPUT:
- RETVAL
-
-void
-snmp_init_mib_internals()
- CODE:
- {
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- /* should test better to see if it has been done already */
- if (Mib == NULL) {
- if (verbose) warn("initializing MIB internals (empty)\n");
- /* init_mib_internals(); */
- }
- }
-
-
-int
-snmp_read_mib(mib_file, force=0)
- char * mib_file
- int force
- CODE:
- {
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- /* if (Mib && force) __free_tree(Mib); needs more work to cleanup */
-
- if ((mib_file == NULL) || (*mib_file == '\0')) {
- if (Mib == NULL) {
- if (verbose) warn("initializing MIB\n");
- /* init_mib_internals(); */
- init_mib();
- if (Mib) {
- if (verbose) warn("done\n");
- } else {
- if (verbose) warn("failed\n");
- }
- }
- } else {
- if (verbose) warn("reading MIB: %s [%s:%s]\n", mib_file, DEFAULT_MIBDIRS, DEFAULT_MIBS);
- /* if (Mib == NULL) init_mib_internals();*/
- if (strcmp("ALL",mib_file))
- read_mib(mib_file);
- else
- read_all_mibs();
- if (Mib) {
- if (verbose) warn("done\n");
- } else {
- if (verbose) warn("failed\n");
- }
- }
- RETVAL = (I32)Mib;
- }
- OUTPUT:
- RETVAL
-
-
-int
-snmp_read_module(module)
- char * module
- CODE:
- {
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- if (!strcmp(module,"ALL")) {
- read_all_mibs();
- } else {
- read_module(module);
- }
- if (Mib) {
- if (verbose) warn("Read %s\n", module);
- } else {
- if (verbose) warn("Failed reading %s\n", module);
- }
- RETVAL = (I32)Mib;
- }
- OUTPUT:
- RETVAL
-
-
-int
-snmp_set(sess_ref, varlist_ref, perl_callback)
- SV * sess_ref
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- SV **varbind_val_f;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- SnmpSession *ss;
- netsnmp_pdu *pdu, *response;
- struct tree *tp;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- char *tag_pv;
- snmp_xs_cb_data *xs_cb_data;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int status = 0;
- int type;
- int res;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int use_enums;
- struct enum_list *ep;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- use_enums = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums",8,1));
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- pdu = snmp_pdu_create(SNMP_MSG_SET);
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
- tag_pv = __av_elem_pv(varbind, VARBIND_TAG_F,NULL);
- tp=__tag2oid(tag_pv,
- __av_elem_pv(varbind, VARBIND_IID_F,NULL),
- oid_arr, &oid_arr_len, &type,0);
-
- if (oid_arr_len==0) {
- if (verbose)
- warn("error: set: unknown object ID (%s)",
- (tag_pv?tag_pv:"<null>"));
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- XPUSHs(&sv_undef); /* unknown OID */
- snmp_free_pdu(pdu);
- goto done;
- }
-
-
- if (type == TYPE_UNKNOWN) {
- type = __translate_appl_type(
- __av_elem_pv(varbind, VARBIND_TYPE_F, NULL));
- if (type == TYPE_UNKNOWN) {
- if (verbose)
- warn("error: set: no type found for object");
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_VAR_TYPE));
- sv_setiv(*err_num_svp, SNMPERR_VAR_TYPE);
- XPUSHs(&sv_undef); /* unknown OID */
- snmp_free_pdu(pdu);
- goto done;
- }
- }
-
- varbind_val_f = av_fetch(varbind, VARBIND_VAL_F, 0);
-
- if (type==TYPE_INTEGER && use_enums && tp && tp->enums) {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (varbind_val_f && SvOK(*varbind_val_f) &&
- !strcmp(ep->label, SvPV(*varbind_val_f,na))) {
- sv_setiv(*varbind_val_f, ep->value);
- break;
- }
- }
- }
-
- res = __add_var_val_str(pdu, oid_arr, oid_arr_len,
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvPV(*varbind_val_f,na):NULL),
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvCUR(*varbind_val_f):0), type);
-
- if (verbose && res == FAILURE)
- warn("error: adding variable/value to PDU");
- } /* if var_ref is ok */
- } /* for all the vars */
-
- if (SvTRUE(perl_callback)) {
- xs_cb_data =
- (snmp_xs_cb_data*)malloc(sizeof(snmp_xs_cb_data));
- xs_cb_data->perl_cb = newSVsv(perl_callback);
- xs_cb_data->sess_ref = newRV_inc(SvRV(sess_ref));
-
- status = snmp_async_send(ss, pdu, __snmp_xs_cb,
- (void*)xs_cb_data);
- if (status != 0) {
- XPUSHs(sv_2mortal(newSViv(status))); /* push the reqid?? */
- } else {
- snmp_free_pdu(pdu);
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- XPUSHs(&sv_undef);
- }
- goto done;
- }
-
- status = __send_sync_pdu(ss, pdu, &response,
- NO_RETRY_NOSUCH,
- *err_str_svp, *err_num_svp,
- *err_ind_svp);
-
- if (response) snmp_free_pdu(response);
-
- if (status) {
- XPUSHs(&sv_undef);
- } else {
- XPUSHs(sv_2mortal(newSVpv(ZERO_BUT_TRUE,0)));
- }
- } else {
-
- /* BUG!!! need to return an error value */
- XPUSHs(&sv_undef); /* no mem or bad args */
- }
-done:
- Safefree(oid_arr);
- }
-
-void
-snmp_catch(sess_ref, perl_callback)
- SV * sess_ref
- SV * perl_callback
- PPCODE:
- {
- netsnmp_session *ss;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
-
- if (SvROK(sess_ref)) {
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- snmp_synch_reset(ss);
- ss->callback = NULL;
- ss->callback_magic = NULL;
-
- if (SvTRUE(perl_callback)) {
- perl_callback = newSVsv(perl_callback);
- # it might be more efficient to pass the varbind_ref to
- # __snmp_xs_cb as part of perl_callback so it is not freed
- # and reconstructed for each call
- ss->callback = __callback_wrapper;
- ss->callback_magic = perl_callback;
- sv_2mortal(newSViv(1));
- goto done;
- }
- }
- sv_2mortal(newSViv(0));
- done:
- ;
- }
-
-void
-snmp_get(sess_ref, retry_nosuch, varlist_ref, perl_callback)
- SV * sess_ref
- int retry_nosuch
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- netsnmp_session *ss;
- netsnmp_pdu *pdu, *response;
- netsnmp_variable_list *vars;
- netsnmp_variable_list *last_vars;
- struct tree *tp;
- int len;
- oid *oid_arr = NULL;
- int oid_arr_len = MAX_OID_LEN;
- SV *tmp_sv;
- char *tag_pv;
- int type;
- char tmp_type_str[MAX_TYPE_NAME_LEN];
- char str_buf[STR_BUF_SIZE];
- snmp_xs_cb_data *xs_cb_data;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int status;
- int sprintval_flag = USE_BASIC;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- SV *sv_timestamp = NULL;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums", 8, 1)))
- sprintval_flag = USE_ENUMS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseSprintValue", 14, 1)))
- sprintval_flag = USE_SPRINT_VALUE;
-
- pdu = snmp_pdu_create(SNMP_MSG_GET);
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
- tag_pv = __av_elem_pv(varbind, VARBIND_TAG_F,NULL);
- tp = __tag2oid(tag_pv,
- __av_elem_pv(varbind, VARBIND_IID_F,NULL),
- oid_arr, &oid_arr_len, NULL,0);
-
- if (oid_arr_len) {
- snmp_add_null_var(pdu, oid_arr, oid_arr_len);
- } else {
- if (verbose)
- warn("error: get: unknown object ID (%s)",
- (tag_pv?tag_pv:"<null>"));
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- XPUSHs(&sv_undef); /* unknown OID */
- snmp_free_pdu(pdu);
- goto done;
- }
- } /* if var_ref is ok */
- } /* for all the vars */
-
- if (perl_callback && SvTRUE(perl_callback)) {
- xs_cb_data =
- (snmp_xs_cb_data*)malloc(sizeof(snmp_xs_cb_data));
- xs_cb_data->perl_cb = newSVsv(perl_callback);
- xs_cb_data->sess_ref = newSVsv(sess_ref);
-
- status = snmp_async_send(ss, pdu, __snmp_xs_cb,
- (void*)xs_cb_data);
- if (status != 0) {
- XPUSHs(sv_2mortal(newSViv(status))); /* push the reqid?? */
- } else {
- snmp_free_pdu(pdu);
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- XPUSHs(&sv_undef);
- }
- goto done;
- }
-
- status = __send_sync_pdu(ss, pdu, &response, retry_nosuch,
- *err_str_svp,*err_num_svp,*err_ind_svp);
-
- last_vars = (response ? response->variables : NULL);
-
- if (SvIOK(*hv_fetch((HV*)SvRV(sess_ref),"TimeStamp", 9, 1)) &&
- SvIV(*hv_fetch((HV*)SvRV(sess_ref),"TimeStamp", 9, 1)))
- sv_timestamp = newSViv((IV)time(NULL));
-
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- tp=__tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F,NULL),
- __av_elem_pv(varbind, VARBIND_IID_F,NULL),
- oid_arr, &oid_arr_len, &type,0);
-
- for (vars = last_vars; vars; vars=vars->next_variable) {
- if (__oid_cmp(oid_arr, oid_arr_len, vars->name,
- vars->name_length) == 0) {
- if (type == TYPE_UNKNOWN)
- type = __translate_asn_type(vars->type);
- last_vars = vars->next_variable;
- break;
- }
- }
- if (vars) {
- __get_type_str(type, tmp_type_str);
- tmp_sv = newSVpv(tmp_type_str,strlen(tmp_type_str));
- av_store(varbind, VARBIND_TYPE_F, tmp_sv);
- len=__snprint_value(str_buf,sizeof(str_buf),
- vars,tp,type,sprintval_flag);
- tmp_sv=newSVpv((char*)str_buf, len);
- av_store(varbind, VARBIND_VAL_F, tmp_sv);
- if (sv_timestamp)
- av_store(varbind, VARBIND_TYPE_F, sv_timestamp);
- XPUSHs(sv_mortalcopy(tmp_sv));
- } else {
- av_store(varbind, VARBIND_VAL_F, &sv_undef);
- av_store(varbind, VARBIND_TYPE_F, &sv_undef);
- XPUSHs(&sv_undef);
- }
- }
- }
- if (response) snmp_free_pdu(response);
- } else {
- XPUSHs(&sv_undef); /* no mem or bad args */
- }
- done:
- Safefree(oid_arr);
- }
-
-int
-snmp_getnext(sess_ref, varlist_ref, perl_callback)
- SV * sess_ref
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- netsnmp_session *ss;
- netsnmp_pdu *pdu, *response;
- netsnmp_variable_list *vars;
- struct tree *tp;
- int len;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- SV *tmp_sv;
- int type;
- char tmp_type_str[MAX_TYPE_NAME_LEN];
- snmp_xs_cb_data *xs_cb_data;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int status;
- u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf;
- size_t str_buf_len = sizeof(str_buf);
- size_t out_len = 0;
- int buf_over = 0;
- char *label;
- char *iid;
- int getlabel_flag = NO_FLAGS;
- int sprintval_flag = USE_BASIC;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int old_numeric, old_printfull; /* Old values of globals */
- SV *sv_timestamp = NULL;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1)))
- getlabel_flag |= USE_LONG_NAMES;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums", 8, 1)))
- sprintval_flag = USE_ENUMS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseSprintValue", 14, 1)))
- sprintval_flag = USE_SPRINT_VALUE;
-
- pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- tp = __tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F, ".0"),
- __av_elem_pv(varbind, VARBIND_IID_F, NULL),
- oid_arr, &oid_arr_len, NULL,0);
-
- if (oid_arr_len) {
- snmp_add_null_var(pdu, oid_arr, oid_arr_len);
- } else {
- if (verbose)
- warn("error: set: unknown object ID");
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- XPUSHs(&sv_undef); /* unknown OID */
- snmp_free_pdu(pdu);
- goto done;
- }
-
- } /* if var_ref is ok */
- } /* for all the vars */
-
- if (SvTRUE(perl_callback)) {
- xs_cb_data =
- (snmp_xs_cb_data*)malloc(sizeof(snmp_xs_cb_data));
- xs_cb_data->perl_cb = newSVsv(perl_callback);
- xs_cb_data->sess_ref = newSVsv(sess_ref);
-
- status = snmp_async_send(ss, pdu, __snmp_xs_cb,
- (void*)xs_cb_data);
- if (status != 0) {
- XPUSHs(sv_2mortal(newSViv(status))); /* push the reqid?? */
- } else {
- snmp_free_pdu(pdu);
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- XPUSHs(&sv_undef);
- }
- goto done;
- }
-
- status = __send_sync_pdu(ss, pdu, &response,
- NO_RETRY_NOSUCH,
- *err_str_svp, *err_num_svp,
- *err_ind_svp);
-
- /*
- ** Set up for numeric OID's, if necessary. Save the old values
- ** so that they can be restored when we finish -- these are
- ** library-wide globals, and have to be set/restored for each
- ** session.
- */
- old_numeric = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS);
- old_printfull = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRINT_FULL_OID);
-
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
- getlabel_flag |= USE_NUMERIC_OIDS;
-
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1);
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1);
- }
-
- if (SvIOK(*hv_fetch((HV*)SvRV(sess_ref),"TimeStamp", 9, 1)) &&
- SvIV(*hv_fetch((HV*)SvRV(sess_ref),"TimeStamp", 9, 1)))
- sv_timestamp = newSViv((IV)time(NULL));
-
- for(vars = (response?response->variables:NULL), varlist_ind = 0;
- vars && (varlist_ind <= varlist_len);
- vars = vars->next_variable, varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- *str_buf = '.';
- *(str_buf+1) = '\0';
- out_len = 0;
- tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len,
- &out_len, 0, &buf_over,
- vars->name,vars->name_length);
- str_buf[sizeof(str_buf)-1] = '\0';
-
- if (__is_leaf(tp)) {
- type = tp->type;
- } else {
- getlabel_flag |= NON_LEAF_NAME;
- type = __translate_asn_type(vars->type);
- }
- __get_label_iid(str_buf,&label,&iid,getlabel_flag);
- if (label) {
- av_store(varbind, VARBIND_TAG_F,
- newSVpv(label, strlen(label)));
- } else {
- av_store(varbind, VARBIND_TAG_F,
- newSVpv("", 0));
- }
- if (iid) {
- av_store(varbind, VARBIND_IID_F,
- newSVpv(iid, strlen(iid)));
- } else {
- av_store(varbind, VARBIND_IID_F,
- newSVpv("", 0));
- }
- __get_type_str(type, tmp_type_str);
- tmp_sv = newSVpv(tmp_type_str, strlen(tmp_type_str));
- av_store(varbind, VARBIND_TYPE_F, tmp_sv);
- len=__snprint_value(str_buf,sizeof(str_buf),
- vars,tp,type,sprintval_flag);
- tmp_sv = newSVpv((char*)str_buf, len);
- av_store(varbind, VARBIND_VAL_F, tmp_sv);
- if (sv_timestamp)
- av_store(varbind, VARBIND_TYPE_F, sv_timestamp);
- XPUSHs(sv_mortalcopy(tmp_sv));
- } else {
- /* Return undef for this variable. */
- XPUSHs(&sv_undef);
- }
- }
-
- /* Reset the library's behavior for numeric/symbolic OID's. */
- if (getlabel_flag & USE_NUMERIC_OIDS) {
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS,
- old_numeric );
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID,
- old_printfull);
- }
-
- if (response) snmp_free_pdu(response);
-
- } else {
- XPUSHs(&sv_undef); /* no mem or bad args */
- }
-done:
- Safefree(oid_arr);
- }
-
-int
-snmp_getbulk(sess_ref, nonrepeaters, maxrepetitions, varlist_ref, perl_callback)
- SV * sess_ref
- int nonrepeaters
- int maxrepetitions
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- netsnmp_session *ss;
- netsnmp_pdu *pdu, *response;
- netsnmp_variable_list *vars;
- struct tree *tp;
- int len;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- SV *tmp_sv;
- int type;
- char tmp_type_str[MAX_TYPE_NAME_LEN];
- snmp_xs_cb_data *xs_cb_data;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int status;
- u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf;
- size_t str_buf_len = sizeof(str_buf);
- size_t out_len = 0;
- int buf_over = 0;
- char *label;
- char *iid;
- int getlabel_flag = NO_FLAGS;
- int sprintval_flag = USE_BASIC;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int old_numeric, old_printfull; /* Old values of globals */
- SV *rv;
- SV *sv_timestamp = NULL;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1)))
- getlabel_flag |= USE_LONG_NAMES;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1)))
- getlabel_flag |= USE_NUMERIC_OIDS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums", 8, 1)))
- sprintval_flag = USE_ENUMS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseSprintValue", 14, 1)))
- sprintval_flag = USE_SPRINT_VALUE;
-
- pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
-
- pdu->errstat = nonrepeaters;
- pdu->errindex = maxrepetitions;
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
- __tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F, "0"),
- __av_elem_pv(varbind, VARBIND_IID_F, NULL),
- oid_arr, &oid_arr_len, NULL,0);
-
-
- if (oid_arr_len) {
- snmp_add_null_var(pdu, oid_arr, oid_arr_len);
- } else {
- if (verbose)
- warn("error: set: unknown object ID");
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- XPUSHs(&sv_undef); /* unknown OID */
- snmp_free_pdu(pdu);
- goto done;
- }
-
-
- } /* if var_ref is ok */
- } /* for all the vars */
-
- if (SvTRUE(perl_callback)) {
- xs_cb_data =
- (snmp_xs_cb_data*)malloc(sizeof(snmp_xs_cb_data));
- xs_cb_data->perl_cb = newSVsv(perl_callback);
- xs_cb_data->sess_ref = newSVsv(sess_ref);
-
- status = snmp_async_send(ss, pdu, __snmp_xs_cb,
- (void*)xs_cb_data);
- if (status != 0) {
- XPUSHs(sv_2mortal(newSViv(status))); /* push the reqid?? */
- } else {
- snmp_free_pdu(pdu);
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- XPUSHs(&sv_undef);
- }
- goto done;
- }
-
- status = __send_sync_pdu(ss, pdu, &response,
- NO_RETRY_NOSUCH,
- *err_str_svp, *err_num_svp,
- *err_ind_svp);
-
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"TimeStamp", 9, 1)))
- sv_timestamp = newSViv((IV)time(NULL));
-
- av_clear(varlist);
-
- /*
- ** Set up for numeric OID's, if necessary. Save the old values
- ** so that they can be restored when we finish -- these are
- ** library-wide globals, and have to be set/restored for each
- ** session.
- */
- old_numeric = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS);
- old_printfull = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_PRINT_FULL_OID);
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
- getlabel_flag |= USE_NUMERIC_OIDS;
-
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS, 1);
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID, 1);
- }
-
- if(response && response->variables) {
- for(vars = response->variables;
- vars;
- vars = vars->next_variable) {
-
- varbind = (AV*) newAV();
- *str_buf = '.';
- *(str_buf+1) = '\0';
- out_len = 0;
- tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len,
- &out_len, 0, &buf_over,
- vars->name,vars->name_length);
- str_buf[sizeof(str_buf)-1] = '\0';
- if (__is_leaf(tp)) {
- type = tp->type;
- } else {
- getlabel_flag |= NON_LEAF_NAME;
- type = __translate_asn_type(vars->type);
- }
- __get_label_iid(str_buf,&label,&iid,getlabel_flag);
-
- av_store(varbind, VARBIND_TAG_F,
- newSVpv(label, strlen(label)));
- av_store(varbind, VARBIND_IID_F,
- newSVpv(iid, strlen(iid)));
-
- __get_type_str(type, tmp_type_str);
- av_store(varbind, VARBIND_TYPE_F, newSVpv(tmp_type_str,
- strlen(tmp_type_str)));
-
- len=__snprint_value(str_buf,sizeof(str_buf),
- vars,tp,type,sprintval_flag);
- tmp_sv = newSVpv((char*)str_buf, len);
- av_store(varbind, VARBIND_VAL_F, tmp_sv);
- if (sv_timestamp)
- av_store(varbind, VARBIND_TYPE_F, SvREFCNT_inc(sv_timestamp));
-
- rv = newRV_noinc((SV *)varbind);
- sv_bless(rv, gv_stashpv("SNMP::Varbind",0));
- av_push(varlist, rv);
-
- XPUSHs(sv_mortalcopy(tmp_sv));
- }
- } else {
- XPUSHs(&sv_undef);
- }
-
- /* Reset the library's behavior for numeric/symbolic OID's. */
- if (getlabel_flag & USE_NUMERIC_OIDS) {
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS,
- old_numeric );
- netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID,
- old_printfull);
- }
-
- if (response) snmp_free_pdu(response);
-
- } else {
- XPUSHs(&sv_undef); /* no mem or bad args */
- }
-done:
- Safefree(oid_arr);
- }
-
-int
-snmp_bulkwalk(sess_ref, nonrepeaters, maxrepetitions, varlist_ref,perl_callback)
- SV * sess_ref
- int nonrepeaters
- int maxrepetitions
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- netsnmp_session *ss;
- netsnmp_pdu *pdu = NULL;
- oid oid_arr[MAX_OID_LEN];
- int oid_arr_len;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- char str_buf[STR_BUF_SIZE];
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- walk_context *context = NULL; /* Context for this bulkwalk */
- bulktbl *bt_entry; /* Current bulktbl/OID entry */
- int i; /* General purpose iterator */
- int npushed; /* Number of return arrays */
- int okay; /* Did bulkwalk complete okay */
-
- if (!SvROK(sess_ref) || !SvROK(varlist_ref)) {
- if (verbose)
- warn("Bad session or varlist reference!\n");
-
- XSRETURN_UNDEF;
- }
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- /* Create and initialize a new session context for this bulkwalk.
- ** This will be used to carry state between callbacks.
- */
- Newz(0x57616b6c /* "Walk" */, context, 1, walk_context);
- if (context == NULL) {
- sprintf(str_buf, "malloc(context) failed (%s)", strerror(errno));
- sv_setpv(*err_str_svp, str_buf);
- sv_setiv(*err_num_svp, SNMPERR_MALLOC);
- goto err;
- }
-
- /* Store the Perl callback and session reference in the context. */
- context->perl_cb = newSVsv(perl_callback);
- context->sess_ref = newSVsv(sess_ref);
-
- DBPRT(3,("bulkwalk: sess_ref = 0x%p, sess_ptr_sv = 0x%p, ss = 0x%p\n",
- sess_ref, sess_ptr_sv, ss));
-
- context->getlabel_f = NO_FLAGS; /* long/numeric name flags */
- context->sprintval_f = USE_BASIC; /* Don't do fancy printing */
- context->req_oids = NULL; /* List of oid's requested */
- context->repbase = NULL; /* Repeaters in req_oids[] */
- context->reqbase = NULL; /* Ptr to start of requests */
- context->nreq_oids = 0; /* Number of oid's in list */
- context->repeaters = 0; /* Repeater count (see below) */
- context->non_reps = nonrepeaters; /* Non-repeater var count */
- context->max_reps = maxrepetitions; /* Max repetition/var count */
- context->pkts_exch = 0; /* Packets exchanged in walk */
- context->oid_total = 0; /* OID's received during walk */
- context->oid_saved = 0; /* OID's saved as results */
-
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1)))
- context->getlabel_f |= USE_LONG_NAMES;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1)))
- context->getlabel_f |= USE_NUMERIC_OIDS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums", 8, 1)))
- context->sprintval_f = USE_ENUMS;
- if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseSprintValue", 14, 1)))
- context->sprintval_f = USE_SPRINT_VALUE;
-
- /* Set up an array of bulktbl's to hold the original list of
- ** requested OID's. This is used to populate the PDU's with
- ** oid values, to contain/sort the return values, and (through
- ** last_oid/last_len) to determine when the bulkwalk for each
- ** variable has completed.
- */
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist) + 1; /* XXX av_len returns index of
- ** last element not #elements */
-
- Newz(0, context->req_oids, varlist_len, bulktbl);
-
- if (context->req_oids == NULL) {
- sprintf(str_buf, "Newz(req_oids) failed (%s)", strerror(errno));
- if (verbose)
- warn(str_buf);
- sv_setpv(*err_str_svp, str_buf);
- sv_setiv(*err_num_svp, SNMPERR_MALLOC);
- goto err;
- }
-
- /* Walk through the varbind_list, parsing and copying each OID
- ** into a bulktbl slot in the req_oids array. Bail if there's
- ** some error. Create the initial packet to send out, which
- ** includes the non-repeaters.
- */
- DBPRT(1,( "Building request table:\n"));
- for (varlist_ind = 0; varlist_ind < varlist_len; varlist_ind++) {
- /* Get a handle on this entry in the request table. */
- bt_entry = &context->req_oids[context->nreq_oids];
-
- DBPRT(1,( " request %d: ", (int)varlist_ind));
-
- /* Get the request varbind from the varlist, parse it out to
- ** tag and index, and copy it to the req_oid[] array slots.
- */
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (!SvROK(*varbind_ref)) {
- sv_setpv(*err_str_svp, \
- (char*)snmp_api_errstring(SNMPERR_BAD_NAME));
- sv_setiv(*err_num_svp, SNMPERR_BAD_NAME);
- goto err;
- }
-
- varbind = (AV*) SvRV(*varbind_ref);
- __tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F, "0"),
- __av_elem_pv(varbind, VARBIND_IID_F, NULL),
- oid_arr, &oid_arr_len, NULL, 0);
-
- if ((oid_arr_len == 0) || (oid_arr_len > MAX_OID_LEN)) {
- if (verbose)
- warn("error: bulkwalk(): unknown object ID");
- sv_setpv(*err_str_svp, \
- (char*)snmp_api_errstring(SNMPERR_UNKNOWN_OBJID));
- sv_setiv(*err_num_svp, SNMPERR_UNKNOWN_OBJID);
- goto err;
- }
-
- /* Copy the now-parsed OID into the first available slot
- ** in the req_oids[] array. Set both the req_oid (original
- ** request) and the last_oid (last requested/seen oid) to
- ** the initial value. We build packets using last_oid (see
- ** below), so initialize last_oid to the initial request.
- */
- Copy((void *)oid_arr, (void *)bt_entry->req_oid,
- oid_arr_len, oid);
- Copy((void *)oid_arr, (void *)bt_entry->last_oid,
- oid_arr_len, oid);
-
- bt_entry->req_len = oid_arr_len;
- bt_entry->last_len = oid_arr_len;
-
- /* Adjust offset to and count of repeaters. Note non-repeater
- ** OID's in the list, if appropriate.
- */
- if (varlist_ind >= context->non_reps) {
-
- /* Store a pointer to the first repeater value. */
- if (context->repbase == NULL)
- context->repbase = bt_entry;
-
- context->repeaters ++;
-
- } else {
- bt_entry->norepeat = 1;
- DBPRT(1,( "(nonrepeater) "));
- }
-
- /* Initialize the array in which to hold the Varbinds to be
- ** returned for the OID or subtree.
- */
- if ((bt_entry->vars = (AV*) newAV()) == NULL) {
- sv_setpv(*err_str_svp, "newAV() failed: ");
- sv_catpv(*err_str_svp, strerror(errno));
- sv_setiv(*err_num_svp, SNMPERR_MALLOC);
- goto err;
- }
-
- DBPRT(1,( "%s\n", snprint_objid(_debugx, sizeof(_debugx), oid_arr, oid_arr_len)));
-
- context->nreq_oids ++;
- }
-
- /* Keep track of the number of outstanding requests. This lets us
- ** finish processing early if we're done with all requests.
- */
- context->req_remain = context->nreq_oids;
- DBPRT(1,( "Total %d variable requests added\n", context->nreq_oids));
-
- /* If no good variable requests were found, return an error. */
- if (context->nreq_oids == 0) {
- sv_setpv(*err_str_svp, "No variables found in varlist");
- sv_setiv(*err_num_svp, SNMPERR_NO_VARS);
- goto err;
- }
-
- /* Note that this is a good context. This allows later callbacks
- ** to ignore re-sent PDU's that correspond to completed (and hence
- ** destroyed) bulkwalk contexts.
- */
- _context_add(context);
-
- /* For asynchronous bulkwalk requests, all we have to do at this
- ** point is enqueue the asynchronous GETBULK request with our
- ** bulkwalk-specific callback and return. Remember that the
- ** bulkwalk_send_pdu() function returns the reqid cast to an
- ** snmp_pdu pointer, or NULL on failure. Return undef if the
- ** initial send fails; bulkwalk_send_pdu() takes care of setting
- ** the various error values.
- **
- ** From here, the callbacks do all the work, including sending
- ** requests for variables and handling responses. The caller's
- ** callback will be invoked as soon as the walk completes.
- */
- if (SvTRUE(perl_callback)) {
- DBPRT(1,( "Starting asynchronous bulkwalk...\n"));
-
- pdu = _bulkwalk_send_pdu(context);
-
- if (pdu == NULL) {
- DBPRT(1,( "Initial asynchronous send failed...\n"));
- XSRETURN_UNDEF;
- }
-
- /* Sent okay... Return the request ID in 'pdu' as an SvIV. */
- DBPRT(1,( "Okay, request id is %d\n", (int)pdu));
-/* XSRETURN_IV((int)pdu); */
- XPUSHs(sv_2mortal(newSViv((int)pdu)));
- XSRETURN(1);
- }
-
- /* For synchronous bulkwalk, we perform the basic send/receive
- ** iteration right here. Once the walk has been completed, the
- ** bulkwalk_finish() function will push the return values onto
- ** the Perl call stack, and we return.
- */
- DBPRT(1,( "Starting synchronous bulkwalk...\n"));
-
- while (!(okay = _bulkwalk_done(context))) {
-
- /* Send a request for the next batch of variables. */
- DBPRT(1, (DBOUT "Building %s GETBULK bulkwalk PDU (%d)...\n",
- context->pkts_exch ? "next" : "first",
- context->pkts_exch));
- pdu = _bulkwalk_send_pdu(context);
-
- /* If the request failed, consider the walk done. */
- if (pdu == NULL) {
- DBPRT(1,( "bulkwalk_send_pdu() failed!\n"));
- break;
- }
-
- /* Handle the variables in this response packet. Break out
- ** of the loop if an error occurs or no variables are found
- ** in the response.
- */
- if ((i = _bulkwalk_recv_pdu(context, pdu)) <= 0) {
- DBPRT(2,( "bulkwalk_recv_pdu() returned %d (error/empty)\n", i));
- break;
- }
-
- /* Free the returned pdu. Don't bother to do this for the async
- ** case, since the SNMP callback mechanism itself does the free
- ** for us.
- */
- snmp_free_pdu(pdu);
-
- /* And loop. The call to bulkwalk_done() sets the ignore flags
- ** for any completed request subtrees. Next time around, they
- ** won't be added to the request sent to the agent.
- */
- continue;
- }
-
- DBPRT(1, (DBOUT "Bulkwalk done... calling bulkwalk_finish(%s)...\n",
- okay ? "okay" : "error"));
- npushed = _bulkwalk_finish(context, okay);
-
- DBPRT(2,( "Returning %d values on the stack.\n", npushed));
- XSRETURN(npushed);
-
- /* Handle error cases and clean up after ourselves. */
- err:
- if (context->req_oids && context->nreq_oids) {
- bt_entry = context->req_oids;
- for (i = 0; i < context->nreq_oids; i++, bt_entry++)
- av_clear(bt_entry->vars);
- }
- if (context->req_oids)
- Safefree(context->req_oids);
- if (context)
- Safefree(context);
- if (pdu)
- snmp_free_pdu(pdu);
-
- XSRETURN_UNDEF;
- }
-
-
-int
-snmp_trapV1(sess_ref,enterprise,agent,generic,specific,uptime,varlist_ref)
- SV * sess_ref
- char * enterprise
- char * agent
- int generic
- int specific
- long uptime
- SV * varlist_ref
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- SV **varbind_val_f;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- SnmpSession *ss;
- netsnmp_pdu *pdu = NULL;
- struct tree *tp;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int type;
- int res;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int use_enums = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums",8,1));
- struct enum_list *ep;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- pdu = snmp_pdu_create(SNMP_MSG_TRAP);
-
- if (SvROK(varlist_ref)) {
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- tp=__tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F, NULL),
- __av_elem_pv(varbind, VARBIND_IID_F, NULL),
- oid_arr, &oid_arr_len, &type,0);
-
- if (oid_arr_len == 0) {
- if (verbose)
- warn("error:trap: unable to determine oid for object");
- goto err;
- }
-
- if (type == TYPE_UNKNOWN) {
- type = __translate_appl_type(
- __av_elem_pv(varbind, VARBIND_TYPE_F, NULL));
- if (type == TYPE_UNKNOWN) {
- if (verbose)
- warn("error:trap: no type found for object");
- goto err;
- }
- }
-
- varbind_val_f = av_fetch(varbind, VARBIND_VAL_F, 0);
-
- if (type==TYPE_INTEGER && use_enums && tp && tp->enums) {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (varbind_val_f && SvOK(*varbind_val_f) &&
- !strcmp(ep->label, SvPV(*varbind_val_f,na))) {
- sv_setiv(*varbind_val_f, ep->value);
- break;
- }
- }
- }
-
- res = __add_var_val_str(pdu, oid_arr, oid_arr_len,
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvPV(*varbind_val_f,na):NULL),
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvCUR(*varbind_val_f):0),
- type);
-
- if(res == FAILURE) {
- if(verbose) warn("error:trap: adding varbind");
- goto err;
- }
-
- } /* if var_ref is ok */
- } /* for all the vars */
- }
-
- pdu->enterprise = (oid *)malloc( MAX_OID_LEN * sizeof(oid));
- tp = __tag2oid(enterprise,NULL, pdu->enterprise,
- &pdu->enterprise_length, NULL,0);
- if (pdu->enterprise_length == 0) {
- if (verbose) warn("error:trap:invalid enterprise id: %s", enterprise);
- goto err;
- }
- /* If agent is given then set the v1-TRAP specific
- agent-address field to that. Otherwise set it to
- our address. */
- if (agent && strlen(agent)) {
- if (__parse_address(agent) == -1 && verbose) {
- warn("error:trap:invalid agent address: %s", agent);
- goto err;
- } else {
- *((in_addr_t *)pdu->agent_addr) = __parse_address(agent);
- }
- } else {
- *((in_addr_t *)pdu->agent_addr) = get_myaddr();
- }
- pdu->trap_type = generic;
- pdu->specific_type = specific;
- pdu->time = uptime;
-
- if (snmp_send(ss, pdu) == 0) {
- snmp_free_pdu(pdu);
- }
- XPUSHs(sv_2mortal(newSVpv(ZERO_BUT_TRUE,0)));
- } else {
-err:
- XPUSHs(&sv_undef); /* no mem or bad args */
- if (pdu) snmp_free_pdu(pdu);
- }
- Safefree(oid_arr);
- }
-
-
-int
-snmp_trapV2(sess_ref,uptime,trap_oid,varlist_ref)
- SV * sess_ref
- char * uptime
- char * trap_oid
- SV * varlist_ref
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- SV **varbind_val_f;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- SnmpSession *ss;
- netsnmp_pdu *pdu = NULL;
- struct tree *tp;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int type;
- int res;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int use_enums = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums",8,1));
- struct enum_list *ep;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- /************************************************/
- res = __add_var_val_str(pdu, sysUpTime, SYS_UPTIME_OID_LEN,
- uptime, strlen(uptime), TYPE_TIMETICKS);
-
- if(res == FAILURE) {
- if(verbose) warn("error:trap v2: adding sysUpTime varbind");
- goto err;
- }
-
- res = __add_var_val_str(pdu, snmpTrapOID, SNMP_TRAP_OID_LEN,
- trap_oid ,strlen(trap_oid) ,TYPE_OBJID);
-
- if(res == FAILURE) {
- if(verbose) warn("error:trap v2: adding snmpTrapOID varbind");
- goto err;
- }
-
-
- /******************************************************/
-
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- tp=__tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F,NULL),
- __av_elem_pv(varbind, VARBIND_IID_F,NULL),
- oid_arr, &oid_arr_len, &type,0);
-
- if (oid_arr_len == 0) {
- if (verbose)
- warn("error:trap v2: unable to determine oid for object");
- goto err;
- }
-
- if (type == TYPE_UNKNOWN) {
- type = __translate_appl_type(
- __av_elem_pv(varbind, VARBIND_TYPE_F, NULL));
- if (type == TYPE_UNKNOWN) {
- if (verbose)
- warn("error:trap v2: no type found for object");
- goto err;
- }
- }
-
- varbind_val_f = av_fetch(varbind, VARBIND_VAL_F, 0);
-
- if (type==TYPE_INTEGER && use_enums && tp && tp->enums) {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (varbind_val_f && SvOK(*varbind_val_f) &&
- !strcmp(ep->label, SvPV(*varbind_val_f,na))) {
- sv_setiv(*varbind_val_f, ep->value);
- break;
- }
- }
- }
-
- res = __add_var_val_str(pdu, oid_arr, oid_arr_len,
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvPV(*varbind_val_f,na):NULL),
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvCUR(*varbind_val_f):0),
- type);
-
- if(res == FAILURE) {
- if(verbose) warn("error:trap v2: adding varbind");
- goto err;
- }
-
- } /* if var_ref is ok */
- } /* for all the vars */
-
- if (snmp_send(ss, pdu) == 0) {
- snmp_free_pdu(pdu);
- }
-
- XPUSHs(sv_2mortal(newSVpv(ZERO_BUT_TRUE,0)));
- } else {
-err:
- XPUSHs(&sv_undef); /* no mem or bad args */
- if (pdu) snmp_free_pdu(pdu);
- }
- Safefree(oid_arr);
- }
-
-
-
-int
-snmp_inform(sess_ref,uptime,trap_oid,varlist_ref,perl_callback)
- SV * sess_ref
- char * uptime
- char * trap_oid
- SV * varlist_ref
- SV * perl_callback
- PPCODE:
- {
- AV *varlist;
- SV **varbind_ref;
- SV **varbind_val_f;
- AV *varbind;
- I32 varlist_len;
- I32 varlist_ind;
- SnmpSession *ss;
- netsnmp_pdu *pdu = NULL;
- netsnmp_pdu *response;
- struct tree *tp;
- oid *oid_arr;
- int oid_arr_len = MAX_OID_LEN;
- snmp_xs_cb_data *xs_cb_data;
- SV **sess_ptr_sv;
- SV **err_str_svp;
- SV **err_num_svp;
- SV **err_ind_svp;
- int status = 0;
- int type;
- int res;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
- int use_enums = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseEnums",8,1));
- struct enum_list *ep;
-
- New (0, oid_arr, MAX_OID_LEN, oid);
-
- if (oid_arr && SvROK(sess_ref) && SvROK(varlist_ref)) {
-
- sess_ptr_sv = hv_fetch((HV*)SvRV(sess_ref), "SessPtr", 7, 1);
- ss = (SnmpSession *)SvIV((SV*)SvRV(*sess_ptr_sv));
- err_str_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorStr", 8, 1);
- err_num_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorNum", 8, 1);
- err_ind_svp = hv_fetch((HV*)SvRV(sess_ref), "ErrorInd", 8, 1);
- sv_setpv(*err_str_svp, "");
- sv_setiv(*err_num_svp, 0);
- sv_setiv(*err_ind_svp, 0);
-
- pdu = snmp_pdu_create(SNMP_MSG_INFORM);
-
- varlist = (AV*) SvRV(varlist_ref);
- varlist_len = av_len(varlist);
- /************************************************/
- res = __add_var_val_str(pdu, sysUpTime, SYS_UPTIME_OID_LEN,
- uptime, strlen(uptime), TYPE_TIMETICKS);
-
- if(res == FAILURE) {
- if(verbose) warn("error:inform: adding sysUpTime varbind");
- goto err;
- }
-
- res = __add_var_val_str(pdu, snmpTrapOID, SNMP_TRAP_OID_LEN,
- trap_oid ,strlen(trap_oid) ,TYPE_OBJID);
-
- if(res == FAILURE) {
- if(verbose) warn("error:inform: adding snmpTrapOID varbind");
- goto err;
- }
-
-
- /******************************************************/
-
- for(varlist_ind = 0; varlist_ind <= varlist_len; varlist_ind++) {
- varbind_ref = av_fetch(varlist, varlist_ind, 0);
- if (SvROK(*varbind_ref)) {
- varbind = (AV*) SvRV(*varbind_ref);
-
- tp=__tag2oid(__av_elem_pv(varbind, VARBIND_TAG_F,NULL),
- __av_elem_pv(varbind, VARBIND_IID_F,NULL),
- oid_arr, &oid_arr_len, &type,0);
-
- if (oid_arr_len == 0) {
- if (verbose)
- warn("error:inform: unable to determine oid for object");
- goto err;
- }
-
- if (type == TYPE_UNKNOWN) {
- type = __translate_appl_type(
- __av_elem_pv(varbind, VARBIND_TYPE_F, NULL));
- if (type == TYPE_UNKNOWN) {
- if (verbose)
- warn("error:inform: no type found for object");
- goto err;
- }
- }
-
- varbind_val_f = av_fetch(varbind, VARBIND_VAL_F, 0);
-
- if (type==TYPE_INTEGER && use_enums && tp && tp->enums) {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (varbind_val_f && SvOK(*varbind_val_f) &&
- !strcmp(ep->label, SvPV(*varbind_val_f,na))) {
- sv_setiv(*varbind_val_f, ep->value);
- break;
- }
- }
- }
-
- res = __add_var_val_str(pdu, oid_arr, oid_arr_len,
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvPV(*varbind_val_f,na):NULL),
- (varbind_val_f && SvOK(*varbind_val_f) ?
- SvCUR(*varbind_val_f):0),
- type);
-
- if(res == FAILURE) {
- if(verbose) warn("error:inform: adding varbind");
- goto err;
- }
-
- } /* if var_ref is ok */
- } /* for all the vars */
-
-
- if (SvTRUE(perl_callback)) {
- xs_cb_data =
- (snmp_xs_cb_data*)malloc(sizeof(snmp_xs_cb_data));
- xs_cb_data->perl_cb = newSVsv(perl_callback);
- xs_cb_data->sess_ref = newRV_inc(SvRV(sess_ref));
-
- status = snmp_async_send(ss, pdu, __snmp_xs_cb,
- (void*)xs_cb_data);
- if (status != 0) {
- XPUSHs(sv_2mortal(newSViv(status))); /* push the reqid?? */
- } else {
- snmp_free_pdu(pdu);
- sv_catpv(*err_str_svp,
- (char*)snmp_api_errstring(ss->s_snmp_errno));
- sv_setiv(*err_num_svp, ss->s_snmp_errno);
- XPUSHs(&sv_undef);
- }
- goto done;
- }
-
- status = __send_sync_pdu(ss, pdu, &response,
- NO_RETRY_NOSUCH,
- *err_str_svp, *err_num_svp,
- *err_ind_svp);
-
- if (response) snmp_free_pdu(response);
-
- if (status) {
- XPUSHs(&sv_undef);
- } else {
- XPUSHs(sv_2mortal(newSVpv(ZERO_BUT_TRUE,0)));
- }
- } else {
-err:
- XPUSHs(&sv_undef); /* no mem or bad args */
- if (pdu) snmp_free_pdu(pdu);
- }
-done:
- Safefree(oid_arr);
- }
-
-
-
-char *
-snmp_get_type(tag)
- char * tag
- CODE:
- {
- struct tree *tp = NULL;
- static char type_str[MAX_TYPE_NAME_LEN];
- char *ret = NULL;
-
- if (tag && *tag) tp = __tag2oid(tag, NULL, NULL, NULL, NULL,0);
- if (tp) __get_type_str(tp->type, ret = type_str);
- RETVAL = ret;
- }
- OUTPUT:
- RETVAL
-
-
-void
-snmp_dump_packet(flag)
- int flag
- CODE:
- {
- snmp_set_dump_packet(flag);
- }
-
-
-char *
-snmp_map_enum(tag, val, iflag)
- char * tag
- char * val
- int iflag
- CODE:
- {
- struct tree *tp = NULL;
- struct enum_list *ep;
- char str_buf[STR_BUF_SIZE];
- int ival;
-
- RETVAL = NULL;
-
- if (tag && *tag) tp = __tag2oid(tag, NULL, NULL, NULL, NULL,0);
-
- if (tp) {
- if (iflag) {
- ival = atoi(val);
- for(ep = tp->enums; ep; ep = ep->next) {
- if (ep->value == ival) {
- RETVAL = ep->label;
- break;
- }
- }
- } else {
- for(ep = tp->enums; ep; ep = ep->next) {
- if (strEQ(ep->label, val)) {
- sprintf(str_buf,"%d", ep->value);
- RETVAL = str_buf;
- break;
- }
- }
- }
- }
- }
- OUTPUT:
- RETVAL
-
-#define SNMP_XLATE_MODE_OID2TAG 1
-#define SNMP_XLATE_MODE_TAG2OID 0
-
-char *
-snmp_translate_obj(var,mode,use_long,auto_init,best_guess)
- char * var
- int mode
- int use_long
- int auto_init
- int best_guess
- CODE:
- {
- char str_buf[STR_BUF_SIZE];
- oid oid_arr[MAX_OID_LEN];
- int oid_arr_len = MAX_OID_LEN;
- char * label;
- char * iid;
- int status = FAILURE;
- int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
-
- str_buf[0] = '\0';
- switch (mode) {
- case SNMP_XLATE_MODE_TAG2OID:
- if (!__tag2oid(var, NULL, oid_arr, &oid_arr_len, NULL, best_guess)) {
- if (verbose) warn("error:snmp_translate_obj:Unknown OID %s\n",var);
- } else {
- status = __sprint_num_objid(str_buf, oid_arr, oid_arr_len);
- }
- break;
- case SNMP_XLATE_MODE_OID2TAG:
- oid_arr_len = 0;
- __concat_oid_str(oid_arr, &oid_arr_len, var);
- snprint_objid(str_buf, sizeof(str_buf), oid_arr, oid_arr_len);
- if (!use_long) {
- label = NULL; iid = NULL;
- if (((status=__get_label_iid(str_buf,
- &label, &iid, NO_FLAGS)) == SUCCESS)
- && label) {
- strcpy(str_buf, label);
- if (iid && *iid) {
- strcat(str_buf, ".");
- strcat(str_buf, iid);
- }
- }
- }
- break;
- default:
- if (verbose) warn("snmp_translate_obj:unknown translation mode: %s\n", mode);
- }
- if (*str_buf) {
- RETVAL = (char*)str_buf;
- } else {
- RETVAL = (char*)NULL;
- }
- }
- OUTPUT:
- RETVAL
-
-void
-snmp_set_replace_newer(val)
- int val
- CODE:
- {
- netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_REPLACE);
- }
-
-void
-snmp_set_save_descriptions(val)
- int val
- CODE:
- {
- snmp_set_save_descriptions(val);
- }
-
-void
-snmp_set_debugging(val)
- int val
- CODE:
- {
- snmp_set_do_debugging(val);
- }
-
-void
-snmp_debug_internals(val)
- int val
- CODE:
- {
-#ifdef DEBUGGING
- _debug_level = val;
-#endif /* DEBUGGING */
- }
-
-
-void
-snmp_sock_cleanup()
- CODE:
- {
- SOCK_CLEANUP;
- }
-
-void
-snmp_mainloop_finish()
- CODE:
- {
- mainloop_finish = 1;
- }
-
-
-void
-snmp_main_loop(timeout_sec,timeout_usec,perl_callback)
- int timeout_sec
- int timeout_usec
- SV * perl_callback
- CODE:
- {
- int numfds, fd_count;
- fd_set fdset;
- struct timeval time_val, *tvp;
- struct timeval last_time, *ltvp;
- struct timeval ctimeout, *ctvp;
- struct timeval interval, *itvp;
- int block;
- SV *cb;
-
-
- mainloop_finish = 0;
-
- itvp = &interval;
- itvp->tv_sec = timeout_sec;
- itvp->tv_usec = timeout_usec;
- ctvp = &ctimeout;
- ctvp->tv_sec = -1;
- ltvp = &last_time;
- gettimeofday(ltvp,(struct timezone*)0);
- timersub(ltvp,itvp,ltvp);
- while (1) {
- numfds = 0;
- FD_ZERO(&fdset);
- block = 1;
- tvp = &time_val;
- timerclear(tvp);
- snmp_select_info(&numfds, &fdset, tvp, &block);
- __recalc_timeout(tvp,ctvp,ltvp,itvp,&block);
- # printf("pre-select: numfds = %ld, block = %ld\n", numfds, block);
- if (block == 1) tvp = NULL; /* block without timeout */
- fd_count = select(numfds, &fdset, 0, 0, tvp);
- #printf("post-select: fd_count = %ld,block = %ld\n",fd_count,block);
- if (fd_count > 0) {
- dSP;
- ENTER;
- SAVETMPS;
- snmp_read(&fdset);
- FREETMPS;
- LEAVE;
-
- } else switch(fd_count) {
- case 0:
- SPAGAIN;
- ENTER;
- SAVETMPS;
- snmp_timeout();
- if (!timerisset(ctvp)) {
- if (SvTRUE(perl_callback)) {
- /* sv_2mortal(perl_callback); */
- cb = __push_cb_args(perl_callback, NULL);
- __call_callback(cb, G_DISCARD);
- ctvp->tv_sec = -1;
-
- } else {
- FREETMPS;
- LEAVE;
- goto done;
- }
- }
- FREETMPS;
- LEAVE;
- break;
- case -1:
- if (errno == EINTR) {
- continue;
- } else {
- /* snmp_set_detail(strerror(errno)); */
- /* snmp_errno = SNMPERR_GENERR; */
- }
- default:;
- }
-
- /* A call to snmp_mainloop_finish() in the callback sets the
- ** mainloop_finish flag. Exit the loop after the callback returns.
- */
- if (mainloop_finish)
- goto done;
-
- }
- done:
- return;
- }
-
-
-void
-snmp_get_select_info()
- PPCODE:
- {
- int numfds;
- fd_set fdset;
- struct timeval time_val, *tvp;
- int block;
- int i;
-
- numfds = 0;
- block = 1;
- tvp = &time_val;
- FD_ZERO(&fdset);
- snmp_select_info(&numfds, &fdset, tvp, &block);
- XPUSHs(sv_2mortal(newSViv(block)));
- if(block){
- XPUSHs(sv_2mortal(newSViv(0)));
- XPUSHs(sv_2mortal(newSViv(0)));
- } else {
- XPUSHs(sv_2mortal(newSViv(tvp->tv_sec)));
- XPUSHs(sv_2mortal(newSViv(tvp->tv_usec)));
- }
- if ( numfds ) {
- for(i=0; i<numfds ; i++) {
- if(FD_ISSET(i, &fdset)){
- XPUSHs(sv_2mortal(newSViv(i)));
- }
- }
- } else {
- XPUSHs(&sv_undef); /* no mem or bad args */
- }
- }
-
-void
-snmp_read_on_fd(fd)
- int fd
- CODE:
- {
- fd_set fdset;
-
- FD_ZERO(&fdset);
- FD_SET(fd, &fdset);
-
- snmp_read(&fdset);
- }
-
-void
-snmp_check_timeout()
- CODE:
- {
- snmp_timeout();
- }
-
-MODULE = SNMP PACKAGE = SNMP::MIB::NODE PREFIX = snmp_mib_node_
-SV *
-snmp_mib_node_TIEHASH(class,key,tp=0)
- char * class
- char * key
- IV tp
- CODE:
- {
- __libraries_init("perl");
- if (!tp) tp = (IV)__tag2oid(key, NULL, NULL, NULL, NULL,0);
- if (tp) {
- ST(0) = sv_newmortal();
- sv_setref_iv(ST(0), class, tp);
- } else {
- ST(0) = &sv_undef;
- }
-
- }
-
-SV *
-snmp_mib_node_FETCH(tp_ref, key)
- SV * tp_ref
- char * key
- CODE:
- {
- char c = *key;
- char str_buf[STR_BUF_SIZE];
- SnmpMibNode *tp = NULL;
- struct index_list *ip;
- struct enum_list *ep;
- struct range_list *rp;
- struct varbind_list *vp;
- struct module *mp;
- SV *child_list_aref, *next_node_href, *mib_tied_href = NULL;
- SV **nn_hrefp;
- HV *mib_hv, *enum_hv, *range_hv;
- AV *index_av, *varbind_av, *ranges_av;
- MAGIC *mg = NULL;
-
- if (SvROK(tp_ref)) tp = (SnmpMibNode*)SvIV((SV*)SvRV(tp_ref));
-
- ST(0) = sv_newmortal();
- if (tp)
- switch (c) {
- case 'a': /* access */
- if (strncmp("access", key, strlen(key))) break;
- switch (tp->access) {
- case MIB_ACCESS_READONLY:
- sv_setpv(ST(0),"ReadOnly");
- break;
- case MIB_ACCESS_READWRITE:
- sv_setpv(ST(0),"ReadWrite");
- break;
- case MIB_ACCESS_WRITEONLY:
- sv_setpv(ST(0),"WriteOnly");
- break;
- case MIB_ACCESS_NOACCESS:
- sv_setpv(ST(0),"NoAccess");
- break;
- case MIB_ACCESS_NOTIFY:
- sv_setpv(ST(0),"Notify");
- break;
- case MIB_ACCESS_CREATE:
- sv_setpv(ST(0),"Create");
- break;
- default:
- break;
- }
- break;
- case 'c': /* children */
- if (strncmp("children", key, strlen(key))) break;
- child_list_aref = newRV((SV*)newAV());
- for (tp = tp->child_list; tp; tp = tp->next_peer) {
- mib_hv = perl_get_hv("SNMP::MIB", FALSE);
- if (SvMAGICAL(mib_hv)) mg = mg_find((SV*)mib_hv, 'P');
- if (mg) mib_tied_href = (SV*)mg->mg_obj;
- next_node_href = newRV((SV*)newHV());
- __tp_sprint_num_objid(str_buf, tp);
- nn_hrefp = hv_fetch((HV*)SvRV(mib_tied_href),
- str_buf, strlen(str_buf), 1);
- if (!SvROK(*nn_hrefp)) {
- sv_setsv(*nn_hrefp, next_node_href);
- ENTER ;
- SAVETMPS ;
- PUSHMARK(sp) ;
- XPUSHs(SvRV(*nn_hrefp));
- XPUSHs(sv_2mortal(newSVpv("SNMP::MIB::NODE",0)));
- XPUSHs(sv_2mortal(newSVpv(str_buf,0)));
- XPUSHs(sv_2mortal(newSViv((IV)tp)));
- PUTBACK ;
- perl_call_pv("SNMP::_tie",G_VOID);
- /* pp_tie(ARGS); */
- SPAGAIN ;
- FREETMPS ;
- LEAVE ;
- } /* if SvROK */
- av_push((AV*)SvRV(child_list_aref), *nn_hrefp);
- } /* for child_list */
- sv_setsv(ST(0), child_list_aref);
- break;
- case 'v':
- if (strncmp("varbinds", key, strlen(key))) break;
- varbind_av = newAV();
- for (vp = tp->varbinds; vp; vp = vp->next) {
- av_push(varbind_av, newSVpv((vp->vblabel),strlen(vp->vblabel)));
- }
- sv_setsv(ST(0), newRV((SV*)varbind_av));
- break;
- case 'd': /* description */
- if (strncmp("description", key, strlen(key))) {
- if(!(strncmp("defaultValue",key,strlen(key)))) {
- /* We're looking at defaultValue */
- sv_setpv(ST(0), tp->defaultValue);
- break;
- } /* end if */
- } /* end if */
- /* we must be looking at description */
- sv_setpv(ST(0),tp->description);
- break;
- case 'i': /* indexes */
- if (strncmp("indexes", key, strlen(key))) break;
- index_av = newAV();
- for(ip=tp->indexes; ip != NULL; ip = ip->next) {
- av_push(index_av,newSVpv((ip->ilabel),strlen(ip->ilabel)));
- }
- sv_setsv(ST(0), newRV((SV*)index_av));
- break;
- case 'l': /* label */
- if (strncmp("label", key, strlen(key))) break;
- sv_setpv(ST(0),tp->label);
- break;
- case 'm': /* moduleID */
- if (strncmp("moduleID", key, strlen(key))) break;
- mp = find_module(tp->modid);
- if (mp) sv_setpv(ST(0), mp->name);
- break;
- case 'n': /* nextNode */
- if (strncmp("nextNode", key, strlen(key))) break;
- tp = __get_next_mib_node(tp);
- if (tp == NULL) {
- sv_setsv(ST(0), &sv_undef);
- break;
- }
- mib_hv = perl_get_hv("SNMP::MIB", FALSE);
- if (SvMAGICAL(mib_hv)) mg = mg_find((SV*)mib_hv, 'P');
- if (mg) mib_tied_href = (SV*)mg->mg_obj;
- __tp_sprint_num_objid(str_buf, tp);
-
- nn_hrefp = hv_fetch((HV*)SvRV(mib_tied_href),
- str_buf, strlen(str_buf), 1);
- /* if (!SvROK(*nn_hrefp)) { */ /* bug in ucd - 2 .0.0 nodes */
- next_node_href = newRV((SV*)newHV());
- sv_setsv(*nn_hrefp, next_node_href);
- ENTER ;
- SAVETMPS ;
- PUSHMARK(sp) ;
- XPUSHs(SvRV(*nn_hrefp));
- XPUSHs(sv_2mortal(newSVpv("SNMP::MIB::NODE",0)));
- XPUSHs(sv_2mortal(newSVpv(str_buf,0)));
- XPUSHs(sv_2mortal(newSViv((IV)tp)));
- PUTBACK ;
- perl_call_pv("SNMP::_tie",G_VOID);
- /* pp_tie(ARGS); */
- SPAGAIN ;
- FREETMPS ;
- LEAVE ;
- /* } */
- sv_setsv(ST(0), *nn_hrefp);
- break;
- case 'o': /* objectID */
- if (strncmp("objectID", key, strlen(key))) break;
- __tp_sprint_num_objid(str_buf, tp);
- sv_setpv(ST(0),str_buf);
- break;
- case 'p': /* parent */
- if (strncmp("parent", key, strlen(key))) break;
- tp = tp->parent;
- if (tp == NULL) {
- sv_setsv(ST(0), &sv_undef);
- break;
- }
- mib_hv = perl_get_hv("SNMP::MIB", FALSE);
- if (SvMAGICAL(mib_hv)) mg = mg_find((SV*)mib_hv, 'P');
- if (mg) mib_tied_href = (SV*)mg->mg_obj;
- next_node_href = newRV((SV*)newHV());
- __tp_sprint_num_objid(str_buf, tp);
- nn_hrefp = hv_fetch((HV*)SvRV(mib_tied_href),
- str_buf, strlen(str_buf), 1);
- if (!SvROK(*nn_hrefp)) {
- sv_setsv(*nn_hrefp, next_node_href);
- ENTER ;
- SAVETMPS ;
- PUSHMARK(sp) ;
- XPUSHs(SvRV(*nn_hrefp));
- XPUSHs(sv_2mortal(newSVpv("SNMP::MIB::NODE",0)));
- XPUSHs(sv_2mortal(newSVpv(str_buf,0)));
- XPUSHs(sv_2mortal(newSViv((IV)tp)));
- PUTBACK ;
- perl_call_pv("SNMP::_tie",G_VOID);
- /* pp_tie(ARGS); */
- SPAGAIN ;
- FREETMPS ;
- LEAVE ;
- }
- sv_setsv(ST(0), *nn_hrefp);
- break;
- case 'r': /* ranges */
- if (strncmp("ranges", key, strlen(key))) break;
- ranges_av = newAV();
- for(rp=tp->ranges; rp ; rp = rp->next) {
- range_hv = newHV();
- hv_store(range_hv, "low", strlen("low"), newSViv(rp->low), 0);
- hv_store(range_hv, "high", strlen("high"), newSViv(rp->high), 0);
- av_push(ranges_av, newRV((SV*)range_hv));
- }
- sv_setsv(ST(0), newRV((SV*)ranges_av));
- break;
- case 's': /* subID */
- if (strncmp("subID", key, strlen(key))) {
- if (strncmp("status", key, strlen(key))) {
- if (strncmp("syntax", key, strlen(key))) break;
- if (tp->tc_index >= 0) {
- sv_setpv(ST(0), get_tc_descriptor(tp->tc_index));
- } else {
- __get_type_str(tp->type, str_buf);
- sv_setpv(ST(0), str_buf);
- }
- break;
- }
-
- switch(tp->status) {
- case MIB_STATUS_MANDATORY:
- sv_setpv(ST(0),"Mandatory");
- break;
- case MIB_STATUS_OPTIONAL:
- sv_setpv(ST(0),"Optional");
- break;
- case MIB_STATUS_OBSOLETE:
- sv_setpv(ST(0),"Obsolete");
- break;
- case MIB_STATUS_DEPRECATED:
- sv_setpv(ST(0),"Deprecated");
- break;
- case MIB_STATUS_CURRENT:
- sv_setpv(ST(0),"Current");
- break;
- default:
- break;
- }
- } else {
- sv_setiv(ST(0),(I32)tp->subid);
- }
- break;
- case 't': /* type */
- if (strncmp("type", key, strlen(key))) {
- if (strncmp("textualConvention", key, strlen(key))) break;
- sv_setpv(ST(0), get_tc_descriptor(tp->tc_index));
- break;
- }
- __get_type_str(tp->type, str_buf);
- sv_setpv(ST(0), str_buf);
- break;
- case 'u': /* units */
- if (strncmp("units", key, strlen(key))) break;
- sv_setpv(ST(0),tp->units);
- break;
- case 'h': /* hint */
- if (strncmp("hint", key, strlen(key))) break;
- sv_setpv(ST(0),tp->hint);
- break;
- case 'e': /* enums */
- if (strncmp("enums", key, strlen(key))) break;
- enum_hv = newHV();
- for(ep=tp->enums; ep != NULL; ep = ep->next) {
- hv_store(enum_hv, ep->label, strlen(ep->label),
- newSViv(ep->value), 0);
- }
- sv_setsv(ST(0), newRV((SV*)enum_hv));
- break;
- default:
- break;
- }
- }
-
-MODULE = SNMP PACKAGE = SnmpSessionPtr PREFIX = snmp_session_
-void
-snmp_session_DESTROY(sess_ptr)
- SnmpSession *sess_ptr
- CODE:
- {
- snmp_close( sess_ptr );
- }
-