Skip to content

Commit da4bd9a

Browse files
authored
report read readiness accurately for freshly bound UDP sockets (#740)
Previously, `wasip2_udp.c` would call `wasi:sockets/udp#udp-socket.streams` lazily as needed in e.g. `sendto` and `recvfrom`. However, it was not doing so when the socket was `poll`ed, which meant `poll` would indicate read readiness and return immediately even though there was nothing ready to read. With this commit, we now create the stream when polling the socket, which allows us to actually wait for real read readiness. This also adds trivial `SO_ERROR` support to `udp_getsockopt`.
1 parent 3c738db commit da4bd9a

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

libc-bottom-half/sources/wasip2_udp.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,11 @@ static int udp_getsockopt(void *data, int level, int optname, void *optval,
627627
value = __wasi_sockets_utils__posix_family(socket->family);
628628
break;
629629
}
630+
631+
case SO_ERROR:
632+
value = 0;
633+
break;
634+
630635
case SO_RCVBUF: {
631636
uint64_t result;
632637
if (!udp_method_udp_socket_receive_buffer_size(socket_borrow, &result,
@@ -825,10 +830,18 @@ static int udp_poll_register(void *data, poll_state_t *state, short events) {
825830
udp_socket_t *socket = (udp_socket_t *)data;
826831
switch (socket->state.tag) {
827832
case UDP_SOCKET_STATE_UNBOUND:
828-
case UDP_SOCKET_STATE_BOUND_NOSTREAMS:
833+
// In the unbound case, all we can do is assume immediate read and write
834+
// readiness:
829835
__wasilibc_poll_ready(state, events);
830836
break;
831837

838+
case UDP_SOCKET_STATE_BOUND_NOSTREAMS:
839+
// We can't know the true state of read and write readiness until we have
840+
// stream handles, so let's add those now:
841+
if (udp_create_streams(socket, NULL) < 0)
842+
return -1;
843+
// Deliberately fall through to next case:
844+
832845
case UDP_SOCKET_STATE_BOUND_STREAMING:
833846
case UDP_SOCKET_STATE_CONNECTED: {
834847
udp_socket_streams_t *streams;

test/src/sockets-nonblocking-udp.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,27 @@ void test_udp_client() {
7171
// Write to socket
7272
ssize_t bytes_sent = send(socket_fd, message, len + 1, 0);
7373

74+
// Wait for server to be read-ready.
75+
while (1) {
76+
if (t_status)
77+
exit(t_status);
78+
79+
struct pollfd poll_fd = {
80+
.fd = server_socket_fd, .events = POLLRDNORM, .revents = 0};
81+
TEST(poll(&poll_fd, 1, 100) != -1);
82+
if (poll_fd.revents) {
83+
break;
84+
}
85+
}
86+
7487
// Receive from client
7588
struct sockaddr_in sockaddr_client;
7689
socklen_t sockaddr_client_len = sizeof(sockaddr_in);
7790
ssize_t bytes_received =
7891
recvfrom(server_socket_fd, server_buffer, BUFSIZE, 0,
7992
(struct sockaddr *)&sockaddr_client, &sockaddr_client_len);
8093
if (bytes_received == -1)
81-
if (errno != EWOULDBLOCK)
82-
t_error("recvfrom failed (errno = %d)\n", errno);
83-
84-
while (bytes_received == -1) {
85-
struct pollfd poll_fd = {
86-
.fd = server_socket_fd, .events = POLLRDNORM, .revents = 0};
87-
poll(&poll_fd, 1, 100);
88-
bytes_received = recv(server_socket_fd, server_buffer, BUFSIZE, 0);
89-
}
94+
t_error("recvfrom failed (errno = %d)\n", errno);
9095

9196
TEST(bytes_sent == len + 1);
9297
TEST(bytes_received == len + 1);
@@ -117,6 +122,14 @@ void test_udp_client() {
117122
if (bytes_sent == bytes_received)
118123
TEST(strcmp(message, client_buffer) == 0);
119124

125+
int value = -1;
126+
socklen_t length = sizeof(value);
127+
TEST(getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &value, &length) == 0 &&
128+
value == 0);
129+
TEST(getsockopt(server_socket_fd, SOL_SOCKET, SO_ERROR, &value, &length) ==
130+
0 &&
131+
value == 0);
132+
120133
// Shut down client
121134
close(socket_fd);
122135

0 commit comments

Comments
 (0)