Skip to content
Draft
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
55 changes: 39 additions & 16 deletions packages/bun-usockets/src/bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
) {

if (bsd_set_reuse(listenFd, options) != 0) {
*error = LIBUS_ERR;
return LIBUS_SOCKET_ERROR;
}

Expand All @@ -1189,6 +1190,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd
if (listenAddr->ai_family == AF_INET6) {
int enabled = (options & LIBUS_SOCKET_IPV6_ONLY) != 0;
if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, &enabled, sizeof(enabled)) != 0) {
*error = LIBUS_ERR;
return LIBUS_SOCKET_ERROR;
}
}
Expand Down Expand Up @@ -1357,7 +1359,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_bound_socket(const char *host, int port, int
return fd;
}

LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error) {
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error, int* dns_error) {
bsd_winsock_ensure();
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
Expand All @@ -1369,15 +1371,36 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int
char port_string[16];
snprintf(port_string, 16, "%d", port);

if (getaddrinfo(host, port_string, &hints, &result)) {
#ifndef _WIN32
errno = 0;
#endif
int gai = getaddrinfo(host, port_string, &hints, &result);
if (gai != 0) {
#ifndef _WIN32
/* At the descriptor limit glibc answers EAI_NONAME or EAI_SYSTEM, with the cause in errno. */
if (errno != 0 && (gai == EAI_SYSTEM || errno == EMFILE || errno == ENFILE)) {
*error = errno;
return LIBUS_SOCKET_ERROR;
}
#endif
if (host && strchr(host, ':')) {
/* An IPv6 literal needs no lookup. It fails when its %zone names no interface. */
#ifdef _WIN32
*error = WSAEINVAL;
#else
*error = EINVAL;
#endif
return LIBUS_SOCKET_ERROR;
}
*dns_error = gai;
return LIBUS_SOCKET_ERROR;
}

LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
struct addrinfo *listenAddr;
for (struct addrinfo *a = result; a != NULL; a = a->ai_next) {
if (a->ai_family == AF_INET6) {
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol, NULL);
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol, error);
if (listenFd == LIBUS_SOCKET_ERROR) {
continue;
}
Expand All @@ -1394,7 +1417,7 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int

for (struct addrinfo *a = result; a != NULL; a = a->ai_next) {
if (a->ai_family == AF_INET) {
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol, NULL);
listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol, error);
if (listenFd == LIBUS_SOCKET_ERROR) {
continue;
}
Expand Down Expand Up @@ -1554,20 +1577,18 @@ static LIBUS_SOCKET_DESCRIPTOR bsd_create_unix_socket_address(const char *path,
static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char* path, int options, struct sockaddr_un* server_address, size_t addrlen, int* error) {
LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;

listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0, NULL);
listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0, error);

if (listenFd == LIBUS_SOCKET_ERROR) {
return LIBUS_SOCKET_ERROR;
}

if (us_internal_bind_and_listen(listenFd, (struct sockaddr *) server_address, (socklen_t) addrlen, 512, error)) {
#if defined(_WIN32)
int shouldSimulateENOENT = WSAGetLastError() == WSAENETDOWN;
#endif
bsd_close_socket(listenFd);
#if defined(_WIN32)
if (shouldSimulateENOENT) {
SetLastError(ERROR_PATH_NOT_FOUND);
/* bind() answers WSAENETDOWN when the directory of the path does not exist. */
if (*error == WSAENETDOWN) {
*error = ERROR_PATH_NOT_FOUND;
}
#endif
return LIBUS_SOCKET_ERROR;
Expand All @@ -1582,17 +1603,21 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t l
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;
* exceeds sun_path even with the dirfd workaround). That helper
* reports through SetLastError on Windows and errno elsewhere. */
#if defined(_WIN32)
*error = (int) GetLastError();
#else
*error = errno;
#endif
return LIBUS_SOCKET_ERROR;
}

#if defined(__APPLE__)
if (dirfd_workaround_for_unix_path_len != -1) {
if (__pthread_fchdir(dirfd_workaround_for_unix_path_len) != 0) {
close(dirfd_workaround_for_unix_path_len);
errno = ENAMETOOLONG;
*error = ENAMETOOLONG;
return LIBUS_SOCKET_ERROR;
}
}
Expand All @@ -1602,10 +1627,8 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t l

#if defined(__APPLE__)
if (dirfd_workaround_for_unix_path_len != -1) {
int saved_errno = errno;
__pthread_fchdir(-1);
close(dirfd_workaround_for_unix_path_len);
errno = saved_errno;
}
#elif defined(__linux__)
if (dirfd_workaround_for_unix_path_len != -1) {
Expand Down
16 changes: 5 additions & 11 deletions packages/bun-usockets/src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,23 +373,19 @@ static void us_internal_init_listen_socket(struct us_listen_socket_t *ls,

struct us_listen_socket_t *us_socket_group_listen(struct us_socket_group_t *group,
unsigned char kind, struct ssl_ctx_st *ssl_ctx,
const char *host, int port, int options, int socket_ext_size, int *error) {
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options, error);
const char *host, int port, int options, int socket_ext_size, int *error, int *dns_error) {
LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options, error, dns_error);
if (listen_socket_fd == LIBUS_SOCKET_ERROR) {
return 0;
}

struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_listen_socket_t));
us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET);
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_READABLE) != 0) {
/* EPOLL_CTL_ADD failed (e.g. ENOSPC at fs.epoll.max_user_watches).
* Report via both the out-param and thread-local errno: Bun.listen
* reads *error, Bun.serve reads errno. */
int saved_errno = errno;
/* EPOLL_CTL_ADD failed (e.g. ENOSPC at fs.epoll.max_user_watches). */
*error = errno;
bsd_close_socket(listen_socket_fd);
us_poll_free(p, group->loop);
*error = saved_errno;
errno = saved_errno;
return 0;
}

