Annotation of loncom/LondConnection.pm, revision 1.45

1.2       albertel    1: #   This module defines and implements a class that represents
                      2: #   a connection to a lond daemon.
                      3: #
1.45    ! albertel    4: # $Id: LondConnection.pm,v 1.44 2007/03/28 20:28:29 albertel Exp $
1.2       albertel    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
1.1       foxr       27: #
1.14      foxr       28: 
1.1       foxr       29: package LondConnection;
                     30: 
1.10      foxr       31: use strict;
1.1       foxr       32: use IO::Socket;
                     33: use IO::Socket::INET;
                     34: use IO::Handle;
                     35: use IO::File;
                     36: use Fcntl;
                     37: use POSIX;
                     38: use Crypt::IDEA;
1.31      foxr       39: use LONCAPA::lonlocal;
                     40: use LONCAPA::lonssl;
1.14      foxr       41: 
1.1       foxr       42: 
1.12      foxr       43: 
                     44: 
1.32      foxr       45: my $DebugLevel=0;
1.12      foxr       46: my %perlvar;
1.31      foxr       47: my $InsecureOk;
1.1       foxr       48: 
1.14      foxr       49: #
1.16      foxr       50: #  Set debugging level
                     51: #
                     52: sub SetDebug {
                     53:     $DebugLevel = shift;
                     54: }
                     55: 
                     56: #
1.14      foxr       57: #   The config read is done in this way to support the read of
                     58: #   the non-default configuration file in the
                     59: #   event we are being used outside of loncapa.
                     60: #
                     61: 
                     62: my $ConfigRead = 0;
                     63: 
1.1       foxr       64: #   Read the configuration file for apache to get the perl
1.31      foxr       65: #   variables set.
1.1       foxr       66: 
1.12      foxr       67: sub ReadConfig {
1.31      foxr       68:     Debug(8, "ReadConfig called");
                     69: 
1.14      foxr       70:     my $perlvarref = read_conf('loncapa.conf');
1.12      foxr       71:     %perlvar    = %{$perlvarref};
1.17      foxr       72:     $ConfigRead = 1;
1.12      foxr       73:     
1.31      foxr       74:     $InsecureOk = $perlvar{loncAllowInsecure};
1.15      foxr       75: }
1.1       foxr       76: 
                     77: sub Debug {
1.30      foxr       78: 
                     79:     my ($level, $message) = @_;
                     80: 
1.1       foxr       81:     if ($level < $DebugLevel) {
1.31      foxr       82: 	print STDERR ($message."\n");
1.1       foxr       83:     }
                     84: }
1.3       albertel   85: 
                     86: =pod
                     87: 
                     88: =head2 Dump
                     89: 
1.12      foxr       90: Dump the internal state of the object: For debugging purposes, to stderr.
1.3       albertel   91: 
1.1       foxr       92: =cut
                     93: 
                     94: sub Dump {
                     95:     my $self   = shift;
1.32      foxr       96:     my $level  = shift;
1.35      foxr       97:     my $now    = time;
                     98:     my $local  = localtime($now);
1.32      foxr       99:     
1.37      albertel  100:     if ($level >= $DebugLevel) {
1.32      foxr      101: 	return;
                    102:     }
                    103: 
1.35      foxr      104:     
1.10      foxr      105:     my $key;
                    106:     my $value;
1.35      foxr      107:     print STDERR "[ $local ] Dumping LondConnectionObject:\n";
1.37      albertel  108:     print STDERR join(':',caller(1))."\n";
1.1       foxr      109:     while(($key, $value) = each %$self) {
1.22      foxr      110: 	print STDERR "$key -> $value\n";
1.1       foxr      111:     }
1.23      foxr      112:     print STDERR "-------------------------------\n";
1.1       foxr      113: }
                    114: 
                    115: =pod
1.3       albertel  116: 
                    117: Local function to do a state transition.  If the state transition
                    118: callback is defined it is called with two parameters: the self and the
                    119: old state.
                    120: 
1.1       foxr      121: =cut
1.3       albertel  122: 
1.1       foxr      123: sub Transition {
1.30      foxr      124: 
                    125:     my ($self, $newstate) = @_;
                    126: 
1.1       foxr      127:     my $oldstate = $self->{State};
                    128:     $self->{State} = $newstate;
                    129:     $self->{TimeoutRemaining} = $self->{TimeoutValue};
                    130:     if($self->{TransitionCallback}) {
                    131: 	($self->{TransitionCallback})->($self, $oldstate); 
                    132:     }
                    133: }
                    134: 
1.3       albertel  135: 
1.14      foxr      136: 
1.1       foxr      137: =pod
1.3       albertel  138: 
                    139: =head2 new
                    140: 
                    141: Construct a new lond connection.
                    142: 
                    143: Parameters (besides the class name) include:
                    144: 
                    145: =item hostname
                    146: 
                    147: host the remote lond is on. This host is a host in the hosts.tab file
                    148: 
                    149: =item port
                    150: 
                    151:  port number the remote lond is listening on.
                    152: 
