diff --git a/libc/sock/send-nt.c b/libc/sock/send-nt.c index 24a0cb76010..b12c0f2b45e 100644 --- a/libc/sock/send-nt.c +++ b/libc/sock/send-nt.c @@ -54,7 +54,14 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen, ssize_t rc; struct Fd *f = g_fds.p + fd; sigset_t m = __sig_block(); - bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT); + + // we don't check O_NONBLOCK because we want to avoid needing to call + // WSAPoll() every time we write() to a non-blocking socket. WIN32 is + // unsafe at canceling socket sends. lots of code doesn't check write + // return status. good programs that sincerely want to avoid blocking + // on send() operations should have already called poll() beforehand. + bool nonblock = flags & _MSG_DONTWAIT; + flags &= ~_MSG_DONTWAIT; rc = __winsock_block(f->handle, flags, -nonblock, f->sndtimeo, m, sys_send_nt_start, &(struct SendArgs){iov, iovlen}); diff --git a/libc/sock/send.c b/libc/sock/send.c index 4050a2fba91..5cb91fad166 100644 --- a/libc/sock/send.c +++ b/libc/sock/send.c @@ -30,6 +30,18 @@ /** * Sends data to network socket. * + * Calling `send(fd, p, n, 0)` is equivalent to `write(fd, p, n)`. + * + * On Windows, calling send() or write() on a socket in `O_NONBLOCK` + * mode will block. This is done for many reasons. First, most UNIX OSes + * have a similar behavior, due to how little code checks the return + * status of write(). Secondly, WIN32 has bugs that prevent us from + * canceling an overlapped WSASend() operation safely. Programs that + * want to avoid send() blocking should call poll() beforehand with the + * POLLOUT flag to test when the socket can safely be written without + * blocking. It's also possible to pass `MSG_DONTWAIT` via `flags` in + * which case send() will do this for you automatically. + * * @param fd is the file descriptor returned by socket() * @param buf is the data to send, which we'll copy if necessary * @param size is the byte-length of buf