Let's say I create a simple multithreaded TCP server like so:
int server_fd = socket(/* args */);
setsockopt(server_fd, /* other args... */);
bind(server_fd, /* other args... */);
listen(server_fd, backlog);
while (1) {
int client_fd = accept(server_fd, /* other args... */);
if (fork() == 0) {
// handle client request
close(client_fd);
exit(0);
}
}
A server like this should be able to handle many clients, but what happens if a malicious client performs the initial TCP handshake extremely slowly? During that, will the server still be able to accept other legitimate clients, or does the slow client prohibit that, as the call to accept()
is blocking?
To clarify my question:
What does the call to accept()
do under the hood? Does it simply take the next incoming socket and prepare it for communication by establishing a file descriptor, or is it actively communicating with the client to complete the handshake? Does the process of waiting for a TCP handshake affect other incoming connections?
In common OS the TCP handshake is done by the OS kernel, which can handle multiple pending handshakes in parallel. Only once the TCP handshake is successfully done is it put on the queue of established connections, where it can then be retrieved with accept
.
Note that some user-space TCP stacks or tiny TCP stacks, like those found in embedded systems, might behave differently.
Note also that contrary to the TCP handshake, a TLS handshake (as in SSL_accept) is usually done in user space. Therefore with your multi-process or multi-threading design it should better be done after the fork
, so that a slow or misbehaving peer does not block parallel TLS handshakes.