Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/lib/libsyscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,8 @@ var SyscallsLibrary = {
// write the source address out
var name = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_name, '*') }}};
if (name) {
var errno = writeSockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port);
var namelen = message + {{{ C_STRUCTS.msghdr.msg_namelen }}};
var errno = writeSockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port, namelen);
#if ASSERTIONS
assert(!errno);
#endif
Expand All @@ -546,12 +547,15 @@ var SyscallsLibrary = {
}
var length = Math.min(iovlen, bytesRemaining);
var buf = msg.buffer.subarray(bytesRead, bytesRead + length);
HEAPU8.set(buf, iovbase + bytesRead);
HEAPU8.set(buf, iovbase);
bytesRead += length;
bytesRemaining -= length;
}

// TODO set msghdr.msg_flags
{{{ makeSetValue('message', C_STRUCTS.msghdr.msg_controllen, '0', 'i32') }}};
{{{ makeSetValue('message', C_STRUCTS.msghdr.msg_flags, '0', 'i32') }}};

// TODO report truncation in msghdr.msg_flags
// MSG_EOR
// End of record was received (if supported by the protocol).
// MSG_OOB
Expand Down
5 changes: 4 additions & 1 deletion src/struct_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,10 @@
"msg_name",
"msg_namelen",
"msg_iov",
"msg_iovlen"
"msg_iovlen",
"msg_control",
"msg_controllen",
"msg_flags"
]
}
},
Expand Down
3 changes: 3 additions & 0 deletions src/struct_info_generated.json
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,9 @@
},
"msghdr": {
"__size__": 28,
"msg_control": 16,
"msg_controllen": 20,
"msg_flags": 24,
"msg_iov": 8,
"msg_iovlen": 12,
"msg_name": 0,
Expand Down
3 changes: 3 additions & 0 deletions src/struct_info_generated_wasm64.json
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,9 @@
},
"msghdr": {
"__size__": 56,
"msg_control": 32,
"msg_controllen": 40,
"msg_flags": 48,
"msg_iov": 16,
"msg_iovlen": 24,
"msg_name": 0,
Expand Down
4 changes: 2 additions & 2 deletions test/codesize/test_codesize_hello_dylink_all.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"a.out.js": 268195,
"a.out.js": 268229,
"a.out.nodebug.wasm": 588191,
"total": 856386,
"total": 856420,
"sent": [
"IMG_Init",
"IMG_Load",
Expand Down
104 changes: 104 additions & 0 deletions test/sockets/test_udp_recvmsg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2026 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/

#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

static int server_fd;
static int client_fd;
static struct sockaddr_in destination;
static bool sent;

static void succeed(void) {
close(server_fd);
close(client_fd);
puts("done");
#ifdef __EMSCRIPTEN__
emscripten_cancel_main_loop();
#else
_exit(0);
#endif
}

static void main_loop(void) {
if (!sent) {
assert(sendto(client_fd, "onetwo", 6, 0, (struct sockaddr*)&destination,
sizeof(destination)) == 6);
sent = true;
}

// Receive the single datagram scattered across two iovecs.
char first[3];
char second[3];
char control[16];
struct sockaddr_in source;
struct iovec iovecs[2] = {
{.iov_base = first, .iov_len = sizeof(first)},
{.iov_base = second, .iov_len = sizeof(second)},
};
struct msghdr message = {
.msg_name = &source,
.msg_namelen = sizeof(source),
.msg_iov = iovecs,
.msg_iovlen = 2,
.msg_control = control,
.msg_controllen = sizeof(control),
};

ssize_t len = recvmsg(server_fd, &message, 0);
if (len < 0) {
assert(errno == EAGAIN || errno == EWOULDBLOCK);
return;
}

assert(len == 6);
assert(memcmp(first, "one", 3) == 0);
assert(memcmp(second, "two", 3) == 0);
assert(message.msg_namelen == sizeof(struct sockaddr_in));
assert(source.sin_family == AF_INET);
assert(message.msg_controllen == 0);
assert(message.msg_flags == 0);
succeed();
}

int main(void) {
server_fd = socket(AF_INET, SOCK_DGRAM, 0);
client_fd = socket(AF_INET, SOCK_DGRAM, 0);
assert(server_fd >= 0 && client_fd >= 0);

struct sockaddr_in address = {
.sin_family = AF_INET,
.sin_port = htons(0),
};
inet_pton(AF_INET, "127.0.0.1", &address.sin_addr);
assert(bind(server_fd, (struct sockaddr*)&address, sizeof(address)) == 0);

socklen_t length = sizeof(destination);
assert(getsockname(server_fd, (struct sockaddr*)&destination, &length) == 0);
assert(fcntl(server_fd, F_SETFL, O_NONBLOCK) == 0);

#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, 0);
#else
while (true) {
main_loop();
usleep(1000);
}
#endif
return 0;
}
5 changes: 5 additions & 0 deletions test/test_sockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,11 @@ def test_noderawsockets_udp(self):
# ephemeral port, the client sends a datagram, the server echoes it back.
self.do_runf('sockets/test_udp_echo.c', 'done\n', cflags=['-sNODERAWSOCKETS'])

def test_noderawsockets_udp_recvmsg(self):
# recvmsg scatters a datagram across multiple iovecs at the right offsets
# and updates msg_namelen/msg_controllen/msg_flags in the caller's msghdr.
self.do_runf('sockets/test_udp_recvmsg.c', 'done\n', cflags=['-sNODERAWSOCKETS'])

@also_with_proxy_to_pthread
def test_noderawsockets_udp_connect(self):
# Connected UDP: sendto() with an address gives EISCONN, send() reaches the
Expand Down
Loading