Skip to content
Closed
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
3 changes: 3 additions & 0 deletions expected/wasm32-wasi-eh/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6227,6 +6227,9 @@
#define __WASI_SOCK_OPTION_SEND_BUF_SIZE (UINT8_C(16))
#define __WASI_SOCK_OPTION_SEND_LOWAT (UINT8_C(18))
#define __WASI_SOCK_OPTION_SEND_TIMEOUT (UINT8_C(20))
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))
#define __WASI_SOCK_OPTION_TTL (UINT8_C(23))
#define __WASI_SOCK_OPTION_TYPE (UINT8_C(25))
#define __WASI_SOCK_PROTO_AH (UINT16_C(51))
Expand Down
3 changes: 3 additions & 0 deletions expected/wasm32-wasi-ehpic/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6236,6 +6236,9 @@
#define __WASI_SOCK_OPTION_SEND_BUF_SIZE (UINT8_C(16))
#define __WASI_SOCK_OPTION_SEND_LOWAT (UINT8_C(18))
#define __WASI_SOCK_OPTION_SEND_TIMEOUT (UINT8_C(20))
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))
#define __WASI_SOCK_OPTION_TTL (UINT8_C(23))
#define __WASI_SOCK_OPTION_TYPE (UINT8_C(25))
#define __WASI_SOCK_PROTO_AH (UINT16_C(51))
Expand Down
3 changes: 3 additions & 0 deletions expected/wasm32-wasi-threads/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6018,6 +6018,9 @@
#define __WASI_SOCK_OPTION_SEND_BUF_SIZE (UINT8_C(16))
#define __WASI_SOCK_OPTION_SEND_LOWAT (UINT8_C(18))
#define __WASI_SOCK_OPTION_SEND_TIMEOUT (UINT8_C(20))
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))
#define __WASI_SOCK_OPTION_TTL (UINT8_C(23))
#define __WASI_SOCK_OPTION_TYPE (UINT8_C(25))
#define __WASI_SOCK_PROTO_AH (UINT16_C(51))
Expand Down
3 changes: 3 additions & 0 deletions expected/wasm32-wasi/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6235,6 +6235,9 @@
#define __WASI_SOCK_OPTION_SEND_BUF_SIZE (UINT8_C(16))
#define __WASI_SOCK_OPTION_SEND_LOWAT (UINT8_C(18))
#define __WASI_SOCK_OPTION_SEND_TIMEOUT (UINT8_C(20))
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))
#define __WASI_SOCK_OPTION_TTL (UINT8_C(23))
#define __WASI_SOCK_OPTION_TYPE (UINT8_C(25))
#define __WASI_SOCK_PROTO_AH (UINT16_C(51))
Expand Down
3 changes: 3 additions & 0 deletions expected/wasm64-wasi/predefined-macros.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6083,6 +6083,9 @@
#define __WASI_SOCK_OPTION_SEND_BUF_SIZE (UINT8_C(16))
#define __WASI_SOCK_OPTION_SEND_LOWAT (UINT8_C(18))
#define __WASI_SOCK_OPTION_SEND_TIMEOUT (UINT8_C(20))
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))
#define __WASI_SOCK_OPTION_TTL (UINT8_C(23))
#define __WASI_SOCK_OPTION_TYPE (UINT8_C(25))
#define __WASI_SOCK_PROTO_AH (UINT16_C(51))
Expand Down
25 changes: 20 additions & 5 deletions libc-bottom-half/cloudlibc/src/libc/sys/socket/getsockopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ int getsockopt(int socket, int level, int option_name,
level = SOL_SOCKET;
option_name = SO_ONLYV6;
}
if (level == IPPROTO_TCP && option_name == TCP_NODELAY) {
if (level == IPPROTO_TCP) {
switch (option_name) {
case TCP_NODELAY: option_name = SO_NODELAY; break;
case TCP_KEEPIDLE: option_name = __WASI_SOCK_OPTION_TCP_KEEP_IDLE; break;
case TCP_KEEPINTVL: option_name = __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL; break;
case TCP_KEEPCNT: option_name = __WASI_SOCK_OPTION_TCP_KEEP_COUNT; break;
default: errno = ENOPROTOOPT; return -1;
}
level = SOL_SOCKET;
option_name = SO_NODELAY;
}

if (level != SOL_SOCKET) {
Expand Down Expand Up @@ -97,16 +103,25 @@ int getsockopt(int socket, int level, int option_name,
case SO_RCVBUF:
case SO_SNDBUF:
case SO_TTL:
case SO_MCASTTTLV4: {
case SO_MCASTTTLV4:
case __WASI_SOCK_OPTION_TCP_KEEP_IDLE:
case __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL:
case __WASI_SOCK_OPTION_TCP_KEEP_COUNT: {
if (option_len == NULL || (*option_len != 0 && option_value == NULL)) {
errno = EFAULT;
return -1;
}
__wasi_filesize_t fs;
__wasi_errno_t error = __wasi_sock_get_opt_size(socket, option_name, &fs);
if (error != 0) {
errno = error;
return -1;
}
socklen_t len = fs;
memcpy(option_value, &len, *option_len < sizeof(socklen_t ) ? *option_len : sizeof(socklen_t ));
*option_len = sizeof(socklen_t );
if (*option_len > sizeof(len))
*option_len = sizeof(len);
if (*option_len != 0)
memcpy(option_value, &len, *option_len);
return 0;
}
case SO_PROTOCOL: {
Expand Down
41 changes: 26 additions & 15 deletions libc-bottom-half/cloudlibc/src/libc/sys/socket/setsockopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ int setsockopt(int socket, int level, int option_name, const void *restrict opti
level = SOL_SOCKET;
option_name = SO_ONLYV6;
}
if (level == IPPROTO_TCP && option_name == TCP_NODELAY) {
if (level == IPPROTO_TCP) {
switch (option_name) {
case TCP_NODELAY: option_name = SO_NODELAY; break;
case TCP_KEEPIDLE: option_name = __WASI_SOCK_OPTION_TCP_KEEP_IDLE; break;
case TCP_KEEPINTVL: option_name = __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL; break;
case TCP_KEEPCNT: option_name = __WASI_SOCK_OPTION_TCP_KEEP_COUNT; break;
default: errno = ENOSYS; return -1;
}
level = SOL_SOCKET;
option_name = SO_NODELAY;
}

if(level!=SOL_SOCKET) {
Expand Down Expand Up @@ -86,19 +92,24 @@ int setsockopt(int socket, int level, int option_name, const void *restrict opti
return 0;
}
case SO_RCVBUF:
case SO_SNDBUF:
case SO_TTL:
case SO_MCASTTTLV4: {
__wasi_filesize_t fs;
if (option_len >= sizeof(socklen_t)) {
socklen_t *len = (socklen_t *)option_value;
fs = *len;
} else {
errno = EINVAL;
return -1;
}

__wasi_errno_t error = __wasi_sock_set_opt_size(socket, option_name, fs);
case SO_SNDBUF:
case SO_TTL:
case SO_MCASTTTLV4:
case __WASI_SOCK_OPTION_TCP_KEEP_IDLE:
case __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL:
case __WASI_SOCK_OPTION_TCP_KEEP_COUNT: {
socklen_t value;
if (option_len < sizeof(value)) {
errno = EINVAL;
return -1;
}
if (option_value == NULL) {
errno = EFAULT;
return -1;
}
memcpy(&value, option_value, sizeof(value));

__wasi_errno_t error = __wasi_sock_set_opt_size(socket, option_name, value);
if (error != 0) {
errno = error;
return -1;
Expand Down
18 changes: 18 additions & 0 deletions libc-bottom-half/headers/public/wasi/api_wasix.h
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,24 @@ typedef uint8_t __wasi_sock_option_t;
*/
#define __WASI_SOCK_OPTION_PROTO (UINT8_C(26))

/**
* TCP idle seconds before sending keepalive probes (positive integer).
* Read and written using sock_get_opt_size and sock_set_opt_size.
*/
#define __WASI_SOCK_OPTION_TCP_KEEP_IDLE (UINT8_C(27))

/**
* TCP seconds between keepalive probes (positive integer).
* Read and written using sock_get_opt_size and sock_set_opt_size.
*/
#define __WASI_SOCK_OPTION_TCP_KEEP_INTERVAL (UINT8_C(28))

/**
* TCP unanswered keepalive probes before closing the connection (positive integer).
* Read and written using sock_get_opt_size and sock_set_opt_size.
*/
#define __WASI_SOCK_OPTION_TCP_KEEP_COUNT (UINT8_C(29))

_Static_assert(sizeof(__wasi_sock_option_t) == 1, "witx calculated size");
_Static_assert(_Alignof(__wasi_sock_option_t) == 1, "witx calculated align");

Expand Down
4 changes: 4 additions & 0 deletions test/wasix/c_tcp_keepalive/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.5.0)
project(c_tcp_keepalive C)

add_executable(main main.c)
124 changes: 124 additions & 0 deletions test/wasix/c_tcp_keepalive/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <wasi/api.h>

_Static_assert(__WASI_SOCK_OPTION_TCP_KEEP_IDLE == 27, "keep idle ABI");
_Static_assert(__WASI_SOCK_OPTION_TCP_KEEP_INTERVAL == 28, "keep interval ABI");
_Static_assert(__WASI_SOCK_OPTION_TCP_KEEP_COUNT == 29, "keep count ABI");

static const int options[] = {TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT};
static const int values[] = {31, 7, 4};

static void check_options(int fd) {
for (unsigned i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
int value = 0;
socklen_t len = sizeof(value);
assert(getsockopt(fd, IPPROTO_TCP, options[i], &value, &len) == 0);
assert(len == sizeof(value));
assert(value == values[i]);
}
}

static void check_validation(int fd) {
for (unsigned i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
int value = 0;
errno = 0;
assert(setsockopt(fd, IPPROTO_TCP, options[i], &value, sizeof(value)) == -1);
assert(errno == EINVAL);
value = -1;
errno = 0;
assert(setsockopt(fd, IPPROTO_TCP, options[i], &value, sizeof(value)) == -1);
assert(errno == EINVAL);
value = 1;
errno = 0;
assert(setsockopt(fd, IPPROTO_TCP, options[i], &value, sizeof(value) - 1) == -1);
assert(errno == EINVAL);
errno = 0;
assert(setsockopt(fd, IPPROTO_TCP, options[i], NULL, sizeof(value)) == -1);
assert(errno == EFAULT);
}
check_options(fd);
}

static void check_output_lengths(int fd, int level, int option, int expected) {
unsigned char output[sizeof(int) + 1];
memset(output, 0xa5, sizeof(output));
socklen_t len = 1;
assert(getsockopt(fd, level, option, output, &len) == 0);
assert(len == 1);
assert(output[0] == ((const unsigned char *)&expected)[0]);
assert(output[1] == 0xa5);

len = sizeof(output);
assert(getsockopt(fd, level, option, output, &len) == 0);
assert(len == sizeof(int));
assert(memcmp(output, &expected, sizeof(int)) == 0);
assert(output[sizeof(int)] == 0xa5);

len = 0;
assert(getsockopt(fd, level, option, NULL, &len) == 0);
assert(len == 0);
len = sizeof(int);
errno = 0;
assert(getsockopt(fd, level, option, NULL, &len) == -1);
assert(errno == EFAULT);
errno = 0;
assert(getsockopt(fd, level, option, output, NULL) == -1);
assert(errno == EFAULT);
}

int main(void) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
assert(fd >= 0);
int enabled = 1;
assert(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enabled, sizeof(enabled)) == 0);
for (unsigned i = 0; i < sizeof(options) / sizeof(options[0]); i++)
assert(setsockopt(fd, IPPROTO_TCP, options[i], &values[i], sizeof(values[i])) == 0);
check_options(fd);
check_validation(fd);
check_output_lengths(fd, IPPROTO_TCP, TCP_KEEPIDLE, values[0]);
int buffer_size = 4096;
assert(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size)) == 0);
check_output_lengths(fd, SOL_SOCKET, SO_RCVBUF, buffer_size);

int server = socket(AF_INET, SOCK_STREAM, 0);
assert(server >= 0);
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
assert(bind(server, (struct sockaddr *)&address, sizeof(address)) == 0);
assert(listen(server, 1) == 0);
socklen_t len = sizeof(address);
assert(getsockname(server, (struct sockaddr *)&address, &len) == 0);
assert(connect(fd, (struct sockaddr *)&address, sizeof(address)) == 0);
int peer = accept(server, NULL, NULL);
assert(peer >= 0);
check_options(fd);
check_validation(fd);

int updated = 9;
assert(setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &updated, sizeof(updated)) == 0);
int actual = 0;
len = sizeof(actual);
assert(getsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &actual, &len) == 0);
assert(actual == updated);

assert(close(peer) == 0);
assert(close(server) == 0);
assert(close(fd) == 0);
errno = 0;
assert(setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &updated, sizeof(updated)) == -1);
assert(errno == EBADF);
errno = 0;
len = sizeof(actual);
assert(getsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &actual, &len) == -1);
assert(errno == EBADF);
puts("TCP keepalive options passed");
return 0;
}
4 changes: 4 additions & 0 deletions test/wasix/c_tcp_keepalive/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail

wasmer run --net ./main
2 changes: 1 addition & 1 deletion tools/wasix-headers/WASI
Loading