Expand Down Expand Up @@ -448,11 +444,9 @@ struct us_listen_socket_t *us_socket_group_listen_unix(struct us_socket_group_t
struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_listen_socket_t));
us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET);
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_READABLE) != 0) {
int saved_errno = errno;
*error = errno;
bsd_close_socket(listen_socket_fd);
us_poll_free(p, group->loop);
*error = saved_errno;
errno = saved_errno;
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/bun-usockets/src/internal/networking/bsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ int bsd_send_is_transient_error();

// return LIBUS_SOCKET_ERROR or the fd that represents listen socket
// listen both on ipv6 and ipv4
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error);
LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options, int* error, int* dns_error);

LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, size_t pathlen, int options, int* error);

Expand Down
11 changes: 8 additions & 3 deletions packages/bun-usockets/src/libusockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,16 @@ void us_socket_set_first_flight_before_fin(us_socket_r s) nonnull_fn_decl;
/* ── Listen ───────────────────────────────────────────────────────────────
* The listener owns: an embedded group for accepted sockets, the SSL_CTX
* (borrowed ref, optional), the SNI tree (optional), and the kind to stamp on
* accepted sockets. */
* accepted sockets.
*
* On NULL, *error is the code of the call that failed: errno, or a WSA /
* Win32 code on Windows. When the lookup of `host` failed instead, *error is
* as the caller set it and *dns_error is what getaddrinfo() returned. The two
* number spaces overlap, so callers zero both first. */
struct us_listen_socket_t *us_socket_group_listen(us_socket_group_r group,
unsigned char kind, struct ssl_ctx_st *ssl_ctx,
const char *host, int port, int options, int socket_ext_size, int *error)
__attribute__((nonnull(1, 8))); /* ssl_ctx, host nullable */
const char *host, int port, int options, int socket_ext_size, int *error, int *dns_error)
__attribute__((nonnull(1, 8, 9))); /* ssl_ctx, host nullable */
struct us_listen_socket_t *us_socket_group_listen_unix(us_socket_group_r group,
unsigned char kind, struct ssl_ctx_st *ssl_ctx,
const char *path, size_t pathlen, int options, int socket_ext_size, int *error)
Expand Down
28 changes: 5 additions & 23 deletions packages/bun-uws/src/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,31 +727,13 @@ struct TemplatedApp {
struct ssl_ctx_st *sslCtxOrNull() { return SSL ? sslCtx : nullptr; }

public:
/* Host, port, options, callback */
TemplatedApp &&listen(const std::string &host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
if (host.empty()) {
return listen(port, options, std::move(handler));
}
handler(httpContext ? trackListenSocket(httpContext->listen(sslCtxOrNull(), host.c_str(), port, options)) : nullptr);
return std::move(*this);
}

/* Port, callback */
TemplatedApp &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
handler(httpContext ? trackListenSocket(httpContext->listen(sslCtxOrNull(), nullptr, port, 0)) : nullptr);
return std::move(*this);
/* host is nullptr for every address. The out-params are those of us_socket_group_listen. */
us_listen_socket_t *listen(const char *host, int port, int options, int *error, int *dnsError) {
return httpContext ? trackListenSocket(httpContext->listen(sslCtxOrNull(), host, port, options, error, dnsError)) : nullptr;
}

/* Port, options, callback */
TemplatedApp &&listen(int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
handler(httpContext ? trackListenSocket(httpContext->listen(sslCtxOrNull(), nullptr, port, options)) : nullptr);
return std::move(*this);
}

/* options, callback, path to unix domain socket */
TemplatedApp &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string_view path) {
handler(httpContext ? trackListenSocket(httpContext->listen_unix(sslCtxOrNull(), path.data(), path.length(), options)) : nullptr);
return std::move(*this);
us_listen_socket_t *listen_unix(std::string_view path, int options, int *error) {
return httpContext ? trackListenSocket(httpContext->listen_unix(sslCtxOrNull(), path.data(), path.length(), options, error)) : nullptr;
}

void setOnSocketClosed(HttpContextData<SSL>::OnSocketClosedCallback onClose) {
Expand Down
10 changes: 4 additions & 6 deletions packages/bun-uws/src/HttpContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1283,15 +1283,13 @@ struct HttpContext {
}

/* Listen to port using this HttpContext. ssl_ctx may be nullptr for plain HTTP. */
us_listen_socket_t *listen(struct ssl_ctx_st *sslCtx, const char *host, int port, int options) {
int error = 0;
return unrefListenSocket(us_socket_group_listen(&group, socketKind(), sslCtx, host, port, tcpListenOptions(options), socketExtSize(), &error));
us_listen_socket_t *listen(struct ssl_ctx_st *sslCtx, const char *host, int port, int options, int *error, int *dnsError) {
return unrefListenSocket(us_socket_group_listen(&group, socketKind(), sslCtx, host, port, tcpListenOptions(options), socketExtSize(), error, dnsError));
}

/* Listen to unix domain socket using this HttpContext */
us_listen_socket_t *listen_unix(struct ssl_ctx_st *sslCtx, const char *path, size_t pathlen, int options) {
int error = 0;
return unrefListenSocket(us_socket_group_listen_unix(&group, socketKind(), sslCtx, path, pathlen, options, socketExtSize(), &error));
us_listen_socket_t *listen_unix(struct ssl_ctx_st *sslCtx, const char *path, size_t pathlen, int options, int *error) {
return unrefListenSocket(us_socket_group_listen_unix(&group, socketKind(), sslCtx, path, pathlen, options, socketExtSize(), error));
}
};

Expand Down
9 changes: 9 additions & 0 deletions src/runtime/dns_jsc/cares_jsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,15 @@ pub(crate) fn error_to_js_with_syscall_and_hostname(
Ok(instance)
}

/// The `getaddrinfo <CODE> <hostname>` error for `gai`, a non-zero return of getaddrinfo(3).
pub(crate) fn getaddrinfo_error(gai: c_int, hostname: &[u8]) -> Option<SystemError> {
if gai == 0 {
return None;
}
c_ares::Error::init_eai(gai)
.map(|error| system_error_with_syscall_and_hostname(error, b"getaddrinfo", hostname))
}

/// Thrown before uSockets' synchronous `getaddrinfo` can block on a name that can never resolve.
pub(crate) fn not_a_hostname_error(global_this: &JSGlobalObject, hostname: &[u8]) -> JSValue {
system_error_with_syscall_and_hostname(c_ares::Error::ENOTFOUND, b"getaddrinfo", hostname)
Expand Down
Loading
Loading