Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ping.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,374 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <math.h> +#include <errno.h> +#include <netinet/in.h> +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +#define PING_DEBUG 0 /* debugging */ + +/* special fields in stats record for rountrip delay and packet loss */ +#define INL_STATS + + +static unsigned char ping_id; /* wraparound expected */ +static int ping_lag; /* ping roundtrip delay */ + +static int tloss_sc, /* total packet loss s-c */ + tloss_cs, /* total packet loss c-s */ + iloss_sc, /* inc. packet loss s-c */ + iloss_cs; /* inc. packet loss c-s */ + +/* + * This structure allows us to send several pings before any response is + * received without losing information -- as would be the case for roundtrip + * times equal to or larger then the ping interval times. HASHSIZE * ping + * interval must be greater then the largest expected roundtrip time. + */ + +#define HASHSIZE 32 +#define PITH(i) (((int)i) & (HASHSIZE-1)) + +static +struct +{ + long time; + long packets_sent_at_ping; +} ping_sent[HASHSIZE]; + + +void calc_loss(); +void update_lag_stats(); +void update_loss_stats(); +int mstime(); +int msetime(); + +/* + * response from client + */ + +void +pingResponse(packet) + struct ping_cpacket *packet; +{ + register i; + static int last_num; + + if (!ping || packet->pingme != 1) + return; /* oops, garbage */ + + ping_ghostbust = 0; /* don't ghostbust, client is alive */ + + /* throw out out-of-order packets */ + i = uchar_diff((int) packet->number, last_num); + if (i < 0) + { +#if PING_DEBUG >= 1 + fprintf(stderr, "out-of-order response ignored: %d (last: %d)\n", + packet->number, last_num); + fflush(stderr); +#endif + return; + } + last_num = packet->number; + i = PITH(last_num); + + /* calculate roundtrip */ + ping_lag = mstime() - ping_sent[i].time; + +#ifdef INL_STATS + /* fill in lag stats fields */ + update_lag_stats(); +#endif + + /* watch out for div by 0 */ + if (!packets_received || !ping_sent[i].packets_sent_at_ping) + return; + + /* calculate total packet loss */ + calc_loss(i, packet); + +#ifdef INL_STATS + update_loss_stats(); +#endif +} + +/* + * request from server + */ + +void +sendClientPing() +{ + struct ping_spacket packet; + + ping_ghostbust++; + ping_id++; /* ok to wrap */ + + packet.type = SP_PING; + packet.number = (unsigned char) ping_id; + packet.lag = htons((unsigned short) ping_lag); + packet.tloss_sc = tloss_sc; + packet.tloss_cs = tloss_cs; + packet.iloss_sc = iloss_sc; + packet.iloss_cs = iloss_cs; + + ping_sent[PITH(ping_id)].time = mstime(); + /* + * printf("ping sent at %d\n", msetime()); + */ + + sendClientPacket(&packet); + + ping_sent[PITH(ping_id)].packets_sent_at_ping = packets_sent; +} + +void +calc_loss(i, packet) + int i; + struct ping_cpacket *packet; +{ + /* tloss vars */ + register cp_recv, /* client packets recv */ + cp_sent; /* client packets sent */ + int s_to_c_dropped, /* server to client */ + c_to_s_dropped; /* client to server */ + static int old_s_to_c_dropped,/* previous update */ + old_c_to_s_dropped; /* "" */ + /* iloss vars */ + int p_sent, p_recv; + + static + int timer; + + static int inc_packets_sent, /* packets sent start-point */ + inc_packets_received, /* packets recvd start-pt */ + inc_s_to_c_dropped, /* dropped s-to-c start-pt */ + inc_c_to_s_dropped; /* dropped c-to-s start-pt */ + + if (!timer) + timer = configvals->ping_iloss_interval; + + cp_recv = ntohl(packet->cp_recv); + cp_sent = ntohl(packet->cp_sent); + + /* at ping time, total packets dropped from server to client */ + s_to_c_dropped = ping_sent[i].packets_sent_at_ping - cp_recv; + + if (s_to_c_dropped < old_s_to_c_dropped) + { + /* + * The network may duplicate or send out-of-order packets. Both are + * detected and thrown out by the client if sequence checking is on. If + * not there's not much we can do -- there's no way to distinguish a + * duplicated packet from a series of out of order packets. While the + * latter case cancels itself out eventually in terms of packet loss, the + * former hides real packet loss by adding extra packets. We'll have to + * kludge it by adding the extra packets the client thinks it got to + * packets_sent + */ + packets_sent += old_s_to_c_dropped - s_to_c_dropped; + /* and adjust s_to_c_dropped so we don't get a negative packet loss */ + s_to_c_dropped = old_s_to_c_dropped; + } + + /* total loss server-to-client since start of connection */ + tloss_sc = 100 - + (100 * (ping_sent[i].packets_sent_at_ping - s_to_c_dropped)) / + ping_sent[i].packets_sent_at_ping; + + /* + * at ping time, total packets dropped from client to server NOTE: not + * packets_received_at_ping since the client may have sent any amount of + * packets between the time we sent the ping and the time the client + * received it. + */ + c_to_s_dropped = cp_sent - packets_received; + +#if PING_DEBUG >= 2 + printf("cp_sent: %d, packets_received: %d\n", + cp_sent, packets_received); +#endif + + if (c_to_s_dropped < old_c_to_s_dropped) + { + /* + * The network may duplicate or send out-of-order packets. Since no + * sequence checking is done by the server, there's not much we can do -- + * there's no way to distinguish a duplicated packet from a series of out + * of order packets. While the latter case cancels itself out eventually + * in terms of packet loss, the former hides real packet loss by adding + * extra packets. We'll have to kludge it by subtracting the extra + * packets we think we got from the client from packets_received. + */ + packets_received -= old_c_to_s_dropped - c_to_s_dropped; + /* and adjust c_to_s_dropped so we don't get a negative packet loss */ + c_to_s_dropped = old_c_to_s_dropped; + } + + /* total loss client-to-server since start of connection */ + tloss_cs = 100 - + (100 * (packets_received - c_to_s_dropped)) / (packets_received ? packets_received : 1); + + old_s_to_c_dropped = s_to_c_dropped; + old_c_to_s_dropped = c_to_s_dropped; + + /* Incremental packet loss */ + + /* packets sent since last ping response */ + p_sent = ping_sent[i].packets_sent_at_ping - inc_packets_sent; + + /* packets received since last ping response */ + p_recv = packets_received - inc_packets_received; + + if (!p_sent || !p_recv) + { + /* just in case */ + return; + } + + /* percent loss server-to-client since PACKET_LOSS_INTERVAL */ + iloss_sc = 100 - + (100 * (p_sent - (s_to_c_dropped - inc_s_to_c_dropped))) / p_sent; + /* + * we're not going to do any of the adjustments we did in tloss + * calculations since this starts fresh every PACKET_LOSS_INTERVAL + */ + if (iloss_sc < 0) + iloss_sc = 0; + + /* total percent loss client-to-server since PACKET_LOSS_INTERVAL */ + iloss_cs = 100 - + (100 * (p_recv - (c_to_s_dropped - inc_c_to_s_dropped))) / p_recv; + /* + * we're not going to do any of the adjustments we did in tloss + * calculations since this starts fresh every PACKET_LOSS_INTERVAL + */ + if (iloss_cs < 0) + iloss_cs = 0; + + /* + * we update these variables every PACKET_LOSS_INTERVAL seconds to start a + * fresh increment + */ + if ((timer % configvals->ping_iloss_interval) == 0) + { + inc_s_to_c_dropped = s_to_c_dropped; + inc_c_to_s_dropped = c_to_s_dropped; + + inc_packets_sent = ping_sent[i].packets_sent_at_ping; + inc_packets_received = packets_received; + } + + timer++; +} + +#ifdef INL_STATS + +/* + * Lag stats struct player .p_avrt - average round trip time ms struct + * player .p_stdv - standard deviation in rt time struct player .p_pkls - + * input/output packet loss + */ + +static int sum, n, s2; +static int M, var; + +void +update_lag_stats() +{ + n++; + sum += ping_lag; + s2 += (ping_lag * ping_lag); + if (n == 1) + return; + + M = sum / n; + var = (s2 - M * sum) / (n - 1); + + /* average round trip time */ + me->p_avrt = M; + /* standard deviation */ + if (var > 0) + me->p_stdv = (int) isqrt(var); +} + +void +update_loss_stats() +{ + /* + * packet loss (as average of server-to-client, client-to-server loss), + * give tloss_sc extra weight (or should we?) + */ + me->p_pkls = (2 * tloss_sc + tloss_cs) / 3; +} +#endif /* INL_STATS */ + +/* utilities */ + +/* ms time from start */ +int +mstime() +{ + static struct timeval tv_base = {0, 0}; + struct timeval tv; + + if (!tv_base.tv_sec) + { + gettimeofday(&tv_base, NULL); + return 0; + } + gettimeofday(&tv, NULL); + return (tv.tv_sec - tv_base.tv_sec) * 1000 + + (tv.tv_usec - tv_base.tv_usec) / 1000; +} + +/* debugging */ +int +msetime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec - 732737182) * 1000 + tv.tv_usec / 1000; +} + +int +uchar_diff(x, y) + int x, y; +{ + register res; + + res = x - y; + + if (res > 128) + return res - 256; + else if (res < -128) + return res + 256; + else + return res; +}