Index: client/civclient.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v retrieving revision 1.149 diff -u -r1.149 civclient.c --- client/civclient.c 9 Oct 2002 13:39:47 -0000 1.149 +++ client/civclient.c 10 Nov 2002 19:05:06 -0000 @@ -456,6 +456,10 @@ handle_thaw_hint(); break; + case PACKET_PING_INFO: + handle_ping_info((struct packet_ping_info *) packet); + break; + default: freelog(LOG_ERROR, "Received unknown packet (type %d) from server!", type); /* Old clients (<= some 1.11.5-devel, capstr +1.11) used to exit() Index: client/packhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v retrieving revision 1.259 diff -u -r1.259 packhand.c --- client/packhand.c 7 Nov 2002 18:55:24 -0000 1.259 +++ client/packhand.c 10 Nov 2002 19:05:11 -0000 @@ -1291,6 +1291,7 @@ pconn = fc_calloc(1, sizeof(struct connection)); pconn->buffer = NULL; pconn->send_buffer = NULL; + pconn->ping_time = -1.0; if (pplayer) { conn_list_insert_back(&pplayer->connections, pconn); } @@ -1317,6 +1318,27 @@ sz_strlcpy(pconn->name, pinfo->name); sz_strlcpy(pconn->addr, pinfo->addr); sz_strlcpy(pconn->capability, pinfo->capability); + } + update_players_dialog(); +} + +/************************************************************************* +... +**************************************************************************/ +void handle_ping_info(struct packet_ping_info *packet) +{ + int i; + + for (i = 0; i < packet->connections; i++) { + struct connection *pconn = find_conn_by_id(packet->conn_id[i]); + + if (!pconn) { + continue; + } + + pconn->ping_time = packet->ping_time[i]; + freelog(LOG_NORMAL, "conn-id=%d, ping=%fs", pconn->id, + pconn->ping_time); } update_players_dialog(); } Index: client/packhand.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/packhand.h,v retrieving revision 1.29 diff -u -r1.29 packhand.h --- client/packhand.h 10 Sep 2002 14:01:06 -0000 1.29 +++ client/packhand.h 10 Nov 2002 19:05:11 -0000 @@ -20,6 +20,7 @@ void handle_tile_info(struct packet_tile_info *packet); void handle_player_info(struct packet_player_info *pinfo); void handle_conn_info(struct packet_conn_info *pinfo); +void handle_ping_info(struct packet_ping_info *packet); void handle_game_info(struct packet_game_info *pinfo); void handle_map_info(struct packet_map_info *pinfo); void handle_select_nation(struct packet_nations_used *packet); Index: client/plrdlg_common.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/plrdlg_common.c,v retrieving revision 1.1 diff -u -r1.1 plrdlg_common.c --- client/plrdlg_common.c 27 Jun 2002 01:00:49 -0000 1.1 +++ client/plrdlg_common.c 10 Nov 2002 19:05:11 -0000 @@ -10,9 +10,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif #include +#include "connection.h" +#include "fcintl.h" +#include "game.h" +#include "support.h" + #include "plrdlg_g.h" #include "plrdlg_common.h" @@ -54,4 +62,25 @@ bool is_plrdlg_frozen(void) { return frozen_level > 0; +} + +/****************************************************************** + ... +*******************************************************************/ +const char *get_ping_time_text(struct player *pplayer) +{ + static char buffer[32]; + + if (conn_list_size(&pplayer->connections) > 0 + && conn_list_get(&pplayer->connections, 0)->ping_time != -1.0) { + double ping_time_in_ms = + 1000 * conn_list_get(&pplayer->connections, 0)->ping_time; + + my_snprintf(buffer, sizeof(buffer), _("%6d.%02d ms"), + (int) ping_time_in_ms, + ((int) (ping_time_in_ms * 100.0)) % 100); + } else { + buffer[0] = '\0'; + } + return buffer; } Index: client/plrdlg_common.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/plrdlg_common.h,v retrieving revision 1.1 diff -u -r1.1 plrdlg_common.h --- client/plrdlg_common.h 27 Jun 2002 01:00:49 -0000 1.1 +++ client/plrdlg_common.h 10 Nov 2002 19:05:12 -0000 @@ -13,11 +13,14 @@ #ifndef FC__PLRDLG_COMMON_H #define FC__PLRDLG_COMMON_H +struct player; + #include "shared.h" /* bool type */ void plrdlg_freeze(void); void plrdlg_thaw(void); void plrdlg_force_thaw(void); bool is_plrdlg_frozen(void); +const char *get_ping_time_text(struct player *pplayer); #endif /* FC__PLRDLG_COMMON_H */ Index: client/gui-gtk/plrdlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/plrdlg.c,v retrieving revision 1.39 diff -u -r1.39 plrdlg.c --- client/gui-gtk/plrdlg.c 7 Nov 2002 18:55:25 -0000 1.39 +++ client/gui-gtk/plrdlg.c 10 Nov 2002 19:05:13 -0000 @@ -70,7 +70,7 @@ static void players_list_ucallback(GtkWidget *w, gint row, gint column); static void players_sship_callback(GtkWidget *w, gpointer data); -#define NUM_COLUMNS 12 /* number of columns in total */ +#define NUM_COLUMNS 13 /* number of columns in total */ #define DEF_SORT_COLUMN 2 /* default sort column (1 = nation) */ /**************************************************************** @@ -122,7 +122,7 @@ static const char *titles_[NUM_COLUMNS] = { N_("Name"), N_("Flag"), N_("Nation"), N_("Team"), N_("Ai"), N_("Embassy"), N_("Dipl.State"), N_("Vision"), N_("Reputation"), - N_("State"), N_("Host"), N_("Idle") + N_("State"), N_("Host"), N_("Idle"), N_("Ping") }; static gchar **titles; int i; @@ -326,6 +326,7 @@ row[9] = statebuf; row[10] = (char *) player_addr_hack(&game.players[i]); /* Fixme */ row[11] = idlebuf; + row[12] = get_ping_time_text(&game.players[i]); } #define MIN_DIMENSION 5 Index: common/connection.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/connection.h,v retrieving revision 1.23 diff -u -r1.23 connection.h --- common/connection.h 30 Oct 2002 22:34:03 -0000 1.23 +++ common/connection.h 10 Nov 2002 19:05:15 -0000 @@ -27,6 +27,7 @@ #include "shared.h" /* bool type */ struct player; +struct timer_list; #define MAX_LEN_PACKET 4096 #define MAX_LEN_CAPSTR 512 @@ -96,8 +97,9 @@ struct socket_packet_buffer *buffer; struct socket_packet_buffer *send_buffer; time_t last_write; - bool ponged; /* have received a PACKET_CONN_PONG? */ + double ping_time; + struct conn_list self; /* list with this connection as single element */ char name[MAX_LEN_NAME]; char addr[MAX_LEN_ADDR]; @@ -149,6 +151,9 @@ * Will increase for every received packet. */ int last_request_id_seen; + + /* How many PACKET_CONN_PING haven't received a PACKET_CONN_PONG? */ + struct timer_list *ping_timers; } server; /* Index: common/game.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.c,v retrieving revision 1.150 diff -u -r1.150 game.c --- common/game.c 2 Nov 2002 13:33:53 -0000 1.150 +++ common/game.c 10 Nov 2002 19:05:17 -0000 @@ -655,6 +655,7 @@ game.netwait = GAME_DEFAULT_NETWAIT; game.last_ping = 0; game.pingtimeout = GAME_DEFAULT_PINGTIMEOUT; + game.pingtime = GAME_DEFAULT_PINGTIME; game.end_year = GAME_DEFAULT_END_YEAR; game.year = GAME_START_YEAR; game.turn = 0; Index: common/game.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.h,v retrieving revision 1.115 diff -u -r1.115 game.h --- common/game.h 7 Nov 2002 15:32:39 -0000 1.115 +++ common/game.h 10 Nov 2002 19:05:17 -0000 @@ -72,6 +72,7 @@ int netwait; time_t last_ping; int pingtimeout; + int pingtime; time_t turn_start; int end_year; int year; @@ -398,6 +399,10 @@ #define GAME_DEFAULT_NETWAIT 4 #define GAME_MIN_NETWAIT 0 #define GAME_MAX_NETWAIT 20 + +#define GAME_DEFAULT_PINGTIME 20 +#define GAME_MIN_PINGTIME 1 +#define GAME_MAX_PINGTIME 1800 #define GAME_DEFAULT_PINGTIMEOUT 60 #define GAME_MIN_PINGTIMEOUT 60 Index: common/packets.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v retrieving revision 1.224 diff -u -r1.224 packets.c --- common/packets.c 7 Nov 2002 18:55:25 -0000 1.224 +++ common/packets.c 10 Nov 2002 19:05:24 -0000 @@ -447,6 +447,9 @@ case PACKET_ATTRIBUTE_CHUNK: return receive_packet_attribute_chunk(pc); + case PACKET_PING_INFO: + return receive_packet_ping_info(pc); + default: freelog(LOG_ERROR, "unknown packet type %d received from %s", type, conn_description(pc)); @@ -805,6 +808,45 @@ dio_get_string(&din, preq->name, sizeof(preq->name)); RECEIVE_PACKET_END(preq); +} + +/************************************************************************* +This is the ping packet +**************************************************************************/ +int send_packet_ping_info(struct connection *pc, + const struct packet_ping_info *packet) +{ + int i; + SEND_PACKET_START(PACKET_PING_INFO); + + dio_put_uint8(&dout, packet->connections); + + for (i = 0; i < packet->connections; i++) { + dio_put_uint8(&dout, packet->conn_id[i]); + dio_put_uint32(&dout, (int) (packet->ping_time[i] * 1e6)); + } + + SEND_PACKET_END; +} + +/************************************************************************* +... +**************************************************************************/ +struct packet_ping_info *receive_packet_ping_info(struct connection *pc) +{ + int i; + RECEIVE_PACKET_START(packet_ping_info, packet); + + dio_get_uint8(&din, &packet->connections); + for (i = 0; i < packet->connections; i++) { + int tmp; + + dio_get_uint8(&din, &packet->conn_id[i]); + dio_get_uint32(&din, &tmp); + packet->ping_time[i] = tmp / 1e6; + } + + RECEIVE_PACKET_END(packet); } /************************************************************************* Index: common/packets.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v retrieving revision 1.128 diff -u -r1.128 packets.h --- common/packets.h 7 Nov 2002 18:55:25 -0000 1.128 +++ common/packets.h 10 Nov 2002 19:05:26 -0000 @@ -128,6 +128,7 @@ PACKET_SELECT_NATION_OK, PACKET_FREEZE_HINT, PACKET_THAW_HINT, + PACKET_PING_INFO, PACKET_LAST /* leave this last */ }; @@ -505,6 +506,15 @@ char capability[MAX_LEN_CAPSTR]; }; +/*************** + Ping packet +***************/ +struct packet_ping_info { + int connections; + int conn_id[MAX_NUM_PLAYERS]; + double ping_time[MAX_NUM_PLAYERS]; +}; + /********************************************************* The server tells the client all about a spaceship: *********************************************************/ @@ -940,6 +950,9 @@ const struct packet_game_info *pinfo); struct packet_game_info *receive_packet_game_info(struct connection *pc); +int send_packet_ping_info(struct connection *pc, + const struct packet_ping_info *packet); +struct packet_ping_info *receive_packet_ping_info(struct connection *pc); struct packet_player_info *receive_packet_player_info(struct connection *pc); int send_packet_player_info(struct connection *pc, Index: common/packets_lsend.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets_lsend.c,v retrieving revision 1.12 diff -u -r1.12 packets_lsend.c --- common/packets_lsend.c 25 Aug 2002 11:20:59 -0000 1.12 +++ common/packets_lsend.c 10 Nov 2002 19:05:26 -0000 @@ -81,6 +81,14 @@ conn_list_iterate_end; } +void lsend_packet_ping_info(struct conn_list *dest, + const struct packet_ping_info *packet) +{ + conn_list_iterate(*dest, pconn) + send_packet_ping_info(pconn, packet); + conn_list_iterate_end; +} + void lsend_packet_player_info(struct conn_list *dest, const struct packet_player_info *pinfo) { Index: common/packets_lsend.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets_lsend.h,v retrieving revision 1.11 diff -u -r1.11 packets_lsend.h --- common/packets_lsend.h 25 Aug 2002 11:20:59 -0000 1.11 +++ common/packets_lsend.h 10 Nov 2002 19:05:27 -0000 @@ -32,6 +32,8 @@ const struct packet_map_info *pinfo); void lsend_packet_game_info(struct conn_list *dest, const struct packet_game_info *pinfo); +void lsend_packet_ping_info(struct conn_list *dest, + const struct packet_ping_info *packet); void lsend_packet_player_info(struct conn_list *dest, const struct packet_player_info *pinfo); void lsend_packet_conn_info(struct conn_list *dest, Index: common/timing.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/timing.c,v retrieving revision 1.10 diff -u -r1.10 timing.c --- common/timing.c 14 Feb 2002 15:17:20 -0000 1.10 +++ common/timing.c 10 Nov 2002 19:05:27 -0000 @@ -96,6 +96,28 @@ } start; }; +static struct timeval last_seen; +static bool last_seen_init=0; + +static void log(struct timeval *p) +{ + if (!last_seen_init) { + last_seen_init = 1; + last_seen = *p; + return; + } + + if (p->tv_sec > last_seen.tv_sec || (p->tv_sec == last_seen.tv_sec && + p->tv_usec > last_seen.tv_usec)) { + return; + } + + freelog(LOG_NORMAL, "last_seen (%d, %d) p (%d,%d)", + (int) last_seen.tv_sec, (int) last_seen.tv_usec, (int) p->tv_sec, + (int) p->tv_usec); + exit(1); +} + /********************************************************************** Report if clock() returns -1, but only the first time. Ignore this timer from now on. @@ -260,6 +282,7 @@ report_gettimeofday_failed(t); return; } + log(&t->start.tv); #else t->start.t = time(NULL); if (t->start.t == (time_t) -1) { @@ -313,6 +336,7 @@ report_gettimeofday_failed(t); return; } + log(&now); t->usec += (now.tv_usec - t->start.tv.tv_usec); t->sec += (now.tv_sec - t->start.tv.tv_sec); if (t->usec < 0) { @@ -353,6 +377,7 @@ stop_timer(t); t->state = TIMER_STARTED; } + assert(t->sec >= 0 && t->usec >= 0); return t->sec + t->usec / (double)N_USEC_PER_SEC; } Index: po/POTFILES.in =================================================================== RCS file: /home/freeciv/CVS/freeciv/po/POTFILES.in,v retrieving revision 1.56 diff -u -r1.56 POTFILES.in --- po/POTFILES.in 16 Oct 2002 23:03:19 -0000 1.56 +++ po/POTFILES.in 10 Nov 2002 19:05:32 -0000 @@ -50,6 +50,7 @@ client/helpdata.c client/options.c client/packhand.c +client/plrdlg_common.c client/tilespec.c client/agents/cma_core.c client/agents/cma_fec.c Index: server/sernet.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/sernet.c,v retrieving revision 1.97 diff -u -r1.97 sernet.c --- server/sernet.c 7 Nov 2002 16:04:55 -0000 1.97 +++ server/sernet.c 10 Nov 2002 19:05:32 -0000 @@ -75,6 +75,7 @@ #include "meta.h" #include "srv_main.h" #include "stdinhand.h" +#include "timing.h" #include "sernet.h" @@ -105,12 +106,22 @@ void user_interrupt_callback(); #endif +#define SPECLIST_TAG timer +#define SPECLIST_TYPE struct timer +#include "speclist.h" + +#define SPECLIST_TAG timer +#define SPECLIST_TYPE struct timer +#include "speclist_c.h" + #define PROCESSING_TIME_STATISTICS 0 static int server_accept_connection(int sockfd); static void start_processing_request(struct connection *pconn, int request_id); static void finish_processing_request(struct connection *pconn); +static void ping_connection(struct connection *pconn); +static void send_ping_times_to_all(void); static bool no_input = FALSE; @@ -164,6 +175,13 @@ *****************************************************************************/ void close_connection(struct connection *pconn) { + while(timer_list_size(pconn->server.ping_timers)> 0) { + struct timer *timer = timer_list_get(pconn->server.ping_timers, 0); + + timer_list_unlink(pconn->server.ping_timers, timer); + free_timer(timer); + } + /* safe to do these even if not in lists: */ conn_list_unlink(&game.all_connections, pconn); conn_list_unlink(&game.est_connections, pconn); @@ -392,22 +410,27 @@ } } - /* send PACKET_CONN_PING & cut mute players */ - if ((time(NULL)>game.last_ping + game.pingtimeout)) { - for(i=0; iused) { - send_packet_generic_empty(pconn, PACKET_CONN_PING); + /* Pinging around for statistics*/ + if (time(NULL) > (game.last_ping + game.pingtime)) { + /* send data about the previous run */ + send_ping_times_to_all(); - if (pconn->ponged) { - pconn->ponged = FALSE; - } else { - freelog(LOG_NORMAL, "cut connection %s due to ping timeout", - conn_description(pconn)); - close_socket_callback(pconn); - } + conn_list_iterate(game.game_connections, pconn) { + if (!pconn->used) { + continue; } - } + + if ((timer_list_size(pconn->server.ping_timers) > 0 + && + read_timer_seconds(timer_list_get(pconn->server.ping_timers, 0)) + > game.pingtimeout) || pconn->ping_time > game.pingtimeout) { + /* cut mute players */ + freelog(LOG_NORMAL, "cut connection %s due to ping timeout", + conn_description(pconn)); + close_socket_callback(pconn); + } + ping_connection(pconn); + } conn_list_iterate_end; game.last_ping = time(NULL); } @@ -699,7 +722,6 @@ pconn->buffer = new_socket_packet_buffer(); pconn->send_buffer = new_socket_packet_buffer(); pconn->last_write = 0; - pconn->ponged = TRUE; pconn->first_packet = TRUE; pconn->byte_swap = FALSE; pconn->capability[0] = '\0'; @@ -708,6 +730,9 @@ pconn->notify_of_writable_data = NULL; pconn->server.currently_processed_request_id = 0; pconn->server.last_request_id_seen = 0; + pconn->server.ping_timers = malloc(sizeof(*pconn->server.ping_timers)); + timer_list_init(pconn->server.ping_timers); + pconn->ping_time = -1.0; pconn->incoming_packet_notify = NULL; pconn->outgoing_packet_notify = NULL; @@ -718,6 +743,7 @@ conn_list_insert_back(&game.all_connections, pconn); freelog(LOG_VERBOSE, "connection (%s) from %s", pconn->name, pconn->addr); + ping_connection(pconn); return 0; } } @@ -818,4 +844,68 @@ pconn->server.currently_processed_request_id, pconn->id); send_packet_generic_empty(pconn, PACKET_PROCESSING_FINISHED); pconn->server.currently_processed_request_id = 0; +} + +/************************************************************************** +This is the ping function +**************************************************************************/ +static void ping_connection(struct connection *pconn) +{ + freelog(LOG_NORMAL, "sending ping to %s (open=%d)", + conn_description(pconn), + timer_list_size(pconn->server.ping_timers)); + timer_list_insert_back(pconn->server.ping_timers, + new_timer_start(TIMER_USER, TIMER_ACTIVE)); + send_packet_generic_empty(pconn, PACKET_CONN_PING); +} + +/************************************************************************** +This is the pong function +**************************************************************************/ +void handle_conn_pong(struct connection *pconn) +{ + struct timer *timer; + + if (timer_list_size(pconn->server.ping_timers) == 0) { + freelog(LOG_NORMAL, "got unexpected pong from %s", + conn_description(pconn)); + return; + } + + timer = timer_list_get(pconn->server.ping_timers, 0); + timer_list_unlink(pconn->server.ping_timers, timer); + pconn->ping_time = read_timer_seconds_free(timer); + freelog(LOG_NORMAL, "got pong from %s (open=%d); ping time = %fs", + conn_description(pconn), + timer_list_size(pconn->server.ping_timers), pconn->ping_time); +} + +/************************************************************************** +... +**************************************************************************/ +static void send_ping_times_to_all(void) +{ + struct packet_ping_info packet; + int i; + + i = 0; + conn_list_iterate(game.game_connections, pconn) { + if (!pconn->used) { + continue; + } + i++; + } conn_list_iterate_end; + + packet.connections = i; + + i = 0; + conn_list_iterate(game.game_connections, pconn) { + if (!pconn->used) { + continue; + } + packet.conn_id[i] = pconn->id; + packet.ping_time[i] = pconn->ping_time; + i++; + } conn_list_iterate_end; + lsend_packet_ping_info(&game.est_connections, &packet); } Index: server/sernet.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/sernet.h,v retrieving revision 1.7 diff -u -r1.7 sernet.h --- server/sernet.h 18 Sep 2000 20:36:15 -0000 1.7 +++ server/sernet.h 10 Nov 2002 19:05:32 -0000 @@ -25,5 +25,6 @@ void close_connections_and_socket(void); void init_connections(void); void close_connection(struct connection *pconn); +void handle_conn_pong(struct connection *pconn); #endif /* FC__SERNET_H */ Index: server/srv_main.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v retrieving revision 1.102 diff -u -r1.102 srv_main.c --- server/srv_main.c 7 Nov 2002 18:55:26 -0000 1.102 +++ server/srv_main.c 10 Nov 2002 19:05:35 -0000 @@ -913,7 +913,7 @@ handle_patrol_route(pplayer, (struct packet_goto_route *)packet); break; case PACKET_CONN_PONG: - pconn->ponged = TRUE; + handle_conn_pong(pconn); break; case PACKET_UNIT_AIRLIFT: handle_unit_airlift(pplayer, (struct packet_unit_request *)packet); Index: server/stdinhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v retrieving revision 1.261 diff -u -r1.261 stdinhand.c --- server/stdinhand.c 7 Nov 2002 18:55:26 -0000 1.261 +++ server/stdinhand.c 10 Nov 2002 19:05:44 -0000 @@ -726,11 +726,15 @@ "wait at all."), NULL, GAME_MIN_NETWAIT, GAME_MAX_NETWAIT, GAME_DEFAULT_NETWAIT) - GEN_INT("pingtimeout", game.pingtimeout, SSET_META, SSET_TO_CLIENT, - N_("Maximum seconds between PINGs"), + GEN_INT("pingtime", game.pingtime, SSET_META, SSET_TO_CLIENT, + N_("Seconds between PINGs"), N_("The civserver will poll the clients with a PING request " - "each time this period elapses. If a client doesn't reply " - "with a PONG before the next server PING request the " + "each time this period elapses."), NULL, + GAME_MIN_PINGTIME, GAME_MAX_PINGTIME, GAME_DEFAULT_PINGTIME) + + GEN_INT("pingtimeout", game.pingtimeout, SSET_META, SSET_TO_CLIENT, + N_("Time to cut a client"), + N_("If a client doesn't reply to a PONG in this time the " "client is disconnected."), NULL, GAME_MIN_PINGTIMEOUT, GAME_MAX_PINGTIMEOUT, GAME_DEFAULT_PINGTIMEOUT)