diff options
Diffstat (limited to 'perl')
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, + '""' => \"e_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 *) <mp, 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 *) <mp, 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 " "; + } + } + 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/\"/"/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 Binary files differnew file mode 100644 index 0000000..b63716d --- /dev/null +++ b/perl/manager/green.gif 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 Binary files differnew file mode 100644 index 0000000..d2eb107 --- /dev/null +++ b/perl/manager/red.gif 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; +} |