--- loncom/lond	2001/11/26 20:31:01	1.57
+++ loncom/lond	2002/02/06 14:18:09	1.68.2.1
@@ -1,6 +1,31 @@
 #!/usr/bin/perl
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
+#
+# $Id: lond,v 1.68.2.1 2002/02/06 14:18:09 albertel Exp $
+#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
 # 5/26/99,6/4,6/10,6/11,6/14,6/15,6/26,6/28,6/30,
 # 7/8,7/9,7/10,7/12,7/17,7/19,9/21,
 # 10/7,10/8,10/9,10/11,10/13,10/15,11/4,11/16,
@@ -10,6 +35,7 @@
 # 06/29,06/30,07/14,07/15,07/17,07/20,07/25,09/18 Gerd Kortemeyer
 # 12/05 Scott Harrison
 # 12/05,12/13,12/29 Gerd Kortemeyer
+# YEAR=2001
 # Jan 01 Scott Harrison
 # 02/12 Gerd Kortemeyer
 # 03/15 Scott Harrison
@@ -17,9 +43,11 @@
 # 04/02 Scott Harrison
 # 05/11,05/28,08/30 Gerd Kortemeyer
 # 9/30,10/22,11/13,11/15,11/16 Scott Harrison
-# 11/26 Gerd Kortemeyer
-#
-# $Id: lond,v 1.57 2001/11/26 20:31:01 www Exp $
+# 11/26,11/27 Gerd Kortemeyer
+# 12/20 Scott Harrison
+# 12/22 Gerd Kortemeyer
+# YEAR=2002
+# 01/20/02,02/05 Gerd Kortemeyer
 ###
 
 # based on "Perl Cookbook" ISBN 1-56592-243-3
@@ -53,9 +81,14 @@ sub catchexception {
      ."a crash with this error msg->[$error]</font>");
     &logthis('Famous last words: '.$status.' - '.$lastlog);
     if ($client) { print $client "error: $error\n"; }
+    $server->close();
     die($error);
 }
 
+sub timeout {
+    &logthis("<font color=ref>CRITICAL: TIME OUT ".$$."</font>");
+    &catchexception('Timeout');
+}
 # -------------------------------- Set signal handlers to record abnormal exits
 
 $SIG{'QUIT'}=\&catchexception;