1.1       foxr      153: =cut
1.3       albertel  154: 
1.1       foxr      155: sub new {
1.44      albertel  156:     my ($class, $DnsName, $Port, $lonid) = @_;
1.14      foxr      157: 
                    158:     if (!$ConfigRead) {
                    159: 	ReadConfig();
                    160: 	$ConfigRead = 1;
                    161:     }
1.45    ! albertel  162:     &Debug(4,$class."::new( ".$DnsName.",".$Port.",".$lonid.")\n");
1.1       foxr      163: 
                    164:     # The host must map to an entry in the hosts table:
                    165:     #  We connect to the dns host that corresponds to that
                    166:     #  system and use the hostname for the encryption key 
                    167:     #  negotion.  In the objec these become the Host and
                    168:     #  LoncapaHim fields of the object respectively.
                    169:     #
1.36      albertel  170:     # if it is me use loopback for connection
1.44      albertel  171:     if ($DnsName eq &main::my_hostname()) { $DnsName="127.0.0.1"; }
                    172:     Debug(9, "Connecting to $DnsName");
1.1       foxr      173:     # Now create the object...
                    174:     my $self     = { Host               => $DnsName,
1.44      albertel  175:                      LoncapaHim         => $lonid,
1.24      foxr      176:                      Port               => $Port,
                    177:                      State              => "Initialized",
1.31      foxr      178: 		     AuthenticationMode => "",
1.24      foxr      179:                      TransactionRequest => "",
                    180:                      TransactionReply   => "",
1.39      albertel  181:                      NextRequest        => "",
1.24      foxr      182:                      InformReadable     => 0,
                    183:                      InformWritable     => 0,
                    184:                      TimeoutCallback    => undef,
                    185:                      TransitionCallback => undef,
                    186:                      Timeoutable        => 0,
1.44      albertel  187:                      TimeoutValue       => 3,
1.24      foxr      188:                      TimeoutRemaining   => 0,
1.31      foxr      189: 		     LocalKeyFile       => "",
1.24      foxr      190:                      CipherKey          => "",
                    191:                      LondVersion        => "Unknown",
                    192:                      Cipher             => undef};
1.1       foxr      193:     bless($self, $class);
                    194:     unless ($self->{Socket} = IO::Socket::INET->new(PeerHost => $self->{Host},
1.27      foxr      195: 					       PeerPort => $self->{Port},
                    196: 					       Type     => SOCK_STREAM,
                    197: 					       Proto    => "tcp",
                    198: 					       Timeout  => 3)) {
1.36      albertel  199: 	Debug(8, "Error? \n$@ \n$!");
1.1       foxr      200: 	return undef;		# Inidicates the socket could not be made.
                    201:     }
1.31      foxr      202:     my $socket = $self->{Socket}; # For local use only.
1.33      foxr      203:     #  If we are local, we'll first try local auth mode, otherwise, we'll try
                    204:     #  the ssl auth mode:
1.31      foxr      205: 
                    206:     my $key;
                    207:     my $keyfile;
1.36      albertel  208:     if ($DnsName eq '127.0.0.1') {
1.31      foxr      209: 	$self->{AuthenticationMode} = "local";
                    210: 	($key, $keyfile)         = lonlocal::CreateKeyFile();
                    211: 	Debug(8, "Local key: $key, stored in $keyfile");
                    212: 	   
                    213: 	#  If I can't make the key file fall back to insecure if 
                    214: 	#  allowed...else give up right away.
                    215: 
                    216: 	if(!(defined $key) || !(defined $keyfile)) {
                    217: 	    if($InsecureOk) {
                    218: 		$self->{AuthenticationMode} = "insecure";
                    219: 		$self->{TransactionRequest} = "init\n";
                    220: 	    } 
                    221: 	    else {
                    222: 		$socket->close;
                    223: 		return undef;
                    224: 	    }
                    225: 	}
                    226: 	$self->{TransactionRequest} = "init:local:$keyfile\n";
                    227: 	Debug(9, "Init string is init:local:$keyfile");
                    228: 	if(!$self->CreateCipher($key)) { # Nothing's going our way...
                    229: 	    $socket->close;
                    230: 	    return undef;
                    231: 	}
                    232: 
1.42      albertel  233:     } else {
1.33      foxr      234: 	#  Remote peer:  I'd like to do ssl, but if my host key or certificates
                    235: 	#  are not all installed, my only choice is insecure, if that's 
                    236: 	#  allowed:
                    237: 
                    238: 	my ($ca, $cert) = lonssl::CertificateFile;
                    239: 	my $sslkeyfile  = lonssl::KeyFile;
                    240: 
                    241: 	if((defined $ca)  && (defined $cert) && (defined $sslkeyfile)) {
                    242: 
                    243: 	    $self->{AuthenticationMode} = "ssl";
                    244: 	    $self->{TransactionRequest} = "init:ssl\n";
                    245: 	} else {
                    246: 	    if($InsecureOk) {		# Allowed to do insecure:
                    247: 		$self->{AuthenticationMode} = "insecure";
                    248: 		$self->{TransactionRequest} = "init\n";
                    249: 	    }
                    250: 	    else {		# Not allowed to do insecure...
                    251: 		$socket->close;
                    252: 		return undef;
                    253: 	    }
                    254: 	}
1.31      foxr      255:     }
                    256: 
1.1       foxr      257:     #
                    258:     # We're connected.  Set the state, and the events we'll accept:
                    259:     #
                    260:     $self->Transition("Connected");
                    261:     $self->{InformWritable}     = 1;    # When  socket is writable we send init
1.9       foxr      262:     $self->{Timeoutable}        = 1;    # Timeout allowed during startup negotiation. 
1.31      foxr      263: 
1.1       foxr      264:     
                    265:     #
                    266:     # Set socket to nonblocking I/O.
                    267:     #
1.31      foxr      268:     my $flags    = fcntl($socket, F_GETFL,0);
                    269:     if(!$flags) {
1.1       foxr      270: 	$socket->close;
                    271: 	return undef;
                    272:     }
1.31      foxr      273:     if(!fcntl($socket, F_SETFL, $flags | O_NONBLOCK)) {
1.1       foxr      274: 	$socket->close;
                    275: 	return undef;
                    276:     }
                    277: 
                    278:     # return the object :
                    279: 
1.31      foxr      280:     Debug(9, "Initial object state: ");
1.32      foxr      281:     $self->Dump(9);
1.31      foxr      282: 
1.1       foxr      283:     return $self;
                    284: }
1.3       albertel  285: 
1.1       foxr      286: =pod
1.3       albertel  287: 
                    288: =head2 Readable
                    289: 
                    290: This member should be called when the Socket becomes readable.  Until
                    291: the read completes, action is state independet. Data are accepted into
                    292: the TransactionReply until a newline character is received.  At that
                    293: time actionis state dependent:
                    294: 
                    295: =item Connected
                    296: 
                    297: in this case we received challenge, the state changes to
                    298: ChallengeReceived, and we initiate a send with the challenge response.
                    299: 
                    300: =item ReceivingReply
                    301: 
                    302: In this case a reply has been received for a transaction, the state
                    303: goes to Idle and we disable write and read notification.
                    304: 
                    305: =item ChallengeReeived
                    306: 
                    307: we just got what should be an ok\n and the connection can now handle
                    308: transactions.
1.1       foxr      309: 
                    310: =cut
