blob: fdcf13791d9ddabb2b62db3657b00e26e81804b2 [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{
Steven2199aab2017-10-15 20:18:47 -07001275 int rv;
1276 uint32_t size = sizeof (*ep);
1277
1278 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1279 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001280}
1281
1282int
1283vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1284 socklen_t * __restrict __len)
1285{
1286 int rv = -1;
1287 vcom_socket_main_t *vsm = &vcom_socket_main;
1288 uword *p;
1289 vcom_socket_t *vsock;
1290
1291
1292 p = hash_get (vsm->sockidx_by_fd, __fd);
1293 if (!p)
1294 return -EBADF;
1295
1296 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1297 if (!vsock)
1298 return -ENOTSOCK;
1299
1300 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1301 return -EINVAL;
1302
1303 if (!__addr || !__len)
1304 return -EFAULT;
1305
1306 if (*__len < 0)
1307 {
1308 return -EINVAL;
1309 }
1310
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001311 vppcom_endpt_t ep;
1312 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1313 rv = vppcom_session_getsockname (vsock->sid, &ep);
1314 if (rv == 0)
1315 {
1316 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1317 {
1318 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1319 switch (__addr->sa_family)
1320 {
1321 case AF_INET:
1322 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1323 *__len = sizeof (struct sockaddr_in);
1324 break;
1325
1326 case AF_INET6:
1327 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1328 *__len = sizeof (struct sockaddr_in6);
1329 break;
1330
1331 default:
1332 break;
1333 }
1334 }
1335 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001336
1337 return rv;
1338}
1339
1340int
1341vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1342{
1343 int rv = -1;
1344 vcom_socket_main_t *vsm = &vcom_socket_main;
1345 uword *p;
1346 vcom_socket_t *vsock;
1347
1348 vppcom_endpt_t ep;
1349
1350 p = hash_get (vsm->sockidx_by_fd, __fd);
1351 if (p)
1352 {
1353 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1354
1355 ep.vrf = VPPCOM_VRF_DEFAULT;
1356 switch (__addr->sa_family)
1357 {
1358 case AF_INET:
1359 ep.is_ip4 = VPPCOM_IS_IP4;
1360 ep.ip =
1361 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1362 ep.port =
1363 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1364 break;
1365
1366 case AF_INET6:
1367 ep.is_ip4 = VPPCOM_IS_IP6;
1368 ep.ip =
1369 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1370 ep.port =
1371 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1372 break;
1373
1374 default:
1375 return -1;
1376 break;
1377 }
1378
1379 rv = vppcom_session_connect (vsock->sid, &ep);
1380 }
1381 return rv;
1382}
1383
1384int
1385vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1386{
Steven2199aab2017-10-15 20:18:47 -07001387 int rv;
1388 uint32_t size = sizeof (*ep);
1389
1390 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1391 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001392}
1393
1394int
1395vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1396 socklen_t * __restrict __len)
1397{
1398 int rv = -1;
1399 vcom_socket_main_t *vsm = &vcom_socket_main;
1400 uword *p;
1401 vcom_socket_t *vsock;
1402
1403
1404 p = hash_get (vsm->sockidx_by_fd, __fd);
1405 if (!p)
1406 return -EBADF;
1407
1408 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1409 if (!vsock)
1410 return -ENOTSOCK;
1411
1412 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1413 return -EINVAL;
1414
1415 if (!__addr || !__len)
1416 return -EFAULT;
1417
1418 if (*__len < 0)
1419 {
1420 return -EINVAL;
1421 }
1422
1423 /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
1424 {
1425 uint8_t *a;
1426 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1427 ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
1428 a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
1429 a[0] = 0x7f;
1430 a[1] = 0x00;
1431 a[2] = 0x00;
1432 a[3] = 0x01;
1433 *__len = sizeof (struct sockaddr_in);
1434 return 0;
1435 }
1436
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001437 vppcom_endpt_t ep;
1438 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1439 rv = vppcom_session_getpeername (vsock->sid, &ep);
1440 if (rv == 0)
1441 {
1442 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1443 {
1444 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1445 switch (__addr->sa_family)
1446 {
1447 case AF_INET:
1448 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1449 *__len = sizeof (struct sockaddr_in);
1450 break;
1451
1452 case AF_INET6:
1453 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1454 *__len = sizeof (struct sockaddr_in6);
1455 break;
1456
1457 default:
1458 break;
1459 }
1460 }
1461 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001462
1463 return rv;
1464}
1465
1466ssize_t
1467vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1468{
1469 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1470}
1471
1472ssize_t
1473vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1474{
1475 int rv = -1;
1476 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1477 return rv;
1478}
1479
1480/*
1481 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1482 * 0 otherwise
1483 * */
1484int
1485vcom_socket_is_connection_mode_socket (int __fd)
1486{
1487 int rv = -1;
1488 /* TBD define new vppcom api */
1489 vcom_socket_main_t *vsm = &vcom_socket_main;
1490 uword *p;
1491 vcom_socket_t *vsock;
1492
1493 int type;
1494 socklen_t optlen;
1495
1496 p = hash_get (vsm->sockidx_by_fd, __fd);
1497
1498 if (p)
1499 {
1500 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1501 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1502 {
1503 optlen = sizeof (type);
1504 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1505 if (rv != 0)
1506 {
1507 return 0;
1508 }
1509 /* get socket type */
1510 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1511 {
1512 case SOCK_STREAM:
1513 case SOCK_SEQPACKET:
1514 return 1;
1515 break;
1516
1517 default:
1518 return 0;
1519 break;
1520 }
1521 }
1522 }
1523 return 0;
1524}
1525
1526ssize_t
1527vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1528 int __flags, __CONST_SOCKADDR_ARG __addr,
1529 socklen_t __addr_len)
1530{
1531 int rv = -1;
1532 /* TBD add new vpp api */
1533 /* TBD add flags parameter */
1534 rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1535 return rv;
1536}
1537
1538ssize_t
1539vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1540 int __flags, __CONST_SOCKADDR_ARG __addr,
1541 socklen_t __addr_len)
1542{
1543 int rv = -1;
1544 vcom_socket_main_t *vsm = &vcom_socket_main;
1545 uword *p;
1546 vcom_socket_t *vsock;
1547
1548 p = hash_get (vsm->sockidx_by_fd, __fd);
1549 if (!p)
1550 return -EBADF;
1551
1552 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1553 if (!vsock)
1554 return -ENOTSOCK;
1555
1556 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1557 return -EINVAL;
1558
1559 if (!__buf || __n < 0)
1560 {
1561 return -EINVAL;
1562 }
1563
1564 if (vcom_socket_is_connection_mode_socket (__fd))
1565 {
1566 /* ignore __addr and _addr_len */
1567 /* and EISCONN may be returned when they are not NULL and 0 */
1568 if ((__addr != NULL) || (__addr_len != 0))
1569 {
1570 return -EISCONN;
1571 }
1572 }
1573 else
1574 {
1575 if (!__addr || __addr_len < 0)
1576 {
1577 return -EDESTADDRREQ;
1578 }
1579 /* not a vppcom supported address family */
1580 if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1581 {
1582 return -EINVAL;
1583 }
1584 }
1585
1586 rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1587 __flags, __addr, __addr_len);
1588 return rv;
1589}
1590
1591/* TBD: move it to vppcom */
1592static ssize_t
1593vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1594 int __flags, __SOCKADDR_ARG __addr,
1595 socklen_t * __restrict __addr_len)
1596{
1597 int rv = -1;
1598
1599 /* TBD add flags parameter */
1600 rv = vppcom_session_read (__sid, __buf, __n);
1601 return rv;
1602}
1603
1604ssize_t
1605vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1606 int __flags, __SOCKADDR_ARG __addr,
1607 socklen_t * __restrict __addr_len)
1608{
1609 int rv = -1;
1610 vcom_socket_main_t *vsm = &vcom_socket_main;
1611 uword *p;
1612 vcom_socket_t *vsock;
1613
1614 p = hash_get (vsm->sockidx_by_fd, __fd);
1615 if (!p)
1616 return -EBADF;
1617
1618 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1619 if (!vsock)
1620 return -ENOTSOCK;
1621
1622 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1623 return -EINVAL;
1624
1625 if (!__buf || __n < 0)
1626 {
1627 return -EINVAL;
1628 }
1629
1630 if (__addr || __addr_len < 0)
1631 {
1632 return -EINVAL;
1633 }
1634
1635 rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1636 __flags, __addr, __addr_len);
1637 return rv;
1638}
1639
1640/* TBD: move it to vppcom */
1641static ssize_t
1642vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1643{
1644 int rv = -1;
1645 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1646 (int)__n); */
1647 return rv;
1648}
1649
1650ssize_t
1651vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1652{
1653 int rv = -1;
1654 vcom_socket_main_t *vsm = &vcom_socket_main;
1655 uword *p;
1656 vcom_socket_t *vsock;
1657
1658 p = hash_get (vsm->sockidx_by_fd, __fd);
1659 if (!p)
1660 return -EBADF;
1661
1662 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1663 if (!vsock)
1664 return -ENOTSOCK;
1665
1666 if (vcom_socket_is_connection_mode_socket (__fd))
1667 {
1668 /* ignore __addr and _addr_len */
1669 /* and EISCONN may be returned when they are not NULL and 0 */
1670 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1671 {
1672 return -EISCONN;
1673 }
1674 }
1675 else
1676 {
1677 /* TBD: validate __message->msg_name and __message->msg_namelen
1678 * and return -EINVAL on validation error
1679 * */
1680 ;
1681 }
1682
1683 rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1684
1685 return rv;
1686}
1687
1688#ifdef __USE_GNU
1689int
1690vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1691 unsigned int __vlen, int __flags)
1692{
1693
1694 /* TBD: define a new vppcom api */
1695 return 0;
1696}
1697#endif
1698
1699/* TBD: move it to vppcom */
1700static ssize_t
1701vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1702{
1703 int rv = -1;
1704 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1705 (int)__n); */
1706 rv = -EOPNOTSUPP;
1707 return rv;
1708}
1709
1710ssize_t
1711vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1712{
1713 int rv = -1;
1714 vcom_socket_main_t *vsm = &vcom_socket_main;
1715 uword *p;
1716 vcom_socket_t *vsock;
1717
1718 p = hash_get (vsm->sockidx_by_fd, __fd);
1719 if (!p)
1720 return -EBADF;
1721
1722 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1723 if (!vsock)
1724 return -ENOTSOCK;
1725
1726 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1727 return -EINVAL;
1728
1729 if (!__message)
1730 {
1731 return -EINVAL;
1732 }
1733
1734 /* validate __flags */
1735
1736 rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1737 return rv;
1738}
1739
1740#ifdef __USE_GNU
1741int
1742vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1743 unsigned int __vlen, int __flags,
1744 struct timespec *__tmo)
1745{
1746 /* TBD: define a new vppcom api */
1747 return 0;
1748}
1749#endif
1750
1751/* TBD: move it to vppcom */
1752static int
1753vppcom_getsockopt (int __sid, int __level, int __optname,
1754 void *__restrict __optval, socklen_t * __restrict __optlen)
1755{
1756 /* 1. for socket level options that are NOT socket attributes
1757 * and that has corresponding vpp options get from vppcom */
1758#if 0
1759 return 0;
1760#endif
1761
1762 /* 2. unhandled options */
1763 return -ENOPROTOOPT;
1764}
1765
1766int
1767vcom_socket_getsockopt (int __fd, int __level, int __optname,
1768 void *__restrict __optval,
1769 socklen_t * __restrict __optlen)
1770{
1771 int rv = -1;
1772 vcom_socket_main_t *vsm = &vcom_socket_main;
1773 uword *p;
1774 vcom_socket_t *vsock;
1775
1776 p = hash_get (vsm->sockidx_by_fd, __fd);
1777 if (!p)
1778 return -EBADF;
1779
1780 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1781 if (!vsock)
1782 return -ENOTSOCK;
1783
1784 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1785 return -EINVAL;
1786
1787 if (!__optval && !__optlen)
1788 return -EFAULT;
1789
1790 if (*__optlen < 0)
1791 {
1792 return -EINVAL;
1793 }
1794
1795 switch (__level)
1796 {
1797 /* handle options at socket level */
1798 case SOL_SOCKET:
1799 switch (__optname)
1800 {
1801/*
1802 * 1. for socket level options that are socket attributes,
1803 * get from libc_getsockopt.
1804 * 2. for socket level options that are NOT socket
1805 * attributes and that has corresponding vpp options
1806 * get from vppcom.
1807 * 3. for socket level options unimplemented
1808 * return -ENOPROTOOPT */
1809 case SO_DEBUG:
1810 case SO_DONTROUTE:
1811 case SO_BROADCAST:
1812 case SO_SNDBUF:
1813 case SO_RCVBUF:
1814 case SO_REUSEADDR:
1815 case SO_REUSEPORT:
1816 case SO_KEEPALIVE:
1817 case SO_TYPE:
1818 case SO_PROTOCOL:
1819 case SO_DOMAIN:
1820 case SO_ERROR:
1821 case SO_OOBINLINE:
1822 case SO_NO_CHECK:
1823 case SO_PRIORITY:
1824 case SO_LINGER:
1825 case SO_BSDCOMPAT:
1826 case SO_TIMESTAMP:
1827 case SO_TIMESTAMPNS:
1828 case SO_TIMESTAMPING:
1829 case SO_RCVTIMEO:
1830 case SO_SNDTIMEO:
1831 case SO_RCVLOWAT:
1832 case SO_SNDLOWAT:
1833 case SO_PASSCRED:
1834 case SO_PEERCRED:
1835 case SO_PEERNAME:
1836 case SO_ACCEPTCONN:
1837 case SO_PASSSEC:
1838 case SO_PEERSEC:
1839 case SO_MARK:
1840 case SO_RXQ_OVFL:
1841 case SO_WIFI_STATUS:
1842 case SO_PEEK_OFF:
1843 case SO_NOFCS:
1844 case SO_BINDTODEVICE:
1845 case SO_GET_FILTER:
1846 case SO_LOCK_FILTER:
1847 case SO_BPF_EXTENSIONS:
1848 case SO_SELECT_ERR_QUEUE:
1849#ifdef CONFIG_NET_RX_BUSY_POLL
1850 case SO_BUSY_POLL:
1851#endif
1852 case SO_MAX_PACING_RATE:
1853 case SO_INCOMING_CPU:
1854 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1855 if (rv != 0)
1856 {
1857 rv = -errno;
1858 return rv;
1859 }
1860 break;
1861
1862 default:
1863 /* We implement the SO_SNDLOWAT etc to not be settable
1864 * (1003.1g 7).
1865 */
1866 return -ENOPROTOOPT;
1867 }
1868
1869 break;
1870
1871 default:
1872 /* 1. handle options that are NOT socket level options,
1873 * but have corresponding vpp otions. */
1874 rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1875 __optval, __optlen);
1876
1877 return rv;
1878#if 0
1879 /* 2. unhandled options */
1880 return -ENOPROTOOPT;
1881#endif
1882 }
1883
1884 return rv;
1885}
1886
1887/* TBD: move it to vppcom */
1888int
Stevenb59f2272017-10-12 17:10:33 -07001889vppcom_session_setsockopt (int __sid, int __level, int __optname,
1890 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001891{
Stevenb59f2272017-10-12 17:10:33 -07001892 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001893
Stevenb59f2272017-10-12 17:10:33 -07001894 switch (__level)
1895 {
Stevenbd187a82017-10-13 12:52:28 -07001896 case SOL_TCP:
1897 switch (__optname)
1898 {
1899 case TCP_KEEPIDLE:
1900 rv =
1901 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1902 break;
1903 case TCP_KEEPINTVL:
1904 rv =
1905 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1906 break;
1907 default:
1908 break;
1909 }
1910 break;
Stevenb59f2272017-10-12 17:10:33 -07001911 case SOL_IPV6:
1912 switch (__optname)
1913 {
1914 case IPV6_V6ONLY:
1915 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001916 break;
Stevenb59f2272017-10-12 17:10:33 -07001917 default:
Stevenbd187a82017-10-13 12:52:28 -07001918 break;
Stevenb59f2272017-10-12 17:10:33 -07001919 }
1920 break;
1921 case SOL_SOCKET:
1922 switch (__optname)
1923 {
Stevenbd187a82017-10-13 12:52:28 -07001924 case SO_KEEPALIVE:
1925 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1926 break;
Stevenb59f2272017-10-12 17:10:33 -07001927 case SO_REUSEADDR:
1928 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001929 break;
Stevenb59f2272017-10-12 17:10:33 -07001930 case SO_BROADCAST:
1931 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001932 break;
Stevenb59f2272017-10-12 17:10:33 -07001933 default:
Stevenbd187a82017-10-13 12:52:28 -07001934 break;
Stevenb59f2272017-10-12 17:10:33 -07001935 }
1936 break;
1937 default:
Stevenbd187a82017-10-13 12:52:28 -07001938 break;
Stevenb59f2272017-10-12 17:10:33 -07001939 }
1940
1941 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001942}
1943
1944int
1945vcom_socket_setsockopt (int __fd, int __level, int __optname,
1946 const void *__optval, socklen_t __optlen)
1947{
1948 int rv = -1;
1949 vcom_socket_main_t *vsm = &vcom_socket_main;
1950 uword *p;
1951 vcom_socket_t *vsock;
1952
1953 p = hash_get (vsm->sockidx_by_fd, __fd);
1954 if (!p)
1955 return -EBADF;
1956
1957 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1958 if (!vsock)
1959 return -ENOTSOCK;
1960
1961 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1962 return -EINVAL;
1963
1964 /*
1965 * Options without arguments
1966 */
1967
1968 if (__optname == SO_BINDTODEVICE)
1969 {
1970 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1971 if (rv != 0)
1972 {
1973 rv = -errno;
1974 }
1975 return rv;
1976 }
1977
1978 if (!__optval)
1979 return -EFAULT;
1980
1981 if ((__optlen < 0) || (__optlen < sizeof (int)))
1982 return -EINVAL;
1983
1984 switch (__level)
1985 {
Stevenb59f2272017-10-12 17:10:33 -07001986 case SOL_IPV6:
1987 switch (__optname)
1988 {
1989 case IPV6_V6ONLY:
1990 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
1991 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001992 break;
Stevenb59f2272017-10-12 17:10:33 -07001993 default:
1994 return -EOPNOTSUPP;
1995 }
1996 break;
1997 case SOL_TCP:
1998 switch (__optname)
1999 {
2000 case TCP_NODELAY:
2001 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002002 case TCP_KEEPIDLE:
2003 case TCP_KEEPINTVL:
2004 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
2005 __optval, __optlen);
2006 break;
Stevenb59f2272017-10-12 17:10:33 -07002007 default:
2008 return -EOPNOTSUPP;
2009 }
2010 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002011 /* handle options at socket level */
2012 case SOL_SOCKET:
2013 switch (__optname)
2014 {
Stevenb59f2272017-10-12 17:10:33 -07002015 case SO_REUSEADDR:
2016 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002017 case SO_KEEPALIVE:
Stevenb59f2272017-10-12 17:10:33 -07002018 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
2019 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002020 break;
Stevenb59f2272017-10-12 17:10:33 -07002021
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002022 /*
2023 * 1. for socket level options that are socket attributes,
2024 * set it from libc_getsockopt
2025 * 2. for socket level options that are NOT socket
2026 * attributes and that has corresponding vpp options
2027 * set it from vppcom
2028 * 3. for socket level options unimplemented
2029 * return -ENOPROTOOPT */
2030 case SO_DEBUG:
2031 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002032 case SO_SNDBUF:
2033 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002034 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002035 case SO_TYPE:
2036 case SO_PROTOCOL:
2037 case SO_DOMAIN:
2038 case SO_ERROR:
2039 case SO_OOBINLINE:
2040 case SO_NO_CHECK:
2041 case SO_PRIORITY:
2042 case SO_LINGER:
2043 case SO_BSDCOMPAT:
2044 case SO_TIMESTAMP:
2045 case SO_TIMESTAMPNS:
2046 case SO_TIMESTAMPING:
2047 case SO_RCVTIMEO:
2048 case SO_SNDTIMEO:
2049 case SO_RCVLOWAT:
2050 case SO_SNDLOWAT:
2051 case SO_PASSCRED:
2052 case SO_PEERCRED:
2053 case SO_PEERNAME:
2054 case SO_ACCEPTCONN:
2055 case SO_PASSSEC:
2056 case SO_PEERSEC:
2057 case SO_MARK:
2058 case SO_RXQ_OVFL:
2059 case SO_WIFI_STATUS:
2060 case SO_PEEK_OFF:
2061 case SO_NOFCS:
2062 /*
2063 * SO_BINDTODEVICE already handled as
2064 * "Options without arguments" */
2065 /* case SO_BINDTODEVICE: */
2066 case SO_GET_FILTER:
2067 case SO_LOCK_FILTER:
2068 case SO_BPF_EXTENSIONS:
2069 case SO_SELECT_ERR_QUEUE:
2070#ifdef CONFIG_NET_RX_BUSY_POLL
2071 case SO_BUSY_POLL:
2072#endif
2073 case SO_MAX_PACING_RATE:
2074 case SO_INCOMING_CPU:
2075 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2076 if (rv != 0)
2077 {
2078 rv = -errno;
2079 return rv;
2080 }
2081 break;
2082
2083 default:
2084 /* We implement the SO_SNDLOWAT etc to not be settable
2085 * (1003.1g 7).
2086 */
2087 return -ENOPROTOOPT;
2088 }
2089
2090 break;
2091
2092 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002093 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002094 }
2095
2096 return rv;
2097}
2098
2099int
2100vcom_socket_listen (int __fd, int __n)
2101{
2102 int rv = -1;
2103 vcom_socket_main_t *vsm = &vcom_socket_main;
2104 uword *p;
2105 vcom_socket_t *vsock;
2106
2107 p = hash_get (vsm->sockidx_by_fd, __fd);
2108 if (p)
2109 {
2110 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2111
2112 /* TBD vppcom to accept __n parameter */
2113 rv = vppcom_session_listen (vsock->sid, __n);
2114 }
2115
2116 return rv;
2117}
2118
2119static int
2120vcom_socket_connected_socket (int __fd, int __sid,
2121 int *__domain,
2122 int *__type, int *__protocol, int flags)
2123{
2124 int rv = -1;
2125 vcom_socket_main_t *vsm = &vcom_socket_main;
2126 vcom_socket_t *vsock;
2127
2128 i32 fd;
2129 i32 sockidx;
2130
2131 socklen_t optlen;
2132
2133 optlen = sizeof (*__domain);
2134 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2135 if (rv != 0)
2136 {
2137 rv = -errno;
2138 goto out;
2139 }
2140
2141 optlen = sizeof (*__type);
2142 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2143 if (rv != 0)
2144 {
2145 rv = -errno;
2146 goto out;
2147 }
2148
2149 optlen = sizeof (*__protocol);
2150 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2151 if (rv != 0)
2152 {
2153 rv = -errno;
2154 goto out;
2155 }
2156
2157 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2158 if (fd < 0)
2159 {
2160 rv = fd;
2161 goto out;
2162 }
2163
2164 pool_get (vsm->vsockets, vsock);
2165 vsocket_init (vsock);
2166
2167 sockidx = vsock - vsm->vsockets;
2168 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2169
2170 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2171 return fd;
2172
2173out:
2174 return rv;
2175}
2176
2177/* If flag is 0, then accept4() is the same as accept().
2178 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2179 */
2180static int
2181vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2182 socklen_t * __restrict __addr_len, int flags)
2183{
2184 int rv = -1;
2185 vcom_socket_main_t *vsm = &vcom_socket_main;
2186 uword *p;
2187 vcom_socket_t *vsock;
2188
2189 int fd;
2190 int sid;
2191 int domain;
2192 int type;
2193 int protocol;
2194
2195 uint8_t addr8[sizeof (struct in6_addr)];
2196 vppcom_endpt_t ep;
2197
2198 ep.ip = addr8;
2199
2200 /* validate flags */
2201
2202 /*
2203 * for documentation
2204 * switch (flags)
2205 * {
2206 * case 0:
2207 * case SOCK_NONBLOCK:
2208 * case SOCK_CLOEXEC:
2209 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2210 * break;
2211 *
2212 * default:
2213 * return -1;
2214 * }
2215 */
2216 /* flags can be 0 or can be bitwise OR
2217 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2218
2219 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2220 {
2221 /* TBD: return proper error code */
2222 return -1;
2223 }
2224
2225 /* TBD: return proper error code */
2226
2227 if (!vcom_socket_is_connection_mode_socket (__fd))
2228 {
2229 return -EOPNOTSUPP;
2230 }
2231
2232 p = hash_get (vsm->sockidx_by_fd, __fd);
2233 if (p)
2234 {
2235 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2236
2237
2238 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2239 if (rv < 0)
2240 {
2241 return rv;
2242 }
2243
2244 /* is blocking */
2245 if (!(rv & O_NONBLOCK))
2246 {
2247 /* socket is not marked as nonblocking
2248 * and no pending connections are present
2249 * on the queue, accept () blocks the caller
2250 * until a connection is present.
2251 */
2252 rv = vppcom_session_accept (vsock->sid, &ep,
2253 -1.0 /* wait forever */ );
2254 }
2255 else
2256 {
2257 /* The file descriptor refers to a socket and has been
2258 * marked nonblocking(O_NONBLOCK) and the accept would
2259 * block.
2260 * */
2261 /* is non blocking */
2262 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2263 /* If the socket is marked nonblocking and
2264 * no pending connections are present on the
2265 * queue, accept fails with the error
2266 * EAGAIN or EWOULDBLOCK
2267 */
2268 if (rv == VPPCOM_ETIMEDOUT)
2269 {
2270 rv = VPPCOM_EAGAIN;
2271 }
2272 }
2273 if (rv < 0)
2274 {
2275 return rv;
2276 }
2277
2278 sid = rv;
2279
2280 /* create a new connected socket resource and set flags
2281 * on the new file descriptor.
2282 * update vsockets and sockidx_by_fd table
2283 * */
2284 fd = vcom_socket_connected_socket (__fd, sid,
2285 &domain, &type, &protocol, flags);
2286 if (fd < 0)
2287 {
2288 return fd;
2289 }
2290
2291 rv = fd;
2292
2293 /* TBD populate __addr and __addr_len */
2294 /* TBD: The returned address is truncated if the buffer
2295 * provided is too small, in this case, __addr_len will
2296 * return a value greater than was supplied to the call.*/
2297 if (__addr)
2298 {
2299 if (ep.is_cut_thru)
2300 {
2301 /* TBD populate __addr and __addr_len */
2302 switch (domain)
2303 {
2304 case AF_INET:
2305 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2306 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2307 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2308 addr8, sizeof (struct in_addr));
2309 /* TBD: populate __addr_len */
2310 if (__addr_len)
2311 {
2312 *__addr_len = sizeof (struct sockaddr_in);
2313 }
2314 break;
2315
2316 case AF_INET6:
2317 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2318 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2319 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2320 __in6_u.__u6_addr8, addr8,
2321 sizeof (struct in6_addr));
2322 /* TBD: populate __addr_len */
2323 if (__addr_len)
2324 {
2325 *__addr_len = sizeof (struct sockaddr_in6);
2326 }
2327 break;
2328
2329 default:
2330 return -EAFNOSUPPORT;
2331 }
2332 }
2333 else
2334 {
2335 switch (ep.is_ip4)
2336 {
2337 case VPPCOM_IS_IP4:
2338 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2339 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2340 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2341 addr8, sizeof (struct in_addr));
2342 /* TBD: populate __addr_len */
2343 if (__addr_len)
2344 {
2345 *__addr_len = sizeof (struct sockaddr_in);
2346 }
2347 break;
2348
2349 case VPPCOM_IS_IP6:
2350 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2351 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2352 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2353 __in6_u.__u6_addr8, addr8,
2354 sizeof (struct in6_addr));
2355 /* TBD: populate __addr_len */
2356 if (__addr_len)
2357 {
2358 *__addr_len = sizeof (struct sockaddr_in6);
2359 }
2360 break;
2361
2362 default:
2363 return -EAFNOSUPPORT;
2364 }
2365 }
2366 }
2367 else
2368 {
2369 /* when __addr is NULL, nothing is filled in,
2370 * in this case, __addr_len is not used,
2371 * and should also be null
2372 * */
2373 if (__addr_len)
2374 {
2375 /* TBD: return proper error code */
2376 return -1;
2377 }
2378 }
2379 }
2380
2381 return rv;
2382}
2383
2384int
2385vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2386 socklen_t * __restrict __addr_len)
2387{
2388 /* set flags to 0 for accept() */
2389 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2390}
2391
2392#ifdef __USE_GNU
2393int
2394vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2395 socklen_t * __restrict __addr_len, int __flags)
2396{
2397 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2398 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2399}
2400#endif
2401
2402/* TBD: move it to vppcom */
2403int
2404vppcom_session_shutdown (int __fd, int __how)
2405{
2406 return 0;
2407}
2408
2409int
2410vcom_socket_shutdown (int __fd, int __how)
2411{
2412 int rv = -1;
2413 vcom_socket_main_t *vsm = &vcom_socket_main;
2414 uword *p;
2415 vcom_socket_t *vsock;
2416
2417 p = hash_get (vsm->sockidx_by_fd, __fd);
2418 if (p)
2419 {
2420 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2421 switch (__how)
2422 {
2423 case SHUT_RD:
2424 case SHUT_WR:
2425 case SHUT_RDWR:
2426 rv = vppcom_session_shutdown (vsock->sid, __how);
2427 return rv;
2428 break;
2429
2430 default:
2431 return -EINVAL;
2432 break;
2433 }
2434 }
2435
2436 return rv;
2437}
2438
2439int
2440vcom_socket_epoll_create1 (int __flags)
2441{
2442 int rv = -1;
2443 vcom_socket_main_t *vsm = &vcom_socket_main;
2444 vcom_epoll_t *vepoll;
2445
2446 i32 epfd;
2447 i32 vep_idx;
2448 i32 epollidx;
2449
2450 epfd = vcom_socket_open_epoll (__flags);
2451 if (epfd < 0)
2452 {
2453 rv = epfd;
2454 goto out;
2455 }
2456
2457 vep_idx = vppcom_epoll_create ();
2458 if (vep_idx < 0)
2459 {
2460 rv = vep_idx;
2461 goto out_close_epoll;
2462 }
2463
2464 pool_get (vsm->vepolls, vepoll);
2465 vepoll_init (vepoll);
2466
2467 epollidx = vepoll - vsm->vepolls;
2468 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2469
2470 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2471
2472 return epfd;
2473
2474out_close_epoll:
2475 vcom_socket_close_epoll (epfd);
2476out:
2477 return rv;
2478}
2479
2480/*
2481 * PRE: vppcom_epoll_ctl() is successful
2482 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2483 */
2484int
2485vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2486 struct epoll_event *__event,
2487 i32 vep_idx, vcom_epoll_t * vepoll,
2488 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2489 int free_vepitem_on_del)
2490{
2491 int rv = -1;
2492 vcom_socket_main_t *vsm = &vcom_socket_main;
2493 vcom_epitem_t *vepitem;
2494
2495 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2496 uword *p;
2497 i32 vepitemidx;
2498
2499 i32 *vepitemidxs = 0;
2500
2501 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2502
2503 i32 vec_idx;
2504
2505 /* perform control operations on the epoll instance */
2506 switch (__op)
2507 {
2508 case EPOLL_CTL_ADD:
2509 /*
2510 * supplied file descriptor is already
2511 * registered with this epoll instance
2512 * */
2513 /* vepitem exists */
2514 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2515 if (p)
2516 {
2517 rv = -EEXIST;
2518 goto out;
2519 }
2520
2521 /* add a new vepitem */
2522 pool_get (vsm->vepitems, vepitem);
2523 vepitem_init (vepitem);
2524
2525 vepitemidx = vepitem - vsm->vepitems;
2526 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2527 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2528
2529 /* update epitemidxs */
2530 /* by_epfd */
2531 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2532 if (!p) /* not exist */
2533 {
2534 vepitemidxs = 0;
2535 vec_add1 (vepitemidxs, vepitemidx);
2536 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2537 }
2538 else /* exists */
2539 {
2540 vepitemidxs = *(i32 **) p;
2541 vec_add1 (vepitemidxs, vepitemidx);
2542 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2543 }
2544 /* update epitemidxs */
2545 /* by_fd */
2546 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2547 if (!p) /* not exist */
2548 {
2549 vepitemidxs = 0;
2550 vec_add1 (vepitemidxs, vepitemidx);
2551 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2552 }
2553 else /* exists */
2554 {
2555 vepitemidxs = *(i32 **) p;
2556 vec_add1 (vepitemidxs, vepitemidx);
2557 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2558 }
2559
2560 /* increment vepoll fd count by 1 */
2561 vepoll->count += 1;
2562
2563 rv = 0;
2564 goto out;
2565 break;
2566
2567 case EPOLL_CTL_MOD:
2568 /*
2569 * supplied file descriptor is not
2570 * registered with this epoll instance
2571 * */
2572 /* vepitem not exist */
2573 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2574 if (!p)
2575 {
2576 rv = -ENOENT;
2577 goto out;
2578 }
2579 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2580 if (vepitem)
2581 {
2582 vepitem->event = *__event;
2583 vepitem->revent = revent;
2584 }
2585
2586 rv = 0;
2587 goto out;
2588 break;
2589
2590 case EPOLL_CTL_DEL:
2591 /*
2592 * supplied file descriptor is not
2593 * registered with this epoll instance
2594 * */
2595 /* vepitem not exist */
2596 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2597 if (!p)
2598 {
2599 rv = -ENOENT;
2600 goto out;
2601 }
2602 vepitemidx = *(i32 *) p;
2603 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2604
2605 /* update epitemidxs */
2606 /* by_epfd */
2607 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2608 if (!p) /* not exist */
2609 {
2610 rv = -ENOENT;
2611 goto out;
2612 }
2613 else /* exists */
2614 {
2615 vepitemidxs = *(i32 **) p;
2616 vec_idx = vec_search (vepitemidxs, vepitemidx);
2617 if (vec_idx != ~0)
2618 {
2619 vec_del1 (vepitemidxs, vec_idx);
2620 if (!vec_len (vepitemidxs))
2621 {
2622 vec_free (vepitemidxs);
2623 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2624 }
2625 }
2626 }
2627
2628 /* update epitemidxs */
2629 /* by_fd */
2630 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2631 if (!p) /* not exist */
2632 {
2633 rv = -ENOENT;
2634 goto out;
2635 }
2636 else /* exists */
2637 {
2638 vepitemidxs = *(i32 **) p;
2639 vec_idx = vec_search (vepitemidxs, vepitemidx);
2640 if (vec_idx != ~0)
2641 {
2642 vec_del1 (vepitemidxs, vec_idx);
2643 if (!vec_len (vepitemidxs))
2644 {
2645 vec_free (vepitemidxs);
2646 hash_unset (vsm->epitemidxs_by_fd, __fd);
2647 }
2648 }
2649 }
2650
2651 /* pool put vepitem */
2652 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2653 if (free_vepitem_on_del)
2654 {
2655 if (!vepitem)
2656 {
2657 rv = -ENOENT;
2658 goto out;
2659 }
2660 vepitem_init (vepitem);
2661 pool_put (vsm->vepitems, vepitem);
2662 }
2663 else
2664 {
2665 if (!vepitem)
2666 {
2667 vepitem_init (vepitem);
2668 }
2669 }
2670
2671 /* decrement vepoll fd count by 1 */
2672 vepoll->count -= 1;
2673
2674 rv = 0;
2675 goto out;
2676 break;
2677
2678 default:
2679 rv = -EINVAL;
2680 goto out;
2681 break;
2682 }
2683
2684out:
2685 return rv;
2686}
2687
2688/*
2689 * PRE: 00. null pointer check on __event
2690 * 01. all other parameters are validated
2691 */
2692
2693static int
2694vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2695 struct epoll_event *__event,
2696 int free_vepitem_on_del)
2697{
2698 int rv = -1;
2699
2700 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2701 vcom_epoll_t *vepoll;
2702
2703 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2704 void *vfd;
2705 vcom_epoll_t *vfd_vepoll;
2706 vcom_socket_t *vfd_vsock;
2707
2708 i32 vep_idx;
2709 i32 vfd_id;
2710
2711 vcom_fd_type_t type = FD_TYPE_INVALID;
2712
2713 /* validate __event */
2714
2715 /* get vep_idx and vepoll */
2716 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2717 if (vep_idx == INVALID_VEP_IDX)
2718 {
2719 return -EBADF;
2720 }
2721
2722 /* get vcom fd type, vfd_id and vfd */
2723 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2724 if (vfd_id != INVALID_SESSION_ID)
2725 {
2726 type = FD_TYPE_VCOM_SOCKET;
2727 vfd = vfd_vsock;
2728 }
2729 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2730 != INVALID_VEP_IDX)
2731 {
2732 type = FD_TYPE_EPOLL;
2733 vfd = vfd_vepoll;
2734 }
2735 else
2736 {
2737 /* FD_TYPE_KERNEL not supported by epoll instance */
2738 type = FD_TYPE_INVALID;
2739 return -EBADF;
2740 }
2741
2742
2743 /* vepoll and vsock are now valid */
2744 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2745 if (rv < 0)
2746 {
2747 return rv;
2748 }
2749
2750 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2751 __event,
2752 vep_idx, vepoll,
2753 vfd_id, vfd, type, free_vepitem_on_del);
2754 return rv;
2755}
2756
2757int
2758vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2759 struct epoll_event *__event)
2760{
2761 int rv = -1;
2762
2763 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2764 return rv;
2765}
2766
2767static int
2768vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2769 struct epoll_event *__event)
2770{
2771 int rv = -1;
2772
2773 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2774 return rv;
2775}
2776
2777int
2778vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2779 int __maxevents, int __timeout,
2780 const __sigset_t * __ss)
2781{
2782 int rv = -EBADF;
2783
2784 /* in seconds eg. 3.123456789 seconds */
2785 double time_to_wait = (double) 0;
2786
2787 i32 vep_idx;
2788
2789 /* validate __event */
2790 if (!__events)
2791 {
2792 rv = -EFAULT;
2793 goto out;
2794 }
2795
2796 /* validate __timeout */
2797 if (__timeout > 0)
2798 {
2799 time_to_wait = (double) __timeout / (double) 1000;
2800 }
2801 else if (__timeout == 0)
2802 {
2803 time_to_wait = (double) 0;
2804 }
2805 else if (__timeout == -1)
2806 {
2807 time_to_wait = ~0;
2808 }
2809 else
2810 {
2811 rv = -EBADF;
2812 goto out;
2813 }
2814
2815 /* get vep_idx */
2816 vep_idx = vcom_socket_get_vep_idx (__epfd);
2817 if (vep_idx != INVALID_VEP_IDX)
2818 {
2819 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2820 }
2821out:
2822 return rv;
2823}
2824
2825int
2826vcom_socket_main_init (void)
2827{
2828 vcom_socket_main_t *vsm = &vcom_socket_main;
2829
2830 if (VCOM_DEBUG > 0)
2831 printf ("vcom_socket_main_init\n");
2832
2833 if (!vsm->init)
2834 {
2835 /* TBD: define FD_MAXSIZE and use it here */
2836 pool_alloc (vsm->vsockets, FD_SETSIZE);
2837 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
2838
2839 pool_alloc (vsm->vepolls, FD_SETSIZE);
2840 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
2841
2842 pool_alloc (vsm->vepitems, FD_SETSIZE);
2843 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
2844
2845 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
2846 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
2847
2848 vsm->init = 1;
2849 }
2850
2851 return 0;
2852}
2853
2854
2855void
2856vcom_socket_main_show (void)
2857{
2858 vcom_socket_main_t *vsm = &vcom_socket_main;
2859 vcom_socket_t *vsock;
2860
2861 vcom_epoll_t *vepoll;
2862
2863 vcom_epitem_t *vepitem;
2864
2865 i32 epfd;
2866 i32 fd;
2867 i32 *vepitemidxs, *vepitemidxs_var;
2868
2869 if (vsm->init)
2870 {
2871 /* from active list of vsockets show vsock */
2872
2873 /* *INDENT-OFF* */
2874 pool_foreach (vsock, vsm->vsockets,
2875 ({
2876 printf(
2877 "fd='%04d', sid='%08x',type='%-30s'\n",
2878 vsock->fd, vsock->sid,
2879 vcom_socket_type_str (vsock->type));
2880 }));
2881 /* *INDENT-ON* */
2882
2883 /* from active list of vepolls, show vepoll */
2884
2885 /* *INDENT-OFF* */
2886 pool_foreach (vepoll, vsm->vepolls,
2887 ({
2888 printf(
2889 "epfd='%04d', vep_idx='%08x', "
2890 "type='%-30s', "
2891 "flags='%d', count='%d', close='%d'\n",
2892 vepoll->epfd, vepoll->vep_idx,
2893 vcom_socket_epoll_type_str (vepoll->type),
2894 vepoll->flags, vepoll->count, vepoll->close);
2895 }));
2896 /* *INDENT-ON* */
2897
2898 /* from active list of vepitems, show vepitem */
2899
2900 /* *INDENT-OFF* */
2901 pool_foreach (vepitem, vsm->vepitems,
2902 ({
2903 printf(
2904 "epfd='%04d', fd='%04d', "
2905 "next_fd='%04d', prev_fd='%04d', "
2906 "type='%-30s', "
2907 "events='%04x', revents='%04x'\n",
2908 vepitem->epfd, vepitem->fd,
2909 vepitem->next_fd, vepitem->prev_fd,
2910 vcom_socket_vcom_fd_type_str (vepitem->type),
2911 vepitem->event.events, vepitem->revent.events);
2912 }));
2913
2914 /* *INDENT-ON* */
2915
2916 /* show epitemidxs for epfd */
2917 /* *INDENT-OFF* */
2918 hash_foreach (epfd, vepitemidxs,
2919 vsm->epitemidxs_by_epfd,
2920 ({
2921 printf("\n[ '%04d': ", epfd);
2922 vec_foreach (vepitemidxs_var,vepitemidxs)
2923 {
2924 printf("'%04d' ", (int)vepitemidxs_var[0]);
2925 }
2926 printf("]\n");
2927 }));
2928 /* *INDENT-ON* */
2929
2930 /* show epitemidxs for fd */
2931 /* *INDENT-OFF* */
2932 hash_foreach (fd, vepitemidxs,
2933 vsm->epitemidxs_by_fd,
2934 ({
2935 printf("\n{ '%04d': ", fd);
2936 vec_foreach (vepitemidxs_var,vepitemidxs)
2937 {
2938 printf("'%04d' ", (int)vepitemidxs_var[0]);
2939 }
2940 printf("}\n");
2941 }));
2942 /* *INDENT-ON* */
2943
2944 }
2945}
2946
2947void
2948vcom_socket_main_destroy (void)
2949{
2950 vcom_socket_main_t *vsm = &vcom_socket_main;
2951 vcom_socket_t *vsock;
2952
2953 vcom_epoll_t *vepoll;
2954
2955 vcom_epitem_t *vepitem;
2956
2957 i32 epfd;
2958 i32 fd;
2959 i32 *vepitemidxs;
2960
2961
2962 if (VCOM_DEBUG > 0)
2963 printf ("vcom_socket_main_destroy\n");
2964
2965 if (vsm->init)
2966 {
2967
2968 /*
2969 * from active list of vepitems,
2970 * remove all "vepitem" elements from the pool in a safe way
2971 * */
2972
2973 /* *INDENT-OFF* */
2974 pool_flush (vepitem, vsm->vepitems,
2975 ({
2976 if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
2977 {
2978 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
2979 vepitem->fd, NULL);
2980 vepitem_init (vepitem);
2981 }
2982 }));
2983 /* *INDENT-ON* */
2984
2985 pool_free (vsm->vepitems);
2986 hash_free (vsm->epitemidx_by_epfdfd);
2987
2988 /* free vepitemidxs for each epfd */
2989 /* *INDENT-OFF* */
2990 hash_foreach (epfd, vepitemidxs,
2991 vsm->epitemidxs_by_epfd,
2992 ({
2993 vec_free (vepitemidxs);
2994 }));
2995 /* *INDENT-ON* */
2996 hash_free (vsm->epitemidxs_by_epfd);
2997
2998 /* free vepitemidxs for each fd */
2999 /* *INDENT-OFF* */
3000 hash_foreach (fd, vepitemidxs,
3001 vsm->epitemidxs_by_fd,
3002 ({
3003 vec_free (vepitemidxs);
3004 }));
3005 /* *INDENT-ON* */
3006 hash_free (vsm->epitemidxs_by_fd);
3007
3008
3009 /*
3010 * from active list of vsockets,
3011 * close socket and vppcom session
3012 * */
3013
3014 /* *INDENT-OFF* */
3015 pool_foreach (vsock, vsm->vsockets,
3016 ({
3017 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3018 {
3019 vppcom_session_close (vsock->sid);
3020 vcom_socket_close_socket (vsock->fd);
3021 vsocket_init (vsock);
3022 }
3023 }));
3024 /* *INDENT-ON* */
3025
3026 /*
3027 * return vsocket element to the pool
3028 * */
3029
3030 /* *INDENT-OFF* */
3031 pool_flush (vsock, vsm->vsockets,
3032 ({
3033 // vsocket_init(vsock);
3034 ;
3035 }));
3036 /* *INDENT-ON* */
3037
3038 pool_free (vsm->vsockets);
3039 hash_free (vsm->sockidx_by_fd);
3040
3041 /*
3042 * from active list of vepolls,
3043 * close epoll and vppcom_epoll
3044 * */
3045
3046 /* *INDENT-OFF* */
3047 pool_foreach (vepoll, vsm->vepolls,
3048 ({
3049 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3050 {
3051 vppcom_session_close (vepoll->vep_idx);
3052 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3053 vepoll_init (vepoll);
3054 }
3055 }));
3056 /* *INDENT-ON* */
3057
3058 /*
3059 * return vepoll element to the pool
3060 * */
3061
3062 /* *INDENT-OFF* */
3063 pool_flush (vepoll, vsm->vepolls,
3064 ({
3065 // vepoll_init(vepoll);
3066 ;
3067 }));
3068 /* *INDENT-ON* */
3069
3070 pool_free (vsm->vepolls);
3071 hash_free (vsm->epollidx_by_epfd);
3072
3073 vsm->init = 0;
3074 }
3075}
3076
3077
3078/*
3079 * fd.io coding-style-patch-verification: ON
3080 *
3081 * Local Variables:
3082 * eval: (c-set-style "gnu")
3083 * End:
3084 */