@@ -130,14 +163,19 @@ $children               = 0;        # cu
 sub REAPER {                        # takes care of dead children
     $SIG{CHLD} = \&REAPER;
     my $pid = wait;
-    $children --;
-    &logthis("Child $pid died");
-    delete $children{$pid};
+    if (defined($children{$pid})) {
+	&logthis("Child $pid died");
+	$children --;
+	delete $children{$pid};
+    } else {
+	&logthis("Unknown Child $pid died");
+    }
 }
 
 sub HUNTSMAN {                      # signal handler for SIGINT
     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
     kill 'INT' => keys %children;
+    &logthis("Free socket: ".shutdown($server,2)); # free up socket
     my $execdir=$perlvar{'lonDaemons'};
     unlink("$execdir/logs/lond.pid");
     &logthis("<font color=red>CRITICAL: Shutting down</font>");
@@ -147,7 +185,7 @@ sub HUNTSMAN {                      # si
 sub HUPSMAN {                      # signal handler for SIGHUP
     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
     kill 'INT' => keys %children;
-    close($server);                # free up socket
+    &logthis("Free socket: ".shutdown($server,2)); # free up socket
     &logthis("<font color=red>CRITICAL: Restarting</font>");
     unlink("$execdir/logs/lond.pid");
     my $execdir=$perlvar{'lonDaemons'};
@@ -158,13 +196,26 @@ sub checkchildren {
     &initnewstatus();
     &logstatus();
     &logthis('Going to check on the children');
-    map {
+    $docdir=$perlvar{'lonDocRoot'};
+    foreach (sort keys %children) {
 	sleep 1;
         unless (kill 'USR1' => $_) {
 	    &logthis ('Child '.$_.' is dead');
             &logstatus($$.' is dead');
         } 
-    } sort keys %children;
+    }
+    sleep 5;
+    foreach (sort keys %children) {
+        unless (-e "$docdir/lon-status/londchld/$_.txt") {
+	    &logthis('Child '.$_.' did not respond');
+	    kill 9 => $_;
+	    $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
+	    $subj="LON: $perlvar{'lonHostID'} killed lond process $_";
+	    my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`;
+	    $execdir=$perlvar{'lonDaemons'};
+	    $result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`
+        }
+    }
 }
 
 # --------------------------------------------------------------------- Logging
@@ -175,6 +226,7 @@ sub logthis {
     my $fh=IO::File->new(">>$execdir/logs/lond.log");
     my $now=time;
     my $local=localtime($now);
+    $lastlog=$local.': '.$message;
     print $fh "$local ($$): $message\n";
 }
 
@@ -182,8 +234,16 @@ sub logthis {
 
 sub logstatus {
     my $docdir=$perlvar{'lonDocRoot'};
+    {
     my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");
     print $fh $$."\t".$status."\t".$lastlog."\n";
+    $fh->close();
+    }
+    {
+	my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt");
+        print $fh $status."\n".$lastlog."\n".time;
+        $fh->close();
+    }
 }
 
 sub initnewstatus {
@@ -192,6 +252,11 @@ sub initnewstatus {
     my $now=time;
     my $local=localtime($now);
     print $fh "LOND status $local - parent $$\n\n";
+    opendir(DIR,"$docdir/lon-status/londchld");
+    while ($filename=readdir(DIR)) {
+        unlink("$docdir/lon-status/londchld/$filename");
+    }
+    closedir(DIR);
 }
 
 # -------------------------------------------------------------- Status setting
@@ -401,6 +466,7 @@ sub make_new_child {
         # Child can *not* return from this subroutine.
         $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before
         $SIG{USR1}= \&logstatus;
+        $SIG{ALRM}= \&timeout;
         $lastlog='Forked ';
         $status='Forked';
 
@@ -445,20 +511,17 @@ sub make_new_child {
                   } else {
 		      &logthis(
  "<font color=blue>WARNING: $clientip did not reply challenge</font>");
-                      print $client "bye\n";
                       &status('No challenge reply '.$clientip);
                   }
               } else {
 		  &logthis(
                     "<font color=blue>WARNING: "
                    ."$clientip failed to initialize: >$remotereq< </font>");
-		  print $client "bye\n";
                   &status('No init '.$clientip);
               }
 	    } else {
               &logthis(
  "<font color=blue>WARNING: Unknown client $clientip</font>");
-              print $client "bye\n";
               &status('Hung up on '.$clientip);
             }
             if ($clientok) {
@@ -466,12 +529,14 @@ sub make_new_child {
 	      &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}");
               &logthis(
        "<font color=green>Established connection: $hostid{$clientip}</font>");
-              &status('Listening to '.$hostid{$clientip});
+              &status('Will listen to '.$hostid{$clientip});
 # ------------------------------------------------------------ Process requests
               while (my $userinput=<$client>) {
                 chomp($userinput);
                 &status('Processing '.$hostid{$clientip}.': '.$userinput);
+                &logthis('Processing '.$hostid{$clientip}.': '.$userinput);
                 my $wasenc=0;
+                alarm(120);
 # ------------------------------------------------------------ See if encrypted
 		if ($userinput =~ /^enc/) {
 		  if ($cipher) {
@@ -486,7 +551,9 @@ sub make_new_child {
 		    $userinput=substr($userinput,0,$cmdlength);
                     $wasenc=1;
 		  }
-		}
+		  &logthis('Decrypted '.$hostid{$clientip}.': '.$userinput);
+	      }
+
 # ------------------------------------------------------------- Normal commands
 # ------------------------------------------------------------------------ ping
 		   if ($userinput =~ /^ping/) {
@@ -650,7 +717,7 @@ sub make_new_child {
                                $fpnow.='/'.$fpparts[$i]; 
                                unless (-e $fpnow) {
 				   unless (mkdir($fpnow,0777)) {
-                                      $fperror="error:$!\n";
+                                      $fperror="error:$!";
                                    }
                                }
                            }
@@ -1063,15 +1130,22 @@ sub make_new_child {
                        }
 # ------------------------------------------------------------------------ dump
                    } elsif ($userinput =~ /^dump/) {
-                       my ($cmd,$udom,$uname,$namespace)
+                       my ($cmd,$udom,$uname,$namespace,$regexp)
                           =split(/:/,$userinput);
                        $namespace=~s/\//\_/g;
                        $namespace=~s/\W//g;
+                       if (defined($regexp)) {
+                          $regexp=&unescape($regexp);
+		       } else {
+                          $regexp='.';
+		       }
                        my $proname=propath($udom,$uname);
                        my $qresult='';
       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER,0640)) {
                            foreach $key (keys %hash) {
-                               $qresult.="$key=$hash{$key}&";
+                               if (eval('$key=~/$regexp/')) {
+                                  $qresult.="$key=$hash{$key}&";
+			       }
                            }
 			   if (untie(%hash)) {
 		              $qresult=~s/\&$//;
@@ -1293,16 +1367,22 @@ sub make_new_child {
                        &logthis(
       "Client $clientip ($hostid{$clientip}) hanging up: $userinput");
                        print $client "bye\n";
+                       $client->close();
 		       last;
 # ------------------------------------------------------------- unknown command
                    } else {
                        # unknown command
                        print $client "unknown_cmd\n";
                    }
-# ------------------------------------------------------ client unknown, refuse
+# -------------------------------------------------------------------- complete
+		   alarm(0);
+                   &status('Listening to '.$hostid{$clientip});
+                   &logthis('Completed '.$userinput.' Listening to '.$hostid{$clientip});
 	       }
+# --------------------------------------------- client unknown or fishy, refuse
             } else {
 	        print $client "refused\n";
+                $client->close();
                 &logthis("<font color=blue>WARNING: "
                 ."Rejected client $clientip, closing connection</font>");
             }              
@@ -1313,6 +1393,9 @@ sub make_new_child {
     
         # tidy up gracefully and finish
     
+        $client->close();
+        $server->close();
+
         # this exit is VERY important, otherwise the child will become
         # a producer of more and more children, forking yourself into
         # process death.
@@ -1320,6 +1403,48 @@ sub make_new_child {
     }
 }
 
+# ----------------------------------- POD (plain old documentation, CPAN style)
+
+=head1 NAME
+
+lond - "LON Daemon" Server (port "LOND" 5663)
+
+=head1 SYNOPSIS
+
+Should only be run as user=www.  Invoked by loncron.
+
+=head1 DESCRIPTION
+
+Preforker - server who forks first. Runs as a daemon. HUPs.
+Uses IDEA encryption
+
+=head1 README
+
+Not yet written.
+
+=head1 PREREQUISITES
+
+IO::Socket
+IO::File
+Apache::File
+Symbol
+POSIX
+Crypt::IDEA
+LWP::UserAgent()
+GDBM_File
+Authen::Krb4
+
+=head1 COREQUISITES
+
+=head1 OSNAMES
+
+linux
+
+=head1 SCRIPT CATEGORIES
+
+Server/Process
+
+=cut