use Filter;
use Prefix;
use Route;
+use Time::HiRes qw(gettimeofday tv_interval);
use strict;
-use vars qw(%channels %valid @ISA $count);
+use vars qw(
+ %channels %pings %valid @ISA $count
+ $pingint $obscount
+ );
-%channels = ();
+%pings = (); # outstanding ping requests outbound
+%channels = (); # the channel list
$count = 0;
+$pingint = 5*60; # default pinginterval
+$obscount = 2; # default obscount for pings
%valid = (
call => '0,Callsign',
inwcyfilter => '5,WCY Filt-inp',
inspotsfilter => '5,Spot Filt-inp',
inroutefilter => '5,Route Filt-inp',
- passwd => '9,Passwd List,parray',
+ passwd => '9,Passwd List,yesno',
pingint => '5,Ping Interval ',
nopings => '5,Ping Obs Count',
lastping => '5,Ping last sent,atime',
badcount => '1,Bad Word Count',
edit => '7,Edit Function',
registered => '9,Registered?,yesno',
+ prompt => '0,Required Prompt',
+ version => '1,Node Version',
+ build => '1,Node Build',
+ verified => '9,Verified?,yesno',
);
use vars qw($VERSION $BRANCH);
$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
-$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ ) || 0;
+$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ || (0,0));
$main::build += $VERSION;
$main::branch += $BRANCH;
return values(%channels);
}
+#
+# route a message down an appropriate interface for a callsign
+#
+# is called route(to, pcline);
+#
+
+sub route
+{
+ my ($self, $call, $line) = @_;
+
+ if (ref $self && $call eq $self->{call}) {
+ dbg("PCPROT: Trying to route back to source, dropped") if isdbg('chanerr');
+ return;
+ }
+
+ # always send it down the local interface if available
+ my $dxchan = DXChannel->get($call);
+ unless ($dxchan) {
+ my $cl = Route::get($call);
+ $dxchan = $cl->dxchan if $cl;
+ if (ref $dxchan) {
+ if (ref $self && $dxchan eq $self) {
+ dbg("PCPROT: Trying to route back to source, dropped") if isdbg('chanerr');
+ return;
+ }
+ }
+ }
+ if ($dxchan) {
+ my $routeit = $dxchan->adjust_hops($line); # adjust its hop count by node name
+ if ($routeit) {
+ $dxchan->send($routeit) unless $dxchan == $main::me;
+ }
+ } else {
+ dbg("PCPROT: No route available, dropped") if isdbg('chanerr');
+ }
+}
+
#
# gimme all the ak1a nodes
#
my $self = shift;
return $self->{'sort'} =~ /[ACRSX]/;
}
+
+# is a node and uses old protocol
+sub is_op
+{
+ my $self = shift;
+ return $self->is_node && !$self->user->wantnp;
+}
+
+# is a node and uses new protocol
+sub is_np
+{
+ my $self = shift;
+ return $self->is_node && $self->user->wantnp;
+}
+
# is it an ak1a node ?
sub is_ak1a
{
{
my $self = shift;
my $user = $self->{user};
+
+ # remove outstanding pings
+ delete $pings{$self->{call}};
$user->close() if defined $user;
$self->{conn}->disconnect;
# the above regexp must work
unless (defined $sort && defined $call && defined $line) {
# $data =~ s/([\x00-\x1f\x7f-\xff])/uc sprintf("%%%02x",ord($1))/eg;
- dbg("DUFF Line on $chcall: $data") if isdbg('err');
+ dbg("DUFF Line on $chcall: $data");
return ();
}
if(ref($dxchan) && $call ne $chcall) {
- dbg("DUFF Line come in for $call on wrong channel $chcall") if isdbg('err');
+ dbg("DUFF Line come in for $call on wrong channel $chcall");
return();
}
if ($nref && $dxchan) {
if ($dxchan == $self) {
return 1 unless $user;
+ return 1 if $user eq $node;
my @users = $nref->users;
return 1 if @users == 0 || grep $user eq $_, @users;
- dbg("RSPF: $user not on $node") if isdbg('rspf');
+ dbg("RSPF: $user not on $node") if isdbg('chanerr');
} else {
- dbg("RSPF: Shortest path for $node is " . $nref->dxchan->{call}) if isdbg('rspf');
+ dbg("RSPF: Shortest path for $node is " . $nref->dxchan->{call}) if isdbg('chanerr');
}
} else {
return 1 if $flag;
- dbg("RSPF: required $node not found" ) if isdbg('rspf');
+ dbg("RSPF: required $node not found" ) if isdbg('chanerr');
}
return 0;
}
}
}
+sub handlepingreply
+{
+ my ($self, $from) = @_;
+
+ 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 || 2;
+ 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
+ }
+ }
+ }
+ }
+}
-no strict;
+#no strict;
sub AUTOLOAD
{
my $self = shift;
+ no strict;
my $name = $AUTOLOAD;
return if $name =~ /::DESTROY$/;
- $name =~ s/.*:://o;
+ $name =~ s/^.*:://o;
confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
# this clever line of code creates a subroutine which takes over from autoload
# from OO Perl - Conway
- *{$AUTOLOAD} = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}} ;
- @_ ? $self->{$name} = shift : $self->{$name} ;
+ *$AUTOLOAD = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}};
+ &$AUTOLOAD($self, @_);
+# *{$AUTOLOAD} = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}} ;
+# @_ ? $self->{$name} = shift : $self->{$name} ;
}