X-Git-Url: http://gb7djk.dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProtHandle.pm;h=e961b02b82231cefe4e7ec6dbed02e4f32723a5e;hb=a559548c82ccb2171c2942be53fc796d8a4390cf;hp=802b9914d5019d961fbc25fd536de237f1c87505;hpb=e8c9de4454a23bab71b5a06d2e0059877f02413d;p=spider.git diff --git a/perl/DXProtHandle.pm b/perl/DXProtHandle.pm index 802b9914..e961b02b 100644 --- a/perl/DXProtHandle.pm +++ b/perl/DXProtHandle.pm @@ -32,7 +32,6 @@ use DXHash; use Route; use Route::Node; use Script; -use Investigate; use RouteDB; @@ -44,6 +43,7 @@ use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restim $investigation_int $pc19_version $myprot_version %nodehops $baddx $badspotter $badnode $censorpc $rspfcheck $allowzero $decode_dk0wcy $send_opernam @checklist + $eph_pc15_restime ); # incoming talk commands @@ -375,6 +375,22 @@ sub handle_12 $self->route($_[2], $line); } } + +sub handle_15 +{ + my $self = shift; + my $pcno = shift; + my $line = shift; + my $origin = shift; + + if (eph_dup($line, $eph_pc15_restime)) { + dbg("PCPROT: Ephemeral dup, dropped") if isdbg('chanerr'); + } else { + unless ($self->{isolate}) { + DXChannel::broadcast_nodes($line, $self) if $line =~ /\^H\d+\^?~?$/; # send it to everyone but me + } + } +} # incoming user sub handle_16 @@ -473,8 +489,10 @@ sub handle_16 $user->lastin($main::systime) unless DXChannel::get($call); $user->put; } - $self->route_pc16($origin, $line, $parent, @rout) if @rout; - + if (@rout) { + $self->route_pc16($origin, $line, $parent, @rout); + $self->route_pc92a($main::mycall, undef, $parent, @rout) if $self->{state} eq 'normal'; + } } # remove a user @@ -541,6 +559,7 @@ sub handle_17 $uref = Route->new($ucall) unless $uref; # throw away $self->route_pc17($origin, $line, $parent, $uref); + $self->route_pc92d($main::mycall, undef, $parent, $uref); } # link request @@ -579,6 +598,23 @@ sub handle_18 $self->send(pc20()); } +sub check_add_node +{ + my $call = shift; + + # add this station to the user database, if required (don't remove SSID from nodes) + my $user = DXUser->get_current($call); + if (!$user) { + $user = DXUser->new($call); + $user->priv(1); # I have relented and defaulted nodes + $user->lockout(1); + $user->homenode($call); + $user->node($call); + } + $user->sort('A') unless $user->is_node; + return $user; +} + # incoming cluster list sub handle_19 { @@ -610,7 +646,8 @@ sub handle_19 # 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. + # From now on we are only going to believe PC92 data and locally connected + # non-pc92 nodes. # for ($i = 1; $i < $#_-1; $i += 4) { my $here = $_[$i]; @@ -635,17 +672,8 @@ sub handle_19 next; } - # add this station to the user database, if required (don't remove SSID from nodes) - my $user = DXUser->get_current($call); - if (!$user) { - $user = DXUser->new($call); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($call); - $user->node($call); - } - $user->sort('A') unless $user->is_node; - + my $user = check_add_node($call); + # if (eph_dup($genline)) { # dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr'); # next; @@ -704,10 +732,24 @@ sub handle_19 if (@rout) { $self->route_pc21($self->{call}, $line, @rout); $self->route_pc19($self->{call}, $line, @rout); - $self->route_pc92a($main::mycall, $line, @rout); + $self->route_pc92a($main::mycall, $line, $main::routeroot, @rout) if $self->{state} eq 'normal'; } } +sub send_delayed_pc92 +{ + my $self = shift; + + # send out delayed PC92 config for this node if it is external + unless ($self->{do_pc92}) { + my $node = Route::Node::get($self->{call}); + if ($node) { + my @rout = map {my $r = Route::User::get($_); $r ? ($r) : ()} $node->users; + $self->route_pc92c($main::mycall, undef, $node, @rout); + } + } +} + # send local configuration sub handle_20 { @@ -719,6 +761,7 @@ sub handle_20 $self->send(pc22()); $self->state('normal'); $self->{lastping} = 0; + $self->send_delayed_pc92; } # delete a cluster from the list @@ -776,7 +819,7 @@ sub handle_21 if (@rout) { $self->route_pc21($origin, $line, @rout); - $self->route_pc92d($main::mycall, $line, @rout); + $self->route_pc92d($main::mycall, $line, $main::routeroot, @rout); } } @@ -789,6 +832,8 @@ sub handle_22 my $origin = shift; $self->state('normal'); $self->{lastping} = 0; + + $self->send_delayed_pc92 } # WWV info @@ -1237,7 +1282,7 @@ sub _decode_pc92_call my $icall = shift; my @part = split /:/, $icall; my ($flag, $call) = unpack "A A*", $part[0]; - return () unless $flag && $flag ge '0' && $flag le '7'; + return () unless defined $flag && $flag ge '0' && $flag le '7'; return () unless $call && is_callsign($call); my $is_node = $flag & 4; my $is_extnode = $flag & 2; @@ -1254,19 +1299,95 @@ sub _encode_pc92_call my $call = $ref->call; my $extra = ''; $flag |= $ref->here ? 1 : 0; - if ($ext && ($ref->isa('Route::Node') || $ref->isa('DXProt'))) { + if ($ref->isa('Route::Node') || $ref->isa('DXProt')) { $flag |= 4; -# if ($ref->version || $ref->build) { - if ($ref->version) { - my $version = $ref->version || 1.0; - $version = $version * 100 + 5300 if $version < 50; - $extra .= ":" . $version; -# $extra .= (":" . ($ref->build ? $ref->build : '')) if $ref->build; + my $dxchan = DXChannel::get($call); + $flag |= 2 if $call ne $main::mycall && $dxchan && !$dxchan->{do_pc92}; + if ($ext) { + if ($ref->version) { + my $version = $ref->version || 1.0; + $version = $version * 100 + 5300 if $version < 50; + $extra .= ":" . $version; + } } } return "$flag$call$extra"; } +sub _add_thingy +{ + my $parent = shift; + my $s = shift; + my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($s); + my @rout; + + if ($call) { + if ($is_node) { + @rout = $parent->add($call, $version, Route::here($here)); + } else { + @rout = $parent->add_user($call, Route::here($here)); + } + } + return @rout; +} + +sub _del_thingy +{ + my $parent = shift; + my $s = shift; + my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($s); + my @rout; + if ($call) { + if ($is_node) { + my $nref = Route::Node::get($call); + @rout = $nref->del($parent) if $nref; + } else { + my $uref = Route::User::get($call); + @rout = $parent->del_user($uref) if $uref; + } + } + return @rout; +} + +my $_last_time; +my $_last_occurs; + +sub gen_pc9x_t +{ + if (!$_last_time || $_last_time != $main::systime) { + $_last_time = $main::systime; + $_last_occurs = 0; + return $_last_time - $main::systime_daystart; + } else { + $_last_occurs++; + return sprintf "%d.%02d", $_last_time - $main::systime_daystart, $_last_occurs; + } +} + +sub check_pc9x_t +{ + my $call = shift; + my $t = shift; + my $pc = shift; + my $create = shift; + + my $parent = ref $call ? $call : Route::Node::get($call); + if ($parent) { + my $lastid = $parent->lastid->{$pc} || 0; + $t += 86400 if $t < $lastid - 43200; + if ($lastid >= $t) { + dbg("PCPROT: dup / old id on $call <= $lastid, ignored") if isdbg('chanerr'); + return; + } + $t -= 86400 if $t >= 86400; + } elsif ($create) { + $parent = Route::Node->new($call); + } + $parent->lastid->{$pc} = $t; + + return $parent; +} + # DXSpider routing entries sub handle_92 { @@ -1277,41 +1398,105 @@ sub handle_92 $self->{do_pc92} ||= 1; - my ($ncall, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_[1]); - unless ($ncall) { + my $pcall = $_[1]; + unless ($pcall) { dbg("PCPROT: invalid callsign string '$_[1]', ignored") if isdbg('chanerr'); return; } my $t = $_[2]; my $sort = $_[3]; - if ($ncall eq $main::mycall) { + my @ent = grep {$_ && /^[0-7]/} @_[4 .. $#_]; + + if ($pcall eq $main::mycall) { dbg("PCPROT: looped back, ignored") if isdbg('chanerr'); return; } - my $nref = Route::Node::get($ncall); - if ($nref) { - my $lastid = $nref->lastid->{92} || 0; - if ($lastid > $t) { - dbg("PCPROT: dup / old id <= $lastid, ignored") if isdbg('chanerr'); + my $parent = check_pc9x_t($pcall, $t, 92, 1) || return; + + $parent->lastid->{92} = $t; + $parent->do_pc92(1); + + 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. + my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($ent[0]); + if ($call && $is_node) { + if ($call eq $main::mycall) { + dbg("PCPROT: looped back on node entry, ignored") if isdbg('chanerr'); + return; + } + 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)) { + dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr'); + return; + } + my $parent = check_pc9x_t($call, $t, 92) || return; + } + } else { + dbg("PCPROT: must be mycall or external node as first entry, ignored") if isdbg('chanerr'); return; } - $nref->flags(Route::flags($here)); - } else { - $nref = Route::Node->new($ncall, $version, Route::here($here)); + $parent->here(Route::here($here)); + $parent->version($version) if $version && $version > $parent->version; + $parent->build($build) if $build && $build > $parent->build; + shift @ent; } - $nref->lastid->{92} = $t; + my (@radd, @rdel); + if ($sort eq 'A') { - + for (@ent) { + push @radd, _add_thingy($parent, $_); + } } elsif ($sort eq 'D') { - + for (@ent) { + push @rdel, _del_thingy($parent, $_); + } } elsif ($sort eq 'C') { + my (@nodes, @users); + for (@ent) { + my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_); + if ($call) { + if ($is_node) { + push @nodes, $call; + } else { + push @users, $call; + } + } else { + dbg("DXPROT: pc92 call entry '$_' not decoded, ignored") if isdbg('chanerr'); + } + } + my ($dnodes, $dusers, $nnodes, $nusers) = $parent->calc_config_changes(\@nodes, \@users); + + for (@ent) { + my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_); + if ($call) { + push @radd,_add_thingy($parent, $_) if grep $call eq $_, (@$nnodes, @$nusers); + push @rdel,_del_thingy($parent, $_) if grep $call eq $_, (@$dnodes, @$dusers); + } + } } else { dbg("PCPROT: unknown action '$sort', ignored") if isdbg('chanerr'); + return; + } + + $self->broadcast_route_pc9x($pcall, undef, $line, 0); + foreach my $r (@rdel) { + next unless $r; + + $self->route_pc21($pcall, undef, $r) if $r->isa('Route::Node'); + $self->route_pc17($pcall, undef, $parent, $r) if $r->isa('Route::User'); } + my @pc19 = grep { $_ && $_->isa('Route::Node') } @radd; + my @pc16 = grep { $_ && $_->isa('Route::User') } @radd; + $self->route_pc19($pcall, undef, @pc19) if @pc19; + $self->route_pc16($pcall, undef, $parent, @pc16) if @pc16; } # if get here then rebroadcast the thing with its Hop count decremented (if @@ -1337,3 +1522,5 @@ sub handle_default } } } + +1;