new keepalive system + timings for PC92 C recs

Added the new K record for keepalives.
Increased the PC92 C interval to 24 hours.
Increased dependent node C interval to 2 hours.
PC50 can reset obs.
PC50 now routed everywhere without filters except isolation,
this may change back in time, when K record is ubiquitous.

Still need to actually issue K record
This commit is contained in:
Dirk Koopman 2007-09-17 22:44:15 +01:00
parent 7e2b5e1e1f
commit 2c50f9b4b2
6 changed files with 151 additions and 75 deletions

View File

@ -122,6 +122,7 @@ $count = 0;
do_pc9x => '9,Handles PC9x,yesno',
inqueue => '9,Input Queue,parray',
next_pc92_update => '9,Next PC92 Update,atime',
next_pc92_keepalive => '9,Next PC92 KeepAlive,atime',
);
# object destruction

View File

@ -46,6 +46,8 @@ use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restim
$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
@ -73,13 +75,12 @@ $chatdupeage = 20 * 60;
$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 =
@ -214,11 +215,19 @@ sub check
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";
@ -239,7 +248,7 @@ sub init
$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);
}
#
@ -348,8 +357,12 @@ sub start
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;
}
#
@ -430,12 +443,6 @@ sub process
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;
@ -466,16 +473,20 @@ sub process
if ($t - $last10 >= 10) {
# clean out ephemera
eph_clean();
import_chat();
if ($main::systime >= $next_pc92_obs_timeout) {
time_out_pc92_routes();
$next_pc92_obs_timeout = $main::systime + $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();
}
# send out config broadcasts
foreach $dxchan (@dxchan) {
next unless $dxchan->is_node;
@ -487,14 +498,32 @@ sub process
# 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;
}
}
}
@ -936,7 +965,7 @@ sub broadcast_pc92_update
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
@ -1462,11 +1491,13 @@ sub route_pc41
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, @_);
}

View File

@ -132,6 +132,8 @@ sub handle_11
}
}
# 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*$/) {
@ -1210,6 +1212,8 @@ sub handle_50
my $line = shift;
my $origin = shift;
return if (eph_dup($line));
my $call = $_[1];
RouteDB::update($call, $self->{call});
@ -1217,12 +1221,16 @@ sub handle_50
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);
}
}
@ -1500,6 +1508,58 @@ sub check_pc9x_t
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
{
@ -1585,6 +1645,22 @@ 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
@ -1612,46 +1688,13 @@ sub handle_92
# 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
@ -1676,13 +1719,8 @@ sub handle_92
} 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) {

View File

@ -12,7 +12,7 @@
package DXProt;
# the interval between pc50s (in seconds)
$pc50_interval = 14*60;
$pc50_interval = 60*60;
# the version of DX cluster (tm) software I am masquerading as
$myprot_version = 5300;

View File

@ -416,6 +416,12 @@ sub pc92c
return _gen_pc92('C', 1, @_);
}
# send a keep alive
sub pc92k
{
return _gen_pc92('K', 1, @_);
}
# send a 'find' message
sub pc92f
{

View File

@ -11,6 +11,6 @@ use vars qw($version $subversion $build);
$version = '1.54';
$subversion = '0';
$build = '144';
$build = '145';
1;