1.3       albertel  311: 
1.1       foxr      312: sub Readable {
                    313:     my $self    = shift;
                    314:     my $socket  = $self->{Socket};
                    315:     my $data    = '';
1.27      foxr      316:     my $rv;
1.31      foxr      317:     my $ConnectionMode = $self->{AuthenticationMode};
                    318: 
1.27      foxr      319:     if ($socket) {
                    320: 	eval {
                    321: 	    $rv = $socket->recv($data, POSIX::BUFSIZ, 0);
                    322: 	}
                    323:     } else {
                    324: 	$self->Transition("Disconnected");
                    325: 	return -1;
                    326:     }
1.1       foxr      327:     my $errno   = $! + 0;	             # Force numeric context.
                    328: 
1.8       foxr      329:     unless (defined($rv) && length $data) {# Read failed,
1.1       foxr      330: 	if(($errno == POSIX::EWOULDBLOCK)   ||
                    331: 	   ($errno == POSIX::EAGAIN)        ||
1.8       foxr      332: 	   ($errno == POSIX::EINTR)) {
1.1       foxr      333: 	    return 0;
                    334: 	}
                    335: 
                    336: 	# Connection likely lost.
                    337: 	&Debug(4, "Connection lost");
                    338: 	$self->{TransactionRequest} = '';
                    339: 	$socket->close();
                    340: 	$self->Transition("Disconnected");
                    341: 	return -1;
                    342:     }
                    343:     #  Append the data to the buffer.  And figure out if the read is done:
                    344: 
                    345:     &Debug(9,"Received from host: ".$data);
                    346:     $self->{TransactionReply} .= $data;
1.29      albertel  347:     if($self->{TransactionReply} =~ m/\n$/) {
1.1       foxr      348: 	&Debug(8,"Readable End of line detected");
1.31      foxr      349: 	
                    350: 
1.1       foxr      351: 	if ($self->{State}  eq "Initialized") { # We received the challenge:
1.31      foxr      352: 	    #   Our init was replied to. What happens next depends both on
                    353: 	    #  the actual init we sent (AuthenticationMode member data)
                    354: 	    #  and the response:
                    355: 	    #     AuthenticationMode == local:
                    356: 	    #       Response ok:   The key has been exchanged and
                    357: 	    #                      the key file destroyed. We can jump
                    358: 	    #                      into setting the host and requesting the
                    359: 	    #                      Later we'll also bypass key exchange.
                    360: 	    #       Response digits: 
                    361: 	    #                      Old style lond. Delete the keyfile.
                    362: 	    #                      If allowed fall back to insecure mode.
                    363: 	    #                      else close connection and fail.
                    364: 	    #       Response other:
                    365: 	    #                      Failed local auth 
                    366: 	    #                      Close connection and fail.
                    367: 	    #
                    368: 	    #    AuthenticationMode == ssl:
                    369: 	    #        Response ok:ssl
                    370: 	    #        Response digits:
                    371: 	    #        Response other:
                    372: 	    #    Authentication mode == insecure
                    373: 	    #        Response digits
                    374: 	    #        Response other:
                    375: 	    
                    376: 	    my $Response = $self->{TransactionReply};
                    377: 	    if($ConnectionMode eq "local") {
                    378: 		if($Response =~ /^ok:local/) { #  Good local auth.
                    379: 		    $self->ToVersionRequest();
                    380: 		    return 0;
                    381: 		}
                    382: 		elsif ($Response =~/^[0-9]+/) {	# Old style lond.
                    383: 		    return $self->CompleteInsecure();
                    384: 
                    385: 		}
                    386: 		else {		                # Complete flop
                    387: 		    &Debug(3, "init:local : unrecognized reply");
                    388: 		    $self->Transition("Disconnected");
                    389: 		    $socket->close;
                    390: 		    return -1;
                    391: 		}
                    392: 	    }
                    393: 	    elsif ($ConnectionMode eq "ssl") {
                    394: 		if($Response =~ /^ok:ssl/) {     # Good ssl...
                    395: 		    if($self->ExchangeKeysViaSSL()) { # Success skip to vsn stuff
                    396: 			# Need to reset to non blocking:
                    397: 
                    398: 			my $flags = fcntl($socket, F_GETFL, 0);
                    399: 			fcntl($socket, F_SETFL, $flags | O_NONBLOCK);
                    400: 			$self->ToVersionRequest();
                    401: 			return 0;
                    402: 		    }
                    403: 		    else {	         # Failed in ssl exchange.
                    404: 			&Debug(3,"init:ssl failed key negotiation!");
                    405: 			$self->Transition("Disconnected");
                    406: 			$socket->close;
                    407: 			return -1;
                    408: 		    }
                    409: 		} 
                    410: 		elsif ($Response =~ /^[0-9]+/) { # Old style lond.
                    411: 		    return $self->CompleteInsecure();
                    412: 		}
                    413: 		else {		                 # Complete flop
                    414: 		}
                    415: 	    }
                    416: 	    elsif ($ConnectionMode eq "insecure") {
                    417: 		if($self->{TransactionReply} eq "refused\n") {	# Remote doesn't have
                    418: 		    
                    419: 		    $self->Transition("Disconnected"); # in host tables.
                    420: 		    $socket->close();
                    421: 		    return -1;
                    422: 
                    423: 		}
                    424: 		return $self->CompleteInsecure();
                    425: 	    }
                    426: 	    else {
                    427: 		&Debug(1,"Authentication mode incorrect");
                    428: 		die "BUG!!! LondConnection::Readable invalid authmode";
1.1       foxr      429: 	    }
1.27      foxr      430: 
1.31      foxr      431: 
1.28      albertel  432: 	}  elsif ($self->{State} eq "ChallengeReplied") {
                    433: 	    if($self->{TransactionReply} ne "ok\n") {
                    434: 		$self->Transition("Disconnected");
                    435: 		$socket->close();
                    436: 		return -1;
                    437: 	    }
1.31      foxr      438: 	    $self->ToVersionRequest();
1.28      albertel  439: 	    return 0;
1.31      foxr      440: 
1.28      albertel  441: 	} elsif ($self->{State} eq "ReadingVersionString") {
1.38      albertel  442: 	    chomp($self->{TransactionReply});
                    443: 	    $self->{LondVersion}       = $self->{TransactionReply};
1.28      albertel  444: 	    $self->Transition("SetHost");
                    445: 	    $self->{InformReadable}    = 0;
                    446: 	    $self->{InformWritable}    = 1;
                    447: 	    my $peer = $self->{LoncapaHim};
                    448: 	    $self->{TransactionRequest}= "sethost:$peer\n";
                    449: 	    return 0;
1.24      foxr      450: 	} elsif ($self->{State} eq "HostSet") { # should be ok.
1.28      albertel  451: 	    if($self->{TransactionReply} ne "ok\n") {
                    452: 		$self->Transition("Disconnected");
                    453: 		$socket->close();
                    454: 		return -1;
                    455: 	    }
1.31      foxr      456: 	    #  If the auth mode is insecure we must still
                    457: 	    #  exchange session keys. Otherwise,
                    458: 	    #  we can just transition to idle.
                    459: 
                    460: 	    if($ConnectionMode eq "insecure") {
                    461: 		$self->Transition("RequestingKey");
                    462: 		$self->{InformReadable}  = 0;
                    463: 		$self->{InformWritable}  = 1;
                    464: 		$self->{TransactionRequest} = "ekey\n";
                    465: 		return 0;
                    466: 	    }
                    467: 	    else {
                    468: 		$self->ToIdle();
                    469: 		return 0;
                    470: 	    }
1.1       foxr      471: 	} elsif ($self->{State}  eq "ReceivingKey") {
                    472: 	    my $buildkey = $self->{TransactionReply};
                    473: 	    my $key = $self->{LoncapaHim}.$perlvar{'lonHostID'};
                    474: 	    $key=~tr/a-z/A-Z/;
                    475: 	    $key=~tr/G-P/0-9/;
                    476: 	    $key=~tr/Q-Z/0-9/;
1.31      foxr      477: 	    $key =$key.$buildkey.$key.$buildkey.$key.$buildkey;
                    478: 	    $key               = substr($key,0,32);
                    479: 	    if(!$self->CreateCipher($key)) {
1.1       foxr      480: 		$self->Transition("Disconnected");
                    481: 		$socket->close();
                    482: 		return -1;
                    483: 	    } else {
1.31      foxr      484: 		$self->ToIdle();
1.1       foxr      485: 		return 0;
                    486: 	    }
                    487: 	} elsif ($self->{State}  eq "ReceivingReply") {
                    488: 
                    489: 	    # If the data are encrypted, decrypt first.
                    490: 
                    491: 	    my $answer = $self->{TransactionReply};
                    492: 	    if($answer =~ /^enc\:/) {
                    493: 		$answer = $self->Decrypt($answer);
1.34      foxr      494: 		$self->{TransactionReply} = "$answer\n";
1.1       foxr      495: 	    }
1.39      albertel  496: 	    # if we have a NextRequest do it immeadiately
                    497: 	    if ($self->{NextRequest}) {
                    498: 		$self->{TransactionRequest} = $self->{NextRequest};
                    499: 		undef( $self->{NextRequest} );
                    500: 		$self->{TransactionReply}   = "";
                    501: 		$self->{InformWritable}     = 1;
                    502: 		$self->{InformReadable}     = 0;
                    503: 		$self->{Timeoutable}        = 1;
                    504: 		$self->{TimeoutRemaining}   = $self->{TimeoutValue};
                    505: 		$self->Transition("SendingRequest");
                    506: 		return 0;
                    507: 	    } else {
1.1       foxr      508: 	    # finish the transaction
                    509: 
1.39      albertel  510: 		$self->ToIdle();
                    511: 		return 0;
                    512: 	    }
1.1       foxr      513: 	} elsif ($self->{State} eq "Disconnected") { # No connection.
                    514: 	    return -1;
                    515: 	} else {			# Internal error: Invalid state.
                    516: 	    $self->Transition("Disconnected");
                    517: 	    $socket->close();
                    518: 	    return -1;
                    519: 	}
                    520:     }
                    521: 
                    522:     return 0;
1.27      foxr      523:     
1.1       foxr      524: }
                    525: 
                    526: 
                    527: =pod
