Diff for /loncom/loncnew between versions 1.41 and 1.60

version 1.41, 2004/02/09 13:39:28 version 1.60, 2004/09/22 11:11:54
Line 82  my $ClientConnection = 0; # Uniquifier f Line 82  my $ClientConnection = 0; # Uniquifier f
   
 my $DebugLevel = 0;  my $DebugLevel = 0;
 my $NextDebugLevel= 2; # So Sigint can toggle this.  my $NextDebugLevel= 2; # So Sigint can toggle this.
 my $IdleTimeout= 3600; # Wait an hour before pruning connections.  my $IdleTimeout= 600; # Wait 10 minutes before pruning connections.
   
 my $LogTransactions = 0; # When True, all transactions/replies get logged.  my $LogTransactions = 0; # When True, all transactions/replies get logged.
   
Line 103  my $RecentLogEntry  = ""; Line 103  my $RecentLogEntry  = "";
 my $ConnectionRetries=2; # Number of connection retries allowed.  my $ConnectionRetries=2; # Number of connection retries allowed.
 my $ConnectionRetriesLeft=2; # Number of connection retries remaining.  my $ConnectionRetriesLeft=2; # Number of connection retries remaining.
 my $LondVersion     = "unknown"; # Version of lond we talk with.  my $LondVersion     = "unknown"; # Version of lond we talk with.
   my $KeyMode         = "";       # e.g. ssl, local, insecure from last connect.
   my $LondConnecting  = 0;       # True when a connection is being built.
   
   
   # DO NOT SET THE NEXT VARIABLE TO NON ZERO!!!!!!!!!!!!!!!
   
   my $DieWhenIdle     = 0; # When true children die when trimmed -> 0.
   
 #  #
 #   The hash below gives the HTML format for log messages  #   The hash below gives the HTML format for log messages
Line 110  my $LondVersion     = "unknown"; # Versi Line 117  my $LondVersion     = "unknown"; # Versi
 #      #    
 my %LogFormats;  my %LogFormats;
   
 $LogFormats{"CRITICAL"} = "<font color=red>CRITICAL: %s</font>";  $LogFormats{"CRITICAL"} = "<font color='red'>CRITICAL: %s</font>";
 $LogFormats{"SUCCESS"}  = "<font color=green>SUCCESS: %s</font>";  $LogFormats{"SUCCESS"}  = "<font color='green'>SUCCESS: %s</font>";
 $LogFormats{"INFO"}     = "<font color=yellow>INFO: %s</font>";  $LogFormats{"INFO"}     = "<font color='yellow'>INFO: %s</font>";
 $LogFormats{"WARNING"}  = "<font color=blue>WARNING: %s</font>";  $LogFormats{"WARNING"}  = "<font color='blue'>WARNING: %s</font>";
 $LogFormats{"DEFAULT"}  = " %s ";  $LogFormats{"DEFAULT"}  = " %s ";
   
   
   #  UpdateStatus;
   #    Update the idle status display to show how many connections
   #    are left, retries and other stuff.
   #
   sub UpdateStatus {
       if ($ConnectionRetriesLeft > 0) {
    ShowStatus(GetServerHost()." Connection count: ".$ConnectionCount
      ." Retries remaining: ".$ConnectionRetriesLeft
      ." ($KeyMode)");
       } else {
    ShowStatus(GetServerHost()." >> DEAD <<");
       }
   }
   
   
 =pod  =pod
   
