Diff for /loncom/loncnew between versions 1.80 and 1.87

version 1.80, 2007/03/28 00:23:46 version 1.87, 2007/06/18 22:49:52
Line 60  use LONCAPA::Stack; Line 60  use LONCAPA::Stack;
 use LONCAPA::LondConnection;  use LONCAPA::LondConnection;
 use LONCAPA::LondTransaction;  use LONCAPA::LondTransaction;
 use LONCAPA::Configuration;  use LONCAPA::Configuration;
 use LONCAPA::HashIterator;  
 use Fcntl qw(:flock);  use Fcntl qw(:flock);
   
   
Line 73  my %perlvar    = %{$perlvarref}; Line 72  my %perlvar    = %{$perlvarref};
 #  #
 #  parent and shared variables.  #  parent and shared variables.
   
 my %ChildHash; # by pid -> host.  my %ChildPid; # by pid -> host.
   my %ChildHost; # by host.
 my %listening_to; # Socket->host table for who the parent  my %listening_to; # Socket->host table for who the parent
                                 # is listening to.                                  # is listening to.
 my %parent_dispatchers;         # host-> listener watcher events.   my %parent_dispatchers;         # host-> listener watcher events. 
Line 94  my $executable      = $0; # Get the full Line 94  my $executable      = $0; # Get the full
 #  The variables below are only used by the child processes.  #  The variables below are only used by the child processes.
 #  #
 my $RemoteHost; # Name of host child is talking to.  my $RemoteHost; # Name of host child is talking to.
   my $RemoteHostId; # default lonid of host child is talking to.
   my @all_host_ids;
 my $UnixSocketDir= $perlvar{'lonSockDir'};  my $UnixSocketDir= $perlvar{'lonSockDir'};
 my $IdleConnections = Stack->new(); # Set of idle connections  my $IdleConnections = Stack->new(); # Set of idle connections
 my %ActiveConnections; # Connections to the remote lond.  my %ActiveConnections; # Connections to the remote lond.
Line 112  my $LondConnecting  = 0;       # True wh Line 114  my $LondConnecting  = 0;       # True wh
   
   
   
 my $hosts_tab       = 0;        # True if we are using a static hosts.tab  
 my $I_am_child      = 0; # True if this is the child process.  my $I_am_child      = 0; # True if this is the child process.
   
 #  #
Line 157  sub LogPerm { Line 158  sub LogPerm {
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log");      my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log");
       chomp($message);
     print $fh "$now:$message:$local\n";      print $fh "$now:$message:$local\n";
 }  }
   
Line 333  sub child_exit { Line 335  sub child_exit {
     open(LOCK,">$lock_file");      open(LOCK,">$lock_file");
     print LOCK "Contents not important";      print LOCK "Contents not important";
     close(LOCK);      close(LOCK);
     if ($hosts_tab) {      unlink(&GetLoncSocketPath());
  unlink(&GetLoncSocketPath());  
     }  
   
     if ($message) {      if ($message) {
  die($message);   die($message);
Line 503  the data and Event->w->fd is the socket Line 503  the data and Event->w->fd is the socket
 sub ClientWritable {  sub ClientWritable {
     my $Event    = shift;      my $Event    = shift;
     my $Watcher  = $Event->w;      my $Watcher  = $Event->w;
       if (!defined($Watcher)) {
    &child_exit(-1,'No watcher for event in ClientWritable');
       }
     my $Data     = $Watcher->data;      my $Data     = $Watcher->data;
     my $Socket   = $Watcher->fd;      my $Socket   = $Watcher->fd;
   
Line 566  sub ClientWritable { Line 569  sub ClientWritable {
  }   }
     } else {      } else {
  $Watcher->cancel(); # A delayed request...just cancel.   $Watcher->cancel(); # A delayed request...just cancel.
    return;
     }      }
 }  }
   
Line 605  sub CompleteTransaction { Line 609  sub CompleteTransaction {
  StartClientReply($Transaction, $data);   StartClientReply($Transaction, $data);
     } else { # Delete deferred transaction file.      } else { # Delete deferred transaction file.
  Log("SUCCESS", "A delayed transaction was completed");   Log("SUCCESS", "A delayed transaction was completed");
  LogPerm("S:$Transaction->getClient() :".$Transaction->getRequest());   LogPerm("S:".$Transaction->getClient().":".$Transaction->getRequest());
  unlink $Transaction->getFile();   unlink($Transaction->getFile());
     }      }
 }  }
   
