ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/host/ihost-perl/ihost.pl
Revision: 1.51
Committed: Fri Mar 28 16:30:30 2003 UTC (21 years, 5 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.50: +1 -1 lines
State: FILE REMOVED
Log Message:
Removed some un-used code from CVS. We can always resurrect this later if
someone feels they want to work on it. Gone are the old perl ihost which
isn't needed now, winhost which is broken and shows no sign of being fixed,
and DBReporter. If someone wants to revive them, I'll undelete them :-)

File Contents

# User Rev Content
1 pjm2 1.6 #!/usr/bin/perl -w
2 pjm2 1.1
3 tdb 1.49 #
4     # i-scream central monitoring system
5 tdb 1.50 # http://www.i-scream.org.uk
6 tdb 1.49 # Copyright (C) 2000-2002 i-scream
7     #
8     # This program is free software; you can redistribute it and/or
9     # modify it under the terms of the GNU General Public License
10     # as published by the Free Software Foundation; either version 2
11     # of the License, or (at your option) any later version.
12     #
13     # This program is distributed in the hope that it will be useful,
14     # but WITHOUT ANY WARRANTY; without even the implied warranty of
15     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     # GNU General Public License for more details.
17     #
18     # You should have received a copy of the GNU General Public License
19     # along with this program; if not, write to the Free Software
20     # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21     #
22    
23 pjm2 1.1 # -----------------------------------------------------------
24     # Perl i-scream Host.
25 pjm2 1.12 # http://www.i-scream.org.uk
26 pjm2 1.1 #
27     # An all-in-one script to act as an i-scream host on
28 tdb 1.36 # a typical Unix/Linux box.
29 pjm2 1.1 #
30 tdb 1.44 # $Author: tdb $
31 tdb 1.51 # $Id: ihost.pl,v 1.50 2002/05/21 16:47:11 tdb Exp $
32 pjm2 1.1 #------------------------------------------------------------
33    
34     $| = 1;
35    
36     use strict;
37     use IO::Socket;
38     use Sys::Hostname;
39    
40     use vars qw (
41     $filter_manager_addr
42     $filter_manager_port
43     $seq_no
44     $udp_update_time
45     $tcp_update_time
46     $last_udp_time
47     $last_tcp_time
48     $last_modified
49     $udp_port
50     $tcp_port
51     $filter_addr
52     $file_list
53 pjm2 1.17 $fqdn
54 tdb 1.25 $pidfile
55 pjm2 1.28 $retry_wait
56 tdb 1.44 $ostype
57 tdb 1.47 $key
58 tdb 1.37 @data
59 pjm2 1.1 );
60    
61     if (@ARGV != 2) {
62     die "Usage: ihost.pl [i-scream filter manager] [TCP port]\n";
63     }
64    
65     $filter_manager_addr = $ARGV[0];
66     $filter_manager_port = $ARGV[1];
67    
68     $seq_no = 1;
69 pjm2 1.33 $retry_wait = 60;
70 pjm2 1.1
71 tdb 1.44 # work out our platform, if we can.
72     $ostype = `uname -s`;
73     chomp $ostype;
74     $ostype = "unknown" if not defined $ostype;
75    
76 tdb 1.25 # write our PID to a file
77 tdb 1.41 # use home dir by default
78 tdb 1.42 #$pidfile = $ENV{"HOME"};
79 tdb 1.41 # or drop it in /var/tmp if we can't find HOME
80     $pidfile = "/var/tmp" if not defined $pidfile;
81     $pidfile .= "/.ihost.pid";
82 tdb 1.25 &write_pid();
83    
84 pjm2 1.1 &tcp_configure();
85 tdb 1.47 &send_tcp_heartbeat();
86 pjm2 1.1 &send_udp_packet();
87    
88     $last_udp_time = time;
89     $last_tcp_time = time;
90     while (1) {
91 pjm2 1.9 my($time) = time;
92     if ($time >= $last_udp_time + $udp_update_time) {
93 pjm2 1.1 &send_udp_packet();
94 pjm2 1.9 $last_udp_time = $time;
95 pjm2 1.1 }
96 pjm2 1.9 if ($time >= $last_tcp_time + $tcp_update_time) {
97 pjm2 1.1 &send_tcp_heartbeat();
98 pjm2 1.9 $last_tcp_time = $time;
99 pjm2 1.1 }
100 pjm2 1.9 my($next_udp) = $udp_update_time - $time + $last_udp_time;
101     my($next_tcp) = $tcp_update_time - $time + $last_tcp_time;
102     my($delay);
103     if ($next_udp < $next_tcp) {
104     $delay = $next_udp
105     }
106     else {
107     $delay = $next_tcp;
108     }
109 tdb 1.35 sleep $delay;
110 pjm2 1.1 }
111    
112 tdb 1.25 # we'll probably never get here...
113     `rm -f $pidfile`;
114 pjm2 1.1 exit(0);
115    
116 pjm2 1.12
117     #-----------------------------------------------------------------------
118 pjm2 1.28 # wait_then_retry
119     # Waits for the period of time specified in $retry_wait, then attempts
120     # to reconfigure with the server.
121     #-----------------------------------------------------------------------
122     sub wait_then_retry() {
123     print "Will retry configuration with filter manager in $retry_wait seconds.\n";
124 tdb 1.35 sleep $retry_wait;
125 pjm2 1.28 }
126    
127    
128     #-----------------------------------------------------------------------
129 pjm2 1.12 # tcp_configure
130     # Establishes a TCP connection to the specified i-scream filter manager.
131     # The host then requests details from the server, such as the intervals
132     # at which to send UDP packets.
133     #-----------------------------------------------------------------------
134 pjm2 1.1 sub tcp_configure() {
135    
136 pjm2 1.31 while (1) {
137 pjm2 1.28 my($sock) = new IO::Socket::INET(
138     PeerAddr => $filter_manager_addr,
139     PeerPort => $filter_manager_port,
140     Proto => 'tcp'
141     ) or die "Cannot connect!";
142     if (!defined $sock) {
143     print "IHOST ERROR: Could not connect to $filter_manager_addr:$filter_manager_port.\n";
144     print "Please check that there is an i-scream server at this address.\n";
145     wait_then_retry();
146     next;
147     }
148    
149     # Now run through the configuration process...
150     my($response);
151    
152     print $sock "STARTCONFIG\n";
153     $response = <$sock>;
154 pjm2 1.32 if ($response && !($response eq "OK\n")) {
155     print "The i-scream server rejected the STARTCONFIG command.\n";
156 pjm2 1.28 close($sock);
157     wait_then_retry();
158     next;
159     }
160    
161     print "Config started okay.\n";
162    
163     print $sock "LASTMODIFIED\n";
164     $response = <$sock>;
165 tdb 1.48 if (!$response || $response eq "ERROR\n") {
166     print "The i-scream server did not provide the LASTMODIFIED value.\n";
167 pjm2 1.32 close($sock);
168     wait_then_retry();
169     next;
170     }
171 tdb 1.48 chomp $response;
172 pjm2 1.28 $last_modified = $response;
173    
174     print "Config last modified: ". (scalar localtime $last_modified/1000) . "\n";
175    
176     print $sock "FILELIST\n";
177     $response = <$sock>;
178 tdb 1.48 if (!$response || $response eq "ERROR\n") {
179 pjm2 1.32 print "The i-scream server did not provide a configuration file list.\n";
180     close($sock);
181     wait_then_retry();
182     next;
183     }
184 tdb 1.48 chomp $response;
185 pjm2 1.28 $file_list = $response;
186    
187     print "File list obtained: $file_list\n";
188    
189     print $sock "FQDN\n";
190     $response = <$sock>;
191 tdb 1.48 if (!$response || $response eq "ERROR\n") {
192 pjm2 1.32 print "The i-scream server did not tell us our FQDN.\n";
193     close($sock);
194     wait_then_retry();
195     next;
196     }
197 tdb 1.48 chomp $response;
198 pjm2 1.28 $fqdn = $response;
199    
200     print "FQDN returned: $fqdn\n";
201    
202     print $sock "UDPUpdateTime\n";
203     $response = <$sock>;
204 tdb 1.48 if (!$response || $response eq "ERROR\n") {
205 pjm2 1.32 print "The i-scream server did not give us a UDPUpdateTime.\n";
206     close($sock);
207     wait_then_retry();
208     next;
209     }
210 tdb 1.48 chomp $response;
211 pjm2 1.28 $udp_update_time = $response;
212    
213     print $sock "TCPUpdateTime\n";
214     $response = <$sock>;
215 tdb 1.48 if (!$response || $response eq "ERROR\n") {
216 pjm2 1.32 print "The i-scream server did not give us a TCPUpdateTime.\n";
217     close($sock);
218     wait_then_retry();
219     next;
220     }
221 tdb 1.48 chomp $response;
222 pjm2 1.28 $tcp_update_time = $response;
223    
224     print "UDP packet period: $udp_update_time seconds.\nTCP heartbeat period: $tcp_update_time seconds.\n";
225    
226     print $sock "ENDCONFIG\n";
227     $response = <$sock>;
228 pjm2 1.32 if ($response && !($response eq "OK\n")) {
229 pjm2 1.28 print "ENDCONFIG command to server failed. Terminated.\n";
230     close($sock);
231     wait_then_retry();
232     next;
233     }
234    
235     print "Config ended.\n";
236    
237     print $sock "FILTER\n";
238     $response = <$sock>;
239 pjm2 1.32 if (!$response) {
240 pjm2 1.28 print "Failed: Could not get a filter address from the filter manager.\n";
241     close($sock);
242     wait_then_retry();
243     next;
244     }
245 tdb 1.48 chomp $response;
246 pjm2 1.28 if ($response eq "ERROR") {
247     print "There are no active configured filters for your host.\n";
248     close($sock);
249     wait_then_retry();
250     next;
251     }
252 tdb 1.48 $response =~ /^(.*);(.*);(.*)/;
253 pjm2 1.28 ($filter_addr, $udp_port, $tcp_port) = ($1, $2, $3);
254     unless (defined($filter_addr) && defined($udp_port) && defined($tcp_port)) {
255     print "Failed: Filter address response from server did not make sense: $response\n";
256     close($sock);
257     wait_then_retry();
258     next;
259     }
260    
261     print "Got filter data ($filter_addr, $udp_port, $tcp_port)\n";
262    
263     print $sock "END\n";
264     $response = <$sock>;
265 pjm2 1.32 if ($response && ($response eq "OK\n")) {
266 pjm2 1.28 print "Host successfully configured via TCP.\n"
267     }
268     else {
269 pjm2 1.32 print "The server failed the host configuration on the END command.\n";
270 pjm2 1.28 close($sock);
271     wait_then_retry();
272     next;
273     }
274 pjm2 1.1
275 pjm2 1.28 close($sock);
276 pjm2 1.1
277 pjm2 1.28 print "Configuration finished sucessfully!\n";
278     last;
279 pjm2 1.1 }
280 pjm2 1.12 return;
281 pjm2 1.1 }
282    
283 pjm2 1.12
284     #-----------------------------------------------------------------------
285     # send_udp_packet
286     # Sends a UDP packet to an i-scream filter.
287     # The packet contains XML markup describing some of the machine's state.
288     # Receipt of UDP packets is not guaranteed.
289     #-----------------------------------------------------------------------
290 pjm2 1.1 sub send_udp_packet() {
291    
292 tdb 1.37 my($plugins_dir) = "plugins";
293    
294     opendir PLUGINS, $plugins_dir;
295     my(@plugins) = readdir PLUGINS;
296     foreach my $plugin (@plugins) {
297 tdb 1.44 push @data, `$plugins_dir/$plugin $ostype` if -x "$plugins_dir/$plugin" && -f "$plugins_dir/$plugin";
298 tdb 1.37 }
299 pjm2 1.1
300 tdb 1.36 # get some extra data
301 pjm2 1.1 my($date) = time;
302 pjm2 1.33 my($ip);
303     $ip = inet_ntoa(scalar(gethostbyname(hostname())) || 'localhost') or $ip = 'localhost';
304 tdb 1.36
305     # add some extra data to the array
306 tdb 1.43 push(@data, "packet.attributes.seq_no $seq_no");
307     push(@data, "packet.attributes.machine_name $fqdn");
308     push(@data, "packet.attributes.date $date");
309     push(@data, "packet.attributes.type data");
310     push(@data, "packet.attributes.ip $ip");
311 tdb 1.47 push(@data, "packet.attributes.key $key");
312 tdb 1.39
313     # sort the data
314 tdb 1.43 @data = sort(grep(!/^$/, grep(/^packet\./, @data)));
315    
316 tdb 1.36 # turn the array into some nice XML
317     my($xml) = &make_xml("", "");
318 tdb 1.43
319 pjm2 1.1 my($sock) = new IO::Socket::INET (
320     PeerPort => $udp_port,
321     PeerAddr => $filter_addr,
322     Proto => 'udp'
323 pjm2 1.21 ) or die "Could not send UDP: $!\n";
324 tdb 1.36
325 pjm2 1.1 print $sock $xml or die "Could not send UDP packet: $!\n";
326     close($sock);
327     $seq_no++;
328 tdb 1.38 print "-";
329 pjm2 1.12
330     return;
331 pjm2 1.1 }
332    
333 pjm2 1.12
334     #-----------------------------------------------------------------------
335     # send_tcp_heartbeat
336     # Establishes a TCP connection to an i-scream filter.
337     # The heartbeat is used as a guaranteed "I'm alive" delivery mechanism.
338 pjm2 1.34 # If we need to reconfigure, then we complete the heartbeat before
339     # doing so.
340 pjm2 1.12 #-----------------------------------------------------------------------
341 pjm2 1.1 sub send_tcp_heartbeat() {
342    
343 pjm2 1.34 my ($doReconfigure) = 0;
344    
345 pjm2 1.1 my($sock) = new IO::Socket::INET(
346     PeerAddr => $filter_addr,
347     PeerPort => $tcp_port,
348     Proto => 'tcp'
349 pjm2 1.21 ) or return;
350 pjm2 1.11 if (!defined $sock) {
351     print "IHOST WARNING: Failed to deliver a heartbeat to the i-scream filter.\n";
352 pjm2 1.27 &tcp_configure();
353 pjm2 1.11 return;
354     }
355 pjm2 1.1
356     # Now run through the configuration process.
357     my($response);
358    
359     print $sock "HEARTBEAT\n";
360     $response = <$sock>;
361 pjm2 1.32 if (!$response eq "OK\n") {
362 pjm2 1.1 close($sock);
363     print "Server gave wrong response to HEARTBEAT: $response\n";
364 pjm2 1.27 &tcp_configure();
365 pjm2 1.1 return;
366     }
367    
368     print $sock "CONFIG\n";
369     $response = <$sock>;
370 pjm2 1.32 if (!$response eq "OK\n") {
371 pjm2 1.1 close($sock);
372     print "Server gave wrong response to CONFIG: $response\n";
373 pjm2 1.27 &tcp_configure();
374 pjm2 1.1 return;
375     }
376    
377     print $sock "$file_list\n";
378     $response = <$sock>;
379 pjm2 1.32 if (!$response eq "OK\n") {
380 pjm2 1.1 close($sock);
381     print "Server gave wrong response to file list: $response\n";
382 pjm2 1.27 &tcp_configure();
383 pjm2 1.1 return;
384     }
385    
386     print $sock "$last_modified\n";
387     $response = <$sock>;
388 pjm2 1.32 if ($response eq "ERROR\n") {
389 pjm2 1.1 close($sock);
390 pjm2 1.27 print "Server configuration changed. Reconfiguring with filter manager.\n";
391 pjm2 1.34 $doReconfigure = 1;
392 pjm2 1.1 }
393 pjm2 1.32 if (!$response eq "OK\n") {
394 pjm2 1.1 close($sock);
395     print "Server gave wrong response to HEARTBEAT: $response\n";
396 pjm2 1.27 &tcp_configure();
397 pjm2 1.1 return;
398     }
399 tdb 1.47
400     print $sock "KEY\n";
401     $key = <$sock>;
402 pjm2 1.1
403     print $sock "ENDHEARTBEAT\n";
404 pjm2 1.23 $response = <$sock>;
405 pjm2 1.32 if (!$response eq "OK\n") {
406 pjm2 1.1 close($sock);
407     print "Server gave wrong response to ENDHEARTBEAT: $response\n";
408 pjm2 1.27 &tcp_configure();
409 pjm2 1.1 return;
410     }
411    
412     close($sock);
413     print "^";
414 pjm2 1.34
415     &tcp_configure() if $doReconfigure;
416 tdb 1.25
417     return;
418     }
419    
420 tdb 1.36
421 tdb 1.25 #-----------------------------------------------------------------------
422     # write_pid
423     # Writes the PID (process ID) of this instance to $pidfile.
424     # This is then used by a seperate script to check (and restart) ihost.
425     #-----------------------------------------------------------------------
426     sub write_pid() {
427     open PID, ">$pidfile";
428     print PID $$;
429     close PID;
430 pjm2 1.12
431     return;
432 tdb 1.36 }
433    
434     #-----------------------------------------------------------------------
435     # make_xml
436 tdb 1.37 # Turns an array of plugins data into an XML string.
437 tdb 1.36 #-----------------------------------------------------------------------
438     sub make_xml() {
439     my($curlevel, $curline) = @_;
440     my($xmltemp) = ""; my($curtag) = ""; my($attributes) = "";
441 tdb 1.40 while(1) {
442 tdb 1.43 $curline = shift(@data) if $curline eq "";
443     return $xmltemp if not defined $curline;
444     chomp $curline;
445     # dealing with nest (or attributes)
446 tdb 1.36 if($curline =~ /^$curlevel([^\.\s]+\.)/) {
447     $curtag=$1;
448 tdb 1.43 if($curline =~ /^$curlevel$curtag([^\.\s]+)\s+(.*)$/) {
449     $xmltemp .= &make_xml("$curlevel$curtag", $curline);
450     }
451     elsif($curline =~ /^$curlevel$curtag(attributes)\.([^\.\s]+)\s+(.*)$/) {
452     $attributes .= " $2=\"$3\"";
453     }
454     else {
455     $xmltemp .= &make_xml("$curlevel$curtag", $curline);
456     }
457     my($nextline) = $data[0]; chomp $nextline if defined $nextline;
458 tdb 1.45 $curtag =~ s/(.*)\./$1/;
459     if((defined $nextline) && ($nextline =~ /^$curlevel$curtag\./)) {
460 tdb 1.43 $curline = "";
461     }
462     else {
463     $xmltemp = "<$curtag$attributes>$xmltemp</$curtag>" unless $curtag eq "";
464     return $xmltemp;
465     }
466 tdb 1.36 }
467 tdb 1.43 # dealing with value
468     elsif($curline =~ /^$curlevel([^\.\s]+)\s+(.*)$/) {
469     $curtag=$1;
470     $xmltemp=$2;
471     my($nextline) = $data[0]; chomp $nextline if defined $nextline;
472     if(defined $nextline && ($nextline =~ /^$curlevel$curtag\./ || $nextline =~ /^$curlevel$curtag\s+/)) {
473     $curline = "";
474     }
475     else {
476     $xmltemp = "<$curtag$attributes>$xmltemp</$curtag>" unless $curtag eq "";
477     return $xmltemp;
478     }
479 tdb 1.36 }
480 tdb 1.46 # dealing with a null value
481     elsif($curline =~ /^$curlevel([^\.\s]+)$/) {
482     # simply adding a space makes the above elsif deal with it :)
483     # just level with an empty tag in the XML
484     $curline .= " ";
485     }
486     # failing all that, skip the line
487     else {
488     $curline = "";
489     }
490 tdb 1.36 }
491 pjm2 1.1 }