new keepalive system + timings for PC92 C recs
authorDirk Koopman <djk@tobit.co.uk>
Mon, 17 Sep 2007 21:44:15 +0000 (22:44 +0100)
committerDirk Koopman <djk@tobit.co.uk>
Mon, 17 Sep 2007 21:44:15 +0000 (22:44 +0100)
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

perl/DXChannel.pm
perl/DXProt.pm
perl/DXProtHandle.pm
perl/DXProtVars.pm
perl/DXProtout.pm
perl/Version.pm

index 460eb525d05d503e32c00a4b4d3184cc238a178d..7d340a6165f5cfde293b725b28efea2edf9c95b7 100644 (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
index eec6b67b2d731730b7df2d52f42c5ee530208d23..41f1debe7bc3a9f1f90bc06218f140c037d98790 100644 (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) {
+               $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;
@@ -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, @_);
 }
 
index 4d69b1aa872b4cadb45feb6786091d5721faea4e..96e62c707f1684d85860361782e567c88c14aa09 100644 (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) {
index ca1538d7e956c7eab778f9b565ba8d4b9ebfdbd7..ae192bcff38d83b6c4dec4c76029dd293507a44c 100644 (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;
index 2325e7a5cb36c9c9d1bfd51531c3638d3e315314..ec9abaa0b0f2c41e945fd205bb24c6dc7dc883e5 100644 (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
 {
index d3d3984ec4d97d84e00fb62a7698765f1ea0b582..b2ca65854e09146f70493784a6ecfbb1f0a445b8 100644 (file)
@@ -11,6 +11,6 @@ use vars qw($version $subversion $build);
 
 $version = '1.54';
 $subversion = '0';
-$build = '144';
+$build = '145';
 
 1;