X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProtHandle.pm;h=5e3f0597d9405d2279ad1d7fab742a3da36b39ff;hb=387b0fecfd3b200cb9c6094103954c2c0ebad7c6;hp=d739d65d72a8cef9c4ac401145f619a4fe12230f;hpb=d3641e4f287c5268bafda521f3bd9cd0080e6165;p=spider.git diff --git a/perl/DXProtHandle.pm b/perl/DXProtHandle.pm index d739d65d..5e3f0597 100644 --- a/perl/DXProtHandle.pm +++ b/perl/DXProtHandle.pm @@ -4,7 +4,7 @@ # # Copyright (c) 1998-2006 Dirk Koopman G1TLH # -# $Id$ +# # package DXProt; @@ -46,7 +46,8 @@ use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restim $eph_pc15_restime $pc9x_past_age $pc9x_future_age ); -$pc9x_past_age = 15*60; # maximum age in the past of a px9x +$pc9x_past_age = 62*60; # maximum age in the past of a px9x (a config record might be the only + # thing a node might send - once an hour) $pc9x_future_age = 5*60; # maximum age in the future ditto # incoming talk commands @@ -107,40 +108,6 @@ sub handle_10 # convert this to a PC93 and process it as such $self->normal(pc93($to, $from, $via, $_[3], $_[6])); - return; - - # this is all redundant but kept for now for reference - - # it is here and logged on - $dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall; - $dxchan = DXChannel::get($to) unless $dxchan; - if ($dxchan && $dxchan->is_user) { - $_[3] =~ s/\%5E/^/g; - $dxchan->talk($from, $to, $via, $_[3]); - return; - } - - # is it elsewhere, visible on the cluster via the to address? - # note: this discards the via unless the to address is on - # the via address - my ($ref, $vref); - if ($ref = Route::get($to)) { - $vref = Route::Node::get($via) if $via; - $vref = undef unless $vref && grep $to eq $_, $vref->users; - $ref->dxchan->talk($from, $to, $vref ? $via : undef, $_[3], $_[6]); - return; - } - - # can we see an interface to send it down? - - # not visible here, send a message of condolence - $vref = undef; - $ref = Route::get($from); - $vref = $ref = Route::Node::get($_[6]) unless $ref; - if ($ref) { - $dxchan = $ref->dxchan; - $dxchan->talk($main::mycall, $from, $vref ? $vref->call : undef, $dxchan->msg('talknh', $to) ); - } } # DX Spot handling @@ -495,18 +462,17 @@ sub handle_16 push @rout, @ans if $h && @ans; } - # send info to all logged in thingies - $self->tell_login('loginu', "$ncall: $call") if DXUser->get_current($ncall)->is_local_node; - $self->tell_buddies('loginb', $call, $ncall); - # add this station to the user database, if required -# $call =~ s/-\d+$//o; # remove ssid for users - my $user = DXUser->get_current($call); - $user = DXUser->new($call) if !$user; + my $user = DXUser->get_current($ncall); + $user = DXUser->new($call) unless $user; $user->homenode($parent->call) if !$user->homenode; $user->node($parent->call); $user->lastin($main::systime) unless DXChannel::get($call); $user->put; + + # send info to all logged in thingies + $self->tell_login('loginu', "$ncall: $call") if $user->is_local_node; + $self->tell_buddies('loginb', $call, $ncall); } if (@rout) { $self->route_pc16($origin, $line, $parent, @rout) if @rout; @@ -574,7 +540,8 @@ sub handle_17 $parent->del_user($uref); # send info to all logged in thingies - $self->tell_login('logoutu', "$ncall: $ucall") if DXUser->get_current($ncall)->is_local_node; + my $user = DXUser->get_current($ncall); + $self->tell_login('logoutu', "$ncall: $ucall") if $user && $user->is_local_node; $self->tell_buddies('logoutb', $ucall, $ncall); if (eph_dup($line)) { @@ -598,24 +565,34 @@ sub handle_18 my $parent = Route::Node::get($self->{call}); # record the type and version offered - if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+(?:\.\d+)?)/) { - $self->{version} = 53 + $1; - $self->user->version(53 + $1); - $parent->version(0 + $1); - $self->{build} = 0 + $2; - $self->user->build(0 + $2); - $parent->build(0 + $2); + if (my ($version) = $_[1] =~ /DXSpider Version: (\d+\.\d+)/) { + $self->{version} = 53 + $version; + $self->user->version(53 + $version); + $parent->version(0 + $version); + my ($build) = $_[1] =~ /Build: (\d+(?:\.\d+)?)/; + $self->{build} = 0 + $build; + $self->user->build(0 + $build); + $parent->build(0 + $build); + dbg("DXSpider version $version build $build"); unless ($self->is_spider) { + dbg("Change U " . $self->user->sort . " C $self->{sort} -> S"); $self->user->sort('S'); $self->user->put; $self->sort('S'); } - $self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml/; +# $self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml/; if ($_[1] =~ /\bpc9x/) { - $self->{do_pc9x} = 1; - dbg("Do px9x set on $self->{call}"); + if ($self->{isolate}) { + dbg("pc9x recognised, but $self->{call} is isolated, using old protocol"); + } elsif (!$self->user->wantpc9x) { + dbg("pc9x explicitly switched off on $self->{call}, using old protocol"); + } else { + $self->{do_pc9x} = 1; + dbg("Do px9x set on $self->{call}"); + } } } else { + dbg("Unknown software"); $self->version(50.0); $self->version($_[2] / 100) if $_[2] && $_[2] =~ /^\d+$/; $self->user->version($self->version); @@ -787,16 +764,14 @@ sub handle_20 my $origin = shift; if ($self->{do_pc9x} && $self->{state} ne 'init92') { - dbg("PCPROT: disconnecting because login call not sent in any pc92") if isdbg('chanerr'); - $self->send("**** You logged in with $self->{call} but that is NOT your \$mycall"); - $self->disconnect; - return; + $self->send("Reseting to oldstyle routing because login call not sent in any pc92"); + $self->{do_pc9x} = 0; } $self->send_local_config; $self->send(pc22()); $self->state('normal'); $self->{lastping} = 0; - $self->route_pc92a($main::mycall, $line, $main::routeroot, Route::Node::get($self->{call})); + $self->route_pc92a($main::mycall, undef, $main::routeroot, Route::Node::get($self->{call})); } # delete a cluster from the list @@ -878,10 +853,8 @@ sub handle_22 if ($self->{do_pc9x}) { if ($self->{state} ne 'init92') { - dbg("PCPROT: disconnecting because login call not sent in any pc92") if isdbg('chanerr'); - $self->send("**** You logged in with $self->{call} but that is NOT your \$mycall"); - $self->disconnect; - return; + $self->send("Reseting to oldstyle routing because login call not sent in any pc92"); + $self->{do_pc9x} = 0; } } $self->{lastping} = 0; @@ -1450,14 +1423,19 @@ sub check_pc9x_t if ($parent->call ne $main::mycall) { my $lastid = $parent->lastid->{$pc} || 0; if ($t < $lastid) { - if ($lastid-86400+$t > $pc9x_past_age) { - dbg("PCPROT: dup id on $t <= $lastid (midnight rollover), ignored") if isdbg('chanerr'); + if ($t+86400-$lastid > $pc9x_past_age) { + dbg("PCPROT: dup id on $t <= $lastid, ignored") if isdbg('chanerr'); return; } - } - if ($lastid >= $t) { - dbg("PCPROT: dup id on $call $lastid >= $t, ignored") if isdbg('chanerr'); + } elsif ($t == $lastid) { + dbg("PCPROT: dup id on $t == $lastid, ignored") if isdbg('chanerr'); return; + } else { + # $t > $lastid, check that the timestamp offered isn't too far away from 'now' + if ($t+$main::systime_daystart-$main::systime > $pc9x_future_age ) { + dbg("PCPROT: id $t too far in the future, ignored") if isdbg('chanerr'); + return; + } } } } elsif ($create) { @@ -1492,9 +1470,17 @@ sub handle_92 } if ($pcall eq $self->{call} && $self->{state} eq 'init') { - $self->state('init92'); - $self->{do_pc9x} = 1; - dbg("Do pc9x set on $pcall"); + if ($self->{isolate}) { + dbg("PC9x received, but $pcall is isolated, ignored"); + return; + } elsif (!$self->user->wantpc9x) { + dbg("PC9x explicitly switched off on $pcall, ignored"); + return; + } else { + $self->state('init92'); + $self->{do_pc9x} = 1; + dbg("Do pc9x set on $pcall"); + } } unless ($self->{do_pc9x}) { dbg("PCPROT: PC9x come in from non-PC9x node, ignored") if isdbg('chanerr'); @@ -1555,39 +1541,56 @@ sub handle_92 # here is where all the routes are created and destroyed my @ent = map {[ _decode_pc92_call($_) ]} grep {$_ && /^[0-7]/} @_[4 .. $#_]; + if (@ent) { # look at the first one which will always be a node of some sort - # and update any information that needs to be done. + # except in the case of 'A' or 'D' in which the $pcall is used + # otherwise use the node call and update any information + # that needs to be done. my ($call, $is_node, $is_extnode, $here, $version, $build) = @{$ent[0]}; - if ($call && $is_node) { - if ($call eq $main::mycall) { - dbg("PCPROT: $call looped back onto $main::mycall, ignored") if isdbg('chanerr'); - return; - } - if ($is_extnode) { - # this is only accepted from my "self" - if (DXChannel::get($call) && $call ne $self->{call}) { - dbg("PCPROT: locally connected node config for $call from other another node $self->{call}, ignored") if isdbg('chanerr'); + if (($sort eq 'A' || $sort eq 'D') && !$is_node) { + # parent is already set correctly + # this is to allow shortcuts for A and D records + # not repeating the origin call to no real purpose + ; + } else { + if ($call && $is_node) { + if ($call eq $main::mycall) { + dbg("PCPROT: $call looped back onto $main::mycall, ignored") if isdbg('chanerr'); return; } - # reparent to external node (note that we must have received a 'C' or 'A' record - # from the true parent node for this external before we get one for the this node - unless ($parent = Route::Node::get($call)) { - dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr'); + # this is only accepted from my "self". + # this also kills configs from PC92 nodes with external PC19 nodes that are also + # locally connected. Local nodes always take precedence. + if (DXChannel::get($call) && $call ne $self->{call}) { + dbg("PCPROT: locally connected node $call from other another node $self->{call}, ignored") if isdbg('chanerr'); return; } - $parent = check_pc9x_t($call, $t, 92) || return; - $parent->via_pc92(1); + if ($is_extnode) { + # reparent to external node (note that we must have received a 'C' or 'A' record + # from the true parent node for this external before we get one for the this node + unless ($parent = Route::Node::get($call)) { + if ($is_extnode && $oparent) { + @radd = _add_thingy($oparent, $ent[0]); + $parent = $radd[0]; + } else { + dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr'); + return; + } + } + $parent = check_pc9x_t($call, $t, 92) || return; + $parent->via_pc92(1); + } + } else { + dbg("PCPROT: must be mycall or external node as first entry, ignored") if isdbg('chanerr'); + return; } - } else { - dbg("PCPROT: must be mycall or external node as first entry, ignored") if isdbg('chanerr'); - return; + $parent->here(Route::here($here)); + $parent->version($version) if $version && $version > $parent->version; + $parent->build($build) if $build && $build > $parent->build; + shift @ent; } - $parent->here(Route::here($here)); - $parent->version($version) if $version && $version > $parent->version; - $parent->build($build) if $build && $build > $parent->build; - shift @ent; } # do a pass through removing any references to either locally connected nodes or mycall @@ -1614,10 +1617,12 @@ sub handle_92 # we only reset obscounts on config records $oparent->reset_obs; - dbg("ROUTE: reset obscount on $pcall now " . $oparent->obscount) if isdbg('route'); + $oparent->PC92C_dxchan($self->{call}) unless $self->{call} eq $oparent->call; + dbg("ROUTE: reset obscount on $pcall now " . $oparent->obscount) if isdbg('obscount'); if ($oparent != $parent) { $parent->reset_obs; - dbg("ROUTE: reset obscount on $parent->{call} now " . $parent->obscount) if isdbg('route'); + $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call; + dbg("ROUTE: reset obscount on $parent->{call} now " . $parent->obscount) if isdbg('obscount'); } # @@ -1650,6 +1655,9 @@ sub handle_92 foreach my $r (@$dusers) { push @rdel,_del_thingy($parent, [$r, 0]); } + + # remember this last PC92C for rebroadcast on demand + $parent->last_PC92C($line); } else { dbg("PCPROT: unknown action '$sort', ignored") if isdbg('chanerr'); return; @@ -1687,6 +1695,12 @@ sub handle_93 dbg("PCPROT: invalid callsign string '$_[1]', ignored") if isdbg('chanerr'); return; } + + unless ($self->{do_pc9x}) { + dbg("PCPROT: PC9x come in from non-PC9x node, ignored") if isdbg('chanerr'); + return; + } + my $t = $_[2]; my $parent = check_pc9x_t($pcall, $t, 93, 1) || return; @@ -1706,6 +1720,11 @@ sub handle_93 } } + # this is catch loops caused by bad software ... + if (eph_dup("PC93|$from|$text|$onode")) { + return; + } + # if this is a 'bad spotter' user then ignore it my $nossid = $from; $nossid =~ s/-\d+$//; @@ -1727,14 +1746,16 @@ sub handle_93 # convert to PC10 talks where appropriate my $ref = Route::get($to); if ($ref) { - my @dxchan = $ref->alldxchan; - for $dxchan (@dxchan) { + # just go for the "best" one for now (rather than broadcast) + $dxchan = $ref->dxchan; +# my @dxchan = $ref->alldxchan; +# for $dxchan (@dxchan) { if ($dxchan->{do_pc9x}) { $dxchan->send($line); } else { $dxchan->talk($from, $to, $via, $text, $onode); } - } +# } return; } @@ -1745,7 +1766,7 @@ sub handle_93 my $wx = uc $to eq 'WX' ? '1' : '0'; my $local = $via eq 'LOCAL' ? '*' : $via; - $self->send_announce(1, pc12($from, $text, $local, $via, $sysop, $wx, $pcall), $from, $local, $text, $sysop, $pcall, $wx, $via eq 'LOCAL' ? $via : undef); + $self->send_announce(1, pc12($from, $text, $local, $sysop, $wx, $pcall), $from, $local, $text, $sysop, $pcall, $wx, $via eq 'LOCAL' ? $via : undef); return if $via eq 'LOCAL'; } else { # chat messages to non-pc9x nodes @@ -1769,9 +1790,7 @@ sub handle_default my $line = shift; my $origin = shift; - if (eph_dup($line)) { - dbg("PCPROT: Ephemeral dup, dropped") if isdbg('chanerr'); - } else { + unless (eph_dup($line)) { if ($pcno >= 90) { my $pcall = $_[1]; unless (is_callsign($pcall)) {