File Coverage

blib/lib/Net/SNMP/QueryEngine/AnyEvent.pm
Criterion Covered Total %
statement 42 101 41.5
branch 0 16 0.0
condition 0 12 0.0
subroutine 14 24 58.3
pod 8 10 80.0
total 64 163 39.2


line stmt bran cond sub pod time code
1             package Net::SNMP::QueryEngine::AnyEvent;
2              
3 1     1   23157 use 5.006;
  1         3  
  1         51  
4 1     1   7 use strict;
  1         2  
  1         49  
5 1     1   11 use warnings;
  1         7  
  1         62  
6              
7             our $VERSION = '0.05';
8              
9 1     1   965 use AnyEvent::Handle;
  1         29900  
  1         51  
10 1     1   13 use base 'AnyEvent::Handle';
  1         4  
  1         152  
11 1     1   735 use Data::MessagePack;
  1         1288  
  1         36  
12 1     1   644 use Data::MessagePack::Stream;
  1         553  
  1         39  
13              
14 1     1   8 use constant RT_SETOPT => 1;
  1         3  
  1         86  
15 1     1   8 use constant RT_INFO => 3;
  1         2  
  1         56  
16 1     1   7 use constant RT_GET => 4;
  1         1  
  1         53  
17 1     1   6 use constant RT_GETTABLE => 5;
  1         2  
  1         60  
18 1     1   6 use constant RT_DEST_INFO => 6;
  1         3  
  1         66  
19 1     1   7 use constant RT_REPLY => 0x10;
  1         2  
  1         73  
20 1     1   20 use constant RT_ERROR => 0x20;
  1         2  
  1         1286  
