File Coverage

blib/lib/FusionInventory/Agent/Task/Deploy/P2P.pm
Criterion Covered Total %
statement 21 108 19.4
branch 0 40 0.0
condition 0 11 0.0
subroutine 7 14 50.0
pod 0 3 0.0
total 28 176 15.9


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Deploy::P2P;
2              
3 1     1   27170915 use strict;
  1         8  
  1         83  
4 1     1   7 use warnings;
  1         1  
  1         73  
5              
6 1     1   9 use English qw(-no_match_vars);
  1         34  
  1         21  
7 1     1   2335 use HTTP::Request::Common qw(GET);
  1         35364  
  1         125  
8 1     1   1053 use Net::IP;
  1         49552  
  1         196  
9 1     1   601 use POE qw(Component::Client::TCP Component::Client::Ping);
  1         41683  
  1         8  
10              
11 1     1   100730 use UNIVERSAL::require;
  1         2  
  1         20  
12              
13             # POE Debug
14             #sub POE::Kernel::TRACE_REFCNT () { 1 }
15              
16             my %cache = (
17             date => 0,
18             data => undef
19             );
20              
21             sub _computeIPToTest {
22 0     0     my ($logger, $addresses, $ipLimit) = @_;
23              
24             # Max number of IP to pick from a network range
25 0 0         $ipLimit = 255 unless $ipLimit;
26              
27 0           my @ipToTest;
28 0           foreach my $address (@$addresses) {
29 0           my @ip_bytes = split(/\./, $address->{ip});
30 0           my @mask_bytes = split(/\./, $address->{mask});
31 0 0         next if $ip_bytes[0] == 127; # Ignore 127.x.x.x addresses
32 0 0         next if $ip_bytes[0] == 169; # Ignore 169.x.x.x range too
33              
34             # compute range
35 0           my @start;
36             my @end;
37              
38 0           foreach my $idx (0..3) {
39             ## no critic (ProhibitBitwise)
40 0           push @start, $ip_bytes[$idx] & (255 & $mask_bytes[$idx]);
41 0           push @end, $ip_bytes[$idx] | (255 - $mask_bytes[$idx]);
42             }
43              
44 0           my $ipStart = join('.', @start);
45 0           my $ipEnd = join('.', @end);
46              
47 0   0       my $ipInterval = Net::IP->new($ipStart.' - '.$ipEnd) || die Net::IP::Error();
48              
49 0 0         next if $ipStart eq $ipEnd;
50              
51 0 0         if ($ipInterval->size() > 5000) {
52 0           $logger->debug("Range to large: ".$ipInterval->size()." (max 5000)");
53 0           next;
54             }
55              
56 0           my $after = 0;
57 0           my @newIPs;
58 0   0       do {
59 0           push @newIPs, $ipInterval->ip();
60 0 0 0       if ($after || $address->{ip} eq $ipInterval->ip()) {
    0          
61 0           $after++;
62             } elsif (@newIPs > ($ipLimit / 2)) {
63 0           shift @newIPs;
64             }
65             } while (++$ipInterval && ($after < ($ipLimit / 2)));
66              
67              
68 0 0         $logger->debug("Scanning from ".$newIPs[0]." to ".$newIPs[@newIPs-1]) if $logger;
69              
70 0           push @ipToTest, @newIPs;
71              
72             }
73 0           return @ipToTest;
74              
75             }
76              
77             sub fisher_yates_shuffle {
78 0     0 0   my $deck = shift; # $deck is a reference to an array
79              
80 0 0         return unless @$deck; # must not be empty!
81              
82 0           my $i = @$deck;
83 0           while (--$i) {
84 0           my $j = int rand ($i+1);
85 0           @$deck[$i,$j] = @$deck[$j,$i];
86             }
87             }
88              
89             sub findPeer {
90 0     0 0   my ( $port, $logger ) = @_;
91              
92             # $logger->debug("cachedate: ".$cache{date});
93 0           $logger->info("looking for a peer in the network");
94 0 0         return $cache{data} if $cache{date} + 600 > time;
95              
96 0           my @interfaces;
97              
98              
99 0 0         if ($OSNAME eq 'linux') {
    0          
100 0           FusionInventory::Agent::Tools::Linux->require();
101 0           @interfaces = FusionInventory::Agent::Tools::Linux::getInterfacesFromIfconfig();
102              
103             } elsif ($OSNAME eq 'MSWin32') {
104 0           FusionInventory::Agent::Tools::Win32->require();
105 0           @interfaces = FusionInventory::Agent::Tools::Win32::getInterfaces();
106             }
107              
108              
109 0           my @addresses;
110              
111 0           foreach my $interface (@interfaces) {
112             #if interface has both ip and netmask setup then push the address
113 0 0         next unless $interface->{IPADDRESS};
114 0 0         next unless $interface->{IPMASK};
115 0 0         next unless lc($interface->{STATUS}) eq 'up';
116 0 0         next if $interface->{IPADDRESS} =~ /^127\./;
117              
118              
119 0           push @addresses, {
120             ip => $interface->{IPADDRESS},
121             mask => $interface->{IPMASK}
122             };
123             }
124              
125              
126 0 0         if (!@addresses) {
127 0           $logger->info("No network to scan...");
128 0           return;
129             }
130              
131 0           $cache{date}=time;
132 0           $cache{data}=scan({logger => $logger, port => $port}, _computeIPToTest($logger, \@addresses));
133 0           return $cache{data};
134             }
135              
136              
137             sub scan {
138 0     0 0   my ($params, @ipToTestList) = @_;
139 0           my $port = $params->{port};
140 0           my $logger = $params->{logger};
141              
142              
143 0           fisher_yates_shuffle(\@ipToTestList);
144              
145 0           POE::Component::Client::Ping->spawn(
146             Timeout => 5, # defaults to 1 second
147             );
148              
149 0           my $ipCpt = int(@ipToTestList);
150 0           my @ipFound;
151             POE::Session->create(
152             inline_states => {
153             _start => sub {
154 0     0     $_[HEAP]->{shutdown_on_error}=1;
155 0           $_[KERNEL]->yield( "add", 0 );
156             },
157             add => sub {
158 0     0     my $ipToTest = shift @ipToTestList;
159              
160 0 0         return unless $ipToTest;
161              
162 0           print ".";
163              
164 0           $_[KERNEL]->post(
165             "pinger", # Post the request to the "pingthing" component.
166             "ping", # Ask it to "ping" an address.
167             "pong", # Have it post an answer as a "pong" event.
168             $ipToTest, # This is the address we want to ping.
169             );
170              
171 0 0 0       if (@ipToTestList && @ipFound < 30) {
172 0           $_[KERNEL]->delay(add => 0.1)
173             } else {
174 0           $_[KERNEL]->yield("shutdown");
175             }
176              
177              
178             },
179             pong => sub {
180 0     0     my ($response) = $_[ARG1];
181              
182 0           my ($addr) = @$response;
183              
184 0 0         if (!$addr) {
185 0           $ipCpt--;
186 0           $logger->debug("cpt:".$ipCpt);
187              
188 0           return;
189             }
190 0           $logger->debug($addr." is up");
191              
192             POE::Component::Client::TCP->new(
193             RemoteAddress => $addr,
194             RemotePort => $port,
195             ConnectTimeout => 10,
196             Connected => sub {
197 0           push @ipFound, "http://$addr:$port/deploy/getFile/";
198             },
199 0           ServerInput => sub { }
200 0           );
201             },
202             },
203 0           );
204             # Run everything, and exit when it's all done.
205 0           $poe_kernel->run();
206 0           $logger->debug("end of POE loop");
207 0           return \@ipFound;
208             }
209              
210             1;