File Coverage

blib/lib/Net/Ping.pm
Criterion Covered Total %
statement 507 881 57.5
branch 220 568 38.7
condition 89 334 26.6
subroutine 55 75 73.3
pod 36 36 100.0
total 907 1894 47.8


line stmt bran cond sub pod time code
1             package Net::Ping;
2              
3             require 5.002;
4             require Exporter;
5              
6 20     20   1311534 use strict;
  20         180  
  20         882  
7 20         2515 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION
8             $def_timeout $def_proto $def_factor $def_family
9 20     20   120 $max_datasize $pingstring $hires $source_verify $syn_forking);
  20         34  
10 20     20   134 use Fcntl qw( F_GETFL F_SETFL O_NONBLOCK );
  20         35  
  20         1619  
11 20         4956 use Socket qw( SOCK_DGRAM SOCK_STREAM SOCK_RAW AF_INET PF_INET IPPROTO_TCP
12             SOL_SOCKET SO_ERROR SO_BROADCAST
13             IPPROTO_IP IP_TOS IP_TTL
14 20     20   3572 inet_ntoa inet_aton getnameinfo sockaddr_in );
  20         22236  
15 20         456 use POSIX qw( ENOTCONN ECONNREFUSED ECONNRESET EINPROGRESS EWOULDBLOCK EAGAIN
16 20     20   10162 WNOHANG );
  20         125859  
17 20     20   37324 use FileHandle;
  20         188836  
  20         113  
18 20     20   6390 use Carp;
  20         47  
  20         1266  
19 20     20   9972 use Time::HiRes;
  20         24157  
  20         95  
