File Coverage

blib/lib/FusionInventory/Agent/Task/Deploy/P2P.pm
Criterion Covered Total %
statement 48 107 44.8
branch 11 40 27.5
condition 6 11 54.5
subroutine 8 14 57.1
pod 0 3 0.0
total 73 175 41.7


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Deploy::P2P;
2              
3 2     2   35331566 use strict;
  2         12  
  2         87  
4 2     2   12 use warnings;
  2         2  
  2         127  
5              
6 2     2   10 use English qw(-no_match_vars);
  2         94  
  2         34  
7 2     2   3246 use HTTP::Request::Common qw(GET);
  2         54071  
  2         179  
8 2     2   2355 use Net::IP;
  2         98890  
  2         446  
9 2     2   1953 use POE qw(Component::Client::TCP Component::Client::Ping);
  2         98344  
  2         17  
10              
11 2     2   210725 use UNIVERSAL::require;
  2         6  
  2         26  
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 3     3   16762 my ($logger, $addresses, $ipLimit) = @_;
23              
24             # Max number of IP to pick from a network range
25 3 50       15 $ipLimit = 255 unless $ipLimit;
26              
27 3         7 my @ipToTest;
28 3         10 foreach my $address (@$addresses) {
29 3         22 my @ip_bytes = split(/\./, $address->{ip});
30 3         16 my @mask_bytes = split(/\./, $address->{mask});
31 3 100       19 next if $ip_bytes[0] == 127; # Ignore 127.x.x.x addresses
32 2 50       10 next if $ip_bytes[0] == 169; # Ignore 169.x.x.x range too
33              
34             # compute range
35 2         5 my @start;
36             my @end;
37              
38 2         8 foreach my $idx (0..3) {
39             ## no critic (ProhibitBitwise)
40 8         19 push @start, $ip_bytes[$idx] & (255 & $mask_bytes[$idx]);
41 8         21 push @end, $ip_bytes[$idx] | (255 - $mask_bytes[$idx]);
42             }
43              
44 2         10 my $ipStart = join('.', @start);
45 2         8 my $ipEnd = join('.', @end);
46              
47 2   50     19 my $ipInterval = Net::IP->new($ipStart.' - '.$ipEnd) || die Net::IP::Error();
48              
49 2 50       2223 next if $ipStart eq $ipEnd;
50              
51 2 50       11 if ($ipInterval->size() > 5000) {
52 0         0 $logger->debug("Range to large: ".$ipInterval->size()." (max 5000)");
53 0         0 next;
54             }
55              
56 2         20245 my $after = 0;
57 2         4 my @newIPs;
58 2   66     5 do {
59 1235         13372380 push @newIPs, $ipInterval->ip();
60 1235 100 100     9624 if ($after || $address->{ip} eq $ipInterval->ip()) {
    100          
61 6         55 $after++;
62             } elsif (@newIPs > ($ipLimit / 2)) {
63 1223         16218 shift @newIPs;
64             }
65             } while (++$ipInterval && ($after < ($ipLimit / 2)));
66              
67              
68 2 50       24324 $logger->debug("Scanning from ".$newIPs[0]." to ".$newIPs[@newIPs-1]) if $logger;
69              
70 2         29 push @ipToTest, @newIPs;
71              
72             }
73 3         24 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             push @addresses, {
120             ip => $interface->{IPADDRESS},
121             mask => $interface->{IPMASK}
122 0           };
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             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;