1.3       albertel  528: 
                    529: This member should be called when the Socket becomes writable.
                    530: 
                    531: The action is state independent. An attempt is made to drain the
                    532: contents of the TransactionRequest member.  Once this is drained, we
                    533: mark the object as waiting for readability.
1.1       foxr      534: 
                    535: Returns  0 if successful, or -1 if not.
1.3       albertel  536: 
1.1       foxr      537: =cut
                    538: sub Writable {
                    539:     my $self     = shift;		# Get reference to the object.
                    540:     my $socket   = $self->{Socket};
1.26      albertel  541:     my $nwritten;
                    542:     if ($socket) {
                    543: 	eval {
                    544: 	    $nwritten = $socket->send($self->{TransactionRequest}, 0);
                    545: 	}
1.27      foxr      546:     } else {
                    547: 	# For whatever reason, there's no longer a socket left.
                    548: 
                    549: 
                    550: 	$self->Transition("Disconnected");
                    551: 	return -1;
1.26      albertel  552:     }
1.1       foxr      553:     my $errno    = $! + 0;
                    554:     unless (defined $nwritten) {
                    555: 	if($errno != POSIX::EINTR) {
                    556: 	    $self->Transition("Disconnected");
                    557: 	    return -1;
                    558: 	}
                    559:       
                    560:     }
1.10      foxr      561:     if (($nwritten >= 0)                        ||
1.1       foxr      562:         ($errno == POSIX::EWOULDBLOCK)    ||
                    563: 	($errno == POSIX::EAGAIN)         ||
                    564: 	($errno == POSIX::EINTR)          ||
                    565: 	($errno ==  0)) {
                    566: 	substr($self->{TransactionRequest}, 0, $nwritten) = ""; # rmv written part
1.27      foxr      567:       if(length $self->{TransactionRequest} == 0) {
                    568:          $self->{InformWritable} = 0;
                    569:          $self->{InformReadable} = 1;
                    570:          $self->{TransactionReply} = '';
                    571:          #
                    572:          # Figure out the next state:
                    573:          #
                    574:          if($self->{State} eq "Connected") {
                    575:             $self->Transition("Initialized");
                    576:          } elsif($self->{State} eq "ChallengeReceived") {
                    577:             $self->Transition("ChallengeReplied");
                    578:          } elsif($self->{State} eq "RequestingVersion") {
                    579:             $self->Transition("ReadingVersionString");
                    580:          } elsif ($self->{State} eq "SetHost") {
                    581:             $self->Transition("HostSet");
                    582:          } elsif($self->{State} eq "RequestingKey") {
                    583:             $self->Transition("ReceivingKey");
1.24      foxr      584: #            $self->{InformWritable} = 0;
                    585: #            $self->{InformReadable} = 1;
                    586: #            $self->{TransactionReply} = '';
1.27      foxr      587:          } elsif ($self->{State} eq "SendingRequest") {
                    588:             $self->Transition("ReceivingReply");
                    589:             $self->{TimeoutRemaining} = $self->{TimeoutValue};
                    590:          } elsif ($self->{State} eq "Disconnected") {
                    591:             return -1;
                    592:          }
                    593:          return 0;
                    594:       }
                    595:    } else {			# The write failed (e.g. partner disconnected).
                    596:       $self->Transition("Disconnected");
                    597:       $socket->close();
                    598:       return -1;
                    599:    }
                    600: 	
1.1       foxr      601: }
                    602: =pod
1.3       albertel  603: 
                    604: =head2 Tick
                    605: 
1.1       foxr      606:    Tick is called every time unit by the event framework.  It
1.3       albertel  607: 
                    608: =item 1 decrements the remaining timeout.
                    609: 
                    610: =item 2 If the timeout is zero, calls TimedOut indicating that the current operation timed out.
1.1       foxr      611: 
                    612: =cut
                    613:     
                    614: sub Tick {
                    615:     my $self = shift;
                    616:     $self->{TimeoutRemaining}--;
                    617:     if ($self->{TimeoutRemaining} < 0) {
                    618: 	$self->TimedOut();
                    619:     }
                    620: }
1.3       albertel  621: 
1.1       foxr      622: =pod
                    623: 
