get alternate pinging working properly at half pingint
[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         if ($self->{to} eq $main::mycall) {
34                 if ($self->{s} eq '1') {
35                         my $rep = DXXml::Ping->new(to=>$self->{o}, 
36                                                                            s=>'0',
37                                                                            oid=>$self->{id},
38                                                                            ot=>$self->{t}
39                                                                           );
40                         $dxchan->send($rep->toxml);
41                         if ($dxchan->{outgoing} && abs($dxchan->{lastping} - $main::systime) < 15) {
42                                 $dxchan->{lastping} += $dxchan->{pingint} / 2; 
43                         }
44                 } else {
45                         handle_ping_reply($dxchan, $self->{o}, $self->{ot}, $self->{oid});
46                 }
47         } else {
48                 $self->route($dxchan);
49         }
50 }
51
52 sub topcxx
53 {
54         my $self = shift;
55         unless (exists $self->{'-pcxx'}) {
56                 $self->{'-pcxx'} = DXProt::pc51($self->{to}, $self->{o}, $self->{s});
57         }
58         return $self->{'-pcxx'};
59 }
60
61 # add a ping request to the ping queues
62 sub add
63 {
64         my ($dxchan, $to, $via) = @_;
65         my $from = $dxchan->call;
66         my $ref = $pings{$to} || [];
67         my $r = {};
68         my $self = DXXml::Ping->new(to=>$to, '-hirestime'=>[ gettimeofday ], s=>'1');
69         $self->{u} = $from unless $from eq $main::mycall;
70         $self->{'-via'} = $via if $via && DXChannel::get($via);
71         $self->{o} = $main::mycall;
72         $self->route($dxchan);
73
74         push @$ref, $self;
75         $pings{$to} = $ref;
76         my $u = DXUser->get_current($to);
77         if ($u) {
78                 $u->lastping(($via || $from), $main::systime);
79                 $u->put;
80         }
81 }
82
83 sub handle_ping_reply
84 {
85         my $fromdxchan = shift;
86         my $from = shift;
87         my $ot = shift;
88         my $oid = shift;
89         my $fromxml;
90         
91         if (ref $from) {
92                 $fromxml = $from;
93                 $from = $from->{o};
94         }
95
96         # it's a reply, look in the ping list for this one
97         my $ref = $pings{$from};
98         return unless $ref;
99
100         my $tochan = DXChannel::get($from);
101         while (@$ref) {
102                 my $r = shift @$ref;
103                 my $dxchan = DXChannel::get($r->{o});
104                 next unless $dxchan;
105                 my $t = tv_interval($r->{'-hirestime'}, [ gettimeofday ]);
106                 if ($dxchan->is_node) {
107                         if ($tochan) {
108                                 my $nopings = $tochan->user->nopings || $DXProt::obscount;
109                                 push @{$tochan->{pingtime}}, $t;
110                                 shift @{$tochan->{pingtime}} if @{$tochan->{pingtime}} > 6;
111                                 
112                                 # cope with a missed ping, this means you must set the pingint large enough
113                                 if ($t > $tochan->{pingint}  && $t < 2 * $tochan->{pingint} ) {
114                                         $t -= $tochan->{pingint};
115                                 }
116                                 
117                                 # calc smoothed RTT a la TCP
118                                 if (@{$tochan->{pingtime}} == 1) {
119                                         $tochan->{pingave} = $t;
120                                 } else {
121                                         $tochan->{pingave} = $tochan->{pingave} + (($t - $tochan->{pingave}) / 6);
122                                 }
123                                 $tochan->{nopings} = $nopings; # pump up the timer
124                         }
125                         _handle_believe($from, $fromdxchan->{call});
126                 } 
127                 if (exists $r->{u} && ($dxchan = DXChannel::get($r->{u})) && $dxchan->is_user) {
128                         my $s = sprintf "%.2f", $t; 
129                         my $ave = sprintf "%.2f", $tochan ? ($tochan->{pingave} || $t) : $t;
130                         $dxchan->send($dxchan->msg('pingi', $from, $s, $ave))
131                 } 
132         }
133 }
134
135 sub _handle_believe
136 {
137         my ($from, $via) = @_;
138         
139         if (my $ivp = Investigate::get($from, $via)) {
140                 $ivp->handle_ping;
141         } else {
142                 my $user = DXUser->get_current($from);
143                 if ($user) {
144                         $user->set_believe($via);
145                         $user->put;
146                 }
147         }
148 }
149 1;