#define _GNU_SOURCE #include #include #include #include #include #include #include #include static int has_status_flag(int fd, int flag) { int value = fcntl(fd, F_GETFL); return value >= 0 && (value & flag) != 0; } static int has_fd_flag(int fd, int flag) { int value = fcntl(fd, F_GETFD); return value >= 0 && (value & flag) != 0; } int main(void) { int ok = 1; int flagged = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (flagged < 0) { perror("socket(flags)"); return 1; } int socket_nonblock = has_status_flag(flagged, O_NONBLOCK); int socket_cloexec = has_fd_flag(flagged, FD_CLOEXEC); printf("socket_nonblock=%s\n", socket_nonblock ? "yes" : "no"); printf("socket_cloexec=%s\n", socket_cloexec ? "yes" : "no"); ok &= socket_nonblock && socket_cloexec; close(flagged); errno = 0; int invalid_socket = socket(AF_INET, SOCK_STREAM | 0x20000000, 0); int invalid_socket_errno = errno; if (invalid_socket >= 0) close(invalid_socket); int invalid_socket_einval = invalid_socket == -1 && invalid_socket_errno == EINVAL; printf("socket_invalid_flag_einval=%s\n", invalid_socket_einval ? "yes" : "no"); ok &= invalid_socket_einval; /* Linux looks up the descriptor before validating accept4 flags. */ errno = 0; int badfd_accept = accept4(-1, NULL, NULL, 0x20000000); int badfd_accept_errno = errno; int badfd_accept_ebadf = badfd_accept == -1 && badfd_accept_errno == EBADF; printf("accept4_badfd_ebadf=%s\n", badfd_accept_ebadf ? "yes" : "no"); ok &= badfd_accept_ebadf; /* Establish a loopback connection in one process. TCP connect may finish * before accept because the listening socket's backlog owns the pending * connection, so no fork/thread is needed by the WASM fixture. */ int listener = socket(AF_INET, SOCK_STREAM, 0); if (listener < 0) { perror("socket(listener)"); return 1; } struct sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); address.sin_port = 0; if (bind(listener, (struct sockaddr *)&address, sizeof(address)) < 0 || listen(listener, 1) < 0) { perror("listen(loopback)"); close(listener); return 1; } errno = 0; int invalid_accept = accept4(listener, NULL, NULL, 0x20000000); int invalid_accept_errno = errno; int invalid_accept_einval = invalid_accept == -1 && invalid_accept_errno == EINVAL; printf("accept4_invalid_flag_einval=%s\n", invalid_accept_einval ? "yes" : "no"); ok &= invalid_accept_einval; socklen_t address_len = sizeof(address); if (getsockname(listener, (struct sockaddr *)&address, &address_len) < 0) { perror("getsockname(listener)"); close(listener); return 1; } int client = socket(AF_INET, SOCK_STREAM, 0); if (client < 0 || connect(client, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("connect(loopback)"); if (client >= 0) close(client); close(listener); return 1; } int accepted = accept4(listener, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); if (accepted < 0) { perror("accept4(flags)"); close(client); close(listener); return 1; } int accept_nonblock = has_status_flag(accepted, O_NONBLOCK); int accept_cloexec = has_fd_flag(accepted, FD_CLOEXEC); printf("accept4_nonblock=%s\n", accept_nonblock ? "yes" : "no"); printf("accept4_cloexec=%s\n", accept_cloexec ? "yes" : "no"); ok &= accept_nonblock && accept_cloexec; /* dup/F_DUPFD share the socket open-file description (including status * flags), but each descriptor has independent FD_CLOEXEC state. */ int duplicate = dup(accepted); int duplicate_ok = duplicate >= 0 && !has_fd_flag(duplicate, FD_CLOEXEC) && has_status_flag(duplicate, O_NONBLOCK); if (duplicate >= 0 && fcntl(duplicate, F_SETFL, 0) == 0) duplicate_ok &= !has_status_flag(accepted, O_NONBLOCK); if (duplicate >= 0 && fcntl(duplicate, F_SETFD, FD_CLOEXEC) == 0) duplicate_ok &= has_fd_flag(duplicate, FD_CLOEXEC) && has_fd_flag(accepted, FD_CLOEXEC); printf("socket_dup_shared_ofd=%s\n", duplicate_ok ? "yes" : "no"); ok &= duplicate_ok; int exact = duplicate >= 0 ? dup2(duplicate, 42) : -1; int dup2_exact = exact == 42 && !has_fd_flag(exact, FD_CLOEXEC); printf("socket_dup2_exact=%s\n", dup2_exact ? "yes" : "no"); ok &= dup2_exact; int minimum = exact >= 0 ? fcntl(exact, F_DUPFD, 50) : -1; int dup_min = minimum >= 50 && !has_fd_flag(minimum, FD_CLOEXEC); printf("socket_f_dupfd_min=%s\n", dup_min ? "yes" : "no"); ok &= dup_min; /* Closing the source must leave each duplicate usable. */ close(accepted); const char byte = 'x'; char received = 0; int independent_close = exact >= 0 && send(client, &byte, 1, 0) == 1 && recv(exact, &received, 1, 0) == 1 && received == byte; printf("socket_dup_independent_close=%s\n", independent_close ? "yes" : "no"); ok &= independent_close; if (duplicate >= 0) close(duplicate); if (exact >= 0) close(exact); if (minimum >= 0) close(minimum); close(client); close(listener); printf("socket_flags=%s\n", ok ? "ok" : "FAIL"); return ok ? 0 : 1; }