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

foxr lon-capa-cvs@mail.lon-capa.org
Tue, 01 Apr 2003 23:22:02 -0000


This is a MIME encoded message

--foxr1049239322
Content-Type: text/plain

foxr		Tue Apr  1 18:22:02 2003 EDT

  Modified files:              
    /newloncapa	loncnew 
  Log:
  Get single client unencrypted traffic working
  
  
--foxr1049239322
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20030401182202.txt"

Index: newloncapa/loncnew
diff -u newloncapa/loncnew:1.3 newloncapa/loncnew:1.4
--- newloncapa/loncnew:1.3	Sat Mar 22 19:04:51 2003
+++ newloncapa/loncnew	Tue Apr  1 18:22:01 2003
@@ -6,7 +6,7 @@
 #    - Setup basic event loop.   (done)
 #    - Add timer dispatch.       (done)
 #    - Add ability to accept lonc UNIX domain sockets.  (done)
-#    - Add ability to create/negotiate lond connections.
+#    - Add ability to create/negotiate lond connections (done).
 #    - Add general logic for dispatching requests and timeouts.
 #    - Add support for the lonc/lond requests.
 #    - Add logging/status monitoring.
@@ -28,20 +28,49 @@
 use Stack;
 use LondConnection;
 
+print "Loncnew starting\n";
+
 #
 #   The stack below is a cache of a idle connections.
 #
 
 my $IdleConnections = Stack->new();
 my %ActiveConnections;		
+my %ActiveTransactions;
+
 
 my $WorkQueue       = Queue->new(); # Queue of pending transactions.
+my $ClientQueue     = Queue->new(); # Queue of clients causing xactinos.
 my $ConnectionCount = 0;
 my $MaxConnectionCount = 5;	# Will get from config later.
+my $ClientConnection = 0;	# Uniquifier for client events.
 
 $DebugLevel = 10;
+$IdleTimeout= 3600;		# Wait an hour before pruning connections.
 
-
+#
+=pod
+=head 2 GetPeerName
+   Returns the name of the host that a socket object is connected
+   to.
+=cut
+
+sub GetPeername {
+    my $connection = shift;
+    my $AdrFamily  = shift;
+    my $peer       = $connection->peername();
+    my $peerport;
+    my $peerip;
+    if($AdrFamily == AF_INET) {
+	($peerport, $peerip) = sockaddr_in($peer);
+	my $peername    = gethostbyaddr($iaddr, $AdrFamily);
+	return $peername;
+    } elsif ($AdrFamily == AF_UNIX) {
+	my $peerfile;
+	($peerfile) = sockaddr_un($peer);
+	return $peerfile;
+    }
+}
 #----------------------------- Timer management ------------------------
 =pod
 =head2 Debug
@@ -94,11 +123,123 @@
 
     &Debug(1, "Server to idle");
 
-    # In this iteration, just put it on the idle queue.
+    #  If there's work to do, start the transaction:
 
-    $IdleConnections->push($Socket);
+    $reqdata = $WorkQueue->dequeue();
+    Debug(9, "Queue gave request data: ".$reqdata);
+    unless($reqdata eq undef)  {
+	my $unixSocket = $ClientQueue->dequeue();
+	&Debug(3, "Starting new work request");
+	&Debug(9, "Request: ".$reqdata);
+	
+	&StartRequest($Socket, $unixSocket, $reqdata);
+    } else {
+	
+    #  There's no work waiting, so push the server to idle list.
+	&Debug(3, "No new work requests, server connection going idle");
+	delete($ActiveTransactions{$Socket});
+	$IdleConnections->push($Socket);
+    }
 }
 =pod
