* Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
* gazelle is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <securec.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <linux/if_xdp.h>
#include <lwip/lwipgz_posix_api.h>
#include <lwip/lwipgz_sock.h>
#include <lwip/tcp.h>
#include "common/gazelle_base_func.h"
#include "lstack_log.h"
#include "lstack_cfg.h"
#include "lstack_preload.h"
#include "lstack_unistd.h"
#include "lstack_epoll.h"
#include "lstack_sockctl.h"
#include "lstack_sockio.h"
#include "lstack_sock_dummy.h"
#include "mbox_ring.h"
#ifndef SOL_XDP
#define SOL_XDP 283
#endif
static posix_api_t g_wrap_api_value = {0};
static posix_api_t *g_wrap_api = NULL;
void wrap_api_init(void)
{
if (g_wrap_api != NULL) {
return;
}
g_wrap_api = &g_wrap_api_value;
if (get_global_cfg_params()->stack_mode_rtc) {
sockctl_rtc_api_init(g_wrap_api);
} else {
sockctl_rtw_api_init(g_wrap_api);
}
epoll_api_init(g_wrap_api);
sockio_api_init(g_wrap_api);
mbox_ring_ops_init();
}
void wrap_api_exit(void)
{
sock_dummy_api_init(g_wrap_api);
}
static inline int32_t do_accept(int32_t s, struct sockaddr *addr, socklen_t *addrlen)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_KERNEL) {
return posix_api->accept_fn(s, addr, addrlen);
}
int fd = 0;
struct lwip_sock *sock = lwip_get_socket(s);
if (POSIX_HAS_TYPE(sock, POSIX_KERNEL)) {
fd = posix_api->accept4_fn(s, addr, addrlen, SOCK_NONBLOCK);
if (fd >= 0) {
return fd;
}
}
fd = g_wrap_api->accept_fn(s, addr, addrlen);
if (fd >= 0) {
sock = lwip_get_socket(fd);
POSIX_SET_TYPE(sock, POSIX_LWIP);
}
return fd;
}
static int32_t do_accept4(int32_t s, struct sockaddr *addr, socklen_t *addrlen, int32_t flags)
{
if (addr == NULL || addrlen == NULL) {
GAZELLE_RETURN(EINVAL);
}
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_KERNEL) {
return posix_api->accept4_fn(s, addr, addrlen, flags);
}
int fd = 0;
struct lwip_sock *sock = lwip_get_socket(s);
if (POSIX_HAS_TYPE(sock, POSIX_KERNEL)) {
fd = posix_api->accept4_fn(s, addr, addrlen, flags);
if (fd >= 0) {
return fd;
}
}
fd = g_wrap_api->accept4_fn(s, addr, addrlen, flags);
if (fd >= 0) {
sock = lwip_get_socket(fd);
POSIX_SET_TYPE(sock, POSIX_LWIP);
}
return fd;
}
static inline int sock_set_nonblocking(int fd)
{
int flags = posix_api->fcntl_fn(fd, F_GETFL, 0);
if (flags == -1) {
LSTACK_LOG(ERR, LSTACK, " get block status faild errno %d.\n", errno);
return -1;
}
flags |= O_NONBLOCK;
if (posix_api->fcntl_fn(fd, F_SETFL, flags) == -1) {
LSTACK_LOG(ERR, LSTACK, " set non_block status faild errno %d.\n", errno);
return -1;
}
return 0;
}
static int kernel_bind_process(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock = lwip_get_socket(s);
int times = 10;
int ret = 0;
bool share_ip = true;
* lstack not sense if ltran enable kni, so only checks use_ltran. */
if (!get_global_cfg_params()->use_ltran && !get_global_cfg_params()->kni_switch &&
!get_global_cfg_params()->flow_bifurcation) {
share_ip = false;
}
ret = posix_api->bind_fn(s, name, namelen);
if (ret < 0 && errno == EADDRNOTAVAIL) {
if (name->sa_family == AF_INET6 && share_ip) {
LSTACK_LOG(WARNING, LSTACK, "virtio_user addr is tentative, please wait... \n");
while (ret != 0 && times-- > 0) {
sleep(1);
ret = posix_api->bind_fn(s, name, namelen);
}
}
}
if (ret == 0) {
if (((struct sockaddr_in *)name)->sin_port == 0) {
struct sockaddr_in kerneladdr;
socklen_t len = sizeof(kerneladdr);
if (posix_api->getsockname_fn(s, (struct sockaddr *)&kerneladdr, &len) < 0) {
LSTACK_LOG(ERR, LSTACK, "kernel getsockname failed, fd=%d, errno=%d\n", s, errno);
return -1;
}
((struct sockaddr_in *)name)->sin_port = kerneladdr.sin_port;
}
sock_set_nonblocking(s);
} else {
POSIX_SET_TYPE(sock, POSIX_LWIP);
LSTACK_LOG(ERR, LSTACK, "kernel bind failed ret %d errno %d sa_family %u times %u\n",
ret, errno, name->sa_family, times);
}
return 0;
}
static int32_t do_bind(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
if (name == NULL) {
GAZELLE_RETURN(EINVAL);
}
struct lwip_sock *sock = lwip_get_socket(s);
if (select_sock_posix_path(sock) == POSIX_KERNEL) {
return posix_api->bind_fn(s, name, namelen);
}
if (IN_MULTICAST(ntohl(((struct sockaddr_in *)name)->sin_addr.s_addr))) {
POSIX_SET_TYPE(sock, POSIX_LWIP);
return g_wrap_api->bind_fn(s, name, namelen);
}
ip_addr_t sock_addr = IPADDR_ANY_TYPE_INIT;
if (name->sa_family == AF_INET) {
sock_addr.type = IPADDR_TYPE_V4;
sock_addr.u_addr.ip4.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
} else if (name->sa_family == AF_INET6) {
sock_addr.type = IPADDR_TYPE_V6;
memcpy_s(sock_addr.u_addr.ip6.addr, IPV6_ADDR_LEN,
((struct sockaddr_in6 *)name)->sin6_addr.s6_addr, IPV6_ADDR_LEN);
}
if (!match_host_addr(&sock_addr)) {
POSIX_SET_TYPE(sock, POSIX_KERNEL);
return posix_api->bind_fn(s, name, namelen);
}
if (kernel_bind_process(s, name, namelen) < 0) {
return -1;
}
return g_wrap_api->bind_fn(s, name, namelen);
}
static bool kernel_ip_match(const struct sockaddr *addr)
{
struct ifaddrs *ifap;
struct ifaddrs *ifa;
if (addr->sa_family == AF_INET) {
if (get_global_cfg_params()->host_addr.addr == ((struct sockaddr_in *)addr)->sin_addr.s_addr) {
return true;
}
} else if (addr->sa_family == AF_INET6) {
if (memcmp(get_global_cfg_params()->host_addr6.addr, &((struct sockaddr_in6 *)addr)->sin6_addr,
sizeof(struct in6_addr)) == 0) {
return true;
}
}
if (getifaddrs(&ifap) == -1) {
LSTACK_LOG(ERR, LSTACK, "get interface IP address failed\n");
return false;
}
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET && addr->sa_family == AF_INET) {
struct sockaddr_in *if_addr = (struct sockaddr_in *)ifa->ifa_addr;
if (memcmp(&if_addr->sin_addr, &((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr)) == 0) {
freeifaddrs(ifap);
return true;
}
} else if (ifa->ifa_addr->sa_family == AF_INET6 && addr->sa_family == AF_INET6) {
struct sockaddr_in6 *if_addr = (struct sockaddr_in6 *)ifa->ifa_addr;
if (memcmp(&if_addr->sin6_addr, &((struct sockaddr_in6 *)addr)->sin6_addr, sizeof(struct in6_addr)) == 0) {
freeifaddrs(ifap);
return true;
}
}
}
freeifaddrs(ifap);
return false;
}
static bool lwip_ip_route(const struct sockaddr *dst_addr)
{
uint32_t host_ip;
uint32_t host_mask;
uint32_t dst_ip;
host_ip = get_global_cfg_params()->host_addr.addr;
host_mask = get_global_cfg_params()->netmask.addr;
if (dst_addr->sa_family == AF_INET) {
dst_ip = ((struct sockaddr_in *)dst_addr) ->sin_addr.s_addr;
if ((host_ip & host_mask) == (dst_ip & host_mask)) {
return true;
}
}
return false;
}
static bool kernel_ip_route(const struct sockaddr *dst_addr)
{
struct ifaddrs *ifap;
struct ifaddrs *ifa;
uint32_t local_ip;
uint32_t local_mask;
uint32_t dst_ip;
bool ret = false;
if (getifaddrs(&ifap) == -1) {
LSTACK_LOG(ERR, LSTACK, "get interface IP address failed\n");
return false;
}
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *if_addr = (struct sockaddr_in *)ifa->ifa_addr;
if (get_global_cfg_params()->host_addr.addr == if_addr->sin_addr.s_addr) {
continue;
}
}
if (ifa->ifa_addr->sa_family == AF_INET && dst_addr->sa_family == AF_INET) {
struct sockaddr_in *if_addr = (struct sockaddr_in *)ifa->ifa_addr;
struct sockaddr_in *ifa_netmask = (struct sockaddr_in *)ifa->ifa_netmask;
local_ip = if_addr->sin_addr.s_addr;
local_mask = ifa_netmask->sin_addr.s_addr;
dst_ip = ((struct sockaddr_in *)dst_addr) ->sin_addr.s_addr;
if ((local_ip & local_mask) == (dst_ip & local_mask)) {
ret = true;
break;
}
}
}
freeifaddrs(ifap);
return ret;
}
static bool should_enter_kernel_connect(const struct sockaddr *addr)
{
#if GAZELLE_SAME_NODE
int32_t remote_port;
char listen_ring_name[RING_NAME_LEN];
remote_port = htons(((struct sockaddr_in *)addr)->sin_port);
snprintf_s(listen_ring_name, sizeof(listen_ring_name), sizeof(listen_ring_name) - 1,
"listen_rx_ring_%d", remote_port);
if (kernel_ip_match(addr) && rte_ring_lookup(listen_ring_name) == NULL) {
return true;
}
#endif
if (lwip_ip_route(addr)) {
return false;
}
if (kernel_ip_route(addr)) {
return true;
}
return false;
}
static int32_t do_connect(int32_t s, const struct sockaddr *addr, socklen_t addrlen)
{
int32_t ret = 0;
if (addr == NULL) {
GAZELLE_RETURN(EINVAL);
}
struct lwip_sock *sock = lwip_get_socket(s);
if (select_sock_posix_path(sock) == POSIX_KERNEL) {
return posix_api->connect_fn(s, addr, addrlen);
}
if (should_enter_kernel_connect(addr)) {
ret = posix_api->connect_fn(s, addr, addrlen);
POSIX_SET_TYPE(sock, POSIX_KERNEL);
return ret;
}
ret = g_wrap_api->connect_fn(s, addr, addrlen);
if (ret == 0 || (ret != 0 && (errno == EINPROGRESS || errno == EISCONN))) {
POSIX_SET_TYPE(sock, POSIX_LWIP);
} else {
ret = posix_api->connect_fn(s, addr, addrlen);
if (ret == 0) {
POSIX_SET_TYPE(sock, POSIX_KERNEL);
}
}
return ret;
}
void do_lwip_connected_callback(int fd)
{
struct lwip_sock *sock = lwip_get_socket(fd);
if (POSIX_IS_CLOSED(sock)) {
return;
}
if (POSIX_HAS_TYPE(sock, POSIX_KERNEL)) {
POSIX_SET_TYPE(sock, POSIX_LWIP);
if (sock->sk_wait != NULL) {
if (sock->sk_wait->type & WAIT_EPOLL) {
epoll_ctl_kernel_event(sock->sk_wait->epfd, EPOLL_CTL_DEL, fd, NULL, sock->sk_wait);
} else if (sock->sk_wait->type & WAIT_POLL) {
poll_ctl_kernel_event(sock->sk_wait->epfd, 0, fd, NULL);
}
}
posix_api->shutdown_fn(fd, SHUT_RDWR);
} else {
POSIX_SET_TYPE(sock, POSIX_LWIP);
}
return;
}
static inline int32_t do_listen(int32_t s, int32_t backlog)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_KERNEL) {
return posix_api->listen_fn(s, backlog);
}
int32_t ret = g_wrap_api->listen_fn(s, backlog);
if (ret != 0) {
return ret;
}
return posix_api->listen_fn(s, backlog);
}
static inline int32_t do_getpeername(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
if (name == NULL || namelen == NULL) {
GAZELLE_RETURN(EINVAL);
}
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->getpeername_fn(s, name, namelen);
}
return posix_api->getpeername_fn(s, name, namelen);
}
static inline int32_t do_getsockname(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
if (name == NULL || namelen == NULL) {
GAZELLE_RETURN(EINVAL);
}
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->getsockname_fn(s, name, namelen);
}
return posix_api->getsockname_fn(s, name, namelen);
}
static bool unsupport_ip_optname(int32_t optname)
{
if (optname == IP_RECVERR) {
return true;
}
return false;
}
static bool unsupport_tcp_optname(int32_t optname)
{
if ((optname == TCP_QUICKACK) ||
(optname == TCP_INFO) ||
(optname == TCP_MAXSEG) ||
(optname == TCP_USER_TIMEOUT) ||
(optname == TCP_CONGESTION)) {
return true;
}
return false;
}
static bool unsupport_socket_optname(int32_t optname)
{
if ((optname == SO_BROADCAST) ||
(optname == SO_PROTOCOL) ||
(optname == SO_RCVBUF) ||
(optname == SO_DONTROUTE)) {
return true;
}
return false;
}
static bool unsupport_xdp_optname(int32_t optname)
{
if (optname == XDP_STATISTICS) {
return true;
}
return false;
}
static bool unsupport_optname(int32_t level, int32_t optname)
{
switch (level) {
case SOL_IP:
return unsupport_ip_optname(optname);
case SOL_TCP:
return unsupport_tcp_optname(optname);
case SOL_SOCKET:
return unsupport_socket_optname(optname);
case SOL_XDP:
return unsupport_xdp_optname(optname);
default:
return false;
}
}
static inline int32_t do_getsockopt(int32_t s, int32_t level, int32_t optname, void *optval, socklen_t *optlen)
{
#define SO_NUMA_ID 0x100c
const struct protocol_stack *stack;
struct lwip_sock *sock;
sock = lwip_get_socket(s);
if (select_sock_posix_path(sock) == POSIX_LWIP && !unsupport_optname(level, optname)) {
if (level == IPPROTO_IP && optname == SO_NUMA_ID) {
stack = get_protocol_stack_by_id(sock->stack_id);
return stack->numa_id;
}
return g_wrap_api->getsockopt_fn(s, level, optname, optval, optlen);
}
return posix_api->getsockopt_fn(s, level, optname, optval, optlen);
}
static inline int32_t do_setsockopt(int32_t s, int32_t level, int32_t optname, const void *optval, socklen_t optlen)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_KERNEL || unsupport_optname(level, optname)) {
return posix_api->setsockopt_fn(s, level, optname, optval, optlen);
}
posix_api->setsockopt_fn(s, level, optname, optval, optlen);
return g_wrap_api->setsockopt_fn(s, level, optname, optval, optlen);
}
static inline int32_t do_socket(int32_t domain, int32_t type, int32_t protocol)
{
int32_t ret;
if (select_posix_path() == POSIX_KERNEL) {
return posix_api->socket_fn(domain, type, protocol);
}
if ((domain != AF_INET && domain != AF_UNSPEC && domain != AF_INET6) ||
((domain == AF_INET6) && ip6_addr_isany(&get_global_cfg_params()->host_addr6)) ||
((type & SOCK_DGRAM) && !get_global_cfg_params()->udp_enable)) {
return posix_api->socket_fn(domain, type, protocol);
}
if (get_global_cfg_params()->stack_mode_rtc) {
if (stack_setup_app_thread() != 0) {
exit(1);
}
}
ret = g_wrap_api->socket_fn(domain, type, protocol);
if (ret >= 0) {
struct lwip_sock *sock = lwip_get_socket(ret);
POSIX_SET_TYPE(sock, POSIX_LWIP | POSIX_KERNEL);
if (type & SOCK_DGRAM) {
POSIX_SET_TYPE(sock, POSIX_LWIP);
}
}
return ret;
}
static inline ssize_t do_recv(int32_t sockfd, void *buf, size_t len, int32_t flags)
{
if (select_sock_posix_path(lwip_get_socket(sockfd)) == POSIX_LWIP) {
return g_wrap_api->recv_fn(sockfd, buf, len, flags);
}
return posix_api->recv_fn(sockfd, buf, len, flags);
}
static inline ssize_t do_read(int32_t s, void *mem, size_t len)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->read_fn(s, mem, len);
}
return posix_api->read_fn(s, mem, len);
}
static inline ssize_t do_readv(int32_t s, const struct iovec *iov, int iovcnt)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->readv_fn(s, iov, iovcnt);
}
return posix_api->readv_fn(s, iov, iovcnt);
}
static inline ssize_t do_send(int32_t sockfd, const void *buf, size_t len, int32_t flags)
{
if (select_sock_posix_path(lwip_get_socket(sockfd)) == POSIX_LWIP) {
return g_wrap_api->send_fn(sockfd, buf, len, flags);
}
return posix_api->send_fn(sockfd, buf, len, flags);
}
static inline ssize_t do_write(int32_t s, const void *mem, size_t size)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->write_fn(s, mem, size);
}
return posix_api->write_fn(s, mem, size);
}
static inline ssize_t do_writev(int32_t s, const struct iovec *iov, int iovcnt)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->writev_fn(s, iov, iovcnt);
}
return posix_api->writev_fn(s, iov, iovcnt);
}
static inline ssize_t do_recvmsg(int32_t s, struct msghdr *message, int32_t flags)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->recvmsg_fn(s, message, flags);
}
return posix_api->recvmsg_fn(s, message, flags);
}
static inline ssize_t do_sendmsg(int32_t s, const struct msghdr *message, int32_t flags)
{
if (select_sock_posix_path(lwip_get_socket(s)) == POSIX_LWIP) {
return g_wrap_api->sendmsg_fn(s, message, flags);
}
return posix_api->sendmsg_fn(s, message, flags);
}
static inline ssize_t do_recvfrom(int32_t sockfd, void *buf, size_t len, int32_t flags,
struct sockaddr *addr, socklen_t *addrlen)
{
if (select_sock_posix_path(lwip_get_socket(sockfd)) == POSIX_LWIP) {
return g_wrap_api->recvfrom_fn(sockfd, buf, len, flags, addr, addrlen);
}
return posix_api->recvfrom_fn(sockfd, buf, len, flags, addr, addrlen);
}
static inline ssize_t do_sendto(int32_t sockfd, const void *buf, size_t len, int32_t flags,
const struct sockaddr *addr, socklen_t addrlen)
{
if (select_sock_posix_path(lwip_get_socket(sockfd)) == POSIX_LWIP) {
return g_wrap_api->sendto_fn(sockfd, buf, len, flags, addr, addrlen);
}
return posix_api->sendto_fn(sockfd, buf, len, flags, addr, addrlen);
}
static inline int32_t do_close(int fd)
{
struct lwip_sock *sock = lwip_get_socket(fd);
* When fd created by lwip_stocket() set as POSIX_KERNEL,
* lwip_close() is still required.
*/
if (select_posix_path() == POSIX_KERNEL ||
POSIX_IS_CLOSED(sock)) {
return posix_api->close_fn(fd);
}
if (select_sock_posix_path(sock) == POSIX_EPOLL) {
return lstack_epoll_close(fd);
}
return g_wrap_api->close_fn(fd);
}
static int32_t do_shutdown(int fd, int how)
{
* When fd created by lwip_stocket() set as POSIX_KERNEL,
* lwip_close() is still required.
*/
if (select_posix_path() == POSIX_KERNEL ||
POSIX_IS_CLOSED(lwip_get_socket(fd))) {
return posix_api->shutdown_fn(fd, how);
}
return g_wrap_api->shutdown_fn(fd, how);
}
static inline int do_epoll_create1(int flags)
{
int epfd;
if (select_posix_path() == POSIX_KERNEL) {
return posix_api->epoll_create1_fn(flags);
}
if (get_global_cfg_params()->stack_mode_rtc) {
if (stack_setup_app_thread() != 0) {
exit(1);
}
}
epfd = g_wrap_api->epoll_create1_fn(flags);
if (epfd > 0) {
POSIX_SET_TYPE(lwip_get_socket(epfd), POSIX_EPOLL);
}
return epfd;
}
static inline int do_epoll_create(int size)
{
* but must be greater than zero. */
return size <= 0 ? -1 : do_epoll_create1(0);
}
static inline int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
{
if (select_sock_posix_path(lwip_get_socket(epfd)) == POSIX_KERNEL) {
return posix_api->epoll_ctl_fn(epfd, op, fd, event);
}
return g_wrap_api->epoll_ctl_fn(epfd, op, fd, event);
}
static inline int do_epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
{
if (select_sock_posix_path(lwip_get_socket(epfd)) == POSIX_KERNEL) {
return posix_api->epoll_wait_fn(epfd, events, maxevents, timeout);
}
return g_wrap_api->epoll_wait_fn(epfd, events, maxevents, timeout);
}
static int32_t do_poll(struct pollfd *fds, nfds_t nfds, int32_t timeout)
{
if ((select_posix_path() == POSIX_KERNEL)) {
return posix_api->poll_fn(fds, nfds, timeout);
}
return g_wrap_api->poll_fn(fds, nfds, timeout);
}
static int32_t do_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)
{
int32_t timeout;
timeout = (tmo_p == NULL) ? -1 : (tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000);
return do_poll(fds, nfds, timeout);
}
static int32_t do_select(int32_t nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
if (select_posix_path() == POSIX_KERNEL) {
return posix_api->select_fn(nfds, readfds, writefds, exceptfds, timeout);
}
return g_wrap_api->select_fn(nfds, readfds, writefds, exceptfds, timeout);
}
static int32_t do_sigaction(int32_t signum, const struct sigaction *act, struct sigaction *oldact)
{
if (unlikely(posix_api == NULL)) {
if (posix_api_init() != 0) {
GAZELLE_RETURN(EAGAIN);
}
return posix_api->sigaction_fn(signum, act, oldact);
}
return lstack_sigaction(signum, act, oldact);
}
#define POSIX_VA_PARAM(fd, cmd, type, lwip_fn, kernel_fn) \
do { \
unsigned long __val; \
va_list __ap; \
va_start(__ap, cmd); \
__val = va_arg(__ap, typeof(__val)); \
va_end(__ap); \
\
int __ret1 = kernel_fn(fd, cmd, __val); \
if (__ret1 == -1 || select_sock_posix_path(lwip_get_socket(fd)) == POSIX_KERNEL) { \
return __ret1; \
} \
int __ret2 = lwip_fn(fd, cmd, (type)__val); \
* if function not implemented, fcntl get/set context will not be modifyed by user path,
* return kernel path result
*/ \
if (__ret2 == -1) { \
if (errno == ENOSYS) { \
return __ret1; \
} \
LSTACK_LOG(ERR, LSTACK, "fd(%d) user path call failed, errno is %d, maybe not error\n", \
fd, errno); \
} \
return __ret2; \
} while (0)
* ------- LD_PRELOAD mode replacement interface --------
* --------------------------------------------------------
*/
int32_t epoll_create1(int32_t flags)
{
return do_epoll_create1(flags);
}
int32_t epoll_create(int32_t size)
{
return do_epoll_create(size);
}
int32_t epoll_ctl(int32_t epfd, int32_t op, int32_t fd, struct epoll_event* event)
{
return do_epoll_ctl(epfd, op, fd, event);
}
int32_t epoll_wait(int32_t epfd, struct epoll_event* events, int32_t maxevents, int32_t timeout)
{
return do_epoll_wait(epfd, events, maxevents, timeout);
}
int32_t fcntl64(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, int, lwip_fcntl, posix_api->fcntl64_fn);
}
int32_t fcntl(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, int, lwip_fcntl, posix_api->fcntl_fn);
}
int32_t ioctl(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, void*, lwip_ioctl, posix_api->ioctl_fn);
}
int32_t accept(int32_t s, struct sockaddr *addr, socklen_t *addrlen)
{
return do_accept(s, addr, addrlen);
}
int32_t accept4(int32_t s, struct sockaddr *addr, socklen_t *addrlen, int32_t flags)
{
return do_accept4(s, addr, addrlen, flags);
}
int32_t bind(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
return do_bind(s, name, namelen);
}
int32_t connect(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
return do_connect(s, name, namelen);
}
int32_t listen(int32_t s, int32_t backlog)
{
return do_listen(s, backlog);
}
int32_t getpeername(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
return do_getpeername(s, name, namelen);
}
int32_t getsockname(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
return do_getsockname(s, name, namelen);
}
int32_t getsockopt(int32_t s, int32_t level, int32_t optname, void *optval, socklen_t *optlen)
{
return do_getsockopt(s, level, optname, optval, optlen);
}
int32_t setsockopt(int32_t s, int32_t level, int32_t optname, const void *optval, socklen_t optlen)
{
return do_setsockopt(s, level, optname, optval, optlen);
}
int32_t socket(int32_t domain, int32_t type, int32_t protocol)
{
return do_socket(domain, type, protocol);
}
ssize_t read(int32_t s, void *mem, size_t len)
{
return do_read(s, mem, len);
}
ssize_t readv(int32_t s, const struct iovec *iov, int iovcnt)
{
return do_readv(s, iov, iovcnt);
}
ssize_t write(int32_t s, const void *mem, size_t size)
{
return do_write(s, mem, size);
}
ssize_t writev(int32_t s, const struct iovec *iov, int iovcnt)
{
return do_writev(s, iov, iovcnt);
}
ssize_t __wrap_write(int32_t s, const void *mem, size_t size)
{
return do_write(s, mem, size);
}
ssize_t __wrap_writev(int32_t s, const struct iovec *iov, int iovcnt)
{
return do_writev(s, iov, iovcnt);
}
ssize_t recv(int32_t sockfd, void *buf, size_t len, int32_t flags)
{
return do_recv(sockfd, buf, len, flags);
}
ssize_t send(int32_t sockfd, const void *buf, size_t len, int32_t flags)
{
return do_send(sockfd, buf, len, flags);
}
ssize_t recvmsg(int32_t s, struct msghdr *message, int32_t flags)
{
return do_recvmsg(s, message, flags);
}
ssize_t sendmsg(int32_t s, const struct msghdr *message, int32_t flags)
{
return do_sendmsg(s, message, flags);
}
ssize_t recvfrom(int32_t sockfd, void *buf, size_t len, int32_t flags,
struct sockaddr *addr, socklen_t *addrlen)
{
return do_recvfrom(sockfd, buf, len, flags, addr, addrlen);
}
ssize_t sendto(int32_t sockfd, const void *buf, size_t len, int32_t flags,
const struct sockaddr *addr, socklen_t addrlen)
{
return do_sendto(sockfd, buf, len, flags, addr, addrlen);
}
int32_t close(int32_t s)
{
return do_close(s);
}
int32_t shutdown(int fd, int how)
{
return do_shutdown(fd, how);
}
int32_t poll(struct pollfd *fds, nfds_t nfds, int32_t timeout)
{
return do_poll(fds, nfds, timeout);
}
int32_t ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)
{
return do_ppoll(fds, nfds, tmo_p, sigmask);
}
int32_t sigaction(int32_t signum, const struct sigaction *act, struct sigaction *oldact)
{
return do_sigaction(signum, act, oldact);
}
pid_t fork(void)
{
return lstack_fork();
}
int32_t select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
return do_select(nfds, readfds, writefds, exceptfds, timeout);
}
* ------- Compile mode replacement interface -----------
* --------------------------------------------------------
*/
int32_t __wrap_epoll_create1(int32_t size)
{
return do_epoll_create1(size);
}
int32_t __wrap_epoll_create(int32_t size)
{
return do_epoll_create(size);
}
int32_t __wrap_epoll_ctl(int32_t epfd, int32_t op, int32_t fd, struct epoll_event* event)
{
return do_epoll_ctl(epfd, op, fd, event);
}
int32_t __wrap_epoll_wait(int32_t epfd, struct epoll_event* events, int32_t maxevents, int32_t timeout)
{
return do_epoll_wait(epfd, events, maxevents, timeout);
}
int32_t __wrap_fcntl64(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, int, lwip_fcntl, posix_api->fcntl64_fn);
}
int32_t __wrap_fcntl(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, int, lwip_fcntl, posix_api->fcntl_fn);
}
int32_t __wrap_ioctl(int32_t s, int32_t cmd, ...)
{
POSIX_VA_PARAM(s, cmd, void*, lwip_ioctl, posix_api->ioctl_fn);
}
int32_t __wrap_accept(int32_t s, struct sockaddr *addr, socklen_t *addrlen)
{
return do_accept(s, addr, addrlen);
}
int32_t __wrap_accept4(int32_t s, struct sockaddr *addr, socklen_t *addrlen, int32_t flags)
{
return do_accept4(s, addr, addrlen, flags);
}
int32_t __wrap_bind(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
return do_bind(s, name, namelen);
}
int32_t __wrap_connect(int32_t s, const struct sockaddr *name, socklen_t namelen)
{
return do_connect(s, name, namelen);
}
int32_t __wrap_listen(int32_t s, int32_t backlog)
{
return do_listen(s, backlog);
}
int32_t __wrap_getpeername(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
return do_getpeername(s, name, namelen);
}
int32_t __wrap_getsockname(int32_t s, struct sockaddr *name, socklen_t *namelen)
{
return do_getsockname(s, name, namelen);
}
int32_t __wrap_getsockopt(int32_t s, int32_t level, int32_t optname, void *optval, socklen_t *optlen)
{
return do_getsockopt(s, level, optname, optval, optlen);
}
int32_t __wrap_setsockopt(int32_t s, int32_t level, int32_t optname, const void *optval, socklen_t optlen)
{
return do_setsockopt(s, level, optname, optval, optlen);
}
int32_t __wrap_socket(int32_t domain, int32_t type, int32_t protocol)
{
return do_socket(domain, type, protocol);
}
ssize_t __wrap_read(int32_t s, void *mem, size_t len)
{
return do_read(s, mem, len);
}
ssize_t __wrap_readv(int32_t s, const struct iovec *iov, int iovcnt)
{
return do_readv(s, iov, iovcnt);
}
ssize_t __wrap_recv(int32_t sockfd, void *buf, size_t len, int32_t flags)
{
return do_recv(sockfd, buf, len, flags);
}
ssize_t __wrap_send(int32_t sockfd, const void *buf, size_t len, int32_t flags)
{
return do_send(sockfd, buf, len, flags);
}
ssize_t __wrap_recvmsg(int32_t s, struct msghdr *message, int32_t flags)
{
return do_recvmsg(s, message, flags);
}
ssize_t __wrap_sendmsg(int32_t s, const struct msghdr *message, int32_t flags)
{
return do_sendmsg(s, message, flags);
}
ssize_t __wrap_recvfrom(int32_t sockfd, void *buf, size_t len, int32_t flags,
struct sockaddr *addr, socklen_t *addrlen)
{
return do_recvfrom(sockfd, buf, len, flags, addr, addrlen);
}
ssize_t __wrap_sendto(int32_t sockfd, const void *buf, size_t len, int32_t flags,
const struct sockaddr *addr, socklen_t addrlen)
{
return do_sendto(sockfd, buf, len, flags, addr, addrlen);
}
int32_t __wrap_close(int32_t s)
{
return do_close(s);
}
int32_t __wrap_shutdown(int fd, int how)
{
return do_shutdown(fd, how);
}
int32_t __wrap_poll(struct pollfd *fds, nfds_t nfds, int32_t timeout)
{
return do_poll(fds, nfds, timeout);
}
int32_t __wrap_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)
{
return do_ppoll(fds, nfds, tmo_p, sigmask);
}
int32_t __wrap_sigaction(int32_t signum, const struct sigaction *act, struct sigaction *oldact)
{
return do_sigaction(signum, act, oldact);
}
pid_t __wrap_fork(void)
{
return lstack_fork();
}
int32_t __wrap_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
return do_select(nfds, readfds, writefds, exceptfds, timeout);
}