From c3bfff58d923285f851382b133746db687af0f7b Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Tue, 14 Oct 2025 18:46:47 -0800 Subject: [PATCH] Revert "Add support for localAddress and localPort in TCP connections" (#23675) --- packages/bun-usockets/src/bsd.c | 29 +-- packages/bun-usockets/src/context.c | 40 +--- packages/bun-usockets/src/crypto/openssl.c | 4 +- packages/bun-usockets/src/internal/internal.h | 5 +- .../src/internal/networking/bsd.h | 2 +- packages/bun-usockets/src/libusockets.h | 2 +- packages/bun-usockets/src/socket.c | 6 - src/bun.js/api/bun/socket.zig | 2 - src/bun.js/api/bun/socket/Handlers.zig | 24 --- src/bun.js/api/bun/socket/Listener.zig | 14 +- src/deps/uws/SocketContext.zig | 6 +- src/deps/uws/socket.zig | 23 +- src/http/HTTPContext.zig | 2 - src/js/node/net.ts | 24 ++- src/sql/mysql/js/JSMySQLConnection.zig | 2 +- src/sql/postgres/PostgresSQLConnection.zig | 2 +- src/valkey/valkey.zig | 2 - .../issue/06888-localaddress.test.ts | 200 ------------------ 18 files changed, 43 insertions(+), 346 deletions(-) delete mode 100644 test/regression/issue/06888-localaddress.test.ts diff --git a/packages/bun-usockets/src/bsd.c b/packages/bun-usockets/src/bsd.c index 58f4aa1c96..732d79559a 100644 --- a/packages/bun-usockets/src/bsd.c +++ b/packages/bun-usockets/src/bsd.c @@ -1467,39 +1467,12 @@ static int is_loopback(struct sockaddr_storage *sockaddr) { } #endif -LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, int options, struct sockaddr_storage *local_addr) { +LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *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 local address if specified - if (local_addr != NULL) { - socklen_t addr_len; - if (local_addr->ss_family == AF_INET) { - addr_len = sizeof(struct sockaddr_in); - } else if (local_addr->ss_family == AF_INET6) { - addr_len = sizeof(struct sockaddr_in6); - } else { - bsd_close_socket(fd); -#ifdef _WIN32 - WSASetLastError(WSAEAFNOSUPPORT); -#endif - errno = EAFNOSUPPORT; - return LIBUS_SOCKET_ERROR; - } - - int bind_result; - do { - bind_result = bind(fd, (struct sockaddr *)local_addr, addr_len); - } while (IS_EINTR(bind_result)); - - if (bind_result != 0) { - bsd_close_socket(fd); - return LIBUS_SOCKET_ERROR; - } - } - #ifdef _WIN32 win32_set_nonblocking(fd); diff --git a/packages/bun-usockets/src/context.c b/packages/bun-usockets/src/context.c index b7c88f4d70..6e2c3f3e18 100644 --- a/packages/bun-usockets/src/context.c +++ b/packages/bun-usockets/src/context.c @@ -430,8 +430,8 @@ struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, struct us_sock return ls; } -struct us_socket_t* us_socket_context_connect_resolved_dns(struct us_socket_context_t *context, struct sockaddr_storage* addr, int options, int socket_ext_size, struct sockaddr_storage* local_addr) { - LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, options, local_addr); +struct us_socket_t* us_socket_context_connect_resolved_dns(struct us_socket_context_t *context, struct sockaddr_storage* addr, int options, int socket_ext_size) { + LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, options); if (connect_socket_fd == LIBUS_SOCKET_ERROR) { return NULL; } @@ -501,39 +501,20 @@ static bool try_parse_ip(const char *ip_str, int port, struct sockaddr_storage * return 0; } -/* Helper function to parse local address for binding */ -static struct sockaddr_storage *parse_local_address(const char *local_host, unsigned short local_port, struct sockaddr_storage *storage) { - if (local_host == NULL) { - return NULL; - } - if (try_parse_ip(local_host, local_port, storage)) { - return storage; - } - errno = EINVAL; - return NULL; -} - -void *us_socket_context_connect(int ssl, struct us_socket_context_t *context, const char *host, int port, const char *local_host, unsigned short local_port, int options, int socket_ext_size, int* has_dns_resolved) { +void *us_socket_context_connect(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size, int* has_dns_resolved) { #ifndef LIBUS_NO_SSL if (ssl == 1) { - return us_internal_ssl_socket_context_connect((struct us_internal_ssl_socket_context_t *) context, host, port, local_host, local_port, options, socket_ext_size, has_dns_resolved); + return us_internal_ssl_socket_context_connect((struct us_internal_ssl_socket_context_t *) context, host, port, options, socket_ext_size, has_dns_resolved); } #endif struct us_loop_t* loop = us_socket_context_loop(ssl, context); - // Parse local address if provided - struct sockaddr_storage local_addr_storage; - struct sockaddr_storage *local_addr = parse_local_address(local_host, local_port, &local_addr_storage); - if (local_host != NULL && local_addr == NULL) { - return NULL; - } - // fast path for IP addresses in text form struct sockaddr_storage addr; if (try_parse_ip(host, port, &addr)) { *has_dns_resolved = 1; - return us_socket_context_connect_resolved_dns(context, &addr, options, socket_ext_size, local_addr); + return us_socket_context_connect_resolved_dns(context, &addr, options, socket_ext_size); } struct addrinfo_request* ai_req; @@ -553,7 +534,7 @@ void *us_socket_context_connect(int ssl, struct us_socket_context_t *context, co struct sockaddr_storage addr; init_addr_with_port(&entries->info, port, &addr); *has_dns_resolved = 1; - struct us_socket_t *s = us_socket_context_connect_resolved_dns(context, &addr, options, socket_ext_size, local_addr); + struct us_socket_t *s = us_socket_context_connect_resolved_dns(context, &addr, options, socket_ext_size); Bun__addrinfo_freeRequest(ai_req, s == NULL); return s; } @@ -567,9 +548,6 @@ void *us_socket_context_connect(int ssl, struct us_socket_context_t *context, co c->long_timeout = 255; c->pending_resolve_callback = 1; c->port = port; - // Duplicate local_host string so it persists after Zig frees its buffer - c->local_host = local_host ? strdup(local_host) : NULL; - c->local_port = local_port; us_internal_socket_context_link_connecting_socket(ssl, context, c); #ifdef _WIN32 @@ -584,15 +562,11 @@ void *us_socket_context_connect(int ssl, struct us_socket_context_t *context, co } int start_connections(struct us_connecting_socket_t *c, int count) { - // Parse local address if provided - struct sockaddr_storage local_addr_storage; - struct sockaddr_storage *local_addr = parse_local_address(c->local_host, c->local_port, &local_addr_storage); - int opened = 0; 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, local_addr); + LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(&addr, c->options); if (connect_socket_fd == LIBUS_SOCKET_ERROR) { continue; } diff --git a/packages/bun-usockets/src/crypto/openssl.c b/packages/bun-usockets/src/crypto/openssl.c index d0cd6e8c05..60e1900da5 100644 --- a/packages/bun-usockets/src/crypto/openssl.c +++ b/packages/bun-usockets/src/crypto/openssl.c @@ -1608,9 +1608,9 @@ static void us_internal_zero_ssl_data_for_connected_socket_before_onopen(struct // TODO does this need more changes? struct us_socket_t *us_internal_ssl_socket_context_connect( struct us_internal_ssl_socket_context_t *context, const char *host, - int port, const char *local_host, unsigned short local_port, int options, int socket_ext_size, int* is_connecting) { + int port, int options, int socket_ext_size, int* is_connecting) { struct us_internal_ssl_socket_t *s = (struct us_internal_ssl_socket_t *)us_socket_context_connect( - 2, &context->sc, host, port, local_host, local_port, options, + 2, &context->sc, host, port, options, sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) + socket_ext_size, is_connecting); if (*is_connecting && s) { diff --git a/packages/bun-usockets/src/internal/internal.h b/packages/bun-usockets/src/internal/internal.h index dff2ca30f0..7ee718e723 100644 --- a/packages/bun-usockets/src/internal/internal.h +++ b/packages/bun-usockets/src/internal/internal.h @@ -202,9 +202,6 @@ struct us_connecting_socket_t { // this is used to track pending connecting sockets in the context struct us_connecting_socket_t* next_pending; struct us_connecting_socket_t* prev_pending; - // local address binding - const char *local_host; - unsigned short local_port; }; struct us_wrapped_socket_context_t { @@ -413,7 +410,7 @@ struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix( struct us_socket_t *us_internal_ssl_socket_context_connect( us_internal_ssl_socket_context_r context, const char *host, - int port, const char *local_host, unsigned short local_port, int options, int socket_ext_size, int* is_resolved); + int port, int options, int socket_ext_size, int* is_resolved); struct us_socket_t *us_internal_ssl_socket_context_connect_unix( us_internal_ssl_socket_context_r context, const char *server_path, diff --git a/packages/bun-usockets/src/internal/networking/bsd.h b/packages/bun-usockets/src/internal/networking/bsd.h index 32b2c67a9a..699aeffa92 100644 --- a/packages/bun-usockets/src/internal/networking/bsd.h +++ b/packages/bun-usockets/src/internal/networking/bsd.h @@ -228,7 +228,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port, int op int bsd_connect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd, const char *host, int port); int bsd_disconnect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd); -LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, int options, struct sockaddr_storage *local_addr); +LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, int options); LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket_unix(const char *server_path, size_t pathlen, int options); diff --git a/packages/bun-usockets/src/libusockets.h b/packages/bun-usockets/src/libusockets.h index d185d81831..0e746a0388 100644 --- a/packages/bun-usockets/src/libusockets.h +++ b/packages/bun-usockets/src/libusockets.h @@ -328,7 +328,7 @@ void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) nonnull_fn_d per the happy eyeballs algorithm */ void *us_socket_context_connect(int ssl, struct us_socket_context_t * nonnull_arg context, - const char *host, int port, const char *local_host, unsigned short local_port, int options, int socket_ext_size, int *is_connecting) __attribute__((nonnull(2))); + const char *host, int port, int options, int socket_ext_size, int *is_connecting) __attribute__((nonnull(2))); struct us_socket_t *us_socket_context_connect_unix(int ssl, us_socket_context_r context, const char *server_path, size_t pathlen, int options, int socket_ext_size) __attribute__((nonnull(2))); diff --git a/packages/bun-usockets/src/socket.c b/packages/bun-usockets/src/socket.c index e3a5f1c64e..a4b02a7f42 100644 --- a/packages/bun-usockets/src/socket.c +++ b/packages/bun-usockets/src/socket.c @@ -142,12 +142,6 @@ void us_connecting_socket_free(int ssl, struct us_connecting_socket_t *c) { // instead, we move it to a close list and free it after the iteration us_internal_socket_context_unlink_connecting_socket(ssl, c->context, c); - // Free duplicated local_host string if present - if (c->local_host) { - free((void*)c->local_host); - c->local_host = NULL; - } - c->next = c->context->loop->data.closed_connecting_head; c->context->loop->data.closed_connecting_head = c; } diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index d10ec27927..3da90d798b 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -121,8 +121,6 @@ pub fn NewSocket(comptime ssl: bool) type { this.socket_context.?, this, this.flags.allow_half_open, - c.local_host, - @as(i32, @intCast(c.local_port)), ); }, .unix => |u| { diff --git a/src/bun.js/api/bun/socket/Handlers.zig b/src/bun.js/api/bun/socket/Handlers.zig index 0385e0e144..b874d9f4f2 100644 --- a/src/bun.js/api/bun/socket/Handlers.zig +++ b/src/bun.js/api/bun/socket/Handlers.zig @@ -217,8 +217,6 @@ pub const SocketConfig = struct { allowHalfOpen: bool = false, reusePort: bool = false, ipv6Only: bool = false, - localAddress: ?jsc.ZigString.Slice = null, - localPort: ?u16 = null, pub fn socketFlags(this: *const SocketConfig) i32 { var flags: i32 = if (this.exclusive) @@ -251,11 +249,6 @@ pub const SocketConfig = struct { var ssl: ?SSLConfig = null; var default_data = JSValue.zero; - // Parse localAddress and localPort for bind address - var localAddress: ?jsc.ZigString.Slice = null; - errdefer if (localAddress) |la| la.deinit(); - var localPort: ?u16 = null; - if (try opts.getTruthy(globalObject, "tls")) |tls| { if (!tls.isBoolean()) { ssl = try SSLConfig.fromJS(vm, globalObject, tls); @@ -308,21 +301,6 @@ pub const SocketConfig = struct { ipv6Only = ipv6_only; } - if (try opts.getStringish(globalObject, "localAddress")) |local_addr| { - defer local_addr.deref(); - localAddress = try local_addr.toUTF8WithoutRef(bun.default_allocator).cloneIfNeeded(bun.default_allocator); - } - - if (try opts.get(globalObject, "localPort")) |local_port_value| { - if (!local_port_value.isEmptyOrUndefinedOrNull()) { - const local_port_i32 = try local_port_value.coerceToInt32(globalObject); - if (local_port_i32 < 0 or local_port_i32 > 65535) { - return globalObject.throwInvalidArguments("Expected \"localPort\" to be a number between 0 and 65535", .{}); - } - localPort = @intCast(local_port_i32); - } - } - if (try opts.getStringish(globalObject, "hostname") orelse try opts.getStringish(globalObject, "host")) |hostname| { defer hostname.deref(); @@ -388,8 +366,6 @@ pub const SocketConfig = struct { .allowHalfOpen = allowHalfOpen, .reusePort = reusePort, .ipv6Only = ipv6Only, - .localAddress = localAddress, - .localPort = localPort, }; } }; diff --git a/src/bun.js/api/bun/socket/Listener.zig b/src/bun.js/api/bun/socket/Listener.zig index 00c1200306..84afd1b5e8 100644 --- a/src/bun.js/api/bun/socket/Listener.zig +++ b/src/bun.js/api/bun/socket/Listener.zig @@ -40,8 +40,6 @@ pub const UnixOrHost = union(enum) { host: struct { host: []const u8, port: u16, - local_host: ?[]const u8 = null, - local_port: u16 = 0, }, fd: bun.FileDescriptor, @@ -57,8 +55,6 @@ pub const UnixOrHost = union(enum) { .host = .{ .host = bun.handleOom(bun.default_allocator.dupe(u8, h.host)), .port = this.host.port, - .local_host = if (h.local_host) |lh| bun.handleOom(bun.default_allocator.dupe(u8, lh)) else null, - .local_port = h.local_port, }, }; }, @@ -73,9 +69,6 @@ pub const UnixOrHost = union(enum) { }, .host => |h| { bun.default_allocator.free(h.host); - if (h.local_host) |lh| { - bun.default_allocator.free(lh); - } }, .fd => {}, // this is an integer } @@ -591,12 +584,7 @@ pub fn connectInner(globalObject: *jsc.JSGlobalObject, prev_maybe_tcp: ?*TCPSock } } if (port) |_| { - break :blk .{ .host = .{ - .host = bun.handleOom(hostname_or_unix.cloneIfNeeded(bun.default_allocator)).slice(), - .port = port.?, - .local_host = if (socket_config.localAddress) |la| bun.handleOom(la.cloneIfNeeded(bun.default_allocator)).slice() else null, - .local_port = socket_config.localPort orelse 0, - } }; + break :blk .{ .host = .{ .host = bun.handleOom(hostname_or_unix.cloneIfNeeded(bun.default_allocator)).slice(), .port = port.? } }; } break :blk .{ .unix = bun.handleOom(hostname_or_unix.cloneIfNeeded(bun.default_allocator)).slice() }; diff --git a/src/deps/uws/SocketContext.zig b/src/deps/uws/SocketContext.zig index d1b1d64277..2672402e7e 100644 --- a/src/deps/uws/SocketContext.zig +++ b/src/deps/uws/SocketContext.zig @@ -196,8 +196,8 @@ pub const SocketContext = opaque { return c.us_socket_context_adopt_socket(@intFromBool(ssl), this, s, ext_size); } - pub fn connect(this: *SocketContext, ssl: bool, host: [*:0]const u8, port: i32, local_host: ?[*:0]const u8, local_port: i32, options: i32, socket_ext_size: i32, has_dns_resolved: *i32) ?*anyopaque { - return c.us_socket_context_connect(@intFromBool(ssl), this, host, port, local_host, local_port, options, socket_ext_size, has_dns_resolved); + pub fn connect(this: *SocketContext, ssl: bool, host: [*:0]const u8, port: i32, options: i32, socket_ext_size: i32, has_dns_resolved: *i32) ?*anyopaque { + return c.us_socket_context_connect(@intFromBool(ssl), this, host, port, options, socket_ext_size, has_dns_resolved); } pub fn connectUnix(this: *SocketContext, ssl: bool, path: [:0]const u8, options: i32, socket_ext_size: i32) ?*us_socket_t { @@ -254,7 +254,7 @@ pub const c = struct { pub extern fn us_create_child_socket_context(ssl: i32, context: ?*SocketContext, context_ext_size: i32) ?*SocketContext; pub extern fn us_socket_context_adopt_socket(ssl: i32, context: *SocketContext, s: *us_socket_t, ext_size: i32) ?*us_socket_t; pub extern fn us_socket_context_close(ssl: i32, ctx: *anyopaque) void; - pub extern fn us_socket_context_connect(ssl: i32, context: *SocketContext, host: [*:0]const u8, port: i32, local_host: ?[*:0]const u8, local_port: i32, options: i32, socket_ext_size: i32, has_dns_resolved: *i32) ?*anyopaque; + pub extern fn us_socket_context_connect(ssl: i32, context: *SocketContext, host: [*:0]const u8, port: i32, options: i32, socket_ext_size: i32, has_dns_resolved: *i32) ?*anyopaque; pub extern fn us_socket_context_connect_unix(ssl: i32, context: *SocketContext, path: [*:0]const u8, pathlen: usize, options: i32, socket_ext_size: i32) ?*us_socket_t; pub extern fn us_socket_context_ext(ssl: i32, context: *SocketContext) ?*anyopaque; pub extern fn us_socket_context_free(ssl: i32, context: *SocketContext) void; diff --git a/src/deps/uws/socket.zig b/src/deps/uws/socket.zig index c686437819..d4f81b8f77 100644 --- a/src/deps/uws/socket.zig +++ b/src/deps/uws/socket.zig @@ -507,7 +507,7 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { comptime socket_field_name: []const u8, allowHalfOpen: bool, ) !*Context { - const this_socket = try connectAnon(host, port, socket_ctx, ctx, allowHalfOpen, null, 0); + const this_socket = try connectAnon(host, port, socket_ctx, ctx, allowHalfOpen); @field(ctx, socket_field_name) = this_socket; return ctx; } @@ -597,11 +597,9 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { socket_ctx: *SocketContext, ptr: *anyopaque, allowHalfOpen: bool, - local_host: ?[]const u8, - local_port: i32, ) !ThisSocket { debug("connect({s}, {d})", .{ raw_host, port }); - var stack_fallback = std.heap.stackFallback(2048, bun.default_allocator); + var stack_fallback = std.heap.stackFallback(1024, bun.default_allocator); var allocator = stack_fallback.get(); // remove brackets from IPv6 addresses, as getaddrinfo doesn't understand them @@ -613,28 +611,11 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type { const host = bun.handleOom(allocator.dupeZ(u8, clean_host)); defer allocator.free(host); - // Handle local_host parameter - also remove brackets from IPv6 addresses - var local_host_z: ?[*:0]const u8 = null; - var local_host_buf: ?[]u8 = null; - defer if (local_host_buf) |buf| allocator.free(buf); - - if (local_host) |lh| { - const clean_local_host = if (lh.len > 1 and lh[0] == '[' and lh[lh.len - 1] == ']') - lh[1 .. lh.len - 1] - else - lh; - const lh_z = bun.handleOom(allocator.dupeZ(u8, clean_local_host)); - local_host_buf = lh_z; - local_host_z = lh_z.ptr; - } - var did_dns_resolve: i32 = 0; const socket_ptr = socket_ctx.connect( is_ssl, host.ptr, port, - local_host_z, - local_port, if (allowHalfOpen) uws.LIBUS_SOCKET_ALLOW_HALF_OPEN else 0, @sizeOf(*anyopaque), &did_dns_resolve, diff --git a/src/http/HTTPContext.zig b/src/http/HTTPContext.zig index 82748021db..a34020012e 100644 --- a/src/http/HTTPContext.zig +++ b/src/http/HTTPContext.zig @@ -473,8 +473,6 @@ pub fn NewHTTPContext(comptime ssl: bool) type { this.us_socket_context, ActiveSocket.init(client).ptr(), false, - null, - 0, ); client.allow_retry = false; return socket; diff --git a/src/js/node/net.ts b/src/js/node/net.ts index 16cbf3afc2..16b65d6cee 100644 --- a/src/js/node/net.ts +++ b/src/js/node/net.ts @@ -653,8 +653,6 @@ function kConnectTcp(self, addressType, req, address, port) { ipv6Only: addressType === 6, allowHalfOpen: self.allowHalfOpen, tls: req.tls, - localAddress: req.localAddress, - localPort: req.localPort, data: { self, req }, socket: self[khandlers], }); @@ -1720,9 +1718,13 @@ function internalConnect(self, options, address, port, addressType, localAddress if (localAddress || localPort) { if (addressType === 4) { localAddress ||= "0.0.0.0"; + // TODO: + // err = self._handle.bind(localAddress, localPort); } else { // addressType === 6 localAddress ||= "::"; + // TODO: + // err = self._handle.bind6(localAddress, localPort, flags); } $debug( "connect: binding to localAddress: %s and localPort: %d (addressType: %d)", @@ -1730,6 +1732,13 @@ function internalConnect(self, options, address, port, addressType, localAddress localPort, addressType, ); + + err = checkBindError(err, localPort, self._handle); + if (err) { + const ex = new ExceptionWithHostPort(err, "bind", localAddress, localPort); + self.destroy(ex); + return; + } } //TLS @@ -1837,9 +1846,13 @@ function internalConnectMultiple(context, canceled?) { if (localPort) { if (addressType === 4) { localAddress = DEFAULT_IPV4_ADDR; + // TODO: + // err = self._handle.bind(localAddress, localPort); } else { // addressType === 6 localAddress = DEFAULT_IPV6_ADDR; + // TODO: + // err = self._handle.bind6(localAddress, localPort, flags); } $debug( @@ -1848,6 +1861,13 @@ function internalConnectMultiple(context, canceled?) { localPort, addressType, ); + + err = checkBindError(err, localPort, self._handle); + if (err) { + ArrayPrototypePush.$call(context.errors, new ExceptionWithHostPort(err, "bind", localAddress, localPort)); + internalConnectMultiple(context); + return; + } } if (self.blockList?.check(address, `ipv${addressType}`)) { diff --git a/src/sql/mysql/js/JSMySQLConnection.zig b/src/sql/mysql/js/JSMySQLConnection.zig index 4540514c61..92b31c1b5d 100644 --- a/src/sql/mysql/js/JSMySQLConnection.zig +++ b/src/sql/mysql/js/JSMySQLConnection.zig @@ -478,7 +478,7 @@ pub fn createInstance(globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFra }); } else { ptr.#connection.setSocket(.{ - .SocketTCP = uws.SocketTCP.connectAnon(hostname.slice(), port, ctx, ptr, false, null, 0) catch |err| { + .SocketTCP = uws.SocketTCP.connectAnon(hostname.slice(), port, ctx, ptr, false) catch |err| { ptr.deref(); return globalObject.throwError(err, "failed to connect to mysql"); }, diff --git a/src/sql/postgres/PostgresSQLConnection.zig b/src/sql/postgres/PostgresSQLConnection.zig index 712f9b0da3..e176281713 100644 --- a/src/sql/postgres/PostgresSQLConnection.zig +++ b/src/sql/postgres/PostgresSQLConnection.zig @@ -750,7 +750,7 @@ pub fn call(globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JS }; } else { ptr.socket = .{ - .SocketTCP = uws.SocketTCP.connectAnon(hostname.slice(), port, ctx, ptr, false, null, 0) catch |err| { + .SocketTCP = uws.SocketTCP.connectAnon(hostname.slice(), port, ctx, ptr, false) catch |err| { tls_config.deinit(); if (tls_ctx) |tls| { tls.deinit(true); diff --git a/src/valkey/valkey.zig b/src/valkey/valkey.zig index b553644142..dbce0e4699 100644 --- a/src/valkey/valkey.zig +++ b/src/valkey/valkey.zig @@ -158,8 +158,6 @@ pub const Address = union(enum) { ctx, client, false, - null, - 0, )); }, } diff --git a/test/regression/issue/06888-localaddress.test.ts b/test/regression/issue/06888-localaddress.test.ts deleted file mode 100644 index 6160ce2946..0000000000 --- a/test/regression/issue/06888-localaddress.test.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { expect, test } from "bun:test"; -import * as net from "net"; -import * as os from "os"; - -test("TCP socket can bind to localAddress - IPv4", async () => { - // Get a local IPv4 address - const interfaces = os.networkInterfaces(); - let localIPv4: string | undefined; - - for (const name of Object.keys(interfaces)) { - const iface = interfaces[name]; - if (!iface) continue; - - for (const addr of iface) { - if (addr.family === "IPv4" && !addr.internal) { - localIPv4 = addr.address; - break; - } - } - if (localIPv4) break; - } - - // Skip test if no non-loopback IPv4 address found - if (!localIPv4) { - console.log("No non-loopback IPv4 address found, skipping test"); - return; - } - - const server = net.createServer(socket => { - const remoteAddr = socket.remoteAddress; - socket.end(`Connected from ${remoteAddr}`); - }); - - await new Promise(resolve => { - server.listen(0, localIPv4, () => resolve()); - }); - - const serverPort = (server.address() as net.AddressInfo).port; - - const clientPromise = new Promise((resolve, reject) => { - const client = net.createConnection({ - host: localIPv4, - port: serverPort, - localAddress: localIPv4, - }); - - client.on("connect", () => { - expect(client.localAddress).toBe(localIPv4); - }); - - let data = ""; - client.on("data", chunk => { - data += chunk.toString(); - }); - - client.on("end", () => { - resolve(data); - }); - - client.on("error", err => { - reject(err); - }); - }); - - const response = await clientPromise; - expect(response).toContain("Connected from"); - - server.close(); -}); - -test("TCP socket can bind to localAddress and localPort - IPv4", async () => { - const server = net.createServer(socket => { - const remoteAddr = socket.remoteAddress; - const remotePort = socket.remotePort; - socket.end(`Connected from ${remoteAddr}:${remotePort}`); - }); - - await new Promise(resolve => { - server.listen(0, "127.0.0.1", () => resolve()); - }); - - const serverPort = (server.address() as net.AddressInfo).port; - - // Use a local port of 0 to let the system assign one - const clientPromise = new Promise<{ data: string; localPort: number }>((resolve, reject) => { - const client = net.createConnection({ - host: "127.0.0.1", - port: serverPort, - localAddress: "127.0.0.1", - localPort: 0, - }); - - let localPort: number; - client.on("connect", () => { - expect(client.localAddress).toBe("127.0.0.1"); - localPort = client.localPort!; - expect(localPort).toBeGreaterThan(0); - }); - - let data = ""; - client.on("data", chunk => { - data += chunk.toString(); - }); - - client.on("end", () => { - resolve({ data, localPort }); - }); - - client.on("error", err => { - reject(err); - }); - }); - - const { data, localPort } = await clientPromise; - expect(data).toContain("Connected from"); - expect(data).toContain(`:${localPort}`); - - server.close(); -}); - -test("TCP socket can bind to localAddress - IPv6 loopback", async () => { - const server = net.createServer(socket => { - const remoteAddr = socket.remoteAddress; - socket.end(`Connected from ${remoteAddr}`); - }); - - await new Promise(resolve => { - server.listen(0, "::1", () => resolve()); - }); - - const serverPort = (server.address() as net.AddressInfo).port; - - const clientPromise = new Promise((resolve, reject) => { - const client = net.createConnection({ - host: "::1", - port: serverPort, - localAddress: "::1", - }); - - client.on("connect", () => { - // IPv6 addresses might be normalized differently - expect(client.localAddress).toContain(":"); - }); - - let data = ""; - client.on("data", chunk => { - data += chunk.toString(); - }); - - client.on("end", () => { - resolve(data); - }); - - client.on("error", err => { - reject(err); - }); - }); - - const response = await clientPromise; - expect(response).toContain("Connected from"); - - server.close(); -}); - -test("TCP socket without localAddress works normally", async () => { - const server = net.createServer(socket => { - socket.end("Hello"); - }); - - await new Promise(resolve => { - server.listen(0, "127.0.0.1", () => resolve()); - }); - - const serverPort = (server.address() as net.AddressInfo).port; - - const clientPromise = new Promise((resolve, reject) => { - const client = net.createConnection({ - host: "127.0.0.1", - port: serverPort, - }); - - let data = ""; - client.on("data", chunk => { - data += chunk.toString(); - }); - - client.on("end", () => { - resolve(data); - }); - - client.on("error", err => { - reject(err); - }); - }); - - const response = await clientPromise; - expect(response).toBe("Hello"); - - server.close(); -});