blob: 1686c4fc3cff2b98d5d57e1b4930e48ad89360e0 [file] [log] [blame]
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001/*
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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15#include <unistd.h>
16#include <stdio.h>
17#include <sys/uio.h>
18#include <limits.h>
19#define __need_IOV_MAX
20#include <bits/stdio_lim.h>
Stevenb59f2272017-10-12 17:10:33 -070021#include <netinet/tcp.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070022
23#include <vppinfra/types.h>
24#include <vppinfra/hash.h>
25#include <vppinfra/pool.h>
26
27#include <libvcl-ldpreload/vcom_socket.h>
28#include <libvcl-ldpreload/vcom_socket_wrapper.h>
29#include <libvcl-ldpreload/vcom.h>
30
31#include <uri/vppcom.h>
32
33
34/*
35 * VCOM_SOCKET Private definitions and functions.
36 */
37
38typedef struct vcom_socket_main_t_
39{
40 u8 init;
41
42 /* vcom_socket pool */
43 vcom_socket_t *vsockets;
44
45 /* Hash table for socketidx to fd mapping */
46 uword *sockidx_by_fd;
47
48 /* vcom_epoll pool */
49 vcom_epoll_t *vepolls;
50
51 /* Hash table for epollidx to epfd mapping */
52 uword *epollidx_by_epfd;
53
54
55 /* common epitem poll for all epfd */
56 /* TBD: epitem poll per epfd */
57 /* vcom_epitem pool */
58 vcom_epitem_t *vepitems;
59
60 /* Hash table for epitemidx to epfdfd mapping */
61 uword *epitemidx_by_epfdfd;
62
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;
67
68} vcom_socket_main_t;
69
70vcom_socket_main_t vcom_socket_main;
71
72
73static int
74vcom_socket_open_socket (int domain, int type, int protocol)
75{
76 int rv = -1;
77
78 /* handle domains implemented by vpp */
79 switch (domain)
80 {
81 case AF_INET:
82 case AF_INET6:
83 /* get socket type and
84 * handle the socket types supported by vpp */
85 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
86 {
87 case SOCK_STREAM:
88 case SOCK_DGRAM:
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);
95 if (rv == -1)
96 rv = -errno;
97 break;
98
99 default:
100 break;
101 }
102
103 break;
104
105 default:
106 break;
107 }
108
109 return rv;
110}
111
112static int
113vcom_socket_open_epoll (int flags)
114{
115 int rv = -1;
116
117 if (flags < 0)
118 {
119 return -EINVAL;
120 }
121 if (flags && (flags & ~EPOLL_CLOEXEC))
122 {
123 return -EINVAL;
124 }
125
126 /* flags can be either zero or EPOLL_CLOEXEC */
127 rv = libc_epoll_create1 (flags);
128 if (rv == -1)
129 rv = -errno;
130
131 return rv;
132}
133
134static int
135vcom_socket_close_socket (int fd)
136{
137 int rv;
138
139 rv = libc_close (fd);
140 if (rv == -1)
141 rv = -errno;
142
143 return rv;
144}
145
146static int
147vcom_socket_close_epoll (int epfd)
148{
149 int rv;
150
151 rv = libc_close (epfd);
152 if (rv == -1)
153 rv = -errno;
154
155 return rv;
156}
157
158/*
159 * Public API functions
160 */
161
162
163int
164vcom_socket_is_vcom_fd (int fd)
165{
166 vcom_socket_main_t *vsm = &vcom_socket_main;
167 uword *p;
168 vcom_socket_t *vsock;
169
170 p = hash_get (vsm->sockidx_by_fd, fd);
171
172 if (p)
173 {
174 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
175 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
176 return 1;
177 }
178 return 0;
179}
180
181int
182vcom_socket_is_vcom_epfd (int epfd)
183{
184 vcom_socket_main_t *vsm = &vcom_socket_main;
185 uword *p;
186 vcom_epoll_t *vepoll;
187
188 p = hash_get (vsm->epollidx_by_epfd, epfd);
189
190 if (p)
191 {
192 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
193 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
194 return 1;
195 }
196 return 0;
197}
198
199static inline int
200vcom_socket_get_sid (int fd)
201{
202 vcom_socket_main_t *vsm = &vcom_socket_main;
203 uword *p;
204 vcom_socket_t *vsock;
205
206 p = hash_get (vsm->sockidx_by_fd, fd);
207
208 if (p)
209 {
210 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
211 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
212 return vsock->sid;
213 }
214 return INVALID_SESSION_ID;
215}
216
217static inline int
218vcom_socket_get_vep_idx (int epfd)
219{
220 vcom_socket_main_t *vsm = &vcom_socket_main;
221 uword *p;
222 vcom_epoll_t *vepoll;
223
224 p = hash_get (vsm->epollidx_by_epfd, epfd);
225
226 if (p)
227 {
228 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
229 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
230 return vepoll->vep_idx;
231 }
232 return INVALID_VEP_IDX;
233}
234
235static inline int
236vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
237{
238 vcom_socket_main_t *vsm = &vcom_socket_main;
239 uword *p;
240 vcom_socket_t *vsock;
241
242 p = hash_get (vsm->sockidx_by_fd, fd);
243
244 if (p)
245 {
246 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
247 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
248 {
249 *vsockp = vsock;
250 return vsock->sid;
251 }
252 }
253 return INVALID_SESSION_ID;
254}
255
256static inline int
257vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
258{
259 vcom_socket_main_t *vsm = &vcom_socket_main;
260 uword *p;
261 vcom_epoll_t *vepoll;
262
263 p = hash_get (vsm->epollidx_by_epfd, epfd);
264
265 if (p)
266 {
267 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
268 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
269 {
270 *vepollp = vepoll;
271 return vepoll->vep_idx;
272 }
273 }
274 return INVALID_VEP_IDX;
275}
276
277
278static int
279vcom_socket_close_vepoll (int epfd)
280{
281 int rv = -1;
282 vcom_socket_main_t *vsm = &vcom_socket_main;
283 uword *p;
284 vcom_epoll_t *vepoll;
285
286 p = hash_get (vsm->epollidx_by_epfd, epfd);
287 if (!p)
288 return -EBADF;
289
290 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
291 if (!vepoll)
292 return -EBADF;
293
294 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
295 return -EINVAL;
296
297 if (vepoll->count)
298 {
299 if (!vepoll->close)
300 {
301 vepoll->close = 1;
302 return 0;
303 }
304 else
305 {
306 return -EBADF;
307 }
308 }
309
310 /* count is zero */
311 rv = vppcom_session_close (vepoll->vep_idx);
312 rv = vcom_socket_close_epoll (vepoll->epfd);
313
314 vepoll_init (vepoll);
315 hash_unset (vsm->epollidx_by_epfd, epfd);
316 pool_put (vsm->vepolls, vepoll);
317
318 return rv;
319}
320
321static int
322vcom_socket_close_vsock (int fd)
323{
324 int rv = -1;
325 vcom_socket_main_t *vsm = &vcom_socket_main;
326 uword *p;
327 vcom_socket_t *vsock;
328
329 vcom_epitem_t *vepitem;
330
331 i32 *vepitemidxs = 0;
332 i32 *vepitemidxs_var = 0;
333
334 p = hash_get (vsm->sockidx_by_fd, fd);
335 if (!p)
336 return -EBADF;
337
338 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
339 if (!vsock)
340 return -ENOTSOCK;
341
342 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
343 return -EINVAL;
344
345 rv = vppcom_session_close (vsock->sid);
346 rv = vcom_socket_close_socket (vsock->fd);
347
348 vsocket_init (vsock);
349 hash_unset (vsm->sockidx_by_fd, fd);
350 pool_put (vsm->vsockets, vsock);
351
352 /*
353 * NOTE:
354 * Before calling close(), user should remove
355 * this fd from the epoll-set of all epoll instances,
356 * otherwise resource(epitems) leaks ensues.
357 */
358
359 /*
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.
364 * */
365
366 /* does this fd participate in epoll */
367 p = hash_get (vsm->epitemidxs_by_fd, fd);
368 if (p)
369 {
370 vepitemidxs = *(i32 **) p;
371 vec_foreach (vepitemidxs_var, vepitemidxs)
372 {
373 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
374 if (vepitem && vepitem->fd == fd &&
375 vepitem->type == FD_TYPE_VCOM_SOCKET)
376 {
377 i32 vep_idx;
378 vcom_epoll_t *vepoll;
379 if ((vep_idx =
380 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
381 &vepoll)) !=
382 INVALID_VEP_IDX)
383 {
384 if (vepoll->close)
385 {
386 if (vepoll->count == 1)
387 {
388 /*
389 * force count to zero and
390 * close this epoll instance
391 * */
392 vepoll->count = 0;
393 vcom_socket_close_vepoll (vepoll->epfd);
394 }
395 else
396 {
397 vepoll->count -= 1;
398 }
399 }
400 }
401 }
402
403 }
404 }
405
406 return rv;
407}
408
409int
410vcom_socket_close (int __fd)
411{
412 int rv;
413
414 if (vcom_socket_is_vcom_fd (__fd))
415 {
416 rv = vcom_socket_close_vsock (__fd);
417 }
418 else if (vcom_socket_is_vcom_epfd (__fd))
419 {
420 rv = vcom_socket_close_vepoll (__fd);
421 }
422 else
423 {
424 rv = -EBADF;
425 }
426
427 return rv;
428}
429
430ssize_t
431vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
432{
433 int rv = -1;
434 vcom_socket_main_t *vsm = &vcom_socket_main;
435 uword *p;
436 vcom_socket_t *vsock;
437
438 p = hash_get (vsm->sockidx_by_fd, __fd);
439 if (!p)
440 return -EBADF;
441
442 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
443 if (!vsock)
444 return -ENOTSOCK;
445
446 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
447 return -EINVAL;
448
449 if (!__buf || __nbytes < 0)
450 {
451 return -EINVAL;
452 }
453
454 rv = vcom_fcntl (__fd, F_GETFL, 0);
455 if (rv < 0)
456 {
457 return rv;
458
459 }
460
461 /* is blocking */
462 if (!(rv & O_NONBLOCK))
463 {
464 do
465 {
466 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
467 }
468 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
469 return rv;
470 }
471 /* The file descriptor refers to a socket and has been
472 * marked nonblocking(O_NONBLOCK) and the read would
473 * block.
474 * */
475 /* is non blocking */
476 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
477 return rv;
478}
479
480ssize_t
481vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
482{
483 int rv;
484 vcom_socket_main_t *vsm = &vcom_socket_main;
485 uword *p;
486 vcom_socket_t *vsock;
487 ssize_t total = 0, len = 0;
488
489 p = hash_get (vsm->sockidx_by_fd, __fd);
490 if (!p)
491 return -EBADF;
492
493 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
494 if (!vsock)
495 return -ENOTSOCK;
496
497 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
498 return -EINVAL;
499
500 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
501 return -EINVAL;
502
503 /* Sanity check */
504 for (int i = 0; i < __iovcnt; ++i)
505 {
506 if (SSIZE_MAX - len < __iov[i].iov_len)
507 return -EINVAL;
508 len += __iov[i].iov_len;
509 }
510
511 rv = vcom_fcntl (__fd, F_GETFL, 0);
512 if (rv < 0)
513 {
514 return rv;
515 }
516
517 /* is blocking */
518 if (!(rv & O_NONBLOCK))
519 {
520 do
521 {
522 for (int i = 0; i < __iovcnt; ++i)
523 {
524 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
525 __iov[i].iov_len);
526 if (rv < 0)
527 break;
528 else
529 {
530 total += rv;
531 if (rv < __iov[i].iov_len)
532 /* Read less than buffer provided, no point to continue */
533 break;
534 }
535 }
536 }
537 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
538 return total;
539 }
540
541 /* is non blocking */
542 for (int i = 0; i < __iovcnt; ++i)
543 {
544 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
545 __iov[i].iov_len);
546 if (rv < 0)
547 {
548 if (total > 0)
549 break;
550 else
551 {
552 errno = rv;
553 return rv;
554 }
555 }
556 else
557 {
558 total += rv;
559 if (rv < __iov[i].iov_len)
560 /* Read less than buffer provided, no point to continue */
561 break;
562 }
563 }
564 return total;
565}
566
567ssize_t
568vcom_socket_write (int __fd, const void *__buf, size_t __n)
569{
570 int rv = -1;
571 vcom_socket_main_t *vsm = &vcom_socket_main;
572 uword *p;
573 vcom_socket_t *vsock;
574
575 p = hash_get (vsm->sockidx_by_fd, __fd);
576 if (!p)
577 return -EBADF;
578
579 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
580 if (!vsock)
581 return -ENOTSOCK;
582
583 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
584 return -EINVAL;
585
586 if (!__buf || __n < 0)
587 {
588 return -EINVAL;
589 }
590
591 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
592 return rv;
593}
594
595ssize_t
596vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
597{
598 int rv = -1;
599 ssize_t total = 0;
600 vcom_socket_main_t *vsm = &vcom_socket_main;
601 uword *p;
602 vcom_socket_t *vsock;
603
604 p = hash_get (vsm->sockidx_by_fd, __fd);
605 if (!p)
606 return -EBADF;
607
608 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
609 if (!vsock)
610 return -ENOTSOCK;
611
612 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
613 return -EINVAL;
614
615 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
616 return -EINVAL;
617
618 for (int i = 0; i < __iovcnt; ++i)
619 {
620 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
621 __iov[i].iov_len);
622 if (rv < 0)
623 {
624 if (total > 0)
625 break;
626 else
627 return rv;
628 }
629 else
630 total += rv;
631 }
632 return total;
633}
634
635/*
636 * RETURN: 0 - invalid cmd
637 * 1 - cmd not handled by vcom and vppcom
638 * 2 - cmd handled by vcom socket resource
639 * 3 - cmd handled by vppcom
640 * */
641/* TBD: incomplete list of cmd */
642static int
643vcom_socket_check_fcntl_cmd (int __cmd)
644{
645 switch (__cmd)
646 {
647 /*cmd not handled by vcom and vppcom */
648 /* Fallthrough */
649 case F_DUPFD:
650 case F_DUPFD_CLOEXEC:
651 return 1;
652
653 /* cmd handled by vcom socket resource */
654 /* Fallthrough */
655 case F_GETFD:
656 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700657 case F_GETLK:
658 case F_SETLK:
659 case F_SETLKW:
660 case F_GETOWN:
661 case F_SETOWN:
662 return 2;
663
Stevenb59f2272017-10-12 17:10:33 -0700664 /* cmd handled by vcom and vppcom */
665 case F_SETFL:
666 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700667 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700668
669 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700670 default:
Stevenb59f2272017-10-12 17:10:33 -0700671 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700672 }
673 return 0;
674}
675
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700676static int
Stevenb59f2272017-10-12 17:10:33 -0700677vppcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700678{
Stevenb59f2272017-10-12 17:10:33 -0700679 int flags = va_arg (__ap, int);
680 int rv = -EOPNOTSUPP;
681 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700682
Stevenb59f2272017-10-12 17:10:33 -0700683 size = sizeof (flags);
684 if (__cmd == F_SETFL)
685 {
686 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
687 }
688 else if (__cmd == F_GETFL)
689 {
690 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
691 if (rv == VPPCOM_OK)
692 rv = flags;
693 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700694
695 return rv;
696}
697
698int
699vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
700{
701 int rv = -EBADF;
702 vcom_socket_main_t *vsm = &vcom_socket_main;
703 uword *p;
704 vcom_socket_t *vsock;
705
706 p = hash_get (vsm->sockidx_by_fd, __fd);
707 if (!p)
708 return -EBADF;
709
710 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
711 if (!vsock)
712 return -ENOTSOCK;
713
714 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
715 return -EINVAL;
716
717 switch (vcom_socket_check_fcntl_cmd (__cmd))
718 {
719 /* invalid cmd */
720 case 0:
721 rv = -EBADF;
722 break;
723 /*cmd not handled by vcom and vppcom */
724 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700725 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700726 break;
727 /* cmd handled by vcom socket resource */
728 case 2:
729 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
730 break;
731 /* cmd handled by vppcom */
732 case 3:
733 rv = vppcom_session_fcntl_va (vsock->sid, __cmd, __ap);
734 break;
735
736 default:
737 rv = -EINVAL;
738 break;
739 }
740
741 return rv;
742}
743
Stevenb59f2272017-10-12 17:10:33 -0700744/*
745 * RETURN: 0 - invalid cmd
746 * 1 - cmd not handled by vcom and vppcom
747 * 2 - cmd handled by vcom socket resource
748 * 3 - cmd handled by vppcom
749 */
750static int
751vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
752{
753 int rc;
754
755 switch (__cmd)
756 {
757 /* cmd handled by vppcom */
758 case FIONREAD:
759 rc = 3;
760 break;
761
762 /* cmd not handled by vcom and vppcom */
763 default:
764 rc = 1;
765 break;
766 }
767 return rc;
768}
769
770static int
771vppcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
772{
773 int rv;
774
775 if (__cmd == FIONREAD)
776 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
777 else
778 rv = -EOPNOTSUPP;
779 return rv;
780}
781
782int
783vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
784{
785 int rv = -EBADF;
786 vcom_socket_main_t *vsm = &vcom_socket_main;
787 uword *p;
788 vcom_socket_t *vsock;
789
790 p = hash_get (vsm->sockidx_by_fd, __fd);
791 if (!p)
792 return -EBADF;
793
794 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
795 if (!vsock)
796 return -ENOTSOCK;
797
798 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
799 return -EINVAL;
800
801 switch (vcom_socket_check_ioctl_cmd (__cmd))
802 {
803 /* Not supported cmd */
804 case 0:
805 rv = -EOPNOTSUPP;
806 break;
807
808 /* cmd not handled by vcom and vppcom */
809 case 1:
810 rv = libc_vioctl (vsock->fd, __cmd, __ap);
811 break;
812
813 /* cmd handled by vcom socket resource */
814 case 2:
815 rv = libc_vioctl (vsock->fd, __cmd, __ap);
816 break;
817
818 /* cmd handled by vppcom */
819 case 3:
820 rv = vppcom_session_ioctl_va (vsock->sid, __cmd, __ap);
821 break;
822
823 default:
824 rv = -EINVAL;
825 break;
826 }
827
828 return rv;
829}
830
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700831static inline int
832vcom_socket_fds_2_sid_fds (
833 /* dest */
834 int *vcom_nsid_fds,
835 fd_set * __restrict vcom_rd_sid_fds,
836 fd_set * __restrict vcom_wr_sid_fds,
837 fd_set * __restrict vcom_ex_sid_fds,
838 /* src */
839 int vcom_nfds,
840 fd_set * __restrict vcom_readfds,
841 fd_set * __restrict vcom_writefds,
842 fd_set * __restrict vcom_exceptfds)
843{
844 int rv = 0;
845 int fd;
846 int sid;
847 /* invalid max_sid is -1 */
848 int max_sid = -1;
849 int nsid = 0;
850
851 /*
852 * set sid in sid sets corresponding to fd's in fd sets
853 * compute nsid and vcom_nsid_fds from sid sets
854 */
855
856 for (fd = 0; fd < vcom_nfds; fd++)
857 {
858 /*
859 * F fd set, src
860 * S sid set, dest
861 */
862#define _(S,F) \
863 if ((F) && (S) && FD_ISSET (fd, (F))) \
864 { \
865 sid = vcom_socket_get_sid (fd); \
866 if (sid != INVALID_SESSION_ID) \
867 { \
868 FD_SET (sid, (S)); \
869 if (sid > max_sid) \
870 { \
871 max_sid = sid; \
872 } \
873 ++nsid; \
874 } \
875 else \
876 { \
877 rv = -EBADFD; \
878 goto done; \
879 } \
880 }
881
882
883 _(vcom_rd_sid_fds, vcom_readfds);
884 _(vcom_wr_sid_fds, vcom_writefds);
885 _(vcom_ex_sid_fds, vcom_exceptfds);
886#undef _
887 }
888
889 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
890 rv = nsid;
891
892done:
893 return rv;
894}
895
896/*
897 * PRE: 00. sid sets were derived from fd sets
898 * 01. sid sets were updated with sids that actually changed
899 * status
900 * 02. fd sets still has watched fds
901 *
902 * This function will modify in place fd sets to indicate which fd's
903 * actually changed status(inferred from sid sets)
904 */
905static inline int
906vcom_socket_sid_fds_2_fds (
907 /* dest */
908 int *new_vcom_nfds,
909 int vcom_nfds,
910 fd_set * __restrict vcom_readfds,
911 fd_set * __restrict vcom_writefds,
912 fd_set * __restrict vcom_exceptfds,
913 /* src */
914 int vcom_nsid_fds,
915 fd_set * __restrict vcom_rd_sid_fds,
916 fd_set * __restrict vcom_wr_sid_fds,
917 fd_set * __restrict vcom_ex_sid_fds)
918{
919 int rv = 0;
920 int fd;
921 int sid;
922 /* invalid max_fd is -1 */
923 int max_fd = -1;
924 int nfd = 0;
925
926
927 /*
928 * modify in place fd sets to indicate which fd's
929 * actually changed status(inferred from sid sets)
930 */
931 for (fd = 0; fd < vcom_nfds; fd++)
932 {
933 /*
934 * F fd set, dest
935 * S sid set, src
936 */
937#define _(S,F) \
938 if ((F) && (S) && FD_ISSET (fd, (F))) \
939 { \
940 sid = vcom_socket_get_sid (fd); \
941 if (sid != INVALID_SESSION_ID) \
942 { \
943 if (!FD_ISSET (sid, (S))) \
944 { \
945 FD_CLR(fd, (F)); \
946 } \
947 } \
948 else \
949 { \
950 rv = -EBADFD; \
951 goto done; \
952 } \
953 }
954
955
956 _(vcom_rd_sid_fds, vcom_readfds);
957 _(vcom_wr_sid_fds, vcom_writefds);
958 _(vcom_ex_sid_fds, vcom_exceptfds);
959#undef _
960 }
961
962 /*
963 * compute nfd and new_vcom_nfds from fd sets
964 */
965 for (fd = 0; fd < vcom_nfds; fd++)
966 {
967
968#define _(F) \
969 if ((F) && FD_ISSET (fd, (F))) \
970 { \
971 if (fd > max_fd) \
972 { \
973 max_fd = fd; \
974 } \
975 ++nfd; \
976 }
977
978
979 _(vcom_readfds);
980 _(vcom_writefds);
981 _(vcom_exceptfds);
982#undef _
983
984 }
985
986 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
987 rv = nfd;
988
989done:
990 return rv;
991}
992
993/*
994 * PRE:
995 * vom_socket_select is always called with
996 * timeout->tv_sec and timeout->tv_usec set to zero.
997 * hence vppcom_select return immediately.
998 */
999/*
1000 * TBD: do{body;} while(timeout conditional); timeout loop
1001 */
1002int
1003vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1004 fd_set * __restrict vcom_writefds,
1005 fd_set * __restrict vcom_exceptfds,
1006 struct timeval *__restrict timeout)
1007{
1008 int rv = -EBADF;
1009 pid_t pid = getpid ();
1010
1011 int new_vcom_nfds = 0;
1012 int new_vcom_nfd = 0;
1013
1014 /* vcom sid fds */
1015 fd_set vcom_rd_sid_fds;
1016 fd_set vcom_wr_sid_fds;
1017 fd_set vcom_ex_sid_fds;
1018 unsigned long vcom_nsid_fds = 0;
1019 int vcom_nsid = 0;
1020
1021 /* in seconds eg. 3.123456789 seconds */
1022 double time_to_wait = (double) 0;
1023
1024 /* validate inputs */
1025 if (vcom_nfds < 0)
1026 {
1027 return -EINVAL;
1028 }
1029
1030 /* convert timeval timeout to double time_to_wait */
1031 if (timeout)
1032 {
1033 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1034 {
1035 /* polling: vppcom_select returns immediately */
1036 time_to_wait = (double) 0;
1037 }
1038 else
1039 {
1040 /*TBD: use timeval api */
1041 time_to_wait = (double) timeout->tv_sec +
1042 (double) timeout->tv_usec / (double) 1000000 +
1043 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1044 }
1045 }
1046 else
1047 {
1048 /*
1049 * no timeout: vppcom_select can block indefinitely
1050 * waiting for a file descriptor to become ready
1051 * */
1052 /* set to a phantom value */
1053 time_to_wait = ~0;
1054 }
1055
1056 /* zero the sid_sets */
1057 /*
1058 * F fd set
1059 * S sid set
1060 */
1061#define _(S,F) \
1062 if ((F)) \
1063 { \
1064 FD_ZERO ((S)); \
1065 }
1066
1067
1068 _(&vcom_rd_sid_fds, vcom_readfds);
1069 _(&vcom_wr_sid_fds, vcom_writefds);
1070 _(&vcom_ex_sid_fds, vcom_exceptfds);
1071#undef _
1072
1073 /* populate read, write and except sid_sets */
1074 vcom_nsid = vcom_socket_fds_2_sid_fds (
1075 /* dest */
1076 vcom_readfds || vcom_writefds
1077 || vcom_exceptfds ? (int *)
1078 &vcom_nsid_fds : NULL,
1079 vcom_readfds ? &vcom_rd_sid_fds :
1080 NULL,
1081 vcom_writefds ? &vcom_wr_sid_fds :
1082 NULL,
1083 vcom_exceptfds ? &vcom_ex_sid_fds :
1084 NULL,
1085 /* src */
1086 vcom_nfds,
1087 vcom_readfds,
1088 vcom_writefds, vcom_exceptfds);
1089 if (vcom_nsid < 0)
1090 {
1091 return vcom_nsid;
1092 }
1093 if (vcom_nsid_fds < 0)
1094 {
1095 return -EINVAL;
1096 }
1097
1098 rv = vppcom_select (vcom_nsid_fds,
1099 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1100 NULL,
1101 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1102 NULL,
1103 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1104 NULL, time_to_wait);
1105 if (VCOM_DEBUG > 0)
1106 fprintf (stderr, "[%d] vppcom_select: "
1107 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1108
1109 /* check if any file descriptors changed status */
1110 if (rv > 0)
1111 {
1112 /*
1113 * on exit, sets are modified in place to indicate which
1114 * file descriptors actually changed status
1115 * */
1116
1117 /*
1118 * comply with pre-condition
1119 * do not clear vcom fd sets befor calling
1120 * vcom_socket_sid_fds_2_fds
1121 */
1122 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1123 /* dest */
1124 &new_vcom_nfds,
1125 vcom_nfds,
1126 vcom_readfds,
1127 vcom_writefds,
1128 vcom_exceptfds,
1129 /* src */
1130 vcom_nsid_fds,
1131 vcom_readfds ?
1132 &vcom_rd_sid_fds : NULL,
1133 vcom_writefds ?
1134 &vcom_wr_sid_fds : NULL,
1135 vcom_exceptfds ?
1136 &vcom_ex_sid_fds : NULL);
1137 if (new_vcom_nfd < 0)
1138 {
1139 return new_vcom_nfd;
1140 }
1141 if (new_vcom_nfds < 0)
1142 {
1143 return -EINVAL;
1144 }
1145 rv = new_vcom_nfd;
1146 }
1147 return rv;
1148}
1149
1150
1151int
1152vcom_socket_socket (int __domain, int __type, int __protocol)
1153{
1154 int rv = -1;
1155 vcom_socket_main_t *vsm = &vcom_socket_main;
1156 vcom_socket_t *vsock;
1157
1158 i32 fd;
1159 i32 sid;
1160 i32 sockidx;
1161 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1162 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1163
1164 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1165 if (fd < 0)
1166 {
1167 rv = fd;
1168 goto out;
1169 }
1170
1171 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1172 (type == SOCK_DGRAM) ?
1173 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1174 is_nonblocking);
1175 if (sid < 0)
1176 {
1177 rv = sid;
1178 goto out_close_socket;
1179 }
1180
1181 pool_get (vsm->vsockets, vsock);
1182 vsocket_init (vsock);
1183
1184 sockidx = vsock - vsm->vsockets;
1185 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1186
1187 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1188 return fd;
1189
1190out_close_socket:
1191 vcom_socket_close_socket (fd);
1192out:
1193 return rv;
1194}
1195
1196int
1197vcom_socket_socketpair (int __domain, int __type, int __protocol,
1198 int __fds[2])
1199{
1200/* TBD: */
1201 return 0;
1202}
1203
1204int
1205vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1206{
1207 int rv = -1;
1208 vcom_socket_main_t *vsm = &vcom_socket_main;
1209 uword *p;
1210 vcom_socket_t *vsock;
1211
1212 vppcom_endpt_t ep;
1213
1214 p = hash_get (vsm->sockidx_by_fd, __fd);
1215 if (!p)
1216 return -EBADF;
1217
1218 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1219 if (!vsock)
1220 return -ENOTSOCK;
1221
1222 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1223 return -EINVAL;
1224
1225 if (!__addr)
1226 {
1227 return -EINVAL;
1228 }
1229
1230 ep.vrf = VPPCOM_VRF_DEFAULT;
1231 switch (__addr->sa_family)
1232 {
1233 case AF_INET:
1234 if (__len != sizeof (struct sockaddr_in))
1235 {
1236 return -EINVAL;
1237 }
1238 ep.is_ip4 = VPPCOM_IS_IP4;
1239 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1240 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1241 break;
1242
1243 case AF_INET6:
1244 if (__len != sizeof (struct sockaddr_in6))
1245 {
1246 return -EINVAL;
1247 }
1248 ep.is_ip4 = VPPCOM_IS_IP6;
1249 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1250 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1251 break;
1252
1253 default:
1254 return -1;
1255 break;
1256 }
1257
1258 rv = vppcom_session_bind (vsock->sid, &ep);
1259 /* TBD: remove libc_bind code snippet
1260 * once vppcom implements vppcom_session_getsockname */
1261 if (rv == 0)
1262 {
1263 rv = libc_bind (__fd, __addr, __len);
1264 if (rv != 0)
1265 {
1266 rv = -errno;
1267 }
1268 }
1269 return rv;
1270}
1271
1272int
1273vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1274{
1275 /* TBD: move it to vppcom */
1276 return 0;
1277}
1278
1279int
1280vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1281 socklen_t * __restrict __len)
1282{
1283 int rv = -1;
1284 vcom_socket_main_t *vsm = &vcom_socket_main;
1285 uword *p;
1286 vcom_socket_t *vsock;
1287
1288
1289 p = hash_get (vsm->sockidx_by_fd, __fd);
1290 if (!p)
1291 return -EBADF;
1292
1293 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1294 if (!vsock)
1295 return -ENOTSOCK;
1296
1297 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1298 return -EINVAL;
1299
1300 if (!__addr || !__len)
1301 return -EFAULT;
1302
1303 if (*__len < 0)
1304 {
1305 return -EINVAL;
1306 }
1307
1308 /* TBD: remove libc_getsockname code snippet
1309 * once vppcom implements vppcom_session_getsockname */
1310 rv = libc_getsockname (__fd, __addr, __len);
1311 if (rv != 0)
1312 {
1313 rv = -errno;
1314 return rv;
1315 }
1316
1317 /* TBD: use the below code snippet when vppcom
1318 * implements vppcom_session_getsockname */
1319#if 0
1320 vppcom_endpt_t ep;
1321 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1322 rv = vppcom_session_getsockname (vsock->sid, &ep);
1323 if (rv == 0)
1324 {
1325 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1326 {
1327 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1328 switch (__addr->sa_family)
1329 {
1330 case AF_INET:
1331 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1332 *__len = sizeof (struct sockaddr_in);
1333 break;
1334
1335 case AF_INET6:
1336 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1337 *__len = sizeof (struct sockaddr_in6);
1338 break;
1339
1340 default:
1341 break;
1342 }
1343 }
1344 }
1345#endif
1346
1347 return rv;
1348}
1349
1350int
1351vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1352{
1353 int rv = -1;
1354 vcom_socket_main_t *vsm = &vcom_socket_main;
1355 uword *p;
1356 vcom_socket_t *vsock;
1357
1358 vppcom_endpt_t ep;
1359
1360 p = hash_get (vsm->sockidx_by_fd, __fd);
1361 if (p)
1362 {
1363 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1364
1365 ep.vrf = VPPCOM_VRF_DEFAULT;
1366 switch (__addr->sa_family)
1367 {
1368 case AF_INET:
1369 ep.is_ip4 = VPPCOM_IS_IP4;
1370 ep.ip =
1371 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1372 ep.port =
1373 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1374 break;
1375
1376 case AF_INET6:
1377 ep.is_ip4 = VPPCOM_IS_IP6;
1378 ep.ip =
1379 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1380 ep.port =
1381 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1382 break;
1383
1384 default:
1385 return -1;
1386 break;
1387 }
1388
1389 rv = vppcom_session_connect (vsock->sid, &ep);
1390 }
1391 return rv;
1392}
1393
1394int
1395vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1396{
1397 /* TBD: move it to vppcom */
1398 return 0;
1399}
1400
1401int
1402vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1403 socklen_t * __restrict __len)
1404{
1405 int rv = -1;
1406 vcom_socket_main_t *vsm = &vcom_socket_main;
1407 uword *p;
1408 vcom_socket_t *vsock;
1409
1410
1411 p = hash_get (vsm->sockidx_by_fd, __fd);
1412 if (!p)
1413 return -EBADF;
1414
1415 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1416 if (!vsock)
1417 return -ENOTSOCK;
1418
1419 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1420 return -EINVAL;
1421
1422 if (!__addr || !__len)
1423 return -EFAULT;
1424
1425 if (*__len < 0)
1426 {
1427 return -EINVAL;
1428 }
1429
1430 /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
1431 {
1432 uint8_t *a;
1433 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1434 ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
1435 a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
1436 a[0] = 0x7f;
1437 a[1] = 0x00;
1438 a[2] = 0x00;
1439 a[3] = 0x01;
1440 *__len = sizeof (struct sockaddr_in);
1441 return 0;
1442 }
1443
1444 /* TBD: remove libc_getpeername code snippet
1445 * once vppcom implements vppcom_session_getpeername */
1446 rv = libc_getpeername (__fd, __addr, __len);
1447 if (rv != 0)
1448 {
1449 rv = -errno;
1450 return rv;
1451 }
1452
1453 /* TBD: use the below code snippet when vppcom
1454 * implements vppcom_session_getpeername */
1455#if 0
1456 vppcom_endpt_t ep;
1457 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1458 rv = vppcom_session_getpeername (vsock->sid, &ep);
1459 if (rv == 0)
1460 {
1461 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1462 {
1463 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1464 switch (__addr->sa_family)
1465 {
1466 case AF_INET:
1467 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1468 *__len = sizeof (struct sockaddr_in);
1469 break;
1470
1471 case AF_INET6:
1472 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1473 *__len = sizeof (struct sockaddr_in6);
1474 break;
1475
1476 default:
1477 break;
1478 }
1479 }
1480 }
1481#endif
1482
1483 return rv;
1484}
1485
1486ssize_t
1487vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1488{
1489 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1490}
1491
1492ssize_t
1493vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1494{
1495 int rv = -1;
1496 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1497 return rv;
1498}
1499
1500/*
1501 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1502 * 0 otherwise
1503 * */
1504int
1505vcom_socket_is_connection_mode_socket (int __fd)
1506{
1507 int rv = -1;
1508 /* TBD define new vppcom api */
1509 vcom_socket_main_t *vsm = &vcom_socket_main;
1510 uword *p;
1511 vcom_socket_t *vsock;
1512
1513 int type;
1514 socklen_t optlen;
1515
1516 p = hash_get (vsm->sockidx_by_fd, __fd);
1517
1518 if (p)
1519 {
1520 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1521 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1522 {
1523 optlen = sizeof (type);
1524 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1525 if (rv != 0)
1526 {
1527 return 0;
1528 }
1529 /* get socket type */
1530 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1531 {
1532 case SOCK_STREAM:
1533 case SOCK_SEQPACKET:
1534 return 1;
1535 break;
1536
1537 default:
1538 return 0;
1539 break;
1540 }
1541 }
1542 }
1543 return 0;
1544}
1545
1546ssize_t
1547vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1548 int __flags, __CONST_SOCKADDR_ARG __addr,
1549 socklen_t __addr_len)
1550{
1551 int rv = -1;
1552 /* TBD add new vpp api */
1553 /* TBD add flags parameter */
1554 rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1555 return rv;
1556}
1557
1558ssize_t
1559vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1560 int __flags, __CONST_SOCKADDR_ARG __addr,
1561 socklen_t __addr_len)
1562{
1563 int rv = -1;
1564 vcom_socket_main_t *vsm = &vcom_socket_main;
1565 uword *p;
1566 vcom_socket_t *vsock;
1567
1568 p = hash_get (vsm->sockidx_by_fd, __fd);
1569 if (!p)
1570 return -EBADF;
1571
1572 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1573 if (!vsock)
1574 return -ENOTSOCK;
1575
1576 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1577 return -EINVAL;
1578
1579 if (!__buf || __n < 0)
1580 {
1581 return -EINVAL;
1582 }
1583
1584 if (vcom_socket_is_connection_mode_socket (__fd))
1585 {
1586 /* ignore __addr and _addr_len */
1587 /* and EISCONN may be returned when they are not NULL and 0 */
1588 if ((__addr != NULL) || (__addr_len != 0))
1589 {
1590 return -EISCONN;
1591 }
1592 }
1593 else
1594 {
1595 if (!__addr || __addr_len < 0)
1596 {
1597 return -EDESTADDRREQ;
1598 }
1599 /* not a vppcom supported address family */
1600 if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1601 {
1602 return -EINVAL;
1603 }
1604 }
1605
1606 rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1607 __flags, __addr, __addr_len);
1608 return rv;
1609}
1610
1611/* TBD: move it to vppcom */
1612static ssize_t
1613vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1614 int __flags, __SOCKADDR_ARG __addr,
1615 socklen_t * __restrict __addr_len)
1616{
1617 int rv = -1;
1618
1619 /* TBD add flags parameter */
1620 rv = vppcom_session_read (__sid, __buf, __n);
1621 return rv;
1622}
1623
1624ssize_t
1625vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1626 int __flags, __SOCKADDR_ARG __addr,
1627 socklen_t * __restrict __addr_len)
1628{
1629 int rv = -1;
1630 vcom_socket_main_t *vsm = &vcom_socket_main;
1631 uword *p;
1632 vcom_socket_t *vsock;
1633
1634 p = hash_get (vsm->sockidx_by_fd, __fd);
1635 if (!p)
1636 return -EBADF;
1637
1638 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1639 if (!vsock)
1640 return -ENOTSOCK;
1641
1642 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1643 return -EINVAL;
1644
1645 if (!__buf || __n < 0)
1646 {
1647 return -EINVAL;
1648 }
1649
1650 if (__addr || __addr_len < 0)
1651 {
1652 return -EINVAL;
1653 }
1654
1655 rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1656 __flags, __addr, __addr_len);
1657 return rv;
1658}
1659
1660/* TBD: move it to vppcom */
1661static ssize_t
1662vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1663{
1664 int rv = -1;
1665 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1666 (int)__n); */
1667 return rv;
1668}
1669
1670ssize_t
1671vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1672{
1673 int rv = -1;
1674 vcom_socket_main_t *vsm = &vcom_socket_main;
1675 uword *p;
1676 vcom_socket_t *vsock;
1677
1678 p = hash_get (vsm->sockidx_by_fd, __fd);
1679 if (!p)
1680 return -EBADF;
1681
1682 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1683 if (!vsock)
1684 return -ENOTSOCK;
1685
1686 if (vcom_socket_is_connection_mode_socket (__fd))
1687 {
1688 /* ignore __addr and _addr_len */
1689 /* and EISCONN may be returned when they are not NULL and 0 */
1690 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1691 {
1692 return -EISCONN;
1693 }
1694 }
1695 else
1696 {
1697 /* TBD: validate __message->msg_name and __message->msg_namelen
1698 * and return -EINVAL on validation error
1699 * */
1700 ;
1701 }
1702
1703 rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1704
1705 return rv;
1706}
1707
1708#ifdef __USE_GNU
1709int
1710vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1711 unsigned int __vlen, int __flags)
1712{
1713
1714 /* TBD: define a new vppcom api */
1715 return 0;
1716}
1717#endif
1718
1719/* TBD: move it to vppcom */
1720static ssize_t
1721vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1722{
1723 int rv = -1;
1724 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1725 (int)__n); */
1726 rv = -EOPNOTSUPP;
1727 return rv;
1728}
1729
1730ssize_t
1731vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1732{
1733 int rv = -1;
1734 vcom_socket_main_t *vsm = &vcom_socket_main;
1735 uword *p;
1736 vcom_socket_t *vsock;
1737
1738 p = hash_get (vsm->sockidx_by_fd, __fd);
1739 if (!p)
1740 return -EBADF;
1741
1742 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1743 if (!vsock)
1744 return -ENOTSOCK;
1745
1746 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1747 return -EINVAL;
1748
1749 if (!__message)
1750 {
1751 return -EINVAL;
1752 }
1753
1754 /* validate __flags */
1755
1756 rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1757 return rv;
1758}
1759
1760#ifdef __USE_GNU
1761int
1762vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1763 unsigned int __vlen, int __flags,
1764 struct timespec *__tmo)
1765{
1766 /* TBD: define a new vppcom api */
1767 return 0;
1768}
1769#endif
1770
1771/* TBD: move it to vppcom */
1772static int
1773vppcom_getsockopt (int __sid, int __level, int __optname,
1774 void *__restrict __optval, socklen_t * __restrict __optlen)
1775{
1776 /* 1. for socket level options that are NOT socket attributes
1777 * and that has corresponding vpp options get from vppcom */
1778#if 0
1779 return 0;
1780#endif
1781
1782 /* 2. unhandled options */
1783 return -ENOPROTOOPT;
1784}
1785
1786int
1787vcom_socket_getsockopt (int __fd, int __level, int __optname,
1788 void *__restrict __optval,
1789 socklen_t * __restrict __optlen)
1790{
1791 int rv = -1;
1792 vcom_socket_main_t *vsm = &vcom_socket_main;
1793 uword *p;
1794 vcom_socket_t *vsock;
1795
1796 p = hash_get (vsm->sockidx_by_fd, __fd);
1797 if (!p)
1798 return -EBADF;
1799
1800 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1801 if (!vsock)
1802 return -ENOTSOCK;
1803
1804 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1805 return -EINVAL;
1806
1807 if (!__optval && !__optlen)
1808 return -EFAULT;
1809
1810 if (*__optlen < 0)
1811 {
1812 return -EINVAL;
1813 }
1814
1815 switch (__level)
1816 {
1817 /* handle options at socket level */
1818 case SOL_SOCKET:
1819 switch (__optname)
1820 {
1821/*
1822 * 1. for socket level options that are socket attributes,
1823 * get from libc_getsockopt.
1824 * 2. for socket level options that are NOT socket
1825 * attributes and that has corresponding vpp options
1826 * get from vppcom.
1827 * 3. for socket level options unimplemented
1828 * return -ENOPROTOOPT */
1829 case SO_DEBUG:
1830 case SO_DONTROUTE:
1831 case SO_BROADCAST:
1832 case SO_SNDBUF:
1833 case SO_RCVBUF:
1834 case SO_REUSEADDR:
1835 case SO_REUSEPORT:
1836 case SO_KEEPALIVE:
1837 case SO_TYPE:
1838 case SO_PROTOCOL:
1839 case SO_DOMAIN:
1840 case SO_ERROR:
1841 case SO_OOBINLINE:
1842 case SO_NO_CHECK:
1843 case SO_PRIORITY:
1844 case SO_LINGER:
1845 case SO_BSDCOMPAT:
1846 case SO_TIMESTAMP:
1847 case SO_TIMESTAMPNS:
1848 case SO_TIMESTAMPING:
1849 case SO_RCVTIMEO:
1850 case SO_SNDTIMEO:
1851 case SO_RCVLOWAT:
1852 case SO_SNDLOWAT:
1853 case SO_PASSCRED:
1854 case SO_PEERCRED:
1855 case SO_PEERNAME:
1856 case SO_ACCEPTCONN:
1857 case SO_PASSSEC:
1858 case SO_PEERSEC:
1859 case SO_MARK:
1860 case SO_RXQ_OVFL:
1861 case SO_WIFI_STATUS:
1862 case SO_PEEK_OFF:
1863 case SO_NOFCS:
1864 case SO_BINDTODEVICE:
1865 case SO_GET_FILTER:
1866 case SO_LOCK_FILTER:
1867 case SO_BPF_EXTENSIONS:
1868 case SO_SELECT_ERR_QUEUE:
1869#ifdef CONFIG_NET_RX_BUSY_POLL
1870 case SO_BUSY_POLL:
1871#endif
1872 case SO_MAX_PACING_RATE:
1873 case SO_INCOMING_CPU:
1874 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1875 if (rv != 0)
1876 {
1877 rv = -errno;
1878 return rv;
1879 }
1880 break;
1881
1882 default:
1883 /* We implement the SO_SNDLOWAT etc to not be settable
1884 * (1003.1g 7).
1885 */
1886 return -ENOPROTOOPT;
1887 }
1888
1889 break;
1890
1891 default:
1892 /* 1. handle options that are NOT socket level options,
1893 * but have corresponding vpp otions. */
1894 rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1895 __optval, __optlen);
1896
1897 return rv;
1898#if 0
1899 /* 2. unhandled options */
1900 return -ENOPROTOOPT;
1901#endif
1902 }
1903
1904 return rv;
1905}
1906
1907/* TBD: move it to vppcom */
1908int
Stevenb59f2272017-10-12 17:10:33 -07001909vppcom_session_setsockopt (int __sid, int __level, int __optname,
1910 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001911{
Stevenb59f2272017-10-12 17:10:33 -07001912 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001913
Stevenb59f2272017-10-12 17:10:33 -07001914 switch (__level)
1915 {
Stevenbd187a82017-10-13 12:52:28 -07001916 case SOL_TCP:
1917 switch (__optname)
1918 {
1919 case TCP_KEEPIDLE:
1920 rv =
1921 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1922 break;
1923 case TCP_KEEPINTVL:
1924 rv =
1925 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1926 break;
1927 default:
1928 break;
1929 }
1930 break;
Stevenb59f2272017-10-12 17:10:33 -07001931 case SOL_IPV6:
1932 switch (__optname)
1933 {
1934 case IPV6_V6ONLY:
1935 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001936 break;
Stevenb59f2272017-10-12 17:10:33 -07001937 default:
Stevenbd187a82017-10-13 12:52:28 -07001938 break;
Stevenb59f2272017-10-12 17:10:33 -07001939 }
1940 break;
1941 case SOL_SOCKET:
1942 switch (__optname)
1943 {
Stevenbd187a82017-10-13 12:52:28 -07001944 case SO_KEEPALIVE:
1945 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1946 break;
Stevenb59f2272017-10-12 17:10:33 -07001947 case SO_REUSEADDR:
1948 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001949 break;
Stevenb59f2272017-10-12 17:10:33 -07001950 case SO_BROADCAST:
1951 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001952 break;
Stevenb59f2272017-10-12 17:10:33 -07001953 default:
Stevenbd187a82017-10-13 12:52:28 -07001954 break;
Stevenb59f2272017-10-12 17:10:33 -07001955 }
1956 break;
1957 default:
Stevenbd187a82017-10-13 12:52:28 -07001958 break;
Stevenb59f2272017-10-12 17:10:33 -07001959 }
1960
1961 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001962}
1963
1964int
1965vcom_socket_setsockopt (int __fd, int __level, int __optname,
1966 const void *__optval, socklen_t __optlen)
1967{
1968 int rv = -1;
1969 vcom_socket_main_t *vsm = &vcom_socket_main;
1970 uword *p;
1971 vcom_socket_t *vsock;
1972
1973 p = hash_get (vsm->sockidx_by_fd, __fd);
1974 if (!p)
1975 return -EBADF;
1976
1977 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1978 if (!vsock)
1979 return -ENOTSOCK;
1980
1981 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1982 return -EINVAL;
1983
1984 /*
1985 * Options without arguments
1986 */
1987
1988 if (__optname == SO_BINDTODEVICE)
1989 {
1990 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1991 if (rv != 0)
1992 {
1993 rv = -errno;
1994 }
1995 return rv;
1996 }
1997
1998 if (!__optval)
1999 return -EFAULT;
2000
2001 if ((__optlen < 0) || (__optlen < sizeof (int)))
2002 return -EINVAL;
2003
2004 switch (__level)
2005 {
Stevenb59f2272017-10-12 17:10:33 -07002006 case SOL_IPV6:
2007 switch (__optname)
2008 {
2009 case IPV6_V6ONLY:
2010 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
2011 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002012 break;
Stevenb59f2272017-10-12 17:10:33 -07002013 default:
2014 return -EOPNOTSUPP;
2015 }
2016 break;
2017 case SOL_TCP:
2018 switch (__optname)
2019 {
2020 case TCP_NODELAY:
2021 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002022 case TCP_KEEPIDLE:
2023 case TCP_KEEPINTVL:
2024 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
2025 __optval, __optlen);
2026 break;
Stevenb59f2272017-10-12 17:10:33 -07002027 default:
2028 return -EOPNOTSUPP;
2029 }
2030 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002031 /* handle options at socket level */
2032 case SOL_SOCKET:
2033 switch (__optname)
2034 {
Stevenb59f2272017-10-12 17:10:33 -07002035 case SO_REUSEADDR:
2036 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002037 case SO_KEEPALIVE:
Stevenb59f2272017-10-12 17:10:33 -07002038 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
2039 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002040 break;
Stevenb59f2272017-10-12 17:10:33 -07002041
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002042 /*
2043 * 1. for socket level options that are socket attributes,
2044 * set it from libc_getsockopt
2045 * 2. for socket level options that are NOT socket
2046 * attributes and that has corresponding vpp options
2047 * set it from vppcom
2048 * 3. for socket level options unimplemented
2049 * return -ENOPROTOOPT */
2050 case SO_DEBUG:
2051 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002052 case SO_SNDBUF:
2053 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002054 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002055 case SO_TYPE:
2056 case SO_PROTOCOL:
2057 case SO_DOMAIN:
2058 case SO_ERROR:
2059 case SO_OOBINLINE:
2060 case SO_NO_CHECK:
2061 case SO_PRIORITY:
2062 case SO_LINGER:
2063 case SO_BSDCOMPAT:
2064 case SO_TIMESTAMP:
2065 case SO_TIMESTAMPNS:
2066 case SO_TIMESTAMPING:
2067 case SO_RCVTIMEO:
2068 case SO_SNDTIMEO:
2069 case SO_RCVLOWAT:
2070 case SO_SNDLOWAT:
2071 case SO_PASSCRED:
2072 case SO_PEERCRED:
2073 case SO_PEERNAME:
2074 case SO_ACCEPTCONN:
2075 case SO_PASSSEC:
2076 case SO_PEERSEC:
2077 case SO_MARK:
2078 case SO_RXQ_OVFL:
2079 case SO_WIFI_STATUS:
2080 case SO_PEEK_OFF:
2081 case SO_NOFCS:
2082 /*
2083 * SO_BINDTODEVICE already handled as
2084 * "Options without arguments" */
2085 /* case SO_BINDTODEVICE: */
2086 case SO_GET_FILTER:
2087 case SO_LOCK_FILTER:
2088 case SO_BPF_EXTENSIONS:
2089 case SO_SELECT_ERR_QUEUE:
2090#ifdef CONFIG_NET_RX_BUSY_POLL
2091 case SO_BUSY_POLL:
2092#endif
2093 case SO_MAX_PACING_RATE:
2094 case SO_INCOMING_CPU:
2095 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2096 if (rv != 0)
2097 {
2098 rv = -errno;
2099 return rv;
2100 }
2101 break;
2102
2103 default:
2104 /* We implement the SO_SNDLOWAT etc to not be settable
2105 * (1003.1g 7).
2106 */
2107 return -ENOPROTOOPT;
2108 }
2109
2110 break;
2111
2112 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002113 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002114 }
2115
2116 return rv;
2117}
2118
2119int
2120vcom_socket_listen (int __fd, int __n)
2121{
2122 int rv = -1;
2123 vcom_socket_main_t *vsm = &vcom_socket_main;
2124 uword *p;
2125 vcom_socket_t *vsock;
2126
2127 p = hash_get (vsm->sockidx_by_fd, __fd);
2128 if (p)
2129 {
2130 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2131
2132 /* TBD vppcom to accept __n parameter */
2133 rv = vppcom_session_listen (vsock->sid, __n);
2134 }
2135
2136 return rv;
2137}
2138
2139static int
2140vcom_socket_connected_socket (int __fd, int __sid,
2141 int *__domain,
2142 int *__type, int *__protocol, int flags)
2143{
2144 int rv = -1;
2145 vcom_socket_main_t *vsm = &vcom_socket_main;
2146 vcom_socket_t *vsock;
2147
2148 i32 fd;
2149 i32 sockidx;
2150
2151 socklen_t optlen;
2152
2153 optlen = sizeof (*__domain);
2154 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2155 if (rv != 0)
2156 {
2157 rv = -errno;
2158 goto out;
2159 }
2160
2161 optlen = sizeof (*__type);
2162 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2163 if (rv != 0)
2164 {
2165 rv = -errno;
2166 goto out;
2167 }
2168
2169 optlen = sizeof (*__protocol);
2170 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2171 if (rv != 0)
2172 {
2173 rv = -errno;
2174 goto out;
2175 }
2176
2177 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2178 if (fd < 0)
2179 {
2180 rv = fd;
2181 goto out;
2182 }
2183
2184 pool_get (vsm->vsockets, vsock);
2185 vsocket_init (vsock);
2186
2187 sockidx = vsock - vsm->vsockets;
2188 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2189
2190 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2191 return fd;
2192
2193out:
2194 return rv;
2195}
2196
2197/* If flag is 0, then accept4() is the same as accept().
2198 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2199 */
2200static int
2201vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2202 socklen_t * __restrict __addr_len, int flags)
2203{
2204 int rv = -1;
2205 vcom_socket_main_t *vsm = &vcom_socket_main;
2206 uword *p;
2207 vcom_socket_t *vsock;
2208
2209 int fd;
2210 int sid;
2211 int domain;
2212 int type;
2213 int protocol;
2214
2215 uint8_t addr8[sizeof (struct in6_addr)];
2216 vppcom_endpt_t ep;
2217
2218 ep.ip = addr8;
2219
2220 /* validate flags */
2221
2222 /*
2223 * for documentation
2224 * switch (flags)
2225 * {
2226 * case 0:
2227 * case SOCK_NONBLOCK:
2228 * case SOCK_CLOEXEC:
2229 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2230 * break;
2231 *
2232 * default:
2233 * return -1;
2234 * }
2235 */
2236 /* flags can be 0 or can be bitwise OR
2237 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2238
2239 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2240 {
2241 /* TBD: return proper error code */
2242 return -1;
2243 }
2244
2245 /* TBD: return proper error code */
2246
2247 if (!vcom_socket_is_connection_mode_socket (__fd))
2248 {
2249 return -EOPNOTSUPP;
2250 }
2251
2252 p = hash_get (vsm->sockidx_by_fd, __fd);
2253 if (p)
2254 {
2255 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2256
2257
2258 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2259 if (rv < 0)
2260 {
2261 return rv;
2262 }
2263
2264 /* is blocking */
2265 if (!(rv & O_NONBLOCK))
2266 {
2267 /* socket is not marked as nonblocking
2268 * and no pending connections are present
2269 * on the queue, accept () blocks the caller
2270 * until a connection is present.
2271 */
2272 rv = vppcom_session_accept (vsock->sid, &ep,
2273 -1.0 /* wait forever */ );
2274 }
2275 else
2276 {
2277 /* The file descriptor refers to a socket and has been
2278 * marked nonblocking(O_NONBLOCK) and the accept would
2279 * block.
2280 * */
2281 /* is non blocking */
2282 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2283 /* If the socket is marked nonblocking and
2284 * no pending connections are present on the
2285 * queue, accept fails with the error
2286 * EAGAIN or EWOULDBLOCK
2287 */
2288 if (rv == VPPCOM_ETIMEDOUT)
2289 {
2290 rv = VPPCOM_EAGAIN;
2291 }
2292 }
2293 if (rv < 0)
2294 {
2295 return rv;
2296 }
2297
2298 sid = rv;
2299
2300 /* create a new connected socket resource and set flags
2301 * on the new file descriptor.
2302 * update vsockets and sockidx_by_fd table
2303 * */
2304 fd = vcom_socket_connected_socket (__fd, sid,
2305 &domain, &type, &protocol, flags);
2306 if (fd < 0)
2307 {
2308 return fd;
2309 }
2310
2311 rv = fd;
2312
2313 /* TBD populate __addr and __addr_len */
2314 /* TBD: The returned address is truncated if the buffer
2315 * provided is too small, in this case, __addr_len will
2316 * return a value greater than was supplied to the call.*/
2317 if (__addr)
2318 {
2319 if (ep.is_cut_thru)
2320 {
2321 /* TBD populate __addr and __addr_len */
2322 switch (domain)
2323 {
2324 case AF_INET:
2325 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2326 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2327 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2328 addr8, sizeof (struct in_addr));
2329 /* TBD: populate __addr_len */
2330 if (__addr_len)
2331 {
2332 *__addr_len = sizeof (struct sockaddr_in);
2333 }
2334 break;
2335
2336 case AF_INET6:
2337 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2338 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2339 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2340 __in6_u.__u6_addr8, addr8,
2341 sizeof (struct in6_addr));
2342 /* TBD: populate __addr_len */
2343 if (__addr_len)
2344 {
2345 *__addr_len = sizeof (struct sockaddr_in6);
2346 }
2347 break;
2348
2349 default:
2350 return -EAFNOSUPPORT;
2351 }
2352 }
2353 else
2354 {
2355 switch (ep.is_ip4)
2356 {
2357 case VPPCOM_IS_IP4:
2358 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2359 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2360 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2361 addr8, sizeof (struct in_addr));
2362 /* TBD: populate __addr_len */
2363 if (__addr_len)
2364 {
2365 *__addr_len = sizeof (struct sockaddr_in);
2366 }
2367 break;
2368
2369 case VPPCOM_IS_IP6:
2370 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2371 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2372 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2373 __in6_u.__u6_addr8, addr8,
2374 sizeof (struct in6_addr));
2375 /* TBD: populate __addr_len */
2376 if (__addr_len)
2377 {
2378 *__addr_len = sizeof (struct sockaddr_in6);
2379 }
2380 break;
2381
2382 default:
2383 return -EAFNOSUPPORT;
2384 }
2385 }
2386 }
2387 else
2388 {
2389 /* when __addr is NULL, nothing is filled in,
2390 * in this case, __addr_len is not used,
2391 * and should also be null
2392 * */
2393 if (__addr_len)
2394 {
2395 /* TBD: return proper error code */
2396 return -1;
2397 }
2398 }
2399 }
2400
2401 return rv;
2402}
2403
2404int
2405vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2406 socklen_t * __restrict __addr_len)
2407{
2408 /* set flags to 0 for accept() */
2409 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2410}
2411
2412#ifdef __USE_GNU
2413int
2414vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2415 socklen_t * __restrict __addr_len, int __flags)
2416{
2417 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2418 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2419}
2420#endif
2421
2422/* TBD: move it to vppcom */
2423int
2424vppcom_session_shutdown (int __fd, int __how)
2425{
2426 return 0;
2427}
2428
2429int
2430vcom_socket_shutdown (int __fd, int __how)
2431{
2432 int rv = -1;
2433 vcom_socket_main_t *vsm = &vcom_socket_main;
2434 uword *p;
2435 vcom_socket_t *vsock;
2436
2437 p = hash_get (vsm->sockidx_by_fd, __fd);
2438 if (p)
2439 {
2440 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2441 switch (__how)
2442 {
2443 case SHUT_RD:
2444 case SHUT_WR:
2445 case SHUT_RDWR:
2446 rv = vppcom_session_shutdown (vsock->sid, __how);
2447 return rv;
2448 break;
2449
2450 default:
2451 return -EINVAL;
2452 break;
2453 }
2454 }
2455
2456 return rv;
2457}
2458
2459int
2460vcom_socket_epoll_create1 (int __flags)
2461{
2462 int rv = -1;
2463 vcom_socket_main_t *vsm = &vcom_socket_main;
2464 vcom_epoll_t *vepoll;
2465
2466 i32 epfd;
2467 i32 vep_idx;
2468 i32 epollidx;
2469
2470 epfd = vcom_socket_open_epoll (__flags);
2471 if (epfd < 0)
2472 {
2473 rv = epfd;
2474 goto out;
2475 }
2476
2477 vep_idx = vppcom_epoll_create ();
2478 if (vep_idx < 0)
2479 {
2480 rv = vep_idx;
2481 goto out_close_epoll;
2482 }
2483
2484 pool_get (vsm->vepolls, vepoll);
2485 vepoll_init (vepoll);
2486
2487 epollidx = vepoll - vsm->vepolls;
2488 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2489
2490 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2491
2492 return epfd;
2493
2494out_close_epoll:
2495 vcom_socket_close_epoll (epfd);
2496out:
2497 return rv;
2498}
2499
2500/*
2501 * PRE: vppcom_epoll_ctl() is successful
2502 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2503 */
2504int
2505vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2506 struct epoll_event *__event,
2507 i32 vep_idx, vcom_epoll_t * vepoll,
2508 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2509 int free_vepitem_on_del)
2510{
2511 int rv = -1;
2512 vcom_socket_main_t *vsm = &vcom_socket_main;
2513 vcom_epitem_t *vepitem;
2514
2515 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2516 uword *p;
2517 i32 vepitemidx;
2518
2519 i32 *vepitemidxs = 0;
2520
2521 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2522
2523 i32 vec_idx;
2524
2525 /* perform control operations on the epoll instance */
2526 switch (__op)
2527 {
2528 case EPOLL_CTL_ADD:
2529 /*
2530 * supplied file descriptor is already
2531 * registered with this epoll instance
2532 * */
2533 /* vepitem exists */
2534 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2535 if (p)
2536 {
2537 rv = -EEXIST;
2538 goto out;
2539 }
2540
2541 /* add a new vepitem */
2542 pool_get (vsm->vepitems, vepitem);
2543 vepitem_init (vepitem);
2544
2545 vepitemidx = vepitem - vsm->vepitems;
2546 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2547 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2548
2549 /* update epitemidxs */
2550 /* by_epfd */
2551 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2552 if (!p) /* not exist */
2553 {
2554 vepitemidxs = 0;
2555 vec_add1 (vepitemidxs, vepitemidx);
2556 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2557 }
2558 else /* exists */
2559 {
2560 vepitemidxs = *(i32 **) p;
2561 vec_add1 (vepitemidxs, vepitemidx);
2562 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2563 }
2564 /* update epitemidxs */
2565 /* by_fd */
2566 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2567 if (!p) /* not exist */
2568 {
2569 vepitemidxs = 0;
2570 vec_add1 (vepitemidxs, vepitemidx);
2571 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2572 }
2573 else /* exists */
2574 {
2575 vepitemidxs = *(i32 **) p;
2576 vec_add1 (vepitemidxs, vepitemidx);
2577 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2578 }
2579
2580 /* increment vepoll fd count by 1 */
2581 vepoll->count += 1;
2582
2583 rv = 0;
2584 goto out;
2585 break;
2586
2587 case EPOLL_CTL_MOD:
2588 /*
2589 * supplied file descriptor is not
2590 * registered with this epoll instance
2591 * */
2592 /* vepitem not exist */
2593 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2594 if (!p)
2595 {
2596 rv = -ENOENT;
2597 goto out;
2598 }
2599 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2600 if (vepitem)
2601 {
2602 vepitem->event = *__event;
2603 vepitem->revent = revent;
2604 }
2605
2606 rv = 0;
2607 goto out;
2608 break;
2609
2610 case EPOLL_CTL_DEL:
2611 /*
2612 * supplied file descriptor is not
2613 * registered with this epoll instance
2614 * */
2615 /* vepitem not exist */
2616 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2617 if (!p)
2618 {
2619 rv = -ENOENT;
2620 goto out;
2621 }
2622 vepitemidx = *(i32 *) p;
2623 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2624
2625 /* update epitemidxs */
2626 /* by_epfd */
2627 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2628 if (!p) /* not exist */
2629 {
2630 rv = -ENOENT;
2631 goto out;
2632 }
2633 else /* exists */
2634 {
2635 vepitemidxs = *(i32 **) p;
2636 vec_idx = vec_search (vepitemidxs, vepitemidx);
2637 if (vec_idx != ~0)
2638 {
2639 vec_del1 (vepitemidxs, vec_idx);
2640 if (!vec_len (vepitemidxs))
2641 {
2642 vec_free (vepitemidxs);
2643 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2644 }
2645 }
2646 }
2647
2648 /* update epitemidxs */
2649 /* by_fd */
2650 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2651 if (!p) /* not exist */
2652 {
2653 rv = -ENOENT;
2654 goto out;
2655 }
2656 else /* exists */
2657 {
2658 vepitemidxs = *(i32 **) p;
2659 vec_idx = vec_search (vepitemidxs, vepitemidx);
2660 if (vec_idx != ~0)
2661 {
2662 vec_del1 (vepitemidxs, vec_idx);
2663 if (!vec_len (vepitemidxs))
2664 {
2665 vec_free (vepitemidxs);
2666 hash_unset (vsm->epitemidxs_by_fd, __fd);
2667 }
2668 }
2669 }
2670
2671 /* pool put vepitem */
2672 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2673 if (free_vepitem_on_del)
2674 {
2675 if (!vepitem)
2676 {
2677 rv = -ENOENT;
2678 goto out;
2679 }
2680 vepitem_init (vepitem);
2681 pool_put (vsm->vepitems, vepitem);
2682 }
2683 else
2684 {
2685 if (!vepitem)
2686 {
2687 vepitem_init (vepitem);
2688 }
2689 }
2690
2691 /* decrement vepoll fd count by 1 */
2692 vepoll->count -= 1;
2693
2694 rv = 0;
2695 goto out;
2696 break;
2697
2698 default:
2699 rv = -EINVAL;
2700 goto out;
2701 break;
2702 }
2703
2704out:
2705 return rv;
2706}
2707
2708/*
2709 * PRE: 00. null pointer check on __event
2710 * 01. all other parameters are validated
2711 */
2712
2713static int
2714vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2715 struct epoll_event *__event,
2716 int free_vepitem_on_del)
2717{
2718 int rv = -1;
2719
2720 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2721 vcom_epoll_t *vepoll;
2722
2723 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2724 void *vfd;
2725 vcom_epoll_t *vfd_vepoll;
2726 vcom_socket_t *vfd_vsock;
2727
2728 i32 vep_idx;
2729 i32 vfd_id;
2730
2731 vcom_fd_type_t type = FD_TYPE_INVALID;
2732
2733 /* validate __event */
2734
2735 /* get vep_idx and vepoll */
2736 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2737 if (vep_idx == INVALID_VEP_IDX)
2738 {
2739 return -EBADF;
2740 }
2741
2742 /* get vcom fd type, vfd_id and vfd */
2743 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2744 if (vfd_id != INVALID_SESSION_ID)
2745 {
2746 type = FD_TYPE_VCOM_SOCKET;
2747 vfd = vfd_vsock;
2748 }
2749 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2750 != INVALID_VEP_IDX)
2751 {
2752 type = FD_TYPE_EPOLL;
2753 vfd = vfd_vepoll;
2754 }
2755 else
2756 {
2757 /* FD_TYPE_KERNEL not supported by epoll instance */
2758 type = FD_TYPE_INVALID;
2759 return -EBADF;
2760 }
2761
2762
2763 /* vepoll and vsock are now valid */
2764 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2765 if (rv < 0)
2766 {
2767 return rv;
2768 }
2769
2770 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2771 __event,
2772 vep_idx, vepoll,
2773 vfd_id, vfd, type, free_vepitem_on_del);
2774 return rv;
2775}
2776
2777int
2778vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2779 struct epoll_event *__event)
2780{
2781 int rv = -1;
2782
2783 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2784 return rv;
2785}
2786
2787static int
2788vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2789 struct epoll_event *__event)
2790{
2791 int rv = -1;
2792
2793 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2794 return rv;
2795}
2796
2797int
2798vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2799 int __maxevents, int __timeout,
2800 const __sigset_t * __ss)
2801{
2802 int rv = -EBADF;
2803
2804 /* in seconds eg. 3.123456789 seconds */
2805 double time_to_wait = (double) 0;
2806
2807 i32 vep_idx;
2808
2809 /* validate __event */
2810 if (!__events)
2811 {
2812 rv = -EFAULT;
2813 goto out;
2814 }
2815
2816 /* validate __timeout */
2817 if (__timeout > 0)
2818 {
2819 time_to_wait = (double) __timeout / (double) 1000;
2820 }
2821 else if (__timeout == 0)
2822 {
2823 time_to_wait = (double) 0;
2824 }
2825 else if (__timeout == -1)
2826 {
2827 time_to_wait = ~0;
2828 }
2829 else
2830 {
2831 rv = -EBADF;
2832 goto out;
2833 }
2834
2835 /* get vep_idx */
2836 vep_idx = vcom_socket_get_vep_idx (__epfd);
2837 if (vep_idx != INVALID_VEP_IDX)
2838 {
2839 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2840 }
2841out:
2842 return rv;
2843}
2844
2845int
2846vcom_socket_main_init (void)
2847{
2848 vcom_socket_main_t *vsm = &vcom_socket_main;
2849
2850 if (VCOM_DEBUG > 0)
2851 printf ("vcom_socket_main_init\n");
2852
2853 if (!vsm->init)
2854 {
2855 /* TBD: define FD_MAXSIZE and use it here */
2856 pool_alloc (vsm->vsockets, FD_SETSIZE);
2857 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
2858
2859 pool_alloc (vsm->vepolls, FD_SETSIZE);
2860 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
2861
2862 pool_alloc (vsm->vepitems, FD_SETSIZE);
2863 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
2864
2865 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
2866 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
2867
2868 vsm->init = 1;
2869 }
2870
2871 return 0;
2872}
2873
2874
2875void
2876vcom_socket_main_show (void)
2877{
2878 vcom_socket_main_t *vsm = &vcom_socket_main;
2879 vcom_socket_t *vsock;
2880
2881 vcom_epoll_t *vepoll;
2882
2883 vcom_epitem_t *vepitem;
2884
2885 i32 epfd;
2886 i32 fd;
2887 i32 *vepitemidxs, *vepitemidxs_var;
2888
2889 if (vsm->init)
2890 {
2891 /* from active list of vsockets show vsock */
2892
2893 /* *INDENT-OFF* */
2894 pool_foreach (vsock, vsm->vsockets,
2895 ({
2896 printf(
2897 "fd='%04d', sid='%08x',type='%-30s'\n",
2898 vsock->fd, vsock->sid,
2899 vcom_socket_type_str (vsock->type));
2900 }));
2901 /* *INDENT-ON* */
2902
2903 /* from active list of vepolls, show vepoll */
2904
2905 /* *INDENT-OFF* */
2906 pool_foreach (vepoll, vsm->vepolls,
2907 ({
2908 printf(
2909 "epfd='%04d', vep_idx='%08x', "
2910 "type='%-30s', "
2911 "flags='%d', count='%d', close='%d'\n",
2912 vepoll->epfd, vepoll->vep_idx,
2913 vcom_socket_epoll_type_str (vepoll->type),
2914 vepoll->flags, vepoll->count, vepoll->close);
2915 }));
2916 /* *INDENT-ON* */
2917
2918 /* from active list of vepitems, show vepitem */
2919
2920 /* *INDENT-OFF* */
2921 pool_foreach (vepitem, vsm->vepitems,
2922 ({
2923 printf(
2924 "epfd='%04d', fd='%04d', "
2925 "next_fd='%04d', prev_fd='%04d', "
2926 "type='%-30s', "
2927 "events='%04x', revents='%04x'\n",
2928 vepitem->epfd, vepitem->fd,
2929 vepitem->next_fd, vepitem->prev_fd,
2930 vcom_socket_vcom_fd_type_str (vepitem->type),
2931 vepitem->event.events, vepitem->revent.events);
2932 }));
2933
2934 /* *INDENT-ON* */
2935
2936 /* show epitemidxs for epfd */
2937 /* *INDENT-OFF* */
2938 hash_foreach (epfd, vepitemidxs,
2939 vsm->epitemidxs_by_epfd,
2940 ({
2941 printf("\n[ '%04d': ", epfd);
2942 vec_foreach (vepitemidxs_var,vepitemidxs)
2943 {
2944 printf("'%04d' ", (int)vepitemidxs_var[0]);
2945 }
2946 printf("]\n");
2947 }));
2948 /* *INDENT-ON* */
2949
2950 /* show epitemidxs for fd */
2951 /* *INDENT-OFF* */
2952 hash_foreach (fd, vepitemidxs,
2953 vsm->epitemidxs_by_fd,
2954 ({
2955 printf("\n{ '%04d': ", fd);
2956 vec_foreach (vepitemidxs_var,vepitemidxs)
2957 {
2958 printf("'%04d' ", (int)vepitemidxs_var[0]);
2959 }
2960 printf("}\n");
2961 }));
2962 /* *INDENT-ON* */
2963
2964 }
2965}
2966
2967void
2968vcom_socket_main_destroy (void)
2969{
2970 vcom_socket_main_t *vsm = &vcom_socket_main;
2971 vcom_socket_t *vsock;
2972
2973 vcom_epoll_t *vepoll;
2974
2975 vcom_epitem_t *vepitem;
2976
2977 i32 epfd;
2978 i32 fd;
2979 i32 *vepitemidxs;
2980
2981
2982 if (VCOM_DEBUG > 0)
2983 printf ("vcom_socket_main_destroy\n");
2984
2985 if (vsm->init)
2986 {
2987
2988 /*
2989 * from active list of vepitems,
2990 * remove all "vepitem" elements from the pool in a safe way
2991 * */
2992
2993 /* *INDENT-OFF* */
2994 pool_flush (vepitem, vsm->vepitems,
2995 ({
2996 if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
2997 {
2998 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
2999 vepitem->fd, NULL);
3000 vepitem_init (vepitem);
3001 }
3002 }));
3003 /* *INDENT-ON* */
3004
3005 pool_free (vsm->vepitems);
3006 hash_free (vsm->epitemidx_by_epfdfd);
3007
3008 /* free vepitemidxs for each epfd */
3009 /* *INDENT-OFF* */
3010 hash_foreach (epfd, vepitemidxs,
3011 vsm->epitemidxs_by_epfd,
3012 ({
3013 vec_free (vepitemidxs);
3014 }));
3015 /* *INDENT-ON* */
3016 hash_free (vsm->epitemidxs_by_epfd);
3017
3018 /* free vepitemidxs for each fd */
3019 /* *INDENT-OFF* */
3020 hash_foreach (fd, vepitemidxs,
3021 vsm->epitemidxs_by_fd,
3022 ({
3023 vec_free (vepitemidxs);
3024 }));
3025 /* *INDENT-ON* */
3026 hash_free (vsm->epitemidxs_by_fd);
3027
3028
3029 /*
3030 * from active list of vsockets,
3031 * close socket and vppcom session
3032 * */
3033
3034 /* *INDENT-OFF* */
3035 pool_foreach (vsock, vsm->vsockets,
3036 ({
3037 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3038 {
3039 vppcom_session_close (vsock->sid);
3040 vcom_socket_close_socket (vsock->fd);
3041 vsocket_init (vsock);
3042 }
3043 }));
3044 /* *INDENT-ON* */
3045
3046 /*
3047 * return vsocket element to the pool
3048 * */
3049
3050 /* *INDENT-OFF* */
3051 pool_flush (vsock, vsm->vsockets,
3052 ({
3053 // vsocket_init(vsock);
3054 ;
3055 }));
3056 /* *INDENT-ON* */
3057
3058 pool_free (vsm->vsockets);
3059 hash_free (vsm->sockidx_by_fd);
3060
3061 /*
3062 * from active list of vepolls,
3063 * close epoll and vppcom_epoll
3064 * */
3065
3066 /* *INDENT-OFF* */
3067 pool_foreach (vepoll, vsm->vepolls,
3068 ({
3069 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3070 {
3071 vppcom_session_close (vepoll->vep_idx);
3072 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3073 vepoll_init (vepoll);
3074 }
3075 }));
3076 /* *INDENT-ON* */
3077
3078 /*
3079 * return vepoll element to the pool
3080 * */
3081
3082 /* *INDENT-OFF* */
3083 pool_flush (vepoll, vsm->vepolls,
3084 ({
3085 // vepoll_init(vepoll);
3086 ;
3087 }));
3088 /* *INDENT-ON* */
3089
3090 pool_free (vsm->vepolls);
3091 hash_free (vsm->epollidx_by_epfd);
3092
3093 vsm->init = 0;
3094 }
3095}
3096
3097
3098/*
3099 * fd.io coding-style-patch-verification: ON
3100 *
3101 * Local Variables:
3102 * eval: (c-set-style "gnu")
3103 * End:
3104 */