20              
21             @ISA = qw(Exporter);
22             @EXPORT = qw(pingecho);
23             @EXPORT_OK = qw(wakeonlan);
24             $VERSION = "2.73";
25              
26             # Globals
27              
28             $def_timeout = 5; # Default timeout to wait for a reply
29             $def_proto = "tcp"; # Default protocol to use for pinging
30             $def_factor = 1.2; # Default exponential backoff rate.
31             $def_family = AF_INET; # Default family.
32             $max_datasize = 65535; # Maximum data bytes. recommended: 1472 (Ethernet MTU: 1500)
33             # The data we exchange with the server for the stream protocol
34             $pingstring = "pingschwingping!\n";
35             $source_verify = 1; # Default is to verify source endpoint
36             $syn_forking = 0;
37              
38             # Constants
39              
40             my $AF_INET6 = eval { Socket::AF_INET6() } || 30;
41             my $AF_UNSPEC = eval { Socket::AF_UNSPEC() };
42             my $AI_NUMERICHOST = eval { Socket::AI_NUMERICHOST() } || 4;
43             my $NI_NUMERICHOST = eval { Socket::NI_NUMERICHOST() } || 2;
44             my $IPPROTO_IPV6 = eval { Socket::IPPROTO_IPV6() } || 41;
45             my $NIx_NOSERV = eval { Socket::NIx_NOSERV() } || 2;
46             #my $IPV6_HOPLIMIT = eval { Socket::IPV6_HOPLIMIT() }; # ping6 -h 0-255
47             my $qr_family = qr/^(?:(?:(:?ip)?v?(?:4|6))|${\AF_INET}|$AF_INET6)$/;
48             my $qr_family4 = qr/^(?:(?:(:?ip)?v?4)|${\AF_INET})$/;
49             my $Socket_VERSION = eval { $Socket::VERSION };
50              
51             if ($^O =~ /Win32/i) {
52             # Hack to avoid this Win32 spewage:
53             # Your vendor has not defined POSIX macro ECONNREFUSED
54             my @pairs = (ECONNREFUSED => 10061, # "Unknown Error" Special Win32 Response?
55             ENOTCONN => 10057,
56             ECONNRESET => 10054,
57             EINPROGRESS => 10036,
58             EWOULDBLOCK => 10035,
59             );
60             while (my $name = shift @pairs) {
61             my $value = shift @pairs;
62             # When defined, these all are non-zero
63             unless (eval $name) {
64 20     20   7070 no strict 'refs';
  20         36  
  20         70718  
65             *{$name} = defined prototype \&{$name} ? sub () {$value} : sub {$value};
66             }
67             }
68             # $syn_forking = 1; # XXX possibly useful in < Win2K ?
69             };
70              
71             # Description: The pingecho() subroutine is provided for backward
72             # compatibility with the original Net::Ping. It accepts a host
73             # name/IP and an optional timeout in seconds. Create a tcp ping
74             # object and try pinging the host. The result of the ping is returned.
75              
76             sub pingecho
77             {
78 1     1 1 91 my ($host, # Name or IP number of host to ping
79             $timeout # Optional timeout in seconds
80             ) = @_;
81 1         2 my ($p); # A ping object
82              
83 1         5 $p = Net::Ping->new("tcp", $timeout);
84 1         12 $p->ping($host); # Going out of scope closes the connection
85             }
86              
87             # Description: The new() method creates a new ping object. Optional
88             # parameters may be specified for the protocol to use, the timeout in
89             # seconds and the size in bytes of additional data which should be
90             # included in the packet.
91             # After the optional parameters are checked, the data is constructed
92             # and a socket is opened if appropriate. The object is returned.
93              
94             sub new
95             {
96 41     41 1 11965 my ($this,
97             $proto, # Optional protocol to use for pinging
98             $timeout, # Optional timeout in seconds
99             $data_size, # Optional additional bytes of data
100             $device, # Optional device to use
101             $tos, # Optional ToS to set
102             $ttl, # Optional TTL to set
103             $family, # Optional address family (AF_INET)
104             ) = @_;
105 41   66     257 my $class = ref($this) || $this;
106 41         99 my $self = {};
107 41         86 my ($cnt, # Count through data bytes
108             $min_datasize # Minimum data bytes required
109             );
110              
111 41         81 bless($self, $class);
112 41 100       120 if (ref $proto eq 'HASH') { # support named args
113 1         5 for my $k (qw(proto timeout data_size device tos ttl family
114             gateway host port bind retrans pingstring source_verify
115             econnrefused dontfrag
116             IPV6_USE_MIN_MTU IPV6_RECVPATHMTU IPV6_HOPLIMIT))
117             {
118 19 100       33 if (exists $proto->{$k}) {
119 2         5 $self->{$k} = $proto->{$k};
120             # some are still globals
121 2 50       4 if ($k eq 'pingstring') { $pingstring = $proto->{$k} }
  0         0  
122 2 50       5 if ($k eq 'source_verify') { $source_verify = $proto->{$k} }
  0         0  
123             # and some are local
124 2 50       3 $timeout = $proto->{$k} if ($k eq 'timeout');
125 2 50       5 $data_size = $proto->{$k} if ($k eq 'data_size');
126 2 50       3 $device = $proto->{$k} if ($k eq 'device');
127 2 50       38 $tos = $proto->{$k} if ($k eq 'tos');
128 2 100       6 $ttl = $proto->{$k} if ($k eq 'ttl');
129 2 50       4 $family = $proto->{$k} if ($k eq 'family');
130 2         5 delete $proto->{$k};
131             }
132             }
133 1 50       32 if (%$proto) {
134 0         0 croak("Invalid named argument: ",join(" ",keys (%$proto)));
135             }
136 1         5 $proto = $self->{'proto'};
137             }
138              
139 41 100       111 $proto = $def_proto unless $proto; # Determine the protocol
140 41 100       524 croak('Protocol for ping must be "icmp", "icmpv6", "udp", "tcp", "syn", "stream" or "external"')
141             unless $proto =~ m/^(icmp|icmpv6|udp|tcp|syn|stream|external)$/;
142 40         204 $self->{proto} = $proto;
143              
144 40 100       121 $timeout = $def_timeout unless defined $timeout; # Determine the timeout
145 40 100       203 croak("Default timeout for ping must be greater than 0 seconds")
146             if $timeout <= 0;
147 39         90 $self->{timeout} = $timeout;
148              
149 39         83 $self->{device} = $device;
150              
151 39         74 $self->{tos} = $tos;
152              
153 39 50       102 if ($self->{'host'}) {
154 0         0 my $host = $self->{'host'};
155 0 0       0 my $ip = $self->_resolv($host) or
156             carp("could not resolve host $host");
157 0         0 $self->{host} = $ip;
158 0         0 $self->{family} = $ip->{family};
159             }
160              
161 39 50       112 if ($self->{bind}) {
162 0         0 my $addr = $self->{bind};
163 0 0       0 my $ip = $self->_resolv($addr)
164             or carp("could not resolve local addr $addr");
165 0         0 $self->{local_addr} = $ip;
166             } else {
167 39         83 $self->{local_addr} = undef; # Don't bind by default
168             }
169              
170 39 100       114 if ($self->{proto} eq 'icmp') {
171 11 100 100     353 croak('TTL must be from 0 to 255')
      100        
172             if ($ttl && ($ttl < 0 || $ttl > 255));
173 9         11 $self->{ttl} = $ttl;
174             }
175              
176 37 50       90 if ($family) {
177 0 0       0 if ($family =~ $qr_family) {
178 0 0       0 if ($family =~ $qr_family4) {
179 0         0 $self->{family} = AF_INET;
180             } else {
181 0         0 $self->{family} = $AF_INET6;
182             }
183             } else {
184 0         0 croak('Family must be "ipv4" or "ipv6"')
185             }
186             } else {
187 37 100       111 if ($self->{proto} eq 'icmpv6') {
188 1         4 $self->{family} = $AF_INET6;
189             } else {
190 36         96 $self->{family} = $def_family;
191             }
192             }
193              
194 37 100       103 $min_datasize = ($proto eq "udp") ? 1 : 0; # Determine data size
195 37 100 66     152 $data_size = $min_datasize unless defined($data_size) && $proto ne "tcp";
196             # allow for fragmented packets if data_size>1472 (MTU 1500)
197 37 100 100     384 croak("Data for ping must be from $min_datasize to $max_datasize bytes")
198             if ($data_size < $min_datasize) || ($data_size > $max_datasize);
199 35 100       108 $data_size-- if $self->{proto} eq "udp"; # We provide the first byte
200 35         77 $self->{data_size} = $data_size;
201              
202 35         108 $self->{data} = ""; # Construct data bytes
203 35         118 for ($cnt = 0; $cnt < $self->{data_size}; $cnt++)
204             {
205 0         0 $self->{data} .= chr($cnt % 256);
206             }
207              
208             # Default exponential backoff rate
209 35 50       133 $self->{retrans} = $def_factor unless exists $self->{retrans};
210             # Default Connection refused behavior
211 35 50       105 $self->{econnrefused} = undef unless exists $self->{econnrefused};
212              
213 35         76 $self->{seq} = 0; # For counting packets
214 35 100 100     284 if ($self->{proto} eq "udp") # Open a socket
    100          
    100          
    100          
    50          
215             {
216 2   33     4 $self->{proto_num} = eval { (getprotobyname('udp'))[2] } ||
217             croak("Can't udp protocol by name");
218             $self->{port_num} = $self->{port}
219 2   33     93 || (getservbyname('echo', 'udp'))[2]
220             || croak("Can't get udp echo port by name");
221 2         22 $self->{fh} = FileHandle->new();
222             socket($self->{fh}, PF_INET, SOCK_DGRAM,
223 2 50       233 $self->{proto_num}) ||
224             croak("udp socket error - $!");
225 2         15 $self->_setopts();
226             }
227             elsif ($self->{proto} eq "icmp")
228             {
229 9 50       32 croak("icmp ping requires root privilege") if !_isroot();
230 9   33     19 $self->{proto_num} = eval { (getprotobyname('icmp'))[2] } ||
231             croak("Can't get icmp protocol by name");
232 9         46 $self->{pid} = $$ & 0xffff; # Save lower 16 bits of pid
233 9         71 $self->{fh} = FileHandle->new();
234 9 50       733 socket($self->{fh}, PF_INET, SOCK_RAW, $self->{proto_num}) ||
235             croak("icmp socket error - $!");
236 9         47 $self->_setopts();
237 9 100       27 if ($self->{'ttl'}) {
238 2 50       29 setsockopt($self->{fh}, IPPROTO_IP, IP_TTL, pack("I*", $self->{'ttl'}))
239             or croak "error configuring ttl to $self->{'ttl'} $!";
240             }
241             }
242             elsif ($self->{proto} eq "icmpv6")
243             {
244             #croak("icmpv6 ping requires root privilege") if !_isroot();
245             croak("Wrong family $self->{family} for icmpv6 protocol")
246 1 50 33     8 if $self->{family} and $self->{family} != $AF_INET6;
247 1         3 $self->{family} = $AF_INET6;
248 1   33     2 $self->{proto_num} = eval { (getprotobyname('ipv6-icmp'))[2] } ||
249             croak("Can't get ipv6-icmp protocol by name"); # 58
250 1         8 $self->{pid} = $$ & 0xffff; # Save lower 16 bits of pid
251 1         9 $self->{fh} = FileHandle->new();
252 1 50       115 socket($self->{fh}, $AF_INET6, SOCK_RAW, $self->{proto_num}) ||
253             croak("icmp socket error - $!");
254 1         6 $self->_setopts();
255 1 50       4 if ($self->{'gateway'}) {
256 0         0 my $g = $self->{gateway};
257 0 0       0 my $ip = $self->_resolv($g)
258             or croak("nonexistent gateway $g");
259 0 0       0 $self->{family} eq $AF_INET6
260             or croak("gateway requires the AF_INET6 family");
261 0 0       0 $ip->{family} eq $AF_INET6
262             or croak("gateway address needs to be IPv6");
263 0   0     0 my $IPV6_NEXTHOP = eval { Socket::IPV6_NEXTHOP() } || 48; # IPV6_3542NEXTHOP, or 21
264 0 0       0 setsockopt($self->{fh}, $IPPROTO_IPV6, $IPV6_NEXTHOP, _pack_sockaddr_in($ip))
265             or croak "error configuring gateway to $g NEXTHOP $!";
266             }
267 1 50       4 if (exists $self->{IPV6_USE_MIN_MTU}) {
268 0   0     0 my $IPV6_USE_MIN_MTU = eval { Socket::IPV6_USE_MIN_MTU() } || 42;
269             setsockopt($self->{fh}, $IPPROTO_IPV6, $IPV6_USE_MIN_MTU,
270 0 0       0 pack("I*", $self->{'IPV6_USE_MIN_MT'}))
271             or croak "error configuring IPV6_USE_MIN_MT} $!";
272             }
273 1 50       4 if (exists $self->{IPV6_RECVPATHMTU}) {
274 0   0     0 my $IPV6_RECVPATHMTU = eval { Socket::IPV6_RECVPATHMTU() } || 43;
275             setsockopt($self->{fh}, $IPPROTO_IPV6, $IPV6_RECVPATHMTU,
276 0 0       0 pack("I*", $self->{'RECVPATHMTU'}))
277             or croak "error configuring IPV6_RECVPATHMTU $!";
278             }
279 1 50       54 if ($self->{'tos'}) {
280 0 0       0 my $proto = $self->{family} == AF_INET ? IPPROTO_IP : $IPPROTO_IPV6;
281 0 0       0 setsockopt($self->{fh}, $proto, IP_TOS, pack("I*", $self->{'tos'}))
282             or croak "error configuring tos to $self->{'tos'} $!";
283             }
284 1 50       7 if ($self->{'ttl'}) {
285 0 0       0 my $proto = $self->{family} == AF_INET ? IPPROTO_IP : $IPPROTO_IPV6;
286 0 0       0 setsockopt($self->{fh}, $proto, IP_TTL, pack("I*", $self->{'ttl'}))
287             or croak "error configuring ttl to $self->{'ttl'} $!";
288             }
289             }
290             elsif ($self->{proto} eq "tcp" || $self->{proto} eq "stream")
291             {
292 15   33     37 $self->{proto_num} = eval { (getprotobyname('tcp'))[2] } ||
293             croak("Can't get tcp protocol by name");
294             $self->{port_num} = $self->{port}
295 15   33     725 || (getservbyname('echo', 'tcp'))[2]
296             || croak("Can't get tcp echo port by name");
297 15         176 $self->{fh} = FileHandle->new();
298             }
299             elsif ($self->{proto} eq "syn")
300             {
301 8   33     30 $self->{proto_num} = eval { (getprotobyname('tcp'))[2] } ||
302             croak("Can't get tcp protocol by name");
303 8   33     279 $self->{port_num} = (getservbyname('echo', 'tcp'))[2] ||
304             croak("Can't get tcp echo port by name");
305 8 50       36 if ($syn_forking) {
306 0         0 $self->{fork_rd} = FileHandle->new();
307 0         0 $self->{fork_wr} = FileHandle->new();
308 0         0 pipe($self->{fork_rd}, $self->{fork_wr});
309 0         0 $self->{fh} = FileHandle->new();
310 0         0 $self->{good} = {};
311 0         0 $self->{bad} = {};
312             } else {
313 8         21 $self->{wbits} = "";
314 8         19 $self->{bad} = {};
315             }
316 8         34 $self->{syn} = {};
317 8         17 $self->{stop_time} = 0;
318             }
319              
320 35         984 return($self);
321             }
322              
323             # Description: Set the local IP address from which pings will be sent.
324             # For ICMP, UDP and TCP pings, just saves the address to be used when
325             # the socket is opened. Returns non-zero if successful; croaks on error.
326             sub bind
327             {
328 0     0 1 0 my ($self,
329             $local_addr # Name or IP number of local interface
330             ) = @_;
331 0         0 my ($ip, # Hash of addr (string), addr_in (packed), family
332             $h # resolved hash
333             );
334              
335 0 0       0 croak("Usage: \$p->bind(\$local_addr)") unless @_ == 2;
336             croak("already bound") if defined($self->{local_addr}) &&
337 0 0 0     0 ($self->{proto} eq "udp" || $self->{proto} eq "icmp");
      0        
338              
339 0         0 $ip = $self->_resolv($local_addr);
340 0 0       0 carp("nonexistent local address $local_addr") unless defined($ip);
341 0         0 $self->{local_addr} = $ip;
342              
343 0 0 0     0 if (($self->{proto} ne "udp") &&
      0        
      0        
344             ($self->{proto} ne "icmp") &&
345             ($self->{proto} ne "tcp") &&
346             ($self->{proto} ne "syn"))
347             {
348 0         0 croak("Unknown protocol \"$self->{proto}\" in bind()");
349             }
350              
351 0         0 return 1;
352             }
353              
354             # Description: A select() wrapper that compensates for platform
355             # peculiarities.
356             sub mselect
357             {
358 63 50 33 63 1 401 if ($_[3] > 0 and $^O eq 'MSWin32') {
359             # On windows, select() doesn't process the message loop,
360             # but sleep() will, allowing alarm() to interrupt the latter.
361             # So we chop up the timeout into smaller pieces and interleave
362             # select() and sleep() calls.
363 0         0 my $t = $_[3];
364 0         0 my $gran = 0.5; # polling granularity in seconds
365 0         0 my @args = @_;
366 0         0 while (1) {
367 0 0       0 $gran = $t if $gran > $t;
368 0         0 my $nfound = select($_[0], $_[1], $_[2], $gran);
369 0 0       0 undef $nfound if $nfound == -1;
370 0         0 $t -= $gran;
371 0 0 0     0 return $nfound if $nfound or !defined($nfound) or $t <= 0;
      0        
372              
373 0         0 sleep(0);
374 0         0 ($_[0], $_[1], $_[2]) = @args;
375             }
376             }
377             else {
378 63         54801594 my $nfound = select($_[0], $_[1], $_[2], $_[3]);
379 63 50       524 undef $nfound if $nfound == -1;
380 62         617 return $nfound;
381             }
382             }
383              
384             # Description: Allow UDP source endpoint comparison to be
385             # skipped for those remote interfaces that do
386             # not response from the same endpoint.
387              
388             sub source_verify
389             {
390 0     0 1 0 my $self = shift;
391 0 0 0     0 $source_verify = 1 unless defined
    0          
392             ($source_verify = ((defined $self) && (ref $self)) ? shift() : $self);
393             }
394              
395             # Description: Set whether or not the connect
396             # behavior should enforce remote service
397             # availability as well as reachability.
398              
399             sub service_check
400             {
401 14     14 1 2351 my $self = shift;
402             $self->{econnrefused} = 1 unless defined
403 14 50       47 ($self->{econnrefused} = shift());
404             }
405              
406             sub tcp_service_check
407             {
408 0     0 1 0 service_check(@_);
409             }
410              
411             # Description: Set exponential backoff for retransmission.
412             # Should be > 1 to retain exponential properties.
413             # If set to 0, retransmissions are disabled.
414              
415             sub retrans
416             {
417 0     0 1 0 my $self = shift;
418 0         0 $self->{retrans} = shift;
419             }
420              
421             sub _IsAdminUser {
422 0 0 0 0   0 return unless $^O eq 'MSWin32' or $^O eq "cygwin";
423 0 0       0 return unless eval { require Win32 };
  0         0  
424 0 0       0 return unless defined &Win32::IsAdminUser;
425 0         0 return Win32::IsAdminUser();
426             }
427              
428             sub _isroot {
429 16 50 33 16   809 if (($> and $^O ne 'VMS' and $^O ne 'cygwin')
      33        
      33        
      33        
      33        
      33        
      33        
430             or (($^O eq 'MSWin32' or $^O eq 'cygwin')
431             and !_IsAdminUser())
432             or ($^O eq 'VMS'
433             and (`write sys\$output f\$privilege("SYSPRV")` =~ m/FALSE/))) {
434 0         0 return 0;
435             }
436             else {
437 16         76 return 1;
438             }
439             }
440              
441             # Description: Sets ipv6 reachability
442             # REACHCONF was removed in RFC3542, ping6 -R supports it. requires root.
443              
444             sub IPV6_REACHCONF
445             {
446 0     0 1 0 my $self = shift;
447 0         0 my $on = shift;
448 0 0       0 if ($on) {
449 0         0 my $reachconf = eval { Socket::IPV6_REACHCONF() };
  0         0  
450 0 0       0 if (!$reachconf) {
451 0         0 carp "IPV6_REACHCONF not supported on this platform";
452 0         0 return 0;
453             }
454 0 0       0 if (!_isroot()) {
455 0         0 carp "IPV6_REACHCONF requires root permissions";
456 0         0 return 0;
457             }
458 0         0 $self->{IPV6_REACHCONF} = 1;
459             }
460             else {
461 0         0 return $self->{IPV6_REACHCONF};
462             }
463             }
464              
465             # Description: set it on or off.
466              
467             sub IPV6_USE_MIN_MTU
468             {
469 0     0 1 0 my $self = shift;
470 0         0 my $on = shift;
471 0 0       0 if (defined $on) {
472 0   0     0 my $IPV6_USE_MIN_MTU = eval { Socket::IPV6_USE_MIN_MTU() } || 43;
473             #if (!$IPV6_USE_MIN_MTU) {
474             # carp "IPV6_USE_MIN_MTU not supported on this platform";
475             # return 0;
476             #}
477 0 0       0 $self->{IPV6_USE_MIN_MTU} = $on ? 1 : 0;
478             setsockopt($self->{fh}, $IPPROTO_IPV6, $IPV6_USE_MIN_MTU,
479 0 0       0 pack("I*", $self->{'IPV6_USE_MIN_MT'}))
480             or croak "error configuring IPV6_USE_MIN_MT} $!";
481             }
482             else {
483 0         0 return $self->{IPV6_USE_MIN_MTU};
484             }
485             }
486              
487             # Description: notify an according MTU
488              
489             sub IPV6_RECVPATHMTU
490             {
491 0     0 1 0 my $self = shift;
492 0         0 my $on = shift;
493 0 0       0 if ($on) {
494 0   0     0 my $IPV6_RECVPATHMTU = eval { Socket::IPV6_RECVPATHMTU() } || 43;
495             #if (!$RECVPATHMTU) {
496             # carp "IPV6_RECVPATHMTU not supported on this platform";
497             # return 0;
498             #}
499 0         0 $self->{IPV6_RECVPATHMTU} = 1;
500             setsockopt($self->{fh}, $IPPROTO_IPV6, $IPV6_RECVPATHMTU,
501 0 0       0 pack("I*", $self->{'IPV6_RECVPATHMTU'}))
502             or croak "error configuring IPV6_RECVPATHMTU} $!";
503             }
504             else {
505 0         0 return $self->{IPV6_RECVPATHMTU};
506             }
507             }
508              
509             # Description: allows the module to use milliseconds as returned by
510             # the Time::HiRes module
511              
512             $hires = 1;
513             sub hires
514             {
515 3     3 1 1850 my $self = shift;
516 3 50 33     18 $hires = 1 unless defined
    100          
517             ($hires = ((defined $self) && (ref $self)) ? shift() : $self);
518             }
519              
520             sub time
521             {
522 108 50   108 1 484 return $hires ? Time::HiRes::time() : CORE::time();
523             }
524              
525             # Description: Sets or clears the O_NONBLOCK flag on a file handle.
526             sub socket_blocking_mode
527             {
528 81     81 1 204 my ($self,
529             $fh, # the file handle whose flags are to be modified
530             $block) = @_; # if true then set the blocking
531             # mode (clear O_NONBLOCK), otherwise
532             # set the non-blocking mode (set O_NONBLOCK)
533              
534 81         131 my $flags;
535 81 50 33     601 if ($^O eq 'MSWin32' || $^O eq 'VMS') {
536             # FIONBIO enables non-blocking sockets on windows and vms.
537             # FIONBIO is (0x80000000|(4<<16)|(ord('f')<<8)|126), as per winsock.h, ioctl.h
538 0         0 my $f = 0x8004667e;
539 0 0       0 my $v = pack("L", $block ? 0 : 1);
540 0 0       0 ioctl($fh, $f, $v) or croak("ioctl failed: $!");
541 0         0 return;
542             }
543 81 50       697 if ($flags = fcntl($fh, F_GETFL, 0)) {
544 81 100       315 $flags = $block ? ($flags & ~O_NONBLOCK) : ($flags | O_NONBLOCK);
545 81 50       575 if (!fcntl($fh, F_SETFL, $flags)) {
546 0         0 croak("fcntl F_SETFL: $!");
547             }
548             } else {
549 0         0 croak("fcntl F_GETFL: $!");
550             }
551             }
552              
553             # Description: Ping a host name or IP number with an optional timeout.
554             # First lookup the host, and return undef if it is not found. Otherwise
555             # perform the specific ping method based on the protocol. Return the
556             # result of the ping.
557              
558             sub ping
559             {
560 60     60 1 21895 my ($self,
561             $host, # Name or IP number of host to ping
562             $timeout, # Seconds after which ping times out
563             $family, # Address family
564             ) = @_;
565 60         127 my ($ip, # Hash of addr (string), addr_in (packed), family
566             $ret, # The return value
567             $ping_time, # When ping began
568             );
569              
570 60 0 33     195 $host = $self->{host} if !defined $host and $self->{host};
571 60 50 33     298 croak("Usage: \$p->ping([ \$host [, \$timeout [, \$family]]])") if @_ > 4 or !$host;
572 60 50       205 $timeout = $self->{timeout} unless $timeout;
573 60 50       209 croak("Timeout must be greater than 0 seconds") if $timeout <= 0;
574              
575 60 50       160 if ($family) {
576 0 0       0 if ($family =~ $qr_family) {
577 0 0       0 if ($family =~ $qr_family4) {
578 0         0 $self->{family_local} = AF_INET;
579             } else {
580 0         0 $self->{family_local} = $AF_INET6;
581             }
582             } else {
583 0         0 croak('Family must be "ipv4" or "ipv6"')
584             }
585             } else {
586 60         146 $self->{family_local} = $self->{family};
587             }
588            
589 60         231 $ip = $self->_resolv($host);
590 60 50       204 return () unless defined($ip); # Does host exist?
591              
592             # Dispatch to the appropriate routine.
593 60         164 $ping_time = &time();
594 60 50       471 if ($self->{proto} eq "external") {
    100          
    100          
    100          
    100          
    50          
    50          
595 0         0 $ret = $self->ping_external($ip, $timeout);
596             }
597             elsif ($self->{proto} eq "udp") {
598 1         5 $ret = $self->ping_udp($ip, $timeout);
599             }
600             elsif ($self->{proto} eq "icmp") {
601 4         11 $ret = $self->ping_icmp($ip, $timeout);
602             }
603             elsif ($self->{proto} eq "icmpv6") {
604 1         4 $ret = $self->ping_icmpv6($ip, $timeout);
605             }
606             elsif ($self->{proto} eq "tcp") {
607 28         97 $ret = $self->ping_tcp($ip, $timeout);
608             }
609             elsif ($self->{proto} eq "stream") {
610 0         0 $ret = $self->ping_stream($ip, $timeout);
611             }
612             elsif ($self->{proto} eq "syn") {
613 26         156 $ret = $self->ping_syn($host, $ip, $ping_time, $ping_time+$timeout);
614             } else {
615 0         0 croak("Unknown protocol \"$self->{proto}\" in ping()");
616             }
617              
618 59 100       513 return wantarray ? ($ret, &time() - $ping_time, $self->ntop($ip)) : $ret;
619             }
620              
621             # Uses Net::Ping::External to do an external ping.
622             sub ping_external {
623 0     0 1 0 my ($self,
624             $ip, # Hash of addr (string), addr_in (packed), family
625             $timeout, # Seconds after which ping times out
626             $family
627             ) = @_;
628              
629 0 0 0     0 $ip = $self->{host} if !defined $ip and $self->{host};
630 0 0 0     0 $timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
631             my @addr = exists $ip->{addr_in}
632             ? ('ip' => $ip->{addr_in})
633 0 0       0 : ('host' => $ip->{host});
634              
635 0 0       0 eval {
636 0         0 local @INC = @INC;
637 0 0       0 pop @INC if $INC[-1] eq '.';
638 0         0 require Net::Ping::External;
639             } or croak('Protocol "external" not supported on your system: Net::Ping::External not found');
640 0         0 return Net::Ping::External::ping(@addr, timeout => $timeout,
641             family => $family);
642             }
643              
644             # h2ph "asm/socket.h"
645             # require "asm/socket.ph";
646 20     20   202 use constant SO_BINDTODEVICE => 25;
  20         48  
  20         2097  
