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 /* coverity[CONSTANT_EXPRESSION_RESULT] */
469 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
472 /* The file descriptor refers to a socket and has been
473 * marked nonblocking(O_NONBLOCK) and the read would
476 /* is non blocking */
477 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
482 vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
485 vcom_socket_main_t *vsm = &vcom_socket_main;
487 vcom_socket_t *vsock;
488 ssize_t total = 0, len = 0;
491 p = hash_get (vsm->sockidx_by_fd, __fd);
495 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
499 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
502 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
506 for (i = 0; i < __iovcnt; ++i)
508 if (SSIZE_MAX - len < __iov[i].iov_len)
510 len += __iov[i].iov_len;
513 rv = vcom_fcntl (__fd, F_GETFL, 0);
520 if (!(rv & O_NONBLOCK))
524 for (i = 0; i < __iovcnt; ++i)
526 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
533 if (rv < __iov[i].iov_len)
534 /* Read less than buffer provided, no point to continue */
539 /* coverity[CONSTANT_EXPRESSION_RESULT] */
540 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
544 /* is non blocking */
545 for (i = 0; i < __iovcnt; ++i)
547 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
562 if (rv < __iov[i].iov_len)
563 /* Read less than buffer provided, no point to continue */
571 vcom_socket_write (int __fd, const void *__buf, size_t __n)
574 vcom_socket_main_t *vsm = &vcom_socket_main;
576 vcom_socket_t *vsock;
583 p = hash_get (vsm->sockidx_by_fd, __fd);
587 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
591 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
594 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
599 vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
603 vcom_socket_main_t *vsm = &vcom_socket_main;
605 vcom_socket_t *vsock;
608 p = hash_get (vsm->sockidx_by_fd, __fd);
612 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
616 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
619 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
622 for (i = 0; i < __iovcnt; ++i)
624 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
640 * RETURN: 0 - invalid cmd
641 * 1 - cmd not handled by vcom and vppcom
642 * 2 - cmd handled by vcom socket resource
643 * 3 - cmd handled by vppcom
645 /* TBD: incomplete list of cmd */
647 vcom_socket_check_fcntl_cmd (int __cmd)
651 /*cmd not handled by vcom and vppcom */
654 case F_DUPFD_CLOEXEC:
657 /* cmd handled by vcom socket resource */
668 /* cmd handled by vcom and vppcom */
673 /* cmd not handled by vcom and vppcom */
681 vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
683 int flags = va_arg (__ap, int);
684 int rv = -EOPNOTSUPP;
687 size = sizeof (flags);
688 if (__cmd == F_SETFL)
690 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
692 else if (__cmd == F_GETFL)
694 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
703 vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
706 vcom_socket_main_t *vsm = &vcom_socket_main;
708 vcom_socket_t *vsock;
710 p = hash_get (vsm->sockidx_by_fd, __fd);
714 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
718 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
721 switch (vcom_socket_check_fcntl_cmd (__cmd))
727 /*cmd not handled by vcom and vppcom */
729 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
731 /* cmd handled by vcom socket resource */
733 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
735 /* cmd handled by vppcom */
737 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
749 * RETURN: 0 - invalid cmd
750 * 1 - cmd not handled by vcom and vppcom
751 * 2 - cmd handled by vcom socket resource
752 * 3 - cmd handled by vppcom
755 vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
761 /* cmd handled by vppcom */
766 /* cmd not handled by vcom and vppcom */
775 vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
779 if (__cmd == FIONREAD)
780 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
787 vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
790 vcom_socket_main_t *vsm = &vcom_socket_main;
792 vcom_socket_t *vsock;
794 p = hash_get (vsm->sockidx_by_fd, __fd);
798 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
802 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
805 switch (vcom_socket_check_ioctl_cmd (__cmd))
807 /* Not supported cmd */
812 /* cmd not handled by vcom and vppcom */
814 rv = libc_vioctl (vsock->fd, __cmd, __ap);
817 /* cmd handled by vcom socket resource */
819 rv = libc_vioctl (vsock->fd, __cmd, __ap);
822 /* cmd handled by vppcom */
824 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
836 vcom_socket_fds_2_sid_fds (
839 fd_set * __restrict vcom_rd_sid_fds,
840 fd_set * __restrict vcom_wr_sid_fds,
841 fd_set * __restrict vcom_ex_sid_fds,
844 fd_set * __restrict vcom_readfds,
845 fd_set * __restrict vcom_writefds,
846 fd_set * __restrict vcom_exceptfds)
851 /* invalid max_sid is -1 */
856 * set sid in sid sets corresponding to fd's in fd sets
857 * compute nsid and vcom_nsid_fds from sid sets
860 for (fd = 0; fd < vcom_nfds; fd++)
867 if ((F) && (S) && FD_ISSET (fd, (F))) \
869 sid = vcom_socket_get_sid (fd); \
870 if (sid != INVALID_SESSION_ID) \
887 _(vcom_rd_sid_fds, vcom_readfds);
888 _(vcom_wr_sid_fds, vcom_writefds);
889 _(vcom_ex_sid_fds, vcom_exceptfds);
893 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
901 * PRE: 00. sid sets were derived from fd sets
902 * 01. sid sets were updated with sids that actually changed
904 * 02. fd sets still has watched fds
906 * This function will modify in place fd sets to indicate which fd's
907 * actually changed status(inferred from sid sets)
910 vcom_socket_sid_fds_2_fds (
914 fd_set * __restrict vcom_readfds,
915 fd_set * __restrict vcom_writefds,
916 fd_set * __restrict vcom_exceptfds,
919 fd_set * __restrict vcom_rd_sid_fds,
920 fd_set * __restrict vcom_wr_sid_fds,
921 fd_set * __restrict vcom_ex_sid_fds)
926 /* invalid max_fd is -1 */
932 * modify in place fd sets to indicate which fd's
933 * actually changed status(inferred from sid sets)
935 for (fd = 0; fd < vcom_nfds; fd++)
942 if ((F) && (S) && FD_ISSET (fd, (F))) \
944 sid = vcom_socket_get_sid (fd); \
945 if (sid != INVALID_SESSION_ID) \
947 if (!FD_ISSET (sid, (S))) \
960 _(vcom_rd_sid_fds, vcom_readfds);
961 _(vcom_wr_sid_fds, vcom_writefds);
962 _(vcom_ex_sid_fds, vcom_exceptfds);
967 * compute nfd and new_vcom_nfds from fd sets
969 for (fd = 0; fd < vcom_nfds; fd++)
973 if ((F) && FD_ISSET (fd, (F))) \
990 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
999 * vom_socket_select is always called with
1000 * timeout->tv_sec and timeout->tv_usec set to zero.
1001 * hence vppcom_select return immediately.
1004 * TBD: do{body;} while(timeout conditional); timeout loop
1007 vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1008 fd_set * __restrict vcom_writefds,
1009 fd_set * __restrict vcom_exceptfds,
1010 struct timeval *__restrict timeout)
1012 static unsigned long vcom_nsid_fds = 0;
1015 pid_t pid = getpid ();
1017 int new_vcom_nfds = 0;
1018 int new_vcom_nfd = 0;
1021 fd_set vcom_rd_sid_fds;
1022 fd_set vcom_wr_sid_fds;
1023 fd_set vcom_ex_sid_fds;
1025 /* in seconds eg. 3.123456789 seconds */
1026 double time_to_wait = (double) 0;
1028 /* validate inputs */
1034 /* convert timeval timeout to double time_to_wait */
1037 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1039 /* polling: vppcom_select returns immediately */
1040 time_to_wait = (double) 0;
1044 /*TBD: use timeval api */
1045 time_to_wait = (double) timeout->tv_sec +
1046 (double) timeout->tv_usec / (double) 1000000 +
1047 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1053 * no timeout: vppcom_select can block indefinitely
1054 * waiting for a file descriptor to become ready
1056 /* set to a phantom value */
1060 /* zero the sid_sets */
1072 _(&vcom_rd_sid_fds, vcom_readfds);
1073 _(&vcom_wr_sid_fds, vcom_writefds);
1074 _(&vcom_ex_sid_fds, vcom_exceptfds);
1079 if (time_to_wait > 0)
1083 "[%d] vcom_socket_select called to "
1084 "emulate delay_ns()!\n", pid);
1085 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1089 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1090 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1095 /* populate read, write and except sid_sets */
1096 vcom_nsid = vcom_socket_fds_2_sid_fds (
1098 vcom_readfds || vcom_writefds
1099 || vcom_exceptfds ? (int *)
1100 &vcom_nsid_fds : NULL,
1101 vcom_readfds ? &vcom_rd_sid_fds :
1103 vcom_writefds ? &vcom_wr_sid_fds :
1105 vcom_exceptfds ? &vcom_ex_sid_fds :
1110 vcom_writefds, vcom_exceptfds);
1116 rv = vppcom_select (vcom_nsid_fds,
1117 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1119 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1121 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1122 NULL, time_to_wait);
1124 fprintf (stderr, "[%d] called vppcom_select(): "
1125 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1127 /* check if any file descriptors changed status */
1131 * on exit, sets are modified in place to indicate which
1132 * file descriptors actually changed status
1136 * comply with pre-condition
1137 * do not clear vcom fd sets befor calling
1138 * vcom_socket_sid_fds_2_fds
1140 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1150 &vcom_rd_sid_fds : NULL,
1152 &vcom_wr_sid_fds : NULL,
1154 &vcom_ex_sid_fds : NULL);
1155 if (new_vcom_nfd < 0)
1157 return new_vcom_nfd;
1159 if (new_vcom_nfds < 0)
1170 vcom_socket_socket (int __domain, int __type, int __protocol)
1173 vcom_socket_main_t *vsm = &vcom_socket_main;
1174 vcom_socket_t *vsock;
1179 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1180 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1182 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1189 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1190 (type == SOCK_DGRAM) ?
1191 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1196 goto out_close_socket;
1199 pool_get (vsm->vsockets, vsock);
1200 vsocket_init (vsock);
1202 sockidx = vsock - vsm->vsockets;
1203 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1205 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1209 vcom_socket_close_socket (fd);
1215 vcom_socket_socketpair (int __domain, int __type, int __protocol,
1223 vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1226 vcom_socket_main_t *vsm = &vcom_socket_main;
1228 vcom_socket_t *vsock;
1232 p = hash_get (vsm->sockidx_by_fd, __fd);
1236 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1240 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1248 ep.vrf = VPPCOM_VRF_DEFAULT;
1249 switch (__addr->sa_family)
1252 if (__len != sizeof (struct sockaddr_in))
1256 ep.is_ip4 = VPPCOM_IS_IP4;
1257 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1258 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1262 if (__len != sizeof (struct sockaddr_in6))
1266 ep.is_ip4 = VPPCOM_IS_IP6;
1267 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1268 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1276 rv = vppcom_session_bind (vsock->sid, &ep);
1281 vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1284 uint32_t size = sizeof (*ep);
1286 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1291 vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1292 socklen_t * __restrict __len)
1295 vcom_socket_main_t *vsm = &vcom_socket_main;
1297 vcom_socket_t *vsock;
1300 p = hash_get (vsm->sockidx_by_fd, __fd);
1304 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1308 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1311 if (!__addr || !__len)
1315 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1316 rv = vcom_session_getsockname (vsock->sid, &ep);
1319 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1321 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1322 switch (__addr->sa_family)
1325 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1326 *__len = sizeof (struct sockaddr_in);
1330 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1331 *__len = sizeof (struct sockaddr_in6);
1344 vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1347 vcom_socket_main_t *vsm = &vcom_socket_main;
1349 vcom_socket_t *vsock;
1353 p = hash_get (vsm->sockidx_by_fd, __fd);
1356 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1358 ep.vrf = VPPCOM_VRF_DEFAULT;
1359 switch (__addr->sa_family)
1362 ep.is_ip4 = VPPCOM_IS_IP4;
1364 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1366 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1370 ep.is_ip4 = VPPCOM_IS_IP6;
1372 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1374 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1382 rv = vppcom_session_connect (vsock->sid, &ep);
1388 vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1391 uint32_t size = sizeof (*ep);
1393 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1398 vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1399 socklen_t * __restrict __len)
1402 vcom_socket_main_t *vsm = &vcom_socket_main;
1404 vcom_socket_t *vsock;
1407 p = hash_get (vsm->sockidx_by_fd, __fd);
1411 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1415 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1418 if (!__addr || !__len)
1422 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1423 rv = vcom_session_getpeername (vsock->sid, &ep);
1426 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1428 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1429 switch (__addr->sa_family)
1432 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1433 *__len = sizeof (struct sockaddr_in);
1437 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1438 *__len = sizeof (struct sockaddr_in6);
1451 vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1453 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1457 vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1460 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1465 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1469 vcom_socket_is_connection_mode_socket (int __fd)
1472 /* TBD define new vppcom api */
1473 vcom_socket_main_t *vsm = &vcom_socket_main;
1475 vcom_socket_t *vsock;
1480 p = hash_get (vsm->sockidx_by_fd, __fd);
1484 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1485 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1487 optlen = sizeof (type);
1488 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1493 /* get socket type */
1494 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1497 case SOCK_SEQPACKET:
1510 static inline ssize_t
1511 vcom_session_sendto (int __sid, void *__buf, size_t __n,
1512 int __flags, __CONST_SOCKADDR_ARG __addr,
1513 socklen_t __addr_len)
1515 vppcom_endpt_t *ep = 0;
1521 ep->vrf = VPPCOM_VRF_DEFAULT;
1522 switch (__addr->sa_family)
1525 ep->is_ip4 = VPPCOM_IS_IP4;
1527 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1529 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1533 ep->is_ip4 = VPPCOM_IS_IP6;
1535 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1537 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1541 return -EAFNOSUPPORT;
1545 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
1549 vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1550 int __flags, __CONST_SOCKADDR_ARG __addr,
1551 socklen_t __addr_len)
1553 vcom_socket_main_t *vsm = &vcom_socket_main;
1555 vcom_socket_t *vsock;
1562 p = hash_get (vsm->sockidx_by_fd, __fd);
1566 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1570 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1575 if (vcom_socket_is_connection_mode_socket (__fd))
1577 /* ignore __addr and _addr_len */
1578 /* and EISCONN may be returned when they are not NULL and 0 */
1579 if ((__addr != NULL) || (__addr_len != 0))
1588 return -EDESTADDRREQ;
1590 /* not a vppcom supported address family */
1591 if (!((__addr->sa_family == AF_INET) ||
1592 (__addr->sa_family == AF_INET6)))
1598 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1599 __flags, __addr, __addr_len);
1602 static inline ssize_t
1603 vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1604 int __flags, __SOCKADDR_ARG __addr,
1605 socklen_t * __restrict __addr_len)
1609 u8 src_addr[sizeof (struct sockaddr_in6)];
1614 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1618 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1621 ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1622 switch (__addr->sa_family)
1625 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1626 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
1627 src_addr, sizeof (struct in_addr));
1629 *__addr_len = sizeof (struct sockaddr_in);
1633 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1634 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1635 __in6_u.__u6_addr8, src_addr,
1636 sizeof (struct in6_addr));
1637 *__addr_len = sizeof (struct sockaddr_in6);
1650 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1656 vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1657 int __flags, __SOCKADDR_ARG __addr,
1658 socklen_t * __restrict __addr_len)
1661 vcom_socket_main_t *vsm = &vcom_socket_main;
1663 vcom_socket_t *vsock;
1665 if (__addr && !__addr_len)
1668 p = hash_get (vsm->sockidx_by_fd, __fd);
1672 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1676 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1681 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1682 __flags, __addr, __addr_len);
1686 /* TBD: move it to vppcom */
1687 static inline ssize_t
1688 vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1691 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1697 vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1700 vcom_socket_main_t *vsm = &vcom_socket_main;
1702 vcom_socket_t *vsock;
1704 p = hash_get (vsm->sockidx_by_fd, __fd);
1708 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1712 if (vcom_socket_is_connection_mode_socket (__fd))
1714 /* ignore __addr and _addr_len */
1715 /* and EISCONN may be returned when they are not NULL and 0 */
1716 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1723 /* TBD: validate __message->msg_name and __message->msg_namelen
1724 * and return -EINVAL on validation error
1729 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
1736 vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1737 unsigned int __vlen, int __flags)
1740 /* TBD: define a new vppcom api */
1745 /* TBD: move it to vppcom */
1746 static inline ssize_t
1747 vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
1750 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1757 vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1760 vcom_socket_main_t *vsm = &vcom_socket_main;
1762 vcom_socket_t *vsock;
1764 p = hash_get (vsm->sockidx_by_fd, __fd);
1768 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1772 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1780 /* validate __flags */
1782 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
1788 vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1789 unsigned int __vlen, int __flags,
1790 struct timespec *__tmo)
1792 /* TBD: define a new vppcom api */
1797 /* TBD: move it to vppcom */
1799 vcom_session_get_sockopt (int __sid, int __level, int __optname,
1800 void *__restrict __optval,
1801 socklen_t * __restrict __optlen)
1805 /* 1. for socket level options that are NOT socket attributes
1806 * and that has corresponding vpp options get from vppcom */
1813 *(int *) __optval = 0;
1821 /* 2. unhandled options */
1826 vcom_socket_getsockopt (int __fd, int __level, int __optname,
1827 void *__restrict __optval,
1828 socklen_t * __restrict __optlen)
1831 vcom_socket_main_t *vsm = &vcom_socket_main;
1833 vcom_socket_t *vsock;
1835 if (!__optval || !__optlen)
1838 p = hash_get (vsm->sockidx_by_fd, __fd);
1842 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1846 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1855 * 1. for socket level options that are socket attributes,
1856 * get from libc_getsockopt.
1857 * 2. for socket level options that are NOT socket
1858 * attributes and that has corresponding vpp options
1860 * 3. for socket level options unimplemented
1861 * return -ENOPROTOOPT */
1879 case SO_TIMESTAMPNS:
1880 case SO_TIMESTAMPING:
1893 case SO_WIFI_STATUS:
1896 case SO_BINDTODEVICE:
1898 case SO_LOCK_FILTER:
1899 case SO_BPF_EXTENSIONS:
1900 case SO_SELECT_ERR_QUEUE:
1901 #ifdef CONFIG_NET_RX_BUSY_POLL
1904 case SO_MAX_PACING_RATE:
1905 #ifdef SO_INCOMING_CPU
1906 case SO_INCOMING_CPU:
1908 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1917 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1918 __optval, __optlen);
1922 /* We implement the SO_SNDLOWAT etc to not be settable
1925 return -ENOPROTOOPT;
1931 /* 1. handle options that are NOT socket level options,
1932 * but have corresponding vpp otions. */
1933 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1934 __optval, __optlen);
1941 /* TBD: move it to vppcom */
1943 vcom_session_setsockopt (int __sid, int __level, int __optname,
1944 const void *__optval, socklen_t __optlen)
1946 int rv = -EOPNOTSUPP;
1955 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1959 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1969 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
1979 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1982 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
1985 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
1999 vcom_socket_setsockopt (int __fd, int __level, int __optname,
2000 const void *__optval, socklen_t __optlen)
2003 vcom_socket_main_t *vsm = &vcom_socket_main;
2005 vcom_socket_t *vsock;
2007 p = hash_get (vsm->sockidx_by_fd, __fd);
2011 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2015 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2019 * Options without arguments
2022 if (__optname == SO_BINDTODEVICE)
2024 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2035 if (__optlen < sizeof (int))
2044 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2045 __optval, __optlen);
2058 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2059 __optval, __optlen);
2065 /* handle options at socket level */
2072 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2073 __optval, __optlen);
2077 * 1. for socket level options that are socket attributes,
2078 * set it from libc_getsockopt
2079 * 2. for socket level options that are NOT socket
2080 * attributes and that has corresponding vpp options
2081 * set it from vppcom
2082 * 3. for socket level options unimplemented
2083 * return -ENOPROTOOPT */
2099 case SO_TIMESTAMPNS:
2100 case SO_TIMESTAMPING:
2113 case SO_WIFI_STATUS:
2117 * SO_BINDTODEVICE already handled as
2118 * "Options without arguments" */
2119 /* case SO_BINDTODEVICE: */
2121 case SO_LOCK_FILTER:
2122 case SO_BPF_EXTENSIONS:
2123 case SO_SELECT_ERR_QUEUE:
2124 #ifdef CONFIG_NET_RX_BUSY_POLL
2127 case SO_MAX_PACING_RATE:
2128 #ifdef SO_INCOMING_CPU
2129 case SO_INCOMING_CPU:
2131 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2140 /* We implement the SO_SNDLOWAT etc to not be settable
2143 return -ENOPROTOOPT;
2149 return -ENOPROTOOPT;
2156 vcom_socket_listen (int __fd, int __n)
2159 vcom_socket_main_t *vsm = &vcom_socket_main;
2161 vcom_socket_t *vsock;
2163 p = hash_get (vsm->sockidx_by_fd, __fd);
2166 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2168 /* TBD vppcom to accept __n parameter */
2169 rv = vppcom_session_listen (vsock->sid, __n);
2176 vcom_socket_connected_socket (int __fd, int __sid,
2178 int *__type, int *__protocol, int flags)
2181 vcom_socket_main_t *vsm = &vcom_socket_main;
2182 vcom_socket_t *vsock;
2189 optlen = sizeof (*__domain);
2190 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2197 optlen = sizeof (*__type);
2198 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2205 optlen = sizeof (*__protocol);
2206 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2213 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2220 pool_get (vsm->vsockets, vsock);
2221 vsocket_init (vsock);
2223 sockidx = vsock - vsm->vsockets;
2224 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2226 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2233 /* If flag is 0, then accept4() is the same as accept().
2234 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2237 vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2238 socklen_t * __restrict __addr_len, int flags)
2241 vcom_socket_main_t *vsm = &vcom_socket_main;
2243 vcom_socket_t *vsock;
2251 uint8_t addr8[sizeof (struct in6_addr)];
2256 /* validate flags */
2263 * case SOCK_NONBLOCK:
2264 * case SOCK_CLOEXEC:
2265 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2272 /* flags can be 0 or can be bitwise OR
2273 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2275 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2277 /* TBD: return proper error code */
2281 /* TBD: return proper error code */
2283 if (!vcom_socket_is_connection_mode_socket (__fd))
2288 p = hash_get (vsm->sockidx_by_fd, __fd);
2291 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2294 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2301 if (!(rv & O_NONBLOCK))
2303 /* socket is not marked as nonblocking
2304 * and no pending connections are present
2305 * on the queue, accept () blocks the caller
2306 * until a connection is present.
2308 rv = vppcom_session_accept (vsock->sid, &ep,
2309 -1.0 /* wait forever */ );
2313 /* The file descriptor refers to a socket and has been
2314 * marked nonblocking(O_NONBLOCK) and the accept would
2317 /* is non blocking */
2318 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2319 /* If the socket is marked nonblocking and
2320 * no pending connections are present on the
2321 * queue, accept fails with the error
2322 * EAGAIN or EWOULDBLOCK
2324 if (rv == VPPCOM_ETIMEDOUT)
2336 /* create a new connected socket resource and set flags
2337 * on the new file descriptor.
2338 * update vsockets and sockidx_by_fd table
2340 fd = vcom_socket_connected_socket (__fd, sid,
2341 &domain, &type, &protocol, flags);
2349 /* TBD populate __addr and __addr_len */
2350 /* TBD: The returned address is truncated if the buffer
2351 * provided is too small, in this case, __addr_len will
2352 * return a value greater than was supplied to the call.*/
2357 /* TBD populate __addr and __addr_len */
2361 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2362 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2363 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2364 addr8, sizeof (struct in_addr));
2365 /* TBD: populate __addr_len */
2368 *__addr_len = sizeof (struct sockaddr_in);
2373 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2374 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2375 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2376 __in6_u.__u6_addr8, addr8,
2377 sizeof (struct in6_addr));
2378 /* TBD: populate __addr_len */
2381 *__addr_len = sizeof (struct sockaddr_in6);
2386 return -EAFNOSUPPORT;
2394 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2395 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2396 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2397 addr8, sizeof (struct in_addr));
2398 /* TBD: populate __addr_len */
2401 *__addr_len = sizeof (struct sockaddr_in);
2406 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2407 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2408 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2409 __in6_u.__u6_addr8, addr8,
2410 sizeof (struct in6_addr));
2411 /* TBD: populate __addr_len */
2414 *__addr_len = sizeof (struct sockaddr_in6);
2419 return -EAFNOSUPPORT;
2425 /* when __addr is NULL, nothing is filled in,
2426 * in this case, __addr_len is not used,
2427 * and should also be null
2431 /* TBD: return proper error code */
2441 vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2442 socklen_t * __restrict __addr_len)
2444 /* set flags to 0 for accept() */
2445 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2450 vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2451 socklen_t * __restrict __addr_len, int __flags)
2453 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2454 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2458 /* TBD: move it to vppcom */
2460 vcom_session_shutdown (int __fd, int __how)
2466 vcom_socket_shutdown (int __fd, int __how)
2469 vcom_socket_main_t *vsm = &vcom_socket_main;
2471 vcom_socket_t *vsock;
2473 p = hash_get (vsm->sockidx_by_fd, __fd);
2476 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2482 rv = vcom_session_shutdown (vsock->sid, __how);
2496 vcom_socket_epoll_create1 (int __flags)
2499 vcom_socket_main_t *vsm = &vcom_socket_main;
2500 vcom_epoll_t *vepoll;
2506 epfd = vcom_socket_open_epoll (__flags);
2513 vep_idx = vppcom_epoll_create ();
2517 goto out_close_epoll;
2520 pool_get (vsm->vepolls, vepoll);
2521 vepoll_init (vepoll);
2523 epollidx = vepoll - vsm->vepolls;
2524 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2526 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2531 vcom_socket_close_epoll (epfd);
2537 * PRE: vppcom_epoll_ctl() is successful
2538 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2541 vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2542 struct epoll_event *__event,
2543 i32 vep_idx, vcom_epoll_t * vepoll,
2544 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2545 int free_vepitem_on_del)
2548 vcom_socket_main_t *vsm = &vcom_socket_main;
2549 vcom_epitem_t *vepitem;
2551 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2555 i32 *vepitemidxs = 0;
2557 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2561 /* perform control operations on the epoll instance */
2566 * supplied file descriptor is already
2567 * registered with this epoll instance
2569 /* vepitem exists */
2570 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2577 /* add a new vepitem */
2578 pool_get (vsm->vepitems, vepitem);
2579 vepitem_init (vepitem);
2581 vepitemidx = vepitem - vsm->vepitems;
2582 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2583 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2585 /* update epitemidxs */
2587 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2588 if (!p) /* not exist */
2591 vec_add1 (vepitemidxs, vepitemidx);
2592 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2596 vepitemidxs = *(i32 **) p;
2597 vec_add1 (vepitemidxs, vepitemidx);
2598 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2600 /* update epitemidxs */
2602 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2603 if (!p) /* not exist */
2606 vec_add1 (vepitemidxs, vepitemidx);
2607 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2611 vepitemidxs = *(i32 **) p;
2612 vec_add1 (vepitemidxs, vepitemidx);
2613 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2616 /* increment vepoll fd count by 1 */
2625 * supplied file descriptor is not
2626 * registered with this epoll instance
2628 /* vepitem not exist */
2629 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2635 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2638 vepitem->event = *__event;
2639 vepitem->revent = revent;
2648 * supplied file descriptor is not
2649 * registered with this epoll instance
2651 /* vepitem not exist */
2652 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2658 vepitemidx = *(i32 *) p;
2659 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2661 /* update epitemidxs */
2663 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2664 if (!p) /* not exist */
2671 vepitemidxs = *(i32 **) p;
2672 vec_idx = vec_search (vepitemidxs, vepitemidx);
2675 vec_del1 (vepitemidxs, vec_idx);
2676 if (!vec_len (vepitemidxs))
2678 vec_free (vepitemidxs);
2679 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2684 /* update epitemidxs */
2686 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2687 if (!p) /* not exist */
2694 vepitemidxs = *(i32 **) p;
2695 vec_idx = vec_search (vepitemidxs, vepitemidx);
2698 vec_del1 (vepitemidxs, vec_idx);
2699 if (!vec_len (vepitemidxs))
2701 vec_free (vepitemidxs);
2702 hash_unset (vsm->epitemidxs_by_fd, __fd);
2707 /* pool put vepitem */
2708 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2709 if (free_vepitem_on_del)
2716 vepitem_init (vepitem);
2717 pool_put (vsm->vepitems, vepitem);
2723 vepitem_init (vepitem);
2727 /* decrement vepoll fd count by 1 */
2745 * PRE: 00. null pointer check on __event
2746 * 01. all other parameters are validated
2750 vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2751 struct epoll_event *__event,
2752 int free_vepitem_on_del)
2756 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2757 vcom_epoll_t *vepoll;
2759 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2761 vcom_epoll_t *vfd_vepoll;
2762 vcom_socket_t *vfd_vsock;
2767 vcom_fd_type_t type = FD_TYPE_INVALID;
2769 /* validate __event */
2771 /* get vep_idx and vepoll */
2772 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2773 if (vep_idx == INVALID_VEP_IDX)
2778 /* get vcom fd type, vfd_id and vfd */
2779 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2780 if (vfd_id != INVALID_SESSION_ID)
2782 type = FD_TYPE_VCOM_SOCKET;
2785 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2788 type = FD_TYPE_EPOLL;
2793 /* FD_TYPE_KERNEL not supported by epoll instance */
2794 type = FD_TYPE_INVALID;
2799 /* vepoll and vsock are now valid */
2800 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2806 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2809 vfd_id, vfd, type, free_vepitem_on_del);
2814 vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2815 struct epoll_event *__event)
2819 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2824 vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2825 struct epoll_event *__event)
2829 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2834 vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2835 int __maxevents, int __timeout,
2836 const __sigset_t * __ss)
2840 /* in seconds eg. 3.123456789 seconds */
2841 double time_to_wait = (double) 0;
2845 /* validate __event */
2852 /* validate __timeout */
2855 time_to_wait = (double) __timeout / (double) 1000;
2857 else if (__timeout == 0)
2859 time_to_wait = (double) 0;
2861 else if (__timeout == -1)
2872 vep_idx = vcom_socket_get_vep_idx (__epfd);
2873 if (vep_idx != INVALID_VEP_IDX)
2875 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2882 vcom_pollfds_2_selectfds (
2884 struct pollfd *__fds, nfds_t __nfds,
2887 fd_set * __restrict vcom_readfds,
2888 fd_set * __restrict vcom_writefds,
2889 fd_set * __restrict vcom_exceptfds)
2893 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2895 /* ignore negative fds */
2896 if (__fds[fds_idx].fd < 0)
2901 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2902 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2904 /* requested events */
2905 if (__fds[fds_idx].events)
2907 if (__fds[fds_idx].events & POLLIN)
2909 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2911 if (__fds[fds_idx].events & POLLPRI)
2913 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2915 if (__fds[fds_idx].events & POLLOUT)
2917 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2919 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2920 if (__fds[fds_idx].events & POLLRDNORM)
2922 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2924 if (__fds[fds_idx].events & POLLRDBAND)
2926 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2928 if (__fds[fds_idx].events & POLLWRNORM)
2930 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2932 if (__fds[fds_idx].events & POLLWRBAND)
2934 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2938 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2942 vcom_selectfds_2_pollfds (
2944 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2947 fd_set * __restrict vcom_readfds,
2948 fd_set * __restrict vcom_writefds,
2949 fd_set * __restrict vcom_exceptfds)
2954 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2956 /* ignore negative fds */
2957 if (__fds[fds_idx].fd < 0)
2959 __fds[fds_idx].revents = 0;
2962 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2963 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2966 * TBD: for now any select exception
2967 * is flagged as POLLERR
2969 __fds[fds_idx].revents |= POLLERR;
2972 /* requested events */
2973 if (__fds[fds_idx].events & POLLIN)
2975 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2977 __fds[fds_idx].revents |= POLLIN;
2980 if (__fds[fds_idx].events & POLLPRI)
2982 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2984 __fds[fds_idx].revents |= POLLIN;
2987 if (__fds[fds_idx].events & POLLOUT)
2989 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2991 __fds[fds_idx].revents |= POLLOUT;
2994 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2995 if (__fds[fds_idx].events & POLLRDNORM)
2997 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2999 __fds[fds_idx].revents |= POLLRDNORM;
3002 if (__fds[fds_idx].events & POLLRDBAND)
3004 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3006 __fds[fds_idx].revents |= POLLRDBAND;
3009 if (__fds[fds_idx].events & POLLWRNORM)
3011 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3013 __fds[fds_idx].revents |= POLLWRNORM;
3016 if (__fds[fds_idx].events & POLLWRBAND)
3018 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3020 __fds[fds_idx].revents |= POLLWRBAND;
3024 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3028 * the number of structures which have nonzero revents fields
3029 * (in other words, those descriptors with events or
3033 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3035 /* ignore negative fds */
3036 if (__fds[fds_idx].fd < 0)
3041 if (__fds[fds_idx].revents)
3049 * PRE: parameters are validated,
3050 * vcom_socket_poll is always called with __timeout set to zero
3051 * hence returns immediately
3053 * ACTION: handle non negative validated vcom fds and ignore rest
3057 * implements vcom_socket_poll () interface
3059 * internally uses vcom_socket_select ()
3060 * to realize the behavior
3063 vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3067 pid_t pid = getpid ();
3074 fd_set vcom_readfds;
3075 fd_set vcom_writefds;
3076 fd_set vcom_exceptfds;
3078 /* invalid max_vcom_fd is -1 */
3079 int max_vcom_fd = -1;
3081 /* __timeout is zero to get ready events and return immediately */
3082 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3084 /* validate __nfds from select perspective */
3085 if (__nfds > FD_SETSIZE)
3091 /* zero vcom fd sets */
3107 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3109 /* ignore negative fds */
3110 if (__fds[fds_idx].fd < 0)
3115 /* non negative validated vcom fds */
3116 if (__fds[fds_idx].fd > FD_SETSIZE)
3122 /* max_vcom_fd and vcom_nfd */
3123 if (__fds[fds_idx].fd > max_vcom_fd)
3125 /* requested events */
3126 if (__fds[fds_idx].events)
3128 max_vcom_fd = __fds[fds_idx].fd;
3134 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3142 vcom_pollfds_2_selectfds (
3147 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3149 /* select on vcom fds */
3150 vcom_nfd = vcom_socket_select (vcom_nfds,
3152 &vcom_writefds, &vcom_exceptfds, &tv);
3155 "[%d] vcom_socket_select: "
3156 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3164 vcom_selectfds_2_pollfds (
3166 __fds, __nfds, &nfd,
3169 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3178 * TBD: remove this static function once vppcom
3179 * has an implementation in place
3184 vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3190 vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3195 /* in seconds eg. 3.123456789 seconds */
3196 double time_to_wait = (double) 0;
3201 /* replace vcom fd with session idx */
3202 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3204 /* ignore negative fds */
3205 if (__fds[fds_idx].fd < 0)
3210 /* non negative validated vcom fds */
3211 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3212 if (sid != INVALID_SESSION_ID)
3214 __fds[fds_idx].fd = sid;
3219 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3220 if (vep_idx != INVALID_VEP_IDX)
3222 __fds[fds_idx].fd = vep_idx;
3231 /* validate __timeout */
3234 time_to_wait = (double) __timeout / (double) 1000;
3236 else if (__timeout == 0)
3238 time_to_wait = (double) 0;
3245 return vppcom_poll (__fds, __nfds, time_to_wait);
3249 vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3251 /* select an implementation */
3253 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3254 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3259 vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3260 const struct timespec *__timeout, const __sigset_t * __ss)
3267 vcom_socket_main_init (void)
3269 vcom_socket_main_t *vsm = &vcom_socket_main;
3272 printf ("vcom_socket_main_init\n");
3276 /* TBD: define FD_MAXSIZE and use it here */
3277 pool_alloc (vsm->vsockets, FD_SETSIZE);
3278 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3280 pool_alloc (vsm->vepolls, FD_SETSIZE);
3281 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3283 pool_alloc (vsm->vepitems, FD_SETSIZE);
3284 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3286 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3287 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3297 vcom_socket_main_show (void)
3299 vcom_socket_main_t *vsm = &vcom_socket_main;
3300 vcom_socket_t *vsock;
3302 vcom_epoll_t *vepoll;
3304 vcom_epitem_t *vepitem;
3308 i32 *vepitemidxs, *vepitemidxs_var;
3312 /* from active list of vsockets show vsock */
3315 pool_foreach (vsock, vsm->vsockets,
3318 "fd='%04d', sid='%08x',type='%-30s'\n",
3319 vsock->fd, vsock->sid,
3320 vcom_socket_type_str (vsock->type));
3324 /* from active list of vepolls, show vepoll */
3327 pool_foreach (vepoll, vsm->vepolls,
3330 "epfd='%04d', vep_idx='%08x', "
3332 "flags='%d', count='%d', close='%d'\n",
3333 vepoll->epfd, vepoll->vep_idx,
3334 vcom_socket_epoll_type_str (vepoll->type),
3335 vepoll->flags, vepoll->count, vepoll->close);
3339 /* from active list of vepitems, show vepitem */
3342 pool_foreach (vepitem, vsm->vepitems,
3345 "epfd='%04d', fd='%04d', "
3346 "next_fd='%04d', prev_fd='%04d', "
3348 "events='%04x', revents='%04x'\n",
3349 vepitem->epfd, vepitem->fd,
3350 vepitem->next_fd, vepitem->prev_fd,
3351 vcom_socket_vcom_fd_type_str (vepitem->type),
3352 vepitem->event.events, vepitem->revent.events);
3357 /* show epitemidxs for epfd */
3359 hash_foreach (epfd, vepitemidxs,
3360 vsm->epitemidxs_by_epfd,
3362 printf("\n[ '%04d': ", epfd);
3363 vec_foreach (vepitemidxs_var,vepitemidxs)
3365 printf("'%04d' ", (int)vepitemidxs_var[0]);
3371 /* show epitemidxs for fd */
3373 hash_foreach (fd, vepitemidxs,
3374 vsm->epitemidxs_by_fd,
3376 printf("\n{ '%04d': ", fd);
3377 vec_foreach (vepitemidxs_var,vepitemidxs)
3379 printf("'%04d' ", (int)vepitemidxs_var[0]);
3389 vcom_socket_main_destroy (void)
3391 vcom_socket_main_t *vsm = &vcom_socket_main;
3392 vcom_socket_t *vsock;
3394 vcom_epoll_t *vepoll;
3396 vcom_epitem_t *vepitem;
3404 printf ("vcom_socket_main_destroy\n");
3410 * from active list of vepitems,
3411 * remove all "vepitem" elements from the pool in a safe way
3415 pool_flush (vepitem, vsm->vepitems,
3417 if ((vepitem->type == FD_TYPE_EPOLL) ||
3418 (vepitem->type == FD_TYPE_VCOM_SOCKET))
3420 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3422 vepitem_init (vepitem);
3427 pool_free (vsm->vepitems);
3428 hash_free (vsm->epitemidx_by_epfdfd);
3430 /* free vepitemidxs for each epfd */
3432 hash_foreach (epfd, vepitemidxs,
3433 vsm->epitemidxs_by_epfd,
3435 vec_free (vepitemidxs);
3438 hash_free (vsm->epitemidxs_by_epfd);
3440 /* free vepitemidxs for each fd */
3442 hash_foreach (fd, vepitemidxs,
3443 vsm->epitemidxs_by_fd,
3445 vec_free (vepitemidxs);
3448 hash_free (vsm->epitemidxs_by_fd);
3452 * from active list of vsockets,
3453 * close socket and vppcom session
3457 pool_foreach (vsock, vsm->vsockets,
3459 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3461 vppcom_session_close (vsock->sid);
3462 vcom_socket_close_socket (vsock->fd);
3463 vsocket_init (vsock);
3469 * return vsocket element to the pool
3473 pool_flush (vsock, vsm->vsockets,
3475 // vsocket_init(vsock);
3480 pool_free (vsm->vsockets);
3481 hash_free (vsm->sockidx_by_fd);
3484 * from active list of vepolls,
3485 * close epoll and vppcom_epoll
3489 pool_foreach (vepoll, vsm->vepolls,
3491 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3493 vppcom_session_close (vepoll->vep_idx);
3494 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3495 vepoll_init (vepoll);
3501 * return vepoll element to the pool
3505 pool_flush (vepoll, vsm->vepolls,
3507 // vepoll_init(vepoll);
3512 pool_free (vsm->vepolls);
3513 hash_free (vsm->epollidx_by_epfd);
3521 * fd.io coding-style-patch-verification: ON
3524 * eval: (c-set-style "gnu")