Compare commits

...

1 Commits

Author SHA1 Message Date
Meghan Denny
0423444f0e node:net: hookup the backlog parameter 2025-11-25 17:14:26 -08:00
13 changed files with 70 additions and 47 deletions

View File

@@ -5104,6 +5104,14 @@ declare module "bun" {
* @default false
*/
allowHalfOpen?: boolean;
/**
* Specifies the maximum length of the queue of pending connections. The actual length
* will be determined by the OS through sysctl settings such as `tcp_max_syn_backlog`
* and `somaxconn` on Linux.
*
* @default 511
*/
backlog?: number;
}
interface TCPSocketListenOptions<Data = undefined> extends SocketOptions<Data> {

View File

@@ -956,6 +956,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
struct addrinfo *listenAddr,
int port,
int options,
int backlog,
int* error
) {
@@ -981,7 +982,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
}
#endif
if (us_internal_bind_and_listen(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen, 512, error)) {
if (us_internal_bind_and_listen(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen, backlog, error)) {
return LIBUS_SOCKET_ERROR;
}
@@ -990,7 +991,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
// return LIBUS_SOCKET_ERROR or the fd that represents listen socket
// listen both on ipv6 and ipv4
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error) {
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int backlog, int* error) {
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
@@ -1015,7 +1016,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int
}
listenAddr = a;
if (bsd_bind_listen_fd(listenFd, listenAddr, port, options, error) != LIBUS_SOCKET_ERROR) {
if (bsd_bind_listen_fd(listenFd, listenAddr, port, options, backlog, error) != LIBUS_SOCKET_ERROR) {
freeaddrinfo(result);
return listenFd;
}
@@ -1032,7 +1033,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int
}
listenAddr = a;
if (bsd_bind_listen_fd(listenFd, listenAddr, port, options, error) != LIBUS_SOCKET_ERROR) {
if (bsd_bind_listen_fd(listenFd, listenAddr, port, options, backlog, error) != LIBUS_SOCKET_ERROR) {
freeaddrinfo(result);
return listenFd;
}
@@ -1137,7 +1138,7 @@ static LIBUS_SOCKET_DESCRIPTOR bsd_create_unix_socket_address(const char *path,
return 0;
}
static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char* path, int options, struct sockaddr_un* server_address, size_t addrlen, int* error) {
static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char* path, int options, struct sockaddr_un* server_address, size_t addrlen, int backlog, int* error) {
LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0, NULL);
@@ -1152,7 +1153,7 @@ static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char
unlink(path);
#endif
if (us_internal_bind_and_listen(listenFd, (struct sockaddr *) server_address, (socklen_t) addrlen, 512, error)) {
if (us_internal_bind_and_listen(listenFd, (struct sockaddr *) server_address, (socklen_t) addrlen, backlog, error)) {
#if defined(_WIN32)
int shouldSimulateENOENT = WSAGetLastError() == WSAENETDOWN;
#endif
@@ -1168,7 +1169,7 @@ static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char
return listenFd;
}
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t len, int options, int* error) {
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t len, int options, int backlog, int* error) {
int dirfd_linux_workaround_for_unix_path_len = -1;
struct sockaddr_un server_address;
size_t addrlen = 0;
@@ -1176,7 +1177,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t l
return LIBUS_SOCKET_ERROR;
}
LIBUS_SOCKET_DESCRIPTOR listenFd = internal_bsd_create_listen_socket_unix(path, options, &server_address, addrlen, error);
LIBUS_SOCKET_DESCRIPTOR listenFd = internal_bsd_create_listen_socket_unix(path, options, &server_address, addrlen, backlog, error);
#if defined(__linux__)
if (dirfd_linux_workaround_for_unix_path_len != -1) {

View File

@@ -361,14 +361,14 @@ void us_socket_context_free(int ssl, struct us_socket_context_t *context) {
us_socket_context_unref(ssl, context);
}
struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size, int* error) {
struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size, int backlog, int* error) {
#ifndef LIBUS_NO_SSL
if (ssl) {
return us_internal_ssl_socket_context_listen((struct us_internal_ssl_socket_context_t *) context, host, port, options, socket_ext_size, error);
return us_internal_ssl_socket_context_listen((struct us_internal_ssl_socket_context_t *) context, host, port, options, socket_ext_size, backlog, error);
}
#endif
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options, error);
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options, backlog, error);
if (listen_socket_fd == LIBUS_SOCKET_ERROR) {
return 0;
@@ -395,14 +395,14 @@ struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_co
return ls;
}
struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, struct us_socket_context_t *context, const char *path, size_t pathlen, int options, int socket_ext_size, int* error) {
struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, struct us_socket_context_t *context, const char *path, size_t pathlen, int options, int socket_ext_size, int backlog, int* error) {
#ifndef LIBUS_NO_SSL
if (ssl) {
return us_internal_ssl_socket_context_listen_unix((struct us_internal_ssl_socket_context_t *) context, path, pathlen, options, socket_ext_size, error);
return us_internal_ssl_socket_context_listen_unix((struct us_internal_ssl_socket_context_t *) context, path, pathlen, options, socket_ext_size, backlog, error);
}
#endif
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket_unix(path, pathlen, options, error);
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket_unix(path, pathlen, options, backlog, error);
if (listen_socket_fd == LIBUS_SOCKET_ERROR) {
return 0;
@@ -961,4 +961,4 @@ void us_socket_context_on_handshake(int ssl, struct us_socket_context_t *context
return;
}
#endif
}
}

