Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

happy eyeballs #11206

Merged
merged 16 commits into from
May 21, 2024
7 changes: 3 additions & 4 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1003,22 +1003,21 @@ declare module "bun" {
*
* **Experimental API**
*
* Prefetch a hostname and port.
* Prefetch a hostname.
*
* This will be used by fetch() and Bun.connect() to avoid DNS lookups.
*
* @param hostname The hostname to prefetch
* @param port The port to prefetch
*
* @example
* ```js
* import { dns } from 'bun';
* dns.prefetch('example.com', 443);
* dns.prefetch('example.com');
* // ... something expensive
* await fetch('https://example.com');
* ```
*/
prefetch(hostname: string, port: number): void;
prefetch(hostname: string): void;

/**
* **Experimental API**
Expand Down
100 changes: 28 additions & 72 deletions packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,19 +888,20 @@ int bsd_disconnect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
// return 0; // no ecn defaults to 0
// }

static int bsd_do_connect_raw(struct addrinfo *rp, LIBUS_SOCKET_DESCRIPTOR fd)
static int bsd_do_connect_raw(struct sockaddr_storage *addr, LIBUS_SOCKET_DESCRIPTOR fd)
{
int namelen = addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
#ifdef _WIN32
do {
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0 || WSAGetLastError() == WSAEINPROGRESS) {
if (connect(fd, (struct sockaddr *)addr, namelen) == 0 || WSAGetLastError() == WSAEINPROGRESS) {
return 0;
}
} while (WSAGetLastError() == WSAEINTR);

return WSAGetLastError();
#else
do {
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0 || errno == EINPROGRESS) {
if (connect(fd, (struct sockaddr *)addr, namelen) == 0 || errno == EINPROGRESS) {
return 0;
}
} while (errno == EINTR);
Expand All @@ -909,86 +910,43 @@ static int bsd_do_connect_raw(struct addrinfo *rp, LIBUS_SOCKET_DESCRIPTOR fd)
#endif
}

static int bsd_do_connect(struct addrinfo *rp, LIBUS_SOCKET_DESCRIPTOR *fd)
{
int lastErr = 0;
while (rp != NULL) {
lastErr = bsd_do_connect_raw(rp, *fd);
if (lastErr == 0) {
return 0;
}

rp = rp->ai_next;
bsd_close_socket(*fd);

if (rp == NULL) {
if (lastErr != 0) {
errno = lastErr;
}
return LIBUS_SOCKET_ERROR;
}

LIBUS_SOCKET_DESCRIPTOR resultFd = bsd_create_socket(rp->ai_family, SOCK_STREAM, 0);
if (resultFd < 0) {
return LIBUS_SOCKET_ERROR;
}
*fd = resultFd;
}

if (lastErr != 0) {
errno = lastErr;
}

return LIBUS_SOCKET_ERROR;
}

#ifdef _WIN32

static int convert_null_addr(struct addrinfo *addrinfo, struct addrinfo* result, struct sockaddr_storage *inaddr) {
static int convert_null_addr(const struct sockaddr_storage *addr, struct sockaddr_storage* result) {
// 1. check that all addrinfo results are 0.0.0.0 or ::
if (addrinfo->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) addrinfo->ai_addr;
if (addr->sin_addr.s_addr == htonl(INADDR_ANY)) {
memcpy(inaddr, addr, sizeof(struct sockaddr_in));
((struct sockaddr_in *) inaddr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);

memcpy(result, addrinfo, sizeof(struct addrinfo));
result->ai_addr = (struct sockaddr *) inaddr;
result->ai_next = NULL;

if (addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
if (addr4->sin_addr.s_addr == htonl(INADDR_ANY)) {
memcpy(result, addr, sizeof(struct sockaddr_in));
((struct sockaddr_in *) result)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
return 1;
}
} else if (addrinfo->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) addrinfo->ai_addr;
if (memcmp(&addr->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0) {
memcpy(inaddr, addr, sizeof(struct sockaddr_in6));
memcpy(&((struct sockaddr_in6 *) inaddr)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));

memcpy(result, addrinfo, sizeof(struct addrinfo));
result->ai_addr = (struct sockaddr *) inaddr;
result->ai_next = NULL;

} else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
if (memcmp(&addr6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0) {
memcpy(result, addr, sizeof(struct sockaddr_in6));
memcpy(&((struct sockaddr_in6 *) result)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));
return 1;
}
}
return 0;
}

static int is_loopback(struct addrinfo *addrinfo) {
if (addrinfo->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) addrinfo->ai_addr;
static int is_loopback(struct sockaddr_storage *sockaddr) {
if (sockaddr->ss_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) sockaddr;
return addr->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
} else if (addrinfo->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) addrinfo->ai_addr;
} else if (sockaddr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) sockaddr;
return memcmp(&addr->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
} else {
return 0;
}
}
#endif

LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct addrinfo *addrinfo, int options) {
LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(addrinfo->ai_family, SOCK_STREAM, 0);
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);
if (fd == LIBUS_SOCKET_ERROR) {
return LIBUS_SOCKET_ERROR;
}
Expand All @@ -997,11 +955,9 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct addrinfo *addrinfo, int

// On windows we can't connect to the null address directly.
// To match POSIX behavior, we need to connect to localhost instead.
struct addrinfo alt_result;
struct sockaddr_storage storage;

if (convert_null_addr(addrinfo, &alt_result, &storage)) {
addrinfo = &alt_result;
struct sockaddr_storage converted;
if (convert_null_addr(addr, &converted)) {
addr = &converted;
}

// This sets the socket to fail quickly if no connection can be established to localhost,
Expand All @@ -1010,7 +966,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct addrinfo *addrinfo, int
// see https://github.com/libuv/libuv/blob/bf61390769068de603e6deec8e16623efcbe761a/src/win/tcp.c#L806
TCP_INITIAL_RTO_PARAMETERS retransmit_ioctl;
DWORD bytes;
if (is_loopback(addrinfo)) {
if (is_loopback(addr)) {
memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl));
retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS;
Expand All @@ -1027,10 +983,10 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct addrinfo *addrinfo, int

#endif

if (bsd_do_connect(addrinfo, &fd) != 0) {
if (bsd_do_connect_raw(addr, fd) != 0) {
bsd_close_socket(fd);
return LIBUS_SOCKET_ERROR;
}

return fd;
}

Expand Down
Loading
Loading