1.3       albertel  624: =head2 TimedOut
                    625: 
                    626: called on a timeout.  If the timeout callback is defined, it is called
                    627: with $self as its parameters.
                    628: 
                    629: =cut
                    630: 
1.1       foxr      631: sub TimedOut  {
                    632: 
                    633:     my $self = shift;
                    634:     if($self->{TimeoutCallback}) {
                    635: 	my $callback = $self->{TimeoutCallback};
                    636: 	my @args = ( $self);
                    637: 	&$callback(@args);
                    638:     }
                    639: }
1.3       albertel  640: 
1.1       foxr      641: =pod
1.3       albertel  642: 
                    643: =head2 InitiateTransaction
                    644: 
                    645: Called to initiate a transaction.  A transaction can only be initiated
                    646: when the object is idle... otherwise an error is returned.  A
                    647: transaction consists of a request to the server that will have a
                    648: reply.  This member sets the request data in the TransactionRequest
                    649: member, makes the state SendingRequest and sets the data to allow a
                    650: timout, and to request writability notification.
                    651: 
1.1       foxr      652: =cut
1.3       albertel  653: 
1.1       foxr      654: sub InitiateTransaction {
1.30      foxr      655: 
                    656:     my ($self, $data) = @_;
1.1       foxr      657: 
1.4       foxr      658:     Debug(1, "initiating transaction: ".$data);
1.1       foxr      659:     if($self->{State} ne "Idle") {
1.4       foxr      660: 	Debug(0," .. but not idle here\n");
1.1       foxr      661: 	return -1;		# Error indicator.
                    662:     }
                    663:     # if the transaction is to be encrypted encrypt the data:
1.39      albertel  664:     (my $sethost, my $server,$data)=split(/:/,$data,3);
1.1       foxr      665: 
                    666:     if($data =~ /^encrypt\:/) {
                    667: 	$data = $self->Encrypt($data);
                    668:     }
                    669: 
                    670:     # Setup the trasaction
1.39      albertel  671:     # currently no version of lond supports inlining the sethost
1.40      albertel  672:     if ($self->PeerVersion() <= 321) {
1.39      albertel  673: 	if ($server ne $self->{LoncapaHim}) {
                    674: 	    $self->{NextRequest}        = $data;
                    675: 	    $self->{TransactionRequest} = "$sethost:$server\n";
                    676: 	    $self->{LoncapaHim}         = $server;
                    677: 	} else {
                    678: 	    $self->{TransactionRequest}        = $data;
                    679: 	}
                    680:     } else {
1.40      albertel  681: 	$self->{LoncapaHim}         = $server;
1.39      albertel  682: 	$self->{TransactionRequest} = "$sethost:$server:$data";
                    683:     }
1.1       foxr      684:     $self->{TransactionReply}   = "";
                    685:     $self->{InformWritable}     = 1;
                    686:     $self->{InformReadable}     = 0;
                    687:     $self->{Timeoutable}        = 1;
                    688:     $self->{TimeoutRemaining}   = $self->{TimeoutValue};
                    689:     $self->Transition("SendingRequest");
                    690: }
                    691: 
                    692: 
                    693: =pod
1.3       albertel  694: 
                    695: =head2 SetStateTransitionCallback
                    696: 
                    697: Sets a callback for state transitions.  Returns a reference to any
                    698: prior established callback, or undef if there was none:
                    699: 
1.1       foxr      700: =cut
1.3       albertel  701: 
1.1       foxr      702: sub SetStateTransitionCallback {
                    703:     my $self        = shift;
                    704:     my $oldCallback = $self->{TransitionCallback};
                    705:     $self->{TransitionCallback} = shift;
                    706:     return $oldCallback;
                    707: }
1.3       albertel  708: 
1.1       foxr      709: =pod
1.3       albertel  710: 
                    711: =head2 SetTimeoutCallback
                    712: 
                    713: Sets the timeout callback.  Returns a reference to any prior
                    714: established callback or undef if there was none.
                    715: 
1.1       foxr      716: =cut
1.3       albertel  717: 
1.1       foxr      718: sub SetTimeoutCallback {
1.30      foxr      719: 
                    720:     my ($self, $callback) = @_;
                    721: 
1.1       foxr      722:     my $oldCallback          = $self->{TimeoutCallback};
                    723:     $self->{TimeoutCallback} = $callback;
                    724:     return $oldCallback;
                    725: }
                    726: 
                    727: =pod
1.3       albertel  728: 
1.5       foxr      729: =head2 Shutdown:
                    730: 
                    731: Shuts down the socket.
                    732: 
                    733: =cut
                    734: 
                    735: sub Shutdown {
                    736:     my $self = shift;
                    737:     my $socket = $self->GetSocket();
1.20      albertel  738:     Debug(5,"socket is -$socket-");
                    739:     if ($socket) {
                    740: 	# Ask lond to exit too.  Non blocking so
                    741: 	# there is no cost for failure.
                    742: 	eval {
                    743: 	    $socket->send("exit\n", 0);
                    744: 	    $socket->shutdown(2);
                    745: 	}
                    746:     }
1.5       foxr      747: }
                    748: 
                    749: =pod
                    750: 
1.3       albertel  751: =head2 GetState
                    752: 
                    753: selector for the object state.
                    754: 
1.1       foxr      755: =cut
1.3       albertel  756: 
1.1       foxr      757: sub GetState {
                    758:     my $self = shift;
                    759:     return $self->{State};
                    760: }
1.3       albertel  761: 
1.1       foxr      762: =pod
1.3       albertel  763: 
                    764: =head2 GetSocket
                    765: 
                    766: selector for the object socket.
                    767: 
1.1       foxr      768: =cut
1.3       albertel  769: 
1.1       foxr      770: sub GetSocket {
                    771:     my $self  = shift;
                    772:     return $self->{Socket};
                    773: }
1.3       albertel  774: 
1.5       foxr      775: 
1.1       foxr      776: =pod
1.3       albertel  777: 
                    778: =head2 WantReadable
                    779: 
                    780: Return the state of the flag that indicates the object wants to be
                    781: called when readable.
                    782: 
1.1       foxr      783: =cut
1.3       albertel  784: 
1.1       foxr      785: sub WantReadable {
                    786:     my   $self = shift;
                    787: 
                    788:     return $self->{InformReadable};
                    789: }
1.3       albertel  790: 
1.1       foxr      791: =pod
1.3       albertel  792: 
                    793: =head2 WantWritable
                    794: 
                    795: Return the state of the flag that indicates the object wants write
                    796: notification.
                    797: 
1.1       foxr      798: =cut
1.3       albertel  799: 
1.1       foxr      800: sub WantWritable {
                    801:     my $self = shift;
                    802:     return $self->{InformWritable};
                    803: }
