diff options
Diffstat (limited to 'extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c')
-rw-r--r-- | extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c | 3447 |
1 files changed, 0 insertions, 3447 deletions
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c deleted file mode 100644 index 7b5f6c84f83..00000000000 --- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c +++ /dev/null @@ -1,3447 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <unistd.h> -#include <stdio.h> -#include <sys/uio.h> -#include <limits.h> -#define __need_IOV_MAX -#include <bits/stdio_lim.h> -#include <netinet/tcp.h> - -#include <vppinfra/types.h> -#include <vppinfra/hash.h> -#include <vppinfra/pool.h> - -#include <libvcl-ldpreload/vcom_socket.h> -#include <libvcl-ldpreload/vcom_socket_wrapper.h> -#include <libvcl-ldpreload/vcom.h> - -#include <uri/vppcom.h> - - -/* - * VCOM_SOCKET Private definitions and functions. - */ - -typedef struct vcom_socket_main_t_ -{ - u8 init; - - /* vcom_socket pool */ - vcom_socket_t *vsockets; - - /* Hash table for socketidx to fd mapping */ - uword *sockidx_by_fd; - - /* vcom_epoll pool */ - vcom_epoll_t *vepolls; - - /* Hash table for epollidx to epfd mapping */ - uword *epollidx_by_epfd; - - - /* common epitem poll for all epfd */ - /* TBD: epitem poll per epfd */ - /* vcom_epitem pool */ - vcom_epitem_t *vepitems; - - /* Hash table for epitemidx to epfdfd mapping */ - uword *epitemidx_by_epfdfd; - - /* Hash table - key:epfd, value:vec of epitemidx */ - uword *epitemidxs_by_epfd; - /* Hash table - key:fd, value:vec of epitemidx */ - uword *epitemidxs_by_fd; - -} vcom_socket_main_t; - -vcom_socket_main_t vcom_socket_main; - - -static int -vcom_socket_open_socket (int domain, int type, int protocol) -{ - int rv = -1; - - /* handle domains implemented by vpp */ - switch (domain) - { - case AF_INET: - case AF_INET6: - /* get socket type and - * handle the socket types supported by vpp */ - switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - { - case SOCK_STREAM: - case SOCK_DGRAM: - /* the type argument serves a second purpose, - * in addition to specifying a socket type, - * it may include the bitwise OR of any of - * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify - * the behavior of socket. */ - rv = libc_socket (domain, type, protocol); - if (rv == -1) - rv = -errno; - break; - - default: - break; - } - - break; - - default: - break; - } - - return rv; -} - -static int -vcom_socket_open_epoll (int flags) -{ - int rv = -1; - - if (flags < 0) - { - return -EINVAL; - } - if (flags && (flags & ~EPOLL_CLOEXEC)) - { - return -EINVAL; - } - - /* flags can be either zero or EPOLL_CLOEXEC */ - rv = libc_epoll_create1 (flags); - if (rv == -1) - rv = -errno; - - return rv; -} - -static int -vcom_socket_close_socket (int fd) -{ - int rv; - - rv = libc_close (fd); - if (rv == -1) - rv = -errno; - - return rv; -} - -static int -vcom_socket_close_epoll (int epfd) -{ - int rv; - - rv = libc_close (epfd); - if (rv == -1) - rv = -errno; - - return rv; -} - -/* - * Public API functions - */ - - -int -vcom_socket_is_vcom_fd (int fd) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, fd); - - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND) - return 1; - } - return 0; -} - -int -vcom_socket_is_vcom_epfd (int epfd) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_epoll_t *vepoll; - - p = hash_get (vsm->epollidx_by_epfd, epfd); - - if (p) - { - vepoll = pool_elt_at_index (vsm->vepolls, p[0]); - if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND) - return 1; - } - return 0; -} - -static inline int -vcom_socket_get_sid (int fd) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, fd); - - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND) - return vsock->sid; - } - return INVALID_SESSION_ID; -} - -static inline int -vcom_socket_get_vep_idx (int epfd) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_epoll_t *vepoll; - - p = hash_get (vsm->epollidx_by_epfd, epfd); - - if (p) - { - vepoll = pool_elt_at_index (vsm->vepolls, p[0]); - if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND) - return vepoll->vep_idx; - } - return INVALID_VEP_IDX; -} - -static inline int -vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, fd); - - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND) - { - *vsockp = vsock; - return vsock->sid; - } - } - return INVALID_SESSION_ID; -} - -static inline int -vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_epoll_t *vepoll; - - p = hash_get (vsm->epollidx_by_epfd, epfd); - - if (p) - { - vepoll = pool_elt_at_index (vsm->vepolls, p[0]); - if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND) - { - *vepollp = vepoll; - return vepoll->vep_idx; - } - } - return INVALID_VEP_IDX; -} - - -static int -vcom_socket_close_vepoll (int epfd) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_epoll_t *vepoll; - - p = hash_get (vsm->epollidx_by_epfd, epfd); - if (!p) - return -EBADF; - - vepoll = pool_elt_at_index (vsm->vepolls, p[0]); - if (!vepoll) - return -EBADF; - - if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (vepoll->count) - { - if (!vepoll->close) - { - vepoll->close = 1; - return 0; - } - else - { - return -EBADF; - } - } - - /* count is zero */ - rv = vppcom_session_close (vepoll->vep_idx); - rv = vcom_socket_close_epoll (vepoll->epfd); - - vepoll_init (vepoll); - hash_unset (vsm->epollidx_by_epfd, epfd); - pool_put (vsm->vepolls, vepoll); - - return rv; -} - -static int -vcom_socket_close_vsock (int fd) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - vcom_epitem_t *vepitem; - - i32 *vepitemidxs = 0; - i32 *vepitemidxs_var = 0; - - p = hash_get (vsm->sockidx_by_fd, fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - rv = vppcom_session_close (vsock->sid); - rv = vcom_socket_close_socket (vsock->fd); - - vsocket_init (vsock); - hash_unset (vsm->sockidx_by_fd, fd); - pool_put (vsm->vsockets, vsock); - - /* - * NOTE: - * Before calling close(), user should remove - * this fd from the epoll-set of all epoll instances, - * otherwise resource(epitems) leaks ensues. - */ - - /* - * 00. close all epoll instances that are marked as "close" - * of which this fd is the "last" remaining member. - * 01. epitems associated with this fd are intentionally - * not removed, see NOTE: above. - * */ - - /* does this fd participate in epoll */ - p = hash_get (vsm->epitemidxs_by_fd, fd); - if (p) - { - vepitemidxs = *(i32 **) p; - vec_foreach (vepitemidxs_var, vepitemidxs) - { - vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]); - if (vepitem && vepitem->fd == fd && - vepitem->type == FD_TYPE_VCOM_SOCKET) - { - i32 vep_idx; - vcom_epoll_t *vepoll; - if ((vep_idx = - vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd, - &vepoll)) != - INVALID_VEP_IDX) - { - if (vepoll->close) - { - if (vepoll->count == 1) - { - /* - * force count to zero and - * close this epoll instance - * */ - vepoll->count = 0; - vcom_socket_close_vepoll (vepoll->epfd); - } - else - { - vepoll->count -= 1; - } - } - } - } - - } - } - - return rv; -} - -int -vcom_socket_close (int __fd) -{ - int rv; - - if (vcom_socket_is_vcom_fd (__fd)) - { - rv = vcom_socket_close_vsock (__fd); - } - else if (vcom_socket_is_vcom_epfd (__fd)) - { - rv = vcom_socket_close_vepoll (__fd); - } - else - { - rv = -EBADF; - } - - return rv; -} - -ssize_t -vcom_socket_read (int __fd, void *__buf, size_t __nbytes) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__buf || __nbytes < 0) - { - return -EINVAL; - } - - rv = vcom_fcntl (__fd, F_GETFL, 0); - if (rv < 0) - { - return rv; - - } - - /* is blocking */ - if (!(rv & O_NONBLOCK)) - { - do - { - rv = vppcom_session_read (vsock->sid, __buf, __nbytes); - } - while (rv == -EAGAIN || rv == -EWOULDBLOCK); - return rv; - } - /* The file descriptor refers to a socket and has been - * marked nonblocking(O_NONBLOCK) and the read would - * block. - * */ - /* is non blocking */ - rv = vppcom_session_read (vsock->sid, __buf, __nbytes); - return rv; -} - -ssize_t -vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt) -{ - int rv; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - ssize_t total = 0, len = 0; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX) - return -EINVAL; - - /* Sanity check */ - for (int i = 0; i < __iovcnt; ++i) - { - if (SSIZE_MAX - len < __iov[i].iov_len) - return -EINVAL; - len += __iov[i].iov_len; - } - - rv = vcom_fcntl (__fd, F_GETFL, 0); - if (rv < 0) - { - return rv; - } - - /* is blocking */ - if (!(rv & O_NONBLOCK)) - { - do - { - for (int i = 0; i < __iovcnt; ++i) - { - rv = vppcom_session_read (vsock->sid, __iov[i].iov_base, - __iov[i].iov_len); - if (rv < 0) - break; - else - { - total += rv; - if (rv < __iov[i].iov_len) - /* Read less than buffer provided, no point to continue */ - break; - } - } - } - while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0); - return total; - } - - /* is non blocking */ - for (int i = 0; i < __iovcnt; ++i) - { - rv = vppcom_session_read (vsock->sid, __iov[i].iov_base, - __iov[i].iov_len); - if (rv < 0) - { - if (total > 0) - break; - else - { - errno = rv; - return rv; - } - } - else - { - total += rv; - if (rv < __iov[i].iov_len) - /* Read less than buffer provided, no point to continue */ - break; - } - } - return total; -} - -ssize_t -vcom_socket_write (int __fd, const void *__buf, size_t __n) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__buf || __n < 0) - { - return -EINVAL; - } - - rv = vppcom_session_write (vsock->sid, (void *) __buf, __n); - return rv; -} - -ssize_t -vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt) -{ - int rv = -1; - ssize_t total = 0; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX) - return -EINVAL; - - for (int i = 0; i < __iovcnt; ++i) - { - rv = vppcom_session_write (vsock->sid, __iov[i].iov_base, - __iov[i].iov_len); - if (rv < 0) - { - if (total > 0) - break; - else - return rv; - } - else - total += rv; - } - return total; -} - -/* - * RETURN: 0 - invalid cmd - * 1 - cmd not handled by vcom and vppcom - * 2 - cmd handled by vcom socket resource - * 3 - cmd handled by vppcom - * */ -/* TBD: incomplete list of cmd */ -static int -vcom_socket_check_fcntl_cmd (int __cmd) -{ - switch (__cmd) - { - /*cmd not handled by vcom and vppcom */ - /* Fallthrough */ - case F_DUPFD: - case F_DUPFD_CLOEXEC: - return 1; - - /* cmd handled by vcom socket resource */ - /* Fallthrough */ - case F_GETFD: - case F_SETFD: - case F_GETLK: - case F_SETLK: - case F_SETLKW: - case F_GETOWN: - case F_SETOWN: - return 2; - - /* cmd handled by vcom and vppcom */ - case F_SETFL: - case F_GETFL: - return 3; - - /* cmd not handled by vcom and vppcom */ - default: - return 1; - } - return 0; -} - -static inline int -vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap) -{ - int flags = va_arg (__ap, int); - int rv = -EOPNOTSUPP; - uint32_t size; - - size = sizeof (flags); - if (__cmd == F_SETFL) - { - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size); - } - else if (__cmd == F_GETFL) - { - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size); - if (rv == VPPCOM_OK) - rv = flags; - } - - return rv; -} - -int -vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap) -{ - int rv = -EBADF; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - switch (vcom_socket_check_fcntl_cmd (__cmd)) - { - /* invalid cmd */ - case 0: - rv = -EBADF; - break; - /*cmd not handled by vcom and vppcom */ - case 1: - rv = libc_vfcntl (vsock->fd, __cmd, __ap); - break; - /* cmd handled by vcom socket resource */ - case 2: - rv = libc_vfcntl (vsock->fd, __cmd, __ap); - break; - /* cmd handled by vppcom */ - case 3: - rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap); - break; - - default: - rv = -EINVAL; - break; - } - - return rv; -} - -/* - * RETURN: 0 - invalid cmd - * 1 - cmd not handled by vcom and vppcom - * 2 - cmd handled by vcom socket resource - * 3 - cmd handled by vppcom - */ -static int -vcom_socket_check_ioctl_cmd (unsigned long int __cmd) -{ - int rc; - - switch (__cmd) - { - /* cmd handled by vppcom */ - case FIONREAD: - rc = 3; - break; - - /* cmd not handled by vcom and vppcom */ - default: - rc = 1; - break; - } - return rc; -} - -static inline int -vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap) -{ - int rv; - - if (__cmd == FIONREAD) - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0); - else - rv = -EOPNOTSUPP; - return rv; -} - -int -vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap) -{ - int rv = -EBADF; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - switch (vcom_socket_check_ioctl_cmd (__cmd)) - { - /* Not supported cmd */ - case 0: - rv = -EOPNOTSUPP; - break; - - /* cmd not handled by vcom and vppcom */ - case 1: - rv = libc_vioctl (vsock->fd, __cmd, __ap); - break; - - /* cmd handled by vcom socket resource */ - case 2: - rv = libc_vioctl (vsock->fd, __cmd, __ap); - break; - - /* cmd handled by vppcom */ - case 3: - rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap); - break; - - default: - rv = -EINVAL; - break; - } - - return rv; -} - -static inline int -vcom_socket_fds_2_sid_fds ( - /* dest */ - int *vcom_nsid_fds, - fd_set * __restrict vcom_rd_sid_fds, - fd_set * __restrict vcom_wr_sid_fds, - fd_set * __restrict vcom_ex_sid_fds, - /* src */ - int vcom_nfds, - fd_set * __restrict vcom_readfds, - fd_set * __restrict vcom_writefds, - fd_set * __restrict vcom_exceptfds) -{ - int rv = 0; - int fd; - int sid; - /* invalid max_sid is -1 */ - int max_sid = -1; - int nsid = 0; - - /* - * set sid in sid sets corresponding to fd's in fd sets - * compute nsid and vcom_nsid_fds from sid sets - */ - - for (fd = 0; fd < vcom_nfds; fd++) - { - /* - * F fd set, src - * S sid set, dest - */ -#define _(S,F) \ - if ((F) && (S) && FD_ISSET (fd, (F))) \ - { \ - sid = vcom_socket_get_sid (fd); \ - if (sid != INVALID_SESSION_ID) \ - { \ - FD_SET (sid, (S)); \ - if (sid > max_sid) \ - { \ - max_sid = sid; \ - } \ - ++nsid; \ - } \ - else \ - { \ - rv = -EBADFD; \ - goto done; \ - } \ - } - - - _(vcom_rd_sid_fds, vcom_readfds); - _(vcom_wr_sid_fds, vcom_writefds); - _(vcom_ex_sid_fds, vcom_exceptfds); -#undef _ - } - - *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0; - rv = nsid; - -done: - return rv; -} - -/* - * PRE: 00. sid sets were derived from fd sets - * 01. sid sets were updated with sids that actually changed - * status - * 02. fd sets still has watched fds - * - * This function will modify in place fd sets to indicate which fd's - * actually changed status(inferred from sid sets) - */ -static inline int -vcom_socket_sid_fds_2_fds ( - /* dest */ - int *new_vcom_nfds, - int vcom_nfds, - fd_set * __restrict vcom_readfds, - fd_set * __restrict vcom_writefds, - fd_set * __restrict vcom_exceptfds, - /* src */ - int vcom_nsid_fds, - fd_set * __restrict vcom_rd_sid_fds, - fd_set * __restrict vcom_wr_sid_fds, - fd_set * __restrict vcom_ex_sid_fds) -{ - int rv = 0; - int fd; - int sid; - /* invalid max_fd is -1 */ - int max_fd = -1; - int nfd = 0; - - - /* - * modify in place fd sets to indicate which fd's - * actually changed status(inferred from sid sets) - */ - for (fd = 0; fd < vcom_nfds; fd++) - { - /* - * F fd set, dest - * S sid set, src - */ -#define _(S,F) \ - if ((F) && (S) && FD_ISSET (fd, (F))) \ - { \ - sid = vcom_socket_get_sid (fd); \ - if (sid != INVALID_SESSION_ID) \ - { \ - if (!FD_ISSET (sid, (S))) \ - { \ - FD_CLR(fd, (F)); \ - } \ - } \ - else \ - { \ - rv = -EBADFD; \ - goto done; \ - } \ - } - - - _(vcom_rd_sid_fds, vcom_readfds); - _(vcom_wr_sid_fds, vcom_writefds); - _(vcom_ex_sid_fds, vcom_exceptfds); -#undef _ - } - - /* - * compute nfd and new_vcom_nfds from fd sets - */ - for (fd = 0; fd < vcom_nfds; fd++) - { - -#define _(F) \ - if ((F) && FD_ISSET (fd, (F))) \ - { \ - if (fd > max_fd) \ - { \ - max_fd = fd; \ - } \ - ++nfd; \ - } - - - _(vcom_readfds); - _(vcom_writefds); - _(vcom_exceptfds); -#undef _ - - } - - *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0; - rv = nfd; - -done: - return rv; -} - -/* - * PRE: - * vom_socket_select is always called with - * timeout->tv_sec and timeout->tv_usec set to zero. - * hence vppcom_select return immediately. - */ -/* - * TBD: do{body;} while(timeout conditional); timeout loop - */ -int -vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds, - fd_set * __restrict vcom_writefds, - fd_set * __restrict vcom_exceptfds, - struct timeval *__restrict timeout) -{ - static unsigned long vcom_nsid_fds = 0; - int vcom_nsid = 0; - int rv = -EBADF; - pid_t pid = getpid (); - - int new_vcom_nfds = 0; - int new_vcom_nfd = 0; - - /* vcom sid fds */ - fd_set vcom_rd_sid_fds; - fd_set vcom_wr_sid_fds; - fd_set vcom_ex_sid_fds; - - /* in seconds eg. 3.123456789 seconds */ - double time_to_wait = (double) 0; - - /* validate inputs */ - if (vcom_nfds < 0) - { - return -EINVAL; - } - - /* convert timeval timeout to double time_to_wait */ - if (timeout) - { - if (timeout->tv_sec == 0 && timeout->tv_usec == 0) - { - /* polling: vppcom_select returns immediately */ - time_to_wait = (double) 0; - } - else - { - /*TBD: use timeval api */ - time_to_wait = (double) timeout->tv_sec + - (double) timeout->tv_usec / (double) 1000000 + - (double) (timeout->tv_usec % 1000000) / (double) 1000000; - } - } - else - { - /* - * no timeout: vppcom_select can block indefinitely - * waiting for a file descriptor to become ready - * */ - /* set to a phantom value */ - time_to_wait = ~0; - } - - /* zero the sid_sets */ - /* - * F fd set - * S sid set - */ -#define _(S,F) \ - if ((F)) \ - { \ - FD_ZERO ((S)); \ - } - - - _(&vcom_rd_sid_fds, vcom_readfds); - _(&vcom_wr_sid_fds, vcom_writefds); - _(&vcom_ex_sid_fds, vcom_exceptfds); -#undef _ - - if (vcom_nfds == 0) - { - if (time_to_wait > 0) - { - if (VCOM_DEBUG > 0) - fprintf (stderr, - "[%d] vcom_socket_select called to " - "emulate delay_ns()!\n", pid); - rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait); - } - else - { - fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 " - "and invalid time_to_wait (%f)!\n", pid, time_to_wait); - } - return 0; - } - - /* populate read, write and except sid_sets */ - vcom_nsid = vcom_socket_fds_2_sid_fds ( - /* dest */ - vcom_readfds || vcom_writefds - || vcom_exceptfds ? (int *) - &vcom_nsid_fds : NULL, - vcom_readfds ? &vcom_rd_sid_fds : - NULL, - vcom_writefds ? &vcom_wr_sid_fds : - NULL, - vcom_exceptfds ? &vcom_ex_sid_fds : - NULL, - /* src */ - vcom_nfds, - vcom_readfds, - vcom_writefds, vcom_exceptfds); - if (vcom_nsid < 0) - { - return vcom_nsid; - } - if (vcom_nsid_fds < 0) - { - return -EINVAL; - } - - rv = vppcom_select (vcom_nsid_fds, - vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds : - NULL, - vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds : - NULL, - vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds : - NULL, time_to_wait); - if (VCOM_DEBUG > 2) - fprintf (stderr, "[%d] called vppcom_select(): " - "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds); - - /* check if any file descriptors changed status */ - if (rv > 0) - { - /* - * on exit, sets are modified in place to indicate which - * file descriptors actually changed status - * */ - - /* - * comply with pre-condition - * do not clear vcom fd sets befor calling - * vcom_socket_sid_fds_2_fds - */ - new_vcom_nfd = vcom_socket_sid_fds_2_fds ( - /* dest */ - &new_vcom_nfds, - vcom_nfds, - vcom_readfds, - vcom_writefds, - vcom_exceptfds, - /* src */ - vcom_nsid_fds, - vcom_readfds ? - &vcom_rd_sid_fds : NULL, - vcom_writefds ? - &vcom_wr_sid_fds : NULL, - vcom_exceptfds ? - &vcom_ex_sid_fds : NULL); - if (new_vcom_nfd < 0) - { - return new_vcom_nfd; - } - if (new_vcom_nfds < 0) - { - return -EINVAL; - } - rv = new_vcom_nfd; - } - return rv; -} - - -int -vcom_socket_socket (int __domain, int __type, int __protocol) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_socket_t *vsock; - - i32 fd; - i32 sid; - i32 sockidx; - u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0; - int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC); - - fd = vcom_socket_open_socket (__domain, __type, __protocol); - if (fd < 0) - { - rv = fd; - goto out; - } - - sid = vppcom_session_create (VPPCOM_VRF_DEFAULT, - (type == SOCK_DGRAM) ? - VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP, - is_nonblocking); - if (sid < 0) - { - rv = sid; - goto out_close_socket; - } - - pool_get (vsm->vsockets, vsock); - vsocket_init (vsock); - - sockidx = vsock - vsm->vsockets; - hash_set (vsm->sockidx_by_fd, fd, sockidx); - - vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND); - return fd; - -out_close_socket: - vcom_socket_close_socket (fd); -out: - return rv; -} - -int -vcom_socket_socketpair (int __domain, int __type, int __protocol, - int __fds[2]) -{ -/* TBD: */ - return 0; -} - -int -vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - vppcom_endpt_t ep; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__addr) - { - return -EINVAL; - } - - ep.vrf = VPPCOM_VRF_DEFAULT; - switch (__addr->sa_family) - { - case AF_INET: - if (__len != sizeof (struct sockaddr_in)) - { - return -EINVAL; - } - ep.is_ip4 = VPPCOM_IS_IP4; - ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr; - ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port; - break; - - case AF_INET6: - if (__len != sizeof (struct sockaddr_in6)) - { - return -EINVAL; - } - ep.is_ip4 = VPPCOM_IS_IP6; - ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr; - ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port; - break; - - default: - return -1; - break; - } - - rv = vppcom_session_bind (vsock->sid, &ep); - return rv; -} - -static inline int -vcom_session_getsockname (int sid, vppcom_endpt_t * ep) -{ - int rv; - uint32_t size = sizeof (*ep); - - rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size); - return rv; -} - -int -vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr, - socklen_t * __restrict __len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__addr || !__len) - return -EFAULT; - - if (*__len < 0) - { - return -EINVAL; - } - - vppcom_endpt_t ep; - ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr; - rv = vcom_session_getsockname (vsock->sid, &ep); - if (rv == 0) - { - if (ep.vrf == VPPCOM_VRF_DEFAULT) - { - __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6; - switch (__addr->sa_family) - { - case AF_INET: - ((struct sockaddr_in *) __addr)->sin_port = ep.port; - *__len = sizeof (struct sockaddr_in); - break; - - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - *__len = sizeof (struct sockaddr_in6); - break; - - default: - break; - } - } - } - - return rv; -} - -int -vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - vppcom_endpt_t ep; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - - ep.vrf = VPPCOM_VRF_DEFAULT; - switch (__addr->sa_family) - { - case AF_INET: - ep.is_ip4 = VPPCOM_IS_IP4; - ep.ip = - (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr; - ep.port = - (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port; - break; - - case AF_INET6: - ep.is_ip4 = VPPCOM_IS_IP6; - ep.ip = - (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr; - ep.port = - (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port; - break; - - default: - return -1; - break; - } - - rv = vppcom_session_connect (vsock->sid, &ep); - } - return rv; -} - -static inline int -vcom_session_getpeername (int sid, vppcom_endpt_t * ep) -{ - int rv; - uint32_t size = sizeof (*ep); - - rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size); - return rv; -} - -int -vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr, - socklen_t * __restrict __len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__addr || !__len) - return -EFAULT; - - if (*__len < 0) - { - return -EINVAL; - } - - vppcom_endpt_t ep; - ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr; - rv = vcom_session_getpeername (vsock->sid, &ep); - if (rv == 0) - { - if (ep.vrf == VPPCOM_VRF_DEFAULT) - { - __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6; - switch (__addr->sa_family) - { - case AF_INET: - ((struct sockaddr_in *) __addr)->sin_port = ep.port; - *__len = sizeof (struct sockaddr_in); - break; - - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - *__len = sizeof (struct sockaddr_in6); - break; - - default: - break; - } - } - } - - return rv; -} - -ssize_t -vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags) -{ - return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0); -} - -ssize_t -vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags) -{ - int rv = -1; - rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0); - return rv; -} - -/* - * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET), - * 0 otherwise - * */ -int -vcom_socket_is_connection_mode_socket (int __fd) -{ - int rv = -1; - /* TBD define new vppcom api */ - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - int type; - socklen_t optlen; - - p = hash_get (vsm->sockidx_by_fd, __fd); - - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND) - { - optlen = sizeof (type); - rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen); - if (rv != 0) - { - return 0; - } - /* get socket type */ - switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - { - case SOCK_STREAM: - case SOCK_SEQPACKET: - return 1; - break; - - default: - return 0; - break; - } - } - } - return 0; -} - -static inline ssize_t -vcom_session_sendto (int __sid, void *__buf, size_t __n, - int __flags, __CONST_SOCKADDR_ARG __addr, - socklen_t __addr_len) -{ - int rv = -1; - /* TBD add new vpp api */ - /* TBD add flags parameter */ - rv = vppcom_session_write (__sid, (void *) __buf, (int) __n); - return rv; -} - -ssize_t -vcom_socket_sendto (int __fd, const void *__buf, size_t __n, - int __flags, __CONST_SOCKADDR_ARG __addr, - socklen_t __addr_len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if ((vsock->type != SOCKET_TYPE_VPPCOM_BOUND) || !__buf || __n < 0) - { - return -EINVAL; - } - - if (vcom_socket_is_connection_mode_socket (__fd)) - { - /* ignore __addr and _addr_len */ - /* and EISCONN may be returned when they are not NULL and 0 */ - if ((__addr != NULL) || (__addr_len != 0)) - { - return -EISCONN; - } - } - else - { - if (!__addr || __addr_len < 0) - { - return -EDESTADDRREQ; - } - /* not a vppcom supported address family */ - if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6)) - { - return -EINVAL; - } - } - - rv = vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n, - __flags, __addr, __addr_len); - return rv; -} - -static inline ssize_t -vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n, - int __flags, __SOCKADDR_ARG __addr, - socklen_t * __restrict __addr_len) -{ - int rv = -1; - - /* TBD add flags parameter */ - rv = vppcom_session_read (__sid, __buf, __n); - return rv; -} - -ssize_t -vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n, - int __flags, __SOCKADDR_ARG __addr, - socklen_t * __restrict __addr_len) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if ((vsock->type != SOCKET_TYPE_VPPCOM_BOUND) || - !__buf || __n < 0 || !__addr || !__addr_len || (__addr_len < 0)) - { - return -EINVAL; - } - - rv = vcom_session_recvfrom (vsock->sid, __buf, __n, - __flags, __addr, __addr_len); - return rv; -} - -/* TBD: move it to vppcom */ -static inline ssize_t -vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags) -{ - int rv = -1; - /* rv = vppcom_session_write (__sid, (void *) __message->__buf, - (int)__n); */ - return rv; -} - -ssize_t -vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vcom_socket_is_connection_mode_socket (__fd)) - { - /* ignore __addr and _addr_len */ - /* and EISCONN may be returned when they are not NULL and 0 */ - if ((__message->msg_name != NULL) || (__message->msg_namelen != 0)) - { - return -EISCONN; - } - } - else - { - /* TBD: validate __message->msg_name and __message->msg_namelen - * and return -EINVAL on validation error - * */ - ; - } - - rv = vcom_session_sendmsg (vsock->sid, __message, __flags); - - return rv; -} - -#ifdef __USE_GNU -int -vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages, - unsigned int __vlen, int __flags) -{ - - /* TBD: define a new vppcom api */ - return 0; -} -#endif - -/* TBD: move it to vppcom */ -static inline ssize_t -vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags) -{ - int rv = -1; - /* rv = vppcom_session_read (__sid, (void *) __message->__buf, - (int)__n); */ - rv = -EOPNOTSUPP; - return rv; -} - -ssize_t -vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__message) - { - return -EINVAL; - } - - /* validate __flags */ - - rv = vcom_session_recvmsg (vsock->sid, __message, __flags); - return rv; -} - -#ifdef __USE_GNU -int -vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages, - unsigned int __vlen, int __flags, - struct timespec *__tmo) -{ - /* TBD: define a new vppcom api */ - return 0; -} -#endif - -/* TBD: move it to vppcom */ -static inline int -vcom_session_get_sockopt (int __sid, int __level, int __optname, - void *__restrict __optval, - socklen_t * __restrict __optlen) -{ - /* 1. for socket level options that are NOT socket attributes - * and that has corresponding vpp options get from vppcom */ - return 0; -} - -int -vcom_socket_getsockopt (int __fd, int __level, int __optname, - void *__restrict __optval, - socklen_t * __restrict __optlen) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - if (!__optval && !__optlen) - return -EFAULT; - - if (*__optlen < 0) - { - return -EINVAL; - } - - switch (__level) - { - /* handle options at socket level */ - case SOL_SOCKET: - switch (__optname) - { -/* - * 1. for socket level options that are socket attributes, - * get from libc_getsockopt. - * 2. for socket level options that are NOT socket - * attributes and that has corresponding vpp options - * get from vppcom. - * 3. for socket level options unimplemented - * return -ENOPROTOOPT */ - case SO_DEBUG: - case SO_DONTROUTE: - case SO_BROADCAST: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_REUSEADDR: - case SO_REUSEPORT: - case SO_KEEPALIVE: - case SO_TYPE: - case SO_PROTOCOL: - case SO_DOMAIN: - case SO_ERROR: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: - case SO_LINGER: - case SO_BSDCOMPAT: - case SO_TIMESTAMP: - case SO_TIMESTAMPNS: - case SO_TIMESTAMPING: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - case SO_RCVLOWAT: - case SO_SNDLOWAT: - case SO_PASSCRED: - case SO_PEERCRED: - case SO_PEERNAME: - case SO_ACCEPTCONN: - case SO_PASSSEC: - case SO_PEERSEC: - case SO_MARK: - case SO_RXQ_OVFL: - case SO_WIFI_STATUS: - case SO_PEEK_OFF: - case SO_NOFCS: - case SO_BINDTODEVICE: - case SO_GET_FILTER: - case SO_LOCK_FILTER: - case SO_BPF_EXTENSIONS: - case SO_SELECT_ERR_QUEUE: -#ifdef CONFIG_NET_RX_BUSY_POLL - case SO_BUSY_POLL: -#endif - case SO_MAX_PACING_RATE: - case SO_INCOMING_CPU: - rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen); - if (rv != 0) - { - rv = -errno; - return rv; - } - break; - - default: - /* We implement the SO_SNDLOWAT etc to not be settable - * (1003.1g 7). - */ - return -ENOPROTOOPT; - } - - break; - - default: - /* 1. handle options that are NOT socket level options, - * but have corresponding vpp otions. */ - rv = vcom_session_get_sockopt (vsock->sid, __level, __optname, - __optval, __optlen); - break; - } - - return rv; -} - -/* TBD: move it to vppcom */ -static inline int -vcom_session_setsockopt (int __sid, int __level, int __optname, - const void *__optval, socklen_t __optlen) -{ - int rv = -EOPNOTSUPP; - - switch (__level) - { - case SOL_TCP: - switch (__optname) - { - case TCP_KEEPIDLE: - rv = - vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0); - break; - case TCP_KEEPINTVL: - rv = - vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0); - break; - default: - break; - } - break; - case SOL_IPV6: - switch (__optname) - { - case IPV6_V6ONLY: - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0); - break; - default: - break; - } - break; - case SOL_SOCKET: - switch (__optname) - { - case SO_KEEPALIVE: - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0); - break; - case SO_REUSEADDR: - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0); - break; - case SO_BROADCAST: - rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0); - break; - default: - break; - } - break; - default: - break; - } - - return rv; -} - -int -vcom_socket_setsockopt (int __fd, int __level, int __optname, - const void *__optval, socklen_t __optlen) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (!p) - return -EBADF; - - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - if (!vsock) - return -ENOTSOCK; - - if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND) - return -EINVAL; - - /* - * Options without arguments - */ - - if (__optname == SO_BINDTODEVICE) - { - rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen); - if (rv != 0) - { - rv = -errno; - } - return rv; - } - - if (!__optval) - return -EFAULT; - - if ((__optlen < 0) || (__optlen < sizeof (int))) - return -EINVAL; - - switch (__level) - { - case SOL_IPV6: - switch (__optname) - { - case IPV6_V6ONLY: - rv = vcom_session_setsockopt (vsock->sid, __level, __optname, - __optval, __optlen); - break; - default: - return -EOPNOTSUPP; - } - break; - case SOL_TCP: - switch (__optname) - { - case TCP_NODELAY: - return 0; - case TCP_KEEPIDLE: - case TCP_KEEPINTVL: - rv = vcom_session_setsockopt (vsock->sid, __level, __optname, - __optval, __optlen); - break; - default: - return -EOPNOTSUPP; - } - break; - /* handle options at socket level */ - case SOL_SOCKET: - switch (__optname) - { - case SO_REUSEADDR: - case SO_BROADCAST: - case SO_KEEPALIVE: - rv = vcom_session_setsockopt (vsock->sid, __level, __optname, - __optval, __optlen); - break; - - /* - * 1. for socket level options that are socket attributes, - * set it from libc_getsockopt - * 2. for socket level options that are NOT socket - * attributes and that has corresponding vpp options - * set it from vppcom - * 3. for socket level options unimplemented - * return -ENOPROTOOPT */ - case SO_DEBUG: - case SO_DONTROUTE: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_REUSEPORT: - case SO_TYPE: - case SO_PROTOCOL: - case SO_DOMAIN: - case SO_ERROR: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: - case SO_LINGER: - case SO_BSDCOMPAT: - case SO_TIMESTAMP: - case SO_TIMESTAMPNS: - case SO_TIMESTAMPING: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - case SO_RCVLOWAT: - case SO_SNDLOWAT: - case SO_PASSCRED: - case SO_PEERCRED: - case SO_PEERNAME: - case SO_ACCEPTCONN: - case SO_PASSSEC: - case SO_PEERSEC: - case SO_MARK: - case SO_RXQ_OVFL: - case SO_WIFI_STATUS: - case SO_PEEK_OFF: - case SO_NOFCS: - /* - * SO_BINDTODEVICE already handled as - * "Options without arguments" */ - /* case SO_BINDTODEVICE: */ - case SO_GET_FILTER: - case SO_LOCK_FILTER: - case SO_BPF_EXTENSIONS: - case SO_SELECT_ERR_QUEUE: -#ifdef CONFIG_NET_RX_BUSY_POLL - case SO_BUSY_POLL: -#endif - case SO_MAX_PACING_RATE: - case SO_INCOMING_CPU: - rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen); - if (rv != 0) - { - rv = -errno; - return rv; - } - break; - - default: - /* We implement the SO_SNDLOWAT etc to not be settable - * (1003.1g 7). - */ - return -ENOPROTOOPT; - } - - break; - - default: - return -ENOPROTOOPT; - } - - return rv; -} - -int -vcom_socket_listen (int __fd, int __n) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - - /* TBD vppcom to accept __n parameter */ - rv = vppcom_session_listen (vsock->sid, __n); - } - - return rv; -} - -static int -vcom_socket_connected_socket (int __fd, int __sid, - int *__domain, - int *__type, int *__protocol, int flags) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_socket_t *vsock; - - i32 fd; - i32 sockidx; - - socklen_t optlen; - - optlen = sizeof (*__domain); - rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen); - if (rv != 0) - { - rv = -errno; - goto out; - } - - optlen = sizeof (*__type); - rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen); - if (rv != 0) - { - rv = -errno; - goto out; - } - - optlen = sizeof (*__protocol); - rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen); - if (rv != 0) - { - rv = -errno; - goto out; - } - - fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol); - if (fd < 0) - { - rv = fd; - goto out; - } - - pool_get (vsm->vsockets, vsock); - vsocket_init (vsock); - - sockidx = vsock - vsm->vsockets; - hash_set (vsm->sockidx_by_fd, fd, sockidx); - - vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND); - return fd; - -out: - return rv; -} - -/* If flag is 0, then accept4() is the same as accept(). - * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags - */ -static int -vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr, - socklen_t * __restrict __addr_len, int flags) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - int fd; - int sid; - int domain; - int type; - int protocol; - - uint8_t addr8[sizeof (struct in6_addr)]; - vppcom_endpt_t ep; - - ep.ip = addr8; - - /* validate flags */ - - /* - * for documentation - * switch (flags) - * { - * case 0: - * case SOCK_NONBLOCK: - * case SOCK_CLOEXEC: - * case SOCK_NONBLOCK | SOCK_CLOEXEC: - * break; - * - * default: - * return -1; - * } - */ - /* flags can be 0 or can be bitwise OR - * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */ - - if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC)))) - { - /* TBD: return proper error code */ - return -1; - } - - /* TBD: return proper error code */ - - if (!vcom_socket_is_connection_mode_socket (__fd)) - { - return -EOPNOTSUPP; - } - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - - - rv = vcom_fcntl (vsock->fd, F_GETFL, 0); - if (rv < 0) - { - return rv; - } - - /* is blocking */ - if (!(rv & O_NONBLOCK)) - { - /* socket is not marked as nonblocking - * and no pending connections are present - * on the queue, accept () blocks the caller - * until a connection is present. - */ - rv = vppcom_session_accept (vsock->sid, &ep, - -1.0 /* wait forever */ ); - } - else - { - /* The file descriptor refers to a socket and has been - * marked nonblocking(O_NONBLOCK) and the accept would - * block. - * */ - /* is non blocking */ - rv = vppcom_session_accept (vsock->sid, &ep, 0); - /* If the socket is marked nonblocking and - * no pending connections are present on the - * queue, accept fails with the error - * EAGAIN or EWOULDBLOCK - */ - if (rv == VPPCOM_ETIMEDOUT) - { - rv = VPPCOM_EAGAIN; - } - } - if (rv < 0) - { - return rv; - } - - sid = rv; - - /* create a new connected socket resource and set flags - * on the new file descriptor. - * update vsockets and sockidx_by_fd table - * */ - fd = vcom_socket_connected_socket (__fd, sid, - &domain, &type, &protocol, flags); - if (fd < 0) - { - return fd; - } - - rv = fd; - - /* TBD populate __addr and __addr_len */ - /* TBD: The returned address is truncated if the buffer - * provided is too small, in this case, __addr_len will - * return a value greater than was supplied to the call.*/ - if (__addr) - { - if (ep.is_cut_thru) - { - /* TBD populate __addr and __addr_len */ - switch (domain) - { - case AF_INET: - ((struct sockaddr_in *) __addr)->sin_family = AF_INET; - ((struct sockaddr_in *) __addr)->sin_port = ep.port; - memcpy (&((struct sockaddr_in *) __addr)->sin_addr, - addr8, sizeof (struct in_addr)); - /* TBD: populate __addr_len */ - if (__addr_len) - { - *__addr_len = sizeof (struct sockaddr_in); - } - break; - - case AF_INET6: - ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6; - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr. - __in6_u.__u6_addr8, addr8, - sizeof (struct in6_addr)); - /* TBD: populate __addr_len */ - if (__addr_len) - { - *__addr_len = sizeof (struct sockaddr_in6); - } - break; - - default: - return -EAFNOSUPPORT; - } - } - else - { - switch (ep.is_ip4) - { - case VPPCOM_IS_IP4: - ((struct sockaddr_in *) __addr)->sin_family = AF_INET; - ((struct sockaddr_in *) __addr)->sin_port = ep.port; - memcpy (&((struct sockaddr_in *) __addr)->sin_addr, - addr8, sizeof (struct in_addr)); - /* TBD: populate __addr_len */ - if (__addr_len) - { - *__addr_len = sizeof (struct sockaddr_in); - } - break; - - case VPPCOM_IS_IP6: - ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6; - ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port; - memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr. - __in6_u.__u6_addr8, addr8, - sizeof (struct in6_addr)); - /* TBD: populate __addr_len */ - if (__addr_len) - { - *__addr_len = sizeof (struct sockaddr_in6); - } - break; - - default: - return -EAFNOSUPPORT; - } - } - } - else - { - /* when __addr is NULL, nothing is filled in, - * in this case, __addr_len is not used, - * and should also be null - * */ - if (__addr_len) - { - /* TBD: return proper error code */ - return -1; - } - } - } - - return rv; -} - -int -vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr, - socklen_t * __restrict __addr_len) -{ - /* set flags to 0 for accept() */ - return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0); -} - -#ifdef __USE_GNU -int -vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr, - socklen_t * __restrict __addr_len, int __flags) -{ - /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */ - return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags); -} -#endif - -/* TBD: move it to vppcom */ -static inline int -vcom_session_shutdown (int __fd, int __how) -{ - return 0; -} - -int -vcom_socket_shutdown (int __fd, int __how) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - uword *p; - vcom_socket_t *vsock; - - p = hash_get (vsm->sockidx_by_fd, __fd); - if (p) - { - vsock = pool_elt_at_index (vsm->vsockets, p[0]); - switch (__how) - { - case SHUT_RD: - case SHUT_WR: - case SHUT_RDWR: - rv = vcom_session_shutdown (vsock->sid, __how); - return rv; - break; - - default: - return -EINVAL; - break; - } - } - - return rv; -} - -int -vcom_socket_epoll_create1 (int __flags) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_epoll_t *vepoll; - - i32 epfd; - i32 vep_idx; - i32 epollidx; - - epfd = vcom_socket_open_epoll (__flags); - if (epfd < 0) - { - rv = epfd; - goto out; - } - - vep_idx = vppcom_epoll_create (); - if (vep_idx < 0) - { - rv = vep_idx; - goto out_close_epoll; - } - - pool_get (vsm->vepolls, vepoll); - vepoll_init (vepoll); - - epollidx = vepoll - vsm->vepolls; - hash_set (vsm->epollidx_by_epfd, epfd, epollidx); - - vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0); - - return epfd; - -out_close_epoll: - vcom_socket_close_epoll (epfd); -out: - return rv; -} - -/* - * PRE: vppcom_epoll_ctl() is successful - * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put - */ -int -vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd, - struct epoll_event *__event, - i32 vep_idx, vcom_epoll_t * vepoll, - i32 vfd_id, void *vfd, vcom_fd_type_t type, - int free_vepitem_on_del) -{ - int rv = -1; - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_epitem_t *vepitem; - - vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd }; - uword *p; - i32 vepitemidx; - - i32 *vepitemidxs = 0; - - struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD }; - - i32 vec_idx; - - /* perform control operations on the epoll instance */ - switch (__op) - { - case EPOLL_CTL_ADD: - /* - * supplied file descriptor is already - * registered with this epoll instance - * */ - /* vepitem exists */ - p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key); - if (p) - { - rv = -EEXIST; - goto out; - } - - /* add a new vepitem */ - pool_get (vsm->vepitems, vepitem); - vepitem_init (vepitem); - - vepitemidx = vepitem - vsm->vepitems; - hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx); - vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent); - - /* update epitemidxs */ - /* by_epfd */ - p = hash_get (vsm->epitemidxs_by_epfd, __epfd); - if (!p) /* not exist */ - { - vepitemidxs = 0; - vec_add1 (vepitemidxs, vepitemidx); - hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs); - } - else /* exists */ - { - vepitemidxs = *(i32 **) p; - vec_add1 (vepitemidxs, vepitemidx); - hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0); - } - /* update epitemidxs */ - /* by_fd */ - p = hash_get (vsm->epitemidxs_by_fd, __fd); - if (!p) /* not exist */ - { - vepitemidxs = 0; - vec_add1 (vepitemidxs, vepitemidx); - hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs); - } - else /* exists */ - { - vepitemidxs = *(i32 **) p; - vec_add1 (vepitemidxs, vepitemidx); - hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0); - } - - /* increment vepoll fd count by 1 */ - vepoll->count += 1; - - rv = 0; - goto out; - break; - - case EPOLL_CTL_MOD: - /* - * supplied file descriptor is not - * registered with this epoll instance - * */ - /* vepitem not exist */ - p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key); - if (!p) - { - rv = -ENOENT; - goto out; - } - vepitem = pool_elt_at_index (vsm->vepitems, p[0]); - if (vepitem) - { - vepitem->event = *__event; - vepitem->revent = revent; - } - - rv = 0; - goto out; - break; - - case EPOLL_CTL_DEL: - /* - * supplied file descriptor is not - * registered with this epoll instance - * */ - /* vepitem not exist */ - p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key); - if (!p) - { - rv = -ENOENT; - goto out; - } - vepitemidx = *(i32 *) p; - hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key); - - /* update epitemidxs */ - /* by_epfd */ - p = hash_get (vsm->epitemidxs_by_epfd, __epfd); - if (!p) /* not exist */ - { - rv = -ENOENT; - goto out; - } - else /* exists */ - { - vepitemidxs = *(i32 **) p; - vec_idx = vec_search (vepitemidxs, vepitemidx); - if (vec_idx != ~0) - { - vec_del1 (vepitemidxs, vec_idx); - if (!vec_len (vepitemidxs)) - { - vec_free (vepitemidxs); - hash_unset (vsm->epitemidxs_by_epfd, __epfd); - } - } - } - - /* update epitemidxs */ - /* by_fd */ - p = hash_get (vsm->epitemidxs_by_fd, __fd); - if (!p) /* not exist */ - { - rv = -ENOENT; - goto out; - } - else /* exists */ - { - vepitemidxs = *(i32 **) p; - vec_idx = vec_search (vepitemidxs, vepitemidx); - if (vec_idx != ~0) - { - vec_del1 (vepitemidxs, vec_idx); - if (!vec_len (vepitemidxs)) - { - vec_free (vepitemidxs); - hash_unset (vsm->epitemidxs_by_fd, __fd); - } - } - } - - /* pool put vepitem */ - vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx); - if (free_vepitem_on_del) - { - if (!vepitem) - { - rv = -ENOENT; - goto out; - } - vepitem_init (vepitem); - pool_put (vsm->vepitems, vepitem); - } - else - { - if (!vepitem) - { - vepitem_init (vepitem); - } - } - - /* decrement vepoll fd count by 1 */ - vepoll->count -= 1; - - rv = 0; - goto out; - break; - - default: - rv = -EINVAL; - goto out; - break; - } - -out: - return rv; -} - -/* - * PRE: 00. null pointer check on __event - * 01. all other parameters are validated - */ - -static int -vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd, - struct epoll_event *__event, - int free_vepitem_on_del) -{ - int rv = -1; - - /* vcom_socket_main_t *vsm = &vcom_socket_main; */ - vcom_epoll_t *vepoll; - - /*__fd could could be vcom socket or vcom epoll or kernel fd */ - void *vfd; - vcom_epoll_t *vfd_vepoll; - vcom_socket_t *vfd_vsock; - - i32 vep_idx; - i32 vfd_id; - - vcom_fd_type_t type = FD_TYPE_INVALID; - - /* validate __event */ - - /* get vep_idx and vepoll */ - vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll); - if (vep_idx == INVALID_VEP_IDX) - { - return -EBADF; - } - - /* get vcom fd type, vfd_id and vfd */ - vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock); - if (vfd_id != INVALID_SESSION_ID) - { - type = FD_TYPE_VCOM_SOCKET; - vfd = vfd_vsock; - } - else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll)) - != INVALID_VEP_IDX) - { - type = FD_TYPE_EPOLL; - vfd = vfd_vepoll; - } - else - { - /* FD_TYPE_KERNEL not supported by epoll instance */ - type = FD_TYPE_INVALID; - return -EBADF; - } - - - /* vepoll and vsock are now valid */ - rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event); - if (rv < 0) - { - return rv; - } - - rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd, - __event, - vep_idx, vepoll, - vfd_id, vfd, type, free_vepitem_on_del); - return rv; -} - -int -vcom_socket_epoll_ctl (int __epfd, int __op, int __fd, - struct epoll_event *__event) -{ - int rv = -1; - - rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1); - return rv; -} - -static int -vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd, - struct epoll_event *__event) -{ - int rv = -1; - - rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0); - return rv; -} - -int -vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events, - int __maxevents, int __timeout, - const __sigset_t * __ss) -{ - int rv = -EBADF; - - /* in seconds eg. 3.123456789 seconds */ - double time_to_wait = (double) 0; - - i32 vep_idx; - - /* validate __event */ - if (!__events) - { - rv = -EFAULT; - goto out; - } - - /* validate __timeout */ - if (__timeout > 0) - { - time_to_wait = (double) __timeout / (double) 1000; - } - else if (__timeout == 0) - { - time_to_wait = (double) 0; - } - else if (__timeout == -1) - { - time_to_wait = ~0; - } - else - { - rv = -EBADF; - goto out; - } - - /* get vep_idx */ - vep_idx = vcom_socket_get_vep_idx (__epfd); - if (vep_idx != INVALID_VEP_IDX) - { - rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait); - } -out: - return rv; -} - -static inline void -vcom_pollfds_2_selectfds ( - /* src */ - struct pollfd *__fds, nfds_t __nfds, - /* dest */ - int vcom_nfds, - fd_set * __restrict vcom_readfds, - fd_set * __restrict vcom_writefds, - fd_set * __restrict vcom_exceptfds) -{ - nfds_t fds_idx = 0; - - for (fds_idx = 0; fds_idx < __nfds; fds_idx++) - { - /* ignore negative fds */ - if (__fds[fds_idx].fd < 0) - { - continue; - } - - /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */ - FD_SET (__fds[fds_idx].fd, vcom_exceptfds); - - /* requested events */ - if (__fds[fds_idx].events) - { - if (__fds[fds_idx].events & POLLIN) - { - FD_SET (__fds[fds_idx].fd, vcom_readfds); - } - if (__fds[fds_idx].events & POLLPRI) - { - FD_SET (__fds[fds_idx].fd, vcom_readfds); - } - if (__fds[fds_idx].events & POLLOUT) - { - FD_SET (__fds[fds_idx].fd, vcom_writefds); - } -#if defined __USE_XOPEN || defined __USE_XOPEN2K8 - if (__fds[fds_idx].events & POLLRDNORM) - { - FD_SET (__fds[fds_idx].fd, vcom_readfds); - } - if (__fds[fds_idx].events & POLLRDBAND) - { - FD_SET (__fds[fds_idx].fd, vcom_readfds); - } - if (__fds[fds_idx].events & POLLWRNORM) - { - FD_SET (__fds[fds_idx].fd, vcom_writefds); - } - if (__fds[fds_idx].events & POLLWRBAND) - { - FD_SET (__fds[fds_idx].fd, vcom_writefds); - } -#endif - } - } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */ -} - -static inline void -vcom_selectfds_2_pollfds ( - /* dest */ - struct pollfd *__fds, nfds_t __nfds, int *nfd, - /* src */ - int vcom_nfds, - fd_set * __restrict vcom_readfds, - fd_set * __restrict vcom_writefds, - fd_set * __restrict vcom_exceptfds) -{ - nfds_t fds_idx = 0; - - - for (fds_idx = 0; fds_idx < __nfds; fds_idx++) - { - /* ignore negative fds */ - if (__fds[fds_idx].fd < 0) - { - __fds[fds_idx].revents = 0; - } - - /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */ - if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds)) - { - /* - * TBD: for now any select exception - * is flagged as POLLERR - * */ - __fds[fds_idx].revents |= POLLERR; - } - - /* requested events */ - if (__fds[fds_idx].events & POLLIN) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds)) - { - __fds[fds_idx].revents |= POLLIN; - } - } - if (__fds[fds_idx].events & POLLPRI) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds)) - { - __fds[fds_idx].revents |= POLLIN; - } - } - if (__fds[fds_idx].events & POLLOUT) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds)) - { - __fds[fds_idx].revents |= POLLOUT; - } - } -#if defined __USE_XOPEN || defined __USE_XOPEN2K8 - if (__fds[fds_idx].events & POLLRDNORM) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds)) - { - __fds[fds_idx].revents |= POLLRDNORM; - } - } - if (__fds[fds_idx].events & POLLRDBAND) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds)) - { - __fds[fds_idx].revents |= POLLRDBAND; - } - } - if (__fds[fds_idx].events & POLLWRNORM) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds)) - { - __fds[fds_idx].revents |= POLLWRNORM; - } - } - if (__fds[fds_idx].events & POLLWRBAND) - { - if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds)) - { - __fds[fds_idx].revents |= POLLWRBAND; - } - } -#endif - } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */ - - /* - * nfd: - * the number of structures which have nonzero revents fields - * (in other words, those descriptors with events or - * errors reported) - * */ - *nfd = 0; - for (fds_idx = 0; fds_idx < __nfds; fds_idx++) - { - /* ignore negative fds */ - if (__fds[fds_idx].fd < 0) - { - continue; - } - - if (__fds[fds_idx].revents) - { - (*nfd)++; - } - } -} - -/* - * PRE: parameters are validated, - * vcom_socket_poll is always called with __timeout set to zero - * hence returns immediately - * - * ACTION: handle non negative validated vcom fds and ignore rest - */ - -/* - * implements vcom_socket_poll () interface - * - * internally uses vcom_socket_select () - * to realize the behavior - * */ -int -vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds, - int __timeout) -{ - int rv; - pid_t pid = getpid (); - - nfds_t fds_idx = 0; - int nfd = 0; - - /* vcom */ - int vcom_nfds = 0; - fd_set vcom_readfds; - fd_set vcom_writefds; - fd_set vcom_exceptfds; - int vcom_nfd = -1; - /* invalid max_vcom_fd is -1 */ - int max_vcom_fd = -1; - - /* __timeout is zero to get ready events and return immediately */ - struct timeval tv = {.tv_sec = 0,.tv_usec = 0 }; - - /* validate __nfds from select perspective */ - if (__nfds < 0 || __nfds > FD_SETSIZE) - { - rv = -EINVAL; - goto poll_done; - } - - /* zero vcom fd sets */ - /* - * V vcom fd set - */ -#define _(V) \ - FD_ZERO ((V)) - - _(&vcom_readfds); - _(&vcom_writefds); - _(&vcom_exceptfds); -#undef _ - - vcom_nfds = 0; - vcom_nfd = -1; - - - for (fds_idx = 0; fds_idx < __nfds; fds_idx++) - { - /* ignore negative fds */ - if (__fds[fds_idx].fd < 0) - { - continue; - } - - /* non negative validated vcom fds */ - if (__fds[fds_idx].fd > FD_SETSIZE) - { - rv = -EINVAL; - goto poll_done; - } - - /* max_vcom_fd and vcom_nfd */ - if (__fds[fds_idx].fd > max_vcom_fd) - { - /* requested events */ - if (__fds[fds_idx].events) - { - max_vcom_fd = __fds[fds_idx].fd; - } - } - ++vcom_nfd; - } - - vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0; - - if (!vcom_nfds) - { - rv = vcom_nfds; - goto poll_done; - } - - vcom_pollfds_2_selectfds ( - /* src */ - __fds, __nfds, - /* dest */ - vcom_nfds, - &vcom_readfds, &vcom_writefds, &vcom_exceptfds); - - /* select on vcom fds */ - vcom_nfd = vcom_socket_select (vcom_nfds, - &vcom_readfds, - &vcom_writefds, &vcom_exceptfds, &tv); - if (VCOM_DEBUG > 2) - fprintf (stderr, - "[%d] vcom_socket_select: " - "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds); - - if (vcom_nfd < 0) - { - rv = vcom_nfd; - goto poll_done; - } - - vcom_selectfds_2_pollfds ( - /* dest */ - __fds, __nfds, &nfd, - /* src */ - vcom_nfds, - &vcom_readfds, &vcom_writefds, &vcom_exceptfds); - - rv = nfd; - -poll_done: - return rv; -} - -/* - * TBD: remove this static function once vppcom - * has an implementation in place - * - * ACTION: - */ -static int -vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait) -{ - return -EOPNOTSUPP; -} - -int -vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds, - int __timeout) -{ - nfds_t fds_idx = 0; - - /* in seconds eg. 3.123456789 seconds */ - double time_to_wait = (double) 0; - - i32 sid; - i32 vep_idx; - - /* replace vcom fd with session idx */ - for (fds_idx = 0; fds_idx < __nfds; fds_idx++) - { - /* ignore negative fds */ - if (__fds[fds_idx].fd < 0) - { - continue; - } - - /* non negative validated vcom fds */ - sid = vcom_socket_get_sid (__fds[fds_idx].fd); - if (sid != INVALID_SESSION_ID) - { - __fds[fds_idx].fd = sid; - } - else - { - /* get vep_idx */ - vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd); - if (vep_idx != INVALID_VEP_IDX) - { - __fds[fds_idx].fd = vep_idx; - } - else - { - return -EBADF; - } - } - } - - /* validate __timeout */ - if (__timeout > 0) - { - time_to_wait = (double) __timeout / (double) 1000; - } - else if (__timeout == 0) - { - time_to_wait = (double) 0; - } - else if (__timeout < 0) - { - time_to_wait = ~0; - } - else - { - return -EBADF; - } - - return vppcom_poll (__fds, __nfds, time_to_wait); -} - -int -vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) -{ - /* select an implementation */ - - /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */ - return vcom_socket_poll_select_impl (__fds, __nfds, __timeout); -} - -#ifdef __USE_GNU -int -vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds, - const struct timespec *__timeout, const __sigset_t * __ss) -{ - return -EOPNOTSUPP; -} -#endif - -int -vcom_socket_main_init (void) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - - if (VCOM_DEBUG > 0) - printf ("vcom_socket_main_init\n"); - - if (!vsm->init) - { - /* TBD: define FD_MAXSIZE and use it here */ - pool_alloc (vsm->vsockets, FD_SETSIZE); - vsm->sockidx_by_fd = hash_create (0, sizeof (i32)); - - pool_alloc (vsm->vepolls, FD_SETSIZE); - vsm->epollidx_by_epfd = hash_create (0, sizeof (i32)); - - pool_alloc (vsm->vepitems, FD_SETSIZE); - vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32)); - - vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *)); - vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *)); - - vsm->init = 1; - } - - return 0; -} - - -void -vcom_socket_main_show (void) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_socket_t *vsock; - - vcom_epoll_t *vepoll; - - vcom_epitem_t *vepitem; - - i32 epfd; - i32 fd; - i32 *vepitemidxs, *vepitemidxs_var; - - if (vsm->init) - { - /* from active list of vsockets show vsock */ - - /* *INDENT-OFF* */ - pool_foreach (vsock, vsm->vsockets, - ({ - printf( - "fd='%04d', sid='%08x',type='%-30s'\n", - vsock->fd, vsock->sid, - vcom_socket_type_str (vsock->type)); - })); - /* *INDENT-ON* */ - - /* from active list of vepolls, show vepoll */ - - /* *INDENT-OFF* */ - pool_foreach (vepoll, vsm->vepolls, - ({ - printf( - "epfd='%04d', vep_idx='%08x', " - "type='%-30s', " - "flags='%d', count='%d', close='%d'\n", - vepoll->epfd, vepoll->vep_idx, - vcom_socket_epoll_type_str (vepoll->type), - vepoll->flags, vepoll->count, vepoll->close); - })); - /* *INDENT-ON* */ - - /* from active list of vepitems, show vepitem */ - - /* *INDENT-OFF* */ - pool_foreach (vepitem, vsm->vepitems, - ({ - printf( - "epfd='%04d', fd='%04d', " - "next_fd='%04d', prev_fd='%04d', " - "type='%-30s', " - "events='%04x', revents='%04x'\n", - vepitem->epfd, vepitem->fd, - vepitem->next_fd, vepitem->prev_fd, - vcom_socket_vcom_fd_type_str (vepitem->type), - vepitem->event.events, vepitem->revent.events); - })); - - /* *INDENT-ON* */ - - /* show epitemidxs for epfd */ - /* *INDENT-OFF* */ - hash_foreach (epfd, vepitemidxs, - vsm->epitemidxs_by_epfd, - ({ - printf("\n[ '%04d': ", epfd); - vec_foreach (vepitemidxs_var,vepitemidxs) - { - printf("'%04d' ", (int)vepitemidxs_var[0]); - } - printf("]\n"); - })); - /* *INDENT-ON* */ - - /* show epitemidxs for fd */ - /* *INDENT-OFF* */ - hash_foreach (fd, vepitemidxs, - vsm->epitemidxs_by_fd, - ({ - printf("\n{ '%04d': ", fd); - vec_foreach (vepitemidxs_var,vepitemidxs) - { - printf("'%04d' ", (int)vepitemidxs_var[0]); - } - printf("}\n"); - })); - /* *INDENT-ON* */ - - } -} - -void -vcom_socket_main_destroy (void) -{ - vcom_socket_main_t *vsm = &vcom_socket_main; - vcom_socket_t *vsock; - - vcom_epoll_t *vepoll; - - vcom_epitem_t *vepitem; - - i32 epfd; - i32 fd; - i32 *vepitemidxs; - - - if (VCOM_DEBUG > 0) - printf ("vcom_socket_main_destroy\n"); - - if (vsm->init) - { - - /* - * from active list of vepitems, - * remove all "vepitem" elements from the pool in a safe way - * */ - - /* *INDENT-OFF* */ - pool_flush (vepitem, vsm->vepitems, - ({ - if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET) - { - vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL, - vepitem->fd, NULL); - vepitem_init (vepitem); - } - })); - /* *INDENT-ON* */ - - pool_free (vsm->vepitems); - hash_free (vsm->epitemidx_by_epfdfd); - - /* free vepitemidxs for each epfd */ - /* *INDENT-OFF* */ - hash_foreach (epfd, vepitemidxs, - vsm->epitemidxs_by_epfd, - ({ - vec_free (vepitemidxs); - })); - /* *INDENT-ON* */ - hash_free (vsm->epitemidxs_by_epfd); - - /* free vepitemidxs for each fd */ - /* *INDENT-OFF* */ - hash_foreach (fd, vepitemidxs, - vsm->epitemidxs_by_fd, - ({ - vec_free (vepitemidxs); - })); - /* *INDENT-ON* */ - hash_free (vsm->epitemidxs_by_fd); - - - /* - * from active list of vsockets, - * close socket and vppcom session - * */ - - /* *INDENT-OFF* */ - pool_foreach (vsock, vsm->vsockets, - ({ - if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND) - { - vppcom_session_close (vsock->sid); - vcom_socket_close_socket (vsock->fd); - vsocket_init (vsock); - } - })); - /* *INDENT-ON* */ - - /* - * return vsocket element to the pool - * */ - - /* *INDENT-OFF* */ - pool_flush (vsock, vsm->vsockets, - ({ - // vsocket_init(vsock); - ; - })); - /* *INDENT-ON* */ - - pool_free (vsm->vsockets); - hash_free (vsm->sockidx_by_fd); - - /* - * from active list of vepolls, - * close epoll and vppcom_epoll - * */ - - /* *INDENT-OFF* */ - pool_foreach (vepoll, vsm->vepolls, - ({ - if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND) - { - vppcom_session_close (vepoll->vep_idx); - vcom_socket_close_epoll (vepoll->epfd); /* TBD: */ - vepoll_init (vepoll); - } - })); - /* *INDENT-ON* */ - - /* - * return vepoll element to the pool - * */ - - /* *INDENT-OFF* */ - pool_flush (vepoll, vsm->vepolls, - ({ - // vepoll_init(vepoll); - ; - })); - /* *INDENT-ON* */ - - pool_free (vsm->vepolls); - hash_free (vsm->epollidx_by_epfd); - - vsm->init = 0; - } -} - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ |