From e020ecec1596192b6e6ffe8453094e37e95a85ef Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sat, 30 Sep 2023 22:59:42 -0700 Subject: Fix bug causing "Connection Refused" errors (#6206) * Loop through the return values of getaddrinfo * Remove incorrect assertion * Remove extra check * Remove extra check * Update bsd.c * More consistent --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> --- packages/bun-usockets/src/bsd.c | 51 +++++++++++++++++++++++++++++++++-------- src/http_client_async.zig | 14 ++++------- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/packages/bun-usockets/src/bsd.c b/packages/bun-usockets/src/bsd.c index 7683acd7d..fc501e4d9 100644 --- a/packages/bun-usockets/src/bsd.c +++ b/packages/bun-usockets/src/bsd.c @@ -665,9 +665,39 @@ int bsd_udp_packet_buffer_ecn(void *msgvec, int index) { return 0; // no ecn defaults to 0 } -static int bsd_do_connect(struct addrinfo *result, int fd) +static int bsd_do_connect_raw(struct addrinfo *rp, int fd) { - return connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen); + do { + if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0 || errno == EINPROGRESS) { + return 0; + } + } while (errno == EINTR); + + return LIBUS_SOCKET_ERROR; +} + +static int bsd_do_connect(struct addrinfo *rp, int *fd) +{ + while (rp != NULL) { + if (bsd_do_connect_raw(rp, *fd) == 0) { + return 0; + } + + rp = rp->ai_next; + bsd_close_socket(*fd); + + if (rp == NULL) { + return LIBUS_SOCKET_ERROR; + } + + int resultFd = bsd_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (resultFd < 0) { + return LIBUS_SOCKET_ERROR; + } + *fd = resultFd; + } + + return LIBUS_SOCKET_ERROR; } LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) { @@ -700,18 +730,21 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, co return LIBUS_SOCKET_ERROR; } } - } - - do { - if (bsd_do_connect(result, fd) != 0 && errno != EINPROGRESS) { + + if (bsd_do_connect_raw(result, fd) != 0) { bsd_close_socket(fd); freeaddrinfo(result); return LIBUS_SOCKET_ERROR; } - } while (errno == EINTR); - + } else { + if (bsd_do_connect(result, &fd) != 0) { + freeaddrinfo(result); + return LIBUS_SOCKET_ERROR; + } + } + + freeaddrinfo(result); - return fd; } diff --git a/src/http_client_async.zig b/src/http_client_async.zig index 1e0ba7cc0..6c731acd5 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -1343,7 +1343,7 @@ pub const InternalState = struct { return this.transfer_encoding == Encoding.chunked; } - pub fn reset(this: *InternalState, buffering: bool, allocator: std.mem.Allocator) void { + pub fn reset(this: *InternalState, allocator: std.mem.Allocator) void { this.compressed_body.deinit(); this.response_message_buffer.deinit(); @@ -1354,12 +1354,6 @@ pub const InternalState = struct { reader.deinit(); } - if (!buffering) { - // if we are holding a cloned_metadata we need to deinit it - // this should never happen because we should always return the metadata to the user - std.debug.assert(this.cloned_metadata == null); - } - // just in case we check and free to avoid leaks if (this.cloned_metadata != null) { this.cloned_metadata.?.deinit(allocator); @@ -2186,7 +2180,7 @@ pub fn doRedirect(this: *HTTPClient) void { this.fail(error.TooManyRedirects); return; } - this.state.reset(this.signals.isEmpty(), this.allocator); + this.state.reset(this.allocator); // also reset proxy to redirect this.proxy_tunneling = false; if (this.proxy_tunnel != null) { @@ -2907,7 +2901,7 @@ fn fail(this: *HTTPClient, err: anyerror) void { _ = socket_async_http_abort_tracker.swapRemove(this.async_http_id); } - this.state.reset(this.signals.isEmpty(), this.allocator); + this.state.reset(this.allocator); this.proxy_tunneling = false; this.state.request_stage = .fail; @@ -2993,7 +2987,7 @@ pub fn progressUpdate(this: *HTTPClient, comptime is_ssl: bool, ctx: *NewHTTPCon socket.close(0, null); } - this.state.reset(this.signals.isEmpty(), this.allocator); + this.state.reset(this.allocator); this.state.response_stage = .done; this.state.request_stage = .done; this.state.stage = .done; -- cgit v1.2.3