Boost socket async_send: how does it handle ewouldblock? - sockets

On Unix, send() on a non-blocking socket could return error EWOULDBLOCK if outbound socket buffer is full. In this case, one should call select() to determine when it's possible to retry. Does Boost sockets in nonblocking mode handle all of this for you?

Yes, it does. You can check for yourself for example here boost/asio/detail/impl/socket_ops.ipp.

Related

SOCK_DGRAM socket recv thread-safe?

Are UNIX SOCK_DGRAM sockets thread-safe for recv() method?
If multiple threads are calling recv() on socket, are both guaranteed to get one clean UDP packet each or is there a chance of data getting mixed up?
Will the behavior be affected by whether socket is in blocking or non-blocking mode? Any pointers to documentation would be highly appreciated.
Calling recv() from multiple threads is a safe operation. If the socket is a datagram socket then each recv returns a unique datagram that is not mixed up with other datagrams.
Posix standard explicitly enumerates all standard functions that are unsafe:
2.9.1 Thread-Safety
All functions defined by this volume of POSIX.1-2017 shall be
thread-safe, except that the following functions1 need not be
thread-safe.
asctime() basename() catgets() crypt() ctime()
....
There are almost 100 unsafe functions and further functions that are safe under certain conditions only. recv() is not there. See POSIX.1-2017 2.9.1 Thread-Safety.

UDP socket gives error WSAETIMEDOUT

I have a call to sendto() for a UDP socket. Sometimes(not always) it blocks my application for ~2.5 seconds. When I check the return value of the sendto() call I get SOCKET_ERROR(-1) and WSAGetLastError() returns WSAETIMEDOUT(10060)
Why would a UDP socket timeout? Under what circumstances would sendto() be a blocking call?
Why would a UDP socket timeout?
It can happen if the socket is running in blocking mode (the default mode), and has a send timeout assigned to it.
Under what circumstances would sendto() be a blocking call?
Sockets are created in blocking mode by default. You have to explicitly request non-blocking behavior if you need it.
In blocking mode, a UDP socket can block if the kernel buffer fills up or if WinSock has to wait for a network event before completing the send. This is documented behavior:
sendto() function
When issuing a blocking Winsock call such as sendto, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread. Issuing another blocking Winsock call inside an APC that interrupted an ongoing blocking Winsock call on the same thread will lead to undefined behavior, and must never be attempted by Winsock clients.
...
If no buffer space is available within the transport system to hold the data to be transmitted, sendto will block unless the socket has been placed in a nonblocking mode. On nonblocking, stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server systems. The select, WSAAsyncSelect or WSAEventSelect function can be used to determine when it is possible to send more data.

How is it possible to have send timeout on a non blocking socket?

I have some problems understanding the working of sockets in Linux.
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(int));
write = write(sockfd, buf, len);
In the above code as writes are buffered, send timeout doesn't make any sense(write system call will return immediately when the user space buffer is copied into the kernel buffers). Send buffer size is much more important parameter, but send timeout seems it does nothing worthwile. But I am certainly wrong, as I have seen quite a lot of code which uses SO_SNDTIMEO. How can user space code timeout using SO_SNDTIMEO assuming that the receiver is very slow?
How is it possible to have send timeout on a non blocking socket?
It isn't. Timeouts are for blocking mode. A non-blocking recv() won't block, and therefore cannot time out either.
I have seen a lot of code which uses SO_SNDTIMEO.
Not in non-blocking mode unless the code concerned is nonsense.
SO_SNDTIMEO is useful for a blocking socket. If the socket's buffer is full, send() can block, in which case it may be useful to use the SO_SNDTIMEO socket option. For non-blocking sockets, if the socket's buffer is full, send will fail immediately, so there is no point in setting SO_SNDTIMEO with a non-blocking socket.

Determine how many bytes can be sent with winsock (FIONWRITE)?

With select I can determine if any bytes can be received or sent without blocking.
With this function I can determine how many bytes can be received:
function BytesAvailable(S: TSocket): Integer;
begin
if ioctlsocket(S, FIONREAD, Result) = SOCKET_ERROR then
Result := -1;
end;
Is there also a way to determine how many bytes can be sent?
So I can be sure when I call send with N bytes, it will return exactly N bytes sent (or SOCKET_ERROR) but not less (send buffer is full).
FIONWRITE is not available for Winsock.
According to MVP Alexander Nickolov, there is no such facility in Windows. He also mentions that "good socket code" doesn't use FIONWRITE-like ioctls, but doesn't explain why.
To circumvent this issue, you could enable non-blocking I/O (using FIONBIO, I guess) on sockets you're interested in. That way, WSASend will succeed on such sockets when it can complete sending without blocking, or fail with WSAGetLastError() == WSAEWOULDBLOCK when the buffer is full (as stated in the documentation for WSASend):
WSAEWOULDBLOCK
Overlapped sockets: There are too many outstanding overlapped I/O requests. Nonoverlapped sockets: The socket is marked as nonblocking and the send operation cannot be completed immediately.
Also read further notes about this error code.
Winsock send() blocks only if the socket is running in blocking mode and the socket's outbound buffer fills up with queued data. If you are managing multiple sockets in the same thread, do not use blocking mode. If one receiver does not read data in a timely maner, it can cause all of the connections on that thread to be affected. Use non-blocking mode instead, then send() will report when a socket has entered a state where blocking would occur, then you can use select() to detect when the socket can accept new data again. A better option is to use overlapped I/O or I/O Completion Ports instead. Submit outbound data to the OS and let the OS handle all of the waiting for you, notifying you when the data has eventually been accepted/sent. Do not submit new data for a given socket until you receive that notification. For scalability to a large number of connections, I/O Completion Ports are generally a better choice.

WinSock select() on listen()ing socket, non-blocking I/O?

When I do a select() on a listen()ing socket on Windows and it is non-blocking. Do I get a read event or a write event when there is a connection pending?
read.
From MSDN:
The parameter readfds identifies the
sockets that are to be checked for
readability. If the socket is
currently in the listen state, it will
be marked as readable if an incoming
connection request has been received
such that an accept is guaranteed to
complete without blocking.