$eph_pc15_restime $pc92_update_period $pc92_obs_timeout
%pc92_find $pc92_find_timeout $pc92_short_update_period
$next_pc92_obs_timeout $pc92_slug_changes $last_pc92_slug
+ $pc92_extnode_update_period $pc50_interval
+ $pc92_keepalive_period
);
$pc11_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc11
$chatimportfn = "$main::root/chat_import";
$investigation_int = 12*60*60; # time between checks to see if we can see this node
$pc19_version = 5454; # the visible version no for outgoing PC19s generated from pc59
-$pc92_update_period = 60*60; # the period between outgoing PC92 C updates
-$pc92_short_update_period = 15*60; # shorten the update period after a connection
+$pc92_update_period = 24*60*60; # the period between outgoing PC92 C updates
+$pc92_short_update_period = 15*60; # shorten the update period after a connection or start up
+$pc92_extnode_update_period = 2*60*60; # the update period for external nodes
+$pc92_keepalive_period = 60*60; # frequency of PC92 K (keepalive) records
%pc92_find = (); # outstanding pc92 find operations
$pc92_find_timeout = 30; # maximum time to wait for a reply
-#$pc92_obs_timeout = $pc92_update_period; # the time between obscount countdowns
-$pc92_obs_timeout = 60*60; # the time between obscount for incoming countdowns
-$next_pc92_obs_timeout = $main::systime + 60*60; # the time between obscount countdowns
@checklist =
sub update_pc92_next
{
my $self = shift;
- my $period = shift || $pc92_update_period;
+ my $period = shift || ($self->{do_pc9x} ? $pc92_update_period : $pc92_extnode_update_period);
$self->{next_pc92_update} = $main::systime + $period - int rand($period / 4);
dbg("ROUTE: update_pc92_next: $self->{call} " . atime($self->{next_pc92_update})) if isdbg('obscount');
}
+sub update_pc92_keepalive
+{
+ my $self = shift;
+ my $period = shift || $pc92_keepalive_period;
+ $self->{next_pc92_keepalive} = $main::systime + $period - int rand($period / 4);
+ dbg("ROUTE: update_pc92_keepalive: $self->{call} " . atime($self->{next_pc92_keepalive})) if isdbg('obscount');
+}
+
sub init
{
do "$main::data/hop_table.pl" if -e "$main::data/hop_table.pl";
$main::me->{version} = $main::version;
$main::me->{build} = "$main::subversion.$main::build";
$main::me->{do_pc9x} = 1;
- $main::me->update_pc92_next($pc92_update_period);
+ $main::me->update_pc92_next($pc92_short_update_period);
}
#
my $script = new Script(lc $call) || new Script('node_default');
$script->run($self) if $script;
- # set next_pc92_update time for this node sooner
- $self->update_pc92_next($self->{outbound} ? $pc92_short_update_period : $pc92_update_period);
+ # set up a config broadcast "quite soon" to converge tables quicker
+ $main::me->update_pc92_next($pc92_short_update_period);
+ $self->update_pc92_next($pc92_short_update_period);
+
+ # set next keepalive time
+ $self->update_pc92_keepalive;
}
#
my $dxchan;
my $pc50s;
- # send out a pc50 on EVERY channel all at once
- if ($t >= $last_pc50 + $DXProt::pc50_interval) {
- $pc50s = pc50($main::me, scalar DXChannel::get_all_users);
- eph_dup($pc50s);
- $last_pc50 = $t;
- }
foreach $dxchan (@dxchan) {
next unless $dxchan->is_node;
if ($t - $last10 >= 10) {
# clean out ephemera
+
eph_clean();
import_chat();
- if ($main::systime >= $next_pc92_obs_timeout) {
+ $last10 = $t;
+
+ # send out a pc50 on EVERY channel all at once
+ if ($t >= $last_pc50 + $pc50_interval) {
+ $pc50s = pc50($main::me, scalar DXChannel::get_all_users);
+ eph_dup($pc50s);
+ $last_pc50 = $t;
time_out_pc92_routes();
- $next_pc92_obs_timeout = $main::systime + $pc92_obs_timeout;
}
- $last10 = $t;
-
# send out config broadcasts
foreach $dxchan (@dxchan) {
next unless $dxchan->is_node;
# records. Someone will win, it does not really matter who, because
# we always believe "us".
if ($main::systime >= $dxchan->{next_pc92_update}) {
- dbg("ROUTE: pc92 broadcast candidate: $dxchan->{call}") if isdbg('obscount');
if ($dxchan == $main::me || !$dxchan->{do_pc9x}) {
+ dbg("ROUTE: pc92 broadcast candidate: $dxchan->{call}") if isdbg('obscount');
my $ref = Route::Node::get($dxchan->{call});
- if ($dxchan == $main::me || ($ref && ($ref->measure_pc9x_t($main::systime-$main::systime_daystart)) >= $pc92_update_period/2)) {
+ if ($dxchan == $main::me || ($ref && ($ref->measure_pc9x_t($main::systime-$main::systime_daystart)) >= $pc92_extnode_update_period/2)) {
$dxchan->broadcast_pc92_update($dxchan->{call});
} else {
- $dxchan->update_pc92_next($pc92_update_period - rand($pc92_update_period/4));
+ $dxchan->update_pc92_next;
}
+ } else {
+ $dxchan->update_pc92_next; # this won't actually do anything, it's just to be tidy
+ }
+ }
+
+ # do the keepalives in the same way, but use a different timer
+ if ($main::systime >= $dxchan->{next_pc92_keepalive}) {
+ if ($dxchan == $main::me || !$dxchan->{do_pc9x}) {
+ dbg("ROUTE: pc92 keepalive candidate: $dxchan->{call}") if isdbg('obscount');
+ my $ref = Route::Node::get($dxchan->{call});
+# if ($dxchan == $main::me || ($ref && ($ref->measure_pc9x_t($main::systime-$main::systime_daystart)) >= $pc92_keepalive_period/2)) {
+# $dxchan->broadcast_pc92_update($dxchan->{call});
+# } else {
+# $dxchan->update_pc92_next($pc92_extnode_update_period);
+# }
+# } else {
+# $dxchan->update_pc92_next; # this won't actually do anything, it's just to be tidy
+ $dxchan->update_pc92_keepalive;
}
}
}
my $l = $nref->last_PC92C(gen_my_pc92_config($nref));
$nref->lastid(last_pc9x_id());
$main::me->broadcast_route_pc9x($main::mycall, undef, $l, 0);
- $self->update_pc92_next($pc92_update_period);
+ $self->update_pc92_next;
}
sub time_out_pc92_routes
broadcast_route($self, $origin, \&pc41, $line, 1, @_);
}
+# this is probably obsolete now
sub route_pc50
{
my $self = shift;
my $origin = shift;
my $line = shift;
+
broadcast_route($self, $origin, \&pc50, $line, 1, @_);
}
}
}
+# my ($hops) = $_[8] =~ /^H(\d+)/;
+
# 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*$/) {
my $line = shift;
my $origin = shift;
+ return if (eph_dup($line));
+
my $call = $_[1];
RouteDB::update($call, $self->{call});
my $node = Route::Node::get($call);
if ($node) {
return unless $node->call eq $self->{call};
- $node->usercount($_[2]);
+ $node->usercount($_[2]) unless $node->users;
+ $node->reset_obs;
# input filter if required
- return unless $self->in_filter_route($node);
+# return unless $self->in_filter_route($node);
- $self->route_pc50($origin, $line, $node, $_[2], $_[3]) unless eph_dup($line);
+ unless ($self->{isolate}) {
+ DXChannel::broadcast_nodes($line, $self); # send it to everyone but me
+ }
+# $self->route_pc50($origin, $line, $node, $_[2], $_[3]) unless eph_dup($line);
}
}
return $parent;
}
+sub pc92_handle_first_slot
+{
+ my $self = shift;
+ my $slot = shift;
+ my $parent = shift;
+ my $t = shift;
+ my $oparent = $parent;
+
+ my @radd;
+
+ my ($call, $is_node, $is_extnode, $here, $version, $build) = @$slot;
+ if ($call && $is_node) {
+ if ($call eq $main::mycall) {
+ dbg("PCPROT: $call looped back onto $main::mycall, ignored") if isdbg('chanerr');
+ return;
+ }
+ # 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. But we remember the lastid
+ # to try to reduce the number of dupe PC92s for this external node.
+ if (DXChannel::get($call) && $call ne $self->{call}) {
+ $parent = check_pc9x_t($call, $t, 92); # this will update the lastid time
+ dbg("PCPROT: locally connected node $call from other another node $self->{call}, 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)) {
+ if ($is_extnode && $oparent) {
+ @radd = _add_thingy($oparent, $slot);
+ $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);
+ $parent->PC92C_dxchan($self->{call});
+ }
+ } 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 || $pc19_version) if $version;
+ $parent->build($build) if $build && $build > $parent->build;
+ $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call;
+ return ($parent, @radd);
+}
+
# DXSpider routing entries
sub handle_92
{
}
return;
}
+
+ } elsif ($sort eq 'K') {
+ # remember the last channel we arrived on
+ $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call;
+
+ my @ent = _decode_pc92_call($_[4]);
+
+ if (@ent) {
+ my $add;
+
+ ($parent, $add) = $self->pc92_handle_first_slot($ent[0], $parent, $t);
+ return unless $parent; # dupe
+
+ push @radd, $add if $add;
+ dbg("ROUTE: reset obscount on $parent->{call} now " . $parent->obscount) if isdbg('obscount');
+ }
} elsif ($sort eq 'A' || $sort eq 'D' || $sort eq 'C') {
# remember the last channel we arrived on
# 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;
- }
- # 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. But we remember the lastid
- # to try to reduce the number of dupe PC92s for this external node.
- if (DXChannel::get($call) && $call ne $self->{call}) {
- $parent = check_pc9x_t($call, $t, 92); # this will update the lastid time
- dbg("PCPROT: locally connected node $call from other another node $self->{call}, 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)) {
- 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);
- $parent->PC92C_dxchan($self->{call});
- }
- } 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 || $pc19_version) if $version;
- $parent->build($build) if $build && $build > $parent->build;
- $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call;
+ my $add;
+
+ ($parent, $add) = $self->pc92_handle_first_slot($ent[0], $parent, $t);
+ return unless $parent; # dupe
+
shift @ent;
+ push @radd, $add if $add;
}
# do a pass through removing any references to either locally connected nodes or mycall
} elsif ($sort eq 'C') {
my (@nodes, @users);
- # we only reset obscounts on config records
- $oparent->reset_obs;
- 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('obscount');
- }
+ # we reset obscounts on config records as well as K records
+ dbg("ROUTE: reset obscount on $parent->{call} now " . $parent->obscount) if isdbg('obscount');
#
foreach my $r (@nent) {