2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
19 #define __need_IOV_MAX
20 #include <bits/stdio_lim.h>
21 #include <netinet/tcp.h>
23 #include <vppinfra/types.h>
24 #include <vppinfra/hash.h>
25 #include <vppinfra/pool.h>
27 #include <vcl/vcom_socket.h>
28 #include <vcl/vcom_socket_wrapper.h>
31 #include <vcl/vppcom.h>
35 * VCOM_SOCKET Private definitions and functions.
38 typedef struct vcom_socket_main_t_
42 /* vcom_socket pool */
43 vcom_socket_t *vsockets;
45 /* Hash table for socketidx to fd mapping */
49 vcom_epoll_t *vepolls;
51 /* Hash table for epollidx to epfd mapping */
52 uword *epollidx_by_epfd;
55 /* common epitem poll for all epfd */
56 /* TBD: epitem poll per epfd */
57 /* vcom_epitem pool */
58 vcom_epitem_t *vepitems;
60 /* Hash table for epitemidx to epfdfd mapping */
61 uword *epitemidx_by_epfdfd;
63 /* Hash table - key:epfd, value:vec of epitemidx */
64 uword *epitemidxs_by_epfd;
65 /* Hash table - key:fd, value:vec of epitemidx */
66 uword *epitemidxs_by_fd;
70 vcom_socket_main_t vcom_socket_main;
74 vcom_socket_open_socket (int domain, int type, int protocol)
78 /* handle domains implemented by vpp */
83 /* get socket type and
84 * handle the socket types supported by vpp */
85 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
89 /* the type argument serves a second purpose,
90 * in addition to specifying a socket type,
91 * it may include the bitwise OR of any of
92 * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
93 * the behavior of socket. */
94 rv = libc_socket (domain, type, protocol);
113 vcom_socket_open_epoll (int flags)
121 if (flags && (flags & ~EPOLL_CLOEXEC))
126 /* flags can be either zero or EPOLL_CLOEXEC */
127 rv = libc_epoll_create1 (flags);
135 vcom_socket_close_socket (int fd)
139 rv = libc_close (fd);
147 vcom_socket_close_epoll (int epfd)
151 rv = libc_close (epfd);
159 * Public API functions
164 vcom_socket_is_vcom_fd (int fd)
166 vcom_socket_main_t *vsm = &vcom_socket_main;
168 vcom_socket_t *vsock;
170 p = hash_get (vsm->sockidx_by_fd, fd);
174 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
175 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
182 vcom_socket_is_vcom_epfd (int epfd)
184 vcom_socket_main_t *vsm = &vcom_socket_main;
186 vcom_epoll_t *vepoll;
188 p = hash_get (vsm->epollidx_by_epfd, epfd);
192 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
193 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
200 vcom_socket_get_sid (int fd)
202 vcom_socket_main_t *vsm = &vcom_socket_main;
204 vcom_socket_t *vsock;
206 p = hash_get (vsm->sockidx_by_fd, fd);
210 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
211 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
214 return INVALID_SESSION_ID;
218 vcom_socket_get_vep_idx (int epfd)
220 vcom_socket_main_t *vsm = &vcom_socket_main;
222 vcom_epoll_t *vepoll;
224 p = hash_get (vsm->epollidx_by_epfd, epfd);
228 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
229 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
230 return vepoll->vep_idx;
232 return INVALID_VEP_IDX;
236 vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
238 vcom_socket_main_t *vsm = &vcom_socket_main;
240 vcom_socket_t *vsock;
242 p = hash_get (vsm->sockidx_by_fd, fd);
246 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
247 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
253 return INVALID_SESSION_ID;
257 vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
259 vcom_socket_main_t *vsm = &vcom_socket_main;
261 vcom_epoll_t *vepoll;
263 p = hash_get (vsm->epollidx_by_epfd, epfd);
267 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
268 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
271 return vepoll->vep_idx;
274 return INVALID_VEP_IDX;
279 vcom_socket_close_vepoll (int epfd)
282 vcom_socket_main_t *vsm = &vcom_socket_main;
284 vcom_epoll_t *vepoll;
286 p = hash_get (vsm->epollidx_by_epfd, epfd);
290 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
294 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
311 rv = vppcom_session_close (vepoll->vep_idx);
312 rv = vcom_socket_close_epoll (vepoll->epfd);
314 vepoll_init (vepoll);
315 hash_unset (vsm->epollidx_by_epfd, epfd);
316 pool_put (vsm->vepolls, vepoll);
322 vcom_socket_close_vsock (int fd)
325 vcom_socket_main_t *vsm = &vcom_socket_main;
327 vcom_socket_t *vsock;
329 vcom_epitem_t *vepitem;
331 i32 *vepitemidxs = 0;
332 i32 *vepitemidxs_var = 0;
334 p = hash_get (vsm->sockidx_by_fd, fd);
338 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
342 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
345 rv = vppcom_session_close (vsock->sid);
346 rv = vcom_socket_close_socket (vsock->fd);
348 vsocket_init (vsock);
349 hash_unset (vsm->sockidx_by_fd, fd);
350 pool_put (vsm->vsockets, vsock);
354 * Before calling close(), user should remove
355 * this fd from the epoll-set of all epoll instances,
356 * otherwise resource(epitems) leaks ensues.
360 * 00. close all epoll instances that are marked as "close"
361 * of which this fd is the "last" remaining member.
362 * 01. epitems associated with this fd are intentionally
363 * not removed, see NOTE: above.
366 /* does this fd participate in epoll */
367 p = hash_get (vsm->epitemidxs_by_fd, fd);
370 vepitemidxs = *(i32 **) p;
371 vec_foreach (vepitemidxs_var, vepitemidxs)
373 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
374 if (vepitem && vepitem->fd == fd &&
375 vepitem->type == FD_TYPE_VCOM_SOCKET)
378 vcom_epoll_t *vepoll;
380 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
386 if (vepoll->count == 1)
389 * force count to zero and
390 * close this epoll instance
393 vcom_socket_close_vepoll (vepoll->epfd);
410 vcom_socket_close (int __fd)
414 if (vcom_socket_is_vcom_fd (__fd))
416 rv = vcom_socket_close_vsock (__fd);
418 else if (vcom_socket_is_vcom_epfd (__fd))
420 rv = vcom_socket_close_vepoll (__fd);
431 vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
434 vcom_socket_main_t *vsm = &vcom_socket_main;
436 vcom_socket_t *vsock;
438 p = hash_get (vsm->sockidx_by_fd, __fd);
442 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
446 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
454 rv = vcom_fcntl (__fd, F_GETFL, 0);
462 if (!(rv & O_NONBLOCK))
466 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
468 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
471 /* The file descriptor refers to a socket and has been
472 * marked nonblocking(O_NONBLOCK) and the read would
475 /* is non blocking */
476 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
481 vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
484 vcom_socket_main_t *vsm = &vcom_socket_main;
486 vcom_socket_t *vsock;
487 ssize_t total = 0, len = 0;
490 p = hash_get (vsm->sockidx_by_fd, __fd);
494 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
498 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
501 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
505 for (i = 0; i < __iovcnt; ++i)
507 if (SSIZE_MAX - len < __iov[i].iov_len)
509 len += __iov[i].iov_len;
512 rv = vcom_fcntl (__fd, F_GETFL, 0);
519 if (!(rv & O_NONBLOCK))
523 for (i = 0; i < __iovcnt; ++i)
525 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
532 if (rv < __iov[i].iov_len)
533 /* Read less than buffer provided, no point to continue */
538 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
542 /* is non blocking */
543 for (i = 0; i < __iovcnt; ++i)
545 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
560 if (rv < __iov[i].iov_len)
561 /* Read less than buffer provided, no point to continue */
569 vcom_socket_write (int __fd, const void *__buf, size_t __n)
572 vcom_socket_main_t *vsm = &vcom_socket_main;
574 vcom_socket_t *vsock;
581 p = hash_get (vsm->sockidx_by_fd, __fd);
585 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
589 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
592 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
597 vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
601 vcom_socket_main_t *vsm = &vcom_socket_main;
603 vcom_socket_t *vsock;
606 p = hash_get (vsm->sockidx_by_fd, __fd);
610 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
614 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
617 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
620 for (i = 0; i < __iovcnt; ++i)
622 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
638 * RETURN: 0 - invalid cmd
639 * 1 - cmd not handled by vcom and vppcom
640 * 2 - cmd handled by vcom socket resource
641 * 3 - cmd handled by vppcom
643 /* TBD: incomplete list of cmd */
645 vcom_socket_check_fcntl_cmd (int __cmd)
649 /*cmd not handled by vcom and vppcom */
652 case F_DUPFD_CLOEXEC:
655 /* cmd handled by vcom socket resource */
666 /* cmd handled by vcom and vppcom */
671 /* cmd not handled by vcom and vppcom */
679 vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
681 int flags = va_arg (__ap, int);
682 int rv = -EOPNOTSUPP;
685 size = sizeof (flags);
686 if (__cmd == F_SETFL)
688 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
690 else if (__cmd == F_GETFL)
692 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
701 vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
704 vcom_socket_main_t *vsm = &vcom_socket_main;
706 vcom_socket_t *vsock;
708 p = hash_get (vsm->sockidx_by_fd, __fd);
712 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
716 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
719 switch (vcom_socket_check_fcntl_cmd (__cmd))
725 /*cmd not handled by vcom and vppcom */
727 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
729 /* cmd handled by vcom socket resource */
731 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
733 /* cmd handled by vppcom */
735 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
747 * RETURN: 0 - invalid cmd
748 * 1 - cmd not handled by vcom and vppcom
749 * 2 - cmd handled by vcom socket resource
750 * 3 - cmd handled by vppcom
753 vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
759 /* cmd handled by vppcom */
764 /* cmd not handled by vcom and vppcom */
773 vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
777 if (__cmd == FIONREAD)
778 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
785 vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
788 vcom_socket_main_t *vsm = &vcom_socket_main;
790 vcom_socket_t *vsock;
792 p = hash_get (vsm->sockidx_by_fd, __fd);
796 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
800 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
803 switch (vcom_socket_check_ioctl_cmd (__cmd))
805 /* Not supported cmd */
810 /* cmd not handled by vcom and vppcom */
812 rv = libc_vioctl (vsock->fd, __cmd, __ap);
815 /* cmd handled by vcom socket resource */
817 rv = libc_vioctl (vsock->fd, __cmd, __ap);
820 /* cmd handled by vppcom */
822 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
834 vcom_socket_fds_2_sid_fds (
837 fd_set * __restrict vcom_rd_sid_fds,
838 fd_set * __restrict vcom_wr_sid_fds,
839 fd_set * __restrict vcom_ex_sid_fds,
842 fd_set * __restrict vcom_readfds,
843 fd_set * __restrict vcom_writefds,
844 fd_set * __restrict vcom_exceptfds)
849 /* invalid max_sid is -1 */
854 * set sid in sid sets corresponding to fd's in fd sets
855 * compute nsid and vcom_nsid_fds from sid sets
858 for (fd = 0; fd < vcom_nfds; fd++)
865 if ((F) && (S) && FD_ISSET (fd, (F))) \
867 sid = vcom_socket_get_sid (fd); \
868 if (sid != INVALID_SESSION_ID) \
885 _(vcom_rd_sid_fds, vcom_readfds);
886 _(vcom_wr_sid_fds, vcom_writefds);
887 _(vcom_ex_sid_fds, vcom_exceptfds);
891 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
899 * PRE: 00. sid sets were derived from fd sets
900 * 01. sid sets were updated with sids that actually changed
902 * 02. fd sets still has watched fds
904 * This function will modify in place fd sets to indicate which fd's
905 * actually changed status(inferred from sid sets)
908 vcom_socket_sid_fds_2_fds (
912 fd_set * __restrict vcom_readfds,
913 fd_set * __restrict vcom_writefds,
914 fd_set * __restrict vcom_exceptfds,
917 fd_set * __restrict vcom_rd_sid_fds,
918 fd_set * __restrict vcom_wr_sid_fds,
919 fd_set * __restrict vcom_ex_sid_fds)
924 /* invalid max_fd is -1 */
930 * modify in place fd sets to indicate which fd's
931 * actually changed status(inferred from sid sets)
933 for (fd = 0; fd < vcom_nfds; fd++)
940 if ((F) && (S) && FD_ISSET (fd, (F))) \
942 sid = vcom_socket_get_sid (fd); \
943 if (sid != INVALID_SESSION_ID) \
945 if (!FD_ISSET (sid, (S))) \
958 _(vcom_rd_sid_fds, vcom_readfds);
959 _(vcom_wr_sid_fds, vcom_writefds);
960 _(vcom_ex_sid_fds, vcom_exceptfds);
965 * compute nfd and new_vcom_nfds from fd sets
967 for (fd = 0; fd < vcom_nfds; fd++)
971 if ((F) && FD_ISSET (fd, (F))) \
988 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
997 * vom_socket_select is always called with
998 * timeout->tv_sec and timeout->tv_usec set to zero.
999 * hence vppcom_select return immediately.
1002 * TBD: do{body;} while(timeout conditional); timeout loop
1005 vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1006 fd_set * __restrict vcom_writefds,
1007 fd_set * __restrict vcom_exceptfds,
1008 struct timeval *__restrict timeout)
1010 static unsigned long vcom_nsid_fds = 0;
1013 pid_t pid = getpid ();
1015 int new_vcom_nfds = 0;
1016 int new_vcom_nfd = 0;
1019 fd_set vcom_rd_sid_fds;
1020 fd_set vcom_wr_sid_fds;
1021 fd_set vcom_ex_sid_fds;
1023 /* in seconds eg. 3.123456789 seconds */
1024 double time_to_wait = (double) 0;
1026 /* validate inputs */
1032 /* convert timeval timeout to double time_to_wait */
1035 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1037 /* polling: vppcom_select returns immediately */
1038 time_to_wait = (double) 0;
1042 /*TBD: use timeval api */
1043 time_to_wait = (double) timeout->tv_sec +
1044 (double) timeout->tv_usec / (double) 1000000 +
1045 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1051 * no timeout: vppcom_select can block indefinitely
1052 * waiting for a file descriptor to become ready
1054 /* set to a phantom value */
1058 /* zero the sid_sets */
1070 _(&vcom_rd_sid_fds, vcom_readfds);
1071 _(&vcom_wr_sid_fds, vcom_writefds);
1072 _(&vcom_ex_sid_fds, vcom_exceptfds);
1077 if (time_to_wait > 0)
1081 "[%d] vcom_socket_select called to "
1082 "emulate delay_ns()!\n", pid);
1083 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1087 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1088 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1093 /* populate read, write and except sid_sets */
1094 vcom_nsid = vcom_socket_fds_2_sid_fds (
1096 vcom_readfds || vcom_writefds
1097 || vcom_exceptfds ? (int *)
1098 &vcom_nsid_fds : NULL,
1099 vcom_readfds ? &vcom_rd_sid_fds :
1101 vcom_writefds ? &vcom_wr_sid_fds :
1103 vcom_exceptfds ? &vcom_ex_sid_fds :
1108 vcom_writefds, vcom_exceptfds);
1114 rv = vppcom_select (vcom_nsid_fds,
1115 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1117 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1119 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1120 NULL, time_to_wait);
1122 fprintf (stderr, "[%d] called vppcom_select(): "
1123 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1125 /* check if any file descriptors changed status */
1129 * on exit, sets are modified in place to indicate which
1130 * file descriptors actually changed status
1134 * comply with pre-condition
1135 * do not clear vcom fd sets befor calling
1136 * vcom_socket_sid_fds_2_fds
1138 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1148 &vcom_rd_sid_fds : NULL,
1150 &vcom_wr_sid_fds : NULL,
1152 &vcom_ex_sid_fds : NULL);
1153 if (new_vcom_nfd < 0)
1155 return new_vcom_nfd;
1157 if (new_vcom_nfds < 0)
1168 vcom_socket_socket (int __domain, int __type, int __protocol)
1171 vcom_socket_main_t *vsm = &vcom_socket_main;
1172 vcom_socket_t *vsock;
1177 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1178 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1180 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1187 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1188 (type == SOCK_DGRAM) ?
1189 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1194 goto out_close_socket;
1197 pool_get (vsm->vsockets, vsock);
1198 vsocket_init (vsock);
1200 sockidx = vsock - vsm->vsockets;
1201 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1203 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1207 vcom_socket_close_socket (fd);
1213 vcom_socket_socketpair (int __domain, int __type, int __protocol,
1221 vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1224 vcom_socket_main_t *vsm = &vcom_socket_main;
1226 vcom_socket_t *vsock;
1230 p = hash_get (vsm->sockidx_by_fd, __fd);
1234 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1238 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1246 ep.vrf = VPPCOM_VRF_DEFAULT;
1247 switch (__addr->sa_family)
1250 if (__len != sizeof (struct sockaddr_in))
1254 ep.is_ip4 = VPPCOM_IS_IP4;
1255 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1256 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1260 if (__len != sizeof (struct sockaddr_in6))
1264 ep.is_ip4 = VPPCOM_IS_IP6;
1265 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1266 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1274 rv = vppcom_session_bind (vsock->sid, &ep);
1279 vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1282 uint32_t size = sizeof (*ep);
1284 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1289 vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1290 socklen_t * __restrict __len)
1293 vcom_socket_main_t *vsm = &vcom_socket_main;
1295 vcom_socket_t *vsock;
1298 p = hash_get (vsm->sockidx_by_fd, __fd);
1302 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1306 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1309 if (!__addr || !__len)
1313 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1314 rv = vcom_session_getsockname (vsock->sid, &ep);
1317 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1319 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1320 switch (__addr->sa_family)
1323 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1324 *__len = sizeof (struct sockaddr_in);
1328 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1329 *__len = sizeof (struct sockaddr_in6);
1342 vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1345 vcom_socket_main_t *vsm = &vcom_socket_main;
1347 vcom_socket_t *vsock;
1351 p = hash_get (vsm->sockidx_by_fd, __fd);
1354 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1356 ep.vrf = VPPCOM_VRF_DEFAULT;
1357 switch (__addr->sa_family)
1360 ep.is_ip4 = VPPCOM_IS_IP4;
1362 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1364 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1368 ep.is_ip4 = VPPCOM_IS_IP6;
1370 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1372 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1380 rv = vppcom_session_connect (vsock->sid, &ep);
1386 vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1389 uint32_t size = sizeof (*ep);
1391 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1396 vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1397 socklen_t * __restrict __len)
1400 vcom_socket_main_t *vsm = &vcom_socket_main;
1402 vcom_socket_t *vsock;
1405 p = hash_get (vsm->sockidx_by_fd, __fd);
1409 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1413 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1416 if (!__addr || !__len)
1420 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1421 rv = vcom_session_getpeername (vsock->sid, &ep);
1424 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1426 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1427 switch (__addr->sa_family)
1430 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1431 *__len = sizeof (struct sockaddr_in);
1435 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1436 *__len = sizeof (struct sockaddr_in6);
1449 vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1451 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1455 vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1458 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1463 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1467 vcom_socket_is_connection_mode_socket (int __fd)
1470 /* TBD define new vppcom api */
1471 vcom_socket_main_t *vsm = &vcom_socket_main;
1473 vcom_socket_t *vsock;
1478 p = hash_get (vsm->sockidx_by_fd, __fd);
1482 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1483 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1485 optlen = sizeof (type);
1486 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1491 /* get socket type */
1492 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1495 case SOCK_SEQPACKET:
1508 static inline ssize_t
1509 vcom_session_sendto (int __sid, void *__buf, size_t __n,
1510 int __flags, __CONST_SOCKADDR_ARG __addr,
1511 socklen_t __addr_len)
1514 /* TBD add new vpp api */
1515 /* TBD add flags parameter */
1516 rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1521 vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1522 int __flags, __CONST_SOCKADDR_ARG __addr,
1523 socklen_t __addr_len)
1526 vcom_socket_main_t *vsm = &vcom_socket_main;
1528 vcom_socket_t *vsock;
1535 p = hash_get (vsm->sockidx_by_fd, __fd);
1539 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1543 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1548 if (vcom_socket_is_connection_mode_socket (__fd))
1550 /* ignore __addr and _addr_len */
1551 /* and EISCONN may be returned when they are not NULL and 0 */
1552 if ((__addr != NULL) || (__addr_len != 0))
1561 return -EDESTADDRREQ;
1563 /* not a vppcom supported address family */
1564 if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1570 rv = vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1571 __flags, __addr, __addr_len);
1575 static inline ssize_t
1576 vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1577 int __flags, __SOCKADDR_ARG __addr,
1578 socklen_t * __restrict __addr_len)
1582 /* TBD add flags parameter */
1583 rv = vppcom_session_read (__sid, __buf, __n);
1588 vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1589 int __flags, __SOCKADDR_ARG __addr,
1590 socklen_t * __restrict __addr_len)
1593 vcom_socket_main_t *vsm = &vcom_socket_main;
1595 vcom_socket_t *vsock;
1597 if (!__buf || !__addr || !__addr_len)
1602 p = hash_get (vsm->sockidx_by_fd, __fd);
1606 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1610 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1615 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1616 __flags, __addr, __addr_len);
1620 /* TBD: move it to vppcom */
1621 static inline ssize_t
1622 vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1625 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1631 vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1634 vcom_socket_main_t *vsm = &vcom_socket_main;
1636 vcom_socket_t *vsock;
1638 p = hash_get (vsm->sockidx_by_fd, __fd);
1642 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1646 if (vcom_socket_is_connection_mode_socket (__fd))
1648 /* ignore __addr and _addr_len */
1649 /* and EISCONN may be returned when they are not NULL and 0 */
1650 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1657 /* TBD: validate __message->msg_name and __message->msg_namelen
1658 * and return -EINVAL on validation error
1663 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
1670 vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1671 unsigned int __vlen, int __flags)
1674 /* TBD: define a new vppcom api */
1679 /* TBD: move it to vppcom */
1680 static inline ssize_t
1681 vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
1684 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1691 vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1694 vcom_socket_main_t *vsm = &vcom_socket_main;
1696 vcom_socket_t *vsock;
1698 p = hash_get (vsm->sockidx_by_fd, __fd);
1702 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1706 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1714 /* validate __flags */
1716 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
1722 vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1723 unsigned int __vlen, int __flags,
1724 struct timespec *__tmo)
1726 /* TBD: define a new vppcom api */
1731 /* TBD: move it to vppcom */
1733 vcom_session_get_sockopt (int __sid, int __level, int __optname,
1734 void *__restrict __optval,
1735 socklen_t * __restrict __optlen)
1737 /* 1. for socket level options that are NOT socket attributes
1738 * and that has corresponding vpp options get from vppcom */
1743 vcom_socket_getsockopt (int __fd, int __level, int __optname,
1744 void *__restrict __optval,
1745 socklen_t * __restrict __optlen)
1748 vcom_socket_main_t *vsm = &vcom_socket_main;
1750 vcom_socket_t *vsock;
1752 p = hash_get (vsm->sockidx_by_fd, __fd);
1756 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1760 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1763 if (!__optval && !__optlen)
1768 /* handle options at socket level */
1773 * 1. for socket level options that are socket attributes,
1774 * get from libc_getsockopt.
1775 * 2. for socket level options that are NOT socket
1776 * attributes and that has corresponding vpp options
1778 * 3. for socket level options unimplemented
1779 * return -ENOPROTOOPT */
1798 case SO_TIMESTAMPNS:
1799 case SO_TIMESTAMPING:
1812 case SO_WIFI_STATUS:
1815 case SO_BINDTODEVICE:
1817 case SO_LOCK_FILTER:
1818 case SO_BPF_EXTENSIONS:
1819 case SO_SELECT_ERR_QUEUE:
1820 #ifdef CONFIG_NET_RX_BUSY_POLL
1823 case SO_MAX_PACING_RATE:
1824 #ifdef SO_INCOMING_CPU
1825 case SO_INCOMING_CPU:
1827 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1836 /* We implement the SO_SNDLOWAT etc to not be settable
1839 return -ENOPROTOOPT;
1845 /* 1. handle options that are NOT socket level options,
1846 * but have corresponding vpp otions. */
1847 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1848 __optval, __optlen);
1855 /* TBD: move it to vppcom */
1857 vcom_session_setsockopt (int __sid, int __level, int __optname,
1858 const void *__optval, socklen_t __optlen)
1860 int rv = -EOPNOTSUPP;
1869 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1873 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1883 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
1893 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1896 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
1899 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
1913 vcom_socket_setsockopt (int __fd, int __level, int __optname,
1914 const void *__optval, socklen_t __optlen)
1917 vcom_socket_main_t *vsm = &vcom_socket_main;
1919 vcom_socket_t *vsock;
1921 p = hash_get (vsm->sockidx_by_fd, __fd);
1925 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1929 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1933 * Options without arguments
1936 if (__optname == SO_BINDTODEVICE)
1938 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1949 if (__optlen < sizeof (int))
1958 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1959 __optval, __optlen);
1972 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1973 __optval, __optlen);
1979 /* handle options at socket level */
1986 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1987 __optval, __optlen);
1991 * 1. for socket level options that are socket attributes,
1992 * set it from libc_getsockopt
1993 * 2. for socket level options that are NOT socket
1994 * attributes and that has corresponding vpp options
1995 * set it from vppcom
1996 * 3. for socket level options unimplemented
1997 * return -ENOPROTOOPT */
2013 case SO_TIMESTAMPNS:
2014 case SO_TIMESTAMPING:
2027 case SO_WIFI_STATUS:
2031 * SO_BINDTODEVICE already handled as
2032 * "Options without arguments" */
2033 /* case SO_BINDTODEVICE: */
2035 case SO_LOCK_FILTER:
2036 case SO_BPF_EXTENSIONS:
2037 case SO_SELECT_ERR_QUEUE:
2038 #ifdef CONFIG_NET_RX_BUSY_POLL
2041 case SO_MAX_PACING_RATE:
2042 #ifdef SO_INCOMING_CPU
2043 case SO_INCOMING_CPU:
2045 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2054 /* We implement the SO_SNDLOWAT etc to not be settable
2057 return -ENOPROTOOPT;
2063 return -ENOPROTOOPT;
2070 vcom_socket_listen (int __fd, int __n)
2073 vcom_socket_main_t *vsm = &vcom_socket_main;
2075 vcom_socket_t *vsock;
2077 p = hash_get (vsm->sockidx_by_fd, __fd);
2080 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2082 /* TBD vppcom to accept __n parameter */
2083 rv = vppcom_session_listen (vsock->sid, __n);
2090 vcom_socket_connected_socket (int __fd, int __sid,
2092 int *__type, int *__protocol, int flags)
2095 vcom_socket_main_t *vsm = &vcom_socket_main;
2096 vcom_socket_t *vsock;
2103 optlen = sizeof (*__domain);
2104 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2111 optlen = sizeof (*__type);
2112 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2119 optlen = sizeof (*__protocol);
2120 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2127 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2134 pool_get (vsm->vsockets, vsock);
2135 vsocket_init (vsock);
2137 sockidx = vsock - vsm->vsockets;
2138 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2140 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2147 /* If flag is 0, then accept4() is the same as accept().
2148 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2151 vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2152 socklen_t * __restrict __addr_len, int flags)
2155 vcom_socket_main_t *vsm = &vcom_socket_main;
2157 vcom_socket_t *vsock;
2165 uint8_t addr8[sizeof (struct in6_addr)];
2170 /* validate flags */
2177 * case SOCK_NONBLOCK:
2178 * case SOCK_CLOEXEC:
2179 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2186 /* flags can be 0 or can be bitwise OR
2187 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2189 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2191 /* TBD: return proper error code */
2195 /* TBD: return proper error code */
2197 if (!vcom_socket_is_connection_mode_socket (__fd))
2202 p = hash_get (vsm->sockidx_by_fd, __fd);
2205 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2208 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2215 if (!(rv & O_NONBLOCK))
2217 /* socket is not marked as nonblocking
2218 * and no pending connections are present
2219 * on the queue, accept () blocks the caller
2220 * until a connection is present.
2222 rv = vppcom_session_accept (vsock->sid, &ep,
2223 -1.0 /* wait forever */ );
2227 /* The file descriptor refers to a socket and has been
2228 * marked nonblocking(O_NONBLOCK) and the accept would
2231 /* is non blocking */
2232 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2233 /* If the socket is marked nonblocking and
2234 * no pending connections are present on the
2235 * queue, accept fails with the error
2236 * EAGAIN or EWOULDBLOCK
2238 if (rv == VPPCOM_ETIMEDOUT)
2250 /* create a new connected socket resource and set flags
2251 * on the new file descriptor.
2252 * update vsockets and sockidx_by_fd table
2254 fd = vcom_socket_connected_socket (__fd, sid,
2255 &domain, &type, &protocol, flags);
2263 /* TBD populate __addr and __addr_len */
2264 /* TBD: The returned address is truncated if the buffer
2265 * provided is too small, in this case, __addr_len will
2266 * return a value greater than was supplied to the call.*/
2271 /* TBD populate __addr and __addr_len */
2275 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2276 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2277 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2278 addr8, sizeof (struct in_addr));
2279 /* TBD: populate __addr_len */
2282 *__addr_len = sizeof (struct sockaddr_in);
2287 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2288 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2289 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2290 __in6_u.__u6_addr8, addr8,
2291 sizeof (struct in6_addr));
2292 /* TBD: populate __addr_len */
2295 *__addr_len = sizeof (struct sockaddr_in6);
2300 return -EAFNOSUPPORT;
2308 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2309 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2310 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2311 addr8, sizeof (struct in_addr));
2312 /* TBD: populate __addr_len */
2315 *__addr_len = sizeof (struct sockaddr_in);
2320 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2321 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2322 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2323 __in6_u.__u6_addr8, addr8,
2324 sizeof (struct in6_addr));
2325 /* TBD: populate __addr_len */
2328 *__addr_len = sizeof (struct sockaddr_in6);
2333 return -EAFNOSUPPORT;
2339 /* when __addr is NULL, nothing is filled in,
2340 * in this case, __addr_len is not used,
2341 * and should also be null
2345 /* TBD: return proper error code */
2355 vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2356 socklen_t * __restrict __addr_len)
2358 /* set flags to 0 for accept() */
2359 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2364 vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2365 socklen_t * __restrict __addr_len, int __flags)
2367 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2368 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2372 /* TBD: move it to vppcom */
2374 vcom_session_shutdown (int __fd, int __how)
2380 vcom_socket_shutdown (int __fd, int __how)
2383 vcom_socket_main_t *vsm = &vcom_socket_main;
2385 vcom_socket_t *vsock;
2387 p = hash_get (vsm->sockidx_by_fd, __fd);
2390 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2396 rv = vcom_session_shutdown (vsock->sid, __how);
2410 vcom_socket_epoll_create1 (int __flags)
2413 vcom_socket_main_t *vsm = &vcom_socket_main;
2414 vcom_epoll_t *vepoll;
2420 epfd = vcom_socket_open_epoll (__flags);
2427 vep_idx = vppcom_epoll_create ();
2431 goto out_close_epoll;
2434 pool_get (vsm->vepolls, vepoll);
2435 vepoll_init (vepoll);
2437 epollidx = vepoll - vsm->vepolls;
2438 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2440 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2445 vcom_socket_close_epoll (epfd);
2451 * PRE: vppcom_epoll_ctl() is successful
2452 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2455 vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2456 struct epoll_event *__event,
2457 i32 vep_idx, vcom_epoll_t * vepoll,
2458 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2459 int free_vepitem_on_del)
2462 vcom_socket_main_t *vsm = &vcom_socket_main;
2463 vcom_epitem_t *vepitem;
2465 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2469 i32 *vepitemidxs = 0;
2471 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2475 /* perform control operations on the epoll instance */
2480 * supplied file descriptor is already
2481 * registered with this epoll instance
2483 /* vepitem exists */
2484 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2491 /* add a new vepitem */
2492 pool_get (vsm->vepitems, vepitem);
2493 vepitem_init (vepitem);
2495 vepitemidx = vepitem - vsm->vepitems;
2496 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2497 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2499 /* update epitemidxs */
2501 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2502 if (!p) /* not exist */
2505 vec_add1 (vepitemidxs, vepitemidx);
2506 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2510 vepitemidxs = *(i32 **) p;
2511 vec_add1 (vepitemidxs, vepitemidx);
2512 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2514 /* update epitemidxs */
2516 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2517 if (!p) /* not exist */
2520 vec_add1 (vepitemidxs, vepitemidx);
2521 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2525 vepitemidxs = *(i32 **) p;
2526 vec_add1 (vepitemidxs, vepitemidx);
2527 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2530 /* increment vepoll fd count by 1 */
2539 * supplied file descriptor is not
2540 * registered with this epoll instance
2542 /* vepitem not exist */
2543 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2549 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2552 vepitem->event = *__event;
2553 vepitem->revent = revent;
2562 * supplied file descriptor is not
2563 * registered with this epoll instance
2565 /* vepitem not exist */
2566 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2572 vepitemidx = *(i32 *) p;
2573 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2575 /* update epitemidxs */
2577 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2578 if (!p) /* not exist */
2585 vepitemidxs = *(i32 **) p;
2586 vec_idx = vec_search (vepitemidxs, vepitemidx);
2589 vec_del1 (vepitemidxs, vec_idx);
2590 if (!vec_len (vepitemidxs))
2592 vec_free (vepitemidxs);
2593 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2598 /* update epitemidxs */
2600 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2601 if (!p) /* not exist */
2608 vepitemidxs = *(i32 **) p;
2609 vec_idx = vec_search (vepitemidxs, vepitemidx);
2612 vec_del1 (vepitemidxs, vec_idx);
2613 if (!vec_len (vepitemidxs))
2615 vec_free (vepitemidxs);
2616 hash_unset (vsm->epitemidxs_by_fd, __fd);
2621 /* pool put vepitem */
2622 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2623 if (free_vepitem_on_del)
2630 vepitem_init (vepitem);
2631 pool_put (vsm->vepitems, vepitem);
2637 vepitem_init (vepitem);
2641 /* decrement vepoll fd count by 1 */
2659 * PRE: 00. null pointer check on __event
2660 * 01. all other parameters are validated
2664 vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2665 struct epoll_event *__event,
2666 int free_vepitem_on_del)
2670 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2671 vcom_epoll_t *vepoll;
2673 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2675 vcom_epoll_t *vfd_vepoll;
2676 vcom_socket_t *vfd_vsock;
2681 vcom_fd_type_t type = FD_TYPE_INVALID;
2683 /* validate __event */
2685 /* get vep_idx and vepoll */
2686 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2687 if (vep_idx == INVALID_VEP_IDX)
2692 /* get vcom fd type, vfd_id and vfd */
2693 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2694 if (vfd_id != INVALID_SESSION_ID)
2696 type = FD_TYPE_VCOM_SOCKET;
2699 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2702 type = FD_TYPE_EPOLL;
2707 /* FD_TYPE_KERNEL not supported by epoll instance */
2708 type = FD_TYPE_INVALID;
2713 /* vepoll and vsock are now valid */
2714 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2720 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2723 vfd_id, vfd, type, free_vepitem_on_del);
2728 vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2729 struct epoll_event *__event)
2733 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2738 vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2739 struct epoll_event *__event)
2743 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2748 vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2749 int __maxevents, int __timeout,
2750 const __sigset_t * __ss)
2754 /* in seconds eg. 3.123456789 seconds */
2755 double time_to_wait = (double) 0;
2759 /* validate __event */
2766 /* validate __timeout */
2769 time_to_wait = (double) __timeout / (double) 1000;
2771 else if (__timeout == 0)
2773 time_to_wait = (double) 0;
2775 else if (__timeout == -1)
2786 vep_idx = vcom_socket_get_vep_idx (__epfd);
2787 if (vep_idx != INVALID_VEP_IDX)
2789 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2796 vcom_pollfds_2_selectfds (
2798 struct pollfd *__fds, nfds_t __nfds,
2801 fd_set * __restrict vcom_readfds,
2802 fd_set * __restrict vcom_writefds,
2803 fd_set * __restrict vcom_exceptfds)
2807 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2809 /* ignore negative fds */
2810 if (__fds[fds_idx].fd < 0)
2815 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2816 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2818 /* requested events */
2819 if (__fds[fds_idx].events)
2821 if (__fds[fds_idx].events & POLLIN)
2823 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2825 if (__fds[fds_idx].events & POLLPRI)
2827 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2829 if (__fds[fds_idx].events & POLLOUT)
2831 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2833 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2834 if (__fds[fds_idx].events & POLLRDNORM)
2836 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2838 if (__fds[fds_idx].events & POLLRDBAND)
2840 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2842 if (__fds[fds_idx].events & POLLWRNORM)
2844 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2846 if (__fds[fds_idx].events & POLLWRBAND)
2848 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2852 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2856 vcom_selectfds_2_pollfds (
2858 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2861 fd_set * __restrict vcom_readfds,
2862 fd_set * __restrict vcom_writefds,
2863 fd_set * __restrict vcom_exceptfds)
2868 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2870 /* ignore negative fds */
2871 if (__fds[fds_idx].fd < 0)
2873 __fds[fds_idx].revents = 0;
2876 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2877 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2880 * TBD: for now any select exception
2881 * is flagged as POLLERR
2883 __fds[fds_idx].revents |= POLLERR;
2886 /* requested events */
2887 if (__fds[fds_idx].events & POLLIN)
2889 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2891 __fds[fds_idx].revents |= POLLIN;
2894 if (__fds[fds_idx].events & POLLPRI)
2896 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2898 __fds[fds_idx].revents |= POLLIN;
2901 if (__fds[fds_idx].events & POLLOUT)
2903 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2905 __fds[fds_idx].revents |= POLLOUT;
2908 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2909 if (__fds[fds_idx].events & POLLRDNORM)
2911 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2913 __fds[fds_idx].revents |= POLLRDNORM;
2916 if (__fds[fds_idx].events & POLLRDBAND)
2918 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2920 __fds[fds_idx].revents |= POLLRDBAND;
2923 if (__fds[fds_idx].events & POLLWRNORM)
2925 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2927 __fds[fds_idx].revents |= POLLWRNORM;
2930 if (__fds[fds_idx].events & POLLWRBAND)
2932 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2934 __fds[fds_idx].revents |= POLLWRBAND;
2938 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2942 * the number of structures which have nonzero revents fields
2943 * (in other words, those descriptors with events or
2947 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2949 /* ignore negative fds */
2950 if (__fds[fds_idx].fd < 0)
2955 if (__fds[fds_idx].revents)
2963 * PRE: parameters are validated,
2964 * vcom_socket_poll is always called with __timeout set to zero
2965 * hence returns immediately
2967 * ACTION: handle non negative validated vcom fds and ignore rest
2971 * implements vcom_socket_poll () interface
2973 * internally uses vcom_socket_select ()
2974 * to realize the behavior
2977 vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
2981 pid_t pid = getpid ();
2988 fd_set vcom_readfds;
2989 fd_set vcom_writefds;
2990 fd_set vcom_exceptfds;
2992 /* invalid max_vcom_fd is -1 */
2993 int max_vcom_fd = -1;
2995 /* __timeout is zero to get ready events and return immediately */
2996 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
2998 /* validate __nfds from select perspective */
2999 if (__nfds > FD_SETSIZE)
3005 /* zero vcom fd sets */
3021 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3023 /* ignore negative fds */
3024 if (__fds[fds_idx].fd < 0)
3029 /* non negative validated vcom fds */
3030 if (__fds[fds_idx].fd > FD_SETSIZE)
3036 /* max_vcom_fd and vcom_nfd */
3037 if (__fds[fds_idx].fd > max_vcom_fd)
3039 /* requested events */
3040 if (__fds[fds_idx].events)
3042 max_vcom_fd = __fds[fds_idx].fd;
3048 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3056 vcom_pollfds_2_selectfds (
3061 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3063 /* select on vcom fds */
3064 vcom_nfd = vcom_socket_select (vcom_nfds,
3066 &vcom_writefds, &vcom_exceptfds, &tv);
3069 "[%d] vcom_socket_select: "
3070 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3078 vcom_selectfds_2_pollfds (
3080 __fds, __nfds, &nfd,
3083 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3092 * TBD: remove this static function once vppcom
3093 * has an implementation in place
3098 vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3104 vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3109 /* in seconds eg. 3.123456789 seconds */
3110 double time_to_wait = (double) 0;
3115 /* replace vcom fd with session idx */
3116 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3118 /* ignore negative fds */
3119 if (__fds[fds_idx].fd < 0)
3124 /* non negative validated vcom fds */
3125 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3126 if (sid != INVALID_SESSION_ID)
3128 __fds[fds_idx].fd = sid;
3133 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3134 if (vep_idx != INVALID_VEP_IDX)
3136 __fds[fds_idx].fd = vep_idx;
3145 /* validate __timeout */
3148 time_to_wait = (double) __timeout / (double) 1000;
3150 else if (__timeout == 0)
3152 time_to_wait = (double) 0;
3154 else if (__timeout < 0)
3163 return vppcom_poll (__fds, __nfds, time_to_wait);
3167 vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3169 /* select an implementation */
3171 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3172 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3177 vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3178 const struct timespec *__timeout, const __sigset_t * __ss)
3185 vcom_socket_main_init (void)
3187 vcom_socket_main_t *vsm = &vcom_socket_main;
3190 printf ("vcom_socket_main_init\n");
3194 /* TBD: define FD_MAXSIZE and use it here */
3195 pool_alloc (vsm->vsockets, FD_SETSIZE);
3196 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3198 pool_alloc (vsm->vepolls, FD_SETSIZE);
3199 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3201 pool_alloc (vsm->vepitems, FD_SETSIZE);
3202 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3204 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3205 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3215 vcom_socket_main_show (void)
3217 vcom_socket_main_t *vsm = &vcom_socket_main;
3218 vcom_socket_t *vsock;
3220 vcom_epoll_t *vepoll;
3222 vcom_epitem_t *vepitem;
3226 i32 *vepitemidxs, *vepitemidxs_var;
3230 /* from active list of vsockets show vsock */
3233 pool_foreach (vsock, vsm->vsockets,
3236 "fd='%04d', sid='%08x',type='%-30s'\n",
3237 vsock->fd, vsock->sid,
3238 vcom_socket_type_str (vsock->type));
3242 /* from active list of vepolls, show vepoll */
3245 pool_foreach (vepoll, vsm->vepolls,
3248 "epfd='%04d', vep_idx='%08x', "
3250 "flags='%d', count='%d', close='%d'\n",
3251 vepoll->epfd, vepoll->vep_idx,
3252 vcom_socket_epoll_type_str (vepoll->type),
3253 vepoll->flags, vepoll->count, vepoll->close);
3257 /* from active list of vepitems, show vepitem */
3260 pool_foreach (vepitem, vsm->vepitems,
3263 "epfd='%04d', fd='%04d', "
3264 "next_fd='%04d', prev_fd='%04d', "
3266 "events='%04x', revents='%04x'\n",
3267 vepitem->epfd, vepitem->fd,
3268 vepitem->next_fd, vepitem->prev_fd,
3269 vcom_socket_vcom_fd_type_str (vepitem->type),
3270 vepitem->event.events, vepitem->revent.events);
3275 /* show epitemidxs for epfd */
3277 hash_foreach (epfd, vepitemidxs,
3278 vsm->epitemidxs_by_epfd,
3280 printf("\n[ '%04d': ", epfd);
3281 vec_foreach (vepitemidxs_var,vepitemidxs)
3283 printf("'%04d' ", (int)vepitemidxs_var[0]);
3289 /* show epitemidxs for fd */
3291 hash_foreach (fd, vepitemidxs,
3292 vsm->epitemidxs_by_fd,
3294 printf("\n{ '%04d': ", fd);
3295 vec_foreach (vepitemidxs_var,vepitemidxs)
3297 printf("'%04d' ", (int)vepitemidxs_var[0]);
3307 vcom_socket_main_destroy (void)
3309 vcom_socket_main_t *vsm = &vcom_socket_main;
3310 vcom_socket_t *vsock;
3312 vcom_epoll_t *vepoll;
3314 vcom_epitem_t *vepitem;
3322 printf ("vcom_socket_main_destroy\n");
3328 * from active list of vepitems,
3329 * remove all "vepitem" elements from the pool in a safe way
3333 pool_flush (vepitem, vsm->vepitems,
3335 if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
3337 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3339 vepitem_init (vepitem);
3344 pool_free (vsm->vepitems);
3345 hash_free (vsm->epitemidx_by_epfdfd);
3347 /* free vepitemidxs for each epfd */
3349 hash_foreach (epfd, vepitemidxs,
3350 vsm->epitemidxs_by_epfd,
3352 vec_free (vepitemidxs);
3355 hash_free (vsm->epitemidxs_by_epfd);
3357 /* free vepitemidxs for each fd */
3359 hash_foreach (fd, vepitemidxs,
3360 vsm->epitemidxs_by_fd,
3362 vec_free (vepitemidxs);
3365 hash_free (vsm->epitemidxs_by_fd);
3369 * from active list of vsockets,
3370 * close socket and vppcom session
3374 pool_foreach (vsock, vsm->vsockets,
3376 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3378 vppcom_session_close (vsock->sid);
3379 vcom_socket_close_socket (vsock->fd);
3380 vsocket_init (vsock);
3386 * return vsocket element to the pool
3390 pool_flush (vsock, vsm->vsockets,
3392 // vsocket_init(vsock);
3397 pool_free (vsm->vsockets);
3398 hash_free (vsm->sockidx_by_fd);
3401 * from active list of vepolls,
3402 * close epoll and vppcom_epoll
3406 pool_foreach (vepoll, vsm->vepolls,
3408 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3410 vppcom_session_close (vepoll->vep_idx);
3411 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3412 vepoll_init (vepoll);
3418 * return vepoll element to the pool
3422 pool_flush (vepoll, vsm->vepolls,
3424 // vepoll_init(vepoll);
3429 pool_free (vsm->vepolls);
3430 hash_free (vsm->epollidx_by_epfd);
3438 * fd.io coding-style-patch-verification: ON
3441 * eval: (c-set-style "gnu")