Skip to content

Commit

Permalink
Make IPV6_V6ONLY configurable in Bun.serve
Browse files Browse the repository at this point in the history
  • Loading branch information
heimskr committed Jan 24, 2025
1 parent 0f85f55 commit 60a2a4d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 34 deletions.
8 changes: 7 additions & 1 deletion packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3734,14 +3734,20 @@ declare module "bun" {
port?: string | number;

/**
* If the `SO_REUSEPORT` flag should be set.
* Whether the `SO_REUSEPORT` flag should be set.
*
* This allows multiple processes to bind to the same port, which is useful for load balancing.
*
* @default false
*/
reusePort?: boolean;

/**
* Whether the `IPV6_V6ONLY` flag should be set.
* @default false
*/
ipv6Only?: boolean;

/**
* What hostname should the server listen on?
*
Expand Down
36 changes: 7 additions & 29 deletions packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,31 +863,13 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
) {

if (bsd_set_reuse(listenFd, options) != 0) {
if (errno == ENOTSUP) {
errno = 0;
} else {
return LIBUS_SOCKET_ERROR;
}
return LIBUS_SOCKET_ERROR;
}

#if defined(SO_REUSEADDR)
#ifndef _WIN32

// Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
// allow binding to addresses that are in use by sockets in TIME_WAIT, it
// effectively allows 'stealing' a port which is in use by another application.
// See libuv issue #1360.


int optval3 = 1;
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &optval3, sizeof(optval3));
#endif
#endif

#ifdef IPV6_V6ONLY
if (listenAddr->ai_family == AF_INET6) {
int disabled = (options & LIBUS_SOCKET_IPV6_ONLY) != 0;
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, &disabled, sizeof(disabled));
int enabled = (options & LIBUS_SOCKET_IPV6_ONLY) != 0;
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, &enabled, sizeof(enabled));
}
#endif

Expand Down Expand Up @@ -1148,18 +1130,14 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port, int op
}

if (bsd_set_reuse(listenFd, options) != 0) {
if (errno == ENOTSUP) {
errno = 0;
} else {
freeaddrinfo(result);
return LIBUS_SOCKET_ERROR;
}
freeaddrinfo(result);
return LIBUS_SOCKET_ERROR;
}

#ifdef IPV6_V6ONLY
if (listenAddr->ai_family == AF_INET6) {
int disabled = (options & LIBUS_SOCKET_IPV6_ONLY) != 0;
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, &disabled, sizeof(disabled));
int enabled = (options & LIBUS_SOCKET_IPV6_ONLY) != 0;
setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, &enabled, sizeof(enabled));
}
#endif

Expand Down
21 changes: 17 additions & 4 deletions src/bun.js/api/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ pub const ServerConfig = struct {
reuse_port: bool = false,
id: []const u8 = "",
allow_hot: bool = true,
ipv6_only: bool = false,

static_routes: std.ArrayList(StaticRouteEntry) = std.ArrayList(StaticRouteEntry).init(bun.default_allocator),

Expand Down Expand Up @@ -449,6 +450,15 @@ pub const ServerConfig = struct {
return arraylist.items;
}

pub fn getUsocketsOptions(this: *const ServerConfig) i32 {
// Unlike Node.js, we set exclusive port in case reuse port is not set
var out: i32 = if (this.reuse_port) uws.LIBUS_LISTEN_REUSE_PORT else uws.LIBUS_LISTEN_EXCLUSIVE_PORT;
if (this.ipv6_only) {
out |= uws.LIBUS_SOCKET_IPV6_ONLY;
}
return out;
}

pub const SSLConfig = struct {
requires_custom_request_ctx: bool = false,
server_name: [*c]const u8 = null,
Expand Down Expand Up @@ -1279,6 +1289,11 @@ pub const ServerConfig = struct {
}
if (global.hasException()) return error.JSError;

if (try arg.get(global, "ipv6Only")) |dev| {
args.ipv6_only = dev.coerce(bool, global);
}
if (global.hasException()) return error.JSError;

if (try arg.get(global, "inspector")) |inspector| {
args.inspector = inspector.coerce(bool, global);

Expand Down Expand Up @@ -7554,8 +7569,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp
app.listenWithConfig(*ThisServer, this, onListen, .{
.port = tcp.port,
.host = host,
// IPV6_ONLY is the default for bun, different from node it also set exclusive port in case reuse port is not set
.options = (if (this.config.reuse_port) uws.LIBUS_LISTEN_REUSE_PORT else uws.LIBUS_LISTEN_EXCLUSIVE_PORT) | uws.LIBUS_SOCKET_IPV6_ONLY,
.options = this.config.getUsocketsOptions(),
});
},

Expand All @@ -7565,8 +7579,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp
this,
onListen,
unix,
// IPV6_ONLY is the default for bun, different from node it also set exclusive port in case reuse port is not set
(if (this.config.reuse_port) uws.LIBUS_LISTEN_REUSE_PORT else uws.LIBUS_LISTEN_EXCLUSIVE_PORT) | uws.LIBUS_SOCKET_IPV6_ONLY,
this.config.getUsocketsOptions(),
);
},
}
Expand Down

0 comments on commit 60a2a4d

Please sign in to comment.