X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=710a3dbf84129a4b0405fc92597c8ff2cd7e2161;hb=638d9efe6fe3d3c4eec08d5e985fce4dd760423b;hp=25d862cfa52910b8d9b8922fa5e6331c73b1cf45;hpb=4f2384c7d1e6ea06fc2d258a02b54409bf324f12;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index 25d862cf..710a3dbf 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -24,6 +24,8 @@ use DXProtout; use DXDebug; use Filter; use Local; +use DXDb; +use Time::HiRes qw(gettimeofday tv_interval); use Carp; @@ -37,10 +39,10 @@ $me = undef; # the channel id for this cluster $decode_dk0wcy = undef; # if set use this callsign to decode announces from the EU WWV data beacon $pc11_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc11 $pc23_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc23 -$pc11_dup_age = 24*3600; # the maximum time to keep the spot dup list for -$pc23_dup_age = 24*3600; # the maximum time to keep the wwv dup list for -$pc12_dup_age = 12*3600; # the maximum time to keep the ann dup list for -$pc12_dup_lth = 72; # the length of ANN text to save for deduping +$pc11_dup_age = 3*3600; # the maximum time to keep the spot dup list for +$pc23_dup_age = 3*3600; # the maximum time to keep the wwv dup list for +$pc12_dup_age = 24*3600; # the maximum time to keep the ann dup list for +$pc12_dup_lth = 60; # the length of ANN text to save for deduping %spotdup = (); # the pc11 and 26 dup hash %wwvdup = (); # the pc23 and 27 dup hash %anndup = (); # the PC12 dup hash @@ -50,6 +52,7 @@ $last_hour = time; # last time I did an hourly periodic update %nodehops = (); # node specific hop control @baddx = (); # list of illegal spotted callsigns + $baddxfn = "$main::data/baddx.pl"; sub init @@ -123,14 +126,30 @@ sub start $self->send_now('B',"0"); $self->send_now('E',"0"); + # ping neighbour node stuff + my $ping = $user->pingint; + $ping = 5*60 unless defined $ping; + $self->{pingint} = $ping; + $self->{nopings} = $user->nopings || 2; + $self->{pingtime} = [ ]; + $self->{pingave} = 0; + # send initialisation string - if (!$self->{outbound}) { + unless ($self->{outbound}) { $self->send(pc38()) if DXNode->get_all(); $self->send(pc18()); + $self->{lastping} = $main::systime; + } else { + # remove from outstanding connects queue + @main::outstanding_connects = grep {$_->{call} ne $call} @main::outstanding_connects; + $self->{lastping} = $main::systime + $self->pingint / 2; } $self->state('init'); $self->pc50_t(time); + # send info to all logged in thingies + $self->tell_login('loginn'); + Log('DXProt', "$call connected"); } @@ -172,7 +191,7 @@ sub normal # is it for me or one of mine? my $call = ($field[5] gt ' ') ? $field[5] : $field[2]; - if ($call eq $main::mycall || grep $_ eq $call, get_all_user_calls()) { + if ($call eq $main::mycall || grep $_ eq $call, DXChannel::get_all_user_calls()) { # yes, it is my $text = unpad($field[3]); @@ -181,7 +200,7 @@ sub normal my $ref = DXChannel->get($call); $ref->send("$call de $field[1]: $text") if $ref && $ref->{talk}; } else { - route($field[2], $line); # relay it on its way + $self->route($field[2], $line); # relay it on its way } return; } @@ -191,7 +210,7 @@ sub normal # route 'foreign' pc26s if ($pcno == 26) { if ($field[7] ne $main::mycall) { - route($field[7], $line); + $self->route($field[7], $line); return; } } @@ -267,7 +286,7 @@ sub normal if ($pcno == 12) { # announces # announce duplicate checking my $text = substr(uc unpad($field[3]), 0, $pc12_dup_lth); - my $dupkey = $field[1].$field[2].$text.$field[4].$field[6]; + my $dupkey = $field[1].$field[2].$text; if ($anndup{$dupkey}) { dbg('chan', "Duplicate Announce ignored\n"); return; @@ -291,11 +310,11 @@ sub normal if ($decode_dk0wcy && $field[1] eq $decode_dk0wcy) { my ($hour, $k, $next, $a, $r, $sfi, $alarm) = $field[3] =~ /^Aurora Beacon\s+(\d+)UTC,\s+Kiel\s+K=(\d+),.*ed\s+K=(\d+),\s+A=(\d+),\s+R=(\d+),\s+SFI=(\d+),.*larm:\s+(\w+)/; $alarm = ($alarm =~ /^Y/i) ? ', Aurora in DE' : ''; - my $wwv = Geomag::update($main::systime, $hour, $sfi, $a, $k, "R=$r, Next K=$next$alarm", $decode_dk0wcy, $field[5], $r); + my $wwv = Geomag::update($main::systime, $hour, $sfi, $a, $k, "R=$r, Next K=$next$alarm", $decode_dk0wcy, $field[5], $r) if $sfi && $r; } } else { - route($field[2], $line); + $self->route($field[2], $line); } return; @@ -360,13 +379,20 @@ sub normal if ($pcno == 17) { # remove a user my $node = DXCluster->get_exact($field[2]); + my $dxchan; + if (!$node && ($dxchan = DXChannel->get($field[2]))) { + # add it to the node table if it isn't present and it's + # connected locally + $node = DXNode->new($dxchan, $field[2], 0, 1, 5400); + broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate}; + return; + } return unless $node; return unless $node->isa('DXNode'); if ($node->dxchan != $self) { dbg('chan', "LOOP: $field[2] came in on wrong channel"); return; } - my $dxchan; if (($dxchan = DXChannel->get($field[2])) && $dxchan != $self) { dbg('chan', "LOOP: $field[2] connected locally"); return; @@ -491,7 +517,7 @@ sub normal # route 'foreign' pc27s if ($pcno == 27) { if ($field[8] ne $main::mycall) { - route($field[8], $line); + $self->route($field[8], $line); return; } } @@ -508,7 +534,7 @@ sub normal dbg('chan', "Dup WWV Spot ignored\n"); return; } - if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 900 || $field[2] < 0 || $field[2] > 23) { + if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 1500 || $field[2] < 0 || $field[2] > 23) { dbg('chan', "WWV Date ($field[1] $field[2]) out of range"); return; } @@ -541,7 +567,7 @@ sub normal if ($pcno == 25) { # merge request if ($field[1] ne $main::mycall) { - route($field[1], $line); + $self->route($field[1], $line); return; } if ($field[2] eq $main::mycall) { @@ -575,7 +601,7 @@ sub normal if ($pcno == 49 || $field[1] eq $main::mycall) { DXMsg::process($self, $line); } else { - route($field[1], $line); + $self->route($field[1], $line); } return; } @@ -605,7 +631,7 @@ sub normal $self->send(pc35($main::mycall, $field[2], "$main::mycall:your attempt is logged, Tut tut tut...!")); } } else { - route($field[1], $line); + $self->route($field[1], $line); } return; } @@ -619,7 +645,7 @@ sub normal delete $rcmds{$field[2]} if !$dxchan; } } else { - route($field[1], $line); + $self->route($field[1], $line); } return; } @@ -663,11 +689,7 @@ sub normal last SWITCH; } if ($pcno == 37 || $pcno == 44 || $pcno == 45 || $pcno == 46 || $pcno == 47) { - if ($field[1] eq $main::mycall) { - ; - } else { - route($field[1], $line); - } + DXDb::process($self, $line); return; } @@ -692,15 +714,34 @@ sub normal # it's a reply, look in the ping list for this one my $ref = $pings{$field[2]}; if ($ref) { - my $r = shift @$ref; - my $dxchan = DXChannel->get($r->{call}); - $dxchan->send($dxchan->msg('pingi', $field[2], atime($main::systime), $main::systime - $r->{t})) if $dxchan; + my $tochan = DXChannel->get($field[2]); + 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', $field[2], $s, $ave)) + } elsif ($dxchan->is_ak1a) { + if ($tochan) { + $tochan->{nopings} = 2; # pump up the timer + push @{$tochan->{pingtime}}, $t; + shift @{$tochan->{pingtime}} if @{$tochan->{pingtime}} > 6; + my $st; + for (@{$tochan->{pingtime}}) { + $st += $_; + } + $tochan->{pingave} = $st / @{$tochan->{pingtime}}; + } + } + } } } - } else { # route down an appropriate thingy - route($field[1], $line); + $self->route($field[1], $line); } return; } @@ -714,7 +755,7 @@ sub normal # REBROADCAST!!!! # - if (!$self->{isolate}) { + unless ($self->{isolate}) { broadcast_ak1a($line, $self); # send it to everyone but me } } @@ -737,6 +778,17 @@ sub process if ($t >= $dxchan->pc50_t + $DXProt::pc50_interval) { $dxchan->send(pc50()); $dxchan->pc50_t($t); + } + + # send a ping out on this channel + if ($dxchan->{pingint} && $t >= $dxchan->{pingint} + $dxchan->{lastping}) { + if ($dxchan->{nopings} <= 0) { + $dxchan->disconnect; + } else { + addping($main::mycall, $dxchan->call); + $dxchan->{nopings} -= 1; + $dxchan->{lastping} = $t; + } } } @@ -767,8 +819,11 @@ sub finish { my $self = shift; my $call = $self->call; + my $nopc39 = shift; my $ref = DXCluster->get_exact($call); + $self->send_now("D", DXProt::pc39($main::mycall, $self->msg('disc1', "System Op"))) unless $nopc39; + # unbusy and stop and outgoing mail my $mref = DXMsg::get_busy($call); $mref->stop_msg($call) if $mref; @@ -788,7 +843,10 @@ sub finish # now broadcast to all other ak1a nodes that I have gone broadcast_ak1a(pc21($call, 'Gone.'), $self) unless $self->{isolate}; - + + # send info to all logged in thingies + $self->tell_login('logoutn'); + Log('DXProt', $call . " Disconnected"); $ref->del() if $ref; } @@ -996,9 +1054,13 @@ sub send_local_config # sub route { - my ($call, $line) = @_; + my ($self, $call, $line) = @_; my $cl = DXCluster->get_exact($call); - if ($cl) { + if ($cl) { # don't route it back down itself + if (ref $self && $call eq $self->{call}) { + dbg('chan', "Trying to route back to source, dropped"); + return; + } my $hops; my $dxchan = $cl->{dxchan}; if ($dxchan) { @@ -1016,7 +1078,7 @@ sub broadcast_ak1a { my $s = shift; # the line to be rebroadcast my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_ak1a(); + my @dxchan = DXChannel::get_all_ak1a(); my $dxchan; # send it if it isn't the except list and isn't isolated and still has a hop count @@ -1033,7 +1095,7 @@ sub broadcast_all_ak1a { my $s = shift; # the line to be rebroadcast my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_ak1a(); + my @dxchan = DXChannel::get_all_ak1a(); my $dxchan; # send it if it isn't the except list and isn't isolated and still has a hop count @@ -1052,7 +1114,7 @@ sub broadcast_users my $sort = shift; # the type of transmission my $fref = shift; # a reference to an object to filter on my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_users(); + my @dxchan = DXChannel::get_all_users(); my $dxchan; my @out; @@ -1093,43 +1155,6 @@ sub broadcast_list } } -# -# gimme all the ak1a nodes -# -sub get_all_ak1a -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref if $ref->is_ak1a; - } - return @out; -} - -# return a list of all users -sub get_all_users -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref if $ref->is_user; - } - return @out; -} - -# return a list of all user callsigns -sub get_all_user_calls -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref->call if $ref->is_user; - } - return @out; -} # # obtain the hops from the list for this callsign and pc no @@ -1200,13 +1225,13 @@ sub unpad sub addping { my ($from, $to) = @_; - my $ref = $pings{$to}; - $ref = $pings{$to} = [] if !$ref; + my $ref = $pings{$to} || []; my $r = {}; $r->{call} = $from; - $r->{t} = $main::systime; - route($to, pc51($to, $main::mycall, 1)); + $r->{t} = [ gettimeofday ]; + route(undef, $to, pc51($to, $main::mycall, 1)); push @$ref, $r; + $pings{$to} = $ref; } # add a rcmd request to the rcmd queues @@ -1217,7 +1242,7 @@ sub addrcmd $r->{call} = $from; $r->{t} = $main::systime; $r->{cmd} = $cmd; - route($to, pc34($main::mycall, $to, $cmd)); + route(undef, $to, pc34($main::mycall, $to, $cmd)); $rcmds{$to} = $r; } 1;