fix badspotters and local ann/full.
[spider.git] / perl / DXXml / Ping.pm
1 #
2 # XML Ping handler
3 #
4 # $Id$
5 #
6 # Copyright (c) Dirk Koopman, G1TLH
7 #
8
9 use strict;
10
11 package DXXml::Ping;
12
13 use DXDebug;
14 use DXProt;
15 use IsoTime;
16 use Investigate;
17 use Time::HiRes qw(gettimeofday tv_interval);
18
19 use vars qw($VERSION $BRANCH @ISA %pings);
20 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
21 $BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/  || (0,0));
22 $main::build += $VERSION;
23 $main::branch += $BRANCH;
24
25 @ISA = qw(DXXml);
26 %pings = ();                    # outstanding ping requests outbound
27
28 sub handle_input
29 {
30         my $self = shift;
31         my $dxchan = shift;
32         
33 }
34
35 sub topcxx
36 {
37         my $self = shift;
38         unless (exists $self->{'-pcxx'}) {
39                 $self->{'-pcxx'} = DXProt::pc51($self->{to}, $self->{o}, $self->{s});
40         }
41         return $self->{'-pcxx'};
42 }
43
44 # add a ping request to the ping queues
45 sub add
46 {
47         my ($dxchan, $to, $via) = @_;
48         my $from = $dxchan->call;
49         my $ref = $pings{$to} || [];
50         my $r = {};
51         my $self = DXXml::Ping->new(to=>$to, '-hirestime'=>[ gettimeofday ], s=>'1');
52         $self->{u} = $from unless $from eq $main::mycall;
53         $self->{'-via'} = $via if $via && DXChannel::get($via);
54         $self->{o} = $main::mycall;
55         $self->{id} = $self->nextid;
56         $self->route($dxchan);
57
58         push @$ref, $self;
59         $pings{$to} = $ref;
60         my $u = DXUser->get_current($to);
61         if ($u) {
62                 $u->lastping(($via || $from), $main::systime);
63                 $u->put;
64         }
65 }
66
67 sub handle_ping_reply
68 {
69         my $fromdxchan = shift;
70         my $from = shift;
71         my $fromxml;
72         
73         if (ref $from) {
74                 $fromxml = $from;
75                 $from = $from->{o};
76         }
77
78         # it's a reply, look in the ping list for this one
79         my $ref = $pings{$from};
80         return unless $ref;
81
82         my $tochan = DXChannel::get($from);
83         while (@$ref) {
84                 my $r = shift @$ref;
85                 my $dxchan = DXChannel::get($r->{to});
86                 next unless $dxchan;
87                 my $t = tv_interval($r->{'-hirestime'}, [ gettimeofday ]);
88                 if ($dxchan->is_user) {
89                         my $s = sprintf "%.2f", $t; 
90                         my $ave = sprintf "%.2f", $tochan ? ($tochan->{pingave} || $t) : $t;
91                         $dxchan->send($dxchan->msg('pingi', $from, $s, $ave))
92                 } elsif ($dxchan->is_node) {
93                         if ($tochan) {
94                                 my $nopings = $tochan->user->nopings || $DXProt::obscount;
95                                 push @{$tochan->{pingtime}}, $t;
96                                 shift @{$tochan->{pingtime}} if @{$tochan->{pingtime}} > 6;
97                                 
98                                 # cope with a missed ping, this means you must set the pingint large enough
99                                 if ($t > $tochan->{pingint}  && $t < 2 * $tochan->{pingint} ) {
100                                         $t -= $tochan->{pingint};
101                                 }
102                                 
103                                 # calc smoothed RTT a la TCP
104                                 if (@{$tochan->{pingtime}} == 1) {
105                                         $tochan->{pingave} = $t;
106                                 } else {
107                                         $tochan->{pingave} = $tochan->{pingave} + (($t - $tochan->{pingave}) / 6);
108                                 }
109                                 $tochan->{nopings} = $nopings; # pump up the timer
110                                 if (my $ivp = Investigate::get($from, $fromdxchan->{call})) {
111                                         $ivp->handle_ping;
112                                 }
113                         } elsif (my $rref = Route::Node::get($r->{to})) {
114                                 if (my $ivp = Investigate::get($from, $fromdxchan->{to})) {
115                                         $ivp->handle_ping;
116                                 }
117                         }
118                 }
119         }
120 }
121
122 1;