1.3       albertel  804: 
1.1       foxr      805: =pod
1.3       albertel  806: 
                    807: =head2 WantTimeout
                    808: 
                    809: return the state of the flag that indicates the object wants to be
                    810: informed of timeouts.
                    811: 
1.1       foxr      812: =cut
1.3       albertel  813: 
1.1       foxr      814: sub WantTimeout {
                    815:     my $self = shift;
                    816:     return $self->{Timeoutable};
                    817: }
                    818: 
                    819: =pod
1.3       albertel  820: 
                    821: =head2 GetReply
                    822: 
                    823: Returns the reply from the last transaction.
                    824: 
1.1       foxr      825: =cut
1.3       albertel  826: 
1.1       foxr      827: sub GetReply {
                    828:     my $self = shift;
                    829:     return $self->{TransactionReply};
                    830: }
                    831: 
                    832: =pod
1.3       albertel  833: 
                    834: =head2 Encrypt
                    835: 
                    836: Returns the encrypted version of the command string.
                    837: 
                    838: The command input string is of the form:
                    839: 
1.1       foxr      840:   encrypt:command
1.3       albertel  841: 
                    842: The output string can be directly sent to lond as it is of the form:
                    843: 
1.1       foxr      844:   enc:length:<encodedrequest>
1.3       albertel  845: 
1.1       foxr      846: =cut
1.3       albertel  847: 
1.1       foxr      848: sub Encrypt {
1.30      foxr      849:     
                    850:     my ($self, $request) = @_;
1.1       foxr      851: 
                    852:    
                    853:     # Split the encrypt: off the request and figure out it's length.
                    854:     # the cipher works in blocks of 8 bytes.
                    855: 
                    856:     my $cmd = $request;
                    857:     $cmd    =~ s/^encrypt\://;	# strip off encrypt:
                    858:     chomp($cmd);		# strip off trailing \n
                    859:     my     $length=length($cmd);	# Get the string length.
                    860:     $cmd .= "         ";	# Pad with blanks so we can fill out a block.
                    861: 
                    862:     # encrypt the request in 8 byte chunks to create the encrypted
                    863:     # output request.
                    864: 
                    865:     my $Encoded = '';
                    866:     for(my $index = 0; $index <= $length; $index += 8) {
                    867: 	$Encoded .= 
                    868: 	    unpack("H16", 
                    869: 		   $self->{Cipher}->encrypt(substr($cmd, 
                    870: 						   $index, 8)));
                    871:     }
                    872: 
                    873:     # Build up the answer as enc:length:$encrequest.
                    874: 
                    875:     $request = "enc:$length:$Encoded\n";
                    876:     return $request;
                    877:     
                    878:     
                    879: }
1.3       albertel  880: 
                    881: =pod
                    882: 
                    883: =head2 Decrypt
                    884: 
                    885: Decrypt a response from the server.  The response is in the form:
                    886: 
                    887:  enc:<length>:<encrypted data>
                    888: 
1.1       foxr      889: =cut
1.3       albertel  890: 
1.1       foxr      891: sub Decrypt {
1.30      foxr      892: 
                    893:     my ($self, $encrypted) = @_;
1.1       foxr      894: 
                    895:     #  Bust up the response into length, and encryptedstring:
                    896: 
                    897:     my ($enc, $length, $EncryptedString) = split(/:/,$encrypted);
                    898:     chomp($EncryptedString);
                    899: 
                    900:     # Decode the data in 8 byte blocks.  The string is encoded
                    901:     # as hex digits so there are two characters per byte:
                    902: 
1.10      foxr      903:     my $decrypted = "";
1.1       foxr      904:     for(my $index = 0; $index < length($EncryptedString);
                    905: 	$index += 16) {
                    906: 	$decrypted .= $self->{Cipher}->decrypt(
                    907: 				    pack("H16",
                    908: 					 substr($EncryptedString,
                    909: 						$index, 
                    910: 						16)));
                    911:     }
                    912:     #  the answer may have trailing pads to fill out a block.
                    913:     #  $length tells us the actual length of the decrypted string:
                    914: 
                    915:     $decrypted = substr($decrypted, 0, $length);
1.34      foxr      916:     Debug(9, "Decrypted $EncryptedString to $decrypted");
1.1       foxr      917: 
                    918:     return $decrypted;
                    919: 
                    920: }
