[LON-CAPA-cvs] cvs: loncom / loncnew

foxr lon-capa-cvs@mail.lon-capa.org
Tue, 17 Feb 2004 09:43:21 -0000


foxr		Tue Feb 17 04:43:21 2004 EDT

  Modified files:              
    /loncom	loncnew 
  Log:
  - Clean up write logic and factor out common code.
  - Fix up some error logic to ensure that:
    o All failed transactions fromthe lonc point of view close the
      associated connection
    o All closures of a lond connection will fail any associated transaction
    o A bit of defensive programming when closing a connection that should be
      idle to ensure that any bad book-keeping gets cleaned up by failing
      the associaed transaction.
  
  
  
Index: loncom/loncnew
diff -u loncom/loncnew:1.41 loncom/loncnew:1.42
--- loncom/loncnew:1.41	Mon Feb  9 08:39:28 2004
+++ loncom/loncnew	Tue Feb 17 04:43:21 2004
@@ -2,7 +2,7 @@
 # The LearningOnline Network with CAPA
 # lonc maintains the connections to remote computers
 #
-# $Id: loncnew,v 1.41 2004/02/09 13:39:28 albertel Exp $
+# $Id: loncnew,v 1.42 2004/02/17 09:43:21 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -262,9 +262,16 @@
     Log("WARNING", "A socket timeout was detected");
     Debug(0, " SocketTimeout called: ");
     $Socket->Dump();
+    if(exists($ActiveTransactions{$Socket})) {
+      FailTransaction($ActiveTransactions{$Socket});
+    }
     KillSocket($Socket);	# A transaction timeout also counts as
                                 # a connection failure:
     $ConnectionRetriesLeft--;
+    if($ConnectionRetriesLeft <= 0) {
+	Log("CRITICAL", "Host marked dead: ".GetServerHost());
+    }
+
 }
 #----------------------------- Timer management ------------------------
 
@@ -326,11 +333,13 @@
 	    if($successCount == 0) { # All connections failed:
 		Debug(5,"Work in queue failed to make any connectiouns\n");
 		EmptyQueue();	# Fail pending transactions with con_lost.
+		CloseAllLondConnections(); # Should all be closed but....
 	    }
 	} else {
 	    ShowStatus(GetServerHost()." >>> DEAD!!! <<<");
 	    Debug(5,"Work in queue, but gave up on connections..flushing\n");
 	    EmptyQueue();	# Connections can't be established.
+	    CloseAllLondConnections(); # Should all already be closed but...
 	}
        
     }
@@ -521,7 +530,9 @@
 	unlink $Transaction->getFile();
     }
 }
+
 =pod
+
 =head1 StartClientReply
 
    Initiates a reply to a client where the reply data is a parameter.
@@ -537,6 +548,7 @@
     The data to send to apached client.
 
 =cut
+
 sub StartClientReply {
     my $Transaction   = shift;
     my $data     = shift;
@@ -554,7 +566,9 @@
 	      cb       => \&ClientWritable,
 	      data     => $data);
 }
+
 =pod
+
 =head2 FailTransaction
 
   Finishes a transaction with failure because the associated lond socket
@@ -564,8 +578,7 @@
   - The transaction is 'live' in which case we initiate the sending
     of "con_lost" to the client.
 
-Deleting the transaction means killing it from the 
-%ActiveTransactions hash.
+Deleting the transaction means killing it from the %ActiveTransactions hash.
 
 Parameters:
 
@@ -573,6 +586,7 @@
  
    The LondTransaction we are failing.
  
+
 =cut
 
 sub FailTransaction {
@@ -584,9 +598,6 @@
 	Debug(1," Replying con_lost to ".$transaction->getRequest());
 	StartClientReply($transaction, "con_lost\n");
     }
-    if($ConnectionRetriesLeft <= 0) {
-	Log("CRITICAL", "Host marked dead: ".GetServerHost());
-    }
 
 }
 
@@ -614,7 +625,10 @@
 =cut
 sub CloseAllLondConnections {
     foreach my $Socket (keys %ActiveConnections) {
-	KillSocket($Socket);
+      if(exists($ActiveTransactions{$Socket})) {
+	FailTransaction($ActiveTransactions{$Socket});
+      }
+      KillSocket($Socket);
     }
 }
 =cut
@@ -666,6 +680,7 @@
     #
     if($ConnectionCount == 0) {
 	EmptyQueue();
+	CloseAllLondConnections; # Should all already be closed but...
     }
 }
 
@@ -932,21 +947,36 @@
 
     SocketDump(6,$Socket);
 
+    #  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      ($State eq "Connected")         {
 
-	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 
@@ -960,13 +990,6 @@
 	# are echoing it back. This is a no-op,
 	# we're waiting for the state to change
 	
-	if($Socket->Writable() != 0) {
-
-	    $Watcher->cancel();
-	    KillSocket($Socket);
-	    return;
-	}
-	
     } elsif ($State eq "ChallengeReplied")  {
 	# The echo was sent back, so we switch
 	# to watching readability.
@@ -975,12 +998,7 @@
 	$Watcher->poll("r");
     } elsif ($State eq "RequestingVersion") {
 	# Sending the peer a version request...
-      
-	if($Socket->Writable() != 0) {
-	    $Watcher->cancel();
-	    KillSocket($Socket);
-	    return;
-	}
+
     } elsif ($State eq "ReadingVersionString") {
 	# Transition to read since we have sent the
 	# version command and now just need to read the
@@ -991,12 +1009,7 @@
       
     } elsif ($State eq "SetHost") {
 	#  Setting the remote domain...
-      
-	if($Socket->Writable() != 0) {
-	    $Watcher->cancel();
-	    KillSocket($Socket);
-	    return;
-	}
+
     } elsif ($State eq "HostSet") {
 	# Back to readable to get the ok.
       
@@ -1007,17 +1020,7 @@
     } elsif ($State eq "RequestingKey")     {
 	# At this time we're requesting the key.
 	# 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")      {
 	# Now we need to wait for the key
 	# to come back from the peer:
@@ -1030,17 +1033,6 @@
 	# At this time we are sending a request to the
 	# 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")    {
 	# The send has completed.  Wait for the
@@ -1229,10 +1221,12 @@
 		Debug(5,"Starting additional lond connection");
 		if(MakeLondConnection() == 0) {
 		    EmptyQueue();	# Fail transactions, can't make connection.
+		    CloseAllLondConnections; # Should all be closed but...
 		}
 	    } else {
 		ShowStatus(GetServerHost()." >>> DEAD !!!! <<<");
 		EmptyQueue();	# It's worse than that ... he's dead Jim.
+		CloseAllLondConnections; # Should all be closed but..
 	    }
 	}
     } else {			# Can start the request: