--- loncom/lonnet/perl/lonnet.pm 2010/05/26 17:14:43 1.1056.4.2 +++ loncom/lonnet/perl/lonnet.pm 2010/08/17 00:19:24 1.1056.4.3 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1056.4.2 2010/05/26 17:14:43 raeburn Exp $ +# $Id: lonnet.pm,v 1.1056.4.3 2010/08/17 00:19:24 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -76,7 +76,7 @@ use HTTP::Date; use Image::Magick; use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir - $_64bit %env %protocol); + $_64bit %env %protocol %loncaparevs %serverhomeIDs); my (%badServerCache, $memcache, %courselogs, %accesshash, %domainrolehash, %userrolehash, $processmarker, $dumpcount, %coursedombuf, @@ -196,7 +196,7 @@ sub get_server_timezone { } sub get_server_loncaparev { - my ($dom,$lonhost) = @_; + my ($dom,$lonhost,$ignore_cache,$caller) = @_; if (defined($lonhost)) { if (!defined(&hostname($lonhost))) { undef($lonhost); @@ -211,15 +211,74 @@ sub get_server_loncaparev { } } if (defined($lonhost)) { - my $cachetime = 24*3600; - my ($loncaparev,$cached)=&is_cached_new('serverloncaparev',$lonhost); + my $cachetime = 12*3600; + if (!$ignore_cache) { + my ($loncaparev,$cached)=&is_cached_new('serverloncaparev',$lonhost); + if (defined($cached)) { + return $loncaparev; + } + } + my ($answer,$loncaparev); + my @ids=¤t_machine_ids(); + if (grep(/^\Q$lonhost\E$/,@ids)) { + $answer = $perlvar{'lonVersion'}; + if ($answer =~ /^[\'\"]?([\d.\-]+)[\'\"]?$/) { + $loncaparev = $1; + } + } else { + $answer = &reply('serverloncaparev',$lonhost); + if (($answer eq 'unknown_cmd') || ($answer eq 'con_lost')) { + if ($caller eq 'loncron') { + my $ua=new LWP::UserAgent; + $ua->timeout(20); + my $protocol = $protocol{$lonhost}; + $protocol = 'http' if ($protocol ne 'https'); + my $url = $protocol.'://'.&hostname($lonhost).'/adm/about.html'; + my $request=new HTTP::Request('GET',$url); + my $response=$ua->request($request); + unless ($response->is_error()) { + my $content = $response->content; + if ($content =~ /
VERSION\:\s*([\d.\-]+)<\/p>/) {
+ $loncaparev = $1;
+ }
+ }
+ } else {
+ $loncaparev = $loncaparevs{$lonhost};
+ }
+ } elsif ($answer =~ /^[\'\"]?([\d.\-]+)[\'\"]?$/) {
+ $loncaparev = $1;
+ }
+ }
+ return &do_cache_new('serverloncaparev',$lonhost,$loncaparev,$cachetime);
+ }
+}
+
+sub get_server_homeID {
+ my ($hostname,$ignore_cache,$caller) = @_;
+ unless ($ignore_cache) {
+ my ($serverhomeID,$cached)=&is_cached_new('serverhomeID',$hostname);
if (defined($cached)) {
- return $loncaparev;
- } else {
- my $loncaparev = &reply('serverloncaparev',$lonhost);
- return &do_cache_new('serverloncaparev',$lonhost,$loncaparev,$cachetime);
+ return $serverhomeID;
+ }
+ }
+ my $cachetime = 12*3600;
+ my $serverhomeID;
+ if ($caller eq 'loncron') {
+ my @machine_ids = &machine_ids($hostname);
+ foreach my $id (@machine_ids) {
+ my $response = &reply('serverhomeID',$id);
+ unless (($response eq 'unknown_cmd') || ($response eq 'con_lost')) {
+ $serverhomeID = $response;
+ last;
+ }
}
+ if ($serverhomeID eq '') {
+ $serverhomeID = $machine_ids[-1];
+ }
+ } else {
+ $serverhomeID = $serverhomeIDs{$hostname};
}
+ return &do_cache_new('serverhomeID',$hostname,$serverhomeID,$cachetime);
}
# -------------------------------------------------- Non-critical communication
@@ -734,7 +793,7 @@ sub compare_server_load {
my $userloadans = &reply('userload',$try_server);
if ($loadans !~ /\d/ && $userloadans !~ /\d/) {
- next; #didn't get a number from the server
+ return; #didn't get a number from the server
}
my $load;
@@ -777,6 +836,27 @@ sub has_user_session {
return 0;
}
+# --------- determine least loaded server in a user's domain which allows login
+
+sub choose_server {
+ my ($udom) = @_;
+ my %domconfhash = &Apache::loncommon::get_domainconf($udom);
+ my %servers = &get_servers($udom);
+ my $lowest_load = 30000;
+ my ($login_host,$hostname);
+ foreach my $lonhost (keys(%servers)) {
+ my $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
+ if ($loginvia eq '') {
+ ($login_host, $lowest_load) =
+ &compare_server_load($lonhost, $login_host, $lowest_load);
+ }
+ }
+ if ($login_host ne '') {
+ $hostname = $servers{$login_host};
+ }
+ return ($login_host,$hostname);
+}
+
# --------------------------------------------- Try to change a user's password
sub changepass {
@@ -835,7 +915,7 @@ sub queryauthenticate {
# --------- Try to authenticate user from domain's lib servers (first this one)
sub authenticate {
- my ($uname,$upass,$udom,$checkdefauth)=@_;
+ my ($uname,$upass,$udom,$checkdefauth,$clientcancheckhost)=@_;
$upass=&escape($upass);
$uname= &LONCAPA::clean_username($uname);
my $uhome=&homeserver($uname,$udom,1);
@@ -858,7 +938,7 @@ sub authenticate {
return 'no_host';
}
}
- my $answer=reply("encrypt:auth:$udom:$uname:$upass:$checkdefauth",$uhome);
+ my $answer=reply("encrypt:auth:$udom:$uname:$upass:$checkdefauth:$clientcancheckhost",$uhome);
if ($answer eq 'authorized') {
if ($newhome) {
&logthis("User $uname at $udom authorized by $uhome, but needs account");
@@ -876,6 +956,64 @@ sub authenticate {
return 'no_host';
}
+sub can_host_session {
+ my ($udom,$lonhost,$remoterev,$remotesessions,$hostedsessions) = @_;
+ my $canhost = 1;
+ my $host_idn = &Apache::lonnet::internet_dom($lonhost);
+ if (ref($remotesessions) eq 'HASH') {
+ if (ref($remotesessions->{'excludedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$host_idn\E$/,@{$remotesessions->{'excludedomain'}})) {
+ $canhost = 0;
+ } else {
+ $canhost = 1;
+ }
+ }
+ if (ref($remotesessions->{'includedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$host_idn\E$/,@{$remotesessions->{'includedomain'}})) {
+ $canhost = 1;
+ } else {
+ $canhost = 0;
+ }
+ }
+ if ($canhost) {
+ if ($remotesessions->{'version'} ne '') {
+ my ($reqmajor,$reqminor) = ($remotesessions->{'version'} =~ /^(\d+)\.(\d+)$/);
+ if ($reqmajor ne '' && $reqminor ne '') {
+ if ($remoterev =~ /^\'?(\d+)\.(\d+)/) {
+ my $major = $1;
+ my $minor = $2;
+ if (($major < $reqmajor ) ||
+ (($major == $reqmajor) && ($minor < $reqminor))) {
+ $canhost = 0;
+ }
+ } else {
+ $canhost = 0;
+ }
+ }
+ }
+ }
+ }
+ if ($canhost) {
+ if (ref($hostedsessions) eq 'HASH') {
+ if (ref($hostedsessions->{'excludedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'excludedomain'}})) {
+ $canhost = 0;
+ } else {
+ $canhost = 1;
+ }
+ }
+ if (ref($hostedsessions->{'includedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'includedomain'}})) {
+ $canhost = 1;
+ } else {
+ $canhost = 0;
+ }
+ }
+ }
+ }
+ return $canhost;
+}
+
# ---------------------- Find the homebase for a user from domain's lib servers
my %homecache;
@@ -1352,7 +1490,7 @@ sub get_domain_defaults {
my %domconfig =
&Apache::lonnet::get_dom('configuration',['defaults','quotas',
'requestcourses','inststatus',
- 'coursedefaults'],$domain);
+ 'coursedefaults','usersessions'],$domain);
if (ref($domconfig{'defaults'}) eq 'HASH') {
$domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'};
$domdefaults{'auth_def'} = $domconfig{'defaults'}{'auth_def'};
@@ -1392,6 +1530,14 @@ sub get_domain_defaults {
$domdefaults{$item} = $domconfig{'coursedefaults'}{$item};
}
}
+ if (ref($domconfig{'usersessions'}) eq 'HASH') {
+ if (ref($domconfig{'usersessions'}{'remote'}) eq 'HASH') {
+ $domdefaults{'remotesessions'} = $domconfig{'usersessions'}{'remote'};
+ }
+ if (ref($domconfig{'usersessions'}{'hosted'}) eq 'HASH') {
+ $domdefaults{'hostedsessions'} = $domconfig{'usersessions'}{'hosted'};
+ }
+ }
&Apache::lonnet::do_cache_new('domdefaults',$domain,\%domdefaults,
$cachetime);
return %domdefaults;
@@ -3059,7 +3205,7 @@ sub courseiddump {
my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,
$coursefilter,$hostidflag,$hostidref,$typefilter,$regexp_ok,
$selfenrollonly,$catfilter,$showhidden,$caller,$cloner,$cc_clone,
- $cloneonly,$createdbefore,$createdafter,$creationcontext)=@_;
+ $cloneonly,$createdbefore,$createdafter,$creationcontext,$domcloner)=@_;
my $as_hash = 1;
my %returnhash;
if (!$domfilter) { $domfilter=''; }
@@ -3081,7 +3227,8 @@ sub courseiddump {
$showhidden.':'.$caller.':'.&escape($cloner).':'.
&escape($cc_clone).':'.$cloneonly.':'.
&escape($createdbefore).':'.&escape($createdafter).':'.
- &escape($creationcontext),$tryserver);
+ &escape($creationcontext).':'.$domcloner,
+ $tryserver);
my @pairs=split(/\&/,$rep);
foreach my $item (@pairs) {
my ($key,$value)=split(/\=/,$item,2);
@@ -3905,9 +4052,10 @@ sub rolesinit {
my ($domain,$username,$authhost)=@_;
my $now=time;
my %userroles = ('user.login.time' => $now);
- my $rolesdump=reply("dump:$domain:$username:roles",$authhost);
+ my $extra = &freeze_escape({'clientcheckrole' => 1});
+ my $rolesdump=reply("dump:$domain:$username:roles:.::$extra",$authhost);
if (($rolesdump eq 'con_lost') || ($rolesdump eq '') ||
- ($rolesdump =~ /^error:/)) {
+ ($rolesdump =~ /^error:/)) {
return \%userroles;
}
my %allroles=();
@@ -9861,6 +10009,14 @@ sub get_dns {
my @uniq = grep(!$seen{$_}++, values(%hostdom));
return @uniq;
}
+
+ sub internet_dom {
+ &load_hosts_tab() if (!$loaded);
+
+ my ($lonid) = @_;
+ return $internetdom{$lonid};
+ }
+
}
{
@@ -9978,6 +10134,40 @@ sub get_dns {
return undef;
}
+ sub get_internet_names {
+ my ($lonid) = @_;
+ return if ($lonid eq '');
+ my ($idnref,$cached)=
+ &Apache::lonnet::is_cached_new('internetnames',$lonid);
+ if ($cached) {
+ return $idnref;
+ }
+ my $ip = &get_host_ip($lonid);
+ my @hosts = &get_hosts_from_ip($ip);
+ my %iphost = &get_iphost();
+ my (@idns,%seen);
+ foreach my $id (@hosts) {
+ my $dom = &host_domain($id);
+ my $prim_id = &domain($dom,'primary');
+ my $prim_ip = &get_host_ip($prim_id);
+ next if ($seen{$prim_ip});
+ if (ref($iphost{$prim_ip}) eq 'ARRAY') {
+ foreach my $id (@{$iphost{$prim_ip}}) {
+ my $intdom = &internet_dom($id);
+ unless (grep(/^\Q$intdom\E$/,@idns)) {
+ push(@idns,$intdom);
+ }
+ }
+ }
+ $seen{$prim_ip} = 1;
+ }
+ return &Apache::lonnet::do_cache_new('internetnames',$lonid,\@idns,12*60*60);
+ }
+
+}
+
+sub all_loncaparevs {
+ return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10);
}
BEGIN {
@@ -10055,6 +10245,34 @@ BEGIN {
close($config);
}
+# ---------------------------------------------------------- Read loncaparev table
+{
+ if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") {
+ if (open(my $config,"<$perlvar{'lonTabDir'}/loncaparevs.tab")) {
+ while (my $configline=<$config>) {
+ chomp($configline);
+ my ($hostid,$loncaparev)=split(/:/,$configline);
+ $loncaparevs{$hostid}=$loncaparev;
+ }
+ close($config);
+ }
+ }
+}
+
+# ---------------------------------------------------------- Read serverhostID table
+{
+ if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {
+ if (open(my $config,"<$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
+ while (my $configline=<$config>) {
+ chomp($configline);
+ my ($name,$id)=split(/:/,$configline);
+ $serverhomeIDs{$name}=$id;
+ }
+ close($config);
+ }
+ }
+}
+
# ------------- set up temporary directory
{
$tmpdir = $perlvar{'lonDaemons'}.'/tmp/';
@@ -10285,9 +10503,14 @@ authentication scheme
=item *
X