[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [UNIKRAFT PATCH 1/3] lib/posix-socket: Introduce abstraction for communication sockets
From: Alexander Jung <alexander.jung@xxxxxxxxx> This initial commit introduces a microlibrary to manage multiple implementations of POSIX compliant sockets. By exposing global prototypes as an abstraction, the microlibrary can interchange between AF socket families. For example, an implementation for AF_INET can register against this microlibrary in order to communicate over the IP/TCP stack. Signed-off-by: Alexander Jung <alexander.jung@xxxxxxxxx> --- lib/posix-socket/Config.uk | 18 + lib/posix-socket/Makefile.uk | 10 + lib/posix-socket/driver.c | 154 +++ lib/posix-socket/exportsyms.uk | 26 + lib/posix-socket/extra.ld | 9 + lib/posix-socket/include/uk/socket.h | 45 + lib/posix-socket/include/uk/socket_driver.h | 1018 +++++++++++++++++++ lib/posix-socket/include/uk/socket_vnops.h | 97 ++ lib/posix-socket/socket.c | 722 +++++++++++++ lib/posix-socket/socket_vnops.c | 323 ++++++ 10 files changed, 2422 insertions(+) create mode 100644 lib/posix-socket/Config.uk create mode 100644 lib/posix-socket/Makefile.uk create mode 100644 lib/posix-socket/driver.c create mode 100644 lib/posix-socket/exportsyms.uk create mode 100644 lib/posix-socket/extra.ld create mode 100644 lib/posix-socket/include/uk/socket.h create mode 100644 lib/posix-socket/include/uk/socket_driver.h create mode 100644 lib/posix-socket/include/uk/socket_vnops.h create mode 100644 lib/posix-socket/socket.c create mode 100644 lib/posix-socket/socket_vnops.c diff --git a/lib/posix-socket/Config.uk b/lib/posix-socket/Config.uk new file mode 100644 index 0000000..bf99f17 --- /dev/null +++ b/lib/posix-socket/Config.uk @@ -0,0 +1,18 @@ +menuconfig LIBPOSIX_SOCKET + bool "posix-socket: Abstraction for communication sockets" + default n + select LIBUKDEBUG + select LIBUKALLOC + select LIBFDTABLE + help + This microlibrary allows other microlibraries to register a socket family + number, such as AF_INET, for their socket implementation and provides the + POSIX socket API unikernel-wide and acts appropriately on a given file + descriptor. + + The API includes prototypes for socket(), accept(), bind(), shutdown(), + connect(), listen(), send(), sendmsg(), sendto(), recv(), recvfrom(), + recvmsg(), getpeername(), getsockname(), getsockopt() and setsockopt(). + +if LIBPOSIX_SOCKET +endif diff --git a/lib/posix-socket/Makefile.uk b/lib/posix-socket/Makefile.uk new file mode 100644 index 0000000..a9beee0 --- /dev/null +++ b/lib/posix-socket/Makefile.uk @@ -0,0 +1,10 @@ +$(eval $(call addlib_s,libposix_socket,$(CONFIG_LIBPOSIX_SOCKET))) + +LIBPOSIX_SOCKET_COMMON_INCLUDES-y += -I$(LIBPOSIX_SOCKET_BASE)/include + +CINCLUDES-$(CONFIG_LIBPOSIX_SOCKET) += $(LIBPOSIX_SOCKET_COMMON_INCLUDES-y) +CXXINCLUDES-$(CONFIG_LIBPOSIX_SOCKET) += $(LIBPOSIX_SOCKET_COMMON_INCLUDES-y) + +LIBPOSIX_SOCKET_SRCS-$(CONFIG_LIBPOSIX_SOCKET) += $(LIBPOSIX_SOCKET_BASE)/driver.c +LIBPOSIX_SOCKET_SRCS-$(CONFIG_LIBPOSIX_SOCKET) += $(LIBPOSIX_SOCKET_BASE)/socket_vnops.c +LIBPOSIX_SOCKET_SRCS-$(CONFIG_LIBPOSIX_SOCKET) += $(LIBPOSIX_SOCKET_BASE)/socket.c diff --git a/lib/posix-socket/driver.c b/lib/posix-socket/driver.c new file mode 100644 index 0000000..ad01241 --- /dev/null +++ b/lib/posix-socket/driver.c @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR SOCKETINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <inttypes.h> +#include <uk/alloc.h> +#include <uk/assert.h> +#include <uk/print.h> +#include <uk/list.h> +#include <uk/socket_driver.h> +#include <sys/types.h> + +/** + * List of socket family drivers + */ +UK_TAILQ_HEAD(posix_socket_driver_list, struct posix_socket_driver); +struct posix_socket_driver_list posix_socket_families = + UK_TAILQ_HEAD_INITIALIZER(posix_socket_families); +static uint16_t uk_posix_socket_family_count; + +unsigned int +posix_socket_family_count(void) +{ + return uk_posix_socket_family_count; +} + +void _posix_socket_family_register(struct posix_socket_driver *d, + int fam, + struct posix_socket_ops *ops, + struct uk_alloc *alloc) +{ + UK_ASSERT(d); + UK_ASSERT(ops); + + if (unlikely(fam == 0)) { + uk_pr_crit("Cannot register unspecified socket family: %p\n", ops); + return; + } + + uk_pr_debug("Registering socket handler: library: %s, family: %d: %p...\n", d->libname, fam, ops); + + struct posix_socket_driver *e; + UK_TAILQ_FOREACH(e, &posix_socket_families, _list) { + if (e->af_family == fam) { + uk_pr_warn("Socket family (%d) already registerd to library %s!", fam, e->libname); + return; + } + } + + new_posix_socket_family(d, fam, alloc, ops); + UK_TAILQ_INSERT_TAIL(&posix_socket_families, d, _list); + uk_posix_socket_family_count++; +} + +void +_posix_socket_family_unregister(struct posix_socket_driver *d) +{ + UK_ASSERT(d); + UK_ASSERT(uk_posix_socket_family_count > 0); + + uk_pr_debug("Unregistering socket handler: %d\n", d->af_family); + + UK_TAILQ_REMOVE(&posix_socket_families, d, _list); + uk_posix_socket_family_count--; +} + +static int +posix_socket_family_init(struct posix_socket_driver *d) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops); + + uk_pr_debug("Initializing socket handler: %d\n", d->af_family); + + /* Assign the default allocator if not specified */ + if (d->allocator == NULL) { + d->allocator = uk_alloc_get_default(); + uk_pr_debug("Using default memory allocator for socket family: %d: %p\n", d->af_family, d->allocator); + } + + if (!d->ops->init) + return 0; + + return d->ops->init(d); +} + +/* Returns the number of successfully initialized device sockets */ +static int +posix_socket_family_lib_init(void) +{ + uk_pr_info("Initializing socket handlers...\n"); + + struct posix_socket_driver *d; + unsigned int ret = 0; + + if (posix_socket_family_count() == 0) + return 0; + + UK_TAILQ_FOREACH(d, &posix_socket_families, _list) { + if (posix_socket_family_init(d) >= 0) + ++ret; + } + + return ret; +} + +struct posix_socket_driver * +posix_socket_driver_get(int af_family) +{ + struct posix_socket_driver *d; + + UK_TAILQ_FOREACH(d, &posix_socket_families, _list) { + if (d->af_family == af_family) + return d; + } + + return NULL; +} + +struct posix_socket_driver * +posix_socket_get_family(int sock) +{ + return NULL; +} + +uk_initcall_class_prio(posix_socket_family_lib_init, POSIX_SOCKET_FAMILY_INIT_CLASS, POSIX_SOCKET_FAMILY_INIT_PRIO); diff --git a/lib/posix-socket/exportsyms.uk b/lib/posix-socket/exportsyms.uk new file mode 100644 index 0000000..f2e2f37 --- /dev/null +++ b/lib/posix-socket/exportsyms.uk @@ -0,0 +1,26 @@ +posix_socket +posix_socket_get_family +posix_socket_family_count +_posix_socket_family_register +_posix_socket_family_unregister +socket_alloc_fd + +# Full socket API +socket +accept +bind +shutdown +getpeername +getsockname +getnameinfo +getsockopt +setsockopt +connect +listen +recv +recvfrom +recvmsg +send +sendmsg +sendto +socketpair diff --git a/lib/posix-socket/extra.ld b/lib/posix-socket/extra.ld new file mode 100644 index 0000000..78346f1 --- /dev/null +++ b/lib/posix-socket/extra.ld @@ -0,0 +1,9 @@ +SECTIONS +{ + .posix_socket_driver_list : { + PROVIDE(posix_socket_driver_list_start = .); + KEEP (*(.posix_socket_driver_list)) + PROVIDE(posix_socket_driver_list_end = .); + } +} +INSERT AFTER .text; diff --git a/lib/posix-socket/include/uk/socket.h b/lib/posix-socket/include/uk/socket.h new file mode 100644 index 0000000..9cd420a --- /dev/null +++ b/lib/posix-socket/include/uk/socket.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __UK_SOCKET__ +#define __UK_SOCKET__ + +#include <uk/socket_driver.h> +#include <uk/socket_vnops.h> + +#define SOCKET_LIB_ERR(d, errno, msg) \ + uk_pr_err("%s_err: %d: %s", d->libname, errno, msg) + +#define SOCKET_ERR(errno, msg) \ + uk_pr_err("%d: %s", errno, msg) + +#endif /* __UK_SOCKET__ */ diff --git a/lib/posix-socket/include/uk/socket_driver.h b/lib/posix-socket/include/uk/socket_driver.h new file mode 100644 index 0000000..2a9226f --- /dev/null +++ b/lib/posix-socket/include/uk/socket_driver.h @@ -0,0 +1,1018 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __UK_SOCKET_DRIVER_H__ +#define __UK_SOCKET_DRIVER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <uk/list.h> +#include <uk/assert.h> +#include <uk/init.h> +#include <uk/list.h> +#include <uk/ctors.h> +#include <uk/alloc.h> +#include <uk/essentials.h> +#include <errno.h> +#include <sys/socket.h> + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define __NEED_socklen_t +#include <bits/alltypes.h> +#endif + +#define POSIX_SOCKET_FAMILY_INIT_CLASS UK_INIT_CLASS_EARLY +#define POSIX_SOCKET_FAMILY_INIT_PRIO 0 +#define POSIX_SOCKET_FAMILY_REGISTER_PRIO 2 + +struct posix_socket_ops; +struct posix_socket_driver; + +/** + * The POSIX socket driver defines the operations to be used for the + * specified AF family as well as the memory allocator. + */ +struct posix_socket_driver { + /* The AF family ID */ + const int af_family; + const char *libname; + /* The interfaces for this socket */ + const struct posix_socket_ops *ops; + /* The memory allocator to be used for this socket driver */ + struct uk_alloc *allocator; + /* Private data for this socket driver. */ + void *private; + /* Entry for list of socket drivers. */ + UK_TAILQ_ENTRY(struct posix_socket_driver) _list; +}; + + +/** + * The initialization function called for this socket family. It's here that + * additional configuration for the driver can be made after it has been + * registered. For instance, an alternative memory allocator can be provided. + * + * @param d + * The socket driver. + */ +typedef int (*posix_socket_driver_init_func_t)(struct posix_socket_driver *d); + +/** + * Create a connection on a socket. + * + * @param driver + * The socket driver. + * @param family + * Specifies a communication family domain and thus driver. + * @param type + * Specifies communication semantics. + * @param protocol + * Specifies a particular protocol to be used with the socket. + */ +typedef void *(*posix_socket_create_func_t)(struct posix_socket_driver *d, + int family, int type, int protocol); + + +/** + * Accept a connection on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The address of the peer socket. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef void *(*posix_socket_accept_func_t)(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len); + + +/** + * Bind a name to a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The assigned address. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef int (*posix_socket_bind_func_t)(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len); + + +/** + * Shut down part of a full-duplex connection. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param how + * The flag to specify the means of shuting down the socket. + */ +typedef int (*posix_socket_shutdown_func_t)(struct posix_socket_driver *d, + void *sock, int how); + + +/** + * Get name of connected peer socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The assigned address. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef int (*posix_socket_getpeername_func_t)(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len); + + +/** + * Get socket name. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The assigned address. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef int (*posix_socket_getsockname_func_t)(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len); + +/** + * Get socket name. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The assigned address. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef int (*posix_socket_getnameinfo_func_t)(struct posix_socket_driver *d, + const struct sockaddr *restrict sa, socklen_t sl, char *restrict node, + socklen_t nodelen, char *restrict serv, socklen_t servlen, int flags); + +/** + * Get options on the socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param level + * Maniipulate the socket at either the API level or protocol level. + * @param optname + * Any specified options are passed uninterpreted to the appropriate protocol + * module for interpretation. + * @param optval + * The option value. + * @param optlen + * The option value length. + */ +typedef int (*posix_socket_getsockopt_func_t)(struct posix_socket_driver *d, + void *sock, int level, int optname, void *restrict optval, + socklen_t *restrict optlen); + + +/** + * Set options on the socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param level + * Maniipulate the socket at either the API level or protocol level. + * @param optname + * Any specified options are passed uninterpreted to the appropriate protocol + * module for interpretation. + * @param optval + * The option value. + * @param optlen + * The option value length. + */ +typedef int (*posix_socket_setsockopt_func_t)(struct posix_socket_driver *d, + void *sock, int level, int optname, const void *optval, + socklen_t optlen); + + +/** + * Initiate a connection on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param addr + * The address to connect to on the socket. + * @param addr_len + * Specifies the size, in bytes, of the address structure pointed to by addr. + */ +typedef int (*posix_socket_connect_func_t)(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len); + + +/** + * Listen for connections on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param backlog + * Defines the maximum length to which the queue of pending connections for + * the socket. + */ +typedef int (*posix_socket_listen_func_t)(struct posix_socket_driver *d, + void *sock, int backlog); + + +/** + * Receive a message from a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param buf + * The buffer for recieved data from the socket. + * @param len + * The size of the buffer. + * @param flags + * Bitwise OR of zero or more flags for the socket. + */ +typedef ssize_t (*posix_socket_recv_func_t)(struct posix_socket_driver *d, + void *sock, void *buf, size_t len, int flags); + + +/** + * Read from a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param buf + * The buffer for recieved data from the socket. + * @param len + * The size of the buffer. + * @param flags + * Bitmap of options for receiving a message. + * @param from + * The source address. + * @param fromlen + * The source address length. + */ +typedef ssize_t (*posix_socket_recvfrom_func_t)(struct posix_socket_driver *d, + void *sock, void *restrict buf, size_t len, int flags, + struct sockaddr *from, socklen_t *restrict fromlen); + + +/** + * Read from a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param msg + * Message structure to minimize the number of directly supplied arguments. + * @param flags + * Bitwise OR of zero or more flags for the socket. + */ +typedef ssize_t (*posix_socket_recvmsg_func_t)(struct posix_socket_driver *d, + void *sock, struct msghdr *msg, int flags); + + +/** + * Send a message on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param buf + * The buffer for sending data to the socket. + * @param len + * The length of the data to send on the socket. + * @param flags + * Bitwise OR of zero or more flags for the socket. + */ +typedef ssize_t (*posix_socket_send_func_t)(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags); + + +/** + * Send a message on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param msg + * Message structure to minimize the number of directly supplied arguments. + * @param flags + * Bitwise OR of zero or more flags for the socket. + */ +typedef ssize_t (*posix_socket_sendmsg_func_t)(struct posix_socket_driver *d, + void *sock, const struct msghdr *msg, int flags); + + +/** + * Send a message on a socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + * @param buf + * The buffer for sending data to the socket. + * @param len + * The length of the data to send on the socket. + * @param flags + * Bitwise OR of zero or more flags for the socket. + * @param dest_addr + * The destination address to send data. + * @param addrlen + * The length of the address to send data to. + */ +typedef ssize_t (*posix_socket_sendto_func_t)(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + + +/** + * Create a pair of connected sockets. + * + * @param driver + * The socket driver. + * @param family + * The domain of the sockets. + * @param type + * The specified type of the sockets. + * @param protocol + * Optionally the protocol. + * @param usockvec + * The structure used in referencing the new sockets are returned in + * usockvec[0] and usockvec[1]. + */ +typedef int (*posix_socket_socketpair_func_t)(struct posix_socket_driver *d, + int family, int type, int protocol, void **usockvec); + + +/** + * Read from a socket file descriptor. + * + * @param driver + * The socket driver. + * @param buf + * The buffer to read the data from the socket into. + * @param count + * The number of bytes to be read. + */ +typedef int (*posix_socket_read_func_t)(struct posix_socket_driver *d, + void *sock, void *buf, size_t count); + + +/** + * Write to a socket file descriptor. + * + * @param driver + * The socket driver. + * @param buf + * The pointer to the buffer to write to the socket. + * @param count + * The number of bytes to be written. + */ +typedef int (*posix_socket_write_func_t)(struct posix_socket_driver *d, + void *sock, const void *buf, size_t count); + +/** + * Close the socket. + * + * @param driver + * The socket driver. + * @param sock + * Reference to the socket. + */ +typedef int (*posix_socket_close_func_t)(struct posix_socket_driver *d, + void *sock); + + +/** + * Manipulate the socket. + * + * @param driver + * The socket driver. + * @TODO + */ +typedef int (*posix_socket_ioctl_func_t)(struct posix_socket_driver *d, + void *sock, int request, void *argp); + + +/** + * A structure containing the functions exported by the Unikraft socket driver + */ +struct posix_socket_ops { + /* The initialization function on socket registration. */ + posix_socket_driver_init_func_t init; + /* POSIX interfaces */ + posix_socket_create_func_t create; + posix_socket_accept_func_t accept; + posix_socket_bind_func_t bind; + posix_socket_shutdown_func_t shutdown; + posix_socket_getpeername_func_t getpeername; + posix_socket_getsockname_func_t getsockname; + posix_socket_getnameinfo_func_t getnameinfo; + posix_socket_getsockopt_func_t getsockopt; + posix_socket_setsockopt_func_t setsockopt; + posix_socket_connect_func_t connect; + posix_socket_listen_func_t listen; + posix_socket_recv_func_t recv; + posix_socket_recvfrom_func_t recvfrom; + posix_socket_recvmsg_func_t recvmsg; + posix_socket_send_func_t send; + posix_socket_sendmsg_func_t sendmsg; + posix_socket_sendto_func_t sendto; + posix_socket_socketpair_func_t socketpair; + /* vfscore ops */ + posix_socket_read_func_t read; + posix_socket_write_func_t write; + posix_socket_close_func_t close; + posix_socket_ioctl_func_t ioctl; +}; + +static inline void * +posix_socket_do_create(struct posix_socket_driver *d, + int family, int type, int protocol) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->create); + return d->ops->create(d, family, type, protocol); +} + +static inline void * +posix_socket_create(struct posix_socket_driver *d, + int family, int type, int protocol) +{ + if (unlikely(!d)) + return NULL; + + return posix_socket_do_create(d, family, type, protocol); +} + +static inline void * +posix_socket_do_accept(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->accept); + return d->ops->accept(d, sock, addr, addr_len); +} + +static inline void * +posix_socket_accept(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + if (unlikely(!d)) + return NULL; + + return posix_socket_do_accept(d, sock, addr, addr_len); +} + + +static inline int +posix_socket_do_bind(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->bind); + return d->ops->bind(d, sock, addr, addr_len); +} + +static inline int +posix_socket_bind(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_bind(d, sock, addr, addr_len); +} + + +static inline int +posix_socket_do_shutdown(struct posix_socket_driver *d, + void *sock, int how) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->shutdown); + return d->ops->shutdown(d, sock, how); +} + +static inline int +posix_socket_shutdown(struct posix_socket_driver *d, + void *sock, int how) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_shutdown(d, sock, how); +} + + +static inline int +posix_socket_do_getpeername(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->getpeername); + return d->ops->getpeername(d, sock, addr, addr_len); +} + +static inline int +posix_socket_getpeername(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_getpeername(d, sock, addr, addr_len); +} + + +static inline int +posix_socket_do_getsockname(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->getsockname); + return d->ops->getsockname(d, sock, addr, addr_len); +} + +static inline int +posix_socket_getsockname(struct posix_socket_driver *d, + void *sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_getsockname(d, sock, addr, addr_len); +} + + +static inline int +posix_socket_do_getnameinfo(struct posix_socket_driver *d, + const struct sockaddr *restrict sa, socklen_t sl, char *restrict node, + socklen_t nodelen, char *restrict serv, socklen_t servlen, int flags) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->getnameinfo); + return d->ops->getnameinfo(d, sa, sl, node, nodelen, serv, servlen, flags); +} + +static inline int +posix_socket_getnameinfo(struct posix_socket_driver *d, + const struct sockaddr *restrict sa, socklen_t sl, char *restrict node, + socklen_t nodelen, char *restrict serv, socklen_t servlen, int flags) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_getnameinfo(d, sa, sl, node, nodelen, serv, servlen, + flags); +} + + +static inline int +posix_socket_do_getsockopt(struct posix_socket_driver *d, + void *sock, int level, int optname, void *restrict optval, + socklen_t *restrict optlen) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->getsockopt); + return d->ops->getsockopt(d, sock, level, optname, optval, optlen); +} + +static inline int +posix_socket_getsockopt(struct posix_socket_driver *d, + void *sock, int level, int optname, void *restrict optval, + socklen_t *restrict optlen) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_getsockopt(d, sock, level, optname, optval, optlen); +} + + +static inline int + +posix_socket_do_setsockopt(struct posix_socket_driver *d, + void *sock, int level, int optname, const void *optval, + socklen_t optlen) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->setsockopt); + return d->ops->setsockopt(d, sock, level, optname, optval, optlen); +} + +static inline int +posix_socket_setsockopt(struct posix_socket_driver *d, + void *sock, int level, int optname, const void *optval, + socklen_t optlen) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_setsockopt(d, sock, level, optname, optval, optlen); +} + + +static inline int +posix_socket_do_connect(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->connect); + return d->ops->connect(d, sock, addr, addr_len); +} + +static inline int +posix_socket_connect(struct posix_socket_driver *d, + void *sock, const struct sockaddr *addr, socklen_t addr_len) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_connect(d, sock, addr, addr_len); +} + + +static inline int +posix_socket_do_listen(struct posix_socket_driver *d, + void *sock, int backlog) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->listen); + return d->ops->listen(d, sock, backlog); +} + +static inline int +posix_socket_listen(struct posix_socket_driver *d, + void *sock, int backlog) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_listen(d, sock, backlog); +} + + +static inline ssize_t +posix_socket_do_recv(struct posix_socket_driver *d, + void *sock, void *buf, size_t len, int flags) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->recv); + return d->ops->recv(d, sock, buf, len, flags); +} + +static inline ssize_t +posix_socket_recv(struct posix_socket_driver *d, + void *sock, void *buf, size_t len, int flags) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_recv(d, sock, buf, len, flags); +} + + +static inline ssize_t +posix_socket_do_recvfrom(struct posix_socket_driver *d, + void *sock, void *buf, size_t len, int flags, struct sockaddr *from, + socklen_t *fromlen) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->recvfrom); + return d->ops->recvfrom(d, sock, buf, len, flags, from, fromlen); +} + +static inline ssize_t +posix_socket_recvfrom(struct posix_socket_driver *d, + void *sock, void *restrict buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_recvfrom(d, sock, buf, len, flags, from, fromlen); +} + + +static inline ssize_t +posix_socket_do_recvmsg(struct posix_socket_driver *d, + void *sock, struct msghdr *msg, int flags) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->recvmsg); + return d->ops->recvmsg(d, sock, msg, flags); +} + +static inline ssize_t +posix_socket_recvmsg(struct posix_socket_driver *d, + void *sock, struct msghdr *msg, int flags) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_recvmsg(d, sock, msg, flags); +} + + +static inline ssize_t +posix_socket_do_send(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->send); + return d->ops->send(d, sock, buf, len, flags); +} + +static inline ssize_t +posix_socket_send(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_send(d, sock, buf, len, flags); +} + + +static inline ssize_t +posix_socket_do_sendmsg(struct posix_socket_driver *d, + void *sock, const struct msghdr *msg, int flags) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->sendmsg); + return d->ops->sendmsg(d, sock, msg, flags); +} + +static inline ssize_t +posix_socket_sendmsg(struct posix_socket_driver *d, + void *sock, const struct msghdr *msg, int flags) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_sendmsg(d, sock, msg, flags); +} + + +static inline ssize_t +posix_socket_do_sendto(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->sendto); + return d->ops->sendto(d, sock, buf, len, flags, dest_addr, addrlen); +} + +static inline ssize_t +posix_socket_sendto(struct posix_socket_driver *d, + void *sock, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_sendto(d, sock, buf, len, flags, dest_addr, addrlen); +} + + +static inline int +posix_socket_do_socketpair(struct posix_socket_driver *d, + int family, int type, int protocol, void **usockvec) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->socketpair); + return d->ops->socketpair(d, family, type, protocol, usockvec); +} + +static inline int +posix_socket_socketpair(struct posix_socket_driver *d, + int family, int type, int protocol, void **usockvec) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_socketpair(d, family, type, protocol, usockvec); +} + + +static inline int +posix_socket_do_read(struct posix_socket_driver *d, + void *sock, void *buf, size_t count) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->read); + return d->ops->read(d, sock, buf, count); +} + +static inline int +posix_socket_read(struct posix_socket_driver *d, + void *sock, void *buf, size_t count) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_read(d, sock, buf, count); +} + + +static inline int +posix_socket_do_write(struct posix_socket_driver *d, + void *sock, const void *buf, size_t count) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->write); + return d->ops->write(d, sock, buf, count); +} + +static inline int +posix_socket_write(struct posix_socket_driver *d, + void *sock, const void *buf, size_t count) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_write(d, sock, buf, count); +} + + +static inline int +posix_socket_do_close(struct posix_socket_driver *d, + void *sock) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->close); + return d->ops->close(d, sock); +} + +static inline int +posix_socket_close(struct posix_socket_driver *d, + void *sock) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_close(d, sock); +} + + +static inline int +posix_socket_do_ioctl(struct posix_socket_driver *d, + void *sock, int request, void *argp) +{ + UK_ASSERT(d); + UK_ASSERT(d->ops->ioctl); + return d->ops->ioctl(d, sock, request, argp); +} + +static inline int +posix_socket_ioctl(struct posix_socket_driver *d, + void *sock, int request, void *argp) +{ + if (unlikely(!d)) + return -ENOSYS; + + return posix_socket_do_ioctl(d, sock, request, argp); +} + +/** + * Return the driver to the corresponding AF family number + * + * @param af_family + * Af family number + */ +struct posix_socket_driver * +posix_socket_driver_get(int af_family); + +/** + * Shortcut for doing a registration a socket to an AF number. + */ +#define new_posix_socket_family(d, fam, alloc, ops) \ + do { \ + (d)->allocator = (alloc); \ + (d)->ops = (ops); \ + } while(0) + +/** + * Returns the number of registered sockets. + */ +unsigned int +posix_socket_family_count(void); + +/* Do not use this function directly */ +void +_posix_socket_family_register(struct posix_socket_driver *d, + int fam, + struct posix_socket_ops *ops, + struct uk_alloc *alloc); + +/** + * Registers a socket family driver to the socket system. + */ +#define _POSIX_SOCKET_FAMILY_REGISTER_CTOR(fam, ctor) \ + UK_CTOR_PRIO(ctor, POSIX_SOCKET_FAMILY_REGISTER_PRIO) + +#define _POSIX_SOCKET_FAMILY_REGFNNAME(x, y) x##_posix_socket_af_##y##_register +#define _POSIX_SOCKET_FAMILY_DRVRNAME(x, y) x##_posix_socket_af_##y + +/* + * Creates a static struct posix_socket_driver with a unique name for the AF + * family which can later be referenced. + */ +#define _POSIX_SOCKET_FAMILY_REGISTER(lib, fam, ops, alloc) \ + static struct posix_socket_driver _POSIX_SOCKET_FAMILY_DRVRNAME(lib, fam) = { \ + .af_family = fam, \ + .libname = STRINGIFY(lib) \ + }; \ + static void \ + _POSIX_SOCKET_FAMILY_REGFNNAME(lib, fam)(void) \ + { \ + _posix_socket_family_register(&_POSIX_SOCKET_FAMILY_DRVRNAME(lib, fam), \ + fam, ops, alloc); \ + } \ + _POSIX_SOCKET_FAMILY_REGISTER_CTOR(fam, _POSIX_SOCKET_FAMILY_REGFNNAME(lib, fam)) + +#define POSIX_SOCKET_FAMILY_REGISTER(fam, ops, alloc) \ + _POSIX_SOCKET_FAMILY_REGISTER(__LIBNAME__, fam, ops, alloc) + +/* Do not use this function directly: */ +void +_posix_socket_family_unregister(struct posix_socket_driver *driver); + +#ifdef __cplusplus +} + +#endif /* __cplusplus */ +#endif /* __UK_SOCKET_DRIVER_H__ */ \ No newline at end of file diff --git a/lib/posix-socket/include/uk/socket_vnops.h b/lib/posix-socket/include/uk/socket_vnops.h new file mode 100644 index 0000000..243622a --- /dev/null +++ b/lib/posix-socket/include/uk/socket_vnops.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __UK_SOCKET_VNOPS__ +#define __UK_SOCKET_VNOPS__ + +#include <vfscore/file.h> +#include <vfscore/vnode.h> + +struct posix_socket_driver; + +#define POSIX_SOCKET_SET_ERRNO(errcode) \ + (errno = -(errcode)) + +#define SOCKFILE_DATA_AS_INT(data) \ + *((int *) data) + +struct posix_socket_file { + /* The fd or data used internaly by the socket implementation. */ + void *sock_data; + /* Internal reference to the vfscore_file when not geenerally available. */ + struct vfscore_file *vfs_file; + /* The driver to use for this socket. */ + struct posix_socket_driver *driver; +}; + +int +posix_socket_vfscore_close(struct vnode *s_vnode, + struct vfscore_file *vfscore_file); + +int +posix_socket_vfscore_read(struct vnode *s_vnode, + struct vfscore_file *vfscore_file __unused, + struct uio *buf, int ioflag __unused); +int +posix_socket_vfscore_write(struct vnode *s_vnode, + struct uio *buf, int ioflag __unused); +int +posix_socket_vfscore_ioctl(struct vnode *s_vnode, + struct vfscore_file *vfscore_file __unused, + unsigned long request, + void *buf); + +/** + * + */ +struct posix_socket_file * +posix_socket_file_get(int sock_fd); + +/** + * + */ +struct posix_socket_driver * +posix_socket_get_family(int sock_fd); + +/** + * Allocate a file descriptor in vfscore for the given socket driver. + * + * @param d + * The driver used to create the socket. + * @param sock_data + * The socket implementation's private data. + */ +int +socket_alloc_fd(struct posix_socket_driver *d, void *sock_data); + +#endif /* __UK_SOCKET_VNOPS__ */ diff --git a/lib/posix-socket/socket.c b/lib/posix-socket/socket.c new file mode 100644 index 0000000..9634e29 --- /dev/null +++ b/lib/posix-socket/socket.c @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <uk/socket.h> +#include <uk/errptr.h> +#include <uk/print.h> +#include <uk/trace.h> +#include <errno.h> + +UK_TRACEPOINT(trace_posix_socket_create, "%d %d %d", int, int, int); +UK_TRACEPOINT(trace_posix_socket_create_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_create_err, "%d", int); + +int +socket(int family, int type, int protocol) +{ + int ret = 0; + int vfs_fd = 0xff; + void *sock = NULL; + struct posix_socket_driver *d; + + trace_posix_socket_create(family, type, protocol); + + d = posix_socket_driver_get(family); + if (d == NULL) { + uk_pr_crit("no socket implementation for family: %d\n", family); + ret = -ENOSYS; + goto EXIT_ERR; + } + + /* Create the socket using the driver */ + sock = posix_socket_create(d, family, type, protocol); + if (sock == NULL) { + uk_pr_debug("failed to create socket %d\n", errno); + ret = -1; + goto EXIT_ERR; + } + + /* Allocate the file descriptor */ + vfs_fd = socket_alloc_fd(d, sock); + if (vfs_fd < 0) { + uk_pr_debug("failed to allocate descriptor %d\n", errno); + ret = -1; + POSIX_SOCKET_SET_ERRNO(vfs_fd); + goto SOCKET_CLEANUP; + } + + /* Returning the file descriptor to the user */ + ret = vfs_fd; + +EXIT: + trace_posix_socket_create_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_create_err(ret); + return ret; +SOCKET_CLEANUP: + posix_socket_close(d, sock); + goto EXIT; +} + +UK_TRACEPOINT(trace_posix_socket_accept, "%d %p %p", int, + struct sockaddr *restrict, socklen_t *restrict); +UK_TRACEPOINT(trace_posix_socket_accept_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_accept_err, "%d", int); + +int accept(int sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + int vfs_fd; + int ret = 0; + void *new_sock; + struct posix_socket_file *file; + + trace_posix_socket_accept(sock, addr, addr_len); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to retrieve socket file descriptor: %p\n", file); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + + /* Accept an incoming connection */ + new_sock = posix_socket_accept(file->driver, file->sock_data, addr, addr_len); + if (new_sock == NULL) { + uk_pr_debug("failed to accept incoming connection\n"); + ret = -1; + goto EXIT_FDROP; + } + + /* Allocate the file descriptor for the accepted connection */ + vfs_fd = socket_alloc_fd(file->driver, new_sock); + if (vfs_fd < 0) { + uk_pr_debug("failed to allocate descriptor for accepted connection\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(vfs_fd); + goto SOCKET_CLEANUP; + } + + ret = vfs_fd; + +EXIT_FDROP: + vfscore_put_file(file->vfs_file); /* release refcount */ + trace_posix_socket_accept_err(ret); + return ret; +EXIT: + trace_posix_socket_accept_ret(ret); + return ret; +SOCKET_CLEANUP: + posix_socket_close(file->driver, file->sock_data); + goto EXIT_FDROP; +} + +UK_TRACEPOINT(trace_posix_socket_bind, "%d %p %d", int, const struct sockaddr *, + socklen_t); +UK_TRACEPOINT(trace_posix_socket_bind_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_bind_err, "%d", int); + +int bind(int sock, const struct sockaddr *addr, socklen_t addr_len) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_bind(sock, addr, addr_len); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Bind an incoming connection */ + ret = posix_socket_bind(file->driver, file->sock_data, addr, addr_len); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to bind with socket\n", file->driver->libname); + goto EXIT_ERR; + } + + trace_posix_socket_bind_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_bind_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_shutdown, "%d %d", int, int); +UK_TRACEPOINT(trace_posix_socket_shutdown_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_shutdown_err, "%d", int); + +int shutdown(int sock, int how) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_shutdown(sock, how); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Shutdown socket */ + ret = posix_socket_shutdown(file->driver, file->sock_data, how); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to shutdown socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_shutdown_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_shutdown_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_getpeername, "%d %p %d", int, + struct sockaddr *restrict, socklen_t *restrict); +UK_TRACEPOINT(trace_posix_socket_getpeername_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_getpeername_err, "%d", int); + +int getpeername(int sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_getpeername(sock, addr, addr_len); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Get peern name of socket */ + ret = posix_socket_getpeername(file->driver, file->sock_data, addr, addr_len); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to getpeername of socket\n", file->driver->libname); + goto EXIT_ERR; + } + + trace_posix_socket_getpeername_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_getpeername_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_getsockname, "%d %p %p", int, + struct sockaddr *restrict, socklen_t *restrict); +UK_TRACEPOINT(trace_posix_socket_getsockname_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_getsockname_err, "%d", int); + +int getsockname(int sock, struct sockaddr *restrict addr, + socklen_t *restrict addr_len) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_getsockname(sock, addr, addr_len); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Get socket name of socket */ + ret = posix_socket_getsockname(file->driver, file->sock_data, addr, addr_len); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to getsockname of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_getsockname_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_getsockname_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_getsockopt, "%d %d %d %p %d", int, int, int, + void *, socklen_t *); +UK_TRACEPOINT(trace_posix_socket_getsockopt_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_getsockopt_err, "%d", int); + +int getsockopt(int sock, int level, int optname, void *restrict optval, + socklen_t *restrict optlen) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_getsockopt(sock, level, optname, optval, optlen); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Get socket options */ + ret = posix_socket_getsockopt(file->driver, file->sock_data, level, optname, + optval, optlen); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to getsockopt of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_getsockopt_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_getsockopt_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_setsockopt, "%d %d %d %p %d", int, int, int, + const void *, socklen_t); +UK_TRACEPOINT(trace_posix_socket_setsockopt_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_setsockopt_err, "%d", int); + +int setsockopt(int sock, int level, int optname, const void *optval, + socklen_t optlen) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_setsockopt(sock, level, optname, optval, optlen); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Set socket options */ + ret = posix_socket_setsockopt(file->driver, file->sock_data, level, optname, + optval, optlen); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to setsockopt of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_setsockopt_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_setsockopt_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_getnameinfo, "%p %d %s %d %s %d %d", + const struct sockaddr *, socklen_t, char *, socklen_t, char *, + socklen_t, int); +UK_TRACEPOINT(trace_posix_socket_getnameinfo_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_getnameinfo_err, "%d", int); + +int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, + char *restrict node, socklen_t nodelen, char *restrict serv, + socklen_t servlen, int flags) +{ + uk_pr_crit("%s: not implemented", __func__); + errno = ENOTSUP; + return -1; +} + +UK_TRACEPOINT(trace_posix_socket_connect, "%d %p %d", int, + const struct sockaddr *, socklen_t); +UK_TRACEPOINT(trace_posix_socket_connect_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_connect_err, "%d", int); + +int connect(int sock, const struct sockaddr *addr, socklen_t addr_len) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_connect(sock, addr, addr_len); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Connect to the socket */ + ret = posix_socket_connect(file->driver, file->sock_data, addr, addr_len); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to connect to socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_connect_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_connect_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_listen, "%d %d", int, int); +UK_TRACEPOINT(trace_posix_socket_listen_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_listen_err, "%d", int); + +int listen(int sock, int backlog) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_listen(sock, backlog); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Listen to the socket */ + ret = posix_socket_listen(file->driver, file->sock_data, backlog); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to listen to socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_listen_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_listen_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_recv, "%d %p %d %d", int, void *, size_t, int); +UK_TRACEPOINT(trace_posix_socket_recv_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_recv_err, "%d", int); + +ssize_t recv(int sock, void *buf, size_t len, int flags) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_recv(sock, buf, len, flags); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Recieve a buffer from a socket */ + ret = posix_socket_recv(file->driver, file->sock_data, buf, len, flags); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to recv of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_recv_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_recv_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_recvfrom, "%d %p %d %d %p %p", int, void *, + size_t, int, struct sockaddr *, socklen_t *); +UK_TRACEPOINT(trace_posix_socket_recvfrom_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_recvfrom_err, "%d", int); + +ssize_t recvfrom(int sock, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_recvfrom(sock, buf, len, flags, from, fromlen); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Recieve a buffer from a socket */ + ret = posix_socket_recvfrom(file->driver, file->sock_data, buf, len, flags, + from, fromlen); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to recvfrom of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_recvfrom_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_recvfrom_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_recvmsg, "%d %p %d", int, struct msghdr*, int); +UK_TRACEPOINT(trace_posix_socket_recvmsg_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_recvmsg_err, "%d", int); + +ssize_t recvmsg(int sock, struct msghdr *msg, int flags) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_recvmsg(sock, msg, flags); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Recieve a structured message from a socket */ + ret = posix_socket_recvmsg(file->driver, file->sock_data, msg, flags); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to recvmsg of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_recvmsg_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_recvmsg_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_send, "%d %p %d %d", int, const void *, size_t, + int); +UK_TRACEPOINT(trace_posix_socket_send_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_send_err, "%d", int); + +ssize_t send(int sock, const void *buf, size_t len, int flags) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_send(sock, buf, len, flags); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Send a structured message to a sockets */ + ret = posix_socket_send(file->driver, file->sock_data, buf, len, flags); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to send of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_send_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_send_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_sendmsg, "%d %p %d", int, const struct msghdr*, + int); +UK_TRACEPOINT(trace_posix_socket_sendmsg_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_sendmsg_err, "%d", int); + +ssize_t sendmsg(int sock, const struct msghdr *msg, int flags) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_sendmsg(sock, msg, flags); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Send a structured message to a sockets */ + ret = posix_socket_sendmsg(file->driver, file->sock_data, msg, flags); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to sendmsg of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_sendmsg_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_sendmsg_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_sendto, "%d %p %d %d %p %d", int, const void *, + size_t, int, const struct sockaddr *, socklen_t); +UK_TRACEPOINT(trace_posix_socket_sendto_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_sendto_err, "%d", int); + +ssize_t sendto(int sock, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + trace_posix_socket_sendto(sock, buf, len, flags, dest_addr, addrlen); + + file = posix_socket_file_get(sock); + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT_ERR; + } + + /* Send to an address over a socket */ + ret = posix_socket_sendto(file->driver, file->sock_data, buf, len, flags, + dest_addr, addrlen); + + /* release refcount */ + vfscore_put_file(file->vfs_file); + + if (ret < 0) { + uk_pr_debug("driver:%s failed to sendto of socket:%p\n", + file->driver->libname, file->sock_data); + goto EXIT_ERR; + } + + trace_posix_socket_sendto_ret(ret); + return ret; +EXIT_ERR: + trace_posix_socket_sendto_err(ret); + return ret; +} + +UK_TRACEPOINT(trace_posix_socket_socketpair, "%d %d %d %p", int, int, int, + int *); +UK_TRACEPOINT(trace_posix_socket_socketpair_ret, "%d", int); +UK_TRACEPOINT(trace_posix_socket_socketpair_err, "%d", int); + +int socketpair(int family, int type, int protocol, int *usockvec) +{ + uk_pr_crit("%s: not implemented", __func__); + errno = ENOTSUP; + return -1; +} diff --git a/lib/posix-socket/socket_vnops.c b/lib/posix-socket/socket_vnops.c new file mode 100644 index 0000000..6409b27 --- /dev/null +++ b/lib/posix-socket/socket_vnops.c @@ -0,0 +1,323 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> + * Alexander Jung <alexander.jung@xxxxxxxxx> + * + * Copyright (c) 2020, NEC Laboratories Europe GmbH, NEC Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <uk/socket_driver.h> +#include <vfscore/vnode.h> +#include <vfscore/mount.h> +#include <vfscore/fs.h> +#include <uk/socket_vnops.h> +#include <uk/errptr.h> +#include <inttypes.h> + +static uint64_t s_inode = 0; + +#define posix_socket_getattr ((vnop_getattr_t) vfscore_vop_einval) +#define posix_socket_inactive ((vnop_inactive_t) vfscore_vop_nullop) + +/* vnode operations */ +struct vnops posix_socket_vnops = { + .vop_close = posix_socket_vfscore_close, + .vop_read = posix_socket_vfscore_read, + .vop_write = posix_socket_vfscore_write, + .vop_ioctl = posix_socket_vfscore_ioctl, + .vop_getattr = posix_socket_getattr, + .vop_inactive = posix_socket_inactive, +}; + +#define posix_socket_vget ((vfsop_vget_t) vfscore_nullop) + +/* file system operations */ +static struct vfsops posix_socket_vfsops = { + .vfs_vget = posix_socket_vget, + .vfs_vnops = &posix_socket_vnops, +}; + +/* bogus mount point used by all sockets */ +static struct mount posix_socket_mount = { + .m_op = &posix_socket_vfsops +}; + +struct posix_socket_file * +posix_socket_file_get(int sock_fd) +{ + struct posix_socket_file *file = NULL; + struct vfscore_file *fos; + + fos = vfscore_get_file(sock_fd); + + if (!fos) { + uk_pr_err("Failed with invalid descriptor\n"); + file = ERR2PTR(-EINVAL); + goto EXIT; + } + + if (fos->f_dentry->d_vnode->v_type != VSOCK) { + uk_pr_err("File descriptor is not a socket\n"); + file = ERR2PTR(-EINVAL); + goto EXIT; + } + + file = fos->f_data; + +EXIT: + return file; +} + +int +socket_alloc_fd(struct posix_socket_driver *d, void *sock_data) +{ + int ret = 0; + int vfs_fd; + struct posix_socket_file *file = NULL; + struct vfscore_file *vfs_file = NULL; + struct dentry *s_dentry; + struct vnode *s_vnode; + + /* Reserve file descriptor number */ + vfs_fd = vfscore_alloc_fd(); + if (vfs_fd < 0) { + ret = -ENFILE; + uk_pr_err("failed to allocate file descriptor number\n"); + goto ERR_EXIT; + } + + /* Allocate file, dentry, and vnode */ + file = uk_calloc(d->allocator, 1, sizeof(*file)); + if (!file) { + ret = -ENOMEM; + uk_pr_err("failed to allocate socket file: out of memory\n"); + goto ERR_MALLOC_FILE; + } + + vfs_file = uk_calloc(d->allocator, 1, sizeof(*vfs_file)); + if (!vfs_file) { + ret = -ENOMEM; + uk_pr_err("failed to allocate socket vfs_file: out of memory\n"); + goto ERR_MALLOC_VFS_FILE; + } + + ret = vfscore_vget(&posix_socket_mount, s_inode++, &s_vnode); + UK_ASSERT(ret == 0); /* we should not find it in cache */ + + if (!s_vnode) { + ret = -ENOMEM; + uk_pr_err("failed to allocate socket vnode: out of memory\n"); + goto ERR_ALLOC_VNODE; + } + + uk_mutex_unlock(&s_vnode->v_lock); + + /* + * it doesn't matter that all the dentries have the + * same path since we never lookup for them + */ + s_dentry = dentry_alloc(NULL, s_vnode, "/"); + + if (!s_dentry) { + ret = -ENOMEM; + uk_pr_err("failed to allocate socket dentry: out of memory\n"); + goto ERR_ALLOC_DENTRY; + } + + /* Put things together, and fill out necessary fields */ + vfs_file->fd = vfs_fd; + vfs_file->f_flags = UK_FWRITE | UK_FREAD; + vfs_file->f_count = 1; + vfs_file->f_data = file; + vfs_file->f_dentry = s_dentry; + vfs_file->f_vfs_flags = UK_VFSCORE_NOPOS; + + s_vnode->v_data = file; + s_vnode->v_type = VSOCK; + + file->vfs_file = vfs_file; + file->sock_data = sock_data; + file->driver = d; + + uk_pr_debug("allocated socket %d for %s (%p)\n", + vfs_fd, + d->libname, + file->sock_data); + + /* Store within the vfs structure */ + ret = vfscore_install_fd(vfs_fd, file->vfs_file); + if (ret) { + uk_pr_err("failed to install socket fd\n"); + goto ERR_VFS_INSTALL; + } + + /* Only the dentry should hold a reference; release ours */ + vrele(s_vnode); + + /* Return file descriptor of our socket */ + return vfs_fd; + +ERR_VFS_INSTALL: + drele(s_dentry); +ERR_ALLOC_DENTRY: + vrele(s_vnode); +ERR_ALLOC_VNODE: + uk_free(d->allocator, vfs_file); +ERR_MALLOC_VFS_FILE: + uk_free(d->allocator, file); +ERR_MALLOC_FILE: + vfscore_put_fd(vfs_fd); +ERR_EXIT: + UK_ASSERT(ret < 0); + return ret; +} + +int +posix_socket_vfscore_close(struct vnode *s_vnode, + struct vfscore_file *vfscore_file) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + file = s_vnode->v_data; + + uk_pr_debug("%s fd:%d driver:%s: sock_data:%p\n", + __func__, + file->vfs_file->fd, + file->driver->libname, + file->sock_data); + + /* Close and release the socket */ + ret = posix_socket_close(file->driver, file->sock_data); + + /* + * Free socket file + * The rest of the resources will be freed by vfs + * + * TODO: vfs ignores close errors right now, so free our file + */ + uk_free(file->driver->allocator, file); + + if (ret < 0) + return errno; + + return ret; +} + +int +posix_socket_vfscore_write(struct vnode *s_vnode, + struct uio *buf, int ioflag __unused) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + file = s_vnode->v_data; + uk_pr_debug("%s fd:%d driver:%s sock_data:%p\n", + __func__, + file->vfs_file->fd, + file->driver->libname, + file->sock_data); + + /* Write to the socket */ + ret = posix_socket_write(file->driver, file->sock_data, buf->uio_iov, buf->uio_iovcnt); + + /* + * Some socket implementations, such as LwIP, may set the errno and return to + * -1 as an error, but vfs expects us to return a positive errno. + */ + if (ret < 0) + return errno; + + buf->uio_resid -= ret; + return 0; +} + +int +posix_socket_vfscore_read(struct vnode *s_vnode, + struct vfscore_file *vfscore_file __unused, + struct uio *buf, int ioflag __unused) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + file = s_vnode->v_data; + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + + uk_pr_debug("%s fd:%d driver:%s sock_data:%p\n", + __func__, + file->vfs_file->fd, + file->driver->libname, + file->sock_data); + + ret = posix_socket_read(file->driver, file->sock_data, buf->uio_iov, buf->uio_iovcnt); + if (ret < 0) { + ret = errno; + goto EXIT; + } + + buf->uio_resid -= ret; + +EXIT: + return ret; +} + +int +posix_socket_vfscore_ioctl(struct vnode *s_vnode, + struct vfscore_file *vfscore_file __unused, + unsigned long request, + void *buf) +{ + int ret = 0; + struct posix_socket_file *file = NULL; + + file = s_vnode->v_data; + if (PTRISERR(file)) { + uk_pr_debug("failed to identify socket descriptor\n"); + ret = -1; + POSIX_SOCKET_SET_ERRNO(PTR2ERR(file)); + goto EXIT; + } + + uk_pr_debug("%s fd:%d driver:%s sock_data:%p\n", + __func__, + file->vfs_file->fd, + file->driver->libname, + file->sock_data); + + ret = posix_socket_ioctl(file->driver, file->sock_data, request, buf); + if (ret < 0) + ret = errno; + +EXIT: + return ret; +} -- 2.20.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |