Half-Established Connections
With a half-established connection I mean a connection for which the client's call to connect()
returned successfully, but the servers call to accept()
didn't. This can happen the following way: The client calls connect()
, resulting in a SYN
packet to the server. The server goes into state SYN-RECEIVED
and sends a SYN-ACK
packet to the client. This causes the client to reply with ACK
, go into state ESTABLISHED
and return from the connect()
call. If the final ACK
is lost (or ignored, due to a full accept queue at the server, which is probably the more likely scenario), the server is still in state SYN-RECEIVED
and the accept()
does not return. Due to timeouts associated with the SYN-RECEIVED
state the SYN-ACK
will be resend, allowing the client to resend the ACK
. If the server is able to process the ACK
eventually, it will go into state ESTABLISHED
as well. Otherwise it will eventually reset the connection (i.e. send a RST
to the client).
You can create this scenario by starting lots of connections on a single listen socket (if you do not adjust the backlog and tcp_max_syn_backlog
). See this questions and this article for more details.
Experiments
I performed several experiments (with variations of this code) and observed some behaviour I cannot explain. All experiments where performed using Erlang's gen_tcp
and a current Linux, but I strongly suspect that the answers are not specific to this setup, so I tried to keep it more general here.
connect()
-> wait -> send()
-> receive()
My starting point was to establish a connection from the client, wait between 1 to 5 seconds, send a "Ping" message to the server and wait for the reply. With this setup I observed that the receive()
failed with the error closed
when I had a half-established connection. There was never an error during the send()
on a half-established connection. You can find a more detailed description of this setup here.
connect()
-> long wait -> send()
To see, if I can get errors while sending data on a half-established connection I waited for 4 minutes before sending data. The 4 minutes should cover all timeouts and retries associated with the half-established connection. Sending data was still possible, i.e. send()
returned without error.
connect()
-> receive()
Next I tested what happens if I only call receive()
with a very long timeout (5 minutes). My expectation was to get an closed
error for the half-established connections, as in the original experiments. Alas, nothing happend, no error was thrown and the receive eventually timed out.
My questions
- Is there a common name for what I call a half-established connection?
- Why is the
send()
on a half-established connection successful? - Why does a
receive()
only fail if I send data first?
Any help, especially links to detailed explanations, are welcome.