X-Git-Url: http://www.dxcluster.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=d8dad2c3280ad54b6716dedf6e57aa968515ba59;hb=86c5d79248c5e263a20e39c85610d531bbb3b37d;hp=b8123bfecd44c8c153c61f89fabcc568efec791e;hpb=89e4fd14125a1eb60cfd9ad2938614083ddaeb67;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index b8123bfe..d8dad2c3 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -214,7 +214,6 @@ sub init my $user = DXUser->get($main::mycall); die "User $main::mycall not setup or disappeared RTFM" unless $user; - $myprot_version += $main::version*100; $main::me = DXProt->new($main::mycall, 0, $user); $main::me->{here} = 1; $main::me->{state} = "indifferent"; @@ -223,8 +222,9 @@ sub init $main::me->{metric} = 0; $main::me->{pingave} = 0; $main::me->{registered} = 1; - $main::me->{version} = 5251 + $main::version; + $main::me->{version} = $myprot_version + int ($main::version * 100); $main::me->{build} = $main::build; + $main::me->{lastcf} = $main::me->{lasthello} = time; } # @@ -238,12 +238,7 @@ sub new # add this node to the table, the values get filled in later my $pkg = shift; my $call = shift; - $main::routeroot->add($call, '5000', Route::here(1)) if $call ne $main::mycall; - if ($self->{call} ne $main::mycall) { - my $thing = Thingy::Hello->new(user=>$call); - $thing->broadcast($self); - } - + $main::routeroot->add($call, '5000', 1) if $call ne $main::mycall; return $self; } @@ -313,6 +308,11 @@ sub start $self->state('init'); $self->{pc50_t} = $main::systime; + # ALWAYS output the hello + my $thing = Thingy::Hello->new(user => $call, h => $self->{here}); + $thing->broadcast($self); + $self->lasthello($main::systime); + # send info to all logged in thingies $self->tell_login('loginn'); @@ -438,8 +438,8 @@ sub handle_10 # RouteDB::update($to, $_[6]); # it is here and logged on - $dxchan = DXChannel->get($main::myalias) if $to eq $main::mycall; - $dxchan = DXChannel->get($to) unless $dxchan; + $dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall; + $dxchan = DXChannel::get($to) unless $dxchan; if ($dxchan && $dxchan->is_user) { $_[3] =~ s/\%5E/^/g; $dxchan->talk($from, $to, $via, $_[3]); @@ -637,7 +637,7 @@ sub handle_12 my $dxchan; - if ((($dxchan = DXChannel->get($_[2])) && $dxchan->is_user) || $_[4] =~ /^[\#\w.]+$/){ + if ((($dxchan = DXChannel::get($_[2])) && $dxchan->is_user) || $_[4] =~ /^[\#\w.]+$/){ $self->send_chat($line, @_[1..6]); } elsif ($_[2] eq '*' || $_[2] eq $main::mycall) { @@ -697,18 +697,17 @@ sub handle_16 return; } - - RouteDB::update($ncall, $origin); + RouteDB::update($ncall, $self->{call}); # do we believe this call? - unless ($ncall eq $origin || $self->is_believed($ncall)) { - if (my $ivp = Investigate::get($ncall, $origin)) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr'); - } - return; - } +# unless ($ncall eq $self->{call} || $self->is_believed($ncall)) { +# if (my $ivp = Investigate::get($ncall, $self->{call})) { +# $ivp->store_pcxx($pcno,$line,$origin,@_); +# } else { +# dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr'); +# } +# return; +# } if (eph_dup($line)) { dbg("PCPROT: dup PC16 detected") if isdbg('chanerr'); @@ -720,39 +719,69 @@ sub handle_16 # if there is a parent, proceed, otherwise if there is a latent PC19 in the PC19list, # fix it up in the routing tables and issue it forth before the PC16 if ($parent) { - $dxchan = $parent->dxchan; if ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC16 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); + dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); return; } + # input filter if required + return unless $self->in_filter_route($parent); + } else { + dbg("PCPROT: Node $ncall not in config") if isdbg('chanerr'); + return; + } + + # is he under the control of the new protocol? +# if ($parent && $parent->np) { +# dbg("PCPROT: $ncall aranea node, ignored") if isdbg('chanerr'); +# return; +# } - my $i; - my $rout; - for ($i = 2; $i < $#_; $i++) { - my ($call, $conf, $here) = $_[$i] =~ /^(\S+) (\S) (\d)/o; - next unless $call && $conf && defined $here && is_callsign($call); - next if $call eq $main::mycall; - - eph_del_regex("^PC17\\^$call\\^$ncall"); - - my $flags = $here ? 1 : 0; - $rout .= "$flags$call:"; + my $i; + my @rout; + for ($i = 2; $i < $#_; $i++) { + my ($call, $conf, $here) = $_[$i] =~ /^(\S+) (\S) (\d)/o; + next unless $call && $conf && defined $here && is_callsign($call); + next if $call eq $main::mycall; + + eph_del_regex("^PC17\\^$call\\^$ncall"); + + $conf = $conf eq '*'; + + # reject this if we think it is a node already + my $r = Route::Node::get($call); + my $u = DXUser->get_current($call) unless $r; + if ($r || ($u && $u->is_node)) { + dbg("PCPROT: $call is a node") if isdbg('chanerr'); + next; } - - if ($rout) { - chop $rout; - my $thing = Thingy::Rt->new(origin=>$main::mycall, user=>$self->{call}); - $thing->from_DXProt(t=>'au', $ncall eq $self->{call} ? () : ('n', "1$ncall"), u=>$rout, DXProt=>$line); - $thing->process($self); + $r = Route::User::get($call); + my $flags = $here; + + if ($r) { + my $au = $r->addparent($parent); + if ($r->flags != $flags) { + $r->flags($flags); + $au = $r; + } + push @rout, $r if $au; } else { - dbg("PCPROT: No usable users") if isdbg('chanerr'); + push @rout, $parent->add_user($call, $flags); } - } else { - dbg("PCPROT: no PC19 seen for $ncall" ) if isdbg('chanerr'); + + + # add this station to the user database, if required + $call =~ s/-\d+$//o; # remove ssid for users + my $user = DXUser->get_current($call); + $user = DXUser->new($call) if !$user; + $user->homenode($parent->call) if !$user->homenode; + $user->node($parent->call); + $user->lastin($main::systime) unless DXChannel::get($call); + $user->put; } + $self->route_pc16($origin, $line, $parent, @rout) if @rout && (DXChannel::get($parent->call) || $parent->np); } # remove a user @@ -770,7 +799,7 @@ sub handle_17 # do I want users from this channel? unless ($self->user->wantpc16) { - dbg("PCPROT: don't send users to $origin") if isdbg('chanerr'); + dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr'); return; } if ($ncall eq $main::mycall) { @@ -778,42 +807,53 @@ sub handle_17 return; } - RouteDB::delete($ncall, $origin); + RouteDB::delete($ncall, $self->{call}); # do we believe this call? - unless ($ncall eq $origin || $self->is_believed($ncall)) { - if (my $ivp = Investigate::get($ncall, $origin)) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr'); - } - return; - } +# unless ($ncall eq $self->{call} || $self->is_believed($ncall)) { +# if (my $ivp = Investigate::get($ncall, $self->{call})) { +# $ivp->store_pcxx($pcno,$line,$origin,@_); +# } else { +# dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr'); +# } +# return; +# } my $uref = Route::User::get($ucall); unless ($uref) { dbg("PCPROT: Route::User $ucall not in config") if isdbg('chanerr'); + return; } my $parent = Route::Node::get($ncall); unless ($parent) { dbg("PCPROT: Route::Node $ncall not in config") if isdbg('chanerr'); + return; } - $dxchan = $parent->dxchan if $parent; + $dxchan = $parent->dxchan; if ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC17 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); + dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); return; } + # is he under the control of the new protocol? +# if ($parent && $parent->np) { +# dbg("PCPROT: $ncall aranea node, ignored") if isdbg('chanerr'); +# return; +# } + + # input filter if required and then remove user if present + if ($parent && !$parent->np) { +# return unless $self->in_filter_route($parent); + $parent->del_user($uref) if $uref; + } + if (eph_dup($line)) { dbg("PCPROT: dup PC17 detected") if isdbg('chanerr'); return; } - $uref = Route->new($ucall) unless $uref; # throw away - my $thing = Thingy::Rt->new(origin=>$main::mycall, user=>$self->{call}); - $thing->from_DXProt(t=>'du', $ncall eq $self->{call} ? () : ('n', "1$ncall"), u=>"1$ucall", DXProt=>$line); - $thing->process($self); + $self->route_pc17($origin, $line, $parent, $uref) if (DXChannel::get($parent->call) || $parent->np); } # link request @@ -827,8 +867,8 @@ sub handle_18 # record the type and version offered if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+\.\d+)/) { - $self->version(52.51 + $1); - $self->user->version(52.51 + $1); + $self->version(0 + $1); + $self->user->version(0 + $1); $self->build(0 + $2); $self->user->build(0 + $2); unless ($self->is_spider) { @@ -872,26 +912,6 @@ sub handle_19 return; } - # if the origin isn't the same as the INTERFACE, then reparent, creating nodes as necessary - if ($origin ne $self->call) { - my $op = Route::Node::get($origin); - unless ($op) { - $op = $parent->add($origin, 5000, Route::here(1)); - my $user = DXUser->get_current($origin); - if (!$user) { - $user = DXUser->new($origin); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($origin); - $user->node($origin); - $user->wantroutepc19(1); - } - $user->sort('A') unless $user->is_node; - $user->put; - } - $parent = $op; - } - # parse the PC19 for ($i = 1; $i < $#_-1; $i += 4) { my $here = $_[$i]; @@ -904,12 +924,12 @@ sub handle_19 # check for sane parameters # $ver = 5000 if $ver eq '0000'; - next if $ver < 5000; # only works with version 5 software + next unless $ver > 5000; # only works with version 5 software that isn't a passive node next if length $call < 3; # min 3 letter callsigns next if $call eq $main::mycall; # check that this PC19 isn't trying to alter the wrong dxchan - my $dxchan = DXChannel->get($call); + my $dxchan = DXChannel::get($call); if ($dxchan && $dxchan != $self) { dbg("PCPROT: PC19 from $origin trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr'); next; @@ -928,30 +948,20 @@ sub handle_19 RouteDB::update($call, $origin); - # do we believe this call? my $genline = "PC19^$here^$call^$conf^$ver^$_[-1]^"; - unless ($call eq $origin || $self->is_believed($call)) { - my $pt = $user->lastping($origin) || 0; - if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $origin)) { - my $ivp = Investigate->new($call, $origin); - $ivp->version($ver); - $ivp->here($here); - $ivp->store_pcxx($pcno,$genline,$origin,'PC19',$here,$call,$conf,$ver,$_[-1]); - } else { - dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr'); - } - $user->put; - next; - } - if (eph_dup($genline)) { dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr'); next; } my $r = Route::Node::get($call); - my $flags = Route::here($here)|Route::conf($conf); + my $flags = $here; + # is he under the control of the new protocol and not my interface call? + if ($call ne $origin && $r && $r->np) { + dbg("PCPROT: $call aranea node, ignored") if isdbg('chanerr'); + next; + } # modify the routing table if it is in it, otherwise store it in the pc19list for now if ($r) { my $ar; @@ -963,11 +973,6 @@ sub handle_19 next; } } - if ($r->version ne $ver || $r->flags != $flags) { - $r->version($ver); - $r->flags($flags); - push @rout, $r unless $ar; - } } else { # if he is directly connected or allowed then add him, otherwise store him up for later @@ -980,10 +985,6 @@ sub handle_19 } else { next; } - } else { - $pc19list{$call} = [] unless exists $pc19list{$call}; - my $nl = $pc19list{$call}; - push @{$pc19list{$call}}, [$origin, $ver, $flags] unless grep $_->[0] eq $origin, @$nl; } } @@ -991,11 +992,12 @@ sub handle_19 my $mref = DXMsg::get_busy($call); $mref->stop_msg($call) if $mref; - $user->lastin($main::systime) unless DXChannel->get($call); + $user->lastin($main::systime) unless DXChannel::get($call); $user->put; } - + # we only output information that we regard as reliable + @rout = grep {$_ && (DXChannel::get($_->{call}) || $_->np) } @rout; $self->route_pc19($origin, $line, @rout) if @rout; } @@ -1010,6 +1012,11 @@ sub handle_20 $self->send(pc22()); $self->state('normal'); $self->{lastping} = 0; + my $thing = Thingy::Rt->new(user=>$self->{call}); + my $nref = Route::Node::get($self->{call}); + $thing->copy_pc16_data($nref); + $thing->broadcast($self); + $self->lastcf($main::systime); } # delete a cluster from the list @@ -1033,51 +1040,53 @@ sub handle_21 RouteDB::delete($call, $origin); # check if we believe this - unless ($call eq $origin || $self->is_believed($call)) { - if (my $ivp = Investigate::get($call, $origin)) { - $ivp->store_pcxx($pcno,$line,$origin,@_); - } else { - dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr'); - } - return; - } +# unless ($call eq $origin || $self->is_believed($call)) { +# if (my $ivp = Investigate::get($call, $origin)) { +# $ivp->store_pcxx($pcno,$line,$origin,@_); +# } else { +# dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr'); +# } +# return; +# } # check to see if we are in the pc19list, if we are then don't bother with any of # this routing table manipulation, just remove it from the list and dump it my @rout; - if (my $nl = $pc19list{$call}) { - $pc19list{$call} = [ grep {$_->[0] ne $origin} @$nl ]; - delete $pc19list{$call} unless @{$pc19list{$call}}; - } else { - - my $parent = Route::Node::get($origin); - unless ($parent) { - dbg("DXPROT: my parent $origin has disappeared"); - $self->disconnect; - return; - } - if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me! - my $node = Route::Node::get($call); - if ($node) { - - my $dxchan = DXChannel->get($call); - if ($dxchan && $dxchan != $self) { - dbg("PCPROT: PC21 from $origin trying to alter locally connected $call, ignored!") if isdbg('chanerr'); - return; - } - - # input filter it - return unless $self->in_filter_route($node); - - # routing objects - push @rout, $node->del($parent); + + my $parent = Route::Node::get($origin); + unless ($parent) { + dbg("DXPROT: my parent $origin has disappeared"); + $self->disconnect; + return; + } + if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me! + my $node = Route::Node::get($call); + if ($node) { + + my $dxchan = DXChannel::get($call); + if ($dxchan && $dxchan != $self) { + dbg("PCPROT: PC21 from $origin trying to alter locally connected $call, ignored!") if isdbg('chanerr'); + return; } - } else { - dbg("PCPROT: I WILL _NOT_ be disconnected!") if isdbg('chanerr'); - return; + + # input filter it + return unless $self->in_filter_route($node); + + # is he under the control of the new protocol? + if ($node->np) { + dbg("PCPROT: $call aranea node, ignored") if isdbg('chanerr'); + return; + } + + # routing objects + push @rout, $node->del($parent); } + } else { + dbg("PCPROT: I WILL _NOT_ be disconnected!") if isdbg('chanerr'); + return; } + @rout = grep {$_ && (DXChannel::get($_->{call}) || $_->np) } @rout; $self->route_pc21($origin, $line, @rout) if @rout; } @@ -1090,6 +1099,11 @@ sub handle_22 my $origin = shift; $self->state('normal'); $self->{lastping} = 0; + my $thing = Thingy::Rt->new(user=>$self->{call}); + my $nref = Route::Node::get($self->{call}); + $thing->copy_pc16_data($nref); + $thing->broadcast($self); + $self->lastcf($main::systime); } # WWV info @@ -1429,70 +1443,15 @@ sub handle_51 my $pcno = shift; my $line = shift; my $origin = shift; - my $to = $_[1]; - my $from = $_[2]; - my $flag = $_[3]; - - # is it for us? - if ($to eq $main::mycall) { - if ($flag == 1) { - $self->send(pc51($from, $to, '0')); - } else { - # it's a reply, look in the ping list for this one - 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 || $obscount; - 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 - if (my $ivp = Investigate::get($from, $origin)) { - $ivp->handle_ping; - } - } elsif (my $rref = Route::Node::get($r->{call})) { - if (my $ivp = Investigate::get($from, $origin)) { - $ivp->handle_ping; - } - } - } - } - } - } - } else { - - RouteDB::update($from, $origin); - - if (eph_dup($line)) { - dbg("PCPROT: dup PC51 detected") if isdbg('chanerr'); - return; - } - # route down an appropriate thingy - $self->route($to, $line); + if (eph_dup($line, 60)) { + dbg("PCPROT: dup PC51 detected") if isdbg('chanerr'); + return; } + + my $thing = Thingy::Ping->new(origin=>$main::mycall); + $thing->from_DXProt($self, $line, @_); + $thing->handle($self); } # dunno but route it @@ -1593,7 +1552,7 @@ sub handle_default sub process { my $t = time; - my @dxchan = DXChannel->get_all(); + my @dxchan = DXChannel::get_all(); my $dxchan; my $pc50s; @@ -1623,7 +1582,7 @@ sub process } } - Investigate::process(); +# Investigate::process(); # every ten seconds if ($t - $last10 >= 10) { @@ -1675,7 +1634,7 @@ sub send_wwv_spot { my $self = shift; my $line = shift; - my @dxchan = DXChannel->get_all(); + my @dxchan = DXChannel::get_all(); my $dxchan; my @dxcc = ((Prefix::cty_data($_[6]))[0..2], (Prefix::cty_data($_[7]))[0..2]); @@ -1709,7 +1668,7 @@ sub send_wcy_spot { my $self = shift; my $line = shift; - my @dxchan = DXChannel->get_all(); + my @dxchan = DXChannel::get_all(); my $dxchan; my @dxcc = ((Prefix::cty_data($_[10]))[0..2], (Prefix::cty_data($_[11]))[0..2]); @@ -1742,7 +1701,7 @@ sub send_announce { my $self = shift; my $line = shift; - my @dxchan = DXChannel->get_all(); + my @dxchan = DXChannel::get_all(); my $dxchan; my $target; my $to = 'To '; @@ -1807,7 +1766,7 @@ sub send_chat { my $self = shift; my $line = shift; - my @dxchan = DXChannel->get_all(); + my @dxchan = DXChannel::get_all(); my $dxchan; my $target = $_[3]; my $text = unpad($_[2]); @@ -1903,7 +1862,7 @@ sub send_local_config # don't appear outside of this node # send locally connected nodes - my @dxchan = grep { $_->call ne $main::mycall && $_ != $self && !$_->{isolate} } DXChannel::get_all_nodes(); + my @dxchan = grep { $_->call ne $main::mycall && $_ != $self && !$_->{isolate} && ($_->is_node || $_->is_aranea) } DXChannel::get_all(); @localnodes = map { my $r = Route::Node::get($_->{call}); $r ? $r : () } @dxchan if @dxchan; $self->send_route($main::mycall, \&pc19, scalar(@localnodes)+1, $main::routeroot, @localnodes); @@ -1918,6 +1877,7 @@ sub send_local_config for $node (@intcalls) { push @remotenodes, Route::Node::get($node) unless grep $node eq $_, @rnodes, @remotenodes; } + @remotenodes = grep {$_ && (DXChannel::get($_->{call}) || $_->np) } @remotenodes; $self->send_route($main::mycall, \&pc19, scalar(@remotenodes), @remotenodes); } @@ -1948,7 +1908,7 @@ sub route } # always send it down the local interface if available - my $dxchan = DXChannel->get($call); + my $dxchan = DXChannel::get($call); if ($dxchan) { dbg("route: $call -> $dxchan->{call} direct" ) if isdbg('route'); } else { @@ -1971,7 +1931,7 @@ sub route dbg("PCPROT: Trying to route back to source, dropped") if isdbg('chanerr'); return; } - $dxchan = DXChannel->get($rcall); + $dxchan = DXChannel::get($rcall); dbg("route: $call -> $rcall using RouteDB" ) if isdbg('route') && $dxchan; } } @@ -2048,22 +2008,9 @@ sub load_hops sub addping { my ($from, $to, $via) = @_; - my $ref = $pings{$to} || []; - my $r = {}; - $r->{call} = $from; - $r->{t} = [ gettimeofday ]; - if ($via && (my $dxchan = DXChannel->get($via))) { - $dxchan->send(pc51($to, $main::mycall, 1)); - } else { - route(undef, $to, pc51($to, $main::mycall, 1)); - } - push @$ref, $r; - $pings{$to} = $ref; - my $u = DXUser->get_current($to); - if ($u) { - $u->lastping(($via || $from), $main::systime); - $u->put; - } + my $thing = Thingy::Ping->new_ping($from eq $main::mycall ? () : (user=>$from), $via ? (touser=> $to, group => $via) : (group => $to)); + $thing->remember; + $thing->broadcast; } sub process_rcmd @@ -2104,13 +2051,13 @@ sub process_rcmd_reply if ($tonode eq $main::mycall) { my $s = $rcmds{$fromnode}; if ($s) { - my $dxchan = DXChannel->get($s->{call}); - my $ref = $user eq $tonode ? $dxchan : (DXChannel->get($user) || $dxchan); + my $dxchan = DXChannel::get($s->{call}); + my $ref = $user eq $tonode ? $dxchan : (DXChannel::get($user) || $dxchan); $ref->send($line) if $ref; delete $rcmds{$fromnode} if !$dxchan; } else { # send unsolicited ones to the sysop - my $dxchan = DXChannel->get($main::myalias); + my $dxchan = DXChannel::get($main::myalias); $dxchan->send($line) if $dxchan; } } else { @@ -2217,7 +2164,7 @@ sub disconnect } # remove outstanding pings - delete $pings{$call}; + Thingy::Ping::forget($call); # I was the last node visited $self->user->node($main::mycall);