File Coverage

blib/lib/SNMP/Class/OID.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package SNMP::Class::OID;
2              
3 1     1   2836 use NetSNMP::OID;
  0            
  0            
4             use Carp;
5             use strict;
6             use warnings;
7             use Clone;
8             use Data::Dumper;
9              
10              
11             =head1 NAME
12              
13             SNMP::Class::OID - Represents an SNMP Object-ID.
14              
15             =cut
16              
17             our $VERSION = '0.12';
18              
19             =head1 SYNOPSIS
20              
21             use SNMP::Class::OID;
22              
23             #create an object
24             my $oid = SNMP::Class::OID->new('.1.3.6.1.2.1.1.5.0');
25             #-or-
26             my $oid = SNMP::Class::OID->new('sysName.0');
27            
28             #overloaded scalar representation
29             print $oid; # evaluates to sysName.0
30              
31             #representations
32             $oid->to_string; #string representation -- sysName.0
33             $oid->numeric; #numeric representation -- .1.3.6.1.2.1.1.5.0
34             $oid->to_array; #(1,3,6,1,2,1,1,5,0)
35             $oid->[1]; #can be used as array reference -- returns 5
36             $oid->length; #9
37              
38             #slicing
39             my $oid2 = $oid->slice(3,6); #new object : .6.1.2.1
40             my $oid2 = $oid->slice(3..6); #same
41              
42             #equality
43             $oid1 == $oid2; # yields true if they are the same
44             $oid1 == '.1.3.6.1.2.1.1.5.0' #also acceptable, second operand will be converted
45              
46             #hierarchy
47             $oid2 = SNMP::Class::OID->new('.1.3.6.1.2.1.1');
48             $oid2->contains($oid); #true; Because .1.3.6.1.2.1.1.5.0 is under .1.3.6.1.2.1.1
49             $oid2->contains('.1.3.6.1.2.1.1.5.0'); #also true, string autoconverted to SNMP::Class::OID
50              
51             #concatenation
52             SNMP::Class::OID(".1.3.6") . SNMP::Class::OID("1.2.1"); #returns .1.3.6.1.2.1
53             SNMP::Class::OID(".1.3.6") . '.1.2.1'; #also acceptable, returns the same
54              
55             =head1 METHODS
56              
57             =head2 overloaded operators
58              
59             The following operators are overloaded:
60              
61             =over 4
62              
63             =item * <=>
64              
65             Two SNMP::Class::OID objects can be compared using the == operator. The result is what everybody expects.
66              
67              
68             =item * '+'
69              
70             Two SNMP::Class::OID objects can be concatenated using the + operator. Note that order actually is important. Example: .1.3.6 + .1.4.1 will yield .1.3.6.1.4.1.
71              
72              
73             =item * @{}
74              
75             If an SNMP::Class::OID object is used as an array reference, it will act as an array containing the individual numbers of the OID. Example:
76              
77              
78             my $oid = SNMP::Class::OID->new("1.3.6.1.4.1");
79             print $oid->[1]; #will print 3
80              
81             =back
82              
83             =cut
84              
85              
86             use overload
87             '<=>' => \&oid_compare,
88             'cmp' => \&oid_compare,
89             '.' => \&add,
90             '@{}' => \&to_arrayref,
91             fallback => 1,
92             ;
93              
94             =head2 new
95              
96             new can be used to construct a new object-id. Takes one string as an argument, like ".1.3.6.4.1". Returns an SNMP::Class::OID object, or confesses if that is not possible. If the 1rst argument is a L instead of a string, the constructor will notice and take appropriate action to return a valid object.
97              
98             =cut
99            
100             sub new {
101             my $class = shift(@_) or croak "Incorrect call to new";
102             my $oid_str = shift(@_);
103             if ( eval { $oid_str->isa("NetSNMP::OID") } ) {
104             return bless { oid => $oid_str }, $class; #it was not a str after all :)
105             }
106             if($oid_str eq "0") {
107             $oid_str = ".0";
108             }
109             # my @arr;
110             # my $num_str = SNMP::Class::Utils::oid_of($oid_str);
111             # while( $num_str =~ /(\d+)/g ){
112             # unshift @arr,($1);
113             # }
114             # print STDERR "Array is ",Dumper(@arr),"\n";
115            
116             my $self = {};
117             $self->{oid} = NetSNMP::OID->new($oid_str) or confess "Cannot create a new NetSNMP::OID object for $oid_str";
118            
119             return bless $self,$class;
120             }
121              
122             #this constructor must DIE. Soon.
123             #sub new_from_netsnmpoid {
124             # my $class = shift(@_) or croak "Incorrect call to new_from_netsnmpoid";
125             # my $self = {};
126             # $self->{oid} = shift(@_) or croak "Missing argument from new_from_netsnmpoid";
127             # return bless $self,$class;
128             #}
129              
130             =head2 get_syntax
131              
132             Returns, if it exists, the SNMP SYNTAX clause for the oid or undef if it doesn't.
133              
134             =cut
135              
136             sub get_syntax {
137             my $self = shift(@_);
138             return SNMP::Class::Utils::syntax_of($self->numeric);
139             }
140              
141             =head2 has_syntax
142              
143             Tells if we know the syntax for the object. Convenience shortcut instead of testing get_syntax for definedness.
144              
145             =cut
146              
147             sub has_syntax {
148             return defined($_[0]->get_syntax);
149             }
150              
151             =head2 get_label
152              
153             Returns the label for this oid if it exists or undef if it doesn't.
154              
155             =cut
156              
157             sub get_label {
158             my $self = shift(@_);
159             return SNMP::Class::Utils::label_of($self->numeric);
160             }
161              
162             =head2 get_label_oid
163              
164             Returns an SNMP::Class::OID object corresponding to the appropriate object-id. For example, for an oid like ifDescr.3, we would get a new SNMP::Class::OID equivalent to ifDescr. May return undef, as the label may not be found in the loaded MIBs.
165              
166             =cut
167              
168             sub get_label_oid {
169             my $self = shift(@_);
170             my $label = $self->get_label;
171             return unless defined($label);
172             return __PACKAGE__->new($label);
173             }
174              
175              
176             =head2 has_label
177              
178             Tells if there is a label for the object. Convenience shortcut instead of testing get_label_oid for definedness.
179              
180             =cut
181              
182             sub has_label {
183             return defined($_[0]->get_label);
184             }
185              
186             =head2 get_instance_oid
187              
188             Returns an SNMP::Class::OID object corresponding to the instance of this oid. For example, for an oid like ifDescr.3, we would get a new SNMP::Class::OID equivalent to .3. May return undef, as there may be no instance (for example a non-leaf oid) or it may not be possible to know it.
189              
190             =cut
191              
192             sub get_instance_oid {
193             my $self = shift(@_);
194             my $label_oid = $self->get_label_oid;
195             return unless defined($label_oid);
196             my $start = $label_oid->length+1;
197             my $end = $self->length;
198             return if($start>$end);
199             return $self->slice($start,$end);
200             }
201              
202             =head2 has_instance
203              
204             Tells if there is an instance for the object. Convenience shortcut instead of testing get_instance_oid for definedness.
205              
206             =cut
207              
208             sub has_instance {
209             return defined($_[0]->get_instance_oid);
210             }
211            
212            
213              
214             =head2 slice
215              
216             Slice can extract a portion of an object-id and return it as a new SNMP::Class::OID object. Example:
217            
218             my $oid = SNMP::Class::OID->new("1.3.6.1.4.1");
219             my $suboid = $oid->slice(1..3); #will return .1.3.6
220             my $suboid = $oid->slice(1,2,3); #completely equivalent
221             my $suboid = $oid->slice(1,3); #also completely equivalent
222              
223             To extract a single number from the object-id you can simply say for example:
224              
225             my $suboid = $oid->slice(2);
226              
227             =cut
228              
229             sub slice {
230             my $self = shift(@_);
231             my $start = shift(@_);
232             my $end = pop(@_) || $start;
233             if($end<$start) {
234             croak "Cannot have the end $end smaller that the $start in the range you requested";
235             }
236             $start-=1;
237             $end-=1;
238             return __PACKAGE__->new('.'.join('.',($self->to_array)[$start..$end]));
239             }
240            
241              
242             sub oid {
243             my $self = shift(@_);
244             croak "self appears to be undefined" unless ref $self;
245             return $self->{oid};
246             }
247              
248             =head2 to_array
249              
250             Returns an array representation of the object OID.
251              
252             =cut
253              
254             sub to_array {
255             my $self = shift(@_);
256             croak "self appears to be undefined" unless ref $self;
257             return $self->oid->to_array;
258             }
259              
260             sub to_arrayref {
261             my $self = shift(@_);
262             croak "self appears to be undefined" unless ref $self;
263             my @array = $self->to_array;
264             return \@array;
265             }
266              
267             =head2 length
268              
269             Returns the length (in items) of the object OID.
270              
271             =cut
272              
273             sub length {
274             my $self = shift(@_);
275             croak "self appears to be undefined" unless ref $self;
276             return $self->oid->length;
277             }
278              
279             =head2 is_null
280              
281             returns true if the object represents the null object identifier.
282             SNMPv2-SMI defines a null object id to be { 0 0 } or 0.0 or zeroDotZero.
283             Let's just hope that we won't encounter 0.0 instances any time soon.
284              
285             =cut
286              
287             sub is_null {
288             my $self = shift(@_);
289             croak "self appears to be undefined" unless ref $self;
290             return 1 if ($self->numeric eq ".0.0");#this should be fairly fast
291             return;
292             }
293            
294            
295             =head2 numeric
296              
297             Returns a numeric representation of the object.
298              
299             =cut
300              
301             sub numeric {
302             my $self = shift(@_);
303             croak "self appears to be undefined" unless ref $self;
304             return '.'.join('.',$self->to_array);
305             }
306              
307             =head2 to_string
308              
309             Returns a string representation of the object. Difference with numeric is that numeric always returns numbers like .1.3.6.1.2.1.1.5.0, while this method may return strings like "sysName.0" etc.
310              
311             =cut
312              
313             sub to_string {
314             my $self = shift(@_);
315             croak "self appears to be undefined" unless ref $self;
316             return $self->oid->quote_oid;
317             }
318              
319             =head2 add
320              
321             Concatenates two OIDs. Use it through the . overloaded operator. Second argument can be a string, will be autoconverted to SNMP::Class::OID before addition. If one of the arguments is 0.0, the result should be equal to the other.
322              
323             =cut
324              
325              
326             sub add {
327             my $self = shift(@_);
328             croak "self appears to be undefined" unless ref $self;
329             my $other = convert_to_oid_object(shift(@_)) or croak "Second argument missing from add";
330             my $reverse = shift(@_);
331             if(defined($reverse)&&$reverse) {
332             ($self,$other) = ($other,$self);
333             }
334             return __PACKAGE__->new($self->numeric) if ($other->is_null);#poor man's clone....
335             return __PACKAGE__->new($other->numeric) if ($self->is_null);
336             return __PACKAGE__->new($self->oid->add($other->oid));
337             }
338              
339             =head2 oid_compare
340              
341             Compares two OIDs. Has the same semantic with the spaceship <=> operator. Second argument can also be a string. You probably will never use that method explicitly, only through the overloaded operators <,>,==,!= etc. See also the is_equal method.
342              
343             =cut
344              
345             sub oid_compare {
346             #print Dumper(@_);
347             my $self = shift(@_);
348             croak "self appears to be undefined" unless ref $self;
349             my $other = convert_to_oid_object(shift(@_));
350             croak "Internal error: Second argument missing from compare. Second argument was ".Dumper($other)."\n" unless(ref $other);
351             my @arr1 = $self->to_array;
352             my @arr2 = $other->to_array;
353              
354             while(1) {
355             my $item1 = shift(@arr1);#left argument
356             my $item2 = shift(@arr2);#right argument
357             ###print STDERR "$item1 $item2 \n";
358             if((!defined($item1))&&(!defined($item2))) {
359             return 0; #items are equal
360             }
361             elsif((!defined($item1))&&(defined($item2))) {
362             return -1;#left is smaller than right, we return -1
363             }
364             elsif((defined($item1))&&(!defined($item2))) {
365             return 1;#opposite
366             }
367             else {#case where both items are defined. Now we must compare the two numbers
368             if ($item1 != $item2) {
369             return $item1 <=> $item2;
370             }
371             }
372             }
373             }
374            
375             =head2 oid_is_equal
376              
377             Returns 1 if the 1st argument is the same oid, else undef.
378              
379             =cut
380              
381             sub oid_is_equal {
382             return 1 if ($_[0]->oid_compare($_[1]) == 0);
383             return;
384             }
385            
386            
387            
388             =head2 contains
389              
390             Can ascertain if an oid is a subset of the oid represented by the object. Takes SNMP::Class::OID as 1st and only argument. String also acceptable as it will be autoconverted. Example:
391            
392             $oid1 = SNMP::Class::OID->new(".1.3.6.1.4.1");
393             $oid2 = SNMP::Class::OID->new(".1.3.6.1.4.1.1");
394             $oid1->contains($oid2); #yields true
395             $oid1->contains(".1.3.6.1.4.1.1");#the same
396            
397             =cut
398            
399             sub contains {
400             my $self = shift(@_);
401             croak "self appears to be undefined" unless ref $self;
402             my $other_oid = convert_to_oid_object(shift(@_));
403             croak "Second argument missing from contains" unless (ref $other_oid);
404             if ($self->length > $other_oid->length) { return }
405             my @arr1 = $self->to_array;
406             my @arr2 = $other_oid->to_array;
407             for(my $i=0;$i<=$#arr1;$i++) {
408             return if (!defined($arr2[$i]));
409             return if ($arr1[$i] != $arr2[$i]);
410             ###print STDERR "iteration=$i\t$arr1[$i]\t$arr2[$i]\n";
411             }
412             return 1;
413             }
414              
415             =head2 new_from_string
416              
417             Can create an oid from a literal string. Useful to generate instances which correspond to strings. 1st argument is the string to represent with an OID. If the 2nd argument is there and is true, the SNMP octet-string is assumed to be IMPLIED, thus the first number which represents the length of the string is missing. Example:
418              
419             my $instance = SNMP::Class::OID->new_from_string("foo"); # returns .3.102.111.111
420              
421             #but
422              
423             my $instance = SNMP::Class::OID->new_from_string("foo","yes_it_is_implied"); # returns .102.111.111
424              
425             =cut
426              
427             sub new_from_string {
428             my $class = shift(@_) or confess "Incorrect call to new";
429             my $str = shift(@_) or confess "Missing string as 1st argument";
430             my $implied = shift(@_) || 0;
431             my $newstr;
432             if(!$implied) { $newstr = "." . CORE::length($str) }
433             map { $newstr .= ".$_" } unpack("c*",$str);
434             ###print $newstr,"\n";
435             my $self={};
436             #$self->{oid} = NetSNMP::OID->new($newstr) or croak "Cannot invoke NetSNMP::OID::new method \n";
437             #return bless $self,$class;
438             return __PACKAGE__->new($newstr);
439             }
440              
441              
442             #utility function, not to be used by the user
443             sub convert_to_oid_object {
444             my $arg = shift(@_);
445             if ( ! eval { $arg->isa(__PACKAGE__) } ) {
446             return __PACKAGE__->new($arg);
447             }
448             else {#indeed a __PACKAGE__
449             ####print "returning ".Dumper($arg);
450             return $arg;
451             }
452             }
453            
454              
455             =head1 AUTHOR
456              
457             Athanasios Douitsis, C<< >>
458              
459             =head1 BUGS
460              
461             Please report any bugs or feature requests to
462             C, or through the web interface at
463             L.
464             I will be notified, and then you'll automatically be notified of progress on
465             your bug as I make changes.
466              
467             =head1 SUPPORT
468              
469             You can find documentation for this module with the perldoc command.
470              
471             perldoc SNMP::Class
472              
473             You can also look for information at:
474              
475             =over 4
476              
477             =item * AnnoCPAN: Annotated CPAN documentation
478              
479             L
480              
481             =item * CPAN Ratings
482              
483             L
484              
485             =item * RT: CPAN's request tracker
486              
487             L
488              
489             =item * Search CPAN
490              
491             L
492              
493             =back
494              
495             =head1 ACKNOWLEDGEMENTS
496              
497             Since I am using NetSNMP::OID internally, my gratitude goes to the fine folks that gave us the original SNMP module. Many thanks to all.
498              
499             =head1 COPYRIGHT & LICENSE
500              
501             Copyright 2008 Athanasios Douitsis, all rights reserved.
502              
503             This program is free software; you can redistribute it and/or modify it
504             under the same terms as Perl itself.
505              
506             =cut
507              
508             1; # End of SNMP::Class::OID