| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
1
|
|
|
1
|
|
549
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
51
|
|
|
2
|
|
|
|
|
|
|
package NSNMP::Simple; |
|
3
|
|
|
|
|
|
|
# Copyright (c) 2003-2004 AirWave Wireless, Inc. |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# Redistribution and use in source and binary forms, with or without |
|
6
|
|
|
|
|
|
|
# modification, are permitted provided that the following conditions |
|
7
|
|
|
|
|
|
|
# are met: |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# 1. Redistributions of source code must retain the above |
|
10
|
|
|
|
|
|
|
# copyright notice, this list of conditions and the following |
|
11
|
|
|
|
|
|
|
# disclaimer. |
|
12
|
|
|
|
|
|
|
# 2. Redistributions in binary form must reproduce the above |
|
13
|
|
|
|
|
|
|
# copyright notice, this list of conditions and the following |
|
14
|
|
|
|
|
|
|
# disclaimer in the documentation and/or other materials provided |
|
15
|
|
|
|
|
|
|
# with the distribution. |
|
16
|
|
|
|
|
|
|
# 3. The name of the author may not be used to endorse or |
|
17
|
|
|
|
|
|
|
# promote products derived from this software without specific |
|
18
|
|
|
|
|
|
|
# prior written permission. |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
|
21
|
|
|
|
|
|
|
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
22
|
|
|
|
|
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23
|
|
|
|
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|
24
|
|
|
|
|
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
25
|
|
|
|
|
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
|
26
|
|
|
|
|
|
|
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
27
|
|
|
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
28
|
|
|
|
|
|
|
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
29
|
|
|
|
|
|
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
30
|
|
|
|
|
|
|
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31
|
1
|
|
|
1
|
|
952
|
use IO::Socket; |
|
|
1
|
|
|
|
|
35310
|
|
|
|
1
|
|
|
|
|
41
|
|
|
32
|
1
|
|
|
1
|
|
643
|
use NSNMP; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
25
|
|
|
33
|
1
|
|
|
1
|
|
7
|
use NSNMP::Mapper; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
25
|
|
|
34
|
1
|
|
|
1
|
|
5
|
use vars qw($error $error_status $socket); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
66
|
|
|
35
|
|
|
|
|
|
|
# these are negative so as not to collide with SNMP protocol error numbers, |
|
36
|
|
|
|
|
|
|
# which count up from 1 |
|
37
|
1
|
|
|
1
|
|
6
|
use constant noResponse => -1; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
61
|
|
|
38
|
1
|
|
|
1
|
|
28
|
use constant badHostName => -2; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1415
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 NAME |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
NSNMP::Simple - simple interface to get and set synchronously |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $sysnameoid = '1.3.6.1.2.1.1.5.0'; |
|
47
|
|
|
|
|
|
|
my $hostname = NSNMP::Simple->get('127.0.0.1', $sysnameoid); |
|
48
|
|
|
|
|
|
|
die $NSNMP::Simple::error unless defined $hostname; |
|
49
|
|
|
|
|
|
|
NSNMP::Simple->set('127.0.0.1', $sysnameoid, NSNMP::OCTET_STRING, |
|
50
|
|
|
|
|
|
|
'thor.cs.cmu.edu', community => 'CMUprivate') |
|
51
|
|
|
|
|
|
|
or die $NSNMP::Simple::error; |
|
52
|
|
|
|
|
|
|
my %sysoids = NSNMP::Simple->get_table('127.0.0.1', '1.3.6.1.2.1'); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
NSNMP::Simple lets you get or set a single OID via SNMP with a single |
|
57
|
|
|
|
|
|
|
line of code. It's easier to use, and roughly an order of magnitude |
|
58
|
|
|
|
|
|
|
faster, than L 4.1.2, but Net::SNMP is still much |
|
59
|
|
|
|
|
|
|
more mature and complete. I don't presently recommend using |
|
60
|
|
|
|
|
|
|
NSNMP::Simple in production code. |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 MODULE CONTENTS |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# some speed costs on my 500MHz PIII laptop: |
|
67
|
|
|
|
|
|
|
# it takes: |
|
68
|
|
|
|
|
|
|
# 3 microseconds to do a function call and return |
|
69
|
|
|
|
|
|
|
# 2 microseconds to do a hash lookup on a 20char string |
|
70
|
|
|
|
|
|
|
# 50 microseconds in the kernel to send a packet and receive a response |
|
71
|
|
|
|
|
|
|
# 600 microseconds to encode the packet, send it, and receive and |
|
72
|
|
|
|
|
|
|
# decode the response (in user time) (getsysname-lots.pl) |
|
73
|
|
|
|
|
|
|
# 150 microseconds to do the socket, address, timeout, and error-status |
|
74
|
|
|
|
|
|
|
# checking |
|
75
|
|
|
|
|
|
|
# this module does |
|
76
|
|
|
|
|
|
|
# another 40 microseconds to do the request_id handling (in the normal case: |
|
77
|
|
|
|
|
|
|
# request ID matches) |
|
78
|
|
|
|
|
|
|
# a negligible amount of time to handle retry logic |
|
79
|
|
|
|
|
|
|
# encoding and decoding of non-OCTET_STRING values |
|
80
|
|
|
|
|
|
|
# all in all: about 1250 microseconds per request-response pair with this |
|
81
|
|
|
|
|
|
|
# module |
|
82
|
|
|
|
|
|
|
# although I still haven't implemented traps, v2 and v3, and handling of |
|
83
|
|
|
|
|
|
|
# failure to socket; all of these will slow this module down more. |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# XXX refactor this a little more |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
my ($nfound, $timeleft); |
|
88
|
|
|
|
|
|
|
sub _read_timeout { |
|
89
|
717
|
|
|
717
|
|
977
|
my ($fh, $timeout) = @_; |
|
90
|
717
|
|
|
|
|
840
|
my $rin = ''; |
|
91
|
717
|
|
|
|
|
3088
|
vec($rin, fileno($fh), 1) = 1; |
|
92
|
717
|
|
|
|
|
12696625
|
return select($rin, undef, undef, $timeout); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub _remember_error { |
|
96
|
13
|
|
|
13
|
|
22
|
my ($response_decoded) = @_; |
|
97
|
13
|
|
|
|
|
38
|
$error_status = $response_decoded->error_status; |
|
98
|
13
|
|
|
|
|
104
|
my $error_name = NSNMP->error_description($error_status); |
|
99
|
13
|
|
|
|
|
76
|
$error = "Received $error_name($error_status) error-status at error-index " |
|
100
|
|
|
|
|
|
|
. $response_decoded->error_index; |
|
101
|
13
|
|
|
|
|
102
|
return undef; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $request_id = 'aaaa'; |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $response; |
|
107
|
|
|
|
|
|
|
sub _synchronous_request_response { |
|
108
|
705
|
|
|
705
|
|
2736
|
my ($host, %args) = @_; |
|
109
|
705
|
|
66
|
|
|
1810
|
$socket ||= IO::Socket::INET->new(Proto => 'udp'); # XXX error check |
|
110
|
705
|
|
|
|
|
1571
|
my $port = 161; # XXX test |
|
111
|
705
|
100
|
|
|
|
5337
|
$port = $1 if $host =~ s/:(\d+)\z//; |
|
112
|
705
|
|
|
|
|
153210
|
my $iaddr = Socket::inet_aton($host); |
|
113
|
705
|
100
|
|
|
|
2523
|
if (not defined $iaddr) { |
|
114
|
2
|
|
|
|
|
31
|
$error = "Unable to resolve destination address '$host'"; |
|
115
|
2
|
|
|
|
|
19
|
$error_status = badHostName; |
|
116
|
2
|
|
|
|
|
14
|
return undef; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# This method of picking request IDs has the following nice properties: |
|
120
|
|
|
|
|
|
|
# - there are 450 000 request IDs available |
|
121
|
|
|
|
|
|
|
# - they're always positive, so if they get sign-extended, it's always |
|
122
|
|
|
|
|
|
|
# with 0s |
|
123
|
|
|
|
|
|
|
# - they can never be represented in less than 4 bytes |
|
124
|
|
|
|
|
|
|
# - it's relatively fast |
|
125
|
703
|
|
|
|
|
1177
|
$request_id++; |
|
126
|
703
|
50
|
|
|
|
1857
|
$request_id = substr($request_id, 1) if length($request_id) > 4; |
|
127
|
|
|
|
|
|
|
|
|
128
|
703
|
100
|
|
|
|
2112
|
my $tries = 1 + (exists $args{retries} ? $args{retries} : 1); |
|
129
|
703
|
|
|
|
|
1856
|
try: while ($tries--) { |
|
130
|
709
|
|
|
|
|
4120
|
send $socket, NSNMP->encode(request_id => $request_id, %args), 0, |
|
131
|
|
|
|
|
|
|
scalar Socket::sockaddr_in($port, $iaddr); # XXX err handling: bad port? |
|
132
|
|
|
|
|
|
|
|
|
133
|
709
|
100
|
|
|
|
142983
|
my $timeout = (exists $args{timeout} ? $args{timeout} : 5); |
|
134
|
709
|
|
|
|
|
949
|
for (;;) { |
|
135
|
|
|
|
|
|
|
# perldoc -f select says, "Most systems do not bother to return |
|
136
|
|
|
|
|
|
|
# anything useful in $timeleft." Well, Linux 2.4 does; so if |
|
137
|
|
|
|
|
|
|
# you're using something that doesn't, upgrade. |
|
138
|
717
|
|
|
|
|
1852
|
((my $success), $timeout) = _read_timeout($socket, $timeout); |
|
139
|
717
|
100
|
|
|
|
2395
|
next try unless $success; |
|
140
|
|
|
|
|
|
|
|
|
141
|
704
|
|
|
|
|
3101
|
$socket->recv($response, 65536, 0); # XXX error handling? |
|
142
|
704
|
|
|
|
|
18670
|
my $resp_decoded = NSNMP->decode($response); |
|
143
|
704
|
100
|
100
|
|
|
9661
|
if (not $resp_decoded or $resp_decoded->request_id ne $request_id |
|
|
|
|
66
|
|
|
|
|
|
144
|
|
|
|
|
|
|
and $resp_decoded->request_id !~ /\A\0+\Q$request_id\E\z/) { |
|
145
|
|
|
|
|
|
|
# ignore it |
|
146
|
8
|
|
|
|
|
41
|
next; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
696
|
100
|
|
|
|
1984
|
return _remember_error($resp_decoded) if $resp_decoded->error_status; |
|
149
|
683
|
|
|
|
|
1096
|
($error, $error_status) = (undef, undef); |
|
150
|
683
|
|
|
|
|
2584
|
return $resp_decoded; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
} |
|
153
|
7
|
|
|
|
|
85
|
($error, $error_status) = |
|
154
|
|
|
|
|
|
|
("No response from remote host '$host'", noResponse); |
|
155
|
7
|
|
|
|
|
210
|
return undef; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub decode_int { |
|
159
|
40
|
|
|
40
|
0
|
80
|
my ($intstr) = @_; |
|
160
|
40
|
100
|
|
|
|
153
|
my $padchar = ("\0" eq ($intstr & "\x80")) ? "\0" : "\377"; |
|
161
|
40
|
100
|
|
|
|
129
|
$intstr = substr($intstr, length($intstr) - 4) if length($intstr) > 4; |
|
162
|
40
|
|
|
|
|
103
|
my $padded = $padchar x (4 - length($intstr)) . $intstr; |
|
163
|
40
|
|
|
|
|
820
|
my $num = unpack "N", $padded; |
|
164
|
40
|
100
|
|
|
|
153
|
$num -= 4294967296 if $padchar ne "\0"; # unpack gave us unsigned |
|
165
|
40
|
|
|
|
|
424
|
return $num; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
my %decoders = ( |
|
169
|
|
|
|
|
|
|
NSNMP::INTEGER => \&decode_int, |
|
170
|
|
|
|
|
|
|
NSNMP::Counter32 => \&decode_int, |
|
171
|
|
|
|
|
|
|
NSNMP::Gauge32 => \&decode_int, |
|
172
|
|
|
|
|
|
|
NSNMP::TimeTicks => \&decode_int, |
|
173
|
|
|
|
|
|
|
NSNMP::OCTET_STRING => sub { $_[0] }, |
|
174
|
|
|
|
|
|
|
NSNMP::IpAddress => sub { join '.', unpack "C*", $_[0] }, |
|
175
|
|
|
|
|
|
|
NSNMP::OBJECT_IDENTIFIER => sub { NSNMP->decode_oid($_[0]) }, |
|
176
|
|
|
|
|
|
|
); |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub encode_int { |
|
179
|
11
|
|
|
11
|
0
|
158
|
my ($int) = @_; |
|
180
|
11
|
|
|
|
|
29
|
my $rv = pack "N", $int; |
|
181
|
11
|
100
|
100
|
|
|
517
|
return "\0$rv" if $int >= 0 and (($rv & "\x80") ne "\00"); |
|
182
|
10
|
|
|
|
|
361
|
return $rv; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
my %encoders = ( |
|
186
|
|
|
|
|
|
|
NSNMP::INTEGER => \&encode_int, |
|
187
|
|
|
|
|
|
|
NSNMP::Counter32 => \&encode_int, # XXX test |
|
188
|
|
|
|
|
|
|
NSNMP::Gauge32 => \&encode_int, |
|
189
|
|
|
|
|
|
|
NSNMP::TimeTicks => \&encode_int, # XXX test |
|
190
|
|
|
|
|
|
|
NSNMP::OCTET_STRING => sub { $_[0] }, |
|
191
|
|
|
|
|
|
|
NSNMP::IpAddress => sub { pack "C*", split /\./, $_[0] }, |
|
192
|
|
|
|
|
|
|
NSNMP::OBJECT_IDENTIFIER => sub { NSNMP->encode_oid($_[0]) }, # XXX test |
|
193
|
|
|
|
|
|
|
); |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 NSNMP::Simple->get($agent, $oid, %args) |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Returns the value of C<$oid> on the SNMP agent at C<$agent>, which can |
|
198
|
|
|
|
|
|
|
be a hostname or an IP address, optionally followed by a colon and a |
|
199
|
|
|
|
|
|
|
numeric port number, which defaults to 161, the default SNMP port. |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
C<%args> can contain any or all of the following: |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=over |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=item C $ver> |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
$ver is an SNMP version number (1 or 2 --- 3 isn't yet supported --- |
|
208
|
|
|
|
|
|
|
see L). Default is 1. |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=item C $comm> |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Specifies the community string. Default is C. |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=item C $retries> |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Specifies retries. Default is 1 --- that is, two tries. Retries are |
|
217
|
|
|
|
|
|
|
evenly spaced. |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item C $timeout> |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Specifies a timeout in (possibly fractional) seconds. Default is 5.0. |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=back |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Translates the value of C<$oid> into a Perlish value, so, for example, |
|
226
|
|
|
|
|
|
|
an INTEGER OID whose value is 1 will be returned as "1", not "\001". |
|
227
|
|
|
|
|
|
|
IpAddresses are translated to dotted-quad notation, integer-like types |
|
228
|
|
|
|
|
|
|
are translated to integers, and OCTET STRINGS, OPAQUES, and |
|
229
|
|
|
|
|
|
|
NsapAddresses are left alone. |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
It doesn't return the type of the value at all. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
In case of failure, it returns C and sets |
|
234
|
|
|
|
|
|
|
C<$NSNMP::Simple::error> to a string describing the error in English, |
|
235
|
|
|
|
|
|
|
in the same format as Net::SNMP's error messages. |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=cut |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# Note that I wanted to put that list of %args first in the text, as a |
|
240
|
|
|
|
|
|
|
# bulleted list. But pod2html barfed on the required blank line after |
|
241
|
|
|
|
|
|
|
# the =item * line, so I gave up on bulleted lists in POD. Yick. |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub get { |
|
244
|
52
|
|
|
52
|
1
|
18664
|
my ($class, $host, $oid, %args) = @_; |
|
245
|
52
|
|
|
|
|
1831
|
my $response_decoded = |
|
246
|
|
|
|
|
|
|
_synchronous_request_response($host, |
|
247
|
|
|
|
|
|
|
type => NSNMP::GET_REQUEST, |
|
248
|
|
|
|
|
|
|
varbindlist => [[NSNMP->encode_oid($oid), |
|
249
|
|
|
|
|
|
|
NSNMP::NULL, '']], |
|
250
|
|
|
|
|
|
|
%args); |
|
251
|
52
|
100
|
|
|
|
681
|
return undef unless $response_decoded; |
|
252
|
44
|
|
|
|
|
163
|
my $varbind = ($response_decoded->varbindlist)[0]; |
|
253
|
44
|
|
|
|
|
246
|
return $decoders{$varbind->[1]}->($varbind->[2]); |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head2 NSNMP::Simple->set($agent, $oid, $type, $value, %args) |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
Sets the value of C<$oid> on the SNMP agent at C<$agent> to the value |
|
259
|
|
|
|
|
|
|
C<$value>, as BER-encoded type C<$type>. Returns true on success, |
|
260
|
|
|
|
|
|
|
false on failure, and also sets C<$NSNMP::Simple::error> on failure. |
|
261
|
|
|
|
|
|
|
Accepts the same C<%args> as C<-Eget>. |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=cut |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub set { |
|
266
|
16
|
|
|
16
|
1
|
319
|
my ($class, $host, $oid, $type, $value, %args) = @_; |
|
267
|
16
|
|
|
|
|
76
|
return !!_synchronous_request_response($host, |
|
268
|
|
|
|
|
|
|
type => NSNMP::SET_REQUEST, |
|
269
|
|
|
|
|
|
|
varbindlist => [[NSNMP->encode_oid($oid), |
|
270
|
|
|
|
|
|
|
$type, $encoders{$type}->($value)]], |
|
271
|
|
|
|
|
|
|
%args); |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head2 NSNMP::Simple->get_table($agent, $oid, %args) |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
Gets the values of all OIDs under C<$oid> on the SNMP agent at |
|
277
|
|
|
|
|
|
|
C<$agent>. Returns a list of alternating OIDs and values, in OID |
|
278
|
|
|
|
|
|
|
lexical order; you can stuff it into a hash if you don't care about |
|
279
|
|
|
|
|
|
|
the order. If there are no OIDs under C<$oid>, returns an empty list |
|
280
|
|
|
|
|
|
|
and clears C<$NSNMP::Simple::error>. Note that this can be caused |
|
281
|
|
|
|
|
|
|
either by misspelling the OID or by actually having an empty table, |
|
282
|
|
|
|
|
|
|
and there's no way to tell which. (See the note in L about |
|
283
|
|
|
|
|
|
|
the SNMP protocol design.) |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
If any of the component SNMP requests returns an unexpected error, |
|
286
|
|
|
|
|
|
|
C returns an empty list and sets C<$NSNMP::Simple::error>. |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
Note for Net::SNMP users: C does not set |
|
289
|
|
|
|
|
|
|
C<$NSNMP::Simple::error> on an empty table, but Net::SNMP's |
|
290
|
|
|
|
|
|
|
C does. |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Accepts the same C<%args> as C<-Eget>. |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
The OIDs in the returned list are spelled in ASCII with or without a |
|
295
|
|
|
|
|
|
|
leading dot, depending on whether or not C<$oid> has a leading dot. |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=cut |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub get_table { |
|
300
|
13
|
|
|
13
|
1
|
5169
|
my ($class, $host, $oid, %args) = @_; |
|
301
|
13
|
|
|
|
|
69
|
my @rv; |
|
302
|
|
|
|
|
|
|
my $response; |
|
303
|
13
|
|
|
|
|
120
|
my $mapper = NSNMP::Mapper->new($oid => 1); |
|
304
|
13
|
|
|
|
|
266
|
my $initial_dot = $oid =~ /\A\./; |
|
305
|
13
|
|
|
|
|
169
|
my $encoded_oid = NSNMP->encode_oid($oid); |
|
306
|
13
|
|
|
|
|
20
|
for (;;) { |
|
307
|
637
|
|
|
|
|
2691
|
$response = _synchronous_request_response($host, |
|
308
|
|
|
|
|
|
|
type => NSNMP::GET_NEXT_REQUEST, |
|
309
|
|
|
|
|
|
|
varbindlist => [[$encoded_oid, NSNMP::NULL, '']], |
|
310
|
|
|
|
|
|
|
%args, |
|
311
|
|
|
|
|
|
|
); |
|
312
|
637
|
100
|
|
|
|
4702
|
if (not defined $response) { |
|
313
|
12
|
100
|
|
|
|
40
|
if ($error_status eq NSNMP::noSuchName) { |
|
314
|
|
|
|
|
|
|
# end of MIB |
|
315
|
10
|
|
|
|
|
26
|
($error_status, $error) = (undef, undef); |
|
316
|
10
|
|
|
|
|
1455
|
return @rv; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
2
|
|
|
|
|
45
|
return (); |
|
319
|
|
|
|
|
|
|
} |
|
320
|
625
|
|
|
|
|
1630
|
my @varbindlist = $response->varbindlist; |
|
321
|
625
|
|
|
|
|
1594
|
$encoded_oid = $varbindlist[0][0]; |
|
322
|
625
|
|
|
|
|
1841
|
$oid = NSNMP->decode_oid($varbindlist[0][0]); |
|
323
|
625
|
100
|
|
|
|
1911
|
return @rv unless ($mapper->map($oid))[0]; |
|
324
|
624
|
100
|
|
|
|
3026
|
push @rv, ($initial_dot ? ".$oid" : $oid), |
|
325
|
|
|
|
|
|
|
$decoders{$varbindlist[0][1]}->($varbindlist[0][2]); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 $error |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
C<$NSNMP::Simple::error> is undef after any successful subroutine |
|
332
|
|
|
|
|
|
|
call on this module, and an English string describing the error after |
|
333
|
|
|
|
|
|
|
any unsuccessful subroutine call. |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
C<$NSNMP::Simple::error_status> is undef when C<$error> is undef, |
|
336
|
|
|
|
|
|
|
and when C<$error> is defined, C<$error_status> contains an integer |
|
337
|
|
|
|
|
|
|
describing the type of error. This may be a raw SNMP C |
|
338
|
|
|
|
|
|
|
code, such as NSNMP::noSuchName, or it may be one of the following |
|
339
|
|
|
|
|
|
|
values: |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=over |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=item NSNMP::Simple::noResponse |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
This code means that the remote host sent no response, or at least, no |
|
346
|
|
|
|
|
|
|
response we could decode, so we timed out. (The timeout value is |
|
347
|
|
|
|
|
|
|
configurable, as described earlier.) |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=item NSNMP::Simple::badHostName |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
This code means that C couldn't resolve the hostname |
|
352
|
|
|
|
|
|
|
given. It might be malformed or a nonexistent DNS name, or it might |
|
353
|
|
|
|
|
|
|
be an existing DNS name, but DNS might be broken for some other |
|
354
|
|
|
|
|
|
|
reason. |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=back |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head1 FILES |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
None. |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=head1 AUTHOR |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
Kragen Sitaker Ekragen@pobox.comE |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=head1 BUGS |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
This module uses L, so it inherits most of the |
|
369
|
|
|
|
|
|
|
bugs of that module. |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
It's still too slow. On my 500MHz laptop, it can SNMP-walk 5675 OIDs |
|
372
|
|
|
|
|
|
|
in about 7.2 CPU seconds, for less than 800 OIDs per second. ucd-snmp |
|
373
|
|
|
|
|
|
|
(now confusingly called net-snmp, not to be confused with Net::SNMP) |
|
374
|
|
|
|
|
|
|
takes 1.8 CPU seconds to perform the same task. That's four times as |
|
375
|
|
|
|
|
|
|
fast. On the other hand, Net::SNMP manages about 110 OIDs per second, |
|
376
|
|
|
|
|
|
|
seven times slower still. |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=cut |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
1; |