647 20     20   169 use constant ICMP_ECHOREPLY => 0; # ICMP packet types
  20         52  
  20         1080  
648 20     20   127 use constant ICMPv6_ECHOREPLY => 129; # ICMP packet types
  20         39  
  20         1020  
649 20     20   123 use constant ICMP_UNREACHABLE => 3; # ICMP packet types
  20         57  
  20         975  
650 20     20   116 use constant ICMPv6_UNREACHABLE => 1; # ICMP packet types
  20         37  
  20         969  
651 20     20   112 use constant ICMP_ECHO => 8;
  20         41  
  20         1137  
652 20     20   196 use constant ICMPv6_ECHO => 128;
  20         34  
  20         1003  
653 20     20   119 use constant ICMP_TIME_EXCEEDED => 11; # ICMP packet types
  20         43  
  20         1077  
654 20     20   137 use constant ICMP_PARAMETER_PROBLEM => 12; # ICMP packet types
  20         45  
  20         1045  
655 20     20   130 use constant ICMP_TIMESTAMP => 13;
  20         35  
  20         922  
656 20     20   112 use constant ICMP_TIMESTAMP_REPLY => 14;
  20         62  
  20         1256  
657 20     20   130 use constant ICMP_STRUCT => "C2 n3 A"; # Structure of a minimal ICMP packet
  20         37  
  20         1054  
658 20     20   122 use constant ICMP_TIMESTAMP_STRUCT => "C2 n3 N3"; # Structure of a minimal timestamp ICMP packet
  20         38  
  20         1309  
659 20     20   134 use constant SUBCODE => 0; # No ICMP subcode for ECHO and ECHOREPLY
  20         32  
  20         915  
660 20     20   120 use constant ICMP_FLAGS => 0; # No special flags for send or recv
  20         33  
  20         911  
661 20     20   106 use constant ICMP_PORT => 0; # No port with ICMP
  20         44  
  20         924  
662 20     20   122 use constant IP_MTU_DISCOVER => 10; # linux only
  20         44  
  20         59884  
