File Coverage

blib/lib/AnyEvent/Ping/TCP.pm
Criterion Covered Total %
statement 18 46 39.1
branch 0 8 0.0
condition 0 4 0.0
subroutine 6 11 54.5
pod 3 3 100.0
total 27 72 37.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             AnyEvent::Ping::TCP - Asynchronous and Synchronous TCP ping functions.
4              
5             =head1 SYNOPSIS
6              
7             use AnyEvent::Ping::TCP;
8            
9             # Synchronous TCP Ping
10             my $latency = tcp_ping 'www.google.co.nz', 80;
11            
12             # Asynchronous TCP Ping
13             tcp_ping_syn 'www.google.co.nz', 80;
14            
15             # Sometime later
16             my $latency = tcp_ping_ack 'www.google.co.nz', 80;
17            
18             =head1 DESCRIPTION
19              
20             This module provides a very simple implementation of TCP Ping, with both an asynchronous and synchronous interface.
21              
22             Latency is always returned in milliseconds, and is provided by Time::HiRes
23              
24             Socket functionality is provided by AnyEvent::Socket
25              
26             All functions are exported by default.
27              
28             =cut
29              
30             package AnyEvent::Ping::TCP;
31              
32 1     1   24369 use strict;
  1         2  
  1         50  
33 1     1   6 use warnings;
  1         1  
  1         40  
34              
35 1     1   1403 use AnyEvent;
  1         6847  
  1         37  
36 1     1   763 use AnyEvent::Socket;
  1         34926  
  1         170  
37 1     1   785 use Time::HiRes qw ( time );
  1         1926  
  1         5  
38              
39 1     1   234 use base 'Exporter';
  1         2  
  1         613  
40              
41             our @EXPORT = qw( tcp_ping_syn tcp_ping_ack tcp_ping );
42              
43             our $VERSION = '1.01';
44              
45             our %PingQueue = ();
46              
47             =head2 Synchronous API
48              
49             =over 4
50            
51             =item $latency = tcp_ping $site, $port [, $timeout]
52              
53             Measures the time taken to connect to the provided $site:$port and returns it synchronously.
54              
55             $timeout is optional, and defaults to 5 seconds if not provided.
56              
57             =back
58              
59             =cut
60              
61             sub tcp_ping {
62 0     0 1   my $host = shift;
63 0           my $port = shift;
64 0   0       my $timeout = shift || 5;
65              
66 0           tcp_ping_syn($host, $port, $timeout);
67 0           return tcp_ping_ack($host, $port);
68             }
69              
70             =head2 Asynchronous API
71              
72             =over 4
73              
74             =item tcp_ping_syn $site, $port [, $timeout]
75              
76             Initiates the connection to the provided $site:$port and sets a callback to calculate the latency. Correct latency measurement is
77             not dependant on timely calls to tcp_ping_ack.
78              
79             $timeout is optional, and defaults to 5 seconds if not provided.
80              
81             If this function is called multiple times for the same $site:$port pair, a counter indicating the number of responses requrested is
82             incremented per call, but additional connections are not initiated - it is therefore safe to call this function on an unsorted list of
83             $site:$port pairs.
84              
85             =cut
86              
87             sub tcp_ping_syn {
88 0     0 1   my $host = shift;
89 0           my $port = shift;
90 0   0       my $timeout = shift || 5;
91              
92 0 0         if ((++$PingQueue{$host}{$port}{Requests}) > 1) {
93             # Ping already underway...
94 0           return;
95             }
96            
97 0           my $cv = AnyEvent->condvar;
98 0           my $startTime;
99             my $endTime;
100            
101 0           $PingQueue{$host}{$port}{CondVar} = $cv;
102            
103             tcp_connect $host, $port, sub {
104 0     0     $endTime = time;
105 0           my ($fh) = @_;
106            
107 0 0         $cv->send(( $fh ? (($endTime - $startTime) * 1000) : undef ));
108             },
109             sub {
110 0     0     $startTime = time;
111 0           $timeout;
112 0           };
113            
114 0           return undef;
115             }
116              
117             =item $latency = tcp_ping_ack $site, $port;
118              
119             Waits for the latency of the connection to the $site:$port pair. If the connection has already completed, it returns the latency immediately.
120              
121             This function uses the counter maintained by tcp_ping_syn to know how many responses are expected before cleaning up the memory associated with
122             the ping operation. Again, this allows the calling program to be fairly naive about the lists it uses. All tcp_ping_syn calls for a given
123             $site:$port pair will yield the same latency value until tcp_ping_ack has drained the queue. Only then will a new connection and measurement
124             be taken.
125              
126             =back
127              
128             =cut
129              
130             sub tcp_ping_ack {
131 0     0 1   my $host = shift;
132 0           my $port = shift;
133            
134 0 0         if ($PingQueue{$host}{$port}{Requests} < 1) {
135             # No outstanding requests...
136 0           return undef;
137             }
138              
139 0           my $latency = $PingQueue{$host}{$port}{CondVar}->recv;
140            
141 0 0         if ((--$PingQueue{$host}{$port}{Requests}) < 1) {
142             # Responded to last request.
143 0           $PingQueue{$host}{$port}{CondVar} = undef;
144             }
145            
146 0           return $latency;
147             }
148              
149              
150             =head1 SEE ALSO
151              
152             L
153             L
154             L
155              
156             =head1 AUTHOR
157              
158             Phillip O'Donnell, Epodonnell@cpan.orgE
159              
160             =head1 COPYRIGHT AND LICENSE
161              
162             Copyright (C) 2013 by Phillip O'Donnell
163              
164             This library is free software; you can redistribute it and/or modify
165             it under the same terms as Perl itself, either Perl version 5.10.1 or,
166             at your option, any later version of Perl 5 you may have available.
167              
168             =cut
169              
170             1;
171