comparison src/ping.c @ 4:aa38447a4b21

First entry of Paradise Server 2.9 patch 10 Beta
author darius
date Sat, 06 Dec 1997 04:37:03 +0000
parents
children
comparison
equal deleted inserted replaced
3:cafa94d86546 4:aa38447a4b21
1 /*--------------------------------------------------------------------------
2 NETREK II -- Paradise
3
4 Permission to use, copy, modify, and distribute this software and its
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL
6 purpose and without fee is hereby granted, provided that this copyright
7 notice appear in all copies. No representations are made about the
8 suitability of this software for any purpose. This software is provided
9 "as is" without express or implied warranty.
10
11 Xtrek Copyright 1986 Chris Guthrie
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith
13 Scott Silvey
14 Paradise II (Netrek II) Copyright 1993 Larry Denys
15 Kurt Olsen
16 Brandon Gillespie
17 --------------------------------------------------------------------------*/
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <signal.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <math.h>
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include "defs.h"
28 #include "struct.h"
29 #include "data.h"
30 #include "packets.h"
31 #include "shmem.h"
32
33 #define PING_DEBUG 0 /* debugging */
34
35 /* special fields in stats record for rountrip delay and packet loss */
36 #define INL_STATS
37
38
39 static unsigned char ping_id; /* wraparound expected */
40 static int ping_lag; /* ping roundtrip delay */
41
42 static int tloss_sc, /* total packet loss s-c */
43 tloss_cs, /* total packet loss c-s */
44 iloss_sc, /* inc. packet loss s-c */
45 iloss_cs; /* inc. packet loss c-s */
46
47 /*
48 * This structure allows us to send several pings before any response is
49 * received without losing information -- as would be the case for roundtrip
50 * times equal to or larger then the ping interval times. HASHSIZE * ping
51 * interval must be greater then the largest expected roundtrip time.
52 */
53
54 #define HASHSIZE 32
55 #define PITH(i) (((int)i) & (HASHSIZE-1))
56
57 static
58 struct
59 {
60 long time;
61 long packets_sent_at_ping;
62 } ping_sent[HASHSIZE];
63
64
65 void calc_loss();
66 void update_lag_stats();
67 void update_loss_stats();
68 int mstime();
69 int msetime();
70
71 /*
72 * response from client
73 */
74
75 void
76 pingResponse(packet)
77 struct ping_cpacket *packet;
78 {
79 register i;
80 static int last_num;
81
82 if (!ping || packet->pingme != 1)
83 return; /* oops, garbage */
84
85 ping_ghostbust = 0; /* don't ghostbust, client is alive */
86
87 /* throw out out-of-order packets */
88 i = uchar_diff((int) packet->number, last_num);
89 if (i < 0)
90 {
91 #if PING_DEBUG >= 1
92 fprintf(stderr, "out-of-order response ignored: %d (last: %d)\n",
93 packet->number, last_num);
94 fflush(stderr);
95 #endif
96 return;
97 }
98 last_num = packet->number;
99 i = PITH(last_num);
100
101 /* calculate roundtrip */
102 ping_lag = mstime() - ping_sent[i].time;
103
104 #ifdef INL_STATS
105 /* fill in lag stats fields */
106 update_lag_stats();
107 #endif
108
109 /* watch out for div by 0 */
110 if (!packets_received || !ping_sent[i].packets_sent_at_ping)
111 return;
112
113 /* calculate total packet loss */
114 calc_loss(i, packet);
115
116 #ifdef INL_STATS
117 update_loss_stats();
118 #endif
119 }
120
121 /*
122 * request from server
123 */
124
125 void
126 sendClientPing()
127 {
128 struct ping_spacket packet;
129
130 ping_ghostbust++;
131 ping_id++; /* ok to wrap */
132
133 packet.type = SP_PING;
134 packet.number = (unsigned char) ping_id;
135 packet.lag = htons((unsigned short) ping_lag);
136 packet.tloss_sc = tloss_sc;
137 packet.tloss_cs = tloss_cs;
138 packet.iloss_sc = iloss_sc;
139 packet.iloss_cs = iloss_cs;
140
141 ping_sent[PITH(ping_id)].time = mstime();
142 /*
143 * printf("ping sent at %d\n", msetime());
144 */
145
146 sendClientPacket(&packet);
147
148 ping_sent[PITH(ping_id)].packets_sent_at_ping = packets_sent;
149 }
150
151 void
152 calc_loss(i, packet)
153 int i;
154 struct ping_cpacket *packet;
155 {
156 /* tloss vars */
157 register cp_recv, /* client packets recv */
158 cp_sent; /* client packets sent */
159 int s_to_c_dropped, /* server to client */
160 c_to_s_dropped; /* client to server */
161 static int old_s_to_c_dropped,/* previous update */
162 old_c_to_s_dropped; /* "" */
163 /* iloss vars */
164 int p_sent, p_recv;
165
166 static
167 int timer;
168
169 static int inc_packets_sent, /* packets sent start-point */
170 inc_packets_received, /* packets recvd start-pt */
171 inc_s_to_c_dropped, /* dropped s-to-c start-pt */
172 inc_c_to_s_dropped; /* dropped c-to-s start-pt */
173
174 if (!timer)
175 timer = configvals->ping_iloss_interval;
176
177 cp_recv = ntohl(packet->cp_recv);
178 cp_sent = ntohl(packet->cp_sent);
179
180 /* at ping time, total packets dropped from server to client */
181 s_to_c_dropped = ping_sent[i].packets_sent_at_ping - cp_recv;
182
183 if (s_to_c_dropped < old_s_to_c_dropped)
184 {
185 /*
186 * The network may duplicate or send out-of-order packets. Both are
187 * detected and thrown out by the client if sequence checking is on. If
188 * not there's not much we can do -- there's no way to distinguish a
189 * duplicated packet from a series of out of order packets. While the
190 * latter case cancels itself out eventually in terms of packet loss, the
191 * former hides real packet loss by adding extra packets. We'll have to
192 * kludge it by adding the extra packets the client thinks it got to
193 * packets_sent
194 */
195 packets_sent += old_s_to_c_dropped - s_to_c_dropped;
196 /* and adjust s_to_c_dropped so we don't get a negative packet loss */
197 s_to_c_dropped = old_s_to_c_dropped;
198 }
199
200 /* total loss server-to-client since start of connection */
201 tloss_sc = 100 -
202 (100 * (ping_sent[i].packets_sent_at_ping - s_to_c_dropped)) /
203 ping_sent[i].packets_sent_at_ping;
204
205 /*
206 * at ping time, total packets dropped from client to server NOTE: not
207 * packets_received_at_ping since the client may have sent any amount of
208 * packets between the time we sent the ping and the time the client
209 * received it.
210 */
211 c_to_s_dropped = cp_sent - packets_received;
212
213 #if PING_DEBUG >= 2
214 printf("cp_sent: %d, packets_received: %d\n",
215 cp_sent, packets_received);
216 #endif
217
218 if (c_to_s_dropped < old_c_to_s_dropped)
219 {
220 /*
221 * The network may duplicate or send out-of-order packets. Since no
222 * sequence checking is done by the server, there's not much we can do --
223 * there's no way to distinguish a duplicated packet from a series of out
224 * of order packets. While the latter case cancels itself out eventually
225 * in terms of packet loss, the former hides real packet loss by adding
226 * extra packets. We'll have to kludge it by subtracting the extra
227 * packets we think we got from the client from packets_received.
228 */
229 packets_received -= old_c_to_s_dropped - c_to_s_dropped;
230 /* and adjust c_to_s_dropped so we don't get a negative packet loss */
231 c_to_s_dropped = old_c_to_s_dropped;
232 }
233
234 /* total loss client-to-server since start of connection */
235 tloss_cs = 100 -
236 (100 * (packets_received - c_to_s_dropped)) / (packets_received ? packets_received : 1);
237
238 old_s_to_c_dropped = s_to_c_dropped;
239 old_c_to_s_dropped = c_to_s_dropped;
240
241 /* Incremental packet loss */
242
243 /* packets sent since last ping response */
244 p_sent = ping_sent[i].packets_sent_at_ping - inc_packets_sent;
245
246 /* packets received since last ping response */
247 p_recv = packets_received - inc_packets_received;
248
249 if (!p_sent || !p_recv)
250 {
251 /* just in case */
252 return;
253 }
254
255 /* percent loss server-to-client since PACKET_LOSS_INTERVAL */
256 iloss_sc = 100 -
257 (100 * (p_sent - (s_to_c_dropped - inc_s_to_c_dropped))) / p_sent;
258 /*
259 * we're not going to do any of the adjustments we did in tloss
260 * calculations since this starts fresh every PACKET_LOSS_INTERVAL
261 */
262 if (iloss_sc < 0)
263 iloss_sc = 0;
264
265 /* total percent loss client-to-server since PACKET_LOSS_INTERVAL */
266 iloss_cs = 100 -
267 (100 * (p_recv - (c_to_s_dropped - inc_c_to_s_dropped))) / p_recv;
268 /*
269 * we're not going to do any of the adjustments we did in tloss
270 * calculations since this starts fresh every PACKET_LOSS_INTERVAL
271 */
272 if (iloss_cs < 0)
273 iloss_cs = 0;
274
275 /*
276 * we update these variables every PACKET_LOSS_INTERVAL seconds to start a
277 * fresh increment
278 */
279 if ((timer % configvals->ping_iloss_interval) == 0)
280 {
281 inc_s_to_c_dropped = s_to_c_dropped;
282 inc_c_to_s_dropped = c_to_s_dropped;
283
284 inc_packets_sent = ping_sent[i].packets_sent_at_ping;
285 inc_packets_received = packets_received;
286 }
287
288 timer++;
289 }
290
291 #ifdef INL_STATS
292
293 /*
294 * Lag stats struct player .p_avrt - average round trip time ms struct
295 * player .p_stdv - standard deviation in rt time struct player .p_pkls -
296 * input/output packet loss
297 */
298
299 static int sum, n, s2;
300 static int M, var;
301
302 void
303 update_lag_stats()
304 {
305 n++;
306 sum += ping_lag;
307 s2 += (ping_lag * ping_lag);
308 if (n == 1)
309 return;
310
311 M = sum / n;
312 var = (s2 - M * sum) / (n - 1);
313
314 /* average round trip time */
315 me->p_avrt = M;
316 /* standard deviation */
317 if (var > 0)
318 me->p_stdv = (int) isqrt(var);
319 }
320
321 void
322 update_loss_stats()
323 {
324 /*
325 * packet loss (as average of server-to-client, client-to-server loss),
326 * give tloss_sc extra weight (or should we?)
327 */
328 me->p_pkls = (2 * tloss_sc + tloss_cs) / 3;
329 }
330 #endif /* INL_STATS */
331
332 /* utilities */
333
334 /* ms time from start */
335 int
336 mstime()
337 {
338 static struct timeval tv_base = {0, 0};
339 struct timeval tv;
340
341 if (!tv_base.tv_sec)
342 {
343 gettimeofday(&tv_base, NULL);
344 return 0;
345 }
346 gettimeofday(&tv, NULL);
347 return (tv.tv_sec - tv_base.tv_sec) * 1000 +
348 (tv.tv_usec - tv_base.tv_usec) / 1000;
349 }
350
351 /* debugging */
352 int
353 msetime()
354 {
355 struct timeval tv;
356 gettimeofday(&tv, NULL);
357 return (tv.tv_sec - 732737182) * 1000 + tv.tv_usec / 1000;
358 }
359
360 int
361 uchar_diff(x, y)
362 int x, y;
363 {
364 register res;
365
366 res = x - y;
367
368 if (res > 128)
369 return res - 256;
370 else if (res < -128)
371 return res + 256;
372 else
373 return res;
374 }