663              
664             sub message_type
665             {
666 6     6 1 1637 my ($self,
667             $type
668             ) = @_;
669              
670             croak "Setting message type only supported on 'icmp' protocol"
671 6 100       813 unless $self->{proto} eq 'icmp';
672              
673 2 100 50     25 return $self->{message_type} || 'echo'
674             unless defined($type);
675              
676 1 50       198 croak "Supported icmp message type are limited to 'echo' and 'timestamp': '$type' not supported"
677             unless $type =~ /^echo|timestamp$/i;
678              
679 0         0 $self->{message_type} = lc($type);
680             }
681              
682             sub ping_icmp
683             {
684 5     5 1 24 my ($self,
685             $ip, # Hash of addr (string), addr_in (packed), family
686             $timeout # Seconds after which ping times out
687             ) = @_;
688              
689 5         16 my ($saddr, # sockaddr_in with port and ip
690             $checksum, # Checksum of ICMP packet
691             $msg, # ICMP packet to send
692             $len_msg, # Length of $msg
693             $rbits, # Read bits, filehandles for reading
694             $nfound, # Number of ready filehandles found
695             $finish_time, # Time ping should be finished
696             $done, # set to 1 when we are done
697             $ret, # Return value
698             $recv_msg, # Received message including IP header
699             $recv_msg_len, # Length of recevied message, less any additional data
700             $from_saddr, # sockaddr_in of sender
701             $from_port, # Port packet was sent from
702             $from_ip, # Packed IP of sender
703             $timestamp_msg, # ICMP timestamp message type
704             $from_type, # ICMP type
705             $from_subcode, # ICMP subcode
706             $from_chk, # ICMP packet checksum
707             $from_pid, # ICMP packet id
708             $from_seq, # ICMP packet sequence
709             $from_msg # ICMP message
710             );
711              
712 5 0 33     12 $ip = $self->{host} if !defined $ip and $self->{host};
713 5 0 33     29 $timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
714 5 50 33     31 $timestamp_msg = $self->{message_type} && $self->{message_type} eq 'timestamp' ? 1 : 0;
715              
716 5 50       232 socket($self->{fh}, $ip->{family}, SOCK_RAW, $self->{proto_num}) ||
717             croak("icmp socket error - $!");
718              
719 5 50 33     26 if (defined $self->{local_addr} &&
720             !CORE::bind($self->{fh}, _pack_sockaddr_in(0, $self->{local_addr}))) {
721 0         0 croak("icmp bind error - $!");
722             }
723 5         29 $self->_setopts();
724              
725 5         18 $self->{seq} = ($self->{seq} + 1) % 65536; # Increment sequence
726 5         8 $checksum = 0; # No checksum for starters
727 5 100       16 if ($ip->{family} == AF_INET) {
728 4 50       9 if ($timestamp_msg) {
729             $msg = pack(ICMP_TIMESTAMP_STRUCT, ICMP_TIMESTAMP, SUBCODE,
730 0         0 $checksum, $self->{pid}, $self->{seq}, 0, 0, 0);
731             } else {
732             $msg = pack(ICMP_STRUCT . $self->{data_size}, ICMP_ECHO, SUBCODE,
733 4         36 $checksum, $self->{pid}, $self->{seq}, $self->{data});
734             }
735             } else {
736             # how to get SRC
737 1         13 my $pseudo_header = pack('a16a16Nnn', $ip->{addr_in}, $ip->{addr_in}, 8+length($self->{data}), 0, 0x003a);
738             $msg = pack(ICMP_STRUCT . $self->{data_size}, ICMPv6_ECHO, SUBCODE,
739 1         7 $checksum, $self->{pid}, $self->{seq}, $self->{data});
740 1         3 $msg = $pseudo_header.$msg
741             }
742 5         25 $checksum = Net::Ping->checksum($msg);
743 5 100       33 if ($ip->{family} == AF_INET) {
744 4 50       11 if ($timestamp_msg) {
745             $msg = pack(ICMP_TIMESTAMP_STRUCT, ICMP_TIMESTAMP, SUBCODE,
746 0         0 $checksum, $self->{pid}, $self->{seq}, 0, 0, 0);
747             } else {
748             $msg = pack(ICMP_STRUCT . $self->{data_size}, ICMP_ECHO, SUBCODE,
749 4         17 $checksum, $self->{pid}, $self->{seq}, $self->{data});
750             }
751             } else {
752             $msg = pack(ICMP_STRUCT . $self->{data_size}, ICMPv6_ECHO, SUBCODE,
753 1         7 $checksum, $self->{pid}, $self->{seq}, $self->{data});
754             }
755 5         16 $len_msg = length($msg);
756 5         19 $saddr = _pack_sockaddr_in(ICMP_PORT, $ip);
757 5         15 $self->{from_ip} = undef;
758 5         9 $self->{from_type} = undef;
759 5         9 $self->{from_subcode} = undef;
760 5         342 send($self->{fh}, $msg, ICMP_FLAGS, $saddr); # Send the message
761              
762 5         19 $rbits = "";
763 5         27 vec($rbits, $self->{fh}->fileno(), 1) = 1;
764 5         59 $ret = 0;
765 5         9 $done = 0;
766 5         13 $finish_time = &time() + $timeout; # Must be done by this time
767 5   66     46 while (!$done && $timeout > 0) # Keep trying if we have time
768             {
769 9         39 $nfound = mselect((my $rout=$rbits), undef, undef, $timeout); # Wait for packet
770 9         29 $timeout = $finish_time - &time(); # Get remaining time
771 9 50       39 if (!defined($nfound)) # Hmm, a strange error
    100          
772             {
773 0         0 $ret = undef;
774 0         0 $done = 1;
775             }
776             elsif ($nfound) # Got a packet from somewhere
777             {
778 8         14 $recv_msg = "";
779 8         13 $from_pid = -1;
780 8         11 $from_seq = -1;
781 8         110 $from_saddr = recv($self->{fh}, $recv_msg, 1500, ICMP_FLAGS);
782 8         24 $recv_msg_len = length($recv_msg) - length($self->{data});
783 8         37 ($from_port, $from_ip) = _unpack_sockaddr_in($from_saddr, $ip->{family});
784 8         27 ($from_type, $from_subcode) = unpack("C2", substr($recv_msg, 20, 2));
785 8 50       34 if ($from_type == ICMP_TIMESTAMP_REPLY) {
    100          
    50          
786 0 0       0 ($from_pid, $from_seq) = unpack("n3", substr($recv_msg, 24, 4))
787             if length $recv_msg >= 28;
788             } elsif ($from_type == ICMP_ECHOREPLY) {
789             #warn "ICMP_ECHOREPLY: ", $ip->{family}, " ",$recv_msg, ":", length($recv_msg);
790             ($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 24, 4))
791 4 50 33     41 if ($ip->{family} == AF_INET && $recv_msg_len == 28);
792             ($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 4, 4))
793 4 50 33     15 if ($ip->{family} == $AF_INET6 && $recv_msg_len == 8);
794             } elsif ($from_type == ICMPv6_ECHOREPLY) {
795             #($from_pid, $from_seq) = unpack("n3", substr($recv_msg, 24, 4))
796             # if length $recv_msg >= 28;
797             #($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 24, 4))
798             # if ($ip->{family} == AF_INET && length $recv_msg == 28);
799             #warn "ICMPv6_ECHOREPLY: ", $ip->{family}, " ",$recv_msg, ":", length($recv_msg);
800             ($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 4, 4))
801 0 0 0     0 if ($ip->{family} == $AF_INET6 && $recv_msg_len == 8);
802             #} elsif ($from_type == ICMPv6_NI_REPLY) {
803             # ($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 4, 4))
804             # if ($ip->{family} == $AF_INET6 && length $recv_msg == 8);
805             } else {
806             #warn "ICMP: ", $from_type, " ",$ip->{family}, " ",$recv_msg, ":", length($recv_msg);
807 4 50       13 ($from_pid, $from_seq) = unpack("n2", substr($recv_msg, 52, 4))
808             if length $recv_msg >= 56;
809             }
810 8         20 $self->{from_ip} = $from_ip;
811 8         16 $self->{from_type} = $from_type;
812 8         10 $self->{from_subcode} = $from_subcode;
813 8 100       32 next if ($from_pid != $self->{pid});
814 4 50       17 next if ($from_seq != $self->{seq});
815 4 50 33     24 if (! $source_verify || ($self->ntop($from_ip) eq $self->ntop($ip))) { # Does the packet check out?
816 4 50 33     31 if (!$timestamp_msg && (($from_type == ICMP_ECHOREPLY) || ($from_type == ICMPv6_ECHOREPLY))) {
    0 33        
    0 0        
    0 0        
817 4         7 $ret = 1;
818 4         15 $done = 1;
819             } elsif ($timestamp_msg && $from_type == ICMP_TIMESTAMP_REPLY) {
820 0         0 $ret = 1;
821 0         0 $done = 1;
822             } elsif (($from_type == ICMP_UNREACHABLE) || ($from_type == ICMPv6_UNREACHABLE)) {
823 0         0 $done = 1;
824             } elsif ($from_type == ICMP_TIME_EXCEEDED) {
825 0         0 $ret = 0;
826 0         0 $done = 1;
827             }
828             }
829             } else { # Oops, timed out
830 1         8 $done = 1;
831             }
832             }
833 5         16 return $ret;
834             }
835              
836             sub ping_icmpv6
837             {
838 1     1 1 4 shift->ping_icmp(@_);
839             }
840              
841             sub icmp_result {
842 0     0 1 0 my ($self) = @_;
843 0   0     0 my $addr = $self->{from_ip} || "";
844 0 0       0 $addr = "\0\0\0\0" unless 4 == length $addr;
845 0   0     0 return ($self->ntop($addr),($self->{from_type} || 0), ($self->{from_subcode} || 0));
      0        
846             }
847              
848             # Description: Do a checksum on the message. Basically sum all of
849             # the short words and fold the high order bits into the low order bits.
850              
851             sub checksum
852             {
853 5     5 1 14 my ($class,
854             $msg # The message to checksum
855             ) = @_;
856 5         11 my ($len_msg, # Length of the message
857             $num_short, # The number of short words in the message
858             $short, # One short word
859             $chk # The checksum
860             );
861              
862 5         9 $len_msg = length($msg);
863 5         16 $num_short = int($len_msg / 2);
864 5         9 $chk = 0;
865 5         37 foreach $short (unpack("n$num_short", $msg))
866             {
867 40         55 $chk += $short;
868             } # Add the odd byte in
869 5 50       15 $chk += (unpack("C", substr($msg, $len_msg - 1, 1)) << 8) if $len_msg % 2;
870 5         22 $chk = ($chk >> 16) + ($chk & 0xffff); # Fold high into low
871 5         17 return(~(($chk >> 16) + $chk) & 0xffff); # Again and complement
872             }
873              
874              
875             # Description: Perform a tcp echo ping. Since a tcp connection is
876             # host specific, we have to open and close each connection here. We
877             # can't just leave a socket open. Because of the robust nature of
878             # tcp, it will take a while before it gives up trying to establish a
879             # connection. Therefore, we use select() on a non-blocking socket to
880             # check against our timeout. No data bytes are actually
881             # sent since the successful establishment of a connection is proof
882             # enough of the reachability of the remote host. Also, tcp is
883             # expensive and doesn't need our help to add to the overhead.
884              
885             sub ping_tcp
886             {
887 28     28 1 68 my ($self,
888             $ip, # Hash of addr (string), addr_in (packed), family
889             $timeout # Seconds after which ping times out
890             ) = @_;
891 28         49 my ($ret # The return value
892             );
893              
894 28 0 33     84 $ip = $self->{host} if !defined $ip and $self->{host};
895 28 0 33     60 $timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
896              
897 28         99 $! = 0;
898 28         103 $ret = $self -> tcp_connect( $ip, $timeout);
899 27 100 100     358 if (!$self->{econnrefused} &&
900             $! == ECONNREFUSED) {
901 11         25 $ret = 1; # "Connection refused" means reachable
902             }
903 27         173 $self->{fh}->close();
904 27         1586 return $ret;
905             }
906              
907             sub tcp_connect
908             {
909 28     28 1 63 my ($self,
910             $ip, # Hash of addr (string), addr_in (packed), family
911             $timeout # Seconds after which connect times out
912             ) = @_;
913 28         38 my ($saddr); # Packed IP and Port
914              
915 28 0 33     74 $ip = $self->{host} if !defined $ip and $self->{host};
916 28 0 33     60 $timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
917              
918 28         93 $saddr = _pack_sockaddr_in($self->{port_num}, $ip);
919              
920 28         96 my $ret = 0; # Default to unreachable
921              
922             my $do_socket = sub {
923 28 50   28   1209 socket($self->{fh}, $ip->{family}, SOCK_STREAM, $self->{proto_num}) ||
924             croak("tcp socket error - $!");
925 28 50 33     148 if (defined $self->{local_addr} &&
926             !CORE::bind($self->{fh}, _pack_sockaddr_in(0, $self->{local_addr}))) {
927 0         0 croak("tcp bind error - $!");
928             }
929 28         109 $self->_setopts();
930 28         220 };
931             my $do_connect = sub {
932 0     0   0 $self->{ip} = $ip->{addr_in};
933             # ECONNREFUSED is 10061 on MSWin32. If we pass it as child error through $?,
934             # we'll get (10061 & 255) = 77, so we cannot check it in the parent process.
935 0   0     0 return ($ret = connect($self->{fh}, $saddr) || ($! == ECONNREFUSED && !$self->{econnrefused}));
936 28         109 };
937             my $do_connect_nb = sub {
938             # Set O_NONBLOCK property on filehandle
939 28     28   107 $self->socket_blocking_mode($self->{fh}, 0);
940              
941             # start the connection attempt
942 28 50       3419 if (!connect($self->{fh}, $saddr)) {
943 28 50 0     426 if ($! == ECONNREFUSED) {
    50 33        
944 0 0       0 $ret = 1 unless $self->{econnrefused};
945             } elsif ($! != EINPROGRESS && ($^O ne 'MSWin32' || $! != EWOULDBLOCK)) {
946             # EINPROGRESS is the expected error code after a connect()
947             # on a non-blocking socket. But if the kernel immediately
948             # determined that this connect() will never work,
949             # Simply respond with "unreachable" status.
950             # (This can occur on some platforms with errno
951             # EHOSTUNREACH or ENETUNREACH.)
952 0         0 return 0;
953             } else {
954             # Got the expected EINPROGRESS.
955             # Just wait for connection completion...
956 28         70 my ($wbits, $wout, $wexc);
957 28         67 $wout = $wexc = $wbits = "";
958 28         166 vec($wbits, $self->{fh}->fileno, 1) = 1;
959              
960 28 50       457 my $nfound = mselect(undef,
961             ($wout = $wbits),
962             ($^O eq 'MSWin32' ? ($wexc = $wbits) : undef),
963             $timeout);
964 27 50       121 warn("select: $!") unless defined $nfound;
965              
966 27 100 66     289 if ($nfound && vec($wout, $self->{fh}->fileno, 1)) {
967             # the socket is ready for writing so the connection
968             # attempt completed. test whether the connection
969             # attempt was successful or not
970              
971 21 100       425 if (getpeername($self->{fh})) {
972             # Connection established to remote host
973 9         47 $ret = 1;
974             } else {
975             # TCP ACK will never come from this host
976             # because there was an error connecting.
977              
978             # This should set $! to the correct error.
979 12         26 my $char;
980 12         168 sysread($self->{fh},$char,1);
981 12 50 33     111 $! = ECONNREFUSED if ($! == EAGAIN && $^O =~ /cygwin/i);
982              
983             $ret = 1 if (!$self->{econnrefused}
984 12 100 66     104 && $! == ECONNREFUSED);
985             }
986             } else {
987             # the connection attempt timed out (or there were connect
988             # errors on Windows)
989 6 50       128 if ($^O =~ 'MSWin32') {
990             # If the connect will fail on a non-blocking socket,
991             # winsock reports ECONNREFUSED as an exception, and we
992             # need to fetch the socket-level error code via getsockopt()
993             # instead of using the thread-level error code that is in $!.
994 0 0 0     0 if ($nfound && vec($wexc, $self->{fh}->fileno, 1)) {
995 0         0 $! = unpack("i", getsockopt($self->{fh}, SOL_SOCKET,
996             SO_ERROR));
997             }
998             }
999             }
1000             }
1001             } else {
1002             # Connection established to remote host
1003 0         0 $ret = 1;
1004             }
1005              
1006             # Unset O_NONBLOCK property on filehandle
1007 27         183 $self->socket_blocking_mode($self->{fh}, 1);
1008 27         138 $self->{ip} = $ip->{addr_in};
1009 27         56 return $ret;
1010 28         116 };
1011              
1012 28 50       79 if ($syn_forking) {
1013             # Buggy Winsock API doesn't allow nonblocking connect.
1014             # Hence, if our OS is Windows, we need to create a separate
1015             # process to do the blocking connect attempt.
1016             # XXX Above comments are not true at least for Win2K, where
1017             # nonblocking connect works.
1018              
1019 0         0 $| = 1; # Clear buffer prior to fork to prevent duplicate flushing.
1020 0         0 $self->{'tcp_chld'} = fork;
1021 0 0       0 if (!$self->{'tcp_chld'}) {
1022 0 0       0 if (!defined $self->{'tcp_chld'}) {
1023             # Fork did not work
1024 0         0 warn "Fork error: $!";
1025 0         0 return 0;
1026             }
1027 0         0 &{ $do_socket }();
  0         0  
1028              
1029             # Try a slow blocking connect() call
1030             # and report the status to the parent.
1031 0 0       0 if ( &{ $do_connect }() ) {
  0         0  
1032 0         0 $self->{fh}->close();
1033             # No error
1034 0         0 exit 0;
1035             } else {
1036             # Pass the error status to the parent
1037             # Make sure that $! <= 255
1038 0 0       0 exit($! <= 255 ? $! : 255);
1039             }
1040             }
1041              
1042 0         0 &{ $do_socket }();
  0         0  
1043              
1044 0         0 my $patience = &time() + $timeout;
1045              
1046 0         0 my ($child, $child_errno);
1047 0         0 $? = 0; $child_errno = 0;
  0         0  
1048             # Wait up to the timeout
1049             # And clean off the zombie
1050             do {
1051 0         0 $child = waitpid($self->{'tcp_chld'}, &WNOHANG());
1052 0         0 $child_errno = $? >> 8;
1053 0         0 select(undef, undef, undef, 0.1);
1054 0   0     0 } while &time() < $patience && $child != $self->{'tcp_chld'};
1055              
1056 0 0       0 if ($child == $self->{'tcp_chld'}) {
1057 0 0       0 if ($self->{proto} eq "stream") {
1058             # We need the socket connected here, in parent
1059             # Should be safe to connect because the child finished
1060             # within the timeout
1061 0         0 &{ $do_connect }();
  0         0  
1062             }
1063             # $ret cannot be set by the child process
1064 0         0 $ret = !$child_errno;
1065             } else {
1066             # Time must have run out.
1067             # Put that choking client out of its misery
1068 0         0 kill "KILL", $self->{'tcp_chld'};
1069             # Clean off the zombie
1070 0         0 waitpid($self->{'tcp_chld'}, 0);
1071 0         0 $ret = 0;
1072             }
1073 0         0 delete $self->{'tcp_chld'};
1074 0         0 $! = $child_errno;
1075             } else {
1076             # Otherwise don't waste the resources to fork
1077              
1078 28         50 &{ $do_socket }();
  28         81  
1079              
1080 28         57 &{ $do_connect_nb }();
  28         87  
1081             }
1082              
1083 27         682 return $ret;
1084             }
1085              
1086             sub DESTROY {
1087 41     41   14291 my $self = shift;
1088 41 50 66     2672 if ($self->{'proto'} eq 'tcp' &&
1089             $self->{'tcp_chld'}) {
1090             # Put that choking client out of its misery
1091 0         0 kill "KILL", $self->{'tcp_chld'};
1092             # Clean off the zombie
1093 0         0 waitpid($self->{'tcp_chld'}, 0);
1094             }
1095             }
1096              
1097             # This writes the given string to the socket and then reads it
1098             # back. It returns 1 on success, 0 on failure.
1099             sub tcp_echo
1100             {
1101 0     0 1 0 my ($self, $timeout, $pingstring) = @_;
1102              
1103 0 0 0     0 $timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
1104 0 0 0     0 $pingstring = $self->{pingstring} if !defined $pingstring and $self->{pingstring};
1105              
1106 0         0 my $ret = undef;
1107 0         0 my $time = &time();
1108 0         0 my $wrstr = $pingstring;
1109 0         0 my $rdstr = "";
1110              
1111 0         0 eval <<'EOM';
1112             do {
1113             my $rin = "";
1114             vec($rin, $self->{fh}->fileno(), 1) = 1;
1115              
1116             my $rout = undef;
1117             if($wrstr) {
1118             $rout = "";
1119             vec($rout, $self->{fh}->fileno(), 1) = 1;
1120             }
1121              
1122             if(mselect($rin, $rout, undef, ($time + $timeout) - &time())) {
1123              
1124             if($rout && vec($rout,$self->{fh}->fileno(),1)) {
1125             my $num = syswrite($self->{fh}, $wrstr, length $wrstr);
1126             if($num) {
1127             # If it was a partial write, update and try again.
1128             $wrstr = substr($wrstr,$num);
1129             } else {
1130             # There was an error.
1131             $ret = 0;
1132             }
1133             }
1134              
1135             if(vec($rin,$self->{fh}->fileno(),1)) {
1136             my $reply;
1137             if(sysread($self->{fh},$reply,length($pingstring)-length($rdstr))) {
1138             $rdstr .= $reply;
1139             $ret = 1 if $rdstr eq $pingstring;
1140             } else {
1141             # There was an error.
1142             $ret = 0;
1143             }
1144             }
1145              
1146             }
1147             } until &time() > ($time + $timeout) || defined($ret);
1148             EOM
1149              
1150 0         0 return $ret;
1151             }
1152              
1153             # Description: Perform a stream ping. If the tcp connection isn't
1154             # already open, it opens it. It then sends some data and waits for
1155             # a reply. It leaves the stream open on exit.
1156              
1157             sub ping_stream
1158             {
1159 0     0 1 0 my ($self,
1160             $ip, # Hash of addr (string), addr_in (packed), family
1161             $timeout # Seconds after which ping times out
1162             ) = @_;
1163              
1164             # Open the stream if it's not already open
1165 0 0       0 if(!defined $self->{fh}->fileno()) {
1166 0 0       0 $self->tcp_connect($ip, $timeout) or return 0;
1167             }
1168              
1169             croak "tried to switch servers while stream pinging"
1170 0 0       0 if $self->{ip} ne $ip->{addr_in};
1171              
1172 0         0 return $self->tcp_echo($timeout, $pingstring);
1173             }
1174              
1175             # Description: opens the stream. You would do this if you want to
1176             # separate the overhead of opening the stream from the first ping.
1177              
1178             sub open
1179             {
1180 0     0 1 0 my ($self,
1181             $host, # Host or IP address
1182             $timeout, # Seconds after which open times out
1183             $family
1184             ) = @_;
1185 0         0 my $ip; # Hash of addr (string), addr_in (packed), family
1186 0 0       0 $host = $self->{host} unless defined $host;
1187              
1188 0 0       0 if ($family) {
1189 0 0       0 if ($family =~ $qr_family) {
1190 0 0       0 if ($family =~ $qr_family4) {
1191 0         0 $self->{family_local} = AF_INET;
1192             } else {
1193 0         0 $self->{family_local} = $AF_INET6;
1194             }
1195             } else {
1196 0         0 croak('Family must be "ipv4" or "ipv6"')
1197             }
1198             } else {
1199 0         0 $self->{family_local} = $self->{family};
1200             }
1201              
1202 0 0       0 $timeout = $self->{timeout} unless $timeout;
1203 0         0 $ip = $self->_resolv($host);
1204              
1205 0 0       0 if ($self->{proto} eq "stream") {
1206 0 0       0 if (defined($self->{fh}->fileno())) {
1207 0         0 croak("socket is already open");
1208             } else {
1209 0 0       0 return () unless $ip;
1210 0         0 $self->tcp_connect($ip, $timeout);
1211             }
1212             }
1213             }
1214              
1215             sub _dontfrag {
1216 0     0   0 my $self = shift;
1217             # bsd solaris
1218 0         0 my $IP_DONTFRAG = eval { Socket::IP_DONTFRAG() };
  0         0  
1219 0 0       0 if ($IP_DONTFRAG) {
1220 0         0 my $i = 1;
1221 0 0       0 setsockopt($self->{fh}, IPPROTO_IP, $IP_DONTFRAG, pack("I*", $i))
1222             or croak "error configuring IP_DONTFRAG $!";
1223             # Linux needs more: Path MTU Discovery as defined in RFC 1191
1224             # For non SOCK_STREAM sockets it is the user's responsibility to packetize
1225             # the data in MTU sized chunks and to do the retransmits if necessary.
1226             # The kernel will reject packets that are bigger than the known path
1227             # MTU if this flag is set (with EMSGSIZE).
1228 0 0       0 if ($^O eq 'linux') {
1229 0         0 my $i = 2; # IP_PMTUDISC_DO
1230 0 0       0 setsockopt($self->{fh}, IPPROTO_IP, IP_MTU_DISCOVER, pack("I*", $i))
1231             or croak "error configuring IP_MTU_DISCOVER $!";
1232             }
1233             }
1234             }
1235              
1236             # SO_BINDTODEVICE + IP_TOS
1237             sub _setopts {
1238 72     72   165 my $self = shift;
1239 72 50       219 if ($self->{'device'}) {
1240 0 0       0 setsockopt($self->{fh}, SOL_SOCKET, SO_BINDTODEVICE, pack("Z*", $self->{'device'}))
1241             or croak "error binding to device $self->{'device'} $!";
1242             }
1243 72 100       199 if ($self->{'tos'}) { # need to re-apply ToS (RT #6706)
1244 2 50       33 setsockopt($self->{fh}, IPPROTO_IP, IP_TOS, pack("I*", $self->{'tos'}))
1245             or croak "error applying tos to $self->{'tos'} $!";
1246             }
1247 72 50       231 if ($self->{'dontfrag'}) {
1248 0         0 $self->_dontfrag;
1249             }
1250             }
1251              
1252              
1253             # Description: Perform a udp echo ping. Construct a message of
1254             # at least the one-byte sequence number and any additional data bytes.
1255             # Send the message out and wait for a message to come back. If we
1256             # get a message, make sure all of its parts match. If they do, we are
1257             # done. Otherwise go back and wait for the message until we run out
1258             # of time. Return the result of our efforts.
1259              
1260 20     20   169 use constant UDP_FLAGS => 0; # Nothing special on send or recv
  20         40  
  20         81470  
