File:  [LON-CAPA] / loncom / Attic / lonc
Revision 1.22: download - view: text, annotated - select for diffs
Thu Nov 29 18:57:46 2001 UTC (22 years, 5 months ago) by www
Branches: MAIN
CVS tags: HEAD
GPL

    1: #!/usr/bin/perl
    2: 
    3: # The LearningOnline Network
    4: # lonc - LON TCP-Client Domain-Socket-Server
    5: # provides persistent TCP connections to the other servers in the network
    6: # through multiplexed domain sockets
    7: #
    8: # $Id: lonc,v 1.22 2001/11/29 18:57:46 www Exp $
    9: #
   10: # Copyright Michigan State University Board of Trustees
   11: #
   12: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
   13: #
   14: # LON-CAPA is free software; you can redistribute it and/or modify
   15: # it under the terms of the GNU General Public License as published by
   16: # the Free Software Foundation; either version 2 of the License, or
   17: # (at your option) any later version.
   18: #
   19: # LON-CAPA is distributed in the hope that it will be useful,
   20: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   21: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22: # GNU General Public License for more details.
   23: #
   24: # You should have received a copy of the GNU General Public License
   25: # along with LON-CAPA; if not, write to the Free Software
   26: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   27: #
   28: # /home/httpd/html/adm/gpl.txt
   29: #
   30: # http://www.lon-capa.org/
   31: #
   32: # PID in subdir logs/lonc.pid
   33: # kill kills
   34: # HUP restarts
   35: # USR1 tries to open connections again
   36: 
   37: # 6/4/99,6/5,6/7,6/8,6/9,6/10,6/11,6/12,7/14,7/19,
   38: # 10/8,10/9,10/15,11/18,12/22,
   39: # 2/8,7/25 Gerd Kortemeyer
   40: # 12/05 Scott Harrison
   41: # 12/05 Gerd Kortemeyer
   42: # 01/10/01 Scott Harrison
   43: # 03/14/01,03/15,06/12,11/26,11/27,11/28 Gerd Kortemeyer
   44: # 
   45: # based on nonforker from Perl Cookbook
   46: # - server who multiplexes without forking
   47: 
   48: use POSIX;
   49: use IO::Socket;
   50: use IO::Select;
   51: use IO::File;
   52: use Socket;
   53: use Fcntl;
   54: use Tie::RefHash;
   55: use Crypt::IDEA;
   56: 
   57: my $status='';
   58: my $lastlog='';
   59: 
   60: # grabs exception and records it to log before exiting
   61: sub catchexception {
   62:     my ($signal)=@_;
   63:     $SIG{'QUIT'}='DEFAULT';
   64:     $SIG{__DIE__}='DEFAULT';
   65:     &logthis("<font color=red>CRITICAL: "
   66:      ."ABNORMAL EXIT. Child $$ for server $wasserver died through "
   67:      ."\"$signal\" with this parameter->[$@]</font>");
   68:     die($@);
   69: }
   70: 
   71: $childmaxattempts=5;
   72: 
   73: # -------------------------------- Set signal handlers to record abnormal exits
   74: 
   75: $SIG{'QUIT'}=\&catchexception;
   76: $SIG{__DIE__}=\&catchexception;
   77: 
   78: # ------------------------------------ Read httpd access.conf and get variables
   79: 
   80: open (CONFIG,"/etc/httpd/conf/access.conf") || die "Can't read access.conf";
   81: 
   82: while ($configline=<CONFIG>) {
   83:     if ($configline =~ /PerlSetVar/) {
   84: 	my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
   85:         chomp($varvalue);
   86:         $perlvar{$varname}=$varvalue;
   87:     }
   88: }
   89: close(CONFIG);
   90: 
   91: # ----------------------------- Make sure this process is running from user=www
   92: my $wwwid=getpwnam('www');
   93: if ($wwwid!=$<) {
   94:    $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
   95:    $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
   96:    system("echo 'User ID mismatch.  lonc must be run as user www.' |\
   97:  mailto $emailto -s '$subj' > /dev/null");
   98:    exit 1;
   99: }
  100: 
  101: # --------------------------------------------- Check if other instance running
  102: 
  103: my $pidfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
  104: 
  105: if (-e $pidfile) {
  106:    my $lfh=IO::File->new("$pidfile");
  107:    my $pide=<$lfh>;
  108:    chomp($pide);
  109:    if (kill 0 => $pide) { die "already running"; }
  110: }
  111: 
  112: # ------------------------------------------------------------- Read hosts file
  113: 
  114: open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
  115: 
  116: while ($configline=<CONFIG>) {
  117:     my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
  118:     chomp($ip);
  119:     $hostip{$id}=$ip;
  120: }
  121: close(CONFIG);
  122: 
  123: # -------------------------------------------------------- Routines for forking
  124: 
  125: %children               = ();       # keys are current child process IDs,
  126:                                     # values are hosts
  127: %childpid               = ();       # the other way around
  128: 
  129: %childatt               = ();       # number of attempts to start server
  130:                                     # for ID
  131: 
  132: sub REAPER {                        # takes care of dead children
  133:     $SIG{CHLD} = \&REAPER;
  134:     my $pid = wait;
  135:     my $wasserver=$children{$pid};
  136:     &logthis("<font color=red>CRITICAL: "
  137:      ."Child $pid for server $wasserver died ($childatt{$wasserver})</font>");
  138:     delete $children{$pid};
  139:     delete $childpid{$wasserver};
  140:     my $port = "$perlvar{'lonSockDir'}/$wasserver";
  141:     unlink($port);
  142: }
  143: 
  144: sub HUNTSMAN {                      # signal handler for SIGINT
  145:     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
  146:     map {
  147:         $wasserver=$children{$_};
  148:         &status("Closing $wasserver");
  149:         &logthis('Closing '.$wasserver.': '.&subreply('exit',$wasserver));
  150:         &status("Kill PID $_ for $wasserver");
  151: 	kill ('INT',$_);
  152:     } keys %children;
  153:     my $execdir=$perlvar{'lonDaemons'};
  154:     unlink("$execdir/logs/lonc.pid");
  155:     &logthis("<font color=red>CRITICAL: Shutting down</font>");
  156:     exit;                           # clean up with dignity
  157: }
  158: 
  159: sub HUPSMAN {                      # signal handler for SIGHUP
  160:     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
  161:     map {
  162:         $wasserver=$children{$_};
  163:         &status("Closing $wasserver");
  164:         &logthis('Closing '.$wasserver.': '.&subreply('exit',$wasserver));
  165:         &status("Kill PID $_ for $wasserver");
  166: 	kill ('INT',$_);
  167:     } keys %children;
  168:     &logthis("<font color=red>CRITICAL: Restarting</font>");
  169:     unlink("$execdir/logs/lonc.pid");
  170:     my $execdir=$perlvar{'lonDaemons'};
  171:     exec("$execdir/lonc");         # here we go again
  172: }
  173: 
  174: sub checkchildren {
  175:     &initnewstatus();
  176:     &logstatus();
  177:     &logthis('Going to check on the children');
  178:     map {
  179: 	sleep 1;
  180:         unless (kill 'USR1' => $_) {
  181: 	    &logthis ('Child '.$_.' is dead');
  182:             &logstatus($$.' is dead');
  183:         } 
  184:     } sort keys %children;
  185: }
  186: 
  187: sub USRMAN {
  188:     &logthis("USR1: Trying to establish connections again");
  189:     foreach $thisserver (keys %hostip) {
  190: 	$answer=subreply("ping",$thisserver);
  191:         &logthis("USR1: Ping $thisserver "
  192:         ."(pid >$childpid{$thisserver}<, $childatt{thisserver} attempts): "
  193:         ." >$answer<");
  194:     }
  195:     %childatt=();
  196:     &checkchildren();
  197: }
  198: 
  199: # -------------------------------------------------- Non-critical communication
  200: sub subreply { 
  201:  my ($cmd,$server)=@_;
  202:  my $answer='';
  203:  if ($server ne $perlvar{'lonHostID'}) { 
  204:     my $peerfile="$perlvar{'lonSockDir'}/$server";
  205:     my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
  206:                                       Type    => SOCK_STREAM,
  207:                                       Timeout => 10)
  208:        or return "con_lost";
  209: 
  210: 
  211:     $SIG{ALRM}=sub { die "timeout" };
  212:     $SIG{__DIE__}='DEFAULT';
  213:     eval {
  214:      alarm(10);
  215:      print $sclient "$cmd\n";
  216:      $answer=<$sclient>;
  217:      chomp($answer);
  218:      alarm(0);
  219:     };
  220:     if ((!$answer) || ($@=~/timeout/)) { $answer="con_lost"; }
  221:     $SIG{ALRM}='DEFAULT';
  222:     $SIG{__DIE__}=\&catchexception;
  223:  } else { $answer='self_reply'; }
  224:  return $answer;
  225: }
  226: 
  227: # --------------------------------------------------------------------- Logging
  228: 
  229: sub logthis {
  230:     my $message=shift;
  231:     my $execdir=$perlvar{'lonDaemons'};
  232:     my $fh=IO::File->new(">>$execdir/logs/lonc.log");
  233:     my $now=time;
  234:     my $local=localtime($now);
  235:     $lastlog=$local.': '.$message;
  236:     print $fh "$local ($$): $message\n";
  237: }
  238: 
  239: 
  240: sub logperm {
  241:     my $message=shift;
  242:     my $execdir=$perlvar{'lonDaemons'};
  243:     my $now=time;
  244:     my $local=localtime($now);
  245:     my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log");
  246:     print $fh "$now:$message:$local\n";
  247: }
  248: # ------------------------------------------------------------------ Log status
  249: 
  250: sub logstatus {
  251:     my $docdir=$perlvar{'lonDocRoot'};
  252:     my $fh=IO::File->new(">>$docdir/lon-status/loncstatus.txt");
  253:     print $fh $$."\t".$status."\t".$lastlog."\n";
  254: }
  255: 
  256: sub initnewstatus {
  257:     my $docdir=$perlvar{'lonDocRoot'};
  258:     my $fh=IO::File->new(">$docdir/lon-status/loncstatus.txt");
  259:     my $now=time;
  260:     my $local=localtime($now);
  261:     print $fh "LONC status $local - parent $$\n\n";
  262: }
  263: 
  264: # -------------------------------------------------------------- Status setting
  265: 
  266: sub status {
  267:     my $what=shift;
  268:     my $now=time;
  269:     my $local=localtime($now);
  270:     $status=$local.': '.$what;
  271: }
  272: 
  273: 
  274: # ---------------------------------------------------- Fork once and dissociate
  275: 
  276: $fpid=fork;
  277: exit if $fpid;
  278: die "Couldn't fork: $!" unless defined ($fpid);
  279: 
  280: POSIX::setsid() or die "Can't start new session: $!";
  281: 
  282: # ------------------------------------------------------- Write our PID on disk
  283: 
  284: $execdir=$perlvar{'lonDaemons'};
  285: open (PIDSAVE,">$execdir/logs/lonc.pid");
  286: print PIDSAVE "$$\n";
  287: close(PIDSAVE);
  288: &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");
  289: 
  290: # ----------------------------- Ignore signals generated during initial startup
  291: $SIG{HUP}=$SIG{USR1}='IGNORE';
  292: # ------------------------------------------------------- Now we are on our own
  293:     
  294: # Fork off our children, one for every server
  295: 
  296: &status("Forking ...");
  297: 
  298: foreach $thisserver (keys %hostip) {
  299:     make_new_child($thisserver);
  300: }
  301: 
  302: &logthis("Done starting initial servers");
  303: # ----------------------------------------------------- Install signal handlers
  304: 
  305: $SIG{CHLD} = \&REAPER;
  306: $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
  307: $SIG{HUP}  = \&HUPSMAN;
  308: $SIG{USR1} = \&USRMAN;
  309: 
  310: # And maintain the population.
  311: while (1) {
  312:     &status("Sleeping");
  313:     sleep;                          # wait for a signal (i.e., child's death)
  314:                                     # See who died and start new one
  315:     &status("Woke up");
  316:     foreach $thisserver (keys %hostip) {
  317:         if (!$childpid{$thisserver}) {
  318: 	    if ($childatt{$thisserver}<$childmaxattempts) {
  319: 	       $childatt{$thisserver}++;
  320:                &logthis(
  321:    "<font color=yellow>INFO: Trying to reconnect for $thisserver "
  322:   ."($childatt{$thisserver} of $childmaxattempts attempts)</font>"); 
  323:                make_new_child($thisserver);
  324: 	    }
  325:         }       
  326:     }
  327: }
  328: 
  329: 
  330: sub make_new_child {
  331:    
  332:     my $conserver=shift;
  333:     my $pid;
  334:     my $sigset;
  335:     &logthis("Attempting to start child for server $conserver");
  336:     # block signal for fork
  337:     $sigset = POSIX::SigSet->new(SIGINT);
  338:     sigprocmask(SIG_BLOCK, $sigset)
  339:         or die "Can't block SIGINT for fork: $!\n";
  340:     
  341:     die "fork: $!" unless defined ($pid = fork);
  342:     
  343:     if ($pid) {
  344:         # Parent records the child's birth and returns.
  345:         sigprocmask(SIG_UNBLOCK, $sigset)
  346:             or die "Can't unblock SIGINT for fork: $!\n";
  347:         $children{$pid} = $conserver;
  348:         $childpid{$conserver} = $pid;
  349:         return;
  350:     } else {
  351:         # Child can *not* return from this subroutine.
  352:         $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before
  353:         $SIG{USR1}= \&logstatus;
  354:    
  355:         # unblock signals
  356:         sigprocmask(SIG_UNBLOCK, $sigset)
  357:             or die "Can't unblock SIGINT for fork: $!\n";
  358: 
  359: # ----------------------------- This is the modified main program of non-forker
  360: 
  361: $port = "$perlvar{'lonSockDir'}/$conserver";
  362: 
  363: unlink($port);
  364: 
  365: # ---------------------------------------------------- Client to network server
  366: 
  367: &status("Opening TCP: $conserver");
  368: 
  369: unless (
  370:   $remotesock = IO::Socket::INET->new(PeerAddr => $hostip{$conserver},
  371:                                       PeerPort => $perlvar{'londPort'},
  372:                                       Proto    => "tcp",
  373:                                       Type     => SOCK_STREAM)
  374:    ) { 
  375:        my $st=120+int(rand(240));
  376:        &logthis(
  377: "<font color=blue>WARNING: Couldn't connect $conserver ($st secs): $@</font>");
  378:        sleep($st);
  379:        exit; 
  380:      };
  381: # ----------------------------------------------------------------- Init dialog
  382: 
  383: &status("Init dialogue: $conserver");
  384: 
  385:      $SIG{ALRM}=sub { die "timeout" };
  386:      $SIG{__DIE__}='DEFAULT';
  387:      eval {
  388:          alarm(60);
  389: print $remotesock "init\n";
  390: $answer=<$remotesock>;
  391: print $remotesock "$answer";
  392: $answer=<$remotesock>;
  393: chomp($answer);
  394:           alarm(0);
  395:      };
  396:      $SIG{ALRM}='DEFAULT';
  397:      $SIG{__DIE__}=\&catchexception;
  398:  
  399:      if ($@=~/timeout/) {
  400: 	 &logthis("Timed out during init: $conserver");
  401:          exit;
  402:      }
  403: 
  404: 
  405: &logthis("Init reply for $conserver: >$answer<");
  406: if ($answer ne 'ok') {
  407:        my $st=120+int(rand(240));
  408:        &logthis(
  409: "<font color=blue>WARNING: Init failed $conserver ($st secs)</font>");
  410:        sleep($st);
  411:        exit; 
  412: }
  413: sleep 5;
  414: &status("Ponging $conserver");
  415: print $remotesock "pong\n";
  416: $answer=<$remotesock>;
  417: chomp($answer);
  418: &logthis("Pong reply for $conserver: >$answer<");
  419: # ----------------------------------------------------------- Initialize cipher
  420: 
  421: &status("Initialize cipher: $conserver");
  422: print $remotesock "ekey\n";
  423: my $buildkey=<$remotesock>;
  424: my $key=$conserver.$perlvar{'lonHostID'};
  425: $key=~tr/a-z/A-Z/;
  426: $key=~tr/G-P/0-9/;
  427: $key=~tr/Q-Z/0-9/;
  428: $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;
  429: $key=substr($key,0,32);
  430: my $cipherkey=pack("H32",$key);
  431: if ($cipher=new IDEA $cipherkey) {
  432:    &logthis("Secure connection initialized: $conserver");
  433: } else {
  434:    my $st=120+int(rand(240));
  435:    &logthis(
  436:      "<font color=blue>WARNING: ".
  437:      "Could not establish secure connection, $conserver ($st secs)!</font>");
  438:    sleep($st);
  439:    exit;
  440: }
  441: 
  442: # ----------------------------------------- We're online, send delayed messages
  443:     &status("Checking for delayed messages");
  444:     my @allbuffered;
  445:     my $path="$perlvar{'lonSockDir'}/delayed";
  446:     opendir(DIRHANDLE,$path);
  447:     @allbuffered=grep /\.$conserver$/, readdir DIRHANDLE;
  448:     closedir(DIRHANDLE);
  449:     my $dfname;
  450:     map {
  451:         &status("Sending delayed $conserver $_");
  452:         $dfname="$path/$_";
  453:         &logthis($dfname);
  454:         my $wcmd;
  455:         {
  456:          my $dfh=IO::File->new($dfname);
  457:          $cmd=<$dfh>;
  458:         }
  459:         chomp($cmd);
  460:         my $bcmd=$cmd;
  461:         if ($cmd =~ /^encrypt\:/) {
  462: 	    my $rcmd=$cmd;
  463:             $rcmd =~ s/^encrypt\://;
  464:             chomp($rcmd);
  465:             my $cmdlength=length($rcmd);
  466:             $rcmd.="         ";
  467:             my $encrequest='';
  468:             for (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
  469:                 $encrequest.=
  470:                     unpack("H16",$cipher->encrypt(substr($rcmd,$encidx,8)));
  471:             }
  472:             $cmd="enc:$cmdlength:$encrequest\n";
  473:         }
  474:     $SIG{ALRM}=sub { die "timeout" };
  475:     $SIG{__DIE__}='DEFAULT';
  476:     eval {
  477:         alarm(60);
  478:         print $remotesock "$cmd\n";
  479:         $answer=<$remotesock>;
  480: 	chomp($answer);
  481:         alarm(0);
  482:     };
  483:     $SIG{ALRM}='DEFAULT';
  484:     $SIG{__DIE__}=\&catchexception;
  485: 
  486:         if (($answer ne '') && ($@!~/timeout/)) {
  487: 	    unlink("$dfname");
  488:             &logthis("Delayed $cmd to $conserver: >$answer<");
  489:             &logperm("S:$conserver:$bcmd");
  490:         }        
  491:     } @allbuffered;
  492: 
  493: # ------------------------------------------------------- Listen to UNIX socket
  494: &status("Opening socket $conserver");
  495: unless (
  496:   $server = IO::Socket::UNIX->new(Local  => $port,
  497:                                   Type   => SOCK_STREAM,
  498:                                   Listen => 10 )
  499:    ) { 
  500:        my $st=120+int(rand(240));
  501:        &logthis(
  502:          "<font color=blue>WARNING: ".
  503:          "Can't make server socket $conserver ($st secs): $@</font>");
  504:        sleep($st);
  505:        exit; 
  506:      };
  507: 
  508: # -----------------------------------------------------------------------------
  509: 
  510: &logthis("<font color=green>$conserver online</font>");
  511: 
  512: # -----------------------------------------------------------------------------
  513: # begin with empty buffers
  514: %inbuffer  = ();
  515: %outbuffer = ();
  516: %ready     = ();
  517: 
  518: tie %ready, 'Tie::RefHash';
  519: 
  520: nonblock($server);
  521: $select = IO::Select->new($server);
  522: 
  523: # Main loop: check reads/accepts, check writes, check ready to process
  524: while (1) {
  525:     my $client;
  526:     my $rv;
  527:     my $data;
  528: 
  529:     # check for new information on the connections we have
  530: 
  531:     # anything to read or accept?
  532:     foreach $client ($select->can_read(0.1)) {
  533: 
  534:         if ($client == $server) {
  535:             # accept a new connection
  536:             &status("Accept new connection: $conserver");
  537:             $client = $server->accept();
  538:             $select->add($client);
  539:             nonblock($client);
  540:         } else {
  541:             # read data
  542:             $data = '';
  543:             $rv   = $client->recv($data, POSIX::BUFSIZ, 0);
  544: 
  545:             unless (defined($rv) && length $data) {
  546:                 # This would be the end of file, so close the client
  547:                 delete $inbuffer{$client};
  548:                 delete $outbuffer{$client};
  549:                 delete $ready{$client};
  550: 
  551:                 &status("Idle $conserver");
  552:                 $select->remove($client);
  553:                 close $client;
  554:                 next;
  555:             }
  556: 
  557:             $inbuffer{$client} .= $data;
  558: 
  559:             # test whether the data in the buffer or the data we
  560:             # just read means there is a complete request waiting
  561:             # to be fulfilled.  If there is, set $ready{$client}
  562:             # to the requests waiting to be fulfilled.
  563:             while ($inbuffer{$client} =~ s/(.*\n)//) {
  564:                 push( @{$ready{$client}}, $1 );
  565:             }
  566:         }
  567:     }
  568: 
  569:     # Any complete requests to process?
  570:     foreach $client (keys %ready) {
  571:         handle($client);
  572:     }
  573: 
  574:     # Buffers to flush?
  575:     foreach $client ($select->can_write(1)) {
  576:         # Skip this client if we have nothing to say
  577:         next unless exists $outbuffer{$client};
  578: 
  579:         $rv = $client->send($outbuffer{$client}, 0);
  580:         unless (defined $rv) {
  581:             # Whine, but move on.
  582:             &logthis("I was told I could write, but I can't.\n");
  583:             next;
  584:         }
  585:         $errno=$!;
  586:         if (($rv == length $outbuffer{$client}) ||
  587:             ($errno == POSIX::EWOULDBLOCK) || ($errno == 0)) {
  588:             substr($outbuffer{$client}, 0, $rv) = '';
  589:             delete $outbuffer{$client} unless length $outbuffer{$client};
  590:         } else {
  591:             # Couldn't write all the data, and it wasn't because
  592:             # it would have blocked.  Shutdown and move on.
  593: 
  594: 	    &logthis("Dropping data with ".$errno.": ".
  595:                      length($outbuffer{$client}).", $rv");
  596: 
  597:             delete $inbuffer{$client};
  598:             delete $outbuffer{$client};
  599:             delete $ready{$client};
  600: 
  601:             $select->remove($client);
  602:             close($client);
  603:             next;
  604:         }
  605:     }
  606: }
  607: }
  608: 
  609: # ------------------------------------------------------- End of make_new_child
  610: 
  611: # handle($socket) deals with all pending requests for $client
  612: sub handle {
  613:     # requests are in $ready{$client}
  614:     # send output to $outbuffer{$client}
  615:     my $client = shift;
  616:     my $request;
  617: 
  618:     foreach $request (@{$ready{$client}}) {
  619: # ============================================================= Process request
  620:         # $request is the text of the request
  621:         # put text of reply into $outbuffer{$client}
  622: # -----------------------------------------------------------------------------
  623:         if ($request =~ /^encrypt\:/) {
  624: 	    my $cmd=$request;
  625:             $cmd =~ s/^encrypt\://;
  626:             chomp($cmd);
  627:             my $cmdlength=length($cmd);
  628:             $cmd.="         ";
  629:             my $encrequest='';
  630:             for (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
  631:                 $encrequest.=
  632:                     unpack("H16",$cipher->encrypt(substr($cmd,$encidx,8)));
  633:             }
  634:             $request="enc:$cmdlength:$encrequest\n";
  635:         }
  636: # --------------------------------------------------------------- Main exchange
  637:     $SIG{ALRM}=sub { die "timeout" };
  638:     $SIG{__DIE__}='DEFAULT';
  639:     eval {
  640:         alarm(300);
  641:         &status("Sending $conserver: $request");
  642:         print $remotesock "$request";
  643:         &status("Waiting for reply from $conserver: $request");
  644:         $answer=<$remotesock>;
  645:         &status("Received reply: $request");
  646:         alarm(0);
  647:     };
  648:     if ($@=~/timeout/) { 
  649:        $answer='';
  650:        &logthis(
  651:         "<font color=red>CRITICAL: Timeout $conserver: $request</font>");
  652:     }  
  653:     $SIG{ALRM}='DEFAULT';
  654:     $SIG{__DIE__}=\&catchexception;
  655: 
  656: 
  657:         if ($answer) {
  658: 	   if ($answer =~ /^enc/) {
  659:                my ($cmd,$cmdlength,$encinput)=split(/:/,$answer);
  660:                chomp($encinput);
  661: 	       $answer='';
  662:                for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {
  663:                   $answer.=$cipher->decrypt(
  664:                    pack("H16",substr($encinput,$encidx,16))
  665:                   );
  666: 	       }
  667: 	      $answer=substr($answer,0,$cmdlength);
  668: 	      $answer.="\n";
  669: 	   }
  670:            $outbuffer{$client} .= $answer;
  671:         } else {
  672:            $outbuffer{$client} .= "con_lost\n";
  673:         }
  674: 
  675: # ===================================================== Done processing request
  676:     }
  677:     delete $ready{$client};
  678:     &status("Completed $conserver: $request");
  679: # -------------------------------------------------------------- End non-forker
  680: }
  681: # ---------------------------------------------------------- End make_new_child
  682: }
  683: 
  684: # nonblock($socket) puts socket into nonblocking mode
  685: sub nonblock {
  686:     my $socket = shift;
  687:     my $flags;
  688: 
  689:     
  690:     $flags = fcntl($socket, F_GETFL, 0)
  691:             or die "Can't get flags for socket: $!\n";
  692:     fcntl($socket, F_SETFL, $flags | O_NONBLOCK)
  693:             or die "Can't make socket nonblocking: $!\n";
  694: }
  695: 

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