X-Git-Url: http://gb7djk.dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=30f03b7ed5e9f11f25fb83ab0c084ec1221367d2;hb=dab9e3607e7a6592fc3e316cc83ab17fcd09cb61;hp=7f30ae62acd446da059cc45283cfe8e6af00bdfe;hpb=3299fa494b66b621ad4f1b78c25a129fe8cbadc7;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index 7f30ae62..30f03b7e 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -27,7 +27,6 @@ use DXDb; use AnnTalk; use Geomag; use WCY; -use Time::HiRes qw(gettimeofday tv_interval); use BadWords; use DXHash; use Route; @@ -50,13 +49,13 @@ use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restim $pingint $obscount %pc19list $chatdupeage $chatimportfn $investigation_int $pc19_version $myprot_version %nodehops $baddx $badspotter $badnode $censorpc $rspfcheck - $allowzero $decode_dk0wcy $send_opernam @checklist); + $allowzero $decode_dk0wcy $send_opernam @checklist + ); $pc11_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc11 $pc23_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc23 $last_hour = time; # last time I did an hourly periodic update -%pings = (); # outstanding ping requests outbound %rcmds = (); # outstanding rcmd requests outbound %nodehops = (); # node specific hop control %pc19list = (); # list of outstanding PC19s that haven't had PC16s on them @@ -82,7 +81,7 @@ $pc19_version = 5466; # the visible version no for outgoing PC19s generated fr @checklist = ( [ qw(i c c m bp bc c) ], # pc10 - [ qw(i f bm d t m c c h) ], # pc11 + [ qw(i f m d t m c c h) ], # pc11 [ qw(i c bm m bm bm p h) ], # pc12 [ qw(i c h) ], # [ qw(i c h) ], # @@ -299,7 +298,7 @@ sub start $self->{pingave} = 999; $self->{metric} ||= 100; $self->{lastping} = $main::systime; - + # send initialisation string unless ($self->{outbound}) { $self->sendinit; @@ -326,21 +325,6 @@ sub sendinit $self->send(pc18()); } -sub removepc90 -{ - $_[0] =~ s/^PC90\^[-A-Z0-9]+\^\d+\^//; - $_[0] =~ s/^PC91\^[-A-Z0-9]+\^\d+\^[-A-Z0-9]+\^//; -} - -#sub send -#{ -# my $self = shift; -# while (@_) { -# my $line = shift; -# $self->SUPER::send($line); -# } -#} - # # This is the normal pcxx despatcher # @@ -348,8 +332,10 @@ sub normal { my ($self, $line) = @_; - # remove any incoming PC90 frames - removepc90($line); + if ($line =~ '^<\w+\s' && $main::do_xml) { + DXXml::normal($self, $line); + return; + } my @field = split /\^/, $line; return unless @field; @@ -490,6 +476,18 @@ sub handle_11 # rsfp check # return if $rspfcheck and !$self->rspfcheck(1, $_[7], $_[6]); + + # is the spotted callsign blank? This should really be trapped earlier but it + # could break other protocol sentences. Also check for lower case characters. + if ($_[2] =~ /^\s*$/) { + dbg("PCPROT: blank callsign, dropped") if isdbg('chanerr'); + return; + } + if ($_[2] =~ /[a-z]/) { + dbg("PCPROT: lowercase characters, dropped") if isdbg('chanerr'); + return; + } + # if this is a 'nodx' node then ignore it if ($badnode->in($_[7])) { @@ -726,83 +724,23 @@ sub handle_16 return; } - RouteDB::update($ncall, $self->{call}); + my $h; + $h = 1 if DXChannel::get($ncall); + RouteDB::update($ncall, $self->{call}, $h); - # do we believe this call? - unless ($ncall eq $self->{call} || $self->is_believed($ncall)) { - if (my $ivp = Investigate::get($ncall, $self->{call})) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr'); - } + if (eph_dup($line)) { + dbg("PCPROT: dup PC16 detected") if isdbg('chanerr'); return; } - if (eph_dup($line)) { - dbg("PCPROT: dup PC16 detected") if isdbg('chanerr'); + unless ($h) { + dbg("PCPROT: non-local PC16, ignored") if isdbg('chanerr'); return; } my $parent = Route::Node::get($ncall); - # if there is a parent, proceed, otherwise if there is a latent PC19 in the PC19list, - # fix it up in the routing tables and issue it forth before the PC16 - unless ($parent) { - my $nl = $pc19list{$ncall}; - - if ($nl && @_ > 3) { # 3 because of the hop count! - - # this is a new (remembered) node, now attach it to me if it isn't in filtered - # and we haven't disallowed it - my $user = DXUser->get_current($ncall); - if (!$user) { - $user = DXUser->new($ncall); - $user->sort('A'); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($ncall); - $user->node($ncall); - } - - my $wantpc19 = $user->wantroutepc19; - if ($wantpc19 || !defined $wantpc19) { - my $new = Route->new($ncall); # throw away - if ($self->in_filter_route($new)) { - my @nrout; - for (@$nl) { - $parent = Route::Node::get($_->[0]); - $dxchan = $parent->dxchan if $parent; - if ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC19 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); - $parent = undef; - } - if ($parent) { - my $r = $parent->add($ncall, $_->[1], $_->[2]); - push @nrout, $r unless @nrout; - } - } - $user->wantroutepc19(1) unless defined $wantpc19; # for now we work on the basis that pc16 = real route - $user->lastin($main::systime) unless DXChannel::get($ncall); - $user->put; - - # route the pc19 - this will cause 'stuttering PC19s' for a while - $self->route_pc19($origin, $line, @nrout) if @nrout ; - $parent = Route::Node::get($ncall); - unless ($parent) { - dbg("PCPROT: lost $ncall after sending PC19 for it?"); - return; - } - } else { - return; - } - delete $pc19list{$ncall}; - } - } else { - dbg("PCPROT: Node $ncall not in config") if isdbg('chanerr'); - return; - } - } else { - + if ($parent) { $dxchan = $parent->dxchan; if ($dxchan && $dxchan ne $self) { dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); @@ -846,9 +784,12 @@ sub handle_16 push @rout, $parent->add_user($call, $flags); } + # 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 +# $call =~ s/-\d+$//o; # remove ssid for users my $user = DXUser->get_current($call); $user = DXUser->new($call) if !$user; $user->homenode($parent->call) if !$user->homenode; @@ -857,6 +798,7 @@ sub handle_16 $user->put; } $self->route_pc16($origin, $line, $parent, @rout) if @rout; + } # remove a user @@ -884,13 +826,8 @@ sub handle_17 RouteDB::delete($ncall, $self->{call}); - # do we believe this call? - unless ($ncall eq $self->{call} || $self->is_believed($ncall)) { - if (my $ivp = Investigate::get($ncall, $self->{call})) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr'); - } + unless ($ncall eq $self->{call}) { + dbg("PCPROT: PC17 from non-local $ncall, ignored") if isdbg('chanerr'); return; } @@ -917,6 +854,10 @@ sub handle_17 $parent = Route->new($ncall); # throw away } + # send info to all logged in thingies + $self->tell_login('logoutu', "$ncall: $ucall") if DXUser->get_current($ncall)->is_local_node; + $self->tell_buddies('logoutb', $ucall, $ncall); + if (eph_dup($line)) { dbg("PCPROT: dup PC17 detected") if isdbg('chanerr'); return; @@ -946,6 +887,8 @@ sub handle_18 $self->user->put; $self->sort('S'); } + $self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml\b/; + $self->{do_pc92}++ if $_[1] =~ /\bpc92\b/; } else { $self->version(50.0); $self->version($_[2] / 100) if $_[2] && $_[2] =~ /^\d+$/; @@ -982,27 +925,17 @@ sub handle_19 return; } - # if the origin isn't the same as the INTERFACE, then reparent, creating nodes as necessary - if ($origin ne $self->call) { - my $op = Route::Node::get($origin); - unless ($op) { - $op = $parent->add($origin, 5000, Route::here(1)); - my $user = DXUser->get_current($origin); - if (!$user) { - $user = DXUser->new($origin); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($origin); - $user->node($origin); - $user->wantroutepc19(1); - } - $user->sort('A') unless $user->is_node; - $user->put; - } - $parent = $op; - } - # parse the PC19 + # + # We are making a major change from now on. We are only going to accept + # PC19s from directly connected nodes. This means that we are probably + # going to throw away most of the data that we are being sent. + # + # The justification for this is that most of it is wrong or out of date + # anyway. + # + # From now on we are only going to believe PC92 data. + # for ($i = 1; $i < $#_-1; $i += 4) { my $here = $_[$i]; my $call = uc $_[$i+1]; @@ -1014,6 +947,7 @@ sub handle_19 # check for sane parameters # $ver = 5000 if $ver eq '0000'; + next unless $ver && $ver =~ /^\d+$/; next if $ver < 5000; # only works with version 5 software next if length $call < 3; # min 3 letter callsigns next if $call eq $main::mycall; @@ -1036,26 +970,15 @@ sub handle_19 } $user->sort('A') unless $user->is_node; - RouteDB::update($call, $self->{call}); - - # do we believe this call? - my $genline = "PC19^$here^$call^$conf^$ver^$_[-1]^"; - unless ($call eq $self->{call} || $self->is_believed($call)) { - my $pt = $user->lastping($self->{call}) || 0; - if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $self->{call})) { - my $ivp = Investigate->new($call, $self->{call}); - $ivp->version($ver); - $ivp->here($here); - $ivp->store_pcxx($pcno,$genline,$origin,'PC19',$here,$call,$conf,$ver,$_[-1]); - } else { - dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr'); - } - $user->put; - next; - } +# if (eph_dup($genline)) { +# dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr'); +# next; +# } + + RouteDB::update($call, $self->{call}, $dxchan ? 1 : undef); - if (eph_dup($genline)) { - dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr'); + unless ($dxchan) { + dbg("PCPROT: PC19 not directly connected, ignored") if isdbg('chanerr'); next; } @@ -1068,7 +991,7 @@ sub handle_19 if ($call ne $parent->call) { if ($self->in_filter_route($r)) { $ar = $parent->add($call, $ver, $flags); - push @rout, $ar if $ar; +# push @rout, $ar if $ar; } else { next; } @@ -1076,11 +999,9 @@ sub handle_19 if ($r->version ne $ver || $r->flags != $flags) { $r->version($ver); $r->flags($flags); - push @rout, $r unless $ar; } + push @rout, $r; } else { - - # if he is directly connected or allowed then add him, otherwise store him up for later if ($call eq $self->{call} || $user->wantroutepc19) { my $new = Route->new($call); # throw away if ($self->in_filter_route($new)) { @@ -1090,10 +1011,6 @@ sub handle_19 } else { next; } - } else { - $pc19list{$call} = [] unless exists $pc19list{$call}; - my $nl = $pc19list{$call}; - push @{$pc19list{$call}}, [$self->{call}, $ver, $flags] unless grep $_->[0] eq $self->{call}, @$nl; } } @@ -1105,8 +1022,13 @@ sub handle_19 $user->put; } - - $self->route_pc19($origin, $line, @rout) if @rout; + # we are not automatically sending out PC19s, we send out a composite PC21,PC19 instead + # but remember there will only be one (pair) these because any extras will be + # thrown away. + if (@rout) { + $self->route_pc21($self->{call}, $line, @rout); + $self->route_pc19($self->{call}, $line, @rout); + } } # send local configuration @@ -1123,6 +1045,9 @@ sub handle_20 } # delete a cluster from the list +# +# This should never occur for directly connected nodes. +# sub handle_21 { my $self = shift; @@ -1133,59 +1058,42 @@ sub handle_21 eph_del_regex("^PC1[679].*$call"); - # if I get a PC21 from the same callsign as self then treat it - # as a PC39: I have gone away + # if I get a PC21 from the same callsign as self then ignore it if ($call eq $self->call) { - $self->disconnect(1); + dbg("PCPROT: self referencing PC21 from $self->{call}"); return; } RouteDB::delete($call, $self->{call}); - # check if we believe this - unless ($call eq $self->{call} || $self->is_believed($call)) { - if (my $ivp = Investigate::get($call, $self->{call})) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr'); - } + my $parent = Route::Node::get($self->{call}); + unless ($parent) { + dbg("PCPROT: my parent $self->{call} has disappeared"); + $self->disconnect; return; } - # check to see if we are in the pc19list, if we are then don't bother with any of - # this routing table manipulation, just remove it from the list and dump it my @rout; - if (my $nl = $pc19list{$call}) { - $pc19list{$call} = [ grep {$_->[0] ne $self->{call}} @$nl ]; - delete $pc19list{$call} unless @{$pc19list{$call}}; - } else { - - my $parent = Route::Node::get($self->{call}); - unless ($parent) { - dbg("DXPROT: my parent $self->{call} has disappeared"); - $self->disconnect; - return; - } - if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me! - my $node = Route::Node::get($call); - if ($node) { - - my $dxchan = DXChannel::get($call); - if ($dxchan && $dxchan != $self) { - dbg("PCPROT: PC21 from $self->{call} trying to alter locally connected $call, ignored!") if isdbg('chanerr'); - return; - } - - # input filter it - return unless $self->in_filter_route($node); - - # routing objects - push @rout, $node->del($parent); + + if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me! + my $node = Route::Node::get($call); + if ($node) { + + my $dxchan = DXChannel::get($call); + if ($dxchan && $dxchan != $self) { + dbg("PCPROT: PC21 from $self->{call} trying to alter locally connected $call, ignored!") if isdbg('chanerr'); + return; } - } else { - dbg("PCPROT: I WILL _NOT_ be disconnected!") if isdbg('chanerr'); - return; + + # input filter it + return unless $self->in_filter_route($node); + + # routing objects + push @rout, $node->del($parent); } + } else { + dbg("PCPROT: I WILL _NOT_ be disconnected!") if isdbg('chanerr'); + return; } $self->route_pc21($origin, $line, @rout) if @rout; @@ -1560,48 +1468,7 @@ sub handle_51 if ($flag == 1) { $self->send(pc51($from, $to, '0')); } else { - # it's a reply, look in the ping list for this one - my $ref = $pings{$from}; - if ($ref) { - my $tochan = DXChannel::get($from); - while (@$ref) { - my $r = shift @$ref; - my $dxchan = DXChannel::get($r->{call}); - next unless $dxchan; - my $t = tv_interval($r->{t}, [ gettimeofday ]); - if ($dxchan->is_user) { - my $s = sprintf "%.2f", $t; - my $ave = sprintf "%.2f", $tochan ? ($tochan->{pingave} || $t) : $t; - $dxchan->send($dxchan->msg('pingi', $from, $s, $ave)) - } elsif ($dxchan->is_node) { - if ($tochan) { - my $nopings = $tochan->user->nopings || $obscount; - push @{$tochan->{pingtime}}, $t; - shift @{$tochan->{pingtime}} if @{$tochan->{pingtime}} > 6; - - # cope with a missed ping, this means you must set the pingint large enough - if ($t > $tochan->{pingint} && $t < 2 * $tochan->{pingint} ) { - $t -= $tochan->{pingint}; - } - - # calc smoothed RTT a la TCP - if (@{$tochan->{pingtime}} == 1) { - $tochan->{pingave} = $t; - } else { - $tochan->{pingave} = $tochan->{pingave} + (($t - $tochan->{pingave}) / 6); - } - $tochan->{nopings} = $nopings; # pump up the timer - if (my $ivp = Investigate::get($from, $self->{call})) { - $ivp->handle_ping; - } - } elsif (my $rref = Route::Node::get($r->{call})) { - if (my $ivp = Investigate::get($from, $self->{call})) { - $ivp->handle_ping; - } - } - } - } - } + DXXml::Ping::handle_ping_reply($self, $from); } } else { @@ -1683,6 +1550,17 @@ sub handle_85 $self->process_rcmd_reply($_[1], $_[2], $_[3], $_[4]); } +# DXSpider routing entries +sub handle_92 +{ + my $self = shift; + my $pcno = shift; + my $line = shift; + my $origin = shift; + + $self->{do_pc92} ||= 1; +} + # if get here then rebroadcast the thing with its Hop count decremented (if # there is one). If it has a hop count and it decrements to zero then don't # rebroadcast it. @@ -1726,7 +1604,8 @@ sub process } foreach $dxchan (@dxchan) { - next unless $dxchan->is_node(); + next unless $dxchan->is_node; + next if $dxchan->handle_xml; next if $dxchan == $main::me; # send the pc50 @@ -1737,9 +1616,10 @@ sub process if ($dxchan->{nopings} <= 0) { $dxchan->disconnect; } else { - addping($main::mycall, $dxchan->call); + DXXml::Ping::add($main::me, $dxchan->call); $dxchan->{nopings} -= 1; $dxchan->{lastping} = $t; + $dxchan->{lastping} += $dxchan->{pingint} / 2 unless @{$dxchan->{pingtime}}; } } } @@ -2194,29 +2074,6 @@ sub load_hops return (); } - -# add a ping request to the ping queues -sub addping -{ - my ($from, $to, $via) = @_; - my $ref = $pings{$to} || []; - my $r = {}; - $r->{call} = $from; - $r->{t} = [ gettimeofday ]; - if ($via && (my $dxchan = DXChannel::get($via))) { - $dxchan->send(pc51($to, $main::mycall, 1)); - } else { - route(undef, $to, pc51($to, $main::mycall, 1)); - } - push @$ref, $r; - $pings{$to} = $ref; - my $u = DXUser->get_current($to); - if ($u) { - $u->lastping(($via || $from), $main::systime); - $u->put; - } -} - sub process_rcmd { my ($self, $tonode, $fromnode, $user, $cmd) = @_; @@ -2342,19 +2199,6 @@ sub disconnect RouteDB::delete_interface($call); - # remove them from the pc19list as well - while (my ($k,$v) = each %pc19list) { - my @l = grep {$_->[0] ne $call} @{$pc19list{$k}}; - if (@l) { - $pc19list{$k} = \@l; - } else { - delete $pc19list{$k}; - } - - # and the ephemera - eph_del_regex("^PC1[679].*$k"); - } - # unbusy and stop and outgoing mail my $mref = DXMsg::get_busy($call); $mref->stop_msg($call) if $mref; @@ -2452,6 +2296,7 @@ sub broadcast_route next if $dxchan == $self; next if $dxchan == $main::me; next unless $dxchan->isa('DXProt'); + next if $self->{do_pc92}; next if ($generate == \&pc16 || $generate==\&pc17) && !$dxchan->user->wantsendpc16; $dxchan->send_route($origin, $generate, @_); @@ -2459,6 +2304,27 @@ sub broadcast_route } } +sub broadcast_route_pc9x +{ + my $self = shift; + my $origin = shift; + my $generate = shift; + my $line = shift; + my @dxchan = DXChannel::get_all_nodes(); + my $dxchan; + + unless ($self->{isolate}) { + foreach $dxchan (@dxchan) { + next if $dxchan == $self; + next if $dxchan == $main::me; + next unless $dxchan->isa('DXProt'); + next unless $self->{do_pc92}; + + $dxchan->send_route($origin, $generate, @_); + } + } +} + sub route_pc16 { my $self = shift; @@ -2517,6 +2383,30 @@ sub route_pc50 broadcast_route($self, $origin, \&pc50, $line, 1, @_); } +sub route_pc92c +{ + my $self = shift; + my $origin = shift; + my $line = shift; + broadcast_route_pc9x($self, $origin, \&pc92c, $line, 1, @_); +} + +sub route_pc92a +{ + my $self = shift; + my $origin = shift; + my $line = shift; + broadcast_route_pc9x($self, $origin, \&pc92a, $line, 1, @_); +} + +sub route_pc92d +{ + my $self = shift; + my $origin = shift; + my $line = shift; + broadcast_route_pc9x($self, $origin, \&pc92d, $line, 1, @_); +} + sub in_filter_route { my $self = shift;