Diff for /loncom/loncnew between versions 1.40 and 1.44

version 1.40, 2004/02/09 10:58:03 version 1.44, 2004/03/02 16:25:17
Line 262  sub SocketTimeout { Line 262  sub SocketTimeout {
     Log("WARNING", "A socket timeout was detected");      Log("WARNING", "A socket timeout was detected");
     Debug(0, " SocketTimeout called: ");      Debug(0, " SocketTimeout called: ");
     $Socket->Dump();      $Socket->Dump();
       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());
       }
   
 }  }
 #----------------------------- Timer management ------------------------  #----------------------------- Timer management ------------------------
   
Line 326  sub Tick { Line 333  sub Tick {
     if($successCount == 0) { # All connections failed:      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 {
     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...
  }   }
                 
     }      }
Line 521  sub CompleteTransaction { Line 530  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 548  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 $Transaction   = shift;
     my $data     = shift;      my $data     = shift;
Line 554  sub StartClientReply { Line 566  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 578  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 586  Parameters:
     
    The LondTransaction we are failing.     The LondTransaction we are failing.
     
   
 =cut  =cut
   
 sub FailTransaction {  sub FailTransaction {
Line 584  sub FailTransaction { Line 598  sub FailTransaction {
  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 625  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 680  sub KillSocket {
     #      #
     if($ConnectionCount == 0) {      if($ConnectionCount == 0) {
  EmptyQueue();   EmptyQueue();
    CloseAllLondConnections; # Should all already be closed but...
     }      }
 }  }
   
Line 740  transaction is in progress, the socket a Line 755  transaction is in progress, the socket a
   
 sub LondReadable {  sub LondReadable {
   
    my $Event      = shift;      my $Event      = shift;
    my $Watcher    = $Event->w;      my $Watcher    = $Event->w;
    my $Socket     = $Watcher->data;      my $Socket     = $Watcher->data;
    my $client     = undef;      my $client     = undef;
   
    &Debug(6,"LondReadable called state = ".$Socket->GetState());      &Debug(6,"LondReadable called state = ".$Socket->GetState());
   
   
    my $State = $Socket->GetState(); # All action depends on the state.      my $State = $Socket->GetState(); # All action depends on the state.
   
    SocketDump(6, $Socket);      SocketDump(6, $Socket);
    my $status = $Socket->Readable();      my $status = $Socket->Readable();
   
    &Debug(2, "Socket->Readable returned: $status");      &Debug(2, "Socket->Readable returned: $status");
   
    if($status != 0) {      if($status != 0) {
       # bad return from socket read. Currently this means that   # bad return from socket read. Currently this means that
       # The socket has become disconnected. We fail the transaction.   # The socket has become disconnected. We fail the transaction.
   
       Log("WARNING",   Log("WARNING",
          "Lond connection lost.");      "Lond connection lost.");
       if(exists($ActiveTransactions{$Socket})) {   if(exists($ActiveTransactions{$Socket})) {
          FailTransaction($ActiveTransactions{$Socket});      FailTransaction($ActiveTransactions{$Socket});
       }   }
       $Watcher->cancel();   $Watcher->cancel();
       KillSocket($Socket);   KillSocket($Socket);
       $ConnectionRetriesLeft--;       # Counts as connection failure   $ConnectionRetriesLeft--;       # Counts as connection failure
       return;   return;
    }      }
    SocketDump(6,$Socket);      SocketDump(6,$Socket);
   
    $State = $Socket->GetState(); # Update in case of transition.      $State = $Socket->GetState(); # Update in case of transition.
    &Debug(6, "After read, state is ".$State);      &Debug(6, "After read, state is ".$State);
   
    if($State eq "Initialized") {      if($State eq "Initialized") {
   
   
    } elsif ($State eq "ChallengeReceived") {      } elsif ($State eq "ChallengeReceived") {
  #  The challenge must be echoed back;  The state machine   #  The challenge must be echoed back;  The state machine
  # in the connection takes care of setting that up.  Just   # in the connection takes care of setting that up.  Just
  # need to transition to writable:   # need to transition to writable:
   
    $Watcher->cb(\&LondWritable);
    $Watcher->poll("w");
   
       $Watcher->cb(\&LondWritable);      } elsif ($State eq "ChallengeReplied") {
       $Watcher->poll("w");  
   
    } elsif ($State eq "ChallengeReplied") {      } elsif ($State eq "RequestingVersion") {
    # Need to ask for the version... that is writiability:
   
    } elsif ($State eq "RequestingVersion") {   $Watcher->cb(\&LondWritable);
       # Need to ask for the version... that is writiability:   $Watcher->poll("w");
         
       $Watcher->cb(\&LondWritable);      } elsif ($State eq "ReadingVersionString") {
       $Watcher->poll("w");   # Read the rest of the version string... 
             } elsif ($State eq "SetHost") {
    } elsif ($State eq "ReadingVersionString") {   # Need to request the actual domain get set...
       # Read the rest of the version string...   
    } elsif ($State eq "SetHost") {   $Watcher->cb(\&LondWritable);
       # Need to request the actual domain get set...   $Watcher->poll("w");
             } elsif ($State eq "HostSet") {
       $Watcher->cb(\&LondWritable);   # Reading the 'ok' from the peer.
       $Watcher->poll("w");  
    } elsif ($State eq "HostSet") {      } elsif ($State eq "RequestingKey") {
       # Reading the 'ok' from the peer.  
         
    } elsif ($State eq "RequestingKey") {  
  #  The ok was received.  Now we need to request the key   #  The ok was received.  Now we need to request the key
  #  That requires us to be writable:   #  That requires us to be writable:
   
       $Watcher->cb(\&LondWritable);   $Watcher->cb(\&LondWritable);
       $Watcher->poll("w");   $Watcher->poll("w");
   
    } elsif ($State eq "ReceivingKey") {      } elsif ($State eq "ReceivingKey") {
   
    } elsif ($State eq "Idle") {      } elsif ($State eq "Idle") {
         
    # This is as good a spot as any to get the peer version   # This is as good a spot as any to get the peer version
    # string:   # string:
         
    if($LondVersion eq "unknown") {   if($LondVersion eq "unknown") {
       $LondVersion = $Socket->PeerVersion();      $LondVersion = $Socket->PeerVersion();
       Log("INFO", "Connected to lond version: $LondVersion");      Log("INFO", "Connected to lond version: $LondVersion");
    }   }
  # If necessary, complete a transaction and then go into the   # If necessary, complete a transaction and then go into the
  # idle queue.   # idle queue.
  #  Note that a trasition to idle indicates a live lond   #  Note that a trasition to idle indicates a live lond
  # on the other end so reset the connection retries.   # on the other end so reset the connection retries.
  #   #
       $ConnectionRetriesLeft = $ConnectionRetries; # success resets the count   $ConnectionRetriesLeft = $ConnectionRetries; # success resets the count
       $Watcher->cancel();   $Watcher->cancel();
       if(exists($ActiveTransactions{$Socket})) {   if(exists($ActiveTransactions{$Socket})) {
          Debug(5,"Completing transaction!!");      Debug(5,"Completing transaction!!");
          CompleteTransaction($Socket,       CompleteTransaction($Socket, 
                              $ActiveTransactions{$Socket});   $ActiveTransactions{$Socket});
       } else {   } else {
          Log("SUCCESS", "Connection ".$ConnectionCount." to "      Log("SUCCESS", "Connection ".$ConnectionCount." to "
             .$RemoteHost." now ready for action");   .$RemoteHost." now ready for action");
       }   }
       ServerToIdle($Socket); # Next work unit or idle.   ServerToIdle($Socket); # Next work unit or idle.
   
    } 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
  #  here inthe first place.   #  here inthe first place.
   
       Deubg(6, "SendingRequest state encountered in readable");   Deubg(6, "SendingRequest state encountered in readable");
       $Watcher->poll("w");   $Watcher->poll("w");
       $Watcher->cb(\&LondWritable);   $Watcher->cb(\&LondWritable);
   
    } elsif ($State eq "ReceivingReply") {      } elsif ($State eq "ReceivingReply") {
   
   
    } else {      } else {
  # Invalid state.   # Invalid state.
       Debug(4, "Invalid state in LondReadable");   Debug(4, "Invalid state in LondReadable");
    }      }
 }  }
   
 =pod  =pod
Line 932  sub LondWritable { Line 947  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.
       # Old logic wrote in state specific code below, however
       # That forces us at least through another invocation of
       # this function after writability is possible again.
       # This logic also factors out common code for handling
       # 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});
    }
    $Watcher->cancel();
    KillSocket($Socket);
    return;
       }
   
       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");  
          FailTransaction($ActiveTransactions{$Socket});  
          $Watcher->cancel();  
          KillSocket($Socket);  
          return;  
       }  
         
    #  "init" is being sent...  
      
    } elsif ($State eq "Initialized")       {  
   
       # Now that init was sent, we switch   
       # to watching for readability:  
   
       $Watcher->cb(\&LondReadable);      if      ($State eq "Connected")         {
       $Watcher->poll("r");  
   
    } elsif ($State eq "ChallengeReceived") {   #  "init" is being sent...
       # We received the challenge, now we    
       # are echoing it back. This is a no-op,      } elsif ($State eq "Initialized")       {
       # we're waiting for the state to change  
   
       if($Socket->Writable() != 0) {  
   
          $Watcher->cancel();   # Now that init was sent, we switch 
          KillSocket($Socket);   # to watching for readability:
          return;  
       }   $Watcher->cb(\&LondReadable);
    $Watcher->poll("r");
   
    } elsif ($State eq "ChallengeReplied")  {      } elsif ($State eq "ChallengeReceived") {
       # The echo was sent back, so we switch   # We received the challenge, now we 
       # to watching readability.   # are echoing it back. This is a no-op,
    # we're waiting for the state to change
       $Watcher->cb(\&LondReadable);  
       $Watcher->poll("r");      } elsif ($State eq "ChallengeReplied")  {
    } elsif ($State eq "RequestingVersion") {   # The echo was sent back, so we switch
       # Sending the peer a version request...   # to watching readability.
         
       if($Socket->Writable() != 0) {   $Watcher->cb(\&LondReadable);
          $Watcher->cancel();   $Watcher->poll("r");
          KillSocket($Socket);      } elsif ($State eq "RequestingVersion") {
          return;   # Sending the peer a version request...
       }  
    } 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
       # version string from the peer:   # version string from the peer:
         
       $Watcher->cb(\&LondReadable);  
       $Watcher->poll("r");  
               
    } elsif ($State eq "SetHost") {   $Watcher->cb(\&LondReadable);
       #  Setting the remote domain...   $Watcher->poll("r");
               
       if($Socket->Writable() != 0) {      } elsif ($State eq "SetHost") {
          $Watcher->cancel();   #  Setting the remote domain...
          KillSocket($Socket);  
          return;      } elsif ($State eq "HostSet") {
       }   # Back to readable to get the ok.
    } elsif ($State eq "HostSet") {  
       # Back to readable to get the ok.  
               
       $Watcher->cb(\&LondReadable);   $Watcher->cb(\&LondReadable);
       $Watcher->poll("r");   $Watcher->poll("r");
               
   
    } 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:  
   
       $Watcher->cb(\&LondReadable);   $Watcher->cb(\&LondReadable);
       $Watcher->poll("r");   $Watcher->poll("r");
   
    } elsif ($State eq "SendingRequest")    {      } elsif ($State eq "SendingRequest")    {
     
    # 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})) {      } elsif ($State eq "ReceivingReply")    {
             Debug(3, "Lond connection lost, failing transactions");   # The send has completed.  Wait for the
             FailTransaction($ActiveTransactions{$Socket});   # data to come in for a reply.
          }   Debug(8,"Writable sent request/receiving reply");
       $Watcher->cancel();   $Watcher->cb(\&LondReadable);
          KillSocket($Socket);   $Watcher->poll("r");
          return;  
       
       }  
   
    } elsif ($State eq "ReceivingReply")    {      } else {
       # The send has completed.  Wait for the   #  Control only passes here on an error: 
       # data to come in for a reply.   #  the socket state does not match any
       Debug(8,"Writable sent request/receiving reply");   #  of the known states... so an error
       $Watcher->cb(\&LondReadable);   #  must be logged.
       $Watcher->poll("r");  
   
    } else {  
       #  Control only passes here on an error:   
       #  the socket state does not match any  
       #  of the known states... so an error  
       #  must be logged.  
   
       &Debug(4, "Invalid socket state ".$State."\n");   &Debug(4, "Invalid socket state ".$State."\n");
    }      }
           
 }  }
 =pod  =pod
Line 1229  sub QueueTransaction { Line 1221  sub QueueTransaction {
  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 !!!! <<<");
  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 1269  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");

Removed from v.1.40  
changed lines
  Added in v.1.44


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