--- loncom/loncnew 2003/04/29 03:24:51 1.5 +++ loncom/loncnew 2003/05/05 23:40:27 1.6 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # lonc maintains the connections to remote computers # -# $Id: loncnew,v 1.5 2003/04/29 03:24:51 foxr Exp $ +# $Id: loncnew,v 1.6 2003/05/05 23:40:27 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -49,6 +49,7 @@ use POSIX qw(:signal_h); use IO::Socket; use IO::Socket::INET; use IO::Socket::UNIX; +use IO::Handle; use Socket; use Crypt::IDEA; use LONCAPA::Queue; @@ -103,6 +104,12 @@ my $ConnectionCount = 0; my $IdleSeconds = 0; # Number of seconds idle. # +# This disconnected socket makes posible a bit more regular +# code when processing delayed requests: +# +my $NullSocket = IO::Socket->new(); + +# =pod @@ -190,7 +197,7 @@ sub Tick { $IdleSeconds++; if($IdleSeconds > $IdleTimeout) { # Prune a connection... $Socket = $IdleConnections->pop(); - KillSocket($Socket, 0); + KillSocket($Socket); } } else { $IdleSeconds = 0; # Reset idle count if not idle. @@ -302,51 +309,55 @@ sub ClientWritable { &Debug(6, "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: - - my $descr = sprintf("Connection to lonc client %d", - $ActiveClients{$Socket}); - Event->io(cb => \&ClientRequest, - poll => 'r', - desc => $descr, - data => "", - fd => $Socket); - - } else { # Partial string sent. - $Watcher->data(substr($Data, $result)); - } + if($Socket->connected) { + my $result = $Socket->send($Data, 0); - } 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".$RemoteHost); - $Watcher->cancel; # Stop the watcher. - $Socket->shutdown(2); # Kill connection - $Socket->close(); # Close the socket. - } + # $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: + + my $descr = sprintf("Connection to lonc client %d", + $ActiveClients{$Socket}); + Event->io(cb => \&ClientRequest, + poll => 'r', + desc => $descr, + 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".$RemoteHost); + $Watcher->cancel; # Stop the watcher. + $Socket->shutdown(2); # Kill connection + $Socket->close(); # Close the socket. + } + + } + } else { + $Watcher->cancel(); # A delayed request...just cancel. } } @@ -379,10 +390,22 @@ sub CompleteTransaction { my $Client = shift; my $data = $Socket->GetReply(); # Data to send. + StartClientReply($Client, $data); +} +=pod +=head1 StartClientReply + + Initiates a reply to a client where the reply data is a parameter. + +=cut +sub StartClientReply { + my $Client = shift; + my $data = shift; &Debug(8," Reply was: ".$data); my $Serial = $ActiveClients{$Client}; my $desc = sprintf("Connection to lonc client %d", + $Serial); Event->io(fd => $Client, poll => "w", @@ -407,20 +430,23 @@ Parameters: sub FailTransaction { my $client = shift; - &Debug(8, "Failing transaction due to disconnect"); - my $Serial = $ActiveClients{$client}; - my $desc = sprintf("Connection to lonc client %d", $Serial); - my $data = "error: Connection to lond lost\n"; - - Event->io(fd => $client, - poll => "w", - desc => $desc, - cb => \&ClientWritable, - data => $data); + StartClientReply($client, "con_lost"); } =pod +=head1 EmptyQueue + Fails all items in the work queue with con_lost. +=cut +sub EmptyQueue { + while($WorkQueue->Count()) { + my $request = $WorkQUeue->dequeue(); # Just to help it become empty. + my $client = $ClientQueue->dequeue(); # Need to con_lost this guy. + FailTransaction($client); + } +} + +=pod =head2 KillSocket @@ -444,7 +470,6 @@ nonzero if we are allowed to create a ne =cut sub KillSocket { my $Socket = shift; - my $Restart= shift; # If the socket came from the active connection set, delete it. # otherwise it came from the idle set and has already been destroyed: @@ -456,10 +481,13 @@ sub KillSocket { delete($ActiveConnections{$Socket}); } $ConnectionCount--; - if( ($ConnectionCount = 0) && ($Restart)) { - MakeLondConnection(); - } + # If the connection count has gone to zero and there is work in the + # work queue, the work all gets failed with con_lost. + # + if($ConnectionCount == 0) { + EmptyQueue; + } } =pod @@ -541,7 +569,7 @@ sub LondReadable { FailTransaction($ActiveTransactions{$Socket}); } $Watcher->cancel(); - KillSocket($Socket, 1); + KillSocket($Socket); return; } SocketDump(6,$Socket); @@ -582,7 +610,7 @@ sub LondReadable { } $Watcher->cancel(); ServerToIdle($Socket); # Next work unit or idle. - + } elsif ($State eq "SendingRequest") { # We need to be writable for this and probably don't belong # here inthe first place. @@ -684,7 +712,7 @@ sub LondWritable { # We'll treat this as if the socket got disconnected: $Watcher->cancel(); - KillSocket($Socket, 1); + KillSocket($Socket); return; } # "init" is being sent... @@ -706,7 +734,7 @@ sub LondWritable { if($Socket->Writable() != 0) { $Watcher->cancel(); - KillSocket($Socket, 1); + KillSocket($Socket); return; } @@ -727,7 +755,7 @@ sub LondWritable { # Write resulted in an error. $Watcher->cancel(); - KillSocket($Socket, 1); + KillSocket($Socket); return; } @@ -749,7 +777,7 @@ sub LondWritable { FailTransaction($ActiveTransactions{$Socket}); } $Watcher->cancel(); - KillSocket($Socket, 1); + KillSocket($Socket); return; } @@ -771,6 +799,25 @@ sub LondWritable { } } +=pod + +=cut +sub QueueDelayed { + my $path = "$perlvar{'lonSockDir'}/delayed"; + opendir(DIRHANDLE, $path); + @alldelayed = grep /\.$RemoteHost$/, readdir DIRHANDLE; + closedir(DIRHANDLE); + my $dfname; + my $reqfile + foreach $reqfile (sort @alldelayed) { + $reqfile = $path/$reqfile; + my $Handle = IO::File->new($reqfile); + my $cmd = <$Handle>; + chomp($cmd); + QueueTransaction($NullSocket, $cmd); + } + +} =pod @@ -815,6 +862,9 @@ sub MakeLondConnection { $ActiveConnections{$Connection} = $event; $ConnectionCount++; + if($ConnectionCount == 1) { # First Connection: + QueueDelayed; + } } } @@ -1125,12 +1175,26 @@ sub CreateChild { # + + ShowStatus("Parent writing pid file:"); $execdir = $perlvar{'lonDaemons'}; open (PIDSAVE, ">$execdir/logs/lonc.pid"); print PIDSAVE "$$\n"; close(PIDSAVE); +ShowStatus("Forming new session"); +my $childpid = fork; +if ($childpid != 0) { + sleep 4; # Give child a chacne to break to + exit 0; # a new sesion. +} + +if (POSIX::setsid() < 0) { + print "Could not create new session\n"; + exit -1; +} + ShowStatus("Forking node servers"); my $HostIterator = LondConnection::GetHostIterator;