21              
22             sub read_handle;
23              
24             sub new
25             {
26 0     0 1   my $class_or_ref = shift;
27 0           my %args = (connect => ["127.0.0.1", 7667], @_, on_read => \&read_handler);
28 0           my $self = $class_or_ref->SUPER::new(%args);
29 0           $self->{sqe}{condvar} = AnyEvent->condvar;
30 0           $self->{sqe}{pending} = 0;
31 0           $self->{sqe}{mp} = Data::MessagePack->new->prefer_integer;
32 0           $self->{sqe}{up} = Data::MessagePack::Stream->new;
33 0           $self->{sqe}{cid} = int rand 1000000;
34 0           $self->{sqe}{cb} = {};
35 0           return $self;
36             }
37              
38             sub when_done
39             {
40 0     0 1   my ($self, $host, $port, $cb) = @_;
41 0           my $hp = "$host:$port";
42 0           $self->{sqe}{hpcb}{$hp} = $cb;
43             }
44              
45             sub wait
46             {
47 0     0 1   my $self = shift;
48 0 0         return unless $self->{sqe}{pending};
49 0           $self->{sqe}{condvar}->recv;
50             }
51              
52             sub cmd
53             {
54 0     0 0   my ($self, $cb, @cmd) = @_;
55 0           $self->{sqe}{cb}{$self->{sqe}{cid}} = $cb;
56 0           $self->{sqe}{pending}++;
57 0 0 0       if ($self->{sqe}{pending} == 1 && $self->{sqe}{condvar}->ready) {
58             # XXX "reset" a condvar so "wait" can be correctly called again
59 0           $self->{sqe}{condvar} = AnyEvent->condvar;
60             }
61 0           $self->push_write($self->{sqe}{mp}->pack(\@cmd));
62             }
63              
64             sub read_handler
65             {
66 0     0 0   my $self = shift;
67              
68 0           $self->{sqe}{up}->feed($self->{rbuf});
69 0           $self->{rbuf} = "";
70              
71 0           while ($self->{sqe}{up}->next) {
72 0           my $data = $self->{sqe}{up}->data;
73              
74 0 0 0       if (ref($data) ne "ARRAY" || @$data < 3 || !$self->{sqe}{cb}{$data->[1]}) {
      0        
75             } else {
76 0           my $cid = $data->[1];
77 0           $self->{sqe}{cb}{$cid}->($self, $data->[0] & RT_REPLY, $data->[2]);
78 0           delete $self->{sqe}{cb}{$cid};
79              
80 0           my $hp = delete $self->{sqe}{cid2hp}{$cid};
81 0 0 0       if ($hp && $self->{sqe}{hp}{$hp}) {
82 0           $self->{sqe}{hp}{$hp}--;
83 0 0         if ($self->{sqe}{hp}{$hp} <= 0) {
84 0 0         $self->{sqe}{hpcb}{$hp}->($self) if $self->{sqe}{hpcb}{$hp};
85             }
86             }
87              
88 0           $self->{sqe}{pending}--;
89 0 0         if ($self->{sqe}{pending} <= 0) {
90 0           $self->{sqe}{condvar}->send;
91             }
92             }
93             }
94             }
95              
96             sub setopt
97             {
98 0     0 1   my ($self, $host, $port, $opts, $cb) = @_;
99 0           $self->cmd($cb, RT_SETOPT, ++$self->{sqe}{cid}, $host, $port, $opts);
100             }
101              
102             sub get
103             {
104 0     0 1   my ($self, $host, $port, $oids, $cb) = @_;
105              
106 0           my $cid = ++$self->{sqe}{cid};
107 0           my $hp = "$host:$port";
108 0           $self->{sqe}{hp}{$hp}++;
109 0           $self->{sqe}{cid2hp}{$cid} = $hp;
110              
111 0           $self->cmd($cb, RT_GET, $cid, $host, $port, $oids);
112             }
113              
114             sub gettable
115             {
116 0     0 1   my ($self, $host, $port, $oid, $max_rep, $cb) = @_;
117              
118 0           my $cid = ++$self->{sqe}{cid};
119 0           my $hp = "$host:$port";
120 0           $self->{sqe}{hp}{$hp}++;
121 0           $self->{sqe}{cid2hp}{$cid} = $hp;
122              
123 0 0         if ($cb) {
124 0           $self->cmd($cb, RT_GETTABLE, $cid, $host, $port, $oid, $max_rep);
125             } else {
126 0           $self->cmd($max_rep, RT_GETTABLE, $cid, $host, $port, $oid);
127             }
128             }
129              
130             sub info
131             {
132 0     0 1   my ($self, $cb) = @_;
133 0           $self->cmd($cb, RT_INFO, ++$self->{sqe}{cid});
134             }
135              
136             sub dest_info
137             {
138 0     0 1   my ($self, $cb, $host, $port) = @_;
139 0           $self->cmd($cb, RT_DEST_INFO, ++$self->{sqe}{cid}, $host, $port);
140             }
141              
142             =head1 NAME
143              
144             Net::SNMP::QueryEngine::AnyEvent - multiplexing SNMP query engine client using AnyEvent
145              
146             =head1 VERSION
147              
148             Version 0.05
149              
150             =head1 SYNOPSIS
151              
152             This is an AnyEvent-flavored Perl client for snmp-query-engine,
153             a multiplexing SNMP query engine.
154              
155             use Net::SNMP::QueryEngine::AnyEvent;
156              
157             my $sqe = Net::SNMP::QueryEngine::AnyEvent->new;
158              
159             $sqe->setopt("127.0.0.1", 161, { community => "meow" }, sub {});
160             $sqe->when_done("127.0.0.1", 161, sub { print "done with localhost\n" });
161              
162             $sqe->gettable("127.0.0.1", 161, "1.3.6.1.2.1.1", sub {
163             my ($h, $ok, $r) = @_;
164             for my $t (@$r) {
165             print "$t->[0] => $t->[1]\n";
166             }
167             });
168              
169             $sqe->get("127.0.0.1", 161,
170             ["1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.25.1.1.0"],
171             sub {
172             my ($h, $ok, $r) = @_;
173             print "Hostname: $r->[0][1]\n";
174             print "Uptime : $r->[1][1]\n";
175             });
176              
177             $sqe->wait;
178              
179             =head1 METHODS
180              
181             =head2 new
182              
183             Constructor. Takes the same arguments as the constructor of
184             the base class, AnyEvent::Handle::new,
185             but always overrides "on_read" callback.
186              
187             By default, connects to snmp-query-engine listening on
188             localhost, port 7667. Override this by specifying
189             a "connect" argument.
190              
191             =head2 when_done
192              
193             Execute provided callback when there are no unfinished
194             get or gettable queries towards a specified host:port.
195              
196             =head2 wait
197              
198             Enters event loop until there are no unanswered queries.
199             Can be called multiple times.
200              
201             =head2 setopt
202              
203             Performs setopt request.
204              
205             =head2 getopt
206              
207             Performs getopt request.
208              
209             =head2 get
210              
211             Performs get request for arbitrary number
212             of OIDs.
213              
214             =head2 gettable
215              
216             Performs gettable request.
217              
218             =head2 info
219              
220             Performs info request.
221              
222             =head2 dest_info
223              
224             Performs dest_info request.
225              
226             =head1 AUTHOR
227              
228             Anton Berezin, C<< >>
229              
230             =head1 BUGS
231              
232             Please report any bugs or feature requests to C, or through
233             the web interface at L. I will be notified, and then you'll
234             automatically be notified of progress on your bug as I make changes.
235              
236              
237             =head1 SEE ALSO
238              
239             The snmp-query-engine daemon can be found on github
240             at L.
241              
242              
243             =head1 SUPPORT
244              
245             You can find documentation for this module with the perldoc command.
246              
247             perldoc Net::SNMP::QueryEngine::AnyEvent
248              
249              
250             You can also look for information at:
251              
252             =over 4
253              
254             =item * RT: CPAN's request tracker (report bugs here)
255              
256             L
257              
258             =item * AnnoCPAN: Annotated CPAN documentation
259              
260             L
261              
262             =item * CPAN Ratings
263              
264             L
265              
266             =item * Search CPAN
267              
268             L
269              
270             =back
271              
272              
273             =head1 ACKNOWLEDGEMENTS
274              
275             This work is in part sponsored by Telia Denmark.
276              
277             =head1 LICENSE AND COPYRIGHT
278              
279             Copyright (c) 2012-2015, Anton Berezin "". All rights
280             reserved.
281              
282             Redistribution and use in source and binary forms, with or without
283             modification, are permitted provided that the following conditions are
284             met:
285              
286             1. Redistributions of source code must retain the above copyright
287             notice, this list of conditions and the following disclaimer.
288              
289             2. Redistributions in binary form must reproduce the above copyright
290             notice, this list of conditions and the following disclaimer in the
291             documentation and/or other materials provided with the distribution.
292              
293             THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
294             EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
295             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
296             PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE
297             LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298             CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
299             SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
300             BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
301             WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
302             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
303             ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
304              
305             =cut
306              
307             1;