blob: 8806ebd011a3c781525b4b734e6f2123447892d6 [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
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040027#include <vcl/vcom_socket.h>
28#include <vcl/vcom_socket_wrapper.h>
29#include <vcl/vcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070030
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040031#include <vcl/vppcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070032
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
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400449 if (!__buf)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700450 {
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;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400488 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700489
490 p = hash_get (vsm->sockidx_by_fd, __fd);
491 if (!p)
492 return -EBADF;
493
494 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
495 if (!vsock)
496 return -ENOTSOCK;
497
498 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
499 return -EINVAL;
500
501 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
502 return -EINVAL;
503
504 /* Sanity check */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400505 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700506 {
507 if (SSIZE_MAX - len < __iov[i].iov_len)
508 return -EINVAL;
509 len += __iov[i].iov_len;
510 }
511
512 rv = vcom_fcntl (__fd, F_GETFL, 0);
513 if (rv < 0)
514 {
515 return rv;
516 }
517
518 /* is blocking */
519 if (!(rv & O_NONBLOCK))
520 {
521 do
522 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400523 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700524 {
525 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
526 __iov[i].iov_len);
527 if (rv < 0)
528 break;
529 else
530 {
531 total += rv;
532 if (rv < __iov[i].iov_len)
533 /* Read less than buffer provided, no point to continue */
534 break;
535 }
536 }
537 }
538 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
539 return total;
540 }
541
542 /* is non blocking */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400543 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700544 {
545 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
546 __iov[i].iov_len);
547 if (rv < 0)
548 {
549 if (total > 0)
550 break;
551 else
552 {
553 errno = rv;
554 return rv;
555 }
556 }
557 else
558 {
559 total += rv;
560 if (rv < __iov[i].iov_len)
561 /* Read less than buffer provided, no point to continue */
562 break;
563 }
564 }
565 return total;
566}
567
568ssize_t
569vcom_socket_write (int __fd, const void *__buf, size_t __n)
570{
571 int rv = -1;
572 vcom_socket_main_t *vsm = &vcom_socket_main;
573 uword *p;
574 vcom_socket_t *vsock;
575
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400576 if (!__buf)
577 {
578 return -EINVAL;
579 }
580
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700581 p = hash_get (vsm->sockidx_by_fd, __fd);
582 if (!p)
583 return -EBADF;
584
585 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
586 if (!vsock)
587 return -ENOTSOCK;
588
589 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
590 return -EINVAL;
591
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700592 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
593 return rv;
594}
595
596ssize_t
597vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
598{
599 int rv = -1;
600 ssize_t total = 0;
601 vcom_socket_main_t *vsm = &vcom_socket_main;
602 uword *p;
603 vcom_socket_t *vsock;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400604 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700605
606 p = hash_get (vsm->sockidx_by_fd, __fd);
607 if (!p)
608 return -EBADF;
609
610 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
611 if (!vsock)
612 return -ENOTSOCK;
613
614 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
615 return -EINVAL;
616
617 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
618 return -EINVAL;
619
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400620 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700621 {
622 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
623 __iov[i].iov_len);
624 if (rv < 0)
625 {
626 if (total > 0)
627 break;
628 else
629 return rv;
630 }
631 else
632 total += rv;
633 }
634 return total;
635}
636
637/*
638 * RETURN: 0 - invalid cmd
639 * 1 - cmd not handled by vcom and vppcom
640 * 2 - cmd handled by vcom socket resource
641 * 3 - cmd handled by vppcom
642 * */
643/* TBD: incomplete list of cmd */
644static int
645vcom_socket_check_fcntl_cmd (int __cmd)
646{
647 switch (__cmd)
648 {
649 /*cmd not handled by vcom and vppcom */
650 /* Fallthrough */
651 case F_DUPFD:
652 case F_DUPFD_CLOEXEC:
653 return 1;
654
655 /* cmd handled by vcom socket resource */
656 /* Fallthrough */
657 case F_GETFD:
658 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700659 case F_GETLK:
660 case F_SETLK:
661 case F_SETLKW:
662 case F_GETOWN:
663 case F_SETOWN:
664 return 2;
665
Stevenb59f2272017-10-12 17:10:33 -0700666 /* cmd handled by vcom and vppcom */
667 case F_SETFL:
668 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700669 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700670
671 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700672 default:
Stevenb59f2272017-10-12 17:10:33 -0700673 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700674 }
675 return 0;
676}
677
Dave Wallacee22aa742017-10-20 12:30:38 -0400678static inline int
679vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700680{
Stevenb59f2272017-10-12 17:10:33 -0700681 int flags = va_arg (__ap, int);
682 int rv = -EOPNOTSUPP;
683 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700684
Stevenb59f2272017-10-12 17:10:33 -0700685 size = sizeof (flags);
686 if (__cmd == F_SETFL)
687 {
688 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
689 }
690 else if (__cmd == F_GETFL)
691 {
692 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
693 if (rv == VPPCOM_OK)
694 rv = flags;
695 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700696
697 return rv;
698}
699
700int
701vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
702{
703 int rv = -EBADF;
704 vcom_socket_main_t *vsm = &vcom_socket_main;
705 uword *p;
706 vcom_socket_t *vsock;
707
708 p = hash_get (vsm->sockidx_by_fd, __fd);
709 if (!p)
710 return -EBADF;
711
712 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
713 if (!vsock)
714 return -ENOTSOCK;
715
716 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
717 return -EINVAL;
718
719 switch (vcom_socket_check_fcntl_cmd (__cmd))
720 {
721 /* invalid cmd */
722 case 0:
723 rv = -EBADF;
724 break;
725 /*cmd not handled by vcom and vppcom */
726 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700727 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700728 break;
729 /* cmd handled by vcom socket resource */
730 case 2:
731 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
732 break;
733 /* cmd handled by vppcom */
734 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400735 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700736 break;
737
738 default:
739 rv = -EINVAL;
740 break;
741 }
742
743 return rv;
744}
745
Stevenb59f2272017-10-12 17:10:33 -0700746/*
747 * RETURN: 0 - invalid cmd
748 * 1 - cmd not handled by vcom and vppcom
749 * 2 - cmd handled by vcom socket resource
750 * 3 - cmd handled by vppcom
751 */
752static int
753vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
754{
755 int rc;
756
757 switch (__cmd)
758 {
759 /* cmd handled by vppcom */
760 case FIONREAD:
761 rc = 3;
762 break;
763
764 /* cmd not handled by vcom and vppcom */
765 default:
766 rc = 1;
767 break;
768 }
769 return rc;
770}
771
Dave Wallacee22aa742017-10-20 12:30:38 -0400772static inline int
773vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
Stevenb59f2272017-10-12 17:10:33 -0700774{
775 int rv;
776
777 if (__cmd == FIONREAD)
778 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
779 else
780 rv = -EOPNOTSUPP;
781 return rv;
782}
783
784int
785vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
786{
787 int rv = -EBADF;
788 vcom_socket_main_t *vsm = &vcom_socket_main;
789 uword *p;
790 vcom_socket_t *vsock;
791
792 p = hash_get (vsm->sockidx_by_fd, __fd);
793 if (!p)
794 return -EBADF;
795
796 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
797 if (!vsock)
798 return -ENOTSOCK;
799
800 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
801 return -EINVAL;
802
803 switch (vcom_socket_check_ioctl_cmd (__cmd))
804 {
805 /* Not supported cmd */
806 case 0:
807 rv = -EOPNOTSUPP;
808 break;
809
810 /* cmd not handled by vcom and vppcom */
811 case 1:
812 rv = libc_vioctl (vsock->fd, __cmd, __ap);
813 break;
814
815 /* cmd handled by vcom socket resource */
816 case 2:
817 rv = libc_vioctl (vsock->fd, __cmd, __ap);
818 break;
819
820 /* cmd handled by vppcom */
821 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400822 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
Stevenb59f2272017-10-12 17:10:33 -0700823 break;
824
825 default:
826 rv = -EINVAL;
827 break;
828 }
829
830 return rv;
831}
832
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700833static inline int
834vcom_socket_fds_2_sid_fds (
835 /* dest */
836 int *vcom_nsid_fds,
837 fd_set * __restrict vcom_rd_sid_fds,
838 fd_set * __restrict vcom_wr_sid_fds,
839 fd_set * __restrict vcom_ex_sid_fds,
840 /* src */
841 int vcom_nfds,
842 fd_set * __restrict vcom_readfds,
843 fd_set * __restrict vcom_writefds,
844 fd_set * __restrict vcom_exceptfds)
845{
846 int rv = 0;
847 int fd;
848 int sid;
849 /* invalid max_sid is -1 */
850 int max_sid = -1;
851 int nsid = 0;
852
853 /*
854 * set sid in sid sets corresponding to fd's in fd sets
855 * compute nsid and vcom_nsid_fds from sid sets
856 */
857
858 for (fd = 0; fd < vcom_nfds; fd++)
859 {
860 /*
861 * F fd set, src
862 * S sid set, dest
863 */
864#define _(S,F) \
865 if ((F) && (S) && FD_ISSET (fd, (F))) \
866 { \
867 sid = vcom_socket_get_sid (fd); \
868 if (sid != INVALID_SESSION_ID) \
869 { \
870 FD_SET (sid, (S)); \
871 if (sid > max_sid) \
872 { \
873 max_sid = sid; \
874 } \
875 ++nsid; \
876 } \
877 else \
878 { \
879 rv = -EBADFD; \
880 goto done; \
881 } \
882 }
883
884
885 _(vcom_rd_sid_fds, vcom_readfds);
886 _(vcom_wr_sid_fds, vcom_writefds);
887 _(vcom_ex_sid_fds, vcom_exceptfds);
888#undef _
889 }
890
891 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
892 rv = nsid;
893
894done:
895 return rv;
896}
897
898/*
899 * PRE: 00. sid sets were derived from fd sets
900 * 01. sid sets were updated with sids that actually changed
901 * status
902 * 02. fd sets still has watched fds
903 *
904 * This function will modify in place fd sets to indicate which fd's
905 * actually changed status(inferred from sid sets)
906 */
907static inline int
908vcom_socket_sid_fds_2_fds (
909 /* dest */
910 int *new_vcom_nfds,
911 int vcom_nfds,
912 fd_set * __restrict vcom_readfds,
913 fd_set * __restrict vcom_writefds,
914 fd_set * __restrict vcom_exceptfds,
915 /* src */
916 int vcom_nsid_fds,
917 fd_set * __restrict vcom_rd_sid_fds,
918 fd_set * __restrict vcom_wr_sid_fds,
919 fd_set * __restrict vcom_ex_sid_fds)
920{
921 int rv = 0;
922 int fd;
923 int sid;
924 /* invalid max_fd is -1 */
925 int max_fd = -1;
926 int nfd = 0;
927
928
929 /*
930 * modify in place fd sets to indicate which fd's
931 * actually changed status(inferred from sid sets)
932 */
933 for (fd = 0; fd < vcom_nfds; fd++)
934 {
935 /*
936 * F fd set, dest
937 * S sid set, src
938 */
939#define _(S,F) \
940 if ((F) && (S) && FD_ISSET (fd, (F))) \
941 { \
942 sid = vcom_socket_get_sid (fd); \
943 if (sid != INVALID_SESSION_ID) \
944 { \
945 if (!FD_ISSET (sid, (S))) \
946 { \
947 FD_CLR(fd, (F)); \
948 } \
949 } \
950 else \
951 { \
952 rv = -EBADFD; \
953 goto done; \
954 } \
955 }
956
957
958 _(vcom_rd_sid_fds, vcom_readfds);
959 _(vcom_wr_sid_fds, vcom_writefds);
960 _(vcom_ex_sid_fds, vcom_exceptfds);
961#undef _
962 }
963
964 /*
965 * compute nfd and new_vcom_nfds from fd sets
966 */
967 for (fd = 0; fd < vcom_nfds; fd++)
968 {
969
970#define _(F) \
971 if ((F) && FD_ISSET (fd, (F))) \
972 { \
973 if (fd > max_fd) \
974 { \
975 max_fd = fd; \
976 } \
977 ++nfd; \
978 }
979
980
981 _(vcom_readfds);
982 _(vcom_writefds);
983 _(vcom_exceptfds);
984#undef _
985
986 }
987
988 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
989 rv = nfd;
990
991done:
992 return rv;
993}
994
995/*
996 * PRE:
997 * vom_socket_select is always called with
998 * timeout->tv_sec and timeout->tv_usec set to zero.
999 * hence vppcom_select return immediately.
1000 */
1001/*
1002 * TBD: do{body;} while(timeout conditional); timeout loop
1003 */
1004int
1005vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1006 fd_set * __restrict vcom_writefds,
1007 fd_set * __restrict vcom_exceptfds,
1008 struct timeval *__restrict timeout)
1009{
Dave Wallacee22aa742017-10-20 12:30:38 -04001010 static unsigned long vcom_nsid_fds = 0;
1011 int vcom_nsid = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001012 int rv = -EBADF;
1013 pid_t pid = getpid ();
1014
1015 int new_vcom_nfds = 0;
1016 int new_vcom_nfd = 0;
1017
1018 /* vcom sid fds */
1019 fd_set vcom_rd_sid_fds;
1020 fd_set vcom_wr_sid_fds;
1021 fd_set vcom_ex_sid_fds;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001022
1023 /* in seconds eg. 3.123456789 seconds */
1024 double time_to_wait = (double) 0;
1025
1026 /* validate inputs */
1027 if (vcom_nfds < 0)
1028 {
1029 return -EINVAL;
1030 }
1031
1032 /* convert timeval timeout to double time_to_wait */
1033 if (timeout)
1034 {
1035 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1036 {
1037 /* polling: vppcom_select returns immediately */
1038 time_to_wait = (double) 0;
1039 }
1040 else
1041 {
1042 /*TBD: use timeval api */
1043 time_to_wait = (double) timeout->tv_sec +
1044 (double) timeout->tv_usec / (double) 1000000 +
1045 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1046 }
1047 }
1048 else
1049 {
1050 /*
1051 * no timeout: vppcom_select can block indefinitely
1052 * waiting for a file descriptor to become ready
1053 * */
1054 /* set to a phantom value */
1055 time_to_wait = ~0;
1056 }
1057
1058 /* zero the sid_sets */
1059 /*
1060 * F fd set
1061 * S sid set
1062 */
1063#define _(S,F) \
1064 if ((F)) \
1065 { \
1066 FD_ZERO ((S)); \
1067 }
1068
1069
1070 _(&vcom_rd_sid_fds, vcom_readfds);
1071 _(&vcom_wr_sid_fds, vcom_writefds);
1072 _(&vcom_ex_sid_fds, vcom_exceptfds);
1073#undef _
1074
Dave Wallacee22aa742017-10-20 12:30:38 -04001075 if (vcom_nfds == 0)
1076 {
1077 if (time_to_wait > 0)
1078 {
1079 if (VCOM_DEBUG > 0)
1080 fprintf (stderr,
1081 "[%d] vcom_socket_select called to "
1082 "emulate delay_ns()!\n", pid);
1083 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1084 }
1085 else
1086 {
1087 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1088 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1089 }
1090 return 0;
1091 }
1092
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001093 /* populate read, write and except sid_sets */
1094 vcom_nsid = vcom_socket_fds_2_sid_fds (
1095 /* dest */
1096 vcom_readfds || vcom_writefds
1097 || vcom_exceptfds ? (int *)
1098 &vcom_nsid_fds : NULL,
1099 vcom_readfds ? &vcom_rd_sid_fds :
1100 NULL,
1101 vcom_writefds ? &vcom_wr_sid_fds :
1102 NULL,
1103 vcom_exceptfds ? &vcom_ex_sid_fds :
1104 NULL,
1105 /* src */
1106 vcom_nfds,
1107 vcom_readfds,
1108 vcom_writefds, vcom_exceptfds);
1109 if (vcom_nsid < 0)
1110 {
1111 return vcom_nsid;
1112 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001113
1114 rv = vppcom_select (vcom_nsid_fds,
1115 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1116 NULL,
1117 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1118 NULL,
1119 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1120 NULL, time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001121 if (VCOM_DEBUG > 2)
1122 fprintf (stderr, "[%d] called vppcom_select(): "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001123 "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1124
1125 /* check if any file descriptors changed status */
1126 if (rv > 0)
1127 {
1128 /*
1129 * on exit, sets are modified in place to indicate which
1130 * file descriptors actually changed status
1131 * */
1132
1133 /*
1134 * comply with pre-condition
1135 * do not clear vcom fd sets befor calling
1136 * vcom_socket_sid_fds_2_fds
1137 */
1138 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1139 /* dest */
1140 &new_vcom_nfds,
1141 vcom_nfds,
1142 vcom_readfds,
1143 vcom_writefds,
1144 vcom_exceptfds,
1145 /* src */
1146 vcom_nsid_fds,
1147 vcom_readfds ?
1148 &vcom_rd_sid_fds : NULL,
1149 vcom_writefds ?
1150 &vcom_wr_sid_fds : NULL,
1151 vcom_exceptfds ?
1152 &vcom_ex_sid_fds : NULL);
1153 if (new_vcom_nfd < 0)
1154 {
1155 return new_vcom_nfd;
1156 }
1157 if (new_vcom_nfds < 0)
1158 {
1159 return -EINVAL;
1160 }
1161 rv = new_vcom_nfd;
1162 }
1163 return rv;
1164}
1165
1166
1167int
1168vcom_socket_socket (int __domain, int __type, int __protocol)
1169{
1170 int rv = -1;
1171 vcom_socket_main_t *vsm = &vcom_socket_main;
1172 vcom_socket_t *vsock;
1173
1174 i32 fd;
1175 i32 sid;
1176 i32 sockidx;
1177 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1178 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1179
1180 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1181 if (fd < 0)
1182 {
1183 rv = fd;
1184 goto out;
1185 }
1186
1187 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1188 (type == SOCK_DGRAM) ?
1189 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1190 is_nonblocking);
1191 if (sid < 0)
1192 {
1193 rv = sid;
1194 goto out_close_socket;
1195 }
1196
1197 pool_get (vsm->vsockets, vsock);
1198 vsocket_init (vsock);
1199
1200 sockidx = vsock - vsm->vsockets;
1201 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1202
1203 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1204 return fd;
1205
1206out_close_socket:
1207 vcom_socket_close_socket (fd);
1208out:
1209 return rv;
1210}
1211
1212int
1213vcom_socket_socketpair (int __domain, int __type, int __protocol,
1214 int __fds[2])
1215{
1216/* TBD: */
1217 return 0;
1218}
1219
1220int
1221vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1222{
1223 int rv = -1;
1224 vcom_socket_main_t *vsm = &vcom_socket_main;
1225 uword *p;
1226 vcom_socket_t *vsock;
1227
1228 vppcom_endpt_t ep;
1229
1230 p = hash_get (vsm->sockidx_by_fd, __fd);
1231 if (!p)
1232 return -EBADF;
1233
1234 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1235 if (!vsock)
1236 return -ENOTSOCK;
1237
1238 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1239 return -EINVAL;
1240
1241 if (!__addr)
1242 {
1243 return -EINVAL;
1244 }
1245
1246 ep.vrf = VPPCOM_VRF_DEFAULT;
1247 switch (__addr->sa_family)
1248 {
1249 case AF_INET:
1250 if (__len != sizeof (struct sockaddr_in))
1251 {
1252 return -EINVAL;
1253 }
1254 ep.is_ip4 = VPPCOM_IS_IP4;
1255 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1256 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1257 break;
1258
1259 case AF_INET6:
1260 if (__len != sizeof (struct sockaddr_in6))
1261 {
1262 return -EINVAL;
1263 }
1264 ep.is_ip4 = VPPCOM_IS_IP6;
1265 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1266 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1267 break;
1268
1269 default:
1270 return -1;
1271 break;
1272 }
1273
1274 rv = vppcom_session_bind (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001275 return rv;
1276}
1277
Dave Wallacee22aa742017-10-20 12:30:38 -04001278static inline int
1279vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001280{
Steven2199aab2017-10-15 20:18:47 -07001281 int rv;
1282 uint32_t size = sizeof (*ep);
1283
1284 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1285 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001286}
1287
1288int
1289vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1290 socklen_t * __restrict __len)
1291{
1292 int rv = -1;
1293 vcom_socket_main_t *vsm = &vcom_socket_main;
1294 uword *p;
1295 vcom_socket_t *vsock;
1296
1297
1298 p = hash_get (vsm->sockidx_by_fd, __fd);
1299 if (!p)
1300 return -EBADF;
1301
1302 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1303 if (!vsock)
1304 return -ENOTSOCK;
1305
1306 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1307 return -EINVAL;
1308
1309 if (!__addr || !__len)
1310 return -EFAULT;
1311
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001312 vppcom_endpt_t ep;
1313 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001314 rv = vcom_session_getsockname (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001315 if (rv == 0)
1316 {
1317 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1318 {
1319 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1320 switch (__addr->sa_family)
1321 {
1322 case AF_INET:
1323 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1324 *__len = sizeof (struct sockaddr_in);
1325 break;
1326
1327 case AF_INET6:
1328 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1329 *__len = sizeof (struct sockaddr_in6);
1330 break;
1331
1332 default:
1333 break;
1334 }
1335 }
1336 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001337
1338 return rv;
1339}
1340
1341int
1342vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1343{
1344 int rv = -1;
1345 vcom_socket_main_t *vsm = &vcom_socket_main;
1346 uword *p;
1347 vcom_socket_t *vsock;
1348
1349 vppcom_endpt_t ep;
1350
1351 p = hash_get (vsm->sockidx_by_fd, __fd);
1352 if (p)
1353 {
1354 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1355
1356 ep.vrf = VPPCOM_VRF_DEFAULT;
1357 switch (__addr->sa_family)
1358 {
1359 case AF_INET:
1360 ep.is_ip4 = VPPCOM_IS_IP4;
1361 ep.ip =
1362 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1363 ep.port =
1364 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1365 break;
1366
1367 case AF_INET6:
1368 ep.is_ip4 = VPPCOM_IS_IP6;
1369 ep.ip =
1370 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1371 ep.port =
1372 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1373 break;
1374
1375 default:
1376 return -1;
1377 break;
1378 }
1379
1380 rv = vppcom_session_connect (vsock->sid, &ep);
1381 }
1382 return rv;
1383}
1384
Dave Wallacee22aa742017-10-20 12:30:38 -04001385static inline int
1386vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001387{
Steven2199aab2017-10-15 20:18:47 -07001388 int rv;
1389 uint32_t size = sizeof (*ep);
1390
1391 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1392 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001393}
1394
1395int
1396vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1397 socklen_t * __restrict __len)
1398{
1399 int rv = -1;
1400 vcom_socket_main_t *vsm = &vcom_socket_main;
1401 uword *p;
1402 vcom_socket_t *vsock;
1403
1404
1405 p = hash_get (vsm->sockidx_by_fd, __fd);
1406 if (!p)
1407 return -EBADF;
1408
1409 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1410 if (!vsock)
1411 return -ENOTSOCK;
1412
1413 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1414 return -EINVAL;
1415
1416 if (!__addr || !__len)
1417 return -EFAULT;
1418
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001419 vppcom_endpt_t ep;
1420 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001421 rv = vcom_session_getpeername (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001422 if (rv == 0)
1423 {
1424 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1425 {
1426 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1427 switch (__addr->sa_family)
1428 {
1429 case AF_INET:
1430 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1431 *__len = sizeof (struct sockaddr_in);
1432 break;
1433
1434 case AF_INET6:
1435 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1436 *__len = sizeof (struct sockaddr_in6);
1437 break;
1438
1439 default:
1440 break;
1441 }
1442 }
1443 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001444
1445 return rv;
1446}
1447
1448ssize_t
1449vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1450{
1451 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1452}
1453
1454ssize_t
1455vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1456{
1457 int rv = -1;
1458 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1459 return rv;
1460}
1461
1462/*
1463 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1464 * 0 otherwise
1465 * */
1466int
1467vcom_socket_is_connection_mode_socket (int __fd)
1468{
1469 int rv = -1;
1470 /* TBD define new vppcom api */
1471 vcom_socket_main_t *vsm = &vcom_socket_main;
1472 uword *p;
1473 vcom_socket_t *vsock;
1474
1475 int type;
1476 socklen_t optlen;
1477
1478 p = hash_get (vsm->sockidx_by_fd, __fd);
1479
1480 if (p)
1481 {
1482 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1483 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1484 {
1485 optlen = sizeof (type);
1486 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1487 if (rv != 0)
1488 {
1489 return 0;
1490 }
1491 /* get socket type */
1492 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1493 {
1494 case SOCK_STREAM:
1495 case SOCK_SEQPACKET:
1496 return 1;
1497 break;
1498
1499 default:
1500 return 0;
1501 break;
1502 }
1503 }
1504 }
1505 return 0;
1506}
1507
Dave Wallacee22aa742017-10-20 12:30:38 -04001508static inline ssize_t
1509vcom_session_sendto (int __sid, void *__buf, size_t __n,
1510 int __flags, __CONST_SOCKADDR_ARG __addr,
1511 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001512{
1513 int rv = -1;
1514 /* TBD add new vpp api */
1515 /* TBD add flags parameter */
1516 rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1517 return rv;
1518}
1519
1520ssize_t
1521vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1522 int __flags, __CONST_SOCKADDR_ARG __addr,
1523 socklen_t __addr_len)
1524{
1525 int rv = -1;
1526 vcom_socket_main_t *vsm = &vcom_socket_main;
1527 uword *p;
1528 vcom_socket_t *vsock;
1529
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001530 if (!__buf)
1531 {
1532 return -EINVAL;
1533 }
1534
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001535 p = hash_get (vsm->sockidx_by_fd, __fd);
1536 if (!p)
1537 return -EBADF;
1538
1539 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1540 if (!vsock)
1541 return -ENOTSOCK;
1542
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001543 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001544 {
1545 return -EINVAL;
1546 }
1547
1548 if (vcom_socket_is_connection_mode_socket (__fd))
1549 {
1550 /* ignore __addr and _addr_len */
1551 /* and EISCONN may be returned when they are not NULL and 0 */
1552 if ((__addr != NULL) || (__addr_len != 0))
1553 {
1554 return -EISCONN;
1555 }
1556 }
1557 else
1558 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001559 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001560 {
1561 return -EDESTADDRREQ;
1562 }
1563 /* not a vppcom supported address family */
1564 if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1565 {
1566 return -EINVAL;
1567 }
1568 }
1569
Dave Wallacee22aa742017-10-20 12:30:38 -04001570 rv = vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1571 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001572 return rv;
1573}
1574
Dave Wallacee22aa742017-10-20 12:30:38 -04001575static inline ssize_t
1576vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1577 int __flags, __SOCKADDR_ARG __addr,
1578 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001579{
1580 int rv = -1;
1581
1582 /* TBD add flags parameter */
1583 rv = vppcom_session_read (__sid, __buf, __n);
1584 return rv;
1585}
1586
1587ssize_t
1588vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1589 int __flags, __SOCKADDR_ARG __addr,
1590 socklen_t * __restrict __addr_len)
1591{
1592 int rv = -1;
1593 vcom_socket_main_t *vsm = &vcom_socket_main;
1594 uword *p;
1595 vcom_socket_t *vsock;
1596
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001597 if (!__buf || !__addr || !__addr_len)
1598 {
1599 return -EINVAL;
1600 }
1601
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001602 p = hash_get (vsm->sockidx_by_fd, __fd);
1603 if (!p)
1604 return -EBADF;
1605
1606 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1607 if (!vsock)
1608 return -ENOTSOCK;
1609
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001610 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001611 {
1612 return -EINVAL;
1613 }
1614
Dave Wallacee22aa742017-10-20 12:30:38 -04001615 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1616 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001617 return rv;
1618}
1619
1620/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001621static inline ssize_t
1622vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001623{
1624 int rv = -1;
1625 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1626 (int)__n); */
1627 return rv;
1628}
1629
1630ssize_t
1631vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1632{
1633 int rv = -1;
1634 vcom_socket_main_t *vsm = &vcom_socket_main;
1635 uword *p;
1636 vcom_socket_t *vsock;
1637
1638 p = hash_get (vsm->sockidx_by_fd, __fd);
1639 if (!p)
1640 return -EBADF;
1641
1642 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1643 if (!vsock)
1644 return -ENOTSOCK;
1645
1646 if (vcom_socket_is_connection_mode_socket (__fd))
1647 {
1648 /* ignore __addr and _addr_len */
1649 /* and EISCONN may be returned when they are not NULL and 0 */
1650 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1651 {
1652 return -EISCONN;
1653 }
1654 }
1655 else
1656 {
1657 /* TBD: validate __message->msg_name and __message->msg_namelen
1658 * and return -EINVAL on validation error
1659 * */
1660 ;
1661 }
1662
Dave Wallacee22aa742017-10-20 12:30:38 -04001663 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001664
1665 return rv;
1666}
1667
1668#ifdef __USE_GNU
1669int
1670vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1671 unsigned int __vlen, int __flags)
1672{
1673
1674 /* TBD: define a new vppcom api */
1675 return 0;
1676}
1677#endif
1678
1679/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001680static inline ssize_t
1681vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001682{
1683 int rv = -1;
1684 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1685 (int)__n); */
1686 rv = -EOPNOTSUPP;
1687 return rv;
1688}
1689
1690ssize_t
1691vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1692{
1693 int rv = -1;
1694 vcom_socket_main_t *vsm = &vcom_socket_main;
1695 uword *p;
1696 vcom_socket_t *vsock;
1697
1698 p = hash_get (vsm->sockidx_by_fd, __fd);
1699 if (!p)
1700 return -EBADF;
1701
1702 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1703 if (!vsock)
1704 return -ENOTSOCK;
1705
1706 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1707 return -EINVAL;
1708
1709 if (!__message)
1710 {
1711 return -EINVAL;
1712 }
1713
1714 /* validate __flags */
1715
Dave Wallacee22aa742017-10-20 12:30:38 -04001716 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001717 return rv;
1718}
1719
1720#ifdef __USE_GNU
1721int
1722vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1723 unsigned int __vlen, int __flags,
1724 struct timespec *__tmo)
1725{
1726 /* TBD: define a new vppcom api */
1727 return 0;
1728}
1729#endif
1730
1731/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001732static inline int
1733vcom_session_get_sockopt (int __sid, int __level, int __optname,
1734 void *__restrict __optval,
1735 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001736{
1737 /* 1. for socket level options that are NOT socket attributes
1738 * and that has corresponding vpp options get from vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001739 return 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001740}
1741
1742int
1743vcom_socket_getsockopt (int __fd, int __level, int __optname,
1744 void *__restrict __optval,
1745 socklen_t * __restrict __optlen)
1746{
1747 int rv = -1;
1748 vcom_socket_main_t *vsm = &vcom_socket_main;
1749 uword *p;
1750 vcom_socket_t *vsock;
1751
1752 p = hash_get (vsm->sockidx_by_fd, __fd);
1753 if (!p)
1754 return -EBADF;
1755
1756 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1757 if (!vsock)
1758 return -ENOTSOCK;
1759
1760 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1761 return -EINVAL;
1762
1763 if (!__optval && !__optlen)
1764 return -EFAULT;
1765
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001766 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:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001824#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001825 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001826#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001827 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1828 if (rv != 0)
1829 {
1830 rv = -errno;
1831 return rv;
1832 }
1833 break;
1834
1835 default:
1836 /* We implement the SO_SNDLOWAT etc to not be settable
1837 * (1003.1g 7).
1838 */
1839 return -ENOPROTOOPT;
1840 }
1841
1842 break;
1843
1844 default:
1845 /* 1. handle options that are NOT socket level options,
1846 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04001847 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1848 __optval, __optlen);
1849 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001850 }
1851
1852 return rv;
1853}
1854
1855/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001856static inline int
1857vcom_session_setsockopt (int __sid, int __level, int __optname,
1858 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001859{
Stevenb59f2272017-10-12 17:10:33 -07001860 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001861
Stevenb59f2272017-10-12 17:10:33 -07001862 switch (__level)
1863 {
Stevenbd187a82017-10-13 12:52:28 -07001864 case SOL_TCP:
1865 switch (__optname)
1866 {
1867 case TCP_KEEPIDLE:
1868 rv =
1869 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1870 break;
1871 case TCP_KEEPINTVL:
1872 rv =
1873 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1874 break;
1875 default:
1876 break;
1877 }
1878 break;
Stevenb59f2272017-10-12 17:10:33 -07001879 case SOL_IPV6:
1880 switch (__optname)
1881 {
1882 case IPV6_V6ONLY:
1883 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001884 break;
Stevenb59f2272017-10-12 17:10:33 -07001885 default:
Stevenbd187a82017-10-13 12:52:28 -07001886 break;
Stevenb59f2272017-10-12 17:10:33 -07001887 }
1888 break;
1889 case SOL_SOCKET:
1890 switch (__optname)
1891 {
Stevenbd187a82017-10-13 12:52:28 -07001892 case SO_KEEPALIVE:
1893 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1894 break;
Stevenb59f2272017-10-12 17:10:33 -07001895 case SO_REUSEADDR:
1896 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001897 break;
Stevenb59f2272017-10-12 17:10:33 -07001898 case SO_BROADCAST:
1899 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001900 break;
Stevenb59f2272017-10-12 17:10:33 -07001901 default:
Stevenbd187a82017-10-13 12:52:28 -07001902 break;
Stevenb59f2272017-10-12 17:10:33 -07001903 }
1904 break;
1905 default:
Stevenbd187a82017-10-13 12:52:28 -07001906 break;
Stevenb59f2272017-10-12 17:10:33 -07001907 }
1908
1909 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001910}
1911
1912int
1913vcom_socket_setsockopt (int __fd, int __level, int __optname,
1914 const void *__optval, socklen_t __optlen)
1915{
1916 int rv = -1;
1917 vcom_socket_main_t *vsm = &vcom_socket_main;
1918 uword *p;
1919 vcom_socket_t *vsock;
1920
1921 p = hash_get (vsm->sockidx_by_fd, __fd);
1922 if (!p)
1923 return -EBADF;
1924
1925 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1926 if (!vsock)
1927 return -ENOTSOCK;
1928
1929 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1930 return -EINVAL;
1931
1932 /*
1933 * Options without arguments
1934 */
1935
1936 if (__optname == SO_BINDTODEVICE)
1937 {
1938 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1939 if (rv != 0)
1940 {
1941 rv = -errno;
1942 }
1943 return rv;
1944 }
1945
1946 if (!__optval)
1947 return -EFAULT;
1948
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001949 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001950 return -EINVAL;
1951
1952 switch (__level)
1953 {
Stevenb59f2272017-10-12 17:10:33 -07001954 case SOL_IPV6:
1955 switch (__optname)
1956 {
1957 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04001958 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1959 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001960 break;
Stevenb59f2272017-10-12 17:10:33 -07001961 default:
1962 return -EOPNOTSUPP;
1963 }
1964 break;
1965 case SOL_TCP:
1966 switch (__optname)
1967 {
1968 case TCP_NODELAY:
1969 return 0;
Stevenbd187a82017-10-13 12:52:28 -07001970 case TCP_KEEPIDLE:
1971 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04001972 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1973 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001974 break;
Stevenb59f2272017-10-12 17:10:33 -07001975 default:
1976 return -EOPNOTSUPP;
1977 }
1978 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001979 /* handle options at socket level */
1980 case SOL_SOCKET:
1981 switch (__optname)
1982 {
Stevenb59f2272017-10-12 17:10:33 -07001983 case SO_REUSEADDR:
1984 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07001985 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04001986 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1987 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07001988 break;
Stevenb59f2272017-10-12 17:10:33 -07001989
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001990 /*
1991 * 1. for socket level options that are socket attributes,
1992 * set it from libc_getsockopt
1993 * 2. for socket level options that are NOT socket
1994 * attributes and that has corresponding vpp options
1995 * set it from vppcom
1996 * 3. for socket level options unimplemented
1997 * return -ENOPROTOOPT */
1998 case SO_DEBUG:
1999 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002000 case SO_SNDBUF:
2001 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002002 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002003 case SO_TYPE:
2004 case SO_PROTOCOL:
2005 case SO_DOMAIN:
2006 case SO_ERROR:
2007 case SO_OOBINLINE:
2008 case SO_NO_CHECK:
2009 case SO_PRIORITY:
2010 case SO_LINGER:
2011 case SO_BSDCOMPAT:
2012 case SO_TIMESTAMP:
2013 case SO_TIMESTAMPNS:
2014 case SO_TIMESTAMPING:
2015 case SO_RCVTIMEO:
2016 case SO_SNDTIMEO:
2017 case SO_RCVLOWAT:
2018 case SO_SNDLOWAT:
2019 case SO_PASSCRED:
2020 case SO_PEERCRED:
2021 case SO_PEERNAME:
2022 case SO_ACCEPTCONN:
2023 case SO_PASSSEC:
2024 case SO_PEERSEC:
2025 case SO_MARK:
2026 case SO_RXQ_OVFL:
2027 case SO_WIFI_STATUS:
2028 case SO_PEEK_OFF:
2029 case SO_NOFCS:
2030 /*
2031 * SO_BINDTODEVICE already handled as
2032 * "Options without arguments" */
2033 /* case SO_BINDTODEVICE: */
2034 case SO_GET_FILTER:
2035 case SO_LOCK_FILTER:
2036 case SO_BPF_EXTENSIONS:
2037 case SO_SELECT_ERR_QUEUE:
2038#ifdef CONFIG_NET_RX_BUSY_POLL
2039 case SO_BUSY_POLL:
2040#endif
2041 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002042#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002043 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002044#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002045 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2046 if (rv != 0)
2047 {
2048 rv = -errno;
2049 return rv;
2050 }
2051 break;
2052
2053 default:
2054 /* We implement the SO_SNDLOWAT etc to not be settable
2055 * (1003.1g 7).
2056 */
2057 return -ENOPROTOOPT;
2058 }
2059
2060 break;
2061
2062 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002063 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002064 }
2065
2066 return rv;
2067}
2068
2069int
2070vcom_socket_listen (int __fd, int __n)
2071{
2072 int rv = -1;
2073 vcom_socket_main_t *vsm = &vcom_socket_main;
2074 uword *p;
2075 vcom_socket_t *vsock;
2076
2077 p = hash_get (vsm->sockidx_by_fd, __fd);
2078 if (p)
2079 {
2080 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2081
2082 /* TBD vppcom to accept __n parameter */
2083 rv = vppcom_session_listen (vsock->sid, __n);
2084 }
2085
2086 return rv;
2087}
2088
2089static int
2090vcom_socket_connected_socket (int __fd, int __sid,
2091 int *__domain,
2092 int *__type, int *__protocol, int flags)
2093{
2094 int rv = -1;
2095 vcom_socket_main_t *vsm = &vcom_socket_main;
2096 vcom_socket_t *vsock;
2097
2098 i32 fd;
2099 i32 sockidx;
2100
2101 socklen_t optlen;
2102
2103 optlen = sizeof (*__domain);
2104 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2105 if (rv != 0)
2106 {
2107 rv = -errno;
2108 goto out;
2109 }
2110
2111 optlen = sizeof (*__type);
2112 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2113 if (rv != 0)
2114 {
2115 rv = -errno;
2116 goto out;
2117 }
2118
2119 optlen = sizeof (*__protocol);
2120 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2121 if (rv != 0)
2122 {
2123 rv = -errno;
2124 goto out;
2125 }
2126
2127 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2128 if (fd < 0)
2129 {
2130 rv = fd;
2131 goto out;
2132 }
2133
2134 pool_get (vsm->vsockets, vsock);
2135 vsocket_init (vsock);
2136
2137 sockidx = vsock - vsm->vsockets;
2138 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2139
2140 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2141 return fd;
2142
2143out:
2144 return rv;
2145}
2146
2147/* If flag is 0, then accept4() is the same as accept().
2148 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2149 */
2150static int
2151vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2152 socklen_t * __restrict __addr_len, int flags)
2153{
2154 int rv = -1;
2155 vcom_socket_main_t *vsm = &vcom_socket_main;
2156 uword *p;
2157 vcom_socket_t *vsock;
2158
2159 int fd;
2160 int sid;
2161 int domain;
2162 int type;
2163 int protocol;
2164
2165 uint8_t addr8[sizeof (struct in6_addr)];
2166 vppcom_endpt_t ep;
2167
2168 ep.ip = addr8;
2169
2170 /* validate flags */
2171
2172 /*
2173 * for documentation
2174 * switch (flags)
2175 * {
2176 * case 0:
2177 * case SOCK_NONBLOCK:
2178 * case SOCK_CLOEXEC:
2179 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2180 * break;
2181 *
2182 * default:
2183 * return -1;
2184 * }
2185 */
2186 /* flags can be 0 or can be bitwise OR
2187 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2188
2189 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2190 {
2191 /* TBD: return proper error code */
2192 return -1;
2193 }
2194
2195 /* TBD: return proper error code */
2196
2197 if (!vcom_socket_is_connection_mode_socket (__fd))
2198 {
2199 return -EOPNOTSUPP;
2200 }
2201
2202 p = hash_get (vsm->sockidx_by_fd, __fd);
2203 if (p)
2204 {
2205 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2206
2207
2208 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2209 if (rv < 0)
2210 {
2211 return rv;
2212 }
2213
2214 /* is blocking */
2215 if (!(rv & O_NONBLOCK))
2216 {
2217 /* socket is not marked as nonblocking
2218 * and no pending connections are present
2219 * on the queue, accept () blocks the caller
2220 * until a connection is present.
2221 */
2222 rv = vppcom_session_accept (vsock->sid, &ep,
2223 -1.0 /* wait forever */ );
2224 }
2225 else
2226 {
2227 /* The file descriptor refers to a socket and has been
2228 * marked nonblocking(O_NONBLOCK) and the accept would
2229 * block.
2230 * */
2231 /* is non blocking */
2232 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2233 /* If the socket is marked nonblocking and
2234 * no pending connections are present on the
2235 * queue, accept fails with the error
2236 * EAGAIN or EWOULDBLOCK
2237 */
2238 if (rv == VPPCOM_ETIMEDOUT)
2239 {
2240 rv = VPPCOM_EAGAIN;
2241 }
2242 }
2243 if (rv < 0)
2244 {
2245 return rv;
2246 }
2247
2248 sid = rv;
2249
2250 /* create a new connected socket resource and set flags
2251 * on the new file descriptor.
2252 * update vsockets and sockidx_by_fd table
2253 * */
2254 fd = vcom_socket_connected_socket (__fd, sid,
2255 &domain, &type, &protocol, flags);
2256 if (fd < 0)
2257 {
2258 return fd;
2259 }
2260
2261 rv = fd;
2262
2263 /* TBD populate __addr and __addr_len */
2264 /* TBD: The returned address is truncated if the buffer
2265 * provided is too small, in this case, __addr_len will
2266 * return a value greater than was supplied to the call.*/
2267 if (__addr)
2268 {
2269 if (ep.is_cut_thru)
2270 {
2271 /* TBD populate __addr and __addr_len */
2272 switch (domain)
2273 {
2274 case AF_INET:
2275 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2276 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2277 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2278 addr8, sizeof (struct in_addr));
2279 /* TBD: populate __addr_len */
2280 if (__addr_len)
2281 {
2282 *__addr_len = sizeof (struct sockaddr_in);
2283 }
2284 break;
2285
2286 case AF_INET6:
2287 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2288 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2289 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2290 __in6_u.__u6_addr8, addr8,
2291 sizeof (struct in6_addr));
2292 /* TBD: populate __addr_len */
2293 if (__addr_len)
2294 {
2295 *__addr_len = sizeof (struct sockaddr_in6);
2296 }
2297 break;
2298
2299 default:
2300 return -EAFNOSUPPORT;
2301 }
2302 }
2303 else
2304 {
2305 switch (ep.is_ip4)
2306 {
2307 case VPPCOM_IS_IP4:
2308 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2309 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2310 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2311 addr8, sizeof (struct in_addr));
2312 /* TBD: populate __addr_len */
2313 if (__addr_len)
2314 {
2315 *__addr_len = sizeof (struct sockaddr_in);
2316 }
2317 break;
2318
2319 case VPPCOM_IS_IP6:
2320 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2321 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2322 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2323 __in6_u.__u6_addr8, addr8,
2324 sizeof (struct in6_addr));
2325 /* TBD: populate __addr_len */
2326 if (__addr_len)
2327 {
2328 *__addr_len = sizeof (struct sockaddr_in6);
2329 }
2330 break;
2331
2332 default:
2333 return -EAFNOSUPPORT;
2334 }
2335 }
2336 }
2337 else
2338 {
2339 /* when __addr is NULL, nothing is filled in,
2340 * in this case, __addr_len is not used,
2341 * and should also be null
2342 * */
2343 if (__addr_len)
2344 {
2345 /* TBD: return proper error code */
2346 return -1;
2347 }
2348 }
2349 }
2350
2351 return rv;
2352}
2353
2354int
2355vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2356 socklen_t * __restrict __addr_len)
2357{
2358 /* set flags to 0 for accept() */
2359 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2360}
2361
2362#ifdef __USE_GNU
2363int
2364vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2365 socklen_t * __restrict __addr_len, int __flags)
2366{
2367 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2368 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2369}
2370#endif
2371
2372/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002373static inline int
2374vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002375{
2376 return 0;
2377}
2378
2379int
2380vcom_socket_shutdown (int __fd, int __how)
2381{
2382 int rv = -1;
2383 vcom_socket_main_t *vsm = &vcom_socket_main;
2384 uword *p;
2385 vcom_socket_t *vsock;
2386
2387 p = hash_get (vsm->sockidx_by_fd, __fd);
2388 if (p)
2389 {
2390 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2391 switch (__how)
2392 {
2393 case SHUT_RD:
2394 case SHUT_WR:
2395 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002396 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002397 return rv;
2398 break;
2399
2400 default:
2401 return -EINVAL;
2402 break;
2403 }
2404 }
2405
2406 return rv;
2407}
2408
2409int
2410vcom_socket_epoll_create1 (int __flags)
2411{
2412 int rv = -1;
2413 vcom_socket_main_t *vsm = &vcom_socket_main;
2414 vcom_epoll_t *vepoll;
2415
2416 i32 epfd;
2417 i32 vep_idx;
2418 i32 epollidx;
2419
2420 epfd = vcom_socket_open_epoll (__flags);
2421 if (epfd < 0)
2422 {
2423 rv = epfd;
2424 goto out;
2425 }
2426
2427 vep_idx = vppcom_epoll_create ();
2428 if (vep_idx < 0)
2429 {
2430 rv = vep_idx;
2431 goto out_close_epoll;
2432 }
2433
2434 pool_get (vsm->vepolls, vepoll);
2435 vepoll_init (vepoll);
2436
2437 epollidx = vepoll - vsm->vepolls;
2438 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2439
2440 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2441
2442 return epfd;
2443
2444out_close_epoll:
2445 vcom_socket_close_epoll (epfd);
2446out:
2447 return rv;
2448}
2449
2450/*
2451 * PRE: vppcom_epoll_ctl() is successful
2452 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2453 */
2454int
2455vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2456 struct epoll_event *__event,
2457 i32 vep_idx, vcom_epoll_t * vepoll,
2458 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2459 int free_vepitem_on_del)
2460{
2461 int rv = -1;
2462 vcom_socket_main_t *vsm = &vcom_socket_main;
2463 vcom_epitem_t *vepitem;
2464
2465 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2466 uword *p;
2467 i32 vepitemidx;
2468
2469 i32 *vepitemidxs = 0;
2470
2471 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2472
2473 i32 vec_idx;
2474
2475 /* perform control operations on the epoll instance */
2476 switch (__op)
2477 {
2478 case EPOLL_CTL_ADD:
2479 /*
2480 * supplied file descriptor is already
2481 * registered with this epoll instance
2482 * */
2483 /* vepitem exists */
2484 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2485 if (p)
2486 {
2487 rv = -EEXIST;
2488 goto out;
2489 }
2490
2491 /* add a new vepitem */
2492 pool_get (vsm->vepitems, vepitem);
2493 vepitem_init (vepitem);
2494
2495 vepitemidx = vepitem - vsm->vepitems;
2496 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2497 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2498
2499 /* update epitemidxs */
2500 /* by_epfd */
2501 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2502 if (!p) /* not exist */
2503 {
2504 vepitemidxs = 0;
2505 vec_add1 (vepitemidxs, vepitemidx);
2506 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2507 }
2508 else /* exists */
2509 {
2510 vepitemidxs = *(i32 **) p;
2511 vec_add1 (vepitemidxs, vepitemidx);
2512 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2513 }
2514 /* update epitemidxs */
2515 /* by_fd */
2516 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2517 if (!p) /* not exist */
2518 {
2519 vepitemidxs = 0;
2520 vec_add1 (vepitemidxs, vepitemidx);
2521 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2522 }
2523 else /* exists */
2524 {
2525 vepitemidxs = *(i32 **) p;
2526 vec_add1 (vepitemidxs, vepitemidx);
2527 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2528 }
2529
2530 /* increment vepoll fd count by 1 */
2531 vepoll->count += 1;
2532
2533 rv = 0;
2534 goto out;
2535 break;
2536
2537 case EPOLL_CTL_MOD:
2538 /*
2539 * supplied file descriptor is not
2540 * registered with this epoll instance
2541 * */
2542 /* vepitem not exist */
2543 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2544 if (!p)
2545 {
2546 rv = -ENOENT;
2547 goto out;
2548 }
2549 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2550 if (vepitem)
2551 {
2552 vepitem->event = *__event;
2553 vepitem->revent = revent;
2554 }
2555
2556 rv = 0;
2557 goto out;
2558 break;
2559
2560 case EPOLL_CTL_DEL:
2561 /*
2562 * supplied file descriptor is not
2563 * registered with this epoll instance
2564 * */
2565 /* vepitem not exist */
2566 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2567 if (!p)
2568 {
2569 rv = -ENOENT;
2570 goto out;
2571 }
2572 vepitemidx = *(i32 *) p;
2573 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2574
2575 /* update epitemidxs */
2576 /* by_epfd */
2577 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2578 if (!p) /* not exist */
2579 {
2580 rv = -ENOENT;
2581 goto out;
2582 }
2583 else /* exists */
2584 {
2585 vepitemidxs = *(i32 **) p;
2586 vec_idx = vec_search (vepitemidxs, vepitemidx);
2587 if (vec_idx != ~0)
2588 {
2589 vec_del1 (vepitemidxs, vec_idx);
2590 if (!vec_len (vepitemidxs))
2591 {
2592 vec_free (vepitemidxs);
2593 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2594 }
2595 }
2596 }
2597
2598 /* update epitemidxs */
2599 /* by_fd */
2600 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2601 if (!p) /* not exist */
2602 {
2603 rv = -ENOENT;
2604 goto out;
2605 }
2606 else /* exists */
2607 {
2608 vepitemidxs = *(i32 **) p;
2609 vec_idx = vec_search (vepitemidxs, vepitemidx);
2610 if (vec_idx != ~0)
2611 {
2612 vec_del1 (vepitemidxs, vec_idx);
2613 if (!vec_len (vepitemidxs))
2614 {
2615 vec_free (vepitemidxs);
2616 hash_unset (vsm->epitemidxs_by_fd, __fd);
2617 }
2618 }
2619 }
2620
2621 /* pool put vepitem */
2622 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2623 if (free_vepitem_on_del)
2624 {
2625 if (!vepitem)
2626 {
2627 rv = -ENOENT;
2628 goto out;
2629 }
2630 vepitem_init (vepitem);
2631 pool_put (vsm->vepitems, vepitem);
2632 }
2633 else
2634 {
2635 if (!vepitem)
2636 {
2637 vepitem_init (vepitem);
2638 }
2639 }
2640
2641 /* decrement vepoll fd count by 1 */
2642 vepoll->count -= 1;
2643
2644 rv = 0;
2645 goto out;
2646 break;
2647
2648 default:
2649 rv = -EINVAL;
2650 goto out;
2651 break;
2652 }
2653
2654out:
2655 return rv;
2656}
2657
2658/*
2659 * PRE: 00. null pointer check on __event
2660 * 01. all other parameters are validated
2661 */
2662
2663static int
2664vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2665 struct epoll_event *__event,
2666 int free_vepitem_on_del)
2667{
2668 int rv = -1;
2669
2670 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2671 vcom_epoll_t *vepoll;
2672
2673 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2674 void *vfd;
2675 vcom_epoll_t *vfd_vepoll;
2676 vcom_socket_t *vfd_vsock;
2677
2678 i32 vep_idx;
2679 i32 vfd_id;
2680
2681 vcom_fd_type_t type = FD_TYPE_INVALID;
2682
2683 /* validate __event */
2684
2685 /* get vep_idx and vepoll */
2686 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2687 if (vep_idx == INVALID_VEP_IDX)
2688 {
2689 return -EBADF;
2690 }
2691
2692 /* get vcom fd type, vfd_id and vfd */
2693 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2694 if (vfd_id != INVALID_SESSION_ID)
2695 {
2696 type = FD_TYPE_VCOM_SOCKET;
2697 vfd = vfd_vsock;
2698 }
2699 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2700 != INVALID_VEP_IDX)
2701 {
2702 type = FD_TYPE_EPOLL;
2703 vfd = vfd_vepoll;
2704 }
2705 else
2706 {
2707 /* FD_TYPE_KERNEL not supported by epoll instance */
2708 type = FD_TYPE_INVALID;
2709 return -EBADF;
2710 }
2711
2712
2713 /* vepoll and vsock are now valid */
2714 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2715 if (rv < 0)
2716 {
2717 return rv;
2718 }
2719
2720 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2721 __event,
2722 vep_idx, vepoll,
2723 vfd_id, vfd, type, free_vepitem_on_del);
2724 return rv;
2725}
2726
2727int
2728vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2729 struct epoll_event *__event)
2730{
2731 int rv = -1;
2732
2733 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2734 return rv;
2735}
2736
2737static int
2738vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2739 struct epoll_event *__event)
2740{
2741 int rv = -1;
2742
2743 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2744 return rv;
2745}
2746
2747int
2748vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2749 int __maxevents, int __timeout,
2750 const __sigset_t * __ss)
2751{
2752 int rv = -EBADF;
2753
2754 /* in seconds eg. 3.123456789 seconds */
2755 double time_to_wait = (double) 0;
2756
2757 i32 vep_idx;
2758
2759 /* validate __event */
2760 if (!__events)
2761 {
2762 rv = -EFAULT;
2763 goto out;
2764 }
2765
2766 /* validate __timeout */
2767 if (__timeout > 0)
2768 {
2769 time_to_wait = (double) __timeout / (double) 1000;
2770 }
2771 else if (__timeout == 0)
2772 {
2773 time_to_wait = (double) 0;
2774 }
2775 else if (__timeout == -1)
2776 {
2777 time_to_wait = ~0;
2778 }
2779 else
2780 {
2781 rv = -EBADF;
2782 goto out;
2783 }
2784
2785 /* get vep_idx */
2786 vep_idx = vcom_socket_get_vep_idx (__epfd);
2787 if (vep_idx != INVALID_VEP_IDX)
2788 {
2789 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2790 }
2791out:
2792 return rv;
2793}
2794
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002795static inline void
2796vcom_pollfds_2_selectfds (
2797 /* src */
2798 struct pollfd *__fds, nfds_t __nfds,
2799 /* dest */
2800 int vcom_nfds,
2801 fd_set * __restrict vcom_readfds,
2802 fd_set * __restrict vcom_writefds,
2803 fd_set * __restrict vcom_exceptfds)
2804{
2805 nfds_t fds_idx = 0;
2806
2807 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2808 {
2809 /* ignore negative fds */
2810 if (__fds[fds_idx].fd < 0)
2811 {
2812 continue;
2813 }
2814
2815 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2816 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2817
2818 /* requested events */
2819 if (__fds[fds_idx].events)
2820 {
2821 if (__fds[fds_idx].events & POLLIN)
2822 {
2823 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2824 }
2825 if (__fds[fds_idx].events & POLLPRI)
2826 {
2827 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2828 }
2829 if (__fds[fds_idx].events & POLLOUT)
2830 {
2831 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2832 }
2833#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2834 if (__fds[fds_idx].events & POLLRDNORM)
2835 {
2836 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2837 }
2838 if (__fds[fds_idx].events & POLLRDBAND)
2839 {
2840 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2841 }
2842 if (__fds[fds_idx].events & POLLWRNORM)
2843 {
2844 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2845 }
2846 if (__fds[fds_idx].events & POLLWRBAND)
2847 {
2848 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2849 }
2850#endif
2851 }
2852 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2853}
2854
2855static inline void
2856vcom_selectfds_2_pollfds (
2857 /* dest */
2858 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2859 /* src */
2860 int vcom_nfds,
2861 fd_set * __restrict vcom_readfds,
2862 fd_set * __restrict vcom_writefds,
2863 fd_set * __restrict vcom_exceptfds)
2864{
2865 nfds_t fds_idx = 0;
2866
2867
2868 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2869 {
2870 /* ignore negative fds */
2871 if (__fds[fds_idx].fd < 0)
2872 {
2873 __fds[fds_idx].revents = 0;
2874 }
2875
2876 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2877 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2878 {
2879 /*
2880 * TBD: for now any select exception
2881 * is flagged as POLLERR
2882 * */
2883 __fds[fds_idx].revents |= POLLERR;
2884 }
2885
2886 /* requested events */
2887 if (__fds[fds_idx].events & POLLIN)
2888 {
2889 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2890 {
2891 __fds[fds_idx].revents |= POLLIN;
2892 }
2893 }
2894 if (__fds[fds_idx].events & POLLPRI)
2895 {
2896 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2897 {
2898 __fds[fds_idx].revents |= POLLIN;
2899 }
2900 }
2901 if (__fds[fds_idx].events & POLLOUT)
2902 {
2903 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2904 {
2905 __fds[fds_idx].revents |= POLLOUT;
2906 }
2907 }
2908#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2909 if (__fds[fds_idx].events & POLLRDNORM)
2910 {
2911 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2912 {
2913 __fds[fds_idx].revents |= POLLRDNORM;
2914 }
2915 }
2916 if (__fds[fds_idx].events & POLLRDBAND)
2917 {
2918 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2919 {
2920 __fds[fds_idx].revents |= POLLRDBAND;
2921 }
2922 }
2923 if (__fds[fds_idx].events & POLLWRNORM)
2924 {
2925 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2926 {
2927 __fds[fds_idx].revents |= POLLWRNORM;
2928 }
2929 }
2930 if (__fds[fds_idx].events & POLLWRBAND)
2931 {
2932 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2933 {
2934 __fds[fds_idx].revents |= POLLWRBAND;
2935 }
2936 }
2937#endif
2938 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2939
2940 /*
2941 * nfd:
2942 * the number of structures which have nonzero revents fields
2943 * (in other words, those descriptors with events or
2944 * errors reported)
2945 * */
2946 *nfd = 0;
2947 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2948 {
2949 /* ignore negative fds */
2950 if (__fds[fds_idx].fd < 0)
2951 {
2952 continue;
2953 }
2954
2955 if (__fds[fds_idx].revents)
2956 {
2957 (*nfd)++;
2958 }
2959 }
2960}
2961
2962/*
2963 * PRE: parameters are validated,
2964 * vcom_socket_poll is always called with __timeout set to zero
2965 * hence returns immediately
2966 *
2967 * ACTION: handle non negative validated vcom fds and ignore rest
2968 */
2969
2970/*
2971 * implements vcom_socket_poll () interface
2972 *
2973 * internally uses vcom_socket_select ()
2974 * to realize the behavior
2975 * */
2976int
2977vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
2978 int __timeout)
2979{
2980 int rv;
2981 pid_t pid = getpid ();
2982
2983 nfds_t fds_idx = 0;
2984 int nfd = 0;
2985
2986 /* vcom */
2987 int vcom_nfds = 0;
2988 fd_set vcom_readfds;
2989 fd_set vcom_writefds;
2990 fd_set vcom_exceptfds;
2991 int vcom_nfd = -1;
2992 /* invalid max_vcom_fd is -1 */
2993 int max_vcom_fd = -1;
2994
2995 /* __timeout is zero to get ready events and return immediately */
2996 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
2997
2998 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002999 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003000 {
3001 rv = -EINVAL;
3002 goto poll_done;
3003 }
3004
3005 /* zero vcom fd sets */
3006 /*
3007 * V vcom fd set
3008 */
3009#define _(V) \
3010 FD_ZERO ((V))
3011
3012 _(&vcom_readfds);
3013 _(&vcom_writefds);
3014 _(&vcom_exceptfds);
3015#undef _
3016
3017 vcom_nfds = 0;
3018 vcom_nfd = -1;
3019
3020
3021 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3022 {
3023 /* ignore negative fds */
3024 if (__fds[fds_idx].fd < 0)
3025 {
3026 continue;
3027 }
3028
3029 /* non negative validated vcom fds */
3030 if (__fds[fds_idx].fd > FD_SETSIZE)
3031 {
3032 rv = -EINVAL;
3033 goto poll_done;
3034 }
3035
3036 /* max_vcom_fd and vcom_nfd */
3037 if (__fds[fds_idx].fd > max_vcom_fd)
3038 {
3039 /* requested events */
3040 if (__fds[fds_idx].events)
3041 {
3042 max_vcom_fd = __fds[fds_idx].fd;
3043 }
3044 }
3045 ++vcom_nfd;
3046 }
3047
3048 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3049
3050 if (!vcom_nfds)
3051 {
3052 rv = vcom_nfds;
3053 goto poll_done;
3054 }
3055
3056 vcom_pollfds_2_selectfds (
3057 /* src */
3058 __fds, __nfds,
3059 /* dest */
3060 vcom_nfds,
3061 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3062
3063 /* select on vcom fds */
3064 vcom_nfd = vcom_socket_select (vcom_nfds,
3065 &vcom_readfds,
3066 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003067 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003068 fprintf (stderr,
3069 "[%d] vcom_socket_select: "
3070 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3071
3072 if (vcom_nfd < 0)
3073 {
3074 rv = vcom_nfd;
3075 goto poll_done;
3076 }
3077
3078 vcom_selectfds_2_pollfds (
3079 /* dest */
3080 __fds, __nfds, &nfd,
3081 /* src */
3082 vcom_nfds,
3083 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3084
3085 rv = nfd;
3086
3087poll_done:
3088 return rv;
3089}
3090
3091/*
3092 * TBD: remove this static function once vppcom
3093 * has an implementation in place
3094 *
3095 * ACTION:
3096 */
3097static int
3098vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3099{
3100 return -EOPNOTSUPP;
3101}
3102
3103int
3104vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3105 int __timeout)
3106{
3107 nfds_t fds_idx = 0;
3108
3109 /* in seconds eg. 3.123456789 seconds */
3110 double time_to_wait = (double) 0;
3111
3112 i32 sid;
3113 i32 vep_idx;
3114
3115 /* replace vcom fd with session idx */
3116 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3117 {
3118 /* ignore negative fds */
3119 if (__fds[fds_idx].fd < 0)
3120 {
3121 continue;
3122 }
3123
3124 /* non negative validated vcom fds */
3125 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3126 if (sid != INVALID_SESSION_ID)
3127 {
3128 __fds[fds_idx].fd = sid;
3129 }
3130 else
3131 {
3132 /* get vep_idx */
3133 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3134 if (vep_idx != INVALID_VEP_IDX)
3135 {
3136 __fds[fds_idx].fd = vep_idx;
3137 }
3138 else
3139 {
3140 return -EBADF;
3141 }
3142 }
3143 }
3144
3145 /* validate __timeout */
3146 if (__timeout > 0)
3147 {
3148 time_to_wait = (double) __timeout / (double) 1000;
3149 }
3150 else if (__timeout == 0)
3151 {
3152 time_to_wait = (double) 0;
3153 }
3154 else if (__timeout < 0)
3155 {
3156 time_to_wait = ~0;
3157 }
3158 else
3159 {
3160 return -EBADF;
3161 }
3162
3163 return vppcom_poll (__fds, __nfds, time_to_wait);
3164}
3165
3166int
3167vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3168{
3169 /* select an implementation */
3170
3171 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3172 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3173}
3174
3175#ifdef __USE_GNU
3176int
3177vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3178 const struct timespec *__timeout, const __sigset_t * __ss)
3179{
3180 return -EOPNOTSUPP;
3181}
3182#endif
3183
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003184int
3185vcom_socket_main_init (void)
3186{
3187 vcom_socket_main_t *vsm = &vcom_socket_main;
3188
3189 if (VCOM_DEBUG > 0)
3190 printf ("vcom_socket_main_init\n");
3191
3192 if (!vsm->init)
3193 {
3194 /* TBD: define FD_MAXSIZE and use it here */
3195 pool_alloc (vsm->vsockets, FD_SETSIZE);
3196 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3197
3198 pool_alloc (vsm->vepolls, FD_SETSIZE);
3199 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3200
3201 pool_alloc (vsm->vepitems, FD_SETSIZE);
3202 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3203
3204 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3205 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3206
3207 vsm->init = 1;
3208 }
3209
3210 return 0;
3211}
3212
3213
3214void
3215vcom_socket_main_show (void)
3216{
3217 vcom_socket_main_t *vsm = &vcom_socket_main;
3218 vcom_socket_t *vsock;
3219
3220 vcom_epoll_t *vepoll;
3221
3222 vcom_epitem_t *vepitem;
3223
3224 i32 epfd;
3225 i32 fd;
3226 i32 *vepitemidxs, *vepitemidxs_var;
3227
3228 if (vsm->init)
3229 {
3230 /* from active list of vsockets show vsock */
3231
3232 /* *INDENT-OFF* */
3233 pool_foreach (vsock, vsm->vsockets,
3234 ({
3235 printf(
3236 "fd='%04d', sid='%08x',type='%-30s'\n",
3237 vsock->fd, vsock->sid,
3238 vcom_socket_type_str (vsock->type));
3239 }));
3240 /* *INDENT-ON* */
3241
3242 /* from active list of vepolls, show vepoll */
3243
3244 /* *INDENT-OFF* */
3245 pool_foreach (vepoll, vsm->vepolls,
3246 ({
3247 printf(
3248 "epfd='%04d', vep_idx='%08x', "
3249 "type='%-30s', "
3250 "flags='%d', count='%d', close='%d'\n",
3251 vepoll->epfd, vepoll->vep_idx,
3252 vcom_socket_epoll_type_str (vepoll->type),
3253 vepoll->flags, vepoll->count, vepoll->close);
3254 }));
3255 /* *INDENT-ON* */
3256
3257 /* from active list of vepitems, show vepitem */
3258
3259 /* *INDENT-OFF* */
3260 pool_foreach (vepitem, vsm->vepitems,
3261 ({
3262 printf(
3263 "epfd='%04d', fd='%04d', "
3264 "next_fd='%04d', prev_fd='%04d', "
3265 "type='%-30s', "
3266 "events='%04x', revents='%04x'\n",
3267 vepitem->epfd, vepitem->fd,
3268 vepitem->next_fd, vepitem->prev_fd,
3269 vcom_socket_vcom_fd_type_str (vepitem->type),
3270 vepitem->event.events, vepitem->revent.events);
3271 }));
3272
3273 /* *INDENT-ON* */
3274
3275 /* show epitemidxs for epfd */
3276 /* *INDENT-OFF* */
3277 hash_foreach (epfd, vepitemidxs,
3278 vsm->epitemidxs_by_epfd,
3279 ({
3280 printf("\n[ '%04d': ", epfd);
3281 vec_foreach (vepitemidxs_var,vepitemidxs)
3282 {
3283 printf("'%04d' ", (int)vepitemidxs_var[0]);
3284 }
3285 printf("]\n");
3286 }));
3287 /* *INDENT-ON* */
3288
3289 /* show epitemidxs for fd */
3290 /* *INDENT-OFF* */
3291 hash_foreach (fd, vepitemidxs,
3292 vsm->epitemidxs_by_fd,
3293 ({
3294 printf("\n{ '%04d': ", fd);
3295 vec_foreach (vepitemidxs_var,vepitemidxs)
3296 {
3297 printf("'%04d' ", (int)vepitemidxs_var[0]);
3298 }
3299 printf("}\n");
3300 }));
3301 /* *INDENT-ON* */
3302
3303 }
3304}
3305
3306void
3307vcom_socket_main_destroy (void)
3308{
3309 vcom_socket_main_t *vsm = &vcom_socket_main;
3310 vcom_socket_t *vsock;
3311
3312 vcom_epoll_t *vepoll;
3313
3314 vcom_epitem_t *vepitem;
3315
3316 i32 epfd;
3317 i32 fd;
3318 i32 *vepitemidxs;
3319
3320
3321 if (VCOM_DEBUG > 0)
3322 printf ("vcom_socket_main_destroy\n");
3323
3324 if (vsm->init)
3325 {
3326
3327 /*
3328 * from active list of vepitems,
3329 * remove all "vepitem" elements from the pool in a safe way
3330 * */
3331
3332 /* *INDENT-OFF* */
3333 pool_flush (vepitem, vsm->vepitems,
3334 ({
3335 if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
3336 {
3337 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3338 vepitem->fd, NULL);
3339 vepitem_init (vepitem);
3340 }
3341 }));
3342 /* *INDENT-ON* */
3343
3344 pool_free (vsm->vepitems);
3345 hash_free (vsm->epitemidx_by_epfdfd);
3346
3347 /* free vepitemidxs for each epfd */
3348 /* *INDENT-OFF* */
3349 hash_foreach (epfd, vepitemidxs,
3350 vsm->epitemidxs_by_epfd,
3351 ({
3352 vec_free (vepitemidxs);
3353 }));
3354 /* *INDENT-ON* */
3355 hash_free (vsm->epitemidxs_by_epfd);
3356
3357 /* free vepitemidxs for each fd */
3358 /* *INDENT-OFF* */
3359 hash_foreach (fd, vepitemidxs,
3360 vsm->epitemidxs_by_fd,
3361 ({
3362 vec_free (vepitemidxs);
3363 }));
3364 /* *INDENT-ON* */
3365 hash_free (vsm->epitemidxs_by_fd);
3366
3367
3368 /*
3369 * from active list of vsockets,
3370 * close socket and vppcom session
3371 * */
3372
3373 /* *INDENT-OFF* */
3374 pool_foreach (vsock, vsm->vsockets,
3375 ({
3376 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3377 {
3378 vppcom_session_close (vsock->sid);
3379 vcom_socket_close_socket (vsock->fd);
3380 vsocket_init (vsock);
3381 }
3382 }));
3383 /* *INDENT-ON* */
3384
3385 /*
3386 * return vsocket element to the pool
3387 * */
3388
3389 /* *INDENT-OFF* */
3390 pool_flush (vsock, vsm->vsockets,
3391 ({
3392 // vsocket_init(vsock);
3393 ;
3394 }));
3395 /* *INDENT-ON* */
3396
3397 pool_free (vsm->vsockets);
3398 hash_free (vsm->sockidx_by_fd);
3399
3400 /*
3401 * from active list of vepolls,
3402 * close epoll and vppcom_epoll
3403 * */
3404
3405 /* *INDENT-OFF* */
3406 pool_foreach (vepoll, vsm->vepolls,
3407 ({
3408 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3409 {
3410 vppcom_session_close (vepoll->vep_idx);
3411 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3412 vepoll_init (vepoll);
3413 }
3414 }));
3415 /* *INDENT-ON* */
3416
3417 /*
3418 * return vepoll element to the pool
3419 * */
3420
3421 /* *INDENT-OFF* */
3422 pool_flush (vepoll, vsm->vepolls,
3423 ({
3424 // vepoll_init(vepoll);
3425 ;
3426 }));
3427 /* *INDENT-ON* */
3428
3429 pool_free (vsm->vepolls);
3430 hash_free (vsm->epollidx_by_epfd);
3431
3432 vsm->init = 0;
3433 }
3434}
3435
3436
3437/*
3438 * fd.io coding-style-patch-verification: ON
3439 *
3440 * Local Variables:
3441 * eval: (c-set-style "gnu")
3442 * End:
3443 */