File Coverage

blib/lib/TRD/Watch/Ping.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package TRD::Watch::Ping;
2              
3 1     1   1353393 use warnings;
  1         2  
  1         23  
4 1     1   4 use strict;
  1         2  
  1         24  
5 1     1   5 use Carp;
  1         5  
  1         77  
6 1     1   1329 use threads ( 'exit' => 'threads_only' );
  0            
  0            
7             use Time::HiRes qw(sleep);
8             use TRD::DebugLog;
9             #$TRD::DebugLog::enabled = 1;
10              
11             use version;
12             our $VERSION = '0.0.4';
13              
14             # Other recommended modules (uncomment to use):
15             # use IO::Prompt;
16             # use Perl6::Export;
17             # use Perl6::Slurp;
18             # use Perl6::Say;
19              
20             our $default_timeout = 5; # sec
21             our $default_interval = 60; # sec
22              
23             #=======================================================================
24             sub new {
25             my $pkg = shift;
26             my $name = (@_) ? shift : '';
27             my $host = (@_) ? shift : undef;
28             my $errfunc = (@_) ? shift : undef;
29             my $recoverfunc = (@_) ? shift : undef;
30             my $timeout = (@_) ? shift : $default_timeout;
31             my $interval = (@_) ? shift : $default_interval;
32             bless {
33             name => $name,
34             timeout => $timeout,
35             interval => $interval,
36             host => $host,
37             errfunc => $errfunc,
38             recoverfunc => $recoverfunc,
39             pid => undef,
40             start => 0,
41             }, $pkg;
42             }
43              
44             #=======================================================================
45             sub setName
46             {
47             my $self = shift;
48             my $name = (@_) ? shift : '';
49             $self->{'name'} = $name;
50             if( $self->{'start'} ){
51             $self->stop;
52             $self->start;
53             }
54             }
55              
56             #=======================================================================
57             sub setTimeout
58             {
59             dlog( "<<<" );
60             my $self = shift;
61             my $timeout = (@_) ? shift : $default_timeout;
62             $self->{'timeout'} = $timeout;
63             if( $self->{'start'} ){
64             $self->stop;
65             $self->start;
66             }
67             dlog( ">>>" );
68             }
69              
70             #=======================================================================
71             sub setInterval
72             {
73             dlog( "<<<" );
74             my $self = shift;
75             my $interval = (@_) ? shift : $default_interval;
76             $self->{'interval'} = $interval;
77             if( $self->{'start'} ){
78             $self->stop;
79             $self->start;
80             }
81             dlog( ">>>" );
82             }
83              
84             #=======================================================================
85             sub setHost
86             {
87             dlog( "<<<" );
88             my $self = shift;
89             my $host = (@_) ? shift : undef;
90             $self->{'host'} = $host;
91             if( $self->{'start'} ){
92             $self->stop;
93             $self->start;
94             }
95             dlog( ">>> ");
96             }
97              
98             #=======================================================================
99             sub setErrorFunc
100             {
101             dlog( "<<<" );
102             my $self = shift;
103             my $errfunc = (@_) ? shift : undef;
104             $self->{'errfunc'} = $errfunc;
105             if( $self->{'start'} ){
106             $self->stop;
107             $self->start;
108             }
109             dlog( ">>>" );
110             }
111              
112             #=======================================================================
113             sub setRecoverFunc
114             {
115             dlog( "<<<" );
116             my $self = shift;
117             my $recoverfunc = (@_) ? shift : undef;
118             $self->{'recoverfunc'} = $recoverfunc;
119             if( $self->{'start'} ){
120             $self->stop;
121             $self->start;
122             }
123             dlog( ">>>" );
124             }
125              
126             #=======================================================================
127             sub start
128             {
129             dlog( "<<<" );
130             my $self = shift;
131              
132             my $retval = 1;
133             if( $self->{'start'} ){
134             dlog( "already started." );
135             } else {
136             my $pid;
137             $pid = threads->new( \&ping_thread, $self );
138             $self->{'pid'} = $pid;
139             $self->{'start'} = 1;
140             $retval = 0;
141             }
142             dlog( ">>>" );
143             return $retval;
144             }
145              
146             #=======================================================================
147             sub stop
148             {
149             dlog( "<<<" );
150             my $self = shift;
151              
152             my $retval = 1;
153             if( !$self->{'start'} ){
154             dlog( "already stoped." );
155             } else {
156             $self->{'pid'}->kill('KILL')->detach();
157             $self->{'pid'} = undef;
158             $self->{'start'} = 0;
159             $retval = 0;
160             }
161             dlog( ">>>" );
162             return $retval;
163             }
164              
165             #=======================================================================
166             sub ping_thread
167             {
168             dlog( "<<<" );
169             my $self = shift;
170             my $stat = 1;
171             my $old_stat = undef;
172              
173             $SIG{'KILL'} = sub { threads->exit(); };
174              
175             while( 1 ){
176             my $pid = threads->new( \&ping, $self );
177             my $t = 0;
178             while( 1 ){
179             if( $pid->is_running ){
180             $stat = 1;
181             } else {
182             $stat = $pid->join();
183             last;
184             }
185             if( $t >= $self->{'timeout'} ){
186             $pid->kill('KILL')->detach();
187             $stat = 1;
188             last;
189             }
190             sleep( 0.1 );
191             $t += 0.1;
192             }
193             if( defined( $old_stat ) ){
194             if( $old_stat != $stat ){
195             my $func = undef;
196             dlog( "stat=${stat}" );
197             if( $stat ){
198             $func = $self->{'errfunc'};
199             } else {
200             $func = $self->{'recoverfunc'};
201             }
202             if( ref( $func ) eq 'CODE' ){
203             &{$func}( $self->{'name'}, $self->{'host'} );
204             }
205             }
206             }
207             $old_stat = $stat;
208             sleep( $self->{'interval'} - $t );
209             }
210              
211             dlog( ">>>" );
212             return $stat;
213             }
214              
215             #=======================================================================
216             sub ping
217             {
218             my $self = shift;
219             dlog( "<<<". $self->{'host'} );
220             $SIG{'KILL'} = sub { threads->exit(); };
221             my $retval = 1;
222              
223             if( !$self->{'host'} ){
224             $retval = 1;
225             } else {
226             my $cmd = 'ping -c 1 -n -q '. $self->{'host'};
227             my $res = `${cmd}`;
228              
229             if( $res =~m/ 0%/ ){
230             $retval = 0;
231             } else {
232             $retval = 1;
233             }
234             }
235             dlog( ">>>". $retval );
236             return $retval;
237             }
238              
239             1; # Magic true value required at end of module
240             __END__
241              
242             =head1 NAME
243              
244             TRD::Watch::Ping - [One line description of module's purpose here]
245              
246              
247             =head1 VERSION
248              
249             This document describes TRD::Watch::Ping version 0.0.1
250              
251              
252             =head1 SYNOPSIS
253              
254             use TRD::Watch::Ping;
255              
256             =for author to fill in:
257             Brief code example(s) here showing commonest usage(s).
258             This section will be as far as many users bother reading
259             so make it as educational and exeplary as possible.
260            
261            
262             =head1 DESCRIPTION
263              
264             =for author to fill in:
265             Write a full description of the module and its features here.
266             Use subsections (=head2, =head3) as appropriate.
267              
268              
269             =head1 INTERFACE
270              
271             =for author to fill in:
272             Write a separate section listing the public components of the modules
273             interface. These normally consist of either subroutines that may be
274             exported, or methods that may be called on objects belonging to the
275             classes provided by the module.
276              
277              
278             =head1 DIAGNOSTICS
279              
280             =for author to fill in:
281             List every single error and warning message that the module can
282             generate (even the ones that will "never happen"), with a full
283             explanation of each problem, one or more likely causes, and any
284             suggested remedies.
285              
286             =over
287              
288             =item C<< Error message here, perhaps with %s placeholders >>
289              
290             [Description of error here]
291              
292             =item C<< Another error message here >>
293              
294             [Description of error here]
295              
296             [Et cetera, et cetera]
297              
298             =back
299              
300              
301             =head1 CONFIGURATION AND ENVIRONMENT
302              
303             =for author to fill in:
304             A full explanation of any configuration system(s) used by the
305             module, including the names and locations of any configuration
306             files, and the meaning of any environment variables or properties
307             that can be set. These descriptions must also include details of any
308             configuration language used.
309            
310             TRD::Watch::Ping requires no configuration files or environment variables.
311              
312              
313             =head1 DEPENDENCIES
314              
315             =for author to fill in:
316             A list of all the other modules that this module relies upon,
317             including any restrictions on versions, and an indication whether
318             the module is part of the standard Perl distribution, part of the
319             module's distribution, or must be installed separately. ]
320              
321             None.
322              
323              
324             =head1 INCOMPATIBILITIES
325              
326             =for author to fill in:
327             A list of any modules that this module cannot be used in conjunction
328             with. This may be due to name conflicts in the interface, or
329             competition for system or program resources, or due to internal
330             limitations of Perl (for example, many modules that use source code
331             filters are mutually incompatible).
332              
333             None reported.
334              
335              
336             =head1 BUGS AND LIMITATIONS
337              
338             =for author to fill in:
339             A list of known problems with the module, together with some
340             indication Whether they are likely to be fixed in an upcoming
341             release. Also a list of restrictions on the features the module
342             does provide: data types that cannot be handled, performance issues
343             and the circumstances in which they may arise, practical
344             limitations on the size of data sets, special cases that are not
345             (yet) handled, etc.
346              
347             No bugs have been reported.
348              
349             Please report any bugs or feature requests to
350             C<bug-trd-watch-ping@rt.cpan.org>, or through the web interface at
351             L<http://rt.cpan.org>.
352              
353              
354             =head1 AUTHOR
355              
356             Takuya Ichikawa C<< <ichi@cpan.org> >>
357              
358              
359             =head1 LICENCE AND COPYRIGHT
360              
361             Copyright (c) 2009, Takuya Ichikawa C<< <ichi@cpan.org> >>. All rights reserved.
362              
363             This module is free software; you can redistribute it and/or
364             modify it under the same terms as Perl itself. See L<perlartistic>.
365              
366              
367             =head1 DISCLAIMER OF WARRANTY
368              
369             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
370             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
371             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
372             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
373             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
374             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
375             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
376             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
377             NECESSARY SERVICING, REPAIR, OR CORRECTION.
378              
379             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
380             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
381             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
382             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
383             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
384             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
385             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
386             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
387             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
388             SUCH DAMAGES.