1261             sub ping_udp
1262             {
1263 1     1 1 4 my ($self,
1264             $ip, # Hash of addr (string), addr_in (packed), family
1265             $timeout # Seconds after which ping times out
1266             ) = @_;
1267              
1268 1         3 my ($saddr, # sockaddr_in with port and ip
1269             $ret, # The return value
1270             $msg, # Message to be echoed
1271             $finish_time, # Time ping should be finished
1272             $flush, # Whether socket needs to be disconnected
1273             $connect, # Whether socket needs to be connected
1274             $done, # Set to 1 when we are done pinging
1275             $rbits, # Read bits, filehandles for reading
1276             $nfound, # Number of ready filehandles found
1277             $from_saddr, # sockaddr_in of sender
1278             $from_msg, # Characters echoed by $host
1279             $from_port, # Port message was echoed from
1280             $from_ip # Packed IP number of sender
1281             );
1282              
1283 1         4 $saddr = _pack_sockaddr_in($self->{port_num}, $ip);
1284 1         5 $self->{seq} = ($self->{seq} + 1) % 256; # Increment sequence
1285 1         10 $msg = chr($self->{seq}) . $self->{data}; # Add data if any
1286              
1287             socket($self->{fh}, $ip->{family}, SOCK_DGRAM,
1288 1 50       49 $self->{proto_num}) ||
1289             croak("udp socket error - $!");
1290              
1291 1 50 33     7 if (defined $self->{local_addr} &&
1292             !CORE::bind($self->{fh}, _pack_sockaddr_in(0, $self->{local_addr}))) {
1293 0         0 croak("udp bind error - $!");
1294             }
1295              
1296 1         4 $self->_setopts();
1297              
1298 1 50       4 if ($self->{connected}) {
1299 0 0       0 if ($self->{connected} ne $saddr) {
1300             # Still connected to wrong destination.
1301             # Need to flush out the old one.
1302 0         0 $flush = 1;
1303             }
1304             } else {
1305             # Not connected yet.
1306             # Need to connect() before send()
1307 1         3 $connect = 1;
1308             }
1309              
1310             # Have to connect() and send() instead of sendto()
1311             # in order to pick up on the ECONNREFUSED setting
1312             # from recv() or double send() errno as utilized in
1313             # the concept by rdw @ perlmonks. See:
1314             # http://perlmonks.thepen.com/42898.html
1315 1 50       7 if ($flush) {
1316             # Need to socket() again to flush the descriptor
1317             # This will disconnect from the old saddr.
1318             socket($self->{fh}, $ip->{family}, SOCK_DGRAM,
1319 0         0 $self->{proto_num});
1320 0         0 $self->_setopts();
1321             }
1322             # Connect the socket if it isn't already connected
1323             # to the right destination.
1324 1 50 33     7 if ($flush || $connect) {
1325 1         25 connect($self->{fh}, $saddr); # Tie destination to socket
1326 1         6 $self->{connected} = $saddr;
1327             }
1328 1         91 send($self->{fh}, $msg, UDP_FLAGS); # Send it
1329              
1330 1         5 $rbits = "";
1331 1         13 vec($rbits, $self->{fh}->fileno(), 1) = 1;
1332 1         14 $ret = 0; # Default to unreachable
1333 1         2 $done = 0;
1334 1         3 my $retrans = 0.01;
1335 1         20 my $factor = $self->{retrans};
1336 1         4 $finish_time = &time() + $timeout; # Ping needs to be done by then
1337 1   66     9 while (!$done && $timeout > 0)
1338             {
1339 1 50       5 if ($factor > 1)
1340             {
1341 1 50       4 $timeout = $retrans if $timeout > $retrans;
1342 1         3 $retrans*= $factor; # Exponential backoff
1343             }
1344 1         4 $nfound = mselect((my $rout=$rbits), undef, undef, $timeout); # Wait for response
1345 1         3 my $why = $!;
1346 1         3 $timeout = $finish_time - &time(); # Get remaining time
1347              
1348 1 50       4 if (!defined($nfound)) # Hmm, a strange error
    50          
    0          
1349             {
1350 0         0 $ret = undef;
1351 0         0 $done = 1;
1352             }
1353             elsif ($nfound) # A packet is waiting
1354             {
1355 1         3 $from_msg = "";
1356 1         24 $from_saddr = recv($self->{fh}, $from_msg, 1500, UDP_FLAGS);
1357 1 50       5 if (!$from_saddr) {
1358             # For example an unreachable host will make recv() fail.
1359 1 50 33     16 if (!$self->{econnrefused} &&
      33        
1360             ($! == ECONNREFUSED ||
1361             $! == ECONNRESET)) {
1362             # "Connection refused" means reachable
1363             # Good, continue
1364 1         2 $ret = 1;
1365             }
1366 1         4 $done = 1;
1367             } else {
1368 0         0 ($from_port, $from_ip) = _unpack_sockaddr_in($from_saddr, $ip->{family});
1369 0 0       0 my $addr_in = ref($ip) eq "HASH" ? $ip->{addr_in} : $ip;
1370 0 0 0     0 if (!$source_verify ||
      0        
      0        
1371             (($from_ip eq $addr_in) && # Does the packet check out?
1372             ($from_port == $self->{port_num}) &&
1373             ($from_msg eq $msg)))
1374             {
1375 0         0 $ret = 1; # It's a winner
1376 0         0 $done = 1;
1377             }
1378             }
1379             }
1380             elsif ($timeout <= 0) # Oops, timed out
1381             {
1382 0         0 $done = 1;
1383             }
1384             else
1385             {
1386             # Send another in case the last one dropped
1387 0 0       0 if (send($self->{fh}, $msg, UDP_FLAGS)) {
1388             # Another send worked? The previous udp packet
1389             # must have gotten lost or is still in transit.
1390             # Hopefully this new packet will arrive safely.
1391             } else {
1392 0 0 0     0 if (!$self->{econnrefused} &&
1393             $! == ECONNREFUSED) {
1394             # "Connection refused" means reachable
1395             # Good, continue
1396 0         0 $ret = 1;
1397             }
1398 0         0 $done = 1;
1399             }
1400             }
1401             }
1402 1         3 return $ret;
1403             }
1404              
1405             # Description: Send a TCP SYN packet to host specified.
1406             sub ping_syn
1407             {
1408 26     26 1 58 my $self = shift;
1409 26         44 my $host = shift;
1410 26         48 my $ip = shift;
1411 26         39 my $start_time = shift;
1412 26         33 my $stop_time = shift;
1413              
1414 26 50       59 if ($syn_forking) {
1415 0         0 return $self->ping_syn_fork($host, $ip, $start_time, $stop_time);
1416             }
1417              
1418 26         235 my $fh = FileHandle->new();
1419 26         1152 my $saddr = _pack_sockaddr_in($self->{port_num}, $ip);
1420              
1421             # Create TCP socket
1422 26 50       1168 if (!socket ($fh, $ip->{family}, SOCK_STREAM, $self->{proto_num})) {
1423 0         0 croak("tcp socket error - $!");
1424             }
1425              
1426 26 50 33     113 if (defined $self->{local_addr} &&
1427             !CORE::bind($fh, _pack_sockaddr_in(0, $self->{local_addr}))) {
1428 0         0 croak("tcp bind error - $!");
1429             }
1430              
1431 26         103 $self->_setopts();
1432             # Set O_NONBLOCK property on filehandle
1433 26         82 $self->socket_blocking_mode($fh, 0);
1434              
1435             # Attempt the non-blocking connect
1436             # by just sending the TCP SYN packet
1437 26 50       2851 if (connect($fh, $saddr)) {
1438             # Non-blocking, yet still connected?
1439             # Must have connected very quickly,
1440             # or else it wasn't very non-blocking.
1441             #warn "WARNING: Nonblocking connect connected anyway? ($^O)";
1442             } else {
1443             # Error occurred connecting.
1444 26 50 0     364 if ($! == EINPROGRESS || ($^O eq 'MSWin32' && $! == EWOULDBLOCK)) {
      33        
1445             # The connection is just still in progress.
1446             # This is the expected condition.
1447             } else {
1448             # Just save the error and continue on.
1449             # The ack() can check the status later.
1450 0         0 $self->{bad}->{$host} = $!;
1451             }
1452             }
1453              
1454 26         123 my $entry = [ $host, $ip, $fh, $start_time, $stop_time, $self->{port_num} ];
1455 26         142 $self->{syn}->{$fh->fileno} = $entry;
1456 26 50       276 if ($self->{stop_time} < $stop_time) {
1457 26         54 $self->{stop_time} = $stop_time;
1458             }
1459 26         74 vec($self->{wbits}, $fh->fileno, 1) = 1;
1460              
1461 26         234 return 1;
1462             }
1463              
1464             sub ping_syn_fork {
1465 0     0 1 0 my ($self, $host, $ip, $start_time, $stop_time) = @_;
1466              
1467             # Buggy Winsock API doesn't allow nonblocking connect.
1468             # Hence, if our OS is Windows, we need to create a separate
1469             # process to do the blocking connect attempt.
1470 0         0 my $pid = fork();
1471 0 0       0 if (defined $pid) {
1472 0 0       0 if ($pid) {
1473             # Parent process
1474 0         0 my $entry = [ $host, $ip, $pid, $start_time, $stop_time ];
1475 0         0 $self->{syn}->{$pid} = $entry;
1476 0 0       0 if ($self->{stop_time} < $stop_time) {
1477 0         0 $self->{stop_time} = $stop_time;
1478             }
1479             } else {
1480             # Child process
1481 0         0 my $saddr = _pack_sockaddr_in($self->{port_num}, $ip);
1482              
1483             # Create TCP socket
1484 0 0       0 if (!socket ($self->{fh}, $ip->{family}, SOCK_STREAM, $self->{proto_num})) {
1485 0         0 croak("tcp socket error - $!");
1486             }
1487              
1488 0 0 0     0 if (defined $self->{local_addr} &&
1489             !CORE::bind($self->{fh}, _pack_sockaddr_in(0, $self->{local_addr}))) {
1490 0         0 croak("tcp bind error - $!");
1491             }
1492              
1493 0         0 $self->_setopts();
1494              
1495 0         0 $!=0;
1496             # Try to connect (could take a long time)
1497 0         0 connect($self->{fh}, $saddr);
1498             # Notify parent of connect error status
1499 0         0 my $err = $!+0;
1500 0         0 my $wrstr = "$$ $err";
1501             # Force to 16 chars including \n
1502 0         0 $wrstr .= " "x(15 - length $wrstr). "\n";
1503 0         0 syswrite($self->{fork_wr}, $wrstr, length $wrstr);
1504 0         0 exit;
1505             }
1506             } else {
1507             # fork() failed?
1508 0         0 die "fork: $!";
1509             }
1510 0         0 return 1;
1511             }
1512              
1513             # Description: Wait for TCP ACK from host specified
1514             # from ping_syn above. If no host is specified, wait
1515             # for TCP ACK from any of the hosts in the SYN queue.
1516             sub ack
1517             {
1518 28     28 1 13506 my $self = shift;
1519              
1520 28 50       89 if ($self->{proto} eq "syn") {
1521 28 50       57 if ($syn_forking) {
1522 0         0 my @answer = $self->ack_unfork(shift);
1523 0 0       0 return wantarray ? @answer : $answer[0];
1524             }
1525 28         44 my $wbits = "";
1526 28         37 my $stop_time = 0;
1527 28 100 66     110 if (my $host = shift or $self->{host}) {
1528             # Host passed as arg or as option to new
1529 8 50       15 $host = $self->{host} unless defined $host;
1530 8 50       16 if (exists $self->{bad}->{$host}) {
1531 0 0 0     0 if (!$self->{econnrefused} &&
      0        
      0        
1532             $self->{bad}->{ $host } &&
1533             (($! = ECONNREFUSED)>0) &&
1534             $self->{bad}->{ $host } eq "$!") {
1535             # "Connection refused" means reachable
1536             # Good, continue
1537             } else {
1538             # ECONNREFUSED means no good
1539 0         0 return ();
1540             }
1541             }
1542 8         12 my $host_fd = undef;
1543 8         10 foreach my $fd (keys %{ $self->{syn} }) {
  8         24  
1544 18         22 my $entry = $self->{syn}->{$fd};
1545 18 100       34 if ($entry->[0] eq $host) {
1546 8         12 $host_fd = $fd;
1547 8   33     23 $stop_time = $entry->[4]
1548             || croak("Corrupted SYN entry for [$host]");
1549 8         11 last;
1550             }
1551             }
1552 8 50       17 croak("ack called on [$host] without calling ping first!")
1553             unless defined $host_fd;
1554 8         31 vec($wbits, $host_fd, 1) = 1;
1555             } else {
1556             # No $host passed so scan all hosts
1557             # Use the latest stop_time
1558 20         30 $stop_time = $self->{stop_time};
1559             # Use all the bits
1560 20         34 $wbits = $self->{wbits};
1561             }
1562              
1563 28         128 while ($wbits !~ /^\0*\z/) {
1564 25         57 my $timeout = $stop_time - &time();
1565             # Force a minimum of 10 ms timeout.
1566 25 100       68 $timeout = 0.01 if $timeout <= 0.01;
1567              
1568 25         31 my $winner_fd = undef;
1569 25         59 my $wout = $wbits;
1570 25         32 my $fd = 0;
1571             # Do "bad" fds from $wbits first
1572 25         74 while ($wout !~ /^\0*\z/) {
1573 233 100       336 if (vec($wout, $fd, 1)) {
1574             # Wipe it from future scanning.
1575 68         123 vec($wout, $fd, 1) = 0;
1576 68 50       173 if (my $entry = $self->{syn}->{$fd}) {
1577 68 50       131 if ($self->{bad}->{ $entry->[0] }) {
1578 0         0 $winner_fd = $fd;
1579 0         0 last;
1580             }
1581             }
1582             }
1583 233         404 $fd++;
1584             }
1585              
1586 25 100 66     112 if (defined($winner_fd) or my $nfound = mselect(undef, ($wout=$wbits), undef, $timeout)) {
    50          
1587 22 50       48 if (defined $winner_fd) {
1588 0         0 $fd = $winner_fd;
1589             } else {
1590             # Done waiting for one of the ACKs
1591 22         40 $fd = 0;
1592             # Determine which one
1593 22   66     139 while ($wout !~ /^\0*\z/ &&
1594             !vec($wout, $fd, 1)) {
1595 165         518 $fd++;
1596             }
1597             }
1598 22 50       69 if (my $entry = $self->{syn}->{$fd}) {
1599             # Wipe it from future scanning.
1600 22         51 delete $self->{syn}->{$fd};
1601 22         75 vec($self->{wbits}, $fd, 1) = 0;
1602 22         55 vec($wbits, $fd, 1) = 0;
1603 22 50 66     372 if (!$self->{econnrefused} &&
    100 33        
      33        
1604             $self->{bad}->{ $entry->[0] } &&
1605             (($! = ECONNREFUSED)>0) &&
1606             $self->{bad}->{ $entry->[0] } eq "$!") {
1607             # "Connection refused" means reachable
1608             # Good, continue
1609             } elsif (getpeername($entry->[2])) {
1610             # Connection established to remote host
1611             # Good, continue
1612             } else {
1613             # TCP ACK will never come from this host
1614             # because there was an error connecting.
1615              
1616             # This should set $! to the correct error.
1617 3         10 my $char;
1618 3         31 sysread($entry->[2],$char,1);
1619             # Store the excuse why the connection failed.
1620 3         23 $self->{bad}->{$entry->[0]} = $!;
1621 3 100 33     28 if (!$self->{econnrefused} &&
      66        
1622             (($! == ECONNREFUSED) ||
1623             ($! == EAGAIN && $^O =~ /cygwin/i))) {
1624             # "Connection refused" means reachable
1625             # Good, continue
1626             } else {
1627             # No good, try the next socket...
1628 1         26 next;
1629             }
1630             }
1631             # Everything passed okay, return the answer
1632             return wantarray ?
1633 21 100       1152 ($entry->[0], &time() - $entry->[3], $self->ntop($entry->[1]), $entry->[5])
1634             : $entry->[0];
1635             } else {
1636 0         0 warn "Corrupted SYN entry: unknown fd [$fd] ready!";
1637 0         0 vec($wbits, $fd, 1) = 0;
1638 0         0 vec($self->{wbits}, $fd, 1) = 0;
1639             }
1640             } elsif (defined $nfound) {
1641             # Timed out waiting for ACK
1642 3         14 foreach my $fd (keys %{ $self->{syn} }) {
  3         49  
1643 10 100       63 if (vec($wbits, $fd, 1)) {
1644 4         17 my $entry = $self->{syn}->{$fd};
1645 4         23 $self->{bad}->{$entry->[0]} = "Timed out";
1646 4         32 vec($wbits, $fd, 1) = 0;
1647 4         27 vec($self->{wbits}, $fd, 1) = 0;
1648 4         271 delete $self->{syn}->{$fd};
1649             }
1650             }
1651             } else {
1652             # Weird error occurred with select()
1653 0         0 warn("select: $!");
1654 0         0 $self->{syn} = {};
1655 0         0 $wbits = "";
1656             }
1657             }
1658             }
1659 7         52 return ();
1660             }
1661              
1662             sub ack_unfork {
1663 0     0 1 0 my ($self,$host) = @_;
1664 0         0 my $stop_time = $self->{stop_time};
1665 0 0       0 if ($host) {
1666             # Host passed as arg
1667 0 0       0 if (my $entry = $self->{good}->{$host}) {
1668 0         0 delete $self->{good}->{$host};
1669 0         0 return ($entry->[0], &time() - $entry->[3], $self->ntop($entry->[1]));
1670             }
1671             }
1672              
1673 0         0 my $rbits = "";
1674 0         0 my $timeout;
1675              
1676 0 0       0 if (keys %{ $self->{syn} }) {
  0         0  
1677             # Scan all hosts that are left
1678 0         0 vec($rbits, fileno($self->{fork_rd}), 1) = 1;
1679 0         0 $timeout = $stop_time - &time();
1680             # Force a minimum of 10 ms timeout.
1681 0 0       0 $timeout = 0.01 if $timeout < 0.01;
1682             } else {
1683             # No hosts left to wait for
1684 0         0 $timeout = 0;
1685             }
1686              
1687 0 0       0 if ($timeout > 0) {
1688 0         0 my $nfound;
1689 0   0     0 while ( keys %{ $self->{syn} } and
  0         0  
1690             $nfound = mselect((my $rout=$rbits), undef, undef, $timeout)) {
1691             # Done waiting for one of the ACKs
1692 0 0       0 if (!sysread($self->{fork_rd}, $_, 16)) {
1693             # Socket closed, which means all children are done.
1694 0         0 return ();
1695             }
1696 0         0 my ($pid, $how) = split;
1697 0 0       0 if ($pid) {
1698             # Flush the zombie
1699 0         0 waitpid($pid, 0);
1700 0 0       0 if (my $entry = $self->{syn}->{$pid}) {
1701             # Connection attempt to remote host is done
1702 0         0 delete $self->{syn}->{$pid};
1703 0 0 0     0 if (!$how || # If there was no error connecting
      0        
1704             (!$self->{econnrefused} &&
1705             $how == ECONNREFUSED)) { # "Connection refused" means reachable
1706 0 0 0     0 if ($host && $entry->[0] ne $host) {
1707             # A good connection, but not the host we need.
1708             # Move it from the "syn" hash to the "good" hash.
1709 0         0 $self->{good}->{$entry->[0]} = $entry;
1710             # And wait for the next winner
1711 0         0 next;
1712             }
1713 0         0 return ($entry->[0], &time() - $entry->[3], $self->ntop($entry->[1]));
1714             }
1715             } else {
1716             # Should never happen
1717 0         0 die "Unknown ping from pid [$pid]";
1718             }
1719             } else {
1720 0         0 die "Empty response from status socket?";
1721             }
1722             }
1723 0 0       0 if (defined $nfound) {
1724             # Timed out waiting for ACK status
1725             } else {
1726             # Weird error occurred with select()
1727 0         0 warn("select: $!");
1728             }
1729             }
1730 0 0       0 if (my @synners = keys %{ $self->{syn} }) {
  0         0  
1731             # Kill all the synners
1732 0         0 kill 9, @synners;
1733 0         0 foreach my $pid (@synners) {
1734             # Wait for the deaths to finish
1735             # Then flush off the zombie
1736 0         0 waitpid($pid, 0);
1737             }
1738             }
1739 0         0 $self->{syn} = {};
1740 0         0 return ();
1741             }
1742              
1743             # Description: Tell why the ack() failed
1744             sub nack {
1745 0     0 1 0 my $self = shift;
1746 0   0     0 my $host = shift || croak('Usage> nack($failed_ack_host)');
1747 0   0     0 return $self->{bad}->{$host} || undef;
1748             }
1749              
1750             # Description: Close the connection.
1751              
1752             sub close
1753             {
1754 3     3 1 7 my ($self) = @_;
1755              
1756 3 50       15 if ($self->{proto} eq "syn") {
    50          
    50          
1757 0         0 delete $self->{syn};
1758             } elsif ($self->{proto} eq "tcp") {
1759             # The connection will already be closed
1760             } elsif ($self->{proto} eq "external") {
1761             # Nothing to close
1762             } else {
1763 3         11 $self->{fh}->close();
1764             }
1765             }
1766              
1767             sub port_number {
1768 8     8 1 5477 my $self = shift;
1769 8 50       22 if(@_) {
1770 8         14 $self->{port_num} = shift @_;
1771 8         28 $self->service_check(1);
1772             }
1773 8         12 return $self->{port_num};
1774             }
1775              
1776             sub ntop {
1777 15     15 1 37 my($self, $ip) = @_;
1778              
1779             # Vista doesn't define a inet_ntop. It has InetNtop instead.
1780             # Not following ANSI... priceless. getnameinfo() is defined
1781             # for Windows 2000 and later, so that may be the choice.
1782              
1783             # Any port will work, even undef, but this will work for now.
1784             # Socket warns when undef is passed in, but it still works.
1785 15         748 my $port = getservbyname('echo', 'udp');
1786 15         57 my $sockaddr = _pack_sockaddr_in($port, $ip);
1787 15         496 my ($error, $address) = getnameinfo($sockaddr, $NI_NUMERICHOST);
1788 15 50       56 croak $error if $error;
1789 15         482 return $address;
1790             }
1791              
1792             sub wakeonlan {
1793 0     0 1 0 my ($mac_addr, $host, $port) = @_;
1794              
1795             # use the discard service if $port not passed in
1796 0 0       0 if (! defined $host) { $host = '255.255.255.255' }
  0         0  
1797 0 0 0     0 if (! defined $port || $port !~ /^\d+$/ ) { $port = 9 }
  0         0  
1798              
1799 0         0 require IO::Socket::INET;
1800 0   0     0 my $sock = IO::Socket::INET->new(Proto=>'udp') || return undef;
1801              
1802 0         0 my $ip_addr = inet_aton($host);
1803 0         0 my $sock_addr = sockaddr_in($port, $ip_addr);
1804 0         0 $mac_addr =~ s/://g;
1805 0         0 my $packet = pack('C6H*', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, $mac_addr x 16);
1806              
1807 0         0 setsockopt($sock, SOL_SOCKET, SO_BROADCAST, 1);
1808 0         0 send($sock, $packet, 0, $sock_addr);
1809 0         0 $sock->close;
1810              
1811 0         0 return 1;
1812             }
1813              
1814             ########################################################
1815             # DNS hostname resolution
1816             # return:
1817             # $h->{name} = host - as passed in
1818             # $h->{host} = host - as passed in without :port
1819             # $h->{port} = OPTIONAL - if :port, then value of port
1820             # $h->{addr} = resolved numeric address
1821             # $h->{addr_in} = aton/pton result
1822             # $h->{family} = AF_INET/6
1823             ############################
1824             sub _resolv {
1825 60     60   193 my ($self,
1826             $name,
1827             ) = @_;
1828              
1829 60         164 my %h;
1830 60         160 $h{name} = $name;
1831 60         148 my $family = $self->{family};
1832              
1833 60 50       161 if (defined($self->{family_local})) {
1834             $family = $self->{family_local}
1835 60         97 }
1836              
1837             # START - host:port
1838 60         95 my $cnt = 0;
1839              
1840             # Count ":"
1841 60         234 $cnt++ while ($name =~ m/:/g);
1842              
1843             # 0 = hostname or IPv4 address
1844 60 100       154 if ($cnt == 0) {
    50          
    50          
1845 59         180 $h{host} = $name
1846             # 1 = IPv4 address with port
1847             } elsif ($cnt == 1) {
1848 0         0 ($h{host}, $h{port}) = split /:/, $name
1849             # >=2 = IPv6 address
1850             } elsif ($cnt >= 2) {
1851             #IPv6 with port - [2001::1]:port
1852 1 50       4 if ($name =~ /^\[.*\]:\d{1,5}$/) {
1853 0         0 ($h{host}, $h{port}) = split /:([^:]+)$/, $name # split after last :
1854             # IPv6 without port
1855             } else {
1856 1         2 $h{host} = $name
1857             }
1858             }
1859              
1860             # Clean up host
1861 60         148 $h{host} =~ s/\[//g;
1862 60         116 $h{host} =~ s/\]//g;
1863             # Clean up port
1864 60 0 0     153 if (defined($h{port}) && (($h{port} !~ /^\d{1,5}$/) || ($h{port} < 1) || ($h{port} > 65535))) {
      33        
1865 0         0 croak("Invalid port `$h{port}' in `$name'");
1866 0         0 return undef;
1867             }
1868             # END - host:port
1869              
1870             # address check
1871             # new way
1872 60 50       208 if ($Socket_VERSION > 1.94) {
1873 60         327 my %hints = (
1874             family => $AF_UNSPEC,
1875             protocol => IPPROTO_TCP,
1876             flags => $AI_NUMERICHOST
1877             );
1878              
1879             # numeric address, return
1880 60         877 my ($err, @getaddr) = Socket::getaddrinfo($h{host}, undef, \%hints);
1881 60 100       233 if (defined($getaddr[0])) {
1882 33         86 $h{addr} = $h{host};
1883 33         66 $h{family} = $getaddr[0]->{family};
1884 33 100       100 if ($h{family} == AF_INET) {
1885 32         149 (undef, $h{addr_in}, undef, undef) = Socket::unpack_sockaddr_in $getaddr[0]->{addr};
1886             } else {
1887 1         7 (undef, $h{addr_in}, undef, undef) = Socket::unpack_sockaddr_in6 $getaddr[0]->{addr};
1888             }
1889 33         180 return \%h
1890             }
1891             # old way
1892             } else {
1893             # numeric address, return
1894 0         0 my $ret = gethostbyname($h{host});
1895 0 0 0     0 if (defined($ret) && (_inet_ntoa($ret) eq $h{host})) {
1896 0         0 $h{addr} = $h{host};
1897 0         0 $h{addr_in} = $ret;
1898 0         0 $h{family} = AF_INET;
1899 0         0 return \%h
1900             }
1901             }
1902              
1903             # resolve
1904             # new way
1905 27 50       70 if ($Socket_VERSION >= 1.94) {
1906 27         69 my %hints = (
1907             family => $family,
1908             protocol => IPPROTO_TCP
1909             );
1910              
1911 27         1355792 my ($err, @getaddr) = Socket::getaddrinfo($h{host}, undef, \%hints);
1912 27 50       321 if (defined($getaddr[0])) {
1913 27         321 my ($err, $address) = Socket::getnameinfo($getaddr[0]->{addr}, $NI_NUMERICHOST, $NIx_NOSERV);
1914 27 50       77 if (defined($address)) {
1915 27         94 $h{addr} = $address;
1916 27         135 $h{addr} =~ s/\%(.)*$//; # remove %ifID if IPv6
1917 27         67 $h{family} = $getaddr[0]->{family};
1918 27 50       98 if ($h{family} == AF_INET) {
1919 27         214 (undef, $h{addr_in}, undef, undef) = Socket::unpack_sockaddr_in $getaddr[0]->{addr};
1920             } else {
1921 0         0 (undef, $h{addr_in}, undef, undef) = Socket::unpack_sockaddr_in6 $getaddr[0]->{addr};
1922             }
1923 27         283 return \%h;
1924             } else {
1925 0         0 carp("getnameinfo($getaddr[0]->{addr}) failed - $err");
1926 0         0 return undef;
1927             }
1928             } else {
1929 0 0       0 warn(sprintf("getaddrinfo($h{host},,%s) failed - $err",
1930             $family == AF_INET ? "AF_INET" : "AF_INET6"));
1931 0         0 return undef;
1932             }
1933             # old way
1934             } else {
1935 0 0       0 if ($family == $AF_INET6) {
1936 0         0 croak("Socket >= 1.94 required for IPv6 - found Socket $Socket::VERSION");
1937 0         0 return undef;
1938             }
1939              
1940 0         0 my @gethost = gethostbyname($h{host});
1941 0 0       0 if (defined($gethost[4])) {
1942 0         0 $h{addr} = inet_ntoa($gethost[4]);
1943 0         0 $h{addr_in} = $gethost[4];
1944 0         0 $h{family} = AF_INET;
1945 0         0 return \%h
1946             } else {
1947 0         0 carp("gethostbyname($h{host}) failed - $^E");
1948 0         0 return undef;
1949             }
1950             }
1951 0         0 return undef;
1952             }
1953              
1954             sub _pack_sockaddr_in($$) {
1955 75     75   181 my ($port,
1956             $ip,
1957             ) = @_;
1958              
1959 75 100       266 my $addr = ref($ip) eq "HASH" ? $ip->{addr_in} : $ip;
1960 75 100       200 if (length($addr) <= 4 ) {
1961 74         352 return Socket::pack_sockaddr_in($port, $addr);
1962             } else {
1963 1         6 return Socket::pack_sockaddr_in6($port, $addr);
1964             }
1965             }
1966              
1967             sub _unpack_sockaddr_in($;$) {
1968 8     8   21 my ($addr,
1969             $family,
1970             ) = @_;
1971              
1972 8         11 my ($port, $host);
1973 8 50 0     27 if ($family == AF_INET || (!defined($family) and length($addr) <= 16 )) {
      33        
1974 8         29 ($port, $host) = Socket::unpack_sockaddr_in($addr);
1975             } else {
1976 0         0 ($port, $host) = Socket::unpack_sockaddr_in6($addr);
1977             }
1978 8         22 return $port, $host
1979             }
1980              
1981             sub _inet_ntoa {
1982 0     0     my ($addr
1983             ) = @_;
1984              
1985 0           my $ret;
1986 0 0         if ($Socket_VERSION >= 1.94) {
1987 0           my ($err, $address) = Socket::getnameinfo($addr, $NI_NUMERICHOST);
1988 0 0         if (defined($address)) {
1989 0           $ret = $address;
1990             } else {
1991 0           carp("getnameinfo($addr) failed - $err");
1992             }
1993             } else {
1994 0           $ret = inet_ntoa($addr)
1995             }
1996            
1997 0           return $ret
1998             }
1999              
2000             1;
2001             __END__