﻿id,summary,reporter,owner,description,type,status,priority,milestone,component,resolution,keywords,cc,phab_field
3264,Better timeout handling,elexis,,"Refs #69   Enhance Multiplayer Experience, #2854 Extensive lag may cause disconnections

'''Problem:'''
When a client drops, the game hangs for up to 30 seconds sometimes. The game appears to be paused and no one knows what's going on (although you can be sure that someone is dropping after like 10 seconds).

'''Fix:'''
(1) Some seconds after the last turn was processed, '''a message should be displayed''' for all clients that we are waiting for.
(2) The '''maximum timeout duration''' could be reduced from 30 to 10-20 seconds.

----

'''Reproduce timeout pauses:'''
Without modifying 0ad, I could reproduce a 5 to 8 second timeout, where the game appears to be paused for that duration. You need to start a game with another client and then kill that client with
{{{
kill -9 <pid>
}}}
To get the correct process ID use:
{{{
pidof pyrogenesis
}}}

Following the timeout model of enet (see below), the 30 second timeout can only be reproduced if you have actual lag.

----

'''Technical Background:'''
Currently the client network timeouts are not set in 0ad, i.e. the default values of the enet library are used. They are hardcoded in `enet.h`:
{{{
   ENET_PEER_TIMEOUT_LIMIT                = 32,
   ENET_PEER_TIMEOUT_MINIMUM              = 5000,
   ENET_PEER_TIMEOUT_MAXIMUM              = 30000,
}}}

The documentation doesn't have too much information. The code can be obtained from http://enet.bespin.org/Downloads.html.

In `peer.c` you can find the following method to change the timeout settings for each peer:
{{{
/** Sets the timeout parameters for a peer.

    The timeout parameter control how and when a peer will timeout from a failure to acknowledge
    reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable
    packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, 
    the timeout will be doubled until it reaches a set limit. If the timeout is thus at this
    limit and reliable packets have been sent but not acknowledged within a certain minimum time 
    period, the peer will be disconnected. Alternatively, if reliable packets have been sent
    but not acknowledged for a certain maximum time period, the peer will be disconnected regardless
    of the current timeout limit value.
    
    @param peer the peer to adjust
    @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0
    @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0
    @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0
*/
}}}

Therefore timeouts can be changed in `NetServer.cpp`in the function `CNetServerWorker::RunStep`, for the case `ENET_EVENT_TYPE_CONNECT` by adding for example:
{{{
enet_peer_timeout(event.peer, 0, 0, 10000);
}}}

The timeout logic can be found in `protocol.c`.

If I understand the matter correctly, the client will be disconnected after 5 seconds if he had good latency before disconnecting. If he already had bad latency then enet will wait up to 30 seconds.",enhancement,new,Should Have,Backlog,Core engine,,,,
