Helps JOY OF PROGRAMMING - Software Engineering Simulator. EA service is also known to break on short writes (that doesn't usually happen on Linux with its socket usage pattern but is known to be a problem on Macos).
I tested much larger buffers in Windows, it does queue at least up to 2GB of data with such send (also tested with local network besides localhost). Queuing 2x 2GB writes on nonblocking socket will succeed (even when there is obviously nothing reading the data on another socket end), the third will WSAEWOULDBLOCK. When tested over the local network with the receiving end, these data are continued to be stubbornly sent over network even after the socket is closed and process exited.
Below is the list of possible (remaining) issues / corner cases I could think of: - If setting FIONBIO to 0 on the socket is racing with this short write handling. The asynchronously queued part may become synchronous and the recursive sent will wait on the wait_handle returned by server. That is probably for good, let's pretend that racing FIONBIO happened before we started sock_send(); - If there is racing send(). It may actually interpose the data in between the short written part and the queued one. That will be wrong, although not worse what is happening now: if now short read happens, the racing data may be interposed the same way, regardless of whether the app is going to handle short write or not. This may be fixed with some added synchronization but so far seems unnecessary; - UDP sockets. Short read is not a thing with UDP socket, attempt to send a bigger packet than supported by socket / network results in [WSA]EMSGSIZE both on Windows and Unix. That's why I didn't add a check for socket type; - Spurious overlapped IO events won't be sent anywhere, apc_context for the added background read is 0; - The consequent writes will mind the non-empty socket write queue, those shouldn't be performed before that is finished (and will be queued async, waited ot timed out accordingly); - If the socket is closed (or process exits) before the background send is complete, the remaing queued data won't be sent (unlike Windows). This is not ideal but probably not the end of the world. When doing the same on Windows there is no way the app can know if the sent data actually reached the peer or not (while it will be much more likely to reach on Windows of course). The case with socket close can be fixed with some complication around delaying actual socket close on the server in the presence of such asyncs. The case of process exit is probably harder, the data are currently only stored on the sending process and only sending process does actual sends.