summaryrefslogtreecommitdiff
path: root/perl
diff options
context:
space:
mode:
Diffstat (limited to 'perl')
-rw-r--r--perl/ASN/ASN.pm163
-rw-r--r--perl/ASN/ASN.xs177
-rw-r--r--perl/ASN/Changes6
-rw-r--r--perl/ASN/MANIFEST6
-rw-r--r--perl/ASN/Makefile.PL233
-rw-r--r--perl/ASN/netsnmp-feature-definitions.h0
-rw-r--r--perl/ASN/test.pl28
-rw-r--r--perl/AnyData_SNMP/Changes1
-rw-r--r--perl/AnyData_SNMP/DBD_AnyData.patch48
-rw-r--r--perl/AnyData_SNMP/Format.pm109
-rw-r--r--perl/AnyData_SNMP/INSTALL44
-rw-r--r--perl/AnyData_SNMP/MANIFEST7
-rw-r--r--perl/AnyData_SNMP/Makefile.PL14
-rw-r--r--perl/AnyData_SNMP/README21
-rw-r--r--perl/AnyData_SNMP/Storage.pm428
-rw-r--r--perl/AnyData_SNMP/configs/scli27
-rw-r--r--perl/AnyData_SNMP/configs/unix34
-rwxr-xr-xperl/AnyData_SNMP/netsh838
-rw-r--r--perl/Makefile.PL160
-rw-r--r--perl/Makefile.makefiles12
-rw-r--r--perl/Makefile.subs.pl136
-rw-r--r--perl/OID/Changes6
-rw-r--r--perl/OID/MANIFEST7
-rw-r--r--perl/OID/Makefile.PL234
-rw-r--r--perl/OID/OID.pm256
-rw-r--r--perl/OID/OID.xs442
-rw-r--r--perl/OID/README31
-rw-r--r--perl/OID/netsnmp-feature-definitions.h6
-rw-r--r--perl/OID/test.pl137
-rw-r--r--perl/OID/typemap2
-rw-r--r--perl/SNMP/BUG40
-rw-r--r--perl/SNMP/MANIFEST37
-rw-r--r--perl/SNMP/MANIFEST.SKIP11
-rw-r--r--perl/SNMP/Makefile.PL363
-rw-r--r--perl/SNMP/README896
-rw-r--r--perl/SNMP/SNMP.pm2680
-rw-r--r--perl/SNMP/SNMP.xs5473
-rw-r--r--perl/SNMP/TODO40
-rw-r--r--perl/SNMP/examples/async1.pl17
-rw-r--r--perl/SNMP/examples/async2.pl19
-rw-r--r--perl/SNMP/examples/bulkwalk.pl121
-rw-r--r--perl/SNMP/examples/ipforward.pl30
-rw-r--r--perl/SNMP/examples/mibtree.pl20
-rw-r--r--perl/SNMP/examples/mibwalk.pl17
-rwxr-xr-xperl/SNMP/examples/pingmib.pl46
-rw-r--r--perl/SNMP/examples/tablewalk.pl19
-rw-r--r--perl/SNMP/examples/testleak.pl19
-rw-r--r--perl/SNMP/examples/trap-example.pl94
-rw-r--r--perl/SNMP/hints/irix.pl2
-rw-r--r--perl/SNMP/hints/solaris.pl4
-rw-r--r--perl/SNMP/netsnmp-feature-definitions.h8
-rw-r--r--perl/SNMP/perlsnmp.h24
-rw-r--r--perl/SNMP/t/README81
-rw-r--r--perl/SNMP/t/async.t169
-rw-r--r--perl/SNMP/t/bulkwalk.t339
-rw-r--r--perl/SNMP/t/conf.t53
-rw-r--r--perl/SNMP/t/conftest.conf2
-rw-r--r--perl/SNMP/t/get.t216
-rw-r--r--perl/SNMP/t/getnext.t102
-rw-r--r--perl/SNMP/t/mib.t226
-rw-r--r--perl/SNMP/t/mib.txt4208
-rw-r--r--perl/SNMP/t/mibload.t95
-rw-r--r--perl/SNMP/t/notify.t106
-rw-r--r--perl/SNMP/t/session.t76
-rw-r--r--perl/SNMP/t/set.t224
-rw-r--r--perl/SNMP/t/snmptest.conf21
-rw-r--r--perl/SNMP/t/startagent.pl125
-rw-r--r--perl/SNMP/typemap2
-rw-r--r--perl/TrapReceiver/Changes8
-rw-r--r--perl/TrapReceiver/MANIFEST12
-rw-r--r--perl/TrapReceiver/Makefile.PL273
-rw-r--r--perl/TrapReceiver/README30
-rw-r--r--perl/TrapReceiver/TrapReceiver.pm286
-rw-r--r--perl/TrapReceiver/TrapReceiver.xs313
-rw-r--r--perl/TrapReceiver/fallback/const-c.inc146
-rw-r--r--perl/TrapReceiver/fallback/const-xs.inc88
-rw-r--r--perl/TrapReceiver/netsnmp-feature-definitions.h6
-rw-r--r--perl/TrapReceiver/perl_snmptrapd.h44
-rw-r--r--perl/TrapReceiver/ppport.h562
-rw-r--r--perl/TrapReceiver/t/1.t38
-rw-r--r--perl/TrapReceiver/typemap5
-rw-r--r--perl/agent/Changes6
-rw-r--r--perl/agent/MANIFEST15
-rw-r--r--perl/agent/Makefile.PL240
-rw-r--r--perl/agent/Support/Makefile.PL229
-rw-r--r--perl/agent/Support/Support.pm461
-rw-r--r--perl/agent/agent.pm563
-rw-r--r--perl/agent/agent.xs941
-rw-r--r--perl/agent/default_store/Makefile.PL228
-rw-r--r--perl/agent/default_store/default_store.pm370
-rw-r--r--perl/agent/default_store/default_store.xs705
-rwxr-xr-xperl/agent/default_store/gen118
-rw-r--r--perl/agent/default_store/test.pl69
-rw-r--r--perl/agent/netsnmp-feature-definitions.h6
-rw-r--r--perl/agent/netsnmp_request_infoPtr.pm23
-rw-r--r--perl/agent/test.pl122
-rw-r--r--perl/agent/typemap6
-rw-r--r--perl/default_store/Changes6
-rw-r--r--perl/default_store/MANIFEST8
-rw-r--r--perl/default_store/Makefile.PL227
-rw-r--r--perl/default_store/README14
-rw-r--r--perl/default_store/default_store.pm366
-rw-r--r--perl/default_store/default_store.xs1411
-rwxr-xr-xperl/default_store/gen131
-rw-r--r--perl/default_store/netsnmp-feature-definitions.h0
-rw-r--r--perl/default_store/test.pl124
-rw-r--r--perl/default_store/typemap1
-rw-r--r--perl/make-perl-makefiles23
-rw-r--r--perl/manager/INSTALL198
-rw-r--r--perl/manager/Makefile.PL16
-rw-r--r--perl/manager/displaytable.pm628
-rw-r--r--perl/manager/getValues.pm49
-rw-r--r--perl/manager/green.gifbin0 -> 870 bytes
-rw-r--r--perl/manager/manager.pm1051
-rw-r--r--perl/manager/red.gifbin0 -> 855 bytes
-rwxr-xr-xperl/manager/setupauth59
-rwxr-xr-xperl/manager/setupdb149
-rwxr-xr-xperl/manager/setupuser45
-rwxr-xr-xperl/manager/snmptosql523
119 files changed, 30580 insertions, 0 deletions
diff --git a/perl/ASN/ASN.pm b/perl/ASN/ASN.pm
new file mode 100644
index 0000000..272048c
--- /dev/null
+++ b/perl/ASN/ASN.pm
@@ -0,0 +1,163 @@
+package NetSNMP::ASN;
+
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD);
+
+@ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::ASN ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ ASN_APPLICATION
+ ASN_BIT_STR
+ ASN_BOOLEAN
+ ASN_COUNTER
+ ASN_COUNTER64
+ ASN_DOUBLE
+ ASN_FLOAT
+ ASN_GAUGE
+ ASN_INTEGER
+ ASN_INTEGER64
+ ASN_IPADDRESS
+ ASN_NULL
+ ASN_OBJECT_ID
+ ASN_OCTET_STR
+ ASN_OPAQUE
+ ASN_SEQUENCE
+ ASN_SET
+ ASN_TIMETICKS
+ ASN_UNSIGNED
+ ASN_UNSIGNED64
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ ASN_APPLICATION
+ ASN_BIT_STR
+ ASN_BOOLEAN
+ ASN_COUNTER
+ ASN_COUNTER64
+ ASN_DOUBLE
+ ASN_FLOAT
+ ASN_GAUGE
+ ASN_INTEGER
+ ASN_INTEGER64
+ ASN_IPADDRESS
+ ASN_NULL
+ ASN_OBJECT_ID
+ ASN_OCTET_STR
+ ASN_OPAQUE
+ ASN_SEQUENCE
+ ASN_SET
+ ASN_TIMETICKS
+ ASN_UNSIGNED
+ ASN_UNSIGNED64
+);
+$VERSION = '5.0702';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "& not defined" if $constname eq 'constant';
+ my $val;
+ ($!, $val) = constant($constname);
+ if ($! != 0) {
+ if ($! =~ /Invalid/ || $!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined NetSNMP::ASN macro $constname";
+ }
+ }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+# if ($] >= 5.00561) {
+# *$AUTOLOAD = sub () { $val };
+# }
+# else {
+ *$AUTOLOAD = sub { $val };
+# }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap NetSNMP::ASN $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::ASN - Perl extension for SNMP ASN.1 types
+
+=head1 SYNOPSIS
+
+ use NetSNMP::ASN qw(:all);
+ my $asn_int = ASN_INTEGER;
+
+=head1 DESCRIPTION
+
+The NetSNMP::ASN module provides the ASN.1 types for SNMP.
+
+=head2 EXPORT
+
+None by default.
+
+=head2 Exportable constants
+
+ ASN_APPLICATION
+ ASN_BIT_STR
+ ASN_BOOLEAN
+ ASN_COUNTER
+ ASN_COUNTER64
+ ASN_DOUBLE
+ ASN_FLOAT
+ ASN_GAUGE
+ ASN_INTEGER
+ ASN_INTEGER64
+ ASN_IPADDRESS
+ ASN_NULL
+ ASN_OBJECT_ID
+ ASN_OCTET_STR
+ ASN_OPAQUE
+ ASN_SEQUENCE
+ ASN_SET
+ ASN_TIMETICKS
+ ASN_UNSIGNED
+ ASN_UNSIGNED64
+
+
+=head1 AUTHOR
+
+Wes Hardaker, E<lt>hardaker@users.sourceforge.netE<gt>
+
+=head1 SEE ALSO
+
+SNMP(3pm), NetSNMP::OID(3pm)
+
+perl(1).
+
+=cut
diff --git a/perl/ASN/ASN.xs b/perl/ASN/ASN.xs
new file mode 100644
index 0000000..e3f6181
--- /dev/null
+++ b/perl/ASN/ASN.xs
@@ -0,0 +1,177 @@
+/* -*- C -*- */
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/library/asn1.h>
+#include <net-snmp/library/snmp_impl.h>
+
+#define TEST_CONSTANT(value, name, C) \
+ if (strEQ(name, #C)) { \
+ *value = C; \
+ return 0; \
+ }
+
+static int constant_ASN_O(double *value, const char *name, const int len)
+{
+ switch (len >= 5 ? name[5] : -1) {
+ case 'B':
+ TEST_CONSTANT(value, name, ASN_OBJECT_ID);
+ break;
+ case 'C':
+ TEST_CONSTANT(value, name, ASN_OCTET_STR);
+ break;
+ case 'P':
+ TEST_CONSTANT(value, name, ASN_OPAQUE);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_B(double *value, const char *name, const int len)
+{
+ switch (len >= 5 ? name[5] : -1) {
+ case 'I':
+ TEST_CONSTANT(value, name, ASN_BIT_STR);
+ break;
+ case 'O':
+ TEST_CONSTANT(value, name, ASN_BOOLEAN);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_S(double *value, const char *name, const int len)
+{
+ switch (len >= 6 ? name[6] : -1) {
+ case 'Q':
+ TEST_CONSTANT(value, name, ASN_SEQUENCE);
+ break;
+ case 'T':
+ TEST_CONSTANT(value, name, ASN_SET);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_C(double *value, const char *name, const int len)
+{
+ switch (len >= 11 ? name[11] : -1) {
+ case '\0':
+ TEST_CONSTANT(value, name, ASN_COUNTER);
+ break;
+ case '6':
+ TEST_CONSTANT(value, name, ASN_COUNTER64);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_U(double *value, const char *name, const int len)
+{
+ switch (len >= 12 ? name[12] : -1) {
+ case '\0':
+ TEST_CONSTANT(value, name, ASN_UNSIGNED);
+ break;
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case '6':
+ TEST_CONSTANT(value, name, ASN_UNSIGNED64);
+ break;
+#endif
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_IN(double *value, const char *name, const int len)
+{
+ switch (len >= 11 ? name[11] : -1) {
+ case '\0':
+ TEST_CONSTANT(value, name, ASN_INTEGER);
+ break;
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case '6':
+ TEST_CONSTANT(value, name, ASN_INTEGER64);
+ break;
+#endif
+ }
+ return EINVAL;
+}
+
+static int constant_ASN_I(double* value, const char *name, const int len)
+{
+ switch (len >= 5 ? name[5] : -1) {
+ case 'N':
+ return constant_ASN_IN(value, name, len);
+ case 'P':
+ TEST_CONSTANT(value, name, ASN_IPADDRESS);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant(double *value, const char *const name, const int len)
+{
+ if (!strnEQ(name, "ASN_", 4))
+ return EINVAL;
+
+ switch (name[4]) {
+ case 'A':
+ TEST_CONSTANT(value, name, ASN_APPLICATION);
+ break;
+ case 'B':
+ return constant_ASN_B(value, name, len);
+ case 'C':
+ return constant_ASN_C(value, name, len);
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case 'D':
+ TEST_CONSTANT(value, name, ASN_DOUBLE);
+ break;
+ case 'F':
+ TEST_CONSTANT(value, name, ASN_FLOAT);
+ break;
+#endif
+ case 'G':
+ TEST_CONSTANT(value, name, ASN_GAUGE);
+ break;
+ case 'I':
+ return constant_ASN_I(value, name, len);
+ case 'N':
+ TEST_CONSTANT(value, name, ASN_NULL);
+ break;
+ case 'O':
+ return constant_ASN_O(value, name, len);
+ case 'S':
+ return constant_ASN_S(value, name, len);
+ case 'T':
+ TEST_CONSTANT(value, name, ASN_TIMETICKS);
+ break;
+ case 'U':
+ return constant_ASN_U(value, name, len);
+ }
+ return EINVAL;
+}
+
+
+MODULE = NetSNMP::ASN PACKAGE = NetSNMP::ASN
+
+
+void
+constant(sv)
+ PREINIT:
+ STRLEN len;
+ INPUT:
+ SV * sv
+ char * s = SvPV(sv, len);
+ INIT:
+ int status;
+ double value;
+ PPCODE:
+ value = 0;
+ status = constant(&value, s, len);
+ XPUSHs(sv_2mortal(newSVuv(status)));
+ XPUSHs(sv_2mortal(newSVnv(value)));
diff --git a/perl/ASN/Changes b/perl/ASN/Changes
new file mode 100644
index 0000000..9b117f5
--- /dev/null
+++ b/perl/ASN/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension NetSNMP::ASN.
+
+0.01 Fri Jan 18 10:33:43 2002
+ - original version; created by h2xs 1.20 with options
+ -n NetSNMP::ASN myconst.h
+
diff --git a/perl/ASN/MANIFEST b/perl/ASN/MANIFEST
new file mode 100644
index 0000000..02c1199
--- /dev/null
+++ b/perl/ASN/MANIFEST
@@ -0,0 +1,6 @@
+ASN.pm
+ASN.xs
+Changes
+MANIFEST
+Makefile.PL
+test.pl
diff --git a/perl/ASN/Makefile.PL b/perl/ASN/Makefile.PL
new file mode 100644
index 0000000..4576781
--- /dev/null
+++ b/perl/ASN/Makefile.PL
@@ -0,0 +1,233 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::ASN',
+ 'VERSION_FROM' => 'ASN.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ 'PREREQ_PM' => {},
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else
+ {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+ return (%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/ASN/netsnmp-feature-definitions.h b/perl/ASN/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/perl/ASN/netsnmp-feature-definitions.h
diff --git a/perl/ASN/test.pl b/perl/ASN/test.pl
new file mode 100644
index 0000000..0429b6e
--- /dev/null
+++ b/perl/ASN/test.pl
@@ -0,0 +1,28 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1; print "1..9\n"; }
+END {print "not ok 1\n" unless $loaded;}
+use NetSNMP::ASN (':all');
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+print ((ASN_INTEGER == 2) ? "ok 2\n" : "not ok 2\n");
+print ((ASN_OCTET_STR == 4) ? "ok 3\n" : "not ok 3\bn");
+print ((ASN_COUNTER == 0x41) ? "ok 4\n" : "not ok 4\n");
+print ((ASN_UNSIGNED == 0x42) ? "ok 5\n" : "not ok 5\n");
+print ((ASN_COUNTER64 == 0x46) ? "ok 6\n" : "not ok 6\n");
+print ((ASN_IPADDRESS == 0x40) ? "ok 7\n" : "not ok 7\n");
+print ((ASN_NULL == 5) ? "ok 8\n" : "not ok 8\n");
+print ((ASN_TIMETICKS == 0x43) ? "ok 9\n" : "not ok 9\n");
diff --git a/perl/AnyData_SNMP/Changes b/perl/AnyData_SNMP/Changes
new file mode 100644
index 0000000..39d8a86
--- /dev/null
+++ b/perl/AnyData_SNMP/Changes
@@ -0,0 +1 @@
+none.
diff --git a/perl/AnyData_SNMP/DBD_AnyData.patch b/perl/AnyData_SNMP/DBD_AnyData.patch
new file mode 100644
index 0000000..56ed3bb
--- /dev/null
+++ b/perl/AnyData_SNMP/DBD_AnyData.patch
@@ -0,0 +1,48 @@
+--- ../AnyData-0.05/DBD/AnyData.pm Tue Jul 17 12:31:44 2001
++++ DBD/AnyData.pm Wed Oct 31 13:08:37 2001
+@@ -63,7 +63,7 @@
+ # PARSE EXTRA STRINGS IN DSN HERE
+ # Process attributes from the DSN; we assume ODBC syntax
+ # here, that is, the DSN looks like var1=val1;...;varN=valN
+- my $var;
++ my ($var, $defaultselector, %defaultflags);
+ $dbh->STORE('f_dir','./');
+ foreach $var (split(/;/, $dbname)) {
+ #######################################################
+@@ -80,9 +80,13 @@
+ #######################################################
+ # Patch from Wes Hardaker
+ #######################################################
+- } elsif( $var =~ m/^\s*?default=(\S+)/i ){
+- # Default catalog selector to use
+- $dbh->func('__default',$1, 'ad_catalog');
++ } elsif( $var =~ m/^\s*?ad_default=(\S+)/i ){
++ # Default catalog selector to use
++ $defaultselector = $1;
++ } elsif( $defaultselector &&
++ $var =~ m/^\s*?ad_${defaultselector}_(\S+)=(\S+)/i ) {
++ # Add to selector flags.
++ $defaultflags{$1} = $2;
+ #######################################################
+ } elsif ($var =~ /(.*?)=(.*)/) {
+ my $key = $1;
+@@ -90,6 +94,10 @@
+ $dbh->STORE($key, $val);
+ }
+ }
++ if ($defaultselector) {
++ $dbh->func('__default', $defaultselector, '', \%defaultflags,
++ 'ad_catalog');
++ }
+ ### $dbh->func('read_catalog_from_disk');
+ $dbh;
+ }
+@@ -520,7 +528,7 @@
+ my($self, $data, $fields) = @_;
+ my $requested_cols=[];
+ my @rc = $data->{f_stmt}->columns();
+- push @$requested_cols, $_->{column} for @rc;
++ push @$requested_cols, $_->{name} for @rc;
+ unshift @$fields, $requested_cols;
+ $self->{ad}->push_row(@$fields);
+ 1;
diff --git a/perl/AnyData_SNMP/Format.pm b/perl/AnyData_SNMP/Format.pm
new file mode 100644
index 0000000..4f3860d
--- /dev/null
+++ b/perl/AnyData_SNMP/Format.pm
@@ -0,0 +1,109 @@
+package AnyData::Format::SNMP;
+#
+# AnyData interface to SNMP queries
+#
+
+use strict;
+use warnings;
+use AnyData::Format::Base;
+use vars qw( @ISA );
+@AnyData::Format::SNMP::ISA = qw( AnyData::Format::Base );
+use Data::Dumper;
+
+sub storage_type {
+# print "calling storage type\n"; 'SNMP';
+}
+
+sub new {
+# print "new format: ", Dumper(@_), "\n";
+ my $class = shift;
+ my $self = shift || {};
+ bless $self, $class;
+ $self->{'storage'} = 'SNMP';
+ $self->{'has_update_function'} = 'SNMP';
+# print Dumper($self), "\n";
+ return $self;
+ 2;
+}
+
+sub get_col_names {
+# print "get_col_names\n";
+ # XXX: get mib column names
+ 2;
+}
+
+sub seek_first_record {
+# print "seek_first\n";
+ my $self = shift;
+ my $var = [$self->{'mibnode'}];
+ $self->{'session'}->getnext($var);
+ 2;
+}
+
+sub get_pos {
+# print "get_pos\n";
+ 2;
+}
+
+sub go_pos {
+# print "go_pos\n";
+ 2;
+}
+
+sub delete_record {
+# print "del_rec\n";
+ 2;
+}
+
+sub get_record {
+# print "get_record\n";
+ 2;
+}
+
+sub push_row {
+# print "push_row\n";
+ 2;
+}
+
+sub truncate {
+# print "truncate\n";
+ 2;
+}
+
+sub close_table {
+# print "close_table\n";
+ 2;
+}
+
+sub drop {
+# print "drop\n";
+ 2;
+}
+
+sub seek {
+# print "seek\n";
+ 2;
+}
+
+sub write_fields {
+# print STDERR "write_fields: ",Dumper(\@_), "\n";
+ my $self = shift;
+ my @ary = @_;
+ return \@ary;
+}
+sub read_fields {
+# print STDERR "read_fields: ",Dumper(\@_), "\n";
+ my $self = shift;
+ my $aryref = shift;
+ return @$aryref;
+}
+
+sub get_data {
+# print "get_data\n";
+ 2;
+}
+
+sub init_parser {
+# print "init_parser\n";
+ 2;
+}
diff --git a/perl/AnyData_SNMP/INSTALL b/perl/AnyData_SNMP/INSTALL
new file mode 100644
index 0000000..1337846
--- /dev/null
+++ b/perl/AnyData_SNMP/INSTALL
@@ -0,0 +1,44 @@
+NOTE NOTE NOTE: this module depends on a modified version of the
+DBD::AnyData module. Do not get the original version from Jeff
+Zucker. He and I are working together to resolve the extra features I
+need, but we haven't quite merged yet.
+
+*** This is currently alpha level code!!! ***
+
+Install steps:
+ 0) install the DBI perl module (run: perl -MCPAN -e "install DBI")
+ and the DBD::File perl module (run: perl -MCPAN -e "install DBD::File")
+
+ 1) download, and install the modified AnyData perl modules from:
+ http://www.net-snmp.org/AnyData-wes/AnyData-0.05.tar.gz
+ http://www.net-snmp.org/AnyData-wes/DBD-AnyData-0.05.wes.tar.gz
+ http://www.net-snmp.org/AnyData-wes/SQL-Statement-1.004.tar.gz
+
+ Extract each of the above tar balls and in the resulting
+ directories run:
+
+ perl Makefile.PL
+ make
+ make install (as root)
+
+ 2) Then in this directory, run:
+ perl Makefile.PL
+ make
+ make install (as root)
+
+To use it:
+ SQL like Shell script:
+ netsh [snmpcmd arguments] HOST [SQL COMMAND]
+
+ Example commands to type at the prompt:
+ select * from ifTable
+ select * from ifTable where ifDescr = 'eth0'
+ alias ifconfig select ifDescr, ifAdminStatus where ifDescr = '\1'
+ ifconfig eth0
+
+
+[Jeff Zucker's original (unpatched) AnyData perl modules can be found
+ at http://www.vpservices.com/jeff/programs/AnyData/ . However, do not
+ use the modules from this site as they won't work with the software in
+ this directory. (Use the download sites in step 1 below instead.) It
+ is a good source for documentation about the AnyData modules.]
diff --git a/perl/AnyData_SNMP/MANIFEST b/perl/AnyData_SNMP/MANIFEST
new file mode 100644
index 0000000..5192993
--- /dev/null
+++ b/perl/AnyData_SNMP/MANIFEST
@@ -0,0 +1,7 @@
+INSTALL
+README
+MANIFEST
+Makefile.PL
+Format.pm
+Storage.pm
+DBD_AnyData.patch
diff --git a/perl/AnyData_SNMP/Makefile.PL b/perl/AnyData_SNMP/Makefile.PL
new file mode 100644
index 0000000..8106650
--- /dev/null
+++ b/perl/AnyData_SNMP/Makefile.PL
@@ -0,0 +1,14 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'AnyData::SNMP',
+ 'VERSION_FROM' => 'Storage.pm', # finds $VERSION
+ 'PREREQ_PM' => {# SNMP => 5.0,
+ AnyData => 0}, # e.g., Module::Name => 1.1
+ 'PM' => {
+ 'Format.pm' => '$(INST_LIBDIR)/Format/SNMP.pm',
+ 'Storage.pm' => '$(INST_LIBDIR)/Storage/SNMP.pm',
+ },
+ 'EXE_FILES' => [qw(netsh)]
+);
diff --git a/perl/AnyData_SNMP/README b/perl/AnyData_SNMP/README
new file mode 100644
index 0000000..7b0fb08
--- /dev/null
+++ b/perl/AnyData_SNMP/README
@@ -0,0 +1,21 @@
+The AnyData::SNMP module is really an augmentation to Jeff Zucker's
+excellent perl AnyData and DBD::AnyData modules. It is designed to
+allow the infamous perl DBI module to translate SQL commands directly
+into network SNMP requests and to manipulate the data in perl
+afterward. See the perl DBI documentation for further details, as
+well as the AnyData documentation.
+
+The netsh command then implements a standard shell around the sql to
+SNMP mapping, such that commands like the following are possible:
+
+ netsh -c public localhost 'select ifIndex, ifDescr, ifType from ifTable'
+ netsh -c public localhost 'update ifTable set ifAdminStatus = 2 where ifType = 6'
+
+Without a command to run, netsh puts you into an interactive shell
+where the commands can be typed at a command prompt.
+
+See the INSTALL file for the necessary prerequisites. Note that this
+currently makes use of a patched copy of the DBD::AnyData module.
+This will be fixed in future versions of both this module and the
+DBD::AnyData module as the authors worth toward a common
+infrastructure.
diff --git a/perl/AnyData_SNMP/Storage.pm b/perl/AnyData_SNMP/Storage.pm
new file mode 100644
index 0000000..489aad9
--- /dev/null
+++ b/perl/AnyData_SNMP/Storage.pm
@@ -0,0 +1,428 @@
+#########################################################################
+package AnyData::Storage::SNMP;
+#########################################################################
+
+## XXX: TODO:
+## scalar sets?
+## multi-hosts
+
+$AnyData::Storage::VERSION = '5.0702';
+use strict;
+use warnings;
+
+use vars qw(@basecols);
+
+@AnyData::Storage::SNMP::basecols = qw(hostname iid);
+$AnyData::Storage::SNMP::iidptr = 1; # must match array column of above
+@AnyData::Storage::SNMP::basetypes = qw(OCTETSTR OBJECTID);
+$AnyData::Storage::SNMP::debug = 0;
+$AnyData::Storage::SNMP::debugre = undef;
+
+use Data::Dumper;
+use AnyData::Storage::File;
+use SNMP;
+SNMP::init_snmp("AnyData::SNMP");
+
+sub new {
+# DEBUG("calling AnyData::Storage::SNMP new\n");
+# DEBUG("new storage: ",Dumper(\@_),"\n");
+ my $class = shift;
+ my $self = shift || {};
+ $self->{open_mode} = 'c';
+ return bless $self, $class;
+}
+
+sub open_table {
+ DEBUG("calling AnyData::Storage::SNMP open_table\n");
+ my ($self, $parser, $table, $mode, $tname) = @_;
+ $self->{'process_table'} = $tname;
+ DEBUG("open_table: ",Dumper(\@_),"\n");
+}
+
+sub get_col_names {
+ DEBUG("calling AnyData::Storage::SNMP get_col_names\n");
+ my ($self, $parser, $tname) = @_;
+ DEBUG("get_col_names\n",Dumper(\@_),"\n");
+ $tname = $self->{'process_table'} if (!$tname);
+
+ # get cached previous results
+ return $self->{col_names}{$tname} if (defined($self->{col_names}{$tname}));
+
+ # table name
+ $tname = $self->{'process_table'} if (!$tname);
+
+ # mib node setup
+ my $mib = $SNMP::MIB{$tname} || return warn "no such table $tname";
+ my $entry = $mib->{'children'}[0];
+
+ # base columns and types
+ my @cols = @AnyData::Storage::SNMP::basecols;
+ my @types = @AnyData::Storage::SNMP::basetypes;
+ my %donecol;
+ my $count = $#cols;
+
+ foreach my $index (@{$entry->{'indexes'}}) {
+ push @cols, $index;
+ push @types, $SNMP::MIB{$index}{type};
+ $donecol{$index} = 1;
+ $count++;
+ if ($SNMP::MIB{$index}{parent}{label} eq $entry->{label}) {
+ # this index is a member of this table
+ $self->{columnmap}[$count] = $index;
+ $self->{coloffset} += 1;
+ }
+ }
+
+ # search children list
+ foreach my $child ( sort { $a->{'subID'} <=> $b->{'subID'} } @{$entry->{'children'}}) {
+ push @{$self->{real_cols}}, $child->{'label'};
+ next if ($donecol{$child->{label}});
+ push @cols, $child->{'label'};
+ push @types, $child->{'type'};
+ $count++;
+ $self->{columnmap}[$count] = $child->{'label'};
+ }
+
+ # save for later.
+ $parser->{col_names} = \@cols;
+ $self->{col_types} = \@types;
+ $self->{col_names} = \@cols;
+ map { $self->{col_uc_map}{uc($_)} = $_ } @cols;
+ return \@cols;
+}
+
+sub set_col_nums {
+ DEBUG("calling AnyData::Storage::SNMP set_col_nums\n");
+ DEBUG("set_col_nums\n",Dumper(\@_),"\n");
+ my ($self, $tname) = @_;
+ return $self->{col_nums} if (defined($self->{col_nums}));
+ my $mib = $SNMP::MIB{$tname};
+ my $entry = $mib->{'children'}[0];
+ my (%cols, %mibnodes);
+ my $cnt = -1;
+
+ foreach my $i (@{$self->{col_names}}) {
+ $cols{$i} = ++$cnt;
+ }
+
+ $self->{col_nums} = \%cols;
+ return \%cols;
+}
+
+# not needed?
+sub get_file_handle {
+ DEBUG("calling AnyData::Storage::SNMP get_file_handle\n");
+ DEBUG("get_file_handle\n",Dumper(\@_),"\n");
+ return shift;
+}
+
+# not needed?
+sub get_file_name {
+ DEBUG("calling AnyData::Storage::SNMP get_file_name\n");
+ DEBUG("get_file_name\n",Dumper(\@_),"\n");
+ my $self = shift;
+ return $self->{process_table} || $self->{table_name};
+}
+
+sub truncate {
+ DEBUG("calling AnyData::Storage::SNMP truncate\n");
+ my ($self) = @_;
+ DEBUG("trunacte, ", Dumper(@_));
+
+ # We must know how to delete rows or else this is all pointless.
+# return $self->{col_nums}{$tname} if (defined($self->{col_nums}{$tname}));
+ my $tablemib = $SNMP::MIB{$self->{process_table}};
+ my $entrymib = $tablemib->{'children'}[0];
+ my ($delcolumn, $delcolumnname, $delcolumnvalue);
+
+ foreach my $child (@{$entrymib->{'children'}}) {
+ if ($child->{'textualConvention'} eq 'RowStatus') {
+ $delcolumn = $child->{subID};
+ $delcolumnname = $child->{label};
+ $delcolumnvalue = 6; # destroy
+ last;
+ }
+ }
+ if (!$delcolumn) {
+ return warn "Can't (or don't know how to) delete from table $self->{process_table}. Failing.\n";
+ }
+
+ # we should have a session, or else something is really wierd but...
+ $self->{'sess'} = $self->make_session() if (!$self->{'sess'});
+
+ # for each key left in our cache, delete it
+ foreach my $key (keys(%{$self->{'existtest'}})) {
+ # xxx: fullyqualified oid better
+ my $vblist = new SNMP::VarList([$delcolumnname, $key,
+ $delcolumnvalue]);
+ DEBUG("truncate $key: \n", Dumper($vblist));
+ $self->{'sess'}->set($vblist) || warn $self->{'sess'}->{ErrorStr};
+ }
+ return;
+}
+
+sub make_session {
+ DEBUG("calling AnyData::Storage::SNMP make_session\n");
+ my $self = shift;
+ my @args = @_;
+ my @sessions;
+ foreach my $key (qw(SecName Version SecLevel AuthPass Community RemotePort Timeout Retries RetryNoSuch SecEngineId ContextEngineId Context AuthProto PrivProto PrivPass)) {
+ push @args, $key, $self->{$key} if ($self->{$key});
+ }
+ foreach my $host (split(/,\s*/,$self->{DestHost})) {
+ push @sessions, new SNMP::Session(@args, 'DestHost' => $host);
+ }
+ return \@sessions;
+}
+
+sub file2str {
+ DEBUG("calling AnyData::Storage::SNMP file2str\n");
+ my ($self, $parser, $uccols) = @_;
+ my ($cols, @retcols);
+ DEBUG("file2str\n",Dumper(\@_),"\n");
+ restart:
+ if (!$self->{lastnode}) {
+# my @vbstuff = @{$parser->{'col_names'}};
+# splice (@vbstuff,0,1+$#AnyData::Storage::SNMP::basecols);
+# map { $_ = [ $_ ] } @vbstuff;
+# $self->{lastnode} = new SNMP::VarList(@vbstuff);
+# splice (@$cols,0,1+$#AnyData::Storage::SNMP::basecols);
+ map { push @$cols,$self->{col_uc_map}{$_} } @$uccols;
+ if ($#$cols == -1) {
+ $cols = $self->{'col_names'};
+ # remove base columns
+ splice (@$cols,0,1+$#AnyData::Storage::SNMP::basecols);
+ # remove not accessible columns
+ foreach my $col (@$cols) {
+ my $mib = $SNMP::MIB{$col};
+ push @retcols, $col if ($mib->{'access'} =~ /Read|Create/);
+ }
+ } else {
+ @retcols = @$cols;
+ # remove base columns
+ foreach my $c (@AnyData::Storage::SNMP::basecols) {
+ @retcols = grep(!/^$c$/, @retcols);
+ }
+ # remove non-accessible columns
+ @retcols = grep {$SNMP::MIB{$_}{'access'} =~ /Read|Create/} @retcols;
+ }
+ map { $_ = [ $_ ] } @retcols;
+ $self->{lastnode} = new SNMP::VarList(@retcols);
+ }
+
+ if (!$self->{'sess'}) {
+ $self->{'sess'} = $self->make_session();
+ if ($#{$self->{'sess'}} == 0 && $self->{'silence_single_host'}) {
+ $self->{'hostname'} = '';
+ } else {
+ $self->{'hostname'} = $self->{'sess'}[0]{'DestHost'};
+ }
+ }
+
+ # perform SNMP operation
+ my $lastnode = $self->{'lastnode'}[0][0];
+ my $result;
+ $result = $self->{'sess'}[0]->getnext($self->{lastnode});
+ if (!defined($result)) {
+ warn " getnext of $self->{lastnode}[0][0] returned undef\n";
+ }
+ DEBUG(" result: ",Dumper($self->{lastnode}),"\n");
+
+ # XXX: check for holes!
+
+ # need proper oid compare here for all nodes
+ if ($self->{'lastnode'}[0][0] ne $lastnode) {
+ if ($#{$self->{'sess'}} > 0) {
+ shift @{$self->{'sess'}};
+ delete($self->{'lastnode'});
+ @$cols = ();
+ $self->{'hostname'} = $self->{'sess'}[0]{'DestHost'} if($self->{'hostname'});
+ goto restart;
+ }
+ return undef;
+ }
+
+ # add in basecols information:
+ my @ret = ($self->{'hostname'}, $self->{'lastnode'}[0][1]);
+ DEBUG("Dump row results: ",Dumper($self->{'lastnode'}),"\n");
+
+ # build result array from result varbind contents
+ map { $ret[$self->{'col_nums'}{$_->[0]}] = map_data($_); } @{$self->{'lastnode'}};
+
+ # store instance ID for later use if deletion is needed later.
+ $self->{'existtest'}{$self->{'lastnode'}[0][1]} = 1;
+
+ DEBUG("Dump row results2: ",Dumper(\@ret),"\n");
+ return \@ret;
+}
+
+sub map_data {
+ if ($_->[3] eq "OBJECTID") {
+ $_->[2] = pretty_print_oid(@_);
+ }
+ return $_->[2];
+}
+
+sub pretty_print_oid {
+ use NetSNMP::default_store qw(:all);
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS,0);
+ my $new = SNMP::translateObj($_->[2], 0);
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS,1);
+ my $new2 = SNMP::translateObj($_->[2], 0);
+ if ($new) {
+ $_->[2] = $new2 . "$new";
+ } else {
+ $_->[2] = $_->[0] . $_->[1];
+ }
+ return $_->[2];
+}
+
+sub push_row {
+ DEBUG("calling AnyData::Storage::SNMP push_row\n");
+ DEBUG("push_row: ",Dumper(\@_),"\n");
+ DEBUG("push_row\n");
+ my ($self, $values, $parser, $cols) = @_;
+ my @callers = caller(3);
+ my $mode = $callers[3];
+ if ($mode =~ /DELETE/) {
+ DEBUG("not deleting $values->[$AnyData::Storage::SNMP::iidptr]\n");
+ delete $self->{'existtest'}{$values->[$AnyData::Storage::SNMP::iidptr]};
+ return;
+ }
+
+ my @origvars;
+ if ($#$cols == -1) {
+ # no column info passed in. Update everything (mode probably INSERTS).
+# @origvars = @{$self->{'col_names'}}};
+# splice (@origvars,0,1+$#AnyData::Storage::SNMP::basecols);
+
+ map { push @origvars, $_ if $SNMP::MIB{$_}{'access'} =~ /Write|Create/; } @{$self->{'real_cols'}} ;
+
+ DEBUG("set cols: ", Dumper(\@origvars));
+ } else {
+ # only update the columns in question. (mode probably UPDATE)
+ map { push @origvars, $self->{col_uc_map}{$_} } @$cols;
+ }
+
+ my @vars;
+ foreach my $var (@origvars) {
+ my $access = $SNMP::MIB{$var}{'access'};
+ # not in this table, probably (hopefully) an index from another:
+ next if ($SNMP::MIB{$var}{'parent'}{'parent'}{'label'} ne
+ $self->{process_table});
+ DEBUG("$var -> $access\n");
+ if ($access =~ /(Write|Create)/) {
+ push @vars, $var;
+ } elsif ($mode eq 'insert') {
+ DEBUG("XXX: error if not index\n");
+ } elsif ($mode eq 'update') {
+ DEBUG("update to non-writable column attempted (SNMP error coming)\n");
+ }
+ }
+
+ # generate index OID component if we don't have it.
+ if ($values->[$AnyData::Storage::SNMP::iidptr] eq '') {
+ $values->[$AnyData::Storage::SNMP::iidptr] =
+ $self->make_iid($self->{process_table}, $values);
+ }
+
+ # add in values to varbind columns passed in from incoming parameters
+ my @newvars;
+ foreach my $v (@vars) {
+ my $num = $self->{'col_nums'}{$v};
+ DEBUG("types: $v -> $num -> ", $self->{'col_types'}[$num],
+ " -> val=", $values->[$num], "\n");
+ next if (!defined($values->[$num]));
+ # build varbind: column-oid, instance-id, value type, value
+ push @newvars, [$v, $values->[1], $values->[$num],
+ $self->{'col_types'}[$num]];
+ };
+
+ # create the varbindlist
+# print STDERR Dumper(\@newvars);
+ my $vblist = new SNMP::VarList(@newvars);
+
+# print STDERR Dumper($vblist);
+ DEBUG("set: ", Dumper($vblist));
+ $self->{'sess'} = $self->make_session() if (!$self->{'sess'});
+ if (!$self->{'sess'}[0]) {
+ warn "couldn't create SNMP session";
+ } elsif (!$self->{'sess'}[0]->set($vblist)) {
+ my $err = "$self->{process_table}: " . $self->{'sess'}[0]->{ErrorStr};
+ if ($self->{'sess'}[0]->{ErrorInd}) {
+ $err = $err . " (at varbind #"
+ . $self->{'sess'}[0]->{ErrorInd} . " = " ;
+ my $dump = Data::Dumper->new([$vblist->[$self->{'sess'}[0]->{ErrorInd} -1]]);
+ $err .= $dump->Indent(0)->Terse(1)->Dump;
+ }
+ warn $err;
+ }
+}
+
+sub seek {
+ DEBUG("calling AnyData::Storage::SNMP seek\n");
+ my ($self, $parser) = @_;
+ DEBUG("seek\n",Dumper(\@_),"\n");
+}
+
+sub make_iid {
+ DEBUG("calling AnyData::Storage::SNMP make_iid\n");
+ my ($self, $tname, $vals) = @_;
+
+ # Get indexes
+ my $mib = $SNMP::MIB{$tname};
+ my $entry = $mib->{'children'}[0];
+ my $indexes = $entry->{'indexes'};
+ my $iid;
+
+ # XXX: implied
+
+# print STDERR "INDEXES: ", Dumper($vals),"\n";
+ foreach my $index (@$indexes) {
+ warn "A null index value was found, which I doubt is correct." if (!defined($vals->[$self->{col_nums}{$index}]));
+ my $val = $vals->[$self->{col_nums}{$index}];
+ my $type = $SNMP::MIB{$index}->{'type'};
+ DEBUG("index type: $index -> $type -> $val -> " . length($val) . "\n");
+ if ($type eq "OCTETSTR") {
+ $iid .= "." . length($val) . "." . join(".", unpack("c*", $val));
+ } elsif ($type eq "OBJID") {
+ $iid .= "." . (scalar grep(/\./,$val) + 1) . "." . $val;
+ } else {
+ # should be only an INTEGER?
+ $iid .= "." . $val;
+ }
+ }
+ DEBUG("made iid: $iid\n");
+ return $iid;
+}
+
+sub DEBUG {
+ my @info = caller(1);
+ if ($AnyData::Storage::SNMP::debug
+ || ($AnyData::Storage::SNMP::debugre &&
+ $_[0] =~ /$AnyData::Storage::SNMP::debugre/)) {
+ DEBUGIT(\@info, @_);
+ }
+}
+
+sub DEBUGIT {
+ my $info;
+ if (ref($_[0]) eq 'ARRAY') {
+ $info = shift @_;
+ } else {
+ my @y;
+ my $c=0;
+ print STDERR "debug chain: ";
+ for(@y = caller($c); $#y > -1; $c++, @y = caller($c)) {
+ print STDERR " $c: $y[3]\n";
+ }
+ my @x = caller(1);
+ $info = \@x;
+ }
+ print STDERR "$info->[3]: ";
+ print STDERR @_;
+}
+
+1;
diff --git a/perl/AnyData_SNMP/configs/scli b/perl/AnyData_SNMP/configs/scli
new file mode 100644
index 0000000..b2e243e
--- /dev/null
+++ b/perl/AnyData_SNMP/configs/scli
@@ -0,0 +1,27 @@
+# scli equivelents
+alias scli_system_info {
+ printf "Name: %s\n" sysName.0
+ #XXX fix:
+ printf "Address: localhost:161\n";
+ printf "Contact: %s\n" sysContact.0
+ printf "Location: %s\n" sysLocation.0
+ printf "Vendor: %s\n" sysObjectID.0
+ #printf "Current Time: %s\n" hrSystemDate.0
+ #printf "Agent Boot Time: %s\n" sysUpTime.0
+ #printf "System Boot Time: %s\n" 2002-06-03 21:33:49 -08:00
+ printf "Users: %s\n" hrSystemNumUsers.0
+ printf "Processes: %s\n" hrSystemProcesses.0
+ printf "Memory: %s\n" select hrStorageSize, hrStorageType from hrStorageTable where hrStorageType = '.1.3.6.1.2.1.25.2.1.2'
+ printf "Interfaces: %s\n" ifNumber.0
+}
+
+alias scli_system_devices {
+ printf "%5d: %s\n" select hrDeviceIndex, hrDeviceDescr from hrDeviceTable;
+}
+
+alias scli_system_storage {
+ printf "Storage Area Size [K] Used [K] Free [K] Use%\n"
+ # fix size, use%
+ printf "%-22s %8d %8d %8d %3d (%s)\n" select hrStorageDescr, hrStorageSize, hrStorageUsed, hrStorageSize, hrStorageIndex, hrStorageType from hrStorageTable
+}
+
diff --git a/perl/AnyData_SNMP/configs/unix b/perl/AnyData_SNMP/configs/unix
new file mode 100644
index 0000000..4bf3fea
--- /dev/null
+++ b/perl/AnyData_SNMP/configs/unix
@@ -0,0 +1,34 @@
+# example ifconfig command
+alias ifconfig {
+ printf "%-10sinet addr: %-15s Mask: %-10s\n %s %s RUNNING:%s MTU:%d\n RX packets: %d errors: %d dropped: %d\n TX packets: %d errors: %d dropped: %d\n RX bytes:%d TX bytes: %d\n\n" select ifDescr, ipAdEntAddr, ipAdEntNetMask, ifAdminStatus, ifType, ifOperStatus, ifMtu, ifInUcastPkts, ifInErrors, ifInDiscards, ifOutUcastPkts, ifOutErrors, ifOutDiscards, ifInOctets, ifOutOctets, ifIndex, ipAdEntIfIndex from ifTable, ipAddrTable where ifIndex = ipAdEntIfIndex
+# select ipAdEntAddr, ifDescr, ifIndex, ipAdEntIfIndex from ifTable, ipAddrTable where ifIndex = ipAdEntIfIndex
+}
+
+# equivelant to netstat -an
+alias netstatan {
+ printf "Active Intenet connections (servers and established)\n"
+ printf "Proto LocalAddress Foreign Address State\n"
+ printf "tcp %-15s:%-5s %-15s:%-5s%-10s\n" select tcpConnLocalAddress, tcpConnLocalPort, tcpConnRemAddress, tcpConnRemPort, tcpConnState from tcpConnTable;
+ printf "udp %-15s:%-5s 0.0.0.0:0 %-10s\n" select udpLocalAddress, udpLocalPort from udpTable;
+}
+
+# equivelent to netstat -rn
+alias netstatrn {
+ printf "Kernel IP Routing Table\n"
+ printf "Destination Gateway Genmask Type Iface\n"
+ printf "%-15s %-15s %-15s %-8s %s\n" select ipRouteDest, ipRouteNextHop, ipRouteMask, ipRouteType, ifDescr, ifIndex, ipRouteIfIndex from ifTable, ipRouteTable where ifIndex = ipRouteIfIndex
+}
+
+alias ps {
+ printf "%6d %1d %s %40.40s\n" select hrSWRunIndex, hrSWRunType, hrSWRunName, hrSWRunParameters from hrSWRunTable
+# printf "%6d %1d %6d %s %40.40s\n" select hrSWRunIndex, hrSWRunType, hrSWRunPerfMem, hrSWRunName, hrSWRunParameters from hrSWRunTable
+}
+
+alias ps_grep {
+ printf "%6d %1d %s %40.40s\n" select hrSWRunIndex, hrSWRunType, hrSWRunName, hrSWRunParameters from hrSWRunTable where hrSWRunName like '%\1%'
+}
+
+alias df {
+ printf "Filesystem Size Used\n"
+ printf "%-20s %8d %8d\n" select hrStorageDescr, hrStorageSize, hrStorageUsed from hrStorageTable
+}
diff --git a/perl/AnyData_SNMP/netsh b/perl/AnyData_SNMP/netsh
new file mode 100755
index 0000000..c743f9c
--- /dev/null
+++ b/perl/AnyData_SNMP/netsh
@@ -0,0 +1,838 @@
+#!/usr/bin/perl
+
+use Getopt::Std;
+
+use DBI;
+use Term::ReadLine;
+use SNMP;
+use AutoLoader;
+use IO::File;
+
+BEGIN {
+ $opts{'t'} = ! eval { require Text::FormatTable; };
+ $ansicolor = eval { require Term::ANSIColor; };
+}
+
+# override some of the functions to force our colorized semantics.
+# This is really ugly, but if you pass colorized strings directly to
+# Text::FormatTable then it calculates the string lengths incorrectly.
+# Children: don't try this at home. We're trained professionals.
+if ($colorize) {
+ eval {
+ #
+ # colorized strings.
+ #
+ package color_string;
+
+ require Term::ANSIColor;
+
+ use overload
+ '""' => \&string_it
+ ;
+
+ sub string_it {
+ if ($_[0][3]) {
+ if ($_[0][3] == 1) {
+ return color_it();
+ } else {
+ $_[0][3] -= 1;
+ return $_[0][1];
+ }
+ }
+ return $_[0][1];
+ }
+
+ sub colorize_next {
+ $_[0][3] = 2;
+ }
+
+ sub color_it {
+ my $str = $_[1] || $_[0][1];
+ return $_[0][0] . $str . $_[0][2];
+ }
+
+ sub new {
+ my $this = [Term::ANSIColor::color($_[2]), $_[1],
+ Term::ANSIColor::color('reset')];
+ return bless($this, $_[0]);
+ }
+ }
+}
+
+if ($opts{'t'} == 0 && $colorize) {
+ eval {
+ package Text::FormatTable;
+
+ sub _l_box($$)
+ {
+ my ($width, $text) = @_;
+ my $lines = _wrap($width, $text);
+ map {
+ if (ref($text) eq "color_string") {
+ $_ .= $text->color_it($_) . ' 'x($width-length($_));
+ } else {
+ $_ .= ' 'x($width-length($_));
+ }
+ } @$lines;
+ return $lines;
+ }
+
+ sub _r_box($$)
+ {
+ my ($width, $text) = @_;
+ my $lines = _wrap($width, $text);
+ map {
+ if (ref($text) eq "color_string") {
+ $_ = ' 'x($width-length($_)) . $text->color_it($_);
+ } else {
+ $_ = ' 'x($width-length($_)) . $_;
+ }
+ } @$lines;
+ return $lines;
+ }
+
+ }
+}
+
+if (!$ansicolor) {
+ $begin = $end = "*";
+}
+
+$SNMP::use_enums=1;
+
+
+#defaults
+$opts{'d'} = "\t";
+$opts{'v'} = 1;
+$opts{'l'} = 'authNoPriv';
+$params = "";
+
+getopts('hd:tR:u:l:v:a:A:x:X:p:c:t:r:',\%opts);
+
+usage() if ($#ARGV == -1 || $opts{'h'});
+
+my %parammap = {
+ 'v' => 'Version',
+ 'u' => 'SecName',
+ 'a' => 'AuthProto',
+ 'A' => 'AuthPass',
+ 'x' => 'PrivProto',
+ 'X' => 'PrivPass',
+ 'p' => 'RemotePort',
+ 't' => 'Timeout',
+ 'r' => 'Retries',
+ 'c' => 'Community',
+ 'l' => 'SecLevel'
+ };
+
+foreach my $x (keys(%opts)) {
+ if ($parammap{$x}) {
+ $params .= ";ad_SNMP_$parammap{$x}=$x";
+ }
+ push @sessparams,$parammap{$x},$x;
+}
+
+my $host = shift @ARGV;
+$params .= ";ad_SNMP_DestHost=" . $host;
+push @sessparms,'DestHost', $host;
+
+# connect to the DBI interface
+$AnyData::Storage::SNMP::debugre = $opts{'R'} if ($opts{'R'});
+($dbh = DBI->connect("dbi:AnyData:ad_default=SNMP$params"))
+ || die "\tConnection problem: $DBI::errstr\n";
+$AnyData::Storage::SNMP::debugre = $opts{'R'} if ($opts{'R'});
+
+$prompt = "netsh> ";
+
+load_rcs();
+
+# setup terminal prompter
+$ENV{'PERL_RL'}='o=0' if (!exists($ENV{'PERL_RL'}));
+# the ornaments are too ugly
+$term = new Term::ReadLine 'netsh';
+
+if ($#ARGV >= 0) {
+ # command line command
+ netsh(join(" ",@ARGV));
+} else {
+ # interactive shell
+ while($cmd = $term->readline($prompt)) {
+ last if ($cmd eq "exit" || $cmd eq "quit" || $cmd eq "q");
+ netsh($cmd, \%conf);
+ }
+}
+
+# load all configuration files we can find.
+sub load_rcs {
+ if (-f "$ENV{'HOME'}/.snmp/netshrc") {
+ source_file("$ENV{'HOME'}/.snmp/netshrc");
+ }
+ if (-d "$ENV{'HOME'}/.snmp/netsh") {
+ foreach my $i (glob("$ENV{'HOME'}/.snmp/netsh/*")) {
+ if (-f "$i" && "$i" !~ /.*(~|.bak)$/) {
+ source_file("$i");
+ }
+ }
+ }
+}
+
+# command definition for sourcing a particular file
+sub source_file {
+ my $fh = new IO::File;
+ if ($fh->open("<$_[0]")) {
+ while(<$fh>) {
+ if (s/<<\s*(\w+)$//) {
+ my $stopat = $1;
+ my $lines = $_;
+ while(<$fh>) {
+ last if (/$stopat/);
+ $lines .= $_;
+ }
+ $_ = $lines;
+ }
+ netsh($_);
+ }
+ } else {
+ print STDERR "no such file: $_[0]\n";
+ }
+}
+
+# export data into an external file
+sub my_export {
+ shift;
+ if (!$insh) {
+ my $cmd = "create table exporttable (" . join (" varchar(255), ",@{$sth->{NAME}}) . " varchar(255))";
+ $exporth->do($cmd);
+ $cmd = "insert into exporttable values(" . ('?, ' x ($#_)) . "?)";
+ $insh = $exporth->prepare($cmd);
+ }
+ $insh->execute(@_);
+}
+
+# the main processing function.
+sub netsh {
+ my $stmt = shift;
+ chomp($stmt); # remove trailing white space
+ $stmt =~ s/^\s+//; # remove leading white space
+ $stmt =~ s/;*$//; # get rid of trailing semicolons
+ return if ($stmt =~ /^\s*$/);
+ return if ($stmt =~ /^\s*\#/);
+ my ($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
+
+ #define alias
+# print "doing [$multi_alias]: $stmt\n";
+ if ($name eq "alias" || $multi_alias) {
+ if ($multi_alias) {
+ if ($stmt =~ /^prompt\s+(\d+)\s+[\"\'](.+)[\"\']/) {
+ $aliases{$current_alias}{'prompts'}[$1] = $2;
+ return;
+ } elsif ($stmt =~ /^prompt\s+(\d+)\s+(.+)/) {
+ my $x = $2;
+ my $spot = $1;
+ $x =~ s/\s+$//;
+ $aliases{$current_alias}{'prompts'}[$spot] = "$x ";
+ return;
+ } elsif ($stmt =~ /^\s*\}\s*$/) {
+ $prompt = $oprompt;
+ $multi_alias = 0;
+ return;
+ }
+ push @{$aliases{$current_alias}{'definition'}},$stmt;
+ return;
+ }
+ $stmt =~ s/^alias\s+//;
+ if ($args eq "") {
+ foreach $i (sort keys(%aliases)) {
+ display_alias($i);
+ }
+ return;
+ }
+ ($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
+ if ($args eq "") {
+ display_alias($name);
+ return;
+ }
+# print "alias: $name $args\n";
+ if ($args eq "{") {
+ $oprompt = $prompt;
+ $prompt = "define $name> ";
+ $current_alias = $name;
+ $multi_alias = 1;
+ $aliases{$name}{'definition'} = [];
+ return;
+ }
+ $aliases{$name}{'definition'} = $args;
+ return;
+ }
+
+ #eval
+ if ($name eq "eval") {
+ eval $args;
+ return;
+ }
+
+ #eval just vars
+ if ($name eq "evalvars") {
+# print "args1:",$args,"\n";
+ $args =~ s/\$(\w+)/$$1/eg;
+# print "args2:",$args,"\n";
+ netsh($args);
+ return;
+ }
+
+ #eval aliases
+ while (exists $aliases{$name}) {
+# print "modified: $stmt -> ";
+ my @ARGS = split(/\s+/,$args);
+ my $statements;
+ if (ref($aliases{$name}{'definition'}) eq "ARRAY") {
+ $statements = $aliases{$name}{'definition'};
+
+ # maybe prompt for values
+ if ($#{$aliases{$name}{'prompts'}} > -1) {
+ my $i;
+ for($i = 1; $i <= $#{$aliases{$name}{'prompts'}}; $i++) {
+ if (!$ARGS[$i-1] && $term) {
+ $ARGS[$i-1] =
+ $term->readline($aliases{$name}{'prompts'}[$i]);
+ }
+ }
+ }
+ } else {
+ $statements = [$aliases{$name}{'definition'}];
+ }
+ foreach my $stmt (@$statements) {
+ #print "$stmt -> ";
+ $stmt =~ s/\\(\d+)/$ARGS[$1-1]/g;
+# print "running $stmt\n";
+ ($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
+ netsh($stmt);
+ }
+ return;
+ }
+
+ if ($stmt =~ /^rehash$/) {
+ load_rcs();
+ return;
+ }
+
+ my $subfn;
+
+ if ($stmt =~ /^eval (.*)/) {
+ eval $1;
+ }
+
+ if ($stmt =~ s/^printf\s+(\".*\")\s*(.*)/$2/) {
+ if ($2 eq "") {
+ print eval $1;
+ return;
+ }
+ $subfn = \&my_printf;
+ $stmt = $2;
+ $printfmt = $1;
+ }
+
+ # special show columns statement
+ if ($stmt =~ /^show columns from (\w+)$/) {
+ my $mibnode = $SNMP::MIB{$1};
+ my $entrynode = $mibnode->{children}[0];
+ if (!defined($mibnode) || !defined($entrynode)) {
+ print STDERR "no such table: $1\n";
+ return;
+ }
+ if ($opts{'t'}) {
+ map { print $_->{label},"\n"; } sort { $a->{subID} <=> $b->{subID}} @{$entrynode->{children}};
+ } else {
+ $table = Text::FormatTable->new('|r|');
+ $table->rule('-');
+ $table->head('Column');
+ $table->rule('-');
+ map { $table->row($_->{label}); } sort { $a->{subID} <=> $b->{subID}} @{$entrynode->{children}};
+ $table->rule('-');
+ print $table->render();
+ }
+ return;
+ }
+
+ if ($stmt =~ /^source\s+(.*)/) {
+ source_file($1);
+ return;
+ }
+
+ if ($stmt =~ s/^export\s+(\S+)\s+(.*)/$2/) {
+ $insh = undef;
+ unlink($1);
+ $exporth = DBI->connect('dbi:AnyData:');
+ $exporth->func('exporttable','CSV',$1,'ad_catalog');
+ $subfn = \&my_export;
+ }
+
+ if ($stmt =~ /^import\s+(\S+)/) {
+ my $exporth = DBI->connect('dbi:AnyData:');
+ $exporth->func('exporttable','CSV',$1,'ad_catalog');
+ my $selh = $exporth->prepare("select * from exporttable");
+ $selh->execute();
+ $old_data = [];
+ while(my $row = $selh->fetchrow_arrayref) {
+ push @$old_data, @$row;
+ }
+ $selh->finish();
+ $exporth->disconnect();
+ return;
+ }
+
+ if ($stmt =~ /^diff\s+(.*)/) {
+ $running_watch = 2;
+ netsh($1);
+ $running_watch = 0;
+ return;
+ }
+
+ if ($stmt =~ /^watch\s+(.*)/) {
+ $running_watch = 1;
+ my $cmd = $1;
+ my $delay = 1;
+ my $clear = `clear`;
+ if ($cmd =~ s/^(\d+)\s+(.*)/$2/) {
+ $delay = $1;
+ $cmd = $2;
+ }
+ $SIG{'TERM'} = sub { $running_watch = 0; };
+ $SIG{'INT'} = sub { $running_watch = 0; };
+ while($running_watch) {
+ print $clear;
+ netsh($cmd);
+ sleep($delay);
+ }
+ $SIG{'TERM'} = \&exit;
+ $SIG{'INT'} = \&exit;
+ return;
+ }
+
+ # we have an SQL statement. process it.
+ if ($stmt =~ /^(select|insert|update|delete)/) {
+ $sth = $dbh->prepare($stmt);
+ $sth->execute();
+ if ($stmt =~ /^select/) {
+ my $table;
+ my $older_data = $old_data;
+ if ($running_watch == 1) {
+ $old_data = [];
+ }
+ my $oldcount = 0;
+ while($row = $sth->fetchrow_arrayref) {
+
+ if ($running_watch) {
+ $newrow=[];
+ my $count;
+ for($count = 0; $count <= $#$row; $count++) {
+ if ($older_data &&
+ $row->[$count] ne
+ $older_data->[$oldcount][$count]) {
+ if ($ansicolor) {
+ push @$newrow, new color_string($row->[$count],'red');
+ } else {
+ push @$newrow,"$begin$row->[$count]$end";
+ }
+ } else {
+ push @$newrow,$row->[$count];
+ }
+ if ($running_watch == 1) {
+ $old_data->[$oldcount][$count] = $row->[$count];
+ }
+ }
+ $oldcount++;
+ $row = $newrow;
+ }
+
+ # self printing;
+ if (ref($subfn) eq "CODE") {
+ &$subfn($printfmt,@$row);
+ next;
+ }
+
+ if ($opts{'t'}) {
+ if ($opts{'d'} eq 'xml') {
+ print " <row>\n";
+ for(my $xx = 0; $xx < $#{$sth->{NAME}}; $xx++) {
+ print " <$sth->{NAME}[$xx]>$row->[$xx]</$sth->{NAME}[$xx]>\n";
+ }
+ print " </row>\n";
+ } elsif ($opts{'d'} eq 'xmlshort') {
+ print " <row ";
+ for(my $xx = 0; $xx < $#{$sth->{NAME}}; $xx++) {
+ print " $sth->{NAME}[$xx]=\"$row->[$xx]\"";
+ }
+ print "/>\n";
+ } else {
+ print join($opts{'d'},@$row),"\n";
+ }
+ } elsif (!$table) {
+ $table = Text::FormatTable->new('|r' x ($#$row+1) . "|");
+ $table->rule('-');
+ $table->head(@{$sth->{NAME}});
+ $table->rule('-');
+ $table->row(@$row);
+ } else {
+ $table->row(@$row);
+ }
+ }
+ if ($table) {
+ $table->rule('-');
+ print $table->render();
+ }
+ }
+ $sth->finish();
+ return;
+ }
+
+ # retrieve just one variable and display it
+ if ($stmt =~ /^(get|)\s*([^\s]+)\s*[^=]/) {
+ my $sess = make_session();
+ if ($sess) {
+ my @results = split(/[,\s]+/,$stmt);
+ my $resultsv = new SNMP::VarList();
+ # expression stolen from the main perl SNMP module
+ map { my ($tag, $iid) =
+ (/^((?:\.\d+)+|(?:\w+(?:\-*\w+)+))\.?(.*)$/);
+ push @$resultsv, [$tag, $iid] } @results;
+ $sess->get($resultsv) ||
+ print STDERR "Error: $sess->{ErrorNum} $sess->{ErrString}\n";
+ @results = ();
+ map { push @results, $_->[2] } @$resultsv;
+ if (ref($subfn) eq "CODE") {
+ &$subfn($printfmt,@results);
+ } else {
+ print join(" ", @results),"\n";
+ }
+ } else {
+ print STDERR "could not establish a SNMP session to $host\n";
+ }
+ return;
+ }
+
+ # set something
+ if ($stmt =~ /^(set|)\s*([^\s]+)\s=\s(.*)$/) {
+ my $sess = make_session();
+ if ($sess) {
+ $sess->set([$2,undef,$1]) ||
+ print STDERR "opps: $sess->{ErrorNum} $sess->{ErrString}\n";
+ } else {
+ print STDERR "could not establish a SNMP session to $host\n";
+ }
+ return;
+ }
+}
+
+sub auto_snmp {
+ my $node = $SNMP::MIB{$_[0]};
+# print STDERR "netsh::fetch_snmp $_[0] $node->{label}\n";
+ my $indexes = $node->{parent}{indexes};
+ if ($#$indexes > -1) {
+# print STDERR "column\n";
+ # table
+ } else {
+ # scalar
+ if (exists($_[1])) {
+ my $sess = make_session();
+ my $val = $sess->set([$_[0],0,$_[1]]) || return;
+# print STDERR "scalar set: $val\n";
+ return $val;
+ } else {
+ my $sess = make_session();
+ my $val = $sess->get([$_[0],0]);
+# print STDERR "scalar get: $val\n";
+ return $val;
+ }
+ }
+}
+
+sub AUTOLOAD {
+ my $nodename = $AUTOLOAD;
+ $nodename =~ s/.*:://;
+ print STDERR "netsh::AUTOLOAD $AUTOLOAD $nodename\n";
+ if ($SNMP::MIB{$nodename}) {
+ eval << "END";
+ sub $AUTOLOAD {
+ auto_snmp($nodename, \@_);
+ }
+END
+ goto &$AUTOLOAD;
+ }
+ print STDERR join(",",@_),"\n";
+}
+
+sub my_printf {
+ # drop quotes
+ my $fmt = shift;
+ $fmt = eval $fmt;
+ map { if (ref($_) eq "color_string") { $_->colorize_next(); } } @_;
+ printf($fmt, @_);
+}
+
+sub display_alias {
+ my $name = shift;
+ if (exists $aliases{$name}{'definition'}) {
+ if (ref($aliases{$name}{'definition'}) eq "ARRAY") {
+ print "alias $name {\n";
+ map { print " $_\n"; } @{$aliases{$name}{'definition'}};
+ print "}\n";
+ } else {
+ print "alias $name $aliases{$name}{'definition'}\n";
+ }
+ } else {
+ print "no alias defined for \"$name\"\n";
+ }
+}
+
+sub make_session {
+ if (!$sess) {
+ $sess = new SNMP::Session(@sessparms);
+ }
+ return $sess;
+}
+
+
+sub usage {
+ print STDERR "
+$0 [ARGUMENTS] HOSTNAME [SQL_COMMAND]
+
+ $0 implements a simple SQL shell which maps onto SNMP. All
+ statements issued within the shell are converted to SNMP requests and
+ sent to HOSTNAME and the results displayed in a nice table output
+ format if the Text::FormatTable module is available. If SQL_COMMAND
+ is given on the command line, then it's interpreted and control is
+ returned to the caller. If not, an interactive prompt is given where
+ multiple commands can be issued.
+
+ARGUMENTS may include:
+
+ -t delimiter separated output, don't print pretty tables.
+ -d DELIM use DELIM as the delimiter. A tab is the default delimiter.
+ 'xml' is a special delimiter to produce xml output.
+
+ARGUMENTS also may include the following. See the net-snmp snmpcmd
+manual page for details on what they mean:
+
+ -v VERSION (default: 1)
+ -t TIMEOUT
+ -r RETRIES
+ -p PORT
+ -c COMMUNITY
+ -a AUTHPROTOCOL (default: MD5)
+ -x PRIVPROTOCOL (default: DES)
+ -A AUTHPASS
+ -X PRIVPASS
+ -l SECURITY_LEVEL (default: authNoPriv)
+
+";
+ exit;
+}
+
+__END__
+
+=head1 NAME
+
+netsh - A shell environment for interacting with networking devices
+
+=head1 SYNOPSIS
+
+netsh [(subset of) snmpcmd arguments] hostname[,hostname...] [command]
+
+=head1 OPTIONAL PERL MODULES
+
+There are some optional perl modules which make using the shell nicer
+in general. These modules are:
+
+ Text::FormatTable
+ Term::ReadLine::Gnu or Term::ReadLine::Perl
+ Term::ANSIColor
+
+You can install these by running [as root]:
+
+ perl -MCPAN -e shell
+ cpan> install Text::FormatTable
+ ...
+
+It is B<strongly> recommend you at least install the Text::FormatTable
+module, and if you like command line editing one of the two extra
+Term::ReadLine modules (Gnu being the better of the two).
+
+=head1 DESCRIPTION
+
+The netsh script provides an interactive, console-like environment
+suitable for monitoring and manipulating data within networking
+devices. The environment is highly extensible through command
+aliases and easy-to-use SQL-like queries.
+
+It is implemented on top of the SNMP protocol using the net-snmp
+package and perl. See the snmpcmd and snmp.conf manual pages for
+details on configuring net-snmp for authentication information for
+the networking devices you wish to access.
+
+=head1 ABOUT THE EXAMLPES IN THIS DOCUMENT
+
+All the examples in this document are exact cut-n-pastes from the
+inside of the netsh shell. This includes the "netsh> " prompt and
+possibly other prompts as well.
+
+=head1 COMMANDS
+
+The following is a list of the basic core commands supported by
+netsh. Many default aliases are also supplied, some of which are
+listed in the next section. At the command prompt type "alias" for
+a full list of all the aliases and their definitions.
+
+=over
+
+=item show columns from TABLE
+
+=item select ...
+
+=item update ...
+
+=item insert ...
+
+=item delete ...
+
+netsh supports the standard sql-like language queries of snmp tables.
+These are implemented via the SQL::Statement parser, so any form of
+expression it accepts netsh will accept as well.
+
+Examples:
+
+ netsh> show columns from ifTable
+ +-----------------+
+ | Column|
+ +-----------------+
+ | ifIndex|
+ ...
+ netsh> select * from ifTable
+ ... [output not shown]
+ netsh> select tcpConnState, tcpConnRemotelAddress from tcpConnTable where tcpConnState = established
+ ... [output not shown]
+ netsh> update ifTable set ifAdminStatus = up where ifOperStatus = down
+ ... [output not shown]
+
+=item SNMPOBJECT
+
+Simple lists of objects may be given which will directly request or
+operate on those objects. See printf below for controlling the
+formatting of results
+
+Examples:
+
+ netsh> sysContact.0, sysLocation.0
+ hardaker@somewhere.net my location
+ netsh> sysContact.0 = my new contact information
+
+=item alias my_command some other command
+
+or
+
+=back
+
+alias my_many_commands {
+ command1
+ command2
+ prompt NUMBER question
+
+}
+
+=over
+
+=item
+
+You can create aliases of your frequently used commands by aliasing
+them to an easy to remember name. \N parameters in the defined
+command will be replaced by the positional argument of options passed
+to the alias name.
+
+For multi-line defined aliases, optional prompts may be given to
+request information from the user when the NUMBERth argument is not
+given to the alias. If it is not given, the prompt will be printed
+and the user will be asked to input a value for it. This allows the
+easy definition of interactive commands. The value will be inserted
+in alias parts containing \N substitution requests.
+
+ netsh> alias interfaces select ifDescr from ifTable
+ netsh> interfaces
+ +-------+
+ |ifDescr|
+ +-------+
+ | lo|
+ | eth0|
+ +-------+
+ netsh> alias interface select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
+ netsh> interface eth0
+ +-------+--------+
+ |ifDescr| ifSpeed|
+ +-------+--------+
+ | eth0|10000000|
+ +-------+--------+
+
+=item printf FORMATSTRING COMMAND
+
+Allows B<careful> formatting of results returned by the commands.
+
+Example:
+
+ netsh> alias interface {
+ define interface> printf "interface %s is running at %d Mb/s\n" select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
+ define interface> prompt 1 Enter the interface to describe:
+ define interface> }
+ netsh> interface
+ Enter the interface to describe: eth0
+ interface eth0 is running at 10000000 Mb/s
+
+To list the definition of an already defined command, simply exclude
+the definition and netsh will report the definition to you:
+
+ netsh> alias interface
+ alias interface {
+ printf "interface %s is running at %d Mb/s\n" select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
+ prompt 1 Enter the interface to describe:
+ }
+
+To list all the aliases defined in the system, just type "alias" by itself.
+
+=item watch [TIME] COMMAND
+
+Continually watches the results of the COMMAND being run, which is run
+every TIME seconds. For select statements, it will attempt to mark
+the changing values from one screen to the next by surrounding them
+with "*"s or color (assuming you have the Term::ANSIColor perl module
+installed) for easy picking out on the screen.
+
+=item rehash
+
+Re-load the alias definitions files in the common directory, as
+well as those files found in $HOME/.snmp/netsh.
+
+=item source FILE
+
+loads definitons and commands from FILE into the running environment.
+
+=back
+
+=head1 FILES
+
+By default, netsh will source all the definition files it can find.
+It does this by first reading everything in
+/usr/local/share/snmp/netsh/* and then reading everything in
+$HOME/.snmp/netsh/*. Everything contained in these files are
+commands, but most frequently they entirely consist of aliases
+definitions.
+
+=head1 AUTHOR
+
+bugs, comments, questions to net-snmp-users@lists.sourceforge.net
+
+=head1 Copyright
+
+ Copyright (c) 2002 Networks Associates Technology, Inc. All
+ rights reserved. This program is free software; you can
+ redistribute it and/or modify it under the same terms as Perl
+ itself.
+
+=cut
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
new file mode 100644
index 0000000..31fdc40
--- /dev/null
+++ b/perl/Makefile.PL
@@ -0,0 +1,160 @@
+use ExtUtils::MakeMaker;
+use Config;
+use Getopt::Long;
+require 5;
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+sub InitMakeParams {
+ $nsconfig="net-snmp-config"; # in path by default
+ my %Params = (
+ 'NAME' => 'Bundle::NetSNMP',
+ 'DIR' => [qw(default_store ASN OID agent SNMP TrapReceiver)],
+ );
+
+ # bogus, but these options need to be passed to the lower levels
+ $opts = NetSNMPGetOpts("./");
+
+ return(%Params);
+}
+
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/Makefile.makefiles b/perl/Makefile.makefiles
new file mode 100644
index 0000000..073815b
--- /dev/null
+++ b/perl/Makefile.makefiles
@@ -0,0 +1,12 @@
+GENERATE_LIST=./Makefile.PL \
+ ./default_store/Makefile.PL \
+ ./ASN/Makefile.PL \
+ ./OID/Makefile.PL \
+ ./agent/Makefile.PL \
+ ./agent/default_store/Makefile.PL \
+ ./agent/Support/Makefile.PL \
+ ./SNMP/Makefile.PL \
+ ./TrapReceiver/Makefile.PL
+
+all:
+ perl make-perl-makefiles $(GENERATE_LIST)
diff --git a/perl/Makefile.subs.pl b/perl/Makefile.subs.pl
new file mode 100644
index 0000000..e3c25ef
--- /dev/null
+++ b/perl/Makefile.subs.pl
@@ -0,0 +1,136 @@
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/OID/Changes b/perl/OID/Changes
new file mode 100644
index 0000000..96fe31d
--- /dev/null
+++ b/perl/OID/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension OID.
+
+0.01 Mon Apr 29 16:58:40 2002
+ - original version; created by h2xs 1.21 with options
+ OID.h
+
diff --git a/perl/OID/MANIFEST b/perl/OID/MANIFEST
new file mode 100644
index 0000000..b9008af
--- /dev/null
+++ b/perl/OID/MANIFEST
@@ -0,0 +1,7 @@
+Changes
+Makefile.PL
+MANIFEST
+OID.pm
+OID.xs
+README
+test.pl
diff --git a/perl/OID/Makefile.PL b/perl/OID/Makefile.PL
new file mode 100644
index 0000000..6bb1616
--- /dev/null
+++ b/perl/OID/Makefile.PL
@@ -0,0 +1,234 @@
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::OID',
+ 'VERSION_FROM' => 'OID.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ 'PREREQ_PM' => {},
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+# } else {
+# $Params{'PREREQ_PM'} = {'SNMP' => '5.0'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+
+ return(%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/OID/OID.pm b/perl/OID/OID.pm
new file mode 100644
index 0000000..fa6b162
--- /dev/null
+++ b/perl/OID/OID.pm
@@ -0,0 +1,256 @@
+package NetSNMP::OID;
+
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+sub compare($$);
+
+use overload
+ '<=>' => \&compare,
+ 'cmp' => \&oidstrcmp,
+ '""' => \&quote_oid,
+ '+' => \&add,
+;
+
+use SNMP;
+
+sub quote_oid {
+ return $_[0]->{'oidptr'}->to_string();
+}
+
+sub length {
+ return $_[0]->{'oidptr'}->length();
+}
+
+sub get_indexes {
+ return $_[0]->{'oidptr'}->get_indexes();
+}
+
+sub append {
+ my $this = shift;
+ my $str = shift;
+
+ if (ref($str) eq 'NetSNMP::OID') {
+ return $this->{'oidptr'}->append_oid($str->{'oidptr'});
+ }
+ $str = "." . $str if ($str =~ /^\d+/);
+ if ($str =~ /^[.\d]+/) {
+ # oid segment
+ return $this->{'oidptr'}->append($str);
+ }
+ if ($str =~ /^\"(.*)\"$/) {
+ # string index
+ my $newstr = "." . CORE::length($1);
+ map { $newstr .= ".$_" } unpack("c*",$1);
+ return $this->{'oidptr'}->append($newstr);
+ }
+ if ($str =~ /^\'(.*)\'$/) {
+ # string index, implied
+ my $newstr;
+ map { $newstr .= ".$_" } unpack("c*",$1);
+ return $this->{'oidptr'}->append($newstr);
+ }
+ # Just Parse it...
+ return $this->{'oidptr'}->append($str);
+}
+
+sub add {
+ my $this = shift;
+ my $str = shift;
+ my ($newoid, %newhash);
+ $newoid = \%newhash;
+ $newoid->{'oidptr'} = $this->{'oidptr'}->clone();
+ bless($newoid, ref($this));
+ $newoid->append($str);
+ return $newoid;
+}
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD);
+
+@ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::OID ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ snmp_oid_compare
+ compare
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ snmp_oid_compare
+ compare
+);
+$VERSION = '5.0702';
+
+sub new {
+ my $type = shift;
+ my $arg = shift;
+ if (!$arg) {
+ $arg = $type;
+ $type = "NetSNMP::OID";
+ }
+ SNMP::init_snmp("perl");
+ my $ptr = NetSNMP::OID::newptr($arg);
+ if ($ptr) {
+ return newwithptr($type, $ptr);
+ }
+}
+
+sub newwithptr {
+ my $type = shift;
+ my $ptr = shift;
+ my $self = {};
+ if (!$ptr) {
+ $ptr = $type;
+ $type = "NetSNMP::OID";
+ }
+ SNMP::init_snmp("perl");
+ $self->{'oidptr'} = $ptr;
+ bless($self, $type);
+ return $self;
+}
+
+sub snmp_oid_compare($$) {
+ my ($oid1, $oid2) = @_;
+ return _snmp_oid_compare($oid1->{oidptr}, $oid2->{oidptr});
+}
+
+sub compare($$) {
+ my ($v1, $v2) = @_;
+ snmp_oid_compare($v1, $v2);
+}
+
+sub oidstrcmp {
+ my ($v1, $v2) = @_;
+ $v1->{'oidptr'}->to_string cmp $v2->{'oidptr'}->to_string;
+}
+
+sub to_array($) {
+ my $self = shift;
+ return $self->{oidptr}->to_array();
+}
+
+sub DESTROY {}
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "& not defined" if $constname eq 'constant';
+ my $val;
+ ($!, $val) = constant($constname);
+ if ($! != 0) {
+ if ($! =~ /Invalid/ || $!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined NetSNMP::OID macro $constname";
+ }
+ }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+ if ($] >= 5.00561) {
+ *$AUTOLOAD = sub () { $val };
+ }
+ else {
+ *$AUTOLOAD = sub { $val };
+ }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap NetSNMP::OID $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::OID - Perl extension for manipulating OIDs
+
+=head1 SYNOPSIS
+
+ use NetSNMP::OID;
+
+ my $oid = new NetSNMP::OID('sysContact.0');
+
+ if ($oid < new NetSNMP::OID('ifTable')) {
+ do_something();
+ }
+
+ my @numarray = $oid->to_array();
+
+ # appending oids
+ $oid = new NetSNMP::OID('.1.3');
+ $oid += ".6.1";
+ # -> .1.3.6.1
+
+ # appending index strings
+
+ $oid2 = $oid + "\"wes\"";
+ # -> .1.3.6.1.3.119.101.115
+
+ $oid3 = $oid + "\'wes\'";
+ # -> .1.3.6.1.119.101.115
+
+ $len = $oid3->length();
+ # -> 7
+
+ # retrieving indexes from an oid:
+ $arrayref = $tableoid->get_indexes()
+
+=head1 DESCRIPTION
+
+The NetSNMP::OID module is a simple wrapper around a C-based net-snmp
+oid (which is an array of unsigned integers). The OID is internally
+stored as a C array of integers for speed purposes when doing
+comparisons, etc.
+
+The standard logical expression operators (<, >, ==, ...) are
+overloaded such that lexographical comparisons may be done with them.
+
+The + operator is overloaded to allow you to append stuff on to the
+end of a OID, like index segments of a table, for example.
+
+=head2 EXPORT
+
+int snmp_oid_compare(oid1, oid2)
+int compare(oid1, oid2)
+
+=head1 AUTHOR
+
+Wes Hardaker, E<lt>hardaker@users.sourceforge.netE<gt>
+
+=head1 SEE ALSO
+
+L<SNMP>, L<perl>.
+
+=head1 Copyright
+
+Copyright (c) 2002 Networks Associates Technology, Inc. All
+Rights Reserved. This program is free software; you can
+redistribute it and/or modify it under the same terms as Perl
+itself.
+
+=cut
diff --git a/perl/OID/OID.xs b/perl/OID/OID.xs
new file mode 100644
index 0000000..10485f9
--- /dev/null
+++ b/perl/OID/OID.xs
@@ -0,0 +1,442 @@
+/* -*- C -*- */
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+/* pulled from Dave's, yet-to-be-used, net-snmp library rewrite.
+ autocompatibility for the future? */
+
+typedef struct netsnmp_oid_s {
+ oid *name;
+ size_t len;
+ oid namebuf[ MAX_OID_LEN ];
+} netsnmp_oid;
+
+static int constant(double *value, const char *name, const int len)
+{
+ return EINVAL;
+}
+
+netsnmp_oid *
+nso_newarrayptr(oid *name, size_t name_len)
+{
+ netsnmp_oid *RETVAL;
+ RETVAL = malloc(sizeof(netsnmp_oid));
+ RETVAL->name = RETVAL->namebuf;
+ RETVAL->len = name_len;
+ memcpy(RETVAL->name, name, name_len * sizeof(oid));
+ return RETVAL;
+}
+
+static int __sprint_num_objid _((char *, oid *, int));
+
+/* stolen from SNMP.xs. Ug, this needs merging to snmplib */
+/* XXX: this is only here because snmplib forces quotes around the
+ data and won't return real binary data or a numeric string. Every
+ app must do its own switch() to get around it. Ug. */
+#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, buf_len, 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,".%" NETSNMP_PRIo "u",*objid++);
+ buf += strlen(buf);
+ }
+ return SNMPERR_SUCCESS;
+}
+
+MODULE = NetSNMP::OID PACKAGE = NetSNMP::OID PREFIX=nso_
+
+netsnmp_oid *
+nso_newptr(initstring)
+ char *initstring
+ CODE:
+ if (get_tree_head() == NULL)
+ netsnmp_init_mib();
+ RETVAL = malloc(sizeof(netsnmp_oid));
+ RETVAL->name = RETVAL->namebuf;
+ RETVAL->len = sizeof(RETVAL->namebuf)/sizeof(RETVAL->namebuf[0]);
+ if (!snmp_parse_oid(initstring, (oid *) RETVAL->name, &RETVAL->len)) {
+ snmp_log(LOG_ERR, "Can't parse: %s\n", initstring);
+ RETVAL->len = 0;
+ free(RETVAL);
+ RETVAL = NULL;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+constant(sv)
+ PREINIT:
+ STRLEN len;
+ INPUT:
+ SV * sv
+ char * s = SvPV(sv, len);
+ INIT:
+ int status;
+ double value;
+ PPCODE:
+ value = 0;
+ status = constant(&value, s, len);
+ XPUSHs(sv_2mortal(newSVuv(status)));
+ XPUSHs(sv_2mortal(newSVnv(value)));
+
+int
+_snmp_oid_compare(oid1, oid2)
+ netsnmp_oid *oid1;
+ netsnmp_oid *oid2;
+ CODE:
+ RETVAL = snmp_oid_compare((oid *) oid1->name, oid1->len,
+ (oid *) oid2->name, oid2->len);
+ OUTPUT:
+ RETVAL
+
+MODULE = NetSNMP::OID PACKAGE = netsnmp_oidPtr PREFIX = nsop_
+
+void
+nsop_DESTROY(oid1)
+ netsnmp_oid *oid1
+ CODE:
+{
+ if (oid1->name != oid1->namebuf) {
+ free(oid1->name);
+ }
+ free(oid1);
+}
+
+char *
+nsop_to_string(oid1)
+ netsnmp_oid *oid1
+ PREINIT:
+ static char mystr[SNMP_MAXBUF];
+ CODE:
+ {
+ if (oid1->len == 0)
+ snprintf(mystr, sizeof(mystr), "Illegal OID");
+ else
+ snprint_objid(mystr, sizeof(mystr),
+ (oid *) oid1->name, oid1->len);
+ RETVAL = mystr;
+ }
+
+ OUTPUT:
+ RETVAL
+
+void
+nsop_to_array(oid1)
+ netsnmp_oid *oid1;
+ PREINIT:
+ int i;
+
+ PPCODE:
+ EXTEND(SP, oid1->len);
+ for(i=0; i < (int)oid1->len; i++) {
+ PUSHs(sv_2mortal(newSVnv(oid1->name[i])));
+ }
+
+SV *
+nsop_get_indexes(oid1)
+ netsnmp_oid *oid1;
+ PREINIT:
+ int i, nodecount;
+ struct tree *tp, *tpe, *tpnode, *indexnode;
+ struct index_list *index;
+ netsnmp_variable_list vbdata;
+ u_char *buf = NULL;
+ size_t buf_len = 256, out_len = 0;
+ oid name[MAX_OID_LEN];
+ size_t name_len = MAX_OID_LEN;
+ oid *oidp;
+ size_t oidp_len;
+ AV *myret;
+ int is_private;
+
+ CODE:
+ {
+ memset(&vbdata, 0, sizeof(vbdata));
+ if (NULL == (tp = get_tree(oid1->name, oid1->len,
+ get_tree_head()))) {
+ RETVAL = NULL;
+ return;
+ }
+
+ if ((buf = netsnmp_malloc(buf_len)) == NULL) {
+ RETVAL = NULL;
+ return;
+ }
+
+ tpe = NULL;
+ nodecount = 0;
+ for(tpnode = tp; tpnode; tpnode = tpnode->parent) {
+ nodecount++;
+ if (nodecount == 2)
+ tpe = tpnode;
+ if (nodecount == 3 &&
+ (strlen(tpnode->label) < 6 ||
+ strcmp(tpnode->label + strlen(tpnode->label) - 5,
+ "Table"))) {
+ /* we're not within a table. bad logic, little choice */
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return;
+ }
+ }
+
+ if (!tpe) {
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return;
+ }
+
+ if (tpe->augments && strlen(tpe->augments) > 0) {
+ /* we're augmenting another table, so use that entry instead */
+ if (!snmp_parse_oid(tpe->augments, name, &name_len) ||
+ (NULL ==
+ (tpe = get_tree(name, name_len,
+ get_tree_head())))) {
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return; /* XXX: better error recovery needed? */
+ }
+ }
+
+ i = 0;
+ for(index = tpe->indexes; index; index = index->next) {
+ i++;
+ }
+
+ myret = (AV *) sv_2mortal((SV *) newAV());
+
+ oidp = oid1->name + nodecount;
+ oidp_len = oid1->len - nodecount;
+
+ for(index = tpe->indexes; index; index = index->next) {
+ /* XXX: NOT efficient! */
+ name_len = MAX_OID_LEN;
+ if (!snmp_parse_oid(index->ilabel, name, &name_len) ||
+ (NULL ==
+ (indexnode = get_tree(name, name_len,
+ get_tree_head())))) {
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return; /* xxx mem leak */
+ }
+ vbdata.type = mib_to_asn_type(indexnode->type);
+
+ if (vbdata.type == (u_char) -1) {
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return; /* XXX: not good. half populated stack? */
+ }
+
+ /* check for fixed length strings */
+ if (vbdata.type == ASN_OCTET_STR &&
+ indexnode->ranges && !indexnode->ranges->next
+ && indexnode->ranges->low == indexnode->ranges->high) {
+ vbdata.val_len = indexnode->ranges->high;
+ vbdata.type |= ASN_PRIVATE;
+ is_private = 1;
+ } else {
+ vbdata.val_len = 0;
+ if (index->isimplied) {
+ vbdata.type |= ASN_PRIVATE;
+ is_private = 1;
+ } else {
+ is_private = 0;
+ }
+ }
+
+ if (parse_one_oid_index(&oidp, &oidp_len, &vbdata, 0)
+ != SNMPERR_SUCCESS) {
+ netsnmp_free(buf);
+ RETVAL = NULL;
+ return;
+ }
+ out_len = 0;
+ if (is_private)
+ vbdata.type ^= ASN_PRIVATE;
+ out_len =
+ __snprint_value (buf, buf_len, &vbdata, indexnode,
+ vbdata.type, 0);
+/*
+ sprint_realloc_value(&buf, &buf_len, &out_len,
+ 1, name, name_len, &vbdata);
+*/
+ snmp_free_var_internals(&vbdata);
+ av_push(myret, newSVpv((char *)buf, out_len));
+ }
+ netsnmp_free(buf);
+ RETVAL = newRV((SV *)myret);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+nsop_append(oid1, string)
+ netsnmp_oid *oid1;
+ char *string;
+ PREINIT:
+ oid name[MAX_OID_LEN];
+ size_t name_len = MAX_OID_LEN;
+ int i;
+ CODE:
+ {
+ if (!snmp_parse_oid(string, (oid *) name, &name_len)) {
+ /* XXX */
+ }
+ if (oid1->len + name_len > MAX_OID_LEN) {
+ /* XXX: illegal */
+ }
+ for(i = 0; i < (int)name_len; i++) {
+ oid1->name[i+oid1->len] = name[i];
+ }
+ oid1->len += name_len;
+ }
+
+void
+nsop_append_oid(oid1, oid2)
+ netsnmp_oid *oid1;
+ netsnmp_oid *oid2;
+ PREINIT:
+ int i;
+ CODE:
+ {
+ if (oid1->len + oid2->len > MAX_OID_LEN) {
+ /* XXX: illegal */
+ }
+ for(i = 0; i < (int)oid2->len; i++) {
+ oid1->name[i+oid1->len] = oid2->name[i];
+ }
+ oid1->len += oid2->len;
+ }
+
+int
+nsop_length(oid1)
+ netsnmp_oid *oid1;
+ CODE:
+ {
+ RETVAL = oid1->len;
+ }
+ OUTPUT:
+ RETVAL
+
+netsnmp_oid *
+nsop_clone(oid1)
+ netsnmp_oid *oid1;
+ PREINIT:
+ netsnmp_oid *oid2;
+ CODE:
+ {
+ oid2 = nso_newarrayptr(oid1->name, oid1->len);
+ RETVAL = oid2;
+ }
+OUTPUT:
+ RETVAL
+
diff --git a/perl/OID/README b/perl/OID/README
new file mode 100644
index 0000000..0355446
--- /dev/null
+++ b/perl/OID/README
@@ -0,0 +1,31 @@
+OID version 0.01
+================
+
+The NetSNMP::OID class is a simple wrapper around a C-based net-snmp
+oid. The OID is internally stored as a C array of integers for speed
+purposes when doing comparisons, etc. The standard logical expression
+operators (<, >, ==, ...) are overloaded such that lexographical
+comparisons may be done with them.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ The net-snmp 5.0 or greater release
+ The SNMP 5.0.1 or greater perl module.
+
+COPYRIGHT AND LICENCE
+
+Copyright (c) 2002 Networks Associates Technology, Inc. All
+Rights Reserved. This program is free software; you can
+redistribute it and/or modify it under the same terms as Perl
+itself.
diff --git a/perl/OID/netsnmp-feature-definitions.h b/perl/OID/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..fb4ccdb
--- /dev/null
+++ b/perl/OID/netsnmp-feature-definitions.h
@@ -0,0 +1,6 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+netsnmp_feature_require(snprint_objid)
+netsnmp_feature_require(snprint_value)
+
diff --git a/perl/OID/test.pl b/perl/OID/test.pl
new file mode 100644
index 0000000..aee410c
--- /dev/null
+++ b/perl/OID/test.pl
@@ -0,0 +1,137 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { eval "use Cwd qw(abs_path)"; plan tests => 38 ; $ENV{'SNMPCONFPATH'} = 'nopath' ; $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs"); };
+use NetSNMP::OID;
+
+ok(1); # If we made it this far, we're ok.
+
+#########################
+
+# Insert your test code below, the Test module is use()ed here so read
+# its man page ( perldoc Test ) for help writing this test script.
+
+my $oid = new NetSNMP::OID(".1.3.6.1");
+ok(ref($oid) eq "NetSNMP::OID");
+ok(ref($oid->{oidptr}) eq "netsnmp_oidPtr");
+#print STDERR ref($oid),"\n";
+
+my $tostring = "$oid";
+#print STDERR "$tostring\n";
+ok($tostring eq "internet");
+
+my $oid2 = new NetSNMP::OID(".1.3.6.1.2");
+$tostring = "$oid2";
+#print STDERR "$tostring\n";
+ok($tostring eq "mgmt");
+
+my $oid3 = new NetSNMP::OID(".1.3.6.1");
+
+my $val = NetSNMP::OID::snmp_oid_compare($oid, $oid2);
+#print STDERR "compare result: $val\n";
+ok($val == -1);
+
+$val = $oid2->snmp_oid_compare($oid);
+#print STDERR "compare result: $val\n";
+ok($val == 1);
+
+$val = NetSNMP::OID::compare($oid, $oid);
+#print STDERR "compare result: $val\n";
+ok($val == 0);
+
+$val = $oid->compare($oid3);
+#print STDERR "compare result: $val\n";
+ok($val == 0);
+
+ok(($oid <=> $oid2) == -1);
+ok(($oid2 <=> $oid) == 1);
+ok(($oid <=> $oid3) == 0);
+
+ok($oid < $oid2);
+ok($oid <= $oid2);
+ok($oid2 > $oid);
+ok($oid2 >= $oid);
+ok($oid == $oid3);
+ok($oid <= $oid3);
+ok($oid >= $oid3);
+
+ok(new NetSNMP::OID('system') < new NetSNMP::OID('interfaces'));
+ok(new NetSNMP::OID('interfaces') > new NetSNMP::OID('system'));
+ok(new NetSNMP::OID('sysORTable') > new NetSNMP::OID('system'));
+
+my @a = $oid->to_array();
+ok($a[0] == 1 && $a[1] == 3 && $a[2] == 6 && $a[3] == 1 && $#a == 3);
+
+$oid->append(".1.2.3");
+ok("$oid" eq "directory.2.3");
+
+$oidmore = $oid + ".8.9.10";
+ok($oidmore == new NetSNMP::OID("directory.2.3.8.9.10"));
+ok("$oid" eq "directory.2.3");
+ok(ref($oidmore) eq "NetSNMP::OID");
+
+# += should work
+$oidmore += ".11";
+ok($oidmore == new NetSNMP::OID("directory.2.3.8.9.10.11"));
+
+$oidstr = $oidmore + "\"wes\"";
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.3.119.101.115"));
+
+$oidstr = $oidmore + "\'wes\'";
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.119.101.115"));
+
+# just make sure you can do it twice (ie, not modify the original)
+$oidstr = $oidmore + "\'wes\'";
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.119.101.115"));
+
+$oidstr = $oidmore + "internet";
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.1.3.6.1"));
+
+$oidstr = $oidmore + "999";
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.999"));
+
+$oidstr = $oidmore + (new NetSNMP::OID(".1.3.6.1"));
+ok($oidstr == new NetSNMP::OID("directory.2.3.8.9.10.11.1.3.6.1"));
+
+$oid = new NetSNMP::OID("nosuchoidexists");
+ok(ref($oid) ne "NetSNMP::OID");
+
+ok($oidstr->length() == 15);
+
+# multiple encoded values
+my $newtest = new NetSNMP::OID ("nsModuleName.5.109.121.99.116.120.2.1.3.14");
+
+if ($newtest) {
+ my $arrayback = $newtest->get_indexes();
+
+ ok($#$arrayback == 2 &&
+ $arrayback->[0] eq 'myctx' &&
+ $arrayback->[1] eq '.1.3' &&
+ $arrayback->[2] eq '14'
+ );
+}
+else {
+ ok(0);
+}
+
+# implied string
+$newtest = new NetSNMP::OID ("snmpNotifyRowStatus.105.110.116.101.114.110.97.108.48");
+
+if ($newtest) {
+ $arrayback = $newtest->get_indexes();
+
+ ok($#$arrayback == 0 &&
+ $arrayback->[0] eq 'internal0'
+ );
+}
+else {
+ ok(0);
+}
+
+
+
diff --git a/perl/OID/typemap b/perl/OID/typemap
new file mode 100644
index 0000000..21efbce
--- /dev/null
+++ b/perl/OID/typemap
@@ -0,0 +1,2 @@
+TYPEMAP
+netsnmp_oid * T_PTROBJ
diff --git a/perl/SNMP/BUG b/perl/SNMP/BUG
new file mode 100644
index 0000000..380e98b
--- /dev/null
+++ b/perl/SNMP/BUG
@@ -0,0 +1,40 @@
+
+1) Memory leak (have not seen this lately)
+
+The following snippet used to grow in memory (and may still) - please
+notify me if anyone still observes this and even better has a fix.
+
+perl -le '
+use SNMP;
+$obj = new SNMP::Session DestHost, "dubravka";
+while (){
+print $obj->get(["ifNumber",0]);
+}
+'
+
+***Note: need to verify this with the async API as well***
+
+2) not sure if this is a bug but I can cause a crash with a 'goto
+LABEL;' from within an async callback function.
+
+3) the following varbind format is not encoded correctly ... I have seen this crash the agent as well
+
+$sess->get(["sysDescr.0"]);
+
+use the following instead:
+
+$sess->get(["sysDescr",0]);
+or
+$sess->get("sysDescr.0");
+
+4) this is not handled yet
+$sess->get(['MODULE-NAME::mibName',0]);
+but strangely
+$sess->get(['MODULE-NAME::mibName.0']);
+works
+
+5) if you are on a system that does not have vsnprintf in libc but you
+do have BerkleyDB installed ucd configure will assume you will get it
+from there - you will need to change hints/solaris.pl to
+
+$self->{LIBS} .= ' -lkstat -ldb';
diff --git a/perl/SNMP/MANIFEST b/perl/SNMP/MANIFEST
new file mode 100644
index 0000000..cb32c37
--- /dev/null
+++ b/perl/SNMP/MANIFEST
@@ -0,0 +1,37 @@
+BUG
+examples/async1.pl
+examples/async2.pl
+examples/bulkwalk.pl
+examples/ipforward.pl
+examples/mibtree.pl
+examples/mibwalk.pl
+examples/pingmib.pl
+examples/tablewalk.pl
+examples/testleak.pl
+examples/trap-example.pl
+hints/irix.pl
+hints/solaris.pl
+Makefile.PL
+MANIFEST
+MANIFEST.SKIP
+perlsnmp.h
+README
+SNMP.pm
+SNMP.xs
+t/async.t
+t/bulkwalk.t
+t/conf.t
+t/get.t
+t/getnext.t
+t/mib.t
+t/mib.txt
+t/mibload.t
+t/notify.t
+t/README
+t/session.t
+t/set.t
+t/startagent.pl
+t/conftest.conf
+t/snmptest.conf
+TODO
+typemap
diff --git a/perl/SNMP/MANIFEST.SKIP b/perl/SNMP/MANIFEST.SKIP
new file mode 100644
index 0000000..d3183e1
--- /dev/null
+++ b/perl/SNMP/MANIFEST.SKIP
@@ -0,0 +1,11 @@
+\.bak$
+\.o$
+~$
+^Makefile$
+^Makefile.old$
+\.bs$
+\.bso$
+\.c
+\.em
+^include
+^host$
diff --git a/perl/SNMP/Makefile.PL b/perl/SNMP/Makefile.PL
new file mode 100644
index 0000000..e617cb7
--- /dev/null
+++ b/perl/SNMP/Makefile.PL
@@ -0,0 +1,363 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+my $opts;
+
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+GetTestInfo();
+
+sub InitMakeParams {
+ my %Params = (
+ NAME => 'SNMP',
+ dist => { SUFFIX => "gz", COMPRESS => "gzip -9f"},
+ MAN3PODS => { 'SNMP.pm' => '$(INST_MAN3DIR)/SNMP.3' },
+ XSPROTOARG => '-noprototypes', # XXX remove later?
+ VERSION_FROM => 'SNMP.pm',
+ realclean => { FILES => 'host' },
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ if (!$ENV{'NETSNMP_LIBS'}) {
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ } else {
+ $Params{'LIBS'} = $ENV{'NETSNMP_LIBS'};
+ }
+ if (!$ENV{'NETSNMP_CCFLAGS'}) {
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ } else {
+ $Params{'CCFLAGS'} = $ENV{'NETSNMP_CCFLAGS'};
+ }
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+# } else {
+# $Params{'PREREQ_PM'} = { 'NetSNMP::default_store' => 0.01 };
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if (!$ENV{'NETSNMP_PREFIX'}) {
+ $prefix = `$opts->{'nsconfig'} --prefix`;
+ chomp($prefix);
+ $sep = '/';
+ } else {
+ $prefix = $ENV{'NETSNMP_PREFIX'};
+ }
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+
+ return(%Params);
+
+}
+
+sub GetTestInfo {
+ my $sep = ($^O =~ /win32/i ? '\\' : '/');
+ my $info_file = "t${sep}snmptest.cmd";
+ my $snmpd_path1 = "${prefix}${sep}sbin";
+ my $snmpd_path2 = "${sep}usr${sep}sbin";
+ my $snmpd_path3 = "${sep}usr${sep}bin";
+ my $win32_snmpd_path = $ENV{'NET-SNMP-PATH'} . $sep . "bin";
+
+ open(H, ">$info_file") || die "Error: could not open file '$info_file'($!)";
+
+ my ($mibdir, $snmpd, $snmptrapd);
+
+ # Windows
+ if ($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '') {
+ if (lc ($opts->{'insource'}) eq "true") {
+ $mibdir = "../../mibs";
+ if (lc($opts->{'debug'}) eq "true") {
+ $snmpd = "../../win32/bin/debug";
+ $snmptrapd = "../../win32/bin/debug";
+ }
+ else {
+ $snmpd = "../../win32/bin/release";
+ $snmptrapd = "../../win32/bin/release";
+ }
+ } else {
+ $mibdir = $ENV{'NET-SNMP-PATH'} . "${sep}share${sep}snmp${sep}mibs";
+ $snmpd = find_files(["snmpd.exe"], [$win32_snmpd_path]);
+ $snmptrapd = find_files(["snmptrapd.exe"], [$win32_snmpd_path]);
+ }
+ }
+
+ # Unix
+ else {
+ if (lc($opts->{'insource'}) eq "true") {
+ $mibdir = "../../mibs";
+ $snmpd = "../../agent/snmpd";
+ $snmptrapd = "../../apps/snmptrapd";
+ } else {
+ $mibdir = "${prefix}${sep}share${sep}snmp${sep}mibs";
+ $snmpd = find_files(["snmpd"], [$snmpd_path1, $snmpd_path2]);
+ $snmptrapd = find_files(["snmptrapd"], [$snmpd_path1, $snmpd_path2]);
+ }
+ }
+
+ $mibdir = find_files(["NET-SNMP-MIB.txt"],[$mibdir]);
+
+ $mibdir ||= prompt("Unable to locate the MIBs, Please enter the path: ",
+ $mibdir);
+ $snmpd ||= prompt("Unable to locate \"snmpd\". Please enter the path: ",
+ $snmpd_path1);
+ $snmptrapd ||=
+ prompt("Unable to locate \"snmptrapd\". Please enter the path: ",
+ $snmpd_path1);
+
+ if ($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '') {
+ $snmpd = $snmpd . $sep . "snmpd.exe";
+ $snmptrapd = $snmptrapd . $sep . "snmptrapd.exe";
+ }
+ else {
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $snmpd =~ s/snmpd$/snmpd.exe/;
+ $snmptrapd =~ s/snmptrapd$/snmptrapd.exe/;
+ }
+ else
+ {
+ $snmpd =~ s/($sep)?(snmpd)?$/${sep}snmpd/;
+ $snmptrapd =~ s/($sep)?(snmptrapd)?$/${sep}snmptrapd/;
+ }
+ }
+
+ print H "SNMPD => $snmpd\n";
+ print H "SNMPTRAPD => $snmptrapd\n";
+ print H "MIBDIR => $mibdir\n";
+
+ if (!(lc($opts->{'insource'}) eq "true")) {
+ if (-e $snmpd and -r $snmpd) {
+ if (not -x $snmpd) {
+ warn("Error: $snmpd not executable. 'make test' will not work.\n");
+ }
+ } else {
+ warn("Error: $snmpd does not exist or is unreadable. 'make test' will not work.\n");
+ }
+
+ if (-e $snmptrapd and -r $snmptrapd) {
+ if (not -x $snmptrapd) {
+ warn("Error: $snmptrapd not executable. 'make test' will not work.\n");
+ }
+ } else {
+ warn("Error: $snmptrapd does not exist or is unreadable. 'make test' will not work.\n");
+ }
+ }
+# end of else
+ close H;
+}
+
+sub HasSSL {
+ my $config_header = shift;
+ my $has_ssl;
+ unless (open(C,"<$config_header")) {
+ warn("Unable to open $config_header, assuming no SSL\n");
+ return undef;
+ }
+ while (<C>) {
+ $has_ssl++, last if /^\s*#define\s+NETSNMP_USE_OPENSSL/;
+ }
+ close C;
+ return $has_ssl;
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/SNMP/README b/perl/SNMP/README
new file mode 100644
index 0000000..5d85aca
--- /dev/null
+++ b/perl/SNMP/README
@@ -0,0 +1,896 @@
+ The Perl5 'SNMP' Extension Module
+ for the Net-SNMP Library
+
+Contents:
+ Introduction:
+ Availability:
+ Contact:
+ Supported Platforms:
+ Release Notes:
+ Installation:
+ Operational Description:
+ Trouble Shooting:
+ Acknowledgments:
+ History:
+ Copyright:
+
+Introduction:
+
+ ******************************NOTE NOTE NOTE**************************
+ This module now relies on many other modules. Ideally, do not try
+ to build it independently, as it won't work as well. Instead of
+ running "perl Makefile.PL" in this directory, run it in the
+ net-snmp/perl directory instead which has a global makefile used to
+ build all the sub-modules in their proper order.
+ ******************************NOTE NOTE NOTE**************************
+
+ Note: The perl SNMP 5.x module which comes with net-snmp 5.0 and
+ higher is different than previous versions in a number of ways. Most
+ importantly, it behaves like a proper net-snmp application and calls
+ init_snmp properly, which means it will read configuration files and
+ use those defaults where appropriate automatically parse MIB files,
+ etc. This will likely affect your perl applications if you have, for
+ instance, default values set up in your snmp.conf file (as the perl
+ module will now make use of those defaults). The docmuentation,
+ however, has sadly not been updated yet (aside from this note).
+
+ This is the Perl5 'SNMP' extension module. The SNMP module provides a
+ full featured, tri-lingual SNMP (SNMPv3, SNMPv2c, SNMPv1) API. The
+ SNMP module also provides an interface to the SMI MIB parse-tree for
+ run-time access to parsed MIB data. The SNMP module internals rely on
+ the Net-SNMP toolkit library (previously known as ucd-snmp). For
+ information on the Net-SNMP library see the documentation provided
+ with the Net-SNMP distribution or the project web page available on
+ 'Source Forge':
+
+ http://www.net-snmp.org/
+
+Availability:
+
+ The most recent release of the Perl5 SNMP module can be found bundled
+ with the latest Net-SNMP distibution available from:
+
+ http://www.net-snmp.org/download.html
+
+ (Note: The perl SNMP distribution obtained this way has the highest
+ chance of being up to date and compatible with the Net-SNMP version
+ with which it is bundled.)
+
+ A seperately bundled package of the SNMP module can be obtained from CPAN.
+
+ (Note: In previous releases this module was compatible with the CMU
+ SNMP library. Starting with Perl5/SNMP-1.7 this module will *only*
+ work with the Net-SNMP (aka ucd-snmp) library due to dependence on new
+ features)
+
+Contact:
+
+ The following mailing list should be consider the primary support
+ mechanism for this module:
+
+ net-snmp-users ATATAT lists.sourceforge.net mail list
+
+ (see http://www.net-snmp.org/lists/users/ to subscribe)
+
+Supported Platforms:
+
+ Linux 1.2.x, 2.x
+ Solaris 2.x (see the net-snmp README.solaris file!)
+ MS Windows
+ Many other UNIX variants
+ Let us know what it *doesn't* work on, as it should on most systems
+
+Release Notes:
+
+ SNMP module version 5.x is being developed against NET-SNMP-5.0
+ see http://www.net-snmp.org/ for details.
+
+ Compatibility with earlier or later versions of Net-SNMP or
+ UCD-SNMP is not guaranteed due to the dynamic nature of open
+ software development :). The perl module will check the version of
+ net-snmp you have installed for a match and warn you if they don't
+ match exactly.
+
+KNOWN BUGS:
+
+ The make test suite likely won't work perfectly. It relies on
+ running an existing Net-SNMP SNMP agent and various configuration
+ which makes it very hard to ensure exact compatibility. If "make
+ test" fails on you we suggest you install the module anyway.
+
+ (none?) (HA!)
+
+**********************************************************************
+* the rest of this file is likely out of date ************************
+* the rest of this file is likely out of date ************************
+* the rest of this file is likely out of date ************************
+**********************************************************************
+
+Installation:
+
+ Build and install the Net-SNMP package - see Net-SNMP README and
+ INSTALL docs.
+
+ (Note: To ensure that any previous Net-SNMP, ucd-snmp or cmu snmp
+ installation's library or headers are not used by mistake, use the
+ -NET-SNMP-CONFIG directive to explicitly set the path to the
+ net-snmp-config command that knows about the net-snmp installation you
+ want to use.)
+
+ NOTE: build all the perl modules at once using the Makefile.PL in the
+ net-snmp/perl directory rather than the one in this directory.
+
+ Unix:
+
+ cd net-snmp/perl
+ perl Makefile.PL [-NET-SNMP-CONFIG="sh ../../net-snmp-config"] [-NET-SNMP-IN-SOURCE=true]
+ make
+ make test
+ make install
+
+ FreeBSD:
+
+ cd net-snmp/perl
+ perl Makefile.PL -NET-SNMP-CONFIG="sh ../../net-snmp-config" -NET-SNMP-IN-SOURCE=true
+ make
+ make test
+ make install
+
+ Win32 (MSVC++)
+
+ This section covers installation of the Perl modules for Microsoft Visual
+ C++ 6.0 and Microsoft Microsoft Development Environment 2003/2003
+ (MSVC 7.0/7.1). See the following sections for Cygwin and MinGW.
+
+ ActiveState Perl is required.
+
+ Note: With ActiveState Perl (currently at 5.8.2 build 808) and possibly other
+ versions of Perl on Windows, if a Perl script modifies a
+ system environment variable and then calls a C function, the
+ C function will not see the new environment variable. This
+ problem can be seen with the failure of test #3 in the SNMP
+ conf test (perl/SNMP/t/conf.t). The change to the
+ SNMPCONFPATH env variable is not seen by the calls to the C
+ SNMP module.
+
+ Note: The source code should *not* be in a folder that contains a space. For
+ example, compiling in your 'My Documents' or your Desktop (usually
+ c:\Documents and Settings\xxxx\Desktop) is not supported.
+
+ Automatic building / testing with nmakeperl.bat:
+
+ 1. Ensure a static version of Net-SNMP has been compiled and
+ installed. Also ensure the DLL version of snmplib has been
+ compiled and installed. The Perl modules will not function
+ correctly without a shared snmplib library or DLL.
+
+ 2. Install the regex win32 package (gnu_regex.exe). It is available from
+
+ http://people.delphiforums.com/gjc/gnu_regex.html
+
+ a. Copy regex.h to the include folder of MSVC++
+
+ Example: "C:\Program Files\Microsoft Visual Studio .NET 2003\
+ Vc7\include\regex.h"
+
+ b. Copy gnu_regex.lib to the lib folder of MSVC++
+
+ Example: "C:\Program Files\Microsoft Visual Studio .NET 2003\
+ Vc7\lib\gnu_regex.lib"
+
+ c. Copy gnu_regex.dll to your %windir%\system32 folder
+
+ Example: "C:\winnt\system32\gnu_regex.dll"
+
+ 3. Set the environment PATH to locate "nmake", "cl", and "link".
+ Visual Studio installs a VCVARS32.BAT batch file for this purpose.
+
+ 4. Using a command prompt window, cd to the source base directory.
+
+ 5. Invoke win32\nmakeperl.bat to build the Perl SNMP modules. If you see
+ errors, review the "nmake.out" file first. If no errors there,
+ then the modules built correctly, but the tests did not rigourously
+ prove the mettle of the modules. Review "nmaketest.out". If the
+ first three sections mostly pass, the modules are well formed.
+
+ NOTE: If the tests fail, there may be a perl application left hanging.
+ Use the Task Manager to remove any stale perl or snmp*.exe process.
+
+ 6. The final step is to invoke "nmake install". If no errors occurred,
+ then the SNMP modules are available for use by your Perl programs.
+
+
+ Manual building / testing:
+
+ 1. Ensure a static version of Net-SNMP has been compiled and
+ installed. Also ensure the DLL version of snmplib has been
+ compiled and installed. The Perl modules will not function
+ correctly without a shared snmplib library or DLL.
+
+ 2. Install the regex win32 package (gnu_regex.exe). It is available from
+
+ http://people.delphiforums.com/gjc/gnu_regex.html
+
+ a. Copy regex.h to the include folder of MSVC++
+
+ Example: "C:\Program Files\Microsoft Visual Studio .NET 2003\
+ Vc7\include\regex.h"
+
+ b. Copy gnu_regex.lib to the lib folder of MSVC++
+
+ Example: "C:\Program Files\Microsoft Visual Studio .NET 2003\
+ Vc7\lib\gnu_regex.lib"
+
+ c. Copy gnu_regex.dll to your %windir%\system32 folder
+
+ Example: "C:\winnt\system32\gnu_regex.dll"
+
+ 3. Set the environment PATH to locate "nmake", "cl", and "link".
+ Visual Studio installs a VCVARS32.BAT for this purpose.
+
+ 4. Using a command prompt window, cd to the perl directory.
+
+ 5. Type:
+
+ perl Makefile.PL CAPI=TRUE -NET-SNMP-IN-SOURCE=TRUE
+
+ to compile against the RELEASE version of Net-SNMP, or:
+
+ perl Makefile.PL CAPI=TRUE -NET-SNMP-IN-SOURCE=TRUE -NET-SNMP-DEBUG=TRUE
+
+ to compile against the DEBUG version of Net-SNMP.
+
+ nmake
+ nmake test
+ nmake install
+
+ Note: The --NET-SNMP-IN-SOURCE=TRUE causes the Makefile to use the
+ library files from the installed Net-SNMP directory.
+ To specify the installed Net-SNMP directory, use:
+
+ perl Makefile.PL CAPI=TRUE -NET-SNMP-PATH="c:\usr"
+
+ Note: -NET-SNMP-DEBUG has no effect while compiling against an
+ installed copy of Net-SNMP.
+
+ Note: To include OpenSSL, see the net-snmp/README.win32 to compile
+ libsnmp with libeay32 and see that libeay.lib is in the
+ lib folder, or in the lib folder of the installed
+ Net-SNMP if using -NET-SNMP-PATH. For example,
+ c:\usr\lib
+
+ Note: 'nmake test' will automatically start and stop the
+ agent(snmpd) and trap receiver (snmptrapd) while testing the
+ SNMP module.
+
+
+ Win32 (Cygwin):
+
+ cd net-snmp\perl
+ perl Makefile.PL -NET-SNMP-IN-SOURCE=true
+ make
+ make test
+ make install
+
+ If you get an error saying your system can't compile, you are
+ probably missing the regex library. Install regex from
+ http://mirrors.sunsite.dk/cygwin/release/regex/regex-4.4-2-src.tar.bz2
+
+ Note: The source code should *not* be in a folder that contains a space. For
+ example, compiling in your 'My Documents' or your Desktop (usually
+ c:\Documents and Settings\xxxx\Desktop) is not supported.
+
+
+ Win32 (MinGW):
+
+ Note: As of February 25th, 2004, the MinGW build of Net-SNMP does not
+ compile the DLL version of libsnmp. Some modules will not function
+ correctly without a shared library / DLL. The OID module does not
+ appear to work at all without the DLL, and some parts of other
+ modules may not work. For example, sharing configurations between
+ modules which is why the SNMP conf test fails.
+
+ Note: The source code should *not* be in a folder that contains a space. For
+ example, compiling in your 'My Documents' or your Desktop (usually
+ c:\Documents and Settings\xxxx\Desktop) is not supported.
+
+ These directions are for MinGW 3.1.0 with MSYS 1.0.9 and ActiveState Perl.
+ Compiling the Perl modules using a MinGW built Perl environment has not
+ been tested.
+
+ Note: With ActiveState Perl (currently at 5.8.2 build 808) and
+ possibly other versions of Perl on Windows, if a Perl script
+ modifies a system environment variable and then calls a C
+ function, the C function will not see the new environment
+ variable. This problem can be seen with the failure of test
+ #3 in the SNMP conf test (perl/SNMP/t/conf.t). The change to
+ the SNMPCONFPATH env variable is not seen by the calls to the
+ C SNMP module.
+
+ The main Net-SNMP package must be compiled with the regex library.
+ See Net-SNMP README.win32 for compiling with MinGW.
+
+ The following additional software is required:
+
+ dmake:
+ http://www.cpan.org/authors/id/GSAR/dmake-4.1pl1-win32.zip
+
+ ExtUtils-FakeConfig:
+ http://search.cpan.org/~mbarbon/ExtUtils-FakeConfig-0.05/
+
+ Note: A PPM package is available from ActiveState for
+ ExtUtils-FakeConfig, but it does not include the
+ make_implib.pl script. Downloading from CPAN is
+ recommended.
+
+ Installing DMAKE and ExtUtils-FakeConfig:
+ -----------------------------------------
+
+ 1. Install DMAKE as described in the README.NOW contained in the DMAKE .ZIP
+ file ensuring the DMAKE program can be found in the system path.
+
+ 2. Extract ExtUtils-FakeConfig-0.05.zip to a temporary folder.
+
+ 3. Add the MinGW bin folder to your system path.
+
+ 4. Open a Windows command prompt (cmd) and cd into
+ ExtUtils-FakeConfig-0.05 and typet he following to build and
+ install the ExtUtils-FakeConfig module:
+
+ perl Makefile.PL
+ dmake
+ dmake install
+
+ 5. A Perl import library needs to be created using the ExtUtils-FakeConfig
+ make_implib.pl script.
+
+ For ActiveState Perl 5.6.x installed to c:\Perl, type the
+ following on one line:
+
+ perl script/make_implib.pl --output-dir=C:/Perl/lib/CORE
+ --output-lib=libperl56.a --target=mingw c:/Perl/bin/Perl56.dll
+
+ For ActiveState Perl 5.8.x installed to c:\Perl, type the
+ following on one line:
+
+ perl script/make_implib.pl --output-dir=C:/Perl/lib/CORE
+ --output-lib=libperl58.a --target=mingw c:/Perl/bin/Perl58.dll
+
+
+Building the Perl module:
+-------------------------
+
+ 1. Complete the section titled 'Installing DMAKE and ExtUtils-FakeConfig'
+
+ 2. Open an MSYS shell and cd into the net-snmp/Perl folder and type the
+ following on one line:
+
+ perl -MConfig_m Makefile.PL -NET-SNMP-IN-SOURCE=true DEFINE=-DMINGW_PERL
+
+ 3. Open a Windows command prompt (cmd) and cd into the net-snmp/perl folder
+ and type:
+
+ dmake
+ dmake test
+ dmake install
+
+ Note: 'dmake test' will automatically start and stop the agent(snmpd) and
+ trap receiver (snmptrapd) while testing the SNMP module.
+
+ 4. Remove the MinGW bin folder to your system path if it was not already in
+ your path for step 3 of 'Installing DMAKE and ExtUtils-FakeConfig'.
+
+
+ Operational Description:
+
+ The basic operations of the SNMP protocol are provided by this module
+ through an object oriented interface for modularity and ease of use.
+ The primary class is SNMP::Session which encapsulates the persistent
+ aspects of a connection between the management application and the
+ managed agent. Internally the class is implemented as a blessed hash
+ reference. This class supplies 'get', 'getnext', 'set', 'fget', and
+ 'fgetnext' and other method calls. The methods take a variety of input
+ argument formats and support both synchronous and asynchronous
+ operation through a polymorphic API (i.e., method behaviour varies
+ dependent on args passed - see below).
+
+ A description of the fields which can be specified when an
+ SNMP::Session object is created follows:
+
+ SNMP::Session
+ public:
+ DestHost - default 'localhost', hostname or ip addr of SNMP agent
+ Community - default 'public', SNMP community string (used for both R/W)
+ Version - default '1', [2 (same as 2c), 2c, 3]
+ RemotePort - default '161', allow remote UDP port to be overridden
+ Timeout - default '1000000', micro-seconds before retry
+ Retries - default '5', retries before failure
+ RetryNoSuch - default '0', if enabled NOSUCH errors in 'get' pdus will
+ be repaired, removing the varbind in error, and resent -
+ undef will be returned for all NOSUCH varbinds, when set
+ to '0' this feature is disabled and the entire get request
+ will fail on any NOSUCH error (applies to v1 only)
+ SecName - default 'initial', security name (v3)
+ SecLevel - default 'noAuthNoPriv', security level [noAuthNoPriv,
+ authNoPriv, authPriv] (v3)
+ SecEngineId - default <none>, security engineID, will be probed if not
+ supplied (v3)
+ ContextEngineId - default <SecEngineId>, context engineID, will be
+ probed if not supplied (v3)
+ Context - default '', context name (v3)
+ AuthProto - default 'MD5', authentication protocol [MD5, SHA] (v3)
+ AuthPass - default <none>, authentication passphrase
+ PrivProto - default 'DES', privacy protocol [DES] (v3)
+ PrivPass - default <none>, privacy passphrase (v3)
+ VarFormats - default 'undef', used by 'fget[next]', holds an hash
+ reference of output value formatters, (e.g., {<obj> =>
+ <sub-ref>, ... }, <obj> must match the <obj> and format
+ used in the get operation. A special <obj>, '*', may be
+ used to apply all <obj>s, the supplied sub is called to
+ translate the value to a new format. The sub is called
+ passing the Varbind as the arg
+ TypeFormats - default 'undef', used by 'fget[next]', holds an hash
+ reference of output value formatters, (e.g., {<type> =>
+ <sub-ref>, ... }, the supplied sub is called to translate
+ the value to a new format, unless a VarFormat mathces first
+ (e.g., $session->{TypeFormats}{INTEGER} = \&mapEnum();
+ although this can be done more efficiently by enabling
+ $SNMP::use_enums or session creation param 'UseEnums')
+ UseLongNames - defaults to the value of SNMP::use_long_names at time
+ of session creation. set to non-zero to have <tags>
+ for 'getnext' methods generated preferring longer Mib name
+ convention (e.g., system.sysDescr vs just sysDescr)
+ UseSprintValue - defaults to the value of SNMP::use_sprint_value at time
+ of session creation. set to non-zero to have return values
+ for 'get' and 'getnext' methods formatted with the libraries
+ sprint_value function. This will result in certain data types
+ being returned in non-canonical format Note: values returned
+ with this option set may not be appropriate for 'set' operations
+ (see discussion of value formats in <vars> description section)
+ UseEnums - defaults to the value of SNMP::use_enums at time of session
+ creation. set to non-zero to have integer return values
+ converted to enumeration identifiers if possible, these values
+ will also be acceptable when supplied to 'set' operations
+ UseNumeric - defaults to the value of SNMP::use_numeric at time of session
+ creation. set to non-zero to have <tags> returned by the 'get'
+ methods untranslated (i.e. dotted-decimal). Setting the
+ UseLongNames value for the session is highly recommended.
+ BestGuess - defaults to the value of SNMP::best_guess at time of session
+ creation. this setting controls how <tags> are parsed. setting
+ to 0 causes a regular lookup. setting to 1 causes a regular
+ expression match (defined as -Ib in snmpcmd) and setting to 2
+ causes a random access lookup (defined as -IR in snmpcmd).
+ ErrorStr - read-only, holds the error message assoc. w/ last request
+ ErrorNum - read-only, holds the snmp_err or status of last request
+ ErrorInd - read-only, holds the snmp_err_index when appropriate
+
+ private:
+ DestAddr - internal field used to hold the translated DestHost field
+ SessPtr - internal field used to cache a created session structure
+
+ methods:
+ new(<fields>) - Constructs a new SNMP::Session object. The fields are
+ passed to the constructor as a hash list
+ (e.g., $session = new SNMP::Session(DestHost => 'foo',
+ Community => 'private');), returns an object reference
+ or undef in case of error.
+ update(<fields>)- Updates the SNMP::Session object with the values fields
+ passed in as a hash list (similar to new(<fields>))
+ (WARNING! not fully implemented)
+ get(<vars>[,<callback>])
+ - do SNMP GET, multiple <vars> formats accepted.
+ for synchronous operation <vars> will be updated
+ with value(s) and type(s) and will also return
+ retrieved value(s). If <callback> supplied method
+ will operate asynchronously
+ fget(<vars>[,<callback>])
+ - do SNMP GET like 'get' and format the values according
+ the handlers specified in $sess->{VarFormats} and
+ $sess->{TypeFormats}. Async *not supported*
+ getnext(<vars>[,<callback>])
+ - do SNMP GETNEXT, multiple <vars> formats accepted,
+ returns retrieved value(s), <vars> passed as arguments are
+ updated to indicate next lexicographical <obj>,<iid>,<val>,
+ and <type> Note: simple string <vars>,(e.g., 'sysDescr.0')
+ form is not updated. If <callback> supplied method
+ will operate asynchronously
+ fgetnext(<vars>[,<callback>])
+ - do SNMP GETNEXT like getnext and format the values according
+ the handlers specified in $sess->{VarFormats} and
+ $sess->{TypeFormats}. Async *not supported*
+ set(<vars>[,<callback>])
+ - do SNMP SET, multiple <vars> formats accepted.
+ the value field in all <vars> formats must be in a canonical
+ format (i.e., well known format) to ensure unambiguous
+ translation to SNMP MIB data value (see discussion of
+ canonical value format <vars> description section),
+ returns true on success or undef on error. If <callback>
+ supplied method will operate asynchronously
+ getbulk(<non-repeaters>, <max-repeaters>, <vars> [, <callback>])
+ - do an SNMP GETBULK, from the list of Varbinds, the single
+ next lexico instance is fetched for the first n Varbinds
+ as defined by <non-repeaters>. For remaining Varbinds,
+ the m lexico instances are retrieved each of the remaining
+ Varbinds, where m is <max-repeaters>.
+ bulkwalk(<non-repeaters>, <max-repeaters>, <vars> [, <callback>])
+ - do an "SNMP bulkwalk" on the given variables. Bulkwalk is
+ implemented by sending an SNMP GETBULK request to fetch the
+ variables. Objects are copied to the return list until the
+ sub-tree is exited. If the request is not completed at the
+ end of a packet, a new request is created, starting where
+ the previous packet left off. This implementation is able
+ to handle multiple repeated vars, as well as non-repeaters.
+ Returns a list (or, in scalar context, a reference to a
+ list) of arrays of VarBinds. The VarBinds consist of the
+ responses for each requested variable. bulkwalk() leaves
+ the original Varbinds list intact to facilitate querying
+ of multiple devices.
+
+ SNMP::TrapSession - supports all applicable fields from SNMP::Session
+ (see above)
+ methods:
+ new(<fields>) - Constructs a new SNMP::TrapSession object. The fields are
+ passed to the constructor as a hash list
+ (e.g., $trapsess = new SNMP::Session(DestHost => 'foo',
+ Community => 'private');), returns an object reference
+ or undef in case of error.
+ trap(enterprise, agent, generic, specific, uptime, <vars>)
+ $sess->trap(enterprise=>'.1.3.6.1.4.1.2021', # or 'ucdavis' [default]
+ agent => '127.0.0.1', # or 'localhost',[dflt 1st intf on host]
+ generic => specific, # can be omitted if 'specific' supplied
+ specific => 5, # can be omitted if 'generic' supplied
+ uptime => 1234, # dflt to localhost uptime (0 on win32)
+ [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+ # always last
+ or v2 format
+ trap(oid, uptime, <vars>)
+ $sess->trap(oid => 'snmpRisingAlarm',
+ uptime => 1234,
+ [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+ # always last
+
+
+ Acceptable variable formats:
+ <vars> may be one of the following forms:
+
+ SNMP::VarList: - represents an array of MIB objects to get or set,
+ implemented as a blessed reference to an array of
+ SNMP::Varbinds, (e.g., [<varbind1>, <varbind2>, ...])
+
+ SNMP::Varbind: - represents a single MIB object to get or set, implemented as
+ a blessed reference to a 4 element array;
+ [<obj>, <iid>, <val>, <type>].
+ <obj> - one of the following forms:
+ 1) leaf identifier (e.g., 'sysDescr') assumed to be
+ unique for practical purposes
+ 2) fully qualified identifier (e.g.,
+ '.iso.org.dod.internet.mgmt.mib-2.system.sysDescr')
+ 3) fully qualified, dotted-decimal, numeric OID (e.g.,
+ '.1.3.6.1.2.1.1.1')
+ <iid> - the dotted-decimal, instance identifier. for
+ scalar MIB objects use '0'
+ <val> - the SNMP data value retrieved from or being set
+ to the agents MIB. for (f)get(next) operations
+ <val> may have a variety of formats as determined by
+ session and package settings. However for set
+ operations the <val> format must be canonical to
+ ensure unambiguous translation. The canonical forms
+ are as follows:
+ OBJECTID => dotted-decimal (e.g., .1.3.6.1.2.1.1.1)
+ OCTETSTR => perl scalar containing octets,
+ INTEGER => decimal signed integer (or enum),
+ NETADDR => dotted-decimal,
+ IPADDR => dotted-decimal,
+ COUNTER => decimal unsigned integer,
+ COUNTER64 => decimal unsigned integer,
+ GAUGE, => decimal unsigned integer,
+ UINTEGER, => decimal unsigned integer,
+ TICKS, => decimal unsigned integer,
+ OPAQUE => perl scalar containing octets,
+ NULL, => perl scalar containing nothing,
+
+
+ <type> - SNMP data type (see list above), this field is
+ populated by 'get' and 'getnext' operations. In
+ some cases the programmer needs to populate this
+ field when passing to a 'set' operation. this
+ field need not be supplied when the attribute
+ indicated by <tag> is already described by loaded
+ Mib modules. for 'set's, if a numeric OID is used
+ and the object is not currently in the loaded Mib,
+ the <type> field must be supplied
+
+ simple string - light weight form of <var> used to 'set' or 'get' a
+ single attribute without constructing an SNMP::Varbind.
+ stored in a perl scalar, has the form '<tag>.<iid>',
+ (e.g., 'sysDescr.0'). for 'set' operations the value
+ is passed as a second arg. Note: This argument form is
+ not updated in get[next] operations as are the other forms.
+
+ Acceptable callback formats:
+ <callback> may be one of the following forms:
+
+ without arguments:
+ \&subname
+ sub { ... }
+ or with arguments:
+ [ \&subname, $arg1, ... ]
+ [ sub { ... }, $arg1, ... ]
+ [ "method", $obj, $arg1, ... ]
+
+ callback will be called when response is received or timeout
+ occurs. the last argument passed to callback will be a
+ SNMP::VarList reference. In case of timeout the last argument
+ will be undef.
+
+ SNMP package variables and functions:
+
+ $SNMP::VERSION - the current version specifier (e.g., 3.1.0)
+
+ $SNMP::auto_init_mib - default '1', set to 0 to disable automatic reading
+ of the MIB upon session creation. set to non-zero
+ to call initMib at session creation which will result
+ in MIB loading according to Net-SNMP env. variables
+ (see man mib_api)
+
+ $SNMP::verbose - default '0', controls warning/info output of
+ SNMP module, 0 => no output, 1 => enables warning/info
+ output from SNMP module itself (is also controlled
+ by SNMP::debugging - see below)
+
+ $SNMP::use_long_names - default '0', set to non-zero to enable the use of
+ longer Mib identifiers. see translateObj. will also
+ influence the formatting of <tag> in varbinds returned
+ from 'getnext' operations. Can be set on a per session
+ basis (UseLongNames)
+
+ $SNMP::use_sprint_value - default '0', set to non-zero to enable formatting of
+ response values using the snmp libraries sprint_value
+ function. can also be set on a per session basis (see
+ UseSprintValue) Note: returned values may not be
+ suitable for 'set' operations
+
+ $SNMP::use_enums - default '0',set non-zero to return values as enums and
+ allow sets using enums where appropriate. integer data
+ will still be accepted for set operations. can also be
+ set on a per session basis (see UseEnums)
+
+ $SNMP::use_numeric - default '0', set to non-zero to return tags as numeric
+ OID's, instead of translating them. Also setting
+ $SNMP::use_long_names to non-zero is highly recommended.
+
+ $SNMP::best_guess - default '0'. this setting controls how <tags> are
+ parsed. setting to 0 causes a regular lookup. setting
+ to 1 causes a regular expression match (defined as -Ib
+ in snmpcmd) and setting to 2 causes a random access
+ lookup (defined as -IR in snmpcmd). can also be set
+ on a per session basis (see BestGuess)
+
+ $SNMP::save_descriptions - default '0',set non-zero to have mib parser save
+ attribute descriptions. must be set prior to mib
+ initialization
+
+ $SNMP::debugging - default '0', controls debugging output level
+ within SNMP module and libsnmp
+ 1 => enables 'SNMP::verbose' (see above)
+ 2 => level 1 plus snmp_set_do_debugging(1),
+ 3 => level 2 plus snmp_set_dump_packet(1)
+
+ $SNMP::dump_packet - default '0', set [non-]zero to independently set
+ snmp_set_dump_packet()
+
+ %SNMP::MIB - a tied hash to access parsed MIB information. After
+ the MIB has been loaded this hash allows access to
+ to the parsed in MIB meta-data(the structure of the
+ MIB (i.e., schema)). The hash returns blessed
+ references to SNMP::MIB::NODE objects which represent
+ a single MIB attribute. The nodes can be fetched with
+ multiple 'key' formats - the leaf name (e.g.,sysDescr)
+ or fully/partially qualified name (e.g.,
+ system.sysDescr) or fully qualified numeric OID. The
+ returned node object supports the following fields:
+
+ objectID - dotted decimal fully qualified OID
+ label - leaf textual identifier (e.g., 'sysDescr')
+ subID - leaf numeric OID component of objectID (e.g., '1')
+ moduleID - textual identifier for module (e.g., 'RFC1213-MIB')
+ parent - parent node
+ children - array reference of children nodes
+ nextNode - next lexico node (BUG!does not return in lexico order)
+ type - returns application type (see getType for values)
+ access - returns ACCESS (ReadOnly, ReadWrite, WriteOnly,
+ NoAccess, Notify, Create)
+ status - returns STATUS (Mandatory, Optional, Obsolete,
+ Deprecated, Current)
+ syntax - returns 'textualConvention' if defined else 'type'
+ textualConvention - returns TEXTUAL-CONVENTION
+ units - returns UNITS
+ hint - returns HINT
+ enums - returns hash ref {tag => num, ...}
+ ranges - returns array ref of hash ref [{low=>num, high=>num}]
+ defaultValue - returns default value
+ description - returns DESCRIPTION ($SNMP::save_descriptions must
+ be set prior to MIB initialization/parsing)
+
+
+ &SNMP::setMib(<file>) - allows dynamic parsing of the mib and explicit
+ specification of mib file independent of environment
+ variables. called with no args acts like initMib,
+ loading MIBs indicated by environment variables (see
+ Net-SNMP mib_api docs). passing non-zero second arg
+ forces previous mib to be freed and replaced
+ (Note: second arg not working since freeing previous
+ Mib is more involved than before).
+
+ &SNMP::initMib() - calls library netsnmp_init_mib function if MIB not
+ already loaded - does nothing if MIB already loaded.
+ Will parse directories and load modules according to
+ environment variables described in Net-SNMP
+ documentations.
+ (see man mib_api, MIBDIRS, MIBS, MIBFILE(S), etc.)
+
+ &SNMP::addMibDirs(<dir>,...) - calls library add_mibdir for each directory
+ supplied. will cause directory(s) to be added to
+ internal list and made available for searching in
+ subsequent loadModules calls
+
+ &SNMP::addMibFiles(<file>,...) - calls library read_mib function. The file(s)
+ supplied will be read and all Mib module definitions
+ contained therein will be added to internal mib tree
+ structure
+
+ &SNMP::loadModules(<mod>,...) - calls library read_module function. The
+ module(s) supplied will be searched for in the
+ current mibdirs and and added to internal mib tree
+ structure. Passing special <mod>, 'ALL', will cause
+ all known modules to be loaded.
+
+ &SNMP::unloadModules(<mod>,...) - *Not Implemented*
+
+ &SNMP::translateObj(<var>[,arg,[arg]]) - will convert a text obj tag to an
+ OID and vice-versa. Any iid suffix is retained
+ numerically. Default behaviour when converting a
+ numeric OID to text form is to return leaf identifier
+ only (e.g.,'sysDescr') but when $SNMP::use_long_names
+ is non-zero or a non-zero second arg is supplied it
+ will return a longer textual identifier. An optional
+ third argument of non-zero will cause the module name
+ to be prepended to the text name (e.g.
+ 'SNMPv2-MIB::sysDescr'). When converting a text obj,
+ the $SNMP::best_guess option is used. If no Mib is
+ loaded when called and $SNMP::auto_init_mib is enabled
+ then the Mib will be loaded. Will return 'undef' upon
+ failure.
+
+ &SNMP::getType(<var>) - return SNMP data type for given textual identifier
+ OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER
+ GAUGE, TIMETICKS, OPAQUE, or undef
+
+ &SNMP::mapEnum(<var>) - converts integer value to enumeration tag defined
+ in Mib or converts tag to integer depending on
+ input. the function will return the corresponding
+ integer value *or* tag for a given MIB attribute
+ and value. The function will sense which direction
+ to perform the conversion. Various arg formats are
+ supported
+ $val = SNMP::mapEnum($varbind);
+ # where $varbind is SNMP::Varbind or equiv
+ # note: $varbind will be updated
+ $val = SNMP::mapEnum('ipForwarding', 'forwarding');
+ $val = SNMP::mapEnum('ipForwarding', 1);
+
+ &SNMP::MainLoop([<timeout>, [<callback>]])
+ - to be used with async SNMP::Session
+ calls. MainLoop must be called after initial async calls
+ so return packets from the agent will not be processed.
+ If no args supplied this function enters an infinite loop
+ so program must be exited in a callback or externally
+ interrupted. If <timeout
+
+ &SNMP::finish()
+ - This function, when called from an SNMP::MainLoop()
+ callback function, will cause the current SNMP::MainLoop
+ to return after the callback is completed. finish() can
+ be used to terminate an otherwise-infinite MainLoop. A
+ new MainLoop() instance can then be started to handle
+ further requests.
+
+ Exported SNMP utility functions
+ &snmp_get() - takes args of SNMP::Session::new followed by those of
+ SNMP::Session::get
+
+ &snmp_getnext() - takes args of SNMP::Session::new followed by those of
+ SNMP::Session::getnext
+
+ &snmp_set() - takes args of SNMP::Session::new followed by those of
+ SNMP::Session::set
+
+ &snmp_trap() - takes args of SNMP::TrapSession::new followed by those of
+ SNMP::TrapSession::trap
+
+ Note: utility functions do not support async operation yet.
+
+Trouble Shooting:
+
+ If problems occur there are number areas to look at to narrow down the
+ possibilities.
+
+ The first step should be to test the Net-SNMP installation
+ independently from the Perl5 SNMP interface.
+
+ Try running the apps from the Net-SNMP distribution.
+
+ Make sure your agent (snmpd) is running and properly configured with
+ read-write access for the community you are using.
+
+ Ensure that your MIBs are installed and environment variables are set
+ appropriately (see man mib_api)
+
+ Be sure to ensure headers and libraries from old CMU installations are
+ not being used by mistake (see -NET-SNMP-PATH).
+
+ If the problem occurs during compilation/linking check that the snmp
+ library being linked is actually the Net-SNMP library (there have been
+ name conflicts with existing snmp libs).
+
+ Also check that the header files are correct and up to date.
+
+ Sometimes compiling the Net-SNMP library with
+ 'position-independent-code' enabled is required (HPUX specifically).
+
+ If you cannot resolve the problem you can post to
+ comp.lang.perl.modules or email net-snmp-users@lists.sourceforge.net.
+
+ please give sufficient information to analyze the problem (OS type,
+ versions for OS/Perl/net-SNMP/compiler, complete error output, etc.)
+
+Acknowledgments:
+
+ Many thanks to all those who supplied patches, suggestions and
+ feedback.
+
+ Joe Marzot (the original author)
+ Wes Hardaker and the net-snmp-coders
+ Dave Perkins
+ Marcel Wiget
+ David Blackburn
+ John Stofell
+ Gary Hayward
+ Claire Harrison
+ Achim Bohnet
+ Doug Kingston
+ Jacques Vidrine
+ Carl Jacobsen
+ Wayne Marquette
+ Scott Schumate
+ Michael Slifcak
+ Srivathsan Srinivasagopalan
+ Bill Fenner
+ Jef Peeraer
+ Daniel Hagerty
+ Karl "Rat" Schilke and Electric Lightwave, Inc.
+ Perl5 Porters
+ Alex Burger
+
+ Apologies to any/all who's patch/feature/request was not mentioned or
+ included - most likely it was lost when paying work intruded on my
+ fun. Please try again if you do not see a desired feature. This may
+ actually turn out to be a decent package with such excellent help and
+ the fact that I have more time to work on it than in the past.
+
+Copyright:
+
+ [See the COPYING file for the copyright license of Net-SNMP]
+
+ Copyright (c) 1995-2000 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.
+
+ Copyright (c) 2001-2002 Networks Associates Technology, Inc. All
+ Rights Reserved. This program is free software; you can
+ redistribute it and/or modify it under the same terms as Perl
+ itself.
+
+ Copyright (c) 2003-2006 SPARTA, Inc. All Rights Reserved. This
+ program is free software; you can redistribute it and/or modify
+ it under the same terms as Perl itself.
diff --git a/perl/SNMP/SNMP.pm b/perl/SNMP/SNMP.pm
new file mode 100644
index 0000000..ffc5a2f
--- /dev/null
+++ b/perl/SNMP/SNMP.pm
@@ -0,0 +1,2680 @@
+# SNMP.pm -- Perl 5 interface to the Net-SNMP toolkit
+#
+# written by G. S. Marzot (marz@users.sourceforge.net)
+#
+# Copyright (c) 1995-2006 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.
+
+package SNMP;
+$VERSION = '5.0702'; # current release version number
+
+use strict;
+use warnings;
+
+require Exporter;
+require DynaLoader;
+require AutoLoader;
+
+use NetSNMP::default_store (':all');
+
+@SNMP::ISA = qw(Exporter AutoLoader DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@SNMP::EXPORT = qw(
+ RECEIVED_MESSAGE
+ SNMPERR_BAD_ADDRESS
+ SNMPERR_BAD_LOCPORT
+ SNMPERR_BAD_SESSION
+ SNMPERR_GENERR
+ SNMPERR_TOO_LONG
+ SNMP_DEFAULT_ADDRESS
+ SNMP_DEFAULT_COMMUNITY_LEN
+ SNMP_DEFAULT_ENTERPRISE_LENGTH
+ SNMP_DEFAULT_ERRINDEX
+ SNMP_DEFAULT_ERRSTAT
+ SNMP_DEFAULT_PEERNAME
+ SNMP_DEFAULT_REMPORT
+ SNMP_DEFAULT_REQID
+ SNMP_DEFAULT_RETRIES
+ SNMP_DEFAULT_TIME
+ SNMP_DEFAULT_TIMEOUT
+ SNMP_DEFAULT_VERSION
+ TIMED_OUT
+ snmp_get
+ snmp_getnext
+ snmp_set
+ snmp_trap
+ SNMP_API_TRADITIONAL
+ SNMP_API_SINGLE
+);
+
+sub AUTOLOAD {
+ no strict;
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+ my($val,$pack,$file,$line);
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ # croak "&$module::constant not defined" if $constname eq 'constant';
+ ($!, $val) = constant($constname, @_ ? $_[0] : 0);
+ if ($! != 0) {
+ if ($! =~ /Invalid/) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ ($pack,$file,$line) = caller;
+ die "Your vendor has not defined SNMP macro $constname, used at $file line $line.
+";
+ }
+ }
+ eval "sub $AUTOLOAD { $val }";
+ goto &$AUTOLOAD;
+}
+
+bootstrap SNMP;
+
+# Preloaded methods go here.
+
+# Package variables
+tie $SNMP::debugging, 'SNMP::DEBUGGING';
+tie $SNMP::debug_internals, 'SNMP::DEBUG_INTERNALS';
+tie $SNMP::dump_packet, 'SNMP::DUMP_PACKET';
+tie %SNMP::MIB, 'SNMP::MIB';
+tie $SNMP::save_descriptions, 'SNMP::MIB::SAVE_DESCR';
+tie $SNMP::replace_newer, 'SNMP::MIB::REPLACE_NEWER';
+tie $SNMP::mib_options, 'SNMP::MIB::MIB_OPTIONS';
+
+%SNMP::V3_SEC_LEVEL_MAP = (noAuthNoPriv => 1, authNoPriv => 2, authPriv =>3);
+
+use vars qw(
+ $auto_init_mib $use_long_names $use_sprint_value $use_enums
+ $use_numeric %MIB $verbose $debugging $dump_packet $save_descriptions
+ $best_guess $non_increasing $replace_newer %session_params
+ $debug_internals $mib_options
+);
+
+$auto_init_mib = 1; # enable automatic MIB loading at session creation time
+$use_long_names = 0; # non-zero to prefer longer mib textual identifiers rather
+ # than just leaf indentifiers (see translateObj)
+ # may also be set on a per session basis(see UseLongNames)
+$use_sprint_value = 0; # non-zero to enable formatting of response values
+ # using the snmp libraries "snprint_value"
+ # may also be set on a per session basis(see UseSprintValue)
+ # note: returned values not suitable for 'set' operations
+$use_enums = 0; # non-zero to return integers as enums and allow sets
+ # using enums where appropriate - integer data will
+ # still be accepted for set operations
+ # may also be set on a per session basis (see UseEnums)
+$use_numeric = 0; # non-zero to return object tags as numeric OID's instead
+ # of converting to textual representations. use_long_names,
+ # if non-zero, returns the entire OID, otherwise, return just
+ # the label portion. use_long_names is also set if the
+ # use_numeric variable is set.
+%MIB = (); # tied hash to access libraries internal mib tree structure
+ # parsed in from mib files
+$verbose = 0; # controls warning/info output of SNMP module,
+ # 0 => no output, 1 => enables warning and info
+ # output from SNMP module itself (is also controlled
+ # by SNMP::debugging)
+$debugging = 0; # non-zero to globally enable libsnmp do_debugging output
+ # set to >= 2 to enabling packet dumping (see below)
+$dump_packet = 0; # non-zero to globally enable libsnmp dump_packet output.
+ # is also enabled when $debugging >= 2
+$save_descriptions = 0; #tied scalar to control saving descriptions during
+ # mib parsing - must be set prior to mib loading
+$best_guess = 0; # determine whether or not to enable best-guess regular
+ # expression object name translation. 1 = Regex (-Ib),
+ # 2 = random (-IR)
+$non_increasing = 0; # stop polling with an "OID not increasing"-error
+ # when an OID does not increases in bulkwalk.
+$replace_newer = 0; # determine whether or not to tell the parser to replace
+ # older MIB modules with newer ones when loading MIBs.
+ # WARNING: This can cause an incorrect hierarchy.
+
+sub register_debug_tokens {
+ my $tokens = shift;
+
+ SNMP::_register_debug_tokens($tokens);
+}
+
+sub getenv {
+ my $name = shift;
+
+ return SNMP::_getenv($name);
+}
+
+sub setenv {
+ my $envname = shift;
+ my $envval = shift;
+ my $overwrite = shift;
+
+ return SNMP::_setenv($envname, $envval, $overwrite);
+}
+
+sub setMib {
+# loads mib from file name provided
+# setting second arg to true causes currently loaded mib to be replaced
+# otherwise mib file will be added to existing loaded mib database
+# NOTE: now deprecated in favor of addMibFiles and new module based funcs
+ my $file = shift;
+ my $force = shift || '0';
+ return 0 if $file and not (-r $file);
+ SNMP::_read_mib($file,$force);
+}
+
+sub initMib {
+# equivalent to calling the snmp library init_mib if Mib is NULL
+# if Mib is already loaded this function does nothing
+# Pass a zero valued argument to get minimal mib tree initialization
+# If non zero argument or no argument then full mib initialization
+
+ SNMP::init_snmp("perl");
+ return;
+
+
+ if (defined $_[0] and $_[0] == 0) {
+ SNMP::_init_mib_internals();
+ } else {
+ SNMP::_read_mib("");
+ }
+}
+
+sub addMibDirs {
+# adds directories to search path when a module is requested to be loaded
+ SNMP::init_snmp("perl");
+ foreach (@_) {
+ SNMP::_add_mib_dir($_) or return undef;
+ }
+ return 1;
+}
+
+sub addMibFiles {
+# adds mib definitions to currently loaded mib database from
+# file(s) supplied
+ SNMP::init_snmp("perl");
+ foreach (@_) {
+ SNMP::_read_mib($_) or return undef;
+ }
+ return 1;
+}
+
+sub loadModules {
+# adds mib module definitions to currently loaded mib database.
+# Modules will be searched from previously defined mib search dirs
+# Passing and arg of 'ALL' will cause all known modules to be loaded
+ SNMP::init_snmp("perl");
+ foreach (@_) {
+ SNMP::_read_module($_) or return undef;
+ }
+ return 1;
+}
+
+sub unloadModules {
+# causes modules to be unloaded from mib database
+# Passing and arg of 'ALL' will cause all known modules to be unloaded
+ warn("SNMP::unloadModules not implemented! (yet)");
+}
+
+sub translateObj {
+# Translate object identifier(tag or numeric) into alternate representation
+# (i.e., sysDescr => '.1.3.6.1.2.1.1.1' and '.1.3.6.1.2.1.1.1' => sysDescr)
+# when $SNMP::use_long_names or second arg is non-zero the translation will
+# return longer textual identifiers (e.g., system.sysDescr). An optional
+# third argument of non-zero will cause the module name to be prepended
+# to the text name (e.g. 'SNMPv2-MIB::sysDescr'). If no Mib is loaded
+# when called and $SNMP::auto_init_mib is enabled then the Mib will be
+# loaded. Will return 'undef' upon failure.
+ SNMP::init_snmp("perl");
+ my $obj = shift;
+ my $temp = shift;
+ my $include_module_name = shift || "0";
+ my $long_names = $temp || $SNMP::use_long_names;
+
+ return undef if not defined $obj;
+ my $res;
+ if ($obj =~ /^\.?(\d+\.)*\d+$/) {
+ $res = SNMP::_translate_obj($obj,1,$long_names,$SNMP::auto_init_mib,0,$include_module_name);
+ } elsif ($obj =~ /(\.\d+)*$/ && $SNMP::best_guess == 0) {
+ $res = SNMP::_translate_obj($`,0,$long_names,$SNMP::auto_init_mib,0,$include_module_name);
+ $res .= $& if defined $res and defined $&;
+ } elsif ($SNMP::best_guess) {
+ $res = SNMP::_translate_obj($obj,0,$long_names,$SNMP::auto_init_mib,$SNMP::best_guess,$include_module_name);
+ }
+
+ return($res);
+}
+
+sub getType {
+# return SNMP data type for given textual identifier
+# OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER
+# GAUGE, TIMETICKS, OPAQUE, or undef
+ my $tag = shift;
+ SNMP::_get_type($tag, $SNMP::best_guess);
+}
+
+sub mapEnum {
+# return the corresponding integer value *or* tag for a given MIB attribute
+# and value. The function will sense which direction to perform the conversion
+# various arg formats are supported
+# $val = SNMP::mapEnum($varbind); # note: will update $varbind
+# $val = SNMP::mapEnum('ipForwarding', 'forwarding');
+# $val = SNMP::mapEnum('ipForwarding', 1);
+#
+ my $var = shift;
+ my ($tag, $val, $update);
+ if (ref($var) =~ /ARRAY/ or ref($var) =~ /Varbind/) {
+ $tag = SNMP::Varbind::tag($var);
+ $val = SNMP::Varbind::val($var);
+ $update = 1;
+ } else {
+ $tag = $var;
+ $val = shift;
+ }
+ my $iflag = $val =~ /^\d+$/;
+ my $res = SNMP::_map_enum($tag, $val, $iflag, $SNMP::best_guess);
+ if ($update and defined $res) { SNMP::Varbind::val($var) = $res; }
+ return($res);
+}
+
+%session_params = (DestHost => 1,
+ Community => 1,
+ Version => 1,
+ Timeout => 1,
+ Retries => 1,
+ RemotePort => 1,
+ LocalPort => 1);
+
+sub strip_session_params {
+ my @params;
+ my @args;
+ my $param;
+ while ($param = shift) {
+ push(@params,$param, shift), next
+ if $session_params{$param};
+ push(@args,$param);
+ }
+ @_ = @args;
+ @params;
+}
+
+
+sub snmp_get {
+# procedural form of 'get' method. sometimes quicker to code
+# but is less efficient since the Session is created and destroyed
+# with each call. Takes all the parameters of both SNMP::Session::new and
+# SNMP::Session::get (*NOTE*: this api does not support async callbacks)
+
+ my @sess_params = &strip_session_params;
+ my $sess = new SNMP::Session(@sess_params);
+
+ $sess->get(@_);
+}
+
+sub snmp_getnext {
+# procedural form of 'getnext' method. sometimes quicker to code
+# but is less efficient since the Session is created and destroyed
+# with each call. Takes all the parameters of both SNMP::Session::new and
+# SNMP::Session::getnext (*NOTE*: this api does not support async callbacks)
+
+ my @sess_params = &strip_session_params;
+ my $sess = new SNMP::Session(@sess_params);
+
+ $sess->getnext(@_);
+}
+
+sub snmp_set {
+# procedural form of 'set' method. sometimes quicker to code
+# but is less efficient since the Session is created and destroyed
+# with each call. Takes all the parameters of both SNMP::Session::new and
+# SNMP::Session::set (*NOTE*: this api does not support async callbacks)
+
+ my @sess_params = &strip_session_params;
+ my $sess = new SNMP::Session(@sess_params);
+
+ $sess->set(@_);
+}
+
+sub snmp_trap {
+# procedural form of 'trap' method. sometimes quicker to code
+# but is less efficient since the Session is created and destroyed
+# with each call. Takes all the parameters of both SNMP::TrapSession::new and
+# SNMP::TrapSession::trap
+
+ my @sess_params = &strip_session_params;
+ my $sess = new SNMP::TrapSession(@sess_params);
+
+ $sess->trap(@_);
+}
+
+#---------------------------------------------------------------------
+# Preserves the ability to call MainLoop() with no args so we don't
+# break old code
+#
+# Alternately, MainLoop() could be called as an object method,
+# ( $sess->MainLoop() ) , so that $self winds up in @_. Then it would
+# be more like :
+# my $self = shift;
+# ....
+# SNMP::_main_loop(......, $self->{SessPtr});
+#---------------------------------------------------------------------
+sub MainLoop {
+ my $ss = shift if(&SNMP::_api_mode() == SNMP::SNMP_API_SINGLE());
+ my $time = shift;
+ my $callback = shift;
+ my $time_sec = ($time ? int $time : 0);
+ my $time_usec = ($time ? int(($time-$time_sec)*1000000) : 0);
+ SNMP::_main_loop($time_sec,$time_usec,$callback,(defined($ss) ? $ss->{SessPtr} : ()));
+}
+
+sub finish {
+ SNMP::_mainloop_finish();
+}
+
+sub reply_cb {
+ # callback function for async snmp calls
+ # when triggered, will do a SNMP read on the
+ # given fd
+ my $fd = shift;
+ SNMP::_read_on_fd($fd);
+}
+
+sub select_info {
+ # retrieves SNMP used fd's and timeout info
+ # calculates timeout in fractional seconds
+ # ( easy to use with select statement )
+ my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info();
+ my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6);
+ #print "fd's for snmp -> ", @fd_set, "\n";
+ #print "block -> ", $block, "\n";
+ #print "timeout_sec -> ", $to_sec, "\n";
+ #print "timeout_usec -> ", $to_usec, "\n";
+ #print "timeout dec -> ", $time_sec_dec, "\n";
+ return ($time_sec_dec,@fd_set);
+}
+
+sub check_timeout {
+ # check to see if a snmp session
+ # timed out, and if so triggers
+ # the callback function
+ SNMP::_check_timeout();
+ # check to see when have to check again
+ my($block, $to_sec, $to_usec, @fd_set)=SNMP::_get_select_info();
+ my $time_sec_dec = ($block? 0 : $to_sec + $to_usec * 1e-6);
+ #print "fd's for snmp -> ", @fd_set, "\n";
+ #print "block -> ", $block, "\n";
+ #print "timeout_sec -> ", $to_sec, "\n";
+ #print "timeout_usec -> ", $to_usec, "\n";
+ #print "timeout dec -> ", $time_sec_dec, "\n";
+ return ($time_sec_dec);
+}
+
+sub _tie {
+# this is a little implementation hack so ActiveState can access pp_tie
+# thru perl code. All other environments allow the calling of pp_tie from
+# XS code but AS was not exporting it when PERL_OBJECT was used.
+#
+# short term solution was call this perl func which calls 'tie'
+#
+# longterm fix is to supply a patch which allows AS to export pp_tie in
+# such a way that it can be called from XS code. gsarathy says:
+# a patch to util.c is needed to provide access to PL_paddr
+# so it is possible to call PL_paddr[OP_TIE] as the compiler does
+ tie($_[0],$_[1],$_[2],$_[3]);
+}
+
+sub split_vars {
+ # This sub holds the regex that is used throughout this module
+ # to parse the base part of an OID from the IID.
+ # eg: portName.9.30 -> ['portName','9.30']
+ my $vars = shift;
+
+ # The regex was changed to this simple form by patch 722075 for some reason.
+ # Testing shows now (2/05) that it is not needed, and that the long expression
+ # works fine. AB
+ # my ($tag, $iid) = ($vars =~ /^(.*?)\.?(\d+)+$/);
+
+ # These following two are the same. Broken down for easier maintenance
+ # my ($tag, $iid) = ($vars =~ /^((?:\.\d+)+|(?:\w+(?:\-*\w+)+))\.?(.*)$/);
+ my ($tag, $iid) =
+ ($vars =~ /^( # Capture $1
+ # 1. either this 5.5.5.5
+ (?:\.\d+)+ # for grouping, won't increment $1
+ |
+ # 2. or asdf-asdf-asdf-asdf
+ (?: # grouping again
+ \w+ # needs some letters followed by
+ (?:\-*\w+)+ # zero or more dashes, one or more letters
+ )
+ )
+ \.? # optionally match a dot
+ (.*) # whatever is left in the string is our iid ($2)
+ $/x
+ );
+ return [$tag,$iid];
+}
+
+package SNMP::Session;
+
+sub new {
+ my $type = shift;
+ my $this = {};
+ my ($name, $aliases, $host_type, $len, $thisaddr);
+
+ SNMP::init_snmp("perl");
+
+ %$this = @_;
+
+ $this->{ErrorStr} = ''; # if methods return undef check for expln.
+ $this->{ErrorNum} = 0; # contains SNMP error return
+
+ $this->{Version} ||=
+ NetSNMP::default_store::netsnmp_ds_get_int(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID,
+ NetSNMP::default_store::NETSNMP_DS_LIB_SNMPVERSION) ||
+ SNMP::SNMP_DEFAULT_VERSION();
+
+ if ($this->{Version} eq 128) {
+ # special handling of the bogus v1 definition.
+ $this->{Version} = 1;
+ }
+
+ # allow override of local SNMP port
+ $this->{LocalPort} ||= 0;
+
+ # destination host defaults to localhost
+ $this->{DestHost} ||= 'localhost';
+
+ # community defaults to public
+ $this->{Community} ||= NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_COMMUNITY()) || 'public';
+
+ # number of retries before giving up, defaults to SNMP_DEFAULT_RETRIES
+ $this->{Retries} = SNMP::SNMP_DEFAULT_RETRIES() unless defined($this->{Retries});
+
+ # timeout before retry, defaults to SNMP_DEFAULT_TIMEOUT
+ $this->{Timeout} = SNMP::SNMP_DEFAULT_TIMEOUT() unless defined($this->{Timeout});
+ # flag to enable fixing pdu and retrying with a NoSuch error
+ $this->{RetryNoSuch} ||= 0;
+
+ # backwards compatibility. Make host = host:port
+ if ($this->{RemotePort} && $this->{DestHost} !~ /:/) {
+ $this->{DestHost} = $this->{DestHost} . ":" . $this->{RemotePort};
+ }
+
+ if ($this->{DestHost} =~ /^(dtls|tls|ssh)/) {
+ # only works with version 3
+ $this->{Version} = 3;
+ }
+
+ if ($this->{Version} eq '1' or $this->{Version} eq '2'
+ or $this->{Version} eq '2c') {
+ $this->{SessPtr} = SNMP::_new_session($this->{Version},
+ $this->{Community},
+ $this->{DestHost},
+ $this->{LocalPort},
+ $this->{Retries},
+ $this->{Timeout},
+ );
+ } elsif ($this->{Version} eq '3' ) {
+ $this->{SecName} ||=
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_SECNAME()) ||
+ 'initial';
+ if (!$this->{SecLevel}) {
+ $this->{SecLevel} =
+ NetSNMP::default_store::netsnmp_ds_get_int(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_SECLEVEL()) ||
+ $SNMP::V3_SEC_LEVEL_MAP{'noAuthNoPriv'};
+ } elsif ($this->{SecLevel} !~ /^\d+$/) {
+ $this->{SecLevel} = $SNMP::V3_SEC_LEVEL_MAP{$this->{SecLevel}};
+ }
+ $this->{SecEngineId} ||= '';
+ $this->{ContextEngineId} ||= $this->{SecEngineId};
+ $this->{Context} ||=
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_CONTEXT()) || '';
+
+ if ($this->{DestHost} =~ /^(dtls|tls|ssh)/) {
+ # this is a tunneled protocol
+
+ $this->{'OurIdentity'} ||= '';
+ $this->{'TheirIdentity'} ||= '';
+ $this->{'TheirHostname'} ||= '';
+ $this->{'TrustCert'} ||= '';
+
+ $this->{'SecLevel'} = $SNMP::V3_SEC_LEVEL_MAP{'authPriv'};
+
+ $this->{SessPtr} =
+ SNMP::_new_tunneled_session($this->{Version},
+ $this->{DestHost},
+ $this->{Retries},
+ $this->{Timeout},
+ $this->{SecName},
+ $this->{SecLevel},
+ $this->{ContextEngineId},
+ $this->{Context},
+ $this->{'OurIdentity'},
+ $this->{'TheirIdentity'},
+ $this->{'TheirHostname'},
+ $this->{'TrustCert'},
+ );
+
+
+ } else {
+ # USM or some other internal security protocol
+
+ # USM specific parameters:
+ $this->{AuthProto} ||= 'DEFAULT'; # use the library's default
+ $this->{AuthPass} ||=
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_AUTHPASSPHRASE()) ||
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_PASSPHRASE()) || '';
+
+ $this->{AuthMasterKey} ||= '';
+ $this->{PrivMasterKey} ||= '';
+ $this->{AuthLocalizedKey} ||= '';
+ $this->{PrivLocalizedKey} ||= '';
+
+ $this->{PrivProto} ||= 'DEFAULT'; # use the library's default
+ $this->{PrivPass} ||=
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_PRIVPASSPHRASE()) ||
+ NetSNMP::default_store::netsnmp_ds_get_string(NetSNMP::default_store::NETSNMP_DS_LIBRARY_ID(),
+ NetSNMP::default_store::NETSNMP_DS_LIB_PASSPHRASE()) || '';
+ $this->{EngineBoots} = 0 if not defined $this->{EngineBoots};
+ $this->{EngineTime} = 0 if not defined $this->{EngineTime};
+
+ $this->{SessPtr} =
+ SNMP::_new_v3_session($this->{Version},
+ $this->{DestHost},
+ $this->{Retries},
+ $this->{Timeout},
+ $this->{SecName},
+ $this->{SecLevel},
+ $this->{SecEngineId},
+ $this->{ContextEngineId},
+ $this->{Context},
+ $this->{AuthProto},
+ $this->{AuthPass},
+ $this->{PrivProto},
+ $this->{PrivPass},
+ $this->{EngineBoots},
+ $this->{EngineTime},
+ $this->{AuthMasterKey},
+ length($this->{AuthMasterKey}),
+ $this->{PrivMasterKey},
+ length($this->{PrivMasterKey}),
+ $this->{AuthLocalizedKey},
+ length($this->{AuthLocalizedKey}),
+ $this->{PrivLocalizedKey},
+ length($this->{PrivLocalizedKey}),
+ );
+ }
+ }
+ unless ($this->{SessPtr}) {
+ warn("unable to create session") if $SNMP::verbose;
+ return undef;
+ }
+
+ SNMP::initMib($SNMP::auto_init_mib); # ensures that *some* mib is loaded
+
+ $this->{UseLongNames} = $SNMP::use_long_names
+ unless exists $this->{UseLongNames};
+ $this->{UseSprintValue} = $SNMP::use_sprint_value
+ unless exists $this->{UseSprintValue};
+ $this->{BestGuess} = $SNMP::best_guess unless exists $this->{BestGuess};
+ $this->{NonIncreasing} ||= $SNMP::non_increasing;
+ $this->{UseEnums} = $SNMP::use_enums unless exists $this->{UseEnums};
+ $this->{UseNumeric} = $SNMP::use_numeric unless exists $this->{UseNumeric};
+
+ # Force UseLongNames if UseNumeric is in use.
+ $this->{UseLongNames}++ if $this->{UseNumeric};
+
+ bless $this, $type;
+}
+
+sub update {
+# *Not Implemented*
+# designed to update the fields of session to allow retargetting to different
+# host, community name change, timeout, retry changes etc. Unfortunately not
+# working yet because some updates (the address in particular) need to be
+# done on the internal session pointer which cannot be fetched w/o touching
+# globals at this point which breaks win32. A patch to the net-snmp toolkit
+# is needed
+ my $this = shift;
+ my ($name, $aliases, $host_type, $len, $thisaddr);
+ my %new_fields = @_;
+
+ @$this{keys %new_fields} = values %new_fields;
+
+ $this->{UseLongNames} = $SNMP::use_long_names
+ unless exists $this->{UseLongNames};
+ $this->{UseSprintValue} = $SNMP::use_sprint_value
+ unless exists $this->{UseSprintValue};
+ $this->{BestGuess} = $SNMP::best_guess unless exists $this->{BestGuess};
+ $this->{NonIncreasing} ||= $SNMP::non_increasing;
+ $this->{UseEnums} = $SNMP::use_enums unless exists $this->{UseEnums};
+ $this->{UseNumeric} = $SNMP::use_numeric unless exists $this->{UseNumeric};
+
+ # Force UseLongNames if UseNumeric is in use.
+ $this->{UseLongNames}++ if $this->{UseNumeric};
+
+ SNMP::_update_session($this->{Version},
+ $this->{Community},
+ $this->{DestHost},
+ $this->{RemotePort},
+ $this->{LocalPort},
+ $this->{Retries},
+ $this->{Timeout},
+ );
+
+
+}
+
+sub set {
+ my $this = shift;
+ my $vars = shift;
+ my $varbind_list_ref;
+ my $res = 0;
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ #$varbind_list_ref = [[$tag, $iid, $val]];
+ my $split_vars = SNMP::split_vars($vars);
+ my $val = shift;
+ push @$split_vars,$val;
+ $varbind_list_ref = [$split_vars];
+ }
+ my $cb = shift;
+
+ $res = SNMP::_set($this, $varbind_list_ref, $cb);
+}
+
+sub get {
+ my $this = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ $varbind_list_ref = [SNMP::split_vars($vars)];
+ }
+
+ my $cb = shift;
+
+ @res = SNMP::_get($this, $this->{RetryNoSuch}, $varbind_list_ref, $cb);
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+
+my $have_netsnmp_oid = eval { require NetSNMP::OID; };
+sub gettable {
+
+ #
+ # getTable
+ # --------
+ #
+ # Get OIDs starting at $table_oid, and continue down the tree
+ # until we get to an OID which does not start with $table_oid,
+ # i.e. we have reached the end of this table.
+ #
+
+ my $state;
+
+ my ($this, $root_oid, @options) = @_;
+ $state->{'options'} = {@options};
+ my ($textnode, $varbinds, $vbl, $res, $repeat);
+
+ # translate the OID into numeric form if its not
+ if ($root_oid !~ /^[\.0-9]+$/) {
+ $textnode = $root_oid;
+ $root_oid = SNMP::translateObj($root_oid);
+ } else {
+ $textnode = SNMP::translateObj($root_oid);
+ }
+
+ # bail if we don't have a valid oid.
+ return if (!$root_oid);
+
+ # deficed if we're going to parse indexes
+ my $parse_indexes = (defined($state->{'options'}{'noindexes'})) ?
+ 0 : $have_netsnmp_oid;
+
+ # get the list of columns we should look at.
+ my @columns;
+ if (!$state->{'options'}{'columns'}) {
+ if ($textnode) {
+ my %indexes;
+
+ if ($parse_indexes) {
+ # get indexes
+ my @indexes =
+ @{$SNMP::MIB{$textnode}{'children'}[0]{'indexes'} || []};
+ # quick translate into a hash
+ map { $indexes{$_} = 1; } @indexes;
+ }
+
+ # calculate the list of accessible columns that aren't indexes
+ my $children = $SNMP::MIB{$textnode}{'children'}[0]{'children'};
+ foreach my $c (@$children) {
+ push @{$state->{'columns'}},
+ $root_oid . ".1." . $c->{'subID'}
+ if (!$indexes{$c->{'label'}});
+ }
+ if ($#{$state->{'columns'}} == -1) {
+ # some tables are only indexes, and we need to walk at
+ # least one column. We pick the last.
+ push @{$state->{'columns'}}, $root_oid . ".1." .
+ $children->[$#$children]{'subID'}
+ if ref($state) eq 'HASH' and ref($children) eq 'ARRAY';
+ }
+ }
+ } else {
+ # XXX: requires specification in numeric OID... ack.!
+ @{$state->{'columns'}} = @{$state->{'options'}{'columns'}};
+
+ # if the columns aren't numeric, we need to turn them into
+ # numeric columns...
+ map {
+ if ($_ !~ /\.1\.3/) {
+ $_ = $SNMP::MIB{$_}{'objectID'};
+ }
+ } @{$state->{'columns'}};
+ }
+
+ # create the initial walking info.
+ foreach my $c (@{$state->{'columns'}}) {
+ push @{$state->{'varbinds'}}, [$c];
+ push @{$state->{'stopconds'}}, $c;
+ }
+
+ if ($#{$state->{'varbinds'}} == -1) {
+ print STDERR "ack: gettable failed to find any columns to look for.\n";
+ return;
+ }
+
+ $vbl = $state->{'varbinds'};
+
+ my $repeatcount;
+ if ($this->{Version} eq '1' || $state->{'options'}{nogetbulk}) {
+ $state->{'repeatcount'} = 1;
+ } elsif ($state->{'options'}{'repeat'}) {
+ $state->{'repeatcount'} = $state->{'options'}{'repeat'};
+ } elsif ($#{$state->{'varbinds'}} == -1) {
+ $state->{'repeatcount'} = 1;
+ } else {
+ # experimentally determined maybe guess at a best repeat value
+ # 1000 bytes max (safe), 30 bytes average for encoding of the
+ # varbind (experimentally determined to be closer to
+ # 26. Again, being safe. Then devide by the number of
+ # varbinds.
+ $state->{'repeatcount'} = int(1000 / 36 / ($#{$state->{'varbinds'}} + 1));
+ }
+ # Make sure we run at least once
+ if ($state->{'repeatcount'} < 1) {
+ $state->{'repeatcount'} = 1;
+ }
+
+ #
+ # if we've been configured with a callback, then call the
+ # sub-functions with a callback to our own "next" processing
+ # function (_gettable_do_it). or else call the blocking method and
+ # call the next processing function ourself.
+ #
+ if ($state->{'options'}{'callback'}) {
+ if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) {
+ $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl,
+ [\&_gettable_do_it, $this, $vbl,
+ $parse_indexes, $textnode, $state]);
+ } else {
+ $res = $this->getnext($vbl,
+ [\&_gettable_do_it, $this, $vbl,
+ $parse_indexes, $textnode, $state]);
+ }
+ } else {
+ if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) {
+ $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl);
+ } else {
+ $res = $this->getnext($vbl);
+ }
+ return $this->_gettable_do_it($vbl, $parse_indexes, $textnode, $state);
+ }
+ return 0;
+}
+
+sub _gettable_do_it() {
+ my ($this, $vbl, $parse_indexes, $textnode, $state) = @_;
+
+ my ($res);
+
+ $vbl = $_[$#_] if ($state->{'options'}{'callback'});
+
+ while ($#$vbl > -1 && !$this->{ErrorNum}) {
+ if (($#$vbl + 1) % ($#{$state->{'stopconds'}} + 1) != 0) {
+ if ($vbl->[$#$vbl][2] ne 'ENDOFMIBVIEW') {
+ # unless it's an end of mib view we didn't get the
+ # proper number of results back.
+ print STDERR "ack: gettable results not appropriate\n";
+ }
+ my @k = keys(%{$state->{'result_hash'}});
+ last if ($#k > -1); # bail with what we have
+ return;
+ }
+
+ $state->{'varbinds'} = [];
+ my $newstopconds;
+
+ my $lastsetstart = ($state->{'repeatcount'}-1) * ($#{$state->{'stopconds'}}+1);
+
+ for (my $i = 0; $i <= $#$vbl; $i++) {
+ my $row_oid = SNMP::translateObj($vbl->[$i][0]);
+ my $row_text = $vbl->[$i][0];
+ my $row_index = $vbl->[$i][1];
+ my $row_value = $vbl->[$i][2];
+ my $row_type = $vbl->[$i][3];
+
+ if ($row_oid =~
+ /^$state->{'stopconds'}[$i % ($#{$state->{'stopconds'}}+1)]/ &&
+ $row_value ne 'ENDOFMIBVIEW' ){
+
+ if ($row_type eq "OBJECTID") {
+
+ # If the value returned is an OID, translate this
+ # back in to a textual OID
+
+ $row_value = SNMP::translateObj($row_value);
+
+ }
+
+ # Place the results in a hash
+
+ $state->{'result_hash'}{$row_index}{$row_text} = $row_value;
+
+ # continue past this next time
+ if ($i >= $lastsetstart) {
+ push @$newstopconds,
+ $state->{'stopconds'}->[$i%($#{$state->{'stopconds'}}+1)];
+ push @{$state->{'varbinds'}},[$vbl->[$i][0],$vbl->[$i][1]];
+ }
+ }
+ }
+ if ($#$newstopconds == -1) {
+ last;
+ }
+ if ($#{$state->{'varbinds'}} == -1) {
+ print "gettable ack. shouldn't get here\n";
+ }
+ $vbl = $state->{'varbinds'};
+ $state->{'stopconds'} = $newstopconds;
+
+ #
+ # if we've been configured with a callback, then call the
+ # sub-functions with a callback to our own "next" processing
+ # function (_gettable_do_it). or else call the blocking method and
+ # call the next processing function ourself.
+ #
+ if ($state->{'options'}{'callback'}) {
+ if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) {
+ $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl,
+ [\&_gettable_do_it, $this, $vbl,
+ $parse_indexes, $textnode, $state]);
+ } else {
+ $res = $this->getnext($vbl,
+ [\&_gettable_do_it, $this, $vbl,
+ $parse_indexes, $textnode, $state]);
+ }
+ return;
+ } else {
+ if ($this->{Version} ne '1' && !$state->{'options'}{'nogetbulk'}) {
+ $res = $this->getbulk(0, $state->{'repeatcount'}, $vbl);
+ } else {
+ $res = $this->getnext($vbl);
+ }
+ }
+ }
+
+ # finish up
+ _gettable_end_routine($state, $parse_indexes, $textnode);
+
+ # return the hash if no callback was specified
+ if (!$state->{'options'}{'callback'}) {
+ return($state->{'result_hash'});
+ }
+
+ #
+ # if they provided a callback, call it
+ # (if an array pass the args as well)
+ #
+ if (ref($state->{'options'}{'callback'}) eq 'ARRAY') {
+ my $code = shift @{$state->{'options'}{'callback'}};
+ $code->(@{$state->{'options'}{'callback'}}, $state->{'result_hash'});
+ } else {
+ $state->{'options'}{'callback'}->($state->{'result_hash'});
+ }
+}
+
+sub _gettable_end_routine {
+ my ($state, $parse_indexes, $textnode) = @_;
+ if ($parse_indexes) {
+ my @indexes = @{$SNMP::MIB{$textnode}{'children'}[0]{'indexes'}};
+ my $i;
+ foreach my $trow (keys(%{$state->{'result_hash'}})) {
+ my $noid = new NetSNMP::OID($state->{'columns'}[0] . "." . $trow);
+ if (!$noid) {
+ print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB OID\n";
+ next;
+ }
+ my $nindexes = $noid->get_indexes();
+ if (!$nindexes || ref($nindexes) ne 'ARRAY' ||
+ $#indexes != $#$nindexes) {
+ print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB indexes:\n $noid => " . ref($nindexes) . "\n [should be an ARRAY]\n expended # indexes = $#indexes\n";
+ if (ref($nindexes) eq 'ARRAY') {
+ print STDERR "***** ERROR parsing $state->{'columns'}[0].$trow MIB indexes: " . ref($nindexes) . " $#indexes $#$nindexes\n";
+ }
+ next;
+ }
+
+ for ($i = 0; $i <= $#indexes; $i++) {
+ $state->{'result_hash'}{$trow}{$indexes[$i]} = $nindexes->[$i];
+ }
+ }
+ }
+}
+
+
+sub fget {
+ my $this = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ $varbind_list_ref = [SNMP::split_vars($vars)];
+ }
+
+ my $cb = shift;
+
+ SNMP::_get($this, $this->{RetryNoSuch}, $varbind_list_ref, $cb);
+
+ foreach my $varbind (@$varbind_list_ref) {
+ my $sub = $this->{VarFormats}{SNMP::Varbind::tag($varbind)} ||
+ $this->{TypeFormats}{SNMP::Varbind::type($varbind)};
+ &$sub($varbind) if defined $sub;
+ push(@res, SNMP::Varbind::val($varbind));
+ }
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+sub getnext {
+ my $this = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ $varbind_list_ref = [SNMP::split_vars($vars)];
+ }
+
+ my $cb = shift;
+
+ @res = SNMP::_getnext($this, $varbind_list_ref, $cb);
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+sub fgetnext {
+ my $this = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ $varbind_list_ref = [SNMP::split_vars($vars)];
+ }
+
+ my $cb = shift;
+
+ SNMP::_getnext($this, $varbind_list_ref, $cb);
+
+ foreach my $varbind (@$varbind_list_ref) {
+ my $sub = $this->{VarFormats}{SNMP::Varbind::tag($varbind)} ||
+ $this->{TypeFormats}{SNMP::Varbind::type($varbind)};
+ &$sub($varbind) if defined $sub;
+ push(@res, SNMP::Varbind::val($varbind));
+ }
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+sub getbulk {
+ my $this = shift;
+ my $nonrepeaters = shift;
+ my $maxrepetitions = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ $varbind_list_ref = [SNMP::split_vars($vars)];
+ }
+
+ my $cb = shift;
+
+ @res = SNMP::_getbulk($this, $nonrepeaters, $maxrepetitions, $varbind_list_ref, $cb);
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+sub bulkwalk {
+ my $this = shift;
+ my $nonrepeaters = shift;
+ my $maxrepetitions = shift;
+ my $vars = shift;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ } else {
+ # my ($tag, $iid) = ($vars =~ /^((?:\.\d+)+|\w+)\.?(.*)$/);
+ my ($tag, $iid) = ($vars =~ /^(.*?)\.?(\d+)+$/);
+ $varbind_list_ref = [[$tag, $iid]];
+ }
+
+ if (scalar @$varbind_list_ref == 0) {
+ $this->{ErrorNum} = SNMP::constant("SNMPERR_GENERR", 0);
+ $this->{ErrorStr} = "cannot bulkwalk() empty variable list";
+ return undef;
+ }
+ if (scalar @$varbind_list_ref < $nonrepeaters) {
+ $this->{ErrorNum} = SNMP::constant("SNMPERR_GENERR", 0);
+ $this->{ErrorStr} = "bulkwalk() needs at least $nonrepeaters varbinds";
+ return undef;
+ }
+
+ my $cb = shift;
+ @res = SNMP::_bulkwalk($this, $nonrepeaters, $maxrepetitions,
+ $varbind_list_ref, $cb);
+
+ # Return, in list context, a copy of the array of arrays of Varbind refs.
+ # In scalar context, return either a reference to the array of arrays of
+ # Varbind refs, or the request ID for an asynchronous bulkwalk. This is
+ # a compromise between the getbulk()-ish return, and the more useful array
+ # of arrays of Varbinds return from the synchronous bulkwalk().
+ #
+ return @res if (wantarray());
+ return defined($cb) ? $res[0] : \@res;
+}
+
+my %trap_type = (coldStart => 0, warmStart => 1, linkDown => 2, linkUp => 3,
+ authFailure => 4, egpNeighborLoss => 5, specific => 6 );
+sub trap {
+# (v1) enterprise, agent, generic, specific, uptime, <vars>
+# $sess->trap(enterprise=>'.1.3.6.1.4.1.2021', # or 'ucdavis' [default]
+# agent => '127.0.0.1', # or 'localhost',[default 1st intf on host]
+# generic => specific, # can be omitted if 'specific' supplied
+# specific => 5, # can be omitted if 'generic' supplied
+# uptime => 1234, # default to localhost uptime (0 on win32)
+# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+# # always last
+# (v2) oid, uptime, <vars>
+# $sess->trap(uptime => 1234,
+# oid => 'snmpRisingAlarm',
+# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+# # always last
+# # always last
+
+
+ my $this = shift;
+ my $vars = pop if ref($_[$#_]); # last arg may be varbind or varlist
+ my %param = @_;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ }
+
+ if ($this->{Version} eq '1') {
+ my $enterprise = $param{enterprise} || 'ucdavis';
+ $enterprise = SNMP::translateObj($enterprise)
+ unless $enterprise =~ /^[\.\d]+$/;
+ my $agent = $param{agent} || '';
+ my $generic = $param{generic} || 'specific';
+ $generic = $trap_type{$generic} || $generic;
+ my $uptime = $param{uptime} || SNMP::_sys_uptime();
+ my $specific = $param{specific} || 0;
+ @res = SNMP::_trapV1($this, $enterprise, $agent, $generic, $specific,
+ $uptime, $varbind_list_ref);
+ } elsif (($this->{Version} eq '2')|| ($this->{Version} eq '2c')) {
+ my $trap_oid = $param{oid} || $param{trapoid} || '.0.0';
+ my $uptime = $param{uptime} || SNMP::_sys_uptime();
+ @res = SNMP::_trapV2($this, $uptime, $trap_oid, $varbind_list_ref);
+ }
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+sub inform {
+# (v3) oid, uptime, <vars>
+# $sess->inform(uptime => 1234,
+# oid => 'coldStart',
+# [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+# # then callback
+ # always last
+
+
+ my $this = shift;
+ my $vars;
+ my $cb;
+ $cb = pop if ref($_[$#_]) eq 'CODE'; # last arg may be code
+ $vars = pop if ref($_[$#_]); # varbind or varlist
+ my %param = @_;
+ my ($varbind_list_ref, @res);
+
+ if (ref($vars) =~ /SNMP::VarList/) {
+ $varbind_list_ref = $vars;
+ } elsif (ref($vars) =~ /SNMP::Varbind/) {
+ $varbind_list_ref = [$vars];
+ } elsif (ref($vars) =~ /ARRAY/) {
+ $varbind_list_ref = [$vars];
+ $varbind_list_ref = $vars if ref($$vars[0]) =~ /ARRAY/;
+ }
+
+ my $trap_oid = $param{oid} || $param{trapoid};
+ my $uptime = $param{uptime} || SNMP::_sys_uptime();
+
+ if($this->{Version} eq '3') {
+ @res = SNMP::_inform($this, $uptime, $trap_oid, $varbind_list_ref, $cb);
+ } else {
+ warn("error:inform: This version doesn't support the command\n");
+ }
+
+ return(wantarray() ? @res : $res[0]);
+}
+
+package SNMP::TrapSession;
+@SNMP::TrapSession::ISA = ('SNMP::Session');
+
+sub new {
+ my $type = shift;
+
+ # allow override of remote SNMP trap port
+ unless (grep(/RemotePort/, @_)) {
+ push(@_, 'RemotePort', 162); # push on new default for trap session
+ }
+
+ SNMP::Session::new($type, @_);
+}
+
+package SNMP::Varbind;
+
+$SNMP::Varbind::tag_f = 0;
+$SNMP::Varbind::iid_f = 1;
+$SNMP::Varbind::val_f = 2;
+$SNMP::Varbind::type_f = 3;
+$SNMP::Varbind::time_f = 4;
+
+sub new {
+ my $type = shift;
+ my $this = shift;
+ $this ||= [];
+ bless $this;
+}
+
+sub tag {
+ $_[0]->[$SNMP::Varbind::tag_f];
+}
+
+sub iid {
+ $_[0]->[$SNMP::Varbind::iid_f];
+}
+
+sub val {
+ $_[0]->[$SNMP::Varbind::val_f];
+}
+
+sub type {
+ $_[0]->[$SNMP::Varbind::type_f];
+}
+
+sub name {
+ if (defined($_[0]->[$SNMP::Varbind::iid_f]) && ($_[0]->[$SNMP::Varbind::iid_f] =~ m/^[0-9]+$/)) {
+ return $_[0]->[$SNMP::Varbind::tag_f] . "." . $_[0]->[$SNMP::Varbind::iid_f];
+ }
+
+ return $_[0]->[$SNMP::Varbind::tag_f];
+}
+
+sub fmt {
+ my $self = shift;
+ return $self->name . " = \"" . $self->val . "\" (" . $self->type . ")";
+}
+
+
+#sub DESTROY {
+# print "SNMP::Varbind::DESTROY($_[0])\n";
+#}
+
+package SNMP::VarList;
+
+sub new {
+ my $type = shift;
+ my $this = [];
+ my $varb;
+ foreach $varb (@_) {
+ $varb = new SNMP::Varbind($varb) unless ref($varb) =~ /SNMP::Varbind/;
+ push(@{$this}, $varb);
+ }
+
+ bless $this;
+}
+
+#sub DESTROY {
+# print "SNMP::VarList::DESTROY($_[0])\n";
+#}
+
+package SNMP::DEBUGGING;
+# controls info/debugging output from SNMP module and libsnmp
+# $SNMP::debugging == 1 => enables general info and warning output
+# (eqiv. to setting $SNMP::verbose)
+# $SNMP::debugging == 2 => enables do_debugging from libsnmp as well
+# $SNMP::debugging == 3 => enables packet_dump from libsnmp as well
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE {
+ $SNMP::verbose = $_[1];
+ SNMP::_set_debugging($_[1]>1);
+ $SNMP::dump_packet = ($_[1]>2);
+ ${$_[0]} = $_[1];
+}
+
+sub DELETE {
+ $SNMP::verbose = 0;
+ SNMP::_set_debugging(0);
+ $SNMP::dump_packet = 0;
+ ${$_[0]} = undef;
+}
+
+package SNMP::DEBUG_INTERNALS; # Controls SNMP.xs debugging.
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE {
+ SNMP::_debug_internals($_[1]);
+ ${$_[0]} = $_[1];
+}
+
+sub DELETE {
+ SNMP::_debug_internals(0);
+ ${$_[0]} = undef;
+}
+
+package SNMP::DUMP_PACKET;
+# controls packet dump output from libsnmp
+
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE { SNMP::_dump_packet($_[1]); ${$_[0]} = $_[1]; }
+
+sub DELETE { SNMP::_dump_packet(0); ${$_[0]} = 0; }
+
+package SNMP::MIB;
+
+sub TIEHASH {
+ bless {};
+}
+
+sub FETCH {
+ my $this = shift;
+ my $key = shift;
+
+ if (!defined $this->{$key}) {
+ tie(%{$this->{$key}}, 'SNMP::MIB::NODE', $key) or return undef;
+ }
+ $this->{$key};
+}
+
+sub STORE {
+ warn "STORE(@_) : write access to the MIB not implemented\n";
+}
+
+sub DELETE {
+ delete $_[0]->{$_[1]}; # just delete cache entry
+}
+
+sub FIRSTKEY { return '.1'; } # this should actually start at .0 but
+ # because nodes are not stored in lexico
+ # order in ucd-snmp node tree walk will
+ # miss most of the tree
+sub NEXTKEY { # this could be sped up by using an XS __get_next_oid maybe
+ my $node = $_[0]->FETCH($_[1])->{nextNode};
+ $node->{objectID};
+}
+sub EXISTS { exists $_[0]->{$_[1]} || $_[0]->FETCH($_[1]); }
+sub CLEAR { undef %{$_[0]}; } # clear the cache
+
+package SNMP::MIB::NODE;
+my %node_elements =
+ (
+ objectID => 0, # dotted decimal fully qualified OID
+ label => 0, # leaf textual identifier (e.g., 'sysDescr')
+ subID => 0, # leaf numeric OID component of objectID (e.g., '1')
+ moduleID => 0, # textual identifier for module (e.g., 'RFC1213-MIB')
+ parent => 0, # parent node
+ children => 0, # array reference of children nodes
+ indexes => 0, # returns array of column labels
+ implied => 0, # boolean: is the last index IMPLIED
+ varbinds => 0, # returns array of trap/notification varbinds
+ nextNode => 0, # next lexico node (BUG! does not return in lexico order)
+ type => 0, # returns simple type (see getType for values)
+ access => 0, # returns ACCESS (ReadOnly, ReadWrite, WriteOnly,
+ # NoAccess, Notify, Create)
+ status => 0, # returns STATUS (Mandatory, Optional, Obsolete,
+ # Deprecated)
+ syntax => 0, # returns 'textualConvention' if defined else 'type'
+ textualConvention => 0, # returns TEXTUAL-CONVENTION
+ units => 0, # returns UNITS
+ hint => 0, # returns HINT
+ enums => 0, # returns hash ref {tag => num, ...}
+ ranges => 0, # returns array ref of hash ref [{low => num, high => num}]
+ defaultValue => 0, # returns default value
+ description => 0, # returns DESCRIPTION ($SNMP::save_descriptions must
+ # be set prior to MIB initialization/parsing
+ augments => 0, # textual identifier of augmented object
+ );
+
+# sub TIEHASH - implemented in SNMP.xs
+
+# sub FETCH - implemented in SNMP.xs
+
+sub STORE {
+ warn "STORE(@_): write access to MIB node not implemented\n";
+}
+
+sub DELETE {
+ warn "DELETE(@_): write access to MIB node not implemented\n";
+}
+
+sub FIRSTKEY { my $k = keys %node_elements; (each(%node_elements))[0]; }
+sub NEXTKEY { (each(%node_elements))[0]; }
+sub EXISTS { exists($node_elements{$_[1]}); }
+sub CLEAR {
+ warn "CLEAR(@_): write access to MIB node not implemented\n";
+}
+
+#sub DESTROY {
+# warn "DESTROY(@_): write access to MIB node not implemented\n";
+# # print "SNMP::MIB::NODE::DESTROY : $_[0]->{label} ($_[0])\n";
+#}
+package SNMP::MIB::SAVE_DESCR;
+
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE { SNMP::_set_save_descriptions($_[1]); ${$_[0]} = $_[1]; }
+
+sub DELETE { SNMP::_set_save_descriptions(0); ${$_[0]} = 0; }
+
+package SNMP::MIB::REPLACE_NEWER; # Controls MIB parsing
+
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE {
+ SNMP::_set_replace_newer($_[1]);
+ ${$_[0]} = $_[1];
+}
+
+sub DELETE {
+ SNMP::_set_replace_newer(0);
+ ${$_[0]} = 0;
+}
+
+package SNMP::MIB::MIB_OPTIONS;
+
+sub TIESCALAR { my $class = shift; my $val; bless \$val, $class; }
+
+sub FETCH { ${$_[0]}; }
+
+sub STORE { SNMP::_mib_toggle_options($_[1]); ${$_[0]} = $_[1]; }
+
+sub DELETE { SNMP::_mib_toggle_options(0); ${$_[0]} = ''; }
+
+package SNMP;
+END{SNMP::_sock_cleanup() if defined &SNMP::_sock_cleanup;}
+# Autoload methods go after __END__, and are processed by the autosplit prog.
+
+1;
+__END__
+
+=head1 NAME
+
+SNMP - The Perl5 'SNMP' Extension Module for the Net-SNMP SNMP package.
+
+=head1 SYNOPSIS
+
+ use SNMP;
+ ...
+ $sess = new SNMP::Session(DestHost => localhost, Community => public);
+ $val = $sess->get('sysDescr.0');
+ ...
+ $vars = new SNMP::VarList([sysDescr,0], [sysContact,0], [sysLocation,0]);
+ @vals = $sess->get($vars);
+ ...
+ $vb = new SNMP::Varbind();
+ do {
+ $val = $sess->getnext($vb);
+ print "@{$vb}\n";
+ } until ($sess->{ErrorNum});
+ ...
+ $SNMP::save_descriptions = 1;
+ SNMP::initMib(); # assuming mib is not already loaded
+ print "$SNMP::MIB{sysDescr}{description}\n";
+
+=head1 DESCRIPTION
+
+
+Note: The perl SNMP 5.0 module which comes with net-snmp 5.0 and
+higher is different than previous versions in a number of ways. Most
+importantly, it behaves like a proper net-snmp application and calls
+init_snmp properly, which means it will read configuration files and
+use those defaults where appropriate automatically parse MIB files,
+etc. This will likely affect your perl applications if you have, for
+instance, default values set up in your snmp.conf file (as the perl
+module will now make use of those defaults). The documentation,
+however, has sadly not been updated yet (aside from this note), nor is
+the read_config default usage implementation fully complete.
+
+The basic operations of the SNMP protocol are provided by this module
+through an object oriented interface for modularity and ease of use.
+The primary class is SNMP::Session which encapsulates the persistent
+aspects of a connection between the management application and the
+managed agent. Internally the class is implemented as a blessed hash
+reference. This class supplies 'get', 'getnext', 'set', 'fget', and
+'fgetnext' method calls. The methods take a variety of input argument
+formats and support both synchronous and asynchronous operation through
+a polymorphic API (i.e., method behaviour varies dependent on args
+passed - see below).
+
+=head1 SNMP::Session
+
+$sess = new SNMP::Session(DestHost => 'host', ...)
+
+The following arguments may be passed to new as a hash.
+
+=head2 Basic Options
+
+=over 4
+
+=item DestHost
+
+Hostname or IP address of the SNMP agent you want to talk to.
+Specified in Net-SNMP formatted agent addresses. These addresses
+typically look like one of the following:
+
+ localhost
+ tcp:localhost
+ tls:localhost
+ tls:localhost:9876
+ udp6:[::1]:9876
+ unix:/some/path/to/file/socket
+
+Defaults to 'localhost'.
+
+=item Version
+
+SNMP version to use.
+
+The default is taken from library configuration - probably 3 [1, 2
+(same as 2c), 2c, 3].
+
+=item Timeout
+
+The number of micro-seconds to wait before resending a request.
+
+The default is '1000000'
+
+=item Retries
+
+The number of times to retry a request.
+
+The default is '5'
+
+=item RetryNoSuch
+
+If enabled NOSUCH errors in 'get' pdus will
+be repaired, removing the varbind in error, and resent -
+undef will be returned for all NOSUCH varbinds, when set
+to '0' this feature is disabled and the entire get request
+will fail on any NOSUCH error (applies to v1 only)
+
+The default is '0'.
+
+=back
+
+=head2 SNMPv3/TLS Options
+
+=over
+
+=item OurIdentity
+
+Our X.509 identity to use, which should either be a fingerprint or the
+filename that holds the certificate.
+
+=item TheirIdentity
+
+The remote server's identity to connect to, specified as eihter a
+fingerprint or a file name. Either this must be specified, or the
+hostname below along with a trust anchor.
+
+=item TheirHostname
+
+The remote server's hostname that is expected. If their certificate
+was signed by a CA then their hostname presented in the certificate
+must match this value or the connection fails to be established (to
+avoid man-in-the-middle attacks).
+
+=item TrustCert
+
+A trusted certificate to use a trust anchor (like a CA certificate)
+for verifying a remote server's certificate. If a CA certificate is
+used to validate a certificate then the TheirHostname parameter must
+also be specified to ensure their presente hostname in the certificate
+matches.
+
+=back
+
+=head2 SNMPv3/USM Options
+
+=over
+
+=item SecName
+
+The SNMPv3 security name to use (most for SNMPv3 with USM).
+
+The default is 'initial'.
+
+=item SecLevel
+
+The SNMPv3 security level to use [noAuthNoPriv, authNoPriv, authPriv] (v3)
+
+The default is 'noAuthNoPriv'.
+
+=item SecEngineId
+
+The SNMPv3 security engineID to use (if the snmpv3 security model
+needs it; for example USM).
+
+The default is <none>, security engineID and it will be probed if not
+supplied (v3)
+
+=item ContextEngineId
+
+The SNMPv3 context engineID to use.
+
+The default is the <none> and will be set either to the SecEngineId
+value if set or discovered or will be discovered in other ways if
+using TLS (RFC5343 based discovery).
+
+=item Context
+
+The SNMPv3 context name to use.
+
+The default is '' (an empty string)
+
+=item AuthProto
+
+The SNMPv3/USM authentication protocol to use [MD5, SHA].
+
+The default is 'MD5'.
+
+=item AuthPass
+
+The SNMPv3/USM authentication passphrase to use.
+
+default <none>, authentication passphrase
+
+=item PrivProto
+
+The SNMPv3/USM privacy protocol to use [DES, AES].
+
+The default is 'DES'.
+
+=item PrivPass
+
+The SNMPv3/USM privacy passphrase to use.
+
+default <none>, privacy passphrase (v3)
+
+=item AuthMasterKey
+
+=item PrivMasterKey
+
+=item AuthLocalizedKey
+
+=item PrivLocalizedKey
+
+Directly specified SNMPv3 USM user keys (used if you want to specify
+the keys instead of deriving them from a password as above).
+
+=back
+
+=head2 SNMPv1 and SNMPv2c Options
+
+=item Community
+
+For SNMPv1 and SNMPv2c, the clear-text community name to use.
+
+The default is 'public'.
+
+=head2 Other Configuration Options
+
+=over
+
+=item VarFormats
+
+default 'undef', used by 'fget[next]', holds an hash
+reference of output value formatters, (e.g., {<obj> =>
+<sub-ref>, ... }, <obj> must match the <obj> and format
+used in the get operation. A special <obj>, '*', may be
+used to apply all <obj>s, the supplied sub is called to
+translate the value to a new format. The sub is called
+passing the Varbind as the arg
+
+=item TypeFormats
+
+default 'undef', used by 'fget[next]', holds an hash
+reference of output value formatters, (e.g., {<type> =>
+<sub-ref>, ... }, the supplied sub is called to translate
+the value to a new format, unless a VarFormat mathces first
+(e.g., $sess->{TypeFormats}{INTEGER} = \&mapEnum();
+although this can be done more efficiently by enabling
+$SNMP::use_enums or session creation param 'UseEnums')
+
+=item UseLongNames
+
+defaults to the value of SNMP::use_long_names at time
+of session creation. set to non-zero to have <tags>
+for 'getnext' methods generated preferring longer Mib name
+convention (e.g., system.sysDescr vs just sysDescr)
+
+=item UseSprintValue
+
+defaults to the value of SNMP::use_sprint_value at time
+of session creation. set to non-zero to have return values
+for 'get' and 'getnext' methods formatted with the libraries
+snprint_value function. This will result in certain data types
+being returned in non-canonical format Note: values returned
+with this option set may not be appropriate for 'set' operations
+(see discussion of value formats in <vars> description section)
+
+=item UseEnums
+
+defaults to the value of SNMP::use_enums at time of session
+creation. set to non-zero to have integer return values
+converted to enumeration identifiers if possible, these values
+will also be acceptable when supplied to 'set' operations
+
+=item UseNumeric
+
+defaults to the value of SNMP::use_numeric at time of session
+creation. set to non-zero to have <tags> for get methods returned
+as numeric OID's rather than descriptions. UseLongNames will be
+set so that the full OID is returned to the caller.
+
+=item BestGuess
+
+defaults to the value of SNMP::best_guess at time of session
+creation. this setting controls how <tags> are parsed. setting to
+0 causes a regular lookup. setting to 1 causes a regular expression
+match (defined as -Ib in snmpcmd) and setting to 2 causes a random
+access lookup (defined as -IR in snmpcmd).
+
+=item NonIncreasing
+
+defaults to the value of SNMP::non_increasing at time of session
+creation. this setting controls if a non-increasing OID during
+bulkwalk will causes an error. setting to 0 causes the default
+behaviour (which may, in very badly performing agents, result in a never-ending loop).
+setting to 1 causes an error (OID not increasing) when this error occur.
+
+=item ErrorStr
+
+read-only, holds the error message assoc. w/ last request
+
+=item ErrorNum
+
+read-only, holds the snmp_err or staus of last request
+
+=item ErrorInd
+
+read-only, holds the snmp_err_index when appropriate
+
+=back
+
+Private variables:
+
+=over
+
+=item DestAddr
+
+internal field used to hold the translated DestHost field
+
+=item SessPtr
+
+internal field used to cache a created session structure
+
+=item RemotePort
+
+Obsolete. Please use the DestHost specifier to indicate the hostname
+and port combination instead of this paramet.
+
+=back
+
+=head2 SNMP::Session methods
+
+=over
+
+=item $sess->update(E<lt>fieldsE<gt>)
+
+Updates the SNMP::Session object with the values fields
+passed in as a hash list (similar to new(E<lt>fieldsE<gt>))
+B<(WARNING! not fully implemented)>
+
+=item $sess->get(E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+do SNMP GET, multiple <vars> formats accepted.
+for syncronous operation <vars> will be updated
+with value(s) and type(s) and will also return
+retrieved value(s). If <callback> supplied method
+will operate asynchronously
+
+=item $sess->fget(E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+do SNMP GET like 'get' and format the values according
+the handlers specified in $sess->{VarFormats} and
+$sess->{TypeFormats}
+
+=item $sess->getnext(E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+do SNMP GETNEXT, multiple <vars> formats accepted,
+returns retrieved value(s), <vars> passed as arguments are
+updated to indicate next lexicographical <obj>,<iid>,<val>,
+and <type>
+
+Note: simple string <vars>,(e.g., 'sysDescr.0')
+form is not updated. If <callback> supplied method
+will operate asynchronously
+
+=item $sess->fgetnext(E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+do SNMP GETNEXT like getnext and format the values according
+the handlers specified in $sess->{VarFormats} and
+$sess->{TypeFormats}
+
+=item $sess->set(E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+do SNMP SET, multiple <vars> formats accepted.
+the value field in all <vars> formats must be in a canonical
+format (i.e., well known format) to ensure unambiguous
+translation to SNMP MIB data value (see discussion of
+canonical value format <vars> description section),
+returns snmp_errno. If <callback> supplied method
+will operate asynchronously
+
+=item $sess->getbulk(E<lt>non-repeatersE<gt>, E<lt>max-repeatersE<gt>, E<lt>varsE<gt>)
+
+do an SNMP GETBULK, from the list of Varbinds, the single
+next lexico instance is fetched for the first n Varbinds
+as defined by <non-repeaters>. For remaining Varbinds,
+the m lexico instances are retrieved each of the remaining
+Varbinds, where m is <max-repeaters>.
+
+=item $sess->bulkwalk(E<lt>non-repeatersE<gt>, E<lt>max-repeatersE<gt>, E<lt>varsE<gt> [,E<lt>callbackE<gt>])
+
+Do a "bulkwalk" of the list of Varbinds. This is done by
+sending a GETBULK request (see getbulk() above) for the
+Varbinds. For each requested variable, the response is
+examined to see if the next lexico instance has left the
+requested sub-tree. Any further instances returned for
+this variable are ignored, and the walk for that sub-tree
+is considered complete.
+
+If any sub-trees were not completed when the end of the
+responses is reached, another request is composed, consisting
+of the remaining variables. This process is repeated until
+all sub-trees have been completed, or too many packets have
+been exchanged (to avoid loops).
+
+The bulkwalk() method returns an array containing an array of
+Varbinds, one for each requested variable, in the order of the
+variable requests. Upon error, bulkwalk() returns undef and
+sets $sess->ErrorStr and $sess->ErrorNum. If a callback is
+supplied, bulkwalk() returns the SNMP request id, and returns
+immediately. The callback will be called with the supplied
+argument list and the returned variables list.
+
+Note: Because the client must "discover" that the tree is
+complete by comparing the returned variables with those that
+were requested, there is a potential "gotcha" when using the
+max-repeaters value. Consider the following code to print a
+list of interfaces and byte counts:
+
+ $numInts = $sess->get('ifNumber.0');
+ ($desc, $in, $out) = $sess->bulkwalk(0, $numInts,
+ [['ifDescr'], ['ifInOctets'], ['ifOutOctets']]);
+
+ for $i (0..($numInts - 1)) {
+ printf "Interface %4s: %s inOctets, %s outOctets\n",
+ $$desc[$i]->val, $$in[$i]->val, $$out[$i]->val;
+ }
+
+This code will produce *two* requests to the agent -- the first
+to get the interface values, and the second to discover that all
+the information was in the first packet. To get around this,
+use '$numInts + 1' for the max_repeaters value. This asks the
+agent to include one additional (unrelated) variable that signals
+the end of the sub-tree, allowing bulkwalk() to determine that
+the request is complete.
+
+=item $results = $sess->gettable(E<lt>TABLE OIDE<gt>, E<lt>OPTIONS<gt>)
+
+This will retrieve an entire table of data and return a hash reference
+to that data. The returned hash reference will have indexes of the
+OID suffixes for the index data as the key. The value for each entry
+will be another hash containing the data for a given row. The keys to
+that hash will be the column names, and the values will be the data.
+
+Example:
+
+ #!/usr/bin/perl
+
+ use SNMP;
+ use Data::Dumper;
+
+ my $s = new SNMP::Session(DestHost => 'localhost');
+
+ print Dumper($s->gettable('ifTable'));
+
+On my machine produces:
+
+ $VAR1 = {
+ '6' => {
+ 'ifMtu' => '1500',
+ 'ifPhysAddress' => 'PV',
+ # ...
+ 'ifInUnknownProtos' => '0'
+ },
+ '4' => {
+ 'ifMtu' => '1480',
+ 'ifPhysAddress' => '',
+ # ...
+ 'ifInUnknownProtos' => '0'
+ },
+ # ...
+ };
+
+By default, it will try to do as optimized retrieval as possible.
+It'll request multiple columns at once, and use GETBULK if possible.
+A few options may be specified by passing in an I<OPTIONS> hash
+containing various parameters:
+
+=over
+
+=item noindexes => 1
+
+Instructs the code not to parse the indexes and place the results in
+the second hash. If you don't need the index data, this will be
+faster.
+
+=item columns => [ colname1, ... ]
+
+This specifies which columns to collect. By default, it will try to
+collect all the columns defined in the MIB table.
+
+=item repeat => I<COUNT>
+
+Specifies a GETBULK repeat I<COUNT>. IE, it will request this many
+varbinds back per column when using the GETBULK operation. Shortening
+this will mean smaller packets which may help going through some
+systems. By default, this value is calculated and attempts to guess
+at what will fit all the results into 1000 bytes. This calculation is
+fairly safe, hopefully, but you can either raise or lower the number
+using this option if desired. In lossy networks, you want to make
+sure that the packets don't get fragmented and lowering this value is
+one way to help that.
+
+=item nogetbulk => 1
+
+Force the use of GETNEXT rather than GETBULK. (always true for
+SNMPv1, as it doesn't have GETBULK anyway). Some agents are great
+implementers of GETBULK and this allows you to force the use of
+GETNEXT operations instead.
+
+=item callback => \&subroutine
+
+=item callback => [\&subroutine, optarg1, optarg2, ...]
+
+If a callback is specified, gettable will return quickly without
+returning results. When the results are finally retrieved the
+callback subroutine will be called (see the other sections defining
+callback behaviour and how to make use of SNMP::MainLoop which is
+required fro this to work). An additional argument of the normal hash
+result will be added to the callback subroutine arguments.
+
+Note 1: internally, the gettable function uses it's own callbacks
+which are passed to getnext/getbulk as appropriate.
+
+Note 2: callback support is only available in the SNMP module version
+5.04 and above. To test for this in code intending to support both
+versions prior to 5.04 and 5.04 and up, the following should work:
+
+ if ($response = $sess->gettable('ifTable', callback => \&my_sub)) {
+ # got a response, gettable doesn't support callback
+ my_sub($response);
+ $no_mainloop = 1;
+ }
+
+Deciding on whether to use SNMP::MainLoop is left as an exercise to
+the reader since it depends on whether your code uses other callbacks
+as well.
+
+=back
+
+=back
+
+=head1 SNMP::TrapSession
+
+$sess = new SNMP::Session(DestHost => 'host', ...)
+
+supports all applicable fields from SNMP::Session
+(see above)
+
+=head2 SNMP::TrapSession methods
+
+=over
+
+=item $sess->trap(enterprise, agent, generic, specific, uptime, <vars>)
+
+ $sess->trap(enterprise=>'.1.3.6.1.4.1.2021', # or 'ucdavis' [default]
+ agent => '127.0.0.1', # or 'localhost',[dflt 1st intf on host]
+ generic => specific, # can be omitted if 'specific' supplied
+ specific => 5, # can be omitted if 'generic' supplied
+ uptime => 1234, # dflt to localhost uptime (0 on win32)
+ [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+ # always last
+
+=item trap(oid, uptime, <vars>) - v2 format
+
+ $sess->trap(oid => 'snmpRisingAlarm',
+ uptime => 1234,
+ [[ifIndex, 1, 1],[sysLocation, 0, "here"]]); # optional vars
+ # always last
+
+=back
+
+=head1 Acceptable variable formats:
+
+<vars> may be one of the following forms:
+
+=over
+
+=item SNMP::VarList
+
+represents an array of MIB objects to get or set,
+implemented as a blessed reference to an array of
+SNMP::Varbinds, (e.g., [<varbind1>, <varbind2>, ...])
+
+=item SNMP::Varbind
+
+represents a single MIB object to get or set, implemented as
+a blessed reference to a 4 element array;
+[<obj>, <iid>, <val>, <type>].
+
+=over
+
+=item <obj>
+
+one of the following forms:
+
+=over
+
+=item 1)
+
+leaf identifier (e.g., 'sysDescr') assumed to be
+unique for practical purposes
+
+=item 2)
+
+fully qualified identifier (e.g.,
+'.iso.org.dod.internet.mgmt.mib-2.system.sysDescr')
+
+=item 3)
+
+fully qualified, dotted-decimal, numeric OID (e.g.,
+'.1.3.6.1.2.1.1.1')
+
+=back
+
+=item <iid>
+
+the dotted-decimal, instance identifier. for
+scalar MIB objects use '0'
+
+=item <val>
+
+the SNMP data value retrieved from or being set
+to the agents MIB. for (f)get(next) operations
+<val> may have a variety of formats as determined by
+session and package settings. However for set
+operations the <val> format must be canonical to
+ensure unambiguous translation. The canonical forms
+are as follows:
+
+=over
+
+=item OBJECTID
+
+dotted-decimal (e.g., .1.3.6.1.2.1.1.1)
+
+=item OCTETSTR
+
+perl scalar containing octets
+
+=item INTEGER
+
+decimal signed integer (or enum)
+
+=item NETADDR
+
+dotted-decimal
+
+=item IPADDR
+
+dotted-decimal
+
+=item COUNTER
+
+decimal unsigned integer
+
+=item COUNTER64
+
+decimal unsigned integer
+
+=item GAUGE
+
+decimal unsigned integer
+
+=item UINTEGER
+
+decimal unsigned integer
+
+=item TICKS
+
+decimal unsigned integer
+
+=item OPAQUE
+
+perl scalar containing octets
+
+=item NULL
+
+perl scalar containing nothing
+
+=back
+
+=item <type>
+
+SNMP data type (see list above), this field is
+populated by 'get' and 'getnext' operations. In
+some cases the programmer needs to populate this
+field when passing to a 'set' operation. this
+field need not be supplied when the attribute
+indicated by <tag> is already described by loaded
+Mib modules. for 'set's, if a numeric OID is used
+and the object is not currently in the loaded Mib,
+the <type> field must be supplied
+
+=back
+
+=item simple string
+
+light weight form of <var> used to 'set' or 'get' a
+single attribute without constructing an SNMP::Varbind.
+stored in a perl scalar, has the form '<tag>.<iid>',
+(e.g., 'sysDescr.0'). for 'set' operations the value
+is passed as a second arg. Note: This argument form is
+not updated in get[next] operations as are the other forms.
+
+=back
+
+=head1 Acceptable callback formats
+
+<callback> may be one of the following forms:
+
+=over
+
+=item without arguments
+
+=over
+
+=item \&subname
+
+=item sub { ... }
+
+=back
+
+=item or with arguments
+
+=over
+
+=item [ \&subname, $arg1, ... ]
+
+=item [ sub { ... }, $arg1, ... ]
+
+=item [ "method", $obj, $arg1, ... ]
+
+=back
+
+=back
+
+callback will be called when response is received or timeout
+occurs. the last argument passed to callback will be a
+SNMP::VarList reference. In case of timeout the last argument
+will be undef.
+
+=over
+
+=item &SNMP::MainLoop([<timeout>, [<callback>]])
+
+to be used with async SNMP::Session
+calls. MainLoop must be called after initial async calls
+so return packets from the agent will not be processed.
+If no args supplied this function enters an infinite loop
+so program must be exited in a callback or externally
+interrupted. If <timeout(sic)
+
+=item &SNMP::finish()
+
+This function, when called from an SNMP::MainLoop() callback
+function, will cause the current SNMP::MainLoop() to return
+after the callback is completed. finish() can be used to
+terminate an otherwise-infinite MainLoop. A new MainLoop()
+instance can then be started to handle further requests.
+
+=back
+
+=head1 SNMP package variables and functions
+
+=over
+
+=item $SNMP::VERSION
+
+the current version specifier (e.g., 3.1.0)
+
+=item $SNMP::auto_init_mib
+
+default '1', set to 0 to disable automatic reading
+of the MIB upon session creation. set to non-zero
+to call initMib at session creation which will result
+in MIB loading according to Net-SNMP env. variables (see
+man mib_api)
+
+=item $SNMP::verbose
+
+default '0', controls warning/info output of
+SNMP module, 0 => no output, 1 => enables warning/info
+output from SNMP module itself (is also controlled
+by SNMP::debugging - see below)
+
+=item $SNMP::use_long_names
+
+default '0', set to non-zero to enable the use of
+longer Mib identifiers. see translateObj. will also
+influence the formatting of <tag> in varbinds returned
+from 'getnext' operations. Can be set on a per session
+basis (UseLongNames)
+
+=item $SNMP::use_sprint_value
+
+default '0', set to non-zero to enable formatting of
+response values using the snmp libraries snprint_value
+function. can also be set on a per session basis (see
+UseSprintValue) Note: returned values may not be
+suitable for 'set' operations
+
+=item $SNMP::use_enums
+
+default '0',set non-zero to return values as enums and
+allow sets using enums where appropriate. integer data
+will still be accepted for set operations. can also be
+set on a per session basis (see UseEnums)
+
+=item $SNMP::use_numeric
+
+default to '0',set to non-zero to have <tags> for 'get'
+methods returned as numeric OID's rather than descriptions.
+UseLongNames will be set so that the entire OID will be
+returned. Set on a per-session basis (see UseNumeric).
+
+=item $SNMP::best_guess
+
+default '0'. This setting controls how <tags> are
+parsed. Setting to 0 causes a regular lookup. Setting
+to 1 causes a regular expression match (defined as -Ib
+in snmpcmd) and setting to 2 causes a random access
+lookup (defined as -IR in snmpcmd). Can also be set
+on a per session basis (see BestGuess)
+
+=item $SNMP::save_descriptions
+
+default '0',set non-zero to have mib parser save
+attribute descriptions. must be set prior to mib
+initialization
+
+=item $SNMP::debugging
+
+default '0', controls debugging output level
+within SNMP module and libsnmp
+
+=over
+
+=item 1
+
+enables 'SNMP::verbose' (see above)
+
+=item 2
+
+level 1 plus snmp_set_do_debugging(1)
+
+=item 3
+
+level 2 plus snmp_set_dump_packet(1)
+
+=back
+
+=item $SNMP::dump_packet
+
+default '0', set [non-]zero to independently set
+snmp_set_dump_packet()
+
+=item SNMP::register_debug_tokens()
+
+Allows to register one or more debug tokens, just like the -D option of snmpd.
+Each debug token enables a group of debug statements. An example:
+SNMP::register_debug_tokens("tdomain,netsnmp_unix");
+
+=back
+
+=head1 %SNMP::MIB
+
+a tied hash to access parsed MIB information. After
+the MIB has been loaded this hash allows access to
+to the parsed in MIB meta-data(the structure of the
+MIB (i.e., schema)). The hash returns blessed
+references to SNMP::MIB::NODE objects which represent
+a single MIB attribute. The nodes can be fetched with
+multiple 'key' formats - the leaf name (e.g.,sysDescr)
+or fully/partially qualified name (e.g.,
+system.sysDescr) or fully qualified numeric OID. The
+returned node object supports the following fields:
+
+=over
+
+=item objectID
+
+dotted decimal fully qualified OID
+
+=item label
+
+leaf textual identifier (e.g., 'sysDescr')
+
+=item subID
+
+leaf numeric OID component of objectID (e.g., '1')
+
+=item moduleID
+
+textual identifier for module (e.g., 'RFC1213-MIB')
+
+=item parent
+
+parent node
+
+=item children
+
+array reference of children nodes
+
+=item nextNode
+
+next lexico node B<(BUG!does not return in lexico order)>
+
+=item type
+
+returns application type (see getType for values)
+
+=item access
+
+returns ACCESS (ReadOnly, ReadWrite, WriteOnly,
+NoAccess, Notify, Create)
+
+=item status
+
+returns STATUS (Mandatory, Optional, Obsolete,
+Deprecated)
+
+=item syntax
+
+returns 'textualConvention' if defined else 'type'
+
+=item textualConvention
+
+returns TEXTUAL-CONVENTION
+
+=item TCDescription
+
+returns the TEXTUAL-CONVENTION's DESCRIPTION field.
+
+=item units
+
+returns UNITS
+
+=item hint
+
+returns HINT
+
+=item enums
+
+returns hash ref {tag => num, ...}
+
+=item ranges
+
+returns array ref of hash ref [{low => num, high => num}, ...]
+
+=item description
+
+returns DESCRIPTION ($SNMP::save_descriptions must
+be set prior to MIB initialization/parsing)
+
+=item reference
+
+returns the REFERENCE clause
+
+=item indexes
+
+returns the objects in the INDEX clause
+
+=item implied
+
+returns true if the last object in the INDEX is IMPLIED
+
+=back
+
+=head1 MIB Functions
+
+=over
+
+=item &SNMP::setMib(<file>)
+
+allows dynamic parsing of the mib and explicit
+specification of mib file independent of environment
+variables. called with no args acts like initMib,
+loading MIBs indicated by environment variables (see
+Net-SNMP mib_api docs). passing non-zero second arg
+forces previous mib to be freed and replaced
+B<(Note: second arg not working since freeing previous
+Mib is more involved than before)>.
+
+=item &SNMP::initMib()
+
+calls library init_mib function if Mib not already
+loaded - does nothing if Mib already loaded. will
+parse directories and load modules according to
+environment variables described in Net-SNMP documentations.
+(see man mib_api, MIBDIRS, MIBS, MIBFILE(S), etc.)
+
+=item &SNMP::addMibDirs(<dir>,...)
+
+calls library add_mibdir for each directory
+supplied. will cause directory(s) to be added to
+internal list and made available for searching in
+subsequent loadModules calls
+
+=item &SNMP::addMibFiles(<file>,...)
+
+calls library read_mib function. The file(s)
+supplied will be read and all Mib module definitions
+contained therein will be added to internal mib tree
+structure
+
+=item &SNMP::loadModules(<mod>,...)
+
+calls library read_module function. The
+module(s) supplied will be searched for in the
+current mibdirs and and added to internal mib tree
+structure. Passing special <mod>, 'ALL', will cause
+all known modules to be loaded.
+
+=item &SNMP::unloadModules(<mod>,...)
+
+B<*Not Implemented*>
+
+=item &SNMP::translateObj(<var>[,arg,[arg]])
+
+will convert a text obj tag to an OID and vice-versa.
+Any iid suffix is retained numerically. Default
+behaviour when converting a numeric OID to text
+form is to return leaf identifier only
+(e.g.,'sysDescr') but when $SNMP::use_long_names
+is non-zero or a non-zero second arg is supplied it
+will return a longer textual identifier. An optional
+third argument of non-zero will cause the module name
+to be prepended to the text name (e.g.
+'SNMPv2-MIB::sysDescr'). When converting a text obj,
+the $SNMP::best_guess option is used. If no Mib is
+loaded when called and $SNMP::auto_init_mib is enabled
+then the Mib will be loaded. Will return 'undef' upon
+failure.
+
+=item &SNMP::getType(<var>)
+
+return SNMP data type for given textual identifier
+OBJECTID, OCTETSTR, INTEGER, NETADDR, IPADDR, COUNTER
+GAUGE, TIMETICKS, OPAQUE, or undef
+
+=item &SNMP::mapEnum(<var>)
+
+converts integer value to enumertion tag defined
+in Mib or converts tag to integer depending on
+input. the function will return the corresponding
+integer value *or* tag for a given MIB attribute
+and value. The function will sense which direction
+to perform the conversion. Various arg formats are
+supported
+
+=over
+
+=item $val = SNMP::mapEnum($varbind);
+
+where $varbind is SNMP::Varbind or equiv.
+note: $varbind will be updated
+
+=item $val = SNMP::mapEnum('ipForwarding', 'forwarding');
+
+=item $val = SNMP::mapEnum('ipForwarding', 1);
+
+=back
+
+=back
+
+=head1 Exported SNMP utility functions
+
+Note: utility functions do not support async operation yet.
+
+=over
+
+=item &snmp_get()
+
+takes args of SNMP::Session::new followed by those of
+SNMP::Session::get
+
+=item &snmp_getnext()
+
+takes args of SNMP::Session::new followed by those of
+SNMP::Session::getnext
+
+=item &snmp_set()
+
+takes args of SNMP::Session::new followed by those of
+SNMP::Session::set
+
+=item &snmp_trap()
+
+takes args of SNMP::TrapSession::new followed by those of
+SNMP::TrapSession::trap
+
+=back
+
+=head1 Trouble Shooting
+
+If problems occur there are number areas to look at to narrow down the
+possibilities.
+
+The first step should be to test the Net-SNMP installation
+independently from the Perl5 SNMP interface.
+
+Try running the apps from the Net-SNMP distribution.
+
+Make sure your agent (snmpd) is running and properly configured with
+read-write access for the community you are using.
+
+Ensure that your MIBs are installed and enviroment variables are set
+appropriately (see man mib_api)
+
+Be sure to remove old net-snmp installations and ensure headers and
+libraries from old CMU installations are not being used by mistake.
+
+If the problem occurs during compilation/linking check that the snmp
+library being linked is actually the Net-SNMP library (there have been
+name conflicts with existing snmp libs).
+
+Also check that the header files are correct and up to date.
+
+Sometimes compiling the Net-SNMP library with
+'position-independent-code' enabled is required (HPUX specifically).
+
+If you cannot resolve the problem you can post to
+comp.lang.perl.modules or
+net-snmp-users@net-snmp-users@lists.sourceforge.net
+
+please give sufficient information to analyze the problem (OS type,
+versions for OS/Perl/Net-SNMP/compiler, complete error output, etc.)
+
+=head1 Acknowledgements
+
+Many thanks to all those who supplied patches, suggestions and
+feedback.
+
+ Joe Marzot (the original author)
+ Wes Hardaker and the net-snmp-coders
+ Dave Perkins
+ Marcel Wiget
+ David Blackburn
+ John Stofell
+ Gary Hayward
+ Claire Harrison
+ Achim Bohnet
+ Doug Kingston
+ Jacques Vidrine
+ Carl Jacobsen
+ Wayne Marquette
+ Scott Schumate
+ Michael Slifcak
+ Srivathsan Srinivasagopalan
+ Bill Fenner
+ Jef Peeraer
+ Daniel Hagerty
+ Karl "Rat" Schilke and Electric Lightwave, Inc.
+ Perl5 Porters
+ Alex Burger
+
+Apologies to any/all who's patch/feature/request was not mentioned or
+included - most likely it was lost when paying work intruded on my
+fun. Please try again if you do not see a desired feature. This may
+actually turn out to be a decent package with such excellent help and
+the fact that I have more time to work on it than in the past.
+
+=head1 AUTHOR
+
+bugs, comments, questions to net-snmp-users@lists.sourceforge.net
+
+=head1 Copyright
+
+ Copyright (c) 1995-2000 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.
+
+ Copyright (c) 2001-2002 Networks Associates Technology, Inc. All
+ Rights Reserved. This program is free software; you can
+ redistribute it and/or modify it under the same terms as Perl
+ itself.
+
+=cut
diff --git a/perl/SNMP/SNMP.xs b/perl/SNMP/SNMP.xs
new file mode 100644
index 0000000..b4f35c8
--- /dev/null
+++ b/perl/SNMP/SNMP.xs
@@ -0,0 +1,5473 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*-
+ SNMP.xs -- Perl 5 interface to the Net-SNMP toolkit
+
+ written by G. S. Marzot (marz@users.sourceforge.net)
+
+ Copyright (c) 1995-2006 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
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#ifndef MSVC_PERL
+ #include <signal.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#ifdef I_SYS_TIME
+#include <sys/time.h>
+#endif
+#include <netdb.h>
+#include <stdlib.h>
+#ifndef MSVC_PERL
+ #include <unistd.h>
+#endif
+
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
+#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
+
+#include "perlsnmp.h"
+
+#define SUCCESS 1
+#define FAILURE 0
+
+#define ZERO_BUT_TRUE "0 but true"
+
+#define SNMP_API_TRADITIONAL 0
+#define SNMP_API_SINGLE 1
+
+#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 32
+#define STR_BUF_SIZE (MAX_TYPE_NAME_LEN * MAX_OID_LEN)
+#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;
+
+/* Internal flag to determine which API we're using */
+static int api_mode = SNMP_API_TRADITIONAL;
+
+/* 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 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 *, size_t *));
+static int __get_type_str _((int, char *));
+static int __get_label_iid _((char *, char **, char **, int));
+static int __oid_cmp _((oid *, size_t, oid *, size_t));
+static int __tp_sprint_num_objid _((char*,SnmpMibNode *));
+static SnmpMibNode * __get_next_mib_node _((SnmpMibNode *));
+static struct tree * __tag2oid _((char *, char *, oid *, size_t *, int *, int));
+static int __concat_oid_str _((oid *, size_t *, char *));
+static int __add_var_val_str _((netsnmp_pdu *, oid *, size_t, 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 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));
+
+#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. */
+ size_t req_len; /* Length of requested OID. */
+ size_t 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));
+
+/* Prototype for error handler */
+void snmp_return_err( struct snmp_session *ss, SV *err_str, SV *err_num, SV *err_ind );
+
+/* 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_printf otherargs; \
+ } \
+ } while (/*CONSTCOND*/0)
+
+char _debugx[1024]; /* Space to sprintf() into - used by sprint_objid(). */
+
+/* wrapper around snprint_objid to snprint_objid to return the pointer
+ instead of length */
+
+static char *
+__snprint_oid(const oid *objid, size_t objidlen) {
+ snprint_objid(_debugx, sizeof(_debugx), objid, objidlen);
+ return _debugx;
+}
+
+#define DBDCL(x) x
+#else /* DEBUGGING */
+#define DBDCL(x)
+#define DBOUT
+/* Do nothing but in such a way that the compiler sees "otherargs". */
+#define DBPRT(severity, otherargs) \
+ do { if (0) printf otherargs; } while(0)
+
+static char *
+__snprint_oid(const oid *objid, size_t objidlen)
+{
+ return "(debugging is disabled)";
+}
+
+#endif /* DEBUGGING */
+
+void
+__libraries_init(char *appname)
+ {
+ static int have_inited = 0;
+
+ if (have_inited)
+ return;
+ have_inited = 1;
+
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_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);
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_SUFFIX);
+ 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 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) {
+ strlcpy(buf, ep->label, buf_len);
+ len = strlen(buf);
+ break;
+ }
+ }
+ }
+ if (!len) {
+ snprintf(buf, buf_len, "%ld", *var->val.integer);
+ buf[buf_len-1] = '\0';
+ len = strlen(buf);
+ }
+ break;
+
+ case ASN_GAUGE:
+ case ASN_COUNTER:
+ case ASN_TIMETICKS:
+ case ASN_UINTEGER:
+ snprintf(buf, buf_len, "%lu", (unsigned long) *var->val.integer);
+ buf[buf_len-1] = '\0';
+ len = strlen(buf);
+ break;
+
+ case ASN_OCTET_STR:
+ case ASN_OPAQUE:
+ len = var->val_len;
+ if ( len > buf_len )
+ len = buf_len;
+ memcpy(buf, (char*)var->val.string, len);
+ break;
+
+ case ASN_IPADDRESS:
+ ip = (u_char*)var->val.string;
+ snprintf(buf, buf_len, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+ buf[buf_len-1] = '\0';
+ 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:
+ snprintf(buf, buf_len, "%s", "ENDOFMIBVIEW");
+ break;
+ case SNMP_NOSUCHOBJECT:
+ snprintf(buf, buf_len, "%s", "NOSUCHOBJECT");
+ break;
+ case SNMP_NOSUCHINSTANCE:
+ snprintf(buf, buf_len, "%s", "NOSUCHINSTANCE");
+ break;
+
+ case ASN_COUNTER64:
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case ASN_OPAQUE_COUNTER64:
+ case ASN_OPAQUE_U64:
+#endif
+ printU64(buf,(struct counter64 *)var->val.counter64);
+ len = strlen(buf);
+ break;
+
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case ASN_OPAQUE_I64:
+ printI64(buf,(struct counter64 *)var->val.counter64);
+ len = strlen(buf);
+ break;
+#endif
+
+ case ASN_BIT_STR:
+ snprint_bitstring(buf, buf_len, var, NULL, NULL, NULL);
+ len = strlen(buf);
+ break;
+#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
+ case ASN_OPAQUE_FLOAT:
+ if (var->val.floatVal)
+ snprintf(buf, buf_len, "%f", *var->val.floatVal);
+ break;
+
+ case ASN_OPAQUE_DOUBLE:
+ if (var->val.doubleVal)
+ snprintf(buf, buf_len, "%f", *var->val.doubleVal);
+ break;
+#endif
+
+ 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,".%" NETSNMP_PRIo "u",*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;
+size_t *len;
+{
+ char *cp;
+ *len = 0;
+ if (*buf == '.') buf++;
+ cp = buf;
+ while (*buf) {
+ if (*buf++ == '.') {
+ sscanf(cp, "%" NETSNMP_PRIo "u", objid++);
+ /* *objid++ = atoi(cp); */
+ (*len)++;
+ cp = buf;
+ } else {
+ if (isalpha((int)*buf)) {
+ return FAILURE;
+ }
+ }
+ }
+ sscanf(cp, "%" NETSNMP_PRIo "u", 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((unsigned char)*lcp)) found_label = 1;
+ lcp--;
+ }
+
+ if (!found_label
+ || ((icp + 1 >= name + len || !isdigit((unsigned char)*(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;
+size_t oida_arr_len;
+oid *oidb_arr;
+size_t 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);
+}
+
+/* Convert a tag (string) to an OID array */
+/* Tag can be either a symbolic name, or an OID string */
+static struct tree *
+__tag2oid(tag, iid, oid_arr, oid_arr_len, type, best_guess)
+char * tag;
+char * iid;
+oid * oid_arr;
+size_t * oid_arr_len;
+int * type;
+int best_guess;
+{
+ struct tree *tp = NULL;
+ struct tree *rtp = NULL;
+ oid newname[MAX_OID_LEN], *op;
+ size_t newname_len = 0;
+
+ if (type) *type = TYPE_UNKNOWN;
+ if (oid_arr_len) *oid_arr_len = 0;
+ if (!tag) goto done;
+
+ /*********************************************************/
+ /* best_guess = 0 - same as no switches (read_objid) */
+ /* if multiple parts, or uses find_node */
+ /* if a single leaf */
+ /* best_guess = 1 - same as -Ib (get_wild_node) */
+ /* best_guess = 2 - same as -IR (get_node) */
+ /*********************************************************/
+
+ /* numeric scalar (1,2) */
+ /* single symbolic (1,2) */
+ /* single regex (1) */
+ /* partial full symbolic (2) */
+ /* full symbolic (2) */
+ /* module::single symbolic (2) */
+ /* module::partial full symbolic (2) */
+ if (best_guess == 1 || best_guess == 2) {
+ if (!__scan_num_objid(tag, newname, &newname_len)) { /* make sure it's not a numeric tag */
+ newname_len = MAX_OID_LEN;
+ if (best_guess == 2) { /* Random search -IR */
+ if (get_node(tag, newname, &newname_len)) {
+ rtp = tp = get_tree(newname, newname_len, get_tree_head());
+ }
+ }
+ else if (best_guess == 1) { /* Regex search -Ib */
+ clear_tree_flags(get_tree_head());
+ if (get_wild_node(tag, newname, &newname_len)) {
+ rtp = tp = get_tree(newname, newname_len, get_tree_head());
+ }
+ }
+ }
+ else {
+ rtp = tp = get_tree(newname, newname_len, get_tree_head());
+ }
+ 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;
+ }
+
+ /* if best_guess is off and multi part tag or module::tag */
+ /* numeric scalar */
+ /* module::single symbolic */
+ /* module::partial full symbolic */
+ /* FULL symbolic OID */
+ else if (strchr(tag,'.') || strchr(tag,':')) {
+ if (!__scan_num_objid(tag, newname, &newname_len)) { /* make sure it's not a numeric tag */
+ newname_len = MAX_OID_LEN;
+ if (read_objid(tag, newname, &newname_len)) { /* long name */
+ rtp = tp = get_tree(newname, newname_len, get_tree_head());
+ }
+ }
+ else {
+ rtp = tp = get_tree(newname, newname_len, get_tree_head());
+ }
+ 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 best_guess is off and it is a single leaf */
+ /* single symbolic */
+ else {
+ rtp = tp = find_node(tag, get_tree_head());
+ 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 && oid_arr_len) __concat_oid_str(oid_arr, oid_arr_len, iid);
+ return(rtp);
+}
+
+/* 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;
+size_t *doid_arr_len;
+char * soid_str;
+{
+ char *soid_buf;
+ char *cp;
+ char *st;
+
+ if (!soid_str || !*soid_str) return SUCCESS;/* successfully added nothing */
+ if (*soid_str == '.') soid_str++;
+ soid_buf = strdup(soid_str);
+ if (!soid_buf)
+ return FAILURE;
+ cp = strtok_r(soid_buf,".",&st);
+ while (cp) {
+ sscanf(cp, "%" NETSNMP_PRIo "u", &(doid_arr[(*doid_arr_len)++]));
+ /* doid_arr[(*doid_arr_len)++] = atoi(cp); */
+ cp = strtok_r(NULL,".",&st);
+ }
+ free(soid_buf);
+ 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;
+ size_t name_length;
+ char * val;
+ int len;
+ int type;
+{
+ netsnmp_variable_list *vars;
+ oid oidbuf[MAX_OID_LEN];
+ int ret = SUCCESS;
+
+ if (pdu->variables == NULL){
+ pdu->variables = vars
+ = netsnmp_calloc(1, sizeof(netsnmp_variable_list));
+ } else {
+ for(vars = pdu->variables;
+ vars->next_variable;
+ vars = vars->next_variable)
+ /*EXIT*/;
+ vars->next_variable = netsnmp_calloc(1, sizeof(netsnmp_variable_list));
+ vars = vars->next_variable;
+ }
+
+ vars->next_variable = NULL;
+ vars->name = netsnmp_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 = netsnmp_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 = netsnmp_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 = netsnmp_malloc(len);
+ vars->val_len = len;
+ if (val && len)
+ memcpy((char *)vars->val.string, val, len);
+ else {
+ ret = FAILURE;
+ vars->val.string = (u_char *) netsnmp_strdup("");
+ vars->val_len = 0;
+ }
+ break;
+
+ case TYPE_IPADDR:
+ vars->type = ASN_IPADDRESS;
+ vars->val.integer = netsnmp_malloc(sizeof(in_addr_t));
+ if (val)
+ *((in_addr_t *)vars->val.integer) = inet_addr(val);
+ else {
+ ret = FAILURE;
+ *(vars->val.integer) = 0;
+ }
+ vars->val_len = sizeof(in_addr_t);
+ 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 = netsnmp_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:
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_synch_response(ss, pdu, response);
+ } else {
+ 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:
+ snmp_return_err(ss, err_str_sv, err_num_sv, err_ind_sv);
+ break;
+
+ default:
+ snmp_return_err(ss, err_str_sv, err_num_sv, err_ind_sv);
+ sv_catpv(err_str_sv, "send_sync_pdu: unknown status");
+ break;
+ }
+
+ return(status);
+}
+
+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];
+ 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, old_format;
+ 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);
+
+ ENTER;
+ SAVETMPS;
+
+ if (cb_data != ss->callback_magic)
+ 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;
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_send(ss, reply_pdu);
+ } else {
+ snmp_send(ss, reply_pdu);
+ }
+ } else {
+ warn("Couldn't clone PDU for inform response");
+ }
+ /* FALLTHRU */
+ case SNMP_MSG_TRAP:
+ 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)));
+ netsnmp_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));
+ if (pdu->command == SNMP_MSG_TRAP) {
+ /* SNMP v1 only trap fields */
+ snprint_objid(str_buf, sizeof(str_buf), pdu->enterprise, pdu->enterprise_length);
+ av_push(traplist, newSVpv(str_buf,strlen(str_buf)));
+ cp = inet_ntoa(*((struct in_addr *) pdu->agent_addr));
+ av_push(traplist, newSVpv(cp,strlen(cp)));
+ av_push(traplist, newSViv(pdu->trap_type));
+ av_push(traplist, newSViv(pdu->specific_type));
+ /* perl didn't have perlSVuv until 5.6.0 */
+ tmp_sv=newSViv(0);
+ sv_setuv(tmp_sv, pdu->time);
+ av_push(traplist, tmp_sv);
+ }
+ /* 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);
+ old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
+ 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);
+ }
+ /* Setting UseNumeric forces UseLongNames on so check for UseNumeric
+ after UseLongNames (above) to make sure the final outcome of
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */
+ 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_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_NUMERIC);
+ }
+
+ sv_bless(varlist_ref, gv_stashpv("SNMP::VarList",0));
+ for(vars = (pdu?pdu->variables:NULL); vars; vars = vars->next_variable) {
+ int local_getlabel_flag = getlabel_flag;
+ 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((u_char**)&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 {
+ local_getlabel_flag |= NON_LEAF_NAME;
+ type = __translate_asn_type(vars->type);
+ }
+ __get_label_iid(str_buf,&label,&iid,local_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);
+ } /* 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);
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, old_format);
+
+ } /* case SNMP_MSG_RESPONSE */
+ break;
+ default:;
+ } /* switch pdu->command */
+ break;
+
+ case NETSNMP_CALLBACK_OP_TIMED_OUT:
+ varlist_ref = &sv_undef;
+ sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_TIMEOUT));
+ sv_setiv(*err_num_svp, SNMPERR_TIMEOUT);
+ break;
+ default:;
+ } /* switch op */
+ if (cb_data != ss->callback_magic)
+ 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;
+ if (cb_data != ss->callback_magic)
+ 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;
+{
+ 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,(DBOUT "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,(DBOUT "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_oid(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;
+ 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,(DBOUT "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,
+ (DBOUT "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,(DBOUT "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,(DBOUT "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,(DBOUT "\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.
+ */
+ _bulkwalk_finish(context, 0 /* NOT OKAY */);
+ return 1;
+ }
+
+ default:
+ {
+ DBPRT(1,(DBOUT "unexpected callback op %d\n", op));
+ sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_GENERR));
+ sv_setiv(*err_num_svp, SNMPERR_GENERR);
+ _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,(DBOUT "bulkwalk not complete -- send next pdu from callback\n"));
+
+ if (_bulkwalk_send_pdu(context) != NULL)
+ return 1;
+
+ DBPRT(1,(DBOUT "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. */
+ _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_oid(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)) {
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ reqid = snmp_sess_async_send(ss, pdu, _bulkwalk_async_cb, (void *)context);
+ } else {
+ reqid = snmp_async_send(ss, pdu, _bulkwalk_async_cb, (void *)context);
+ }
+
+ DBPRT(2,(DBOUT "bulkwalk_send_pdu(): snmp_async_send => 0x%08X\n", reqid));
+
+ if (reqid == 0) {
+ snmp_return_err(ss, *err_num_svp, *err_ind_svp, *err_str_svp);
+ 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 *)(intptr_t)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,(DBOUT "__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];
+ 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);
+ int check = SvIV(*hv_fetch((HV*)SvRV(context->sess_ref), "NonIncreasing",13,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,(DBOUT "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,(DBOUT "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.
+ */
+ /* In previous version we started from 1st repeater any time when
+ ** pix == 0. But if 1st repeater is ignored we can get wrong results,
+ ** because it was not included in 2nd and later request. So we set
+ ** expect to repbase-1 and then search for 1st non-ignored repeater.
+ ** repbase-1 is nessessary because we're starting search in loop below
+ ** from ++expect and it will be exactly repbase on 1st search pass.
+ */
+ if (pix == 0)
+ expect = context->repbase - 1;
+
+ /* 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;
+ }
+ }
+
+ DBPRT(2, (DBOUT "Var %03d request %s\n", pix,
+ __snprint_oid(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,(DBOUT "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_oid(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) {
+ if (__oid_cmp(vars->name, vars->name_length,
+ expect->last_oid, expect->last_len) <= 0)
+ {
+ if (check)
+ {
+ DBPRT(2, (DBOUT "Error: OID not increasing: %s\n",
+ __snprint_oid(vars->name,vars->name_length)));
+ sv_setpv(*err_str_svp, (char*)snmp_api_errstring(SNMPERR_OID_NONINCREASING));
+ sv_setiv(*err_num_svp, SNMPERR_OID_NONINCREASING);
+ sv_setiv(*err_ind_svp, pix);
+ goto err;
+ }
+
+ DBPRT(2, (DBOUT "Ignoring repeat oid: %s\n",
+ __snprint_oid(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().
+ */
+ if (context->oid_saved < context->non_reps) {
+ DBPRT(2, (DBOUT " expected var %s (nonrepeater %d/%d)\n",
+ __snprint_oid(expect->req_oid, expect->req_len),
+ pix, context->non_reps));
+ DBPRT(2, (DBOUT " received var %s\n",
+ __snprint_oid(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_oid(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,(DBOUT " 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,(DBOUT " 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((u_char**)&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,(DBOUT " 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(str_buf, len));
+
+ str_buf[len] = '\0';
+ DBPRT(3,(DBOUT "'%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:
+ 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)
+{
+ dSP;
+ 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);
+
+ async = SvTRUE(context->perl_cb);
+
+ /* XXX
+ _bulkwalk_finish() was originally intended to be called from XS code, and
+ would extend the caller's stack with result. Later it was changed into
+ an asynchronous version that calls perl code instead. These two branches
+ differ significantly in how they treat perl stack. Due to these differences,
+ often implicit (f.ex. dMARK calls POPMARK ), it would be a good idea
+ to write two different procedures, _bulkwalk_finish_sync and _bulkwalk_finish_async
+ for cleaner separation. */
+
+ if (async) PUSHMARK(sp);
+
+ {
+
+#ifdef dITEMS
+ dMARK;
+ dITEMS;
+#else
+ /* unfortunately this may pop a mark, which is not what we want */
+ /* older perl versions don't declare dITEMS though and the
+ following declars it but also uses dAXMARK instead of dMARK
+ which is the bad popping version */
+ dMARK;
+
+ /* err... This is essentially what the newer dITEMS does */
+ I32 items = sp - mark;
+#endif
+
+
+ /* 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_oid(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,(DBOUT " [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;
+ } else {
+ for (i = 0; i < context->nreq_oids; i++) {
+ sv_2mortal((SV *) (context->req_oids[i].vars));
+ }
+ }
+ }
+
+ /* 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.
+ */
+ if(!async)
+ SP -= items;
+
+ 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,(DBOUT "Free() context->req_oids\n"));
+ Safefree(context->req_oids);
+ DBPRT(2,(DBOUT "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(const char *s)
+{
+ warn("%s not implemented on this architecture", s);
+ return -1;
+}
+
+#define TEST_CONSTANT(value, name, C) \
+ if (strEQ(name, #C)) { \
+ *value = C; \
+ return 0; \
+ }
+#define TEST_CONSTANT2(value, name, C, V) \
+ if (strEQ(name, #C)) { \
+ *value = V; \
+ return 0; \
+ }
+
+static int constant(double *value, const char * const name, const int arg)
+{
+ switch (*name) {
+ case 'N':
+ TEST_CONSTANT(value, name, NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE);
+ TEST_CONSTANT(value, name, NETSNMP_CALLBACK_OP_TIMED_OUT);
+ break;
+ case 'S':
+ TEST_CONSTANT(value, name, SNMPERR_BAD_ADDRESS);
+ TEST_CONSTANT(value, name, SNMPERR_BAD_LOCPORT);
+ TEST_CONSTANT(value, name, SNMPERR_BAD_SESSION);
+ TEST_CONSTANT(value, name, SNMPERR_GENERR);
+ TEST_CONSTANT(value, name, SNMPERR_TOO_LONG);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_ADDRESS);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_COMMUNITY_LEN);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_ENTERPRISE_LENGTH);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_ERRINDEX);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_ERRSTAT);
+ TEST_CONSTANT2(value, name, SNMP_DEFAULT_PEERNAME, 0);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_REMPORT);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_REQID);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_RETRIES);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_TIME);
+ TEST_CONSTANT(value, name, SNMP_DEFAULT_TIMEOUT);
+ TEST_CONSTANT2(value, name, SNMP_DEFAULT_VERSION,
+ NETSNMP_DEFAULT_SNMP_VERSION);
+ TEST_CONSTANT(value, name, SNMP_API_SINGLE);
+ TEST_CONSTANT(value, name, SNMP_API_TRADITIONAL);
+ break;
+ case 'X':
+ goto not_there;
+ break;
+ default:
+ break;
+ }
+ return EINVAL;
+
+not_there:
+ not_here(name);
+ return ENOENT;
+}
+
+/*
+ Since s_snmp_errno can't be trusted with Single Session, this calls either
+ snmp_error or snmp_sess_error to populate ErrorStr,ErrorNum, and ErrorInd
+ in SNMP::Session objects
+*/
+void snmp_return_err( struct snmp_session *ss, SV *err_str, SV *err_num, SV *err_ind )
+{
+ int err;
+ int liberr;
+ char *errstr;
+ if(ss == NULL)
+ return;
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_error(ss, &err, &liberr, &errstr);
+ } else {
+ snmp_error(ss, &err, &liberr, &errstr);
+ }
+ sv_catpv(err_str, errstr);
+ sv_setiv(err_num, liberr);
+ sv_setiv(err_ind, err);
+ netsnmp_free(errstr);
+}
+
+
+/*
+ int snmp_api_mode( int mode )
+ Returns or sets static int api_mode for reference by functions to determine
+ whether to use Traditional (non-threadsafe) or Single-Session (threadsafe)
+ SNMP API calls.
+
+ Call with (int)NULL to return the current mode, or with SNMP_API_TRADITIONAL
+ or SNMP_API_SINGLE to set the current mode. (defined above)
+
+ pm side call defaults to (int)NULL
+*/
+int snmp_api_mode( int mode )
+{
+ if (mode == 0)
+ return api_mode;
+ api_mode = mode;
+ return api_mode;
+}
+
+MODULE = SNMP PACKAGE = SNMP PREFIX = snmp
+
+void
+constant(name,arg)
+ char * name
+ int arg
+ INIT:
+ int status;
+ double value;
+ PPCODE:
+ value = 0;
+ status = constant(&value, name, arg);
+ XPUSHs(sv_2mortal(newSVuv(status)));
+ XPUSHs(sv_2mortal(newSVnv(value)));
+
+long
+snmp_sys_uptime()
+ CODE:
+ RETVAL = get_uptime();
+ OUTPUT:
+ RETVAL
+
+void
+init_snmp(appname)
+ char *appname
+ CODE:
+ __libraries_init(appname);
+
+#----------------------------------------------------------------------
+# Perl call defaults to (int)NULL when given no args, so it will return
+# the current api_mode values
+#----------------------------------------------------------------------
+int
+snmp_api_mode(mode=0)
+ int mode
+
+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");
+
+ session.version = -1;
+#ifndef NETSNMP_DISABLE_SNMPV1
+ if (!strcmp(version, "1")) {
+ session.version = SNMP_VERSION_1;
+ }
+#endif
+#ifndef NETSNMP_DISABLE_SNMPV2C
+ if ((!strcmp(version, "2")) || (!strcmp(version, "2c"))) {
+ session.version = SNMP_VERSION_2c;
+ }
+#endif
+ if (!strcmp(version, "3")) {
+ session.version = SNMP_VERSION_3;
+ }
+ if (session.version == -1) {
+ 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;
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ ss = snmp_sess_open(&session);
+ } else {
+ 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, auth_master_key, auth_master_key_len, priv_master_key, priv_master_key_len, auth_localized_key, auth_localized_key_len, priv_localized_key, priv_localized_key_len)
+ 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
+ char * auth_master_key
+ size_t auth_master_key_len
+ char * priv_master_key
+ size_t priv_master_key_len
+ char * auth_localized_key
+ size_t auth_localized_key_len
+ char * priv_localized_key
+ size_t priv_localized_key_len
+ CODE:
+ {
+ 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 = 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.securityEngineIDLen =
+ hex_to_binary2((u_char*)sec_eng_id, strlen(sec_eng_id),
+ (char **) &session.securityEngineID);
+ session.contextEngineIDLen =
+ hex_to_binary2((u_char*)context_eng_id, strlen(context_eng_id),
+ (char **) &session.contextEngineID);
+ session.engineBoots = eng_boots;
+ session.engineTime = eng_time;
+#ifndef NETSNMP_DISABLE_MD5
+ if (!strcmp(auth_proto, "MD5")) {
+ session.securityAuthProto =
+ snmp_duplicate_objid(usmHMACMD5AuthProtocol,
+ USM_AUTH_PROTO_MD5_LEN);
+ session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
+ } else
+#endif
+ 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 (!strcmp(auth_proto, "DEFAULT")) {
+ const oid *theoid =
+ get_default_authtype(&session.securityAuthProtoLen);
+ session.securityAuthProto =
+ snmp_duplicate_objid(theoid, session.securityAuthProtoLen);
+ } 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) {
+ if (auth_localized_key_len) {
+ memdup(&session.securityAuthLocalKey,
+ (u_char*)auth_localized_key,
+ auth_localized_key_len);
+ session.securityAuthLocalKeyLen = auth_localized_key_len;
+ } else if (auth_master_key_len) {
+ session.securityAuthKeyLen =
+ SNMP_MIN(auth_master_key_len,
+ sizeof(session.securityAuthKey));
+ memcpy(session.securityAuthKey, auth_master_key,
+ session.securityAuthKeyLen);
+ } else {
+ if (strlen(auth_pass) > 0) {
+ 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;
+ }
+ }
+ }
+ }
+#ifndef NETSNMP_DISABLE_DES
+ if (!strcmp(priv_proto, "DES")) {
+ session.securityPrivProto =
+ snmp_duplicate_objid(usmDESPrivProtocol,
+ USM_PRIV_PROTO_DES_LEN);
+ session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
+ } else
+#endif
+ if (!strncmp(priv_proto, "AES", 3)) {
+ session.securityPrivProto =
+ snmp_duplicate_objid(usmAESPrivProtocol,
+ USM_PRIV_PROTO_AES_LEN);
+ session.securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
+ } else if (!strcmp(priv_proto, "DEFAULT")) {
+ const oid *theoid =
+ get_default_privtype(&session.securityPrivProtoLen);
+ session.securityPrivProto =
+ snmp_duplicate_objid(theoid, session.securityPrivProtoLen);
+ } 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) {
+ if (priv_localized_key_len) {
+ memdup(&session.securityPrivLocalKey,
+ (u_char*)priv_localized_key,
+ priv_localized_key_len);
+ session.securityPrivLocalKeyLen = priv_localized_key_len;
+ } else if (priv_master_key_len) {
+ session.securityPrivKeyLen =
+ SNMP_MIN(auth_master_key_len,
+ sizeof(session.securityPrivKey));
+ memcpy(session.securityPrivKey, priv_master_key,
+ session.securityPrivKeyLen);
+ } else {
+ 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;
+ }
+ }
+ }
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ ss = snmp_sess_open(&session);
+ } else {
+ ss = snmp_open(&session);
+ }
+
+ if (ss == NULL) {
+ if (verbose) warn("error:snmp_new_v3_session:Couldn't open SNMP session");
+ }
+ end:
+ RETVAL = ss;
+ netsnmp_free(session.securityPrivLocalKey);
+ netsnmp_free(session.securityPrivProto);
+ netsnmp_free(session.securityAuthLocalKey);
+ netsnmp_free(session.securityAuthProto);
+ netsnmp_free(session.contextEngineID);
+ netsnmp_free(session.securityEngineID);
+ }
+ OUTPUT:
+ RETVAL
+
+SnmpSession *
+snmp_new_tunneled_session(version, peer, retries, timeout, sec_name, sec_level, context_eng_id, context, our_identity, their_identity, their_hostname, trust_cert)
+ int version
+ char * peer
+ int retries
+ int timeout
+ char * sec_name
+ int sec_level
+ char * context_eng_id
+ char * context
+ char * our_identity
+ char * their_identity
+ char * their_hostname
+ char * trust_cert
+ CODE:
+ {
+ SnmpSession session = {0};
+ SnmpSession *ss = NULL;
+ int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
+
+ __libraries_init("perl");
+
+ session.version = version;
+
+ session.peername = peer;
+ session.retries = retries; /* 5 */
+ session.timeout = timeout; /* 1000000L */
+ session.contextNameLen = strlen(context);
+ session.contextName = context;
+ session.securityNameLen = strlen(sec_name);
+ session.securityName = sec_name;
+ session.securityLevel = sec_level;
+ session.securityModel = NETSNMP_TSM_SECURITY_MODEL;
+ session.contextEngineIDLen =
+ hex_to_binary2((u_char*)context_eng_id, strlen(context_eng_id),
+ (char **) &session.contextEngineID);
+
+ /* create the transport configuration store */
+ if (!session.transport_configuration) {
+ netsnmp_container_init_list();
+ session.transport_configuration =
+ netsnmp_container_find("transport_configuration:fifo");
+ if (!session.transport_configuration) {
+ fprintf(stderr, "failed to initialize the transport configuration container\n");
+ RETVAL = NULL;
+ return;
+ }
+
+ session.transport_configuration->compare =
+ (netsnmp_container_compare*)
+ netsnmp_transport_config_compare;
+ }
+
+ if (our_identity && our_identity[0] != '\0')
+ CONTAINER_INSERT(session.transport_configuration,
+ netsnmp_transport_create_config("our_identity",
+ our_identity));
+
+ if (their_identity && their_identity[0] != '\0')
+ CONTAINER_INSERT(session.transport_configuration,
+ netsnmp_transport_create_config("their_identity",
+ their_identity));
+
+ if (their_hostname && their_hostname[0] != '\0')
+ CONTAINER_INSERT(session.transport_configuration,
+ netsnmp_transport_create_config("their_hostname",
+ their_hostname));
+
+ if (trust_cert && trust_cert[0] != '\0')
+ CONTAINER_INSERT(session.transport_configuration,
+ netsnmp_transport_create_config("trust_cert",
+ trust_cert));
+
+
+ ss = snmp_open(&session);
+
+ if (ss == NULL) {
+ if (verbose) warn("error:snmp_new_v3_session:Couldn't open SNMP session");
+ }
+
+ RETVAL = ss;
+ netsnmp_free(session.securityPrivLocalKey);
+ netsnmp_free(session.securityPrivProto);
+ netsnmp_free(session.securityAuthLocalKey);
+ netsnmp_free(session.securityAuthProto);
+ netsnmp_free(session.contextEngineID);
+ netsnmp_free(session.securityEngineID);
+ }
+ 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;
+
+ ss->version = -1;
+#ifndef NETSNMP_DISABLE_SNMPV1
+ if (!strcmp(version, "1")) {
+ ss->version = SNMP_VERSION_1;
+ }
+#endif
+#ifndef NETSNMP_DISABLE_SNMPV2C
+ if (!strcmp(version, "2") || !strcmp(version, "2c")) {
+ ss->version = SNMP_VERSION_2c;
+ }
+#endif
+ if (!strcmp(version, "3")) {
+ ss->version = SNMP_VERSION_3;
+ }
+ if (ss->version == -1) {
+ if (verbose)
+ warn("snmp_update_session: 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 *)netsnmp_strdup(community);
+ ss->peername = netsnmp_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));
+
+ DBPRT(999, (DBOUT "force=%d\n", force));
+
+ if (mib_dir && *mib_dir) {
+ result = add_mibdir(mib_dir);
+ }
+ if (result) {
+ if (verbose) warn("snmp_add_mib_dir: Added mib dir %s\n", mib_dir);
+ } else {
+ if (verbose) warn("snmp_add_mib_dir: Failed to add %s\n", mib_dir);
+ }
+ RETVAL = (I32)result;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+snmp_init_mib_internals()
+ CODE:
+ {
+ int notused = 1; notused++;
+ /* this function does nothing */
+ /* it is kept only for backwards compatibility */
+ }
+
+
+char *
+snmp_getenv(name)
+ char *name;
+CODE:
+ RETVAL = netsnmp_getenv(name);
+OUTPUT:
+ RETVAL
+
+int
+snmp_setenv(envname, envval, overwrite)
+ char *envname;
+ char *envval;
+ int overwrite;
+CODE:
+ RETVAL = netsnmp_setenv(envname, envval, overwrite);
+OUTPUT:
+ RETVAL
+
+int
+snmp_read_mib(mib_file, force=0)
+ char * mib_file
+ int force
+ CODE:
+ {
+ int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
+
+ DBPRT(999, (DBOUT "force=%d\n", force));
+
+ if ((mib_file == NULL) || (*mib_file == '\0')) {
+ if (get_tree_head() == NULL) {
+ if (verbose) warn("snmp_read_mib: initializing MIB\n");
+ netsnmp_init_mib();
+ if (get_tree_head()) {
+ if (verbose) warn("done\n");
+ } else {
+ if (verbose) warn("failed\n");
+ }
+ }
+ } else {
+ if (verbose) warn("snmp_read_mib: reading MIB: %s\n", mib_file);
+ if (strcmp("ALL",mib_file))
+ read_mib(mib_file);
+ else
+ read_all_mibs();
+ if (get_tree_head()) {
+ if (verbose) warn("done\n");
+ } else {
+ if (verbose) warn("failed\n");
+ }
+ }
+ RETVAL = (IV)get_tree_head();
+ }
+ 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 {
+ netsnmp_read_module(module);
+ }
+ if (get_tree_head()) {
+ if (verbose) warn("Read %s\n", module);
+ } else {
+ if (verbose) warn("Failed reading %s\n", module);
+ }
+ RETVAL = (IV)get_tree_head();
+ }
+ OUTPUT:
+ RETVAL
+
+
+void
+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;
+ size_t 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;
+ int best_guess;
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+
+ 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);
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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, best_guess);
+
+ 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 && SvPOK(*varbind_val_f) ?
+ SvCUR(*varbind_val_f):0), type);
+
+ if (verbose && res == FAILURE)
+ warn("error: set: 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));
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_async_send(ss, pdu, __snmp_xs_cb,
+ (void*)xs_cb_data);
+ } else {
+ 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);
+ snmp_return_err(ss, *err_str_svp, *err_num_svp, *err_ind_svp);
+ 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 */
+ }
+#else /* NETSNMP_NO_WRITE_SUPPORT */
+ warn("error: Net-SNMP was compiled using --enable-read-only, set() can not be used.");
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+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);
+
+ ss->callback = NULL;
+ ss->callback_magic = NULL;
+
+ if (SvTRUE(perl_callback)) {
+ snmp_xs_cb_data *xs_cb_data;
+ 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));
+
+ # 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 = __snmp_xs_cb;
+ ss->callback_magic = xs_cb_data;
+ 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;
+ struct tree *tp;
+ int len;
+ oid *oid_arr;
+ size_t 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;
+ 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_format;
+ SV *sv_timestamp = NULL;
+ int best_guess;
+
+ 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;
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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)) {
+ char *tag_pv;
+ varbind = (AV*) SvRV(*varbind_ref);
+
+ tag_pv = __av_elem_pv(varbind, VARBIND_TAG_F, ".0");
+ tp = __tag2oid(tag_pv,
+ __av_elem_pv(varbind, VARBIND_IID_F, NULL),
+ oid_arr, &oid_arr_len, NULL, best_guess);
+
+ 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);
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_async_send(ss, pdu, __snmp_xs_cb,
+ (void*)xs_cb_data);
+ } else {
+ 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);
+ snmp_return_err(ss, *err_num_svp, *err_ind_svp, *err_str_svp);
+ XPUSHs(&sv_undef);
+ }
+ goto done;
+ }
+
+ status = __send_sync_pdu(ss, pdu, &response,
+ retry_nosuch,
+ *err_str_svp, *err_num_svp,
+ *err_ind_svp);
+
+ /*
+ ** Set up for numeric or full OID's, if necessary. Save the old
+ ** output format so that it can be restored when we finish -- this
+ ** is a library-wide global, and has to be set/restored for each
+ ** session.
+ */
+ old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
+
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_FULL);
+ }
+ /* Setting UseNumeric forces UseLongNames on so check for UseNumeric
+ after UseLongNames (above) to make sure the final outcome of
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+ getlabel_flag |= USE_NUMERIC_OIDS;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_NUMERIC);
+ }
+
+ 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++) {
+ int local_getlabel_flag = getlabel_flag;
+ 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((u_char**)&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 {
+ local_getlabel_flag |= NON_LEAF_NAME;
+ type = __translate_asn_type(vars->type);
+ }
+ __get_label_iid(str_buf,&label,&iid,local_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(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. */
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ old_format);
+
+ if (response) snmp_free_pdu(response);
+
+ } else {
+ XPUSHs(&sv_undef); /* no mem or bad args */
+ }
+done:
+ Safefree(oid_arr);
+ }
+
+void
+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;
+ size_t 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;
+ char str_buf[STR_BUF_SIZE], *str_bufp = str_buf;
+ size_t str_buf_len = sizeof(str_buf);
+ char tmp_buf_prefix[STR_BUF_SIZE];
+ char str_buf_prefix[STR_BUF_SIZE];
+ 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_format;
+ SV *sv_timestamp = NULL;
+ int best_guess;
+ char *tmp_prefix_ptr;
+ char *st;
+
+ 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;
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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)) {
+ char *tag_pv;
+ varbind = (AV*) SvRV(*varbind_ref);
+
+ /* If the varbind includes the module prefix, capture it for use later */
+ strlcpy(tmp_buf_prefix, __av_elem_pv(varbind, VARBIND_TAG_F, ".0"), STR_BUF_SIZE);
+ tmp_prefix_ptr = strstr(tmp_buf_prefix,"::");
+ if (tmp_prefix_ptr) {
+ tmp_prefix_ptr = strtok_r(tmp_buf_prefix, "::", &st);
+ strlcpy(str_buf_prefix, tmp_prefix_ptr, STR_BUF_SIZE);
+ }
+ else {
+ *str_buf_prefix = '\0';
+ }
+
+ tag_pv = __av_elem_pv(varbind, VARBIND_TAG_F, ".0");
+ tp = __tag2oid(tag_pv,
+ __av_elem_pv(varbind, VARBIND_IID_F, NULL),
+ oid_arr, &oid_arr_len, NULL, best_guess);
+
+ if (oid_arr_len) {
+ snmp_add_null_var(pdu, oid_arr, oid_arr_len);
+ } else {
+ if (verbose)
+ warn("error: getnext: 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 (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);
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_async_send(ss, pdu, __snmp_xs_cb,
+ (void*)xs_cb_data);
+ } else {
+ 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);
+ snmp_return_err(ss, *err_num_svp, *err_ind_svp, *err_str_svp);
+ 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 or full OID's, if necessary. Save the old
+ ** output format so that it can be restored when we finish -- this
+ ** is a library-wide global, and has to be set/restored for each
+ ** session.
+ */
+ old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
+
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_FULL);
+ }
+ /* Setting UseNumeric forces UseLongNames on so check
+ for UseNumeric after UseLongNames (above) to make
+ sure the final outcome of
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is
+ NETSNMP_OID_OUTPUT_NUMERIC */
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+ getlabel_flag |= USE_NUMERIC_OIDS;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_NUMERIC);
+ }
+
+ 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++) {
+ int local_getlabel_flag = getlabel_flag;
+ 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((u_char**)&str_bufp,
+ &str_buf_len,
+ &out_len, 0,
+ &buf_over,
+ vars->name,
+ vars->name_length);
+ str_buf[sizeof(str_buf)-1] = '\0';
+
+ /* Prepend the module prefix to the next OID if needed */
+ if (*str_buf_prefix) {
+ strlcat(str_buf_prefix, "::", STR_BUF_SIZE);
+ strlcat(str_buf_prefix, str_buf, STR_BUF_SIZE);
+ strlcpy(str_buf, str_buf_prefix, STR_BUF_SIZE);
+ }
+
+ if (__is_leaf(tp)) {
+ type = tp->type;
+ } else {
+ local_getlabel_flag |= NON_LEAF_NAME;
+ type = __translate_asn_type(vars->type);
+ }
+ __get_label_iid(str_buf,&label,&iid,local_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(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. */
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ old_format);
+
+ if (response) snmp_free_pdu(response);
+
+ } else {
+ XPUSHs(&sv_undef); /* no mem or bad args */
+ }
+done:
+ Safefree(oid_arr);
+ }
+
+void
+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;
+ size_t 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;
+ 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_format;
+ SV *rv;
+ SV *sv_timestamp = NULL;
+ int best_guess;
+
+ 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;
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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)) {
+ char *tag_pv;
+ varbind = (AV*) SvRV(*varbind_ref);
+ tag_pv = __av_elem_pv(varbind, VARBIND_TAG_F, "0");
+ __tag2oid(tag_pv,
+ __av_elem_pv(varbind, VARBIND_IID_F, NULL),
+ oid_arr, &oid_arr_len, NULL, best_guess);
+
+
+ if (oid_arr_len) {
+ snmp_add_null_var(pdu, oid_arr, oid_arr_len);
+ } else {
+ if (verbose)
+ warn("error: getbulk: 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 (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);
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_async_send(ss, pdu, __snmp_xs_cb,
+ (void*)xs_cb_data);
+ } else {
+ 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);
+ snmp_return_err(ss, *err_num_svp, *err_ind_svp, *err_str_svp);
+ 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 (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));
+
+ av_clear(varlist);
+
+ /*
+ ** Set up for numeric or full OID's, if necessary. Save the old
+ ** output format so that it can be restored when we finish -- this
+ ** is a library-wide global, and has to be set/restored for each
+ ** session.
+ */
+ old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseLongNames", 12, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_FULL);
+ }
+ /* Setting UseNumeric forces UseLongNames on so check for UseNumeric
+ after UseLongNames (above) to make sure the final outcome of
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */
+ if (SvIV(*hv_fetch((HV*)SvRV(sess_ref),"UseNumeric", 10, 1))) {
+ getlabel_flag |= USE_LONG_NAMES;
+ getlabel_flag |= USE_NUMERIC_OIDS;
+
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ NETSNMP_OID_OUTPUT_NUMERIC);
+ }
+
+ if(response && response->variables) {
+ for(vars = response->variables;
+ vars;
+ vars = vars->next_variable) {
+
+ int local_getlabel_flag = getlabel_flag;
+ varbind = (AV*) newAV();
+ *str_buf = '.';
+ *(str_buf+1) = '\0';
+ out_len = 0;
+ buf_over = 0;
+ str_bufp = str_buf;
+ tp = netsnmp_sprint_realloc_objid_tree((u_char**)&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 {
+ local_getlabel_flag |= NON_LEAF_NAME;
+ type = __translate_asn_type(vars->type);
+ }
+ __get_label_iid(str_buf,&label,&iid,local_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);
+ 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(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. */
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
+ old_format);
+
+ if (response) snmp_free_pdu(response);
+
+ } else {
+ XPUSHs(&sv_undef); /* no mem or bad args */
+ }
+done:
+ Safefree(oid_arr);
+ }
+
+void
+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];
+ size_t 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 */
+ int best_guess;
+
+ if (!SvROK(sess_ref) || !SvROK(varlist_ref)) {
+ if (verbose)
+ warn("bulkwalk: 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);
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ /* 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,(DBOUT "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("%s", 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,(DBOUT "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,(DBOUT " 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, best_guess);
+
+ 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,(DBOUT "HERE 1\n"));
+ DBPRT(1,(DBOUT "(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,(DBOUT "%s\n", __snprint_oid(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,(DBOUT "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,(DBOUT "Starting asynchronous bulkwalk...\n"));
+
+ pdu = _bulkwalk_send_pdu(context);
+
+ if (pdu == NULL) {
+ DBPRT(1,(DBOUT "Initial asynchronous send failed...\n"));
+ XSRETURN_UNDEF;
+ }
+
+ /* Sent okay... Return the request ID in 'pdu' as an SvIV. */
+ DBPRT(1,(DBOUT "Okay, request id is %ld\n", (long)(intptr_t)pdu));
+/* XSRETURN_IV((intptr_t)pdu); */
+ XPUSHs(sv_2mortal(newSViv((IV)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,(DBOUT "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,(DBOUT "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,(DBOUT "bulkwalk_recv_pdu() returned %d (error/empty)\n", i));
+ goto err;
+ }
+
+ /* 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,(DBOUT "Returning %d values on the stack.\n", npushed));
+ XSRETURN(npushed);
+
+ /* Handle error cases and clean up after ourselves. */
+ err:
+ if (context) {
+ 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);
+ Safefree(context);
+ }
+ if (pdu)
+ snmp_free_pdu(pdu);
+
+ XSRETURN_UNDEF;
+ }
+
+
+void
+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;
+ size_t 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;
+ int best_guess;
+
+ 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);
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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, best_guess);
+
+ 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 && SvPOK(*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 *)netsnmp_malloc(MAX_OID_LEN * sizeof(oid));
+ tp = __tag2oid(enterprise,NULL, pdu->enterprise,
+ &pdu->enterprise_length, NULL, best_guess);
+ 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 (0 > netsnmp_gethostbyname_v4(agent,
+ (in_addr_t *)pdu->agent_addr)){
+ if (verbose)
+ warn("error:trap:invalid agent address: %s", agent);
+ goto err;
+ }
+ } else {
+ *((in_addr_t *)pdu->agent_addr) = get_myaddr();
+ }
+ pdu->trap_type = generic;
+ pdu->specific_type = specific;
+ pdu->time = uptime;
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ if(snmp_sess_send(ss,pdu) == 0)
+ snmp_free_pdu(pdu);
+ } else {
+ 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);
+ }
+
+
+void
+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;
+ size_t 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;
+ int best_guess;
+
+ 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);
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
+
+ if (SvROK(varlist_ref)) {
+ varlist = (AV*) SvRV(varlist_ref);
+ varlist_len = av_len(varlist);
+ } else {
+ varlist = NULL;
+ varlist_len = -1;
+ }
+ /************************************************/
+ 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, best_guess);
+
+ 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 && SvPOK(*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(api_mode == SNMP_API_SINGLE)
+ {
+ if (snmp_sess_send(ss, pdu) == 0)
+ snmp_free_pdu(pdu);
+ } else {
+ 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);
+ }
+
+
+
+void
+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;
+ size_t 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;
+ int best_guess;
+
+ 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);
+ best_guess = SvIV(*hv_fetch((HV*)SvRV(sess_ref),"BestGuess",9,1));
+
+ 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, best_guess);
+
+ 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 && SvPOK(*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));
+
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ status = snmp_sess_async_send(ss, pdu, __snmp_xs_cb,
+ (void*)xs_cb_data);
+ } else {
+ 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);
+ snmp_return_err(ss, *err_num_svp, *err_ind_svp, *err_str_svp);
+ 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, best_guess)
+ char * tag
+ int best_guess
+ 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, best_guess);
+ if (tp) __get_type_str(tp->type, ret = type_str);
+ RETVAL = ret;
+ }
+ OUTPUT:
+ RETVAL
+
+
+void
+snmp_dump_packet(flag)
+ int flag
+ CODE:
+ {
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DUMP_PACKET, flag);
+ }
+
+
+char *
+snmp_map_enum(tag, val, iflag, best_guess)
+ char * tag
+ char * val
+ int iflag
+ int best_guess
+ 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, best_guess);
+
+ 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,include_module_name)
+ char * var
+ int mode
+ int use_long
+ int auto_init
+ int best_guess
+ int include_module_name
+ CODE:
+ {
+ char str_buf[STR_BUF_SIZE];
+ char str_buf_temp[STR_BUF_SIZE];
+ oid oid_arr[MAX_OID_LEN];
+ size_t oid_arr_len = MAX_OID_LEN;
+ char * label;
+ char * iid;
+ int status = FAILURE;
+ int verbose = SvIV(perl_get_sv("SNMP::verbose", 0x01 | 0x04));
+ struct tree *module_tree = NULL;
+ char modbuf[256];
+ int old_format; /* Current NETSNMP_DS_LIB_OID_OUTPUT_FORMAT */
+
+ str_buf[0] = '\0';
+ str_buf_temp[0] = '\0';
+
+ if (auto_init)
+ netsnmp_init_mib(); /* vestigial */
+
+ /* Save old output format and set to FULL so long_names works */
+ old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_FULL);
+
+ 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_temp, sizeof(str_buf_temp), oid_arr, oid_arr_len);
+
+ if (!use_long) {
+ label = NULL; iid = NULL;
+ if (((status=__get_label_iid(str_buf_temp,
+ &label, &iid, NO_FLAGS)) == SUCCESS)
+ && label) {
+ strlcpy(str_buf_temp, label, sizeof(str_buf_temp));
+ if (iid && *iid) {
+ strlcat(str_buf_temp, ".", sizeof(str_buf_temp));
+ strlcat(str_buf_temp, iid, sizeof(str_buf_temp));
+ }
+ }
+ }
+
+ /* Prepend modulename:: if enabled */
+ if (include_module_name) {
+ module_tree = get_tree (oid_arr, oid_arr_len, get_tree_head());
+ if (module_tree) {
+ if (strcmp(module_name(module_tree->modid, modbuf), "#-1") ) {
+ strcat(str_buf, modbuf);
+ strcat(str_buf, "::");
+ }
+ else {
+ strcat(str_buf, "UNKNOWN::");
+ }
+ }
+ }
+ strcat(str_buf, str_buf_temp);
+
+ break;
+ default:
+ if (verbose) warn("snmp_translate_obj:unknown translation mode: %d\n", mode);
+ }
+ if (*str_buf) {
+ RETVAL = (char*)str_buf;
+ } else {
+ RETVAL = (char*)NULL;
+ }
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, old_format);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+snmp_set_replace_newer(val)
+ int val
+ CODE:
+ {
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_MIB_REPLACE, val);
+ }
+
+void
+snmp_set_save_descriptions(val)
+ int val
+ CODE:
+ {
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_SAVE_MIB_DESCRS, val);
+ }
+
+void
+snmp_set_debugging(val)
+ int val
+ CODE:
+ {
+ snmp_set_do_debugging(val);
+ }
+
+void
+snmp_register_debug_tokens(tokens)
+ char *tokens
+ CODE:
+ {
+ debug_register_tokens(tokens);
+ snmp_set_do_debugging(1);
+ }
+
+void
+snmp_debug_internals(val)
+ int val
+ CODE:
+ {
+#ifdef DEBUGGING
+ _debug_level = val;
+#else
+ val++;
+#endif /* DEBUGGING */
+ }
+
+
+void
+snmp_mib_toggle_options(options)
+ char *options
+ CODE:
+ {
+ snmp_mib_toggle_options(options);
+ }
+
+void
+snmp_sock_cleanup()
+ CODE:
+ {
+ SOCK_CLEANUP;
+ }
+
+void
+snmp_mainloop_finish()
+ CODE:
+ {
+ mainloop_finish = 1;
+ }
+
+
+#-----------------------------------------------------------------------------
+# Note: ss=(SnmpSession*)NULL is so &SNMP::MainLoop() can still be called
+# without a sess handler argument, this way I'm not breaking anyone's old code
+#
+# see MainLoop() in SNMP.pm for more details
+#-----------------------------------------------------------------------------
+void
+snmp_main_loop(timeout_sec,timeout_usec,perl_callback,ss=(SnmpSession*)NULL)
+ int timeout_sec
+ int timeout_usec
+ SV * perl_callback
+ SnmpSession *ss
+ 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;
+ ctvp->tv_usec = 0;
+ 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);
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_select_info(ss,&numfds, &fdset, tvp, &block);
+ } else {
+ 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) {
+ ENTER;
+ SAVETMPS;
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_read(ss, &fdset);
+ } else {
+ snmp_read(&fdset);
+ }
+ FREETMPS;
+ LEAVE;
+
+ } else switch(fd_count) {
+ case 0:
+ SPAGAIN;
+ ENTER;
+ SAVETMPS;
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_timeout( ss );
+ } else {
+ 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(cl,key,tp=0)
+ char * cl
+ char * key
+ IV tp
+ CODE:
+ {
+ __libraries_init("perl");
+ if (!tp) tp = (IV)__tag2oid(key, NULL, NULL, NULL, NULL,0);
+ if (tp) {
+ RETVAL = sv_setref_iv(newSV(0), cl, tp);
+ } else {
+ RETVAL = &sv_undef;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+
+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, *tptmp = 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;
+ SV *ret = NULL;
+
+ if (SvROK(tp_ref)) tp = (SnmpMibNode*)SvIV((SV*)SvRV(tp_ref));
+
+ ret = newSV(0);
+ if (tp)
+ switch (c) {
+ case 'a': /* access */
+ if (strncmp("access", key, strlen(key)) == 0) {
+ switch (tp->access) {
+ case MIB_ACCESS_READONLY:
+ sv_setpv(ret,"ReadOnly");
+ break;
+ case MIB_ACCESS_READWRITE:
+ sv_setpv(ret,"ReadWrite");
+ break;
+ case MIB_ACCESS_WRITEONLY:
+ sv_setpv(ret,"WriteOnly");
+ break;
+ case MIB_ACCESS_NOACCESS:
+ sv_setpv(ret,"NoAccess");
+ break;
+ case MIB_ACCESS_NOTIFY:
+ sv_setpv(ret,"Notify");
+ break;
+ case MIB_ACCESS_CREATE:
+ sv_setpv(ret,"Create");
+ break;
+ default:
+ break;
+ }
+ } else if (strncmp("augments", key, strlen(key)) == 0) {
+ sv_setpv(ret,tp->augments);
+ }
+ 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(ret, 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(ret, 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(ret, tp->defaultValue);
+ break;
+ } /* end if */
+ } /* end if */
+ /* we must be looking at description */
+ sv_setpv(ret,tp->description);
+ break;
+ case 'i': /* indexes, implied */
+ if (tp->augments) {
+ clear_tree_flags(get_tree_head());
+ tptmp = find_best_tree_node(tp->augments, get_tree_head(), NULL);
+ if (tptmp == NULL) {
+ tptmp = tp;
+ }
+ } else {
+ tptmp = tp;
+ }
+ if (strcmp("implied", key) == 0) {
+ /* only the last index can be implied */
+ int isimplied = 0;
+ if (tptmp && tptmp->indexes) {
+ for(ip=tptmp->indexes; ip->next; ip = ip->next) {
+ }
+ isimplied = ip->isimplied;
+ }
+ sv_setiv(ret, isimplied);
+ break;
+ }
+ if (strncmp("indexes", key, strlen(key))) break;
+ index_av = newAV();
+ if (tptmp)
+ for(ip=tptmp->indexes; ip != NULL; ip = ip->next) {
+ av_push(index_av,newSVpv((ip->ilabel),strlen(ip->ilabel)));
+ }
+ sv_setsv(ret, newRV((SV*)index_av));
+ break;
+ case 'l': /* label */
+ if (strncmp("label", key, strlen(key))) break;
+ sv_setpv(ret,tp->label);
+ break;
+ case 'm': /* moduleID */
+ if (strncmp("moduleID", key, strlen(key))) break;
+ mp = find_module(tp->modid);
+ if (mp) sv_setpv(ret, mp->name);
+ break;
+ case 'n': /* nextNode */
+ if (strncmp("nextNode", key, strlen(key))) break;
+ tp = __get_next_mib_node(tp);
+ if (tp == NULL) {
+ sv_setsv(ret, &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(ret, *nn_hrefp);
+ break;
+ case 'o': /* objectID */
+ if (strncmp("objectID", key, strlen(key))) break;
+ __tp_sprint_num_objid(str_buf, tp);
+ sv_setpv(ret,str_buf);
+ break;
+ case 'p': /* parent */
+ if (strncmp("parent", key, strlen(key))) break;
+ tp = tp->parent;
+ if (tp == NULL) {
+ sv_setsv(ret, &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(ret, *nn_hrefp);
+ break;
+ case 'r': /* ranges */
+ if (strncmp("reference", key, strlen(key)) == 0) {
+ sv_setpv(ret,tp->reference);
+ break;
+ }
+ if (strncmp("ranges", key, strlen(key))) break;
+ ranges_av = newAV();
+ for(rp=tp->ranges; rp ; rp = rp->next) {
+ range_hv = newHV();
+ (void)hv_store(range_hv, "low", strlen("low"), newSViv(rp->low), 0);
+ (void)hv_store(range_hv, "high", strlen("high"), newSViv(rp->high), 0);
+ av_push(ranges_av, newRV((SV*)range_hv));
+ }
+ sv_setsv(ret, 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(ret, get_tc_descriptor(tp->tc_index));
+ } else {
+ __get_type_str(tp->type, str_buf);
+ sv_setpv(ret, str_buf);
+ }
+ break;
+ }
+
+ switch(tp->status) {
+ case MIB_STATUS_MANDATORY:
+ sv_setpv(ret,"Mandatory");
+ break;
+ case MIB_STATUS_OPTIONAL:
+ sv_setpv(ret,"Optional");
+ break;
+ case MIB_STATUS_OBSOLETE:
+ sv_setpv(ret,"Obsolete");
+ break;
+ case MIB_STATUS_DEPRECATED:
+ sv_setpv(ret,"Deprecated");
+ break;
+ case MIB_STATUS_CURRENT:
+ sv_setpv(ret,"Current");
+ break;
+ default:
+ break;
+ }
+ } else {
+ sv_setiv(ret,(I32)tp->subid);
+ }
+ break;
+ case 't': /* type */
+ if (strncmp("type", key, strlen(key))) {
+ if (strncmp("textualConvention", key, strlen(key))) break;
+ sv_setpv(ret, get_tc_descriptor(tp->tc_index));
+ break;
+ }
+ __get_type_str(tp->type, str_buf);
+ sv_setpv(ret, str_buf);
+ break;
+ case 'T': /* textual convention description */
+ if (strncmp("TCDescription", key, strlen(key))) break;
+ sv_setpv(ret, get_tc_description(tp->tc_index));
+ break;
+ case 'u': /* units */
+ if (strncmp("units", key, strlen(key))) break;
+ sv_setpv(ret,tp->units);
+ break;
+ case 'h': /* hint */
+ if (strncmp("hint", key, strlen(key))) break;
+ sv_setpv(ret,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) {
+ (void)hv_store(enum_hv, ep->label, strlen(ep->label),
+ newSViv(ep->value), 0);
+ }
+ sv_setsv(ret, newRV((SV*)enum_hv));
+ break;
+ default:
+ break;
+ }
+ RETVAL = ret;
+ }
+ OUTPUT:
+ RETVAL
+
+MODULE = SNMP PACKAGE = SnmpSessionPtr PREFIX = snmp_session_
+
+void
+snmp_session_DESTROY(sess_ptr)
+ SnmpSession *sess_ptr
+ CODE:
+ {
+ if(sess_ptr != NULL)
+ {
+ if(api_mode == SNMP_API_SINGLE)
+ {
+ snmp_sess_close( sess_ptr );
+ } else {
+ snmp_close( sess_ptr );
+ }
+ }
+ }
+
diff --git a/perl/SNMP/TODO b/perl/SNMP/TODO
new file mode 100644
index 0000000..edd7c7c
--- /dev/null
+++ b/perl/SNMP/TODO
@@ -0,0 +1,40 @@
+enhance make test
+
+implement v2 traps and v3 inform requests.
+
+solidify/enhance the V3 api
+
+handle TCP sessions
+
+See that informative strings are returned and the the error number is
+useful in all cases. (need to set $! for errors where a session is not
+returned (failed engineId discovery, memory alloc error, failed key
+computation?))
+
+PC and other unix builds - any platform issues
+
+building with shared libs
+
+ensure module does not complain with -w.
+
+enhance async api so that a boolean false return from a callback exits
+the MainLoop
+
+enhance async api to store a reference to the perl SNMP::Sesion object
+for 2 reasons: 1) if the initial calling session goes out of scope we
+won't destroy the C-struct session until the callback is called. 2) it
+allows us to set error codes in the perl SNMP::Session object
+
+see if new async hooks play with Event.pm
+
+handle dynamic changes to Session parameters, perhaps tie Error* to
+snmp_session struct rather than current duplicate representation.
+
+make the parsed mib interface $SNMP::MIB writable
+
+allow unloading and reinitialization of parsed MIB
+
+attach to libucdagent - provide agent functionality
+
+look for *Not Implemeted* and implement :)
+
diff --git a/perl/SNMP/examples/async1.pl b/perl/SNMP/examples/async1.pl
new file mode 100644
index 0000000..ffd6065
--- /dev/null
+++ b/perl/SNMP/examples/async1.pl
@@ -0,0 +1,17 @@
+use SNMP;
+
+$SNMP::auto_init_mib = 0;
+
+$sess = new SNMP::Session();
+
+sub poller {
+ # VarList is undefined if TIMEOUT occured
+ if (!defined($_[1])) { die "request timed out[$_[0]->{ErrorStr}]\n"; }
+ if ($i++>100000) { die "completed 500 polls\n"; }
+ #print $_[1][0]->tag, " = ", $_[1][0]->val, "\n";
+ $_[0]->get($_[1], [\&poller, $_[0]]);
+}
+
+$sess->get([[".1.3.6.1.2.1.1.3.0"]], [\&poller, $sess]);
+
+SNMP::MainLoop();
diff --git a/perl/SNMP/examples/async2.pl b/perl/SNMP/examples/async2.pl
new file mode 100644
index 0000000..f0e41b3
--- /dev/null
+++ b/perl/SNMP/examples/async2.pl
@@ -0,0 +1,19 @@
+use SNMP;
+
+$SNMP::auto_init_mib = 0;
+
+$sess = new SNMP::Session();
+
+sub poller_handler {
+ if (++$i>500) { die "completed 500 polls\n"; };
+ # VarList is undefined if TIMEOUT occured
+ if (!defined($_[1])) {
+ warn "request timed out[$_[0]->{ErrorStr}]\n";
+ return;
+ }
+# print "$i) ",$_[1][0]->tag, " = ", $_[1][0]->val, "\n";
+}
+
+# $sess->get([[".1.3.6.1.2.1.1.3.0"]], [\&poller_handler, $sess]);
+
+SNMP::MainLoop(.1,sub {for (1..50) {$sess->get([['.1.3.6.1.2.1.1.3.0']], [\&poller_handler, $sess]);} });
diff --git a/perl/SNMP/examples/bulkwalk.pl b/perl/SNMP/examples/bulkwalk.pl
new file mode 100644
index 0000000..3ee2412
--- /dev/null
+++ b/perl/SNMP/examples/bulkwalk.pl
@@ -0,0 +1,121 @@
+use SNMP;
+
+# Hard-coded hostname and community. This is icky, but I didn't want to
+# muddle the example with parsing command line arguments. Deal with it. -r
+#
+my $hostname='localhost';
+my $port='161';
+my $community='public';
+
+$SNMP::debugging = 0;
+$SNMP::dump_packet = 0;
+
+$sess = new SNMP::Session( 'DestHost' => $hostname,
+ 'Community' => $community,
+ 'RemotePort' => $port,
+ 'Timeout' => 300000,
+ 'Retries' => 3,
+ 'Version' => '2c',
+ 'UseLongNames' => 1, # Return full OID tags
+ 'UseNumeric' => 1, # Return dotted decimal OID
+ 'UseEnums' => 0, # Don't use enumerated vals
+ 'UseSprintValue' => 0); # Don't pretty-print values
+
+die "Cannot create session: ${SNMP::ErrorStr}\n" unless defined $sess;
+
+# Set up a list of two non-repeaters and some repeated variables.
+#
+# IMPORTANT NOTE:
+#
+# The 'get' performed for non-repeaters is a "GETNEXT" (the non-repeater
+# requests are not fulfilled with SNMP GET's). This means that you must
+# ask for the lexicographically preceeding variable for non-repeaters.
+#
+# For most branches (i.e. 'sysUpTime'), this "just works" -- be sure you
+# don't ask for an instance, and the response will be as expected. However,
+# if you want a specific variable instance (i.e. 'ifSpeed.5'), you must
+# ask for the _preceeding_ variable ('ifSpeed.4' in this example).
+#
+# See section 4.2.3 of RFC 1905 for more details on GETBULK PDU handling.
+#
+
+my $vars = new SNMP::VarList( ['sysUpTime'], # Nonrepeater variable
+ ['ifNumber'], # Nonrepeater variable
+ ['ifSpeed'], # Repeated variable
+ ['ifDescr'] ); # Repeated variable.
+
+# Do the bulkwalk of the two non-repeaters, and the repeaters. Ask for no
+# more than 8 values per response packet. If the caller already knows how
+# many instances will be returned for the repeaters, it can ask only for
+# that many repeaters.
+#
+@resp = $sess->bulkwalk(2, 8, $vars);
+die "Cannot do bulkwalk: $sess->{ErrorStr} ($sess->{ErrorNum})\n"
+ if $sess->{ErrorNum};
+
+# Print out the returned response for each variable.
+for $vbarr ( @resp ) {
+ # Determine which OID this request queried. This is kept in the VarList
+ # reference passed to bulkwalk().
+ $oid = $$vars[$i++]->tag();
+
+ # Count the number of responses to this query. The count will be 1 for
+ # non-repeaters, 1 or more for repeaters.
+ $num = scalar @$vbarr;
+ print "$num responses for oid $oid: \n";
+
+ # Display the returned list of varbinds using the SNMP::Varbind methods.
+ for $v (@$vbarr) {
+ printf("\t%s = %s (%s)\n", $v->name, $v->val, $v->type);
+ }
+ print "\n";
+}
+
+#
+# Now do the same bulkwalk again, but in asynchronous mode. Set up a Perl
+# callback to receive the reference to the array of arrays of Varbind's for
+# the return value, and pass along the $vars VarList to it. This allows us
+# to print the oid tags (the callback code is almost the same as above).
+#
+# First, define the Perl callback to be called when the bulkwalk completes.
+# The call to SNMP::finish() will cause the SNMP::MainLoop() to return once
+# the callback has completed, so that processing can continue.
+#
+sub callback {
+ my ($vars, $values) = @_;
+
+ for $vbarr ( @$values ) {
+ # Determine which OID this request queried. This is kept in the
+ # '$vars' VarList reference passed to the Perl callback by the
+ # asynchronous callback.
+ $oid = (shift @$vars)->tag();
+
+ # Count the number of responses to this query. The count will be 1 for
+ # non-repeaters, 1 or more for repeaters.
+ $num = scalar @$vbarr;
+ print "$num responses for oid $oid: \n";
+
+ # Display the returned list of varbinds using the SNMP::Varbind methods.
+ for $v (@$vbarr) {
+ printf("\t%s = %s (%s)\n", $v->name, $v->val, $v->type);
+ }
+ print "\n";
+ }
+
+ SNMP::finish();
+}
+
+# The actual bulkwalk request is done here. Note that the $vars VarList
+# reference will be passed to the Perl callback when the bulkwalk completes.
+#
+my $reqid = $sess->bulkwalk(2, 8, $vars, [ \&callback, $vars ]);
+die "Cannot do async bulkwalk: $sess->{ErrorStr} ($sess->{ErrorNum})\n"
+ if $sess->{ErrorNum};
+
+# Now drop into the SNMP event loop and await completion of the bulkwalk.
+# The call to SNMP::finish() in &callback will make the SNMP::MainLoop()
+# return to the caller.
+#
+SNMP::MainLoop();
+
+exit 0;
diff --git a/perl/SNMP/examples/ipforward.pl b/perl/SNMP/examples/ipforward.pl
new file mode 100644
index 0000000..de61e40
--- /dev/null
+++ b/perl/SNMP/examples/ipforward.pl
@@ -0,0 +1,30 @@
+use SNMP;
+$SNMP::use_enums = 1;
+
+my $host = shift;
+my $comm = shift;
+$sess = new SNMP::Session(DestHost => $host, Community => $comm);
+
+$vars = new SNMP::VarList( ['ipRouteIfIndex'], ['ipRouteType'],
+ ['ipRouteProto'], ['ipRouteMask'],
+ ['ipRouteNextHop'], ['ipRouteAge'],
+ ['ipRouteMetric1']);
+
+format STDOUT_TOP =
+ Destination Next Hop Mask Proto Age Metric
+--------------- --------------- -------------- ------- -------- ------
+.
+
+format STDOUT =
+@<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<< @|||||| @||||||| @|||||
+$dest, $nhop, $mask, $proto, $age, $metric
+.
+
+for (($index,$type,$proto,$mask,$nhop,$age,$metric) = $sess->getnext($vars);
+ $$vars[0]->tag eq 'ipRouteIfIndex' and not $sess->{ErrorStr};
+ ($index,$type,$proto,$mask,$nhop,$age,$metric) = $sess->getnext($vars)) {
+ $dest = $$vars[0]->iid;
+ write;
+}
+
+print "$sess->{ErrorStr}\n";
diff --git a/perl/SNMP/examples/mibtree.pl b/perl/SNMP/examples/mibtree.pl
new file mode 100644
index 0000000..0616126
--- /dev/null
+++ b/perl/SNMP/examples/mibtree.pl
@@ -0,0 +1,20 @@
+use SNMP;
+$SNMP::save_descriptions = 1; # must be set prior to mib initialization
+SNMP::initMib(); # parses default list of Mib modules from default dirs
+
+# read dotted decimal oid or symbolic name to look up
+# partial name will be searched and all matches returned
+$val = shift || die "supply partial or complete object name or identifier\n";
+
+if ($node = $SNMP::MIB{$val}) {
+ print "$node:$node->{label} [$node->{objectID}]\n";
+ while (($k,$v) = each %$node) {
+ print "\t$k => $v\n";
+ }
+} else {
+ while (($k,$v) = each %SNMP::MIB) {
+ print "$v->{label} [$v->{obj}]\n" #accepts unique partial key(objectID)
+ if $k =~ /$val/ or $v->{label} =~ /$val/;
+ }
+}
+
diff --git a/perl/SNMP/examples/mibwalk.pl b/perl/SNMP/examples/mibwalk.pl
new file mode 100644
index 0000000..d62dc68
--- /dev/null
+++ b/perl/SNMP/examples/mibwalk.pl
@@ -0,0 +1,17 @@
+# snmpwalk of entire MIB
+# stop on error at end of MIB
+
+use SNMP 1.8;
+$SNMP::use_sprint_value = 1;
+my $host = shift || localhost;
+my $comm = shift || public;
+
+$sess = new SNMP::Session(DestHost => $host, Community => $comm);
+
+$var = new SNMP::Varbind([]);
+
+do {
+ $val = $sess->getnext($var);
+ print SNMP::Varbind::tag($var).".".SNMP::Varbind::iid($var)." = ".
+ SNMP::Varbind::val($var)."\n";
+} until ($sess->{ErrorStr});
diff --git a/perl/SNMP/examples/pingmib.pl b/perl/SNMP/examples/pingmib.pl
new file mode 100755
index 0000000..e6aa792
--- /dev/null
+++ b/perl/SNMP/examples/pingmib.pl
@@ -0,0 +1,46 @@
+#!/usr/bin/env perl
+
+# Ping a host via the CISCO-PING-MIB. For more information about the
+# CISCO-PING-MIB, see also
+# http://tools.cisco.com/Support/SNMP/do/BrowseMIB.do?local=en&mibName=CISCO-PING-MIB.
+
+use strict;
+use SNMP;
+
+my $target = shift || die "no ping target supplied\n"; # numeric ip address
+my $host = shift || 'localhost';
+my $community = shift || 'private';
+
+{
+ my $sess = new SNMP::Session (DestHost => $host,
+ Community => $community,
+ Retries => 1);
+
+ my $dec = pack("C*",split /\./, $target);
+ my $oid = ".1.3.6.1.4.1.9.9.16.1.1.1";
+ my $row = "300";
+ my $res;
+
+ $res = $sess->set([
+ ["$oid.16", $row, 6, "INTEGER"],
+ ["$oid.16", $row, 5, "INTEGER"],
+ ["$oid.15", $row, "MoNDS", "OCTETSTR"],
+ ["$oid.2", $row, 1, "INTEGER"],
+ ["$oid.4", $row, 20, "INTEGER"],
+ ["$oid.5", $row, 150, "INTEGER"],
+ ["$oid.3", $row, $dec, "OCTETSTR"]]);
+ defined($res) || die "row creation failed";
+
+ $res = $sess->set([["$oid.16", $row, 1, "INTEGER"]]);
+ defined($res) || die "row activation failed";
+
+ sleep 30;
+ my ($sent, $received, $low, $avg, $high, $completed) = $sess->get([
+ ["$oid.9", $row], ["$oid.10", $row], ["$oid.11", $row],
+ ["$oid.12", $row], ["$oid.13", $row], ["$oid.14", $row]]);
+
+ printf "Packet loss: %d% (%d/%d)\n", (100 * ($sent-$received)) / $sent,
+ $received, $sent;
+ print "Average delay $avg (low: $low high: $high)\n";
+ $sess->set(["$oid.16", $row, 6, "INTEGER"]);
+}
diff --git a/perl/SNMP/examples/tablewalk.pl b/perl/SNMP/examples/tablewalk.pl
new file mode 100644
index 0000000..6fe344c
--- /dev/null
+++ b/perl/SNMP/examples/tablewalk.pl
@@ -0,0 +1,19 @@
+# snmpwalk of a single table
+# getnext of 3 columns from ipAddrEntry table
+# stop after last row in table
+
+use SNMP 1.8;
+
+my $host = shift || localhost;
+my $comm = shift || public;
+
+my $sess = new SNMP::Session ( DestHost => $host, Community => $comm );
+
+my $vars = new SNMP::VarList([ipAdEntAddr],[ipAdEntIfIndex],[ipAdEntNetMask]);
+
+for (@vals = $sess->getnext($vars);
+ $vars->[0]->tag =~ /ipAdEntAddr/ # still in table
+ and not $sess->{ErrorStr}; # and not end of mib or other error
+ @vals = $sess->getnext($vars)) {
+ print " ($vals[1]) $vals[0]/$vals[2]\n";
+}
diff --git a/perl/SNMP/examples/testleak.pl b/perl/SNMP/examples/testleak.pl
new file mode 100644
index 0000000..495f33b
--- /dev/null
+++ b/perl/SNMP/examples/testleak.pl
@@ -0,0 +1,19 @@
+use SNMP 1.6;
+
+$host = shift;
+unless ($host) {
+ $| = 1; print "enter SNMP host address: "; $| = 0;
+ chomp($host = <STDIN>);
+}
+
+$obj = new SNMP::Session DestHost, $host;
+
+while (){
+print $obj->get(["ifNumber",0]);
+ open(COM,"ps -u$$|") || die;
+ @bar = <COM>;
+ $siz = (split(' ',$bar[1]))[4];
+ $rss = (split(' ',$bar[1]))[5];
+ close(COM);
+ print "siz = $siz, rss = $rss\n";
+}
diff --git a/perl/SNMP/examples/trap-example.pl b/perl/SNMP/examples/trap-example.pl
new file mode 100644
index 0000000..8b8913f
--- /dev/null
+++ b/perl/SNMP/examples/trap-example.pl
@@ -0,0 +1,94 @@
+use strict;
+use vars qw();
+use SNMP qw();
+
+&SNMP::initMib();
+
+&SNMP::loadModules(
+ 'RFC2127-MIB',
+ );
+
+sub trap_call_setup;
+sub trap_dummy;
+
+#
+# should eventually get these out of the MIB...
+#
+my %dispatch_table = (
+ 'isdnMibCallInformation', \&trap_call_setup,
+ '.', \&trap_dummy,
+);
+
+sub trap_dispatcher
+{
+ my $session = shift;
+ my $ref = shift;
+ my $trapType;
+ my ($reqid, $addr, $community);
+
+ # if this is a timeout, then there will be no args...
+ if (defined($ref)) {
+ $ref->[1]->[2] = SNMP::translateObj($ref->[1]->val);
+ $trapType = $ref->[1]->val;
+ my $args = shift;
+ ($reqid, $addr, $community) = @{$args};
+ } else {
+ $trapType = 'timeout';
+ }
+
+ if (defined($dispatch_table{$trapType})) {
+ &{$dispatch_table{$trapType}}($session, $ref);
+ } elsif (defined($dispatch_table{'.'})) {
+ &{$dispatch_table{'.'}}($session, $ref);
+ } else {
+ # don't do anything... silently discard.
+ }
+}
+
+sub trap_dummy
+{
+ my $session = shift;
+ my $ref = shift;
+
+ my $trapType = $ref->[1]->val;
+
+ warn "unexpected trap " . $trapType;
+}
+
+
+sub trap_call_setup
+{
+ my $session = shift;
+ my $varlist = shift;
+ my $args = shift;
+
+ my $ifIndex = $varlist->[2]->val;
+ my $isdnBearerOperStatus = $varlist->[3]->val;
+ my $isdnBearerPeerAddress = $varlist->[4]->val;
+ my $isdnBearerPeerSubAddress = $varlist->[5]->val;
+ my $isdnBearerInfoType = $varlist->[6]->val;
+ my $isdnBearerCallOrigin = $varlist->[5]->val;
+
+ my ($reqid, $ipaddr, $community) = @{$args};
+
+ printf "Call from %s", $isdnBearerPeerAddress;
+ printf "*%s", $isdnBearerPeerSubAddress if ($isdnBearerPeerSubAddress ne '');
+ printf "\n";
+}
+
+my $session = new SNMP::Session(
+ DestHost => 'udp:162',
+ LocalPort => 1,
+ Version => '2c',
+ UseEnums => 0,
+ );
+
+if (!defined($session)) {
+ die "can't create listener session";
+}
+
+# otherwise assume that ErrorNum is zero...
+
+$session->SNMP::_catch([\&trap_dispatcher, $session]);
+
+&SNMP::MainLoop();
diff --git a/perl/SNMP/hints/irix.pl b/perl/SNMP/hints/irix.pl
new file mode 100644
index 0000000..3e38826
--- /dev/null
+++ b/perl/SNMP/hints/irix.pl
@@ -0,0 +1,2 @@
+# uses libelf for nlist on irix (>= 5.3?)
+$self->{LIBS} .= ' -lelf';
diff --git a/perl/SNMP/hints/solaris.pl b/perl/SNMP/hints/solaris.pl
new file mode 100644
index 0000000..87dccd1
--- /dev/null
+++ b/perl/SNMP/hints/solaris.pl
@@ -0,0 +1,4 @@
+# uses kstat on solaris for get_uptime
+$self->{LIBS} .= ' -lkstat';
+# add -ldb if you are getting the vsnprintf not found error
+# $self->{LIBS} .= ' -lkstat -ldb';
diff --git a/perl/SNMP/netsnmp-feature-definitions.h b/perl/SNMP/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..adc642c
--- /dev/null
+++ b/perl/SNMP/netsnmp-feature-definitions.h
@@ -0,0 +1,8 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+netsnmp_feature_require(snprint_objid)
+netsnmp_feature_require(snprint_value)
+netsnmp_feature_require(find_module)
+netsnmp_feature_require(get_tc_description)
+
diff --git a/perl/SNMP/perlsnmp.h b/perl/SNMP/perlsnmp.h
new file mode 100644
index 0000000..57bb064
--- /dev/null
+++ b/perl/SNMP/perlsnmp.h
@@ -0,0 +1,24 @@
+#ifndef timeradd
+#define timeradd(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
+ if ((result)->tv_usec >= 1000000) \
+ { \
+ ++(result)->tv_sec; \
+ (result)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif
+
+#ifndef timersub
+#define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif
diff --git a/perl/SNMP/t/README b/perl/SNMP/t/README
new file mode 100644
index 0000000..7921732
--- /dev/null
+++ b/perl/SNMP/t/README
@@ -0,0 +1,81 @@
+
+mibload
+(save_descriptions, use_long_names)
+ setmib
+ initMib
+ addMibDirs
+ addMibFiles
+ loadModules
+ unloadModules (todo)
+
+mib
+ translateObj
+ getType
+ mapEnum
+ SNMP::MIB::NODE
+
+session
+ connectivity
+ error handling
+ mib loading
+ parameters
+
+get
+(use_enums, sprint_val, long_names)
+ var formats
+ fget
+ multi varbinds
+ error reporting
+
+getnext
+
+set
+
+trap??
+
+async
+
+snmpv3
+
+
+This is the first stab at setting up comprehensive tests for
+SNMP-1.7 which look and act like regular perl5 test results.
+
+Use teststub.t attached below as a template for creating additional
+test modules.
+
+Add more tests and feed them back into the distribution! The more the
+better!
+
+Written by John Stoffel (jfs@fluent.com =or= john@nesc.org) 10/14/1997
+
+------------<teststub.t>--------------------------------
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+}
+use Test;
+use SNMP 3.0;
+
+$SNMP::verbose = 0;
+$num = 0; # Number of tests to run
+
+print "1..$num\n";
+$n = 1;
+
+my $junk_oid = ".1.3.6.1.2.1.1.1.1.1.1";
+my $oid = '.1.3.6.1.2.1.1.1';
+my $name = 'sysDescr';
+my $junk_name = 'fooDescr';
+
+######################################################################
+# Garbage names return Undef.
+# test 1
+$type = SNMP::getType($junk_name);
+printf "%s %d\n", (!defined($type)) ? "ok" :"not ok", $n++;
+
+
diff --git a/perl/SNMP/t/async.t b/perl/SNMP/t/async.t
new file mode 100644
index 0000000..f3fb38d
--- /dev/null
+++ b/perl/SNMP/t/async.t
@@ -0,0 +1,169 @@
+#!./perl
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+
+ $skipped_tests = ($^O =~ /win32/i) ? 20 : 0;
+}
+
+use Test;
+BEGIN {plan tests => 20 - $skipped_tests}
+use SNMP;
+use vars qw($agent_port $comm $agent_host);
+
+if ($^O =~ /win32/i) {
+ warn "Win32/Win64 detected - skipping async calls\n";
+ exit;
+}
+
+require "t/startagent.pl";
+
+
+sub cb1; # forward reference
+sub cb2;
+sub cb3;
+sub cb4;
+sub cb5;
+sub cb6;
+sub cb7;
+sub cbDummy;
+
+$SNMP::verbose = 0;
+$SNMP::dump_packet = 0;
+
+my $sess = new SNMP::Session(DestHost => $agent_host,
+ Version => 1,
+ Community => $comm,
+ RemotePort => $agent_port);
+
+# try getting unregistered OID.
+my $result = $sess->get([["HooHaaHooHaa","0"]], [\&cbDummy, $sess]);
+ok(!defined($result));
+
+# this get should work
+$result = $sess->get([["sysDescr","0"]], [\&cb1, $sess]);
+ok($result);
+
+SNMP::MainLoop();
+
+snmptest_cleanup();
+
+exit 0;
+
+sub cb1{
+ my $sess = shift;
+ my $vlist = shift;
+
+ ok(defined($vlist));
+ my $tag = $vlist->[0]->tag;
+ ok($tag eq 'sysDescr');
+ my $val = $vlist->[0]->val;
+ ok(defined $val);
+ my $iid = $vlist->[0]->iid;
+ my $type = $vlist->[0]->type;
+ ok($type eq 'OCTETSTR');
+ my $res = $sess->getnext([["sysDescr",0]], [\&cb2, $sess]);
+ ok ($res);
+} # end of cb1
+
+sub cb2{
+ my $sess = shift;
+ my $vlist = shift;
+
+ ok(defined($vlist));
+ ok(ref($vlist->[0]) =~ /Varbind/);
+ ok($vlist->[0][0] eq 'sysObjectID');
+ my $res = $sess->get([[".1.3.6.1.2.1.1.1.0"]], [\&cb3, $sess]);
+ ok($res);
+} # end of cb2
+
+sub cb3{
+ my $sess = shift;
+ my $vlist = shift;
+
+ ok(defined($vlist));
+
+ ok($vlist->[0][0] eq 'sysDescr');
+
+ my $res = $sess->getnext([["sysDescr",0]], [\&cb4, $sess]);
+ ok($res);
+} # end of cb3
+
+sub cb4{
+ my $sess = shift;
+ my $vlist = shift;
+
+ ok(defined $vlist);
+ my $res = $sess->set("sysDescr.0", "hahaha", [\&cb5, $sess]);
+} # end of cb4
+
+sub cb5{
+ my $sess = shift;
+ my $vlist = shift;
+
+ ok(defined($vlist));
+
+ my $res = $sess->set("sysORID.1", ".1.3.6.1.2.1.1.1", [\&cb6, $sess]);
+ ok(defined $res);
+} # end of cb5
+
+sub cb6{
+ my $sess = shift;
+ my $vlist = shift;
+ my $tag = $vlist->[0]->tag;
+ my $val = $vlist->[0]->val;
+
+ ok($tag =~ /^sysORID/);
+# create list of varbinds for GETS, val field can be null or omitted
+ my $vars =
+ new SNMP::VarList (
+ ['sysDescr', '0', ''],
+ ['sysObjectID', '0'],
+ ['sysUpTime', '0'],
+ ['sysContact', '0'],
+ ['sysName', '0'],
+ ['sysLocation', '0'],
+ ['sysServices', '0'],
+ ['ifNumber', '0'],
+ ['ifDescr', '1'],
+ ['ifSpeed', '1'],
+ ['snmpInPkts', '0'],
+ ['snmpInBadVersions', '0'],
+ ['snmpInBadCommunityNames', '0'],
+ ['snmpInBadCommunityUses', '0'],
+ ['snmpInASNParseErrs', '0'],
+ ['snmpEnableAuthenTraps', '0'],
+ ['sysORID', '1'],
+ ['sysORDescr', '1'],
+ ['sysORUpTime', '1'],
+ ['sysORLastChange', '0'],
+ ['ipInHdrErrors', '0'],
+ ['ipDefaultTTL', '0'],
+ ['ipInHdrErrors', '0'],
+ );
+ my $res = $sess->get($vars, [\&cb7, $sess]);
+ ok(defined $res);
+} # end of cb6
+
+sub cb7{
+ my $sess = shift;
+ my $vlist = shift;
+
+
+ my $tag = $vlist->[0]->tag;
+ my $val = $vlist->[0]->val;
+
+ ok(@{$vlist} == 23);
+
+ SNMP::finish();
+} # end of cb7
+
+sub cbDummy {
+ warn("error: this should not get called");
+}
+
diff --git a/perl/SNMP/t/bulkwalk.t b/perl/SNMP/t/bulkwalk.t
new file mode 100644
index 0000000..2d13e7b
--- /dev/null
+++ b/perl/SNMP/t/bulkwalk.t
@@ -0,0 +1,339 @@
+#!./perl
+#
+# $Id$
+#
+# Test bulkwalk functionality.
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+ $skipped_tests = ($^O =~ /win32/i) ? 21 : 0;
+}
+use Test;
+BEGIN { $num = 62 - $skipped_tests; plan test => $num; }
+
+use SNMP;
+
+require "t/startagent.pl";
+
+use vars qw($agent_port $comm2 $agent_host);
+
+$SNMP::debugging = 0;
+$SNMP::verbose = 0;
+
+#print "1..$num\n";
+
+######################################################################
+# Fire up a session.
+$s1 = new SNMP::Session(
+ 'DestHost' => $agent_host,
+ 'Community' => $comm2,
+ 'RemotePort' => $agent_port,
+ 'Version' => '2c',
+ 'UseNumeric' => 1,
+ 'UseEnum' => 0,
+ 'UseLongNames' => 1
+);
+ok(defined($s1));
+
+######################################################################
+#
+# Attempt to use the bulkwalk method to get a few variables from the
+# SNMP agent.
+# test 1
+$vars = new SNMP::VarList ( ['sysUpTime'], ['ifNumber'], # NON-repeaters
+ ['ifSpeed'], ['ifDescr']); # Repeated variables.
+
+$expect = scalar @$vars;
+@list = $s1->bulkwalk(2, 16, $vars);
+
+ok($s1->{ErrorNum} == 0);
+
+# Did we get back the list of references to returned values?
+#
+ok(scalar @list == $expect);
+if (defined($list[0][0])) {
+ # Sanity check the returned values. list[0] is sysUptime nonrepeater.
+ ok($list[0][0]->tag eq ".1.3.6.1.2.1.1.3"); # check system.sysUptime OID
+ ok($list[0][0]->iid eq "0"); # check system.sysUptime.0 IID
+ ok($list[0][0]->val =~ m/^\d+$/); # Uptime is numeric
+ ok($list[0][0]->type eq "TICKS"); # Uptime should be in ticks.
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+}
+if (defined($list[1][0])) {
+ # Find out how many interfaces to expect. list[1] is ifNumber nonrepeater.
+ ok($list[1][0]->tag eq ".1.3.6.1.2.1.2.1"); # Should be system.ifNumber OID.
+ ok($list[1][0]->iid eq "0"); # system.ifNumber.0 IID.
+ ok($list[1][0]->val =~ m/^\d+$/); # Number is all numeric
+ #XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+ #ok($list[1][0]->type eq "INTEGER32"); # Number should be integer.
+
+ $ifaces = $list[1][0]->val;
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+# Make sure we got an ifSpeed for each interface. list[2] is ifSpeed repeater.
+ok(scalar @{$list[2]} == $ifaces);
+# Make sure we got an ifDescr for each interface. list[3] is ifDescr repeater.
+ok(scalar @{$list[3]} == $ifaces);
+
+if (defined($list[2][0])) {
+ # Test for reasonable values from the agent.
+ ok($list[2][0]->tag eq ".1.3.6.1.2.1.2.2.1.5"); # Should be system.ifSpeed OID.
+ ok($list[2][0]->iid eq "1"); # Instance should be 1.
+ ok($list[2][0]->val =~ m/^\d+$/); # Number is all numeric
+ ok($list[2][0]->type eq "GAUGE"); # Number should be a gauge.
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+if (defined($list[3][0])) {
+ ok($list[3][0]->tag eq ".1.3.6.1.2.1.2.2.1.2"); # Should be system.ifDescr OID.
+ ok($list[3][0]->iid eq "1"); # Instance should be 1.
+
+ # The first interface is probably loopback. Check this.
+ ok($list[3][0]->type eq "OCTETSTR"); # Description is a string.
+
+ # This might fail on systems that don't have lo0/loopback as their first
+ # interface. Please adjust accordingly.
+ $loopback = $list[3][0]->val;
+ if ($^O =~ /win32/i) {
+ ok(($loopback =~ /loopback/i));
+ } elsif ($^O =~ /(irix|hpux)/i) {
+ # IRIX/HP-UX may have lo0 at the *end* of the interface list,
+ # so just check for a non-empty string
+ ok(($loopback ne ''));
+ } elsif ($^O eq 'freebsd') {
+ $loopback = $list[3][-1]->val;
+ ok(($loopback =~ /^lo/));
+ } else {
+ ok(($loopback =~ /^lo/));
+ }
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+###############################################################################
+# Attempt to use the bulkwalk method to get only non-repeaters
+# test 2
+$vars = new SNMP::VarList ( ['sysUpTime'], ['ifNumber'] ); # NON-repeaters
+
+$expect = scalar @$vars;
+@list = $s1->bulkwalk(2, 0, $vars);
+#@list = $s1->bulkwalk(2, 16, $vars);
+ok($s1->{ErrorNum} == 0);
+
+# Did we get back the list of references to returned values?
+#
+ok(scalar @list == $expect);
+
+if (defined($list[0][0])) {
+ # Sanity check the returned values. list[0] is sysUptime nonrepeater.
+ ok($list[0][0]->tag eq ".1.3.6.1.2.1.1.3"); # check system.sysUptime OID
+ ok($list[0][0]->iid eq "0"); # check system.sysUptime.0 IID
+ ok($list[0][0]->val =~ m/^\d+$/); # Uptime is numeric
+ ok($list[0][0]->type eq "TICKS"); # Uptime should be in ticks.
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+if (defined($list[1][0])) {
+ # Find out how many interfaces to expect. list[1] is ifNumber nonrepeater.
+ ok($list[1][0]->tag eq ".1.3.6.1.2.1.2.1"); # Should be system.ifNumber OID.
+ ok($list[1][0]->iid eq "0"); # system.ifNumber.0 IID.
+ ok($list[1][0]->val =~ m/^\d+$/); # Number is all numeric
+ #XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+ #ok($list[1][0]->type eq "INTEGER32"); # Number should be integer.
+ $ifaces = $list[1][0]->val;
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+###############################################################################
+# Attempt to use the bulkwalk method to get only repeated variables
+# test 3
+$vars = new SNMP::VarList ( ['ifIndex'], ['ifSpeed'] ); # repeaters
+
+$expect = scalar @$vars;
+@list = $s1->bulkwalk(0, 16, $vars);
+ok($s1->{ErrorNum} == 0);
+
+# Did we get back the list of references to returned values?
+#
+ok(scalar @list == $expect);
+
+# Make sure we got an ifIndex for each interface. list[0] is ifIndex repeater.
+ok(scalar @{$list[0]} == $ifaces);
+
+# Make sure we got an ifSpeed for each interface. list[0] is ifSpeed repeater.
+ok(scalar @{$list[1]} == $ifaces);
+
+if (defined($list[0][0])) {
+ # Test for reasonable values from the agent.
+ ok($list[0][0]->tag eq ".1.3.6.1.2.1.2.2.1.1"); # Should be system.ifIndex OID.
+ ok($list[0][0]->iid eq "1"); # Instance should be 1.
+ ok($list[0][0]->val =~ m/^\d+$/); # Number is all numeric
+ #XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+ #ok($list[0][0]->type eq "INTEGER32"); # Number should be an integer.
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+if (defined($list[1][0])) {
+ ok($list[1][0]->tag eq ".1.3.6.1.2.1.2.2.1.5"); # Should be system.ifSpeed OID.
+ ok($list[1][0]->iid eq "1"); # Instance should be 1.
+ ok($list[1][0]->val =~ m/^\d+$/); # Number is all numeric
+ ok($list[1][0]->type eq "GAUGE"); # Number should be a gauge.
+}
+else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+}
+
+######################################################################
+# Asynchronous Bulkwalk Methods
+######################################################################
+#
+# Attempt to use the bulkwalk method to get a few variables from the
+# SNMP agent.
+# test 4
+sub async_cb1 {
+ my ($vars, $list) = @_;
+ ok(defined $list && ref($list) =~ m/ARRAY/);
+ ok(defined $vars && ref($vars) =~ m/SNMP::VarList/);
+
+ ok(scalar @$list == scalar @$vars);
+
+ my $vbr;
+
+ if (defined($list->[0][0])) {
+ # Sanity check the returned values. First is sysUptime nonrepeater.
+ $vbr = $list->[0][0];
+ ok($vbr->tag eq ".1.3.6.1.2.1.1.3"); # check system.sysUptime OID
+ ok($vbr->iid eq "0"); # check system.sysUptime.0 IID
+ ok($vbr->val =~ m/^\d+$/); # Uptime is numeric
+ ok($vbr->type eq "TICKS"); # Uptime should be in ticks.
+ }
+ else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+ }
+
+ if (defined($list->[1][0])) {
+ # Find out how many interfaces to expect. Next is ifNumber nonrepeater.
+ $vbr = $list->[1][0];
+ ok($vbr->tag eq ".1.3.6.1.2.1.2.1"); # Should be system.ifNumber OID.
+ ok($vbr->iid eq "0"); # system.ifNumber.0 IID.
+ ok($vbr->val =~ m/^\d+$/); # Number is all numeric
+ #XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+ # ok($vbr->type eq "INTEGER32"); # Number should be integer.
+ $ifaces = $vbr->[2];
+ }
+ else {
+ ok(0);
+ ok(0);
+ ok(0);
+ }
+
+ # Test for reasonable values from the agent.
+ ok(scalar @{$list->[2]} == $ifaces);
+
+ if (defined($list->[2][0])) {
+ $vbr = $list->[2][0];
+ ok($vbr->tag eq ".1.3.6.1.2.1.2.2.1.5"); # Should be ifSpeed OID
+ ok($vbr->iid eq "1"); # Instance should be 1.
+ ok($vbr->val =~ m/^\d+$/); # Number is all numeric
+ ok($vbr->type eq "GAUGE"); # Should be a gauge.
+
+ ok(scalar @{$list->[3]} == $ifaces);
+ }
+ else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+ }
+
+ if (defined($list->[3][0])) {
+ $vbr = $list->[3][0];
+ ok($vbr->tag eq ".1.3.6.1.2.1.2.2.1.2"); # Should be ifDescr OID
+ ok($vbr->iid eq "1"); # Instance should be 1.
+
+ # The first interface is probably loopback. Check this.
+ ok($vbr->type eq "OCTETSTR");
+
+ # This might fail on systems that don't have lo0/loopback as their first
+ # interface. Please adjust accordingly.
+ if ($^O =~ /(irix|hpux)/i) {
+ # IRIX/HP-UX may have lo0 at the *end* of the interface list,
+ # so just check for a non-empty string
+ ok(($vbr->val ne ''));
+ } elsif ($^O eq 'freebsd') {
+ $vbr = $list->[3][-1];
+ ok(($vbr->val =~ /^lo/));
+ } else {
+ ok(($vbr->val =~ /^lo/));
+ }
+ }
+ else {
+ ok(0);
+ ok(0);
+ ok(0);
+ ok(0);
+ }
+
+ SNMP::finish();
+}
+
+$vars = new SNMP::VarList ( ['sysUpTime'], ['ifNumber'], # NON-repeaters
+ ['ifSpeed'], ['ifDescr']); # Repeated variables.
+
+if ($^O =~ /win32/i) {
+ warn "Win32/Win64 detected - skipping async calls\n";
+}
+else {
+ @list = $s1->bulkwalk(2, 16, $vars, [ \&async_cb1, $vars ] );
+ ok($s1->{ErrorNum} == 0);
+ SNMP::MainLoop();
+}
+ok(1);
+
+snmptest_cleanup();
+
diff --git a/perl/SNMP/t/conf.t b/perl/SNMP/t/conf.t
new file mode 100644
index 0000000..9a37048
--- /dev/null
+++ b/perl/SNMP/t/conf.t
@@ -0,0 +1,53 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ $ENV{'MIBS'} = '';
+}
+
+# This merely checks to see if the default_store routines work from
+# read configuration files. Functionally, if this fails then it's a
+# serious problem because they linked with static libraries instead of
+# shared ones as the memory space is different.
+
+use Test;
+BEGIN {plan tests => 3}
+
+my $envsep = ($^O =~ /win32/i) ? ';' : ':';
+
+SNMP::setenv('SNMPCONFPATH', '.' . $envsep . 't', 1);
+
+ok(1); # just start up
+
+use SNMP;
+use NetSNMP::default_store(':all');
+
+# should be 0, as it's un-initialized
+$myint = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS);
+
+ok($myint == 0);
+
+SNMP::init_snmp("conftest");
+
+$myint = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS);
+
+# ok, should be 1 as it's initalized by the snmp.conf config file.
+ok($myint == 1);
+
+# this is a pretty major error, so if it's not true we really really
+# print a big big warning. Technically, I suspect this is a bad thing
+# to do in perl tests but...
+if ($myint != 1) {
+ die "\n\n\n" . "*" x 75 . "\nBIG PROBLEM($myint): I wasn't able to read
+ data from a configuration file. This likely means that you've
+ compiled the net-snmp package with static libraries, which can
+ cause real problems with the perl module. Please reconfigure your
+ net-snmp package for use with shared libraries (run configure with
+ --enable-shared)\n" . "*" x 75 . "\n\n\n\n";
+}
+
diff --git a/perl/SNMP/t/conftest.conf b/perl/SNMP/t/conftest.conf
new file mode 100644
index 0000000..9cf5219
--- /dev/null
+++ b/perl/SNMP/t/conftest.conf
@@ -0,0 +1,2 @@
+[snmp]
+numericTimeticks 1
diff --git a/perl/SNMP/t/get.t b/perl/SNMP/t/get.t
new file mode 100644
index 0000000..f88de65
--- /dev/null
+++ b/perl/SNMP/t/get.t
@@ -0,0 +1,216 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+use Test;
+BEGIN { $n = 17; plan tests => $n }
+use SNMP;
+use vars qw($agent_port $comm $agent_host);
+require "t/startagent.pl";
+$SNMP::debugging = 0;
+$SNMP::verbose = 0;
+$SNMP::dump_packet = 0;
+
+my $junk_oid = ".1.3.6.1.2.1.1.1.1.1.1";
+my $oid = '.1.3.6.1.2.1.1.1';
+my $junk_name = 'fooDescr';
+my $junk_host = 'no.host.here';
+my $name = "gmarzot\@nortelnetworks.com";
+my $s1;
+
+# create list of varbinds for GETS, val field can be null or omitted
+$vars = new SNMP::VarList (
+ ['sysDescr', '0', ''],
+ ['sysObjectID', '0'],
+ ['sysUpTime', '0'],
+ ['sysContact', '0'],
+ ['sysName', '0'],
+ ['sysLocation', '0'],
+ ['sysServices', '0'],
+
+ ['snmpInPkts', '0'],
+ ['snmpInBadVersions', '0'],
+ ['snmpInBadCommunityNames', '0'],
+ ['snmpInBadCommunityUses', '0'],
+ ['snmpInASNParseErrs', '0'],
+ ['snmpEnableAuthenTraps', '0'],
+
+ ['sysORID', '1'],
+ ['sysORDescr', '1'],
+ ['sysORUpTime', '1'],
+ ['sysORLastChange', '0'],
+ ['snmpSilentDrops', '0'],
+ ['snmpProxyDrops', '0'],
+
+## not all agents we know will support these objects
+# ['hrStorageType', '2'],
+# ['hrSystemDate', '0'],
+# ['sysORIndex', '1'],
+# ['ifName', '1'],
+# ['ifNumber', '0'],
+# ['ifDescr', '1'],
+# ['ifSpeed', '1'],
+# ['snmpTrapEnterprise', '2'],
+# ['ipInHdrErrors', '0'],
+# ['ipDefaultTTL', '0'],
+# ['ipInHdrErrors', '0'],
+
+ );
+################################################################
+# Yet to do:
+# test for the max limit the 'get' can provide.
+# Figure out why the IP and Physical address are not getting printed.
+# why ifname is not getting printed?
+################################################################
+# ['ipNetToMediaPhysAddress', '0'],
+# ['ipAdEntAddr', '0'],
+# ['snmpTrapOID', '0'],
+# ['hrSystemNumUsers', '0'],
+# ['hrFSLastFullBackupDate', '0'],
+# ['ifPromiscuousMode', '0'],
+
+
+
+######################################################################
+# Fire up a session.
+ $s1 =
+ new SNMP::Session (DestHost=>$agent_host,Version=>1,Community=>$comm,RemotePort=>$agent_port);
+ ok(defined($s1));
+
+######################################################################
+# Get the standard Vars and check that we got some defined vars back
+@ret = $s1->get($vars);
+ok(!$s1->{ErrorStr} and defined($ret[0]));
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+######################################################################
+# Check that we got back the number we asked for.
+ok($#ret == $#{$vars});
+#print("dude : $#ret\n");
+################################################
+
+# Test for a string
+$contact = $s1->get('sysContact.0');
+#print("contact is : $contact\n");
+ok( defined($contact));
+
+
+$name = $s1->get('sysName.0');
+#print("Name is : $name\n");
+ok( defined($name));
+
+
+$location = $s1->get('sysLocation.0');
+#print("Location is : $location\n");
+ok( defined($location));
+#########################################
+
+
+# Test for an integer
+$ttl = $s1->get('ipDefaultTTL.0');
+#print("TTL is : $ttl\n");
+ok( defined($ttl));
+########################################
+
+
+# Test for a TimeTicks
+$time = $s1->get('sysUpTime.0');
+#print("up time is : $time hundredths of a second\n");
+ok( defined($time));
+#########################################
+
+
+#Test for a Counter32 type.
+$totalDatagramsReceived = $s1->get('ipInHdrErrors.0');
+#print("totalDatagramsReceived is : $totalDatagramsReceived\n");
+ok( defined($totalDatagramsReceived));
+################################################
+
+
+#Test for a PhysicalAddr type
+$physaddr = $s1->get('ipNetToMediaPhysAddress.0');
+#print("physical addr is : $physaddr \n");
+ok( defined($physaddr));
+##############################################
+
+
+#Test for a IpAddr type
+$ipaddr = $s1->get('ipAdEntAddr.0');
+#print("Ip address is : $ipaddr \n");
+ok( defined($ipaddr));
+##############################################
+
+
+#Test for a OID type
+$trapOID = $s1->get('snmpTrapOID.0');
+#print("trap OID is : $trapOID $s1->{ErrorStr}\n");
+ok( defined($trapOID));
+##############################################
+
+
+#Test for a Gauge type
+#$numusers = $s1->get('hrSystemNumUsers.0');
+#print("Number of users is : $numusers \n");
+#ok( defined($numusers));
+##############################################
+
+#nosuchname
+#Test for a date & time type
+#$datetime = $s1->get('hrFSLastFullBackupDate.0');
+#print("Number of users is : $datetime \n");
+#ok( defined($datetime));
+##############################################
+
+#nosuchname
+#Test for a Truth value type
+#$mode = $s1->get('ifPromiscuousMode.16');
+#print("Truth value(1 true, 2 false) is : $mode \n");
+#ok( defined($mode));
+##############################################
+
+# Time stamp test
+$time = $s1->get('sysORLastChange.0');
+#print("time stamp is : $time \n");
+ok(defined($time));
+#############################################
+
+# Integer test
+#$index = $s1->get('sysORIndex.0');
+#print("index is : $index\n");
+#ok(defined($index));
+#############################################
+
+# OID test
+$oid = $s1->get('sysORID.1');
+#print("index is : $oid\n");
+ok(defined($oid));
+#############################################
+
+# String test
+$descr = $s1->get('sysORDescr.1');
+#print("Sys Descr is : $descr\n");
+ok(defined($descr));
+#############################################
+
+# string String test
+$ifname = $s1->get('ifDescr.1');
+#print("ifname is : $ifname $s1->{ErrorStr}\n");
+ok(defined($ifname));
+#############################################
+
+
+# Try getting some unknown(wrong ?) data
+$unknown = $s1->get('ifmyData.0');
+ok(!defined($unknown));
+##############################################
+
+
+snmptest_cleanup();
+
+
diff --git a/perl/SNMP/t/getnext.t b/perl/SNMP/t/getnext.t
new file mode 100644
index 0000000..417ae91
--- /dev/null
+++ b/perl/SNMP/t/getnext.t
@@ -0,0 +1,102 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+
+use Test;
+BEGIN { plan tests => 9 }
+use SNMP;
+use vars qw($agent_port $comm $agent_host);
+require "t/startagent.pl";
+
+
+my $junk_oid = ".1.3.6.1.2.1.1.1.1.1.1";
+my $oid = '.1.3.6.1.2.1.1.1';
+my $junk_name = 'fooDescr';
+my $junk_host = 'no.host.here';
+my $name = "gmarzot\@nortelnetworks.com";
+
+$SNMP::debugging = 0;
+my $n = 9; # Number of tests to run
+
+#print "1..$n\n";
+#if ($n == 0) { exit 0; }
+
+# create list of varbinds for GETS, val field can be null or omitted
+my $vars = new SNMP::VarList (
+ ['sysDescr', '0', ''],
+ ['sysContact', '0'],
+ ['sysName', '0'],
+ ['sysLocation', '0'],
+ ['sysServices', '0'],
+ ['ifNumber', '0'],
+ ['ifDescr', '1'],
+ ['ifSpeed', '1'],
+ );
+
+
+############################## 1 #####################################
+# Fire up a session.
+ my $s1 =
+ new SNMP::Session (DestHost=>$agent_host,Version=>1,Community=>$comm,RemotePort=>$agent_port);
+ ok(defined($s1));
+
+############################# 2 #######################################
+# Try getnext on sysDescr.0
+
+my $next = $s1->getnext('sysDescr.0');
+#print ("The next OID is : $next\n");
+ok($s1->{ErrorStr} eq '');
+#print STDERR "Error string1 = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+########################### 3 ########################################
+#$v1 = $s1->getnext('sysLocation.0');
+#print ("The next OID is : $v1\n");
+my $v2 = $s1->getnext('sysServices.0');
+#print ("The next OID is : $v2\n");
+ok($s1->{ErrorStr} eq '');
+#print STDERR "Error string2 = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+
+############################ 4 #######################################
+# try it on an unknown OID
+my $v3 = $s1->getnext('Srivathsan.0');
+#print ("The unknown OID is : $v3\n");
+ok($s1->{ErrorStr} =~ /^Unknown/);
+#print STDERR "Error string5 = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+############################# 5 #######################################
+# On a non-accessible value
+#my $kkk = $s1->getnext('vacmSecurityName.1');
+#print("kkk is $kkk\n");
+#ok($s1->{ErrorInd} != 0);
+#print STDERR "Error string5 = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+############################# 6 ####################################
+# We should get back sysDescr.0 here.
+my $var = new SNMP::Varbind(['sysDescr']);
+my $res2 = $s1->getnext($var);
+#print("res2 is : $res2\n");
+ok((not $s1->{ErrorStr} and not $s1->{ErrorInd}));
+ok((defined $var->iid and $var->iid eq 0));
+ok((defined $var->val and $var->val eq $res2));
+
+############################# 7 ######################################
+# get the next one after that as well for a second check
+my $res3 = $s1->getnext($var);
+#print("res3 is : $res3\n");
+ok((defined $var->tag and $var->tag eq 'sysObjectID'));
+ok((defined $var->val and $var->val eq $res3));
+
+
+ snmptest_cleanup();
diff --git a/perl/SNMP/t/mib.t b/perl/SNMP/t/mib.t
new file mode 100644
index 0000000..f4ba91a
--- /dev/null
+++ b/perl/SNMP/t/mib.t
@@ -0,0 +1,226 @@
+#!./perl
+
+# Written by John Stoffel (jfs@fluent.com) - 10/13/1997
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+ $ENV{'MIBS'} = 'ALL';
+}
+
+# to print the description...
+$SNMP::save_descriptions = 1;
+
+use Test;
+BEGIN {plan tests => 35}
+use SNMP;
+
+$SNMP::verbose = 0;
+$SNMP::best_guess = 2;
+
+use vars qw($bad_oid);
+require "t/startagent.pl";
+
+############################# 1 ######################################
+#check if
+my $res = $SNMP::MIB{sysDescr}{label};
+#print("Label is:$res\n");
+ok("sysDescr" eq $res);
+#print("\n");
+############################# 2 ######################################
+$res = $SNMP::MIB{sysDescr}{objectID};
+#print("OID is: $res\n");
+ok(defined($res));
+#print("\n");
+############################# 3 ######################################
+$res = $SNMP::MIB{sysDescr}{access};
+#print("access is: $res\n");
+ok($res eq 'ReadOnly');
+#print("\n");
+############################## 4 ###################################
+$res = $SNMP::MIB{sysLocation}{access};
+#$res = $SNMP::MIB{sysORIndex}{access};
+ok($res eq 'ReadWrite');
+############################## 5 ###################################
+$res = $SNMP::MIB{sysLocation}{type};
+ok($res eq 'OCTETSTR');
+############################# 6 ####################################
+$res = $SNMP::MIB{sysLocation}{status};
+#print STDERR ("status is: $res\n");
+ok($res eq 'Current');
+#print STDERR ("\n");
+############################# 7 #################################
+$res = $SNMP::MIB{sysORTable}{access};
+#print("access is: $res\n");
+ok($res eq 'NoAccess');
+#print("\n");
+############################# 8 ###############################
+$res = $SNMP::MIB{sysLocation}{subID};
+#print("subID is: $res\n");
+ok(defined($res));
+#print("\n");
+############################ 9 ##############################
+$res = $SNMP::MIB{sysLocation}{syntax};
+#print("syntax is: $res\n");
+ok($res eq 'DisplayString');
+#print("\n");
+############################ 10 ###########################
+$res = $SNMP::MIB{ipAdEntAddr}{syntax};
+ok($res eq 'IPADDR');
+#print("\n");
+########################## 11 ##########################
+$res = $SNMP::MIB{atNetAddress}{syntax};
+#print ("syntax is: $res\n");
+ok($res eq 'NETADDR');
+#print("\n");
+######################## 12 ###############################
+$res = $SNMP::MIB{ipReasmOKs}{syntax};
+#print("syntax is: $res\n");
+ok($res eq 'COUNTER');
+#print("\n");
+###################### 13 ##############################
+$res = $SNMP::MIB{sysDescr}{moduleID};
+#print("Module ID is: $res\n");
+ok(defined($res));
+#print("\n");
+###################### 14 #########################
+$des = $SNMP::MIB{atNetAddress}{description};
+#print("des is --> $des\n");
+ok(defined($des));
+#print("\n");
+
+###################### 15 #########################
+$res = $SNMP::MIB{atNetAddress}{nextNode};
+#print("res is --> $res\n");
+ok(ref($res) eq "HASH");
+#print("\n");
+
+######################## 16 #########################
+$res = $SNMP::MIB{sysDescr}{children};
+#print("res is --> $res\n");
+ok(ref($res) eq "ARRAY");
+#print("\n");
+#################### 17 #########################
+
+$res = $SNMP::MIB{sysDescr}{badField};
+ok(!defined($res));
+
+
+###################### 18 #########################
+$res = $SNMP::MIB{sysDescr}{hint};
+#print("res is --> $res\n");
+#XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+#ok(defined($res) && $res =~ /^255a/);
+#print("\n");
+###################### 19 #########################
+
+$res = $SNMP::MIB{ifPhysAddress}{hint};
+#print("res is --> $res\n");
+#XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+#ok(defined($res) && $res =~ /^1x:/);
+#print("\n");
+
+
+###################### some translate tests #######
+
+##################### 20 #########################
+# Garbage names return Undef.
+
+my $type1 = SNMP::getType($bad_name);
+ok(!defined($type1));
+#printf "%s %d\n", (!defined($type1)) ? "ok" :"not ok", $n++;
+
+######################################################################
+# getType() supports numeric OIDs now
+
+my $type2 = SNMP::getType($oid);
+#XXX: test fails due SMIv1 codes being returned intstead of SMIv2...
+#ok(defined($type2) && $type2 =~ /OCTETSTR/);
+
+######################################################################
+# This tests that sysDescr returns a valid type.
+
+my $type3 = SNMP::getType($name);
+ok(defined($type3));
+
+######################################################################
+# Translation tests from Name -> OID
+# sysDescr to .1.3.6.1.2.1.1.1
+$oid_tag = SNMP::translateObj($name);
+ok($oid eq $oid_tag);
+
+######################################################################
+# Translation tests from Name -> OID
+# RFC1213-MIB::sysDescr to .1.3.6.1.2.1.1.1
+$oid_tag = SNMP::translateObj($name_module);
+ok($oid eq $oid_tag);
+
+######################################################################
+# Translation tests from Name -> OID
+# .iso.org.dod.internet.mgmt.mib-2.system.sysDescr to .1.3.6.1.2.1.1.1
+$oid_tag = SNMP::translateObj($name_long);
+ok($oid eq $oid_tag);
+
+######################################################################
+# bad name returns 'undef'
+$oid_tag = '';
+$oid_tag = SNMP::translateObj($bad_name);
+ok(!defined($oid_tag));
+
+
+######################################################################
+# OID -> name
+# .1.3.6.1.2.1.1.1 to sysDescr
+$name_tag = SNMP::translateObj($oid);
+ok($name eq $name_tag);
+
+######################################################################
+# OID -> name
+# .1.3.6.1.2.1.1.1 to RFC1213-MIB::sysDescr or
+# .1.3.6.1.2.1.1.1 to SNMPv2-MIB::sysDescr
+$name_tag = SNMP::translateObj($oid,0,1);
+$name_module2 = $name_module2; # To eliminate 'only use once' variable warning
+ok(($name_module eq $name_tag) || ($name_module2 eq $name_tag));
+
+######################################################################
+# OID -> name
+# .1.3.6.1.2.1.1.1 to .iso.org.dod.internet.mgmt.mib-2.system.sysDescr
+$name_tag = SNMP::translateObj($oid,1);
+ok($name_long eq $name_tag);
+
+######################################################################
+# OID -> name
+# .1.3.6.1.2.1.1.1 to RFC1213-MIB::.iso.org.dod.internet.mgmt.mib-2.system.sysDescr or
+# .1.3.6.1.2.1.1.1 to SNMPv2-MIB::.iso.org.dod.internet.mgmt.mib-2.system.sysDescr
+$name_module_long = $name_module_long; # To eliminate 'only use once' variable warning
+$name_module_long2 = $name_module_long2; # To eliminate 'only use once' variable warning
+$name_tag = SNMP::translateObj($oid,1,1);
+ok(($name_module_long eq $name_tag) || ($name_module_long2 eq $name_tag));
+
+######################################################################
+# bad OID -> Name
+
+$name_tag = SNMP::translateObj($bad_oid);
+ok($name ne $name_tag);
+#printf "%s %d\n", ($name ne $name_tag) ? "ok" :"not ok", $n++;
+
+
+######################################################################
+# ranges
+
+$node = $SNMP::MIB{snmpTargetAddrMMS};
+ok($node);
+$ranges = $node->{ranges};
+ok($ranges and ref $ranges eq 'ARRAY');
+ok(@$ranges == 2);
+ok($$ranges[0]{low} == 0);
+ok($$ranges[0]{high} == 0);
+ok($$ranges[1]{low} == 484);
+ok($$ranges[1]{high} == 2147483647);
+
+snmptest_cleanup();
diff --git a/perl/SNMP/t/mib.txt b/perl/SNMP/t/mib.txt
new file mode 100644
index 0000000..347a2af
--- /dev/null
+++ b/perl/SNMP/t/mib.txt
@@ -0,0 +1,4208 @@
+RFC1155-SMI DEFINITIONS ::= BEGIN
+ nullOID OBJECT IDENTIFIER ::= { ccitt 0 }
+ internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
+ directory OBJECT IDENTIFIER ::= { internet 1 }
+ mgmt OBJECT IDENTIFIER ::= { internet 2 }
+ experimental OBJECT IDENTIFIER ::= { internet 3 }
+ private OBJECT IDENTIFIER ::= { internet 4 }
+ enterprises OBJECT IDENTIFIER ::= { private 1 }
+END
+
+-- @(#)WSCCS o/mibs-rfc1213.mib 1.1 8/30/95
+-- Changes to rfc1213 (MIB-II):
+-- No changes needed.
+
+
+ RFC1213-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [14];
+
+
+ -- MIB-II (same prefix as MIB-I)
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ -- textual conventions
+
+ DisplayString ::=
+ OCTET STRING
+ -- This data type is used to model textual information taken
+ -- from the NVT ASCII character set. By convention, objects
+ -- with this syntax are declared as having
+ --
+ -- SIZE (0..255)
+
+ PhysAddress ::=
+ OCTET STRING
+ -- This data type is used to model media addresses. For many
+ -- types of media, this will be in a binary representation.
+ -- For example, an ethernet address would be represented as
+ -- a string of 6 octets.
+
+
+ -- groups in MIB-II
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+ interfaces OBJECT IDENTIFIER ::= { mib-2 2 }
+
+ at OBJECT IDENTIFIER ::= { mib-2 3 }
+
+ ip OBJECT IDENTIFIER ::= { mib-2 4 }
+
+ icmp OBJECT IDENTIFIER ::= { mib-2 5 }
+
+ tcp OBJECT IDENTIFIER ::= { mib-2 6 }
+
+ udp OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ egp OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ -- historical (some say hysterical)
+ -- cmot OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+ -- the Interfaces group
+
+ -- Implementation of the Interfaces group is mandatory for
+ -- all systems.
+
+ ifNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of network interfaces (regardless of
+ their current state) present on this system."
+ ::= { interfaces 1 }
+
+
+ -- the Interfaces table
+
+ -- The Interfaces table contains information on the entity's
+ -- interfaces. Each interface is thought of as being
+ -- attached to a `subnetwork'. Note that this term should
+ -- not be confused with `subnet' which refers to an
+ -- addressing partitioning scheme used in the Internet suite
+ -- of protocols.
+
+ ifTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of interface entries. The number of
+ entries is given by the value of ifNumber."
+ ::= { interfaces 2 }
+
+ ifEntry OBJECT-TYPE
+ SYNTAX IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An interface entry containing objects at the
+ subnetwork layer and below for a particular
+ interface."
+ INDEX { ifIndex }
+ ::= { ifTable 1 }
+
+ IfEntry ::=
+ SEQUENCE {
+ ifIndex
+ INTEGER,
+ ifDescr
+ DisplayString,
+ ifType
+ INTEGER,
+ ifMtu
+ INTEGER,
+ ifSpeed
+ Gauge,
+ ifPhysAddress
+ PhysAddress,
+ ifAdminStatus
+ INTEGER,
+ ifOperStatus
+ INTEGER,
+ ifLastChange
+ TimeTicks,
+ ifInOctets
+ Counter,
+ ifInUcastPkts
+ Counter,
+ ifInNUcastPkts
+ Counter,
+ ifInDiscards
+ Counter,
+ ifInErrors
+ Counter,
+ ifInUnknownProtos
+ Counter,
+ ifOutOctets
+ Counter,
+ ifOutUcastPkts
+ Counter,
+ ifOutNUcastPkts
+ Counter,
+ ifOutDiscards
+ Counter,
+ ifOutErrors
+ Counter,
+ ifOutQLen
+ Gauge,
+ ifSpecific
+ OBJECT IDENTIFIER
+ }
+
+ ifIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each interface. Its value
+ ranges between 1 and the value of ifNumber. The
+ value for each interface must remain constant at
+ least from one re-initialization of the entity's
+ network management system to the next re-
+ initialization."
+ ::= { ifEntry 1 }
+
+ ifDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual string containing information about the
+ interface. This string should include the name of
+ the manufacturer, the product name and the version
+ of the hardware interface."
+ ::= { ifEntry 2 }
+
+ ifType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ regular1822(2),
+ hdh1822(3),
+ ddn-x25(4),
+ rfc877-x25(5),
+ ethernet-csmacd(6),
+ iso88023-csmacd(7),
+ iso88024-tokenBus(8),
+ iso88025-tokenRing(9),
+ iso88026-man(10),
+ starLan(11),
+ proteon-10Mbit(12),
+ proteon-80Mbit(13),
+ hyperchannel(14),
+ fddi(15),
+ lapb(16),
+ sdlc(17),
+ ds1(18), -- T-1
+ e1(19), -- european equiv. of T-1
+ basicISDN(20),
+ primaryISDN(21), -- proprietary serial
+ propPointToPointSerial(22),
+ ppp(23),
+ softwareLoopback(24),
+ eon(25), -- CLNP over IP [11]
+ ethernet-3Mbit(26),
+ nsip(27), -- XNS over IP
+ slip(28), -- generic SLIP
+ ultra(29), -- ULTRA technologies
+ ds3(30), -- T-3
+ sip(31), -- SMDS
+ frame-relay(32)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The type of interface, distinguished according to
+ the physical/link protocol(s) immediately `below'
+ the network layer in the protocol stack."
+ ::= { ifEntry 3 }
+
+ ifMtu OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest datagram which can be
+ sent/received on the interface, specified in
+ octets. For interfaces that are used for
+ transmitting network datagrams, this is the size
+ of the largest network datagram that can be sent
+ on the interface."
+ ::= { ifEntry 4 }
+
+ ifSpeed OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An estimate of the interface's current bandwidth
+ in bits per second. For interfaces which do not
+ vary in bandwidth or for those where no accurate
+ estimation can be made, this object should contain
+ the nominal bandwidth."
+ ::= { ifEntry 5 }
+
+ ifPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interface's address at the protocol layer
+ immediately `below' the network layer in the
+ protocol stack. For interfaces which do not have
+ such an address (e.g., a serial line), this object
+ should contain an octet string of zero length."
+ ::= { ifEntry 6 }
+
+ ifAdminStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The desired state of the interface. The
+ testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 7 }
+
+ ifOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the interface.
+ The testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 8 }
+
+ ifLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the interface
+ entered its current operational state. If the
+ current state was entered prior to the last re-
+ initialization of the local network management
+ subsystem, then this object contains a zero
+ value."
+ ::= { ifEntry 9 }
+
+ ifInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets received on the
+ interface, including framing characters."
+ ::= { ifEntry 10 }
+
+ ifInUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of subnetwork-unicast packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 11 }
+
+ ifInNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of non-unicast (i.e., subnetwork-
+ broadcast or subnetwork-multicast) packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 12 }
+
+ ifInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being deliverable to a
+ higher-layer protocol. One possible reason for
+ discarding such a packet could be to free up
+ buffer space."
+ ::= { ifEntry 13 }
+
+ ifInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets that contained
+ errors preventing them from being deliverable to a
+ higher-layer protocol."
+ ::= { ifEntry 14 }
+ ifInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received via the interface
+ which were discarded because of an unknown or
+ unsupported protocol."
+ ::= { ifEntry 15 }
+
+ ifOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets transmitted out of the
+ interface, including framing characters."
+ ::= { ifEntry 16 }
+
+ ifOutUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a
+ subnetwork-unicast address, including those that
+ were discarded or not sent."
+ ::= { ifEntry 17 }
+
+ ifOutNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a non-
+ unicast (i.e., a subnetwork-broadcast or
+ subnetwork-multicast) address, including those
+ that were discarded or not sent."
+ ::= { ifEntry 18 }
+
+ ifOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being transmitted. One
+ possible reason for discarding such a packet could
+ be to free up buffer space."
+ ::= { ifEntry 19 }
+
+ ifOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets that could not be
+ transmitted because of errors."
+ ::= { ifEntry 20 }
+
+ ifOutQLen OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The length of the output packet queue (in
+ packets)."
+ ::= { ifEntry 21 }
+
+ ifSpecific OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular media being used to realize the
+ interface. For example, if the interface is
+ realized by an ethernet, then the value of this
+ object refers to a document defining objects
+ specific to ethernet. If this information is not
+ present, its value should be set to the OBJECT
+ IDENTIFIER { 0 0 }, which is a syntatically valid
+ object identifier, and any conformant
+ implementation of ASN.1 and BER must be able to
+ generate and recognize this value."
+ ::= { ifEntry 22 }
+
+
+ -- the Address Translation group
+
+ -- Implementation of the Address Translation group is
+ -- mandatory for all systems. Note however that this group
+ -- is deprecated by MIB-II. That is, it is being included
+ -- solely for compatibility with MIB-I nodes, and will most
+ -- likely be excluded from MIB-III nodes. From MIB-II and
+ -- onwards, each network protocol group contains its own
+ -- address translation tables.
+
+ -- The Address Translation group contains one table which is
+ -- the union across all interfaces of the translation tables
+ -- for converting a NetworkAddress (e.g., an IP address) into
+ -- a subnetwork-specific address. For lack of a better term,
+ -- this document refers to such a subnetwork-specific address
+ -- as a `physical' address.
+
+ -- Examples of such translation tables are: for broadcast
+ -- media where ARP is in use, the translation table is
+ -- equivalent to the ARP cache; or, on an X.25 network where
+ -- non-algorithmic translation to X.121 addresses is
+ -- required, the translation table contains the
+ -- NetworkAddress to X.121 address equivalences.
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The Address Translation tables contain the
+ NetworkAddress to `physical' address equivalences.
+ Some interfaces do not use translation tables for
+ determining address equivalences (e.g., DDN-X.25
+ has an algorithmic method); if all interfaces are
+ of this type, then the Address Translation table
+ is empty, i.e., has zero entries."
+ ::= { at 1 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "Each entry contains one NetworkAddress to
+ `physical' address equivalence."
+ INDEX { atIfIndex,
+ atNetAddress }
+ ::= { atTable 1 }
+
+ AtEntry ::=
+ SEQUENCE {
+ atIfIndex
+ INTEGER,
+ atPhysAddress
+ PhysAddress,
+ atNetAddress
+ NetworkAddress
+ }
+
+ atIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The media-dependent `physical' address.
+
+ Setting this object to a null string (one of zero
+ length) has the effect of invaliding the
+ corresponding entry in the atTable object. That
+ is, it effectively dissasociates the interface
+ identified with said entry from the mapping
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant atPhysAddress object."
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The NetworkAddress (e.g., the IP address)
+ corresponding to the media-dependent `physical'
+ address."
+ ::= { atEntry 3 }
+
+
+ -- the IP group
+
+ -- Implementation of the IP group is mandatory for all
+ -- systems.
+
+ ipForwarding OBJECT-TYPE
+ SYNTAX INTEGER {
+ forwarding(1), -- acting as a gateway
+ not-forwarding(2) -- NOT acting as a gateway
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The indication of whether this entity is acting
+ as an IP gateway in respect to the forwarding of
+ datagrams received by, but not addressed to, this
+ entity. IP gateways forward datagrams. IP hosts
+ do not (except those source-routed via the host).
+
+ Note that for some managed nodes, this object may
+ take on only a subset of the values possible.
+ Accordingly, it is appropriate for an agent to
+ return a `badValue' response if a management
+ station attempts to change this object to an
+ inappropriate value."
+ ::= { ip 1 }
+
+ ipDefaultTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The default value inserted into the Time-To-Live
+ field of the IP header of datagrams originated at
+ this entity, whenever a TTL value is not supplied
+ by the transport layer protocol."
+ ::= { ip 2 }
+
+ ipInReceives OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams received from
+ interfaces, including those received in error."
+ ::= { ip 3 }
+
+ ipInHdrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded due to
+ errors in their IP headers, including bad
+ checksums, version number mismatch, other format
+ errors, time-to-live exceeded, errors discovered
+ in processing their IP options, etc."
+ ::= { ip 4 }
+
+ ipInAddrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded because
+ the IP address in their IP header's destination
+ field was not a valid address to be received at
+ this entity. This count includes invalid
+ addresses (e.g., 0.0.0.0) and addresses of
+ unsupported Classes (e.g., Class E). For entities
+ which are not IP Gateways and therefore do not
+ forward datagrams, this counter includes datagrams
+ discarded because the destination address was not
+ a local address."
+ ::= { ip 5 }
+
+ ipForwDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams for which this
+ entity was not their final IP destination, as a
+ result of which an attempt was made to find a
+ route to forward them to that final destination.
+ In entities which do not act as IP Gateways, this
+ counter will include only those packets which were
+ Source-Routed via this entity, and the Source-
+ Route option processing was successful."
+ ::= { ip 6 }
+
+ ipInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally-addressed datagrams
+ received successfully but discarded because of an
+ unknown or unsupported protocol."
+ ::= { ip 7 }
+
+ ipInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input IP datagrams for which no
+ problems were encountered to prevent their
+ continued processing, but which were discarded
+ (e.g., for lack of buffer space). Note that this
+ counter does not include any datagrams discarded
+ while awaiting re-assembly."
+ ::= { ip 8 }
+
+ ipInDelivers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams successfully
+ delivered to IP user-protocols (including ICMP)."
+ ::= { ip 9 }
+
+ ipOutRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of IP datagrams which local IP
+ user-protocols (including ICMP) supplied to IP in
+ requests for transmission. Note that this counter
+ does not include any datagrams counted in
+ ipForwDatagrams."
+ ::= { ip 10 }
+
+ ipOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of output IP datagrams for which no
+ problem was encountered to prevent their
+ transmission to their destination, but which were
+ discarded (e.g., for lack of buffer space). Note
+ that this counter would include datagrams counted
+ in ipForwDatagrams if any such packets met this
+ (discretionary) discard criterion."
+ ::= { ip 11 }
+
+ ipOutNoRoutes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams discarded because no
+ route could be found to transmit them to their
+ destination. Note that this counter includes any
+ packets counted in ipForwDatagrams which meet this
+ `no-route' criterion. Note that this includes any
+ datagarms which a host cannot route because all of
+ its default gateways are down."
+ ::= { ip 12 }
+
+ ipReasmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of seconds which received
+ fragments are held while they are awaiting
+ reassembly at this entity."
+ ::= { ip 13 }
+
+ ipReasmReqds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP fragments received which needed
+ to be reassembled at this entity."
+ ::= { ip 14 }
+
+ ipReasmOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams successfully re-
+ assembled."
+ ::= { ip 15 }
+
+ ipReasmFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of failures detected by the IP re-
+ assembly algorithm (for whatever reason: timed
+ out, errors, etc). Note that this is not
+ necessarily a count of discarded IP fragments
+ since some algorithms (notably the algorithm in
+ RFC 815) can lose track of the number of fragments
+ by combining them as they are received."
+ ::= { ip 16 }
+
+ ipFragOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ successfully fragmented at this entity."
+ ::= { ip 17 }
+
+ ipFragFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ discarded because they needed to be fragmented at
+ this entity but could not be, e.g., because their
+ Don't Fragment flag was set."
+ ::= { ip 18 }
+
+ ipFragCreates OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagram fragments that have
+ been generated as a result of fragmentation at
+ this entity."
+ ::= { ip 19 }
+
+ -- the IP address table
+
+ -- The IP address table contains this entity's IP addressing
+ -- information.
+
+ ipAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The table of addressing information relevant to
+ this entity's IP addresses."
+ ::= { ip 20 }
+
+ ipAddrEntry OBJECT-TYPE
+ SYNTAX IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The addressing information for one of this
+ entity's IP addresses."
+ INDEX { ipAdEntAddr }
+ ::= { ipAddrTable 1 }
+
+ IpAddrEntry ::=
+ SEQUENCE {
+ ipAdEntAddr
+ IpAddress,
+ ipAdEntIfIndex
+ INTEGER,
+ ipAdEntNetMask
+ IpAddress,
+ ipAdEntBcastAddr
+ INTEGER,
+ ipAdEntReasmMaxSize
+ INTEGER (0..65535)
+ }
+
+ ipAdEntAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address to which this entry's addressing
+ information pertains."
+ ::= { ipAddrEntry 1 }
+
+ ipAdEntIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ interface to which this entry is applicable. The
+ interface identified by a particular value of this
+ index is the same interface as identified by the
+ same value of ifIndex."
+ ::= { ipAddrEntry 2 }
+
+ ipAdEntNetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The subnet mask associated with the IP address of
+ this entry. The value of the mask is an IP
+ address with all the network bits set to 1 and all
+ the hosts bits set to 0."
+ ::= { ipAddrEntry 3 }
+
+ ipAdEntBcastAddr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the least-significant bit in the IP
+ broadcast address used for sending datagrams on
+ the (logical) interface associated with the IP
+ address of this entry. For example, when the
+ Internet standard all-ones broadcast address is
+ used, the value will be 1. This value applies to
+ both the subnet and network broadcasts addresses
+ used by the entity on this (logical) interface."
+ ::= { ipAddrEntry 4 }
+
+ ipAdEntReasmMaxSize OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest IP datagram which this
+ entity can re-assemble from incoming IP fragmented
+ datagrams received on this interface."
+ ::= { ipAddrEntry 5 }
+
+ -- the IP routing table
+
+ -- The IP routing table contains an entry for each route
+ -- presently known to this entity.
+
+ ipRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entity's IP Routing table."
+ ::= { ip 21 }
+
+ ipRouteEntry OBJECT-TYPE
+ SYNTAX IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A route to a particular destination."
+ INDEX { ipRouteDest }
+ ::= { ipRouteTable 1 }
+
+ IpRouteEntry ::=
+ SEQUENCE {
+ ipRouteDest
+ IpAddress,
+ ipRouteIfIndex
+ INTEGER,
+ ipRouteMetric1
+ INTEGER,
+ ipRouteMetric2
+ INTEGER,
+ ipRouteMetric3
+ INTEGER,
+ ipRouteMetric4
+ INTEGER,
+ ipRouteNextHop
+ IpAddress,
+ ipRouteType
+ INTEGER,
+ ipRouteProto
+ INTEGER,
+ ipRouteAge
+ INTEGER,
+ ipRouteMask
+ IpAddress,
+ ipRouteMetric5
+ INTEGER,
+ ipRouteInfo
+ OBJECT IDENTIFIER
+ }
+
+ ipRouteDest OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The destination IP address of this route. An
+ entry with a value of 0.0.0.0 is considered a
+ default route. Multiple routes to a single
+ destination can appear in the table, but access to
+ such multiple entries is dependent on the table-
+ access mechanisms defined by the network
+ management protocol in use."
+ ::= { ipRouteEntry 1 }
+
+ ipRouteIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ local interface through which the next hop of this
+ route should be reached. The interface identified
+ by a particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipRouteEntry 2 }
+
+ ipRouteMetric1 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The primary routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 3 }
+
+ ipRouteMetric2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 4 }
+
+ ipRouteMetric3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 5 }
+
+ ipRouteMetric4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 6 }
+
+ ipRouteNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of the next hop of this route.
+ (In the case of a route bound to an interface
+ which is realized via a broadcast media, the value
+ of this field is the agent's IP address on that
+ interface.)"
+ ::= { ipRouteEntry 7 }
+
+ ipRouteType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ invalid(2), -- an invalidated route
+ -- route to directly
+
+ direct(3), -- connected (sub-)network
+
+ -- route to a non-local
+ indirect(4) -- host/network/sub-network
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of route. Note that the values
+ direct(3) and indirect(4) refer to the notion of
+ direct and indirect routing in the IP
+ architecture.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipRouteTable object. That is, it
+ effectively dissasociates the destination
+ identified with said entry from the route
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant ipRouteType object."
+ ::= { ipRouteEntry 8 }
+
+ ipRouteProto OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ -- non-protocol information,
+ -- e.g., manually configured
+ local(2), -- entries
+
+ -- set via a network
+ netmgmt(3), -- management protocol
+
+ -- obtained via ICMP,
+ icmp(4), -- e.g., Redirect
+
+ -- the remaining values are
+ -- all gateway routing
+ -- protocols
+ egp(5),
+ ggp(6),
+ hello(7),
+ rip(8),
+ is-is(9),
+ es-is(10),
+ ciscoIgrp(11),
+ bbnSpfIgp(12),
+ ospf(13),
+ bgp(14)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The routing mechanism via which this route was
+ learned. Inclusion of values for gateway routing
+ protocols is not intended to imply that hosts
+ should support those protocols."
+ ::= { ipRouteEntry 9 }
+
+ ipRouteAge OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds since this route was last
+ updated or otherwise determined to be correct.
+ Note that no semantics of `too old' can be implied
+ except through knowledge of the routing protocol
+ by which the route was learned."
+ ::= { ipRouteEntry 10 }
+
+ ipRouteMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicate the mask to be logical-ANDed with the
+ destination address before being compared to the
+ value in the ipRouteDest field. For those systems
+ that do not support arbitrary subnet masks, an
+ agent constructs the value of the ipRouteMask by
+ determining whether the value of the correspondent
+ ipRouteDest field belong to a class-A, B, or C
+ network, and then using one of:
+
+ mask network
+ 255.0.0.0 class-A
+ 255.255.0.0 class-B
+ 255.255.255.0 class-C
+
+ If the value of the ipRouteDest is 0.0.0.0 (a
+ default route), then the mask value is also
+ 0.0.0.0. It should be noted that all IP routing
+ subsystems implicitly use this mechanism."
+ ::= { ipRouteEntry 11 }
+
+ ipRouteMetric5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 12 }
+
+ ipRouteInfo OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular routing protocol which is responsible
+ for this route, as determined by the value
+ specified in the route's ipRouteProto value. If
+ this information is not present, its value should
+ be set to the OBJECT IDENTIFIER { 0 0 }, which is
+ a syntatically valid object identifier, and any
+ conformant implementation of ASN.1 and BER must be
+ able to generate and recognize this value."
+ ::= { ipRouteEntry 13 }
+
+
+ -- the IP Address Translation table
+
+ -- The IP address translation table contain the IpAddress to
+ -- `physical' address equivalences. Some interfaces do not
+ -- use translation tables for determining address
+ -- equivalences (e.g., DDN-X.25 has an algorithmic method);
+ -- if all interfaces are of this type, then the Address
+ -- Translation table is empty, i.e., has zero entries.
+
+ ipNetToMediaTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The IP Address Translation table used for mapping
+ from IP addresses to physical addresses."
+ ::= { ip 22 }
+
+ ipNetToMediaEntry OBJECT-TYPE
+ SYNTAX IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Each entry contains one IpAddress to `physical'
+ address equivalence."
+ INDEX { ipNetToMediaIfIndex,
+ ipNetToMediaNetAddress }
+ ::= { ipNetToMediaTable 1 }
+
+ IpNetToMediaEntry ::=
+ SEQUENCE {
+ ipNetToMediaIfIndex
+ INTEGER,
+ ipNetToMediaPhysAddress
+ PhysAddress,
+ ipNetToMediaNetAddress
+ IpAddress,
+ ipNetToMediaType
+ INTEGER
+ }
+
+ ipNetToMediaIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipNetToMediaEntry 1 }
+
+ ipNetToMediaPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The media-dependent `physical' address."
+ ::= { ipNetToMediaEntry 2 }
+
+ ipNetToMediaNetAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IpAddress corresponding to the media-
+ dependent `physical' address."
+ ::= { ipNetToMediaEntry 3 }
+
+ ipNetToMediaType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ invalid(2), -- an invalidated mapping
+ dynamic(3),
+ static(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of mapping.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipNetToMediaTable. That is, it effectively
+ dissasociates the interface identified with said
+ entry from the mapping identified with said entry.
+ It is an implementation-specific matter as to
+ whether the agent removes an invalidated entry
+ from the table. Accordingly, management stations
+ must be prepared to receive tabular information
+ from agents that corresponds to entries not
+ currently in use. Proper interpretation of such
+ entries requires examination of the relevant
+ ipNetToMediaType object."
+ ::= { ipNetToMediaEntry 4 }
+
+
+ -- additional IP objects
+
+ ipRoutingDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of routing entries which were chosen
+ to be discarded even though they are valid. One
+ possible reason for discarding such an entry could
+ be to free-up buffer space for other routing
+ entries."
+ ::= { ip 23 }
+
+
+ -- the ICMP group
+
+ -- Implementation of the ICMP group is mandatory for all
+ -- systems.
+
+ icmpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which the
+ entity received. Note that this counter includes
+ all those counted by icmpInErrors."
+ ::= { icmp 1 }
+
+ icmpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which the entity
+ received but determined as having ICMP-specific
+ errors (bad ICMP checksums, bad length, etc.)."
+ ::= { icmp 2 }
+
+ icmpInDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages received."
+ ::= { icmp 3 }
+
+ icmpInTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages
+ received."
+ ::= { icmp 4 }
+
+ icmpInParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ received."
+ ::= { icmp 5 }
+
+ icmpInSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages
+ received."
+ ::= { icmp 6 }
+
+ icmpInRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages received."
+ ::= { icmp 7 }
+
+ icmpInEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages
+ received."
+ ::= { icmp 8 }
+
+ icmpInEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages received."
+ ::= { icmp 9 }
+
+ icmpInTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ received."
+ ::= { icmp 10 }
+
+ icmpInTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ received."
+ ::= { icmp 11 }
+
+ icmpInAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ received."
+ ::= { icmp 12 }
+
+ icmpInAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ received."
+ ::= { icmp 13 }
+
+ icmpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which this
+ entity attempted to send. Note that this counter
+ includes all those counted by icmpOutErrors."
+ ::= { icmp 14 }
+
+ icmpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which this entity did
+ not send due to problems discovered within ICMP
+ such as a lack of buffers. This value should not
+ include errors discovered outside the ICMP layer
+ such as the inability of IP to route the resultant
+ datagram. In some implementations there may be no
+ types of error which contribute to this counter's
+ value."
+ ::= { icmp 15 }
+
+ icmpOutDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages sent."
+ ::= { icmp 16 }
+
+ icmpOutTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages sent."
+ ::= { icmp 17 }
+
+ icmpOutParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ sent."
+ ::= { icmp 18 }
+
+ icmpOutSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages sent."
+ ::= { icmp 19 }
+
+ icmpOutRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages sent. For a
+ host, this object will always be zero, since hosts
+ do not send redirects."
+ ::= { icmp 20 }
+
+ icmpOutEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages sent."
+ ::= { icmp 21 }
+
+ icmpOutEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages sent."
+ ::= { icmp 22 }
+
+ icmpOutTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ sent."
+ ::= { icmp 23 }
+
+ icmpOutTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ sent."
+ ::= { icmp 24 }
+
+ icmpOutAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ sent."
+ ::= { icmp 25 }
+
+ icmpOutAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ sent."
+ ::= { icmp 26 }
+
+
+ -- the TCP group
+
+ -- Implementation of the TCP group is mandatory for all
+ -- systems that implement the TCP.
+
+ -- Note that instances of object types that represent
+ -- information about a particular TCP connection are
+ -- transient; they persist only as long as the connection
+ -- in question.
+
+ tcpRtoAlgorithm OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ constant(2), -- a constant rto
+ rsre(3), -- MIL-STD-1778, Appendix B
+ vanj(4) -- Van Jacobson's algorithm [10]
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The algorithm used to determine the timeout value
+ used for retransmitting unacknowledged octets."
+ ::= { tcp 1 }
+
+ tcpRtoMin OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The minimum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ LBOUND quantity described in RFC 793."
+ ::= { tcp 2 }
+
+
+ tcpRtoMax OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ UBOUND quantity described in RFC 793."
+ ::= { tcp 3 }
+
+ tcpMaxConn OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The limit on the total number of TCP connections
+ the entity can support. In entities where the
+ maximum number of connections is dynamic, this
+ object should contain the value -1."
+ ::= { tcp 4 }
+
+ tcpActiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-SENT state from the
+ CLOSED state."
+ ::= { tcp 5 }
+
+ tcpPassiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-RCVD state from the
+ LISTEN state."
+ ::= { tcp 6 }
+
+ tcpAttemptFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the SYN-SENT state or the SYN-RCVD state, plus the
+ number of times TCP connections have made a direct
+ transition to the LISTEN state from the SYN-RCVD
+ state."
+ ::= { tcp 7 }
+
+ tcpEstabResets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the ESTABLISHED state or the CLOSE-WAIT state."
+ ::= { tcp 8 }
+
+ tcpCurrEstab OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP connections for which the
+ current state is either ESTABLISHED or CLOSE-
+ WAIT."
+ ::= { tcp 9 }
+
+ tcpInSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received, including
+ those received in error. This count includes
+ segments received on currently established
+ connections."
+ ::= { tcp 10 }
+
+ tcpOutSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments sent, including
+ those on current connections but excluding those
+ containing only retransmitted octets."
+ ::= { tcp 11 }
+
+ tcpRetransSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments retransmitted - that
+ is, the number of TCP segments transmitted
+ containing one or more previously transmitted
+ octets."
+ ::= { tcp 12 }
+
+
+ -- the TCP Connection table
+
+ -- The TCP connection table contains information about this
+ -- entity's existing TCP connections.
+
+ tcpConnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing TCP connection-specific
+ information."
+ ::= { tcp 13 }
+
+ tcpConnEntry OBJECT-TYPE
+ SYNTAX TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current TCP
+ connection. An object of this type is transient,
+ in that it ceases to exist when (or soon after)
+ the connection makes the transition to the CLOSED
+ state."
+ INDEX { tcpConnLocalAddress,
+ tcpConnLocalPort,
+ tcpConnRemAddress,
+ tcpConnRemPort }
+ ::= { tcpConnTable 1 }
+
+ TcpConnEntry ::=
+ SEQUENCE {
+ tcpConnState
+ INTEGER,
+ tcpConnLocalAddress
+ IpAddress,
+ tcpConnLocalPort
+ INTEGER (0..65535),
+ tcpConnRemAddress
+ IpAddress,
+ tcpConnRemPort
+ INTEGER (0..65535)
+ }
+
+ tcpConnState OBJECT-TYPE
+ SYNTAX INTEGER {
+ closed(1),
+ listen(2),
+ synSent(3),
+ synReceived(4),
+ established(5),
+ finWait1(6),
+ finWait2(7),
+ closeWait(8),
+ lastAck(9),
+ closing(10),
+ timeWait(11),
+ deleteTCB(12)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The state of this TCP connection.
+
+ The only value which may be set by a management
+ station is deleteTCB(12). Accordingly, it is
+ appropriate for an agent to return a `badValue'
+ response if a management station attempts to set
+ this object to any other value.
+
+ If a management station sets this object to the
+ value deleteTCB(12), then this has the effect of
+ deleting the TCB (as defined in RFC 793) of the
+ corresponding connection on the managed node,
+ resulting in immediate termination of the
+ connection.
+
+ As an implementation-specific option, a RST
+ segment may be sent from the managed node to the
+ other TCP endpoint (note however that RST segments
+ are not sent reliably)."
+ ::= { tcpConnEntry 1 }
+
+ tcpConnLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this TCP connection. In
+ the case of a connection in the listen state which
+ is willing to accept connections for any IP
+ interface associated with the node, the value
+ 0.0.0.0 is used."
+ ::= { tcpConnEntry 2 }
+
+ tcpConnLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this TCP connection."
+ ::= { tcpConnEntry 3 }
+
+ tcpConnRemAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote IP address for this TCP connection."
+ ::= { tcpConnEntry 4 }
+
+ tcpConnRemPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote port number for this TCP connection."
+ ::= { tcpConnEntry 5 }
+
+
+ -- additional TCP objects
+
+ tcpInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received in error
+ (e.g., bad TCP checksums)."
+ ::= { tcp 14 }
+
+ tcpOutRsts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP segments sent containing the
+ RST flag."
+ ::= { tcp 15 }
+
+
+ -- the UDP group
+
+ -- Implementation of the UDP group is mandatory for all
+ -- systems which implement the UDP.
+
+ udpInDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams delivered to
+ UDP users."
+ ::= { udp 1 }
+
+ udpNoPorts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of received UDP datagrams for
+ which there was no application at the destination
+ port."
+ ::= { udp 2 }
+
+ udpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of received UDP datagrams that could
+ not be delivered for reasons other than the lack
+ of an application at the destination port."
+ ::= { udp 3 }
+
+ udpOutDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams sent from this
+ entity."
+ ::= { udp 4 }
+
+
+ -- the UDP Listener table
+
+ -- The UDP listener table contains information about this
+ -- entity's UDP end-points on which a local application is
+ -- currently accepting datagrams.
+
+ udpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing UDP listener information."
+ ::= { udp 5 }
+
+ udpEntry OBJECT-TYPE
+ SYNTAX UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current UDP
+ listener."
+ INDEX { udpLocalAddress, udpLocalPort }
+ ::= { udpTable 1 }
+
+ UdpEntry ::=
+ SEQUENCE {
+ udpLocalAddress
+ IpAddress,
+ udpLocalPort
+ INTEGER (0..65535)
+ }
+
+ udpLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this UDP listener. In
+ the case of a UDP listener which is willing to
+ accept datagrams for any IP interface associated
+ with the node, the value 0.0.0.0 is used."
+ ::= { udpEntry 1 }
+
+ udpLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this UDP listener."
+ ::= { udpEntry 2 }
+
+
+ -- the EGP group
+
+ -- Implementation of the EGP group is mandatory for all
+ -- systems which implement the EGP.
+
+ egpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without
+ error."
+ ::= { egp 1 }
+
+ egpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received that proved
+ to be in error."
+ ::= { egp 2 }
+
+ egpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of locally generated EGP
+ messages."
+ ::= { egp 3 }
+
+ egpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent due to resource limitations within an EGP
+ entity."
+ ::= { egp 4 }
+
+
+ -- the EGP Neighbor table
+
+ -- The EGP neighbor table contains information about this
+ -- entity's EGP neighbors.
+
+ egpNeighTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP neighbor table."
+ ::= { egp 5 }
+
+ egpNeighEntry OBJECT-TYPE
+ SYNTAX EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about this entity's relationship with
+ a particular EGP neighbor."
+ INDEX { egpNeighAddr }
+ ::= { egpNeighTable 1 }
+
+ EgpNeighEntry ::=
+ SEQUENCE {
+ egpNeighState
+ INTEGER,
+ egpNeighAddr
+ IpAddress,
+ egpNeighAs
+ INTEGER,
+ egpNeighInMsgs
+ Counter,
+ egpNeighInErrs
+ Counter,
+ egpNeighOutMsgs
+ Counter,
+ egpNeighOutErrs
+ Counter,
+ egpNeighInErrMsgs
+ Counter,
+ egpNeighOutErrMsgs
+ Counter,
+ egpNeighStateUps
+ Counter,
+ egpNeighStateDowns
+ Counter,
+ egpNeighIntervalHello
+ INTEGER,
+ egpNeighIntervalPoll
+ INTEGER,
+ egpNeighMode
+ INTEGER,
+ egpNeighEventTrigger
+ INTEGER
+ }
+
+ egpNeighState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ acquisition(2),
+ down(3),
+ up(4),
+ cease(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP state of the local system with respect to
+ this entry's EGP neighbor. Each EGP state is
+ represented by a value that is one greater than
+ the numerical value associated with said state in
+ RFC 904."
+ ::= { egpNeighEntry 1 }
+
+ egpNeighAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this entry's EGP neighbor."
+ ::= { egpNeighEntry 2 }
+
+ egpNeighAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system of this EGP peer. Zero
+ should be specified if the autonomous system
+ number of the neighbor is not yet known."
+ ::= { egpNeighEntry 3 }
+
+ egpNeighInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without error
+ from this EGP peer."
+ ::= { egpNeighEntry 4 }
+
+ egpNeighInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received from this EGP
+ peer that proved to be in error (e.g., bad EGP
+ checksum)."
+ ::= { egpNeighEntry 5 }
+
+ egpNeighOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages to
+ this EGP peer."
+ ::= { egpNeighEntry 6 }
+
+ egpNeighOutErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent to this EGP peer due to resource limitations
+ within an EGP entity."
+ ::= { egpNeighEntry 7 }
+
+ egpNeighInErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages received
+ from this EGP peer."
+ ::= { egpNeighEntry 8 }
+
+ egpNeighOutErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages sent to
+ this EGP peer."
+ ::= { egpNeighEntry 9 }
+
+ egpNeighStateUps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions to the UP
+ state with this EGP peer."
+ ::= { egpNeighEntry 10 }
+
+ egpNeighStateDowns OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions from the UP
+ state to any other state with this EGP peer."
+ ::= { egpNeighEntry 11 }
+
+ egpNeighIntervalHello OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP Hello command
+ retransmissions (in hundredths of a second). This
+ represents the t1 timer as defined in RFC 904."
+ ::= { egpNeighEntry 12 }
+
+ egpNeighIntervalPoll OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP poll command
+ retransmissions (in hundredths of a second). This
+ represents the t3 timer as defined in RFC 904."
+ ::= { egpNeighEntry 13 }
+
+ egpNeighMode OBJECT-TYPE
+ SYNTAX INTEGER { active(1), passive(2) }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The polling mode of this EGP entity, either
+ passive or active."
+ ::= { egpNeighEntry 14 }
+
+ egpNeighEventTrigger OBJECT-TYPE
+ SYNTAX INTEGER { start(1), stop(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A control variable used to trigger operator-
+ initiated Start and Stop events. When read, this
+ variable always returns the most recent value that
+ egpNeighEventTrigger was set to. If it has not
+ been set since the last initialization of the
+ network management subsystem on the node, it
+ returns a value of `stop'.
+
+ When set, this variable causes a Start or Stop
+ event on the specified neighbor, as specified on
+ pages 8-10 of RFC 904. Briefly, a Start event
+ causes an Idle peer to begin neighbor acquisition
+ and a non-Idle peer to reinitiate neighbor
+ acquisition. A stop event causes a non-Idle peer
+ to return to the Idle state until a Start event
+ occurs, either via egpNeighEventTrigger or
+ otherwise."
+ ::= { egpNeighEntry 15 }
+
+
+ -- additional EGP objects
+
+ egpAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system number of this EGP entity."
+ ::= { egp 6 }
+
+
+ -- the Transmission group
+
+ -- Based on the transmission media underlying each interface
+ -- on a system, the corresponding portion of the Transmission
+ -- group is mandatory for that system.
+
+ -- When Internet-standard definitions for managing
+ -- transmission media are defined, the transmission group is
+ -- used to provide a prefix for the names of those objects.
+
+ -- Typically, such definitions reside in the experimental
+ -- portion of the MIB until they are "proven", then as a
+ -- part of the Internet standardization process, the
+ -- definitions are accordingly elevated and a new object
+ -- identifier, under the transmission group is defined. By
+ -- convention, the name assigned is:
+ --
+ -- type OBJECT IDENTIFIER ::= { transmission number }
+ --
+ -- where "type" is the symbolic value used for the media in
+ -- the ifType column of the ifTable object, and "number" is
+ -- the actual integer value corresponding to the symbol.
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+ -- { snmp 7 } is not used in rfc1213, but MIBII.mdl had one :(
+ snmpInBadTypes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Total number of PDUs having an unknown PDU type"
+ ::= { snmp 7 }
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used in rfc1213, but MIBII.mdl had one :(
+ snmpOutReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'."
+ ::= { snmp 23 }
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+ ::= { snmp 30 }
+
+ END
+-- @(#)WSCCS g/mibs-wfcommon.mib 1.4 10/26/95
+Wellfleet-COMMON-MIB
+
+DEFINITIONS ::= BEGIN
+
+IMPORTS
+
+ enterprises
+ FROM RFC1155-SMI;
+
+wellfleet OBJECT IDENTIFIER ::= { enterprises 18 }
+
+wfSwSeries7 OBJECT IDENTIFIER ::= { wellfleet 3 }
+
+wfHardwareConfig OBJECT IDENTIFIER ::= { wfSwSeries7 1 }
+
+wfHwModuleGroup OBJECT IDENTIFIER ::= { wfHardwareConfig 4 }
+
+wfSystem OBJECT IDENTIFIER ::= { wfSwSeries7 3 }
+
+END -- Wellfleet-COMMON-MIB
+-- @(#)WSCCS i/mibs-hardware.mib 1.2 10/9/95
+Wellfleet-HARDWARE-MIB DEFINITIONS ::= BEGIN
+
+-- Created by mdl2asn version 3.1
+-- Creation date: Wed Aug 30 16:42:01 EDT 1995
+
+
+ IMPORTS
+
+ IpAddress, Counter, Gauge, TimeTicks, Opaque, enterprises, mgmt
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ TRAP-TYPE
+ FROM RFC-1215
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ wfHardwareConfig
+ FROM Wellfleet-COMMON-MIB;
+
+
+ wfHwBase OBJECT IDENTIFIER ::= { wfHardwareConfig 1 }
+
+ wfHwBpIdOpt OBJECT-TYPE
+ SYNTAX INTEGER {
+ acefn(1),
+ aceln(2),
+ acecn(3),
+ afn(4),
+ in(5),
+ an(16),
+ sys5000(5000),
+ freln(16640),
+ frecn(16896),
+ frerbln(17152),
+ asn(20480),
+ asnzcable(20736),
+ asnbcable(20992)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The BackPlane identification number."
+ ::= { wfHwBase 1 }
+
+ wfHwBpRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the BackPlane. High byte is in upper 2 bytes."
+ ::= { wfHwBase 2 }
+
+ wfHwBpSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the BackPlane."
+ ::= { wfHwBase 3 }
+
+ wfBCNPwrSupply1 OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ fail(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Hot-Swappable Power Supply 1"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 4 }
+
+ wfBCNPwrSupply2 OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ fail(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Hot-Swappable Power Supply 2"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 5 }
+
+ wfBCNPwrSupply3 OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ fail(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Hot-Swappable Power Supply 3"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 6 }
+
+ wfBCNPwrSupply4 OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ fail(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Hot-Swappable Power Supply 4"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 7 }
+
+ wfBCNFanStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ fail(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Fan Tray"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 8 }
+
+ wfBCNTemperature OBJECT-TYPE
+ SYNTAX INTEGER {
+ ok(1),
+ caution(2),
+ notpresent(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Status of BCN Temperature sensor"
+ DEFVAL { notpresent }
+ ::= { wfHwBase 9 }
+
+ wfHwTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WfHwEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Hardware Table - indexed by slot number"
+ ::= { wfHardwareConfig 2 }
+
+ wfHwEntry OBJECT-TYPE
+ SYNTAX WfHwEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Hardware specific information about a slot."
+ INDEX { wfHwSlot }
+ ::= { wfHwTable 1 }
+
+ WfHwEntry ::= SEQUENCE {
+ wfHwSlot
+ INTEGER,
+ wfHwModIdOpt
+ INTEGER,
+ wfHwModRev
+ OCTET STRING,
+ wfHwModSerialNumber
+ OCTET STRING,
+ wfHwMotherBdIdOpt
+ INTEGER,
+ wfHwMotherBdRev
+ OCTET STRING,
+ wfHwMotherBdSerialNumber
+ OCTET STRING,
+ wfHwDaughterBdIdOpt
+ INTEGER,
+ wfHwDaughterBdRev
+ OCTET STRING,
+ wfHwDaughterBdSerialNumber
+ OCTET STRING,
+ wfHwBabyBdIdOpt
+ INTEGER,
+ wfHwBabyBdRev
+ OCTET STRING,
+ wfHwBabyBdSerialNumber
+ OCTET STRING,
+ wfHwDiagPromRev
+ OCTET STRING,
+ wfHwDiagPromDate
+ DisplayString,
+ wfHwDiagPromSource
+ DisplayString,
+ wfHwBootPromRev
+ OCTET STRING,
+ wfHwBootPromDate
+ DisplayString,
+ wfHwBootPromSource
+ DisplayString,
+ wfHwSparePromRev
+ OCTET STRING,
+ wfHwSparePromDate
+ DisplayString,
+ wfHwSparePromSource
+ DisplayString,
+ wfHwFileSysPresent
+ INTEGER,
+ wfHwFileSysPresent2
+ INTEGER,
+ wfHwConfigServer
+ INTEGER,
+ wfHwConfigFile
+ DisplayString,
+ wfHwConfigDateAndTime
+ OCTET STRING,
+ wfHwActiveImageName
+ DisplayString,
+ wfHwActiveImageSource
+ DisplayString,
+ wfHwActiveImageDate
+ DisplayString,
+ wfHwMotherBdMemorySize
+ INTEGER,
+ wfHwFastPacketCacheSize
+ INTEGER,
+ wfHwModDaughterBd1IdOpt
+ INTEGER,
+ wfHwModDaughterBd1AwRev
+ OCTET STRING,
+ wfHwModDaughterBd1Rev
+ OCTET STRING,
+ wfHwModDaughterBd1SerialNumber
+ OCTET STRING,
+ wfHwModDaughterBd2IdOpt
+ INTEGER,
+ wfHwModDaughterBd2AwRev
+ OCTET STRING,
+ wfHwModDaughterBd2Rev
+ OCTET STRING,
+ wfHwModDaughterBd2SerialNumber
+ OCTET STRING
+ }
+
+ wfHwSlot OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each slot.
+ Its value ranges between 1 and 14.
+ There are products in this family that contain 1, 5, and 14 slots."
+ ::= { wfHwEntry 1 }
+
+ wfHwModIdOpt OBJECT-TYPE
+ SYNTAX INTEGER {
+ enet1(1),
+ enet2(8),
+ sync1(16),
+ sync1a(17),
+ t11(24),
+ dse1(32),
+ dse1a(33),
+ dst416(40),
+ sst416a(41),
+ dst4(42),
+ sst4a(43),
+ sst416(44),
+ stok416(45),
+ sst4(46),
+ stok4(47),
+ floppy(48),
+ necfloppy(49),
+ t12(56),
+ t12a(57),
+ st1(58),
+ t156k(60),
+ e1(61),
+ st156k(62),
+ se1(63),
+ t12n(64),
+ st1n(65),
+ t156kn(66),
+ st156kn(67),
+ e1n(68),
+ se1n(69),
+ sync(80),
+ sync2a(81),
+ cmcfddi(88),
+ iphfddi(89),
+ dt(104),
+ dsde1(112),
+ dsde1a(113),
+ enet(114),
+ dse2(116),
+ dse2a(117),
+ sse(118),
+ ssea(119),
+ dsde10bt(120),
+ enet3(132),
+ dsde2(156),
+ oldqenf(160),
+ denf(161),
+ qenf(162),
+ qef(164),
+ def(165),
+ mct1(168),
+ smct1(169),
+ dtok(176),
+ mce1(184),
+ smce1(185),
+ mce1ii75(188),
+ smce1ii75(189),
+ mce1ii120(190),
+ smce1ii120(191),
+ wffddi2m(192),
+ wffddi1m(193),
+ wffddi2s(194),
+ wffddi1s(195),
+ wffddi2mf(196),
+ wffddi1mf(197),
+ wffddi2sf(198),
+ wffddi1sf(199),
+ fmdset(200),
+ fmdst(201),
+ fmdse(202),
+ fmsst(203),
+ fmsse(204),
+ fnsdse(208),
+ fnsdsdt(216),
+ fnsdst(217),
+ dhssi(224),
+ shssi(225),
+ esafnf(232),
+ esafdsenf(233),
+ esafssenf(234),
+ esafdenf(235),
+ esaf(236),
+ esafdse(237),
+ esafsse(238),
+ esafde(239),
+ qtok(256),
+ asn(511),
+ anseds(1024),
+ ansedst(1025),
+ ansedsh(1026),
+ ansedsi(1027),
+ ansedsti(1028),
+ ansedshi(1029),
+ ansets(1030),
+ ansetst(1031),
+ ansetsh(1032),
+ andeds(1033),
+ andedst(1034),
+ andedsh(1035),
+ andstx(1036),
+ andst(1037),
+ andsti(1038),
+ antst(1039),
+ antstx(1040),
+ ansdsedst(1041),
+ ansdsedstx(1042),
+ ansedsi2(1043),
+ ansedsti2(1044),
+ ansedshi2(1045),
+ andsti2(1046),
+ ansedsg(1047),
+ ansedsgx(1048),
+ ansetsg(1049),
+ andedsg(1050),
+ ansedsgi(1051),
+ ansetsgx(1052),
+ andedsgx(1053),
+ ansedsgix(1054),
+ ansedsx(1055),
+ ansetsx(1056),
+ andedsx(1057),
+ ansedstx(1058),
+ ansetstx(1059),
+ andedstx(1060),
+ andsti2x(1061),
+ ansedsi2x(1062),
+ ansedsti2x(1063),
+ atmalc(4096),
+ atmalctaxi100(4097),
+ atmalcsonetmm(4098),
+ atmalcsonetsm(4099),
+ osync(4352),
+ comp(4353),
+ comp128(4354),
+ atmcoc3mm(4608),
+ atmcoc3sm(4609),
+ atmcoc3utp5(4610),
+ de100(4864),
+ atmcds3(5120),
+ atmce3(5121),
+ qmct1rj45(5376),
+ qmct1db15(5377),
+ srml(8448),
+ atm5000ah(524288),
+ qe(1048799),
+ qehwf(1048798),
+ qefddi2m(1048831),
+ qefddi2mhwf(1048830),
+ qefddi2s(1048823),
+ qefddi2shwf(1048822),
+ qefddi1m(1048815),
+ qefddi1mhwf(1048814),
+ qefddi1s(1048807),
+ qefddi1shwf(1048806),
+ qecddi2stp(1048827),
+ qecddi2stphwf(1048826),
+ qecddi1stp(1048811),
+ qecddi1stphwf(1048810),
+ qecddi2utp(1048763),
+ qecddi2utphwf(1048762),
+ qecddi1utp(1048747),
+ qecddi1utphwf(1048746),
+ enet3atm(1048832),
+ enet3enet(1048833),
+ enet3fddi(1048834),
+ enet3tok(1048835),
+ enet3tokf(1048836),
+ enet3sync(1048837),
+ enet3only(1048863),
+ fddiatm(1048864),
+ fddienet(1048865),
+ fddifddi(1048866),
+ fdditok(1048867),
+ fdditokf(1048868),
+ fddisync(1048869),
+ fddionly(1048895),
+ tok3atm(1048896),
+ tok3enet(1048897),
+ tok3fddi(1048898),
+ tok3tok(1048899),
+ tok3tokf(1048900),
+ tok3sync(1048901),
+ tok3only(1048927),
+ tokf3atm(1048928),
+ tokf3enet(1048929),
+ tokf3fddi(1048930),
+ tokf3tok(1048931),
+ tokf3tokf(1048932),
+ tokf3sync(1048933),
+ tokf3only(1048959),
+ enet3datm(1048960),
+ enet3denet(1048961),
+ enet3dfddi(1048962),
+ enet3dtok(1048963),
+ enet3dtokf(1048964),
+ enet3dsync(1048965),
+ enet3donly(1048991),
+ chipcomfenet(1049089),
+ chipcomffddi(1049090),
+ chipcomftok(1049091),
+ chipcomftokf(1049092),
+ chipcomfdsync(1049093),
+ chipcomfisdn(1049094),
+ chipcomffddis(1049095),
+ chipcomfonly(1049119),
+ chipcomenet(1049217),
+ chipcomfddi(1049218),
+ chipcomtok(1049219),
+ chipcomtokf(1049220),
+ chipcomdsync(1049221),
+ chipcomisdn(1049222),
+ chipcomfddis(1049223),
+ chipcomonly(1049247)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The module identification number.
+
+ Port Configurations
+ HWStat Name Enet Sync Async Token Framer Fiber
+ ------ ------------ ------ ---- ----- ----- ------ -----
+ 1 ENET-1 2 0 0 0 0 0
+ 8 ENET-2 2 0 0 0 0 0
+
+ 16 SYNC-1 0 4 1 0 0 0
+ 17 SYNC-1 [1] 0 4 1 0 0 0
+
+ 24 T1-1 0 2 1 0 2 0
+
+ 32 DSE-1 1 2 1 0 0 0
+ 33 DSE-1 [1] 1 2 1 0 0 0
+
+ 40 DST-4/16 0 2 1 1 0 0
+ 41 SST-4/16 [1] 0 1 1 1 0 0
+ 42 DST-4 0 2 1 1 0 0
+ 43 SST-4 [1] 0 1 1 1 0 0
+ 44 SST-4/16 0 1 1 1 0 0
+ 45 STOK-4/16 [3] 0 0 0 1 0 0
+ 46 SST-4 0 1 1 1 0 0
+ 47 STOK-4 [3] 0 0 0 1 0 0
+
+ 48 FLOPPY 0 0 0 0 0 0
+
+ 56 T1-2 0 2 1 0 2 0
+ 57 T1-2 0 2 1 0 2 0
+ 58 ST1 0 1 1 0 1 0
+ 60 T1-56K 0 1 1 0 1 0
+ 61 E1 [3] 0 2 0 0 2 0
+ 62 ST1-56K 0 1 1 0 1 0
+ 63 SE1 [3] 0 1 0 0 1 0
+
+ 64 T1-2n 0 2 1 0 2 0
+ 65 ST1n 0 1 1 0 1 0
+ 66 T1-56Kn 0 1 1 0 1 0
+ 67 ST1-56Kn 0 1 1 0 1 0
+ 68 E1n [3] 0 2 0 0 2 0
+ 69 SE1n [3] 0 1 0 0 1 0
+
+ 80 SYNC-2 0 4 1 0 0 0
+ 81 SYNC-2 [1] 0 4 1 0 0 0
+
+ 88 CMC-FDDI [6] 0 0 0 0 0 1
+ 89 IPHASE-FDDI [6] 0 0 0 0 0 1
+
+ 112 DSDE-1 2 2 1 0 0 0
+ 113 DSDE-1 [1] 2 2 1 0 0 0
+ 114 ENET 2 0 0 0 0 0
+ 116 DSE-2 1 2 1 0 0 0
+ 117 DSE-2 [1] 1 2 1 0 0 0
+ 118 SSE 1 1 1 0 0 0
+ 119 SSE [1] 1 1 1 0 0 0
+
+ 132 ENET-3 [2] 2 0 0 0 0 0
+
+ 156 DSDE-2 [2] 2 2 1 0 0 0
+
+ 160 QE/NF 4 0 0 0 0 0
+ 161 DE/NF [5] 2 0 0 0 0 0
+ 162 QE/NF 4 0 0 0 0 0
+ 164 QE/F [4] 4 0 0 0 0 0
+ 165 DE/F [4,5] 2 0 0 0 0 0
+
+ 168 MCT1 0 2 Munich 0 0 2 0
+ 169 SMCT1 0 1 Munich 0 0 1 0
+
+ 176 DTOK 0 0 0 2 0 0
+
+ 184 MCE1 0 2 Munich 0 0 2 0
+ 185 SMCE1 0 1 Munich 0 0 1 0
+ 188 MCE1II75 0 2 Munich 0 0 2 0
+ 189 SMCE1II75 0 1 Munich 0 0 1 0
+ 190 MCE1II120 0 2 Munich 0 0 2 0
+ 191 SMCE1II120 0 1 Munich 0 0 1 0
+
+ 192 WF_FDDI_2M 0 0 0 0 0 1
+ 193 WF_FDDI_1M 0 0 0 0 0 1
+ 194 WF_FDDI_2S 0 0 0 0 0 1
+ 195 WF_FDDI_1S 0 0 0 0 0 1
+ 196 WF_FDDI_2MF 0 0 0 0 0 1
+ 197 WF_FDDI_1MF 0 0 0 0 0 1
+ 198 WF_FDDI_2SF 0 0 0 0 0 1
+ 199 WF_FDDI_1SF 0 0 0 0 0 1
+
+ 200 HW_MODULE_FMDSET [7] 1 2 0 1 0 0
+ 201 HW_MODULE_FMDST [7] 0 2 0 1 0 0
+ 202 HW_MODULE_FMDSE [7] 1 2 0 0 0 0
+ 203 HW_MODULE_FMSST [7] 0 1 0 1 0 0
+ 204 HW_MODULE_FMSSE [7] 1 1 0 0 0 0
+
+ 208 FNSDSE [7] 1 2 0 0 0 0
+ 216 FNSDSDT [7] 0 2 0 2 0 0
+ 217 FNSDST [7] 0 2 0 1 0 0
+
+ 224 DHSSI 0 2 hssi 0 0 0 0
+ 225 SHSSI 0 1 hssi 0 0 0 0
+
+ 232 ESAF_NF 2 2 0 0 0 0
+ 233 ESAF_DSE_NF 1 2 0 0 0 0
+ 234 ESAF_SSE_NF 1 1 0 0 0 0
+ 235 ESAF_DE_NF 2 0 0 0 0 0
+ 236 ESAF [2] 2 2 0 0 0 0
+ 237 ESAF_DSE [2] 1 2 0 0 0 0
+ 238 ESAF_SSE [2] 1 1 0 0 0 0
+ 239 ESAF_DE [2] 2 0 0 0 0 0
+
+ 256 QTOK 0 0 0 4 0 0
+
+ ASN (Barracuda)
+
+ 511 ASN[8]
+
+
+ AN Module IDs (Piranha, Guppy...)
+
+ ID Mnemonic ENET SYNC ISDN TR HUB DCM
+ -- -------- ---- ---- ---- -- --- ---
+ 1024 ANSEDS 1 2 0 0 0 N
+
+ 1025 ANSEDST 1 2 0 1 0 N
+
+ 1026 ANSEDSH 1 2 0 0 12 N
+
+ 1027 ANSEDSI 1 2 1 0 0 N
+
+ 1028 ANSEDSTI 1 2 1 1 0 N
+
+ 1029 ANSEDSHI 1 2 1 0 12 N
+
+ 1030 ANSETS 1 3 0 0 0 N
+
+ 1031 ANSETST 1 3 0 1 0 N
+
+ 1032 ANSETSH 1 3 0 0 12 N
+
+ 1033 ANDEDS 2 2 0 0 0 N
+
+ 1034 ANDEDST 2 2 0 1 0 N
+
+ 1035 ANDEDSH 2 2 0 0 12 N
+
+ 1036 ANDSTX 0 2 0 1 0 Y
+ (formerly ANDS)
+
+ 1037 ANDST 0 2 0 1 0 N
+
+ 1038 ANDSTI 0 2 1 1 0 N
+
+ 1039 ANTST 0 3 0 1 0 N
+
+ 1040 ANTSTX 0 3 0 1 0 Y
+ (formerly ANSDSEDS)
+
+ 1041 ANSDSEDST 1 2 0 1 0 N
+
+ 1042 ANSDSEDSTX 1 2 0 1 0 Y
+ (formerly ANSDSEDSH)
+
+ 1043 ANSEDSI2 1 2 1 0 0 N
+
+ 1044 ANSEDSTI2 1 2 1 1 0 N
+
+ 1045 ANSEDSHI2 1 2 1 0 12 N
+
+ 1046 ANDSTI2 0 2 1 1 0 N
+
+ 1047 ANSEDSG 1 2 0 0 8 N
+
+ 1048 ANSEDSGX 1 2 0 0 8 Y
+
+ 1049 ANSETSG 1 3 0 0 8 N
+
+ 1050 ANDEDSG 2 2 0 0 8 N
+
+ 1051 ANSEDSGI 1 2 1 0 8 N
+
+ 1052 ANSETSGX 1 3 0 0 8 Y
+
+ 1053 ANDEDSGX 2 2 0 0 8 Y
+
+ 1054 ANSEDSGIX 1 2 1 0 8 Y
+
+ 1055 ANSEDSX 1 2 0 0 0 Y
+
+ 1056 ANSETSX 1 3 0 0 0 Y
+
+ 1057 ANDEDSX 2 2 0 0 0 Y
+
+ 1058 ANSEDSTX 1 2 0 1 0 Y
+
+ 1059 ANSETSTX 1 3 0 1 0 Y
+
+ 1060 ANDEDSTX 2 2 0 1 0 Y
+
+ 1061 ANDSTI2X 0 2 1 0 0 Y
+
+ 1062 ANSEDSI2X 1 2 1 0 0 Y
+
+ 1063 ANSEDSTI2X 1 2 1 1 0 Y
+
+
+ 4096 ATMALC 0 0 0 0 0 0
+ 4097 ATMALCTAXI100 0 0 0 0 0 1
+ 4098 ATMALCSONETMM 0 0 0 0 1 1 [9]
+ 4099 ATMALCSONETSM 0 0 0 0 1 1 [9]
+ 4352 OSYNC 0 8 0 0 0 0
+ 4353 OSYNC_COMP (32) 0 8 0 0 0 0
+ 4354 OSYNC_COMP128 0 8 0 0 0 0
+
+ 4608 ATMCOC3MM 0 0 0 0 1 1 [10]
+ 4609 ATMCOC3SM 0 0 0 0 1 1 [10]
+ 4610 ATMCOC3UTP5 0 0 0 0 1 0 [10]
+
+ 4864 DE100 2 0 0 0 0 0
+
+ 5120 ATMCDS3 0 0 0 0 1 0 [10]
+ 5121 ATMCE3 0 0 0 0 1 0 [10]
+
+ 8448 SRML 0 0 0 0 0 0
+
+
+ NOTES:
+ [1] Indicates Module has COM Port 1 configured for ASYNC.
+ The AM8530's port B is configured for COM1.
+
+ [2] This Module contains the DEFA - Hardware Filtering. CAMS
+ must be programmed (can contain 2 - 6 CAMS onboard).
+
+ [3] The AM8530 has been removed (depopulated) from this module.
+ Programming this device should not be performed.
+
+ [4] Contains Dual Defa hardware. (Can be depopulated)
+
+ [5] Depop'd two ports of hardware to make Dual Ethernet module.
+
+ [6] These are FDDI modules. The ID cannot be read from the Link
+ module I/O space.
+
+ [7] These are AFN Platform Integrated 'Modules' - Cannot be detached
+ or be used by any other platform.
+
+ [8] Module IDs from 1280(0x500) to 2559(0x9ff) are used
+ for the ASN Net Modules. Module ID 512(0x200) is
+ used for the ASN SPEX. These IDs are documented in
+ MODULE.mdl. A module ID of 511(0x1ff) in
+ 'wfHwEntry.wfHwModIdOpt' indicates that it is an
+ ASN platform and the user should refer to
+ 'wfHwModuleEntry.wfHwModuleModIdOpt' for Module ID details
+
+ [9] ATMALC link modules. The physical option for SONET includes a
+ framer and the medium is fiber optics. Only one port per physical
+ daughtercard per link module.
+
+ [10] ARE UTOPIA link modules. "
+ ::= { wfHwEntry 2 }
+
+ wfHwModRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the module. High byte is in upper 2 bytes."
+ ::= { wfHwEntry 3 }
+
+ wfHwModSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the module."
+ ::= { wfHwEntry 4 }
+
+ wfHwMotherBdIdOpt OBJECT-TYPE
+ SYNTAX INTEGER {
+ sysctrl(1),
+ ace12(2),
+ ace25(3),
+ ace32(4),
+ afn(5),
+ in(6),
+ sysctrl2(7),
+ an(16),
+ fre(256),
+ fre2(768),
+ o60(769),
+ asn(1024),
+ are(1280),
+ srmf(8704)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The mother board identification number."
+ ::= { wfHwEntry 5 }
+
+ wfHwMotherBdRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the mother board. High byte is in upper 2 bytes."
+ ::= { wfHwEntry 6 }
+
+ wfHwMotherBdSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the mother board."
+ ::= { wfHwEntry 7 }
+
+ wfHwDaughterBdIdOpt OBJECT-TYPE
+ SYNTAX INTEGER {
+ sysctrl(1),
+ ace68020mhz12(2),
+ ace68020mhz25(3),
+ ace68030mhz32(4),
+ fre68040mhz25(4352),
+ fre68040mhz33(4608)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The daughter board identification number."
+ ::= { wfHwEntry 8 }
+
+ wfHwDaughterBdRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the daughter board. High byte is in upper 2 bytes."
+ ::= { wfHwEntry 9 }
+
+ wfHwDaughterBdSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the daughter board."
+ ::= { wfHwEntry 10 }
+
+ wfHwBabyBdIdOpt OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The baby board identification number."
+ ::= { wfHwEntry 11 }
+
+ wfHwBabyBdRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the baby board. High byte is in upper 2 bytes."
+ ::= { wfHwEntry 12 }
+
+ wfHwBabyBdSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the baby board."
+ ::= { wfHwEntry 13 }
+
+ wfHwDiagPromRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the Diagnostic PROM. Major revision level
+ is in the upper 2 bytes, minor revision level in the lower 2 bytes."
+ ::= { wfHwEntry 14 }
+
+ wfHwDiagPromDate OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The creation date of the Diagnostic PROM"
+ ::= { wfHwEntry 15 }
+
+ wfHwDiagPromSource OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The origin of the Diagnostic PROM contents"
+ ::= { wfHwEntry 16 }
+
+ wfHwBootPromRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the BOOT PROM. Major revision level
+ is in the upper 2 bytes, minor revision level in the lower 2 bytes."
+ ::= { wfHwEntry 17 }
+
+ wfHwBootPromDate OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The creation date of the Boot PROM"
+ ::= { wfHwEntry 18 }
+
+ wfHwBootPromSource OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The origin of the Boot PROM contents"
+ ::= { wfHwEntry 19 }
+
+ wfHwSparePromRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the BOOT PROM. Major revision level
+ is in the upper 2 bytes, minor revision level in the lower 2 bytes."
+ ::= { wfHwEntry 20 }
+
+ wfHwSparePromDate OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The creation date of the Spare PROM"
+ ::= { wfHwEntry 21 }
+
+ wfHwSparePromSource OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The origin of the Spare PROM contents"
+ ::= { wfHwEntry 22 }
+
+ wfHwFileSysPresent OBJECT-TYPE
+ SYNTAX INTEGER {
+ filesys(1),
+ nofilesys(2)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Flag indicating presence of File System on this slot."
+ DEFVAL { nofilesys }
+ ::= { wfHwEntry 23 }
+
+ wfHwFileSysPresent2 OBJECT-TYPE
+ SYNTAX INTEGER {
+ filesys(1),
+ nofilesys(2)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Flag indicating presence of File System (Syscon2 volume#2) on this slot."
+ DEFVAL { nofilesys }
+ ::= { wfHwEntry 24 }
+
+ wfHwConfigServer OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The slot number from which this slot was served its
+ configuration. If the value for this attribute is 0, this
+ slot obtained its configuration from a file system resource
+ (not necessarily local); If the value for this attribute is
+ -1, this slot does not participate in the boot process (e.g.
+ SRM). A positive value indicates that the configuration was
+ obtained from memory from the slot indicated by the value of
+ this attribute."
+ ::= { wfHwEntry 25 }
+
+ wfHwConfigFile OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The name of the config file the active configuration was
+ derived from. This does NOT necessarily reflect the
+ current configuration!"
+ ::= { wfHwEntry 26 }
+
+ wfHwConfigDateAndTime OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The 11 octet date and time that a configuration was
+ loaded on/served to this slot. Octet map: 1-2 Year,
+ 3 Month, 4 Day, 5 Hour, 6 Minutes, 7 Seconds,
+ 8 Deci-seconds, 9 Direction from GMT ('+'|`-'), 10 GMT Hour
+ Offset, 11 GMT Minute Offset."
+ ::= { wfHwEntry 27 }
+
+ wfHwActiveImageName OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "If slot was booted from a local source: this is the name of the active
+ image, which is in the form of <volume>:<image name>.
+ If slot was booted from a network source: this is the full pathname
+ where the active image was found on the remote server."
+ ::= { wfHwEntry 28 }
+
+ wfHwActiveImageSource OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The origin of the active image"
+ ::= { wfHwEntry 29 }
+
+ wfHwActiveImageDate OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The date which the active image was created"
+ ::= { wfHwEntry 30 }
+
+ wfHwMotherBdMemorySize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total installed dram size in kilobytes."
+ ::= { wfHwEntry 31 }
+
+ wfHwFastPacketCacheSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the installed fast packet cache in kilobytes."
+ ::= { wfHwEntry 32 }
+
+ wfHwModDaughterBd1IdOpt OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #1 identification number"
+ ::= { wfHwEntry 33 }
+
+ wfHwModDaughterBd1AwRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #1 artwork revision level"
+ ::= { wfHwEntry 34 }
+
+ wfHwModDaughterBd1Rev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #1 board revision level"
+ ::= { wfHwEntry 35 }
+
+ wfHwModDaughterBd1SerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #1 serial number"
+ ::= { wfHwEntry 36 }
+
+ wfHwModDaughterBd2IdOpt OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #2 identification number"
+ ::= { wfHwEntry 37 }
+
+ wfHwModDaughterBd2AwRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #2 artwork revision level"
+ ::= { wfHwEntry 38 }
+
+ wfHwModDaughterBd2Rev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #2 board revision level"
+ ::= { wfHwEntry 39 }
+
+ wfHwModDaughterBd2SerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Link module daughter board #2 serial number"
+ ::= { wfHwEntry 40 }
+
+ END -- Wellfleet-HARDWARE-MIB
+-- @(#)WSCCS q/mibs-module.mib 1.1 8/30/95
+Wellfleet-MODULE-MIB DEFINITIONS ::= BEGIN
+
+-- Created by mdl2asn version 3.1
+-- Creation date: Wed Aug 30 16:45:27 EDT 1995
+
+
+ IMPORTS
+
+ IpAddress, Counter, Gauge, TimeTicks, Opaque, enterprises, mgmt
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ TRAP-TYPE
+ FROM RFC-1215
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ wfHwModuleGroup
+ FROM Wellfleet-COMMON-MIB;
+
+
+ wfHwModuleTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WfHwModuleEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Hardware Module Table
+ Filled in by the Module Driver. Read by SNMP to
+ build the driver load records "
+ ::= { wfHwModuleGroup 1 }
+
+ wfHwModuleEntry OBJECT-TYPE
+ SYNTAX WfHwModuleEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Hardware specific information about a slot."
+ INDEX { wfHwModuleSlot,
+ wfHwModuleModule }
+ ::= { wfHwModuleTable 1 }
+
+ WfHwModuleEntry ::= SEQUENCE {
+ wfHwModuleSlot
+ INTEGER,
+ wfHwModuleModule
+ INTEGER,
+ wfHwModuleModIdOpt
+ INTEGER,
+ wfHwModuleModRev
+ OCTET STRING,
+ wfHwModuleModSerialNumber
+ OCTET STRING,
+ wfHwModuleArtworkRev
+ DisplayString
+ }
+
+ wfHwModuleSlot OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each slot.
+ Its value ranges between 1 and 4."
+ ::= { wfHwModuleEntry 1 }
+
+ wfHwModuleModule OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This value ranges between 1 and 4"
+ ::= { wfHwModuleEntry 2 }
+
+ wfHwModuleModIdOpt OBJECT-TYPE
+ SYNTAX INTEGER {
+ spex(512),
+ hss(768),
+ hsd(769),
+ denm(1280),
+ denmhwf(1281),
+ dsnmnn(1536),
+ dsnmn1(1537),
+ dsnmn2(1538),
+ dsnm1n(1540),
+ dsnm11(1541),
+ dsnm12(1542),
+ dsnm2n(1544),
+ dsnm21(1545),
+ dsnm22(1546),
+ dsnmnnisdn(1584),
+ dsnmn1isdn(1585),
+ dsnmn2isdn(1586),
+ dsnm1nisdn(1588),
+ dsnm11isdn(1589),
+ dsnm12isdn(1590),
+ dsnm2nisdn(1592),
+ dsnm21isdn(1593),
+ dsnm22isdn(1594),
+ mmfsdsas(1792),
+ mmfsddas(1793),
+ smfsdsas(1800),
+ smfsddas(1801),
+ mmscsas(1808),
+ mmscdas(1809),
+ smammbdas(1825),
+ mmasmbdas(1833),
+ mmfsdsashwf(1856),
+ mmfsddashwf(1857),
+ smfsdsashwf(1864),
+ smfsddashwf(1865),
+ mmscsashwf(1872),
+ mmscdashwf(1873),
+ smammbdashwf(1889),
+ mmasmbdashwf(1897),
+ dtnm(2048),
+ cam(2049),
+ se100nm(2304),
+ asnqbri(2560)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Module IDs for the net modules modules"
+ ::= { wfHwModuleEntry 3 }
+
+ wfHwModuleModRev OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the module. High byte is in upper 2 bytes."
+ ::= { wfHwModuleEntry 4 }
+
+ wfHwModuleModSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The serial number of the module."
+ ::= { wfHwModuleEntry 5 }
+
+ wfHwModuleArtworkRev OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The Artwork Revision number of the module"
+ ::= { wfHwModuleEntry 6 }
+
+ wfModuleTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF WfModuleEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This table is used by the module driver for Barracuda"
+ ::= { wfHwModuleGroup 2 }
+
+ wfModuleEntry OBJECT-TYPE
+ SYNTAX WfModuleEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Hardware specific information about a slot."
+ INDEX { wfModuleSlot }
+ ::= { wfModuleTable 1 }
+
+ WfModuleEntry ::= SEQUENCE {
+ wfModuleDelete
+ INTEGER,
+ wfModuleSlot
+ INTEGER,
+ wfModuleTimerFrequency
+ INTEGER,
+ wfModuleBufferBalance
+ INTEGER,
+ wfModuleFddiWeight
+ INTEGER,
+ wfModuleTokenRingWeight
+ INTEGER,
+ wfModuleCsmacdWeight
+ INTEGER,
+ wfModuleSyncWeight
+ INTEGER,
+ wfModuleFreeBufferCredits
+ INTEGER,
+ wfModuleTotalBufferCredits
+ INTEGER,
+ wfModuleRestart
+ INTEGER,
+ wfModuleCsmacd100Weight
+ INTEGER
+ }
+
+ wfModuleDelete OBJECT-TYPE
+ SYNTAX INTEGER {
+ created(1),
+ deleted(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "create/delete parameter"
+ DEFVAL { created }
+ ::= { wfModuleEntry 1 }
+
+ wfModuleSlot OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each slot.
+ Its value ranges between 1 and 14.
+ There are products in this family that contain 1, 5, and 14 slots."
+ ::= { wfModuleEntry 2 }
+
+ wfModuleTimerFrequency OBJECT-TYPE
+ SYNTAX INTEGER {
+ timerdefault(1)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the frequency for the buffer balance
+ algorithm to run"
+ DEFVAL { timerdefault }
+ ::= { wfModuleEntry 3 }
+
+ wfModuleBufferBalance OBJECT-TYPE
+ SYNTAX INTEGER {
+ txrx(1),
+ none(2),
+ rx(3),
+ tx(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Enable/Disable buffer balancing algorithm selectively"
+ DEFVAL { txrx }
+ ::= { wfModuleEntry 4 }
+
+ wfModuleFddiWeight OBJECT-TYPE
+ SYNTAX INTEGER(1..10)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the weight of the fddi line
+ for the buffer balancing algorithm"
+ DEFVAL { 6 }
+ ::= { wfModuleEntry 5 }
+
+ wfModuleTokenRingWeight OBJECT-TYPE
+ SYNTAX INTEGER(1..10)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the weight of the token-ring
+ for the buffer balancing algorithm"
+ DEFVAL { 4 }
+ ::= { wfModuleEntry 6 }
+
+ wfModuleCsmacdWeight OBJECT-TYPE
+ SYNTAX INTEGER(1..10)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the weight of the csmacd line
+ for the buffer balancing algorithm"
+ DEFVAL { 3 }
+ ::= { wfModuleEntry 7 }
+
+ wfModuleSyncWeight OBJECT-TYPE
+ SYNTAX INTEGER(1..10)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the weight of the sync line
+ for the buffer balancing algorithm"
+ DEFVAL { 2 }
+ ::= { wfModuleEntry 8 }
+
+ wfModuleFreeBufferCredits OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This attribute indicates the number of buffers
+ available to line drivers but not used by them"
+ ::= { wfModuleEntry 9 }
+
+ wfModuleTotalBufferCredits OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This attribute indicates the total number of buffers
+ available to line drivers"
+ ::= { wfModuleEntry 10 }
+
+ wfModuleRestart OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This attribute should be touched after the queue
+ lengths are configured in the line-records"
+ ::= { wfModuleEntry 11 }
+
+ wfModuleCsmacd100Weight OBJECT-TYPE
+ SYNTAX INTEGER(1..10)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This value determines the weight of the csmacd 100MB line
+ for the buffer balancing algorithm"
+ DEFVAL { 6 }
+ ::= { wfModuleEntry 12 }
+
+ END -- Wellfleet-MODULE-MIB
+-- @(#)WSCCS h/mibs-sys.mib 1.1 8/30/95
+Wellfleet-SYS-MIB DEFINITIONS ::= BEGIN
+
+-- Created by mdl2asn version 3.1
+-- Creation date: Wed Aug 30 16:48:50 EDT 1995
+
+
+ IMPORTS
+
+ IpAddress, Counter, Gauge, TimeTicks, Opaque, enterprises, mgmt
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ TRAP-TYPE
+ FROM RFC-1215
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ wfSystem
+ FROM Wellfleet-COMMON-MIB;
+
+
+ wfSys OBJECT IDENTIFIER ::= { wfSystem 1 }
+
+ wfSysDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity including full name and version of
+ the system's hardware type, OS, and networking SW "
+ ::= { wfSys 1 }
+
+ wfSysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Provides an unambiguous means for determining the MIB type (old product vs.
+ harpoon MIB)."
+ ::= { wfSys 2 }
+
+ wfSysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Time in seconds/100 since the last cold start"
+ ::= { wfSys 3 }
+
+ wfSysContact OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Contact person for this node and where/how to contact them"
+ ::= { wfSys 4 }
+
+ wfSysName OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Node's fully qualified domain name or administratively assigned name"
+ ::= { wfSys 5 }
+
+ wfSysLocation OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Physical Location of this Node"
+ ::= { wfSys 6 }
+
+ wfSysServices OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A sum of numbers indicating the set of services the entity offers. For each
+ layer L, add 2**(L - 1). Example: 78 = Layers 2,3,4, and 7."
+ DEFVAL { 78 }
+ ::= { wfSys 7 }
+
+ wfSysGmtOffset OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The positive or negative offset from Greenwich Mean Time (GMT). This
+ effectively describes the time zone."
+ ::= { wfSys 8 }
+
+ wfSysMibVersion OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The version of the private management information base currently being
+ used by the system software. Format is: xV.RR"
+ ::= { wfSys 9 }
+
+ wfSysMibRevision OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The revision level of the private management information base currently
+ being used by the system software."
+ ::= { wfSys 10 }
+
+ wfSysAgentType OBJECT-TYPE
+ SYNTAX INTEGER {
+ anrptragenttype(29),
+ anhubagenttype(30)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The network management agent's module type"
+ ::= { wfSys 11 }
+
+ wfSysMibCounterEnable OBJECT-TYPE
+ SYNTAX INTEGER {
+ enabled(1),
+ disabled(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Mib II counter Switch"
+ DEFVAL { enabled }
+ ::= { wfSys 12 }
+
+ END -- Wellfleet-SYS-MIB
diff --git a/perl/SNMP/t/mibload.t b/perl/SNMP/t/mibload.t
new file mode 100644
index 0000000..e44748a
--- /dev/null
+++ b/perl/SNMP/t/mibload.t
@@ -0,0 +1,95 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+
+use Test;
+BEGIN {plan tests => 7}
+use SNMP;
+
+require "t/startagent.pl";
+
+use vars qw($mibdir);
+
+$SNMP::verbose = 0;
+
+my $mib_file = 't/mib.txt';
+my $junk_mib_file = 'mib.txt';
+
+my $mibfile1;
+my @mibdir;
+my $mibfile2;
+
+if ($^O =~ /win32/i) {
+ $mibdir =~ s"/"\\"g;
+ $mibfile1 = "$mibdir\\TCP-MIB.txt";
+ @mibdir = ("$mibdir");
+ $mibfile2 = "$mibdir\\IPV6-TCP-MIB.txt";
+}
+else {
+ $mibfile1 = "$mibdir/TCP-MIB.txt";
+ @mibdir = ("$mibdir");
+ $mibfile2 = "$mibdir/IPV6-TCP-MIB.txt";
+}
+
+if ($^O =~ /win32/i) {
+ $mibdir =~ s"/"\\"g;
+}
+
+
+######################################################################
+# See if we can find a mib to use, return of 0 means the file wasn't
+# found or isn't readable.
+
+$res = SNMP::setMib($junk_mib_file,1);
+ok(defined(!$res));
+######################################################################
+# Now we give the right name
+
+$res = SNMP::setMib($mib_file,1);
+ok(defined($res));
+######################################################################
+# See if we can find a mib to use
+
+$res = SNMP::setMib($mib_file,0);
+ok(defined($res));
+######################## 4 ################################
+# add a mib dir
+
+$res = SNMP::addMibDirs($mibdir[0]);
+
+SNMP::loadModules("IP-MIB", "IF-MIB", "IANAifType-MIB", "RFC1213-MIB");
+#SNMP::unloadModules(RMON-MIB);
+#etherStatsDataSource shouldn't be found.
+#present only in 1271 & RMON-MIB.
+#
+# XXX: because we can't count on user .conf files, we should turn off
+# support for them (maybe set SNMPCONFPATH at the top of this
+# script?). But for the mean time just search for a bogus node that
+# will never exist.
+$res = $SNMP::MIB{bogusetherStatsDataSource};
+
+ok(!defined($res));
+
+######################## 5 ############################
+# add mib file
+
+$res1 = SNMP::addMibFiles($mibfile1);
+ok(defined($res1));
+$res2 = SNMP::addMibFiles($mibfile2);
+ok(defined($res2));
+
+$res = $SNMP::MIB{ipv6TcpConnState}{moduleID};
+
+ok($res =~ /^IPV6-TCP-MIB/);
+#################################################
+
+snmptest_cleanup();
+
diff --git a/perl/SNMP/t/notify.t b/perl/SNMP/t/notify.t
new file mode 100644
index 0000000..72600fa
--- /dev/null
+++ b/perl/SNMP/t/notify.t
@@ -0,0 +1,106 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+use Test;
+BEGIN { $n = 11; plan tests => $n }
+use SNMP;
+use vars qw($agent_port $comm $comm2 $trap_port $agent_host $sec_name $priv_pass $auth_pass $bad_name);
+require 't/startagent.pl';
+$SNMP::debugging = 0;
+
+my $res;
+my $enterprise = '.1.3.6.1.2.1.1.1.0';
+my $generic = 'specific';
+
+# V1 trap testing
+######################## 1 ############################
+# Fire up a trap session.
+my $s1 =
+ new SNMP::Session (DestHost=>$agent_host,Version=>1,Community=>$comm,RemotePort=>$trap_port);
+ok(defined($s1));
+
+######################## 2 ############################
+# test v1 trap
+if (defined($s1)) {
+ $res = $s1->trap(enterprise => $enterprise, agent=>$agent_host, generic=>$generic,[[sysContact, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+}
+ok($res =~ /^0 but true/);
+
+######################## 3 ############################
+# test with wrong varbind
+undef $res;
+if (defined($s1)) {
+ $res = $s1->trap([[$bad_name, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+ #print("res is $res\n");
+}
+ok(!defined($res));
+#########################################################
+
+# V2 testing
+######################## 4 ############################
+# Fire up a v2 trap session.
+my $s2 =
+ new SNMP::Session (Version=>2, DestHost=>$agent_host,Community=>$comm2,RemotePort=>$trap_port);
+ok(defined($s2));
+######################## 5 ############################
+# test v2 trap
+undef $res;
+if (defined($s2)) {
+ $res = $s2->trap(uptime=>200, trapoid=>'coldStart',[[sysContact, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+ #print("res is $res\n");
+}
+ok($res =~ /^0 but true/);
+######################## 6 ############################
+# no trapoid and uptime given. Should take defaults...
+my $ret;
+if (defined($s2)) {
+ $ret = $s2->trap([[sysContact, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+ #print("res is $ret\n");
+}
+ok(defined($ret));
+######################## 7 ############################
+# no varbind list given.
+undef $res;
+if (defined($s2)) {
+ $res = $s2->trap(trapoid=>'coldStart');
+ #print("res is $res\n");
+}
+ok(defined($res) && $res =~ /^0 but true/);
+
+#########################################################
+
+# v3 testing
+######################## 8 ############################
+# Fire up a v3 trap session.
+my $s3 = new SNMP::Session(Version=>3, DestHost=> $agent_host, RemotePort=>$trap_port, SecName => $sec_name);
+ok(defined($s3));
+
+######################## 9 ############################
+if (defined($s3)) {
+ $res = $s3->inform(uptime=>111, trapoid=>'coldStart', [[sysContact, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+}
+ok($res =~ /^0 but true/);
+
+######################## 10 ############################
+# Fire up a v3 trap session.
+$s3 = new SNMP::Session(Version=>3, DestHost=> $agent_host, RemotePort=>$trap_port, SecName => $sec_name, SecLevel => authPriv, AuthPass => $auth_pass, PrivPass => $priv_pass);
+ok(defined($s3));
+
+######################## 11 ############################
+undef $res;
+if (defined($s3)) {
+ $res = $s3->inform(uptime=>111, trapoid=>'coldStart', [[sysContact, 0, 'root@localhost'], [sysLocation, 0, 'here']] );
+ print "res = $res\n";
+}
+
+ok(defined($res) && ($res =~ /^0 but true/));
+
+snmptest_cleanup();
diff --git a/perl/SNMP/t/session.t b/perl/SNMP/t/session.t
new file mode 100644
index 0000000..3f51386
--- /dev/null
+++ b/perl/SNMP/t/session.t
@@ -0,0 +1,76 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+use Test;
+BEGIN { plan tests => 5}
+use SNMP;
+use vars qw($agent_port $comm $agent_host $bad_auth_pass $auth_pass $sec_name $bad_sec_name $bad_version $bad_priv_pass $priv_pass);
+require "t/startagent.pl";
+
+$SNMP::debugging = 0;
+
+# create list of varbinds for GETS, val field can be null or omitted
+my $vars = new SNMP::VarList (
+ ['sysDescr', '0', ''],
+ ['sysContact', '0'],
+ ['sysName', '0'],
+ ['sysLocation', '0'],
+ ['sysServices', '0'],
+ ['ifNumber', '0'],
+ ['ifDescr', '1'],
+ ['ifSpeed', '1'],
+ );
+
+#########################== 1 ===#########################################
+# Create a bogus session, undef means the host can't be found.
+# removed! this test can hang for a long time if DNS is not functioning
+# my $s1 = new SNMP::Session (DestHost => $bad_host );
+# ok(!defined($s1));
+#print("\n");
+#####################== 2 ====############################################
+# Fire up a session.
+ my $s2 =
+ new SNMP::Session (DestHost=>$agent_host, Community=>$comm,
+ RemotePort=>$agent_port);
+ ok(defined($s2));
+######################== 3 ==== ##########################################
+
+# Fire up a V3 session
+my $s3 = new SNMP::Session (Version => 3 , RemotePort => $agent_port,
+ SecName => $sec_name );
+ok(defined($s3));
+#print STDERR "Error string1 = $s3->{ErrorStr}:$s3->{ErrorInd}\n";
+#print("\n");
+#####################=== 4 ====###########################################
+#create a V3 session by setting an IP address/port not running an agent
+my $s4 = new SNMP::Session (Version => 3, RemotePort => 1002, Retries => 0);
+# engineId discovery should fail resulting in session creation failure (undef)
+ok(!defined($s4));
+#print STDERR "Error string1 = $s4->{ErrorStr}:$s4->{ErrorInd}\n";
+#print("\n");
+###################### 5 ###########################################
+#create a session with bad version
+my $s5 = new SNMP::Session (Version=>$bad_version);
+ok(!defined($s5));
+#print("\n");
+######################## 6 ########################################
+#Test for v3 session creation success
+my $s6 = new SNMP::Session (Version => 3, RemotePort => $agent_port,
+ SecLevel => 'authPriv',
+ SecName => $sec_name,
+ PrivPass => $priv_pass,
+ AuthPass => $auth_pass);
+ok(defined($s6));
+#print STDERR "Error string2 = $s6->{ErrorStr}:$s6->{ErrorInd}\n";
+#print("\n");
+##################### 7 ############################################
+
+snmptest_cleanup();
diff --git a/perl/SNMP/t/set.t b/perl/SNMP/t/set.t
new file mode 100644
index 0000000..9925654
--- /dev/null
+++ b/perl/SNMP/t/set.t
@@ -0,0 +1,224 @@
+#!./perl
+
+BEGIN {
+ unless(grep /blib/, @INC) {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib';
+ }
+ eval "use Cwd qw(abs_path)";
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBDIRS'} = '+' . abs_path("../../mibs");
+}
+use Test;
+BEGIN { plan tests => 7 }
+use SNMP;
+use vars qw($agent_port $comm $agent_host);
+require "t/startagent.pl";
+
+
+my $junk_oid = ".1.3.6.1.2.1.1.1.1.1.1";
+my $oid = ".1.3.6.1.2.1.1.1";
+my $junk_name = 'fooDescr';
+my $junk_host = 'no.host.here';
+my $name = "gmarzot\@nortelnetworks.com";
+
+$SNMP::debugging = 0;
+$n = 15; # Number of tests to run
+
+#print "1..$n\n";
+if ($n == 0) { exit 0; }
+
+# create list of varbinds for GETS, val field can be null or omitted
+my $vars = new SNMP::VarList (
+ ['sysDescr', '0', ''],
+ ['sysObjectID', '0'],
+ ['sysUpTime', '0'],
+ ['sysContact', '0'],
+ ['sysName', '0'],
+ ['sysLocation', '0'],
+ ['sysServices', '0'],
+ ['ifNumber', '0'],
+ ['ifDescr', '1'],
+ ['ifSpeed', '1'],
+
+ ['snmpInPkts', '0'],
+ ['snmpInBadVersions', '0'],
+ ['snmpInBadCommunityNames', '0'],
+ ['snmpInBadCommunityUses', '0'],
+ ['snmpInASNParseErrs', '0'],
+ ['snmpEnableAuthenTraps', '0'],
+# ['snmpSilentDrops', '0'],
+# ['snmpProxyDrops', '0'],
+# ['snmpTrapEnterprise', '2'],
+
+# ['hrStorageType', '2'],
+# ['hrSystemDate', '0'],
+ ['sysORIndex', '1'],
+ ['sysORID', '2'],
+ ['sysORDescr', '3'],
+ ['sysORUpTime', '4'],
+# ['ifName', '1'],
+ ['sysORLastChange', '0'],
+ ['ipInHdrErrors', '0'],
+ ['ipDefaultTTL', '0'],
+ ['ipInHdrErrors', '0'],
+ );
+################################################################
+# ['ipNetToMediaPhysAddress', '0'],
+# ['ipAdEntAddr', '0'],
+# ['snmpTrapOID', '0'],
+# ['hrSystemNumUsers', '0'],
+# ['hrFSLastFullBackupDate', '0'],
+# ['ifPromiscuousMode', '0'],
+
+
+
+######################### 1 #######################################
+# Fire up a session.
+ my $s1 =
+ new SNMP::Session (DestHost=>$agent_host,Version=>1,Community=>$comm,RemotePort=>$agent_port);
+ ok(defined($s1));
+
+####################### 2 ##########################################
+# Set some value and see if the value is set properly.
+
+$originalLocation = $s1->get('sysLocation.0');
+$value = 'Router Management Labs';
+$s1->set('sysLocation.0', $value);
+$finalvalue = $s1->get('sysLocation.0');
+ok($originalLocation ne $finalvalue);
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("set value is: $finalvalue\n\n");
+$s1->set('sysLocation.0', $originalLocation);
+
+######################## 3 #######################################
+
+# Now, reset that string with a non-string value.
+# This will FAIL. :)
+
+#$nonstrvalue = '.9.23.56.7';
+#$s1->set('sysLocation.0', $nonstrvalue);
+#$finalvalue = $s1->get('sysLocation.0');
+#ok(!defined($finalvalue));
+
+#if (($initialvalue cmp $finalvalue) != 0 ) {
+# ok(1);
+#}
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("set value is: $finalvalue\n\n");
+#$s1->set('sysLocation.0', $originalLocation);
+
+####################### 4 #####################################
+
+# Test for an integer (READ-ONLY)
+$originalservice = $s1->get('sysServices.0');
+#print("services is: $originalservice\n");
+$junk_service = "Nortel Networks";
+$s1->set('sysServices.0', $junk_service);
+
+$finalvalue = $s1->get('sysServices.0');
+#print("services is: $finalvalue\n");
+#print("Services is: $originalservice\n");
+ok($originalservice eq $finalvalue);
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+$s1->set('sysServices.0',$originalservice);
+#print("\n");
+
+################## 5 ######################
+# Test for an integer (READ-WRITE)
+# The snmpEnableAuthenTraps takes only two values - 1 and 2.
+# If any other value is tried to be set, it doesn't set and
+# retains the old value.
+
+$originalTrap = $s1->get('snmpEnableAuthenTraps.0');
+#print("trap is -- $originalTrap\n");
+$junk_trap = "Nortel Networks";
+$s1->set('snmpEnableAuthenTraps.0', $junk_trap);
+$finalvalue = $s1->get('snmpEnableAuthenTraps.0');
+#print("final trap is: $finalvalue\n");
+ok($finalvalue ne $junk_trap);
+# Should the error be 'Value out of range: SNMPERR_RANGE ?
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+$s1->set('snmpEnableAuthenTraps.0',$originalTrap);
+#print("\n");
+################### 6 #######################
+# Test for a TimeTicks (is this advisable? )
+# Trying to set uptime which cannot be done (READ-ONLY).
+#$time = $s1->get('sysUpTime.0');
+#print("up time is : $time hundredths of a second\n");
+#$junk_time = 12345;
+#$s1->set('sysUpTime.0', $junk_time);
+#$finalvalue = $s1->get('sysUpTime.0');
+#print("final time is: $finalvalue hundredths of a second \n");
+# Will the final value always be equal to the initial value?
+# depends on how fast this piece of code executes?
+#ok($finalvalue == $time);
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+################### 7 ######################
+
+
+#Test for a Counter32 type.
+# READ-ONLY.
+
+#$Pkts = $s1->get('snmpInPkts.0');
+#print(" pkts is : $Pkts\n");
+#$junk_pkts = -1234;
+#$s1->set('snmpInPkts.0', $junk_pkts);
+#$finalPkts = $s1->get('snmpInPkts.0');
+#print("now pkts is : $finalPkts\n");
+#ok($finalPkts > $Pkts);
+# Expecting genErr
+#ok($s1->{ErrorStr} =~ /^\(gen/);
+#print STDERR "pkts is = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+################## 8 ##############################
+
+# Set a non-accessible attribute
+$s1->set('ipAddrEntry.1', 'MyEID');
+# What should I expect - genErr or Bad variable type ?
+# What gets checked first - type or accessibility?
+# if type, then this is right..else, genErr is expected.
+ok($s1->{ErrorStr} =~ /^Bad/ );
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+################# 12 ##########################
+# Time stamp test - READ-ONLY
+#$origtime = $s1->get('sysORLastChange.0');
+#print("Time is: $origtime\n");
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#$time = $s1->set('sysORLastChange.0', 12345);
+#print("time stamp is : $time \n");
+# Should get genErr.
+#ok($time =~ /^genErr/);
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+
+############## 13 ############################
+
+# OID test
+my $oldoid = $s1->get("sysORID.1");
+#print("OID is : $oldoid\n");
+$junk_OID = ".6.6.6.6.6.6";
+$s1->set('sysORID.1', $junk_OID);
+$newOID = $s1->get("sysORID.1");
+#print("new oid is $newOID\n");
+ok($oldoid eq $newOID);
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+#print("\n");
+################ 14 ##########################
+
+# Try setting an unregistered OID.
+$junk_data = 'hehehe';
+$s1->set('ifmyData.0', $junk_data);
+
+#print STDERR "Error string = $s1->{ErrorStr}:$s1->{ErrorInd}\n";
+ok( $s1->{ErrorStr} =~ /^Unknown/ );
+
+##############################################
+
+snmptest_cleanup();
+
+
diff --git a/perl/SNMP/t/snmptest.conf b/perl/SNMP/t/snmptest.conf
new file mode 100644
index 0000000..355e310
--- /dev/null
+++ b/perl/SNMP/t/snmptest.conf
@@ -0,0 +1,21 @@
+sysservices 72
+
+createUser v3_user MD5 test_pass_auth DES test_pass_priv
+
+# sec.name source community
+com2sec v2c_user default v2c_private
+com2sec v1_user default v1_private
+com2sec v3_user default v3_private
+
+# sec.model sec.name
+group v2c_group v2c v2c_user
+group v1_group v1 v1_user
+group v3_group usm v3_user
+
+# incl/excl subtree mask
+view all included .1 80
+
+# context sec.model sec.level match read write notif
+access v2c_group "" any noauth exact all all all
+access v1_group "" any noauth exact all all all
+access v3_group "" any noauth exact all all all
diff --git a/perl/SNMP/t/startagent.pl b/perl/SNMP/t/startagent.pl
new file mode 100644
index 0000000..3e92c12
--- /dev/null
+++ b/perl/SNMP/t/startagent.pl
@@ -0,0 +1,125 @@
+# common parameters used in SNMP::Session creation and tests
+$agent_host = 'localhost';
+$agent_port = 8765;
+$trap_port = 8764;
+$mibdir = '/usr/local/share/snmp/mibs';
+$comm = 'v1_private';
+$comm2 = 'v2c_private';
+$comm3 = 'v3_private';
+$sec_name = 'v3_user';
+$oid = '.1.3.6.1.2.1.1.1';
+$name = 'sysDescr';
+$name_module = 'RFC1213-MIB::sysDescr';
+$name_module2 = 'SNMPv2-MIB::sysDescr';
+$name_long = '.iso.org.dod.internet.mgmt.mib-2.system.sysDescr';
+$name_module_long = 'RFC1213-MIB::.iso.org.dod.internet.mgmt.mib-2.system.sysDescr';
+$name_module_long2 = 'SNMPv2-MIB::.iso.org.dod.internet.mgmt.mib-2.system.sysDescr';
+$auth_pass = 'test_pass_auth';
+$priv_pass = 'test_pass_priv';
+
+# don't use any .conf files other than those specified.
+$ENV{'SNMPCONFPATH'} |= "bogus";
+
+# erroneous input to test failure cases
+$bad_comm = 'BAD_COMMUNITY';
+$bad_name = "badName";
+$bad_oid = ".1.3.6.1.2.1.1.1.1.1.1";
+$bad_host = 'bad.host.here';
+$bad_port = '9999999';
+$bad_auth_pass = 'bad_auth_pass';
+$bad_priv_pass = 'bad_priv_pass';
+$bad_sec_name = 'bad_sec_name';
+$bad_version = 7;
+
+local $snmpd_cmd;
+local $snmptrapd_cmd;
+my $line;
+
+if ($^O =~ /win32/i) {
+ require Win32::Process;
+}
+
+sub run_async {
+ my ($pidfile, $cmd, @args) = @_;
+ if (-r "$cmd" and -x "$cmd") {
+ if ($^O =~ /win32/i) {
+ $cmd =~ s/\//\\/g;
+ system "start \"$cmd\" /min cmd /c \"$cmd @args 2>&1\"";
+ } else {
+ system "$cmd @args 2>&1";
+ }
+ # Wait at most three seconds for the pid file to appear.
+ for ($i = 0; ($i < 3) && ! (-r "$pidfile"); ++$i) {
+ sleep 1;
+ }
+ } else {
+ warn "Couldn't run $cmd\n";
+ }
+}
+
+sub snmptest_cleanup {
+ kill_by_pid_file("t/snmpd.pid");
+ unlink("t/snmpd.pid");
+ kill_by_pid_file("t/snmptrapd.pid");
+ unlink("t/snmptrapd.pid");
+}
+
+sub kill_by_pid_file {
+ if ((-e "$_[0]") && (-r "$_[0]")) {
+ if ($^O !~ /win32/i) {
+ # Unix or Windows + Cygwin.
+ system "kill `cat $_[0]` > /dev/null 2>&1";
+ } else {
+ # Windows + MSVC or Windows + MinGW.
+ open(H, "<$_[0]");
+ my $pid = (<H>);
+ close (H);
+ if ($pid > 0) {
+ Win32::Process::KillProcess($pid, 0)
+ }
+ }
+ }
+}
+
+
+# Stop any processes started during a previous test.
+snmptest_cleanup();
+
+#Open the snmptest.cmd file and get the info
+if (open(CMD, "<t/snmptest.cmd")) {
+ while ($line = <CMD>) {
+ if ($line =~ /HOST\s*=>\s*(.*?)\s+$/) {
+ $agent_host = $1;
+ } elsif ($line =~ /MIBDIR\s*=>\s*(.*?)\s+$/) {
+ $mibdir = $1;
+ } elsif ($line =~ /AGENT_PORT\s*=>\s*(.*?)\s+$/) {
+ $agent_port = $1;
+ } elsif ($line =~ /SNMPD\s*=>\s*(.*?)\s+$/) {
+ $snmpd_cmd = $1;
+ } elsif ($line =~ /SNMPTRAPD\s*=>\s*(.*?)\s+$/) {
+ $snmptrapd_cmd = $1;
+ }
+ } # end of while
+ close CMD;
+} else {
+ die ("Could not start agent. Couldn't find snmptest.cmd file\n");
+}
+
+# Start snmpd and snmptrapd.
+
+#warn "\nStarting agents for test script $0\n";
+
+my $scriptname = "snmptest";
+if ($0 =~ /^t[\/\\](.*)\.t$/) {
+ $scriptname = $1;
+}
+
+if ($snmpd_cmd) {
+ run_async("t/snmpd.pid", "$snmpd_cmd", "-r -d -Lf t/snmpd-$scriptname.log -M+$mibdir -C -c t/snmptest.conf -p t/snmpd.pid ${agent_host}:${agent_port} >t/snmpd-$scriptname.stderr");
+}
+if ($snmptrapd_cmd) {
+ run_async("t/snmptrapd.pid", "$snmptrapd_cmd", "-d -Lf t/snmptrapd-$scriptname.log -p t/snmptrapd.pid -M+$mibdir -C -c t/snmptest.conf -C ${agent_host}:${trap_port} >t/snmptrapd-$scriptname.stderr");
+}
+
+1;
+
diff --git a/perl/SNMP/typemap b/perl/SNMP/typemap
new file mode 100644
index 0000000..f5e9826
--- /dev/null
+++ b/perl/SNMP/typemap
@@ -0,0 +1,2 @@
+SnmpSession * T_PTROBJ
+SnmpMibNode * T_PTROBJ
diff --git a/perl/TrapReceiver/Changes b/perl/TrapReceiver/Changes
new file mode 100644
index 0000000..cbdcdcd
--- /dev/null
+++ b/perl/TrapReceiver/Changes
@@ -0,0 +1,8 @@
+Revision history for Perl extension NetSNMP::TrapReceiver.
+
+(Please see the Net-SNMP ChangeLog file for complete details)
+
+5.2 Fri Feb 6 15:58:25 2004
+ - original version; created by h2xs 1.22 with options
+ -a -b 5.0.6 -O -n NetSNMP::TrapReceiver -x perl_snmptrapd.h
+
diff --git a/perl/TrapReceiver/MANIFEST b/perl/TrapReceiver/MANIFEST
new file mode 100644
index 0000000..469bb23
--- /dev/null
+++ b/perl/TrapReceiver/MANIFEST
@@ -0,0 +1,12 @@
+Changes
+Makefile.PL
+MANIFEST
+perl_snmptrapd.h
+ppport.h
+README
+TrapReceiver.pm
+TrapReceiver.xs
+typemap
+t/1.t
+fallback/const-c.inc
+fallback/const-xs.inc
diff --git a/perl/TrapReceiver/Makefile.PL b/perl/TrapReceiver/Makefile.PL
new file mode 100644
index 0000000..874ee21
--- /dev/null
+++ b/perl/TrapReceiver/Makefile.PL
@@ -0,0 +1,273 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+if (eval {require ExtUtils::Constant; 1}) {
+ # If you edit these definitions to change the constants used by this module,
+ # you will need to use the generated const-c.inc and const-xs.inc
+ # files to replace their "fallback" counterparts before distributing your
+ # changes.
+ my @names = (qw(NETSNMPTRAPD_AUTH_HANDLER NETSNMPTRAPD_HANDLER_BREAK
+ NETSNMPTRAPD_HANDLER_FAIL NETSNMPTRAPD_HANDLER_FINISH
+ NETSNMPTRAPD_HANDLER_OK NETSNMPTRAPD_POST_HANDLER
+ NETSNMPTRAPD_PRE_HANDLER));
+ ExtUtils::Constant::WriteConstants(
+ NAME => 'NetSNMP::TrapReceiver',
+ NAMES => \@names,
+ DEFAULT_TYPE => 'IV',
+ C_FILE => 'const-c.inc',
+ XS_FILE => 'const-xs.inc',
+ );
+
+} else {
+ use File::Copy;
+ use File::Spec;
+ foreach my $file ('const-c.inc', 'const-xs.inc') {
+ my $fallback = File::Spec->catfile('fallback', $file);
+ copy ($fallback, $file) or die "Can't copy $fallback to $file: $!";
+ }
+}
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::TrapReceiver',
+ 'VERSION_FROM' => 'TrapReceiver.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ 'PREREQ_PM' => { NetSNMP::OID => 5.02 },
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'TrapReceiver.pm',
+ AUTHOR =>
+ 'W. Hardaker <hardaker@users.sourceforge.net>') : ()),
+ 'INC' => '-I.', # e.g., '-I. -I/usr/include/other'
+ );
+
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+ $agent_link_lib = 'netsnmpagent';
+ $mibs_link_lib = 'netsnmpmibs';
+ $trapd_link_lib = 'netsnmptrapd';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib -l$agent_link_lib " .
+ "-l$mibs_link_lib -l$trapd_link_lib ";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib -l$agent_link_lib -l$mibs_link_lib -l$trapd_link_lib ";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ $Params{'LIBS'} = '-lnetsnmptrapd ' . `$opts->{'nsconfig'} --base-agent-libs`;
+ chomp($Params{'LIBS'});
+ if (!$ENV{'NETSNMP_CCFLAGS'}) {
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ } else {
+ $Params{'CCFLAGS'} = $ENV{'NETSNMP_CCFLAGS'};
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../apps/.libs -L../../apps -L../../agent/.libs -L../../agent -L../../snmplib/.libs -L../../snmplib " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+ } else {
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libdir` . " $Params{'LIBS'}";
+ }
+
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ }
+
+ return(%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/TrapReceiver/README b/perl/TrapReceiver/README
new file mode 100644
index 0000000..f1ce9fc
--- /dev/null
+++ b/perl/TrapReceiver/README
@@ -0,0 +1,30 @@
+NetSNMP/TrapReceiver version 5.2
+=================================
+
+This module will only work if Net-SNMP was compiled with
+--enable-embedded-perl and you follow the instructions in the perldoc
+manual page.
+
+INSTALLATION
+
+To install this module type the following in the Net-SNMP source directory:
+
+ ./configure --enable-embedded-perl
+ make
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ Net-SNMP, NetSNMP::OID
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2004 W. Hardaker
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
diff --git a/perl/TrapReceiver/TrapReceiver.pm b/perl/TrapReceiver/TrapReceiver.pm
new file mode 100644
index 0000000..e7e2921
--- /dev/null
+++ b/perl/TrapReceiver/TrapReceiver.pm
@@ -0,0 +1,286 @@
+package NetSNMP::TrapReceiver;
+
+use 5.00006;
+use strict;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+
+use AutoLoader;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);
+@ISA = qw(Exporter
+ DynaLoader);
+
+require NetSNMP::OID;
+
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::TrapReceiver ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ NETSNMPTRAPD_AUTH_HANDLER
+ NETSNMPTRAPD_HANDLER_BREAK
+ NETSNMPTRAPD_HANDLER_FAIL
+ NETSNMPTRAPD_HANDLER_FINISH
+ NETSNMPTRAPD_HANDLER_OK
+ NETSNMPTRAPD_POST_HANDLER
+ NETSNMPTRAPD_PRE_HANDLER
+ netsnmp_add_default_traphandler
+ netsnmp_add_global_traphandler
+ netsnmp_add_traphandler
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ NETSNMPTRAPD_AUTH_HANDLER
+ NETSNMPTRAPD_HANDLER_BREAK
+ NETSNMPTRAPD_HANDLER_FAIL
+ NETSNMPTRAPD_HANDLER_FINISH
+ NETSNMPTRAPD_HANDLER_OK
+ NETSNMPTRAPD_POST_HANDLER
+ NETSNMPTRAPD_PRE_HANDLER
+);
+
+$VERSION = '5.0702';
+
+# sub new {
+# my $type = shift;
+# my ($self);
+# %$self = @_;
+# bless($self, $type);
+# return $self;
+# }
+
+# sub register($$$$) {
+# my ($self, $oid, $sub) = @_;
+# my $reg = NetSNMP::TrapReceiver::registration::new($oid, $sub);
+# if ($reg) {
+# $reg->register();
+# $self->{'regobjs'}{$name} = $reg;
+# }
+# return $reg;
+# }
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "&NetSNMP::TrapReceiver::constant not defined" if $constname eq 'constant';
+ my ($error, $val) = constant($constname);
+ if ($error) { croak $error; }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+#XXX if ($] >= 5.00561) {
+#XXX *$AUTOLOAD = sub () { $val };
+#XXX }
+#XXX else {
+ *$AUTOLOAD = sub { $val };
+#XXX }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap NetSNMP::TrapReceiver $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::TrapReceiver - Embedded perl trap handling for Net-SNMP's snmptrapd
+
+=head1 SYNOPSIS
+
+Put the following lines in your snmptrapd.conf file:
+
+ perl NetSNMP::TrapReceiver::register("trapOID", \&myfunc);
+
+=head1 ABSTRACT
+
+The NetSNMP::TrapReceiver module is used to register perl
+subroutines into the Net-SNMP snmptrapd process. Net-SNMP MUST have
+been configured using --enable-embedded-perl. Registration of
+functions is then done through the snmptrapd.conf configuration
+file. This module can NOT be used in a normal perl script to
+receive traps. It is intended solely for embedded use within the
+snmptrapd demon.
+
+=head1 DESCRIPTION
+
+Within the snmptrapd.conf file, the keyword "perl" may be used to call
+any perl expression and using this ability, you can use the
+NetSNMP::TrapReceiver module to register functions which will be
+called every time a given notification (a trap or an inform) is
+received. Registered functions are called with 2 arguments. The
+first is a reference to a hash containing information about how the
+trap was received (what version of the SNMP protocol was used, where
+it came from, what SNMP user name or community name it was sent under,
+etc). The second argument is a reference to an array containing the
+variable bindings (OID and value information) that define the
+noification itself. Each variable is itself a reference to an array
+containing three values: a NetSNMP::OID object, the value that came
+associated with it, and the value's numeric type (see NetSNMP::ASN for
+further details on SNMP typing information).
+
+Registered functions should return one of the following values:
+
+=over 2
+
+=item NETSNMPTRAPD_HANDLER_OK
+
+Handling the trap succeeded, but lets the snmptrapd demon check for
+further appropriate handlers.
+
+=item NETSNMPTRAPD_HANDLER_FAIL
+
+Handling the trap failed, but lets the snmptrapd demon check for
+further appropriate handlers.
+
+=item NETSNMPTRAPD_HANDLER_BREAK
+
+Stops evaluating the list of handlers for this specific trap, but lets
+the snmptrapd demon apply global handlers.
+
+=item NETSNMPTRAPD_HANDLER_FINISH
+
+Stops searching for further appropriate handlers.
+
+=back
+
+If a handler function does not return anything appropriate or even
+nothing at all, a return value of NETSNMPTRAPD_HANDLER_OK is assumed.
+
+Subroutines are registered using the NetSNMP::TrapReceiver::register
+function, which takes two arguments. The first is a string describing
+the notification you want to register for (such as "linkUp" or
+"MyMIB::MyTrap" or ".1.3.6.1.4.1.2021...."). Two special keywords can
+be used in place of an OID: "default" and "all". The "default"
+keyword indicates you want your handler to be called in the case where
+no other handlers are called. The "all" keyword indicates that the
+handler should ALWAYS be called for every notification.
+
+
+=head1 EXAMPLE
+
+As an example, put the following code into a file (say
+"/usr/local/share/snmp/mytrapd.pl"):
+
+ #!/usr/bin/perl
+
+ sub my_receiver {
+ print "********** PERL RECEIVED A NOTIFICATION:\n";
+
+ # print the PDU info (a hash reference)
+ print "PDU INFO:\n";
+ foreach my $k(keys(%{$_[0]})) {
+ if ($k eq "securityEngineID" || $k eq "contextEngineID") {
+ printf " %-30s 0x%s\n", $k, unpack('h*', $_[0]{$k});
+ }
+ else {
+ printf " %-30s %s\n", $k, $_[0]{$k};
+ }
+ }
+
+ # print the variable bindings:
+ print "VARBINDS:\n";
+ foreach my $x (@{$_[1]}) {
+ printf " %-30s type=%-2d value=%s\n", $x->[0], $x->[2], $x->[1];
+ }
+ }
+
+ NetSNMP::TrapReceiver::register("all", \&my_receiver) ||
+ warn "failed to register our perl trap handler\n";
+
+ print STDERR "Loaded the example perl snmptrapd handler\n";
+
+Then, put the following line in your snmprapd.conf file:
+
+ perl do "/usr/local/share/snmp/mytrapd.pl";
+
+Start snmptrapd (as root, and the following other opions make it stay
+in the foreground and log to stderr):
+
+ snmptrapd -f -Le
+
+You should see it start up and display the final message from the end
+of the above perl script:
+
+ Loaded the perl snmptrapd handler
+ 2004-02-11 10:08:45 NET-SNMP version 5.2 Started.
+
+Then, if you send yourself a fake trap using the following example command:
+
+ snmptrap -v 2c -c mycommunity localhost 0 linkUp ifIndex.1 i 1 \
+ ifAdminStatus.1 i up ifOperStatus.1 i up ifDescr s eth0
+
+You should see the following output appear from snmptrapd as your perl
+code gets executed:
+
+ ********** PERL RECEIVED A NOTIFICATION:
+ PDU INFO:
+ notificationtype TRAP
+ receivedfrom 127.0.0.1
+ version 1
+ errorstatus 0
+ messageid 0
+ community mycommunity
+ transactionid 2
+ errorindex 0
+ requestid 765160220
+ VARBINDS:
+ sysUpTimeInstance type=67 value=0:0:00:00.00
+ snmpTrapOID.0 type=6 value=linkUp
+ ifIndex.1 type=2 value=1
+ ifAdminStatus.1 type=2 value=1
+ ifOperStatus.1 type=2 value=1
+ ifDescr type=4 value="eth0"
+
+=head1 EXPORT
+
+None by default.
+
+# =head2 Exportable constants
+
+# NETSNMPTRAPD_AUTH_HANDLER
+# NETSNMPTRAPD_HANDLER_BREAK
+# NETSNMPTRAPD_HANDLER_FAIL
+# NETSNMPTRAPD_HANDLER_FINISH
+# NETSNMPTRAPD_HANDLER_OK
+# NETSNMPTRAPD_POST_HANDLER
+# NETSNMPTRAPD_PRE_HANDLER
+
+=head1 SEE ALSO
+
+NetSNMP::OID, NetSNMP::ASN
+
+snmptrapd.conf(5) for configuring the Net-SNMP trap receiver.
+
+snmpd.conf(5) for configuring the Net-SNMP snmp agent for sending traps.
+
+http://www.Net-SNMP.org/
+
+=head1 AUTHOR
+
+W. Hardaker, E<lt>hardaker@users.sourceforge.netE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2004 by W. Hardaker
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
diff --git a/perl/TrapReceiver/TrapReceiver.xs b/perl/TrapReceiver/TrapReceiver.xs
new file mode 100644
index 0000000..531bfa4
--- /dev/null
+++ b/perl/TrapReceiver/TrapReceiver.xs
@@ -0,0 +1,313 @@
+/* -*- c -*- */
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "ppport.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "perl_snmptrapd.h"
+
+#include "const-c.inc"
+
+typedef struct trapd_cb_data_s {
+ SV *perl_cb;
+} trapd_cb_data;
+
+typedef struct netsnmp_oid_s {
+ oid *name;
+ size_t len;
+ oid namebuf[ MAX_OID_LEN ];
+} netsnmp_oid;
+
+int perl_trapd_handler( netsnmp_pdu *pdu,
+ netsnmp_transport *transport,
+ netsnmp_trapd_handler *handler)
+{
+ trapd_cb_data *cb_data;
+ SV *pcallback;
+ netsnmp_variable_list *vb;
+ netsnmp_oid *o;
+ SV **tmparray;
+ int i, c = 0;
+ u_char *outbuf;
+ size_t ob_len = 0, oo_len = 0;
+ AV *varbinds;
+ HV *pduinfo;
+ int noValuesReturned;
+ int callingCFfailed = 0;
+ int result = NETSNMPTRAPD_HANDLER_OK;
+ netsnmp_pdu * v2pdu = NULL;
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+
+ if (!pdu || !handler)
+ return 0;
+
+ /* nuke v1 PDUs */
+ if (pdu->command == SNMP_MSG_TRAP) {
+ v2pdu = convert_v1pdu_to_v2(pdu);
+ pdu = v2pdu;
+ }
+
+ cb_data = handler->handler_data;
+ if (!cb_data || !cb_data->perl_cb)
+ return 0;
+
+ pcallback = cb_data->perl_cb;
+
+ /* get PDU related info */
+ pduinfo = newHV();
+#define STOREPDU(n, v) (void)hv_store(pduinfo, n, strlen(n), v, 0)
+#define STOREPDUi(n, v) STOREPDU(n, newSViv(v))
+#define STOREPDUs(n, v) STOREPDU(n, newSVpv(v, 0))
+ STOREPDUi("version", pdu->version);
+ STOREPDUs("notificationtype", ((pdu->command == SNMP_MSG_INFORM) ? "INFORM":"TRAP"));
+ STOREPDUi("requestid", pdu->reqid);
+ STOREPDUi("messageid", pdu->msgid);
+ STOREPDUi("transactionid", pdu->transid);
+ STOREPDUi("errorstatus", pdu->errstat);
+ STOREPDUi("errorindex", pdu->errindex);
+ if (pdu->version == 3) {
+ STOREPDUi("securitymodel", pdu->securityModel);
+ STOREPDUi("securitylevel", pdu->securityLevel);
+ STOREPDU("contextName",
+ newSVpv(pdu->contextName, pdu->contextNameLen));
+ STOREPDU("contextEngineID",
+ newSVpv((char *) pdu->contextEngineID,
+ pdu->contextEngineIDLen));
+ STOREPDU("securityEngineID",
+ newSVpv((char *) pdu->securityEngineID,
+ pdu->securityEngineIDLen));
+ STOREPDU("securityName",
+ newSVpv((char *) pdu->securityName, pdu->securityNameLen));
+ } else {
+ STOREPDU("community",
+ newSVpv((char *) pdu->community, pdu->community_len));
+ }
+
+ if (transport && transport->f_fmtaddr) {
+ char *tstr = transport->f_fmtaddr(transport, pdu->transport_data,
+ pdu->transport_data_length);
+ STOREPDUs("receivedfrom", tstr);
+ netsnmp_free(tstr);
+ }
+
+
+ /*
+ * collect OID objects in a temp array first
+ */
+ /* get VARBIND related info */
+ i = count_varbinds(pdu->variables);
+ tmparray = malloc(sizeof(*tmparray) * i);
+
+ for(vb = pdu->variables; vb; vb = vb->next_variable) {
+
+ /* get the oid */
+ o = malloc(sizeof(netsnmp_oid));
+ o->name = o->namebuf;
+ o->len = vb->name_length;
+ memcpy(o->name, vb->name, vb->name_length * sizeof(oid));
+
+#undef CALL_EXTERNAL_OID_NEW
+
+#ifdef CALL_EXTERNAL_OID_NEW
+ {
+ SV *arg;
+ SV *rarg;
+
+ PUSHMARK(sp);
+
+ rarg = sv_2mortal(newSViv((IV) 0));
+ arg = sv_2mortal(newSVrv(rarg, "netsnmp_oidPtr"));
+ sv_setiv(arg, (IV) o);
+ XPUSHs(rarg);
+
+ PUTBACK;
+ i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
+ SPAGAIN;
+
+ if (i != 1) {
+ snmp_log(LOG_ERR, "unhandled OID error.\n");
+ /* ack XXX */
+ }
+ /* get the value */
+ tmparray[c++] = POPs;
+ SvREFCNT_inc(tmparray[c-1]);
+ PUTBACK;
+ }
+#else /* build it and bless ourselves */
+ {
+ HV *hv = newHV();
+ SV *rv = newRV_noinc((SV *) hv);
+ SV *rvsub = newRV_noinc((SV *) newSViv((UV) o));
+ rvsub = sv_bless(rvsub, gv_stashpv("netsnmp_oidPtr", 1));
+ (void)hv_store(hv, "oidptr", 6, rvsub, 0);
+ rv = sv_bless(rv, gv_stashpv("NetSNMP::OID", 1));
+ tmparray[c++] = rv;
+ }
+
+#endif /* build oid ourselves */
+ }
+
+ /*
+ * build the varbind lists
+ */
+ varbinds = newAV();
+ for(vb = pdu->variables, i = 0; vb; vb = vb->next_variable, i++) {
+ /* push the oid */
+ AV *vba;
+ vba = newAV();
+
+
+ /* get the value */
+ outbuf = NULL;
+ ob_len = 0;
+ oo_len = 0;
+ sprint_realloc_by_type(&outbuf, &ob_len, &oo_len, 1,
+ vb, 0, 0, 0);
+
+ av_push(vba,tmparray[i]);
+ av_push(vba,newSVpvn((char *) outbuf, oo_len));
+ netsnmp_free(outbuf);
+ av_push(vba,newSViv(vb->type));
+ av_push(varbinds, (SV *) newRV_noinc((SV *) vba));
+ }
+
+ PUSHMARK(sp);
+
+ /* store the collected information on the stack */
+ XPUSHs(sv_2mortal(newRV_noinc((SV*) pduinfo)));
+ XPUSHs(sv_2mortal(newRV_noinc((SV*) varbinds)));
+
+ /* put the stack back in order */
+ PUTBACK;
+
+ /* actually call the callback function */
+ if (SvTYPE(pcallback) == SVt_PVCV) {
+ noValuesReturned = perl_call_sv(pcallback, G_SCALAR);
+ /* XXX: it discards the results, which isn't right */
+ } else if (SvROK(pcallback) && SvTYPE(SvRV(pcallback)) == SVt_PVCV) {
+ /* reference to code */
+ noValuesReturned = perl_call_sv(SvRV(pcallback), G_SCALAR);
+ } else {
+ snmp_log(LOG_ERR, " tried to call a perl function but failed to understand its type: (ref = %p, svrok: %lu, SVTYPE: %lu)\n", pcallback, (unsigned long)SvROK(pcallback), (unsigned long)SvTYPE(pcallback));
+ callingCFfailed = 1;
+ }
+
+ if (!callingCFfailed) {
+ SPAGAIN;
+
+ if ( noValuesReturned == 0 ) {
+ snmp_log(LOG_WARNING, " perl callback function %p did not return a scalar, assuming %d (NETSNMPTRAPD_HANDLER_OK)\n", pcallback, NETSNMPTRAPD_HANDLER_OK);
+ }
+ else {
+ SV *rv = POPs;
+
+ if (SvTYPE(rv) != SVt_IV) {
+ snmp_log(LOG_WARNING, " perl callback function %p returned a scalar of type %lu instead of an integer, assuming %d (NETSNMPTRAPD_HANDLER_OK)\n", pcallback, (unsigned long)SvTYPE(rv), NETSNMPTRAPD_HANDLER_OK);
+ }
+ else {
+ int rvi = (IV)SvIVx(rv);
+
+ if ((NETSNMPTRAPD_HANDLER_OK <= rvi) && (rvi <= NETSNMPTRAPD_HANDLER_FINISH)) {
+ snmp_log(LOG_DEBUG, " perl callback function %p returns %d\n", pcallback, rvi);
+ result = rvi;
+ }
+ else {
+ snmp_log(LOG_WARNING, " perl callback function %p returned an invalid scalar integer value (%d), assuming %d (NETSNMPTRAPD_HANDLER_OK)\n", pcallback, rvi, NETSNMPTRAPD_HANDLER_OK);
+ }
+ }
+ }
+
+ PUTBACK;
+ }
+
+#ifdef DUMPIT
+ fprintf(stderr, "DUMPDUMPDUMPDUMPDUMPDUMP\n");
+ sv_dump(pduinfo);
+ fprintf(stderr, "--------------------\n");
+ sv_dump(varbinds);
+#endif
+
+ /* svREFCNT_dec((SV *) pduinfo); */
+#ifdef NOT_THIS
+ {
+ SV *vba;
+ while(vba = av_pop(varbinds)) {
+ av_undef((AV *) vba);
+ }
+ }
+ av_undef(varbinds);
+#endif
+ free(tmparray);
+
+ if (v2pdu) {
+ snmp_free_pdu(v2pdu);
+ }
+
+ FREETMPS;
+ LEAVE;
+ return result;
+}
+
+MODULE = NetSNMP::TrapReceiver PACKAGE = NetSNMP::TrapReceiver
+
+INCLUDE: const-xs.inc
+
+MODULE = NetSNMP::TrapReceiver PACKAGE = NetSNMP::TrapReceiver PREFIX=trapd_
+int
+trapd_register(regoid, perlcallback)
+ char *regoid;
+ SV *perlcallback;
+ PREINIT:
+ oid myoid[MAX_OID_LEN];
+ size_t myoid_len = MAX_OID_LEN;
+ trapd_cb_data *cb_data;
+ netsnmp_trapd_handler *handler = NULL;
+ CODE:
+ {
+ if (!regoid || !perlcallback) {
+ RETVAL = 0;
+ return;
+ }
+ if (strcmp(regoid,"all") == 0) {
+ handler =
+ netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER,
+ perl_trapd_handler);
+ } else if (strcmp(regoid,"default") == 0) {
+ handler =
+ netsnmp_add_default_traphandler(perl_trapd_handler);
+ } else if (!snmp_parse_oid(regoid, myoid, &myoid_len)) {
+ snmp_log(LOG_ERR,
+ "Failed to parse oid for perl registration: %s\n",
+ regoid);
+ RETVAL = 0;
+ return;
+ } else {
+ handler =
+ netsnmp_add_traphandler(perl_trapd_handler,
+ myoid, myoid_len);
+ }
+
+ if (handler) {
+ cb_data = malloc(sizeof(trapd_cb_data));
+ cb_data->perl_cb = newSVsv(perlcallback);
+ handler->handler_data = cb_data;
+ handler->authtypes = (1 << VACM_VIEW_EXECUTE);
+ RETVAL = 1;
+ } else {
+ RETVAL = 0;
+ }
+ }
+ OUTPUT:
+ RETVAL
diff --git a/perl/TrapReceiver/fallback/const-c.inc b/perl/TrapReceiver/fallback/const-c.inc
new file mode 100644
index 0000000..fb31362
--- /dev/null
+++ b/perl/TrapReceiver/fallback/const-c.inc
@@ -0,0 +1,146 @@
+#define PERL_constant_NOTFOUND 1
+#define PERL_constant_NOTDEF 2
+#define PERL_constant_ISIV 3
+#define PERL_constant_ISNO 4
+#define PERL_constant_ISNV 5
+#define PERL_constant_ISPV 6
+#define PERL_constant_ISPVN 7
+#define PERL_constant_ISSV 8
+#define PERL_constant_ISUNDEF 9
+#define PERL_constant_ISUV 10
+#define PERL_constant_ISYES 11
+
+#ifndef NVTYPE
+typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
+#endif
+#ifndef aTHX_
+#define aTHX_ /* 5.6 or later define this for threading support. */
+#endif
+#ifndef pTHX_
+#define pTHX_ /* 5.6 or later define this for threading support. */
+#endif
+
+static int
+constant_25 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMPTRAPD_AUTH_HANDLER NETSNMPTRAPD_HANDLER_FAIL
+ NETSNMPTRAPD_POST_HANDLER */
+ /* Offset 15 gives the best switch position. */
+ switch (name[15]) {
+ case 'N':
+ if (memEQ(name, "NETSNMPTRAPD_HANDLER_FAIL", 25)) {
+ /* ^ */
+#ifdef NETSNMPTRAPD_HANDLER_FAIL
+ *iv_return = NETSNMPTRAPD_HANDLER_FAIL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMPTRAPD_POST_HANDLER", 25)) {
+ /* ^ */
+#ifdef NETSNMPTRAPD_POST_HANDLER
+ *iv_return = NETSNMPTRAPD_POST_HANDLER;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'T':
+ if (memEQ(name, "NETSNMPTRAPD_AUTH_HANDLER", 25)) {
+ /* ^ */
+#ifdef NETSNMPTRAPD_AUTH_HANDLER
+ *iv_return = NETSNMPTRAPD_AUTH_HANDLER;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant (pTHX_ const char *name, STRLEN len, IV *iv_return) {
+ /* Initially switch on the length of the name. */
+ /* When generated this function returned values for the list of names given
+ in this section of perl code. Rather than manually editing these functions
+ to add or remove constants, which would result in this comment and section
+ of code becoming inaccurate, we recommend that you edit this section of
+ code, and use it to regenerate a new set of constant functions which you
+ then use to replace the originals.
+
+ Regenerate these constant functions by feeding this entire source file to
+ perl -x
+
+#!/usr/bin/perl -w
+use ExtUtils::Constant qw (constant_types C_constant XS_constant);
+
+my $types = {map {($_, 1)} qw(IV)};
+my @names = (qw(NETSNMPTRAPD_AUTH_HANDLER NETSNMPTRAPD_HANDLER_BREAK
+ NETSNMPTRAPD_HANDLER_FAIL NETSNMPTRAPD_HANDLER_FINISH
+ NETSNMPTRAPD_HANDLER_OK NETSNMPTRAPD_POST_HANDLER
+ NETSNMPTRAPD_PRE_HANDLER));
+
+print constant_types(); # macro defs
+foreach (C_constant ("NetSNMP::TrapReceiver", 'constant', 'IV', $types, undef, 3, @names) ) {
+ print $_, "\n"; # C constant subs
+}
+print "#### XS Section:\n";
+print XS_constant ("NetSNMP::TrapReceiver", $types);
+__END__
+ */
+
+ switch (len) {
+ case 23:
+ if (memEQ(name, "NETSNMPTRAPD_HANDLER_OK", 23)) {
+#ifdef NETSNMPTRAPD_HANDLER_OK
+ *iv_return = NETSNMPTRAPD_HANDLER_OK;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 24:
+ if (memEQ(name, "NETSNMPTRAPD_PRE_HANDLER", 24)) {
+#ifdef NETSNMPTRAPD_PRE_HANDLER
+ *iv_return = NETSNMPTRAPD_PRE_HANDLER;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 25:
+ return constant_25 (aTHX_ name, iv_return);
+ break;
+ case 26:
+ if (memEQ(name, "NETSNMPTRAPD_HANDLER_BREAK", 26)) {
+#ifdef NETSNMPTRAPD_HANDLER_BREAK
+ *iv_return = NETSNMPTRAPD_HANDLER_BREAK;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 27:
+ if (memEQ(name, "NETSNMPTRAPD_HANDLER_FINISH", 27)) {
+#ifdef NETSNMPTRAPD_HANDLER_FINISH
+ *iv_return = NETSNMPTRAPD_HANDLER_FINISH;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
diff --git a/perl/TrapReceiver/fallback/const-xs.inc b/perl/TrapReceiver/fallback/const-xs.inc
new file mode 100644
index 0000000..faa384b
--- /dev/null
+++ b/perl/TrapReceiver/fallback/const-xs.inc
@@ -0,0 +1,88 @@
+void
+constant(sv)
+ PREINIT:
+#ifdef dXSTARG
+ dXSTARG; /* Faster if we have it. */
+#else
+ dTARGET;
+#endif
+ STRLEN len;
+ int type;
+ IV iv;
+ /* NV nv; Uncomment this if you need to return NVs */
+ /* const char *pv; Uncomment this if you need to return PVs */
+ INPUT:
+ SV * sv;
+ const char * s = SvPV(sv, len);
+ PPCODE:
+ /* Change this to constant(aTHX_ s, len, &iv, &nv);
+ if you need to return both NVs and IVs */
+ type = constant(aTHX_ s, len, &iv);
+ /* Return 1 or 2 items. First is error message, or undef if no error.
+ Second, if present, is found value */
+ switch (type) {
+ case PERL_constant_NOTFOUND:
+ sv = sv_2mortal(newSVpvf("%s is not a valid NetSNMP::TrapReceiver macro", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_NOTDEF:
+ sv = sv_2mortal(newSVpvf(
+ "Your vendor has not defined NetSNMP::TrapReceiver macro %s, used", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_ISIV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHi(iv);
+ break;
+ /* Uncomment this if you need to return NOs
+ case PERL_constant_ISNO:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_no);
+ break; */
+ /* Uncomment this if you need to return NVs
+ case PERL_constant_ISNV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHn(nv);
+ break; */
+ /* Uncomment this if you need to return PVs
+ case PERL_constant_ISPV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, strlen(pv));
+ break; */
+ /* Uncomment this if you need to return PVNs
+ case PERL_constant_ISPVN:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, iv);
+ break; */
+ /* Uncomment this if you need to return SVs
+ case PERL_constant_ISSV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(sv);
+ break; */
+ /* Uncomment this if you need to return UNDEFs
+ case PERL_constant_ISUNDEF:
+ break; */
+ /* Uncomment this if you need to return UVs
+ case PERL_constant_ISUV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHu((UV)iv);
+ break; */
+ /* Uncomment this if you need to return YESs
+ case PERL_constant_ISYES:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_yes);
+ break; */
+ default:
+ sv = sv_2mortal(newSVpvf(
+ "Unexpected return type %d while processing NetSNMP::TrapReceiver macro %s, used",
+ type, s));
+ PUSHs(sv);
+ }
diff --git a/perl/TrapReceiver/netsnmp-feature-definitions.h b/perl/TrapReceiver/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..bd331e3
--- /dev/null
+++ b/perl/TrapReceiver/netsnmp-feature-definitions.h
@@ -0,0 +1,6 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+netsnmp_feature_require(netsnmp_add_default_traphandler)
+netsnmp_feature_require(memory_free)
+
diff --git a/perl/TrapReceiver/perl_snmptrapd.h b/perl/TrapReceiver/perl_snmptrapd.h
new file mode 100644
index 0000000..cce1d6a
--- /dev/null
+++ b/perl/TrapReceiver/perl_snmptrapd.h
@@ -0,0 +1,44 @@
+/* h2xs -b 5.0.6 -O -n NetSNMP::TrapReceiver -x perl_snmptrapd.h */
+
+/* this file was crafted by hand from the contents of the Net-SNMP
+ file: apps/snmaptrapd_handlers.h and other headers. */
+
+typedef struct netsnmp_trapd_handler_s netsnmp_trapd_handler;
+
+typedef int (Netsnmp_Trap_Handler)(netsnmp_pdu *pdu,
+ netsnmp_transport *transport,
+ netsnmp_trapd_handler *handler);
+
+struct netsnmp_trapd_handler_s {
+ int *trapoid;
+ int trapoid_len;
+ char *token; /* Or an array of tokens? */
+ char *format; /* Formatting string */
+ int version; /* ??? */
+ int authtypes;
+ int flags;
+ Netsnmp_Trap_Handler *handler;
+ void *handler_data;
+
+ netsnmp_trapd_handler *nexth; /* Next handler for this trap */
+ /* Doubly-linked list of traps with registered handlers */
+ netsnmp_trapd_handler *prevt;
+ netsnmp_trapd_handler *nextt;
+};
+
+#define NETSNMPTRAPD_AUTH_HANDLER 1
+#define NETSNMPTRAPD_PRE_HANDLER 2
+#define NETSNMPTRAPD_POST_HANDLER 3
+
+#define NETSNMPTRAPD_HANDLER_OK 1 /* Succeed, & keep going */
+#define NETSNMPTRAPD_HANDLER_FAIL 2 /* Failed but keep going */
+#define NETSNMPTRAPD_HANDLER_BREAK 3 /* Move to the next list */
+#define NETSNMPTRAPD_HANDLER_FINISH 4 /* No further processing */
+
+netsnmp_trapd_handler *netsnmp_add_global_traphandler(int list, Netsnmp_Trap_Handler handler);
+netsnmp_trapd_handler *netsnmp_add_default_traphandler(Netsnmp_Trap_Handler handler);
+netsnmp_trapd_handler *netsnmp_add_traphandler(Netsnmp_Trap_Handler handler,
+ oid *trapOid, int trapOidLen);
+/*
+netsnmp_trapd_handler *netsnmp_get_traphandler(oid *trapOid, int trapOidLen);
+*/
diff --git a/perl/TrapReceiver/ppport.h b/perl/TrapReceiver/ppport.h
new file mode 100644
index 0000000..b2dbb6a
--- /dev/null
+++ b/perl/TrapReceiver/ppport.h
@@ -0,0 +1,562 @@
+
+/* ppport.h -- Perl/Pollution/Portability Version 2.0002
+ *
+ * Automatically Created by Devel::PPPort on Fri Feb 6 15:58:25 2004
+ *
+ * Do NOT edit this file directly! -- Edit PPPort.pm instead.
+ *
+ * Version 2.x, Copyright (C) 2001, Paul Marquess.
+ * Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+ * This code may be used and distributed under the same license as any
+ * version of Perl.
+ *
+ * This version of ppport.h is designed to support operation with Perl
+ * installations back to 5.004, and has been tested up to 5.8.0.
+ *
+ * If this version of ppport.h is failing during the compilation of this
+ * module, please check if a newer version of Devel::PPPort is available
+ * on CPAN before sending a bug report.
+ *
+ * If you are using the latest version of Devel::PPPort and it is failing
+ * during compilation of this module, please send a report to perlbug@perl.com
+ *
+ * Include all following information:
+ *
+ * 1. The complete output from running "perl -V"
+ *
+ * 2. This file.
+ *
+ * 3. The name & version of the module you were trying to build.
+ *
+ * 4. A full log of the build that failed.
+ *
+ * 5. Any other information that you think could be relevant.
+ *
+ *
+ * For the latest version of this code, please retreive the Devel::PPPort
+ * module from CPAN.
+ *
+ */
+
+/*
+ * In order for a Perl extension module to be as portable as possible
+ * across differing versions of Perl itself, certain steps need to be taken.
+ * Including this header is the first major one, then using dTHR is all the
+ * appropriate places and using a PL_ prefix to refer to global Perl
+ * variables is the second.
+ *
+ */
+
+
+/* If you use one of a few functions that were not present in earlier
+ * versions of Perl, please add a define before the inclusion of ppport.h
+ * for a static include, or use the GLOBAL request in a single module to
+ * produce a global definition that can be referenced from the other
+ * modules.
+ *
+ * Function: Static define: Extern define:
+ * newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
+ *
+ */
+
+
+/* To verify whether ppport.h is needed for your module, and whether any
+ * special defines should be used, ppport.h can be run through Perl to check
+ * your source code. Simply say:
+ *
+ * perl -x ppport.h *.c *.h *.xs foo/bar*.c [etc]
+ *
+ * The result will be a list of patches suggesting changes that should at
+ * least be acceptable, if not necessarily the most efficient solution, or a
+ * fix for all possible problems. It won't catch where dTHR is needed, and
+ * doesn't attempt to account for global macro or function definitions,
+ * nested includes, typemaps, etc.
+ *
+ * In order to test for the need of dTHR, please try your module under a
+ * recent version of Perl that has threading compiled-in.
+ *
+ */
+
+
+/*
+#!/usr/bin/perl
+@ARGV = ("*.xs") if !@ARGV;
+%badmacros = %funcs = %macros = (); $replace = 0;
+foreach (<DATA>) {
+ $funcs{$1} = 1 if /Provide:\s+(\S+)/;
+ $macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
+ $replace = $1 if /Replace:\s+(\d+)/;
+ $badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/;
+ $badmacros{$1}=$2 if /Replace (\S+) with (\S+)/;
+}
+foreach $filename (map(glob($_),@ARGV)) {
+ unless (open(IN, "<$filename")) {
+ warn "Unable to read from $file: $!\n";
+ next;
+ }
+ print "Scanning $filename...\n";
+ $c = ""; while (<IN>) { $c .= $_; } close(IN);
+ $need_include = 0; %add_func = (); $changes = 0;
+ $has_include = ($c =~ /#.*include.*ppport/m);
+
+ foreach $func (keys %funcs) {
+ if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
+ if ($c !~ /\b$func\b/m) {
+ print "If $func isn't needed, you don't need to request it.\n" if
+ $changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
+ } else {
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ } else {
+ if ($c =~ /\b$func\b/m) {
+ $add_func{$func} =1 ;
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ if (not $need_include) {
+ foreach $macro (keys %macros) {
+ if ($c =~ /\b$macro\b/m) {
+ print "Uses $macro\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ foreach $badmacro (keys %badmacros) {
+ if ($c =~ /\b$badmacro\b/m) {
+ $changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
+ print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
+ $need_include = 1;
+ }
+ }
+
+ if (scalar(keys %add_func) or $need_include != $has_include) {
+ if (!$has_include) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
+ "#include \"ppport.h\"\n";
+ $c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
+ } elsif (keys %add_func) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func));
+ $c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
+ }
+ if (!$need_include) {
+ print "Doesn't seem to need ppport.h.\n";
+ $c =~ s/^.*#.*include.*ppport.*\n//m;
+ }
+ $changes++;
+ }
+
+ if ($changes) {
+ open(OUT,">/tmp/ppport.h.$$");
+ print OUT $c;
+ close(OUT);
+ open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
+ while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
+ close(DIFF);
+ unlink("/tmp/ppport.h.$$");
+ } else {
+ print "Looks OK\n";
+ }
+}
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef PERL_REVISION
+# ifndef __PATCHLEVEL_H_INCLUDED__
+# include "patchlevel.h"
+# endif
+# ifndef PERL_REVISION
+# define PERL_REVISION (5)
+ /* Replace: 1 */
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+ /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+ /* Replace: 0 */
+# endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6
+ (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+# error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifndef ERRSV
+# define ERRSV perl_get_sv("@",FALSE)
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+# define PL_Sv Sv
+# define PL_compiling compiling
+# define PL_copline copline
+# define PL_curcop curcop
+# define PL_curstash curstash
+# define PL_defgv defgv
+# define PL_dirty dirty
+# define PL_dowarn dowarn
+# define PL_hints hints
+# define PL_na na
+# define PL_perldb perldb
+# define PL_rsfp_filters rsfp_filters
+# define PL_rsfpv rsfp
+# define PL_stdingv stdingv
+# define PL_sv_no sv_no
+# define PL_sv_undef sv_undef
+# define PL_sv_yes sv_yes
+/* Replace: 0 */
+#endif
+
+#ifndef PERL_UNUSED_DECL
+#ifdef HASATTRIBUTE
+# if defined(__GNUC__) && defined(__cplusplus)
+# define PERL_UNUSED_DECL
+# else
+# define PERL_UNUSED_DECL __attribute__((unused))
+# endif
+#else
+# define PERL_UNUSED_DECL
+#endif
+#endif
+
+#ifndef dNOOP
+# define NOOP (void)0
+# define dNOOP extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef dTHR
+# define dTHR dNOOP
+#endif
+
+#ifndef dTHX
+# define dTHX dNOOP
+# define dTHXa(x) dNOOP
+# define dTHXoa(x) dNOOP
+#endif
+
+#ifndef pTHX
+# define pTHX void
+# define pTHX_
+# define aTHX
+# define aTHX_
+#endif
+
+/* IV could also be a quad (say, a long long), but Perls
+ * capable of those should have IVSIZE already. */
+#if !defined(IVSIZE) && defined(LONGSIZE)
+# define IVSIZE LONGSIZE
+#endif
+#ifndef IVSIZE
+# define IVSIZE 4 /* A bold guess, but the best we can make. */
+#endif
+
+#ifndef UVSIZE
+# define UVSIZE IVSIZE
+#endif
+
+#ifndef NVTYPE
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+# define NVTYPE long double
+# else
+# define NVTYPE double
+# endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+# define PTRV UV
+# define INT2PTR(any,d) (any)(d)
+#else
+# if PTRSIZE == LONGSIZE
+# define PTRV unsigned long
+# else
+# define PTRV unsigned
+# endif
+# define INT2PTR(any,d) (any)(PTRV)(d)
+#endif
+#define NUM2PTR(any,d) (any)(PTRV)(d)
+#define PTR2IV(p) INT2PTR(IV,p)
+#define PTR2UV(p) INT2PTR(UV,p)
+#define PTR2NV(p) NUM2PTR(NV,p)
+#if PTRSIZE == LONGSIZE
+# define PTR2ul(p) (unsigned long)(p)
+#else
+# define PTR2ul(p) INT2PTR(unsigned long,p)
+#endif
+
+#endif /* !INT2PTR */
+
+#ifndef boolSV
+# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+#ifndef gv_stashpvn
+# define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
+#endif
+
+#ifndef newSVpvn
+# define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0))
+#endif
+
+#ifndef newRV_inc
+/* Replace: 1 */
+# define newRV_inc(sv) newRV(sv)
+/* Replace: 0 */
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+# define DEFSV GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+#ifndef newRV_noinc
+# ifdef __GNUC__
+# define newRV_noinc(sv) \
+ ({ \
+ SV *nsv = (SV*)newRV(sv); \
+ SvREFCNT_dec(sv); \
+ nsv; \
+ })
+# else
+# if defined(USE_THREADS)
+static SV * newRV_noinc (SV * sv)
+{
+ SV *nsv = (SV*)newRV(sv);
+ SvREFCNT_dec(sv);
+ return nsv;
+}
+# else
+# define newRV_noinc(sv) \
+ (PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv)
+# endif
+# endif
+#endif
+
+/* Provide: newCONSTSUB */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))
+
+#if defined(NEED_newCONSTSUB)
+static
+#else
+extern void newCONSTSUB(HV * stash, char * name, SV *sv);
+#endif
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+void
+newCONSTSUB(stash,name,sv)
+HV *stash;
+char *name;
+SV *sv;
+{
+ U32 oldhints = PL_hints;
+ HV *old_cop_stash = PL_curcop->cop_stash;
+ HV *old_curstash = PL_curstash;
+ line_t oldline = PL_curcop->cop_line;
+ PL_curcop->cop_line = PL_copline;
+
+ PL_hints &= ~HINT_BLOCK_SCOPE;
+ if (stash)
+ PL_curstash = PL_curcop->cop_stash = stash;
+
+ newSUB(
+
+#if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22))
+ /* before 5.003_22 */
+ start_subparse(),
+#else
+# if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22)
+ /* 5.003_22 */
+ start_subparse(0),
+# else
+ /* 5.003_23 onwards */
+ start_subparse(FALSE, 0),
+# endif
+#endif
+
+ newSVOP(OP_CONST, 0, newSVpv(name,0)),
+ newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */
+ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+ );
+
+ PL_hints = oldhints;
+ PL_curcop->cop_stash = old_cop_stash;
+ PL_curstash = old_curstash;
+ PL_curcop->cop_line = oldline;
+}
+#endif
+
+#endif /* newCONSTSUB */
+
+#ifndef START_MY_CXT
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C. All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe. See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ * all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ * (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ * MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ * access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT)
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope). The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = perl_get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \
+ sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+ dMY_CXT_SV; \
+ /* newSV() allocates one more than needed */ \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Zero(my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT (*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used. Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT my_cxt_t *my_cxtp
+#define pMY_CXT_ pMY_CXT,
+#define _pMY_CXT ,pMY_CXT
+#define aMY_CXT my_cxtp
+#define aMY_CXT_ aMY_CXT,
+#define _aMY_CXT ,aMY_CXT
+
+#else /* single interpreter */
+
+#define START_MY_CXT static my_cxt_t my_cxt;
+#define dMY_CXT_SV dNOOP
+#define dMY_CXT dNOOP
+#define MY_CXT_INIT NOOP
+#define MY_CXT my_cxt
+
+#define pMY_CXT void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif
+
+#endif /* START_MY_CXT */
+
+#ifndef IVdf
+# if IVSIZE == LONGSIZE
+# define IVdf "ld"
+# define UVuf "lu"
+# define UVof "lo"
+# define UVxf "lx"
+# define UVXf "lX"
+# else
+# if IVSIZE == INTSIZE
+# define IVdf "d"
+# define UVuf "u"
+# define UVof "o"
+# define UVxf "x"
+# define UVXf "X"
+# endif
+# endif
+#endif
+
+#ifndef NVef
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+ defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
+# define NVef PERL_PRIeldbl
+# define NVff PERL_PRIfldbl
+# define NVgf PERL_PRIgldbl
+# else
+# define NVef "e"
+# define NVff "f"
+# define NVgf "g"
+# endif
+#endif
+
+#ifndef AvFILLp /* Older perls (<=5.003) lack AvFILLp */
+# define AvFILLp AvFILL
+#endif
+
+#ifdef SvPVbyte
+# if PERL_REVISION == 5 && PERL_VERSION < 7
+ /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+# undef SvPVbyte
+# define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+ static char *
+ my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+ {
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+ }
+# endif
+#else
+# define SvPVbyte SvPV
+#endif
+
+#ifndef SvPV_nolen
+# define SvPV_nolen(sv) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? SvPVX(sv) : sv_2pv_nolen(sv))
+ static char *
+ sv_2pv_nolen(pTHX_ register SV *sv)
+ {
+ STRLEN n_a;
+ return sv_2pv(sv, &n_a);
+ }
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
diff --git a/perl/TrapReceiver/t/1.t b/perl/TrapReceiver/t/1.t
new file mode 100644
index 0000000..2ece8f2
--- /dev/null
+++ b/perl/TrapReceiver/t/1.t
@@ -0,0 +1,38 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl 1.t'
+
+#########################
+
+# change 'tests => 2' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { plan tests => 2 };
+# use NetSNMP::TrapReceiver; # we can't include this directly in a module.
+ok(1); # If we made it this far, we're ok. Bogus test!
+
+
+my $fail;
+foreach my $constname (qw(
+ NETSNMPTRAPD_AUTH_HANDLER NETSNMPTRAPD_HANDLER_BREAK
+ NETSNMPTRAPD_HANDLER_FAIL NETSNMPTRAPD_HANDLER_FINISH
+ NETSNMPTRAPD_HANDLER_OK NETSNMPTRAPD_POST_HANDLER
+ NETSNMPTRAPD_PRE_HANDLER)) {
+ next if (eval "my \$a = $constname; 1");
+ if ($@ =~ /^Your vendor has not defined NetSNMP::TrapReceiver macro $constname/) {
+ print "# pass: $@";
+ } else {
+ print "# fail: $@";
+ $fail = 1;
+ }
+}
+if ($fail) {
+ print "not ok 2\n";
+} else {
+ print "ok 2\n";
+}
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
diff --git a/perl/TrapReceiver/typemap b/perl/TrapReceiver/typemap
new file mode 100644
index 0000000..6dea727
--- /dev/null
+++ b/perl/TrapReceiver/typemap
@@ -0,0 +1,5 @@
+TYPEMAP
+netsnmp_trapd_registration * T_PTROBJ
+Netsnmp_Trap_Handler T_PTROBJ
+netsnmp_trapd_handler * T_PTROBJ
+oid * T_PTROBJ
diff --git a/perl/agent/Changes b/perl/agent/Changes
new file mode 100644
index 0000000..fce59c2
--- /dev/null
+++ b/perl/agent/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension NetSNMP::agent.
+
+0.01 Thu Dec 27 22:24:58 2001
+ - original version; created by h2xs 1.20 with options
+ -x -O -n NetSNMP::agent ./stuff/perl_agent.h
+
diff --git a/perl/agent/MANIFEST b/perl/agent/MANIFEST
new file mode 100644
index 0000000..156494a
--- /dev/null
+++ b/perl/agent/MANIFEST
@@ -0,0 +1,15 @@
+Changes
+MANIFEST
+Makefile.PL
+agent.pm
+netsnmp_request_infoPtr.pm
+agent.xs
+test.pl
+typemap
+default_store/Makefile.PL
+default_store/default_store.pm
+default_store/default_store.xs
+default_store/test.pl
+Support/Makefile.PL
+Support/Support.pm
+
diff --git a/perl/agent/Makefile.PL b/perl/agent/Makefile.PL
new file mode 100644
index 0000000..4f7bee3
--- /dev/null
+++ b/perl/agent/Makefile.PL
@@ -0,0 +1,240 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::agent',
+ 'VERSION_FROM' => 'agent.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ 'PM' => {
+ 'agent.pm' => '$(INST_LIBDIR)/agent.pm',
+ 'netsnmp_request_infoPtr.pm' =>
+ '$(INST_LIBDIR)/agent/netsnmp_request_infoPtr.pm'
+ },
+ 'PREREQ_PM' => {},
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+ $agent_link_lib = 'netsnmpagent';
+ $mibs_link_lib = 'netsnmpmibs';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib -l$agent_link_lib " .
+ "-l$mibs_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib -l$agent_link_lib -l$mibs_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --base-agent-libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ -L../../agent/.libs -L../../agent/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+# } else {
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libdir` . $Params{'LIBS'};
+# $Params{'PREREQ_PM'} = {'NetSNMP::OID' => '0.1'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+
+ return(%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/agent/Support/Makefile.PL b/perl/agent/Support/Makefile.PL
new file mode 100644
index 0000000..48815b6
--- /dev/null
+++ b/perl/agent/Support/Makefile.PL
@@ -0,0 +1,229 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::agent::Support',
+ 'VERSION_FROM' => 'Support.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ 'PREREQ_PM' => {},
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ @LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ @LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else
+ {
+ $opts = NetSNMPGetOpts("../../");
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+ return (%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/agent/Support/Support.pm b/perl/agent/Support/Support.pm
new file mode 100644
index 0000000..41cf694
--- /dev/null
+++ b/perl/agent/Support/Support.pm
@@ -0,0 +1,461 @@
+####################################################################
+#
+# SnmpAgent module for use with the code generated by mib2c with the
+# embedded perl configuration file mib2c.perl.conf
+#
+# Copyright Tripleplay Services Limited 2005
+# All rights reserved.
+#
+# Use is subject to license terms specified in the COPYING file
+# distributed with the Net-SNMP package.
+#
+####################################################################
+
+package NetSNMP::agent::Support;
+require Exporter;
+
+use NetSNMP::OID (':all');
+use NetSNMP::agent (':all');
+use NetSNMP::ASN (':all');
+use NetSNMP::default_store (':all');
+use Data::Dumper;
+
+
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
+
+@ISA = qw(Exporter getLeaf);
+@EXPORT = qw(registerAgent getOidElement setOidElement);
+@EXPORT_OK = qw();
+$VERSION = '5.0702';
+
+use strict;
+use warnings;
+
+BEGIN {
+ print STDERR "Module SnmpAgent.pm loaded ok\n";
+}
+
+# set to 1 to get extra debugging information
+my $debugging = 0;
+
+# if we're not embedded, this will get auto-set below to 1
+my $subagent = 0;
+
+################################################################
+# The oidtable is used for rapid random access to elements with known
+# oids, such as when doing gets/sets. It is not so good for
+# ordered access. For that we build a tree (see below) and setup
+# next links in the oidtable to aid in evaluating where to go next
+# for GETNEXT requests.
+################################################################
+my $oidtable;
+my $oidtree;
+
+# oidroot holds the top most oid record in the table.
+my $oidroot = "";
+
+################################################################
+# Build a tree for handling getnext requests
+# Some parts borrowed from the perl cookbook
+################################################################
+sub buildTree {
+ my ($new_oidtable) = @_;
+ foreach my $key (keys %$new_oidtable) {
+ insert($oidtree, $key);
+ }
+}
+
+sub printTree {
+ my ($tree) = @_;
+ return unless $tree;
+ printTree($tree->{LEFT});
+ print $tree->{VALUE}. "\n";
+ printTree($tree->{RIGHT});
+}
+
+my $prev="";
+##############################################################
+# Walk the sorted oid tree and set the 'next' links in the
+# oidtable.
+##############################################################
+sub doLinks {
+ my ($tree) = @_;
+ return unless $tree;
+ doLinks($tree->{LEFT});
+ if($oidroot eq "") {
+ $oidroot = $tree->{VALUE};
+# print "Setting oidroot to $oidroot\n";
+ }
+ if($prev ne "") {
+ $oidtable->{$prev}->{next} = $tree->{VALUE};
+ }
+ $prev = $tree->{VALUE};
+ my $node = $oidtable->{$tree->{VALUE}};
+ doLinks($tree->{RIGHT});
+}
+
+################################################################
+# Insert a node into the tree
+################################################################
+sub insert {
+ my ($tree, $value) = @_;
+ unless ($tree) {
+ $tree = {}; # Allocate memory
+ $tree->{VALUE} = $value;
+ $tree->{LEFT} = undef;
+ $tree->{RIGHT} = undef;
+ $_[0] = $tree;
+ return ;
+ }
+ my $tv = new NetSNMP::OID($tree->{VALUE});
+ my $mv = new NetSNMP::OID($value);
+ if ($tv > $mv) {
+ insert($tree->{LEFT}, $value);
+ } elsif ($tv < $mv) {
+ insert($tree->{RIGHT}, $value);
+ } else {
+ print "ERR: Duplicate insert of $value\n";
+ }
+}
+
+#################################################################
+## Main interface.
+## registerAgent(oid);
+#################################################################
+sub registerAgent {
+ my $agent = shift;
+ my $regat = shift;
+ my $new_oidtable = shift;
+
+ foreach (keys %$new_oidtable) { $oidtable->{$_} = $new_oidtable->{$_}; }
+
+ # This is necessary to avoid problems traversing trees where the
+ # IID index is range-limited to not include .0, which is used as a
+ # placeholder in the oidtable.
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DONT_CHECK_RANGE, 1);
+
+ print STDERR "Building OID tree\n";
+ buildTree($new_oidtable);
+ doLinks($oidtree);
+
+# print Dumper($oidtable);
+
+ # Debug. Print the list of oids in their next ordering
+ my $node = $oidroot;
+ while($node) {
+# print $node . "\n";
+ $node = $oidtable->{$node}->{next};
+ }
+
+# where we are going to hook onto
+ my $regoid = new NetSNMP::OID($regat);
+ print "registering at ",$regoid,"\n" if ($debugging);
+
+# If we're not running embedded within the agent, then try to start
+# our own subagent instead.
+ if (! $agent) {
+ $agent = new NetSNMP::agent('Name' => 'test', # reads test.conf
+ 'AgentX' => 1); # make us a subagent
+ $subagent = 1;
+ print STDERR "started us as a subagent ($agent)\n"
+ }
+
+# we register ourselves with the master agent we're embedded in. The
+# global $agent variable is how we do this:
+ print Dumper($agent) if ($debugging);
+ $agent->register('myname',$regoid, \&my_snmp_handler);
+}
+
+
+######################################################################
+# The subroutine to handle the incoming requests to our
+# part of the OID tree. This subroutine will get called for all
+# requests within the OID space under the registration oid made above.
+######################################################################
+sub my_snmp_handler {
+ my ($handler, $registration_info, $request_info, $requests) = @_;
+
+ my $request;
+ my $reqnum=1;
+
+# print STDERR "refs: ",join(", ", ref($handler), ref($registration_info),
+ # ref($request_info), ref($requests)),"\n";
+
+ print "==============================================\n" if ($debugging);
+
+ print STDERR "processing a request of type " .
+ $request_info->getMode() . "\n" if ($debugging) ;
+ #
+ # Process each varbind in teh list of requests
+ #
+ for($request = $requests; $request; $request = $request->next()) {
+ my $oid = $request->getOID();
+ print STDERR "-- processing request of $oid (request $reqnum) \n" if ($debugging);
+
+ #
+ # Handle the different request types
+ #
+ my $mode = $request_info->getMode();
+ if ($mode == MODE_GET) {
+ getLeaf($oid, $request, $request_info);
+ } elsif ($mode == MODE_GETNEXT) {
+ getNextOid($oid, $request, $request_info);
+ } else {
+ print STDERR "Request type $mode not supported\n";
+ }
+
+ $reqnum++;
+ }
+
+ print STDERR " finished processing\n"
+ if ($debugging);
+}
+
+##########################################################
+# Given an oid see if there is an entry in the oidtable
+# and get the record if there is.
+#
+# Passed the oid as a NetSNMP oid
+#
+# Returns the record if found
+#
+##########################################################
+sub findOid {
+ my $oid = shift;
+
+ # Convert the OID to a string
+ # The index items are temporarily set to zero to cater for tables
+ my @indexes = $oid->to_array();
+
+ my $idxoffset = $oid->length() - 1;
+
+ # Locate the record in the table if it exists
+ # If no match then try setting index values to zero until
+ # we have a match of we exhaust the oid
+ while($idxoffset) {
+ my $oidstr="." . join ".", @indexes;
+ my $rec = $oidtable->{$oidstr};
+
+ # Return the record if found and the repaired index array
+ if($rec) {
+ print "Found OID $oid ($oidstr) in the table\n" if ($debugging);
+ return ($rec);
+ } else {
+ # Not found. Set the next potential index to zero and
+ # try again
+ $indexes[$idxoffset] = 0;
+ $idxoffset--;
+ }
+ }
+ return (0);
+}
+
+
+##########################################################
+# Sub to return an element of an OID
+# This is commonly used to get an index item from
+# an OID for table accesses.
+##########################################################
+sub getOidElement {
+ my ($oid, $idx) = @_;
+
+ my @idx = $oid->to_array();
+ my $len = $oid->length();
+ my $val = $idx[$idx];
+ return $val;
+}
+##########################################################
+# Sub to set an element of an OID
+# Returns a new NetSNMP::OID object
+##########################################################
+sub setOidElement {
+ my ($oid, $offset, $val) = @_;
+
+ my @idx = $oid->to_array();
+ $idx[$offset] = $val;
+ my $str = "." . join ".", @idx;
+ return new NetSNMP::OID($str);;
+}
+
+
+##########################################################
+# Given scalar record in the oidtable get the value.
+# Passed the record and the request.
+##########################################################
+sub getScalar {
+ my ($rec, $request) = @_;
+
+ # Got a scalar node from the table
+ my $type = $rec->{type};
+
+ # Call the GET function
+ my $val = $rec->{func}();
+
+ $request->setValue($type, $val);
+}
+
+############################################################
+# Given a record in the OID table that is a columnar object
+# locate any objects that have the required index.
+#
+# Passed the record, the oid object and the request
+############################################################
+sub getColumnar {
+ my ($rec, $oid, $request) = @_;
+
+ print "Get Columnar $oid\n" if ($debugging);
+
+ my $type = $rec->{type};
+ my $args = $rec->{args};
+
+ # Check the index is in range and exists
+ if($rec->{check}($oid)) {
+
+ # Call the handler function with the oid
+ my $val = $rec->{func}($oid);
+
+ # Set the value found in the request
+ $request->setValue($type, $val);
+ }
+}
+
+######################################################################
+#
+# If the oid is in range then set the data in the supplied request
+# object.
+#
+# Tries to get a scalar first then checks the coumnar second
+#
+# Return 1 if successful or 0 if not
+#
+#######################################################################
+sub getLeaf {
+ my $oid = shift;
+ my $request = shift;
+ my $request_info = shift;
+
+ print "getLeaf: $oid\n" if ($debugging);
+
+ # Find an oid entry in the table
+ my ($rec) = findOid($oid);
+ if($rec) {
+
+ # Record found. Use the istable flag to pass control to the
+ # scalar or coulmnar handler
+ if($rec->{istable} == 1) {
+ return getColumnar($rec, $oid, $request);
+ } else {
+ return getScalar($rec, $request);
+ }
+ }
+}
+
+#####################################################
+#
+# getNextOid
+#
+# The workhorse for GETNEXT.
+# Given an OID, locates the next oid and if valid does
+# a getLeaf on that OID. It does this by walking the list of
+# OIDs. We try to otimise the walk by first looking for an oid
+# in the list as follows:
+#
+# 1. Try to locate an oid match in the table.
+# If that succeeds then look for the next object in the table
+# using the next attribute and get that object.
+#
+# 2. If the OID found is a table element then use the table
+# specific index handler to see if there is an item with the
+# next index.This will retutn either an oid which we get, or 0.
+# If there is not then we continue our walk along the tree
+#
+# 3.If the supplied oid is not found, but is in the range of our oids
+# then we start at the root oid and walk the list until we either
+# drop of the end, or we fnd an OID that is greater than the OID supplied.
+# In all cases if we sucessfully find an OID to retrieve,
+# then we set the next OID in the resposnse.
+#
+######################################################
+sub getNextOid {
+ my $oid = shift;
+ my $request = shift;
+ my $request_info = shift;
+
+ my $curoid = new NetSNMP::OID($oidroot); # Current OID in the walk
+
+ # Find the starting position if we can
+ my $current = findOid($oid);
+# print Dumper($current);
+ if($current) {
+ # Found the start in the table
+ $curoid = new NetSNMP::OID($oid);
+
+ # If the node we found is not a table then start at the
+ # next oid in the table
+ unless($current->{istable}) {
+
+ my $nextoid = $current->{next};
+ $curoid = new NetSNMP::OID($nextoid);
+# print "Not a table so using the next $nextoid\n";
+ $current = $oidtable->{$nextoid};
+ }
+ }
+
+ # If we cannot find the starting point in the table, then start
+ # at the top and
+ # walk along the list until we drop off the end
+ # or we get to an oid that is >= to the one we want.
+ else {
+
+# print "Not found so using the top ($oidroot)\n";
+ $current = $oidtable->{$oidroot};
+
+ while($current && $curoid <= $oid) {
+ my $nextoid = $current->{next};
+ print "Trying $nextoid\n" if ($debugging);
+ $current = $oidtable->{$nextoid};
+ $curoid = $current ? new NetSNMP::OID($nextoid) : undef;
+ }
+ }
+
+ ##
+ ## Got a starting point
+ ## $current points to the node in the table
+ ## $curoid is a NetSNMP::OID object with the oid we are trying
+ ##
+ print "Got a startng point of " . Dumper($current) if ($debugging);
+ while($current) {
+ if($current->{istable}) {
+
+ # Got a table oid. See if the next is valid for the table
+# print "Trying table\n";
+
+ my $nextoid = $current->{nextoid}($curoid);
+
+# print Dumper($nextoid);
+ if($nextoid) {
+ getColumnar($current, $nextoid, $request);
+ $request->setOID($nextoid);
+ return;
+ }
+
+ # No not this one so try the next
+ $nextoid = $current->{next};
+ $current = $oidtable->{$nextoid};
+ $curoid = $current ? new NetSNMP::OID($nextoid) : undef;
+ print "Trying next $curoid $nextoid\n" if ($debugging);
+ } else {
+
+ # Must be the current node
+ if(getScalar($current, $request)) {
+ $request->setOID($curoid);
+ return 1;
+ }
+ }
+ }
+}
+
+
+# Return true from this module
+1;
diff --git a/perl/agent/agent.pm b/perl/agent/agent.pm
new file mode 100644
index 0000000..310e9e5
--- /dev/null
+++ b/perl/agent/agent.pm
@@ -0,0 +1,563 @@
+package NetSNMP::agent;
+
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+use NetSNMP::default_store (':all');
+use NetSNMP::agent::default_store (':all');
+use NetSNMP::OID (':all');
+use NetSNMP::agent::netsnmp_request_infoPtr;
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD);
+
+@ISA = qw(Exporter AutoLoader DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::agent ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ MODE_GET
+ MODE_GETBULK
+ MODE_GETNEXT
+ MODE_SET_ACTION
+ MODE_SET_BEGIN
+ MODE_SET_COMMIT
+ MODE_SET_FREE
+ MODE_SET_RESERVE1
+ MODE_SET_RESERVE2
+ MODE_SET_UNDO
+ SNMP_ERR_NOERROR
+ SNMP_ERR_TOOBIG
+ SNMP_ERR_NOSUCHNAME
+ SNMP_ERR_BADVALUE
+ SNMP_ERR_READONLY
+ SNMP_ERR_GENERR
+ SNMP_ERR_NOACCESS
+ SNMP_ERR_WRONGTYPE
+ SNMP_ERR_WRONGLENGTH
+ SNMP_ERR_WRONGENCODING
+ SNMP_ERR_WRONGVALUE
+ SNMP_ERR_NOCREATION
+ SNMP_ERR_INCONSISTENTVALUE
+ SNMP_ERR_RESOURCEUNAVAILABLE
+ SNMP_ERR_COMMITFAILED
+ SNMP_ERR_UNDOFAILED
+ SNMP_ERR_AUTHORIZATIONERROR
+ SNMP_ERR_NOTWRITABLE
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ MODE_GET
+ MODE_GETBULK
+ MODE_GETNEXT
+ MODE_SET_ACTION
+ MODE_SET_BEGIN
+ MODE_SET_COMMIT
+ MODE_SET_FREE
+ MODE_SET_RESERVE1
+ MODE_SET_RESERVE2
+ MODE_SET_UNDO
+ SNMP_ERR_NOERROR
+ SNMP_ERR_TOOBIG
+ SNMP_ERR_NOSUCHNAME
+ SNMP_ERR_BADVALUE
+ SNMP_ERR_READONLY
+ SNMP_ERR_GENERR
+ SNMP_ERR_NOACCESS
+ SNMP_ERR_WRONGTYPE
+ SNMP_ERR_WRONGLENGTH
+ SNMP_ERR_WRONGENCODING
+ SNMP_ERR_WRONGVALUE
+ SNMP_ERR_NOCREATION
+ SNMP_ERR_INCONSISTENTVALUE
+ SNMP_ERR_RESOURCEUNAVAILABLE
+ SNMP_ERR_COMMITFAILED
+ SNMP_ERR_UNDOFAILED
+ SNMP_ERR_AUTHORIZATIONERROR
+ SNMP_ERR_NOTWRITABLE
+);
+$VERSION = '5.0702';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "& not defined" if $constname eq 'constant';
+ my $val;
+ ($!, $val) = constant($constname);
+ if ($! != 0) {
+ if ($! =~ /Invalid/ || $!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined NetSNMP::agent macro $constname";
+ }
+ }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+# if ($] >= 5.00561) {
+# *$AUTOLOAD = sub () { $val };
+# }
+# else {
+ *$AUTOLOAD = sub { $val };
+# }
+ }
+ goto &$AUTOLOAD;
+}
+
+{
+ my $haveinit = 0;
+
+ sub mark_init_agent_done {
+ $haveinit = 1;
+ }
+
+ sub maybe_init_agent {
+ return if ($haveinit);
+ $haveinit = 1;
+
+ my $flags = $_[0];
+ if ($flags->{'AgentX'}) {
+ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
+ }
+ init_agent($flags->{'Name'} || "perl");
+ if ($flags->{'Ports'}) {
+ netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, $flags->{'Ports'});
+ }
+ init_mib();
+ }
+}
+
+{
+ my $haveinit = 0;
+
+ sub mark_init_lib_done {
+ $haveinit = 1;
+ }
+
+ sub maybe_init_lib {
+ return if ($haveinit);
+ $haveinit = 1;
+
+ my $flags = $_[0];
+ init_snmp($flags->{'Name'} || "perl");
+ if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) != 1) {
+ init_master_agent();
+ }
+ }
+}
+
+sub new {
+ my $type = shift;
+ my ($self);
+ %$self = @_;
+ bless($self, $type);
+ if ($self->{'dont_init_agent'}) {
+ $self->mark_init_agent_done();
+ } else {
+ $self->maybe_init_agent();
+ }
+ if ($self->{'dont_init_lib'}) {
+ $self->mark_init_lib_done();
+ }
+ return $self;
+}
+
+sub register($$$$) {
+ my ($self, $name, $oid, $sub) = @_;
+ my $reg = NetSNMP::agent::netsnmp_handler_registration::new($name, $oid, $sub);
+ $reg->register() if ($reg);
+ return $reg;
+}
+
+sub main_loop {
+ my $self = shift;
+ while(1) {
+ $self->agent_check_and_process(1);
+ }
+}
+
+sub agent_check_and_process {
+ my ($self, $blocking) = @_;
+ $self->maybe_init_lib();
+ __agent_check_and_process($blocking || 0);
+}
+
+sub uptime {
+ my $self = shift;
+ $self->maybe_init_lib();
+ return _uptime();
+}
+
+bootstrap NetSNMP::agent $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::agent - Perl extension for the net-snmp agent.
+
+=head1 SYNOPSIS
+
+ use NetSNMP::agent;
+
+ my $agent = new NetSNMP::agent('Name' => 'my_agent_name');
+
+
+=head1 DESCRIPTION
+
+This module implements an API set to make a SNMP agent act as a snmp
+agent, a snmp subagent (using the AgentX subagent protocol) and/or
+embedded perl-APIs directly within the traditional net-snmp agent demon.
+
+Also see the tutorial about the genaral Net-SNMP C API, which this
+module implements in a perl-way, and a perl specific tutorial at:
+
+ http://www.net-snmp.org/tutorial-5/toolkit/
+
+=head1 EXAMPLES
+
+=head2 Sub-agent example
+
+ use NetSNMP::agent (':all');
+ use NetSNMP::ASN qw(ASN_OCTET_STR);
+
+ my $value = "hello world";
+ sub myhandler {
+ my ($handler, $registration_info, $request_info, $requests) = @_;
+ my $request;
+
+ for($request = $requests; $request; $request = $request->next()) {
+ my $oid = $request->getOID();
+ if ($request_info->getMode() == MODE_GET) {
+ # ... generally, you would calculate value from oid
+ if ($oid == new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) {
+ $request->setValue(ASN_OCTET_STR, $value);
+ }
+ } elsif ($request_info->getMode() == MODE_GETNEXT) {
+ # ... generally, you would calculate value from oid
+ if ($oid < new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) {
+ $request->setOID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0");
+ $request->setValue(ASN_OCTET_STR, $value);
+ }
+ } elsif ($request_info->getMode() == MODE_SET_RESERVE1) {
+ if ($oid != new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) { # do error checking here
+ $request->setError($request_info, SNMP_ERR_NOSUCHNAME);
+ }
+ } elsif ($request_info->getMode() == MODE_SET_ACTION) {
+ # ... (or use the value)
+ $value = $request->getValue();
+ }
+ }
+
+ }
+
+ my $agent = new NetSNMP::agent(
+ # makes the agent read a my_agent_name.conf file
+ 'Name' => "my_agent_name",
+ 'AgentX' => 1
+ );
+ $agent->register("my_agent_name", ".1.3.6.1.4.1.8072.9999.9999.7375",
+ \&myhandler);
+
+ my $running = 1;
+ while($running) {
+ $agent->agent_check_and_process(1);
+ }
+
+ $agent->shutdown();
+
+
+=head2 Embedded agent example
+
+ # place this in a .pl file, and then in your snmpd.conf file put:
+ # perl do '/path/to/file.pl';
+
+ use NetSNMP::agent;
+ my $agent;
+
+ sub myhandler {
+ my ($handler, $registration_info, $request_info, $requests) = @_;
+ # ...
+ }
+
+ $agent = new NetSNMP::agent(
+ 'Name' => 'my_agent_name'
+ );
+
+ $agent->register("my_agent_name", ".1.3.6.1.4.1.8072.9999.9999.7375",
+ \&myhandler);
+
+ $agent->main_loop();
+
+
+=head1 CONSTRUCTOR
+
+ new ( OPTIONS )
+ This is the constructor for a new NetSNMP::agent object.
+
+ Possible options are:
+
+ Name - Name of the agent (optional, defaults to "perl")
+ (The snmp library will read a NAME.conf snmp
+ configuration file based on this argument.)
+ AgentX - Make us a sub-agent (0 = false, 1 = true)
+ (The Net-SNMP master agent must be running first)
+ Ports - Ports this agent will listen on (EG: "udp:161,tcp:161")
+
+ Example:
+
+ $agent = new NetSNMP::agent(
+ 'Name' => 'my_agent_name',
+ 'AgentX' => 1
+ );
+
+
+=head1 METHODS
+
+ register (NAME, OID, \&handler_routine )
+ Registers the callback handler with given OID.
+
+ $agent->register();
+
+ A return code of 0 indicates no error.
+
+ agent_check_and_process ( BLOCKING )
+ Run one iteration of the main loop.
+
+ BLOCKING - Blocking or non-blocking call. 1 = true, 0 = false.
+
+ $agent->agent_check_and_process(1);
+
+ main_loop ()
+ Runs the agent in a loop. Does not return.
+
+ shutdown ()
+ Nicely shuts down the agent or sub-agent.
+
+ $agent->shutdown();
+
+=head1 HANDLER CALLBACKS
+
+ handler ( HANDLER, REGISTRATION_INFO, REQUEST_INFO, REQUESTS )
+
+ The handler is called with the following parameters:
+
+ HANDLER - FIXME
+ REGISTRATION_INFO - what are the correct meanings of these?
+ REQUEST_INFO -
+ REQUESTS -
+
+ Example handler:
+
+ sub myhandler {
+ my ($handler, $reg_info, $request_info, $requests) = @_;
+ # ...
+ }
+
+The handler subroutine will be called when a SNMP request received by
+the agent for anything below the registered OID. The handler is
+passed 4 arguments: $handler, $registration_info, $request_info,
+$requests. These match the arguments passed to the C version of the
+same API. Note that they are not entirely complete objects but are
+functional "enough" at this point in time.
+
+=head2 $request_info object functions
+
+ getMode ()
+ Returns the mode of the request. See the MODES section for
+ list of valid modes.
+
+ $mode = $request->getMode();
+
+=head2 $registration_info object functions
+
+ getRootOID ()
+ Returns a NetSNMP::OID object that describes the registration
+ point that the handler is getting called for (in case you
+ register one handler function with multiple OIDs, which should
+ be rare anyway)
+
+ $root_oid = $request->getRootOID();
+
+=head2 $request object functions
+
+ next ()
+ Returns the next request in the list or undef if there is no
+ next request.
+
+ $request = $request->next();
+
+ getOID ()
+ Returns the oid of the request (a NetSNMP::OID class).
+
+ $oid = $request->getOID();
+
+ setOID (new NetSNMP::OID("someoid"))
+ Sets the OID of the request to a passed oid value. This
+ should generally only be done during handling of GETNEXT
+ requests.
+
+ $request->setOID(new NetSNMP::OID("someoid"));
+
+ getValue ()
+ Returns the value of the request. Used for example when
+ setting values.
+
+ $value = $request->getValue();
+
+ FIXME: how to get the type of the value? Is it even available?
+ [Wes: no, not yet.]
+
+ setValue ( TYPE, DATA )
+ Sets the data to be returned to the daemon.
+
+ Returns 1 on success, 0 on error.
+
+ TYPE - Type of the data. See NetSNMP::ASN for valid types.
+ DATA - The data to return.
+
+ $ret = $request->setValue(ASN_OCTET_STR, "test");
+
+ setError ( REQUEST_INFO, ERROR_CODE )
+ Sets the given error code for the request. See the ERROR CODES
+ section for list of valid codes.
+
+ $request->setError($request_info, SNMP_ERR_NOTWRITABLE);
+
+ getProcessed ()
+ The processed flag indicates that a request does not need to
+ be dealt with because someone else (a higher handler) has
+ dealt with it already.
+
+ $processed = $request->getProcessed();
+
+ setProcessed ( PROCESSED )
+ Sets the processed flag flag in the request. You generally
+ should not have to set this yourself.
+
+ PROCESSED - 0 = false, 1 = true
+
+ $request->setProcessed(1);
+
+ getDelegated ()
+ If you can handle a request in the background or at a future
+ time (EG, you're waiting on a file handle, or network traffic,
+ or ...), the delegated flag can be set in the request. When
+ the request is processed in the future the flag should be set
+ back to 0 so the agent will know that it can wrap up the
+ original request and send it back to the manager. This has
+ not been tested within perl, but it hopefully should work.
+
+ $delegated = $request->getDelegated();
+
+ setDelegated ( DELEGATED )
+ Sets the delegated flag.
+
+ DELEGATED - 0 = false, 1 = true
+
+ $request->setDelegated(1);
+
+ getRepeat ()
+ The repeat flag indicates that a getbulk operation is being
+ handled and this indicates how many answers need to be
+ returned. Generally, if you didn't register to directly
+ handle getbulk support yourself, you won't need to deal with
+ this value.
+
+ $repeat = $request->getRepeat();
+
+ setRepeat ( REPEAT )
+ Sets the repeat count (decrement after answering requests if
+ you handle getbulk requests yourself)
+
+ REPEAT - repeat count FIXME
+
+ $request->setRepeat(5);
+
+ getSourceIp ()
+
+ Gets the IPv4 address of the device making the request to the handler.
+
+ use Socket;
+ print "Source: ", inet_ntoa($request->getSourceIp()), "\n";
+
+ getDestIp ()
+
+ Gets the IPv4 address of the destination that the request was sent to.
+
+ use Socket;
+ print "Destination: ", inet_ntoa($request->getDestIp()), "\n";
+
+=head1 MODES
+
+ MODE_GET
+ MODE_GETBULK
+ MODE_GETNEXT
+ MODE_SET_ACTION
+ MODE_SET_BEGIN
+ MODE_SET_COMMIT
+ MODE_SET_FREE
+ MODE_SET_RESERVE1
+ MODE_SET_RESERVE2
+ MODE_SET_UNDO
+
+=head1 ERROR CODES
+
+ SNMP_ERR_NOERROR
+ SNMP_ERR_TOOBIG
+ SNMP_ERR_NOSUCHNAME
+ SNMP_ERR_BADVALUE
+ SNMP_ERR_READONLY
+ SNMP_ERR_GENERR
+ SNMP_ERR_NOACCESS
+ SNMP_ERR_WRONGTYPE
+ SNMP_ERR_WRONGLENGTH
+ SNMP_ERR_WRONGENCODING
+ SNMP_ERR_WRONGVALUE
+ SNMP_ERR_NOCREATION
+ SNMP_ERR_INCONSISTENTVALUE
+ SNMP_ERR_RESOURCEUNAVAILABLE
+ SNMP_ERR_COMMITFAILED
+ SNMP_ERR_UNDOFAILED
+ SNMP_ERR_AUTHORIZATIONERROR
+ SNMP_ERR_NOTWRITABLE
+
+=head1 AUTHOR
+
+Please mail the net-snmp-users@lists.sourceforge.net mailing list for
+help, questions or comments about this module.
+
+Module written by:
+ Wes Hardaker <hardaker@users.sourceforge.net>
+
+Documentation written by:
+ Toni Willberg <toniw@iki.fi>
+ Wes Hardaker <hardaker@users.sourceforge.net>
+
+=head1 SEE ALSO
+
+NetSNMP::OID(3), NetSNMP::ASN(3), perl(1).
+
+=cut
diff --git a/perl/agent/agent.xs b/perl/agent/agent.xs
new file mode 100644
index 0000000..c7b5d9a
--- /dev/null
+++ b/perl/agent/agent.xs
@@ -0,0 +1,941 @@
+/* -*- C -*- */
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include <netdb.h>
+#include <sys/socket.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#ifndef sv_undef
+#define sv_undef PL_sv_undef
+#endif
+
+typedef netsnmp_handler_registration *NetSNMP__agent__netsnmp_handler_registration;
+
+/*
+ * needs to be in sync with the definitions in snmplib/snmpUDPDomain.c
+ * and snmplib/snmpTCPDomain.c
+ */
+typedef netsnmp_indexed_addr_pair netsnmp_udp_addr_pair;
+
+typedef struct handler_cb_data_s {
+ SV *perl_cb;
+} handler_cb_data;
+
+typedef struct netsnmp_oid_s {
+ oid *name;
+ size_t len;
+ oid namebuf[ MAX_OID_LEN ];
+} netsnmp_oid;
+
+#define TEST_CONSTANT(value, name, C) \
+ if (strEQ(name, #C)) { \
+ *value = C; \
+ return 0; \
+ }
+
+static int constant_MODE_G(double *value, const char *name, const int len)
+{
+ switch (len >= 8 ? name[8] : -1) {
+ case '\0':
+ TEST_CONSTANT(value, name, MODE_GET);
+ break;
+ case 'B':
+ TEST_CONSTANT(value, name, MODE_GETBULK);
+ break;
+ case 'N':
+ TEST_CONSTANT(value, name, MODE_GETNEXT);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_MODE_SET_R(double *value, const char *name, const int len)
+{
+ switch (len >= 16 ? name[16] : -1) {
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+ case '1':
+ TEST_CONSTANT(value, name, MODE_SET_RESERVE1);
+ break;
+ case '2':
+ TEST_CONSTANT(value, name, MODE_SET_RESERVE2);
+ break;
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+ }
+ return EINVAL;
+}
+
+static int constant_SNMP_ERR(double *value, char *name, int len)
+{
+ switch (len >= 9 ? name[9] : -1) {
+ case 'A':
+ TEST_CONSTANT(value, name, SNMP_ERR_AUTHORIZATIONERROR);
+ break;
+ case 'B':
+ TEST_CONSTANT(value, name, SNMP_ERR_BADVALUE);
+ break;
+ case 'C':
+ TEST_CONSTANT(value, name, SNMP_ERR_COMMITFAILED);
+ break;
+ case 'G':
+ TEST_CONSTANT(value, name, SNMP_ERR_GENERR);
+ break;
+ case 'I':
+ TEST_CONSTANT(value, name, SNMP_ERR_INCONSISTENTVALUE);
+ break;
+ case 'N':
+ TEST_CONSTANT(value, name, SNMP_ERR_NOACCESS);
+ TEST_CONSTANT(value, name, SNMP_ERR_NOCREATION);
+ TEST_CONSTANT(value, name, SNMP_ERR_NOERROR);
+ TEST_CONSTANT(value, name, SNMP_ERR_NOSUCHNAME);
+ TEST_CONSTANT(value, name, SNMP_ERR_NOTWRITABLE);
+ break;
+ case 'R':
+ TEST_CONSTANT(value, name, SNMP_ERR_READONLY);
+ TEST_CONSTANT(value, name, SNMP_ERR_RESOURCEUNAVAILABLE);
+ break;
+ case 'T':
+ TEST_CONSTANT(value, name, SNMP_ERR_TOOBIG);
+ break;
+ case 'U':
+ TEST_CONSTANT(value, name, SNMP_ERR_UNDOFAILED);
+ break;
+ case 'W':
+ TEST_CONSTANT(value, name, SNMP_ERR_WRONGENCODING);
+ TEST_CONSTANT(value, name, SNMP_ERR_WRONGLENGTH);
+ TEST_CONSTANT(value, name, SNMP_ERR_WRONGTYPE);
+ TEST_CONSTANT(value, name, SNMP_ERR_WRONGVALUE);
+ break;
+ }
+ return EINVAL;
+}
+
+static int constant_MODE_S(double *value, char *name, int len)
+{
+ if (!strnEQ(name + 6, "ET_", 3))
+ return EINVAL;
+
+ switch (len >= 9 ? name[9] : -1) {
+#ifndef NETSNMP_NO_WRITE_SUPPORT
+ case 'A':
+ TEST_CONSTANT(value, name, MODE_SET_ACTION);
+ break;
+ case 'B':
+ TEST_CONSTANT(value, name, MODE_SET_BEGIN);
+ break;
+ case 'C':
+ TEST_CONSTANT(value, name, MODE_SET_COMMIT);
+ break;
+ case 'F':
+ TEST_CONSTANT(value, name, MODE_SET_FREE);
+ break;
+ case 'U':
+ TEST_CONSTANT(value, name, MODE_SET_UNDO);
+ break;
+#endif /* NETSNMP_NO_WRITE_SUPPORT */
+ case 'R':
+ return constant_MODE_SET_R(value, name, len);
+ }
+ return EINVAL;
+}
+
+static int constant(double *value, char *name, int len)
+{
+ switch (len >= 5 ? name[5] : -1) {
+ case 'G':
+ if (strnEQ(name + 0,"MODE_", 5))
+ return constant_MODE_G(value, name, len);
+ break;
+ case 'S':
+ if (strnEQ(name + 0,"MODE_", 5))
+ return constant_MODE_S(value, name, len);
+ break;
+ case 'E':
+ if (strnEQ(name + 0,"SNMP_ERR_", 9))
+ return constant_SNMP_ERR(value, name, len);
+ break;
+ }
+ return EINVAL;
+}
+
+int
+handler_wrapper(netsnmp_mib_handler *handler,
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests)
+{
+ handler_cb_data *cb_data = (handler_cb_data *) handler->myvoid;
+ SV *cb;
+
+ if (cb_data && (cb = cb_data->perl_cb)) {
+ SV *arg;
+ SV *rarg;
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(sp);
+ rarg = newSViv(0);
+ arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_mib_handler");
+ sv_setiv(arg, (IV) handler);
+ XPUSHs(sv_2mortal(rarg));
+ rarg = newSViv(0);
+ arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_handler_registrationPtr");
+ sv_setiv(arg, (IV) reginfo);
+ XPUSHs(sv_2mortal(rarg));
+ rarg = newSViv(0);
+ arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_agent_request_info");
+ sv_setiv(arg, (IV) reqinfo);
+ XPUSHs(sv_2mortal(rarg));
+ rarg = newSViv(0);
+ arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr");
+ sv_setiv(arg, (IV) requests);
+ XPUSHs(sv_2mortal(rarg));
+ PUTBACK;
+ if (SvTYPE(cb) == SVt_PVCV) {
+ perl_call_sv(cb, G_DISCARD);
+
+ } else if (SvROK(cb) && SvTYPE(SvRV(cb)) == SVt_PVCV) {
+ perl_call_sv(SvRV(cb), G_DISCARD);
+ }
+ SPAGAIN;
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ }
+ return SNMP_ERR_NOERROR;
+}
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent
+
+void
+constant(sv)
+ PREINIT:
+ STRLEN len;
+ INPUT:
+ SV * sv
+ char * s = SvPV(sv, len);
+ INIT:
+ int status;
+ double value;
+ PPCODE:
+ value = 0;
+ status = constant(&value, s, len);
+ XPUSHs(sv_2mortal(newSVuv(status)));
+ XPUSHs(sv_2mortal(newSVnv(value)));
+
+int
+__agent_check_and_process(block = 1)
+ int block;
+ CODE:
+ RETVAL = agent_check_and_process(block);
+ OUTPUT:
+ RETVAL
+
+int
+_uptime()
+ CODE:
+ RETVAL = netsnmp_get_agent_uptime();
+ OUTPUT:
+ RETVAL
+
+void
+init_mib()
+ CODE:
+ {
+ netsnmp_init_mib();
+ }
+
+int
+init_agent(name)
+ const char *name;
+ CODE:
+ SOCK_STARTUP;
+ RETVAL = init_agent(name);
+ OUTPUT:
+ RETVAL
+
+void
+init_snmp(name)
+ const char *name;
+
+int
+init_master_agent()
+
+void
+snmp_enable_stderrlog()
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent PREFIX = na_
+
+void
+na_shutdown(me)
+ SV *me;
+ CODE:
+ {
+ if (0)
+ printf("me = %p\n", me);
+ snmp_shutdown("perl");
+ }
+
+void
+na_errlog(me,value)
+ SV *me;
+ SV *value;
+ PREINIT:
+ STRLEN stringlen;
+ char * stringptr;
+ CODE:
+ {
+ if (0)
+ printf("me = %p\n", me);
+ stringptr = SvPV(value, stringlen);
+ snmp_log(LOG_ERR, "%s", stringptr );
+ }
+
+
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_handler_registration PREFIX = nsahr_
+
+NetSNMP::agent::netsnmp_handler_registration
+nsahr_new(name, regoid, perlcallback)
+ char *name;
+ char *regoid;
+ SV *perlcallback;
+ PREINIT:
+ oid myoid[MAX_OID_LEN];
+ size_t myoid_len = MAX_OID_LEN;
+ handler_cb_data *cb_data;
+ int gotit=1;
+ CODE:
+ if (!snmp_parse_oid(regoid, myoid, &myoid_len)) {
+ if (!read_objid(regoid, myoid, &myoid_len)) {
+ snmp_log(LOG_ERR, "couldn't parse %s (reg name: %s)\n",
+ regoid, name);
+ RETVAL = NULL;
+ gotit = 0;
+ }
+ }
+ if (gotit) {
+ cb_data = (handler_cb_data *) malloc(sizeof(handler_cb_data));
+ RETVAL = netsnmp_create_handler_registration(name, handler_wrapper,
+ myoid, myoid_len,
+ HANDLER_CAN_RWRITE);
+ cb_data->perl_cb = newSVsv(perlcallback);
+ RETVAL->handler->myvoid = cb_data;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+nsahr_DESTROY(reginfo)
+ netsnmp_handler_registration *reginfo
+ PREINIT:
+ handler_cb_data *cb_data;
+ CODE:
+ if (reginfo && reginfo->handler && reginfo->handler->myvoid) {
+ cb_data = (handler_cb_data *) (reginfo->handler->myvoid);
+ SvREFCNT_dec(cb_data->perl_cb);
+ free(cb_data);
+ }
+ netsnmp_handler_registration_free(reginfo);
+
+int
+nsahr_register(me)
+ SV *me;
+ PREINIT:
+ netsnmp_handler_registration *reginfo;
+ handler_cb_data *cb_data = NULL;
+ CODE:
+ {
+ reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me));
+ if (reginfo && reginfo->handler && reginfo->handler->myvoid)
+ cb_data = (handler_cb_data *) (reginfo->handler->myvoid);
+ RETVAL = netsnmp_register_handler(reginfo);
+ if (!RETVAL) {
+ /* the agent now has a "reference" to this reg pointer */
+ SvREFCNT_inc(me);
+ } else {
+ /*
+ * The reginfo was freed by netsnmp_register_handler,
+ * don't touch it in nsahr_DESTROY!
+ */
+ sv_setiv(SvRV(me), 0);
+ if (cb_data) {
+ /* And just free the callback. */
+ SvREFCNT_dec(cb_data->perl_cb);
+ free(cb_data);
+ }
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_handler_registrationPtr PREFIX = nsahr_
+
+void
+nsahr_getRootOID(me)
+ SV *me;
+ PREINIT:
+ int i;
+ netsnmp_oid *o;
+ netsnmp_handler_registration *reginfo;
+ SV *arg, *rarg;
+ PPCODE:
+ {
+ dSP;
+ PUSHMARK(SP);
+ reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me));
+
+ o = malloc(sizeof(netsnmp_oid));
+ o->name = o->namebuf;
+ o->len = reginfo->rootoid_len;
+ memcpy(o->name, reginfo->rootoid,
+ reginfo->rootoid_len * sizeof(oid));
+
+ rarg = newSViv((int) 0);
+ arg = newSVrv(rarg, "netsnmp_oidPtr");
+ sv_setiv(arg, (IV) o);
+
+ XPUSHs(sv_2mortal(rarg));
+
+ PUTBACK;
+ i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
+ SPAGAIN;
+ if (i != 1) {
+ snmp_log(LOG_ERR, "unhandled OID error.\n");
+ /* ack XXX */
+ }
+ ST(0) = POPs;
+ XSRETURN(1);
+ }
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_request_infoPtr PREFIX = nari_
+
+void
+getOID(me)
+ SV *me;
+ PREINIT:
+ int i;
+ netsnmp_oid *o;
+ netsnmp_request_info *request;
+ SV *arg, *rarg;
+ PPCODE:
+ {
+ dSP;
+ PUSHMARK(SP);
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+
+ o = malloc(sizeof(netsnmp_oid));
+ o->name = o->namebuf;
+ o->len = request->requestvb->name_length;
+ memcpy(o->name, request->requestvb->name,
+ request->requestvb->name_length * sizeof(oid));
+
+ rarg = newSViv((int) 0);
+ arg = newSVrv(rarg, "netsnmp_oidPtr");
+ sv_setiv(arg, (IV) o);
+
+ XPUSHs(sv_2mortal(rarg));
+
+ PUTBACK;
+ i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
+ SPAGAIN;
+ if (i != 1) {
+ snmp_log(LOG_ERR, "unhandled OID error.\n");
+ /* ack XXX */
+ }
+ ST(0) = POPs;
+ XSRETURN(1);
+ }
+
+netsnmp_oid *
+nari_getOIDptr(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ RETVAL = malloc(sizeof(netsnmp_oid));
+ RETVAL->name = RETVAL->namebuf;
+ RETVAL->len = request->requestvb->name_length;
+ memcpy(RETVAL->name, request->requestvb->name,
+ request->requestvb->name_length * sizeof(oid));
+ OUTPUT:
+ RETVAL
+
+int
+nari_getType(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+
+ RETVAL = request->requestvb->type ;
+ OUTPUT:
+ RETVAL
+
+void
+nari_setType(me, newvalue)
+ SV *me;
+ int newvalue;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ request->requestvb->type=newvalue;
+
+SV *
+nari_getValue(me)
+ SV *me;
+ PREINIT:
+ char *outbuf = NULL;
+ size_t ob_len = 0, oo_len = 0;
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ sprint_realloc_by_type((u_char **) &outbuf, &ob_len, &oo_len, 1,
+ request->requestvb, 0, 0, 0);
+ RETVAL = newSVpv(outbuf, 0);
+ netsnmp_free(outbuf);
+ OUTPUT:
+ RETVAL
+
+int
+nari_getDelegated(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ RETVAL = request->delegated;
+ OUTPUT:
+ RETVAL
+
+void
+nari_setDelegated(me, newdelegated)
+ SV *me;
+ int newdelegated;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ request->delegated = newdelegated;
+
+int
+nari_getProcessed(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ RETVAL = request->processed;
+ OUTPUT:
+ RETVAL
+
+void
+nari_setProcessed(me, newprocessed)
+ SV *me;
+ int newprocessed;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ request->processed = newprocessed;
+
+int
+nari_getStatus(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ RETVAL = request->status;
+ OUTPUT:
+ RETVAL
+
+void
+nari_setStatus(me, newstatus)
+ SV *me;
+ int newstatus;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ request->status = newstatus;
+
+int
+nari_getRepeat(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ RETVAL = request->repeat;
+ OUTPUT:
+ RETVAL
+
+void
+nari_setRepeat(me, newrepeat)
+ SV *me;
+ int newrepeat;
+ PREINIT:
+ netsnmp_request_info *request;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ request->repeat = newrepeat;
+
+int
+nari_setValue(me, type, value)
+ SV *me;
+ int type;
+ SV *value;
+ PREINIT:
+ netsnmp_request_info *request;
+ u_long utmp;
+ long ltmp;
+ uint64_t ulltmp;
+ struct counter64 c64;
+ oid myoid[MAX_OID_LEN];
+ size_t myoid_len;
+ STRLEN stringlen;
+ char * stringptr;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ switch(type) {
+ case SNMP_NOSUCHINSTANCE :
+ snmp_set_var_typed_value(request->requestvb,SNMP_NOSUCHINSTANCE,0,0) ;
+ RETVAL = 1;
+ break ;
+ case SNMP_NOSUCHOBJECT :
+ snmp_set_var_typed_value(request->requestvb,SNMP_NOSUCHOBJECT,0,0) ;
+ RETVAL = 1;
+ break ;
+ case SNMP_ENDOFMIBVIEW :
+ snmp_set_var_typed_value(request->requestvb,SNMP_ENDOFMIBVIEW,0,0) ;
+ RETVAL = 1;
+ break ;
+ case ASN_INTEGER:
+ /* We want an integer here */
+ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG) ||
+ SvIOK(value)) {
+ /* Good - got a real one (or a blessed object that we hope will turn out OK) */
+ ltmp = SvIV(value);
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) &ltmp, sizeof(ltmp));
+ RETVAL = 1;
+ break;
+ }
+ else if (SvPOKp(value)) {
+ /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
+ stringptr = SvPV(value, stringlen);
+ ltmp = strtol( stringptr, NULL, 0 );
+ if (errno == EINVAL) {
+ snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
+ RETVAL = 0;
+ break;
+ }
+
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) &ltmp, sizeof(ltmp));
+ RETVAL = 1;
+ break;
+ }
+ else {
+ snmp_log(LOG_ERR, "Non-integer value passed to setValue with ASN_INTEGER: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ break;
+ }
+
+
+ case ASN_UNSIGNED:
+ case ASN_COUNTER:
+ case ASN_TIMETICKS:
+ /* We want an integer here */
+ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG) ||
+ SvIOK(value)) {
+ /* Good - got a real one (or a blessed scalar which we have to hope will turn out OK) */
+ utmp = SvIV(value);
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) &utmp, sizeof(utmp));
+ RETVAL = 1;
+ break;
+ }
+ else if (SvPOKp(value)) {
+ /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
+ stringptr = SvPV(value, stringlen);
+ utmp = strtoul( stringptr, NULL, 0 );
+ if (errno == EINVAL) {
+ snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
+ RETVAL = 0;
+ break;
+ }
+
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) &utmp, sizeof(utmp));
+ RETVAL = 1;
+ break;
+ }
+ else {
+ snmp_log(LOG_ERR, "Non-unsigned-integer value passed to setValue with ASN_UNSIGNED/ASN_COUNTER/ASN_TIMETICKS: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ break;
+ }
+
+ case ASN_COUNTER64:
+ /* We want an integer here */
+ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG)) {
+ /* Good - got a real one (or a blessed scalar which we have to hope will turn out OK) */
+ ulltmp = SvIV(value);
+ RETVAL = 1;
+ }
+ else if (SvPOKp(value)) {
+ /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
+ stringptr = SvPV(value, stringlen);
+ errno = 0;
+ ulltmp = strtoull( stringptr, NULL, 0 );
+ if (errno != 0) {
+ snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
+ RETVAL = 0;
+ } else
+
+ RETVAL = 1;
+ }
+ else {
+ snmp_log(LOG_ERR, "Non-unsigned-integer value passed to setValue with ASN_COUNTER64: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ }
+ if (RETVAL) {
+ c64.high = (uint32_t)(ulltmp >> 32);
+ c64.low = (uint32_t)(ulltmp >> 0);
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) &c64, sizeof(struct counter64));
+ }
+ break;
+
+ case ASN_OCTET_STR:
+ case ASN_BIT_STR:
+ case ASN_OPAQUE:
+ /* Check that we have been passed something with a string value (or a blessed scalar) */
+ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
+ snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OCTET_STR/ASN_BIT_STR: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ break;
+ }
+
+ /* Find length of string (strlen will *not* do, as these are binary strings) */
+ stringptr = SvPV(value, stringlen);
+
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) stringptr,
+ stringlen);
+ RETVAL = 1;
+ break;
+
+ case ASN_IPADDRESS:
+ /* IP addresses are passed as *binary* strings.
+ * In the case of IPv4 addresses, these are 4 bytes long.
+ * NOTE: the use of binary strings rather than dotted-quad or FQDNs was
+ * introduced here by Andrew Findlay's patch of March 17th 2003,
+ * and is effectively a change to the previous implied API which assumed
+ * the value was a (valid) hostname.
+ * Responsibility for decoding and resolving has been passed up to the Perl script.
+ */
+
+ /* Check that we have been passed something with a string value (or a blessed scalar) */
+ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
+ snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_IPADDRESS: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ break;
+ }
+
+ /* Find length of string (strlen will *not* do, as these are binary strings) */
+ stringptr = SvPV(value, stringlen);
+
+ # snmp_log(LOG_ERR, "IP address returned with length %d: %u.%u.%u.%u\n", stringlen, stringptr[0],
+ # stringptr[1], stringptr[2], stringptr[3] );
+
+ # Sanity check on address length
+ if ((stringlen != 4) && (stringlen != 16)) {
+ snmp_log(LOG_ERR, "IP address of %" NETSNMP_PRIz "d bytes passed to setValue with ASN_IPADDRESS\n", stringlen);
+ RETVAL = 0;
+ break;
+ }
+
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ stringptr, stringlen);
+ RETVAL = 1;
+ break;
+
+ case ASN_OBJECT_ID:
+ /* Check that we have been passed something with a string value (or a blessed scalar) */
+ if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
+ snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OBJECT_ID: type was %lu\n",
+ (unsigned long)SvTYPE(value));
+ RETVAL = 0;
+ break;
+ }
+
+ /* Extract the string */
+ stringptr = SvPV(value, stringlen);
+
+ /* snmp_log(LOG_ERR, "setValue returning OID '%s'\n", stringptr); */
+
+ myoid_len = MAX_OID_LEN;
+ if (!snmp_parse_oid(stringptr, myoid, &myoid_len)) {
+ snmp_log(LOG_ERR, "couldn't parse %s in setValue\n", stringptr);
+ RETVAL = 0;
+ break;
+ } else {
+ /* snmp_log(LOG_ERR, "setValue returning OID length %d\n", myoid_len); */
+
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ snmp_set_var_typed_value(request->requestvb, (u_char)type,
+ (u_char *) myoid, (myoid_len * sizeof(myoid[0])) );
+ }
+
+ RETVAL = 1;
+ break;
+
+ default:
+ snmp_log(LOG_ERR, "unknown var value type: %d\n",
+ type);
+ RETVAL = 0;
+ break;
+ }
+
+ OUTPUT:
+ RETVAL
+
+void
+nari_setOID(me, value)
+ SV *me;
+ char *value;
+ PREINIT:
+ oid myoid[MAX_OID_LEN];
+ size_t myoid_len = MAX_OID_LEN;
+ netsnmp_request_info *request;
+ CODE:
+ myoid_len = MAX_OID_LEN;
+ if (!snmp_parse_oid(value, myoid, &myoid_len)) {
+ snmp_log(LOG_ERR, "couldn't parse %s in setOID\n", value);
+ } else {
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ snmp_set_var_objid(request->requestvb, myoid, myoid_len);
+ }
+
+void
+nari_setError(me, rinfo, ecode)
+ SV *me;
+ SV *rinfo;
+ int ecode;
+ PREINIT:
+ netsnmp_request_info *request;
+ netsnmp_agent_request_info *reqinfo;
+ CODE:
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(rinfo));
+ netsnmp_set_request_error(reqinfo, request, ecode);
+
+SV *
+nari_next(me)
+ SV *me;
+ PREINIT:
+ netsnmp_request_info *request;
+ SV *arg, *rarg;
+ CODE:
+ {
+ request = (netsnmp_request_info *) SvIV(SvRV(me));
+ if (request && request->next) {
+ request = request->next;
+ rarg = newSViv(0);
+ arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr");
+ sv_setiv(arg, (IV) request);
+ RETVAL = rarg;
+ } else {
+ RETVAL = &sv_undef;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_agent_request_info PREFIX = narqi_
+
+
+SV *
+narqi_getSourceIp(me)
+ SV *me;
+ PREINIT:
+ netsnmp_agent_request_info *reqinfo;
+ netsnmp_udp_addr_pair *addr_pair;
+ struct sockaddr_in *from;
+ SV *rarg;
+
+ CODE:
+ reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
+
+ /* XXX: transport-specific: UDP/IPv4 only! */
+ addr_pair = (netsnmp_udp_addr_pair *) (reqinfo->asp->pdu->transport_data);
+ from = (struct sockaddr_in *) &(addr_pair->remote_addr);
+ rarg = newSVpv((const char *)(&from->sin_addr.s_addr), sizeof(from->sin_addr.s_addr));
+ RETVAL = rarg;
+ OUTPUT:
+ RETVAL
+
+
+SV *
+narqi_getDestIp(me)
+ SV *me;
+ PREINIT:
+ netsnmp_agent_request_info *reqinfo;
+ netsnmp_udp_addr_pair *addr_pair;
+ struct in_addr *to;
+ SV *rarg;
+
+ CODE:
+ reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
+
+ /* XXX: transport-specific: UDP/IPv4 only! */
+ addr_pair = (netsnmp_udp_addr_pair *) (reqinfo->asp->pdu->transport_data);
+ to = (struct in_addr *) &(addr_pair->local_addr);
+ rarg = newSVpv((const char *)(&to->s_addr), sizeof(to->s_addr));
+ RETVAL = rarg;
+ OUTPUT:
+ RETVAL
+
+int
+narqi_getMode(me)
+ SV *me;
+ PREINIT:
+ netsnmp_agent_request_info *reqinfo;
+ CODE:
+ reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
+ RETVAL = reqinfo->mode;
+ OUTPUT:
+ RETVAL
+
+void
+narqi_setMode(me, newvalue)
+ SV *me;
+ int newvalue;
+ PREINIT:
+ netsnmp_agent_request_info *reqinfo;
+ CODE:
+ reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
+ reqinfo->mode = newvalue;
+
+
+MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent
+
diff --git a/perl/agent/default_store/Makefile.PL b/perl/agent/default_store/Makefile.PL
new file mode 100644
index 0000000..ed6483a
--- /dev/null
+++ b/perl/agent/default_store/Makefile.PL
@@ -0,0 +1,228 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+Check_Version();
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::agent::default_store',
+ 'VERSION_FROM' => 'default_store.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts("../../");
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ if ($opts->{'insource'} eq "true") {
+ $Params{'LIBS'} = "-L../../../snmplib/.libs -L../../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../../include " . $Params{'CCFLAGS'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+
+ return(%Params);
+}
+
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/agent/default_store/default_store.pm b/perl/agent/default_store/default_store.pm
new file mode 100644
index 0000000..ebac1ec
--- /dev/null
+++ b/perl/agent/default_store/default_store.pm
@@ -0,0 +1,370 @@
+package NetSNMP::agent::default_store;
+
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD);
+
+@ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::agent::default_store ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+ NETSNMP_DS_AGENT_MAX_GETBULKREPEATS
+ NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+ NETSNMP_DS_AGENT_MAX_GETBULKREPEATS
+ NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES
+);
+$VERSION = '5.0702';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "&NetSNMP::agent::default_store::constant not defined" if $constname eq 'cons
+tant';
+ my ($error, $val) = constant($constname);
+ if ($error) { croak $error; }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+#XXX if ($] >= 5.00561) {
+#XXX *$AUTOLOAD = sub () { $val };
+#XXX }
+#XXX else {
+ *$AUTOLOAD = sub { $val };
+#XXX }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap NetSNMP::agent::default_store $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::agent::default_store - Perl extension for Net-SNMP agent default storage
+
+=head1 SYNOPSIS
+
+ use NetSNMP::agent::default_store qw(:all);
+
+=head1 DESCRIPTION
+
+The NetSNMP::agent::default_store module defines the agent-specific Net-SNMP
+default storage variables.
+
+=head2 EXPORT
+
+None by default.
+
+=head2 Exportable constants
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+ NETSNMP_DS_AGENT_MAX_GETBULKREPEATS
+ NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES
+
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_STRICT_DISMAN
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_SMUX_SOCKET
+ NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_AGENTX_RETRIES
+ NETSNMP_DS_AGENT_X_SOCK_PERM
+ NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+
+
+
+
+ NETSNMP_DS_AGENT_VERBOSE
+ NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_X_SOCKET
+ NETSNMP_DS_AGENT_PORTS
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_AGENT_FLAGS
+ NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+
+
+ DS_AGENT_AGENTX_MASTER
+ DS_AGENT_AGENTX_PING_INTERVAL
+ DS_AGENT_FLAGS
+ DS_AGENT_GROUPID
+ DS_AGENT_INTERNAL_SECNAME
+ DS_AGENT_NO_ROOT_ACCESS
+ DS_AGENT_PORTS
+ DS_AGENT_PROGNAME
+ DS_AGENT_ROLE
+ DS_AGENT_USERID
+ DS_AGENT_VERBOSE
+ DS_AGENT_X_SOCKET
+
+
+=head1 AUTHOR
+
+Wes Hardaker, E<lt>hardaker@users.sourceforge.netE<gt>
+
+=head1 SEE ALSO
+
+NetSNMP::default_store(3pm), NetSNMP::agent(3pm), perl(1).
+
+=cut
diff --git a/perl/agent/default_store/default_store.xs b/perl/agent/default_store/default_store.xs
new file mode 100644
index 0000000..bff1485
--- /dev/null
+++ b/perl/agent/default_store/default_store.xs
@@ -0,0 +1,705 @@
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/agent/ds_agent.h>
+
+
+/* autogenerated by "gen" from const-c.inc */
+
+#define PERL_constant_NOTFOUND 1
+#define PERL_constant_NOTDEF 2
+#define PERL_constant_ISIV 3
+#define PERL_constant_ISNO 4
+#define PERL_constant_ISNV 5
+#define PERL_constant_ISPV 6
+#define PERL_constant_ISPVN 7
+#define PERL_constant_ISSV 8
+#define PERL_constant_ISUNDEF 9
+#define PERL_constant_ISUV 10
+#define PERL_constant_ISYES 11
+
+#ifndef NVTYPE
+typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
+#endif
+#ifndef aTHX_
+#define aTHX_ /* 5.6 or later define this for threading support. */
+#endif
+#ifndef pTHX_
+#define pTHX_ /* 5.6 or later define this for threading support. */
+#endif
+
+static int
+constant_22 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_AGENT_FLAGS NETSNMP_DS_AGENT_PORTS NETSNMP_DS_SMUX_SOCKET */
+ /* Offset 17 gives the best switch position. */
+ switch (name[17]) {
+ case 'F':
+ if (memEQ(name, "NETSNMP_DS_AGENT_FLAGS", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_FLAGS
+ *iv_return = NETSNMP_DS_AGENT_FLAGS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_SMUX_SOCKET", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_SMUX_SOCKET
+ *iv_return = NETSNMP_DS_SMUX_SOCKET;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_AGENT_PORTS", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_PORTS
+ *iv_return = NETSNMP_DS_AGENT_PORTS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_24 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_AGENT_GROUPID NETSNMP_DS_AGENT_VERBOSE NETSNMP_DS_NOTIF_LOG_CTX
+ */
+ /* Offset 19 gives the best switch position. */
+ switch (name[19]) {
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_NOTIF_LOG_CTX", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_NOTIF_LOG_CTX
+ *iv_return = NETSNMP_DS_NOTIF_LOG_CTX;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_AGENT_GROUPID", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_GROUPID
+ *iv_return = NETSNMP_DS_AGENT_GROUPID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'R':
+ if (memEQ(name, "NETSNMP_DS_AGENT_VERBOSE", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_VERBOSE
+ *iv_return = NETSNMP_DS_AGENT_VERBOSE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_30 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_AGENT_AGENTX_MASTER NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ NETSNMP_DS_AGENT_LEAVE_PIDFILE NETSNMP_DS_AGENT_STRICT_DISMAN */
+ /* Offset 27 gives the best switch position. */
+ switch (name[27]) {
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_AGENT_LEAVE_PIDFILE", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ *iv_return = NETSNMP_DS_AGENT_LEAVE_PIDFILE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_AGENT_STRICT_DISMAN", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_STRICT_DISMAN
+ *iv_return = NETSNMP_DS_AGENT_STRICT_DISMAN;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_AGENT_CACHE_TIMEOUT", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_CACHE_TIMEOUT
+ *iv_return = NETSNMP_DS_AGENT_CACHE_TIMEOUT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'T':
+ if (memEQ(name, "NETSNMP_DS_AGENT_AGENTX_MASTER", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_AGENTX_MASTER
+ *iv_return = NETSNMP_DS_AGENT_AGENTX_MASTER;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_31 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_AGENT_AGENTX_RETRIES NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS NETSNMP_DS_AGENT_PERL_INIT_FILE */
+ /* Offset 27 gives the best switch position. */
+ switch (name[27]) {
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_AGENT_NO_ROOT_ACCESS", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_NO_ROOT_ACCESS
+ *iv_return = NETSNMP_DS_AGENT_NO_ROOT_ACCESS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_AGENT_AGENTX_TIMEOUT", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ *iv_return = NETSNMP_DS_AGENT_AGENTX_TIMEOUT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'F':
+ if (memEQ(name, "NETSNMP_DS_AGENT_PERL_INIT_FILE", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_PERL_INIT_FILE
+ *iv_return = NETSNMP_DS_AGENT_PERL_INIT_FILE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'R':
+ if (memEQ(name, "NETSNMP_DS_AGENT_AGENTX_RETRIES", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_AGENTX_RETRIES
+ *iv_return = NETSNMP_DS_AGENT_AGENTX_RETRIES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_33 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME NETSNMP_DS_AGENT_INTERNAL_VERSION
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY */
+ /* Offset 31 gives the best switch position. */
+ switch (name[31]) {
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_AGENT_QUIT_IMMEDIATELY", 33)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_QUIT_IMMEDIATELY
+ *iv_return = NETSNMP_DS_AGENT_QUIT_IMMEDIATELY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_AGENT_INTERNAL_SECNAME", 33)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ *iv_return = NETSNMP_DS_AGENT_INTERNAL_SECNAME;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_AGENT_INTERNAL_VERSION", 33)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_INTERNAL_VERSION
+ *iv_return = NETSNMP_DS_AGENT_INTERNAL_VERSION;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant (pTHX_ const char *name, STRLEN len, IV *iv_return) {
+ /* Initially switch on the length of the name. */
+ /* When generated this function returned values for the list of names given
+ in this section of perl code. Rather than manually editing these functions
+ to add or remove constants, which would result in this comment and section
+ of code becoming inaccurate, we recommend that you edit this section of
+ code, and use it to regenerate a new set of constant functions which you
+ then use to replace the originals.
+
+ Regenerate these constant functions by feeding this entire source file to
+ perl -x
+
+#!/usr/bin/perl -w
+use ExtUtils::Constant qw (constant_types C_constant XS_constant);
+
+my $types = {map {($_, 1)} qw(IV)};
+my @names = (qw(NETSNMP_DS_AGENT_AGENTX_MASTER
+ NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_AGENTX_RETRIES NETSNMP_DS_AGENT_AGENTX_TIMEOUT
+ NETSNMP_DS_AGENT_CACHE_TIMEOUT NETSNMP_DS_AGENT_DISABLE_PERL
+ NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ NETSNMP_DS_AGENT_FLAGS NETSNMP_DS_AGENT_GROUPID
+ NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+ NETSNMP_DS_AGENT_INTERNAL_SECNAME
+ NETSNMP_DS_AGENT_INTERNAL_VERSION NETSNMP_DS_AGENT_LEAVE_PIDFILE
+ NETSNMP_DS_AGENT_MAX_GETBULKREPEATS
+ NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES
+ NETSNMP_DS_AGENT_NO_CACHING
+ NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS NETSNMP_DS_AGENT_PERL_INIT_FILE
+ NETSNMP_DS_AGENT_PORTS NETSNMP_DS_AGENT_PROGNAME
+ NETSNMP_DS_AGENT_QUIT_IMMEDIATELY NETSNMP_DS_AGENT_ROLE
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ NETSNMP_DS_AGENT_STRICT_DISMAN NETSNMP_DS_AGENT_USERID
+ NETSNMP_DS_AGENT_VERBOSE NETSNMP_DS_AGENT_X_DIR_PERM
+ NETSNMP_DS_AGENT_X_SOCKET NETSNMP_DS_AGENT_X_SOCK_GROUP
+ NETSNMP_DS_AGENT_X_SOCK_PERM NETSNMP_DS_AGENT_X_SOCK_USER
+ NETSNMP_DS_APP_DONT_LOG NETSNMP_DS_NOTIF_LOG_CTX
+ NETSNMP_DS_SMUX_SOCKET));
+
+print constant_types(); # macro defs
+foreach (C_constant ("NetSNMP::agent::default_store", 'constant', 'IV', $types, undef, 3, @names) ) {
+ print $_, "\n"; # C constant subs
+}
+print "#### XS Section:\n";
+print XS_constant ("NetSNMP::agent::default_store", $types);
+__END__
+ */
+
+ switch (len) {
+ case 21:
+ if (memEQ(name, "NETSNMP_DS_AGENT_ROLE", 21)) {
+#ifdef NETSNMP_DS_AGENT_ROLE
+ *iv_return = NETSNMP_DS_AGENT_ROLE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 22:
+ return constant_22 (aTHX_ name, iv_return);
+ break;
+ case 23:
+ /* Names all of length 23. */
+ /* NETSNMP_DS_AGENT_USERID NETSNMP_DS_APP_DONT_LOG */
+ /* Offset 18 gives the best switch position. */
+ switch (name[18]) {
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_AGENT_USERID", 23)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_USERID
+ *iv_return = NETSNMP_DS_AGENT_USERID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'T':
+ if (memEQ(name, "NETSNMP_DS_APP_DONT_LOG", 23)) {
+ /* ^ */
+#ifdef NETSNMP_DS_APP_DONT_LOG
+ *iv_return = NETSNMP_DS_APP_DONT_LOG;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 24:
+ return constant_24 (aTHX_ name, iv_return);
+ break;
+ case 25:
+ /* Names all of length 25. */
+ /* NETSNMP_DS_AGENT_PROGNAME NETSNMP_DS_AGENT_X_SOCKET */
+ /* Offset 19 gives the best switch position. */
+ switch (name[19]) {
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_AGENT_PROGNAME", 25)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_PROGNAME
+ *iv_return = NETSNMP_DS_AGENT_PROGNAME;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_AGENT_X_SOCKET", 25)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_X_SOCKET
+ *iv_return = NETSNMP_DS_AGENT_X_SOCKET;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 27:
+ /* Names all of length 27. */
+ /* NETSNMP_DS_AGENT_NO_CACHING NETSNMP_DS_AGENT_X_DIR_PERM */
+ /* Offset 24 gives the best switch position. */
+ switch (name[24]) {
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_AGENT_X_DIR_PERM", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_X_DIR_PERM
+ *iv_return = NETSNMP_DS_AGENT_X_DIR_PERM;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_AGENT_NO_CACHING", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_NO_CACHING
+ *iv_return = NETSNMP_DS_AGENT_NO_CACHING;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 28:
+ /* Names all of length 28. */
+ /* NETSNMP_DS_AGENT_X_SOCK_PERM NETSNMP_DS_AGENT_X_SOCK_USER */
+ /* Offset 27 gives the best switch position. */
+ switch (name[27]) {
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_AGENT_X_SOCK_PER", 27)) {
+ /* M */
+#ifdef NETSNMP_DS_AGENT_X_SOCK_PERM
+ *iv_return = NETSNMP_DS_AGENT_X_SOCK_PERM;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'R':
+ if (memEQ(name, "NETSNMP_DS_AGENT_X_SOCK_USE", 27)) {
+ /* R */
+#ifdef NETSNMP_DS_AGENT_X_SOCK_USER
+ *iv_return = NETSNMP_DS_AGENT_X_SOCK_USER;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 29:
+ /* Names all of length 29. */
+ /* NETSNMP_DS_AGENT_DISABLE_PERL NETSNMP_DS_AGENT_X_SOCK_GROUP */
+ /* Offset 21 gives the best switch position. */
+ switch (name[21]) {
+ case 'B':
+ if (memEQ(name, "NETSNMP_DS_AGENT_DISABLE_PERL", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_DISABLE_PERL
+ *iv_return = NETSNMP_DS_AGENT_DISABLE_PERL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_AGENT_X_SOCK_GROUP", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_X_SOCK_GROUP
+ *iv_return = NETSNMP_DS_AGENT_X_SOCK_GROUP;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 30:
+ return constant_30 (aTHX_ name, iv_return);
+ break;
+ case 31:
+ return constant_31 (aTHX_ name, iv_return);
+ break;
+ case 33:
+ return constant_33 (aTHX_ name, iv_return);
+ break;
+ case 34:
+ if (memEQ(name, "NETSNMP_DS_AGENT_INTERNAL_SECLEVEL", 34)) {
+#ifdef NETSNMP_DS_AGENT_INTERNAL_SECLEVEL
+ *iv_return = NETSNMP_DS_AGENT_INTERNAL_SECLEVEL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 35:
+ if (memEQ(name, "NETSNMP_DS_AGENT_MAX_GETBULKREPEATS", 35)) {
+#ifdef NETSNMP_DS_AGENT_MAX_GETBULKREPEATS
+ *iv_return = NETSNMP_DS_AGENT_MAX_GETBULKREPEATS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 37:
+ /* Names all of length 37. */
+ /* NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES */
+ /* Offset 26 gives the best switch position. */
+ switch (name[26]) {
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES", 37)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES
+ *iv_return = NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL", 37)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL
+ *iv_return = NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 39:
+ /* Names all of length 39. */
+ /* NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES */
+ /* Offset 21 gives the best switch position. */
+ switch (name[21]) {
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES", 39)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES
+ *iv_return = NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS", 39)) {
+ /* ^ */
+#ifdef NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS
+ *iv_return = NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 42:
+ if (memEQ(name, "NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS", 42)) {
+#ifdef NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS
+ *iv_return = NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 46:
+ if (memEQ(name, "NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS", 46)) {
+#ifdef NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS
+ *iv_return = NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+
+
+/* autogenerated by "gen" from const-xs.inc */
+
+MODULE = NetSNMP::agent::default_store PACKAGE = NetSNMP::agent::default_store
+
+void
+constant(sv)
+ PREINIT:
+#ifdef dXSTARG
+ dXSTARG; /* Faster if we have it. */
+#else
+ dTARGET;
+#endif
+ STRLEN len;
+ int type;
+ IV iv = 0;
+ /* NV nv; Uncomment this if you need to return NVs */
+ /* const char *pv; Uncomment this if you need to return PVs */
+ INPUT:
+ SV * sv;
+ const char * s = SvPV(sv, len);
+ PPCODE:
+ /* Change this to constant(aTHX_ s, len, &iv, &nv);
+ if you need to return both NVs and IVs */
+ type = constant(aTHX_ s, len, &iv);
+ /* Return 1 or 2 items. First is error message, or undef if no error.
+ Second, if present, is found value */
+ switch (type) {
+ case PERL_constant_NOTFOUND:
+ sv = sv_2mortal(newSVpvf("%s is not a valid NetSNMP::agent::default_store macro", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_NOTDEF:
+ sv = sv_2mortal(newSVpvf(
+ "Your vendor has not defined NetSNMP::agent::default_store macro %s, used", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_ISIV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHi(iv);
+ break;
+ /* Uncomment this if you need to return NOs
+ case PERL_constant_ISNO:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_no);
+ break; */
+ /* Uncomment this if you need to return NVs
+ case PERL_constant_ISNV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHn(nv);
+ break; */
+ /* Uncomment this if you need to return PVs
+ case PERL_constant_ISPV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, strlen(pv));
+ break; */
+ /* Uncomment this if you need to return PVNs
+ case PERL_constant_ISPVN:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, iv);
+ break; */
+ /* Uncomment this if you need to return SVs
+ case PERL_constant_ISSV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(sv);
+ break; */
+ /* Uncomment this if you need to return UNDEFs
+ case PERL_constant_ISUNDEF:
+ break; */
+ /* Uncomment this if you need to return UVs
+ case PERL_constant_ISUV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHu((UV)iv);
+ break; */
+ /* Uncomment this if you need to return YESs
+ case PERL_constant_ISYES:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_yes);
+ break; */
+ default:
+ sv = sv_2mortal(newSVpvf(
+ "Unexpected return type %d while processing NetSNMP::agent::default_store macro %s, used",
+ type, s));
+ PUSHs(sv);
+ }
+
+
+
diff --git a/perl/agent/default_store/gen b/perl/agent/default_store/gen
new file mode 100755
index 0000000..55823d6
--- /dev/null
+++ b/perl/agent/default_store/gen
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+
+system("grep 'define NETSNMP_DS_' ../../../include/net-snmp/agent/ds_agent.h > default_store.h");
+#gcc -E ../../include/net-snmp/library/default_store.h | grep -v default_store.h >> default_store.h
+system("h2xs -b 5.5.0 -n NetSNMP::agent::default_store -O default_store.h");
+
+open(ORIG,"default_store.xs");
+open(NEW1,"NetSNMP-agent-default_store/fallback/const-c.inc") || die "can't open inc file 1";
+open(NEW2,"NetSNMP-agent-default_store/fallback/const-xs.inc") || die "can't open inc file 2";
+open(OUT,">default_store_new.xs");
+
+# get up to the include from the original file
+while(<ORIG>) {
+ print OUT;
+ last if (/include <net-snmp\/agent\/ds_agent.h/);
+}
+
+# include the entire new file
+print OUT "\n\n/* autogenerated by \"gen\" from const-c.inc */\n\n";
+print OUT <NEW1>;
+print OUT "\n\n/* autogenerated by \"gen\" from const-xs.inc */\n\n";
+print OUT "MODULE = NetSNMP::agent::default_store PACKAGE = NetSNMP::agent::default_store\n\n";
+
+print OUT <NEW2>;
+
+#print OUT "\n\n/* autogenerated by \"gen\" from tail of old .xs file */\n\n";
+print OUT "\n\n\n";
+
+close(OUT);
+
+#
+# generate test
+#
+open(H,"default_store.h");
+open(ORIG,"test.pl");
+open(OUT,">test.pl.new");
+
+while(<ORIG>) {
+ print OUT;
+ last if (/\%tests =/);
+}
+
+while(<H>) {
+ if (/define\s+(\w+)\s+(\d+)/) {
+ printf OUT (" %-40s => %d,\n", "\"$1\"", $2);
+ $tokenlist .= " $1\n";
+ }
+}
+
+while(<ORIG>) {
+ last if (/\);/);
+}
+print OUT;
+print OUT <ORIG>;
+close(OUT);
+
+#
+# modify the perl module itself
+#
+open(H,"default_store.h");
+open(ORIG,"default_store.pm");
+open(OUT,">default_store_new.pm");
+
+# first list
+while(<ORIG>) {
+ print OUT;
+ last if (/\%EXPORT_TAGS =/);
+}
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/\) \] \);/);
+}
+print OUT;
+
+# second list
+while(<ORIG>) {
+ print OUT;
+ last if (/\@EXPORT =/);
+}
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/\);/);
+}
+print OUT;
+
+# last section
+while(<ORIG>) {
+ print OUT;
+ last if (/head2 Exportable constants/);
+}
+print OUT "\n";
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/^\s*$/);
+}
+print OUT "\n";
+print OUT;
+
+# tail end
+print OUT <ORIG>;
+close(OUT);
+
+#
+# install new files
+#
+print "updated test.pl\n";
+rename("test.pl.new","test.pl");
+rename("default_store_new.pm", "default_store.pm");
+print "updated default_store.pm\n";
+rename("default_store_new.xs", "default_store.xs");
+print "updated default_store.xs\n";
+
+#
+# remove the temp files.
+#
+system("rm -rf NetSNMP-agent-default_store");
+unlink("default_store.h");
+
diff --git a/perl/agent/default_store/test.pl b/perl/agent/default_store/test.pl
new file mode 100644
index 0000000..23b5611
--- /dev/null
+++ b/perl/agent/default_store/test.pl
@@ -0,0 +1,69 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1;
+
+ %tests = (
+ "NETSNMP_DS_AGENT_VERBOSE" => 0,
+ "NETSNMP_DS_AGENT_ROLE" => 1,
+ "NETSNMP_DS_AGENT_NO_ROOT_ACCESS" => 2,
+ "NETSNMP_DS_AGENT_AGENTX_MASTER" => 3,
+ "NETSNMP_DS_AGENT_QUIT_IMMEDIATELY" => 4,
+ "NETSNMP_DS_AGENT_DISABLE_PERL" => 5,
+ "NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS" => 6,
+ "NETSNMP_DS_AGENT_LEAVE_PIDFILE" => 7,
+ "NETSNMP_DS_AGENT_NO_CACHING" => 8,
+ "NETSNMP_DS_AGENT_STRICT_DISMAN" => 9,
+ "NETSNMP_DS_AGENT_DONT_RETAIN_NOTIFICATIONS" => 10,
+ "NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS" => 12,
+ "NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES" => 13,
+ "NETSNMP_DS_AGENT_PROGNAME" => 0,
+ "NETSNMP_DS_AGENT_X_SOCKET" => 1,
+ "NETSNMP_DS_AGENT_PORTS" => 2,
+ "NETSNMP_DS_AGENT_INTERNAL_SECNAME" => 3,
+ "NETSNMP_DS_AGENT_PERL_INIT_FILE" => 4,
+ "NETSNMP_DS_SMUX_SOCKET" => 5,
+ "NETSNMP_DS_NOTIF_LOG_CTX" => 6,
+ "NETSNMP_DS_AGENT_FLAGS" => 0,
+ "NETSNMP_DS_AGENT_USERID" => 1,
+ "NETSNMP_DS_AGENT_GROUPID" => 2,
+ "NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL" => 3,
+ "NETSNMP_DS_AGENT_AGENTX_TIMEOUT" => 4,
+ "NETSNMP_DS_AGENT_AGENTX_RETRIES" => 5,
+ "NETSNMP_DS_AGENT_X_SOCK_PERM" => 6,
+ "NETSNMP_DS_AGENT_X_DIR_PERM" => 7,
+ "NETSNMP_DS_AGENT_X_SOCK_USER" => 8,
+ "NETSNMP_DS_AGENT_X_SOCK_GROUP" => 9,
+ "NETSNMP_DS_AGENT_CACHE_TIMEOUT" => 10,
+ "NETSNMP_DS_AGENT_INTERNAL_VERSION" => 11,
+ "NETSNMP_DS_AGENT_INTERNAL_SECLEVEL" => 12,
+ "NETSNMP_DS_AGENT_MAX_GETBULKREPEATS" => 13,
+ "NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES" => 14,
+ );
+
+ print "1.." . (scalar(keys(%tests)) + 2) . "\n";
+ }
+END {print "not ok 1\n" unless $loaded;}
+use NetSNMP::agent::default_store (':all');
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+$c = 2;
+foreach my $i (keys(%tests)) {
+ my $str = "NetSNMP::agent::default_store::$i";
+ my $val = eval $str;
+# print "$i -> $val -> $tests{$i}\n";
+ $c++;
+ print (($val eq $tests{$i})?"ok $c\n" : "not ok $c\n# error: name=$i value_expected=$tests{$i} value_got=$val \n");
+}
diff --git a/perl/agent/netsnmp-feature-definitions.h b/perl/agent/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..4f2630e
--- /dev/null
+++ b/perl/agent/netsnmp-feature-definitions.h
@@ -0,0 +1,6 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+netsnmp_feature_require(agent_check_and_process)
+netsnmp_feature_require(snmp_enable_stderrlog)
+
diff --git a/perl/agent/netsnmp_request_infoPtr.pm b/perl/agent/netsnmp_request_infoPtr.pm
new file mode 100644
index 0000000..6678e9e
--- /dev/null
+++ b/perl/agent/netsnmp_request_infoPtr.pm
@@ -0,0 +1,23 @@
+package NetSNMP::agent::netsnmp_request_infoPtr;
+
+# bogus file
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::agent::netsnmp_request_infoPtr - Perl extension for request information
+
+=head1 SYNOPSIS
+
+ see NetSNMP::agent documentation
+
+=head1 AUTHOR
+
+Please mail the net-snmp-users@lists.sourceforge.net mailing list for
+help, questions or comments about this module.
+
+Wes Hardaker, hardaker@users.sourceforge.net
+
+=cut
diff --git a/perl/agent/test.pl b/perl/agent/test.pl
new file mode 100644
index 0000000..88cba56
--- /dev/null
+++ b/perl/agent/test.pl
@@ -0,0 +1,122 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1;
+ $ENV{'SNMPCONFPATH'} = 'nopath';
+ $ENV{'MIBS'} = '';
+ print "1..6\n";
+ }
+END {print "not ok 1\n" unless $loaded;}
+use NetSNMP::agent (':all');
+use NetSNMP::default_store (':all');
+use NetSNMP::agent::default_store (':all');
+use NetSNMP::ASN (':all');
+use NetSNMP::OID;
+#use NetSNMP::agent (':all');
+use SNMP;
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+sub it {
+ if ($_[0]) {
+ return "ok " . $_[1] . "\n";
+ } else {
+ return "not ok ". $_[1] ."\n";
+ }
+}
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+print it((MODE_GET == 0xa0 &&
+ MODE_GETNEXT == 0xa1 &&
+ MODE_GETBULK == 0xa5 &&
+ MODE_SET_BEGIN == -1 &&
+ MODE_SET_RESERVE1 == 0 &&
+ MODE_SET_RESERVE2 == 1 &&
+ MODE_SET_ACTION == 2 &&
+ MODE_SET_COMMIT == 3 &&
+ MODE_SET_FREE == 4 &&
+ MODE_SET_UNDO == 5 &&
+ SNMP_ERR_NOERROR == 0 &&
+ SNMP_ERR_TOOBIG == 1 &&
+ SNMP_ERR_NOSUCHNAME == 2 &&
+ SNMP_ERR_BADVALUE == 3 &&
+ SNMP_ERR_READONLY == 4 &&
+ SNMP_ERR_GENERR == 5 &&
+ SNMP_ERR_NOACCESS == 6 &&
+ SNMP_ERR_WRONGTYPE == 7 &&
+ SNMP_ERR_WRONGLENGTH == 8 &&
+ SNMP_ERR_WRONGENCODING == 9 &&
+ SNMP_ERR_WRONGVALUE == 10 &&
+ SNMP_ERR_NOCREATION == 11 &&
+ SNMP_ERR_INCONSISTENTVALUE == 12 &&
+ SNMP_ERR_RESOURCEUNAVAILABLE == 13 &&
+ SNMP_ERR_COMMITFAILED == 14 &&
+ SNMP_ERR_UNDOFAILED == 15 &&
+ SNMP_ERR_AUTHORIZATIONERROR == 16 &&
+ SNMP_ERR_NOTWRITABLE == 17
+ ), 2);
+
+netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+ NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
+my $agent = new NetSNMP::agent('Name' => 'test',
+ 'Ports' => '9161');
+print it($agent, 3);
+
+$regitem = $agent->register("test_reg", ".1.3.6.1.8888", \&testsub);
+print it($regitem, 4);
+#print STDERR $regitem,":",ref($regitem),"\n";
+print it(ref($regitem) eq "NetSNMP::agent::netsnmp_handler_registration", 5);
+
+my $uptime1 = $agent->uptime();
+my $uptime2 = $agent->uptime(666);
+my $uptime3 = $agent->uptime(555, 444);
+print it($uptime1 <= $uptime2 && $uptime2 <= $uptime3, 6);
+
+exit;
+
+while(1) {
+ print netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
+ NETSNMP_DS_AGENT_PORTS), "\n";
+ $agent->agent_check_and_process(1);
+ print netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
+ NETSNMP_DS_AGENT_PORTS), "\n";
+ print "got something\n";
+}
+exit;
+
+$x = NetSNMP::agent::handler_registration::new("hi",\&testsub,".1.3.6.1.999");
+print ((ref($x) eq "handler_registrationPtr") ? "ok 2\n" : "not ok 2\n");
+
+print (($x->register() == 0) ? "ok 3\n" : "not ok 3\n");
+
+my $y = NetSNMP::agent::register_mib("me",\&testsub,".1.3.6.1.8888");
+while(1) {
+ NetSNMP::agent::agent_check_and_process();
+ print "got something\n";
+}
+
+#use Data::Dumper;
+sub testsub {
+ print STDERR "in perl handler sub\n";
+ print STDERR " args: ", join(", ", @_), "\n";
+ #print STDERR " dumped args: ", Dumper(@_);
+ $oid= $_[3]->getOID();
+ print STDERR " request oid: ", ref($oid), " -> ", $oid, "\n";
+ print STDERR " mode: ", $_[2]->getMode(),"\n";
+ $_[3]->setOID(".1.3.6.1.8888.1");
+ $_[3]->setValue(2, 42);
+ $_[3]->setValue(ASN_INTEGER, 42);
+ print STDERR " oid: ", $_[3]->getOID(),"\n";
+ print STDERR " ref: ", ref($_[3]),"\n";
+ print STDERR " val: ", $_[3]->getValue(),"\n";
+}
diff --git a/perl/agent/typemap b/perl/agent/typemap
new file mode 100644
index 0000000..ff2b844
--- /dev/null
+++ b/perl/agent/typemap
@@ -0,0 +1,6 @@
+TYPEMAP
+netsnmp_handler_registration * T_PTROBJ
+NetSNMP::agent::netsnmp_handler_registration T_PTROBJ
+netsnmp_request_info * T_PTROBJ
+const char * T_PV
+netsnmp_oid * T_PTROBJ
diff --git a/perl/default_store/Changes b/perl/default_store/Changes
new file mode 100644
index 0000000..87e1133
--- /dev/null
+++ b/perl/default_store/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension NetSNMP::default_store.
+
+0.01 Thu Jan 3 22:35:38 2002
+ - original version; created by h2xs 1.20 with options
+ -F '-Du_char="unsigned char"' -x -O -n NetSNMP::default_store ucd-snmp/default_store.h
+
diff --git a/perl/default_store/MANIFEST b/perl/default_store/MANIFEST
new file mode 100644
index 0000000..ea73c2e
--- /dev/null
+++ b/perl/default_store/MANIFEST
@@ -0,0 +1,8 @@
+Changes
+MANIFEST
+Makefile.PL
+default_store.pm
+default_store.xs
+test.pl
+typemap
+README
diff --git a/perl/default_store/Makefile.PL b/perl/default_store/Makefile.PL
new file mode 100644
index 0000000..7c671b8
--- /dev/null
+++ b/perl/default_store/Makefile.PL
@@ -0,0 +1,227 @@
+use ExtUtils::MakeMaker;
+require 5;
+use Config;
+use Getopt::Long;
+my $lib_version;
+my %MakeParams = ();
+
+%MakeParams = InitMakeParams();
+
+WriteMakefile(%MakeParams);
+
+
+sub InitMakeParams {
+ my $opts;
+ my %Params = (
+ 'NAME' => 'NetSNMP::default_store',
+ 'VERSION_FROM' => 'default_store.pm', # finds $VERSION
+ 'XSPROTOARG' => '-prototypes',
+ );
+
+ if ($ENV{'OSTYPE'} eq 'msys') {
+ $Params{'DEFINE'} = "-DMINGW_PERL";
+ }
+
+ my ($snmp_lib, $snmp_llib, $sep);
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+ $opts = NetSNMPGetOpts();
+ $Params{'DEFINE'} = "-DMSVC_PERL -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS";
+ $sep = '\\';
+ $snmp_lib_file = 'netsnmp.lib';
+ $snmp_link_lib = 'netsnmp';
+
+ if (lc($opts->{'debug'}) eq "true") {
+ $lib_dir = 'lib\\debug';
+ }
+ else {
+ $lib_dir = 'lib\\release';
+ }
+
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L$basedir\\win32\\$lib_dir\\ -l$snmp_link_lib";
+ }
+ else {
+ my @LibDirs = split (';',$ENV{LIB});
+ my $LibDir;
+ if ($opts->{'prefix'}) {
+ push (@LibDirs,"$ENV{'NET-SNMP-PATH'}${sep}lib");
+ }
+ $noLibDir = 1;
+ while ($noLibDir) {
+ $LibDir = find_files(["$snmp_lib_file"],\@LibDirs);
+ if ($LibDir ne '') {
+ $noLibDir = 0;
+ # Put quotes around LibDir to allow spaces in paths
+ $LibDir = '"' . $LibDir . '"';
+ }
+ else
+ {
+ @LibDirs = ();
+ $LibDirs[0] = prompt("The Net-SNMP library ($snmp_lib_file) could not be found.\nPlease enter the directory where it is located:");
+ $LibDirs[0] =~ s/\\$//;
+ }
+ }
+ $Params{LIBS} = "-L$LibDir -l$snmp_link_lib";
+ }
+
+ $Params{'INC'} = "-I$basedir\\include\\ -I$basedir\\include\\net-snmp\\ -I$basedir\\win32\\ ";
+ }
+ else {
+ $opts = NetSNMPGetOpts();
+ $Params{'LDDLFLAGS'} = "$Config{lddlflags} " . `$opts->{'nsconfig'} --ldflags`;
+ $Params{'LIBS'} = `$opts->{'nsconfig'} --libs`;
+ chomp($Params{'LIBS'});
+ $Params{'CCFLAGS'} = `$opts->{'nsconfig'} --cflags`;
+ chomp($Params{'CCFLAGS'});
+ $Params{'CCFLAGS'} .= " " . $Config{'ccflags'};
+ $lib_version = `$opts->{'nsconfig'} --version`;
+ if (lc($opts->{'insource'}) eq "true") {
+ $Params{'LIBS'} = "-L../../snmplib/.libs -L../../snmplib/ " . $Params{'LIBS'};
+ $Params{'CCFLAGS'} = "-I../../include " . $Params{'CCFLAGS'};
+ }
+ $Params{'CCFLAGS'} =~ s/ -W(all|inline|strict-prototypes|write-strings|cast-qual|no-char-subscripts)//g; # ignore developer warnings
+ if ($Params{'LIBS'} eq "" || $Params{'CCFLAGS'} eq "") {
+ die "You need to install net-snmp first (I can't find net-snmp-config)";
+ }
+ }
+
+ return(%Params);
+}
+# common subroutines -- DO NOT EDIT.
+# They are imported from the Makefile.subs.pl file
+sub NetSNMPGetOpts {
+ my %ret;
+ my $rootpath = shift;
+ $rootpath = "../" if (!$rootpath);
+ $rootpath .= '/' if ($rootpath !~ /\/$/);
+
+ if (($Config{'osname'} eq 'MSWin32' && $ENV{'OSTYPE'} eq '')) {
+
+ # Grab command line options first. Only used if environment variables are not set
+ GetOptions("NET-SNMP-IN-SOURCE=s" => \$ret{'insource'},
+ "NET-SNMP-PATH=s" => \$ret{'prefix'},
+ "NET-SNMP-DEBUG=s" => \$ret{'debug'});
+
+ if ($ENV{'NET-SNMP-IN-SOURCE'})
+ {
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ undef ($ret{'prefix'});
+ }
+ elsif ($ENV{'NET-SNMP-PATH'})
+ {
+ $ret{'prefix'} = $ENV{'NET-SNMP-PATH'};
+ }
+
+ if ($ENV{'NET-SNMP-DEBUG'})
+ {
+ $ret{'debug'} = $ENV{'NET-SNMP-DEBUG'};
+ }
+
+ # Update environment variables in case they are needed
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ $ENV{'NET-SNMP-PATH'} = $ret{'prefix'};
+ $ENV{'NET-SNMP-DEBUG'} = $ret{'debug'};
+
+ $basedir = `%COMSPEC% /c cd`;
+ chomp $basedir;
+ $basedir =~ /(.*?)\\perl.*/;
+ $basedir = $1;
+ print "Net-SNMP base directory: $basedir\n";
+ if ($basedir =~ / /) {
+ die "\nA space has been detected in the base directory. This is not " .
+ "supported\nPlease rename the folder and try again.\n\n";
+ }
+ }
+ else
+ {
+ if ($ENV{'NET-SNMP-CONFIG'} &&
+ $ENV{'NET-SNMP-IN-SOURCE'}) {
+ # have env vars, pull from there
+ $ret{'nsconfig'} = $ENV{'NET-SNMP-CONFIG'};
+ $ret{'insource'} = $ENV{'NET-SNMP-IN-SOURCE'};
+ } else {
+ # don't have env vars, pull from command line and put there
+ GetOptions("NET-SNMP-CONFIG=s" => \$ret{'nsconfig'},
+ "NET-SNMP-IN-SOURCE=s" => \$ret{'insource'});
+
+ if (lc($ret{'insource'}) eq "true" && $ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="sh ROOTPATH../net-snmp-config";
+ } elsif ($ret{'nsconfig'} eq "") {
+ $ret{'nsconfig'}="net-snmp-config";
+ }
+
+ $ENV{'NET-SNMP-CONFIG'} = $ret{'nsconfig'};
+ $ENV{'NET-SNMP-IN-SOURCE'} = $ret{'insource'};
+ }
+ }
+
+ $ret{'nsconfig'} =~ s/ROOTPATH/$rootpath/;
+
+ $ret{'rootpath'} = $rootpath;
+
+ \%ret;
+}
+
+sub find_files {
+ my($f,$d) = @_;
+ my ($dir,$found,$file);
+ for $dir (@$d){
+ $found = 0;
+ for $file (@$f) {
+ $found++ if -f "$dir/$file";
+ }
+ if ($found == @$f) {
+ return $dir;
+ }
+ }
+}
+
+
+sub Check_Version {
+ if (($Config{'osname'} ne 'MSWin32' || $ENV{'OSTYPE'} ne '')) {
+ my $foundversion = 0;
+ return if ($ENV{'NETSNMP_DONT_CHECK_VERSION'});
+ open(I,"<Makefile");
+ while (<I>) {
+ if (/^VERSION = (.*)/) {
+ my $perlver = $1;
+ my $srcver = $lib_version;
+ chomp($srcver);
+ my $srcfloat = floatize_version($srcver);
+ $perlver =~ s/pre/0./;
+ # we allow for perl/CPAN-only revisions beyond the default
+ # version formatting of net-snmp itself.
+ $perlver =~ s/(\.\d{5}).*/\1/;
+ $perlver =~ s/0*$//;
+ if ($srcfloat ne $perlver) {
+ if (!$foundversion) {
+ print STDERR "ERROR:
+Net-SNMP installed version: $srcver => $srcfloat
+Perl Module Version: $perlver
+
+These versions must match for perfect support of the module. It is possible
+that different versions may work together, but it is strongly recommended
+that you make these two versions identical. You can get the Net-SNMP
+source code and the associated perl modules directly from
+
+ http://www.net-snmp.org/
+
+If you want to continue anyway please set the NETSNMP_DONT_CHECK_VERSION
+environmental variable to 1 and re-run the Makefile.PL script.\n";
+ exit(1);
+ }
+ }
+ $foundversion = 1;
+ last;
+ }
+ }
+ close(I);
+ die "ERROR: Couldn't find version number of this module\n"
+ if (!$foundversion);
+ }
+}
+
+sub floatize_version {
+ my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/);
+ return $major + $minor/100 + $patch/10000 + $opps/100000;
+}
diff --git a/perl/default_store/README b/perl/default_store/README
new file mode 100644
index 0000000..680446a
--- /dev/null
+++ b/perl/default_store/README
@@ -0,0 +1,14 @@
+This module is a wrapper around the net-snmp default store routines.
+See the net-snmp default_store manual page for details.
+
+To install:
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+To compile in the source tree before the net-snmp itself has been installed:
+ perl Makefile.PL -NET-SNMP-CONFIG="sh ../../net-snmp-config" -NET-SNMP-IN-SOURCE=true
+ make
+ make test
+ make install
diff --git a/perl/default_store/default_store.pm b/perl/default_store/default_store.pm
new file mode 100644
index 0000000..3d18ffc
--- /dev/null
+++ b/perl/default_store/default_store.pm
@@ -0,0 +1,366 @@
+package NetSNMP::default_store;
+
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD);
+
+@ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use NetSNMP::default_store ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+%EXPORT_TAGS = ( 'all' => [ qw(
+ NETSNMP_DS_MAX_IDS
+ NETSNMP_DS_MAX_SUBIDS
+ NETSNMP_DS_LIBRARY_ID
+ NETSNMP_DS_APPLICATION_ID
+ NETSNMP_DS_TOKEN_ID
+ NETSNMP_DS_LIB_MIB_ERRORS
+ NETSNMP_DS_LIB_SAVE_MIB_DESCRS
+ NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ NETSNMP_DS_LIB_DUMP_PACKET
+ NETSNMP_DS_LIB_LOG_TIMESTAMP
+ NETSNMP_DS_LIB_DONT_READ_CONFIGS
+ NETSNMP_DS_LIB_MIB_REPLACE
+ NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
+ NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ NETSNMP_DS_LIB_ALARM_DONT_USE_SIG
+ NETSNMP_DS_LIB_PRINT_FULL_OID
+ NETSNMP_DS_LIB_QUICK_PRINT
+ NETSNMP_DS_LIB_RANDOM_ACCESS
+ NETSNMP_DS_LIB_REGEX_ACCESS
+ NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ NETSNMP_DS_LIB_NO_TOKEN_WARNINGS
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS
+ NETSNMP_DS_LIB_ESCAPE_QUOTES
+ NETSNMP_DS_LIB_REVERSE_ENCODE
+ NETSNMP_DS_LIB_PRINT_BARE_VALUE
+ NETSNMP_DS_LIB_EXTENDED_INDEX
+ NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID
+ NETSNMP_DS_LIB_READ_UCD_STYLE_OID
+ NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG
+ NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ NETSNMP_DS_LIB_QUICKE_PRINT
+ NETSNMP_DS_LIB_DONT_PRINT_UNITS
+ NETSNMP_DS_LIB_NO_DISPLAY_HINT
+ NETSNMP_DS_LIB_16BIT_IDS
+ NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT
+ NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ NETSNMP_DS_LIB_APPEND_LOGFILES
+ NETSNMP_DS_LIB_MIB_WARNINGS
+ NETSNMP_DS_LIB_SECLEVEL
+ NETSNMP_DS_LIB_SNMPVERSION
+ NETSNMP_DS_LIB_DEFAULT_PORT
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ NETSNMP_DS_LIB_SERVERSENDBUF
+ NETSNMP_DS_LIB_SERVERRECVBUF
+ NETSNMP_DS_LIB_CLIENTSENDBUF
+ NETSNMP_DS_LIB_CLIENTRECVBUF
+ NETSNMP_DS_SNMP_VERSION_1
+ NETSNMP_DS_SNMP_VERSION_2c
+ NETSNMP_DS_SNMP_VERSION_3
+ NETSNMP_DS_LIB_SECNAME
+ NETSNMP_DS_LIB_CONTEXT
+ NETSNMP_DS_LIB_PASSPHRASE
+ NETSNMP_DS_LIB_AUTHPASSPHRASE
+ NETSNMP_DS_LIB_PRIVPASSPHRASE
+ NETSNMP_DS_LIB_OPTIONALCONFIG
+ NETSNMP_DS_LIB_APPTYPE
+ NETSNMP_DS_LIB_COMMUNITY
+ NETSNMP_DS_LIB_PERSISTENT_DIR
+ NETSNMP_DS_LIB_CONFIGURATION_DIR
+ NETSNMP_DS_LIB_SECMODEL
+ NETSNMP_DS_LIB_MIBDIRS
+ NETSNMP_DS_LIB_OIDSUFFIX
+ NETSNMP_DS_LIB_OIDPREFIX
+ NETSNMP_DS_LIB_CLIENT_ADDR
+ NETSNMP_DS_LIB_TEMP_FILE_PATTERN
+ NETSNMP_DS_LIB_AUTHMASTERKEY
+ NETSNMP_DS_LIB_PRIVMASTERKEY
+ NETSNMP_DS_LIB_AUTHLOCALIZEDKEY
+ NETSNMP_DS_LIB_PRIVLOCALIZEDKEY
+ NETSNMP_DS_LIB_APPTYPES
+ NETSNMP_DS_LIB_KSM_KEYTAB
+ NETSNMP_DS_LIB_KSM_SERVICE_NAME
+ NETSNMP_DS_LIB_SBSM_LOCAL_PWD
+ netsnmp_ds_get_boolean
+ netsnmp_ds_get_int
+ netsnmp_ds_get_string
+ netsnmp_ds_get_void
+ netsnmp_ds_register_config
+ netsnmp_ds_register_premib
+ netsnmp_ds_set_boolean
+ netsnmp_ds_set_int
+ netsnmp_ds_set_string
+ netsnmp_ds_set_void
+ netsnmp_ds_shutdown
+ netsnmp_ds_toggle_boolean
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+@EXPORT = qw(
+ NETSNMP_DS_MAX_IDS
+ NETSNMP_DS_MAX_SUBIDS
+ NETSNMP_DS_LIBRARY_ID
+ NETSNMP_DS_APPLICATION_ID
+ NETSNMP_DS_TOKEN_ID
+ NETSNMP_DS_LIB_MIB_ERRORS
+ NETSNMP_DS_LIB_SAVE_MIB_DESCRS
+ NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ NETSNMP_DS_LIB_DUMP_PACKET
+ NETSNMP_DS_LIB_LOG_TIMESTAMP
+ NETSNMP_DS_LIB_DONT_READ_CONFIGS
+ NETSNMP_DS_LIB_MIB_REPLACE
+ NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
+ NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ NETSNMP_DS_LIB_ALARM_DONT_USE_SIG
+ NETSNMP_DS_LIB_PRINT_FULL_OID
+ NETSNMP_DS_LIB_QUICK_PRINT
+ NETSNMP_DS_LIB_RANDOM_ACCESS
+ NETSNMP_DS_LIB_REGEX_ACCESS
+ NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ NETSNMP_DS_LIB_NO_TOKEN_WARNINGS
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS
+ NETSNMP_DS_LIB_ESCAPE_QUOTES
+ NETSNMP_DS_LIB_REVERSE_ENCODE
+ NETSNMP_DS_LIB_PRINT_BARE_VALUE
+ NETSNMP_DS_LIB_EXTENDED_INDEX
+ NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID
+ NETSNMP_DS_LIB_READ_UCD_STYLE_OID
+ NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG
+ NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ NETSNMP_DS_LIB_QUICKE_PRINT
+ NETSNMP_DS_LIB_DONT_PRINT_UNITS
+ NETSNMP_DS_LIB_NO_DISPLAY_HINT
+ NETSNMP_DS_LIB_16BIT_IDS
+ NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT
+ NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ NETSNMP_DS_LIB_APPEND_LOGFILES
+ NETSNMP_DS_LIB_MIB_WARNINGS
+ NETSNMP_DS_LIB_SECLEVEL
+ NETSNMP_DS_LIB_SNMPVERSION
+ NETSNMP_DS_LIB_DEFAULT_PORT
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ NETSNMP_DS_LIB_SERVERSENDBUF
+ NETSNMP_DS_LIB_SERVERRECVBUF
+ NETSNMP_DS_LIB_CLIENTSENDBUF
+ NETSNMP_DS_LIB_CLIENTRECVBUF
+ NETSNMP_DS_SNMP_VERSION_1
+ NETSNMP_DS_SNMP_VERSION_2c
+ NETSNMP_DS_SNMP_VERSION_3
+ NETSNMP_DS_LIB_SECNAME
+ NETSNMP_DS_LIB_CONTEXT
+ NETSNMP_DS_LIB_PASSPHRASE
+ NETSNMP_DS_LIB_AUTHPASSPHRASE
+ NETSNMP_DS_LIB_PRIVPASSPHRASE
+ NETSNMP_DS_LIB_OPTIONALCONFIG
+ NETSNMP_DS_LIB_APPTYPE
+ NETSNMP_DS_LIB_COMMUNITY
+ NETSNMP_DS_LIB_PERSISTENT_DIR
+ NETSNMP_DS_LIB_CONFIGURATION_DIR
+ NETSNMP_DS_LIB_SECMODEL
+ NETSNMP_DS_LIB_MIBDIRS
+ NETSNMP_DS_LIB_OIDSUFFIX
+ NETSNMP_DS_LIB_OIDPREFIX
+ NETSNMP_DS_LIB_CLIENT_ADDR
+ NETSNMP_DS_LIB_TEMP_FILE_PATTERN
+ NETSNMP_DS_LIB_AUTHMASTERKEY
+ NETSNMP_DS_LIB_PRIVMASTERKEY
+ NETSNMP_DS_LIB_AUTHLOCALIZEDKEY
+ NETSNMP_DS_LIB_PRIVLOCALIZEDKEY
+ NETSNMP_DS_LIB_APPTYPES
+ NETSNMP_DS_LIB_KSM_KEYTAB
+ NETSNMP_DS_LIB_KSM_SERVICE_NAME
+ NETSNMP_DS_LIB_SBSM_LOCAL_PWD
+);
+$VERSION = '5.0702';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function.
+
+ my $constname;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "&NetSNMP::default_store::constant not defined" if $constname eq 'cons
+tant';
+ my ($error, $val) = constant($constname);
+ if ($error) { croak $error; }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+#XXX if ($] >= 5.00561) {
+#XXX *$AUTOLOAD = sub () { $val };
+#XXX }
+#XXX else {
+ *$AUTOLOAD = sub { $val };
+#XXX }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap NetSNMP::default_store $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+NetSNMP::default_store - Perl extension for Net-SNMP generic storage of global data
+
+=head1 SYNOPSIS
+
+ use NetSNMP::default_store qw(:all);
+ $port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
+ netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT, 161);
+
+=head1 DESCRIPTION
+
+This module is a wrapper around the net-snmp default store routines.
+See the net-snmp default_store manual page for details on what the
+various functions do and the values that can be set/retrieved.
+
+=head2 EXPORT
+
+None by default.
+
+=head2 Exportable constants
+
+ NETSNMP_DS_MAX_IDS
+ NETSNMP_DS_MAX_SUBIDS
+ NETSNMP_DS_LIBRARY_ID
+ NETSNMP_DS_APPLICATION_ID
+ NETSNMP_DS_TOKEN_ID
+ NETSNMP_DS_LIB_MIB_ERRORS
+ NETSNMP_DS_LIB_SAVE_MIB_DESCRS
+ NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ NETSNMP_DS_LIB_DUMP_PACKET
+ NETSNMP_DS_LIB_LOG_TIMESTAMP
+ NETSNMP_DS_LIB_DONT_READ_CONFIGS
+ NETSNMP_DS_LIB_MIB_REPLACE
+ NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
+ NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ NETSNMP_DS_LIB_ALARM_DONT_USE_SIG
+ NETSNMP_DS_LIB_PRINT_FULL_OID
+ NETSNMP_DS_LIB_QUICK_PRINT
+ NETSNMP_DS_LIB_RANDOM_ACCESS
+ NETSNMP_DS_LIB_REGEX_ACCESS
+ NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ NETSNMP_DS_LIB_NO_TOKEN_WARNINGS
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS
+ NETSNMP_DS_LIB_ESCAPE_QUOTES
+ NETSNMP_DS_LIB_REVERSE_ENCODE
+ NETSNMP_DS_LIB_PRINT_BARE_VALUE
+ NETSNMP_DS_LIB_EXTENDED_INDEX
+ NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID
+ NETSNMP_DS_LIB_READ_UCD_STYLE_OID
+ NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG
+ NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ NETSNMP_DS_LIB_QUICKE_PRINT
+ NETSNMP_DS_LIB_DONT_PRINT_UNITS
+ NETSNMP_DS_LIB_NO_DISPLAY_HINT
+ NETSNMP_DS_LIB_16BIT_IDS
+ NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT
+ NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ NETSNMP_DS_LIB_APPEND_LOGFILES
+ NETSNMP_DS_LIB_MIB_WARNINGS
+ NETSNMP_DS_LIB_SECLEVEL
+ NETSNMP_DS_LIB_SNMPVERSION
+ NETSNMP_DS_LIB_DEFAULT_PORT
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ NETSNMP_DS_LIB_SERVERSENDBUF
+ NETSNMP_DS_LIB_SERVERRECVBUF
+ NETSNMP_DS_LIB_CLIENTSENDBUF
+ NETSNMP_DS_LIB_CLIENTRECVBUF
+ NETSNMP_DS_SNMP_VERSION_1
+ NETSNMP_DS_SNMP_VERSION_2c
+ NETSNMP_DS_SNMP_VERSION_3
+ NETSNMP_DS_LIB_SECNAME
+ NETSNMP_DS_LIB_CONTEXT
+ NETSNMP_DS_LIB_PASSPHRASE
+ NETSNMP_DS_LIB_AUTHPASSPHRASE
+ NETSNMP_DS_LIB_PRIVPASSPHRASE
+ NETSNMP_DS_LIB_OPTIONALCONFIG
+ NETSNMP_DS_LIB_APPTYPE
+ NETSNMP_DS_LIB_COMMUNITY
+ NETSNMP_DS_LIB_PERSISTENT_DIR
+ NETSNMP_DS_LIB_CONFIGURATION_DIR
+ NETSNMP_DS_LIB_SECMODEL
+ NETSNMP_DS_LIB_MIBDIRS
+ NETSNMP_DS_LIB_OIDSUFFIX
+ NETSNMP_DS_LIB_OIDPREFIX
+ NETSNMP_DS_LIB_CLIENT_ADDR
+ NETSNMP_DS_LIB_TEMP_FILE_PATTERN
+ NETSNMP_DS_LIB_AUTHMASTERKEY
+ NETSNMP_DS_LIB_PRIVMASTERKEY
+ NETSNMP_DS_LIB_AUTHLOCALIZEDKEY
+ NETSNMP_DS_LIB_PRIVLOCALIZEDKEY
+ NETSNMP_DS_LIB_APPTYPES
+ NETSNMP_DS_LIB_KSM_KEYTAB
+ NETSNMP_DS_LIB_KSM_SERVICE_NAME
+ NETSNMP_DS_LIB_SBSM_LOCAL_PWD
+
+=head2 Exportable functions
+
+ int netsnmp_ds_get_boolean(int storeid, int which)
+ int netsnmp_ds_get_int(int storeid, int which)
+ char *netsnmp_ds_get_string(int storeid, int which)
+ void *netsnmp_ds_get_void(int storeid, int which)
+ int netsnmp_ds_register_config(unsigned char type, const char *ftype, const char *token,
+ int storeid, int which)
+ int netsnmp_ds_register_premib(unsigned char type, const char *ftype, const char *token,
+ int storeid, int which)
+ int netsnmp_ds_set_boolean(int storeid, int which, int value)
+ int netsnmp_ds_set_int(int storeid, int which, int value)
+ int netsnmp_ds_set_string(int storeid, int which, const char *value)
+ int netsnmp_ds_set_void(int storeid, int which, void *value)
+ void netsnmp_ds_shutdown(void)
+ int netsnmp_ds_toggle_boolean(int storeid, int which)
+
+=head1 AUTHOR
+
+Wes Hardaker, hardaker@users.sourceforge.net
+
+=head1 SEE ALSO
+
+perl(1), default_store(3).
+
+=cut
diff --git a/perl/default_store/default_store.xs b/perl/default_store/default_store.xs
new file mode 100644
index 0000000..ca252fb
--- /dev/null
+++ b/perl/default_store/default_store.xs
@@ -0,0 +1,1411 @@
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x501
+#endif
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/library/default_store.h>
+
+
+/* autogenerated by "gen" from const-c.inc */
+
+#define PERL_constant_NOTFOUND 1
+#define PERL_constant_NOTDEF 2
+#define PERL_constant_ISIV 3
+#define PERL_constant_ISNO 4
+#define PERL_constant_ISNV 5
+#define PERL_constant_ISPV 6
+#define PERL_constant_ISPVN 7
+#define PERL_constant_ISSV 8
+#define PERL_constant_ISUNDEF 9
+#define PERL_constant_ISUV 10
+#define PERL_constant_ISYES 11
+
+#ifndef NVTYPE
+typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
+#endif
+#ifndef aTHX_
+#define aTHX_ /* 5.6 or later define this for threading support. */
+#endif
+#ifndef pTHX_
+#define pTHX_ /* 5.6 or later define this for threading support. */
+#endif
+
+static int
+constant_22 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_APPTYPE NETSNMP_DS_LIB_CONTEXT NETSNMP_DS_LIB_MIBDIRS
+ NETSNMP_DS_LIB_SECNAME */
+ /* Offset 16 gives the best switch position. */
+ switch (name[16]) {
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_SECNAME", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SECNAME
+ *iv_return = NETSNMP_DS_LIB_SECNAME;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIBDIRS", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_MIBDIRS
+ *iv_return = NETSNMP_DS_LIB_MIBDIRS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'O':
+ if (memEQ(name, "NETSNMP_DS_LIB_CONTEXT", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_CONTEXT
+ *iv_return = NETSNMP_DS_LIB_CONTEXT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_LIB_APPTYPE", 22)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_APPTYPE
+ *iv_return = NETSNMP_DS_LIB_APPTYPE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_23 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_APPTYPES NETSNMP_DS_LIB_SECLEVEL NETSNMP_DS_LIB_SECMODEL */
+ /* Offset 18 gives the best switch position. */
+ switch (name[18]) {
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_SECLEVEL", 23)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SECLEVEL
+ *iv_return = NETSNMP_DS_LIB_SECLEVEL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_LIB_SECMODEL", 23)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SECMODEL
+ *iv_return = NETSNMP_DS_LIB_SECMODEL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'T':
+ if (memEQ(name, "NETSNMP_DS_LIB_APPTYPES", 23)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_APPTYPES
+ *iv_return = NETSNMP_DS_LIB_APPTYPES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_24 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_16BIT_IDS NETSNMP_DS_LIB_COMMUNITY NETSNMP_DS_LIB_OIDPREFIX
+ NETSNMP_DS_LIB_OIDSUFFIX */
+ /* Offset 18 gives the best switch position. */
+ switch (name[18]) {
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_16BIT_IDS", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_16BIT_IDS
+ *iv_return = NETSNMP_DS_LIB_16BIT_IDS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_LIB_COMMUNITY", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_COMMUNITY
+ *iv_return = NETSNMP_DS_LIB_COMMUNITY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_LIB_OIDPREFIX", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_OIDPREFIX
+ *iv_return = NETSNMP_DS_LIB_OIDPREFIX;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_LIB_OIDSUFFIX", 24)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_OIDSUFFIX
+ *iv_return = NETSNMP_DS_LIB_OIDSUFFIX;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_25 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_APPLICATION_ID NETSNMP_DS_LIB_KSM_KEYTAB
+ NETSNMP_DS_LIB_MIB_ERRORS NETSNMP_DS_LIB_PASSPHRASE
+ NETSNMP_DS_SNMP_VERSION_1 NETSNMP_DS_SNMP_VERSION_3 */
+ /* Offset 24 gives the best switch position. */
+ switch (name[24]) {
+ case '1':
+ if (memEQ(name, "NETSNMP_DS_SNMP_VERSION_", 24)) {
+ /* 1 */
+#ifdef NETSNMP_DS_SNMP_VERSION_1
+ *iv_return = NETSNMP_DS_SNMP_VERSION_1;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case '3':
+ if (memEQ(name, "NETSNMP_DS_SNMP_VERSION_", 24)) {
+ /* 3 */
+#ifdef NETSNMP_DS_SNMP_VERSION_3
+ *iv_return = NETSNMP_DS_SNMP_VERSION_3;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'B':
+ if (memEQ(name, "NETSNMP_DS_LIB_KSM_KEYTA", 24)) {
+ /* B */
+#ifdef NETSNMP_DS_LIB_KSM_KEYTAB
+ *iv_return = NETSNMP_DS_LIB_KSM_KEYTAB;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'D':
+ if (memEQ(name, "NETSNMP_DS_APPLICATION_I", 24)) {
+ /* D */
+#ifdef NETSNMP_DS_APPLICATION_ID
+ *iv_return = NETSNMP_DS_APPLICATION_ID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_PASSPHRAS", 24)) {
+ /* E */
+#ifdef NETSNMP_DS_LIB_PASSPHRASE
+ *iv_return = NETSNMP_DS_LIB_PASSPHRASE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIB_ERROR", 24)) {
+ /* S */
+#ifdef NETSNMP_DS_LIB_MIB_ERRORS
+ *iv_return = NETSNMP_DS_LIB_MIB_ERRORS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_26 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_CLIENT_ADDR NETSNMP_DS_LIB_DUMP_PACKET
+ NETSNMP_DS_LIB_MIB_REPLACE NETSNMP_DS_LIB_QUICK_PRINT
+ NETSNMP_DS_LIB_SNMPVERSION NETSNMP_DS_SNMP_VERSION_2c */
+ /* Offset 22 gives the best switch position. */
+ switch (name[22]) {
+ case 'A':
+ if (memEQ(name, "NETSNMP_DS_LIB_CLIENT_ADDR", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_CLIENT_ADDR
+ *iv_return = NETSNMP_DS_LIB_CLIENT_ADDR;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_LIB_DUMP_PACKET", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DUMP_PACKET
+ *iv_return = NETSNMP_DS_LIB_DUMP_PACKET;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIB_REPLACE", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_MIB_REPLACE
+ *iv_return = NETSNMP_DS_LIB_MIB_REPLACE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_SNMP_VERSION_2c", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_SNMP_VERSION_2c
+ *iv_return = NETSNMP_DS_SNMP_VERSION_2c;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'R':
+ if (memEQ(name, "NETSNMP_DS_LIB_QUICK_PRINT", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_QUICK_PRINT
+ *iv_return = NETSNMP_DS_LIB_QUICK_PRINT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_LIB_SNMPVERSION", 26)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SNMPVERSION
+ *iv_return = NETSNMP_DS_LIB_SNMPVERSION;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_27 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_DEFAULT_PORT NETSNMP_DS_LIB_MIB_WARNINGS
+ NETSNMP_DS_LIB_QUICKE_PRINT NETSNMP_DS_LIB_REGEX_ACCESS */
+ /* Offset 17 gives the best switch position. */
+ switch (name[17]) {
+ case 'B':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIB_WARNINGS", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_MIB_WARNINGS
+ *iv_return = NETSNMP_DS_LIB_MIB_WARNINGS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'F':
+ if (memEQ(name, "NETSNMP_DS_LIB_DEFAULT_PORT", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DEFAULT_PORT
+ *iv_return = NETSNMP_DS_LIB_DEFAULT_PORT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_LIB_REGEX_ACCESS", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_REGEX_ACCESS
+ *iv_return = NETSNMP_DS_LIB_REGEX_ACCESS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_QUICKE_PRINT", 27)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_QUICKE_PRINT
+ *iv_return = NETSNMP_DS_LIB_QUICKE_PRINT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_28 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_AUTHMASTERKEY NETSNMP_DS_LIB_CLIENTRECVBUF
+ NETSNMP_DS_LIB_CLIENTSENDBUF NETSNMP_DS_LIB_ESCAPE_QUOTES
+ NETSNMP_DS_LIB_LOG_TIMESTAMP NETSNMP_DS_LIB_PRIVMASTERKEY
+ NETSNMP_DS_LIB_RANDOM_ACCESS NETSNMP_DS_LIB_SERVERRECVBUF
+ NETSNMP_DS_LIB_SERVERSENDBUF */
+ /* Offset 15 gives the best switch position. */
+ switch (name[15]) {
+ case 'A':
+ if (memEQ(name, "NETSNMP_DS_LIB_AUTHMASTERKEY", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_AUTHMASTERKEY
+ *iv_return = NETSNMP_DS_LIB_AUTHMASTERKEY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_LIB_CLIENTRECVBUF", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_CLIENTRECVBUF
+ *iv_return = NETSNMP_DS_LIB_CLIENTRECVBUF;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ if (memEQ(name, "NETSNMP_DS_LIB_CLIENTSENDBUF", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_CLIENTSENDBUF
+ *iv_return = NETSNMP_DS_LIB_CLIENTSENDBUF;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_ESCAPE_QUOTES", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_ESCAPE_QUOTES
+ *iv_return = NETSNMP_DS_LIB_ESCAPE_QUOTES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_LOG_TIMESTAMP", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_LOG_TIMESTAMP
+ *iv_return = NETSNMP_DS_LIB_LOG_TIMESTAMP;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRIVMASTERKEY", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRIVMASTERKEY
+ *iv_return = NETSNMP_DS_LIB_PRIVMASTERKEY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'R':
+ if (memEQ(name, "NETSNMP_DS_LIB_RANDOM_ACCESS", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_RANDOM_ACCESS
+ *iv_return = NETSNMP_DS_LIB_RANDOM_ACCESS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_LIB_SERVERRECVBUF", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SERVERRECVBUF
+ *iv_return = NETSNMP_DS_LIB_SERVERRECVBUF;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ if (memEQ(name, "NETSNMP_DS_LIB_SERVERSENDBUF", 28)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SERVERSENDBUF
+ *iv_return = NETSNMP_DS_LIB_SERVERSENDBUF;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_29 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_AUTHPASSPHRASE NETSNMP_DS_LIB_EXTENDED_INDEX
+ NETSNMP_DS_LIB_OPTIONALCONFIG NETSNMP_DS_LIB_PERSISTENT_DIR
+ NETSNMP_DS_LIB_PRINT_FULL_OID NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ NETSNMP_DS_LIB_PRIVPASSPHRASE NETSNMP_DS_LIB_REVERSE_ENCODE
+ NETSNMP_DS_LIB_SBSM_LOCAL_PWD */
+ /* Offset 23 gives the best switch position. */
+ switch (name[23]) {
+ case 'A':
+ if (memEQ(name, "NETSNMP_DS_LIB_SBSM_LOCAL_PWD", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SBSM_LOCAL_PWD
+ *iv_return = NETSNMP_DS_LIB_SBSM_LOCAL_PWD;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_LIB_OPTIONALCONFIG", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_OPTIONALCONFIG
+ *iv_return = NETSNMP_DS_LIB_OPTIONALCONFIG;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_REVERSE_ENCODE", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_REVERSE_ENCODE
+ *iv_return = NETSNMP_DS_LIB_REVERSE_ENCODE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_FULL_OID", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRINT_FULL_OID
+ *iv_return = NETSNMP_DS_LIB_PRINT_FULL_OID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_LIB_PERSISTENT_DIR", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PERSISTENT_DIR
+ *iv_return = NETSNMP_DS_LIB_PERSISTENT_DIR;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_LIB_AUTHPASSPHRASE", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_AUTHPASSPHRASE
+ *iv_return = NETSNMP_DS_LIB_AUTHPASSPHRASE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ if (memEQ(name, "NETSNMP_DS_LIB_PRIVPASSPHRASE", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRIVPASSPHRASE
+ *iv_return = NETSNMP_DS_LIB_PRIVPASSPHRASE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'X':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_HEX_TEXT", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ *iv_return = NETSNMP_DS_LIB_PRINT_HEX_TEXT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case '_':
+ if (memEQ(name, "NETSNMP_DS_LIB_EXTENDED_INDEX", 29)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_EXTENDED_INDEX
+ *iv_return = NETSNMP_DS_LIB_EXTENDED_INDEX;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_30 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_APPEND_LOGFILES NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ NETSNMP_DS_LIB_NO_DISPLAY_HINT NETSNMP_DS_LIB_SAVE_MIB_DESCRS */
+ /* Offset 27 gives the best switch position. */
+ switch (name[27]) {
+ case 'B':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIB_PARSE_LABEL", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ *iv_return = NETSNMP_DS_LIB_MIB_PARSE_LABEL;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_LIB_SAVE_MIB_DESCRS", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_SAVE_MIB_DESCRS
+ *iv_return = NETSNMP_DS_LIB_SAVE_MIB_DESCRS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_NO_DISPLAY_HINT", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_NO_DISPLAY_HINT
+ *iv_return = NETSNMP_DS_LIB_NO_DISPLAY_HINT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_APPEND_LOGFILES", 30)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_APPEND_LOGFILES
+ *iv_return = NETSNMP_DS_LIB_APPEND_LOGFILES;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_31 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_AUTHLOCALIZEDKEY NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ NETSNMP_DS_LIB_DONT_PRINT_UNITS NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ NETSNMP_DS_LIB_KSM_SERVICE_NAME NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ NETSNMP_DS_LIB_PRINT_BARE_VALUE NETSNMP_DS_LIB_PRIVLOCALIZEDKEY */
+ /* Offset 28 gives the best switch position. */
+ switch (name[28]) {
+ case 'A':
+ if (memEQ(name, "NETSNMP_DS_LIB_KSM_SERVICE_NAME", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_KSM_SERVICE_NAME
+ *iv_return = NETSNMP_DS_LIB_KSM_SERVICE_NAME;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_MIB_COMMENT_TERM", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ *iv_return = NETSNMP_DS_LIB_MIB_COMMENT_TERM;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'F':
+ if (memEQ(name, "NETSNMP_DS_LIB_HAVE_READ_CONFIG", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ *iv_return = NETSNMP_DS_LIB_HAVE_READ_CONFIG;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_DONT_PRINT_UNITS", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DONT_PRINT_UNITS
+ *iv_return = NETSNMP_DS_LIB_DONT_PRINT_UNITS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'K':
+ if (memEQ(name, "NETSNMP_DS_LIB_AUTHLOCALIZEDKEY", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_AUTHLOCALIZEDKEY
+ *iv_return = NETSNMP_DS_LIB_AUTHLOCALIZEDKEY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ if (memEQ(name, "NETSNMP_DS_LIB_PRIVLOCALIZEDKEY", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRIVLOCALIZEDKEY
+ *iv_return = NETSNMP_DS_LIB_PRIVLOCALIZEDKEY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_BARE_VALUE", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRINT_BARE_VALUE
+ *iv_return = NETSNMP_DS_LIB_PRINT_BARE_VALUE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_LIB_DONT_CHECK_RANGE", 31)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ *iv_return = NETSNMP_DS_LIB_DONT_CHECK_RANGE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_32 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT NETSNMP_DS_LIB_CONFIGURATION_DIR
+ NETSNMP_DS_LIB_DONT_READ_CONFIGS NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ NETSNMP_DS_LIB_NO_TOKEN_WARNINGS NETSNMP_DS_LIB_NUMERIC_TIMETICKS
+ NETSNMP_DS_LIB_OID_OUTPUT_FORMAT NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY
+ NETSNMP_DS_LIB_TEMP_FILE_PATTERN */
+ /* Offset 29 gives the best switch position. */
+ switch (name[29]) {
+ case 'C':
+ if (memEQ(name, "NETSNMP_DS_LIB_NUMERIC_TIMETICKS", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_NUMERIC_TIMETICKS
+ *iv_return = NETSNMP_DS_LIB_NUMERIC_TIMETICKS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'D':
+ if (memEQ(name, "NETSNMP_DS_LIB_CONFIGURATION_DIR", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_CONFIGURATION_DIR
+ *iv_return = NETSNMP_DS_LIB_CONFIGURATION_DIR;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_TEMP_FILE_PATTERN", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_TEMP_FILE_PATTERN
+ *iv_return = NETSNMP_DS_LIB_TEMP_FILE_PATTERN;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ *iv_return = NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'I':
+ if (memEQ(name, "NETSNMP_DS_LIB_DONT_READ_CONFIGS", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DONT_READ_CONFIGS
+ *iv_return = NETSNMP_DS_LIB_DONT_READ_CONFIGS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_LIB_OID_OUTPUT_FORMAT", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
+ *iv_return = NETSNMP_DS_LIB_OID_OUTPUT_FORMAT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_LIB_NO_TOKEN_WARNINGS", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_NO_TOKEN_WARNINGS
+ *iv_return = NETSNMP_DS_LIB_NO_TOKEN_WARNINGS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY
+ *iv_return = NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'P':
+ if (memEQ(name, "NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT", 32)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT
+ *iv_return = NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_33 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_ALARM_DONT_USE_SIG NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ NETSNMP_DS_LIB_READ_UCD_STYLE_OID */
+ /* Offset 32 gives the best switch position. */
+ switch (name[32]) {
+ case 'D':
+ if (memEQ(name, "NETSNMP_DS_LIB_READ_UCD_STYLE_OI", 32)) {
+ /* D */
+#ifdef NETSNMP_DS_LIB_READ_UCD_STYLE_OID
+ *iv_return = NETSNMP_DS_LIB_READ_UCD_STYLE_OID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_DONT_PERSIST_STAT", 32)) {
+ /* E */
+#ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ *iv_return = NETSNMP_DS_LIB_DONT_PERSIST_STATE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_LIB_ALARM_DONT_USE_SI", 32)) {
+ /* G */
+#ifdef NETSNMP_DS_LIB_ALARM_DONT_USE_SIG
+ *iv_return = NETSNMP_DS_LIB_ALARM_DONT_USE_SIG;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_NUMERIC_ENU", 32)) {
+ /* M */
+#ifdef NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
+ *iv_return = NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'S':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_NUMERIC_OID", 32)) {
+ /* S */
+#ifdef NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ *iv_return = NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_34 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID */
+ /* Offset 28 gives the best switch position. */
+ switch (name[28]) {
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD", 34)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD
+ *iv_return = NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID", 34)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID
+ *iv_return = NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY", 34)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY
+ *iv_return = NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'N':
+ if (memEQ(name, "NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS", 34)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ *iv_return = NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant_38 (pTHX_ const char *name, IV *iv_return) {
+ /* When generated this function returned values for the list of names given
+ here. However, subsequent manual editing may have added or removed some.
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG */
+ /* Offset 37 gives the best switch position. */
+ switch (name[37]) {
+ case 'D':
+ if (memEQ(name, "NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOA", 37)) {
+ /* D */
+#ifdef NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ *iv_return = NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'E':
+ if (memEQ(name, "NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAV", 37)) {
+ /* E */
+#ifdef NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ *iv_return = NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'G':
+ if (memEQ(name, "NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFI", 37)) {
+ /* G */
+#ifdef NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG
+ *iv_return = NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+static int
+constant (pTHX_ const char *name, STRLEN len, IV *iv_return) {
+ /* Initially switch on the length of the name. */
+ /* When generated this function returned values for the list of names given
+ in this section of perl code. Rather than manually editing these functions
+ to add or remove constants, which would result in this comment and section
+ of code becoming inaccurate, we recommend that you edit this section of
+ code, and use it to regenerate a new set of constant functions which you
+ then use to replace the originals.
+
+ Regenerate these constant functions by feeding this entire source file to
+ perl -x
+
+#!/usr/bin/perl -w
+use ExtUtils::Constant qw (constant_types C_constant XS_constant);
+
+my $types = {map {($_, 1)} qw(IV)};
+my @names = (qw(NETSNMP_DS_APPLICATION_ID NETSNMP_DS_LIBRARY_ID
+ NETSNMP_DS_LIB_16BIT_IDS NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT
+ NETSNMP_DS_LIB_ALARM_DONT_USE_SIG NETSNMP_DS_LIB_APPEND_LOGFILES
+ NETSNMP_DS_LIB_APPTYPE NETSNMP_DS_LIB_APPTYPES
+ NETSNMP_DS_LIB_AUTHLOCALIZEDKEY NETSNMP_DS_LIB_AUTHMASTERKEY
+ NETSNMP_DS_LIB_AUTHPASSPHRASE NETSNMP_DS_LIB_CLIENTRECVBUF
+ NETSNMP_DS_LIB_CLIENTSENDBUF NETSNMP_DS_LIB_CLIENT_ADDR
+ NETSNMP_DS_LIB_COMMUNITY NETSNMP_DS_LIB_CONFIGURATION_DIR
+ NETSNMP_DS_LIB_CONTEXT NETSNMP_DS_LIB_DEFAULT_PORT
+ NETSNMP_DS_LIB_DISABLE_CONFIG_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
+ NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE
+ NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS
+ NETSNMP_DS_LIB_DONT_CHECK_RANGE
+ NETSNMP_DS_LIB_DONT_PERSIST_STATE
+ NETSNMP_DS_LIB_DONT_PRINT_UNITS NETSNMP_DS_LIB_DONT_READ_CONFIGS
+ NETSNMP_DS_LIB_DUMP_PACKET NETSNMP_DS_LIB_ESCAPE_QUOTES
+ NETSNMP_DS_LIB_EXTENDED_INDEX NETSNMP_DS_LIB_HAVE_READ_CONFIG
+ NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG
+ NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH
+ NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY NETSNMP_DS_LIB_KSM_KEYTAB
+ NETSNMP_DS_LIB_KSM_SERVICE_NAME NETSNMP_DS_LIB_LOG_TIMESTAMP
+ NETSNMP_DS_LIB_MIBDIRS NETSNMP_DS_LIB_MIB_COMMENT_TERM
+ NETSNMP_DS_LIB_MIB_ERRORS NETSNMP_DS_LIB_MIB_PARSE_LABEL
+ NETSNMP_DS_LIB_MIB_REPLACE NETSNMP_DS_LIB_MIB_WARNINGS
+ NETSNMP_DS_LIB_NO_DISPLAY_HINT NETSNMP_DS_LIB_NO_TOKEN_WARNINGS
+ NETSNMP_DS_LIB_NUMERIC_TIMETICKS NETSNMP_DS_LIB_OIDPREFIX
+ NETSNMP_DS_LIB_OIDSUFFIX NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_OPTIONALCONFIG NETSNMP_DS_LIB_PASSPHRASE
+ NETSNMP_DS_LIB_PERSISTENT_DIR NETSNMP_DS_LIB_PRINT_BARE_VALUE
+ NETSNMP_DS_LIB_PRINT_FULL_OID NETSNMP_DS_LIB_PRINT_HEX_TEXT
+ NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
+ NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS
+ NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY
+ NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID
+ NETSNMP_DS_LIB_PRIVLOCALIZEDKEY NETSNMP_DS_LIB_PRIVMASTERKEY
+ NETSNMP_DS_LIB_PRIVPASSPHRASE NETSNMP_DS_LIB_QUICKE_PRINT
+ NETSNMP_DS_LIB_QUICK_PRINT NETSNMP_DS_LIB_RANDOM_ACCESS
+ NETSNMP_DS_LIB_READ_UCD_STYLE_OID NETSNMP_DS_LIB_REGEX_ACCESS
+ NETSNMP_DS_LIB_REVERSE_ENCODE NETSNMP_DS_LIB_SAVE_MIB_DESCRS
+ NETSNMP_DS_LIB_SBSM_LOCAL_PWD NETSNMP_DS_LIB_SECLEVEL
+ NETSNMP_DS_LIB_SECMODEL NETSNMP_DS_LIB_SECNAME
+ NETSNMP_DS_LIB_SERVERRECVBUF NETSNMP_DS_LIB_SERVERSENDBUF
+ NETSNMP_DS_LIB_SNMPVERSION NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT
+ NETSNMP_DS_LIB_TEMP_FILE_PATTERN NETSNMP_DS_MAX_IDS
+ NETSNMP_DS_MAX_SUBIDS NETSNMP_DS_SNMP_VERSION_1
+ NETSNMP_DS_SNMP_VERSION_2c NETSNMP_DS_SNMP_VERSION_3
+ NETSNMP_DS_TOKEN_ID));
+
+print constant_types(); # macro defs
+foreach (C_constant ("NetSNMP::default_store", 'constant', 'IV', $types, undef, 3, @names) ) {
+ print $_, "\n"; # C constant subs
+}
+print "#### XS Section:\n";
+print XS_constant ("NetSNMP::default_store", $types);
+__END__
+ */
+
+ switch (len) {
+ case 18:
+ if (memEQ(name, "NETSNMP_DS_MAX_IDS", 18)) {
+#ifdef NETSNMP_DS_MAX_IDS
+ *iv_return = NETSNMP_DS_MAX_IDS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 19:
+ if (memEQ(name, "NETSNMP_DS_TOKEN_ID", 19)) {
+#ifdef NETSNMP_DS_TOKEN_ID
+ *iv_return = NETSNMP_DS_TOKEN_ID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 21:
+ /* Names all of length 21. */
+ /* NETSNMP_DS_LIBRARY_ID NETSNMP_DS_MAX_SUBIDS */
+ /* Offset 11 gives the best switch position. */
+ switch (name[11]) {
+ case 'L':
+ if (memEQ(name, "NETSNMP_DS_LIBRARY_ID", 21)) {
+ /* ^ */
+#ifdef NETSNMP_DS_LIBRARY_ID
+ *iv_return = NETSNMP_DS_LIBRARY_ID;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 'M':
+ if (memEQ(name, "NETSNMP_DS_MAX_SUBIDS", 21)) {
+ /* ^ */
+#ifdef NETSNMP_DS_MAX_SUBIDS
+ *iv_return = NETSNMP_DS_MAX_SUBIDS;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ }
+ break;
+ case 22:
+ return constant_22 (aTHX_ name, iv_return);
+ break;
+ case 23:
+ return constant_23 (aTHX_ name, iv_return);
+ break;
+ case 24:
+ return constant_24 (aTHX_ name, iv_return);
+ break;
+ case 25:
+ return constant_25 (aTHX_ name, iv_return);
+ break;
+ case 26:
+ return constant_26 (aTHX_ name, iv_return);
+ break;
+ case 27:
+ return constant_27 (aTHX_ name, iv_return);
+ break;
+ case 28:
+ return constant_28 (aTHX_ name, iv_return);
+ break;
+ case 29:
+ return constant_29 (aTHX_ name, iv_return);
+ break;
+ case 30:
+ return constant_30 (aTHX_ name, iv_return);
+ break;
+ case 31:
+ return constant_31 (aTHX_ name, iv_return);
+ break;
+ case 32:
+ return constant_32 (aTHX_ name, iv_return);
+ break;
+ case 33:
+ return constant_33 (aTHX_ name, iv_return);
+ break;
+ case 34:
+ return constant_34 (aTHX_ name, iv_return);
+ break;
+ case 35:
+ if (memEQ(name, "NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT", 35)) {
+#ifdef NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT
+ *iv_return = NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT;
+ return PERL_constant_ISIV;
+#else
+ return PERL_constant_NOTDEF;
+#endif
+ }
+ break;
+ case 38:
+ return constant_38 (aTHX_ name, iv_return);
+ break;
+ }
+ return PERL_constant_NOTFOUND;
+}
+
+
+
+/* autogenerated by "gen" from const-xs.inc */
+
+MODULE = NetSNMP::default_store PACKAGE = NetSNMP::default_store
+
+void
+constant(sv)
+ PREINIT:
+#ifdef dXSTARG
+ dXSTARG; /* Faster if we have it. */
+#else
+ dTARGET;
+#endif
+ STRLEN len;
+ int type;
+ IV iv = 0;
+ /* NV nv; Uncomment this if you need to return NVs */
+ /* const char *pv; Uncomment this if you need to return PVs */
+ INPUT:
+ SV * sv;
+ const char * s = SvPV(sv, len);
+ PPCODE:
+ /* Change this to constant(aTHX_ s, len, &iv, &nv);
+ if you need to return both NVs and IVs */
+ type = constant(aTHX_ s, len, &iv);
+ /* Return 1 or 2 items. First is error message, or undef if no error.
+ Second, if present, is found value */
+ switch (type) {
+ case PERL_constant_NOTFOUND:
+ sv = sv_2mortal(newSVpvf("%s is not a valid NetSNMP::default_store macro", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_NOTDEF:
+ sv = sv_2mortal(newSVpvf(
+ "Your vendor has not defined NetSNMP::default_store macro %s, used", s));
+ PUSHs(sv);
+ break;
+ case PERL_constant_ISIV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHi(iv);
+ break;
+ /* Uncomment this if you need to return NOs
+ case PERL_constant_ISNO:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_no);
+ break; */
+ /* Uncomment this if you need to return NVs
+ case PERL_constant_ISNV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHn(nv);
+ break; */
+ /* Uncomment this if you need to return PVs
+ case PERL_constant_ISPV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, strlen(pv));
+ break; */
+ /* Uncomment this if you need to return PVNs
+ case PERL_constant_ISPVN:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHp(pv, iv);
+ break; */
+ /* Uncomment this if you need to return SVs
+ case PERL_constant_ISSV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(sv);
+ break; */
+ /* Uncomment this if you need to return UNDEFs
+ case PERL_constant_ISUNDEF:
+ break; */
+ /* Uncomment this if you need to return UVs
+ case PERL_constant_ISUV:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHu((UV)iv);
+ break; */
+ /* Uncomment this if you need to return YESs
+ case PERL_constant_ISYES:
+ EXTEND(SP, 1);
+ PUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_yes);
+ break; */
+ default:
+ sv = sv_2mortal(newSVpvf(
+ "Unexpected return type %d while processing NetSNMP::default_store macro %s, used",
+ type, s));
+ PUSHs(sv);
+ }
+
+
+
+int
+netsnmp_ds_get_boolean(storeid, which)
+ int storeid
+ int which
+
+int
+netsnmp_ds_get_int(storeid, which)
+ int storeid
+ int which
+
+char *
+netsnmp_ds_get_string(storeid, which)
+ int storeid
+ int which
+
+void *
+netsnmp_ds_get_void(storeid, which)
+ int storeid
+ int which
+
+int
+netsnmp_ds_register_config(type, ftype, token, storeid, which)
+ unsigned char type
+ const char * ftype
+ const char * token
+ int storeid
+ int which
+
+int
+netsnmp_ds_register_premib(type, ftype, token, storeid, which)
+ unsigned char type
+ const char * ftype
+ const char * token
+ int storeid
+ int which
+
+int
+netsnmp_ds_set_boolean(storeid, which, value)
+ int storeid
+ int which
+ int value
+
+int
+netsnmp_ds_set_int(storeid, which, value)
+ int storeid
+ int which
+ int value
+
+int
+netsnmp_ds_set_string(storeid, which, value)
+ int storeid
+ int which
+ const char * value
+
+int
+netsnmp_ds_set_void(storeid, which, value)
+ int storeid
+ int which
+ void * value
+
+void
+netsnmp_ds_shutdown()
+
+int
+netsnmp_ds_toggle_boolean(storeid, which)
+ int storeid
+ int which
diff --git a/perl/default_store/gen b/perl/default_store/gen
new file mode 100755
index 0000000..7691296
--- /dev/null
+++ b/perl/default_store/gen
@@ -0,0 +1,131 @@
+#!/usr/bin/perl
+
+system("grep 'define NETSNMP_DS_' ../../include/net-snmp/library/default_store.h > default_store.h");
+#gcc -E ../../include/net-snmp/library/default_store.h | grep -v default_store.h >> default_store.h
+system("h2xs -b 5.5.0 -n NetSNMP::default_store -O default_store.h");
+
+open(ORIG,"default_store.xs");
+open(NEW1,"NetSNMP-default_store/fallback/const-c.inc");
+open(NEW2,"NetSNMP-default_store/fallback/const-xs.inc");
+open(OUT,">default_store_new.xs");
+
+# get up to the include from the original file
+while(<ORIG>) {
+ print OUT;
+ last if (/include <net-snmp\/library\/default_store.h/);
+}
+
+# include the entire new file
+print OUT "\n\n/* autogenerated by \"gen\" from const-c.inc */\n\n";
+print OUT <NEW1>;
+print OUT "\n\n/* autogenerated by \"gen\" from const-xs.inc */\n\n";
+print OUT "MODULE = NetSNMP::default_store PACKAGE = NetSNMP::default_store\n\n";
+
+print OUT <NEW2>;
+
+#print OUT "\n\n/* autogenerated by \"gen\" from tail of old .xs file */\n\n";
+print OUT "\n\n\n";
+
+# skip past the constant portion of the old file
+while (<ORIG>) {
+ last if (/netsnmp_ds_get_bool/);
+ $last = $_;
+}
+
+# We need the last two lines
+print OUT $last;
+print OUT $_;
+
+# and the rest
+print OUT <ORIG>;
+
+close(OUT);
+
+#
+# generate test
+#
+open(H,"default_store.h");
+open(ORIG,"test.pl");
+open(OUT,">test.pl.new");
+
+while(<ORIG>) {
+ print OUT;
+ last if (/\%tests =/);
+}
+
+while(<H>) {
+ if (/define\s+(\w+)\s+(\d+)/) {
+ printf OUT (" %-40s => %d,\n", "\"$1\"", $2);
+ $tokenlist .= " $1\n";
+ }
+}
+
+while(<ORIG>) {
+ last if (/\);/);
+}
+print OUT;
+print OUT <ORIG>;
+close(OUT);
+
+#
+# modify the perl module itself
+#
+open(H,"default_store.h");
+open(ORIG,"default_store.pm");
+open(OUT,">default_store_new.pm");
+
+# first list
+while(<ORIG>) {
+ print OUT;
+ last if (/\%EXPORT_TAGS =/);
+}
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/netsnmp_ds_get_boolean/);
+}
+print OUT;
+
+# second list
+while(<ORIG>) {
+ print OUT;
+ last if (/\@EXPORT =/);
+}
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/\);/);
+}
+print OUT;
+
+# last section
+while(<ORIG>) {
+ print OUT;
+ last if (/head2 Exportable constants/);
+}
+print OUT "\n";
+print OUT $tokenlist;
+while(<ORIG>) {
+ last if (/head2 Exportable functions/);
+}
+print OUT "\n";
+print OUT;
+
+# tail end
+print OUT <ORIG>;
+close(OUT);
+
+#
+# install new files
+#
+print "updated test.pl\n";
+rename("test.pl.new","test.pl");
+rename("default_store_new.pm", "default_store.pm");
+print "updated default_store.pm\n";
+rename("default_store_new.xs", "default_store.xs");
+print "updated default_store.xs\n";
+
+#
+# remove the temp files.
+#
+system("rm -rf NetSNMP-default_store");
+unlink("default_store.h");
+
diff --git a/perl/default_store/netsnmp-feature-definitions.h b/perl/default_store/netsnmp-feature-definitions.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/perl/default_store/netsnmp-feature-definitions.h
diff --git a/perl/default_store/test.pl b/perl/default_store/test.pl
new file mode 100644
index 0000000..b429c6b
--- /dev/null
+++ b/perl/default_store/test.pl
@@ -0,0 +1,124 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN { $| = 1;
+
+ %tests = (
+ "NETSNMP_DS_MAX_IDS" => 3,
+ "NETSNMP_DS_MAX_SUBIDS" => 48,
+ "NETSNMP_DS_LIBRARY_ID" => 0,
+ "NETSNMP_DS_APPLICATION_ID" => 1,
+ "NETSNMP_DS_TOKEN_ID" => 2,
+ "NETSNMP_DS_LIB_MIB_ERRORS" => 0,
+ "NETSNMP_DS_LIB_SAVE_MIB_DESCRS" => 1,
+ "NETSNMP_DS_LIB_MIB_COMMENT_TERM" => 2,
+ "NETSNMP_DS_LIB_MIB_PARSE_LABEL" => 3,
+ "NETSNMP_DS_LIB_DUMP_PACKET" => 4,
+ "NETSNMP_DS_LIB_LOG_TIMESTAMP" => 5,
+ "NETSNMP_DS_LIB_DONT_READ_CONFIGS" => 6,
+ "NETSNMP_DS_LIB_MIB_REPLACE" => 7,
+ "NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM" => 8,
+ "NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS" => 9,
+ "NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS" => 10,
+ "NETSNMP_DS_LIB_ALARM_DONT_USE_SIG" => 11,
+ "NETSNMP_DS_LIB_PRINT_FULL_OID" => 12,
+ "NETSNMP_DS_LIB_QUICK_PRINT" => 13,
+ "NETSNMP_DS_LIB_RANDOM_ACCESS" => 14,
+ "NETSNMP_DS_LIB_REGEX_ACCESS" => 15,
+ "NETSNMP_DS_LIB_DONT_CHECK_RANGE" => 16,
+ "NETSNMP_DS_LIB_NO_TOKEN_WARNINGS" => 17,
+ "NETSNMP_DS_LIB_NUMERIC_TIMETICKS" => 18,
+ "NETSNMP_DS_LIB_ESCAPE_QUOTES" => 19,
+ "NETSNMP_DS_LIB_REVERSE_ENCODE" => 20,
+ "NETSNMP_DS_LIB_PRINT_BARE_VALUE" => 21,
+ "NETSNMP_DS_LIB_EXTENDED_INDEX" => 22,
+ "NETSNMP_DS_LIB_PRINT_HEX_TEXT" => 23,
+ "NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID" => 24,
+ "NETSNMP_DS_LIB_READ_UCD_STYLE_OID" => 25,
+ "NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG" => 26,
+ "NETSNMP_DS_LIB_HAVE_READ_CONFIG" => 27,
+ "NETSNMP_DS_LIB_QUICKE_PRINT" => 28,
+ "NETSNMP_DS_LIB_DONT_PRINT_UNITS" => 29,
+ "NETSNMP_DS_LIB_NO_DISPLAY_HINT" => 30,
+ "NETSNMP_DS_LIB_16BIT_IDS" => 31,
+ "NETSNMP_DS_LIB_DONT_PERSIST_STATE" => 32,
+ "NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT" => 33,
+ "NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY" => 34,
+ "NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD" => 35,
+ "NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE" => 36,
+ "NETSNMP_DS_LIB_APPEND_LOGFILES" => 37,
+ "NETSNMP_DS_LIB_MIB_WARNINGS" => 0,
+ "NETSNMP_DS_LIB_SECLEVEL" => 1,
+ "NETSNMP_DS_LIB_SNMPVERSION" => 2,
+ "NETSNMP_DS_LIB_DEFAULT_PORT" => 3,
+ "NETSNMP_DS_LIB_OID_OUTPUT_FORMAT" => 4,
+ "NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT" => 5,
+ "NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH" => 6,
+ "NETSNMP_DS_LIB_SERVERSENDBUF" => 7,
+ "NETSNMP_DS_LIB_SERVERRECVBUF" => 8,
+ "NETSNMP_DS_LIB_CLIENTSENDBUF" => 9,
+ "NETSNMP_DS_LIB_CLIENTRECVBUF" => 10,
+ "NETSNMP_DS_SNMP_VERSION_1" => 128,
+ "NETSNMP_DS_SNMP_VERSION_2c" => 1,
+ "NETSNMP_DS_SNMP_VERSION_3" => 3,
+ "NETSNMP_DS_LIB_SECNAME" => 0,
+ "NETSNMP_DS_LIB_CONTEXT" => 1,
+ "NETSNMP_DS_LIB_PASSPHRASE" => 2,
+ "NETSNMP_DS_LIB_AUTHPASSPHRASE" => 3,
+ "NETSNMP_DS_LIB_PRIVPASSPHRASE" => 4,
+ "NETSNMP_DS_LIB_OPTIONALCONFIG" => 5,
+ "NETSNMP_DS_LIB_APPTYPE" => 6,
+ "NETSNMP_DS_LIB_COMMUNITY" => 7,
+ "NETSNMP_DS_LIB_PERSISTENT_DIR" => 8,
+ "NETSNMP_DS_LIB_CONFIGURATION_DIR" => 9,
+ "NETSNMP_DS_LIB_SECMODEL" => 10,
+ "NETSNMP_DS_LIB_MIBDIRS" => 11,
+ "NETSNMP_DS_LIB_OIDSUFFIX" => 12,
+ "NETSNMP_DS_LIB_OIDPREFIX" => 13,
+ "NETSNMP_DS_LIB_CLIENT_ADDR" => 14,
+ "NETSNMP_DS_LIB_TEMP_FILE_PATTERN" => 15,
+ "NETSNMP_DS_LIB_AUTHMASTERKEY" => 16,
+ "NETSNMP_DS_LIB_PRIVMASTERKEY" => 17,
+ "NETSNMP_DS_LIB_AUTHLOCALIZEDKEY" => 18,
+ "NETSNMP_DS_LIB_PRIVLOCALIZEDKEY" => 19,
+ "NETSNMP_DS_LIB_APPTYPES" => 20,
+ "NETSNMP_DS_LIB_KSM_KEYTAB" => 21,
+ "NETSNMP_DS_LIB_KSM_SERVICE_NAME" => 22,
+ );
+
+ print "1.." . (scalar(keys(%tests)) + 10) . "\n";
+ }
+END {print "not ok 1\n" unless $loaded;}
+use NetSNMP::default_store (':all');
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+print ((netsnmp_ds_set_string(1, 1, "hi there") == 0) ? "ok 2\n" : "not ok 2\n");
+print ((netsnmp_ds_get_string(1, 1) eq "hi there") ? "ok 3\n" : "not ok 3\n");
+print ((netsnmp_ds_set_int(1, 1, 42) == 0) ? "ok 4\n" : "not ok 4\n");
+print ((netsnmp_ds_get_int(1, 1) == 42) ? "ok 5\n" : "not ok 5\n");
+print ((netsnmp_ds_get_int(1, 2) == 0) ? "ok 6\n" : "not ok 6\n");
+print ((NETSNMP_DS_LIB_REGEX_ACCESS == 15) ? "ok 7\n" : "not ok 7\n");
+print ((netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 1) == 42) ? "ok 8\n" : "not ok 8\n");
+print ((netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT, 9161) == 0) ? "ok 9\n" : "not ok 9\n");
+print ((netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT) == 9161) ? "ok 10\n" : "not ok 10\n");
+
+$c = 10;
+foreach my $i (keys(%tests)) {
+ my $str = "NetSNMP::default_store::$i";
+ my $val = eval $str;
+# print "$i -> $val -> $tests{$i}\n";
+ $c++;
+ print (($val eq $tests{$i})?"ok $c\n" : "not ok $c\n# error: name=$i value_expected=$tests{$i} value_got=$val \n");
+}
diff --git a/perl/default_store/typemap b/perl/default_store/typemap
new file mode 100644
index 0000000..0422417
--- /dev/null
+++ b/perl/default_store/typemap
@@ -0,0 +1 @@
+const char * T_PV
diff --git a/perl/make-perl-makefiles b/perl/make-perl-makefiles
new file mode 100644
index 0000000..8a96487
--- /dev/null
+++ b/perl/make-perl-makefiles
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+
+open(I, "Makefile.subs.pl");
+@stuff = <I>;
+
+foreach my $i (@ARGV) {
+ print "updating $i\n";
+ open(I, $i);
+ open(O,">$i.new");
+ while(<I>) {
+ # start replacement here
+ last if /common subroutines -- DO NOT EDIT/;
+ print O;
+ }
+ print O "# common subroutines -- DO NOT EDIT.\n";
+ print O "# They are imported from the Makefile.subs.pl file\n";
+ print O @stuff;
+ close(I);
+ close(O);
+ rename($i,"$i.bak");
+ rename("$i.new", "$i");
+}
diff --git a/perl/manager/INSTALL b/perl/manager/INSTALL
new file mode 100644
index 0000000..27d7436
--- /dev/null
+++ b/perl/manager/INSTALL
@@ -0,0 +1,198 @@
+REQUIREMENTS
+
+ A knowledgeable user. This system is *not* entirely user friendly
+ yet. You have been warned. Use at your own risk. yada yada yada.
+
+ Get and install:
+
+ the mysql (http://www.mysql.com) database
+ it may work with other databases, but I haven't tried.
+
+ Apache (http://www.apache.org)
+
+ The following perl modules (http://www.cpan.org):
+ mod_perl
+ SNMP (from the net-snmp source tree: SRCTREE/perl/SNMP)
+ CGI
+ DBI
+ DBD::mSQL
+ GD::Graph
+
+ You may need more modules depending on your perl version, so sorry
+ in advance if I missed some.
+
+ Building and setting up mysql (a summary of what is needed. See the
+ mysql documentation for further details):
+ ./configure
+ make
+ make install
+ scripts/mysql_install_db
+
+ start it by running 'safe_mysqld'.
+ To run the sql commands listed in the following text, run
+ 'mysql'.
+
+SQL REQUIREMENTS
+
+ The scripts used by this project automatically create, edit, delete,
+ insert, update, etc everything necessary. Because of this, you'll
+ need to set up a SQL user with the ability to modify the heck out of
+ a database called "snmp" on your mysql server. We'll call this user
+ SQLUSER below, and its password SQLPASSWORD. Replace these with
+ your appropriate information anytime you see them listed below.
+
+INSTALLING THE PERL MODULES
+
+ perl Makefile.PL
+ make
+ make install
+
+ Copy the red.gif, and green.gif graphics files to your apache
+ HTML-ROOT/graphics/.
+
+SETTING UP APACHE
+
+ (assumes you have mod_perl installed properly from above)
+
+ Idealy, it should be put behind a user/password database in your web
+ server (something that sets the REMOTE_USER environmental for CGI
+ scripts). This will greatly enhance its operation so that different
+ users can be users of different groups of hosts, etc... If this is
+ not done, everyone will use the user name "guest".
+
+ At the bottom of your httpd.conf file or in an apporpriate
+ VirtualHost directive put the following lines, appropriately
+ configuring the sql username, etc. I strongly recommend turning on
+ SSL support for this as well.:
+
+ PerlModule netsnmp::manager
+ <Location /manage>
+ # put apache protection stuff here, like a password database etc!!!
+ SetHandler perl-script
+ PerlHandler ucdsnmp::manager
+ PerlSetVar hostname SQLHOST
+ PerlSetVar dbname snmp
+ PerlSetVar user SQLUSER
+ PerlSetVar pass SQLPASSWORD
+
+ # turn on password protection. see apache htpasswd documentation.
+ # comment these out for unauthenticated access (generally a bad idea)
+ AuthType Basic
+ AuthName "SNMP manager access"
+ AuthUserFile /etc/httpd/conf/manager-passwd
+ require valid-user
+
+ </Location>
+
+ Restart apache after you've done the above.
+
+SETTING UP THE MYSQL UCD-SNMP DATABASES
+
+ Use the following perl script to set up the mysql database tables
+ required:
+
+ ./setupdb -u SQLUSER -p SQLPASSWORD -h SQLHOST
+
+ To display what this will do before you run it:
+
+ ./setupdb -v -n
+
+SETTING UP USERS OF THE SYSTEM
+
+ Now you need to add yourself as a user. You'll want to use a
+ username that you configured for your apache password file (or
+ whatever), or the user "guest" if you didn't configure apache for
+ authenticated access. The -a in this case grants "administrative"
+ rights to the group of hosts, and thus allows the user to add new
+ hosts to the group, delete hosts, etc. Non-administrative users are
+ mostly "read-only" type users.
+
+ The interface groups hosts together in "groups", and you put users
+ in these groups to assign responsiblity for them. Groups are
+ created when a user gets assigned to one, so just pick a groupname
+ for now and use it below. Maybe later you can add yourself to a new
+ group using a similar command, and the web interface will change to
+ reflect that you are now in more than one group. Use the same group
+ name for multiple users that all belong to a single "group".
+
+ If you add an email address to the argument list the system will
+ mail that user every time it finds a problem or finds a problem that
+ has been fixed.
+
+ *** DO NOT PICK A GROUP WITH THE NAME "default" ***
+
+ ./setupuser -u SQLUSER -p SQLPASSWORD -h SQLHOST -a GROUPNAME USERNAME [EMAILADDRESS]
+
+SETTING UP SNMP AUTHORIZATION INFORMATION
+
+ Now, you need to add in your default authorization information for
+ how to make SNMP requests to your host. The parameter names you can
+ pick come straight from the SNMP perl module, so see "perldoc SNMP"
+ for all the parameter names you can pick from.
+
+ Examples:
+
+ ./setupauth -u SQLUSER -p SQLPASSWORD -h SQLHOST Version 1 Community public
+ ./setupauth -u SQLUSER -p SQLPASSWORD -h SQLHOST Version 3 SecName 'v3user' AuthPass 'myv3passphrase' SecLevel authNoPriv
+
+ I also recommend adding a large default timeout (30 secs):
+
+ ./setupauth -u SQLUSER -p SQLPASSWORD -h SQLHOST Timeout 30000000
+
+ If you want different parameters for a group, it'll inherit
+ everything from the default parameters specified above plus any more
+ that you set or override:
+
+ ./setupauth -u SQLUSER -p SQLPASSWORD -h SQLHOST -g agroup Community private
+
+ Further, hosts can be given specific parameters as well if they're
+ really special:
+
+ ./setupauth -u SQLUSER -p SQLPASSWORD -h SQLHOST -m host Timeout 60000000
+
+COLLECTING THE DATA
+
+ The command you need to run to collect data is snmptosql, which will
+ use the information defined above to fill your data base with all
+ sorts of useful information that you've asked it to collect.
+ Something like:
+
+ snmptosql -H SQLHOST -u SQLUSER -p SQLPASSWORD
+
+ should be put in cron to update a regular intervals. I run mine
+ every 10 minutes. Note that it will *not* scale to a large number
+ of hosts easily at the moment. Start with no more than 20 or so to
+ begin with.
+
+USING THE SYSTEM
+
+ Most of the things you'll need to do can be done from the web
+ interface that you've just set up as /manager on some system in the
+ step above. Go to this web page to see what you can do.
+
+MONITORING HOSTS WITH IT (finally)
+
+ It's *not* entirely intuitive yet. So, lets give you an example. In
+ your snmpd.conf file, put a line that says "proc sendmail". This will
+ check to see if sendmail is running on your system. Also put "disk /
+ 10%" which will require the disk has at least 10% of free space.
+ Restart the snmpd (or kill -HUP). See the snmpd.conf manual page
+ for some details.
+
+ Then, go to the above URL and click on the group name you want to
+ add a host to and enter the host name in the dialog box near the
+ bottom of the page (assuming you're logged in as an administrator
+ user setup using the -a flag to setupuser above). Click on the
+ "setup group XXX" link at the bottom of the group's page and click
+ on all the check buttons (you can turn them all on even if you're
+ not really using them all) and hit the submit button.
+
+ Come back 10 minutes later, reload the group and click on the host
+ name. You should see pretty red/green lights if there is or isn't a
+ problem. It'll show you a few tables with the various bits of data
+ it collected (including how many sendmail processes are running, an
+ how much disk space is actually being used), etc.
+
+GRAPHING
+
+ To be written.
diff --git a/perl/manager/Makefile.PL b/perl/manager/Makefile.PL
new file mode 100644
index 0000000..633243d
--- /dev/null
+++ b/perl/manager/Makefile.PL
@@ -0,0 +1,16 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'NetSNMP::manager',
+ 'VERSION' => '', # finds $VERSION
+ 'PREREQ_PM' => {# SNMP => 4.0,
+ DBI => 0,
+ CGI => 0}, # e.g., Module::Name => 1.1
+ 'PM' => {
+ 'displaytable.pm' => '$(INST_LIBDIR)/../displaytable.pm',
+ 'getValues.pm' => '$(INST_LIBDIR)/../getValues.pm',
+ 'manager.pm' => '$(INST_LIBDIR)/manager.pm'
+ },
+ 'EXE_FILES' => [qw(snmptosql setupdb setupuser setupauth)]
+);
diff --git a/perl/manager/displaytable.pm b/perl/manager/displaytable.pm
new file mode 100644
index 0000000..1eceacd
--- /dev/null
+++ b/perl/manager/displaytable.pm
@@ -0,0 +1,628 @@
+# displaytable(TABLENAME, CONFIG...):
+#
+# stolen from sqltohtml in the ucd-snmp package
+#
+
+package NetSNMP::manager::displaytable;
+use POSIX (isprint);
+
+BEGIN {
+ use Exporter ();
+ use vars qw(@ISA @EXPORT_OK $tableparms $headerparms);
+ @ISA = qw(Exporter);
+ @EXPORT=qw(&displaytable &displaygraph);
+
+ require DBI;
+ require CGI;
+
+ use GD::Graph();
+ use GD::Graph::lines();
+ use GD::Graph::bars();
+ use GD::Graph::points();
+ use GD::Graph::linespoints();
+ use GD::Graph::area();
+ use GD::Graph::pie();
+};
+
+$tableparms="border=1 bgcolor=\"#c0c0e0\"";
+$headerparms="border=1 bgcolor=\"#b0e0b0\"";
+
+sub displaygraph {
+ my $dbh = shift;
+ my $tablename = shift;
+ my %config = @_;
+ my $type = $config{'-type'} || "lines";
+ my $x = $config{'-x'} || "640";
+ my $y = $config{'-y'} || "480";
+ my $bgcolor = $config{'-bgcolor'} || "white";
+ my $datecol = $config{'-xcol'} || "updated";
+ my $xtickevery = $config{'-xtickevery'} || 50;
+ my ($thetable);
+
+# print STDERR join(",",@_),"\n";
+
+ return -1 if (!defined($dbh) || !defined($tablename) ||
+ !defined ($config{'-columns'}) ||
+ ref($config{'-columns'}) ne "ARRAY" ||
+ !defined ($config{'-indexes'}) ||
+ ref($config{'-indexes'}) ne "ARRAY");
+
+
+ my $cmd = "SELECT " .
+ join(",",@{$config{'-columns'}},
+ @{$config{'-indexes'}}, $datecol) .
+ " FROM $tablename $config{'-clauses'}";
+ ( $thetable = $dbh->prepare($cmd))
+ or return -1;
+ ( $thetable->execute )
+ or return -1;
+
+ my %data;
+ my $count = 0;
+
+ while( $row = $thetable->fetchrow_hashref() ) {
+ # XXX: multiple indexe columns -> unique name
+ # save all the row's data based on the index column(s)
+ foreach my $j (@{$config{'-columns'}}) {
+ if ($config{'-difference'} || $config{'-rate'}) {
+ if (defined($lastval{$row->{$config{'-indexes'}[0]}}{$j}{'value'})) {
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j}=
+ $row->{$j} -
+ $lastval{$row->{$config{'-indexes'}[0]}}{$j}{'value'};
+ #
+ # convert to a rate if desired.
+ #
+ if ($config{'-rate'}) {
+ if (($row->{$datecol} - $lastval{$row->{$config{'-indexes'}[0]}}{$j}{'index'})) {
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} = $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j}*$config{'-rate'}/($row->{$datecol} - $lastval{$row->{$config{'-indexes'}[0]}}{$j}{'index'});
+ } else {
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} = -1;
+ }
+ }
+
+ }
+ $lastval{$row->{$config{'-indexes'}[0]}}{$j}{'value'} = $row->{$j};
+ $lastval{$row->{$config{'-indexes'}[0]}}{$j}{'index'} = $row->{$datecol};
+ } else {
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} = $row->{$j};
+ }
+
+ #
+ # limit the data to a vertical range.
+ #
+ if (defined($config{'-max'}) &&
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} >
+ $config{'-max'}) {
+ # set to max value
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} =
+ $config{'-max'};
+ }
+
+ if (defined($config{'-min'}) &&
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} <
+ $config{'-min'}) {
+ # set to min value
+ $data{$row->{$config{'-indexes'}[0]}}{$row->{$datecol}}{$j} =
+ $config{'-min'};
+ }
+ }
+ push @xdata,$row->{$datecol};
+ }
+
+ my @pngdata;
+
+ if (defined($config{'-createdata'})) {
+ &{$config{'-createdata'}}(\@pngdata, \@xdata, \%data);
+ } else {
+ push @pngdata, \@xdata;
+
+ my @datakeys = keys(%data);
+
+# open(O,">/tmp/data");
+ foreach my $i (@datakeys) {
+ foreach my $j (@{$config{'-columns'}}) {
+ my @newrow;
+ foreach my $k (@xdata) {
+# print O "i=$i k=$k j=$j :: $data{$i}{$k}{$j}\n";
+ push @newrow, ($data{$i}{$k}{$j} || 0);
+ }
+ push @pngdata,\@newrow;
+ }
+ }
+ }
+# close O;
+
+ if ($#pngdata > 0) {
+ # create the graph itself
+ my $graph = new GD::Graph::lines($x, $y);
+ $graph->set('bgclr' => $bgcolor);
+# print STDERR "columns: ", join(",",@{$config{'-columns'}}), "\n";
+ if (defined($config{'-legend'})) {
+# print STDERR "legend: ", join(",",@{$config{'-legend'}}), "\n";
+ $graph->set_legend(@{$config{'-legend'}});
+ } else {
+ my @legend;
+ foreach my $xxx (@{$config{'-columns'}}) {
+ push @legend, "$xxx = $config{'-indexes'}[0]";
+ }
+ $graph->set_legend(@legend);
+ }
+ foreach my $i (qw(title x_label_skip x_labels_vertical x_tick_number x_number_format y_number_format x_min_value x_max_value y_min_value y_max_value)) {
+# print STDERR "setting $i from -$i = " . $config{"-$i"} . "\n";
+ $graph->set("$i" => $config{"-$i"}) if ($config{"-$i"});
+ }
+ if ($config{'-pngparms'}) {
+ $graph->set(@{$config{'-pngparms'}});
+ }
+ print $graph->plot(\@pngdata);
+ return $#{$pngdata[0]};
+ }
+ return -1;
+}
+
+sub displaytable {
+ my $dbh = shift;
+ my $tablename = shift;
+ my %config = @_;
+ my $clauses = $config{'-clauses'};
+ my $dolink = $config{'-dolink'};
+ my $datalink = $config{'-datalink'};
+ my $beginhook = $config{'-beginhook'};
+ my $modifiedhook = $config{'-modifiedhook'};
+ my $endhook = $config{'-endhook'};
+ my $selectwhat = $config{'-select'};
+# my $printonly = $config{'-printonly'};
+ $selectwhat = "*" if (!defined($selectwhat));
+ my $tableparms = $config{'-tableparms'} || $displaytable::tableparms;
+ my $headerparms = $config{'-headerparms'} || $displaytable::headerparms;
+ my ($thetable, $data, $ref, $prefs, $xlattable);
+
+ if ($config{'-dontdisplaycol'}) {
+ ($prefs = $dbh->prepare($config{'-dontdisplaycol'}) )
+ or die "\nnot ok: $DBI::errstr\n";
+ }
+
+ # get a list of data from the table we want to display
+ ( $thetable = $dbh->prepare("SELECT $selectwhat FROM $tablename $clauses"))
+ or return -1;
+ ( $thetable->execute )
+ or return -1;
+
+ # get a list of data from the table we want to display
+ if ($config{'-xlat'}) {
+ ( $xlattable =
+ $dbh->prepare("SELECT newname FROM $config{'-xlat'} where oldname = ?"))
+ or die "\nnot ok: $DBI::errstr\n";
+ }
+
+ # editable/markable setup
+ my $edited = 0;
+ my $editable = 0;
+ my $markable = 0;
+ my (@indexkeys, @valuekeys, $uph, %indexhash, $q);
+ if (defined($config{'-editable'})) {
+ $editable = 1;
+ }
+
+ if (defined($config{'-mark'}) || defined($config{'-onmarked'})) {
+ $markable = 1;
+ }
+
+ if (defined($config{'-CGI'}) && ref($config{'-CGI'}) eq "CGI") {
+ $q = $config{'-CGI'};
+ }
+
+ if (($editable || $markable)) {
+ if (ref($config{'-indexes'}) eq ARRAY && defined($q)) {
+ @indexkeys = @{$config{'-indexes'}};
+ foreach my $kk (@indexkeys) {
+ $indexhash{$kk} = 1;
+ }
+ } else {
+ $editable = $markable = 0;
+ print STDERR "displaytable error: no -indexes option specified or -CGI not specified\n";
+ }
+ }
+
+ if (($editable || $markable) &&
+ $q->param('edited_' . toalpha($tablename))) {
+ $edited = 1;
+ }
+
+ # table header
+ my $doheader = 1;
+ my @keys;
+ my $rowcount = 0;
+ $thetable->execute();
+ if ($editable || $markable) {
+ print "<input type=hidden name=\"edited_" . toalpha($tablename) . "\" value=1>\n";
+ }
+
+ while( $data = $thetable->fetchrow_hashref() ) {
+ $rowcount++;
+ if ($edited && $editable && !defined($uph)) {
+ foreach my $kk (keys(%$data)) {
+ push (@valuekeys, maybe_from_hex($kk)) if (!defined($indexhash{$kk}));
+ }
+ my $cmd = "update $tablename set " .
+ join(" = ?, ",@valuekeys) .
+ " = ? where " .
+ join(" = ? and ",@indexkeys) .
+ " = ?";
+ $uph = $dbh->prepare($cmd);
+# print STDERR "setting up: $cmd<br>\n";
+ }
+ if ($doheader) {
+ if ($config{'-selectorder'} &&
+ ref($config{'-selectorder'}) eq "ARRAY") {
+ @keys = @{$config{'-selectorder'}};
+ } elsif ($config{'-selectorder'}) {
+ $_ = $selectwhat;
+ @keys = split(/, */);
+ } else {
+ @keys = (sort keys(%$data));
+ }
+ if (defined($config{'-title'})) {
+ print "<br><b>$config{'-title'}</b>\n";
+ } elsif (!defined($config{'-notitle'})) {
+ print "<br><b>";
+ print "<a href=\"$ref\">" if (defined($dolink) &&
+ defined($ref = &$dolink($tablename)));
+ if ($config{'-xlat'}) {
+ my $toval = $xlattable->execute($tablename);
+ if ($toval > 0) {
+ print $xlattable->fetchrow_array;
+ } else {
+ print "$tablename";
+ }
+ } else {
+ print "$tablename";
+ }
+ print "</a>" if (defined($ref));
+ print "</b>\n";
+ }
+ print "<br>\n";
+ print "<table $tableparms>\n";
+ if (!$config{'-noheaders'}) {
+ print "<tr $headerparms>";
+ }
+ if (defined($beginhook)) {
+ &$beginhook($dbh, $tablename);
+ }
+ if (!$config{'-noheaders'}) {
+ if ($markable) {
+ my $ukey = to_unique_key($key, $data, @indexkeys);
+ print "<td>Mark</td>\n";
+ }
+ foreach $l (@keys) {
+ if (!defined($prefs) ||
+ $prefs->execute($tablename, $l) eq "0E0") {
+ print "<th>";
+ print "<a href=\"$ref\">" if (defined($dolink) &&
+ defined($ref = &$dolink($l)));
+ if ($config{'-xlat'}) {
+ my $toval = $xlattable->execute($l);
+ if ($toval > 0) {
+ print $xlattable->fetchrow_array;
+ } else {
+ print "$l";
+ }
+ } else {
+ print "$l";
+ }
+ print "</a>" if (defined($ref));
+ print "</th>";
+ }
+ }
+ }
+ if (defined($endhook)) {
+ &$endhook($dbh, $tablename);
+ }
+ if (!$config{'-noheaders'}) {
+ print "</tr>\n";
+ }
+ $doheader = 0;
+ }
+
+ print "<tr>";
+ if (defined($beginhook)) {
+ &$beginhook($dbh, $tablename, $data);
+ }
+ if ($edited && $editable) {
+ my @indexvalues = getvalues($data, @indexkeys);
+ if ($modifiedhook) {
+ foreach my $valkey (@valuekeys) {
+ my ($value) = getquery($q, $data, \@indexkeys, $valkey);
+ if ($value ne $data->{$valkey}) {
+ &$modifiedhook($dbh, $tablename, $valkey,
+ $data, @indexvalues);
+ }
+ }
+ }
+
+ my $ret = $uph->execute(getquery($q, $data, \@indexkeys, @valuekeys),
+ @indexvalues);
+ foreach my $x (@indexkeys) {
+ next if (defined($indexhash{$x}));
+ $data->{$x} = $q->param(to_unique_key($x, $data, @indexkeys));
+ }
+# print "ret: $ret, $DBI::errstr<br>\n";
+ }
+ if ($markable) {
+ my $ukey = to_unique_key("mark", $data, @indexkeys);
+ print "<td><input type=checkbox value=Y name=\"$ukey\"" .
+ (($q->param($ukey) eq "Y") ? " checked" : "") . "></td>\n";
+ if ($q->param($ukey) eq "Y" && $config{'-onmarked'}) {
+ &{$config{'-onmarked'}}($dbh, $tablename, $data);
+ }
+ }
+
+ foreach $key (@keys) {
+ if (!defined($prefs) ||
+ $prefs->execute($tablename, $key) eq "0E0") {
+ print "<td>";
+ print "<a href=\"$ref\">" if (defined($datalink) &&
+ defined($ref = &$datalink($key, $data->{$key})));
+ if ($editable && !defined($indexhash{$key})) {
+ my $ukey = to_unique_key($key, $data, @indexkeys);
+ my $sz;
+ if ($config{'-sizehash'}) {
+ $sz = "size=" . $config{'-sizehash'}{$key};
+ }
+ if (!$sz && $config{'-inputsize'}) {
+ $sz = "size=" . $config{'-inputsize'};
+ }
+ print STDERR "size $key: $sz from $config{'-sizehash'}{$key} / $config{'-inputsize'}\n";
+ print "<input type=text name=\"$ukey\" value=\"" .
+ maybe_to_hex($data->{$key}) . "\" $sz>";
+ } else {
+ if ($config{'-printer'}) {
+ &{$config{'-printer'}}($key, $data->{$key}, $data);
+ } elsif ($data->{$key} ne "") {
+ print $data->{$key};
+ } else {
+ print "&nbsp";
+ }
+ }
+ print "</a>" if (defined($ref));
+ print "</td>";
+ }
+ }
+
+ if (defined($endhook)) {
+ &$endhook($dbh, $tablename, $data);
+ }
+ print "</tr>\n";
+ last if (defined($config{'-maxrows'}) &&
+ $rowcount >= $config{'-maxrows'});
+ }
+ if ($rowcount > 0) {
+ print "</table>\n";
+ }
+ return $rowcount;
+}
+
+sub to_unique_key {
+ my $ret = shift;
+ $ret .= "_";
+ my $data = shift;
+ if (!defined($data)) {
+ $ret .= join("_",@_);
+ } else {
+ foreach my $i (@_) {
+ $ret .= "_" . $data->{$i};
+ }
+ }
+ return toalpha($ret);
+}
+
+sub toalpha {
+ my $ret = join("",@_);
+ $ret =~ s/([^A-Za-z0-9_])/ord($1)/eg;
+ return $ret;
+}
+
+sub getvalues {
+ my $hash = shift;
+ my @ret;
+ foreach my $i (@_) {
+ push @ret, maybe_from_hex($hash->{$i});
+ }
+ return @ret;
+}
+
+sub getquery {
+ my $q = shift;
+ my $data = shift;
+ my $keys = shift;
+ my @ret;
+ foreach my $i (@_) {
+ push @ret, maybe_from_hex($q->param(to_unique_key($i, $data, @$keys)));
+ }
+ return @ret;
+}
+
+sub maybe_to_hex {
+ my $str = shift;
+ if (!isprint($str)) {
+ $str = "0x" . (unpack("H*", $str))[0];
+ }
+ $str =~ s/\"/&quot;/g;
+ return $str;
+}
+
+sub maybe_from_hex {
+ my $str = shift;
+ if (substr($str,0,2) eq "0x") {
+ ($str) = pack("H*", substr($str,2));
+ }
+ return $str;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+SNMP - The Perl5 'SNMP' Extension Module v3.1.0 for the UCD SNMPv3 Library
+
+=head1 SYNOPSIS
+
+ use DBI;
+ use displaytable;
+
+ $dbh = DBI->connect(...);
+ $numshown = displaytable($dbh, 'tablename', [options]);
+
+=head1 DESCRIPTION
+
+The displaytable and displaygraph functions format the output of a DBI
+database query into an html or graph output.
+
+=head1 DISPLAYTABLE OPTIONS
+
+=over 4
+
+=item -select => VALUE
+
+Selects a set of columns, or functions to be displayed in the resulting table.
+
+Example: -select => 'column1, column2'
+
+Default: *
+
+=item -title => VALUE
+
+Use VALUE as the title of the table.
+
+=item -notitle => 1
+
+Don't print a title for the table.
+
+=item -noheaders => 1
+
+Don't print a header row at the top of the table.
+
+=item -selectorder => 1
+
+=item -selectorder => [qw(column1 column2)]
+
+Defines the order of the columns. A value of 1 will use the order of
+the -select statement by textually parsing it's comma seperated list.
+If an array is passed containing the column names, that order will be
+used.
+
+Example:
+
+ -select => distinct(column1) as foo, -selectorder => [qw(foo)]
+
+=item -maxrows => NUM
+
+Limits the number of display lines to NUM.
+
+=item -tableparms => PARAMS
+
+=item -headerparms => PARAMS
+
+The parameters to be used for formating the table contents and the
+header contents.
+
+Defaults:
+
+ -tableparms => "border=1 bgcolor='#c0c0e0'"
+
+ -headerparms => "border=1 bgcolor='#b0e0b0'"
+
+=item -dolink => \&FUNC
+
+If passed, FUNC(name) will be called on the tablename or header. The
+function should return a web url that the header/table name should be
+linked to.
+
+=item -datalink => \&FUNC
+
+Identical to -dolink, but called for the data portion of the table.
+Arguments are the column name and the data element for that column.
+
+=item -printer => \&FUNC
+
+Calls FUNC(COLUMNNAME, COLUMNDATA, DATA) to print the data from each
+column. COLUMNDATA is the data itself, and DATA is a reference to the
+hash for the entire row (IE, COLUMNDATA = $DATA->{$COLUMNNAME}).
+
+=item -beginhook => \&FUNC
+
+=item -endhook => \&FUNC
+
+displaytable will call these functions at the beginning and end of the
+printing of a row. Useful for inserting new columns at the beginning
+or end of the table. When the headers to the table are being printed,
+they will be called like FUNC($dbh, TABLENAME). When the data is
+being printed, they will be called like FUNC($dbh, TABLENAME, DATA),
+which DATA is a reference to the hash containing the row data.
+
+Example:
+
+ -endhook => sub {
+ my ($d, $t, $data) = @_;
+ if (defined($data)) {
+ print "<td>",(100 * $data->{'column1'} / $data->{'column2'}),"</td>";
+ } else {
+ print "<td>Percentage</td>";
+ }
+ }
+
+=item -clauses => sql_clauses
+
+Adds clauses to the sql expression.
+
+Example: -clauses => "where column1 = 'value' limit 10 order by column2"
+
+=item -xlat => xlattable
+
+Translates column headers and the table name by looking in a table for
+the appropriate translation. Essentially uses:
+
+ SELECT newname FROM xlattable where oldname = ?
+
+to translate everything.
+
+=item -editable => 1
+
+=item -indexes => [qw(INDEX_COLUMNS)]
+
+=item -CGI => CGI_REFERENCE
+
+If both of these are passed as arguments, the table is printed in
+editable format. The INDEX_COLUMNS should be a list of columns that
+can be used to uniquely identify a row. They will be the non-editable
+columns shown in the table. Everything else will be editable. The
+form and the submit button written by the rest of the script must loop
+back to the same displaytable clause for the edits to be committed to
+the database. CGI_REFERENCE should be a reference to the CGI object
+used to query web parameters from ($CGI_REFERENCE = new CGI);
+
+=item -mark => 1
+
+=item -indexes => [qw(INDEX_COLUMNS)]
+
+=item -CGI => CGI_REFERENCE
+
+=item -onmarked => \&FUNC
+
+When the first three of these are specified, the left hand most column
+will be a check box that allows users to mark the row for future work.
+
+FUNC($dbh, TABLENAME, DATA) will be called for each marked entry when
+a submission data has been processed. $DATA is a hash reference to
+the rows dataset. See -editable above for more information.
+
+-onmarked => \&FUNC implies -mark => 1.
+
+=back
+
+=head1 Author
+
+wjhardaker@ucdavis.edu
+
+=cut
diff --git a/perl/manager/getValues.pm b/perl/manager/getValues.pm
new file mode 100644
index 0000000..bd0b9a6
--- /dev/null
+++ b/perl/manager/getValues.pm
@@ -0,0 +1,49 @@
+#
+# getValues($dbh,
+# [-varcol => varname,]
+# [-valcol => varval,]
+# [-key => keyname,]
+# tablename => indexname,
+# ...)
+
+package NetSNMP::manager::getValues;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT_OK=(getValues);
+
+my $varcol = "varcol";
+my $valcol = "valcol";
+my $key = "lookup";
+
+sub getValues {
+ my $dbh = shift;
+ my (@vars2, $tmp, $cursor, $row, %results, $i, $cursor);
+ my ($varcol, $valcol, $key) = ($varcol, $valcol, $key);
+ my @vars = @_;
+ while($#vars >= 0) {
+ $i = shift @vars;
+ $tmp = shift @vars;
+ if ($i =~ /^-/) {
+ $varcol = $tmp if ($i =~ /-varcol/);
+ $valcol = $tmp if ($i =~ /-valcol/);
+ $key = $tmp if ($i =~ /-key/);
+ } else {
+ push(@vars2,$i,$tmp);
+ }
+ }
+ while($#vars2 >= 0) {
+ $i = shift @vars2;
+ $tmp = shift @vars2;
+# print "select $varcol,$valcol from $i where $key = '$tmp'\n";
+ ($cursor =
+ $dbh->prepare("select $varcol,$valcol from $i where $key = '$tmp'"))
+ or die "\nnot ok: $DBI::errstr\n";
+ ($cursor->execute)
+ or die "\nnot ok: $DBI::errstr\n";
+ while ( $row = $cursor->fetchrow_hashref ) {
+ $results{$row->{$varcol}} = $row->{$valcol};
+ }
+ }
+ return %results;
+}
+1;
diff --git a/perl/manager/green.gif b/perl/manager/green.gif
new file mode 100644
index 0000000..b63716d
--- /dev/null
+++ b/perl/manager/green.gif
Binary files differ
diff --git a/perl/manager/manager.pm b/perl/manager/manager.pm
new file mode 100644
index 0000000..0450625
--- /dev/null
+++ b/perl/manager/manager.pm
@@ -0,0 +1,1051 @@
+package NetSNMP::manager;
+
+use strict ();
+use warnings;
+use Apache::Constants qw(:common);
+use CGI qw(:standard delete_all);
+use SNMP ();
+use DBI ();
+use NetSNMP::manager::displaytable qw(displaytable displaygraph);
+
+# globals
+$NetSNMP::manager::hostname = 'localhost'; # Host that serves the mSQL Database
+$NetSNMP::manager::dbname = 'snmp'; # mySQL Database name
+$NetSNMP::manager::user = 'root';
+# $NetSNMP::manager::pass = "password";
+$NetSNMP::manager::imagebase = "/home/hardaker/src/snmp/manager"; # <=== CHANGE ME ====
+$NetSNMP::manager::redimage = "/graphics/red.gif";
+$NetSNMP::manager::greenimage = "/graphics/green.gif";
+#$NetSNMP::manager::verbose = 1;
+$NetSNMP::manager::tableparms = "border=1 bgcolor=\"#c0c0e0\"";
+$NetSNMP::manager::headerparms = "border=1 bgcolor=\"#b0e0b0\"";
+
+# init the snmp library
+$SNMP::save_descriptions=1;
+#SNMP::init_mib();
+
+%NetSNMP::manager::myorder = qw(id 0 oidindex 1 host 2 updated 3);
+
+sub handler {
+ my $r = shift;
+ Apache->request($r);
+
+ # get info from handler
+ my $hostname = $r->dir_config('hostname') || $NetSNMP::manager::hostname;
+ my $dbname = $r->dir_config('dbname') || $NetSNMP::manager::dbname;
+ my $sqluser = $r->dir_config('user') || $NetSNMP::manager::user;
+ my $pass = $r->dir_config('pass') || $NetSNMP::manager::pass;
+ my $verbose = $r->dir_config('verbose') || $NetSNMP::manager::verbose;
+
+#===========================================================================
+# Global defines
+#===========================================================================
+
+my ($dbh, $query, $remuser);
+
+$remuser = $ENV{'REMOTE_USER'};
+$remuser = "guest" if (!defined($remuser) || $remuser eq "");
+
+#===========================================================================
+# Connect to the mSQL database with the appropriate driver
+#===========================================================================
+($dbh = DBI->connect("DBI:mysql:database=$dbname;host=$hostname", $sqluser, $pass))
+ or die "\tConnect not ok: $DBI::errstr\n";
+
+#===========================================================================
+# stats Images, for inclusion on another page. (ie, slashdot user box)
+#===========================================================================
+if (my $group = param('groupstat')) {
+ $r->content_type("image/gif");
+ $r->send_http_header();
+ my $cur = getcursor($dbh, "select host from usergroups as ug, hostgroups as hg where ug.groupname = '$group' and hg.groupname = '$group' and user = '$remuser'");
+ while (my $row = $cur->fetchrow_hashref ) {
+ if (checkhost($dbh, $group, $row->{'host'})) {
+ open(I, "$NetSNMP::manager::imagebase$NetSNMP::manager::redimage");
+ while(read(I, $_, 4096)) { print; }
+ close(I);
+ }
+ }
+ open(I, "$NetSNMP::manager::imagebase$NetSNMP::manager::greenimage");
+ while(read(I, $_, 4096)) { print; }
+ close(I);
+ return OK();
+}
+
+
+sub date_format {
+ my $time = shift;
+ my @out = localtime($time);
+ my $ret = $out[4] . "-" . $out[3] . "-" . $out[5] . " " . $out[2] . " " . $out[1];
+# print STDERR "$time: $ret\n";
+ return $ret;
+}
+
+
+#
+# Graphing of historical data
+#
+if ((param('displaygraph') || param('dograph')) && param('table')) {
+ my $host = param('host');
+ my $group = param('group');
+ if (!isuser($dbh, $remuser, $group)) {
+ $r->content_type("image/png");
+ $r->send_http_header();
+ print "Unauthorized access to that group ($group)\n";
+ return Exit($dbh, $group);
+ }
+ my $table = param('table');
+ my @columns;
+
+ if (!param('dograph')) {
+ $r->content_type("text/html");
+ $r->send_http_header();
+ print "<body bgcolor=\"#ffffff\">\n";
+ print "<form>\n";
+ print "<table border=1><tr><td>\n";
+
+ print "<table>\n";
+ print "<tr align=top><th></th><th>Select indexes<br>to graph</th></tr>\n";
+
+ my $handle = getcursor($dbh, "SELECT sql_small_result distinct(oidindex) FROM $table where host = '$host'");
+ my @cols;
+ while ( $row = $handle->fetchrow_hashref ) {
+ print "<tr><td>$row->{oidindex}</td><td><input type=checkbox value=1 name=" . 'graph_' . displaytable::to_unique_key($row->{'oidindex'}) . "></td></tr>\n";
+ }
+ print "</table>\n";
+
+ print "</td><td>\n";
+
+ print "<table>\n";
+ print "<tr align=top><th></th><th>Select Columns<br>to graph</th></tr>\n";
+ my $handle = getcursor($dbh, "SELECT * FROM $table limit 1");
+ my $row = $handle->fetchrow_hashref;
+ map { print "<tr><td>$_</td><td><input type=checkbox value=1 name=column_" . displaytable::to_unique_key($_) . "></td></tr>\n"; } keys(%$row);
+ print "</table>\n";
+
+ print "</td></tr></table>\n";
+
+ print "<br>Graph as a Rate: <input type=checkbox value=1 name=graph_as_rate><br>\n";
+ print "<br>Maximum Y Value: <input type=text value=inf name=max_y><br>\n";
+ print "<br>Minimum Y Value: <input type=text value=-inf name=min_y><br>\n";
+
+ print "<input type=hidden name=table value=\"$table\">\n";
+ print "<input type=hidden name=host value=\"$host\">\n";
+ print "<input type=hidden name=dograph value=1>\n";
+ print "<input type=hidden name=group value=\"$group\">\n";
+ print "<input type=submit name=\"Make Graph\">\n";
+
+ print "</form>\n";
+
+ my $handle = getcursor($dbh, "SELECT distinct(oidindex) FROM $table where host = '$host' order by oidindex");
+ return Exit($dbh, $group);
+ }
+ if (param('graph_all_data')) {
+ $clause = "host = '$host'";
+ } else {
+ my $handle = getcursor($dbh, "SELECT distinct(oidindex) FROM $table where host = '$host'");
+ $clause = "where (";
+ while ( $row = $handle->fetchrow_hashref ) {
+# print STDERR "graph test: " . $row->{'oidindex'} . "=" . "graph_" . displaytable::to_unique_key($row->{'oidindex'}) . "=" . param("graph_" . displaytable::to_unique_key($row->{'oidindex'})) . "\n";
+ if (param("graph_" . displaytable::to_unique_key($row->{'oidindex'}))) {
+ $clause .= " or oidindex = " . $row->{'oidindex'} . "";
+ }
+ }
+
+ my $handle = getcursor($dbh, "SELECT * FROM $table limit 1");
+ my $row = $handle->fetchrow_hashref;
+ map { push @columns, $_ if (param('column_' . displaytable::to_unique_key($_))) } keys(%$row);
+
+ $clause .= ")";
+ $clause =~ s/\( or /\(/;
+ if ($clause =~ /\(\)/ || $#columns == -1) {
+ $r->content_type("text/html");
+ $r->send_http_header();
+ print "<body bgcolor=\"#ffffff\">\n";
+ print "<h1>No Data to Graph</h1>\n";
+ print STDERR "No data to graph: $clause, $#columns\n";
+ return Exit($dbh, "$group");
+ }
+ $clause .= " and host = '$host'";
+ }
+
+# print STDERR "graphing clause: $clause\n";
+
+ # all is ok, display the graph
+
+ $r->content_type("image/png");
+ $r->send_http_header();
+
+ print STDERR "graphing clause: $clause, columns: ", join(", ",@columns), "\n";
+ my @args;
+ push (@args, '-rate', '60') if (param('graph_as_rate'));
+ push (@args, '-max', param('max_y')) if (param('max_y') && param('max_y') =~ /^[-.\d]+$/);
+ push (@args, '-min', param('min_y')) if (param('min_y') && param('min_y') =~ /^[-.\d]+$/);
+
+ my $ret =
+ displaygraph($dbh, $table,
+# '-xcol', "date_format(updated,'%m-%d-%y %h:%i')",
+ '-xcol', "unix_timestamp(updated)",
+ '-pngparms', [
+ 'x_labels_vertical', '1',
+ 'x_tick_number', 6,
+ 'x_number_format', \&date_format,
+ 'y_label', 'Count/Min',
+ 'title', $table,
+# 'y_min_value', 0,
+ ],
+ '-clauses', "$clause order by updated",
+ @args,
+ '-columns', \@columns,
+ '-indexes', ['oidindex']);
+ print STDERR "$ret rows graphed\n";
+ return OK();
+}
+
+#===========================================================================
+# Start HTML.
+#===========================================================================
+$r->content_type("text/html");
+$r->send_http_header();
+print "<body bgcolor=\"#ffffff\">\n";
+print "<h1>UCD-SNMP Management Console</h1>\n";
+print "<hr>\n";
+
+#===========================================================================
+# Display mib related data information
+#===========================================================================
+if (param('displayinfo')) {
+ makemibtable(param('displayinfo'));
+ return Exit($dbh, "");
+}
+
+#===========================================================================
+# Display a generic sql table of any kind (debugging).
+#===========================================================================
+# if (my $disptable = param('displaytable')) {
+# if (param('editable') == 1) {
+# print "<form submit=dont>\n";
+# displaytable($disptable, -editable, 1);
+# print "</form>\n";
+# } else {
+# displaytable($disptable);
+# }
+# return Exit($dbh, "");
+# }
+
+#===========================================================================
+# Get host and group from CGI query.
+#===========================================================================
+my $host = param('host');
+my $group = param('group');
+
+#===========================================================================
+# Editable user information
+#===========================================================================
+
+if (param('setuponcall')) {
+ print "<title>oncall schedule for user: $remuser</title>\n";
+ print "<h2>oncall schedule for user: $remuser</h2>\n";
+ print "<p>Please select your oncall schedule and mailing addresses for your groups below:";
+ if (!isexpert($remuser)) {
+ print "<ul>\n";
+ print "<li>Values for the days/hours fields can be comma seperated lists of hours/days/ranges. EG: hours: 7-18,0-4.\n";
+ print "</ul>\n";
+ }
+ print "<form method=post><input type=hidden name=setuponcall value=1>\n";
+ displaytable($dbh, 'oncall',
+ '-clauses',"where user = '$remuser' order by groupname",
+ '-select','id, user, groupname, email, pager, days, hours',
+ '-selectorder', 1,
+ '-notitle', 1,
+ '-editable', 1,
+ '-indexes', ['id','user','groupname'],
+ '-CGI', $CGI::Q
+ );
+ print "<input type=submit value=\"submit changes\">\n";
+ print "</form>\n";
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# show the list of groups a user belongs to.
+#===========================================================================
+if (!defined($group)) {
+ my @groups = getgroupsforuser($dbh, $remuser);
+ print "<title>Net-SNMP Group List</title>\n";
+ print "<h2>Host groupings you may access:</h2>\n";
+ if (!isexpert($remuser)) {
+ print "<ul>\n";
+ print "<li>Click on a group to operate or view the hosts in that group.\n";
+ print "<li>Click on a red status light below to list the problems found.\n";
+ print "</ul>\n";
+ }
+
+ if ($#groups > 0) {
+ displaytable($dbh, 'usergroups',
+ '-clauses', "where (user = '$remuser')",
+ '-select', 'distinct groupname',
+ '-notitle', 1,
+ '-printonly', ['groupname'],
+ '-datalink', sub { my $q = self_url();
+ my $key = shift;
+ my $h = shift;
+ return if ($key ne "groupname");
+ return addtoken($q,"group=$h");
+ },
+ '-beginhook',
+ sub {
+ my $q = self_url();
+ my($dbh, $junk, $data) = @_;
+ if (!defined($data)) {
+ print "<th>Status</th>";
+ return;
+ }
+ my ($cur, $row);
+ $cur = getcursor($dbh, "select host from hostgroups where groupname = '$data->{groupname}'");
+ while ( $row = $cur->fetchrow_hashref ) {
+ if (checkhost($dbh, $data->{'groupname'},
+ $row->{'host'})) {
+ print "<td><a href=\"" . addtoken($q,"group=$data->{groupname}&summarizegroup=1") . "\"><img border=0 src=$NetSNMP::manager::redimage></a></td>\n";
+ return;
+ }
+ }
+ print "<td><img src=$NetSNMP::manager::greenimage></td>\n";
+ }
+ );
+ $dbh->disconnect();
+ return Exit($dbh, $group);
+ } else {
+ if ($#groups == -1) {
+ print "You are not configured to use the Net-SNMP-manager, please contact your system administrator.";
+ return Exit($dbh, $group);
+ }
+ $group = $groups[0];
+ }
+}
+
+#===========================================================================
+# reject un-authorized people accessing a certain group
+#===========================================================================
+if (!isuser($dbh, $remuser, $group)) {
+ print "Unauthorized access to that group ($group)\n";
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# add a new host to a group
+#===========================================================================
+if (defined(my $newhost = param('newhost'))) {
+ if (isadmin($dbh, $remuser, $group)) {
+ if ($dbh->do("select * from hostgroups where host = '$newhost' and groupname = '$group'") eq "0E0") {
+ $dbh->do("insert into hostgroups(host,groupname) values('$newhost','$group')") ;
+ } else {
+ print "<b>ERROR: host $newhost already in $group</b>\n";
+ }
+ CGI::delete('newhost');
+ }
+}
+
+#===========================================================================
+# display setup configuration for a group
+#===========================================================================
+if (defined(param('setupgroup'))) {
+ if (isadmin($dbh, $remuser, $group)) {
+ setupgroup($dbh, $group);
+ } else {
+ print "<h2>You're not able to perform setup operations for group $group\n";
+ }
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# save configuration information submitted about a group
+#===========================================================================
+if (defined(param('setupgroupsubmit')) &&
+ isadmin($dbh, $remuser, $group)) {
+ setupgroupsubmit($dbh, $group);
+ delete_all();
+ param(-name => 'group', -value => $group);
+ print "<a href=\"" . self_url() . "\">Entries submitted</a>";
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# user preferences
+#===========================================================================
+if (defined(param('userprefs'))) {
+ setupuserpreferences($dbh, $remuser, $group);
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# save submitted user preferences
+#===========================================================================
+if (defined(param('setupuserprefssubmit')) &&
+ isadmin($dbh, $remuser, $group)) {
+ setupusersubmit($dbh, $remuser, $group);
+ delete_all();
+ param(-name => 'group', -value => $group);
+ print "<a href=\"" . self_url() . "\">Entries submitted</a>";
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# summarize problems in a group
+#===========================================================================
+if (defined(param('summarizegroup'))) {
+ print "<title>group problem summary: $group</title>\n";
+ print "<h2>The following is a list of problems in the group \"$group\":</h2>\n";
+ summarizeerrors($dbh, "where groupname = '$group'");
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# summarize problems on a host
+#===========================================================================
+if (defined($host) && defined(param('summarizehost'))) {
+ print "<title>host summary: $host</title>\n";
+ print "<h2>The following is a list of problems for the host \"$host\":</h2>\n";
+ summarizeerrors($dbh, "where groupname = '$group' and host = '$host'");
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# display a list of hosts in a group
+#===========================================================================
+if (!defined($host)) {
+ print "<title>Net-SNMP Host $host</title>\n";
+ print "<h2>Hosts in the group \"$group\":</h2>\n";
+ if (!isexpert($remuser)) {
+ print "<ul>\n";
+ if (isadmin($dbh, $remuser, $group)) {
+ my $q = self_url();
+ $q =~ s/\?.*//;
+ print "<li>Make sure you <a href=\"" . addtoken($q,"group=$group&setupgroup=1") . "\">set up the host</a> for the SNMP tables you want to monitor.\n";
+ }
+ print "<li>Click on a hostname to operate on or view the information tables associated with that group.\n";
+ print "<li>Click on a red status light below to list the problems found in with a particular host.\n";
+ print "</ul>\n";
+ }
+ displaytable($dbh, 'hostgroups',
+ '-notitle',0,
+ '-clauses', "where (groupname = '$group')",
+ '-select', 'distinct host, sysObjectId, sysDescr, sysUpTime, versionTag',
+ '-datalink', sub { my $q = self_url();
+ my $key = shift;
+ my $h = shift;
+ return if ($key ne "host");
+ return addtoken($q,"host=$h");
+ },
+ '-beginhook',
+ sub {
+ my $q = self_url();
+ my($dbh, $junk, $data) = @_;
+ if (!defined($data)) {
+ print "<th>Status</th>";
+ return;
+ }
+ if (checkhost($dbh, $group, $data->{'host'})) {
+ print "<td><a href=\"" . addtoken($q,"group=$group&summarizehost=1&host=$data->{host}") . "\"><img border=0 src=$NetSNMP::manager::redimage></a></td>\n";
+ } else {
+ print "<td><img src=$NetSNMP::manager::greenimage></td>\n";
+ }
+ }
+ );
+ if (isadmin($dbh, $remuser, $group)) {
+ addhostentryform($group);
+ my $q = self_url();
+ $q =~ s/\?.*//;
+ print "<a href=\"" . addtoken($q,"group=$group&setupgroup=1") . "\">setup group $group</a>\n";
+ }
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# setup the host's history records
+#===========================================================================
+if (param('setuphost')) {
+ print "<title>Net-SNMP history setup for host: $host</title>\n";
+ print "<h2>Net-SNMP history setup for the host: \"$host\"</h2>\n";
+ print "<p>Enter the number of days to keep the data for a given table for the host \"$host\":\n";
+ if (!isexpert($remuser)) {
+ print "<ul>\n";
+ print "<li>Numbers must be greater than or equal to 1 to enable history logging.\n";
+ print "</ul>\n";
+ }
+ print "<form method=post><input type=hidden name=setuphost value=1><input type=hidden name=host value=\"$host\"><input type=hidden name=group value=\"$group\">\n";
+ displaytable($dbh, 'hosttables',
+ '-clauses',"where host = '$host' and groupname = '$group'",
+ '-select','groupname, host, tablename, keephistory',
+ '-selectorder', 1,
+ '-notitle', 1,
+ '-editable', 1,
+ '-indexes', ['groupname','host','tablename'],
+ '-CGI', $CGI::Q
+ );
+ print "<input type=submit value=\"submit changes\">\n";
+ print "</form>\n";
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# display a huge table of history about something
+#===========================================================================
+if (param('displayhistory')) {
+ if (!isuser($dbh, $remuser, $group)) {
+ print "Unauthorized access to that group ($group)\n";
+ return Exit($dbh, $group);
+ }
+ displaytable($dbh, param('table'),
+ '-clauses', "where (host = '$host')",
+ '-dolink', \&linktodisplayinfo,
+ '-dontdisplaycol', "select * from userprefs where user = '$remuser' and groupname = '$group' and tablename = ? and columnname = ? and displayit = 'N'"
+ );
+ return Exit($dbh, $group);
+}
+
+#===========================================================================
+# display inforamation about a host
+# optionally add new collection tables
+#===========================================================================
+showhost($dbh, $host, $group, $remuser);
+if (isadmin($dbh, $remuser, $group)) {
+ if (param('newtables')) {
+ my $x = param('newtables');
+ $x =~ s/,/ /g;
+ if (/[^\w\s]/) {
+ print "<br>Illegal table names in addition list: $x<br>\n"
+ } else {
+ my @x = split(/\s+/,$x);
+ foreach my $i (@x) {
+ $dbh->do("insert into hosttables(host, groupname, tablename, keephistory) values('$host','$group','$i','0')");
+ }
+ print "<br>adding: ",join(", ",@x),"<br>\n";
+ }
+ } else {
+ print "<br>Add new MIB Tables or Groups that you want to collect for this host: <form><input type=hidden name=host value=\"$host\"><input type=hidden name=group value=\"$group\"><input name=\"newtables\" type=text><br><input type=submit value=\"add tables\"></form>\n";
+ }
+ my $q = self_url();
+ $q =~ s/\?.*//;
+ print "<a href=\"" . addtoken($q, "setuphost=1&host=$host&group=$group") . "\">setup host $host</a>\n";
+}
+return Exit($dbh, $group);
+
+#===========================================================================
+# END of handler
+#===========================================================================
+
+}
+
+# add a token to a url string. Use either a ? or an & depending on
+# existence of ?.
+sub addtoken {
+ my $url = shift;
+ my $token = shift;
+ return "$url&$token" if ($url =~ /\?/);
+ return "$url?$token";
+}
+
+#
+# summarizeerrors(DB-HANDLE, CLAUSE):
+# summarize the list of errors in a given CLAUSE
+#
+sub summarizeerrors {
+ my $dbh = shift;
+ my $clause = shift;
+ $clause = "where" if ($clause eq "");
+ my $clause2 = $clause;
+ $clause2 =~ s/ host / hosterrors.host /;
+
+ # Major errors
+ displaytable($dbh, 'hosterrors, hostgroups', # , hostgroups
+ '-select', "hosterrors.host as host, errormsg",
+ '-notitle', 1,
+ '-title', "Fatal Errors",
+ '-clauses', "$clause2 and hosterrors.host = hostgroups.host",
+ '-beginhook', sub {
+ if ($#_ < 2) {
+ #doing header;
+ print "<td></td>";
+ } else {
+ print "<td><img src=\"$NetSNMP::manager::redimage\"></td>\n";
+ }});
+
+ my $tabletop = "<br><table $NetSNMP::manager::tableparms><tr $NetSNMP::manager::headerparms><th><b>Host</b></th><th><b>Table</b></th><th><b>Description</b></th></tr>\n";
+ my $donetop = 0;
+ my $cursor =
+ getcursor($dbh, "SELECT * FROM hosttables $clause");
+
+ while (my $row = $cursor->fetchrow_hashref ) {
+
+ my $exprs = getcursor($dbh, "SELECT * FROM errorexpressions where (tablename = '$row->{tablename}')");
+
+ while (my $expr = $exprs->fetchrow_hashref ) {
+ my $errors = getcursor($dbh, "select * from $row->{tablename} where $expr->{expression} and host = '$row->{host}'");
+ while (my $error = $errors->fetchrow_hashref ) {
+ print $tabletop if ($donetop++ == 0);
+ print "<tr><td>$row->{host}</td><td>$row->{tablename}</td><td>$expr->{returnfield}: $error->{$expr->{returnfield}}</td></tr>";
+ }
+ }
+ }
+ print "</table>";
+}
+
+#
+# getcursor(CMD):
+# genericlly get a cursor for a given sql command, displaying and
+# printing errors where necessary.
+#
+sub getcursor {
+ my $dbh = shift;
+ my $cmd = shift;
+ my $cursor;
+ ( $cursor = $dbh->prepare( $cmd ))
+ or print "\nnot ok: $DBI::errstr\n";
+ ( $cursor->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+ return $cursor;
+}
+
+#
+# mykeysort($a, $b)
+# sorts $a and $b against the order in the mib or against the hard
+# coded special list.
+#
+sub mykeysort {
+ my $a = $displaytable::a;
+ my $b = $displaytable::b;
+ my $mb = $SNMP::MIB{SNMP::translateObj($b)};
+ my $ma = $SNMP::MIB{SNMP::translateObj($a)};
+
+ return $NetSNMP::manager::myorder{$a} <=> $NetSNMP::manager::myorder{$b} if ((defined($NetSNMP::manager::myorder{$a}) || !defined($ma->{'subID'})) && (defined($NetSNMP::manager::myorder{$b}) || !defined($mb->{'subID'})));
+ return 1 if (defined($NetSNMP::manager::myorder{$b}) || !defined($mb->{'subID'}));
+ return -1 if (defined($NetSNMP::manager::myorder{$a}) || !defined($ma->{'subID'}));
+
+ $ma->{'subID'} <=> $mb->{'subID'};
+}
+
+#
+# checkhost(GROUP, HOST):
+# if anything in a host is an error, as defined by the
+# errorexpressions table, return 1, else 0
+#
+sub checkhost {
+ my $dbh = shift;
+ my $group = shift;
+ my $host = shift;
+ my ($tblh);
+
+ return 2 if ($dbh->do("select * from hosterrors where host = '$host'") ne "0E0");
+
+ # get a list of tables we want to display
+ $tblh = getcursor($dbh, "SELECT * FROM hosttables where (host = '$host' and groupname = '$group')");
+
+ # table data
+ my($exprs, $tablelist);
+ while ( $tablelist = $tblh->fetchrow_hashref ) {
+ $exprs = getcursor($dbh, "SELECT * FROM errorexpressions where (tablename = '$tablelist->{tablename}')");
+ while(my $expr = $exprs->fetchrow_hashref) {
+ if ($dbh->do("select * from $tablelist->{tablename} where $expr->{expression} and host = '$host'") ne "0E0") {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+#
+# showhost(HOST):
+#
+# display all the tables monitored for a given host (in a group).
+#
+sub showhost {
+ my $dbh = shift;
+ my $host = shift;
+ my $group = shift;
+ my $remuser = shift;
+ my $q = self_url();
+ $q =~ s/\?.*//;
+ # host header
+ print "<title>Net-SNMP manager report for host: $host</title>\n";
+ print "<h2>Monitored information for the host $host</h2>\n";
+ if (!isexpert($remuser)) {
+ print "<ul>\n";
+ print "<li>Click on a column name for information about the data in that column.\n";
+ print "<li>Click on a column name or table name for information about the data in the table.\n";
+ print "<li>If you are <a href=\"" . addtoken($q, "setuphost=1&host=$host&group=$group") . "\">collecting past history</a> for a data set, links will appear below the table that allow you to view and/or graph the historic data.\n";
+ print "</ul>\n";
+ }
+
+ # does the host have a serious error?
+
+ my $errlist = getcursor($dbh, "SELECT * FROM hosterrors where (host = '$host')");
+ if ( $dbh->do("SELECT * FROM hosterrors where (host = '$host')") ne "0E0") {
+ displaytable($dbh, 'hosterrors',
+ '-clauses', "where (host = '$host')",
+ '-dontdisplaycol', "select * from userprefs where user = '$remuser' and groupname = '$group' and tablename = ? and columnname = ? and displayit = 'N'",
+ '-beginhook', sub {
+ if ($#_ < 2) {
+ #doing header;
+ print "<td></td>";
+ } else {
+ print "<td><img src=\"$NetSNMP::manager::redimage\"></td>\n";
+ }});
+ }
+
+ # get a list of tables we want to display
+ my $tblh = getcursor($dbh, "SELECT * FROM hosttables where (host = '$host' and groupname = '$group')");
+
+ # table data
+ my($tablelist);
+ while ( $tablelist = $tblh->fetchrow_hashref ) {
+
+ displaytable($dbh, $tablelist->{'tablename'},
+ '-clauses', "where (host = '$host') order by oidindex",
+ '-dontdisplaycol', "select * from userprefs where user = '$remuser' and groupname = '$group' and tablename = ? and columnname = ? and displayit = 'N'",
+ '-sort', \&mykeysort,
+ '-dolink', \&linktodisplayinfo,
+ '-beginhook', \&printredgreen);
+ if ($tablelist->{'keephistory'}) {
+ my $q = self_url();
+ $q =~ s/\?.*//;
+ print "history: ";
+ print "<a href=\"" . addtoken($q, "displayhistory=1&host=$host&group=$group&table=$tablelist->{'tablename'}hist") . "\">[table]</a>\n";
+ print "<a href=\"" . addtoken($q, "displaygraph=1&host=$host&group=$group&table=$tablelist->{'tablename'}hist") . "\">[graph]</a>\n";
+ print "<br>\n";
+ }
+ }
+}
+
+#
+# linktodisplayinfo(STRING):
+#
+# returns a url to the appropriate displayinfo link if STRING is a
+# mib node.
+#
+sub linktodisplayinfo {
+ return if (exists($NetSNMP::manager::myorder{shift}));
+ return self_url() . "&displayinfo=" . shift;
+}
+
+# printredgreen(TABLENAME, DATA):
+#
+# display a red or a green dot in a table dependent on the table's
+# values and associated expression
+#
+# DATA is NULL when in a header row (displaying header names).
+#
+sub printredgreen {
+ my $dbh = shift;
+ my $tablename = shift;
+ my $data = shift;
+ my ($exprs, $expr, $img);
+
+ if (!defined($data)) {
+ #doing header;
+ print "<td></td>";
+ return;
+ }
+
+ my $cmd = "SELECT * FROM errorexpressions where (tablename = '$tablename')";
+ print " $cmd\n" if ($NetSNMP::manager::verbose);
+ ( $exprs = $dbh->prepare( $cmd ) )
+ or die "\nnot ok: $DBI::errstr\n";
+ ( $exprs->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+
+ $img = $NetSNMP::manager::greenimage;
+ while($expr = $exprs->fetchrow_hashref) {
+ if ($dbh->do("select oidindex from $tablename where host = '$data->{host}' and oidindex = '$data->{oidindex}' and $expr->{expression}") ne "0E0") {
+ $img = $NetSNMP::manager::redimage;
+ }
+ }
+ print "<td><img src=$img></td>";
+}
+
+#
+# display information about a given mib node as a table.
+#
+sub makemibtable {
+ my $dispinfo = shift;
+ # display information about a data type in a table
+ my $mib = $SNMP::MIB{SNMP::translateObj($dispinfo)};
+ print "<table $NetSNMP::manager::tableparms><tr><td>\n";
+ foreach my $i (qw(label type access status units hint moduleID description enums)) {
+# foreach my $i (keys(%$mib)) {
+ next if (!defined($$mib{$i}) || $$mib{$i} eq "");
+ next if (ref($$mib{$i}) eq "HASH" && $#{keys(%{$$mib{$i}})} == -1);
+ print "<tr><td>$i</td><td>";
+ if (ref($$mib{$i}) eq "HASH") {
+ print "<table $NetSNMP::manager::tableparms><tr><td>\n";
+ foreach my $j (sort { $$mib{$i}{$a} <=> $$mib{$i}{$b} } keys(%{$$mib{$i}})) {
+ print "<tr><td>$$mib{$i}{$j}</td><td>$j</td></tr>";
+ }
+ print "</table>\n";
+ } else {
+ print "$$mib{$i}";
+ }
+ print "</td></tr>\n";
+ }
+ print "</table>\n";
+}
+
+# given a user, get all the groups he belongs to.
+sub getgroupsforuser {
+ my (@ret, $cursor, $row);
+ my ($dbh, $remuser) = @_;
+ ( $cursor = $dbh->prepare( "SELECT * FROM usergroups where (user = '$remuser')"))
+ or die "\nnot ok: $DBI::errstr\n";
+ ( $cursor->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+
+ while ( $row = $cursor->fetchrow_hashref ) {
+ push(@ret, $row->{'groupname'});
+ }
+ @ret;
+}
+
+# given a host, get all the groups it belongs to.
+sub gethostsforgroup {
+ my (@ret, $cursor, $row);
+ my ($dbh, $group) = @_;
+ ( $cursor = $dbh->prepare( "SELECT * FROM hostgroups where (groupname = '$group')"))
+ or die "\nnot ok: $DBI::errstr\n";
+ ( $cursor->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+
+ while ( $row = $cursor->fetchrow_hashref ) {
+ push(@ret, $row->{'host'});
+ }
+ @ret;
+}
+
+# display the host add entry box
+sub addhostentryform {
+ my $group = shift;
+ print "<form method=\"get\" action=\"" . self_url() . "\">\n";
+ print "Add a new host to the group \"$group\": <input type=\"text\" name=\"newhost\"><br>";
+ print "<input type=\"hidden\" name=\"group\" value=\"$group\">";
+ print "<input type=submit value=\"Add Hosts\">\n";
+ print "</form>";
+}
+
+#is an expert user?
+sub isexpert {
+ return 0;
+}
+
+#is remuser a admin?
+sub isadmin {
+ my ($dbh, $remuser, $group) = @_;
+ return 0 if (!defined($remuser) || !defined($group));
+ return 1 if ($dbh->do("select * from usergroups where user = '$remuser' and groupname = '$group' and isadmin = 'Y'") ne "0E0");
+ return 0;
+}
+
+#is user a member of this group?
+sub isuser {
+ my ($dbh, $remuser, $group) = @_;
+ return 0 if (!defined($remuser) || !defined($group));
+ return 1 if ($dbh->do("select * from usergroups where user = '$remuser' and groupname = '$group'") ne "0E0");
+ return 0;
+}
+
+# displayconfigarray(HOSTS, NAMES, CONFIG):
+#
+# displays an array of generic check buttons to turn on/off certain
+# variables.
+sub displayconfigarray {
+ my $dbh = shift;
+ my $hosts = shift;
+ my $names = shift;
+ my %config = @_;
+
+ my $cmd;
+ if ($config{'-check'}) {
+ ( $cmd = $dbh->prepare( $config{'-check'} ) )
+ or die "\nnot ok: $DBI::errstr\n";
+ }
+
+ print "<table $NetSNMP::manager::tableparms>\n";
+ print "<tr><td></td>";
+ my ($i, $j);
+ foreach $j (@$names) {
+ my $nj = $j;
+ $nj = $j->[0] if ($config{'-arrayrefs'} || $config{'-arrayref2'});
+ print "<td>$nj</td>";
+ }
+ foreach my $i (@$hosts) {
+ my $ni = $i;
+ $ni = $i->[0] if ($config{'-arrayrefs'} || $config{'-arrayref1'});
+ print "<tr><td>$ni</td>";
+ foreach $j (@$names) {
+ my $nj = $j;
+ $nj = $j->[0] if ($config{'-arrayrefs'} || $config{'-arrayref2'});
+ my $checked = "checked" if (defined($cmd) && $cmd->execute($ni,$nj) ne "0E0");
+ print "<td><input type=checkbox $checked value=y name=" . $config{prefix} . $ni . $nj . "></td>\n";
+ }
+ print "</tr>\n";
+ }
+ print "</tr>";
+ print "</table>";
+}
+
+sub adddefaulttables {
+ my ($dbh, $names) = @_;
+ my $row;
+ # add in known expression tables.
+ my $handle = getcursor($dbh, "SELECT * FROM errorexpressions");
+
+ expr:
+ while($row = $handle->fetchrow_hashref) {
+ foreach $i (@$names) {
+ if ($i->[0] eq $row->{tablename}) {
+ next expr;
+ }
+ }
+ push @$names, [$row->{tablename}];
+ }
+}
+
+#
+# display the setup information page for a given group.
+#
+sub setupgroup {
+ my $dbh = shift;
+ my $group = shift;
+
+ my ($hosts, $names) = gethostandgroups($dbh, $group);
+ adddefaulttables($dbh, $names);
+
+ print "<form method=\"post\" action=\"" . self_url() . "\">\n";
+ print "<input type=hidden text=\"setupgroupsubmit\" value=\"y\">";
+ displayconfigarray($dbh, $hosts, $names,
+ -arrayrefs, 1,
+ -check, "select * from hosttables where (host = ? and tablename = ? and groupname = '$group')");
+ print "<input type=hidden name=group value=\"$group\">\n";
+ print "<input type=submit value=submit name=\"setupgroupsubmit\">\n";
+ print "</form>";
+}
+
+# a wrapper around fetching arrays of everything in a table.
+sub getarrays {
+ my $dbh = shift;
+ my $table = shift;
+ my %config = @_;
+ my $selectwhat = $config{'-select'} || "*";
+ my $handle;
+
+ $handle = getcursor($dbh, "SELECT $selectwhat FROM $table $config{-clauses}");
+ return $handle->fetchall_arrayref;
+}
+
+#
+# get a list of all tablenames and hostnames for a given group.
+#
+sub gethostandgroups {
+ my $dbh = shift;
+ my $group = shift;
+ my ($tbnms);
+
+ my $names = getarrays($dbh, 'hosttables',
+ "-select", 'distinct tablename',
+ "-clauses", "where groupname = '$group'");
+
+ my $hosts = getarrays($dbh, 'hostgroups',
+ "-select", 'distinct host',
+ "-clauses", "where groupname = '$group'");
+
+ return ($hosts, $names);
+}
+
+sub setupgroupsubmit {
+ my $dbh = shift;
+ my $group = shift;
+
+ my ($hosts, $names) = gethostandgroups($dbh, $group);
+ adddefaulttables($dbh, $names);
+
+ foreach my $i (@$hosts) {
+ $dbh->do("delete from hosttables where host = '${$i}[0]' and groupname = '$group'");
+ }
+ my $rep = $dbh->prepare("insert into hosttables(host,tablename,groupname) values(?,?,'$group')");
+
+ foreach my $i (@$hosts) {
+ foreach my $j (@$names) {
+ if (param("${$i}[0]" . "${$j}[0]")) {
+ print "test: ","${$i}[0] : ${$j}[0]<br>\n";
+ $rep->execute("${$i}[0]", "${$j}[0]") || print "$! $DBI::errstr<br>\n";
+ }
+ }
+ }
+
+}
+
+#
+# save user pref data submitted by the user
+#
+sub setupusersubmit {
+ my ($dbh, $remuser, $group) = @_;
+ my $tables = getarrays($dbh, 'hosttables',
+ "-select", 'distinct tablename',
+ "-clauses", "where groupname = '$group'");
+
+ $dbh->do("delete from userprefs where user = '$remuser' and groupname = '$group'");
+ my $rep = $dbh->prepare("insert into userprefs(user, groupname, tablename, columnname, displayit) values('$remuser', '$group', ?, ?, 'N')");
+
+ my ($i, $j);
+ foreach my $i (@$tables) {
+ my $sth = $dbh->prepare("select * from ${$i}[0] where 1 = 0");
+ $sth->execute();
+
+ foreach $j (@{$sth->{NAME}}) {
+ if (param("${$i}[0]" . "$j")) {
+ $rep->execute("${$i}[0]", "$j");
+ }
+ }
+ }
+}
+
+sub Exit {
+ my ($dbh, $group) = @_;
+ my $tq = self_url();
+ $tq =~ s/\?.*//;
+ print "<hr>\n";
+ print "<a href=\"$tq\">[TOP]</a>\n";
+ print "<a href=\"$tq?userprefs=1&group=$group\">[display options]</a>\n";
+ print "<a href=\"$tq?setuponcall=1\">[setup oncall schedule]</a>\n";
+ if (defined($group)) {
+ print "<a href=\"$tq?group=$group\">[group: $group]</a>\n";
+ print "<a href=\"$tq?group=$group&summarizegroup=1\">[summarize errors]</a>\n";
+ }
+ $dbh->disconnect() if (defined($dbh));
+ return OK();
+# exit shift;
+}
+
+#
+# setup user preferences by displaying a configuration array of
+# checkbuttons for each table.
+#
+sub setupuserpreferences {
+ my ($dbh, $remuser, $group) = @_;
+ my $tables = getarrays($dbh, 'hosttables',
+ "-select", 'distinct tablename',
+ "-clauses", "where groupname = '$group'");
+
+ print "<h3>Select the columns from the tables that you want to <b>hide</b> below and click on submit:</h3>\n";
+ print "<form method=\"post\" action=\"" . self_url() . "\">\n";
+
+ my ($i, $j);
+ foreach my $i (@$tables) {
+ my $sth = $dbh->prepare("select * from ${$i}[0] where 1 = 0");
+ $sth->execute();
+ displayconfigarray($dbh, [${$i}[0]], $sth->{NAME},
+ -check, "select * from userprefs where (tablename = ? and columnname = ? and user = '$remuser' and groupname = '$group' and displayit = 'N')");
+ print "<br>\n";
+ }
+ print "<input type=hidden name=group value=\"$group\">\n";
+ print "<input type=submit value=submit name=\"setupuserprefssubmit\">\n";
+ print "</form>";
+}
diff --git a/perl/manager/red.gif b/perl/manager/red.gif
new file mode 100644
index 0000000..d2eb107
--- /dev/null
+++ b/perl/manager/red.gif
Binary files differ
diff --git a/perl/manager/setupauth b/perl/manager/setupauth
new file mode 100755
index 0000000..d10a62e
--- /dev/null
+++ b/perl/manager/setupauth
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+use DBI;
+$hostname = 'localhost'; # Host that serves the mSQL Database
+$dbname = 'snmp'; # mySQL Database name
+$doit = 1;
+
+sub usage {
+ print "$0 [-H host] [-u user] [-p password] [-v] [-h] [-n] [-g groupname] [-m machinename] TOKEN VALUE\n";
+ exit 0;
+}
+
+while ($#ARGV > -1 && $ARGV[0] =~ /^-/) {
+ $_ = shift @ARGV;
+ usage if (/-h/);
+ $hostname = shift if (/-H/);
+ $user = shift if (/-u/);
+ $pass = shift if (/-p/);
+ $group = shift if (/-g/);
+ $machine = shift if (/-m/);
+ $verbose = 1 if (/-v/);
+ $doit = 0 if (/-n/);
+}
+
+( $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$hostname", $user, $pass))
+ or die "\tConnect not ok: $DBI::errstr\n";
+
+if (defined($machine)) {
+ $table = "authhost";
+ $group = $machine;
+} else {
+ $table = "authgroup";
+ $group = "default" if (!defined($group));
+}
+
+$token = shift;
+$value = shift;
+while(defined($value)) {
+ if (DO("select * from $table where lookup = '$group' and varcol = '$token'") eq "0E0") {
+ DO("insert into $table(lookup, varcol, valcol) values('$group', '$token', '$value')");
+ } else {
+ DO("update $table set valcol = '$value' where lookup = '$group' and varcol = '$token'");
+ }
+ $token = shift;
+ $value = shift;
+}
+
+$dbh->disconnect();
+
+sub DO {
+ my $cmd = shift;
+ print $cmd,"\n" if ($verbose);
+ my $ret = $dbh->do($cmd) if ($doit);
+ print " returned: $ret\n" if ($verbose);
+ if ($DBI::errstr) {
+ print "db error ($ret): $DBI::errstr\n";
+ }
+ return $ret;
+}
diff --git a/perl/manager/setupdb b/perl/manager/setupdb
new file mode 100755
index 0000000..03066fd
--- /dev/null
+++ b/perl/manager/setupdb
@@ -0,0 +1,149 @@
+#!/usr/bin/perl
+
+use DBI;
+$hostname = 'localhost'; # Host that serves the mSQL Database
+$dbname = 'snmp'; # mySQL Database name
+$doit = 1;
+
+sub usage {
+ print "$0 [-H sqlhost] [-u user] [-p password] [-d] [-n]\n";
+ exit 0;
+}
+
+while ($#ARGV > -1 && $ARGV[0] =~ /^-/) {
+ $_ = shift @ARGV;
+ usage if (/-h/);
+ $hostname = shift if (/-H/);
+ $user = shift if (/-u/);
+ $pass = shift if (/-p/);
+ $delete = 1 if (/-d/);
+ $verbose = 1 if (/-v/);
+ $doit = 0 if (/-n/);
+}
+
+( $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$hostname", $user, $pass))
+ or die "\tConnect not ok: $DBI::errstr\n";
+
+# run a whole ton of setup stuff
+
+if ($delete) {
+ DO("drop database if exists $dbname");
+}
+
+# here we go
+
+DO("create database $dbname");
+DO("use $dbname");
+
+# tables dumped with
+#
+# mysqldump -d ... snmp TABLE | perl -n -e 'while(<>) { last if (/CREATE/);} print "DO(\"$_"; while (<>) { last if (/\);/); print; } print ")\");\n";'
+
+DO("CREATE TABLE hosterrors (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ host varchar(64),
+ errormsg varchar(128),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE hosttables (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ host varchar(64),
+ tablename varchar(64),
+ groupname varchar(32),
+ keephistory int(2),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE usergroups (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ user varchar(16),
+ groupname varchar(32),
+ isadmin enum('N','Y') DEFAULT 'N',
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE userprefs (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ user varchar(16),
+ groupname varchar(32),
+ tablename varchar(64),
+ columnname varchar(64),
+ displayit enum('N','Y') DEFAULT 'Y',
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE hostgroups (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ host varchar(64),
+ groupname varchar(32),
+ sysObjectId varchar(255),
+ sysDescr varchar(255),
+ versionTag varchar(32),
+ sysUpTime varchar(64),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE oncall (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ user varchar(16),
+ groupname varchar(32),
+ email varchar(64),
+ days varchar(64),
+ hours varchar(64),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE errorexpressions (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ tablename varchar(64),
+ expression varchar(255),
+ returnfield varchar(64),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE setup (
+ lookup varchar(64),
+ varcol varchar(128),
+ valcol varchar(128)
+)");
+
+DO("CREATE TABLE authgroup (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ lookup varchar(64),
+ varcol varchar(128),
+ valcol varchar(128),
+ PRIMARY KEY (id)
+)");
+
+DO("CREATE TABLE authhost (
+ id int(11) DEFAULT '0' NOT NULL auto_increment,
+ lookup varchar(64),
+ varcol varchar(128),
+ valcol varchar(128),
+ PRIMARY KEY (id)
+)");
+
+# insert the standard ucd-snmp expressions
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('prTable', 'prErrorFlag > 0', 'prErrMessage')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('extTable', 'extResult > 0', 'extOutput')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('dskTable', 'dskErrorFlag > 0', 'dskErrMessage')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('laTable', 'laErrorFlag > 0', 'laErrMessage')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('fileTable', 'fileErrorFlag > 0', 'fileErrMessage')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('snmperrs', 'snmperrErrorFlag > 0', 'snmperrErrMessage')");
+DO("insert into errorexpressions(tablename, expression, returnfield)
+ values('memory', 'memSwapError > 0', 'memSwapErrMessage')");
+
+$dbh->disconnect();
+
+sub DO {
+ my $cmd = shift;
+ print $cmd,"\n" if ($verbose);
+ $dbh->do($cmd) if ($doit);
+}
diff --git a/perl/manager/setupuser b/perl/manager/setupuser
new file mode 100755
index 0000000..84fbcac
--- /dev/null
+++ b/perl/manager/setupuser
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+
+use DBI;
+$hostname = 'localhost'; # Host that serves the mSQL Database
+$dbname = 'snmp'; # mySQL Database name
+$doit = 1;
+
+sub usage {
+ print "$0 [-H host] [-u user] [-p password] [-v] [-h] [-n] [-d] [-a] GROUP USER EMAILADDRESS\n";
+ exit 0;
+}
+
+while ($#ARGV > -1 && $ARGV[0] =~ /^-/) {
+ $_ = shift @ARGV;
+ usage if (/-h/);
+ $hostname = shift if (/-H/);
+ $sqluser = shift if (/-u/);
+ $pass = shift if (/-p/);
+ $admin = 1 if (/-a/);
+ $verbose = 1 if (/-v/);
+ $delete = 1 if (/-d/);
+ $doit = 0 if (/-n/);
+}
+
+($group, $user, $email) = @ARGV;
+
+die "group $group is a reserved group name, you can't use it. Sorry." if ($group eq "default");
+
+die "no group specified" if (!defined($group));
+
+( $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$hostname", $sqluser, $pass))
+ or die "\tConnect not ok: $DBI::errstr\n";
+
+DO("insert into usergroups(user, groupname, isadmin) values('$user', '$group', " . (($admin) ? "'Y'" : "'N'") . ")");
+if (defined($email)) {
+ DO("insert into oncall(user, groupname, email, days, hours) values('$user', '$group', '$email', '*', '*')");
+}
+
+$dbh->disconnect();
+
+sub DO {
+ my $cmd = shift;
+ print $cmd,"\n" if ($verbose);
+ $dbh->do($cmd) if ($doit);
+}
diff --git a/perl/manager/snmptosql b/perl/manager/snmptosql
new file mode 100755
index 0000000..ae51733
--- /dev/null
+++ b/perl/manager/snmptosql
@@ -0,0 +1,523 @@
+#!/usr/bin/perl
+
+use NetSNMP::manager::getValues qw(getValues);
+use SNMP;
+use DBI;
+use Net::SMTP;
+
+#===========================================================================
+# Global defines
+#===========================================================================
+
+$hostname = 'localhost'; # Host that serves the mSQL Database
+$dbname = 'snmp'; # mySQL Database name
+$smtpserver = 'localhost';
+$smtpfrom = 'Net-SNMP Manager <wjhardaker@ucdavis.edu>'; # <=== CHANGE ME ========
+$doit = 1;
+$somehosts = 0;
+
+sub usage {
+ print "$0 [-H host] [-u user] [-p password] [-l hostlist,...] [-v] [-h] [-n] [-d] [-m mib-to-load] <-m mibnode>\n";
+ exit 0;
+}
+
+while ($#ARGV > -1) {
+ $_ = shift @ARGV;
+ usage if (/-h/);
+ $hostname = shift if (/-H/);
+ if (/-l/) {
+ my $arg = shift;
+ my @a = split(/,/,$arg);
+ my $i;
+ $somehosts = 1;
+ foreach $i (@a) {
+ $dohost{$i} = 1;
+ }
+ }
+ $user = shift if (/-u/);
+ $pass = shift if (/-p/);
+ $verbose = 1 if (/-v/);
+ $delete = 1 if (/-d/);
+ $doit = 0 if (/-n/);
+ $tableexpr = shift if (/-t/);
+ if (/-m/) {
+ # load some mibs
+ # SNMP::loadModules(shift);
+ $ENV{'MIBS'} = shift;
+ }
+ if (/-M/) {
+ # add a mib directory to look in
+ $ENV{'MIBDIRS'} = shift;
+ # SNMP::addMibDirs(shift);
+ }
+}
+
+init_mib;
+
+#===========================================================================
+# Connect to the mSQL database with the appropriate driver
+( $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$hostname", $user, $pass))
+ or die "\tConnect not ok: $DBI::errstr\n";
+
+#
+# delete history rows every so often.
+#
+my %count = getValues($dbh, 'setup', 'deletecount');
+
+if (!defined($count{'max'})) {
+ # default is to delete history rows once an hour.
+ $dbh->do("insert into setup values('deletecount','max','6')");
+ $count{'max'} = 6;
+}
+
+if (!defined($count{'current'})) {
+ $dbh->do("insert into setup values('deletecount','current','0')");
+} else {
+ $count{'current'}++;
+ if ($count{'max'} <= $count{'current'}) {
+ $count{'current'} = 0;
+ $deletehist = 1;
+ }
+ $dbh->do("update setup set valcol = $count{'current'} where lookup = 'deletecount' and varcol = 'current'");
+}
+
+#===========================================================================
+# Get host records from database and process
+
+$cursor = getcursor("SELECT distinct host FROM hosttables");
+nexthost: while ( $hostrow = $cursor->fetchrow_hashref ) {
+
+ my $host = $hostrow->{'host'};
+
+ next if ($somehosts && !defined($dohost{$host}));
+
+ #set up the session
+ print STDERR " starting $host\n" if ($verbose);
+ my $x = $dbh->prepare("select groupname from hostgroups where host = '$host'");
+ my $y = $x->execute();
+ my $group = ${$x->fetchrow_hashref}{'groupname'};
+ my @args = ('authgroup','default');
+ print STDERR "$host...$y\n" if ($verbose);
+ if (defined($y) && "$y" ne "0E0") {
+ push @args,'authgroup',$group;
+ }
+ push @args,'authhost',$host;
+ print STDERR "$host: $group\n" if ($verbose);
+
+ print STDERR "authvals: ", join(", ", @args), "\n" if ($verbose);
+ my %authvals = getValues($dbh, @args);
+ if ($verbose) {
+ print STDERR "parms for $host:";
+ foreach my $i (keys(%authvals)) {
+ print STDERR "$i => $authvals{$i}, ";
+ }
+ print STDERR "\n";
+ }
+
+ my $sess = new SNMP::Session ( DestHost => $host,
+ UseSprintValue => 1,
+ %authvals );
+ print STDERR "Sess ($host): $sess, ref=" . ref($sess). "\n" if ($verbose);
+ if (ref ($sess) ne "SNMP::Session") {
+# print STDERR "ack: \$sess not a SNMP::Session for $host ($!)\n";
+ hosterror("$host");
+ next nexthost;
+ }
+
+ # get various bits of system information.
+ my $sysDescr = $sess->get('sysDescr.0');
+ my $sysId = SNMP::translateObj($sess->get('sysObjectID.0'));
+ my $versiontag = $sess->get('versionTag.0');
+ my $sysuptime = $sess->get('sysUpTime.0');
+
+ if ($sysDescr eq "" || $sysId eq "" || $versiontag eq "" ||
+ $sysuptime eq "") {
+ hosterror("$host","Problem collecting basic info");
+ next;
+ }
+
+ $dbh->do("update hostgroups set sysObjectId = '$sysId', sysDescr = '$sysDescr', versionTag = '$versiontag', sysUpTime = '$sysuptime' where host = '$host'");
+
+ # translate the sysUpTime to a real number for future use:
+ {
+ my ($d,$h,$m,$s,$fs) = ($sysuptime =~ /^(\d+):(\d+):(\d+):(\d+)\.(\d+)$/);
+ $sysuptime = $fs + $s*100 + $m*100*60 + $h*100*60*60 + $d*100*60*60*24;
+ }
+
+ # get a list of tables we want to store
+ $cmd = "SELECT * FROM hosttables where (host = '$host')";
+ print STDERR " $cmd\n" if ($verbose);
+ ( $tblh = $dbh->prepare( $cmd ) )
+ or warn "\nnot ok: $DBI::errstr\n";
+ ( $tblh->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+
+ while ( $tablelist = $tblh->fetchrow_hashref ) {
+ next if (defined($tableexpr) && $tablelist->{'tablename'} !~ /$tableexpr/);
+ print STDERR "starting table $tablelist->{'tablename'}\n" if ($verbose);
+ my $mib = $SNMP::MIB{SNMP::translateObj($tablelist->{'tablename'})};
+ if (!$mib) {
+ warn "mib node $tablelist->{'tablename'} doesn't exist";
+ next;
+ }
+ my $children = get_children($mib);
+
+ # create the table in our database if it doesn't exist.
+ setuptable($dbh, $tablelist->{tablename}, $delete);
+ if ($tablelist->{'keephistory'} > 0) {
+ setuptable($dbh, $tablelist->{tablename}, $delete, "hist");
+ }
+
+ $var =
+ new SNMP::Varbind([SNMP::translateObj($tablelist->{'tablename'})]);
+ my $void = SNMP::translateObj($tablelist->{'tablename'});
+ my $val = $sess->getnext($var);
+ print STDERR "init err: $sess->{'ErrorStr'}\n" if ($verbose);
+ if ($sess->{'ErrorStr'} =~ /Timeout/) {
+ print STDERR "$host timed out\n" if ($verbose);
+ hosterror($host);
+ next nexthost;
+ }
+ $initlabel = "";
+ print STDERR " starting $tablelist->{tablename}\n" if ($verbose);
+ my %tbl_ids;
+ while (1) {
+ my $varlabel = SNMP::Varbind::tag($var);
+ print STDERR "last $host " . SNMP::translateObj($varlabel) . ": $void\n" if ($verbose && SNMP::translateObj($varlabel) !~ /^$void/);
+
+ last if (SNMP::translateObj($varlabel) !~ /^$void/);
+ $varlabel = SNMP::translateObj(SNMP::Varbind::tag($var)) if ($varlabel =~ /^[\.0-9]+$/);
+ $initlabel = $varlabel if ($initlabel eq "");
+
+ my $val = $sess->getnext($var);
+ if ($sess->{'ErrorStr'} =~ /Timeout/) {
+ print STDERR "$host timed out\n" if ($verbose);
+ hosterror($host);
+ next nexthost;
+ }
+ last if ($sess->{'ErrorStr'});
+ my $id = SNMP::Varbind::iid($var);
+ print STDERR "$initlabel = $varlabel\n" if ($verbose);
+ last if ($varlabel ne $initlabel);
+ my %vals;
+ $tbl_ids{$id} = 1;
+ foreach $c (@$children) {
+ my $oid = $$c{'objectID'} . "." . $id;
+ my $newvar = new SNMP::Varbind([$oid]);
+ my $val = $sess->get($newvar);
+ my $label = SNMP::translateObj($$c{'objectID'});
+ $vals{$label} = $val;
+ }
+ my $cmd;
+
+ # check to see if the error previously existed and then
+ # delete the old entry.
+ my $olderr =
+ checkrowforerrors($tablelist->{'tablename'}, $host, $id);
+ $dbh->do("delete from $tablelist->{tablename} where ( host = '$host' and oidindex = '$id')");
+ $res = $dbh->do("select * from $tablelist->{'tablename'} where ( host = '$host' and oidindex = '$id')");
+ print STDERR " result: $res\n" if ($verbose);
+ if ($res ne "0E0") {
+ $cmd = "update $tablelist->{'tablename'} set ";
+ foreach $h (keys(%vals)) {
+ $cmd .= "$h = '$vals{$h}', ";
+ }
+ $cmd .= " updated = NULL where (host = '$host' and oidindex = '$id')";
+
+ } else {
+ $cmd = "insert into $tablelist->{'tablename'}(host, oidindex, " . join(", ",keys(%vals)) .
+ ") values('$host', '$id', '" .
+ join("', '",values(%vals)). "')";
+ }
+
+ print STDERR " $cmd\n" if ($verbose);
+ $dbh->do("$cmd")
+ or warn "\nnot ok: $cmd => $DBI::errstr\n" if ($doit);
+
+ if ($tablelist->{'keephistory'} > 0) {
+ $cmd = "insert into $tablelist->{'tablename'}hist (host, oidindex, sysUpTime, "
+ . join(", ",keys(%vals))
+ . ") values('$host', '$id', $sysuptime, '"
+ . join("', '",values(%vals)). "')";
+ print STDERR " $cmd\n" if ($verbose);
+ $dbh->do("$cmd")
+ or warn "\nnot ok: $cmd -> $DBI::errstr\n" if ($doit);
+
+ }
+
+ my $newerr =
+ checkrowforerrors($tablelist->{'tablename'}, $host, $id);
+ if ($newerr->{retval} != $olderr->{retval}) {
+ logerror($host, $newerr->{retval}, $newerr->{errfield},
+ $newerr->{errvalue});
+ }
+ } # snmp loop
+
+ # delete the data beyond the number of days requested.
+ if ($deletehist && $tablelist->{'keephistory'} > 0) {
+ $dbh->do("delete from $tablelist->{'tablename'}hist where (unix_timestamp() - unix_timestamp(updated)) > $tablelist->{'keephistory'}*24*60*60 and host = '$host'") or warn "\nnot ok: $DBI::errstr\n" if ($doit);
+ }
+
+ my $curs = getcursor("select oidindex from $tablelist->{tablename} where host = '$host'");
+ my $row;
+ while ($row = $curs->fetchrow_hashref) {
+ print STDERR " $row->{oidindex}\n" if ($verbose);
+ if (!defined($tbl_ids{$row->{oidindex}})) {
+ $dbh->do("delete from $tablelist->{tablename} where oidindex = '$row->{oidindex}'");
+ print STDERR "deleting: $host $tablelist->{tablename} $row->{oidindex}\n" if ($verbose);
+ }
+ }
+ print STDERR " done with $tablelist->{tablename}\n" if ($verbose);
+ } # table loop
+
+ if (isbadhost($host)) {
+ # let them out, they're no longer being bad.
+ print STDERR "deleting: delete from hosterrors where host = '$host'\n" if ($verbose);
+ $dbh->do("delete from hosterrors where host = '$host'");
+ mailusers("$host responding again", "$host responding again",
+ getoncallforhost($host));
+ }
+ print STDERR " done with $host\n" if ($verbose);
+} # host loop
+
+# disconnect
+$cursor->finish();
+$dbh->disconnect();
+
+#
+# Subroutines
+#
+
+# setup a table in the database based on a MIB table.
+sub setuptable {
+
+ my %conversions = qw(INTEGER integer INTEGER32 integer OCTETSTR varchar(254) COUNTER integer UINTEGER integer IPADDR varchar(254) OBJECTID varchar(254) GAGUE integer OPAQUE varchar(254) TICKS integer GAUGE integer);
+
+ # set up mib info
+ my ($dbh, $mibnode, $delete, $suffix) = @_;
+
+ my $mib = $SNMP::MIB{SNMP::translateObj($mibnode)};
+ my $children = get_children($mib);
+ my ($cmd, $j);
+
+ if ($delete) {
+ $cmd = "drop table if exists $mib->{label}";
+ print STDERR "cmd: $cmd\n" if ($verbose);
+ $dbh->do($cmd)
+ or warn "\nnot ok: $cmd -> $DBI::errstr\n" if ($doit);
+ } elsif (($ret = $dbh->do("show tables like '$mib->{label}$suffix'")) ne "0E0") {
+ # the table already exists
+ return;
+ }
+
+ print STDERR "show tables like $mib->{label}$suffix: $ret\n" if($verbose);
+ print STDERR " creating table for $mibnode ($mib->{label}$suffix)\n" if ($verbose);
+
+ $cmd = "create table $mib->{label}$suffix (id integer auto_increment primary key, host varchar(32) not null, oidindex varchar(32) not null";
+ foreach $j (sort { $a->{'subID'} <=> $b->{'subID'} } @$children) {
+ if (!defined($conversions{$j->{type}})) {
+ print STDERR "no conversion for $j->{label} = ". $j->{type} . "!\n";
+ return;
+ }
+ $cmd .= ", $j->{label} $conversions{$j->{type}}";
+ }
+ $cmd .= ", updated timestamp";
+ $cmd .= ", sysUpTime integer" if (defined($suffix));
+ $cmd .= ",key oidindex (oidindex), key host (host))";
+
+ print STDERR "cmd: $cmd\n" if ($verbose);
+ $dbh->do("$cmd")
+ or warn "\nnot ok: $cmd -> $DBI::errstr\n" if ($doit);
+
+}
+
+sub getoncall {
+ my @groups = @_;
+ my $cur;
+ my $row;
+ my ($emails, @days, @hours, @two, $i);
+ my %dayscon = qw(Sun 0 Mon 1 Tue 2 Wed 3 Thu 4 Fri 5 Sat 6);
+ my @now = localtime(time());
+ my %people;
+ my $group;
+
+ foreach $group (@groups) {
+ $cur = getcursor("select * from oncall where groupname = '$group'");
+ row: while ( $row = $cur->fetchrow_hashref ) {
+ @days = split(/,/,$row->{'days'});
+ foreach $i (@days) {
+ @two = split(/-/,$i);
+ if ($row->{'days'} eq "*" ||
+ (defined($dayscon{$i}) && $dayscon{$i} == $now[6]) ||
+ (defined($dayscon{$two[0]}) && defined($dayscon{$two[1]}) &&
+ (($dayscon{$two[0]} <= $now[6] &&
+ $dayscon{$two[1]} >= $now[6]) ||
+ (($dayscon{$two[0]} > $dayscon{$two[1]}) &&
+ ($dayscon{$two[0]} <= $now[6] ||
+ $dayscon{$two[1]} >= $now[6]))))) {
+ # we hit a valid day range
+ print STDERR " hit it $row->{'email'} $now[6]\t($i)\t$row->{'days'}\n"
+ if ($verbose);
+ $people{$row->{'email'}} = $row->{'email'};
+ } else {
+ print STDERR "not hit it $row->{'email'} $now[6]\t($i)\t$row->{'days'}\n"
+ if ($verbose);
+ }
+ }
+ }
+ }
+ return keys(%people);
+}
+
+sub getoncallforhost {
+ my $host = shift;
+ return getoncall(getgroupsforhost($host));
+}
+
+sub getcursor {
+ my $cmd = shift;
+ my $cursor;
+ print STDERR "cmd: $cmd\n" if ($verbose);
+ ( $cursor = $dbh->prepare( $cmd ))
+ or die "\nnot ok: $DBI::errstr\n";
+ ( $cursor->execute )
+ or print( "\tnot ok: $DBI::errstr\n" );
+ return $cursor;
+}
+
+my %expressions;
+sub getexpr {
+ my $table = shift;
+ print "ref: ",ref($expressions{$table}),"\n" if ($verbose);
+ if (!defined($expressions{$table})) {
+ my $exprs = getcursor("SELECT * FROM errorexpressions where (tablename = '$table')");
+ while ( $expr = $exprs->fetchrow_hashref ) {
+ push @{$expressions{$table}{'expr'}},$expr->{expression};
+ push @{$expressions{$table}{'returnfield'}},$expr->{returnfield};
+ }
+ }
+ if (ref($expressions{$table}) ne "HASH") {
+ # no expressions for this table.
+ $expressions{$table}{'expr'} = [];
+ $expressions{$table}{'returnfield'} = [];
+ }
+ return $expressions{$table};
+}
+
+sub checkrowforerrors {
+ my ($table, $host, $id) = @_;
+ my $error;
+
+ my $lastres = 0, $lastfield = '';
+ my $expressions = getexpr($table);
+ my $i;
+ for($i=0; $i <= $#{$expressions->{'expr'}}; $i++) {
+ if (!defined($expressions->{'prepared'}[$i])) {
+ $expressions->{'prepared'}[$i] = $dbh->prepare("select * from $table where $expressions->{'expr'}[$i] and host = ? and oidindex = ?")
+ or warn "\nnot ok: $DBI::errstr\n";
+ print STDERR "preparing select * from $table where $expressions->{'expr'}[$i] and host = ? and oidindex = ? ==> ",ref($expressions->{'prepared'}[$i]),"\n" if($verbose);
+ }
+ my $prepared = $expressions->{'prepared'}[$i];
+ print STDERR "x: ",ref($prepared),"\n" if($verbose);
+ $prepared->execute($host, $id) or warn "\nnot ok: $DBI::errstr\n";
+ while ( $error = $prepared->fetchrow_hashref ) {
+ print STDERR "$host: $expressions->{returnfield}[$i] = $error->{$expressions->{returnfield}[$i]}\n" if ($verbose);
+ return {'retval', 1,
+ 'errfield', $expressions->{returnfield}[$i],
+ 'errvalue', $error->{$expressions->{returnfield}[$i]}};
+ }
+ $lastres = $error->{$expressions->{returnfield}[$i]};
+ $lastfield = $expressions->{returnfield}[$i];
+ }
+ return {'retval', 0,
+ 'errfield', $lastfield,
+ 'errvalue', $lastres};
+}
+
+sub logerror {
+ my ($host, $err, $field, $result) = @_;
+ my $groups = getcursor("SELECT distinct groupname FROM hosttables where host = '$host'");
+ my ($group, $person);
+ my $msg = (($err) ? "error" : "normal");
+
+ my @people = getoncallforhost($host);
+ $msg = "$msg: $host";
+ $msg .= " $field = $result" if ($field || $result);
+ mailusers("SNMP: $msg: $host $field", "$msg\n", @people);
+}
+
+sub mailusers {
+ my $subject = shift;
+ my $msg = shift;
+ my @people = @_;
+ my $person;
+ my $smtpsock = Net::SMTP->new($smtpserver);
+
+ $smtpsock->mail($smtpfrom);
+ my $error = $smtpsock->recipient(@people);
+ if (!$error) {
+ print STDERR "failed to send mail to ",join(",",@people),"\n";
+ }
+ $smtpsock->data();
+ $subject =~ s/\n//;
+ $smtpsock->datasend("To: " . join(", ",@people) . "\n");
+ $smtpsock->datasend("From: $smtpfrom\n");
+ $smtpsock->datasend("Subject: $subject\n");
+ $smtpsock->datasend("\n");
+ $smtpsock->datasend("$msg\n");
+ $smtpsock->dataend();
+ $smtpsock->quit;
+ print STDERR "mailed ",join(",",@people)," with $msg, $subject ($!)\n" if ($verbose);
+}
+
+sub hosterror {
+ my $host = shift;
+ my $error = shift || "No response";
+ my $groups = getcursor("SELECT distinct groupname FROM hosttables where host = '$host'");
+ my ($group, $person);
+ my %mailed;
+
+ return if (isbadhost($host)); # only send out a message once.
+
+ $dbh->do("insert into hosterrors(host, errormsg) values('$host','$error');");
+ my @people = getoncallforhost($host);
+ mailusers("No Response from $host", "$host: $error", @people);
+}
+
+sub isbadhost {
+ my $host = shift;
+ my $hosterr = getcursor("SELECT distinct host FROM hosterrors where host = '$host'");
+ if ($hosterr->fetchrow_hashref) {
+ return 1;
+ }
+ return 0;
+}
+
+sub getgroupsforhost {
+ my $host = shift;
+ my @retgroups;
+ my $groups = getcursor("SELECT distinct groupname FROM hosttables where host = '$host'");
+ while( $group = $groups->fetchrow_hashref ) {
+ push @retgroups,$group->{'groupname'};
+ }
+ @retgroups;
+}
+
+sub get_children {
+ my $mib = shift;
+ my $children = $$mib{'children'};
+ if (ref($children) ne "ARRAY") {
+ warn "$mib has no chlidren";
+ return;
+ }
+
+ if ($#{$children} == 0 && $mib->{'label'} =~ /Table$/) {
+ # is a table, use entry?
+ $children = $children->[0]{'children'};
+ if (ref($children) ne "ARRAY") {
+ warn "$mib has no chlidren";
+ return;
+ }
+ }
+ return $children;
+}