blob: 4a5f28574edf91191fbc01ab076320b6ec47a972 [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);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001259 return rv;
1260}
1261
1262int
1263vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1264{
Steven2199aab2017-10-15 20:18:47 -07001265 int rv;
1266 uint32_t size = sizeof (*ep);
1267
1268 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1269 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001270}
1271
1272int
1273vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1274 socklen_t * __restrict __len)
1275{
1276 int rv = -1;
1277 vcom_socket_main_t *vsm = &vcom_socket_main;
1278 uword *p;
1279 vcom_socket_t *vsock;
1280
1281
1282 p = hash_get (vsm->sockidx_by_fd, __fd);
1283 if (!p)
1284 return -EBADF;
1285
1286 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1287 if (!vsock)
1288 return -ENOTSOCK;
1289
1290 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1291 return -EINVAL;
1292
1293 if (!__addr || !__len)
1294 return -EFAULT;
1295
1296 if (*__len < 0)
1297 {
1298 return -EINVAL;
1299 }
1300
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001301 vppcom_endpt_t ep;
1302 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1303 rv = vppcom_session_getsockname (vsock->sid, &ep);
1304 if (rv == 0)
1305 {
1306 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1307 {
1308 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1309 switch (__addr->sa_family)
1310 {
1311 case AF_INET:
1312 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1313 *__len = sizeof (struct sockaddr_in);
1314 break;
1315
1316 case AF_INET6:
1317 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1318 *__len = sizeof (struct sockaddr_in6);
1319 break;
1320
1321 default:
1322 break;
1323 }
1324 }
1325 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001326
1327 return rv;
1328}
1329
1330int
1331vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1332{
1333 int rv = -1;
1334 vcom_socket_main_t *vsm = &vcom_socket_main;
1335 uword *p;
1336 vcom_socket_t *vsock;
1337
1338 vppcom_endpt_t ep;
1339
1340 p = hash_get (vsm->sockidx_by_fd, __fd);
1341 if (p)
1342 {
1343 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1344
1345 ep.vrf = VPPCOM_VRF_DEFAULT;
1346 switch (__addr->sa_family)
1347 {
1348 case AF_INET:
1349 ep.is_ip4 = VPPCOM_IS_IP4;
1350 ep.ip =
1351 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1352 ep.port =
1353 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1354 break;
1355
1356 case AF_INET6:
1357 ep.is_ip4 = VPPCOM_IS_IP6;
1358 ep.ip =
1359 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1360 ep.port =
1361 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1362 break;
1363
1364 default:
1365 return -1;
1366 break;
1367 }
1368
1369 rv = vppcom_session_connect (vsock->sid, &ep);
1370 }
1371 return rv;
1372}
1373
1374int
1375vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1376{
Steven2199aab2017-10-15 20:18:47 -07001377 int rv;
1378 uint32_t size = sizeof (*ep);
1379
1380 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1381 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001382}
1383
1384int
1385vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1386 socklen_t * __restrict __len)
1387{
1388 int rv = -1;
1389 vcom_socket_main_t *vsm = &vcom_socket_main;
1390 uword *p;
1391 vcom_socket_t *vsock;
1392
1393
1394 p = hash_get (vsm->sockidx_by_fd, __fd);
1395 if (!p)
1396 return -EBADF;
1397
1398 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1399 if (!vsock)
1400 return -ENOTSOCK;
1401
1402 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1403 return -EINVAL;
1404
1405 if (!__addr || !__len)
1406 return -EFAULT;
1407
1408 if (*__len < 0)
1409 {
1410 return -EINVAL;
1411 }
1412
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001413 vppcom_endpt_t ep;
1414 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1415 rv = vppcom_session_getpeername (vsock->sid, &ep);
1416 if (rv == 0)
1417 {
1418 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1419 {
1420 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1421 switch (__addr->sa_family)
1422 {
1423 case AF_INET:
1424 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1425 *__len = sizeof (struct sockaddr_in);
1426 break;
1427
1428 case AF_INET6:
1429 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1430 *__len = sizeof (struct sockaddr_in6);
1431 break;
1432
1433 default:
1434 break;
1435 }
1436 }
1437 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001438
1439 return rv;
1440}
1441
1442ssize_t
1443vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1444{
1445 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1446}
1447
1448ssize_t
1449vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1450{
1451 int rv = -1;
1452 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1453 return rv;
1454}
1455
1456/*
1457 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1458 * 0 otherwise
1459 * */
1460int
1461vcom_socket_is_connection_mode_socket (int __fd)
1462{
1463 int rv = -1;
1464 /* TBD define new vppcom api */
1465 vcom_socket_main_t *vsm = &vcom_socket_main;
1466 uword *p;
1467 vcom_socket_t *vsock;
1468
1469 int type;
1470 socklen_t optlen;
1471
1472 p = hash_get (vsm->sockidx_by_fd, __fd);
1473
1474 if (p)
1475 {
1476 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1477 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1478 {
1479 optlen = sizeof (type);
1480 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1481 if (rv != 0)
1482 {
1483 return 0;
1484 }
1485 /* get socket type */
1486 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1487 {
1488 case SOCK_STREAM:
1489 case SOCK_SEQPACKET:
1490 return 1;
1491 break;
1492
1493 default:
1494 return 0;
1495 break;
1496 }
1497 }
1498 }
1499 return 0;
1500}
1501
1502ssize_t
1503vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1504 int __flags, __CONST_SOCKADDR_ARG __addr,
1505 socklen_t __addr_len)
1506{
1507 int rv = -1;
1508 /* TBD add new vpp api */
1509 /* TBD add flags parameter */
1510 rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1511 return rv;
1512}
1513
1514ssize_t
1515vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1516 int __flags, __CONST_SOCKADDR_ARG __addr,
1517 socklen_t __addr_len)
1518{
1519 int rv = -1;
1520 vcom_socket_main_t *vsm = &vcom_socket_main;
1521 uword *p;
1522 vcom_socket_t *vsock;
1523
1524 p = hash_get (vsm->sockidx_by_fd, __fd);
1525 if (!p)
1526 return -EBADF;
1527
1528 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1529 if (!vsock)
1530 return -ENOTSOCK;
1531
1532 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1533 return -EINVAL;
1534
1535 if (!__buf || __n < 0)
1536 {
1537 return -EINVAL;
1538 }
1539
1540 if (vcom_socket_is_connection_mode_socket (__fd))
1541 {
1542 /* ignore __addr and _addr_len */
1543 /* and EISCONN may be returned when they are not NULL and 0 */
1544 if ((__addr != NULL) || (__addr_len != 0))
1545 {
1546 return -EISCONN;
1547 }
1548 }
1549 else
1550 {
1551 if (!__addr || __addr_len < 0)
1552 {
1553 return -EDESTADDRREQ;
1554 }
1555 /* not a vppcom supported address family */
1556 if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1557 {
1558 return -EINVAL;
1559 }
1560 }
1561
1562 rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1563 __flags, __addr, __addr_len);
1564 return rv;
1565}
1566
1567/* TBD: move it to vppcom */
1568static ssize_t
1569vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1570 int __flags, __SOCKADDR_ARG __addr,
1571 socklen_t * __restrict __addr_len)
1572{
1573 int rv = -1;
1574
1575 /* TBD add flags parameter */
1576 rv = vppcom_session_read (__sid, __buf, __n);
1577 return rv;
1578}
1579
1580ssize_t
1581vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1582 int __flags, __SOCKADDR_ARG __addr,
1583 socklen_t * __restrict __addr_len)
1584{
1585 int rv = -1;
1586 vcom_socket_main_t *vsm = &vcom_socket_main;
1587 uword *p;
1588 vcom_socket_t *vsock;
1589
1590 p = hash_get (vsm->sockidx_by_fd, __fd);
1591 if (!p)
1592 return -EBADF;
1593
1594 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1595 if (!vsock)
1596 return -ENOTSOCK;
1597
1598 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1599 return -EINVAL;
1600
1601 if (!__buf || __n < 0)
1602 {
1603 return -EINVAL;
1604 }
1605
1606 if (__addr || __addr_len < 0)
1607 {
1608 return -EINVAL;
1609 }
1610
1611 rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1612 __flags, __addr, __addr_len);
1613 return rv;
1614}
1615
1616/* TBD: move it to vppcom */
1617static ssize_t
1618vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1619{
1620 int rv = -1;
1621 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1622 (int)__n); */
1623 return rv;
1624}
1625
1626ssize_t
1627vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
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 (vcom_socket_is_connection_mode_socket (__fd))
1643 {
1644 /* ignore __addr and _addr_len */
1645 /* and EISCONN may be returned when they are not NULL and 0 */
1646 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1647 {
1648 return -EISCONN;
1649 }
1650 }
1651 else
1652 {
1653 /* TBD: validate __message->msg_name and __message->msg_namelen
1654 * and return -EINVAL on validation error
1655 * */
1656 ;
1657 }
1658
1659 rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1660
1661 return rv;
1662}
1663
1664#ifdef __USE_GNU
1665int
1666vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1667 unsigned int __vlen, int __flags)
1668{
1669
1670 /* TBD: define a new vppcom api */
1671 return 0;
1672}
1673#endif
1674
1675/* TBD: move it to vppcom */
1676static ssize_t
1677vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1678{
1679 int rv = -1;
1680 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1681 (int)__n); */
1682 rv = -EOPNOTSUPP;
1683 return rv;
1684}
1685
1686ssize_t
1687vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1688{
1689 int rv = -1;
1690 vcom_socket_main_t *vsm = &vcom_socket_main;
1691 uword *p;
1692 vcom_socket_t *vsock;
1693
1694 p = hash_get (vsm->sockidx_by_fd, __fd);
1695 if (!p)
1696 return -EBADF;
1697
1698 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1699 if (!vsock)
1700 return -ENOTSOCK;
1701
1702 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1703 return -EINVAL;
1704
1705 if (!__message)
1706 {
1707 return -EINVAL;
1708 }
1709
1710 /* validate __flags */
1711
1712 rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1713 return rv;
1714}
1715
1716#ifdef __USE_GNU
1717int
1718vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1719 unsigned int __vlen, int __flags,
1720 struct timespec *__tmo)
1721{
1722 /* TBD: define a new vppcom api */
1723 return 0;
1724}
1725#endif
1726
1727/* TBD: move it to vppcom */
1728static int
1729vppcom_getsockopt (int __sid, int __level, int __optname,
1730 void *__restrict __optval, socklen_t * __restrict __optlen)
1731{
1732 /* 1. for socket level options that are NOT socket attributes
1733 * and that has corresponding vpp options get from vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001734 return 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001735}
1736
1737int
1738vcom_socket_getsockopt (int __fd, int __level, int __optname,
1739 void *__restrict __optval,
1740 socklen_t * __restrict __optlen)
1741{
1742 int rv = -1;
1743 vcom_socket_main_t *vsm = &vcom_socket_main;
1744 uword *p;
1745 vcom_socket_t *vsock;
1746
1747 p = hash_get (vsm->sockidx_by_fd, __fd);
1748 if (!p)
1749 return -EBADF;
1750
1751 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1752 if (!vsock)
1753 return -ENOTSOCK;
1754
1755 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1756 return -EINVAL;
1757
1758 if (!__optval && !__optlen)
1759 return -EFAULT;
1760
1761 if (*__optlen < 0)
1762 {
1763 return -EINVAL;
1764 }
1765
1766 switch (__level)
1767 {
1768 /* handle options at socket level */
1769 case SOL_SOCKET:
1770 switch (__optname)
1771 {
1772/*
1773 * 1. for socket level options that are socket attributes,
1774 * get from libc_getsockopt.
1775 * 2. for socket level options that are NOT socket
1776 * attributes and that has corresponding vpp options
1777 * get from vppcom.
1778 * 3. for socket level options unimplemented
1779 * return -ENOPROTOOPT */
1780 case SO_DEBUG:
1781 case SO_DONTROUTE:
1782 case SO_BROADCAST:
1783 case SO_SNDBUF:
1784 case SO_RCVBUF:
1785 case SO_REUSEADDR:
1786 case SO_REUSEPORT:
1787 case SO_KEEPALIVE:
1788 case SO_TYPE:
1789 case SO_PROTOCOL:
1790 case SO_DOMAIN:
1791 case SO_ERROR:
1792 case SO_OOBINLINE:
1793 case SO_NO_CHECK:
1794 case SO_PRIORITY:
1795 case SO_LINGER:
1796 case SO_BSDCOMPAT:
1797 case SO_TIMESTAMP:
1798 case SO_TIMESTAMPNS:
1799 case SO_TIMESTAMPING:
1800 case SO_RCVTIMEO:
1801 case SO_SNDTIMEO:
1802 case SO_RCVLOWAT:
1803 case SO_SNDLOWAT:
1804 case SO_PASSCRED:
1805 case SO_PEERCRED:
1806 case SO_PEERNAME:
1807 case SO_ACCEPTCONN:
1808 case SO_PASSSEC:
1809 case SO_PEERSEC:
1810 case SO_MARK:
1811 case SO_RXQ_OVFL:
1812 case SO_WIFI_STATUS:
1813 case SO_PEEK_OFF:
1814 case SO_NOFCS:
1815 case SO_BINDTODEVICE:
1816 case SO_GET_FILTER:
1817 case SO_LOCK_FILTER:
1818 case SO_BPF_EXTENSIONS:
1819 case SO_SELECT_ERR_QUEUE:
1820#ifdef CONFIG_NET_RX_BUSY_POLL
1821 case SO_BUSY_POLL:
1822#endif
1823 case SO_MAX_PACING_RATE:
1824 case SO_INCOMING_CPU:
1825 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1826 if (rv != 0)
1827 {
1828 rv = -errno;
1829 return rv;
1830 }
1831 break;
1832
1833 default:
1834 /* We implement the SO_SNDLOWAT etc to not be settable
1835 * (1003.1g 7).
1836 */
1837 return -ENOPROTOOPT;
1838 }
1839
1840 break;
1841
1842 default:
1843 /* 1. handle options that are NOT socket level options,
1844 * but have corresponding vpp otions. */
1845 rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1846 __optval, __optlen);
1847
1848 return rv;
1849#if 0
1850 /* 2. unhandled options */
1851 return -ENOPROTOOPT;
1852#endif
1853 }
1854
1855 return rv;
1856}
1857
1858/* TBD: move it to vppcom */
1859int
Stevenb59f2272017-10-12 17:10:33 -07001860vppcom_session_setsockopt (int __sid, int __level, int __optname,
1861 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001862{
Stevenb59f2272017-10-12 17:10:33 -07001863 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001864
Stevenb59f2272017-10-12 17:10:33 -07001865 switch (__level)
1866 {
Stevenbd187a82017-10-13 12:52:28 -07001867 case SOL_TCP:
1868 switch (__optname)
1869 {
1870 case TCP_KEEPIDLE:
1871 rv =
1872 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1873 break;
1874 case TCP_KEEPINTVL:
1875 rv =
1876 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1877 break;
1878 default:
1879 break;
1880 }
1881 break;
Stevenb59f2272017-10-12 17:10:33 -07001882 case SOL_IPV6:
1883 switch (__optname)
1884 {
1885 case IPV6_V6ONLY:
1886 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001887 break;
Stevenb59f2272017-10-12 17:10:33 -07001888 default:
Stevenbd187a82017-10-13 12:52:28 -07001889 break;
Stevenb59f2272017-10-12 17:10:33 -07001890 }
1891 break;
1892 case SOL_SOCKET:
1893 switch (__optname)
1894 {
Stevenbd187a82017-10-13 12:52:28 -07001895 case SO_KEEPALIVE:
1896 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1897 break;
Stevenb59f2272017-10-12 17:10:33 -07001898 case SO_REUSEADDR:
1899 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001900 break;
Stevenb59f2272017-10-12 17:10:33 -07001901 case SO_BROADCAST:
1902 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001903 break;
Stevenb59f2272017-10-12 17:10:33 -07001904 default:
Stevenbd187a82017-10-13 12:52:28 -07001905 break;
Stevenb59f2272017-10-12 17:10:33 -07001906 }
1907 break;
1908 default:
Stevenbd187a82017-10-13 12:52:28 -07001909 break;
Stevenb59f2272017-10-12 17:10:33 -07001910 }
1911
1912 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001913}
1914
1915int
1916vcom_socket_setsockopt (int __fd, int __level, int __optname,
1917 const void *__optval, socklen_t __optlen)
1918{
1919 int rv = -1;
1920 vcom_socket_main_t *vsm = &vcom_socket_main;
1921 uword *p;
1922 vcom_socket_t *vsock;
1923
1924 p = hash_get (vsm->sockidx_by_fd, __fd);
1925 if (!p)
1926 return -EBADF;
1927
1928 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1929 if (!vsock)
1930 return -ENOTSOCK;
1931
1932 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1933 return -EINVAL;
1934
1935 /*
1936 * Options without arguments
1937 */
1938
1939 if (__optname == SO_BINDTODEVICE)
1940 {
1941 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1942 if (rv != 0)
1943 {
1944 rv = -errno;
1945 }
1946 return rv;
1947 }
1948
1949 if (!__optval)
1950 return -EFAULT;
1951
1952 if ((__optlen < 0) || (__optlen < sizeof (int)))
1953 return -EINVAL;
1954
1955 switch (__level)
1956 {
Stevenb59f2272017-10-12 17:10:33 -07001957 case SOL_IPV6:
1958 switch (__optname)
1959 {
1960 case IPV6_V6ONLY:
1961 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
1962 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001963 break;
Stevenb59f2272017-10-12 17:10:33 -07001964 default:
1965 return -EOPNOTSUPP;
1966 }
1967 break;
1968 case SOL_TCP:
1969 switch (__optname)
1970 {
1971 case TCP_NODELAY:
1972 return 0;
Stevenbd187a82017-10-13 12:52:28 -07001973 case TCP_KEEPIDLE:
1974 case TCP_KEEPINTVL:
1975 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
1976 __optval, __optlen);
1977 break;
Stevenb59f2272017-10-12 17:10:33 -07001978 default:
1979 return -EOPNOTSUPP;
1980 }
1981 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001982 /* handle options at socket level */
1983 case SOL_SOCKET:
1984 switch (__optname)
1985 {
Stevenb59f2272017-10-12 17:10:33 -07001986 case SO_REUSEADDR:
1987 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07001988 case SO_KEEPALIVE:
Stevenb59f2272017-10-12 17:10:33 -07001989 rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
1990 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001991 break;
Stevenb59f2272017-10-12 17:10:33 -07001992
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001993 /*
1994 * 1. for socket level options that are socket attributes,
1995 * set it from libc_getsockopt
1996 * 2. for socket level options that are NOT socket
1997 * attributes and that has corresponding vpp options
1998 * set it from vppcom
1999 * 3. for socket level options unimplemented
2000 * return -ENOPROTOOPT */
2001 case SO_DEBUG:
2002 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002003 case SO_SNDBUF:
2004 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002005 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002006 case SO_TYPE:
2007 case SO_PROTOCOL:
2008 case SO_DOMAIN:
2009 case SO_ERROR:
2010 case SO_OOBINLINE:
2011 case SO_NO_CHECK:
2012 case SO_PRIORITY:
2013 case SO_LINGER:
2014 case SO_BSDCOMPAT:
2015 case SO_TIMESTAMP:
2016 case SO_TIMESTAMPNS:
2017 case SO_TIMESTAMPING:
2018 case SO_RCVTIMEO:
2019 case SO_SNDTIMEO:
2020 case SO_RCVLOWAT:
2021 case SO_SNDLOWAT:
2022 case SO_PASSCRED:
2023 case SO_PEERCRED:
2024 case SO_PEERNAME:
2025 case SO_ACCEPTCONN:
2026 case SO_PASSSEC:
2027 case SO_PEERSEC:
2028 case SO_MARK:
2029 case SO_RXQ_OVFL:
2030 case SO_WIFI_STATUS:
2031 case SO_PEEK_OFF:
2032 case SO_NOFCS:
2033 /*
2034 * SO_BINDTODEVICE already handled as
2035 * "Options without arguments" */
2036 /* case SO_BINDTODEVICE: */
2037 case SO_GET_FILTER:
2038 case SO_LOCK_FILTER:
2039 case SO_BPF_EXTENSIONS:
2040 case SO_SELECT_ERR_QUEUE:
2041#ifdef CONFIG_NET_RX_BUSY_POLL
2042 case SO_BUSY_POLL:
2043#endif
2044 case SO_MAX_PACING_RATE:
2045 case SO_INCOMING_CPU:
2046 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2047 if (rv != 0)
2048 {
2049 rv = -errno;
2050 return rv;
2051 }
2052 break;
2053
2054 default:
2055 /* We implement the SO_SNDLOWAT etc to not be settable
2056 * (1003.1g 7).
2057 */
2058 return -ENOPROTOOPT;
2059 }
2060
2061 break;
2062
2063 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002064 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002065 }
2066
2067 return rv;
2068}
2069
2070int
2071vcom_socket_listen (int __fd, int __n)
2072{
2073 int rv = -1;
2074 vcom_socket_main_t *vsm = &vcom_socket_main;
2075 uword *p;
2076 vcom_socket_t *vsock;
2077
2078 p = hash_get (vsm->sockidx_by_fd, __fd);
2079 if (p)
2080 {
2081 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2082
2083 /* TBD vppcom to accept __n parameter */
2084 rv = vppcom_session_listen (vsock->sid, __n);
2085 }
2086
2087 return rv;
2088}
2089
2090static int
2091vcom_socket_connected_socket (int __fd, int __sid,
2092 int *__domain,
2093 int *__type, int *__protocol, int flags)
2094{
2095 int rv = -1;
2096 vcom_socket_main_t *vsm = &vcom_socket_main;
2097 vcom_socket_t *vsock;
2098
2099 i32 fd;
2100 i32 sockidx;
2101
2102 socklen_t optlen;
2103
2104 optlen = sizeof (*__domain);
2105 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2106 if (rv != 0)
2107 {
2108 rv = -errno;
2109 goto out;
2110 }
2111
2112 optlen = sizeof (*__type);
2113 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2114 if (rv != 0)
2115 {
2116 rv = -errno;
2117 goto out;
2118 }
2119
2120 optlen = sizeof (*__protocol);
2121 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2122 if (rv != 0)
2123 {
2124 rv = -errno;
2125 goto out;
2126 }
2127
2128 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2129 if (fd < 0)
2130 {
2131 rv = fd;
2132 goto out;
2133 }
2134
2135 pool_get (vsm->vsockets, vsock);
2136 vsocket_init (vsock);
2137
2138 sockidx = vsock - vsm->vsockets;
2139 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2140
2141 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2142 return fd;
2143
2144out:
2145 return rv;
2146}
2147
2148/* If flag is 0, then accept4() is the same as accept().
2149 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2150 */
2151static int
2152vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2153 socklen_t * __restrict __addr_len, int flags)
2154{
2155 int rv = -1;
2156 vcom_socket_main_t *vsm = &vcom_socket_main;
2157 uword *p;
2158 vcom_socket_t *vsock;
2159
2160 int fd;
2161 int sid;
2162 int domain;
2163 int type;
2164 int protocol;
2165
2166 uint8_t addr8[sizeof (struct in6_addr)];
2167 vppcom_endpt_t ep;
2168
2169 ep.ip = addr8;
2170
2171 /* validate flags */
2172
2173 /*
2174 * for documentation
2175 * switch (flags)
2176 * {
2177 * case 0:
2178 * case SOCK_NONBLOCK:
2179 * case SOCK_CLOEXEC:
2180 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2181 * break;
2182 *
2183 * default:
2184 * return -1;
2185 * }
2186 */
2187 /* flags can be 0 or can be bitwise OR
2188 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2189
2190 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2191 {
2192 /* TBD: return proper error code */
2193 return -1;
2194 }
2195
2196 /* TBD: return proper error code */
2197
2198 if (!vcom_socket_is_connection_mode_socket (__fd))
2199 {
2200 return -EOPNOTSUPP;
2201 }
2202
2203 p = hash_get (vsm->sockidx_by_fd, __fd);
2204 if (p)
2205 {
2206 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2207
2208
2209 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2210 if (rv < 0)
2211 {
2212 return rv;
2213 }
2214
2215 /* is blocking */
2216 if (!(rv & O_NONBLOCK))
2217 {
2218 /* socket is not marked as nonblocking
2219 * and no pending connections are present
2220 * on the queue, accept () blocks the caller
2221 * until a connection is present.
2222 */
2223 rv = vppcom_session_accept (vsock->sid, &ep,
2224 -1.0 /* wait forever */ );
2225 }
2226 else
2227 {
2228 /* The file descriptor refers to a socket and has been
2229 * marked nonblocking(O_NONBLOCK) and the accept would
2230 * block.
2231 * */
2232 /* is non blocking */
2233 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2234 /* If the socket is marked nonblocking and
2235 * no pending connections are present on the
2236 * queue, accept fails with the error
2237 * EAGAIN or EWOULDBLOCK
2238 */
2239 if (rv == VPPCOM_ETIMEDOUT)
2240 {
2241 rv = VPPCOM_EAGAIN;
2242 }
2243 }
2244 if (rv < 0)
2245 {
2246 return rv;
2247 }
2248
2249 sid = rv;
2250
2251 /* create a new connected socket resource and set flags
2252 * on the new file descriptor.
2253 * update vsockets and sockidx_by_fd table
2254 * */
2255 fd = vcom_socket_connected_socket (__fd, sid,
2256 &domain, &type, &protocol, flags);
2257 if (fd < 0)
2258 {
2259 return fd;
2260 }
2261
2262 rv = fd;
2263
2264 /* TBD populate __addr and __addr_len */
2265 /* TBD: The returned address is truncated if the buffer
2266 * provided is too small, in this case, __addr_len will
2267 * return a value greater than was supplied to the call.*/
2268 if (__addr)
2269 {
2270 if (ep.is_cut_thru)
2271 {
2272 /* TBD populate __addr and __addr_len */
2273 switch (domain)
2274 {
2275 case AF_INET:
2276 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2277 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2278 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2279 addr8, sizeof (struct in_addr));
2280 /* TBD: populate __addr_len */
2281 if (__addr_len)
2282 {
2283 *__addr_len = sizeof (struct sockaddr_in);
2284 }
2285 break;
2286
2287 case AF_INET6:
2288 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2289 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2290 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2291 __in6_u.__u6_addr8, addr8,
2292 sizeof (struct in6_addr));
2293 /* TBD: populate __addr_len */
2294 if (__addr_len)
2295 {
2296 *__addr_len = sizeof (struct sockaddr_in6);
2297 }
2298 break;
2299
2300 default:
2301 return -EAFNOSUPPORT;
2302 }
2303 }
2304 else
2305 {
2306 switch (ep.is_ip4)
2307 {
2308 case VPPCOM_IS_IP4:
2309 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2310 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2311 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2312 addr8, sizeof (struct in_addr));
2313 /* TBD: populate __addr_len */
2314 if (__addr_len)
2315 {
2316 *__addr_len = sizeof (struct sockaddr_in);
2317 }
2318 break;
2319
2320 case VPPCOM_IS_IP6:
2321 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2322 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2323 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2324 __in6_u.__u6_addr8, addr8,
2325 sizeof (struct in6_addr));
2326 /* TBD: populate __addr_len */
2327 if (__addr_len)
2328 {
2329 *__addr_len = sizeof (struct sockaddr_in6);
2330 }
2331 break;
2332
2333 default:
2334 return -EAFNOSUPPORT;
2335 }
2336 }
2337 }
2338 else
2339 {
2340 /* when __addr is NULL, nothing is filled in,
2341 * in this case, __addr_len is not used,
2342 * and should also be null
2343 * */
2344 if (__addr_len)
2345 {
2346 /* TBD: return proper error code */
2347 return -1;
2348 }
2349 }
2350 }
2351
2352 return rv;
2353}
2354
2355int
2356vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2357 socklen_t * __restrict __addr_len)
2358{
2359 /* set flags to 0 for accept() */
2360 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2361}
2362
2363#ifdef __USE_GNU
2364int
2365vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2366 socklen_t * __restrict __addr_len, int __flags)
2367{
2368 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2369 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2370}
2371#endif
2372
2373/* TBD: move it to vppcom */
2374int
2375vppcom_session_shutdown (int __fd, int __how)
2376{
2377 return 0;
2378}
2379
2380int
2381vcom_socket_shutdown (int __fd, int __how)
2382{
2383 int rv = -1;
2384 vcom_socket_main_t *vsm = &vcom_socket_main;
2385 uword *p;
2386 vcom_socket_t *vsock;
2387
2388 p = hash_get (vsm->sockidx_by_fd, __fd);
2389 if (p)
2390 {
2391 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2392 switch (__how)
2393 {
2394 case SHUT_RD:
2395 case SHUT_WR:
2396 case SHUT_RDWR:
2397 rv = vppcom_session_shutdown (vsock->sid, __how);
2398 return rv;
2399 break;
2400
2401 default:
2402 return -EINVAL;
2403 break;
2404 }
2405 }
2406
2407 return rv;
2408}
2409
2410int
2411vcom_socket_epoll_create1 (int __flags)
2412{
2413 int rv = -1;
2414 vcom_socket_main_t *vsm = &vcom_socket_main;
2415 vcom_epoll_t *vepoll;
2416
2417 i32 epfd;
2418 i32 vep_idx;
2419 i32 epollidx;
2420
2421 epfd = vcom_socket_open_epoll (__flags);
2422 if (epfd < 0)
2423 {
2424 rv = epfd;
2425 goto out;
2426 }
2427
2428 vep_idx = vppcom_epoll_create ();
2429 if (vep_idx < 0)
2430 {
2431 rv = vep_idx;
2432 goto out_close_epoll;
2433 }
2434
2435 pool_get (vsm->vepolls, vepoll);
2436 vepoll_init (vepoll);
2437
2438 epollidx = vepoll - vsm->vepolls;
2439 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2440
2441 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2442
2443 return epfd;
2444
2445out_close_epoll:
2446 vcom_socket_close_epoll (epfd);
2447out:
2448 return rv;
2449}
2450
2451/*
2452 * PRE: vppcom_epoll_ctl() is successful
2453 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2454 */
2455int
2456vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2457 struct epoll_event *__event,
2458 i32 vep_idx, vcom_epoll_t * vepoll,
2459 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2460 int free_vepitem_on_del)
2461{
2462 int rv = -1;
2463 vcom_socket_main_t *vsm = &vcom_socket_main;
2464 vcom_epitem_t *vepitem;
2465
2466 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2467 uword *p;
2468 i32 vepitemidx;
2469
2470 i32 *vepitemidxs = 0;
2471
2472 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2473
2474 i32 vec_idx;
2475
2476 /* perform control operations on the epoll instance */
2477 switch (__op)
2478 {
2479 case EPOLL_CTL_ADD:
2480 /*
2481 * supplied file descriptor is already
2482 * registered with this epoll instance
2483 * */
2484 /* vepitem exists */
2485 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2486 if (p)
2487 {
2488 rv = -EEXIST;
2489 goto out;
2490 }
2491
2492 /* add a new vepitem */
2493 pool_get (vsm->vepitems, vepitem);
2494 vepitem_init (vepitem);
2495
2496 vepitemidx = vepitem - vsm->vepitems;
2497 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2498 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2499
2500 /* update epitemidxs */
2501 /* by_epfd */
2502 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2503 if (!p) /* not exist */
2504 {
2505 vepitemidxs = 0;
2506 vec_add1 (vepitemidxs, vepitemidx);
2507 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2508 }
2509 else /* exists */
2510 {
2511 vepitemidxs = *(i32 **) p;
2512 vec_add1 (vepitemidxs, vepitemidx);
2513 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2514 }
2515 /* update epitemidxs */
2516 /* by_fd */
2517 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2518 if (!p) /* not exist */
2519 {
2520 vepitemidxs = 0;
2521 vec_add1 (vepitemidxs, vepitemidx);
2522 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2523 }
2524 else /* exists */
2525 {
2526 vepitemidxs = *(i32 **) p;
2527 vec_add1 (vepitemidxs, vepitemidx);
2528 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2529 }
2530
2531 /* increment vepoll fd count by 1 */
2532 vepoll->count += 1;
2533
2534 rv = 0;
2535 goto out;
2536 break;
2537
2538 case EPOLL_CTL_MOD:
2539 /*
2540 * supplied file descriptor is not
2541 * registered with this epoll instance
2542 * */
2543 /* vepitem not exist */
2544 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2545 if (!p)
2546 {
2547 rv = -ENOENT;
2548 goto out;
2549 }
2550 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2551 if (vepitem)
2552 {
2553 vepitem->event = *__event;
2554 vepitem->revent = revent;
2555 }
2556
2557 rv = 0;
2558 goto out;
2559 break;
2560
2561 case EPOLL_CTL_DEL:
2562 /*
2563 * supplied file descriptor is not
2564 * registered with this epoll instance
2565 * */
2566 /* vepitem not exist */
2567 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2568 if (!p)
2569 {
2570 rv = -ENOENT;
2571 goto out;
2572 }
2573 vepitemidx = *(i32 *) p;
2574 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2575
2576 /* update epitemidxs */
2577 /* by_epfd */
2578 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2579 if (!p) /* not exist */
2580 {
2581 rv = -ENOENT;
2582 goto out;
2583 }
2584 else /* exists */
2585 {
2586 vepitemidxs = *(i32 **) p;
2587 vec_idx = vec_search (vepitemidxs, vepitemidx);
2588 if (vec_idx != ~0)
2589 {
2590 vec_del1 (vepitemidxs, vec_idx);
2591 if (!vec_len (vepitemidxs))
2592 {
2593 vec_free (vepitemidxs);
2594 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2595 }
2596 }
2597 }
2598
2599 /* update epitemidxs */
2600 /* by_fd */
2601 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2602 if (!p) /* not exist */
2603 {
2604 rv = -ENOENT;
2605 goto out;
2606 }
2607 else /* exists */
2608 {
2609 vepitemidxs = *(i32 **) p;
2610 vec_idx = vec_search (vepitemidxs, vepitemidx);
2611 if (vec_idx != ~0)
2612 {
2613 vec_del1 (vepitemidxs, vec_idx);
2614 if (!vec_len (vepitemidxs))
2615 {
2616 vec_free (vepitemidxs);
2617 hash_unset (vsm->epitemidxs_by_fd, __fd);
2618 }
2619 }
2620 }
2621
2622 /* pool put vepitem */
2623 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2624 if (free_vepitem_on_del)
2625 {
2626 if (!vepitem)
2627 {
2628 rv = -ENOENT;
2629 goto out;
2630 }
2631 vepitem_init (vepitem);
2632 pool_put (vsm->vepitems, vepitem);
2633 }
2634 else
2635 {
2636 if (!vepitem)
2637 {
2638 vepitem_init (vepitem);
2639 }
2640 }
2641
2642 /* decrement vepoll fd count by 1 */
2643 vepoll->count -= 1;
2644
2645 rv = 0;
2646 goto out;
2647 break;
2648
2649 default:
2650 rv = -EINVAL;
2651 goto out;
2652 break;
2653 }
2654
2655out:
2656 return rv;
2657}
2658
2659/*
2660 * PRE: 00. null pointer check on __event
2661 * 01. all other parameters are validated
2662 */
2663
2664static int
2665vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2666 struct epoll_event *__event,
2667 int free_vepitem_on_del)
2668{
2669 int rv = -1;
2670
2671 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2672 vcom_epoll_t *vepoll;
2673
2674 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2675 void *vfd;
2676 vcom_epoll_t *vfd_vepoll;
2677 vcom_socket_t *vfd_vsock;
2678
2679 i32 vep_idx;
2680 i32 vfd_id;
2681
2682 vcom_fd_type_t type = FD_TYPE_INVALID;
2683
2684 /* validate __event */
2685
2686 /* get vep_idx and vepoll */
2687 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2688 if (vep_idx == INVALID_VEP_IDX)
2689 {
2690 return -EBADF;
2691 }
2692
2693 /* get vcom fd type, vfd_id and vfd */
2694 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2695 if (vfd_id != INVALID_SESSION_ID)
2696 {
2697 type = FD_TYPE_VCOM_SOCKET;
2698 vfd = vfd_vsock;
2699 }
2700 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2701 != INVALID_VEP_IDX)
2702 {
2703 type = FD_TYPE_EPOLL;
2704 vfd = vfd_vepoll;
2705 }
2706 else
2707 {
2708 /* FD_TYPE_KERNEL not supported by epoll instance */
2709 type = FD_TYPE_INVALID;
2710 return -EBADF;
2711 }
2712
2713
2714 /* vepoll and vsock are now valid */
2715 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2716 if (rv < 0)
2717 {
2718 return rv;
2719 }
2720
2721 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2722 __event,
2723 vep_idx, vepoll,
2724 vfd_id, vfd, type, free_vepitem_on_del);
2725 return rv;
2726}
2727
2728int
2729vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2730 struct epoll_event *__event)
2731{
2732 int rv = -1;
2733
2734 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2735 return rv;
2736}
2737
2738static int
2739vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2740 struct epoll_event *__event)
2741{
2742 int rv = -1;
2743
2744 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2745 return rv;
2746}
2747
2748int
2749vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2750 int __maxevents, int __timeout,
2751 const __sigset_t * __ss)
2752{
2753 int rv = -EBADF;
2754
2755 /* in seconds eg. 3.123456789 seconds */
2756 double time_to_wait = (double) 0;
2757
2758 i32 vep_idx;
2759
2760 /* validate __event */
2761 if (!__events)
2762 {
2763 rv = -EFAULT;
2764 goto out;
2765 }
2766
2767 /* validate __timeout */
2768 if (__timeout > 0)
2769 {
2770 time_to_wait = (double) __timeout / (double) 1000;
2771 }
2772 else if (__timeout == 0)
2773 {
2774 time_to_wait = (double) 0;
2775 }
2776 else if (__timeout == -1)
2777 {
2778 time_to_wait = ~0;
2779 }
2780 else
2781 {
2782 rv = -EBADF;
2783 goto out;
2784 }
2785
2786 /* get vep_idx */
2787 vep_idx = vcom_socket_get_vep_idx (__epfd);
2788 if (vep_idx != INVALID_VEP_IDX)
2789 {
2790 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2791 }
2792out:
2793 return rv;
2794}
2795
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002796static inline void
2797vcom_pollfds_2_selectfds (
2798 /* src */
2799 struct pollfd *__fds, nfds_t __nfds,
2800 /* dest */
2801 int vcom_nfds,
2802 fd_set * __restrict vcom_readfds,
2803 fd_set * __restrict vcom_writefds,
2804 fd_set * __restrict vcom_exceptfds)
2805{
2806 nfds_t fds_idx = 0;
2807
2808 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2809 {
2810 /* ignore negative fds */
2811 if (__fds[fds_idx].fd < 0)
2812 {
2813 continue;
2814 }
2815
2816 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2817 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2818
2819 /* requested events */
2820 if (__fds[fds_idx].events)
2821 {
2822 if (__fds[fds_idx].events & POLLIN)
2823 {
2824 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2825 }
2826 if (__fds[fds_idx].events & POLLPRI)
2827 {
2828 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2829 }
2830 if (__fds[fds_idx].events & POLLOUT)
2831 {
2832 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2833 }
2834#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2835 if (__fds[fds_idx].events & POLLRDNORM)
2836 {
2837 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2838 }
2839 if (__fds[fds_idx].events & POLLRDBAND)
2840 {
2841 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2842 }
2843 if (__fds[fds_idx].events & POLLWRNORM)
2844 {
2845 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2846 }
2847 if (__fds[fds_idx].events & POLLWRBAND)
2848 {
2849 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2850 }
2851#endif
2852 }
2853 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2854}
2855
2856static inline void
2857vcom_selectfds_2_pollfds (
2858 /* dest */
2859 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2860 /* src */
2861 int vcom_nfds,
2862 fd_set * __restrict vcom_readfds,
2863 fd_set * __restrict vcom_writefds,
2864 fd_set * __restrict vcom_exceptfds)
2865{
2866 nfds_t fds_idx = 0;
2867
2868
2869 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2870 {
2871 /* ignore negative fds */
2872 if (__fds[fds_idx].fd < 0)
2873 {
2874 __fds[fds_idx].revents = 0;
2875 }
2876
2877 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2878 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2879 {
2880 /*
2881 * TBD: for now any select exception
2882 * is flagged as POLLERR
2883 * */
2884 __fds[fds_idx].revents |= POLLERR;
2885 }
2886
2887 /* requested events */
2888 if (__fds[fds_idx].events & POLLIN)
2889 {
2890 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2891 {
2892 __fds[fds_idx].revents |= POLLIN;
2893 }
2894 }
2895 if (__fds[fds_idx].events & POLLPRI)
2896 {
2897 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2898 {
2899 __fds[fds_idx].revents |= POLLIN;
2900 }
2901 }
2902 if (__fds[fds_idx].events & POLLOUT)
2903 {
2904 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2905 {
2906 __fds[fds_idx].revents |= POLLOUT;
2907 }
2908 }
2909#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2910 if (__fds[fds_idx].events & POLLRDNORM)
2911 {
2912 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2913 {
2914 __fds[fds_idx].revents |= POLLRDNORM;
2915 }
2916 }
2917 if (__fds[fds_idx].events & POLLRDBAND)
2918 {
2919 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2920 {
2921 __fds[fds_idx].revents |= POLLRDBAND;
2922 }
2923 }
2924 if (__fds[fds_idx].events & POLLWRNORM)
2925 {
2926 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2927 {
2928 __fds[fds_idx].revents |= POLLWRNORM;
2929 }
2930 }
2931 if (__fds[fds_idx].events & POLLWRBAND)
2932 {
2933 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2934 {
2935 __fds[fds_idx].revents |= POLLWRBAND;
2936 }
2937 }
2938#endif
2939 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2940
2941 /*
2942 * nfd:
2943 * the number of structures which have nonzero revents fields
2944 * (in other words, those descriptors with events or
2945 * errors reported)
2946 * */
2947 *nfd = 0;
2948 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2949 {
2950 /* ignore negative fds */
2951 if (__fds[fds_idx].fd < 0)
2952 {
2953 continue;
2954 }
2955
2956 if (__fds[fds_idx].revents)
2957 {
2958 (*nfd)++;
2959 }
2960 }
2961}
2962
2963/*
2964 * PRE: parameters are validated,
2965 * vcom_socket_poll is always called with __timeout set to zero
2966 * hence returns immediately
2967 *
2968 * ACTION: handle non negative validated vcom fds and ignore rest
2969 */
2970
2971/*
2972 * implements vcom_socket_poll () interface
2973 *
2974 * internally uses vcom_socket_select ()
2975 * to realize the behavior
2976 * */
2977int
2978vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
2979 int __timeout)
2980{
2981 int rv;
2982 pid_t pid = getpid ();
2983
2984 nfds_t fds_idx = 0;
2985 int nfd = 0;
2986
2987 /* vcom */
2988 int vcom_nfds = 0;
2989 fd_set vcom_readfds;
2990 fd_set vcom_writefds;
2991 fd_set vcom_exceptfds;
2992 int vcom_nfd = -1;
2993 /* invalid max_vcom_fd is -1 */
2994 int max_vcom_fd = -1;
2995
2996 /* __timeout is zero to get ready events and return immediately */
2997 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
2998
2999 /* validate __nfds from select perspective */
3000 if (__nfds < 0 || __nfds > FD_SETSIZE)
3001 {
3002 rv = -EINVAL;
3003 goto poll_done;
3004 }
3005
3006 /* zero vcom fd sets */
3007 /*
3008 * V vcom fd set
3009 */
3010#define _(V) \
3011 FD_ZERO ((V))
3012
3013 _(&vcom_readfds);
3014 _(&vcom_writefds);
3015 _(&vcom_exceptfds);
3016#undef _
3017
3018 vcom_nfds = 0;
3019 vcom_nfd = -1;
3020
3021
3022 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3023 {
3024 /* ignore negative fds */
3025 if (__fds[fds_idx].fd < 0)
3026 {
3027 continue;
3028 }
3029
3030 /* non negative validated vcom fds */
3031 if (__fds[fds_idx].fd > FD_SETSIZE)
3032 {
3033 rv = -EINVAL;
3034 goto poll_done;
3035 }
3036
3037 /* max_vcom_fd and vcom_nfd */
3038 if (__fds[fds_idx].fd > max_vcom_fd)
3039 {
3040 /* requested events */
3041 if (__fds[fds_idx].events)
3042 {
3043 max_vcom_fd = __fds[fds_idx].fd;
3044 }
3045 }
3046 ++vcom_nfd;
3047 }
3048
3049 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3050
3051 if (!vcom_nfds)
3052 {
3053 rv = vcom_nfds;
3054 goto poll_done;
3055 }
3056
3057 vcom_pollfds_2_selectfds (
3058 /* src */
3059 __fds, __nfds,
3060 /* dest */
3061 vcom_nfds,
3062 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3063
3064 /* select on vcom fds */
3065 vcom_nfd = vcom_socket_select (vcom_nfds,
3066 &vcom_readfds,
3067 &vcom_writefds, &vcom_exceptfds, &tv);
3068 if (VCOM_DEBUG > 0)
3069 fprintf (stderr,
3070 "[%d] vcom_socket_select: "
3071 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3072
3073 if (vcom_nfd < 0)
3074 {
3075 rv = vcom_nfd;
3076 goto poll_done;
3077 }
3078
3079 vcom_selectfds_2_pollfds (
3080 /* dest */
3081 __fds, __nfds, &nfd,
3082 /* src */
3083 vcom_nfds,
3084 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3085
3086 rv = nfd;
3087
3088poll_done:
3089 return rv;
3090}
3091
3092/*
3093 * TBD: remove this static function once vppcom
3094 * has an implementation in place
3095 *
3096 * ACTION:
3097 */
3098static int
3099vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3100{
3101 return -EOPNOTSUPP;
3102}
3103
3104int
3105vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3106 int __timeout)
3107{
3108 nfds_t fds_idx = 0;
3109
3110 /* in seconds eg. 3.123456789 seconds */
3111 double time_to_wait = (double) 0;
3112
3113 i32 sid;
3114 i32 vep_idx;
3115
3116 /* replace vcom fd with session idx */
3117 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3118 {
3119 /* ignore negative fds */
3120 if (__fds[fds_idx].fd < 0)
3121 {
3122 continue;
3123 }
3124
3125 /* non negative validated vcom fds */
3126 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3127 if (sid != INVALID_SESSION_ID)
3128 {
3129 __fds[fds_idx].fd = sid;
3130 }
3131 else
3132 {
3133 /* get vep_idx */
3134 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3135 if (vep_idx != INVALID_VEP_IDX)
3136 {
3137 __fds[fds_idx].fd = vep_idx;
3138 }
3139 else
3140 {
3141 return -EBADF;
3142 }
3143 }
3144 }
3145
3146 /* validate __timeout */
3147 if (__timeout > 0)
3148 {
3149 time_to_wait = (double) __timeout / (double) 1000;
3150 }
3151 else if (__timeout == 0)
3152 {
3153 time_to_wait = (double) 0;
3154 }
3155 else if (__timeout < 0)
3156 {
3157 time_to_wait = ~0;
3158 }
3159 else
3160 {
3161 return -EBADF;
3162 }
3163
3164 return vppcom_poll (__fds, __nfds, time_to_wait);
3165}
3166
3167int
3168vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3169{
3170 /* select an implementation */
3171
3172 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3173 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3174}
3175
3176#ifdef __USE_GNU
3177int
3178vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3179 const struct timespec *__timeout, const __sigset_t * __ss)
3180{
3181 return -EOPNOTSUPP;
3182}
3183#endif
3184
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003185int
3186vcom_socket_main_init (void)
3187{
3188 vcom_socket_main_t *vsm = &vcom_socket_main;
3189
3190 if (VCOM_DEBUG > 0)
3191 printf ("vcom_socket_main_init\n");
3192
3193 if (!vsm->init)
3194 {
3195 /* TBD: define FD_MAXSIZE and use it here */
3196 pool_alloc (vsm->vsockets, FD_SETSIZE);
3197 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3198
3199 pool_alloc (vsm->vepolls, FD_SETSIZE);
3200 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3201
3202 pool_alloc (vsm->vepitems, FD_SETSIZE);
3203 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3204
3205 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3206 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3207
3208 vsm->init = 1;
3209 }
3210
3211 return 0;
3212}
3213
3214
3215void
3216vcom_socket_main_show (void)
3217{
3218 vcom_socket_main_t *vsm = &vcom_socket_main;
3219 vcom_socket_t *vsock;
3220
3221 vcom_epoll_t *vepoll;
3222
3223 vcom_epitem_t *vepitem;
3224
3225 i32 epfd;
3226 i32 fd;
3227 i32 *vepitemidxs, *vepitemidxs_var;
3228
3229 if (vsm->init)
3230 {
3231 /* from active list of vsockets show vsock */
3232
3233 /* *INDENT-OFF* */
3234 pool_foreach (vsock, vsm->vsockets,
3235 ({
3236 printf(
3237 "fd='%04d', sid='%08x',type='%-30s'\n",
3238 vsock->fd, vsock->sid,
3239 vcom_socket_type_str (vsock->type));
3240 }));
3241 /* *INDENT-ON* */
3242
3243 /* from active list of vepolls, show vepoll */
3244
3245 /* *INDENT-OFF* */
3246 pool_foreach (vepoll, vsm->vepolls,
3247 ({
3248 printf(
3249 "epfd='%04d', vep_idx='%08x', "
3250 "type='%-30s', "
3251 "flags='%d', count='%d', close='%d'\n",
3252 vepoll->epfd, vepoll->vep_idx,
3253 vcom_socket_epoll_type_str (vepoll->type),
3254 vepoll->flags, vepoll->count, vepoll->close);
3255 }));
3256 /* *INDENT-ON* */
3257
3258 /* from active list of vepitems, show vepitem */
3259
3260 /* *INDENT-OFF* */
3261 pool_foreach (vepitem, vsm->vepitems,
3262 ({
3263 printf(
3264 "epfd='%04d', fd='%04d', "
3265 "next_fd='%04d', prev_fd='%04d', "
3266 "type='%-30s', "
3267 "events='%04x', revents='%04x'\n",
3268 vepitem->epfd, vepitem->fd,
3269 vepitem->next_fd, vepitem->prev_fd,
3270 vcom_socket_vcom_fd_type_str (vepitem->type),
3271 vepitem->event.events, vepitem->revent.events);
3272 }));
3273
3274 /* *INDENT-ON* */
3275
3276 /* show epitemidxs for epfd */
3277 /* *INDENT-OFF* */
3278 hash_foreach (epfd, vepitemidxs,
3279 vsm->epitemidxs_by_epfd,
3280 ({
3281 printf("\n[ '%04d': ", epfd);
3282 vec_foreach (vepitemidxs_var,vepitemidxs)
3283 {
3284 printf("'%04d' ", (int)vepitemidxs_var[0]);
3285 }
3286 printf("]\n");
3287 }));
3288 /* *INDENT-ON* */
3289
3290 /* show epitemidxs for fd */
3291 /* *INDENT-OFF* */
3292 hash_foreach (fd, vepitemidxs,
3293 vsm->epitemidxs_by_fd,
3294 ({
3295 printf("\n{ '%04d': ", fd);
3296 vec_foreach (vepitemidxs_var,vepitemidxs)
3297 {
3298 printf("'%04d' ", (int)vepitemidxs_var[0]);
3299 }
3300 printf("}\n");
3301 }));
3302 /* *INDENT-ON* */
3303
3304 }
3305}
3306
3307void
3308vcom_socket_main_destroy (void)
3309{
3310 vcom_socket_main_t *vsm = &vcom_socket_main;
3311 vcom_socket_t *vsock;
3312
3313 vcom_epoll_t *vepoll;
3314
3315 vcom_epitem_t *vepitem;
3316
3317 i32 epfd;
3318 i32 fd;
3319 i32 *vepitemidxs;
3320
3321
3322 if (VCOM_DEBUG > 0)
3323 printf ("vcom_socket_main_destroy\n");
3324
3325 if (vsm->init)
3326 {
3327
3328 /*
3329 * from active list of vepitems,
3330 * remove all "vepitem" elements from the pool in a safe way
3331 * */
3332
3333 /* *INDENT-OFF* */
3334 pool_flush (vepitem, vsm->vepitems,
3335 ({
3336 if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
3337 {
3338 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3339 vepitem->fd, NULL);
3340 vepitem_init (vepitem);
3341 }
3342 }));
3343 /* *INDENT-ON* */
3344
3345 pool_free (vsm->vepitems);
3346 hash_free (vsm->epitemidx_by_epfdfd);
3347
3348 /* free vepitemidxs for each epfd */
3349 /* *INDENT-OFF* */
3350 hash_foreach (epfd, vepitemidxs,
3351 vsm->epitemidxs_by_epfd,
3352 ({
3353 vec_free (vepitemidxs);
3354 }));
3355 /* *INDENT-ON* */
3356 hash_free (vsm->epitemidxs_by_epfd);
3357
3358 /* free vepitemidxs for each fd */
3359 /* *INDENT-OFF* */
3360 hash_foreach (fd, vepitemidxs,
3361 vsm->epitemidxs_by_fd,
3362 ({
3363 vec_free (vepitemidxs);
3364 }));
3365 /* *INDENT-ON* */
3366 hash_free (vsm->epitemidxs_by_fd);
3367
3368
3369 /*
3370 * from active list of vsockets,
3371 * close socket and vppcom session
3372 * */
3373
3374 /* *INDENT-OFF* */
3375 pool_foreach (vsock, vsm->vsockets,
3376 ({
3377 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3378 {
3379 vppcom_session_close (vsock->sid);
3380 vcom_socket_close_socket (vsock->fd);
3381 vsocket_init (vsock);
3382 }
3383 }));
3384 /* *INDENT-ON* */
3385
3386 /*
3387 * return vsocket element to the pool
3388 * */
3389
3390 /* *INDENT-OFF* */
3391 pool_flush (vsock, vsm->vsockets,
3392 ({
3393 // vsocket_init(vsock);
3394 ;
3395 }));
3396 /* *INDENT-ON* */
3397
3398 pool_free (vsm->vsockets);
3399 hash_free (vsm->sockidx_by_fd);
3400
3401 /*
3402 * from active list of vepolls,
3403 * close epoll and vppcom_epoll
3404 * */
3405
3406 /* *INDENT-OFF* */
3407 pool_foreach (vepoll, vsm->vepolls,
3408 ({
3409 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3410 {
3411 vppcom_session_close (vepoll->vep_idx);
3412 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3413 vepoll_init (vepoll);
3414 }
3415 }));
3416 /* *INDENT-ON* */
3417
3418 /*
3419 * return vepoll element to the pool
3420 * */
3421
3422 /* *INDENT-OFF* */
3423 pool_flush (vepoll, vsm->vepolls,
3424 ({
3425 // vepoll_init(vepoll);
3426 ;
3427 }));
3428 /* *INDENT-ON* */
3429
3430 pool_free (vsm->vepolls);
3431 hash_free (vsm->epollidx_by_epfd);
3432
3433 vsm->init = 0;
3434 }
3435}
3436
3437
3438/*
3439 * fd.io coding-style-patch-verification: ON
3440 *
3441 * Local Variables:
3442 * eval: (c-set-style "gnu")
3443 * End:
3444 */