I have to make a simple IRC client/server programs for my IT school. The subject asks us to use select(2)
for socket polling but forbids us to use O_NONBLOCK
sockets.
- Your server will accept multiple simultaneous connections.
Attention, the use offork
is prohibited. So you should imperatively useselect
- Your server must not be blocking.
This has nothing to do with non-blocking sockets, which are prohibited (so do not usefcntl(s, O_NONBLOCK)
)
I’m wondering if it is even possible to design a non-blocking server (which does not fork) with blocking sockets even using select(2)
.
Here is a simple example: let say we have a simple text protocol with one command per line. Each client has a buffer. When select(2)
tells us a client is ready for read(2)
, we read until we found a \n
in the client buffer, therefor we process the command. With non-blocking sockets, we would read until EAGAIN
.
Let imagine now that we are using blocking sockets and a malicious client sends text with no line-break. select(2)
tells us data is available, we then read(2)
on the client. But we will never read the expected \n
. Instead of returning EAGAIN
, the syscall will block indefinitely. This is a denial of service attack.
Is it really possible to design a non-blocking server with blocking-sockets and select(2)
(no fork(2)
)?
Yes, you read once from the socket that select
tells you is ready. If the read
contains the \n
, then process that line. Otherwise, store any data that was received, and immediately go back to the select
.
This means of course, that for every open socket, you must maintain state information, and a buffer of data read so far. This allows the code to process each read
independently, without the need to finish a full line before going back to the select
.