enet
enet copied to clipboard
enet_host_service problem
I think there is a problem within the control flow of enet_host_service (in the case of low RTO).
From my understanding, given some non-zero event time-out x, the following occurs:
dispatch_incoming_commands
do {
send_outgoing_commands
receive_incoming_commands
send_outgoing_commands
dispatch_incoming_commands
do {
wait for socket
} while wait condition met was interrupt
} while wait condition met was receive
and along the way, if there is an event to return, or the timeout is hit, we break out and return.
I think that there are two potential problems with the control flow, and both have to do with when disconnects are initiated by the host, and it takes the client more than one RTO to ACK the disconnect
Suppose the following scenario:
- Host sends a disconnect to the client
- The client does not ACK to the first transmission, and
enet_host_servicetimes out without a response - Loop calls
enet_host_serviceagain. Still no response, so it hits theenet_waitfunction. - The ack arrives so there is something to receive on the sock, so we restart the loop
- We run
send_outgoingbeforereceive_incomingbased off the order of calls - the last
disconnectwe sent has timed out. retransmit it (however at this point, the client has already acked the disconnect) - This returns out of
enet_host_service - The next call of
enet_host_servicethen finally actually runsreceive_incoming_message, which actually fully tears down the enet peer from the host (including clearing all of the queues) - The last
disconnectwe sent has already been sent, and then we get anICMP destination unreachable, which causes the nextenet_host_serviceto return with -1.
TLDR: The way we reloop is conditioned on the socket having something to listen to, but then we call send_outgoing before we actually receive the incoming command. (this is fine usually, but in the case of disconnects, we don't want to be retransmitting when we received an ack for our last disconnect). While enet_host_service can be run with a lower event timeout to fix this, the larger issue is why send_outgoing runs before receive_incoming in the loop, when the event that triggers restarting the loop is that the socket is ready to receive from. Wouldn't it make more sense to receive_incoming_commands first if the socket signals that there is data to listen to?