Line 1150  sub LondWritable { Line 1154  sub LondWritable {
     }      }
           
 }  }
   
 =pod  =pod
           
 =cut  =cut
   
   
 sub QueueDelayed {  sub QueueDelayed {
     Debug(3,"QueueDelayed called");      Debug(3,"QueueDelayed called");
   
Line 1162  sub QueueDelayed { Line 1168  sub QueueDelayed {
     Debug(4, "Delayed path: ".$path);      Debug(4, "Delayed path: ".$path);
     opendir(DIRHANDLE, $path);      opendir(DIRHANDLE, $path);
   
     my @all_host_ids;      my $host_id_re = '(?:'.join('|',map {quotemeta($_)} (@all_host_ids)).')';
     my $host_iterator =   &LondConnection::GetHostIterator();  
     while (!$host_iterator->end()) {  
  my ($host_id,$host_name) = @{$host_iterator->get()}[0,3];  
  if ($host_name eq $RemoteHost) {  
     push(@all_host_ids, $host_id);  
  }  
  $host_iterator->next();  
     }  
     my $host_id_re = '(?:'.join('|',@all_host_ids).')';  
     my @alldelayed = grep(/\.$host_id_re$/, readdir(DIRHANDLE));      my @alldelayed = grep(/\.$host_id_re$/, readdir(DIRHANDLE));
     closedir(DIRHANDLE);      closedir(DIRHANDLE);
     foreach my $dfname (sort(@alldelayed)) {      foreach my $dfname (sort(@alldelayed)) {
Line 1206  sub MakeLondConnection { Line 1203  sub MakeLondConnection {
   .GetServerPort());    .GetServerPort());
   
     my $Connection = LondConnection->new(&GetServerHost(),      my $Connection = LondConnection->new(&GetServerHost(),
  &GetServerPort());   &GetServerPort(),
    &GetHostId());
   
     if($Connection eq undef) { # Needs to be more robust later.      if($Connection eq undef) { # Needs to be more robust later.
  Log("CRITICAL","Failed to make a connection with lond.");   Log("CRITICAL","Failed to make a connection with lond.");
Line 1214  sub MakeLondConnection { Line 1212  sub MakeLondConnection {
  return 0; # Failure.   return 0; # Failure.
     }  else {      }  else {
   
    $LondConnecting = 1; # Connection in progress.
  # The connection needs to have writability    # The connection needs to have writability 
  # monitored in order to send the init sequence   # monitored in order to send the init sequence
  # that starts the whole authentication/key   # that starts the whole authentication/key
Line 1244  sub MakeLondConnection { Line 1243  sub MakeLondConnection {
  }   }
  Log("SUCESS", "Created connection ".$ConnectionCount   Log("SUCESS", "Created connection ".$ConnectionCount
     ." to host ".GetServerHost());      ." to host ".GetServerHost());
  $LondConnecting = 1; # Connection in progress.  
  return 1; # Return success.   return 1; # Return success.
     }      }
           
Line 1385  sub ClientRequest { Line 1383  sub ClientRequest {
     $data = $data.$thisread; # Append new data.      $data = $data.$thisread; # Append new data.
     $watcher->data($data);      $watcher->data($data);
     if($data =~ /\n$/) { # Request entirely read.      if($data =~ /\n$/) { # Request entirely read.
  if($data eq "close_connection_exit\n") {   if ($data eq "close_connection_exit\n") {
     Log("CRITICAL",      Log("CRITICAL",
  "Request Close Connection ... exiting");   "Request Close Connection ... exiting");
     CloseAllLondConnections();      CloseAllLondConnections();
     exit;      exit;
    } elsif ($data eq "reset_retries\n") {
       Log("INFO", "Resetting Connection Retries.");
       $ConnectionRetriesLeft = $ConnectionRetries;
       &UpdateStatus();
       my $Transaction = LondTransaction->new($data);
       $Transaction->SetClient($socket);
       StartClientReply($Transaction, "ok\n");
       $watcher->cancel();
       return;
  }   }
  Debug(8, "Complete transaction received: ".$data);   Debug(8, "Complete transaction received: ".$data);
  if($LogTransactions) {   if ($LogTransactions) {
     Log("SUCCESS", "Transaction: '$data'"); # Transaction has \n.      Log("SUCCESS", "Transaction: '$data'"); # Transaction has \n.
  }   }
  my $Transaction = LondTransaction->new($data);   my $Transaction = LondTransaction->new($data);
Line 1496  sub GetServerHost { Line 1503  sub GetServerHost {
   
 =pod  =pod
   
   =head2 GetServerId
   
   Returns the hostid whose lond we talk with.
   
   =cut
   
   sub GetHostId {
       return $RemoteHostId; # Setup by the fork.
   }
   
   =pod
   
 =head2 GetServerPort  =head2 GetServerPort
   
 Returns the lond port number.  Returns the lond port number.
Line 1749  sub ChildProcess { Line 1768  sub ChildProcess {
 #  Create a new child for host passed in:  #  Create a new child for host passed in:
   
 sub CreateChild {  sub CreateChild {
     my ($host, $socket) = @_;      my ($host, $hostid) = @_;
   
     my $sigset = POSIX::SigSet->new(SIGINT);      my $sigset = POSIX::SigSet->new(SIGINT);
     sigprocmask(SIG_BLOCK, $sigset);      sigprocmask(SIG_BLOCK, $sigset);
Line 1758  sub CreateChild { Line 1777  sub CreateChild {
     my $pid          = fork;      my $pid          = fork;
     if($pid) { # Parent      if($pid) { # Parent
  $RemoteHost = "Parent";   $RemoteHost = "Parent";
  $ChildHash{$pid} = $host;   $ChildPid{$pid} = $host;
  sigprocmask(SIG_UNBLOCK, $sigset);   sigprocmask(SIG_UNBLOCK, $sigset);
    undef(@all_host_ids);
     } else { # child.      } else { # child.
    $RemoteHostId = $hostid;
  ShowStatus("Connected to ".$RemoteHost);   ShowStatus("Connected to ".$RemoteHost);
  $SIG{INT} = 'DEFAULT';   $SIG{INT} = 'DEFAULT';
  sigprocmask(SIG_UNBLOCK, $sigset);   sigprocmask(SIG_UNBLOCK, $sigset);
  if(defined $socket) {   &ChildProcess(); # Does not return.
     &ChildProcess($socket);  
  } else {  
     ChildProcess; # Does not return.  
  }  
     }      }
 }  }
   
Line 1797  sub parent_client_connection { Line 1813  sub parent_client_connection {
  my ($event)   = @_;   my ($event)   = @_;
  my $watcher   = $event->w;   my $watcher   = $event->w;
  my $socket    = $watcher->fd;   my $socket    = $watcher->fd;
  if ($hosts_tab) {   my $connection = $socket->accept(); # Accept the client connection.
    Event->io(cb      => \&get_remote_hostname,
     # Lookup the host associated with this socket:    poll    => 'r',
     data    => "",
     my $host = $listening_to{$socket};    fd      => $connection);
   
     # Start the child:  
   
   
   
     &Debug(9,"Creating child for $host (parent_client_connection)");  
     &CreateChild($host, $socket);  
       
     # Clean up the listen since now the child takes over until it exits.  
   
     $watcher->cancel(); # Nolonger listening to this event  
     delete($listening_to{$socket});  
     delete($parent_dispatchers{$host});  
     $socket->close();  
   
  } else {  
     my $connection = $socket->accept(); # Accept the client connection.  
     Event->io(cb      => \&get_remote_hostname,  
       poll    => 'r',  
       data    => "",  
       fd      => $connection);  
  }  
     }      }
 }  }
   
 sub get_remote_hostname {  sub get_remote_hostname {
  my ($event)   = @_;      my ($event)   = @_;
  my $watcher   = $event->w;      my $watcher   = $event->w;
  my $socket    = $watcher->fd;      my $socket    = $watcher->fd;
   
  my $thisread;  
  my $rv = $socket->recv($thisread, POSIX::BUFSIZ, 0);  
  Debug(8, "rcv:  data length = ".length($thisread)." read =".$thisread);  
  if (!defined($rv) || length($thisread) == 0) {  
     # Likely eof on socket.  
     Debug(5,"Client Socket closed on lonc for p_c_c");  
     close($socket);  
     $watcher->cancel();  
     return;  
  }  
   
  my $data    = $watcher->data().$thisread;      my $thisread;
  $watcher->data($data);      my $rv = $socket->recv($thisread, POSIX::BUFSIZ, 0);
  if($data =~ /\n$/) { # Request entirely read.      Debug(8, "rcv:  data length = ".length($thisread)." read =".$thisread);
     chomp($data);      if (!defined($rv) || length($thisread) == 0) {
  } else {   # Likely eof on socket.
     return;   Debug(5,"Client Socket closed on lonc for p_c_c");
  }   close($socket);
    $watcher->cancel();
  &Debug(5,"Creating child for $data (parent_client_connection)");   return;
  &CreateChild($data);      }
   
  # Clean up the listen since now the child takes over until it exits.      my $data    = $watcher->data().$thisread;
  $watcher->cancel(); # Nolonger listening to this event      $watcher->data($data);
  $socket->send("done\n");      if($data =~ /\n$/) { # Request entirely read.
  $socket->close();   chomp($data);
       } else {
    return;
       }
   
       &Debug(5,"Creating child for $data (parent_client_connection)");
       (my $hostname,my $lonid,@all_host_ids) = split(':',$data);
       $ChildHost{$hostname}++;
       if ($ChildHost{$hostname} == 1) {
    &CreateChild($hostname,$lonid);
       } else {
    &Log('WARNING',"Request for a second child on $hostname");
       }
       # Clean up the listen since now the child takes over until it exits.
       $watcher->cancel(); # Nolonger listening to this event
       $socket->send("done\n");
       $socket->close();
 }  }
   
 # parent_listen:  # parent_listen:
Line 1908  sub parent_listen { Line 1907  sub parent_listen {
   
 sub parent_clean_up {  sub parent_clean_up {
     my ($loncapa_host) = @_;      my ($loncapa_host) = @_;
     Debug(5, "parent_clean_up: $loncapa_host");      Debug(1, "parent_clean_up: $loncapa_host");
   
     my $socket_file = &GetLoncSocketPath($loncapa_host);      my $socket_file = &GetLoncSocketPath($loncapa_host);
     unlink($socket_file); # No problem if it doesn't exist yet [startup e.g.]      unlink($socket_file); # No problem if it doesn't exist yet [startup e.g.]
Line 1917  sub parent_clean_up { Line 1916  sub parent_clean_up {
 }  }
   
   
 # listen_on_all_unix_sockets:  
 #    This sub initiates a listen on all unix domain lonc client sockets.  #    This sub initiates a listen on the common unix domain lonc client socket.
 #    This will be called in the case where we are trimming idle processes.  #    loncnew starts up with no children, and only spawns off children when a
 #    When idle processes are trimmed, loncnew starts up with no children,  #    connection request occurs on the common client unix socket.  The spawned
 #    and only spawns off children when a connection request occurs on the  #    child continues to run until it has been idle a while at which point it
 #    client unix socket.  The spawned child continues to run until it has  #    eventually exits and once more the parent picks up the listen.
 #    been idle a while at which point it eventually exits and once more  
 #    the parent picks up the listen.  
 #  #
 #  Parameters:  #  Parameters:
 #      NONE  #      NONE
Line 1933  sub parent_clean_up { Line 1930  sub parent_clean_up {
 #  Returns:  #  Returns:
 #     NONE  #     NONE
 #  #
 sub listen_on_all_unix_sockets {  
     Debug(5, "listen_on_all_unix_sockets");  
     my $host_iterator      =   &LondConnection::GetHostIterator();  
     while (!$host_iterator->end()) {  
  my $host_entry_ref =   $host_iterator->get();  
  my $host_name      = $host_entry_ref->[3];  
  Debug(9, "Listen for $host_name");  
  &parent_listen($host_name);  
  $host_iterator->next();  
     }  
 }  
   
 sub listen_on_common_socket {  sub listen_on_common_socket {
     Debug(5, "listen_on_common_socket");      Debug(5, "listen_on_common_socket");
     &parent_listen();      &parent_listen();
Line 1969  sub server_died { Line 1954  sub server_died {
  }   }
  # need the host to restart:   # need the host to restart:
   
  my $host = $ChildHash{$pid};   my $host = $ChildPid{$pid};
  if($host) { # It's for real...   if($host) { # It's for real...
     &Debug(9, "Caught sigchild for $host");      &Debug(9, "Caught sigchild for $host");
     delete($ChildHash{$pid});      delete($ChildPid{$pid});
     if ($hosts_tab) {      delete($ChildHost{$host});
  &parent_listen($host);      &parent_clean_up($host);
     } else {  
  &parent_clean_up($host);  
     }  
       
  } else {   } else {
     &Debug(5, "Caught sigchild for pid not in hosts hash: $pid");      &Debug(5, "Caught sigchild for pid not in hosts hash: $pid");
  }   }
Line 2036  Log("CRITICAL", "--------------- Startin Line 2018  Log("CRITICAL", "--------------- Startin
 LondConnection::ReadConfig;               # Read standard config files.  LondConnection::ReadConfig;               # Read standard config files.
   
 $RemoteHost = "[parent]";  $RemoteHost = "[parent]";
 if ($hosts_tab) {  &listen_on_common_socket();
     &listen_on_all_unix_sockets();  
 } else {  
     &listen_on_common_socket();  
 }  
   
 $RemoteHost = "Parent Server";  $RemoteHost = "Parent Server";
   
Line 2065  $parent_handlers{INT} = Event->signal(cb Line 2043  $parent_handlers{INT} = Event->signal(cb
 $parent_handlers{TERM} = Event->signal(cb       => \&Terminate,  $parent_handlers{TERM} = Event->signal(cb       => \&Terminate,
        desc     => "Parent TERM handler",         desc     => "Parent TERM handler",
        signal   => "TERM");         signal   => "TERM");
 if ($hosts_tab) {  $parent_handlers{HUP}  = Event->signal(cb       => \&KillThemAll,
     $parent_handlers{HUP}  = Event->signal(cb       => \&Restart,         desc     => "Parent HUP handler.",
    desc     => "Parent HUP handler.",         signal   => "HUP");
    signal   => "HUP");  
 } else {  
     $parent_handlers{HUP}  = Event->signal(cb       => \&KillThemAll,  
    desc     => "Parent HUP handler.",  
    signal   => "HUP");  
 }  
 $parent_handlers{USR1} = Event->signal(cb       => \&CheckKids,  $parent_handlers{USR1} = Event->signal(cb       => \&CheckKids,
        desc     => "Parent USR1 handler",         desc     => "Parent USR1 handler",
        signal   => "USR1");         signal   => "USR1");
Line 2110  sub CheckKids { Line 2082  sub CheckKids {
     foreach my $host (keys %parent_dispatchers) {      foreach my $host (keys %parent_dispatchers) {
  print $fh "LONC Parent process listening for $host\n";   print $fh "LONC Parent process listening for $host\n";
     }      }
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildPid) {
  Debug(2, "Sending USR1 -> $pid");   Debug(2, "Sending USR1 -> $pid");
  kill 'USR1' => $pid; # Tell Child to report status.   kill 'USR1' => $pid; # Tell Child to report status.
     }      }
Line 2154  sub UpdateKids { Line 2126  sub UpdateKids {
     # The down side is transactions that are in flight will get timed out      # The down side is transactions that are in flight will get timed out
     # (lost unless they are critical).      # (lost unless they are critical).
   
     if ($hosts_tab) {      &KillThemAll();
  &Restart();  
     } else {  
  &KillThemAll();  
     }  
 }  }
   
   
Line 2191  SIGHUP.  Responds to sigint and sigterm. Line 2159  SIGHUP.  Responds to sigint and sigterm.
   
 sub KillThemAll {  sub KillThemAll {
     Debug(2, "Kill them all!!");      Debug(2, "Kill them all!!");
     local($SIG{CHLD}) = 'IGNORE';      # Our children >will< die.      
     foreach my $pid (keys %ChildHash) {      #local($SIG{CHLD}) = 'IGNORE';
  my $serving = $ChildHash{$pid};      # Our children >will< die.
       # but we need to catch their death and cleanup after them in case this is 
       # a restart set of kills
       my @allpids = keys(%ChildPid);
       foreach my $pid (@allpids) {
    my $serving = $ChildPid{$pid};
  ShowStatus("Nicely Killing lonc for $serving pid = $pid");   ShowStatus("Nicely Killing lonc for $serving pid = $pid");
  Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid");   Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid");
  kill 'QUIT' => $pid;   kill 'QUIT' => $pid;
     }      }
       ShowStatus("Finished killing child processes off.");
 }  }
   
   
Line 2209  sub really_kill_them_all_dammit Line 2183  sub really_kill_them_all_dammit
 {  {
     Debug(2, "Kill them all Dammit");      Debug(2, "Kill them all Dammit");
     local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them.      local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them.
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildPid) {
  my $serving = $ChildHash{$pid};   my $serving = $ChildPid{$pid};
  &ShowStatus("Nastily killing lonc for $serving pid = $pid");   &ShowStatus("Nastily killing lonc for $serving pid = $pid");
  Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid");   Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid");
  kill 'KILL' => $pid;   kill 'KILL' => $pid;
  delete($ChildHash{$pid});   delete($ChildPid{$pid});
  my $execdir = $perlvar{'lonDaemons'};   my $execdir = $perlvar{'lonDaemons'};
  unlink("$execdir/logs/lonc.pid");   unlink("$execdir/logs/lonc.pid");
     }      }
Line 2242  sub Terminate { Line 2216  sub Terminate {
     exit 0;      exit 0;
   
 }  }
   
   sub my_hostname {
       use Sys::Hostname;
       my $name = &hostname();
       &Debug(9,"Name is $name");
       return $name;
   }
   
 =pod  =pod
   
 =head1 Theory  =head1 Theory

Removed from v.1.80  
changed lines
  Added in v.1.87


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>