View File

@@ -857,7 +857,7 @@ create_ssl_context_from_options(struct us_socket_context_options_t options) {
if (options.ssl_ciphers) {
if (!SSL_CTX_set_cipher_list(ssl_context, options.ssl_ciphers)) {
unsigned long ssl_err = ERR_get_error();
unsigned long ssl_err = ERR_get_error();
if (!(strlen(options.ssl_ciphers) == 0 && ERR_GET_REASON(ssl_err) == SSL_R_NO_CIPHER_MATCH)) {
// TLS1.2 ciphers were deliberately cleared, so don't consider
// SSL_R_NO_CIPHER_MATCH to be an error (this is how _set_cipher_suites()
@@ -1300,7 +1300,7 @@ SSL_CTX *create_ssl_context_from_bun_options(
if (options.ssl_ciphers) {
if (!SSL_CTX_set_cipher_list(ssl_context, options.ssl_ciphers)) {
unsigned long ssl_err = ERR_get_error();
unsigned long ssl_err = ERR_get_error();
if (!(strlen(options.ssl_ciphers) == 0 && ERR_GET_REASON(ssl_err) == SSL_R_NO_CIPHER_MATCH)) {
char error_msg[256];
ERR_error_string_n(ERR_peek_last_error(), error_msg, sizeof(error_msg));
@@ -1308,7 +1308,7 @@ SSL_CTX *create_ssl_context_from_bun_options(
// SSL_R_NO_CIPHER_MATCH to be an error (this is how _set_cipher_suites()
// works). If the user actually sets a value (like "no-such-cipher"), then
// that's actually an error.
*err = CREATE_BUN_SOCKET_ERROR_INVALID_CIPHERS;
*err = CREATE_BUN_SOCKET_ERROR_INVALID_CIPHERS;
free_ssl_context(ssl_context);
return NULL;
}
@@ -1579,21 +1579,27 @@ void us_internal_ssl_socket_context_free(
}
struct us_listen_socket_t *us_internal_ssl_socket_context_listen(
struct us_internal_ssl_socket_context_t *context, const char *host,
int port, int options, int socket_ext_size, int* error) {
return us_socket_context_listen(0, &context->sc, host, port, options,
sizeof(struct us_internal_ssl_socket_t) -
sizeof(struct us_socket_t) +
socket_ext_size, error);
struct us_internal_ssl_socket_context_t *context,
const char *host,
int port,
int options,
int socket_ext_size,
int backlog,
int* error
) {
return us_socket_context_listen(0, &context->sc, host, port, options, sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) + socket_ext_size, backlog, error);
}
struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix(
struct us_internal_ssl_socket_context_t *context, const char *path,
size_t pathlen, int options, int socket_ext_size, int* error) {
return us_socket_context_listen_unix(0, &context->sc, path, pathlen, options,
sizeof(struct us_internal_ssl_socket_t) -
sizeof(struct us_socket_t) +
socket_ext_size, error);
struct us_internal_ssl_socket_context_t *context,
const char *path,
size_t pathlen,
int options,
int socket_ext_size,
int backlog,
int* error
) {
return us_socket_context_listen_unix(0, &context->sc, path, pathlen, options, sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) + socket_ext_size, backlog, error);
}
// https://github.com/oven-sh/bun/issues/16995

View File

@@ -402,11 +402,11 @@ void us_internal_ssl_socket_context_on_socket_connect_error(
struct us_listen_socket_t *us_internal_ssl_socket_context_listen(
us_internal_ssl_socket_context_r context, const char *host,
int port, int options, int socket_ext_size, int* error);
int port, int options, int socket_ext_size, int backlog, int* error);
struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix(
us_internal_ssl_socket_context_r context, const char *path,
size_t pathlen, int options, int socket_ext_size, int* error);
size_t pathlen, int options, int socket_ext_size, int backlog, int* error);
struct us_socket_t *us_internal_ssl_socket_context_connect(
us_internal_ssl_socket_context_r context, const char *host,

View File

@@ -219,9 +219,9 @@ int bsd_would_block();
// return LIBUS_SOCKET_ERROR or the fd that represents listen socket
// listen both on ipv6 and ipv4
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error);
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int backlog, int* error);
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t pathlen, int options, int* error);
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t pathlen, int options, int backlog, int* error);
/* Creates an UDP socket bound to the hostname and port */
LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port, int options, int *err);

View File

@@ -310,10 +310,10 @@ void us_socket_context_close(int ssl, us_socket_context_r context);
/* Listen for connections. Acts as the main driving cog in a server. Will call set async callbacks. */
struct us_listen_socket_t *us_socket_context_listen(int ssl, us_socket_context_r context,
const char *host, int port, int options, int socket_ext_size, int* error);
const char *host, int port, int options, int socket_ext_size, int backlog, int* error);
struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, us_socket_context_r context,
const char *path, size_t pathlen, int options, int socket_ext_size, int* error);
const char *path, size_t pathlen, int options, int socket_ext_size, int backlog, int* error);
/* listen_socket.c/.h */
void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) nonnull_fn_decl;