Line 156  host and the time will be formatted into Line 177  host and the time will be formatted into
 =cut  =cut
   
 sub Log {  sub Log {
     my $severity = shift;  
     my $message  = shift;      my ($severity, $message) = @_;
      
     if(!$LogFormats{$severity}) {      if(!$LogFormats{$severity}) {
  $severity = "DEFAULT";   $severity = "DEFAULT";
     }      }
Line 193  Returns the name of the host that a sock Line 214  Returns the name of the host that a sock
 =cut  =cut
   
 sub GetPeername {  sub GetPeername {
     my $connection = shift;  
     my $AdrFamily  = shift;  
       my ($connection, $AdrFamily) = @_;
   
     my $peer       = $connection->peername();      my $peer       = $connection->peername();
     my $peerport;      my $peerport;
     my $peerip;      my $peerip;
Line 217  Invoked to issue a debug message. Line 240  Invoked to issue a debug message.
 =cut  =cut
   
 sub Debug {  sub Debug {
     my $level   = shift;  
     my $message = shift;      my ($level, $message) = @_;
   
     if ($level <= $DebugLevel) {      if ($level <= $DebugLevel) {
  Log("INFO", "-Debug- $message host = $RemoteHost");   Log("INFO", "-Debug- $message host = $RemoteHost");
     }      }
 }  }
   
 sub SocketDump {  sub SocketDump {
     my $level = shift;  
     my $socket= shift;      my ($level, $socket) = @_;
   
     if($level <= $DebugLevel) {      if($level <= $DebugLevel) {
  $socket->Dump();   $socket->Dump(-1); # Ensure it will get dumped.
     }      }
 }  }
   
Line 260  sub ShowStatus { Line 285  sub ShowStatus {
 sub SocketTimeout {  sub SocketTimeout {
     my $Socket = shift;      my $Socket = shift;
     Log("WARNING", "A socket timeout was detected");      Log("WARNING", "A socket timeout was detected");
     Debug(0, " SocketTimeout called: ");      Debug(5, " SocketTimeout called: ");
     $Socket->Dump();      $Socket->Dump(0);
       if(exists($ActiveTransactions{$Socket})) {
    FailTransaction($ActiveTransactions{$Socket});
       }
     KillSocket($Socket); # A transaction timeout also counts as      KillSocket($Socket); # A transaction timeout also counts as
                                 # a connection failure:                                  # a connection failure:
     $ConnectionRetriesLeft--;      $ConnectionRetriesLeft--;
       if($ConnectionRetriesLeft <= 0) {
    Log("CRITICAL", "Host marked DEAD: ".GetServerHost());
    $LondConnecting = 0;
       }
   
 }  }
 #----------------------------- Timer management ------------------------  #----------------------------- Timer management ------------------------
   
Line 278  Invoked  each timer tick. Line 311  Invoked  each timer tick.
   
   
 sub Tick {  sub Tick {
       my ($Event)       = @_;
       my $clock_watcher = $Event->w;
   
     my $client;      my $client;
     if($ConnectionRetriesLeft > 0) {      UpdateStatus();
  ShowStatus(GetServerHost()." Connection count: ".$ConnectionCount  
    ." Retries remaining: ".$ConnectionRetriesLeft);  
     } else {  
  ShowStatus(GetServerHost()." >> DEAD <<");  
     }  
     # Is it time to prune connection count:      # Is it time to prune connection count:
   
   
Line 294  sub Tick { Line 326  sub Tick {
  if($IdleSeconds > $IdleTimeout) { # Prune a connection...   if($IdleSeconds > $IdleTimeout) { # Prune a connection...
     my $Socket = $IdleConnections->pop();      my $Socket = $IdleConnections->pop();
     KillSocket($Socket);      KillSocket($Socket);
       $IdleSeconds = 0; # Otherwise all connections get trimmed to fast.
       UpdateStatus();
       if(($ConnectionCount == 0) && $DieWhenIdle) {
    #
    #  Create a lock file since there will be a time window
    #  between our exit and the parent's picking up the listen
    #  during which no listens will be done on the
    #  lonnet client socket.
    #
    my $lock_file = GetLoncSocketPath().".lock";
    open(LOCK,">$lock_file");
    print LOCK "Contents not important";
    close(LOCK);
   
    exit(0);
       }
  }   }
     } else {      } else {
  $IdleSeconds = 0; # Reset idle count if not idle.   $IdleSeconds = 0; # Reset idle count if not idle.
Line 312  sub Tick { Line 360  sub Tick {
     # Do we have work in the queue, but no connections to service them?      # Do we have work in the queue, but no connections to service them?
     # If so, try to make some new connections to get things going again.      # If so, try to make some new connections to get things going again.
     #      #
           #   Note this code is dead now...
       #
     my $Requests = $WorkQueue->Count();      my $Requests = $WorkQueue->Count();
     if (($ConnectionCount == 0)  && ($Requests > 0)) {       if (($ConnectionCount == 0)  && ($Requests > 0) && (!$LondConnecting)) { 
  if ($ConnectionRetriesLeft > 0) {   if ($ConnectionRetriesLeft > 0) {
     my $Connections = ($Requests <= $MaxConnectionCount) ?      Debug(5,"Work but no connections, Make a new one");
  $Requests : $MaxConnectionCount;      my $success;
     Debug(5,"Work but no connections, start ".$Connections." of them");      $success    = &MakeLondConnection;
     my $successCount = 0;      if($success == 0) { # All connections failed:
     for (my $i =0; $i < $Connections; $i++) {  
  $successCount += MakeLondConnection();  
     }  
     if($successCount == 0) { # All connections failed:  
  Debug(5,"Work in queue failed to make any connectiouns\n");   Debug(5,"Work in queue failed to make any connectiouns\n");
  EmptyQueue(); # Fail pending transactions with con_lost.   EmptyQueue(); # Fail pending transactions with con_lost.
    CloseAllLondConnections(); # Should all be closed but....
     }      }
  } else {   } else {
       $LondConnecting = 0;
     ShowStatus(GetServerHost()." >>> DEAD!!! <<<");      ShowStatus(GetServerHost()." >>> DEAD!!! <<<");
     Debug(5,"Work in queue, but gave up on connections..flushing\n");      Debug(5,"Work in queue, but gave up on connections..flushing\n");
     EmptyQueue(); # Connections can't be established.      EmptyQueue(); # Connections can't be established.
       CloseAllLondConnections(); # Should all already be closed but...
  }   }
                 
     }      }
       if ($ConnectionCount == 0) {
    $KeyMode = ""; 
    $clock_watcher->cancel();
       }
 }  }
   
 =pod  =pod
Line 374  long enough, it will be shut down and re Line 426  long enough, it will be shut down and re
   
 sub ServerToIdle {  sub ServerToIdle {
     my $Socket   = shift; # Get the socket.      my $Socket   = shift; # Get the socket.
       $KeyMode = $Socket->{AuthenticationMode};
     delete($ActiveTransactions{$Socket}); # Server has no transaction      delete($ActiveTransactions{$Socket}); # Server has no transaction
   
     &Debug(5, "Server to idle");      &Debug(5, "Server to idle");
Line 453  sub ClientWritable { Line 506  sub ClientWritable {
     } else { # Partial string sent.      } else { # Partial string sent.
  $Watcher->data(substr($Data, $result));   $Watcher->data(substr($Data, $result));
  if($result == 0) {    # client hung up on us!!   if($result == 0) {    # client hung up on us!!
     Log("INFO", "lonc pipe client hung up on us!");      # Log("INFO", "lonc pipe client hung up on us!");
     $Watcher->cancel;      $Watcher->cancel;
     $Socket->shutdown(2);      $Socket->shutdown(2);
     $Socket->close();      $Socket->close();
Line 506  The transaction that is being completed. Line 559  The transaction that is being completed.
   
 sub CompleteTransaction {  sub CompleteTransaction {
     &Debug(5,"Complete transaction");      &Debug(5,"Complete transaction");
     my $Socket = shift;  
     my $Transaction = shift;      my ($Socket, $Transaction) = @_;
   
     if (!$Transaction->isDeferred()) { # Normal transaction      if (!$Transaction->isDeferred()) { # Normal transaction
  my $data   = $Socket->GetReply(); # Data to send.   my $data   = $Socket->GetReply(); # Data to send.
Line 521  sub CompleteTransaction { Line 574  sub CompleteTransaction {
  unlink $Transaction->getFile();   unlink $Transaction->getFile();
     }      }
 }  }
   
 =pod  =pod
   
 =head1 StartClientReply  =head1 StartClientReply
   
    Initiates a reply to a client where the reply data is a parameter.     Initiates a reply to a client where the reply data is a parameter.
Line 537  sub CompleteTransaction { Line 592  sub CompleteTransaction {
     The data to send to apached client.      The data to send to apached client.
   
 =cut  =cut
   
 sub StartClientReply {  sub StartClientReply {
     my $Transaction   = shift;  
     my $data     = shift;  
   
       my ($Transaction, $data) = @_;
   
     my $Client   = $Transaction->getClient();      my $Client   = $Transaction->getClient();
   
Line 554  sub StartClientReply { Line 609  sub StartClientReply {
       cb       => \&ClientWritable,        cb       => \&ClientWritable,
       data     => $data);        data     => $data);
 }  }
   
 =pod  =pod
   
 =head2 FailTransaction  =head2 FailTransaction
   
   Finishes a transaction with failure because the associated lond socket    Finishes a transaction with failure because the associated lond socket
Line 564  sub StartClientReply { Line 621  sub StartClientReply {
   - The transaction is 'live' in which case we initiate the sending    - The transaction is 'live' in which case we initiate the sending
     of "con_lost" to the client.      of "con_lost" to the client.
   
 Deleting the transaction means killing it from the   Deleting the transaction means killing it from the %ActiveTransactions hash.
 %ActiveTransactions hash.  
   
 Parameters:  Parameters:
   
Line 573  Parameters: Line 629  Parameters:
     
    The LondTransaction we are failing.     The LondTransaction we are failing.
     
   
 =cut  =cut
   
 sub FailTransaction {  sub FailTransaction {
     my $transaction = shift;      my $transaction = shift;
     Log("WARNING", "Failing transaction ".$transaction->getRequest());      
       #  If the socket is dead, that's already logged.
   
       if ($ConnectionRetriesLeft > 0) {
    Log("WARNING", "Failing transaction "
       .$transaction->getRequest());
       }
     Debug(1, "Failing transaction: ".$transaction->getRequest());      Debug(1, "Failing transaction: ".$transaction->getRequest());
     if (!$transaction->isDeferred()) { # If the transaction is deferred we'll get to it.      if (!$transaction->isDeferred()) { # If the transaction is deferred we'll get to it.
  my $client  = $transaction->getClient();   my $client  = $transaction->getClient();
  Debug(1," Replying con_lost to ".$transaction->getRequest());   Debug(1," Replying con_lost to ".$transaction->getRequest());
  StartClientReply($transaction, "con_lost\n");   StartClientReply($transaction, "con_lost\n");
     }      }
     if($ConnectionRetriesLeft <= 0) {  
  Log("CRITICAL", "Host marked dead: ".GetServerHost());  
     }  
   
 }  }
   
Line 614  Close all connections open on lond prior Line 674  Close all connections open on lond prior
 =cut  =cut
 sub CloseAllLondConnections {  sub CloseAllLondConnections {
     foreach my $Socket (keys %ActiveConnections) {      foreach my $Socket (keys %ActiveConnections) {
  KillSocket($Socket);        if(exists($ActiveTransactions{$Socket})) {
    FailTransaction($ActiveTransactions{$Socket});
         }
         KillSocket($Socket);
     }      }
 }  }
 =cut  =cut
Line 666  sub KillSocket { Line 729  sub KillSocket {
     #      #
     if($ConnectionCount == 0) {      if($ConnectionCount == 0) {
  EmptyQueue();   EmptyQueue();
    CloseAllLondConnections; # Should all already be closed but...
     }      }
 }  }
   
Line 763  sub LondReadable { Line 827  sub LondReadable {
     "Lond connection lost.");      "Lond connection lost.");
  if(exists($ActiveTransactions{$Socket})) {   if(exists($ActiveTransactions{$Socket})) {
     FailTransaction($ActiveTransactions{$Socket});      FailTransaction($ActiveTransactions{$Socket});
    } else {
       #  Socket is connecting and failed... need to mark
       #  no longer connecting.
      
       $LondConnecting = 0;
  }   }
  $Watcher->cancel();   $Watcher->cancel();
  KillSocket($Socket);   KillSocket($Socket);
Line 837  sub LondReadable { Line 906  sub LondReadable {
  .$RemoteHost." now ready for action");   .$RemoteHost." now ready for action");
  }   }
  ServerToIdle($Socket); # Next work unit or idle.   ServerToIdle($Socket); # Next work unit or idle.
   
    #
    $LondConnecting = 0; # Best spot I can think of for this.
    # 
   
     } elsif ($State eq "SendingRequest") {      } elsif ($State eq "SendingRequest") {
  #  We need to be writable for this and probably don't belong   #  We need to be writable for this and probably don't belong
Line 932  sub LondWritable { Line 1005  sub LondWritable {
   
     SocketDump(6,$Socket);      SocketDump(6,$Socket);
   
     if      ($State eq "Connected")         {      #  If the socket is writable, we must always write.
       # Only by writing will we undergo state transitions.
  if ($Socket->Writable() != 0) {      # Old logic wrote in state specific code below, however
     #  The write resulted in an error.      # That forces us at least through another invocation of
     # We'll treat this as if the socket got disconnected:      # this function after writability is possible again.
     Log("WARNING", "Connection to ".$RemoteHost.      # This logic also factors out common code for handling
  " has been disconnected");      # write failures... in all cases, write failures 
       # Kill the socket.
       #  This logic makes the branches of the >big< if below
       # so that the writing states are actually NO-OPs.
   
       if ($Socket->Writable() != 0) {
    #  The write resulted in an error.
    # We'll treat this as if the socket got disconnected:
    Log("WARNING", "Connection to ".$RemoteHost.
       " has been disconnected");
    if(exists($ActiveTransactions{$Socket})) {
     FailTransaction($ActiveTransactions{$Socket});      FailTransaction($ActiveTransactions{$Socket});
     $Watcher->cancel();   } else {
     KillSocket($Socket);      #  In the process of conneting, so need to turn that off.
     return;      
       $LondConnecting = 0;
  }   }
          $Watcher->cancel();
    KillSocket($Socket);
    return;
       }
   
   
   
       if      ($State eq "Connected")         {
   
  #  "init" is being sent...   #  "init" is being sent...
       
     } elsif ($State eq "Initialized")       {      } elsif ($State eq "Initialized")       {
   
  # Now that init was sent, we switch    # Now that init was sent, we switch 
Line 960  sub LondWritable { Line 1052  sub LondWritable {
  # are echoing it back. This is a no-op,   # are echoing it back. This is a no-op,
  # we're waiting for the state to change   # we're waiting for the state to change
   
  if($Socket->Writable() != 0) {  
   
     $Watcher->cancel();  
     KillSocket($Socket);  
     return;  
  }  
   
     } elsif ($State eq "ChallengeReplied")  {      } elsif ($State eq "ChallengeReplied")  {
  # The echo was sent back, so we switch   # The echo was sent back, so we switch
  # to watching readability.   # to watching readability.
Line 975  sub LondWritable { Line 1060  sub LondWritable {
  $Watcher->poll("r");   $Watcher->poll("r");
     } elsif ($State eq "RequestingVersion") {      } elsif ($State eq "RequestingVersion") {
  # Sending the peer a version request...   # Sending the peer a version request...
         
  if($Socket->Writable() != 0) {  
     $Watcher->cancel();  
     KillSocket($Socket);  
     return;  
  }  
     } elsif ($State eq "ReadingVersionString") {      } elsif ($State eq "ReadingVersionString") {
  # Transition to read since we have sent the   # Transition to read since we have sent the
  # version command and now just need to read the   # version command and now just need to read the
Line 991  sub LondWritable { Line 1071  sub LondWritable {
               
     } elsif ($State eq "SetHost") {      } elsif ($State eq "SetHost") {
  #  Setting the remote domain...   #  Setting the remote domain...
         
  if($Socket->Writable() != 0) {  
     $Watcher->cancel();  
     KillSocket($Socket);  
     return;  
  }  
     } elsif ($State eq "HostSet") {      } elsif ($State eq "HostSet") {
  # Back to readable to get the ok.   # Back to readable to get the ok.
               
Line 1007  sub LondWritable { Line 1082  sub LondWritable {
     } elsif ($State eq "RequestingKey")     {      } elsif ($State eq "RequestingKey")     {
  # At this time we're requesting the key.   # At this time we're requesting the key.
  # again, this is essentially a no-op.   # again, this is essentially a no-op.
  # we'll write the next chunk until the  
  # state changes.  
   
  if($Socket->Writable() != 0) {  
     # Write resulted in an error.  
   
     $Watcher->cancel();  
     KillSocket($Socket);  
     return;  
   
  }  
     } elsif ($State eq "ReceivingKey")      {      } elsif ($State eq "ReceivingKey")      {
  # Now we need to wait for the key   # Now we need to wait for the key
  # to come back from the peer:   # to come back from the peer:
Line 1030  sub LondWritable { Line 1095  sub LondWritable {
  # At this time we are sending a request to the   # At this time we are sending a request to the
  # peer... write the next chunk:   # peer... write the next chunk:
   
  if($Socket->Writable() != 0) {  
   
     if(exists($ActiveTransactions{$Socket})) {  
  Debug(3, "Lond connection lost, failing transactions");  
  FailTransaction($ActiveTransactions{$Socket});  
     }  
     $Watcher->cancel();  
     KillSocket($Socket);  
     return;  
       
  }  
   
     } elsif ($State eq "ReceivingReply")    {      } elsif ($State eq "ReceivingReply")    {
  # The send has completed.  Wait for the   # The send has completed.  Wait for the
Line 1133  sub MakeLondConnection { Line 1187  sub MakeLondConnection {
    data     => $Connection,     data     => $Connection,
    desc => 'Connection to lond server');     desc => 'Connection to lond server');
  $ActiveConnections{$Connection} = $event;   $ActiveConnections{$Connection} = $event;
    if ($ConnectionCount == 0) {
       &SetupTimer; # Need to handle timeouts with connections...
    }
  $ConnectionCount++;   $ConnectionCount++;
  Debug(4, "Connection count = ".$ConnectionCount);   Debug(4, "Connection count = ".$ConnectionCount);
  if($ConnectionCount == 1) { # First Connection:   if($ConnectionCount == 1) { # First Connection:
Line 1141  sub MakeLondConnection { Line 1197  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 1172  The text of the request to send. Line 1229  The text of the request to send.
 =cut  =cut
   
 sub StartRequest {  sub StartRequest {
     my $Lond     = shift;  
     my $Request  = shift; # This is a LondTransaction.      my ($Lond, $Request) = @_;
           
     Debug(6, "StartRequest: ".$Request->getRequest());      Debug(6, "StartRequest: ".$Request->getRequest());
   
Line 1224  sub QueueTransaction { Line 1281  sub QueueTransaction {
     if(!defined $LondSocket) { # Need to queue request.      if(!defined $LondSocket) { # Need to queue request.
  Debug(5,"Must queue...");   Debug(5,"Must queue...");
  $WorkQueue->enqueue($requestData);   $WorkQueue->enqueue($requestData);
  if($ConnectionCount < $MaxConnectionCount) {   Debug(5, "Queue Transaction startnew $ConnectionCount $LondConnecting");
    if(($ConnectionCount < $MaxConnectionCount)   && (! $LondConnecting)) {
   
     if($ConnectionRetriesLeft > 0) {      if($ConnectionRetriesLeft > 0) {
  Debug(5,"Starting additional lond connection");   Debug(5,"Starting additional lond connection");
  if(MakeLondConnection() == 0) {   if(&MakeLondConnection() == 0) {
     EmptyQueue(); # Fail transactions, can't make connection.      EmptyQueue(); # Fail transactions, can't make connection.
       CloseAllLondConnections; # Should all be closed but...
  }   }
     } else {      } else {
  ShowStatus(GetServerHost()." >>> DEAD !!!! <<<");   ShowStatus(GetServerHost()." >>> DEAD !!!! <<<");
    $LondConnecting = 0;
  EmptyQueue(); # It's worse than that ... he's dead Jim.   EmptyQueue(); # It's worse than that ... he's dead Jim.
    CloseAllLondConnections; # Should all be closed but..
     }      }
  }   }
     } else { # Can start the request:      } else { # Can start the request:
Line 1275  sub ClientRequest { Line 1337  sub ClientRequest {
     Debug(8,"Data: ".$data." this read: ".$thisread);      Debug(8,"Data: ".$data." this read: ".$thisread);
     $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");
Line 1336  sub NewClient { Line 1398  sub NewClient {
 Returns the name of the UNIX socket on which to listen for client  Returns the name of the UNIX socket on which to listen for client
 connections.  connections.
   
   =head2 Parameters:
   
       host (optional)  - Name of the host socket to return.. defaults to
                          the return from GetServerHost().
   
 =cut  =cut
   
 sub GetLoncSocketPath {  sub GetLoncSocketPath {
     return $UnixSocketDir."/".GetServerHost();  
       my $host = GetServerHost(); # Default host.
       if (@_) {
    ($host)  = @_; # Override if supplied.
       }
       return $UnixSocketDir."/".$host;
 }  }
   
 =pod  =pod
Line 1376  connection.  The event handler establish Line 1448  connection.  The event handler establish
 (creating a communcations channel), that int turn will establish  (creating a communcations channel), that int turn will establish
 another event handler to subess requests.  another event handler to subess requests.
   
   =head2  Parameters:
   
      host (optional)   Name of the host to set up a unix socket to.
   
 =cut  =cut
   
 sub SetupLoncListener {  sub SetupLoncListener {
   
       my $host       = GetServerHost(); # Default host.
       if (@_) {
    ($host)    = @_ # Override host with parameter.
       }
   
     my $socket;      my $socket;
     my $SocketName = GetLoncSocketPath();      my $SocketName = GetLoncSocketPath($host);
     unlink($SocketName);      unlink($SocketName);
     unless ($socket =IO::Socket::UNIX->new(Local  => $SocketName,      unless ($socket =IO::Socket::UNIX->new(Local  => $SocketName,
     Listen => 10,       Listen => 250, 
     Type   => SOCK_STREAM)) {      Type   => SOCK_STREAM)) {
  die "Failed to create a lonc listner socket";   die "Failed to create a lonc listner socket";
     }      }
     Event->io(cb     => \&NewClient,      return $socket;
       poll   => 'r',  
       desc   => 'Lonc listener Unix Socket',  
       fd     => $socket);  
 }  }
   
 #  #
Line 1422  into the status file. Line 1500  into the status file.
 We also use this to reset the retries count in order to allow the  We also use this to reset the retries count in order to allow the
 client to retry connections with a previously dead server.  client to retry connections with a previously dead server.
 =cut  =cut
   
 sub ChildStatus {  sub ChildStatus {
     my $event = shift;      my $event = shift;
     my $watcher = $event->w;      my $watcher = $event->w;
Line 1434  sub ChildStatus { Line 1513  sub ChildStatus {
     #      #
     #  Write out information about each of the connections:      #  Write out information about each of the connections:
     #      #
     print $fh "Active connection statuses: \n";      if ($DebugLevel > 2) {
     my $i = 1;   print $fh "Active connection statuses: \n";
     print STDERR  "================================= Socket Status Dump:\n";   my $i = 1;
     foreach my $item (keys %ActiveConnections) {   print STDERR  "================================= Socket Status Dump:\n";
  my $Socket = $ActiveConnections{$item}->data;   foreach my $item (keys %ActiveConnections) {
  my $state  = $Socket->GetState();      my $Socket = $ActiveConnections{$item}->data;
  print $fh "Connection $i State: $state\n";      my $state  = $Socket->GetState();
  print STDERR "---------------------- Connection $i \n";      print $fh "Connection $i State: $state\n";
  $Socket->Dump();      print STDERR "---------------------- Connection $i \n";
  $i++;      $Socket->Dump(-1); # Ensure it gets dumped..
       $i++;
    }
     }      }
     $ConnectionRetriesLeft = $ConnectionRetries;      $ConnectionRetriesLeft = $ConnectionRetries;
 }  }
Line 1515  sub ChildProcess { Line 1596  sub ChildProcess {
   cb       => \&ToggleDebug,    cb       => \&ToggleDebug,
   data     => "INT");    data     => "INT");
   
     SetupTimer();  
           
     SetupLoncListener();      my $socket =  SetupLoncListener();
       Event->io(cb   => \&NewClient,
         poll => 'r',
         desc => 'Lonc Listener Unix Socket',
         fd   => $socket);
           
     $Event::Debuglevel = $DebugLevel;      $Event::Debuglevel = $DebugLevel;
           
Line 1538  sub ChildProcess { Line 1622  sub ChildProcess {
 #  Create a new child for host passed in:  #  Create a new child for host passed in:
   
 sub CreateChild {  sub CreateChild {
       my $host = shift;
   
     my $sigset = POSIX::SigSet->new(SIGINT);      my $sigset = POSIX::SigSet->new(SIGINT);
     sigprocmask(SIG_BLOCK, $sigset);      sigprocmask(SIG_BLOCK, $sigset);
     my $host = shift;  
     $RemoteHost = $host;      $RemoteHost = $host;
     Log("CRITICAL", "Forking server for ".$host);      Log("CRITICAL", "Forking server for ".$host);
     my $pid          = fork;      my $pid          = fork;
Line 1607  Log("CRITICAL", "--------------- Startin Line 1692  Log("CRITICAL", "--------------- Startin
   
 LondConnection::ReadConfig;               # Read standard config files.  LondConnection::ReadConfig;               # Read standard config files.
 my $HostIterator = LondConnection::GetHostIterator;  my $HostIterator = LondConnection::GetHostIterator;
 while (! $HostIterator->end()) {  
   
     my $hostentryref = $HostIterator->get();  if ($DieWhenIdle) {
     CreateChild($hostentryref->[0]);      print "Die when idle socket monitoring is not yet implemented\n";
     $HostHash{$hostentryref->[0]} = $hostentryref->[4];      exit(-1);
     $HostIterator->next();  } else {
       
       while (! $HostIterator->end()) {
   
    my $hostentryref = $HostIterator->get();
    CreateChild($hostentryref->[0]);
    $HostHash{$hostentryref->[0]} = $hostentryref->[4];
    $HostIterator->next();
       }
 }  }
   
 $RemoteHost = "Parent Server";  $RemoteHost = "Parent Server";
   
 # Maintain the population:  # Maintain the population:
Line 1624  ShowStatus("Parent keeping the flock"); Line 1717  ShowStatus("Parent keeping the flock");
 #   Set up parent signals:  #   Set up parent signals:
 #  #
   
 $SIG{INT}  = \&Terminate;  if ($DieWhenIdle) {
 $SIG{TERM} = \&Terminate;       print "Die when idle main processing not yet implemented";
 $SIG{HUP}  = \&Restart;      exit (-1);
 $SIG{USR1} = \&CheckKids;   } else {
 $SIG{USR2} = \&UpdateKids; # LonManage update request.      
       $SIG{INT}  = \&Terminate;
 while(1) {      $SIG{TERM} = \&Terminate; 
     my $deadchild = wait();      $SIG{HUP}  = \&Restart;
     if(exists $ChildHash{$deadchild}) { # need to restart.      $SIG{USR1} = \&CheckKids; 
  my $deadhost = $ChildHash{$deadchild};      $SIG{USR2} = \&UpdateKids; # LonManage update request.
  delete($HostToPid{$deadhost});      
  delete($ChildHash{$deadchild});      while(1) {
  Log("WARNING","Lost child pid= ".$deadchild.   my $deadchild = wait();
       "Connected to host ".$deadhost);   if(exists $ChildHash{$deadchild}) { # need to restart.
  Log("INFO", "Restarting child procesing ".$deadhost);      my $deadhost = $ChildHash{$deadchild};
  CreateChild($deadhost);      delete($HostToPid{$deadhost});
       delete($ChildHash{$deadchild});
       Log("WARNING","Lost child pid= ".$deadchild.
    "Connected to host ".$deadhost);
       Log("INFO", "Restarting child procesing ".$deadhost);
       CreateChild($deadhost);
    }
     }      }
 }  }
   
   
   
 =pod  =pod
   
 =head1 CheckKids  =head1 CheckKids
Line 1811  sub KillThemAll { Line 1909  sub KillThemAll {
     local($SIG{CHLD}) = 'IGNORE';      # Our children >will< die.      local($SIG{CHLD}) = 'IGNORE';      # Our children >will< die.
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildHash) {
  my $serving = $ChildHash{$pid};   my $serving = $ChildHash{$pid};
  Debug(2, "Killing lonc for $serving pid = $pid");   ShowStatus("Nicely Killing lonc for $serving pid = $pid");
  ShowStatus("Killing lonc for $serving pid = $pid");   Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid");
  Log("CRITICAL", "Killing lonc for $serving pid = $pid");  
  kill 'QUIT' => $pid;   kill 'QUIT' => $pid;
  delete($ChildHash{$pid});  
     }      }
     my $execdir = $perlvar{'lonDaemons'};  
     unlink("$execdir/logs/lonc.pid");  
   
 }  }
   
   
   #
   #  Kill all children via KILL.  Just in case the
   #  first shot didn't get them.
   
   sub really_kill_them_all_dammit
   {
       Debug(2, "Kill them all Dammit");
       local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them.
       foreach my $pid (keys %ChildHash) {
    my $serving = $ChildHash{$pid};
    &ShowStatus("Nastily killing lonc for $serving pid = $pid");
    Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid");
    kill 'KILL' => $pid;
    delete($ChildHash{$pid});
    my $execdir = $perlvar{'lonDaemons'};
    unlink("$execdir/logs/lonc.pid");
       }
   }
 =pod  =pod
   
 =head1 Terminate  =head1 Terminate
Line 1831  Terminate the system. Line 1945  Terminate the system.
 =cut  =cut
   
 sub Terminate {  sub Terminate {
     KillThemAll;      &Log("CRITICAL", "Asked to kill children.. first be nice...");
       &KillThemAll;
       #
       #  By now they really should all be dead.. but just in case 
       #  send them all SIGKILL's after a bit of waiting:
   
       sleep(4);
       &Log("CRITICAL", "Now kill children nasty");
       &really_kill_them_all_dammit;
     Log("CRITICAL","Master process exiting");      Log("CRITICAL","Master process exiting");
     exit 0;      exit 0;
   

Removed from v.1.41  
changed lines
  Added in v.1.60


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