Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,66 @@ int bsd_socket_keepalive(LIBUS_SOCKET_DESCRIPTOR fd, int on, unsigned int delay)
#endif
}

/* IP type-of-service / traffic-class. The option level depends on the socket
* family (IP_TOS for IPv4, IPV6_TCLASS for IPv6), detected via getsockname.
* Returns 0 on success or a negative platform errno on failure (the negative
* convention matches what node:net's ErrnoException expects). */
static int bsd_socket_tos_level(LIBUS_SOCKET_DESCRIPTOR fd, int *level, int *option) {
struct sockaddr_storage storage;
socklen_t addrlen = sizeof(storage);
if (getsockname(fd, (struct sockaddr *) &storage, &addrlen)) {
#ifdef _WIN32
return -WSAGetLastError();
#else
return -errno;
#endif
}
if (storage.ss_family == AF_INET) {
*level = IPPROTO_IP;
*option = IP_TOS;
} else if (storage.ss_family == AF_INET6) {
*level = IPPROTO_IPV6;
*option = IPV6_TCLASS;
} else {
return -EINVAL;
}
return 0;
}

int bsd_socket_set_tos(LIBUS_SOCKET_DESCRIPTOR fd, int tos) {
int level, option;
int err = bsd_socket_tos_level(fd, &level, &option);
if (err) return err;
#ifdef _WIN32
if (setsockopt(fd, level, option, (const char *) &tos, sizeof(tos))) {
return -WSAGetLastError();
}
#else
if (setsockopt(fd, level, option, &tos, sizeof(tos))) {
return -errno;
}
#endif
return 0;
}

int bsd_socket_get_tos(LIBUS_SOCKET_DESCRIPTOR fd) {
int level, option;
int err = bsd_socket_tos_level(fd, &level, &option);
if (err) return err;
int tos = 0;
socklen_t len = sizeof(tos);
#ifdef _WIN32
if (getsockopt(fd, level, option, (char *) &tos, (int *) &len)) {
return -WSAGetLastError();
}
#else
if (getsockopt(fd, level, option, &tos, &len)) {
return -errno;
}
#endif
return tos;
}

void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) {
// Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE
#ifdef TCP_CORK
Expand Down Expand Up @@ -1261,6 +1321,10 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t l
struct sockaddr_un server_address;
size_t addrlen = 0;
if (bsd_create_unix_socket_address(path, len, &dirfd_workaround_for_unix_path_len, &server_address, &addrlen)) {
/* The path could not be expressed as a sockaddr_un (the basename
* exceeds sun_path even with the dirfd workaround); surface the errno
* so the caller can report something better than a codeless failure. */
if (error && errno) *error = errno;
return LIBUS_SOCKET_ERROR;
}

Expand Down Expand Up @@ -1599,12 +1663,31 @@ static int is_loopback(struct sockaddr_storage *sockaddr) {
}
#endif

LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, int options) {
LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(struct sockaddr_storage *addr, struct sockaddr_storage *local_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 the requested local address/port before connecting (the
* `localAddress`/`localPort` connect options). A failure here - typically
* EADDRINUSE or EADDRNOTAVAIL - fails the connect with that errno. */
if (local_addr) {
socklen_t local_len = local_addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
if (bind(fd, (struct sockaddr *) local_addr, local_len)) {
#ifdef _WIN32
int bind_err = WSAGetLastError();
bsd_close_socket(fd);
WSASetLastError(bind_err);
#else
int bind_err = errno;
bsd_close_socket(fd);
errno = bind_err;
#endif
return LIBUS_SOCKET_ERROR;
}
}

#ifdef _WIN32
win32_set_nonblocking(fd);

Expand Down
21 changes: 15 additions & 6 deletions packages/bun-usockets/src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,8 @@ static inline void us_internal_init_connect_socket(struct us_socket_t *s,

struct us_socket_t *us_socket_group_connect_resolved_dns(struct us_socket_group_t *group,
unsigned char kind, struct ssl_ctx_st *ssl_ctx,
struct sockaddr_storage *addr, int options, int socket_ext_size) {
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, options);
struct sockaddr_storage *addr, struct sockaddr_storage *local_addr, int options, int socket_ext_size) {
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(addr, local_addr, options);
if (connect_socket_fd == LIBUS_SOCKET_ERROR) {
return NULL;
}
Expand Down Expand Up @@ -539,14 +539,22 @@ static bool try_parse_ip(const char *ip_str, int port, struct sockaddr_storage *
}

void *us_socket_group_connect(struct us_socket_group_t *group, unsigned char kind,
struct ssl_ctx_st *ssl_ctx, const char *host, int port, int options,
struct ssl_ctx_st *ssl_ctx, const char *host, int port,
const char *local_host, int local_port, int options,
int socket_ext_size, int *has_dns_resolved) {
struct us_loop_t *loop = group->loop;

/* The local address is always a literal IP (Node validates it as one). */
struct sockaddr_storage local_addr_storage;
struct sockaddr_storage *local_addr = NULL;
if (local_host && try_parse_ip(local_host, local_port, &local_addr_storage)) {
local_addr = &local_addr_storage;
}

struct sockaddr_storage addr;
if (try_parse_ip(host, port, &addr)) {
*has_dns_resolved = 1;
return us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &addr, options, socket_ext_size);
return us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &addr, local_addr, options, socket_ext_size);
}

struct addrinfo_request *ai_req;
Expand All @@ -563,7 +571,7 @@ void *us_socket_group_connect(struct us_socket_group_t *group, unsigned char kin
struct sockaddr_storage a;
init_addr_with_port(&entries->info, port, &a);
*has_dns_resolved = 1;
struct us_socket_t *s = us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &a, options, socket_ext_size);
struct us_socket_t *s = us_socket_group_connect_resolved_dns(group, kind, ssl_ctx, &a, local_addr, options, socket_ext_size);
Bun__addrinfo_freeRequest(ai_req, s == NULL);
return s;
}
Expand Down Expand Up @@ -628,7 +636,8 @@ int start_connections(struct us_connecting_socket_t *c, int count) {
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);
/* The deferred-DNS path does not carry a local binding. */
LIBUS_SOCKET_DESCRIPTOR connect_socket_fd = bsd_create_connect_socket(&addr, NULL, c->options);
if (connect_socket_fd == LIBUS_SOCKET_ERROR) {
continue;
}
Expand Down
Loading
Loading