1.31      foxr      921: # ToIdle
                    922: #     Called to transition to idle... done enough it's worth subbing
                    923: #     off to ensure it's always done right!!
                    924: #
                    925: sub ToIdle {
                    926:     my $self   = shift;
                    927: 
                    928:     $self->Transition("Idle");
                    929:     $self->{InformWritiable} = 0;
                    930:     $self->{InformReadable}  = 0;
                    931:     $self->{Timeoutable}     = 0;
                    932: }
                    933: 
                    934: #  ToVersionRequest
                    935: #    Called to transition to "RequestVersion"  also done a few times
                    936: #    so worth subbing out.
                    937: #
                    938: sub ToVersionRequest {
                    939:     my $self   = shift;
                    940:     
                    941:     $self->Transition("RequestingVersion");
                    942:     $self->{InformReadable}   = 0;
                    943:     $self->{InformWritable}   = 1;
                    944:     $self->{TransactionRequest} = "version\n";
                    945:     
                    946: }
                    947: #
                    948: #  CreateCipher
                    949: #    Given a cipher key stores the key in the object context,
                    950: #    creates the cipher object, (stores that in object context),
                    951: #    This is done a couple of places, so it's worth factoring it out.
                    952: #
                    953: # Parameters:
                    954: #    (self)
                    955: #    key - The Cipher key.
                    956: #
                    957: # Returns:
                    958: #    0   - Failure to create IDEA cipher.
                    959: #    1   - Success.
                    960: #
                    961: sub CreateCipher {
                    962:     my ($self, $key)   = @_;	# According to coding std.
                    963: 
                    964:     $self->{CipherKey} = $key; # Save the text key...
                    965:     my $packedkey = pack ("H32", $key);
                    966:     my $cipher            = new IDEA $packedkey;
                    967:     if($cipher) {
                    968: 	$self->{Cipher} = $cipher;
                    969: 	Debug("Cipher created  dumping socket: ");
1.32      foxr      970: 	$self->Dump(9);
1.31      foxr      971: 	return 1;
                    972:     }
                    973:     else {
                    974: 	return 0;
                    975:     }
                    976: }
                    977: # ExchangeKeysViaSSL
                    978: #     Called to do cipher key exchange via SSL.
                    979: #     The socket is promoted to an SSL socket. If that's successful,
                    980: #     we read out cipher key through the socket and create an IDEA
                    981: #     cipher object.
                    982: # Parameters:
                    983: #    (self)
                    984: # Returns:
                    985: #      true    - Success.
                    986: #      false   - Failure.
                    987: #
                    988: # Assumptions:
                    989: #  1.   The ssl session setup has timeout logic built in so we don't
                    990: #     have to worry about DOS attacks at that stage.
                    991: #  2.   If the ssl session gets set up we are talking to a legitimate
                    992: #     lond so again we don't have to worry about DOS attacks.
                    993: #  All this allows us just to call 
                    994: sub ExchangeKeysViaSSL {
                    995:     my $self   = shift;
                    996:     my $socket = $self->{Socket};
                    997: 
                    998:     #  Get our signed certificate, the certificate authority's 
                    999:     #  certificate and our private key file.  All of these
                   1000:     #  are needed to create the ssl connection.
                   1001: 
                   1002:     my ($SSLCACertificate,
                   1003: 	$SSLCertificate) = lonssl::CertificateFile();
                   1004:     my $SSLKey             = lonssl::KeyFile();
                   1005: 
                   1006:     #  Promote our connection to ssl and read the key from lond.
                   1007: 
                   1008:     my $SSLSocket = lonssl::PromoteClientSocket($socket,
                   1009: 						$SSLCACertificate,
                   1010: 						$SSLCertificate,
                   1011: 						$SSLKey);
                   1012:     if(defined $SSLSocket) {
                   1013: 	my $key  = <$SSLSocket>;
                   1014: 	lonssl::Close($SSLSocket);
                   1015: 	if($key) {
                   1016: 	    chomp($key);	# \n is not part of the key.
                   1017: 	    return $self->CreateCipher($key);
                   1018: 	} 
                   1019: 	else {
                   1020: 	    Debug(3, "Failed to read ssl key");
                   1021: 	    return 0;
                   1022: 	}
                   1023:     }
                   1024:     else {
                   1025: 	# Failed!!
                   1026: 	Debug(3, "Failed to negotiate SSL connection!");
                   1027: 	return 0;
                   1028:     }
                   1029:     # should not get here
                   1030:     return 0;
                   1031: 
                   1032: }
                   1033: 
                   1034: 
                   1035: 
                   1036: #
                   1037: #  CompleteInsecure:
                   1038: #      This function is called to initiate the completion of
                   1039: #      insecure challenge response negotiation.
                   1040: #      To do this, we copy the challenge string to the transaction
                   1041: #      request, flip to writability and state transition to 
                   1042: #      ChallengeReceived..
                   1043: #      All this is only possible if InsecureOk is true.
                   1044: # Parameters:
                   1045: #      (self)    - This object's context hash.
                   1046: #  Return:
                   1047: #      0   - Ok to transition.
                   1048: #     -1   - Not ok to transition (InsecureOk not ok).
                   1049: #
                   1050: sub CompleteInsecure {
                   1051:     my $self = shift;
                   1052:     if($InsecureOk) {
                   1053: 	$self->{AuthenticationMode} = "insecure";
                   1054: 	&Debug(8," Transition out of Initialized:insecure");
                   1055: 	$self->{TransactionRequest} = $self->{TransactionReply};
                   1056: 	$self->{InformWritable}     = 1;
                   1057: 	$self->{InformReadable}     = 0;
                   1058: 	$self->Transition("ChallengeReceived");
                   1059: 	$self->{TimeoutRemaining}   = $self->{TimeoutValue};
                   1060: 	return 0;
                   1061: 	
                   1062: 	
                   1063:     }
                   1064:     else {
                   1065: 	&Debug(3, "Insecure key negotiation disabled!");
                   1066: 	my $socket = $self->{Socket};
                   1067: 	$socket->close;
                   1068: 	return -1;
                   1069:     }
                   1070: }
1.1       foxr     1071: 
1.14      foxr     1072: ###########################################################
                   1073: #
                   1074: #  The following is an unashamed kludge that is here to
                   1075: # allow LondConnection to be used outside of the
                   1076: # loncapa environment (e.g. by lonManage).
                   1077: # 
                   1078: #   This is a textual inclusion of pieces of the
                   1079: #   Configuration.pm module.
                   1080: #
                   1081: 
                   1082: 
