--- loncom/lond 2006/02/02 10:32:31 1.305.2.2 +++ loncom/lond 2006/01/27 23:04:27 1.308 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.305.2.2 2006/02/02 10:32:31 albertel Exp $ +# $Id: lond,v 1.308 2006/01/27 23:04:27 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,15 +53,13 @@ use LONCAPA::ConfigFileEdit; use LONCAPA::lonlocal; use LONCAPA::lonssl; use Fcntl qw(:flock); -use Symbol; my $DEBUG = 0; # Non zero to enable debug log entries. my $status=''; my $lastlog=''; -my $lond_max_wait_time = 13; -my $VERSION='$Revision: 1.305.2.2 $'; #' stupid emacs +my $VERSION='$Revision: 1.308 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -89,6 +87,7 @@ my $ConnectionType; my %hostid; # ID's for hosts in cluster by ip. my %hostdom; # LonCAPA domain for hosts in cluster. +my %hostname; # DNSname -> ID's mapping. my %hostip; # IPs for hosts in cluster. my %hostdns; # ID's of hosts looked up by DNS name. @@ -972,13 +971,23 @@ sub tie_domain_hash { my $user_top_dir = $perlvar{'lonUsersDir'}; my $domain_dir = $user_top_dir."/$domain"; - my $resource_file = $domain_dir."/$namespace"; - return &_locking_hash_tie($resource_file,$namespace,$how,$loghead,$logtail); + my $resource_file = $domain_dir."/$namespace.db"; + my %hash; + if(tie(%hash, 'GDBM_File', $resource_file, $how, 0640)) { + if (defined($loghead)) { # Need to log the operation. + my $logFh = IO::File->new(">>$domain_dir/$namespace.hist"); + if($logFh) { + my $timestamp = time; + print $logFh "$loghead:$timestamp:$logtail\n"; + } + $logFh->close; + } + return \%hash; # Return the tied hash. + } else { + return undef; # Tie failed. + } } -sub untie_domain_hash { - return &_locking_hash_untie(@_); -} # # Ties a user's resource file to a hash. # If necessary, an appropriate history @@ -1004,27 +1013,18 @@ sub tie_user_hash { $namespace=~s/\//\_/g; # / -> _ $namespace=~s/\W//g; # whitespace eliminated. my $proname = propath($domain, $user); - - my $file_prefix="$proname/$namespace"; - return &_locking_hash_tie($file_prefix,$namespace,$how,$loghead,$what); -} - -sub untie_user_hash { - return &_locking_hash_untie(@_); -} - -# internal routines that handle the actual tieing and untieing process - -sub _do_hash_tie { - my ($file_prefix,$namespace,$how,$loghead,$what) = @_; + + # Tie the database. + my %hash; - if(tie(%hash, 'GDBM_File', "$file_prefix.db", $how, 0640)) { + if(tie(%hash, 'GDBM_File', "$proname/$namespace.db", + $how, 0640)) { # If this is a namespace for which a history is kept, # make the history log entry: if (($namespace !~/^nohist\_/) && (defined($loghead))) { my $args = scalar @_; - Debug(" Opening history: $file_prefix $args"); - my $hfh = IO::File->new(">>$file_prefix.hist"); + Debug(" Opening history: $namespace $args"); + my $hfh = IO::File->new(">>$proname/$namespace.hist"); if($hfh) { my $now = time; print $hfh "$loghead:$now:$what\n"; @@ -1035,72 +1035,7 @@ sub _do_hash_tie { } else { return undef; } -} - -sub _do_hash_untie { - my ($hashref) = @_; - my $result = untie(%$hashref); - return $result; -} - -{ - my $sym; - - sub _locking_hash_tie { - my ($file_prefix,$namespace,$how,$loghead,$what) = @_; - - my ($lock); - - if ($how eq &GDBM_READER()) { - $lock=LOCK_SH; - $how=$how|&GDBM_NOLOCK(); - #if the db doesn't exist we can't read from it - if (! -e "$file_prefix.db") { - $! = 2; - return undef; - } - } elsif ($how eq &GDBM_WRCREAT()) { - $lock=LOCK_EX; - $how=$how|&GDBM_NOLOCK(); - if (! -e "$file_prefix.db") { - # doesn't exist but we need it to in order to successfully - # lock it so bring it into existance - open(TOUCH,">>$file_prefix.db"); - close(TOUCH); - } - } else { - &logthis("Unknown method $how for $file_prefix"); - die(); - } - $sym=&Symbol::gensym(); - open($sym,"$file_prefix.db"); - my $failed=0; - eval { - local $SIG{__DIE__}='DEFAULT'; - local $SIG{ALRM}=sub { - $failed=1; - die("failed lock"); - }; - alarm($lond_max_wait_time); - flock($sym,$lock); - alarm(0); - }; - if ($failed) { - $! = 100; # throwing error # 100 - return undef; - } - return &_do_hash_tie($file_prefix,$namespace,$how,$loghead,$what); - } - - sub _locking_hash_untie { - my ($hashref) = @_; - my $result = untie(%$hashref); - flock($sym,LOCK_UN); - close($sym); - undef($sym); - return $result; - } } # read_profile @@ -1133,7 +1068,7 @@ sub read_profile { $qresult.="$hashref->{$queries[$i]}&"; # Presumably failure gives empty string. } $qresult=~s/\&$//; # Remove trailing & from last lookup. - if (&untie_user_hash($hashref)) { + if (untie %$hashref) { return $qresult; } else { return "error: ".($!+0)." untie (GDBM) Failed"; @@ -2442,7 +2377,7 @@ sub put_user_profile_entry { my ($key,$value)=split(/=/,$pair); $hashref->{$key}=$value; } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". @@ -2450,7 +2385,7 @@ sub put_user_profile_entry { $userinput); } } else { - &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + &Failure( $client, "error: ".($!)." tie(GDBM) Failed ". "while attempting put\n", $userinput); } } else { @@ -2486,7 +2421,7 @@ sub newput_user_profile_entry { my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_WRCREAT(),"N",$what); if(!$hashref) { - &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ". + &Failure( $client, "error: ".($!)." tie(GDBM) Failed ". "while attempting put\n", $userinput); return 1; } @@ -2505,7 +2440,7 @@ sub newput_user_profile_entry { $hashref->{$key}=$value; } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". @@ -2558,7 +2493,7 @@ sub increment_user_value_handler { } } } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) failed ". @@ -2625,7 +2560,7 @@ sub roles_put_handler { $auth_type); $hashref->{$key}=$value; } - if (&untie_user_hash($hashref)) { + if (untie($hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -2676,7 +2611,7 @@ sub roles_delete_handler { foreach my $key (@rolekeys) { delete $hashref->{$key}; } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -2817,7 +2752,7 @@ sub delete_profile_entry { foreach my $key (@keys) { delete($hashref->{$key}); } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -2859,7 +2794,7 @@ sub get_profile_keys { foreach my $key (keys %$hashref) { $qresult.="$key&"; } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { $qresult=~s/\&$//; &Reply($client, "$qresult\n", $userinput); } else { @@ -2920,7 +2855,7 @@ sub dump_profile_database { $data{$symb}->{$param}=$value; $data{$symb}->{'v.'.$param}=$v; } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { while (my ($symb,$param_hash) = each(%data)) { while(my ($param,$value) = each (%$param_hash)){ next if ($param =~ /^v\./); # Ignore versions... @@ -2975,27 +2910,44 @@ sub dump_with_regexp { my $userinput = "$cmd:$tail"; - my ($udom,$uname,$namespace,$regexp)=split(/:/,$tail); + my ($udom,$uname,$namespace,$regexp,$range)=split(/:/,$tail); if (defined($regexp)) { $regexp=&unescape($regexp); } else { $regexp='.'; } + my ($start,$end); + if (defined($range)) { + if ($range =~/^(\d+)\-(\d+)$/) { + ($start,$end) = ($1,$2); + } elsif ($range =~/^(\d+)$/) { + ($start,$end) = (0,$1); + } else { + undef($range); + } + } my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_READER()); if ($hashref) { my $qresult=''; + my $count=0; while (my ($key,$value) = each(%$hashref)) { if ($regexp eq '.') { + $count++; + if (defined($range) && $count >= $end) { last; } + if (defined($range) && $count < $start) { next; } $qresult.=$key.'='.$value.'&'; } else { my $unescapeKey = &unescape($key); if (eval('$unescapeKey=~/$regexp/')) { + $count++; + if (defined($range) && $count >= $end) { last; } + if (defined($range) && $count < $start) { next; } $qresult.="$key=$value&"; } } } - if (&untie_user_hash($hashref)) { + if (untie(%$hashref)) { chop($qresult); &Reply($client, "$qresult\n", $userinput); } else { @@ -3057,7 +3009,7 @@ sub store_handler { $hashref->{"$version:$rid:timestamp"}=$now; $allkeys.='timestamp'; $hashref->{"$version:keys:$rid"}=$allkeys; - if (&untie_user_hash($hashref)) { + if (untie($hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -3109,22 +3061,24 @@ sub restore_handler { $namespace=~s/\//\_/g; $namespace=~s/\W//g; chomp($rid); + my $proname=&propath($udom,$uname); my $qresult=''; - my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_READER()); - if ($hashref) { - my $version=$hashref->{"version:$rid"}; + my %hash; + if (tie(%hash,'GDBM_File',"$proname/$namespace.db", + &GDBM_READER(),0640)) { + my $version=$hash{"version:$rid"}; $qresult.="version=$version&"; my $scope; for ($scope=1;$scope<=$version;$scope++) { - my $vkeys=$hashref->{"$scope:keys:$rid"}; + my $vkeys=$hash{"$scope:keys:$rid"}; my @keys=split(/:/,$vkeys); my $key; $qresult.="$scope:keys=$vkeys&"; foreach $key (@keys) { - $qresult.="$scope:$key=".$hashref->{"$scope:$rid:$key"}."&"; + $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&"; } } - if (&untie_user_hash($hashref)) { + if (untie(%hash)) { $qresult=~s/\&$//; &Reply( $client, "$qresult\n", $userinput); } else { @@ -3357,7 +3311,7 @@ sub put_course_id_handler { } $hashref->{$key}=$courseinfo.':'.$now; } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { &Reply( $client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0) @@ -3473,7 +3427,7 @@ sub dump_course_id_handler { $qresult.=$key.'='.$descr.':'.$inst_code.':'.$owner.'&'; } } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { chop($qresult); &Reply($client, "$qresult\n", $userinput); } else { @@ -3522,7 +3476,7 @@ sub put_id_handler { my ($key,$value)=split(/=/,$pair); $hashref->{$key}=$value; } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -3571,7 +3525,7 @@ sub get_id_handler { for (my $i=0;$i<=$#queries;$i++) { $qresult.="$hashref->{$queries[$i]}&"; } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { $qresult=~s/\&$//; &Reply($client, "$qresult\n", $userinput); } else { @@ -3615,7 +3569,7 @@ sub put_dcmail_handler { my ($key,$value)=split(/=/,$what); $hashref->{$key}=$value; } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -3695,7 +3649,7 @@ sub dump_dcmail_handler { $qresult.=$key.'='.$value.'&'; } } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { chop($qresult); &Reply($client, "$qresult\n", $userinput); } else { @@ -3742,7 +3696,7 @@ sub put_domainroles_handler { my ($key,$value)=split(/=/,$pair); $hashref->{$key}=$value; } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { &Reply($client, "ok\n", $userinput); } else { &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ". @@ -3823,7 +3777,7 @@ sub dump_domainroles_handler { $qresult.=$key.'='.$value.'&'; } } - if (&untie_domain_hash($hashref)) { + if (untie(%$hashref)) { chop($qresult); &Reply($client, "$qresult\n", $userinput); } else { @@ -4762,6 +4716,7 @@ sub ReadHostTable { } $hostid{$ip}=$id; # LonCAPA name of host by IP. $hostdom{$id}=$domain; # LonCAPA domain name of host. + $hostname{$id}=$name; # LonCAPA name -> DNS name $hostip{$id}=$ip; # IP address of host. $hostdns{$name} = $id; # LonCAPA name of host by DNS. @@ -5012,12 +4967,12 @@ sub reconlonc { sub subreply { my ($cmd,$server)=@_; - my $peerfile="$perlvar{'lonSockDir'}/$server"; + my $peerfile="$perlvar{'lonSockDir'}/".$hostname{$server}; my $sclient=IO::Socket::UNIX->new(Peer =>"$peerfile", Type => SOCK_STREAM, Timeout => 10) or return "con_lost"; - print $sclient "$cmd\n"; + print $sclient "sethost:$server:$cmd\n"; my $answer=<$sclient>; chomp($answer); if (!$answer) { $answer="con_lost"; } @@ -5033,7 +4988,7 @@ sub reply { $answer=subreply("ping",$server); if ($answer ne $server) { &logthis("sub reply: answer != server answer is $answer, server is $server"); - &reconlonc("$perlvar{'lonSockDir'}/$server"); + &reconlonc("$perlvar{'lonSockDir'}/".$hostname{$server}); } $answer=subreply($cmd,$server); } @@ -5339,7 +5294,7 @@ sub make_new_child { # no need to try to do recon's to myself next; } - &reconlonc("$perlvar{'lonSockDir'}/$id"); + &reconlonc("$perlvar{'lonSockDir'}/".$hostname{$id}); } &logthis("Established connection: $clientname"); &status('Will listen to '.$clientname); @@ -5670,38 +5625,38 @@ sub addline { sub get_chat { my ($cdom,$cname,$udom,$uname)=@_; - + my %hash; + my $proname=&propath($cdom,$cname); my @entries=(); - my $hashref = &tie_user_hash($cdom, $cname, 'nohist_chatroom', - &GDBM_READER()); - if ($hashref) { - @entries=map { $_.':'.$hashref->{$_} } sort(keys(%$hashref)); - &untie_user_hash($hashref); + if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db", + &GDBM_READER(),0640)) { + @entries=map { $_.':'.$hash{$_} } sort keys %hash; + untie %hash; } my @participants=(); my $cutoff=time-60; - $hashref = &tie_user_hash($cdom, $cname, 'nohist_inchatroom', - &GDBM_WRCREAT()); - if ($hashref) { - $hashref->{$uname.':'.$udom}=time; - foreach my $user (sort(keys(%$hashref))) { - if ($hashref->{$user}>$cutoff) { - push(@participants, 'active_participant:'.$user); + if (tie(%hash,'GDBM_File',"$proname/nohist_inchatroom.db", + &GDBM_WRCREAT(),0640)) { + $hash{$uname.':'.$udom}=time; + foreach (sort keys %hash) { + if ($hash{$_}>$cutoff) { + $participants[$#participants+1]='active_participant:'.$_; } } - &untie_user_hash($hashref); + untie %hash; } return (@participants,@entries); } sub chat_add { my ($cdom,$cname,$newchat)=@_; + my %hash; + my $proname=&propath($cdom,$cname); my @entries=(); my $time=time; - my $hashref = &tie_user_hash($cdom, $cname, 'nohist_chatroom', - &GDBM_WRCREAT()); - if ($hashref) { - @entries=map { $_.':'.$hashref->{$_} } sort(keys(%$hashref)); + if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db", + &GDBM_WRCREAT(),0640)) { + @entries=map { $_.':'.$hash{$_} } sort keys %hash; my ($lastid)=($entries[$#entries]=~/^(\w+)\:/); my ($thentime,$idnum)=split(/\_/,$lastid); my $newid=$time.'_000000'; @@ -5711,22 +5666,21 @@ sub chat_add { $idnum=substr('000000'.$idnum,-6,6); $newid=$time.'_'.$idnum; } - $hashref->{$newid}=$newchat; + $hash{$newid}=$newchat; my $expired=$time-3600; - foreach my $comment (keys(%$hashref)) { - my ($thistime) = ($comment=~/(\d+)\_/); + foreach (keys %hash) { + my ($thistime)=($_=~/(\d+)\_/); if ($thistime<$expired) { - delete $hashref->{$comment}; + delete $hash{$_}; } } - { - my $proname=&propath($cdom,$cname); - if (open(CHATLOG,">>$proname/chatroom.log")) { - print CHATLOG ("$time:".&unescape($newchat)."\n"); - } - close(CHATLOG); + untie %hash; + } + { + my $hfh; + if ($hfh=IO::File->new(">>$proname/chatroom.log")) { + print $hfh "$time:".&unescape($newchat)."\n"; } - &untie_user_hash($hashref); } }