aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/_fdserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/_fdserver.c')
-rw-r--r--platform/linux-generic/_fdserver.c694
1 files changed, 0 insertions, 694 deletions
diff --git a/platform/linux-generic/_fdserver.c b/platform/linux-generic/_fdserver.c
deleted file mode 100644
index d1b16f622..000000000
--- a/platform/linux-generic/_fdserver.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/* Copyright (c) 2016, Linaro Limited
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/*
- * This file implements a file descriptor sharing server enabling
- * sharing of file descriptors between processes, regardless of fork time.
- *
- * File descriptors are process scoped, but they can be "sent and converted
- * on the fly" between processes using special unix domain socket ancillary
- * data.
- * The receiving process gets a file descriptor "pointing" to the same thing
- * as the one sent (but the value of the file descriptor itself may be different
- * from the one sent).
- * Because ODP applications are responsible for creating ODP threads (i.e.
- * pthreads or linux processes), ODP has no control on the order things happen:
- * Nothing prevent a thread A to fork B and C, and then C creating a pktio
- * which will be used by A and B to send/receive packets.
- * Assuming this pktio uses a file descriptor, the latter will need to be
- * shared between the processes, despite the "non convenient" fork time.
- * The shared memory allocator is likely to use this as well to be able to
- * share memory regardless of fork() time.
- * This server handles a table of {(context,key)<-> fd} pair, and is
- * interfaced by the following functions:
- *
- * _odp_fdserver_register_fd(context, key, fd_to_send);
- * _odp_fdserver_deregister_fd(context, key);
- * _odp_fdserver_lookup_fd(context, key);
- *
- * which are used to register/deregister or querry for file descriptor based
- * on a context and key value couple, which has to be unique.
- *
- * Note again that the file descriptors stored here are local to this server
- * process and get converted both when registered or looked up.
- */
-
-#include <odp_posix_extensions.h>
-#include <odp/api/spinlock.h>
-#include <odp_internal.h>
-#include <odp_debug_internal.h>
-#include <_fdserver_internal.h>
-#include <sys/prctl.h>
-#include <signal.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#define FDSERVER_SOCKPATH_MAXLEN 255
-#define FDSERVER_SOCK_FORMAT "%s/%s/odp-%d-fdserver"
-#define FDSERVER_SOCKDIR_FORMAT "%s/%s"
-#define FDSERVER_DEFAULT_DIR "/dev/shm"
-#define FDSERVER_BACKLOG 5
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-/* when accessing the client functions, clients should be mutexed: */
-static odp_spinlock_t *client_lock;
-
-/* define the tables of file descriptors handled by this server: */
-#define FDSERVER_MAX_ENTRIES 256
-typedef struct fdentry_s {
- fd_server_context_e context;
- uint64_t key;
- int fd;
-} fdentry_t;
-static fdentry_t *fd_table;
-static int fd_table_nb_entries;
-
-/*
- * define the message struct used for communication between client and server
- * (this single message is used in both direction)
- * The file descriptors are sent out of band as ancillary data for conversion.
- */
-typedef struct fd_server_msg {
- int command;
- fd_server_context_e context;
- uint64_t key;
-} fdserver_msg_t;
-/* possible commands are: */
-#define FD_REGISTER_REQ 1 /* client -> server */
-#define FD_REGISTER_ACK 2 /* server -> client */
-#define FD_REGISTER_NACK 3 /* server -> client */
-#define FD_LOOKUP_REQ 4 /* client -> server */
-#define FD_LOOKUP_ACK 5 /* server -> client */
-#define FD_LOOKUP_NACK 6 /* server -> client */
-#define FD_DEREGISTER_REQ 7 /* client -> server */
-#define FD_DEREGISTER_ACK 8 /* server -> client */
-#define FD_DEREGISTER_NACK 9 /* server -> client */
-#define FD_SERVERSTOP_REQ 10 /* client -> server (stops) */
-
-/*
- * Client and server function:
- * Send a fdserver_msg, possibly including a file descriptor, on the socket
- * This function is used both by:
- * -the client (sending a FD_REGISTER_REQ with a file descriptor to be shared,
- * or FD_LOOKUP_REQ/FD_DEREGISTER_REQ without a file descriptor)
- * -the server (sending FD_REGISTER_ACK/NACK, FD_LOOKUP_NACK,
- * FD_DEREGISTER_ACK/NACK... without a fd or a
- * FD_LOOKUP_ACK with a fd)
- * This function make use of the ancillary data (control data) to pass and
- * convert file descriptors over UNIX sockets
- * Return -1 on error, 0 on success.
- */
-static int send_fdserver_msg(int sock, int command,
- fd_server_context_e context, uint64_t key,
- int fd_to_send)
-{
- struct msghdr socket_message;
- struct iovec io_vector[1]; /* one msg frgmt only */
- struct cmsghdr *control_message = NULL;
- int *fd_location;
- fdserver_msg_t msg;
- int res;
-
- char ancillary_data[CMSG_SPACE(sizeof(int))];
-
- /* prepare the register request body (single framgent): */
- msg.command = command;
- msg.context = context;
- msg.key = key;
- io_vector[0].iov_base = &msg;
- io_vector[0].iov_len = sizeof(fdserver_msg_t);
-
- /* initialize socket message */
- memset(&socket_message, 0, sizeof(struct msghdr));
- socket_message.msg_iov = io_vector;
- socket_message.msg_iovlen = 1;
-
- if (fd_to_send >= 0) {
- /* provide space for the ancillary data */
- memset(ancillary_data, 0, CMSG_SPACE(sizeof(int)));
- socket_message.msg_control = ancillary_data;
- socket_message.msg_controllen = CMSG_SPACE(sizeof(int));
-
- /* initialize a single ancillary data element for fd passing */
- control_message = CMSG_FIRSTHDR(&socket_message);
- control_message->cmsg_level = SOL_SOCKET;
- control_message->cmsg_type = SCM_RIGHTS;
- control_message->cmsg_len = CMSG_LEN(sizeof(int));
- fd_location = (int *)(void *)CMSG_DATA(control_message);
- *fd_location = fd_to_send;
- }
- res = sendmsg(sock, &socket_message, 0);
- if (res < 0) {
- ODP_ERR("send_fdserver_msg: %s\n", strerror(errno));
- return(-1);
- }
-
- return 0;
-}
-
-/*
- * Client and server function
- * Receive a fdserver_msg, possibly including a file descriptor, on the
- * given socket.
- * This function is used both by:
- * -the server (receiving a FD_REGISTER_REQ with a file descriptor to be shared,
- * or FD_LOOKUP_REQ, FD_DEREGISTER_REQ without a file descriptor)
- * -the client (receiving FD_REGISTER_ACK...without a fd or a FD_LOOKUP_ACK with
- * a fd)
- * This function make use of the ancillary data (control data) to pass and
- * convert file descriptors over UNIX sockets.
- * Return -1 on error, 0 on success.
- */
-static int recv_fdserver_msg(int sock, int *command,
- fd_server_context_e *context, uint64_t *key,
- int *recvd_fd)
-{
- struct msghdr socket_message;
- struct iovec io_vector[1]; /* one msg frgmt only */
- struct cmsghdr *control_message = NULL;
- int *fd_location;
- fdserver_msg_t msg;
- char ancillary_data[CMSG_SPACE(sizeof(int))];
-
- memset(&socket_message, 0, sizeof(struct msghdr));
- memset(ancillary_data, 0, CMSG_SPACE(sizeof(int)));
-
- /* setup a place to fill in message contents */
- io_vector[0].iov_base = &msg;
- io_vector[0].iov_len = sizeof(fdserver_msg_t);
- socket_message.msg_iov = io_vector;
- socket_message.msg_iovlen = 1;
-
- /* provide space for the ancillary data */
- socket_message.msg_control = ancillary_data;
- socket_message.msg_controllen = CMSG_SPACE(sizeof(int));
-
- /* receive the message */
- if (recvmsg(sock, &socket_message, MSG_CMSG_CLOEXEC) < 0) {
- ODP_ERR("recv_fdserver_msg: %s\n", strerror(errno));
- return(-1);
- }
-
- *command = msg.command;
- *context = msg.context;
- *key = msg.key;
-
- /* grab the converted file descriptor (if any) */
- *recvd_fd = -1;
-
- if ((socket_message.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
- return 0;
-
- /* iterate ancillary elements to find the file descriptor: */
- for (control_message = CMSG_FIRSTHDR(&socket_message);
- control_message != NULL;
- control_message = CMSG_NXTHDR(&socket_message, control_message)) {
- if ((control_message->cmsg_level == SOL_SOCKET) &&
- (control_message->cmsg_type == SCM_RIGHTS)) {
- fd_location = (int *)(void *)CMSG_DATA(control_message);
- *recvd_fd = *fd_location;
- break;
- }
- }
-
- return 0;
-}
-
-/* opens and returns a connected socket to the server */
-static int get_socket(void)
-{
- char sockpath[FDSERVER_SOCKPATH_MAXLEN];
- int s_sock; /* server socket */
- struct sockaddr_un remote;
- int len;
-
- /* construct the named socket path: */
- snprintf(sockpath, FDSERVER_SOCKPATH_MAXLEN, FDSERVER_SOCK_FORMAT,
- odp_global_data.shm_dir,
- odp_global_data.uid,
- odp_global_data.main_pid);
-
- s_sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (s_sock == -1) {
- ODP_ERR("cannot connect to server: %s\n", strerror(errno));
- return(-1);
- }
-
- remote.sun_family = AF_UNIX;
- strcpy(remote.sun_path, sockpath);
- len = strlen(remote.sun_path) + sizeof(remote.sun_family);
- if (connect(s_sock, (struct sockaddr *)&remote, len) == -1) {
- ODP_ERR("cannot connect to server: %s\n", strerror(errno));
- close(s_sock);
- return(-1);
- }
-
- return s_sock;
-}
-
-/*
- * Client function:
- * Register a file descriptor to the server. Return -1 on error.
- */
-int _odp_fdserver_register_fd(fd_server_context_e context, uint64_t key,
- int fd_to_send)
-{
- int s_sock; /* server socket */
- int res;
- int command;
- int fd;
-
- odp_spinlock_lock(client_lock);
-
- ODP_DBG("FD client register: pid=%d key=%" PRIu64 ", fd=%d\n",
- getpid(), key, fd_to_send);
-
- s_sock = get_socket();
- if (s_sock < 0) {
- odp_spinlock_unlock(client_lock);
- return(-1);
- }
-
- res = send_fdserver_msg(s_sock, FD_REGISTER_REQ, context, key,
- fd_to_send);
- if (res < 0) {
- ODP_ERR("fd registration failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- res = recv_fdserver_msg(s_sock, &command, &context, &key, &fd);
-
- if ((res < 0) || (command != FD_REGISTER_ACK)) {
- ODP_ERR("fd registration failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- close(s_sock);
-
- odp_spinlock_unlock(client_lock);
- return 0;
-}
-
-/*
- * Client function:
- * Deregister a file descriptor from the server. Return -1 on error.
- */
-int _odp_fdserver_deregister_fd(fd_server_context_e context, uint64_t key)
-{
- int s_sock; /* server socket */
- int res;
- int command;
- int fd;
-
- odp_spinlock_lock(client_lock);
-
- ODP_DBG("FD client deregister: pid=%d key=%" PRIu64 "\n",
- getpid(), key);
-
- s_sock = get_socket();
- if (s_sock < 0) {
- odp_spinlock_unlock(client_lock);
- return(-1);
- }
-
- res = send_fdserver_msg(s_sock, FD_DEREGISTER_REQ, context, key, -1);
- if (res < 0) {
- ODP_ERR("fd de-registration failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- res = recv_fdserver_msg(s_sock, &command, &context, &key, &fd);
-
- if ((res < 0) || (command != FD_DEREGISTER_ACK)) {
- ODP_ERR("fd de-registration failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- close(s_sock);
-
- odp_spinlock_unlock(client_lock);
- return 0;
-}
-
-/*
- * client function:
- * lookup a file descriptor from the server. return -1 on error,
- * or the file descriptor on success (>=0).
- */
-int _odp_fdserver_lookup_fd(fd_server_context_e context, uint64_t key)
-{
- int s_sock; /* server socket */
- int res;
- int command;
- int fd;
-
- odp_spinlock_lock(client_lock);
-
- s_sock = get_socket();
- if (s_sock < 0) {
- odp_spinlock_unlock(client_lock);
- return(-1);
- }
-
- res = send_fdserver_msg(s_sock, FD_LOOKUP_REQ, context, key, -1);
- if (res < 0) {
- ODP_ERR("fd lookup failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- res = recv_fdserver_msg(s_sock, &command, &context, &key, &fd);
-
- if ((res < 0) || (command != FD_LOOKUP_ACK)) {
- ODP_ERR("fd lookup failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- close(s_sock);
- ODP_DBG("FD client lookup: pid=%d, key=%" PRIu64 ", fd=%d\n",
- getpid(), key, fd);
-
- odp_spinlock_unlock(client_lock);
- return fd;
-}
-
-/*
- * request server terminaison:
- */
-static int stop_server(void)
-{
- int s_sock; /* server socket */
- int res;
-
- odp_spinlock_lock(client_lock);
-
- ODP_DBG("FD sending server stop request\n");
-
- s_sock = get_socket();
- if (s_sock < 0) {
- odp_spinlock_unlock(client_lock);
- return(-1);
- }
-
- res = send_fdserver_msg(s_sock, FD_SERVERSTOP_REQ, 0, 0, -1);
- if (res < 0) {
- ODP_ERR("fd stop request failure\n");
- close(s_sock);
- odp_spinlock_unlock(client_lock);
- return -1;
- }
-
- close(s_sock);
-
- odp_spinlock_unlock(client_lock);
- return 0;
-}
-
-/*
- * server function
- * receive a client request and handle it.
- * Always returns 0 unless a stop request is received.
- */
-static int handle_request(int client_sock)
-{
- int command;
- fd_server_context_e context;
- uint64_t key;
- int fd;
- int i;
-
- /* get a client request: */
- recv_fdserver_msg(client_sock, &command, &context, &key, &fd);
- switch (command) {
- case FD_REGISTER_REQ:
- if ((fd < 0) || (context >= FD_SRV_CTX_END)) {
- ODP_ERR("Invalid register fd or context\n");
- send_fdserver_msg(client_sock, FD_REGISTER_NACK,
- FD_SRV_CTX_NA, 0, -1);
- return 0;
- }
-
- /* store the file descriptor in table: */
- if (fd_table_nb_entries < FDSERVER_MAX_ENTRIES) {
- fd_table[fd_table_nb_entries].context = context;
- fd_table[fd_table_nb_entries].key = key;
- fd_table[fd_table_nb_entries++].fd = fd;
- ODP_DBG("storing {ctx=%d, key=%" PRIu64 "}->fd=%d\n",
- context, key, fd);
- } else {
- ODP_ERR("FD table full\n");
- send_fdserver_msg(client_sock, FD_REGISTER_NACK,
- FD_SRV_CTX_NA, 0, -1);
- return 0;
- }
-
- send_fdserver_msg(client_sock, FD_REGISTER_ACK,
- FD_SRV_CTX_NA, 0, -1);
- break;
-
- case FD_LOOKUP_REQ:
- if (context >= FD_SRV_CTX_END) {
- ODP_ERR("invalid lookup context\n");
- send_fdserver_msg(client_sock, FD_LOOKUP_NACK,
- FD_SRV_CTX_NA, 0, -1);
- return 0;
- }
-
- /* search key in table and sent reply: */
- for (i = 0; i < fd_table_nb_entries; i++) {
- if ((fd_table[i].context == context) &&
- (fd_table[i].key == key)) {
- fd = fd_table[i].fd;
- ODP_DBG("lookup {ctx=%d,"
- " key=%" PRIu64 "}->fd=%d\n",
- context, key, fd);
- send_fdserver_msg(client_sock,
- FD_LOOKUP_ACK, context, key,
- fd);
- return 0;
- }
- }
-
- /* context+key not found... send nack */
- send_fdserver_msg(client_sock, FD_LOOKUP_NACK, context, key,
- -1);
- break;
-
- case FD_DEREGISTER_REQ:
- if (context >= FD_SRV_CTX_END) {
- ODP_ERR("invalid deregister context\n");
- send_fdserver_msg(client_sock, FD_DEREGISTER_NACK,
- FD_SRV_CTX_NA, 0, -1);
- return 0;
- }
-
- /* search key in table and remove it if found, and reply: */
- for (i = 0; i < fd_table_nb_entries; i++) {
- if ((fd_table[i].context == context) &&
- (fd_table[i].key == key)) {
- ODP_DBG("drop {ctx=%d,"
- " key=%" PRIu64 "}->fd=%d\n",
- context, key, fd_table[i].fd);
- close(fd_table[i].fd);
- fd_table[i] = fd_table[--fd_table_nb_entries];
- send_fdserver_msg(client_sock,
- FD_DEREGISTER_ACK,
- context, key, -1);
- return 0;
- }
- }
-
- /* key not found... send nack */
- send_fdserver_msg(client_sock, FD_DEREGISTER_NACK,
- context, key, -1);
- break;
-
- case FD_SERVERSTOP_REQ:
- ODP_DBG("Stoping FD server\n");
- return 1;
-
- default:
- ODP_ERR("Unexpected request\n");
- break;
- }
- return 0;
-}
-
-/*
- * server function
- * loop forever, handling client requests one by one
- */
-static void wait_requests(int sock)
-{
- int c_socket; /* client connection */
- unsigned int addr_sz;
- struct sockaddr_un remote;
-
- for (;;) {
- addr_sz = sizeof(remote);
- c_socket = accept(sock, (struct sockaddr *)&remote, &addr_sz);
- if (c_socket == -1) {
- ODP_ERR("wait_requests: %s\n", strerror(errno));
- return;
- }
-
- if (handle_request(c_socket))
- break;
- close(c_socket);
- }
- close(c_socket);
-}
-
-/*
- * Create a unix domain socket and fork a process to listen to incoming
- * requests.
- */
-int _odp_fdserver_init_global(void)
-{
- char sockpath[FDSERVER_SOCKPATH_MAXLEN];
- int sock;
- struct sockaddr_un local;
- pid_t server_pid;
- int res;
-
- /* create the client spinlock that any client can see: */
- client_lock = mmap(NULL, sizeof(odp_spinlock_t), PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-
- odp_spinlock_init(client_lock);
-
- snprintf(sockpath, FDSERVER_SOCKPATH_MAXLEN, FDSERVER_SOCKDIR_FORMAT,
- odp_global_data.shm_dir,
- odp_global_data.uid);
-
- mkdir(sockpath, 0744);
-
- /* construct the server named socket path: */
- snprintf(sockpath, FDSERVER_SOCKPATH_MAXLEN, FDSERVER_SOCK_FORMAT,
- odp_global_data.shm_dir,
- odp_global_data.uid,
- odp_global_data.main_pid);
-
- /* create UNIX domain socket: */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock == -1) {
- ODP_ERR("_odp_fdserver_init_global: %s\n", strerror(errno));
- return(-1);
- }
-
- /* remove previous named socket if it already exists: */
- unlink(sockpath);
-
- /* bind to new named socket: */
- local.sun_family = AF_UNIX;
- strncpy(local.sun_path, sockpath, sizeof(local.sun_path));
- res = bind(sock, (struct sockaddr *)&local, sizeof(struct sockaddr_un));
- if (res == -1) {
- ODP_ERR("_odp_fdserver_init_global: %s\n", strerror(errno));
- close(sock);
- return(-1);
- }
-
- /* listen for incoming conections: */
- if (listen(sock, FDSERVER_BACKLOG) == -1) {
- ODP_ERR("_odp_fdserver_init_global: %s\n", strerror(errno));
- close(sock);
- return(-1);
- }
-
- /* fork a server process: */
- server_pid = fork();
- if (server_pid == -1) {
- ODP_ERR("Could not fork!\n");
- close(sock);
- return(-1);
- }
-
- if (server_pid == 0) { /*child */
- /* TODO: pin the server on appropriate service cpu mask */
- /* when (if) we can agree on the usage of service mask */
-
- /* request to be killed if parent dies, hence avoiding */
- /* orphans being "adopted" by the init process... */
- prctl(PR_SET_PDEATHSIG, SIGTERM);
-
- /* allocate the space for the file descriptor<->key table: */
- fd_table = malloc(FDSERVER_MAX_ENTRIES * sizeof(fdentry_t));
- if (!fd_table) {
- ODP_ERR("maloc failed!\n");
- exit(1);
- }
-
- /* wait for clients requests */
- wait_requests(sock); /* Returns when server is stopped */
- close(sock);
-
- /* release the file descriptor table: */
- free(fd_table);
-
- exit(0);
- }
-
- /* parent */
- close(sock);
- return 0;
-}
-
-/*
- * Terminate the server
- */
-int _odp_fdserver_term_global(void)
-{
- int status;
- char sockpath[FDSERVER_SOCKPATH_MAXLEN];
-
- /* close the server and wait for child terminaison*/
- stop_server();
- wait(&status);
-
- /* construct the server named socket path: */
- snprintf(sockpath, FDSERVER_SOCKPATH_MAXLEN, FDSERVER_SOCK_FORMAT,
- odp_global_data.shm_dir,
- odp_global_data.uid,
- odp_global_data.main_pid);
-
- /* delete the UNIX domain socket: */
- unlink(sockpath);
-
- /* delete shm files directory */
- snprintf(sockpath, FDSERVER_SOCKPATH_MAXLEN, FDSERVER_SOCKDIR_FORMAT,
- odp_global_data.shm_dir,
- odp_global_data.uid);
- rmdir(sockpath);
-
- return 0;
-}