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>
34 #define IOV_MAX __IOV_MAX
38 * VCOM_SOCKET Private definitions and functions.
41 typedef struct vcom_socket_main_t_
45 /* vcom_socket pool */
46 vcom_socket_t *vsockets;
48 /* Hash table for socketidx to fd mapping */
52 vcom_epoll_t *vepolls;
54 /* Hash table for epollidx to epfd mapping */
55 uword *epollidx_by_epfd;
58 /* common epitem poll for all epfd */
59 /* TBD: epitem poll per epfd */
60 /* vcom_epitem pool */
61 vcom_epitem_t *vepitems;
63 /* Hash table for epitemidx to epfdfd mapping */
64 uword *epitemidx_by_epfdfd;
66 /* Hash table - key:epfd, value:vec of epitemidx */
67 uword *epitemidxs_by_epfd;
68 /* Hash table - key:fd, value:vec of epitemidx */
69 uword *epitemidxs_by_fd;
73 vcom_socket_main_t vcom_socket_main;
77 vcom_socket_open_socket (int domain, int type, int protocol)
81 /* handle domains implemented by vpp */
86 /* get socket type and
87 * handle the socket types supported by vpp */
88 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
92 /* the type argument serves a second purpose,
93 * in addition to specifying a socket type,
94 * it may include the bitwise OR of any of
95 * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
96 * the behavior of socket. */
97 rv = libc_socket (domain, type, protocol);
116 vcom_socket_open_epoll (int flags)
124 if (flags && (flags & ~EPOLL_CLOEXEC))
129 /* flags can be either zero or EPOLL_CLOEXEC */
130 rv = libc_epoll_create1 (flags);
138 vcom_socket_close_socket (int fd)
142 rv = libc_close (fd);
150 vcom_socket_close_epoll (int epfd)
154 rv = libc_close (epfd);
162 * Public API functions
167 vcom_socket_is_vcom_fd (int fd)
169 vcom_socket_main_t *vsm = &vcom_socket_main;
171 vcom_socket_t *vsock;
173 p = hash_get (vsm->sockidx_by_fd, fd);
177 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
178 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
185 vcom_socket_is_vcom_epfd (int epfd)
187 vcom_socket_main_t *vsm = &vcom_socket_main;
189 vcom_epoll_t *vepoll;
191 p = hash_get (vsm->epollidx_by_epfd, epfd);
195 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
196 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
203 vcom_socket_get_sid (int fd)
205 vcom_socket_main_t *vsm = &vcom_socket_main;
207 vcom_socket_t *vsock;
209 p = hash_get (vsm->sockidx_by_fd, fd);
213 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
214 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
217 return INVALID_SESSION_ID;
221 vcom_socket_get_vep_idx (int epfd)
223 vcom_socket_main_t *vsm = &vcom_socket_main;
225 vcom_epoll_t *vepoll;
227 p = hash_get (vsm->epollidx_by_epfd, epfd);
231 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
232 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
233 return vepoll->vep_idx;
235 return INVALID_VEP_IDX;
239 vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
241 vcom_socket_main_t *vsm = &vcom_socket_main;
243 vcom_socket_t *vsock;
245 p = hash_get (vsm->sockidx_by_fd, fd);
249 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
250 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
256 return INVALID_SESSION_ID;
260 vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
262 vcom_socket_main_t *vsm = &vcom_socket_main;
264 vcom_epoll_t *vepoll;
266 p = hash_get (vsm->epollidx_by_epfd, epfd);
270 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
271 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
274 return vepoll->vep_idx;
277 return INVALID_VEP_IDX;
282 vcom_socket_close_vepoll (int epfd)
285 vcom_socket_main_t *vsm = &vcom_socket_main;
287 vcom_epoll_t *vepoll;
289 p = hash_get (vsm->epollidx_by_epfd, epfd);
293 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
297 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
314 rv = vppcom_session_close (vepoll->vep_idx);
315 rv = vcom_socket_close_epoll (vepoll->epfd);
317 vepoll_init (vepoll);
318 hash_unset (vsm->epollidx_by_epfd, epfd);
319 pool_put (vsm->vepolls, vepoll);
325 vcom_socket_close_vsock (int fd)
328 vcom_socket_main_t *vsm = &vcom_socket_main;
330 vcom_socket_t *vsock;
332 vcom_epitem_t *vepitem;
334 i32 *vepitemidxs = 0;
335 i32 *vepitemidxs_var = 0;
337 p = hash_get (vsm->sockidx_by_fd, fd);
341 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
345 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
348 rv = vppcom_session_close (vsock->sid);
349 rv = vcom_socket_close_socket (vsock->fd);
351 vsocket_init (vsock);
352 hash_unset (vsm->sockidx_by_fd, fd);
353 pool_put (vsm->vsockets, vsock);
357 * Before calling close(), user should remove
358 * this fd from the epoll-set of all epoll instances,
359 * otherwise resource(epitems) leaks ensues.
363 * 00. close all epoll instances that are marked as "close"
364 * of which this fd is the "last" remaining member.
365 * 01. epitems associated with this fd are intentionally
366 * not removed, see NOTE: above.
369 /* does this fd participate in epoll */
370 p = hash_get (vsm->epitemidxs_by_fd, fd);
373 vepitemidxs = *(i32 **) p;
374 vec_foreach (vepitemidxs_var, vepitemidxs)
376 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
377 if (vepitem && vepitem->fd == fd &&
378 vepitem->type == FD_TYPE_VCOM_SOCKET)
381 vcom_epoll_t *vepoll;
383 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
389 if (vepoll->count == 1)
392 * force count to zero and
393 * close this epoll instance
396 vcom_socket_close_vepoll (vepoll->epfd);
413 vcom_socket_close (int __fd)
417 if (vcom_socket_is_vcom_fd (__fd))
419 rv = vcom_socket_close_vsock (__fd);
421 else if (vcom_socket_is_vcom_epfd (__fd))
423 rv = vcom_socket_close_vepoll (__fd);
434 vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
437 vcom_socket_main_t *vsm = &vcom_socket_main;
439 vcom_socket_t *vsock;
441 p = hash_get (vsm->sockidx_by_fd, __fd);
445 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
449 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
457 rv = vcom_fcntl (__fd, F_GETFL, 0);
465 if (!(rv & O_NONBLOCK))
469 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
471 /* coverity[CONSTANT_EXPRESSION_RESULT] */
472 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
475 /* The file descriptor refers to a socket and has been
476 * marked nonblocking(O_NONBLOCK) and the read would
479 /* is non blocking */
480 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
485 vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
488 vcom_socket_main_t *vsm = &vcom_socket_main;
490 vcom_socket_t *vsock;
491 ssize_t total = 0, len = 0;
494 p = hash_get (vsm->sockidx_by_fd, __fd);
498 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
502 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
505 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
509 for (i = 0; i < __iovcnt; ++i)
511 if (SSIZE_MAX - len < __iov[i].iov_len)
513 len += __iov[i].iov_len;
516 rv = vcom_fcntl (__fd, F_GETFL, 0);
523 if (!(rv & O_NONBLOCK))
527 for (i = 0; i < __iovcnt; ++i)
529 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
536 if (rv < __iov[i].iov_len)
537 /* Read less than buffer provided, no point to continue */
542 /* coverity[CONSTANT_EXPRESSION_RESULT] */
543 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
547 /* is non blocking */
548 for (i = 0; i < __iovcnt; ++i)
550 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
565 if (rv < __iov[i].iov_len)
566 /* Read less than buffer provided, no point to continue */
574 vcom_socket_write (int __fd, const void *__buf, size_t __n)
577 vcom_socket_main_t *vsm = &vcom_socket_main;
579 vcom_socket_t *vsock;
586 p = hash_get (vsm->sockidx_by_fd, __fd);
590 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
594 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
597 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
602 vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
606 vcom_socket_main_t *vsm = &vcom_socket_main;
608 vcom_socket_t *vsock;
611 p = hash_get (vsm->sockidx_by_fd, __fd);
615 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
619 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
622 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
625 for (i = 0; i < __iovcnt; ++i)
627 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
643 * RETURN: 0 - invalid cmd
644 * 1 - cmd not handled by vcom and vppcom
645 * 2 - cmd handled by vcom socket resource
646 * 3 - cmd handled by vppcom
648 /* TBD: incomplete list of cmd */
650 vcom_socket_check_fcntl_cmd (int __cmd)
654 /*cmd not handled by vcom and vppcom */
657 case F_DUPFD_CLOEXEC:
660 /* cmd handled by vcom socket resource */
671 /* cmd handled by vcom and vppcom */
676 /* cmd not handled by vcom and vppcom */
684 vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
686 int flags = va_arg (__ap, int);
687 int rv = -EOPNOTSUPP;
690 size = sizeof (flags);
691 if (__cmd == F_SETFL)
693 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
695 else if (__cmd == F_GETFL)
697 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
706 vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
709 vcom_socket_main_t *vsm = &vcom_socket_main;
711 vcom_socket_t *vsock;
713 p = hash_get (vsm->sockidx_by_fd, __fd);
717 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
721 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
724 switch (vcom_socket_check_fcntl_cmd (__cmd))
730 /*cmd not handled by vcom and vppcom */
732 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
734 /* cmd handled by vcom socket resource */
736 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
738 /* cmd handled by vppcom */
740 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
752 * RETURN: 0 - invalid cmd
753 * 1 - cmd not handled by vcom and vppcom
754 * 2 - cmd handled by vcom socket resource
755 * 3 - cmd handled by vppcom
758 vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
764 /* cmd handled by vppcom */
769 /* cmd not handled by vcom and vppcom */
778 vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
782 if (__cmd == FIONREAD)
783 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
790 vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
793 vcom_socket_main_t *vsm = &vcom_socket_main;
795 vcom_socket_t *vsock;
797 p = hash_get (vsm->sockidx_by_fd, __fd);
801 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
805 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
808 switch (vcom_socket_check_ioctl_cmd (__cmd))
810 /* Not supported cmd */
815 /* cmd not handled by vcom and vppcom */
817 rv = libc_vioctl (vsock->fd, __cmd, __ap);
820 /* cmd handled by vcom socket resource */
822 rv = libc_vioctl (vsock->fd, __cmd, __ap);
825 /* cmd handled by vppcom */
827 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
839 vcom_socket_fds_2_sid_fds (
842 fd_set * __restrict vcom_rd_sid_fds,
843 fd_set * __restrict vcom_wr_sid_fds,
844 fd_set * __restrict vcom_ex_sid_fds,
847 fd_set * __restrict vcom_readfds,
848 fd_set * __restrict vcom_writefds,
849 fd_set * __restrict vcom_exceptfds)
854 /* invalid max_sid is -1 */
859 * set sid in sid sets corresponding to fd's in fd sets
860 * compute nsid and vcom_nsid_fds from sid sets
863 for (fd = 0; fd < vcom_nfds; fd++)
870 if ((F) && (S) && FD_ISSET (fd, (F))) \
872 sid = vcom_socket_get_sid (fd); \
873 if (sid != INVALID_SESSION_ID) \
890 _(vcom_rd_sid_fds, vcom_readfds);
891 _(vcom_wr_sid_fds, vcom_writefds);
892 _(vcom_ex_sid_fds, vcom_exceptfds);
896 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
904 * PRE: 00. sid sets were derived from fd sets
905 * 01. sid sets were updated with sids that actually changed
907 * 02. fd sets still has watched fds
909 * This function will modify in place fd sets to indicate which fd's
910 * actually changed status(inferred from sid sets)
913 vcom_socket_sid_fds_2_fds (
917 fd_set * __restrict vcom_readfds,
918 fd_set * __restrict vcom_writefds,
919 fd_set * __restrict vcom_exceptfds,
922 fd_set * __restrict vcom_rd_sid_fds,
923 fd_set * __restrict vcom_wr_sid_fds,
924 fd_set * __restrict vcom_ex_sid_fds)
929 /* invalid max_fd is -1 */
935 * modify in place fd sets to indicate which fd's
936 * actually changed status(inferred from sid sets)
938 for (fd = 0; fd < vcom_nfds; fd++)
945 if ((F) && (S) && FD_ISSET (fd, (F))) \
947 sid = vcom_socket_get_sid (fd); \
948 if (sid != INVALID_SESSION_ID) \
950 if (!FD_ISSET (sid, (S))) \
963 _(vcom_rd_sid_fds, vcom_readfds);
964 _(vcom_wr_sid_fds, vcom_writefds);
965 _(vcom_ex_sid_fds, vcom_exceptfds);
970 * compute nfd and new_vcom_nfds from fd sets
972 for (fd = 0; fd < vcom_nfds; fd++)
976 if ((F) && FD_ISSET (fd, (F))) \
993 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
1002 * vom_socket_select is always called with
1003 * timeout->tv_sec and timeout->tv_usec set to zero.
1004 * hence vppcom_select return immediately.
1007 * TBD: do{body;} while(timeout conditional); timeout loop
1010 vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1011 fd_set * __restrict vcom_writefds,
1012 fd_set * __restrict vcom_exceptfds,
1013 struct timeval *__restrict timeout)
1015 static unsigned long vcom_nsid_fds = 0;
1018 pid_t pid = getpid ();
1020 int new_vcom_nfds = 0;
1021 int new_vcom_nfd = 0;
1024 fd_set vcom_rd_sid_fds;
1025 fd_set vcom_wr_sid_fds;
1026 fd_set vcom_ex_sid_fds;
1028 /* in seconds eg. 3.123456789 seconds */
1029 double time_to_wait = (double) 0;
1031 /* validate inputs */
1037 /* convert timeval timeout to double time_to_wait */
1040 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1042 /* polling: vppcom_select returns immediately */
1043 time_to_wait = (double) 0;
1047 /*TBD: use timeval api */
1048 time_to_wait = (double) timeout->tv_sec +
1049 (double) timeout->tv_usec / (double) 1000000 +
1050 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1056 * no timeout: vppcom_select can block indefinitely
1057 * waiting for a file descriptor to become ready
1059 /* set to a phantom value */
1063 /* zero the sid_sets */
1075 _(&vcom_rd_sid_fds, vcom_readfds);
1076 _(&vcom_wr_sid_fds, vcom_writefds);
1077 _(&vcom_ex_sid_fds, vcom_exceptfds);
1082 if (time_to_wait > 0)
1086 "[%d] vcom_socket_select called to "
1087 "emulate delay_ns()!\n", pid);
1088 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1092 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1093 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1098 /* populate read, write and except sid_sets */
1099 vcom_nsid = vcom_socket_fds_2_sid_fds (
1101 vcom_readfds || vcom_writefds
1102 || vcom_exceptfds ? (int *)
1103 &vcom_nsid_fds : NULL,
1104 vcom_readfds ? &vcom_rd_sid_fds :
1106 vcom_writefds ? &vcom_wr_sid_fds :
1108 vcom_exceptfds ? &vcom_ex_sid_fds :
1113 vcom_writefds, vcom_exceptfds);
1119 rv = vppcom_select (vcom_nsid_fds,
1120 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1122 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1124 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1125 NULL, time_to_wait);
1127 fprintf (stderr, "[%d] called vppcom_select(): "
1128 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1130 /* check if any file descriptors changed status */
1134 * on exit, sets are modified in place to indicate which
1135 * file descriptors actually changed status
1139 * comply with pre-condition
1140 * do not clear vcom fd sets befor calling
1141 * vcom_socket_sid_fds_2_fds
1143 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1153 &vcom_rd_sid_fds : NULL,
1155 &vcom_wr_sid_fds : NULL,
1157 &vcom_ex_sid_fds : NULL);
1158 if (new_vcom_nfd < 0)
1160 return new_vcom_nfd;
1162 if (new_vcom_nfds < 0)
1173 vcom_socket_socket (int __domain, int __type, int __protocol)
1176 vcom_socket_main_t *vsm = &vcom_socket_main;
1177 vcom_socket_t *vsock;
1182 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1183 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1185 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1192 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1193 (type == SOCK_DGRAM) ?
1194 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1199 goto out_close_socket;
1202 pool_get (vsm->vsockets, vsock);
1203 vsocket_init (vsock);
1205 sockidx = vsock - vsm->vsockets;
1206 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1208 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1212 vcom_socket_close_socket (fd);
1218 vcom_socket_socketpair (int __domain, int __type, int __protocol,
1226 vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1229 vcom_socket_main_t *vsm = &vcom_socket_main;
1231 vcom_socket_t *vsock;
1235 p = hash_get (vsm->sockidx_by_fd, __fd);
1239 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1243 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1251 ep.vrf = VPPCOM_VRF_DEFAULT;
1252 switch (__addr->sa_family)
1255 if (__len != sizeof (struct sockaddr_in))
1259 ep.is_ip4 = VPPCOM_IS_IP4;
1260 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1261 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1265 if (__len != sizeof (struct sockaddr_in6))
1269 ep.is_ip4 = VPPCOM_IS_IP6;
1270 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1271 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1279 rv = vppcom_session_bind (vsock->sid, &ep);
1284 vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1287 uint32_t size = sizeof (*ep);
1289 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1294 vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1295 socklen_t * __restrict __len)
1298 vcom_socket_main_t *vsm = &vcom_socket_main;
1300 vcom_socket_t *vsock;
1303 p = hash_get (vsm->sockidx_by_fd, __fd);
1307 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1311 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1314 if (!__addr || !__len)
1318 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1319 rv = vcom_session_getsockname (vsock->sid, &ep);
1322 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1324 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1325 switch (__addr->sa_family)
1328 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1329 *__len = sizeof (struct sockaddr_in);
1333 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1334 *__len = sizeof (struct sockaddr_in6);
1347 vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1350 vcom_socket_main_t *vsm = &vcom_socket_main;
1352 vcom_socket_t *vsock;
1356 p = hash_get (vsm->sockidx_by_fd, __fd);
1359 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1361 ep.vrf = VPPCOM_VRF_DEFAULT;
1362 switch (__addr->sa_family)
1365 ep.is_ip4 = VPPCOM_IS_IP4;
1367 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1369 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1373 ep.is_ip4 = VPPCOM_IS_IP6;
1375 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1377 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1385 rv = vppcom_session_connect (vsock->sid, &ep);
1391 vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1394 uint32_t size = sizeof (*ep);
1396 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1401 vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1402 socklen_t * __restrict __len)
1405 vcom_socket_main_t *vsm = &vcom_socket_main;
1407 vcom_socket_t *vsock;
1410 p = hash_get (vsm->sockidx_by_fd, __fd);
1414 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1418 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1421 if (!__addr || !__len)
1425 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1426 rv = vcom_session_getpeername (vsock->sid, &ep);
1429 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1431 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1432 switch (__addr->sa_family)
1435 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1436 *__len = sizeof (struct sockaddr_in);
1440 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1441 *__len = sizeof (struct sockaddr_in6);
1454 vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1456 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1460 vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1463 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1468 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1472 vcom_socket_is_connection_mode_socket (int __fd)
1475 /* TBD define new vppcom api */
1476 vcom_socket_main_t *vsm = &vcom_socket_main;
1478 vcom_socket_t *vsock;
1483 p = hash_get (vsm->sockidx_by_fd, __fd);
1487 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1488 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1490 optlen = sizeof (type);
1491 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1496 /* get socket type */
1497 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1500 case SOCK_SEQPACKET:
1513 static inline ssize_t
1514 vcom_session_sendto (int __sid, void *__buf, size_t __n,
1515 int __flags, __CONST_SOCKADDR_ARG __addr,
1516 socklen_t __addr_len)
1518 vppcom_endpt_t *ep = 0;
1524 ep->vrf = VPPCOM_VRF_DEFAULT;
1525 switch (__addr->sa_family)
1528 ep->is_ip4 = VPPCOM_IS_IP4;
1530 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1532 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1536 ep->is_ip4 = VPPCOM_IS_IP6;
1538 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1540 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1544 return -EAFNOSUPPORT;
1548 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
1552 vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1553 int __flags, __CONST_SOCKADDR_ARG __addr,
1554 socklen_t __addr_len)
1556 vcom_socket_main_t *vsm = &vcom_socket_main;
1558 vcom_socket_t *vsock;
1565 p = hash_get (vsm->sockidx_by_fd, __fd);
1569 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1573 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1578 if (vcom_socket_is_connection_mode_socket (__fd))
1580 /* ignore __addr and _addr_len */
1581 /* and EISCONN may be returned when they are not NULL and 0 */
1582 if ((__addr != NULL) || (__addr_len != 0))
1591 return -EDESTADDRREQ;
1593 /* not a vppcom supported address family */
1594 if (!((__addr->sa_family == AF_INET) ||
1595 (__addr->sa_family == AF_INET6)))
1601 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1602 __flags, __addr, __addr_len);
1605 static inline ssize_t
1606 vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1607 int __flags, __SOCKADDR_ARG __addr,
1608 socklen_t * __restrict __addr_len)
1612 u8 src_addr[sizeof (struct sockaddr_in6)];
1617 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1621 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1624 ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1625 switch (__addr->sa_family)
1628 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1629 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
1630 src_addr, sizeof (struct in_addr));
1632 *__addr_len = sizeof (struct sockaddr_in);
1636 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1637 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1638 __in6_u.__u6_addr8, src_addr,
1639 sizeof (struct in6_addr));
1640 *__addr_len = sizeof (struct sockaddr_in6);
1653 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1659 vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1660 int __flags, __SOCKADDR_ARG __addr,
1661 socklen_t * __restrict __addr_len)
1664 vcom_socket_main_t *vsm = &vcom_socket_main;
1666 vcom_socket_t *vsock;
1668 if (__addr && !__addr_len)
1671 p = hash_get (vsm->sockidx_by_fd, __fd);
1675 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1679 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1684 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1685 __flags, __addr, __addr_len);
1689 /* TBD: move it to vppcom */
1690 static inline ssize_t
1691 vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1694 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1700 vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1703 vcom_socket_main_t *vsm = &vcom_socket_main;
1705 vcom_socket_t *vsock;
1707 p = hash_get (vsm->sockidx_by_fd, __fd);
1711 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1715 if (vcom_socket_is_connection_mode_socket (__fd))
1717 /* ignore __addr and _addr_len */
1718 /* and EISCONN may be returned when they are not NULL and 0 */
1719 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1726 /* TBD: validate __message->msg_name and __message->msg_namelen
1727 * and return -EINVAL on validation error
1732 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
1739 vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1740 unsigned int __vlen, int __flags)
1743 /* TBD: define a new vppcom api */
1748 /* TBD: move it to vppcom */
1749 static inline ssize_t
1750 vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
1753 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1760 vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1763 vcom_socket_main_t *vsm = &vcom_socket_main;
1765 vcom_socket_t *vsock;
1767 p = hash_get (vsm->sockidx_by_fd, __fd);
1771 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1775 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1783 /* validate __flags */
1785 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
1791 vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1792 unsigned int __vlen, int __flags,
1793 struct timespec *__tmo)
1795 /* TBD: define a new vppcom api */
1800 /* TBD: move it to vppcom */
1802 vcom_session_get_sockopt (int __sid, int __level, int __optname,
1803 void *__restrict __optval,
1804 socklen_t * __restrict __optlen)
1808 /* 1. for socket level options that are NOT socket attributes
1809 * and that has corresponding vpp options get from vppcom */
1816 *(int *) __optval = 0;
1824 /* 2. unhandled options */
1829 vcom_socket_getsockopt (int __fd, int __level, int __optname,
1830 void *__restrict __optval,
1831 socklen_t * __restrict __optlen)
1834 vcom_socket_main_t *vsm = &vcom_socket_main;
1836 vcom_socket_t *vsock;
1838 if (!__optval || !__optlen)
1841 p = hash_get (vsm->sockidx_by_fd, __fd);
1845 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1849 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1858 * 1. for socket level options that are socket attributes,
1859 * get from libc_getsockopt.
1860 * 2. for socket level options that are NOT socket
1861 * attributes and that has corresponding vpp options
1863 * 3. for socket level options unimplemented
1864 * return -ENOPROTOOPT */
1882 case SO_TIMESTAMPNS:
1883 case SO_TIMESTAMPING:
1896 case SO_WIFI_STATUS:
1899 case SO_BINDTODEVICE:
1901 case SO_LOCK_FILTER:
1902 case SO_BPF_EXTENSIONS:
1903 case SO_SELECT_ERR_QUEUE:
1904 #ifdef CONFIG_NET_RX_BUSY_POLL
1907 case SO_MAX_PACING_RATE:
1908 #ifdef SO_INCOMING_CPU
1909 case SO_INCOMING_CPU:
1911 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1920 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1921 __optval, __optlen);
1925 /* We implement the SO_SNDLOWAT etc to not be settable
1928 return -ENOPROTOOPT;
1934 /* 1. handle options that are NOT socket level options,
1935 * but have corresponding vpp otions. */
1936 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1937 __optval, __optlen);
1944 /* TBD: move it to vppcom */
1946 vcom_session_setsockopt (int __sid, int __level, int __optname,
1947 const void *__optval, socklen_t __optlen)
1949 int rv = -EOPNOTSUPP;
1958 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1962 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1972 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
1982 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1985 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
1988 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
2002 vcom_socket_setsockopt (int __fd, int __level, int __optname,
2003 const void *__optval, socklen_t __optlen)
2006 vcom_socket_main_t *vsm = &vcom_socket_main;
2008 vcom_socket_t *vsock;
2010 p = hash_get (vsm->sockidx_by_fd, __fd);
2014 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2018 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2022 * Options without arguments
2025 if (__optname == SO_BINDTODEVICE)
2027 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2038 if (__optlen < sizeof (int))
2047 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2048 __optval, __optlen);
2061 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2062 __optval, __optlen);
2068 /* handle options at socket level */
2075 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2076 __optval, __optlen);
2080 * 1. for socket level options that are socket attributes,
2081 * set it from libc_getsockopt
2082 * 2. for socket level options that are NOT socket
2083 * attributes and that has corresponding vpp options
2084 * set it from vppcom
2085 * 3. for socket level options unimplemented
2086 * return -ENOPROTOOPT */
2102 case SO_TIMESTAMPNS:
2103 case SO_TIMESTAMPING:
2116 case SO_WIFI_STATUS:
2120 * SO_BINDTODEVICE already handled as
2121 * "Options without arguments" */
2122 /* case SO_BINDTODEVICE: */
2124 case SO_LOCK_FILTER:
2125 case SO_BPF_EXTENSIONS:
2126 case SO_SELECT_ERR_QUEUE:
2127 #ifdef CONFIG_NET_RX_BUSY_POLL
2130 case SO_MAX_PACING_RATE:
2131 #ifdef SO_INCOMING_CPU
2132 case SO_INCOMING_CPU:
2134 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2143 /* We implement the SO_SNDLOWAT etc to not be settable
2146 return -ENOPROTOOPT;
2152 return -ENOPROTOOPT;
2159 vcom_socket_listen (int __fd, int __n)
2162 vcom_socket_main_t *vsm = &vcom_socket_main;
2164 vcom_socket_t *vsock;
2166 p = hash_get (vsm->sockidx_by_fd, __fd);
2169 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2171 /* TBD vppcom to accept __n parameter */
2172 rv = vppcom_session_listen (vsock->sid, __n);
2179 vcom_socket_connected_socket (int __fd, int __sid,
2181 int *__type, int *__protocol, int flags)
2184 vcom_socket_main_t *vsm = &vcom_socket_main;
2185 vcom_socket_t *vsock;
2192 optlen = sizeof (*__domain);
2193 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2200 optlen = sizeof (*__type);
2201 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2208 optlen = sizeof (*__protocol);
2209 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2216 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2223 pool_get (vsm->vsockets, vsock);
2224 vsocket_init (vsock);
2226 sockidx = vsock - vsm->vsockets;
2227 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2229 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2236 /* If flag is 0, then accept4() is the same as accept().
2237 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2240 vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2241 socklen_t * __restrict __addr_len, int flags)
2244 vcom_socket_main_t *vsm = &vcom_socket_main;
2246 vcom_socket_t *vsock;
2254 uint8_t addr8[sizeof (struct in6_addr)];
2259 /* validate flags */
2266 * case SOCK_NONBLOCK:
2267 * case SOCK_CLOEXEC:
2268 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2275 /* flags can be 0 or can be bitwise OR
2276 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2278 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2280 /* TBD: return proper error code */
2284 /* TBD: return proper error code */
2286 if (!vcom_socket_is_connection_mode_socket (__fd))
2291 p = hash_get (vsm->sockidx_by_fd, __fd);
2294 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2297 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2304 if (!(rv & O_NONBLOCK))
2306 /* socket is not marked as nonblocking
2307 * and no pending connections are present
2308 * on the queue, accept () blocks the caller
2309 * until a connection is present.
2311 rv = vppcom_session_accept (vsock->sid, &ep,
2312 -1.0 /* wait forever */ );
2316 /* The file descriptor refers to a socket and has been
2317 * marked nonblocking(O_NONBLOCK) and the accept would
2320 /* is non blocking */
2321 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2322 /* If the socket is marked nonblocking and
2323 * no pending connections are present on the
2324 * queue, accept fails with the error
2325 * EAGAIN or EWOULDBLOCK
2327 if (rv == VPPCOM_ETIMEDOUT)
2339 /* create a new connected socket resource and set flags
2340 * on the new file descriptor.
2341 * update vsockets and sockidx_by_fd table
2343 fd = vcom_socket_connected_socket (__fd, sid,
2344 &domain, &type, &protocol, flags);
2352 /* TBD populate __addr and __addr_len */
2353 /* TBD: The returned address is truncated if the buffer
2354 * provided is too small, in this case, __addr_len will
2355 * return a value greater than was supplied to the call.*/
2360 /* TBD populate __addr and __addr_len */
2364 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2365 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2366 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2367 addr8, sizeof (struct in_addr));
2368 /* TBD: populate __addr_len */
2371 *__addr_len = sizeof (struct sockaddr_in);
2376 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2377 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2378 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2379 __in6_u.__u6_addr8, addr8,
2380 sizeof (struct in6_addr));
2381 /* TBD: populate __addr_len */
2384 *__addr_len = sizeof (struct sockaddr_in6);
2389 return -EAFNOSUPPORT;
2397 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2398 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2399 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2400 addr8, sizeof (struct in_addr));
2401 /* TBD: populate __addr_len */
2404 *__addr_len = sizeof (struct sockaddr_in);
2409 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2410 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2411 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2412 __in6_u.__u6_addr8, addr8,
2413 sizeof (struct in6_addr));
2414 /* TBD: populate __addr_len */
2417 *__addr_len = sizeof (struct sockaddr_in6);
2422 return -EAFNOSUPPORT;
2428 /* when __addr is NULL, nothing is filled in,
2429 * in this case, __addr_len is not used,
2430 * and should also be null
2434 /* TBD: return proper error code */
2444 vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2445 socklen_t * __restrict __addr_len)
2447 /* set flags to 0 for accept() */
2448 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2453 vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2454 socklen_t * __restrict __addr_len, int __flags)
2456 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2457 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2461 /* TBD: move it to vppcom */
2463 vcom_session_shutdown (int __fd, int __how)
2469 vcom_socket_shutdown (int __fd, int __how)
2472 vcom_socket_main_t *vsm = &vcom_socket_main;
2474 vcom_socket_t *vsock;
2476 p = hash_get (vsm->sockidx_by_fd, __fd);
2479 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2485 rv = vcom_session_shutdown (vsock->sid, __how);
2499 vcom_socket_epoll_create1 (int __flags)
2502 vcom_socket_main_t *vsm = &vcom_socket_main;
2503 vcom_epoll_t *vepoll;
2509 epfd = vcom_socket_open_epoll (__flags);
2516 vep_idx = vppcom_epoll_create ();
2520 goto out_close_epoll;
2523 pool_get (vsm->vepolls, vepoll);
2524 vepoll_init (vepoll);
2526 epollidx = vepoll - vsm->vepolls;
2527 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2529 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2534 vcom_socket_close_epoll (epfd);
2540 * PRE: vppcom_epoll_ctl() is successful
2541 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2544 vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2545 struct epoll_event *__event,
2546 i32 vep_idx, vcom_epoll_t * vepoll,
2547 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2548 int free_vepitem_on_del)
2551 vcom_socket_main_t *vsm = &vcom_socket_main;
2552 vcom_epitem_t *vepitem;
2554 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2558 i32 *vepitemidxs = 0;
2560 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2564 /* perform control operations on the epoll instance */
2569 * supplied file descriptor is already
2570 * registered with this epoll instance
2572 /* vepitem exists */
2573 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2580 /* add a new vepitem */
2581 pool_get (vsm->vepitems, vepitem);
2582 vepitem_init (vepitem);
2584 vepitemidx = vepitem - vsm->vepitems;
2585 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2586 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2588 /* update epitemidxs */
2590 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2591 if (!p) /* not exist */
2594 vec_add1 (vepitemidxs, vepitemidx);
2595 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2599 vepitemidxs = *(i32 **) p;
2600 vec_add1 (vepitemidxs, vepitemidx);
2601 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2603 /* update epitemidxs */
2605 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2606 if (!p) /* not exist */
2609 vec_add1 (vepitemidxs, vepitemidx);
2610 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2614 vepitemidxs = *(i32 **) p;
2615 vec_add1 (vepitemidxs, vepitemidx);
2616 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2619 /* increment vepoll fd count by 1 */
2628 * supplied file descriptor is not
2629 * registered with this epoll instance
2631 /* vepitem not exist */
2632 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2638 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2641 vepitem->event = *__event;
2642 vepitem->revent = revent;
2651 * supplied file descriptor is not
2652 * registered with this epoll instance
2654 /* vepitem not exist */
2655 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2661 vepitemidx = *(i32 *) p;
2662 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2664 /* update epitemidxs */
2666 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2667 if (!p) /* not exist */
2674 vepitemidxs = *(i32 **) p;
2675 vec_idx = vec_search (vepitemidxs, vepitemidx);
2678 vec_del1 (vepitemidxs, vec_idx);
2679 if (!vec_len (vepitemidxs))
2681 vec_free (vepitemidxs);
2682 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2687 /* update epitemidxs */
2689 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2690 if (!p) /* not exist */
2697 vepitemidxs = *(i32 **) p;
2698 vec_idx = vec_search (vepitemidxs, vepitemidx);
2701 vec_del1 (vepitemidxs, vec_idx);
2702 if (!vec_len (vepitemidxs))
2704 vec_free (vepitemidxs);
2705 hash_unset (vsm->epitemidxs_by_fd, __fd);
2710 /* pool put vepitem */
2711 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2712 if (free_vepitem_on_del)
2719 vepitem_init (vepitem);
2720 pool_put (vsm->vepitems, vepitem);
2726 vepitem_init (vepitem);
2730 /* decrement vepoll fd count by 1 */
2748 * PRE: 00. null pointer check on __event
2749 * 01. all other parameters are validated
2753 vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2754 struct epoll_event *__event,
2755 int free_vepitem_on_del)
2759 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2760 vcom_epoll_t *vepoll;
2762 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2764 vcom_epoll_t *vfd_vepoll;
2765 vcom_socket_t *vfd_vsock;
2770 vcom_fd_type_t type = FD_TYPE_INVALID;
2772 /* validate __event */
2774 /* get vep_idx and vepoll */
2775 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2776 if (vep_idx == INVALID_VEP_IDX)
2781 /* get vcom fd type, vfd_id and vfd */
2782 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2783 if (vfd_id != INVALID_SESSION_ID)
2785 type = FD_TYPE_VCOM_SOCKET;
2788 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2791 type = FD_TYPE_EPOLL;
2796 /* FD_TYPE_KERNEL not supported by epoll instance */
2797 type = FD_TYPE_INVALID;
2802 /* vepoll and vsock are now valid */
2803 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2809 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2812 vfd_id, vfd, type, free_vepitem_on_del);
2817 vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2818 struct epoll_event *__event)
2822 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2827 vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2828 struct epoll_event *__event)
2832 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2837 vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2838 int __maxevents, int __timeout,
2839 const __sigset_t * __ss)
2843 /* in seconds eg. 3.123456789 seconds */
2844 double time_to_wait = (double) 0;
2848 /* validate __event */
2855 /* validate __timeout */
2858 time_to_wait = (double) __timeout / (double) 1000;
2860 else if (__timeout == 0)
2862 time_to_wait = (double) 0;
2864 else if (__timeout == -1)
2875 vep_idx = vcom_socket_get_vep_idx (__epfd);
2876 if (vep_idx != INVALID_VEP_IDX)
2878 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2885 vcom_pollfds_2_selectfds (
2887 struct pollfd *__fds, nfds_t __nfds,
2890 fd_set * __restrict vcom_readfds,
2891 fd_set * __restrict vcom_writefds,
2892 fd_set * __restrict vcom_exceptfds)
2896 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2898 /* ignore negative fds */
2899 if (__fds[fds_idx].fd < 0)
2904 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2905 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2907 /* requested events */
2908 if (__fds[fds_idx].events)
2910 if (__fds[fds_idx].events & POLLIN)
2912 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2914 if (__fds[fds_idx].events & POLLPRI)
2916 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2918 if (__fds[fds_idx].events & POLLOUT)
2920 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2922 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2923 if (__fds[fds_idx].events & POLLRDNORM)
2925 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2927 if (__fds[fds_idx].events & POLLRDBAND)
2929 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2931 if (__fds[fds_idx].events & POLLWRNORM)
2933 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2935 if (__fds[fds_idx].events & POLLWRBAND)
2937 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2941 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2945 vcom_selectfds_2_pollfds (
2947 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2950 fd_set * __restrict vcom_readfds,
2951 fd_set * __restrict vcom_writefds,
2952 fd_set * __restrict vcom_exceptfds)
2957 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2959 /* ignore negative fds */
2960 if (__fds[fds_idx].fd < 0)
2962 __fds[fds_idx].revents = 0;
2965 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2966 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2969 * TBD: for now any select exception
2970 * is flagged as POLLERR
2972 __fds[fds_idx].revents |= POLLERR;
2975 /* requested events */
2976 if (__fds[fds_idx].events & POLLIN)
2978 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2980 __fds[fds_idx].revents |= POLLIN;
2983 if (__fds[fds_idx].events & POLLPRI)
2985 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2987 __fds[fds_idx].revents |= POLLIN;
2990 if (__fds[fds_idx].events & POLLOUT)
2992 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2994 __fds[fds_idx].revents |= POLLOUT;
2997 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2998 if (__fds[fds_idx].events & POLLRDNORM)
3000 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3002 __fds[fds_idx].revents |= POLLRDNORM;
3005 if (__fds[fds_idx].events & POLLRDBAND)
3007 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3009 __fds[fds_idx].revents |= POLLRDBAND;
3012 if (__fds[fds_idx].events & POLLWRNORM)
3014 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3016 __fds[fds_idx].revents |= POLLWRNORM;
3019 if (__fds[fds_idx].events & POLLWRBAND)
3021 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3023 __fds[fds_idx].revents |= POLLWRBAND;
3027 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3031 * the number of structures which have nonzero revents fields
3032 * (in other words, those descriptors with events or
3036 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3038 /* ignore negative fds */
3039 if (__fds[fds_idx].fd < 0)
3044 if (__fds[fds_idx].revents)
3052 * PRE: parameters are validated,
3053 * vcom_socket_poll is always called with __timeout set to zero
3054 * hence returns immediately
3056 * ACTION: handle non negative validated vcom fds and ignore rest
3060 * implements vcom_socket_poll () interface
3062 * internally uses vcom_socket_select ()
3063 * to realize the behavior
3066 vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3070 pid_t pid = getpid ();
3077 fd_set vcom_readfds;
3078 fd_set vcom_writefds;
3079 fd_set vcom_exceptfds;
3081 /* invalid max_vcom_fd is -1 */
3082 int max_vcom_fd = -1;
3084 /* __timeout is zero to get ready events and return immediately */
3085 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3087 /* validate __nfds from select perspective */
3088 if (__nfds > FD_SETSIZE)
3094 /* zero vcom fd sets */
3110 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3112 /* ignore negative fds */
3113 if (__fds[fds_idx].fd < 0)
3118 /* non negative validated vcom fds */
3119 if (__fds[fds_idx].fd > FD_SETSIZE)
3125 /* max_vcom_fd and vcom_nfd */
3126 if (__fds[fds_idx].fd > max_vcom_fd)
3128 /* requested events */
3129 if (__fds[fds_idx].events)
3131 max_vcom_fd = __fds[fds_idx].fd;
3137 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3145 vcom_pollfds_2_selectfds (
3150 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3152 /* select on vcom fds */
3153 vcom_nfd = vcom_socket_select (vcom_nfds,
3155 &vcom_writefds, &vcom_exceptfds, &tv);
3158 "[%d] vcom_socket_select: "
3159 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3167 vcom_selectfds_2_pollfds (
3169 __fds, __nfds, &nfd,
3172 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3181 * TBD: remove this static function once vppcom
3182 * has an implementation in place
3187 vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3193 vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3198 /* in seconds eg. 3.123456789 seconds */
3199 double time_to_wait = (double) 0;
3204 /* replace vcom fd with session idx */
3205 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3207 /* ignore negative fds */
3208 if (__fds[fds_idx].fd < 0)
3213 /* non negative validated vcom fds */
3214 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3215 if (sid != INVALID_SESSION_ID)
3217 __fds[fds_idx].fd = sid;
3222 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3223 if (vep_idx != INVALID_VEP_IDX)
3225 __fds[fds_idx].fd = vep_idx;
3234 /* validate __timeout */
3237 time_to_wait = (double) __timeout / (double) 1000;
3239 else if (__timeout == 0)
3241 time_to_wait = (double) 0;
3248 return vppcom_poll (__fds, __nfds, time_to_wait);
3252 vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3254 /* select an implementation */
3256 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3257 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3262 vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3263 const struct timespec *__timeout, const __sigset_t * __ss)
3270 vcom_socket_main_init (void)
3272 vcom_socket_main_t *vsm = &vcom_socket_main;
3275 printf ("vcom_socket_main_init\n");
3279 /* TBD: define FD_MAXSIZE and use it here */
3280 pool_alloc (vsm->vsockets, FD_SETSIZE);
3281 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3283 pool_alloc (vsm->vepolls, FD_SETSIZE);
3284 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3286 pool_alloc (vsm->vepitems, FD_SETSIZE);
3287 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3289 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3290 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3300 vcom_socket_main_show (void)
3302 vcom_socket_main_t *vsm = &vcom_socket_main;
3303 vcom_socket_t *vsock;
3305 vcom_epoll_t *vepoll;
3307 vcom_epitem_t *vepitem;
3311 i32 *vepitemidxs, *vepitemidxs_var;
3315 /* from active list of vsockets show vsock */
3318 pool_foreach (vsock, vsm->vsockets,
3321 "fd='%04d', sid='%08x',type='%-30s'\n",
3322 vsock->fd, vsock->sid,
3323 vcom_socket_type_str (vsock->type));
3327 /* from active list of vepolls, show vepoll */
3330 pool_foreach (vepoll, vsm->vepolls,
3333 "epfd='%04d', vep_idx='%08x', "
3335 "flags='%d', count='%d', close='%d'\n",
3336 vepoll->epfd, vepoll->vep_idx,
3337 vcom_socket_epoll_type_str (vepoll->type),
3338 vepoll->flags, vepoll->count, vepoll->close);
3342 /* from active list of vepitems, show vepitem */
3345 pool_foreach (vepitem, vsm->vepitems,
3348 "epfd='%04d', fd='%04d', "
3349 "next_fd='%04d', prev_fd='%04d', "
3351 "events='%04x', revents='%04x'\n",
3352 vepitem->epfd, vepitem->fd,
3353 vepitem->next_fd, vepitem->prev_fd,
3354 vcom_socket_vcom_fd_type_str (vepitem->type),
3355 vepitem->event.events, vepitem->revent.events);
3360 /* show epitemidxs for epfd */
3362 hash_foreach (epfd, vepitemidxs,
3363 vsm->epitemidxs_by_epfd,
3365 printf("\n[ '%04d': ", epfd);
3366 vec_foreach (vepitemidxs_var,vepitemidxs)
3368 printf("'%04d' ", (int)vepitemidxs_var[0]);
3374 /* show epitemidxs for fd */
3376 hash_foreach (fd, vepitemidxs,
3377 vsm->epitemidxs_by_fd,
3379 printf("\n{ '%04d': ", fd);
3380 vec_foreach (vepitemidxs_var,vepitemidxs)
3382 printf("'%04d' ", (int)vepitemidxs_var[0]);
3392 vcom_socket_main_destroy (void)
3394 vcom_socket_main_t *vsm = &vcom_socket_main;
3395 vcom_socket_t *vsock;
3397 vcom_epoll_t *vepoll;
3399 vcom_epitem_t *vepitem;
3407 printf ("vcom_socket_main_destroy\n");
3413 * from active list of vepitems,
3414 * remove all "vepitem" elements from the pool in a safe way
3418 pool_flush (vepitem, vsm->vepitems,
3420 if ((vepitem->type == FD_TYPE_EPOLL) ||
3421 (vepitem->type == FD_TYPE_VCOM_SOCKET))
3423 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3425 vepitem_init (vepitem);
3430 pool_free (vsm->vepitems);
3431 hash_free (vsm->epitemidx_by_epfdfd);
3433 /* free vepitemidxs for each epfd */
3435 hash_foreach (epfd, vepitemidxs,
3436 vsm->epitemidxs_by_epfd,
3438 vec_free (vepitemidxs);
3441 hash_free (vsm->epitemidxs_by_epfd);
3443 /* free vepitemidxs for each fd */
3445 hash_foreach (fd, vepitemidxs,
3446 vsm->epitemidxs_by_fd,
3448 vec_free (vepitemidxs);
3451 hash_free (vsm->epitemidxs_by_fd);
3455 * from active list of vsockets,
3456 * close socket and vppcom session
3460 pool_foreach (vsock, vsm->vsockets,
3462 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3464 vppcom_session_close (vsock->sid);
3465 vcom_socket_close_socket (vsock->fd);
3466 vsocket_init (vsock);
3472 * return vsocket element to the pool
3476 pool_flush (vsock, vsm->vsockets,
3478 // vsocket_init(vsock);
3483 pool_free (vsm->vsockets);
3484 hash_free (vsm->sockidx_by_fd);
3487 * from active list of vepolls,
3488 * close epoll and vppcom_epoll
3492 pool_foreach (vepoll, vsm->vepolls,
3494 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3496 vppcom_session_close (vepoll->vep_idx);
3497 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3498 vepoll_init (vepoll);
3504 * return vepoll element to the pool
3508 pool_flush (vepoll, vsm->vepolls,
3510 // vepoll_init(vepoll);
3515 pool_free (vsm->vepolls);
3516 hash_free (vsm->epollidx_by_epfd);
3524 * fd.io coding-style-patch-verification: ON
3527 * eval: (c-set-style "gnu")