+=head2 ClientWritable
+  Event callback for when a client socket is writable.
+  This callback is established when a transaction reponse is
+  avaiable from lond.  The response is forwarded to the unix socket
+  as it becomes writable in this sub.
+Parameters:
+
+=item Event - The event that has been triggered. Event->w->data is
+              the data and Event->w->fd is the socket to write.
+
+=cut
+sub ClientWritable {
+    my $Event    = shift;
+    my $Watcher  = $Event->w;
+    my $Data     = $Watcher->data;
+    my $Socket   = $Watcher->fd;
+
+    # Try to send the data:
+
+    &Debug(1, "ClientWritable writing".$Data);
+    &Debug(9, "Socket is: ".$Socket);
+
+    my $result = $Socket->send($Data, 0);
+
+    # $result undefined: the write failed.
+    # otherwise $result is the number of bytes written.
+    # Remove that preceding string from the data.
+    # If the resulting data is empty, destroy the watcher
+    # and set up a read event handler to accept the next
+    # request.
+
+    &Debug(9,"Send result is ".$result." Defined: ".defined($result));
+    if(defined($result)) {
+	&Debug(9, "send result was defined");
+	if($result == length($Data)) { # Entire string sent.
+	    &Debug(9, "ClientWritable data all written");
+	    $Watcher->cancel();
+	    #
+	    #  Set up to read next request from socket:
+	    
+	    Event->io(cb    => \&ClientRequest,
+		      poll  => 'r',
+		      desc  => "Connection to lonc client",
+		      data  => "",
+		      fd    => $Socket);
+
+	} else {		# Partial string sent.
+	    $Watcher->data(substr($Data, $result));
+	}
+	
+    } else {			# Error of some sort...
+
+	# Some errnos are possible:
+	my $errno = $!;
+	if($errno == POSIX::EWOULDBLOCK   ||
+	   $errno == POSIX::EAGAIN        ||
+	   $errno == POSIX::EINTR) {
+	    # No action taken?
+	} else {		# Unanticipated errno.
+	    &Debug(5,"ClientWritable error or peer shutdown");
+	    $Watcher->cancel;	# Stop the watcher.
+	    $Socket->shutdown(2); # Kill connection
+	    $Socket->close();	# Close the socket.
+	}
+	
+    }
+}
+
+=pod
+=head2 CompleteTransaction
+  Called when the reply data has been received for a lond 
+transaction.   The reply data must now be sent to the
+ultimate client on the other end of the Unix socket.  This is
+done by setting up a writable event for the socket with the
+data the reply data.
+Parameters:
+=item Socket - Socket on which the lond transaction occured.  This
+      is a LondConnection. The data received is in the 
+	TransactionReply member.
+=item Client - Unix domain socket open on the ultimate client.
+
+=cut
+sub CompleteTransaction {
+    &Debug(4,"Complete transaction");
+    my $Socket = shift;
+    my $Client = shift;
+
+    my $data   = $Socket->GetReply(); # Data to send.
+
+    &Debug(8," Reply was: ".$data);
+    Event->io(fd       => $Client,
+	      poll     => "w",
+	      cb       => \&ClientWritable,
+	      data     => $data);
+}
+
+
+=pod
 =head2 LondReadable
 This function is called whenever a lond connection
 is readable.  The action is state dependent:
@@ -141,13 +282,10 @@
 sub LondReadable {
     my $Event      = shift;
     my $Watcher    = $Event->w;
-    my @data       = $Watcher->data;
-    my $Socket     = $data[0];
+    my $Socket     = $Watcher->data;
     my $client     = undef;
 
-    if ($data == 2) {
-	$client = $data [1];	# There may be a client UNIX socket.
-    }
+
     my $State = $Socket->GetState(); # All action depends on the state.
 
     &Debug(4,"LondReadable called state = ".$State);
@@ -155,6 +293,7 @@
     if($Socket->Readable() != 0) {
 	 # bad return from socket read.
     }
+    $Socket->Dump();
 
     $State = $Socket->GetState(); # Update in case of transition.
     &Debug(5, "After read, state is ".$State);
@@ -185,8 +324,10 @@
     } elsif ($State eq "Idle") {
 	# If necessary, complete a transaction and then go into the
 	# idle queue.
-	if($client) {
-	    CompleteTransaction($Socket, $client);
+	if(exists($ActiveTransactions{$Socket})) {
+	    Debug(8,"Completing transaction!!");
+	    CompleteTransaction($Socket, 
+				$ActiveTransactions{$Socket});
 	}
 	$Watcher->cancel();
 	ServerToIdle($Socket);	# Next work unit or idle.
@@ -261,14 +402,16 @@
     my $Event   = shift;
     my $Watcher = $Event->w;
     my @data    = $Watcher->data;
+    Debug(4,"LondWritable State = ".$State." data has ".@data." elts.\n");
+
     my $Socket  = $data[0];	# I know there's at least a socket.
 
     #  Figure out what to do depending on the state of the socket:
     
+
     my $State   = $Socket->GetState();
 
 
-    &Debug(4,"LondWritable State = ".$State."\n");
     $Socket->Dump();
 
     if      ($State eq "Connected")         {
@@ -331,7 +474,7 @@
     } elsif ($State eq "ReceivingReply")    {
 	# The send has completed.  Wait for the
 	# data to come in for a reply.
-
+	Debug(8,"Writable sent request/receiving reply");
 	$Watcher->poll("r");
 	$Watcher->cb(\&LondReadable);
 
@@ -405,14 +548,20 @@
     my $Client   = shift;
     my $Request  = shift;
     
-    Debug(4, "StartRequest");
+    Debug(4, "StartRequest: ".$Request);
+
+    my $Socket = $Lond->GetSocket();
     
+    $ActiveTransactions{$Lond} = $Client; # Socket to relay to client.
+
     $Lond->InitiateTransaction($Request);
-    $event = Event::io->new(fd      => $Lond->GetSocket(),
-			    poll    => "w",
-			    callback=> &LondWritable,
-			    data    => ($Lond, $Client));
+    $event = Event->io(fd      => $Lond->GetSocket(),
+		       poll    => "w",
+		       cb      => \&LondWritable,
+		       data    => $Lond,
+		       desc    => "lond transaction connection");
     $ActiveConnections{$Lond} = $event;
+    Debug(8," Start Request made watcher data with ".$event->data."\n");
 }
 
 =pod
@@ -433,13 +582,19 @@
     my $requestSocket = shift;
     my $requestData   = shift;
 
+    Debug(4,"QueueTransaction: ".$requestData);
+
     my $LondSocket    = $IdleConnections->pop();
     if(!defined $LondSocket) {	# Need to queue request.
-	$WorkQueue->enqueue(($requestSocket, $requestData));
+	Debug(4,"Must queue...");
+	$ClientQueue->enqueue($requestSocket);
+	$WorkQueue->enqueue($requestData);
 	if($ConnectionCount < $MaxConneciontCount) {
+	    Debug(4,"Starting additional lond connection");
 	    MakeLondConnection();
 	}
     } else {			# Can start the request:
+	Debug(4,"Can start...");
 	StartRequest($LondSocket, $requestSocket, $requestData);
     }
 }
@@ -458,20 +613,24 @@
     my $watcher = $event->w;
     my $socket  = $watcher->fd;
     my $data    = $watcher->data;
-
     my $thisread;
 
+    Debug(9, "  Watcher named: ".$watcher->desc);
+
     my $rv = $socket->recv($thisread, POSIX::BUFSIZ, 0);
+    Debug(8, "rcv:  data length = ".length($thisread)
+	  ." read =".$thisread);
     unless (defined $rv && length($thisread)) {
 	 # Likely eof on socket.
 	Debug(2,"Socket closed");
 	close($socket);
 	$watcher->cancel();
     }
+    Debug(8,"Data: ".$data." this read: ".$thisread);
     $data = $data.$thisread;	# Append new data.
-    $watcher->data = $data;
-    if($data =~ s/(.*\n)//) {	# Request entirely read.
-	Debug(2, "Complete transaction received".$data);
+    $watcher->data($data);
+    if($data =~ /(.*\n)/) {	# Request entirely read.
+	Debug(2, "Complete transaction received: ".$data);
 	QueueTransaction($socket, $data);
 	$watcher->cancel();	# Done looking for input data.
     }
@@ -493,14 +652,19 @@
     my $watcher    = $event->w; 
     my $socket     = $watcher->fd;	# Get the event' socket.
     my $connection = $socket->accept();	# Accept the client connection.
+    Debug(3,"Connection request accepted from "
+	  .GetPeername($connection, AF_UNIX));
 
-    Debug(3,"Connection request accepted from ".$connection->peername());
 
+    my $description = sprintf("Connection to lonc client %d",
+			      $ClientConnection);
+    Debug(4, "Creating event named: ".$description);
     Event->io(cb      => \&ClientRequest,
 	      poll    => 'r',
-	      desc    => 'Connection to lonc client '.$connection->peername(),
+	      desc    => $description,
 	      data    => "",
 	      fd      => $connection);
+    $ClientConnection++;
 }
 =pod GetLoncSocketPath
     Returns the name of the UNIX socket on which to listen for client
@@ -552,16 +716,19 @@
 #  the timer then dive into the main event loop.
 #
 
-
+print "Loncnew\n";
 SetupTimer();
+
 SetupLoncListener();
 
 $Event::Debuglevel = $DebugLevel;
 
+Debug(9, "Making lond connection");
 # Setup the initial server connection:
 
 &MakeLondConnection();
 
+Debug(9,"Entering event loop");
 my $ret = Event::loop();		#  Start the main event loop.
 
 
@@ -588,6 +755,10 @@
 
 =item ActiveConnections - A hash of lond connections that have transactions
     in process that are available to be timed out.
+
+=item ActiveTransactions - A hash indexed by lond connections that
+    contain the client reply socket for each connection that has an active
+    transaction on it.
 
 =item IdleConnections - A hash of lond connections that have no work
     to do.  These connections can be closed if they are idle for a long

--foxr1049239322--