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