line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MMM::Host; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
9355
|
use strict; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
373
|
|
4
|
5
|
|
|
5
|
|
29
|
use warnings; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
135
|
|
5
|
5
|
|
|
5
|
|
4404
|
use URI; |
|
5
|
|
|
|
|
41380
|
|
|
5
|
|
|
|
|
191
|
|
6
|
5
|
|
|
5
|
|
5895
|
use POSIX qw(strftime); |
|
5
|
|
|
|
|
42909
|
|
|
5
|
|
|
|
|
40
|
|
7
|
5
|
|
|
5
|
|
15883
|
use Math::Trig; |
|
5
|
|
|
|
|
165099
|
|
|
5
|
|
|
|
|
1441
|
|
8
|
5
|
|
|
5
|
|
7400
|
use Net::DNS; |
|
5
|
|
|
|
|
731961
|
|
|
5
|
|
|
|
|
3074
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
MMM::Host |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 DESCRIPTION |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
An object to retain host information |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 METHODS |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head2 new |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Create a MMM::Host object from information found in hash passed |
23
|
|
|
|
|
|
|
as arguments. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $mirror MMM::Mirror->new( host => 'host.domain' ); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=cut |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub _rev { |
30
|
12
|
|
|
12
|
|
836
|
strftime( '%Y%m%d%H%M%S', gmtime(time) ); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub new { |
34
|
13
|
|
|
13
|
1
|
2709
|
my ( $class, %infos ) = @_; |
35
|
13
|
100
|
|
|
|
48
|
$infos{hostname} or return; |
36
|
12
|
|
|
|
|
48
|
$infos{hostname} = lc( $infos{hostname} ); |
37
|
12
|
|
33
|
|
|
67
|
$infos{revision} ||= _rev(); |
38
|
12
|
100
|
|
|
|
49
|
if ( $infos{geolocation} ) { |
39
|
5
|
|
|
|
|
40
|
( $infos{longitude}, $infos{latitude} ) = |
40
|
|
|
|
|
|
|
$infos{geolocation} =~ /([\d\.]+),([\d\.]+)/; |
41
|
|
|
|
|
|
|
} |
42
|
12
|
|
|
|
|
146
|
bless( {%infos}, $class ); |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head2 hostname |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Return the hostname of the host |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=cut |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub hostname { |
52
|
1
|
|
|
1
|
1
|
325
|
my ($self) = @_; |
53
|
1
|
|
|
|
|
10
|
$self->{hostname}; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 revision |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
Return the revision of the entry. The revision is an id to identify if an |
59
|
|
|
|
|
|
|
entry is newer than another for same mirror. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=cut |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub revision { |
64
|
2
|
|
|
2
|
1
|
7
|
my ($self) = @_; |
65
|
2
|
|
|
|
|
10
|
$self->{revision}; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 refresh_revision |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Reset revision to current timestamp |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub refresh_revision { |
75
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
76
|
0
|
|
|
|
|
0
|
$self->{revision} = _rev(); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 geo |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Return the latitude and the longitude for this host |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=cut |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub geo { |
86
|
14
|
|
|
14
|
1
|
64
|
return ( $_[0]->{latitude}, $_[0]->{longitude} ); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head2 get_geo |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Try to use various method to find latitude and longitude |
92
|
|
|
|
|
|
|
and return them |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=cut |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub get_geo { |
97
|
0
|
0
|
|
0
|
1
|
0
|
if ( !$_[0]->{get_geo_done} ) { |
98
|
0
|
0
|
0
|
|
|
0
|
if ( |
99
|
|
|
|
|
|
|
!( defined( $_[0]->{latitude} ) && defined( $_[0]->{longitude} ) ) ) |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
0
|
|
|
|
0
|
$_[0]->get_dnsloc || $_[0]->get_hostiploc; |
102
|
|
|
|
|
|
|
} |
103
|
0
|
|
|
|
|
0
|
$_[0]->{get_geo_done} = 1; |
104
|
|
|
|
|
|
|
} |
105
|
0
|
|
|
|
|
0
|
return $_[0]->geo; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head2 get_hostiploc |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Get and set information from hostip.info website |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=cut |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub get_hostiploc { |
115
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
0
|
my ( $name, $aliases, $addrtype, $length, $paddr, @addrs ) = |
118
|
|
|
|
|
|
|
gethostbyname( $self->hostname ) |
119
|
|
|
|
|
|
|
or return; |
120
|
0
|
|
|
|
|
0
|
my $addr = join( '.', unpack( 'C4', $paddr ) ); |
121
|
5
|
|
|
5
|
|
5398
|
use WWW::HostipInfo; |
|
5
|
|
|
|
|
402912
|
|
|
5
|
|
|
|
|
5420
|
|
122
|
0
|
|
|
|
|
0
|
my $hostip = new WWW::HostipInfo; |
123
|
0
|
0
|
|
|
|
0
|
my $info = $hostip->get_info($addr) or return; |
124
|
0
|
0
|
|
|
|
0
|
$self->{latitude} = $info->latitude |
125
|
|
|
|
|
|
|
if ( defined( $info->latitude ) ); |
126
|
0
|
0
|
|
|
|
0
|
$self->{longitude} = $info->longitude |
127
|
|
|
|
|
|
|
if ( defined( $info->longitude ) ); |
128
|
0
|
0
|
|
|
|
0
|
$self->{country} = $info->country_name |
129
|
|
|
|
|
|
|
if ( defined( $info->country_name ) ); |
130
|
0
|
0
|
|
|
|
0
|
$self->{city} = $info->city if ( defined( $info->city ) ); |
131
|
0
|
|
|
|
|
0
|
$self->refresh_revision; |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
0
|
1; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 get_dnsloc |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Try to find geolocalisation from DNS LOC record |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub get_dnsloc { |
143
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
144
|
0
|
|
|
|
|
0
|
return; |
145
|
0
|
|
|
|
|
0
|
my @partname = split( /\./, $self->hostname ); |
146
|
0
|
|
|
|
|
0
|
my $dnsq = Net::DNS::Resolver->new(); |
147
|
0
|
|
|
|
|
0
|
do { |
148
|
0
|
0
|
|
|
|
0
|
my $answer = $dnsq->query( join( '.', @partname ), 'LOC' ) or return; |
149
|
0
|
|
|
|
|
0
|
foreach my $ans ( $answer->answer ) { |
150
|
0
|
0
|
|
|
|
0
|
if ( $ans->type eq 'LOC' ) { |
151
|
0
|
|
|
|
|
0
|
( $self->{latitude}, $self->{longitude} ) = $ans->latlon(); |
152
|
0
|
|
|
|
|
0
|
$self->refresh_revision; |
153
|
0
|
|
|
|
|
0
|
return 1; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} while ( shift(@partname) ); |
157
|
|
|
|
|
|
|
|
158
|
0
|
|
|
|
|
0
|
return; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 set_geo($latitude, $longitude) |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Set the geolocalisation for this host |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub set_geo { |
168
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $lat, $lon ) = @_; |
169
|
0
|
|
|
|
|
0
|
( $self->{latitude}, $self->{longitude} ) = ( $lat, $lon ); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 distance( $host ) |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Calcule the distance (angle in degrees) to another host |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=cut |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub distance { |
179
|
3
|
|
|
3
|
1
|
5
|
my ( $self, $host ) = @_; |
180
|
3
|
50
|
|
|
|
10
|
grep { !defined($_) } ($self->geo, $host->geo) and return; |
|
12
|
|
|
|
|
32
|
|
181
|
3
|
|
|
|
|
8
|
my ( $lat1, $lon1 ) = map { deg2rad($_) } $self->geo; |
|
6
|
|
|
|
|
57
|
|
182
|
3
|
|
|
|
|
32
|
my ( $lat2, $lon2 ) = map { deg2rad($_) } $host->geo; |
|
6
|
|
|
|
|
34
|
|
183
|
3
|
|
|
|
|
166
|
rad2deg( |
184
|
|
|
|
|
|
|
acos( |
185
|
|
|
|
|
|
|
sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) * |
186
|
|
|
|
|
|
|
cos( $lon1 - $lon2 ) |
187
|
|
|
|
|
|
|
) |
188
|
|
|
|
|
|
|
); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 same_host($host) |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Compare two host entry and return true if they identify the same |
194
|
|
|
|
|
|
|
computer |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub same_host { |
199
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $host ) = @_; |
200
|
0
|
0
|
|
|
|
0
|
if ( $self->hostname eq $host->hostname ) { |
201
|
0
|
|
|
|
|
0
|
return 1; |
202
|
|
|
|
|
|
|
} |
203
|
0
|
|
|
|
|
0
|
return; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head2 sync_host($host) |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Get unknown values from $host if defined. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub sync_host { |
213
|
1
|
|
|
1
|
1
|
3
|
my ( $self, $host ) = @_; |
214
|
1
|
|
|
|
|
3
|
foreach (qw(city continent country latitude longiture)) { |
215
|
5
|
50
|
0
|
|
|
18
|
if ( |
|
|
|
33
|
|
|
|
|
216
|
|
|
|
|
|
|
( !defined( $self->{$_} ) ) |
217
|
|
|
|
|
|
|
|| ( defined( $host->{$_} ) |
218
|
|
|
|
|
|
|
&& $host->revision > $self->revision ) |
219
|
|
|
|
|
|
|
) |
220
|
|
|
|
|
|
|
{ |
221
|
5
|
|
|
|
|
13
|
$self->{$_} = $host->{$_}; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
1
|
50
|
|
|
|
6
|
if ( $host->revision > $self->revision ) { |
226
|
0
|
|
|
|
|
|
$self->{revision} = $host->{revision}; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 xml_output |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Return a xml string describing this mirror. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
See also |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=cut |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub xml_output { |
239
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
240
|
0
|
|
|
|
|
|
my $xml = "\t\t\n"; |
241
|
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
|
foreach (qw(hostname continent country city revision)) { |
243
|
0
|
0
|
|
|
|
|
if ( $self->{$_} ) { |
244
|
0
|
|
|
|
|
|
$xml .= sprintf( "\t\t\t<%s>%s%s>\n", $_, $self->{$_}, $_ ); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
0
|
0
|
0
|
|
|
|
if ( defined( $self->{latitude} ) && defined( $self->{longitude} ) ) { |
249
|
0
|
|
|
|
|
|
$xml .= |
250
|
|
|
|
|
|
|
"\t\t\t$self->{longitude},$self->{latitude}\n"; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
$xml .= "\t\t\n"; |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
$xml; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
1; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head1 AUTHOR |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Olivier Thauvin |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Copyright (C) 2006 Olivier Thauvin |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or |
269
|
|
|
|
|
|
|
modify it under the terms of the GNU General Public License |
270
|
|
|
|
|
|
|
as published by the Free Software Foundation; either version 2 |
271
|
|
|
|
|
|
|
of the License, or (at your option) any later version. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
274
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
275
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
276
|
|
|
|
|
|
|
GNU General Public License for more details. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
279
|
|
|
|
|
|
|
along with this program; if not, write to the Free Software |
280
|
|
|
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
283
|
|
|
|
|
|
|
|