fix: net::poll() with negative timeout

If the timeout to net::poll() is -1, poll() will block until a requested
event occurs. However, in the poll() function, the Duration timeout is
converted to milliseconds (Duration is in microseconds). The conversion
involves integer arithmetics which results in a zero timeout (= -1 /
1000), i.e. poll() will return immediately and the following accept will
fail.

To fix this, only convert to milliseconds if timeout paramter is
non-negative.

Example to reproduce the error:

```
module echo;
import std::io, std::net;
fn void main()
{
	TcpServerSocket server = tcp::listen("localhost", 6969, 69, REUSEADDR)!!;
	server.sock.set_non_blocking(true)!!;
	Poll[*] polls = {{ .socket = server.sock, .events = net::SUBSCRIBE_READ }};
	if (catch net::poll(polls[..], net::POLL_FOREVER)) io::printn("poll error");
	TcpSocket client = tcp::accept(&server)!!;
	io::printn("OK");
}
```

Poll() will return immediately and the following tcp::accept() will fail
with an "ACCEPT_FAILED" error.

Reported-by: Alexey Kutepov <reximkut@gmail.com>
This commit is contained in:
Koni Marti
2025-01-02 14:28:38 +01:00
committed by Christoffer Lerno
parent 1994cba73e
commit 72839d7654

View File

@@ -63,7 +63,7 @@ fn ulong! poll_ms(Poll[] polls, long timeout_ms)
*>
fn ulong! poll(Poll[] polls, Duration timeout)
{
long time_ms = timeout.to_ms();
long time_ms = (timeout < 0) ? (long)POLL_FOREVER : timeout.to_ms();
if (time_ms > CInt.max) time_ms = CInt.max;
$if env::WIN32:
CInt result = win32_WSAPoll((Win32_LPWSAPOLLFD)polls.ptr, (Win32_ULONG)polls.len, (CInt)time_ms);