--- loncom/lond 2003/09/23 11:23:31 1.147 +++ loncom/lond 2003/10/08 14:30:09 1.153 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.147 2003/09/23 11:23:31 foxr Exp $ +# $Id: lond,v 1.153 2003/10/08 14:30:09 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -60,6 +60,30 @@ # 09/08/2003 Ron Fox: Told lond to take care of change logging so we # don't have to remember it: # $Log: lond,v $ +# Revision 1.153 2003/10/08 14:30:09 www +# Minor typos. +# +# Revision 1.152 2003/10/08 14:18:34 www +# Not good: this should be backported into 1.0.2! +# +# Revision 1.151 2003/10/03 15:11:03 albertel +# - if we fail to fetch an update to the file, don't blow away the old one +# (this was the BUG that blew away that one default.sequence that Matthew +# ended up restoring from data.) +# +# Revision 1.150 2003/09/30 10:16:06 foxr +# Added invocation of apachereload in ReloadApache sub. +# This completes the addtion of the reinit functionality. +# +# Revision 1.149 2003/09/30 09:44:13 foxr +# Tested UpdateHosts ability to +# - Remove live children for hosts that are no longer in the hosts.tab +# - Remove live children for hosts whose IPs have changed in the hosts.tab +# +# Revision 1.148 2003/09/29 10:09:18 foxr +# Put in logic to reinit lond itself (except for apache reload). I don't believe +# this logic works correctly yet, however lond still does everything it used to doso I'll do the commit anyway. +# # Revision 1.147 2003/09/23 11:23:31 foxr # Comlplete implementation of reinit functionality. Must still implement # the actual initialization functionality, but the process can now @@ -116,7 +140,7 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.147 $'; #' stupid emacs +my $VERSION='$Revision: 1.153 $'; #' stupid emacs my $remoteVERSION; my $currenthostid; my $currentdomainid; @@ -160,10 +184,10 @@ my @adderrors = ("ok", "lcuseradd Incorrect number of stdinput lines, must be 3", "lcuseradd Too many other simultaneous pwd changes in progress", "lcuseradd User does not exist", - "lcuseradd Unabel to mak ewww member of users's group", + "lcuseradd Unable to make www member of users's group", "lcuseradd Unable to su to root", "lcuseradd Unable to set password", - "lcuseradd Usrname has invbalid charcters", + "lcuseradd Usrname has invalid characters", "lcuseradd Password has an invalid character", "lcuseradd User already exists", "lcuseradd Could not add user.", @@ -492,17 +516,7 @@ if (-e $pidfile) { # ------------------------------------------------------------- Read hosts file -open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file"; -while (my $configline=) { - my ($id,$domain,$role,$name,$ip)=split(/:/,$configline); - chomp($ip); $ip=~s/\D+$//; - $hostid{$ip}=$id; - $hostdom{$id}=$domain; - $hostip{$id}=$ip; - if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; } -} -close(CONFIG); # establish SERVER socket, bind and listen. $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'}, @@ -552,6 +566,53 @@ sub HUPSMAN { # sig } # +# Kill off hashes that describe the host table prior to re-reading it. +# Hashes affected are: +# %hostid, %hostdom %hostip +# +sub KillHostHashes { + foreach my $key (keys %hostid) { + delete $hostid{$key}; + } + foreach my $key (keys %hostdom) { + delete $hostdom{$key}; + } + foreach my $key (keys %hostip) { + delete $hostip{$key}; + } +} +# +# Read in the host table from file and distribute it into the various hashes: +# +# - %hostid - Indexed by IP, the loncapa hostname. +# - %hostdom - Indexed by loncapa hostname, the domain. +# - %hostip - Indexed by hostid, the Ip address of the host. +sub ReadHostTable { + + open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file"; + + while (my $configline=) { + my ($id,$domain,$role,$name,$ip)=split(/:/,$configline); + chomp($ip); $ip=~s/\D+$//; + $hostid{$ip}=$id; + $hostdom{$id}=$domain; + $hostip{$id}=$ip; + if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; } + } + close(CONFIG); +} +# +# Reload the Apache daemon's state. +# This is done by invoking /home/httpd/perl/apachereload +# a setuid perl script that can be root for us to do this job. +# +sub ReloadApache { + my $execdir = $perlvar{'lonDaemons'}; + my $script = $execdir."/apachereload"; + system($script); +} + +# # Called in response to a USR2 signal. # - Reread hosts.tab # - All children connected to hosts that were removed from hosts.tab @@ -563,8 +624,32 @@ sub HUPSMAN { # sig # sub UpdateHosts { logthis(' Updating connections '); + # + # The %children hash has the set of IP's we currently have children + # on. These need to be matched against records in the hosts.tab + # Any ip's no longer in the table get killed off they correspond to + # either dropped or changed hosts. Note that the re-read of the table + # will take care of new and changed hosts as connections come into being. + + + KillHostHashes; + ReadHostTable; + + foreach my $child (keys %children) { + my $childip = $children{$child}; + if(!$hostid{$childip}) { + logthis(' UpdateHosts killing child ' + ." $child for ip $childip "); + kill('INT', $child); + } else { + logthis(' keeping child for ip ' + ." $childip (pid=$child) "); + } + } + ReloadApache; } + sub checkchildren { &initnewstatus(); &logstatus(); @@ -596,7 +681,7 @@ sub checkchildren { } } $SIG{ALRM} = 'DEFAULT'; - $SIG{__DIE__} = \&cathcexception; + $SIG{__DIE__} = \&catchcexception; } # --------------------------------------------------------------------- Logging @@ -809,6 +894,9 @@ $SIG{HUP} = \&HUPSMAN; $SIG{USR1} = \&checkchildren; $SIG{USR2} = \&UpdateHosts; +# Read the host hashes: + +ReadHostTable; # -------------------------------------------------------------- # Accept connections. When a connection comes in, it is validated @@ -833,12 +921,23 @@ sub make_new_child { or die "Can't block SIGINT for fork: $!\n"; die "fork: $!" unless defined ($pid = fork); + + $client->sockopt(SO_KEEPALIVE, 1); # Enable monitoring of + # connection liveness. + + # + # Figure out who we're talking to so we can record the peer in + # the pid hash. + # + my $caller = getpeername($client); + my ($port,$iaddr)=unpack_sockaddr_in($caller); + $clientip=inet_ntoa($iaddr); if ($pid) { # Parent records the child's birth and returns. sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n"; - $children{$pid} = 1; + $children{$pid} = $clientip; $children++; &status('Started child '.$pid); return; @@ -865,12 +964,8 @@ sub make_new_child { # ============================================================================= # do something with the connection # ----------------------------------------------------------------------------- - $client->sockopt(SO_KEEPALIVE, 1);# Enable monitoring of - # connection liveness. - # see if we know client and check for spoof IP by challenge - my $caller = getpeername($client); - my ($port,$iaddr)=unpack_sockaddr_in($caller); - $clientip=inet_ntoa($iaddr); + # see if we know client and check for spoof IP by challenge + my $clientrec=($hostid{$clientip} ne undef); &logthis( "INFO: Connection, $clientip ($hostid{$clientip})" @@ -1326,33 +1421,39 @@ sub make_new_child { } # -------------------------------------- fetch a user file from a remote server } elsif ($userinput =~ /^fetchuserfile/) { - my ($cmd,$fname)=split(/:/,$userinput); - my ($udom,$uname,$ufile)=split(/\//,$fname); - my $udir=propath($udom,$uname).'/userfiles'; - unless (-e $udir) { mkdir($udir,0770); } + my ($cmd,$fname)=split(/:/,$userinput); + my ($udom,$uname,$ufile)=split(/\//,$fname); + my $udir=propath($udom,$uname).'/userfiles'; + unless (-e $udir) { mkdir($udir,0770); } if (-e $udir) { - $ufile=~s/^[\.\~]+//; - $ufile=~s/\///g; - my $transname=$udir.'/'.$ufile; - my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; - my $response; - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - if ($response->is_error()) { - unlink($transname); - my $message=$response->status_line; - &logthis( - "LWP GET: $message for $fname ($remoteurl)"); - print $client "failed\n"; - } else { - print $client "ok\n"; - } - } else { - print $client "not_home\n"; - } + $ufile=~s/^[\.\~]+//; + $ufile=~s/\///g; + my $destname=$udir.'/'.$ufile; + my $transname=$udir.'/'.$ufile.'.in.transit'; + my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; + my $response; + { + my $ua=new LWP::UserAgent; + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=$ua->request($request,$transname); + } + if ($response->is_error()) { + unlink($transname); + my $message=$response->status_line; + &logthis("LWP GET: $message for $fname ($remoteurl)"); + print $client "failed\n"; + } else { + if (!rename($transname,$destname)) { + &logthis("Unable to move $transname to $destname"); + unlink($transname); + print $client "failed\n"; + } else { + print $client "ok\n"; + } + } + } else { + print $client "not_home\n"; + } # ------------------------------------------ authenticate access to a user file } elsif ($userinput =~ /^tokenauthuserfile/) { my ($cmd,$fname,$session)=split(/:/,$userinput);