View File

@@ -650,7 +650,7 @@ public:
/* Listen to port using this HttpContext */
us_listen_socket_t *listen(const char *host, int port, int options) {
int error = 0;
auto socket = us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>), &error);
auto socket = us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData<SSL>), 511, &error);
// we dont depend on libuv ref for keeping it alive
if (socket) {
us_socket_unref(&socket->s);
@@ -661,7 +661,7 @@ public:
/* Listen to unix domain socket using this HttpContext */
us_listen_socket_t *listen_unix(const char *path, size_t pathlen, int options) {
int error = 0;
auto* socket = us_socket_context_listen_unix(SSL, getSocketContext(), path, pathlen, options, sizeof(HttpResponseData<SSL>), &error);
auto* socket = us_socket_context_listen_unix(SSL, getSocketContext(), path, pathlen, options, sizeof(HttpResponseData<SSL>), 511, &error);
// we dont depend on libuv ref for keeping it alive
if (socket) {
us_socket_unref(&socket->s);

View File

@@ -238,6 +238,7 @@ pub const SocketConfig = struct {
allowHalfOpen: bool = false,
reusePort: bool = false,
ipv6Only: bool = false,
backlog: i32 = 511,
/// Deinitializes everything and `unprotect`s `handlers`.
pub fn deinit(this: *SocketConfig) void {

View File

@@ -155,7 +155,7 @@ pub fn listen(globalObject: *jsc.JSGlobalObject, opts: JSValue) bun.JSError!JSVa
.namedPipe = WindowsNamedPipeListeningContext.listen(
globalObject,
pipe_name,
511,
socket_config.backlog,
ssl,
this,
) catch return globalObject.throwInvalidArguments(
@@ -249,7 +249,7 @@ pub fn listen(globalObject: *jsc.JSGlobalObject, opts: JSValue) bun.JSError!JSVa
const host = bun.handleOom(bun.default_allocator.dupeZ(u8, c.host));
defer bun.default_allocator.free(host);
const socket = socket_context.listen(ssl_enabled, host.ptr, c.port, socket_flags, 8, &errno);
const socket = socket_context.listen(ssl_enabled, host.ptr, c.port, socket_flags, 8, socket_config.backlog, &errno);
// should return the assigned port
if (socket) |s| {
connection.host.port = @as(u16, @intCast(s.getLocalPort(ssl_enabled)));
@@ -259,7 +259,7 @@ pub fn listen(globalObject: *jsc.JSGlobalObject, opts: JSValue) bun.JSError!JSVa
.unix => |u| {
const host = bun.handleOom(bun.default_allocator.dupeZ(u8, u));
defer bun.default_allocator.free(host);
break :brk socket_context.listenUnix(ssl_enabled, host, host.len, socket_flags, 8, &errno);
break :brk socket_context.listenUnix(ssl_enabled, host, host.len, socket_flags, 8, socket_config.backlog, &errno);
},
.fd => |fd| {
const err: bun.jsc.SystemError = .{

View File

@@ -79,5 +79,6 @@ export const SocketConfig = b.dictionary(
internalName: "unix_", // `unix` is a predefined C macro...
},
fd: b.i32.optional,
backlog: b.i32.nullable,
},
);

View File

@@ -208,12 +208,12 @@ pub const SocketContext = opaque {
c.us_socket_context_free(@intFromBool(ssl), this);
}
pub fn listen(this: *SocketContext, ssl: bool, host: ?[*:0]const u8, port: i32, options: i32, socket_ext_size: i32, err: *c_int) ?*ListenSocket {
return c.us_socket_context_listen(@intFromBool(ssl), this, host, port, options, socket_ext_size, err);
pub fn listen(this: *SocketContext, ssl: bool, host: ?[*:0]const u8, port: i32, options: i32, socket_ext_size: i32, backlog: i32, err: *c_int) ?*ListenSocket {
return c.us_socket_context_listen(@intFromBool(ssl), this, host, port, options, socket_ext_size, backlog, err);
}
pub fn listenUnix(this: *SocketContext, ssl: bool, path: [*:0]const u8, pathlen: usize, options: i32, socket_ext_size: i32, err: *c_int) ?*ListenSocket {
return c.us_socket_context_listen_unix(@intFromBool(ssl), this, path, pathlen, options, socket_ext_size, err);
pub fn listenUnix(this: *SocketContext, ssl: bool, path: [*:0]const u8, pathlen: usize, options: i32, socket_ext_size: i32, backlog: i32, err: *c_int) ?*ListenSocket {
return c.us_socket_context_listen_unix(@intFromBool(ssl), this, path, pathlen, options, socket_ext_size, backlog, err);
}
pub fn loop(this: *SocketContext, ssl: bool) ?*Loop {
@@ -259,8 +259,8 @@ pub const c = struct {
pub extern fn us_socket_context_ext(ssl: i32, context: *SocketContext) ?*anyopaque;
pub extern fn us_socket_context_free(ssl: i32, context: *SocketContext) void;
pub extern fn us_socket_context_get_native_handle(ssl: i32, context: *SocketContext) ?*anyopaque;
pub extern fn us_socket_context_listen(ssl: i32, context: *SocketContext, host: ?[*:0]const u8, port: i32, options: i32, socket_ext_size: i32, err: *c_int) ?*ListenSocket;
pub extern fn us_socket_context_listen_unix(ssl: i32, context: *SocketContext, path: [*:0]const u8, pathlen: usize, options: i32, socket_ext_size: i32, err: *c_int) ?*ListenSocket;
pub extern fn us_socket_context_listen(ssl: i32, context: *SocketContext, host: ?[*:0]const u8, port: i32, options: i32, socket_ext_size: i32, backlog: i32, err: *c_int) ?*ListenSocket;
pub extern fn us_socket_context_listen_unix(ssl: i32, context: *SocketContext, path: [*:0]const u8, pathlen: usize, options: i32, socket_ext_size: i32, backlog: i32, err: *c_int) ?*ListenSocket;
pub extern fn us_socket_context_loop(ssl: i32, context: *SocketContext) ?*Loop;
pub extern fn us_socket_context_on_close(ssl: i32, context: *SocketContext, on_close: ?*const fn (*us_socket_t, i32, ?*anyopaque) callconv(.c) ?*us_socket_t) void;
pub extern fn us_socket_context_on_connect_error(ssl: i32, context: *SocketContext, on_connect_error: ?*const fn (*uws.ConnectingSocket, i32) callconv(.c) ?*uws.ConnectingSocket) void;

View File

@@ -2351,6 +2351,7 @@ Server.prototype[kRealListen] = function (
contexts,
_onListen,
fd,
backlog,
) {
if (path) {
this._handle = Bun.listen({
@@ -2362,6 +2363,7 @@ Server.prototype[kRealListen] = function (
exclusive: exclusive || this[bunSocketServerOptions]?.exclusive || false,
socket: ServerHandlers,
data: this,
backlog,
});
} else if (fd != null) {
this._handle = Bun.listen({
@@ -2374,6 +2376,7 @@ Server.prototype[kRealListen] = function (
exclusive: exclusive || this[bunSocketServerOptions]?.exclusive || false,
socket: ServerHandlers,
data: this,
backlog,
});
} else {
this._handle = Bun.listen({
@@ -2386,6 +2389,7 @@ Server.prototype[kRealListen] = function (
exclusive: exclusive || this[bunSocketServerOptions]?.exclusive || false,
socket: ServerHandlers,
data: this,
backlog,
});
}
@@ -2494,6 +2498,7 @@ function listenInCluster(
contexts,
onListen,
fd,
backlog,
);
return;
}
@@ -2524,6 +2529,7 @@ function listenInCluster(
contexts,
onListen,
fd,
backlog,
);
});
}