Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e656682
net,tls: port Node.js net/tls compatibility tests and fix the gaps th…
cirospaciari May 20, 2026
7586bf0
net: validate Server keepAliveInitialDelay; fix stale half-open comments
robobun May 21, 2026
f49ffa0
test(http2): scale maxSessionMemory timeout for debug builds
robobun May 21, 2026
1e7bfcb
net,tls: Node.js compatibility - half-open/reset/write semantics, server
cirospaciari May 28, 2026
c5a623c
Merge remote-tracking branch 'origin/main' into claude/port-node-net-…
cirospaciari May 29, 2026
6fc61d5
[autofix.ci] apply automated fixes
autofix-ci[bot] May 29, 2026
faa2b82
tls: PKCS#12-embedded CAs extend the trust set instead of replacing it
cirospaciari May 29, 2026
d0e6fa1
net,usockets: fail node:net writes on fatal send errors via an opt-in…
cirospaciari May 29, 2026
11bacc5
tls: only treat protocol-level handshake failures as fatal in the nod…
cirospaciari May 29, 2026
2d8281a
[autofix.ci] apply automated fixes
autofix-ci[bot] May 29, 2026
b275845
tls,net,test: harden FFI boundaries and test hygiene from review feed…
cirospaciari May 29, 2026
d32fcdd
usockets,uws: fix Windows would-block detection and lints in the fata…
cirospaciari May 29, 2026
7600f1f
[autofix.ci] apply automated fixes
autofix-ci[bot] May 29, 2026
1902306
tls,net: fix pfx-embedded CA trust on the server path and raw-twin wr…
cirospaciari May 29, 2026
8ab9aa5
net: fail the drain-path retry on fatal send errors too
cirospaciari May 29, 2026
46d4a42
tls: a hostname-mismatch-only handshake still marks the session estab…
cirospaciari May 29, 2026
86934e9
Merge remote-tracking branch 'origin/main' into claude/port-node-net-…
cirospaciari May 29, 2026
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
25 changes: 24 additions & 1 deletion packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,10 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t l
struct sockaddr_un server_address;
size_t addrlen = 0;
if (bsd_create_unix_socket_address(path, len, &dirfd_workaround_for_unix_path_len, &server_address, &addrlen)) {
/* The path could not be expressed as a sockaddr_un (the basename
* exceeds sun_path even with the dirfd workaround); surface the errno
* so the caller can report something better than a codeless failure. */
if (error && errno) *error = errno;
return LIBUS_SOCKET_ERROR;
}

Expand Down Expand Up @@ -1599,12 +1603,31 @@ static int is_loopback(struct sockaddr_storage *sockaddr) {
}
#endif

LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, int options) {
LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, struct sockaddr_storage *local_addr, int options) {
LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(addr->ss_family, SOCK_STREAM, 0, NULL);
if (fd == LIBUS_SOCKET_ERROR) {
return LIBUS_SOCKET_ERROR;
}

/* Bind to the requested local address/port before connecting (the
* `localAddress`/`localPort` connect options). A failure here - typically
* EADDRINUSE or EADDRNOTAVAIL - fails the connect with that errno. */
if (local_addr) {
socklen_t local_len = local_addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
if (bind(fd, (struct sockaddr *) local_addr, local_len)) {
#ifdef _WIN32
int bind_err = WSAGetLastError();
bsd_close_socket(fd);
WSASetLastError(bind_err);
#else
int bind_err = errno;
bsd_close_socket(fd);
errno = bind_err;
#endif
return LIBUS_SOCKET_ERROR;
}
}

#ifdef _WIN32
win32_set_nonblocking(fd);

Expand Down
21 changes: 15 additions & 6 deletions packages/bun-usockets/src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,8 @@ static inline void us_internal_init_connect_socket(struct us_socket_t *s,

struct us_socket_t *us_socket_group_connect_resolved_dns(struct us_socket_group_t *group,
unsigned char kind, struct ssl_ctx_st *ssl_ctx,
struct sockaddr_storage *addr, int options, int socket_ext_size) {
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, options);
struct sockaddr_storage *addr, struct sockaddr_storage *local_addr, int options, int socket_ext_size) {
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, local_addr, options);
if (connect_socket_fd == LIBUS_SOCKET_ERROR) {
return NULL;
}
Expand Down Expand Up @@ -539,14 +539,22 @@ static bool try_parse_ip(const char *ip_str, int port, struct sockaddr_storage *
}

void *us_socket_group_connect(struct us_socket_group_t *group, unsigned char kind,
struct ssl_ctx_st *ssl_ctx, const char *host, int port, int options,
struct ssl_ctx_st *ssl_ctx, const char *host, int port,
const char *local_host, int local_port, int options,
int socket_ext_size, int *has_dns_resolved) {
struct us_loop_t *loop = group->loop;

/* The local address is always a literal IP (Node validates it as one). */
struct sockaddr_storage local_addr_storage;
struct sockaddr_storage *local_addr = NULL;
if (local_host && try_parse_ip(local_host, local_port, &local_addr_storage)) {
local_addr = &local_addr_storage;
}

struct sockaddr_storage addr;
if (try_parse_ip(host, port, &addr)) {
*has_dns_resolved = 1;
return us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &addr, options, socket_ext_size);
return us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &addr, local_addr, options, socket_ext_size);
}

struct addrinfo_request *ai_req;
Expand All @@ -563,7 +571,7 @@ void *us_socket_group_connect(struct us_socket_group_t *group, unsigned char kin
struct sockaddr_storage a;
init_addr_with_port(&entries->info, port, &a);
*has_dns_resolved = 1;
struct us_socket_t *s = us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &a, options, socket_ext_size);
struct us_socket_t *s = us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &a, local_addr, options, socket_ext_size);
Bun__addrinfo_freeRequest(ai_req, s == NULL);
return s;
}
Expand Down Expand Up @@ -628,7 +636,8 @@ int start_connections(struct us_connecting_socket_t *c, int count) {
for (; c->addrinfo_head != NULL && opened < count; c->addrinfo_head = c->addrinfo_head->ai_next) {
struct sockaddr_storage addr;
init_addr_with_port(c->addrinfo_head, c->port, &addr);
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(&addr, c->options);
/* The deferred-DNS path does not carry a local binding. */
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(&addr, NULL, c->options);
if (connect_socket_fd == LIBUS_SOCKET_ERROR) {
continue;
}
Expand Down
Loading
Loading