#!/usr/bin/perl -w # # LiveJournal Remote Procedure Call Client (ljrpc) # Copyright 2001 Dormando (dormando@rydia.net) # Going to add a license (GPL?) later. # # # This client runs commands you give it at the prompt through the RPC # system. By default, first it sends out a 'ping', then sends the # command to any machine that replies to it. Prints out replies it # gets, too. It can also be invoked with --now, in which case it # broadcasts the command and exits immediately. # # # lib: IO::Socket, Getopt::Long # use strict; use IO::Socket; use Getopt::Long; use constant SEC_SLAVE_WAIT => 4; use lib "$ENV{'LJHOME'}/cgi-bin"; require "ljconfig.pl"; $SIG{CHLD} = 'IGNORE'; my $MAXLEN = 512; my $PORTNO = 6100; if ($LJ::BCAST_ADDR) { } # shutup warning my $bcastaddr = $LJ::BCAST_ADDR || '10.0.0.255'; my ($cmdmsg, $remhost, @hosts); ### option processing my $timeout = 0; my $quick = 0; my $server = "web"; my $ping = 0; my $delay = 0; my $serialized = 0; exit 1 unless GetOptions('timeout=i' => \$timeout, 'now' => \$quick, 'server=s' => \$server, 'ping' => \$ping, 'serialized|s' => \$serialized, 'dest=s' => \$bcastaddr, 'delay|d=i' => \$delay, ); my $msg = "@ARGV"; $msg = "cmd: " . $msg; # Creat socket. Shoot the broadcast off. my $sock = IO::Socket::INET->new(Proto => 'udp') or die "Creating socket: $!\n"; $sock->sockopt(SO_BROADCAST, 1); my $ipaddr = inet_aton($bcastaddr); my $portaddr = sockaddr_in($PORTNO, $ipaddr); print STDERR "Broadcasting.\n"; if ($quick) { $sock->send($msg, 0, $portaddr) or die "send: $!\n"; exit 0; } else { $sock->send("marco $server", 0, $portaddr) or die "send: $!\n"; } my $count = 0; $| = 1; # First loop, grabs machines that are up. my %mark; if ($server eq "web") { open (O, "$ENV{LJHOME}/cgi-bin/pool_int_web.txt"); while () { chomp; $mark{$_} = 1; } close O; } eval { local $SIG{ALRM} = sub { die "timeout" }; alarm(SEC_SLAVE_WAIT); while ($sock->recv($cmdmsg, $MAXLEN)) { my ($port, $ipaddr) = sockaddr_in($sock->peername); $remhost = gethostbyaddr($ipaddr, AF_INET) || ""; my $remip = inet_ntoa($ipaddr); if ($cmdmsg eq "pollo") { alarm(SEC_SLAVE_WAIT); $count++; print "$count: $remhost [$remip]\n"; delete $mark{$remip}; push(@hosts, $remhost); } } alarm(0); }; print "\n"; if ($ping) { print "Unreported int_web nodes:\n" if %mark; foreach (keys %mark) { print " $_\n"; } exit; } if ($serialized) { foreach my $host (@hosts) { printf "Sending: %-30s", "$host ..."; my $ipaddr = inet_aton($host); my $portaddr = sockaddr_in($PORTNO, $ipaddr); if ($sock->send($msg, 0, $portaddr)) { print "sent.\n"; } else { print "failed.\n"; } if ($delay) { sleep $delay; } else { $sock->recv($cmdmsg, $MAXLEN); my ($port, $remipaddr) = sockaddr_in($sock->peername); $remhost = gethostbyaddr($remipaddr, AF_INET); print "Server $remhost:\n===============================\n"; print $cmdmsg; print "\n\n"; } } exit; } foreach my $host (@hosts) { printf "Sending: %-30s", "$host ..."; my $ipaddr = inet_aton($host); my $portaddr = sockaddr_in($PORTNO, $ipaddr); if ($sock->send($msg, 0, $portaddr)) { print "sent.\n"; } else { print "failed.\n"; } sleep $timeout; } print "\n\n"; # Loop receiving command stuffs. for (my $i = 0; $i < @hosts; $i++) { $sock->recv($cmdmsg, $MAXLEN); my ($port, $ipaddr) = sockaddr_in($sock->peername); $remhost = gethostbyaddr($ipaddr, AF_INET); # Parse thing. print "Server $remhost:\n===============================\n"; print $cmdmsg; print "\n\n"; }