File Coverage

blib/lib/Net/SNMP/Mixin/Util.pm
Criterion Covered Total %
statement 64 64 100.0
branch 32 36 88.8
condition 7 12 58.3
subroutine 9 9 100.0
pod 5 5 100.0
total 117 126 92.8


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::Util;
2              
3 6     6   134718 use strict;
  6         4  
  6         131  
4 6     6   20 use warnings;
  6         6  
  6         128  
5              
6             #
7             # this module import config
8             #
9 6     6   746 use Net::SNMP ();
  6         53576  
  6         135  
10              
11             #
12             # this module export config
13             #
14 6         37 use Sub::Exporter -setup =>
15             { exports => [qw/idx2val hex2octet normalize_mac push_error get_init_slot/],
16 6     6   2859 };
  6         44069  
17              
18             =head1 NAME
19              
20             Net::SNMP::Mixin::Util - helper class for Net::SNMP mixins
21              
22             =head1 VERSION
23              
24             Version 0.14
25              
26             =cut
27              
28             our $VERSION = '0.14';
29              
30             =head1 SYNOPSIS
31              
32             A helper class for Net::SNMP mixins.
33              
34             use Net::SNMP::Mixin::Util qw/idx2val hex2octet normalize_mac/;
35              
36             =head1 EXPORTS
37              
38             The following routines are exported by request:
39              
40             =over 2
41              
42             =item B<< idx2val($var_bind_list, $base_oid, [$pre], [$tail]) >>
43              
44             convert a var_bind_list into a index => value form,
45             removing the base_oid from oid.
46              
47             e.g. if base_oid is '1.3.6.1.2.1.17.1.4.1.2',
48             convert from:
49            
50             '1.3.6.1.2.1.17.1.4.1.2.1' => 'foo'
51             '1.3.6.1.2.1.17.1.4.1.2.2' => 'bar'
52              
53             to:
54              
55             '1' => 'foo'
56             '2' => 'bar'
57            
58             or if base_oid is '1.0.8802.4.1.1.12' and pre == 1 and tail == 2,
59             convert from:
60              
61             '1.0.8802.4.1.1.12.0.10.0.0.2.99.185' => 'foo',
62             '1.0.8802.4.1.1.12.0.10.0.0.3.99.186' => 'bar',
63             '1.0.8802.4.1.1.12.0.10.0.0.4.99.187' => 'baz',
64             ^ ^ ^ ^ ^ ^ ^
65             |.....base_oid....|.|.index..|.tail.| |value|
66             ^
67             pre ---------------|
68              
69             to:
70              
71             '10.0.0.2' => 'foo',
72             '10.0.0.3' => 'bar',
73             '10.0.0.4' => 'baz',
74              
75             Returns the hash reference with index => value. Dies on error.
76              
77             =cut
78              
79             sub idx2val {
80 10     10 1 1261 my ( $var_bind_list, $base_oid, $pre, $tail ) = @_;
81              
82 10 100       28 die "missing attribute 'var_bind_list'," unless defined $var_bind_list;
83 9 100       17 die "missing attribute 'base_oid'," unless defined $base_oid;
84              
85 8   100     20 $pre ||= 0;
86 8   100     15 $tail ||= 0;
87              
88 8 100       19 die "wrong format for 'pre'," if $pre < 0;
89 7 100       17 die "wrong format for 'tail'," if $tail < 0;
90              
91 6         4 my $idx;
92 6         6 my $idx2val = {};
93 6         13 foreach my $oid ( keys %$var_bind_list ) {
94 23 100       131 next unless Net::SNMP::oid_base_match( $base_oid, $oid );
95              
96 18         305 $idx = $oid;
97              
98             # cutoff leading and trailing whitespace, bloody SNMP agents!
99 18         44 $idx =~ s/^\s*//;
100 18         69 $idx =~ s/\s*$//;
101              
102             # cutoff the basoid, get the idx
103 18         91 $idx =~ s/^$base_oid//;
104              
105             # if the idx isn't at the front of the index
106             # cut off the n fold pre
107 18 100       93 $idx =~ s/^\.?(\d+\.?){$pre}// if $pre > 0;
108              
109             # if the idx isn't at the end of the oid
110             # cut off the n fold tail
111 18 100       93 $idx =~ s/(\d+\.?){$tail}$// if $tail > 0;
112              
113             # cut off remaining dangling '.'
114 18         20 $idx =~ s/^\.//;
115 18         22 $idx =~ s/\.$//;
116              
117 18         44 $idx2val->{$idx} = $var_bind_list->{$oid};
118             }
119 6         22 return $idx2val;
120             }
121              
122             =item B<< hex2octet($hex_string) >>
123              
124             Sometimes it's importend that the returned SNMP values were untranslated by Net::SNMP. If already translated, we must reconvert it to pure OCTET_STRINGs for some calculations. Returns the input parameter untranslated if it's no string in the form /^0x[0-9a-f]+$/i .
125              
126             =cut
127              
128             sub hex2octet {
129 3     3 1 3 my $hex_string = shift;
130              
131             # don't touch, it's no hex_string
132 3 100       21 return $hex_string unless $hex_string =~ m/^0x[0-9a-f]+$/i;
133              
134             # remove '0x' in front
135 1         2 $hex_string = substr( $hex_string, 2 );
136              
137             # return octet_string
138 1         9 return pack 'H*', $hex_string;
139             }
140              
141             =item B<< normalize_mac($mac_address) >>
142              
143             normalize MAC addresses to the IEEE form XX:XX:XX:XX:XX:XX
144              
145             normalize the different formats like,
146              
147             x:xx:x:xx:Xx:xx to XX:XX:XX:XX:XX:XX
148             or xxxxxx-xxxxxx to XX:XX:XX:XX:XX:XX
149             or xx-xx-xx-xx-xx-xx to XX:XX:XX:XX:XX:XX
150             or xxxx.xxxx.xxxx to XX:XX:XX:XX:XX:XX
151             or 0x xxxxxxxxxxxx to XX:XX:XX:XX:XX:XX
152             or plain packed '6C' to XX:XX:XX:XX:XX:XX
153              
154             or returns undef for format errors.
155              
156             =cut
157              
158             sub normalize_mac {
159 20     20 1 4263 my ($mac) = @_;
160 20 100       43 return unless defined $mac;
161              
162             # translate this OCTET_STRING to hexadecimal, unless already translated
163 19 100       38 if ( length $mac == 6 ) {
164 1         6 $mac = unpack 'H*', $mac;
165             }
166              
167             # to upper case
168 19         22 my $norm_address = uc($mac);
169              
170             # remove '-' in bloody Microsoft format
171 19         28 $norm_address =~ s/-//g;
172              
173             # remove '.' in bloody Cisco format
174 19         17 $norm_address =~ s/\.//g;
175              
176             # remove '0X' in front of, we are already upper case
177 19         19 $norm_address =~ s/^0X//;
178              
179             # we are already upper case
180 19         42 my $hex_digit = qr/[A-F,0-9]/;
181              
182             # insert leading 0 in bloody Sun format
183 19         124 $norm_address =~ s/\b($hex_digit)\b/0$1/g;
184              
185             # insert ':' aabbccddeeff -> aa:bb:cc:dd:ee:ff
186 19         144 $norm_address =~ s/($hex_digit{2})(?=$hex_digit)/$1:/g;
187              
188             # wrong format
189 19 100       140 return unless $norm_address =~ m /^($hex_digit{2}:){5}$hex_digit{2}$/;
190              
191 12         80 return $norm_address;
192             }
193              
194             =item B<< push_error($session, $error_msg) >>
195              
196             Net::SNMP has only one slot for errors. During nonblocking calls it's possible that an error followed by a successful transaction is cleared before the user gets the chance to see the error. At least for the mixin modules we use an array buffer for all seen errors until they are explicit cleared.
197              
198             This utility routine helps the mixin authors to push an error into the buffer without the knowledge of the buffer internas.
199              
200             Dies if session isn't a Net::SNMP object or error_msg is missing.
201              
202             =cut
203              
204             sub push_error {
205 4     4 1 3190 my ( $session, $error_msg ) = @_;
206              
207 4 100       19 die "missing attribute 'session'," unless defined $session;
208 3 100       15 die "missing attribute 'error_msg'," unless defined $error_msg;
209              
210 2 50 33     17 die "'session' isn't a Net::SNMP object,"
211             unless ref $session && $session->isa('Net::SNMP');
212              
213             # prepare the error buffer if not already done
214 2   50     18 $session->{'Net::SNMP::Mixin'}{errors} ||= [];
215 2         3 my @errors = @{ $session->{'Net::SNMP::Mixin'}{errors} };
  2         5  
216              
217             # store the error_msg at the buffer end if not already in the buffer
218 2 50       8 push @{ $session->{'Net::SNMP::Mixin'}{errors} }, $error_msg
  2         9  
219             unless grep m/\Q$error_msg\E$/, @errors;
220             }
221              
222             =item B<< get_init_slot() >>
223              
224             Helper method, defines and returns the init hash slot for all mixin modules.
225              
226             =back
227              
228             =cut
229              
230             sub get_init_slot {
231 3     3 1 400 my ($session) = @_;
232              
233 3 100       12 die "missing attribute 'session'," unless defined $session;
234              
235 2 50 33     17 die "'session' isn't a Net::SNMP object,"
236             unless ref $session && $session->isa('Net::SNMP');
237              
238             $session->{'Net::SNMP::Mixin'}{init_jobs_left} = {}
239 2 50       10 unless exists $session->{'Net::SNMP::Mixin'}{init_jobs_left};
240              
241 2         10 return $session->{'Net::SNMP::Mixin'}{init_jobs_left};
242             }
243              
244             unless ( caller() ) {
245             print __PACKAGE__ . " compiles and initializes successful.\n";
246             }
247              
248             =head1 REQUIREMENTS
249              
250             L, L
251              
252             =head1 BUGS, PATCHES & FIXES
253              
254             There are no known bugs at the time of this release. However, if you spot a bug or are experiencing difficulties that are not explained within the POD documentation, please submit a bug to the RT system (see link below). However, it would help greatly if you are able to pinpoint problems or even supply a patch.
255              
256             Fixes are dependant upon their severity and my availablity. Should a fix not be forthcoming, please feel free to (politely) remind me by sending an email to gaissmai@cpan.org .
257              
258             RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Net-SNMP-Mixin
259              
260             =head1 AUTHOR
261              
262             Karl Gaissmaier
263              
264             =head1 COPYRIGHT & LICENSE
265              
266             Copyright 2008-2015 Karl Gaissmaier, all rights reserved.
267              
268             This program is free software; you can redistribute it and/or modify it
269             under the same terms as Perl itself.
270              
271             =cut
272              
273             1;
274              
275             # vim: sw=2