Add support for IPv6 in WAMR (#1411)

For now this implementation only covers posix platforms, as defined in MVP #1336
This commit is contained in:
Marcin Kolny 2022-09-01 16:20:53 +02:00 committed by GitHub
parent 0e17ab2f75
commit 0ffac101a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 551 additions and 165 deletions

View File

@ -59,7 +59,7 @@ wasm_create_gdbserver(const char *host, int32 *port)
memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t));
if (0 != os_socket_create(&listen_fd, 1)) {
if (0 != os_socket_create(&listen_fd, true, true)) {
LOG_ERROR("wasm gdb server error: create socket failed");
goto fail;
}

View File

@ -31,21 +31,38 @@ ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
out->addr.ip4.addr.n3 = (addr_num & 0x000000FF);
}
static void
ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out)
{
out->kind = IPv6;
out->addr.ip6.port = ntohs(port);
out->addr.ip6.addr.n0 = ntohs(addr[0]);
out->addr.ip6.addr.n1 = ntohs(addr[1]);
out->addr.ip6.addr.n2 = ntohs(addr[2]);
out->addr.ip6.addr.n3 = ntohs(addr[3]);
out->addr.ip6.addr.h0 = ntohs(addr[4]);
out->addr.ip6.addr.h1 = ntohs(addr[5]);
out->addr.ip6.addr.h2 = ntohs(addr[6]);
out->addr.ip6.addr.h3 = ntohs(addr[7]);
}
static __wasi_errno_t
sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
__wasi_addr_t *wasi_addr)
{
__wasi_errno_t ret = __WASI_ERRNO_SUCCESS;
if (AF_INET == sock_addr->sa_family) {
assert(sizeof(struct sockaddr_in) == addrlen);
assert(sizeof(struct sockaddr_in) <= addrlen);
ipv4_addr_to_wasi_addr(
((struct sockaddr_in *)sock_addr)->sin_addr.s_addr,
((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr);
}
else if (AF_INET6 == sock_addr->sa_family) {
// TODO: IPV6
ret = __WASI_ERRNO_AFNOSUPPORT;
assert(sizeof(struct sockaddr_in6) == addrlen);
ipv6_addr_to_wasi_addr(
(uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr,
((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr);
}
else {
ret = __WASI_ERRNO_AFNOSUPPORT;
@ -78,8 +95,26 @@ wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr,
break;
}
case IPv6:
// TODO: IPV6
return __WASI_ERRNO_AFNOSUPPORT;
{
struct sockaddr_in6 sock_addr_in6 = { 0 };
uint16_t *addr_buf = (uint16_t *)sock_addr_in6.sin6_addr.s6_addr;
addr_buf[0] = htons(wasi_addr->addr.ip6.addr.n0);
addr_buf[1] = htons(wasi_addr->addr.ip6.addr.n1);
addr_buf[2] = htons(wasi_addr->addr.ip6.addr.n2);
addr_buf[3] = htons(wasi_addr->addr.ip6.addr.n3);
addr_buf[4] = htons(wasi_addr->addr.ip6.addr.h0);
addr_buf[5] = htons(wasi_addr->addr.ip6.addr.h1);
addr_buf[6] = htons(wasi_addr->addr.ip6.addr.h2);
addr_buf[7] = htons(wasi_addr->addr.ip6.addr.h3);
sock_addr_in6.sin6_family = AF_INET6;
sock_addr_in6.sin6_port = htons(wasi_addr->addr.ip6.port);
memcpy(sock_addr, &sock_addr_in6, sizeof(sock_addr_in6));
*addrlen = sizeof(sock_addr_in6);
break;
}
default:
return __WASI_ERRNO_AFNOSUPPORT;
}

View File

@ -2948,6 +2948,35 @@ wasi_ssp_sock_addr_remote(
return __WASI_ESUCCESS;
}
static bool
wasi_addr_to_string(__wasi_addr_t *addr, char *buf, size_t buflen)
{
if (addr->kind == IPv4) {
const char *format = "%u.%u.%u.%u";
assert(buflen >= 16);
snprintf(buf, buflen, format, addr->addr.ip4.addr.n0,
addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2,
addr->addr.ip4.addr.n3);
return true;
}
else if (addr->kind == IPv6) {
const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x";
__wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr;
assert(buflen >= 40);
snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3,
ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3);
return true;
}
return false;
}
__wasi_errno_t
wasi_ssp_sock_bind(
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
@ -2955,15 +2984,15 @@ wasi_ssp_sock_bind(
#endif
__wasi_fd_t fd, __wasi_addr_t *addr)
{
char buf[24] = { 0 };
const char *format = "%u.%u.%u.%u";
char buf[48] = { 0 };
struct fd_object *fo;
__wasi_errno_t error;
int port = addr->addr.ip4.port;
int port = addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port;
int ret;
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
return __WASI_EPROTONOSUPPORT;
}
if (!addr_pool_search(addr_pool, buf)) {
return __WASI_EACCES;
@ -3017,7 +3046,8 @@ wasi_ssp_sock_addr_resolve(
addr_info_size < *max_info_size ? addr_info_size : *max_info_size;
for (size_t i = 0; i < actual_info_size; i++) {
addr_info[i].type = wamr_addr_info[i].is_tcp ? SOCK_STREAM : SOCK_DGRAM;
addr_info[i].type =
wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM;
if (wamr_addr_info[i].is_ipv4) {
ipv4_addr_to_wasi_addr(*(uint32_t *)wamr_addr_info[i].addr,
wamr_addr_info[i].port, &addr_info[i].addr);
@ -3039,14 +3069,14 @@ wasi_ssp_sock_connect(
#endif
__wasi_fd_t fd, __wasi_addr_t *addr)
{
char buf[24] = { 0 };
const char *format = "%u.%u.%u.%u";
char buf[48] = { 0 };
struct fd_object *fo;
__wasi_errno_t error;
int ret;
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
return __WASI_EPROTONOSUPPORT;
}
if (!addr_pool_search(addr_pool, buf)) {
return __WASI_EACCES;
@ -3056,7 +3086,9 @@ wasi_ssp_sock_connect(
if (error != __WASI_ESUCCESS)
return error;
ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port);
ret = os_socket_connect(fd_number(fo), buf,
addr->kind == IPv4 ? addr->addr.ip4.port
: addr->addr.ip6.port);
fd_object_release(fo);
if (BHT_OK != ret) {
return convert_errno(errno);
@ -3097,7 +3129,8 @@ wasi_ssp_sock_open(
__wasi_fd_t *sockfd)
{
bh_socket_t sock;
int tcp_or_udp = 0;
bool is_tcp = SOCKET_DGRAM == socktype ? false : true;
bool is_ipv4 = INET6 ? false : true;
int ret;
__wasi_filetype_t wasi_type;
__wasi_rights_t max_base, max_inheriting;
@ -3105,13 +3138,7 @@ wasi_ssp_sock_open(
(void)poolfd;
if (INET4 != af) {
return __WASI_EAFNOSUPPORT;
}
tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1;
ret = os_socket_create(&sock, tcp_or_udp);
ret = os_socket_create(&sock, is_ipv4, is_tcp);
if (BHT_OK != ret) {
return convert_errno(errno);
}
@ -3337,9 +3364,8 @@ fd_prestats_destroy(struct fd_prestats *pt)
bool
addr_pool_init(struct addr_pool *addr_pool)
{
addr_pool->next = NULL;
addr_pool->addr = 0;
addr_pool->mask = 0;
memset(addr_pool, 0, sizeof(*addr_pool));
return true;
}
@ -3348,6 +3374,7 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
{
struct addr_pool *cur = addr_pool;
struct addr_pool *next;
bh_inet_network_output_t target;
if (!addr_pool) {
return false;
@ -3359,9 +3386,20 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
next->next = NULL;
next->mask = mask;
if (os_socket_inet_network(addr, &next->addr) != BHT_OK) {
wasm_runtime_free(next);
return false;
if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
// If parsing IPv4 fails, try IPv6
if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
wasm_runtime_free(next);
return false;
}
next->type = IPv6;
bh_memcpy_s(next->addr.ip6, sizeof(next->addr.ip6), target.ipv6,
sizeof(target.ipv6));
}
else {
next->type = IPv4;
next->addr.ip4 = target.ipv4;
}
/* attach with */
@ -3372,47 +3410,106 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
return true;
}
static bool
compare_address(const struct addr_pool *addr_pool_entry, const char *addr)
static inline size_t
min(size_t a, size_t b)
{
/* host order */
uint32 target;
uint32 address = addr_pool_entry->addr;
/* 0.0.0.0 means any address */
if (0 == address) {
return a > b ? b : a;
}
static void
init_address_mask(uint8_t *buf, size_t buflen, size_t mask)
{
size_t element_size = sizeof(uint8_t) * 8;
for (size_t i = 0; i < buflen; i++) {
if (mask <= i * element_size) {
buf[i] = 0;
}
else {
size_t offset = min(mask - i * element_size, element_size);
buf[i] = (~0u) << (element_size - offset);
}
}
}
/* target must be in network byte order */
static bool
compare_address(const struct addr_pool *addr_pool_entry,
bh_inet_network_output_t *target)
{
uint8_t maskbuf[16] = { 0 };
uint8_t basebuf[16] = { 0 };
size_t addr_size;
uint8_t max_addr_mask;
if (addr_pool_entry->type == IPv4) {
uint32_t addr_ip4 = htonl(addr_pool_entry->addr.ip4);
bh_memcpy_s(basebuf, sizeof(addr_ip4), &addr_ip4, sizeof(addr_ip4));
addr_size = 4;
}
else {
uint16_t partial_addr_ip6;
for (int i = 0; i < 8; i++) {
partial_addr_ip6 = htons(addr_pool_entry->addr.ip6[i]);
bh_memcpy_s(&basebuf[i * sizeof(partial_addr_ip6)],
sizeof(partial_addr_ip6), &partial_addr_ip6,
sizeof(partial_addr_ip6));
}
addr_size = 16;
}
max_addr_mask = addr_size * 8;
/* IPv4 0.0.0.0 or IPv6 :: means any address */
if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {
return true;
}
if (os_socket_inet_network(addr, &target) != BHT_OK) {
/* No support for invalid mask value */
if (addr_pool_entry->mask > max_addr_mask) {
return false;
}
const uint32 max_mask_value = 32;
/* no support for invalid mask values */
if (addr_pool_entry->mask > max_mask_value) {
return false;
init_address_mask(maskbuf, addr_size, addr_pool_entry->mask);
for (size_t i = 0; i < addr_size; i++) {
uint8_t addr_mask = target->data[i] & maskbuf[i];
uint8_t range_mask = basebuf[i] & maskbuf[i];
if (addr_mask != range_mask) {
return false;
}
}
/* convert mask number into 32-bit mask value, i.e. mask /24 will be
converted to 4294967040 (binary: 11111111 11111111 11111111 00000000) */
uint32 mask = 0;
for (int i = 0; i < addr_pool_entry->mask; i++) {
mask |= 1 << (max_mask_value - 1 - i);
}
uint32 first_address = address & mask;
uint32 last_address = address | (~mask);
return first_address <= target && target <= last_address;
return true;
}
bool
addr_pool_search(struct addr_pool *addr_pool, const char *addr)
{
struct addr_pool *cur = addr_pool->next;
bh_inet_network_output_t target;
__wasi_addr_type_t addr_type;
if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
size_t i;
if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
return false;
}
addr_type = IPv6;
for (i = 0; i < sizeof(target.ipv6) / sizeof(target.ipv6[0]); i++) {
target.ipv6[i] = htons(target.ipv6[i]);
}
}
else {
addr_type = IPv4;
target.ipv4 = htonl(target.ipv4);
}
while (cur) {
if (compare_address(cur, addr))
if (cur->type == addr_type && compare_address(cur, &target)) {
return true;
}
cur = cur->next;
}

View File

@ -47,9 +47,13 @@ struct argv_environ_values {
};
struct addr_pool {
struct addr_pool *next;
/* addr and mask in host order */
uint32 addr;
union {
uint32 ip4;
uint16 ip6[8];
} addr;
struct addr_pool *next;
__wasi_addr_type_t type;
uint8 mask;
};

View File

@ -9,28 +9,45 @@
#include <arpa/inet.h>
#include <netdb.h>
static void
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
static bool
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out)
{
struct sockaddr_in *v4;
struct sockaddr_in6 *v6;
assert(textual);
out->sin_family = AF_INET;
out->sin_port = htons(port);
out->sin_addr.s_addr = inet_addr(textual);
v4 = (struct sockaddr_in *)out;
if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
v4->sin_family = AF_INET;
v4->sin_port = htons(port);
return true;
}
v6 = (struct sockaddr_in6 *)out;
if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) {
v6->sin6_family = AF_INET6;
v6->sin6_port = htons(port);
return true;
}
return false;
}
int
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
{
int af = is_ipv4 ? AF_INET : AF_INET6;
if (!sock) {
return BHT_ERROR;
}
if (1 == tcp_or_udp) {
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (is_tcp) {
*sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
}
else if (0 == tcp_or_udp) {
*sock = socket(AF_INET, SOCK_DGRAM, 0);
else {
*sock = socket(af, SOCK_DGRAM, 0);
}
return (*sock == -1) ? BHT_ERROR : BHT_OK;
@ -39,7 +56,7 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
int
os_socket_bind(bh_socket_t socket, const char *host, int *port)
{
struct sockaddr_in addr;
struct sockaddr_storage addr;
struct linger ling;
socklen_t socklen;
int ret;
@ -60,7 +77,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
goto fail;
}
textual_addr_to_sockaddr(host, *port, &addr);
if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr)) {
goto fail;
}
ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
@ -72,7 +91,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
goto fail;
}
*port = ntohs(addr.sin_port);
*port = ntohs(addr.ss_family == AF_INET
? ((struct sockaddr_in *)&addr)->sin_port
: ((struct sockaddr_in6 *)&addr)->sin6_port);
return BHT_OK;
@ -113,7 +134,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
struct sockaddr addr_tmp;
unsigned int len = sizeof(struct sockaddr);
*sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len);
*sock = accept(server_sock, &addr_tmp, &len);
if (*sock < 0) {
return BHT_ERROR;
@ -125,11 +146,13 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
int
os_socket_connect(bh_socket_t socket, const char *addr, int port)
{
struct sockaddr_in addr_in = { 0 };
socklen_t addr_len = sizeof(struct sockaddr_in);
struct sockaddr_storage addr_in = { 0 };
socklen_t addr_len = sizeof(struct sockaddr_storage);
int ret = 0;
textual_addr_to_sockaddr(addr, port, &addr_in);
if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in)) {
return BHT_ERROR;
}
ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
if (ret == -1) {
@ -166,13 +189,28 @@ os_socket_shutdown(bh_socket_t socket)
}
int
os_socket_inet_network(const char *cp, uint32 *out)
os_socket_inet_network(bool is_ipv4, const char *cp,
bh_inet_network_output_t *out)
{
if (!cp)
return BHT_ERROR;
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
*out = ntohl(inet_addr(cp));
if (is_ipv4) {
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
return BHT_ERROR;
}
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
out->ipv4 = ntohl(out->ipv4);
}
else {
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
return BHT_ERROR;
}
for (int i = 0; i < 8; i++) {
out->ipv6[i] = ntohs(out->ipv6[i]);
}
}
return BHT_OK;
}

View File

@ -296,12 +296,13 @@ os_sem_unlink(const char *name);
* Create a socket
*
* @param sock [OUTPUT] the pointer of socket
* @param tcp_or_udp 1 for tcp, 0 for udp
* @param is_ipv4 true for IPv4, false for IPv6
* @param is_tcp true for tcp, false for udp
*
* @return 0 if success, -1 otherwise
*/
int
os_socket_create(bh_socket_t *sock, int tcp_or_udp);
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp);
/**
* Assign the address and port to the socket
@ -412,17 +413,30 @@ os_socket_close(bh_socket_t socket);
int
os_socket_shutdown(bh_socket_t socket);
typedef union {
uint32 ipv4;
uint16 ipv6[8];
uint8_t data[0];
} bh_inet_network_output_t;
/**
* converts cp into a number in host byte order suitable for use as
* an Internet network address
*
* @param cp a string in IPv4 numbers-and-dots notation
* @param is_ipv4 a flag that indicates whether the string is an IPv4 or
* IPv6 address
*
* @return On success, the converted address is returned.
* @param cp a string in IPv4 numbers-and-dots notation or IPv6
* numbers-and-colons notation
*
* @param out an output buffer to store binary address
*
* @return On success, the function returns 0.
* If the input is invalid, -1 is returned
*/
int
os_socket_inet_network(const char *cp, uint32 *out);
os_socket_inet_network(bool is_ipv4, const char *cp,
bh_inet_network_output_t *out);
typedef struct {
uint8_t addr[16];

View File

@ -92,7 +92,7 @@ swap16(uint8 *pData)
*(pData + 1) = value;
}
static uint32
uint32
htonl(uint32 value)
{
uint32 ret;
@ -111,7 +111,7 @@ ntohl(uint32 value)
return htonl(value);
}
static uint16
uint16
htons(uint16 value)
{
uint16 ret;
@ -132,57 +132,96 @@ ntohs(uint16 value)
/* Coming from musl, under MIT license */
static int
__inet_aton(const char *s0, struct in_addr *dest)
hexval(unsigned c)
{
const char *s = s0;
unsigned char *d = (void *)dest;
unsigned long a[4] = { 0 };
char *z;
int i;
for (i = 0; i < 4; i++) {
a[i] = strtoul(s, &z, 0);
if (z == s || (*z && *z != '.') || !isdigit(*s))
return 0;
if (!*z)
break;
s = z + 1;
}
if (i == 4)
return 0;
switch (i) {
case 0:
a[1] = a[0] & 0xffffff;
a[0] >>= 24;
case 1:
a[2] = a[1] & 0xffff;
a[1] >>= 16;
case 2:
a[3] = a[2] & 0xff;
a[2] >>= 8;
}
for (i = 0; i < 4; i++) {
if (a[i] > 255)
return 0;
d[i] = a[i];
}
return 1;
if (c - '0' < 10)
return c - '0';
c |= 32;
if (c - 'a' < 6)
return c - 'a' + 10;
return -1;
}
/* Coming from musl, under MIT license */
static int
inet_addr(const char *p)
inet_pton(int af, const char *restrict s, void *restrict a0)
{
struct in_addr a;
if (!__inet_aton(p, &a))
uint16_t ip[8];
unsigned char *a = a0;
int i, j, v, d, brk = -1, need_v4 = 0;
if (af == AF_INET) {
for (i = 0; i < 4; i++) {
for (v = j = 0; j < 3 && isdigit(s[j]); j++)
v = 10 * v + s[j] - '0';
if (j == 0 || (j > 1 && s[0] == '0') || v > 255)
return 0;
a[i] = v;
if (s[j] == 0 && i == 3)
return 1;
if (s[j] != '.')
return 0;
s += j + 1;
}
return 0;
}
else if (af != AF_INET6) {
errno = EAFNOSUPPORT;
return -1;
return a.s_addr;
}
if (*s == ':' && *++s != ':')
return 0;
for (i = 0;; i++) {
if (s[0] == ':' && brk < 0) {
brk = i;
ip[i & 7] = 0;
if (!*++s)
break;
if (i == 7)
return 0;
continue;
}
for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++)
v = 16 * v + d;
if (j == 0)
return 0;
ip[i & 7] = v;
if (!s[j] && (brk >= 0 || i == 7))
break;
if (i == 7)
return 0;
if (s[j] != ':') {
if (s[j] != '.' || (i < 6 && brk < 0))
return 0;
need_v4 = 1;
i++;
break;
}
s += j + 1;
}
if (brk >= 0) {
memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk));
for (j = 0; j < 7 - i; j++)
ip[brk + j] = 0;
}
for (j = 0; j < 8; j++) {
*a++ = ip[j] >> 8;
*a++ = ip[j];
}
if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0)
return 0;
return 1;
}
static int
inet_network(const char *p)
inet_addr(const char *p)
{
return ntohl(inet_addr(p));
struct in_addr a;
if (!inet_pton(AF_INET, p, &a))
return -1;
return a.s_addr;
}
/** In-enclave implementation of POSIX functions end **/
@ -528,21 +567,30 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port)
}
int
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
{
int af;
if (!sock) {
return BHT_ERROR;
}
if (1 == tcp_or_udp) {
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
!= SGX_SUCCESS) {
if (is_ipv4) {
af = AF_INET;
}
else {
errno = ENOSYS;
return BHT_ERROR;
}
if (is_tcp) {
if (ocall_socket(sock, af, SOCK_STREAM, IPPROTO_TCP) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
}
else if (0 == tcp_or_udp) {
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
else {
if (ocall_socket(sock, af, SOCK_DGRAM, 0) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
return -1;
}
@ -557,12 +605,27 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
}
int
os_socket_inet_network(const char *cp, uint32 *out)
os_socket_inet_network(bool is_ipv4, const char *cp,
bh_inet_network_output_t *out)
{
if (!cp)
return BHT_ERROR;
*out = inet_network(cp);
if (is_ipv4) {
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
return BHT_ERROR;
}
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
out->ipv4 = ntohl(out->ipv4);
}
else {
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
return BHT_ERROR;
}
for (int i = 0; i < 8; i++) {
out->ipv6[i] = ntohs(out->ipv6[i]);
}
}
return BHT_OK;
}

View File

@ -47,6 +47,7 @@ extern "C" {
/* Address families. */
#define AF_INET 2 /* IP protocol family. */
#define AF_INET6 10 /* IP version 6. */
/* Standard well-defined IP protocols. */
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */
@ -98,6 +99,12 @@ struct sockaddr {
uint32_t
ntohl(uint32_t value);
uint32_t
htonl(uint32_t value);
uint16_t
htons(uint16_t value);
int
socket(int domain, int type, int protocol);

View File

@ -37,17 +37,27 @@ deinit_winsock()
}
int
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
{
int af;
if (!sock) {
return BHT_ERROR;
}
if (1 == tcp_or_udp) {
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (is_ipv4) {
af = AF_INET;
}
else if (0 == tcp_or_udp) {
*sock = socket(AF_INET, SOCK_DGRAM, 0);
else {
errno = ENOSYS;
return BHT_ERROR;
}
if (is_tcp) {
*sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
}
else {
*sock = socket(af, SOCK_DGRAM, 0);
}
return (*sock == -1) ? BHT_ERROR : BHT_OK;
@ -154,12 +164,28 @@ os_socket_shutdown(bh_socket_t socket)
}
int
os_socket_inet_network(const char *cp, uint32 *out)
os_socket_inet_network(bool is_ipv4, const char *cp,
bh_inet_network_output_t *out)
{
if (!cp)
return BHT_ERROR;
*out = inet_addr(cp);
if (is_ipv4) {
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
return BHT_ERROR;
}
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
out->ipv4 = ntohl(out->ipv4);
}
else {
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
return BHT_ERROR;
}
for (int i = 0; i < 8; i++) {
out->ipv6[i] = ntohs(out->ipv6[i]);
}
}
return BHT_OK;
}

View File

@ -2,6 +2,7 @@
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "tcp_utils.h"
#include <arpa/inet.h>
#include <netinet/in.h>
@ -14,28 +15,50 @@
#include <wasi_socket_ext.h>
#endif
static void
init_sockaddr_inet(struct sockaddr_in *addr)
{
/* 127.0.0.1:1234 */
addr->sin_family = AF_INET;
addr->sin_port = htons(1234);
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
static void
init_sockaddr_inet6(struct sockaddr_in6 *addr)
{
/* [::1]:1234 */
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(1234);
addr->sin6_addr = in6addr_loopback;
}
int
main(int argc, char *argv[])
{
int socket_fd, ret, total_size = 0;
int socket_fd, ret, total_size = 0, af;
char buffer[1024] = { 0 };
char ip_string[16] = { 0 };
struct sockaddr_in server_address = { 0 };
struct sockaddr_in local_address = { 0 };
char ip_string[64] = { 0 };
socklen_t len;
struct sockaddr_storage server_address = { 0 };
struct sockaddr_storage local_address = { 0 };
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
af = AF_INET6;
init_sockaddr_inet6((struct sockaddr_in6 *)&server_address);
}
else {
af = AF_INET;
init_sockaddr_inet((struct sockaddr_in *)&server_address);
}
printf("[Client] Create socket\n");
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd == -1) {
perror("Create socket failed");
return EXIT_FAILURE;
}
/* 127.0.0.1:1234 */
server_address.sin_family = AF_INET;
server_address.sin_port = htons(1234);
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("[Client] Connect socket\n");
if (connect(socket_fd, (struct sockaddr *)&server_address,
sizeof(server_address))
@ -53,11 +76,15 @@ main(int argc, char *argv[])
return EXIT_FAILURE;
}
inet_ntop(AF_INET, &local_address.sin_addr, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]));
if (sockaddr_to_string((struct sockaddr *)&local_address, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]))
!= 0) {
printf("[Client] failed to parse local address\n");
close(socket_fd);
return EXIT_FAILURE;
}
printf("[Client] Local address is: %s:%d\n", ip_string,
ntohs(local_address.sin_port));
printf("[Client] Local address is: %s\n", ip_string);
printf("[Client] Client receive\n");
while (1) {

View File

@ -2,6 +2,8 @@
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "tcp_utils.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
@ -41,28 +43,50 @@ run(void *arg)
return NULL;
}
static void
init_sockaddr_inet(struct sockaddr_in *addr)
{
/* 0.0.0.0:1234 */
addr->sin_family = AF_INET;
addr->sin_port = htons(1234);
addr->sin_addr.s_addr = htonl(INADDR_ANY);
}
static void
init_sockaddr_inet6(struct sockaddr_in6 *addr)
{
/* [::]:1234 */
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(1234);
addr->sin6_addr = in6addr_any;
}
int
main(int argc, char *argv[])
{
int socket_fd = -1, addrlen = 0;
struct sockaddr_in addr = { 0 };
int socket_fd = -1, addrlen = 0, af;
struct sockaddr_storage addr = { 0 };
unsigned connections = 0;
pthread_t workers[WORKER_NUM] = { 0 };
int client_sock_fds[WORKER_NUM] = { 0 };
char ip_string[16];
char ip_string[64];
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
af = AF_INET6;
init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
}
else {
af = AF_INET;
init_sockaddr_inet((struct sockaddr_in *)&addr);
}
printf("[Server] Create socket\n");
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd < 0) {
perror("Create socket failed");
goto fail;
}
/* 0.0.0.0:1234 */
addr.sin_family = AF_INET;
addr.sin_port = htons(1234);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("[Server] Bind socket\n");
addrlen = sizeof(addr);
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
@ -85,11 +109,14 @@ main(int argc, char *argv[])
break;
}
inet_ntop(AF_INET, &addr.sin_addr, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]));
if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]))
!= 0) {
printf("[Server] failed to parse client address\n");
goto fail;
}
printf("[Server] Client connected (%s:%d)\n", ip_string,
ntohs(addr.sin_port));
printf("[Server] Client connected (%s)\n", ip_string);
if (pthread_create(&workers[connections], NULL, run,
&client_sock_fds[connections])) {
perror("Create a worker thread failed");

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef TCP_UTILS_H
#define TCP_UTILS_H
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
int
sockaddr_to_string(struct sockaddr *addr, char *str, size_t len)
{
uint16_t port;
char ip_string[64];
void *addr_buf;
int ret;
switch (addr->sa_family) {
case AF_INET:
{
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
port = addr_in->sin_port;
addr_buf = &addr_in->sin_addr;
break;
}
case AF_INET6:
{
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
port = addr_in6->sin6_port;
addr_buf = &addr_in6->sin6_addr;
break;
}
default:
return -1;
}
inet_ntop(addr->sa_family, addr_buf, ip_string,
sizeof(ip_string) / sizeof(ip_string[0]));
ret = snprintf(str, len, "%s:%d", ip_string, ntohs(port));
return ret > 0 && (size_t)ret < len ? 0 : -1;
}
#endif /* TCP_UTILS_H */