1.43      raeburn  1083: my @confdirs=('/etc/httpd/conf/','/etc/apache2/');
1.14      foxr     1084: 
                   1085: # ------------------- Subroutine read_conf: read LON-CAPA server configuration.
                   1086: # This subroutine reads PerlSetVar values out of specified web server
                   1087: # configuration files.
                   1088: sub read_conf
                   1089:   {
                   1090:     my (@conf_files)=@_;
1.43      raeburn  1091:     my (%perlvar,%configdirs);
                   1092:     foreach my $filename (@conf_files,'loncapa_apache.conf') {
                   1093:         my $configdir = '';
                   1094:         $configdirs{$filename} = [@confdirs];
                   1095:         while ($configdir eq '' && @{$configdirs{$filename}} > 0) {
                   1096:             my $testdir = shift(@{$configdirs{$filename}});
                   1097:             if (-e $testdir.$filename) {
                   1098:                 $configdir = $testdir;
                   1099:             }
                   1100:         }
                   1101:         if ($configdir eq '') {
                   1102:             die("Couldn't find a directory containing $filename");
                   1103:         }
                   1104: 	if($DebugLevel > 3) {
                   1105: 	    print STDERR ("Going to read $configdir.$filename\n");
                   1106: 	}
                   1107: 	open(CONFIG,'<'.$configdir.$filename) or
                   1108: 	    die("Can't read $configdir$filename");
                   1109: 	while (my $configline=<CONFIG>) {
                   1110: 	    if ($configline =~ /^[^\#]*PerlSetVar/) {
                   1111: 	        my ($unused,$varname,$varvalue)=split(/\s+/,$configline);
1.14      foxr     1112: 		chomp($varvalue);
                   1113: 		$perlvar{$varname}=$varvalue;
1.43      raeburn  1114: 	    }
                   1115: 	}
1.14      foxr     1116: 	close(CONFIG);
1.43      raeburn  1117:     }
1.21      foxr     1118:     if($DebugLevel > 3) {
1.31      foxr     1119: 	print STDERR "Dumping perlvar:\n";
1.21      foxr     1120: 	foreach my $var (keys %perlvar) {
1.31      foxr     1121: 	    print STDERR "$var = $perlvar{$var}\n";
1.21      foxr     1122: 	}
                   1123:     }
1.14      foxr     1124:     my $perlvarref=\%perlvar;
1.21      foxr     1125:     return $perlvarref;
                   1126: }
1.14      foxr     1127: 
1.24      foxr     1128: #
                   1129: #   Get the version of our peer.  Note that this is only well
                   1130: #   defined if the state machine has hit the idle state at least
                   1131: #   once (well actually if it has transitioned out of 
                   1132: #   ReadingVersionString   The member data LondVersion is returned.
                   1133: #
                   1134: sub PeerVersion {
                   1135:    my $self = shift;
1.40      albertel 1136:    my ($version) = ($self->{LondVersion} =~ /Revision: 1\.(\d+)/);
                   1137:    return $version;
1.24      foxr     1138: }
1.1       foxr     1139: 
                   1140: 1;
                   1141: 
                   1142: =pod
1.3       albertel 1143: 
1.1       foxr     1144: =head1 Theory
                   1145: 
1.3       albertel 1146: The lond object is a state machine.  It lives through the following states:
                   1147: 
                   1148: =item Connected:
                   1149: 
                   1150: a TCP connection has been formed, but the passkey has not yet been
                   1151: negotiated.
                   1152: 
                   1153: =item Initialized:
                   1154: 
                   1155: "init" sent.
                   1156: 
                   1157: =item ChallengeReceived:
                   1158: 
                   1159: lond sent its challenge to us.
                   1160: 
                   1161: =item ChallengeReplied:
                   1162: 
                   1163: We replied to lond's challenge waiting for lond's ok.
                   1164: 
                   1165: =item RequestingKey:
                   1166: 
                   1167: We are requesting an encryption key.
                   1168: 
                   1169: =item ReceivingKey:
                   1170: 
                   1171: We are receiving an encryption key.
                   1172: 
                   1173: =item Idle:
                   1174: 
                   1175: Connection was negotiated but no requests are active.
                   1176: 
                   1177: =item SendingRequest:
                   1178: 
                   1179: A request is being sent to the peer.
                   1180: 
                   1181: =item ReceivingReply:
                   1182: 
                   1183: Waiting for an entire reply from the peer.
                   1184: 
                   1185: =item Disconnected:
                   1186: 
                   1187: For whatever reason, the connection was dropped.
                   1188: 
                   1189: When we need to be writing data, we have a writable event. When we
                   1190: need to be reading data, a readable event established.  Events
                   1191: dispatch through the class functions Readable and Writable, and the
                   1192: watcher contains a reference to the associated object to allow object
                   1193: context to be reached.
1.1       foxr     1194: 
                   1195: =head2 Member data.
                   1196: 
1.3       albertel 1197: =item Host
                   1198: 
                   1199: Host socket is connected to.
                   1200: 
                   1201: =item Port
                   1202: 
                   1203: The port the remote lond is listening on.
                   1204: 
                   1205: =item Socket
                   1206: 
                   1207: Socket open on the connection.
                   1208: 
                   1209: =item State
                   1210: 
                   1211: The current state.
                   1212: 
1.31      foxr     1213: =item AuthenticationMode
                   1214: 
                   1215: How authentication is being done. This can be any of:
                   1216: 
                   1217:     o local - Authenticate via a key exchanged in a file.
                   1218:     o ssl   - Authenticate via a key exchaned through a temporary ssl tunnel.
                   1219:     o insecure - Exchange keys in an insecure manner.
                   1220: 
                   1221: insecure is only allowed if the configuration parameter loncAllowInsecure 
                   1222: is nonzero.
                   1223: 
1.3       albertel 1224: =item TransactionRequest
                   1225: 
                   1226: The request being transmitted.
                   1227: 
                   1228: =item TransactionReply
                   1229: 
                   1230: The reply being received from the transaction.
                   1231: 
                   1232: =item InformReadable
                   1233: 
                   1234: True if we want to be called when socket is readable.
                   1235: 
                   1236: =item InformWritable
                   1237: 
                   1238: True if we want to be informed if the socket is writable.
                   1239: 
                   1240: =item Timeoutable
                   1241: 
                   1242: True if the current operation is allowed to timeout.
                   1243: 
                   1244: =item TimeoutValue
                   1245: 
                   1246: Number of seconds in the timeout.
                   1247: 
                   1248: =item TimeoutRemaining
                   1249: 
                   1250: Number of seconds left in the timeout.
                   1251: 
                   1252: =item CipherKey
                   1253: 
                   1254: The key that was negotiated with the peer.
                   1255: 
                   1256: =item Cipher
                   1257: 
                   1258: The cipher obtained via the key.
1.1       foxr     1259: 
                   1260: 
                   1261: =head2 The following are callback like members:
1.3       albertel 1262: 
                   1263: =item Tick:
                   1264: 
                   1265: Called in response to a timer tick. Used to managed timeouts etc.
                   1266: 
                   1267: =item Readable:
                   1268: 
                   1269: Called when the socket becomes readable.
                   1270: 
                   1271: =item Writable:
                   1272: 
                   1273: Called when the socket becomes writable.
                   1274: 
                   1275: =item TimedOut:
                   1276: 
                   1277: Called when a timed operation timed out.
                   1278: 
1.1       foxr     1279: 
                   1280: =head2 The following are operational member functions.
1.3       albertel 1281: 
                   1282: =item InitiateTransaction:
                   1283: 
                   1284: Called to initiate a new transaction
                   1285: 
                   1286: =item SetStateTransitionCallback:
                   1287: 
                   1288: Called to establish a function that is called whenever the object goes
                   1289: through a state transition.  This is used by The client to manage the
                   1290: work flow for the object.
                   1291: 
                   1292: =item SetTimeoutCallback:
                   1293: 
                   1294: Set a function to be called when a transaction times out.  The
                   1295: function will be called with the object as its sole parameter.
                   1296: 
                   1297: =item Encrypt:
                   1298: 
                   1299: Encrypts a block of text according to the cipher negotiated with the
                   1300: peer (assumes the text is a command).
                   1301: 
                   1302: =item Decrypt:
                   1303: 
                   1304: Decrypts a block of text according to the cipher negotiated with the
                   1305: peer (assumes the block was a reply.
1.5       foxr     1306: 
                   1307: =item Shutdown:
                   1308: 
                   1309: Shuts off the socket.
1.1       foxr     1310: 
                   1311: =head2 The following are selector member functions:
                   1312: 
1.3       albertel 1313: =item GetState:
                   1314: 
                   1315: Returns the current state
                   1316: 
                   1317: =item GetSocket:
                   1318: 
                   1319: Gets the socekt open on the connection to lond.
                   1320: 
                   1321: =item WantReadable:
                   1322: 
                   1323: true if the current state requires a readable event.
                   1324: 
                   1325: =item WantWritable:
                   1326: 
                   1327: true if the current state requires a writable event.
                   1328: 
                   1329: =item WantTimeout:
                   1330: 
                   1331: true if the current state requires timeout support.
                   1332: 
1.1       foxr     1333: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.