diff options
Diffstat (limited to '')
-rw-r--r-- | libc-bottom-half/sources/getsockpeername.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/libc-bottom-half/sources/getsockpeername.c b/libc-bottom-half/sources/getsockpeername.c new file mode 100644 index 0000000..463c233 --- /dev/null +++ b/libc-bottom-half/sources/getsockpeername.c @@ -0,0 +1,229 @@ +#include <errno.h> +#include <netinet/in.h> + +#include <wasi/descriptor_table.h> +#include <wasi/sockets_utils.h> + +int tcp_getsockname(tcp_socket_t *socket, struct sockaddr *addr, + socklen_t *addrlen) +{ + output_sockaddr_t output_addr; + if (!__wasi_sockets_utils__output_addr_validate( + socket->family, addr, addrlen, &output_addr)) { + errno = EINVAL; + return -1; + } + + if (output_addr.tag == OUTPUT_SOCKADDR_NULL) { + errno = EINVAL; + return -1; + } + + switch (socket->state.tag) { + case TCP_SOCKET_STATE_UNBOUND: + errno = EINVAL; + return -1; + + case TCP_SOCKET_STATE_BOUND: + case TCP_SOCKET_STATE_CONNECTING: + case TCP_SOCKET_STATE_CONNECT_FAILED: + case TCP_SOCKET_STATE_LISTENING: + case TCP_SOCKET_STATE_CONNECTED: + // OK. Continue.. + break; + + default: /* unreachable */ + abort(); + } + + network_error_code_t error; + network_ip_socket_address_t result; + tcp_borrow_tcp_socket_t socket_borrow = + tcp_borrow_tcp_socket(socket->socket); + if (!tcp_method_tcp_socket_local_address(socket_borrow, &result, + &error)) { + errno = __wasi_sockets_utils__map_error(error); + return -1; + } + + __wasi_sockets_utils__output_addr_write(result, &output_addr); + + return 0; +} + +int tcp_getpeername(tcp_socket_t *socket, struct sockaddr *addr, + socklen_t *addrlen) +{ + output_sockaddr_t output_addr; + if (!__wasi_sockets_utils__output_addr_validate( + socket->family, addr, addrlen, &output_addr)) { + errno = EINVAL; + return -1; + } + + if (output_addr.tag == OUTPUT_SOCKADDR_NULL) { + errno = EINVAL; + return -1; + } + + switch (socket->state.tag) { + case TCP_SOCKET_STATE_UNBOUND: + case TCP_SOCKET_STATE_BOUND: + case TCP_SOCKET_STATE_CONNECTING: + case TCP_SOCKET_STATE_CONNECT_FAILED: + case TCP_SOCKET_STATE_LISTENING: + errno = ENOTCONN; + return -1; + + case TCP_SOCKET_STATE_CONNECTED: + // OK. Continue.. + break; + + default: /* unreachable */ + abort(); + } + + network_error_code_t error; + network_ip_socket_address_t result; + tcp_borrow_tcp_socket_t socket_borrow = + tcp_borrow_tcp_socket(socket->socket); + if (!tcp_method_tcp_socket_remote_address(socket_borrow, &result, + &error)) { + errno = __wasi_sockets_utils__map_error(error); + return -1; + } + + __wasi_sockets_utils__output_addr_write(result, &output_addr); + + return 0; +} + +int udp_getsockname(udp_socket_t *socket, struct sockaddr *addr, + socklen_t *addrlen) +{ + output_sockaddr_t output_addr; + if (!__wasi_sockets_utils__output_addr_validate( + socket->family, addr, addrlen, &output_addr)) { + errno = EINVAL; + return -1; + } + + if (output_addr.tag == OUTPUT_SOCKADDR_NULL) { + errno = EINVAL; + return -1; + } + + switch (socket->state.tag) { + case UDP_SOCKET_STATE_UNBOUND: + errno = EINVAL; + return -1; + + case UDP_SOCKET_STATE_BOUND_NOSTREAMS: + case UDP_SOCKET_STATE_BOUND_STREAMING: + case UDP_SOCKET_STATE_CONNECTED: + // OK. Continue.. + break; + + default: /* unreachable */ + abort(); + } + + network_error_code_t error; + network_ip_socket_address_t result; + udp_borrow_udp_socket_t socket_borrow = + udp_borrow_udp_socket(socket->socket); + if (!udp_method_udp_socket_local_address(socket_borrow, &result, + &error)) { + errno = __wasi_sockets_utils__map_error(error); + return -1; + } + + __wasi_sockets_utils__output_addr_write(result, &output_addr); + + return 0; +} + +int udp_getpeername(udp_socket_t *socket, struct sockaddr *addr, + socklen_t *addrlen) +{ + output_sockaddr_t output_addr; + if (!__wasi_sockets_utils__output_addr_validate( + socket->family, addr, addrlen, &output_addr)) { + errno = EINVAL; + return -1; + } + + if (output_addr.tag == OUTPUT_SOCKADDR_NULL) { + errno = EINVAL; + return -1; + } + + switch (socket->state.tag) { + case UDP_SOCKET_STATE_UNBOUND: + case UDP_SOCKET_STATE_BOUND_NOSTREAMS: + case UDP_SOCKET_STATE_BOUND_STREAMING: + errno = ENOTCONN; + return -1; + + case UDP_SOCKET_STATE_CONNECTED: + // OK. Continue.. + break; + + default: /* unreachable */ + abort(); + } + + network_error_code_t error; + network_ip_socket_address_t result; + udp_borrow_udp_socket_t socket_borrow = + udp_borrow_udp_socket(socket->socket); + if (!udp_method_udp_socket_remote_address(socket_borrow, &result, + &error)) { + errno = __wasi_sockets_utils__map_error(error); + return -1; + } + + __wasi_sockets_utils__output_addr_write(result, &output_addr); + + return 0; +} + +int getsockname(int socket, struct sockaddr *__restrict addr, + socklen_t *__restrict addrlen) +{ + descriptor_table_entry_t *entry; + if (!descriptor_table_get_ref(socket, &entry)) { + errno = EBADF; + return -1; + } + + switch (entry->tag) { + case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET: + return tcp_getsockname(&entry->tcp_socket, addr, addrlen); + case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET: + return udp_getsockname(&entry->udp_socket, addr, addrlen); + default: + errno = EOPNOTSUPP; + return -1; + } +} + +int getpeername(int socket, struct sockaddr *__restrict addr, + socklen_t *__restrict addrlen) +{ + descriptor_table_entry_t *entry; + if (!descriptor_table_get_ref(socket, &entry)) { + errno = EBADF; + return -1; + } + + switch (entry->tag) { + case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET: + return tcp_getpeername(&entry->tcp_socket, addr, addrlen); + case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET: + return udp_getpeername(&entry->udp_socket, addr, addrlen); + default: + errno = EOPNOTSUPP; + return -1; + } +} |