blob: 6ce15148d219414bfffef67c41a04fb2547eb6ce [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 }
Dave Wallace60f54822017-10-24 20:47:45 -0400468 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700469 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
470 return rv;
471 }
472 /* The file descriptor refers to a socket and has been
473 * marked nonblocking(O_NONBLOCK) and the read would
474 * block.
475 * */
476 /* is non blocking */
477 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
478 return rv;
479}
480
481ssize_t
482vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
483{
484 int rv;
485 vcom_socket_main_t *vsm = &vcom_socket_main;
486 uword *p;
487 vcom_socket_t *vsock;
488 ssize_t total = 0, len = 0;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400489 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700490
491 p = hash_get (vsm->sockidx_by_fd, __fd);
492 if (!p)
493 return -EBADF;
494
495 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
496 if (!vsock)
497 return -ENOTSOCK;
498
499 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
500 return -EINVAL;
501
502 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
503 return -EINVAL;
504
505 /* Sanity check */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400506 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700507 {
508 if (SSIZE_MAX - len < __iov[i].iov_len)
509 return -EINVAL;
510 len += __iov[i].iov_len;
511 }
512
513 rv = vcom_fcntl (__fd, F_GETFL, 0);
514 if (rv < 0)
515 {
516 return rv;
517 }
518
519 /* is blocking */
520 if (!(rv & O_NONBLOCK))
521 {
522 do
523 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400524 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700525 {
526 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
527 __iov[i].iov_len);
528 if (rv < 0)
529 break;
530 else
531 {
532 total += rv;
533 if (rv < __iov[i].iov_len)
534 /* Read less than buffer provided, no point to continue */
535 break;
536 }
537 }
538 }
Dave Wallace60f54822017-10-24 20:47:45 -0400539 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700540 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
541 return total;
542 }
543
544 /* is non blocking */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400545 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700546 {
547 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
548 __iov[i].iov_len);
549 if (rv < 0)
550 {
551 if (total > 0)
552 break;
553 else
554 {
555 errno = rv;
556 return rv;
557 }
558 }
559 else
560 {
561 total += rv;
562 if (rv < __iov[i].iov_len)
563 /* Read less than buffer provided, no point to continue */
564 break;
565 }
566 }
567 return total;
568}
569
570ssize_t
571vcom_socket_write (int __fd, const void *__buf, size_t __n)
572{
573 int rv = -1;
574 vcom_socket_main_t *vsm = &vcom_socket_main;
575 uword *p;
576 vcom_socket_t *vsock;
577
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400578 if (!__buf)
579 {
580 return -EINVAL;
581 }
582
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700583 p = hash_get (vsm->sockidx_by_fd, __fd);
584 if (!p)
585 return -EBADF;
586
587 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
588 if (!vsock)
589 return -ENOTSOCK;
590
591 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
592 return -EINVAL;
593
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700594 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
595 return rv;
596}
597
598ssize_t
599vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
600{
601 int rv = -1;
602 ssize_t total = 0;
603 vcom_socket_main_t *vsm = &vcom_socket_main;
604 uword *p;
605 vcom_socket_t *vsock;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400606 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700607
608 p = hash_get (vsm->sockidx_by_fd, __fd);
609 if (!p)
610 return -EBADF;
611
612 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
613 if (!vsock)
614 return -ENOTSOCK;
615
616 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
617 return -EINVAL;
618
619 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
620 return -EINVAL;
621
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400622 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700623 {
624 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
625 __iov[i].iov_len);
626 if (rv < 0)
627 {
628 if (total > 0)
629 break;
630 else
631 return rv;
632 }
633 else
634 total += rv;
635 }
636 return total;
637}
638
639/*
640 * RETURN: 0 - invalid cmd
641 * 1 - cmd not handled by vcom and vppcom
642 * 2 - cmd handled by vcom socket resource
643 * 3 - cmd handled by vppcom
644 * */
645/* TBD: incomplete list of cmd */
646static int
647vcom_socket_check_fcntl_cmd (int __cmd)
648{
649 switch (__cmd)
650 {
651 /*cmd not handled by vcom and vppcom */
652 /* Fallthrough */
653 case F_DUPFD:
654 case F_DUPFD_CLOEXEC:
655 return 1;
656
657 /* cmd handled by vcom socket resource */
658 /* Fallthrough */
659 case F_GETFD:
660 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700661 case F_GETLK:
662 case F_SETLK:
663 case F_SETLKW:
664 case F_GETOWN:
665 case F_SETOWN:
666 return 2;
667
Stevenb59f2272017-10-12 17:10:33 -0700668 /* cmd handled by vcom and vppcom */
669 case F_SETFL:
670 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700671 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700672
673 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700674 default:
Stevenb59f2272017-10-12 17:10:33 -0700675 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700676 }
677 return 0;
678}
679
Dave Wallacee22aa742017-10-20 12:30:38 -0400680static inline int
681vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700682{
Stevenb59f2272017-10-12 17:10:33 -0700683 int flags = va_arg (__ap, int);
684 int rv = -EOPNOTSUPP;
685 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700686
Stevenb59f2272017-10-12 17:10:33 -0700687 size = sizeof (flags);
688 if (__cmd == F_SETFL)
689 {
690 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
691 }
692 else if (__cmd == F_GETFL)
693 {
694 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
695 if (rv == VPPCOM_OK)
696 rv = flags;
697 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700698
699 return rv;
700}
701
702int
703vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
704{
705 int rv = -EBADF;
706 vcom_socket_main_t *vsm = &vcom_socket_main;
707 uword *p;
708 vcom_socket_t *vsock;
709
710 p = hash_get (vsm->sockidx_by_fd, __fd);
711 if (!p)
712 return -EBADF;
713
714 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
715 if (!vsock)
716 return -ENOTSOCK;
717
718 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
719 return -EINVAL;
720
721 switch (vcom_socket_check_fcntl_cmd (__cmd))
722 {
723 /* invalid cmd */
724 case 0:
725 rv = -EBADF;
726 break;
727 /*cmd not handled by vcom and vppcom */
728 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700729 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700730 break;
731 /* cmd handled by vcom socket resource */
732 case 2:
733 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
734 break;
735 /* cmd handled by vppcom */
736 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400737 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700738 break;
739
740 default:
741 rv = -EINVAL;
742 break;
743 }
744
745 return rv;
746}
747
Stevenb59f2272017-10-12 17:10:33 -0700748/*
749 * RETURN: 0 - invalid cmd
750 * 1 - cmd not handled by vcom and vppcom
751 * 2 - cmd handled by vcom socket resource
752 * 3 - cmd handled by vppcom
753 */
754static int
755vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
756{
757 int rc;
758
759 switch (__cmd)
760 {
761 /* cmd handled by vppcom */
762 case FIONREAD:
763 rc = 3;
764 break;
765
766 /* cmd not handled by vcom and vppcom */
767 default:
768 rc = 1;
769 break;
770 }
771 return rc;
772}
773
Dave Wallacee22aa742017-10-20 12:30:38 -0400774static inline int
775vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
Stevenb59f2272017-10-12 17:10:33 -0700776{
777 int rv;
778
779 if (__cmd == FIONREAD)
780 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
781 else
782 rv = -EOPNOTSUPP;
783 return rv;
784}
785
786int
787vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
788{
789 int rv = -EBADF;
790 vcom_socket_main_t *vsm = &vcom_socket_main;
791 uword *p;
792 vcom_socket_t *vsock;
793
794 p = hash_get (vsm->sockidx_by_fd, __fd);
795 if (!p)
796 return -EBADF;
797
798 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
799 if (!vsock)
800 return -ENOTSOCK;
801
802 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
803 return -EINVAL;
804
805 switch (vcom_socket_check_ioctl_cmd (__cmd))
806 {
807 /* Not supported cmd */
808 case 0:
809 rv = -EOPNOTSUPP;
810 break;
811
812 /* cmd not handled by vcom and vppcom */
813 case 1:
814 rv = libc_vioctl (vsock->fd, __cmd, __ap);
815 break;
816
817 /* cmd handled by vcom socket resource */
818 case 2:
819 rv = libc_vioctl (vsock->fd, __cmd, __ap);
820 break;
821
822 /* cmd handled by vppcom */
823 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400824 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
Stevenb59f2272017-10-12 17:10:33 -0700825 break;
826
827 default:
828 rv = -EINVAL;
829 break;
830 }
831
832 return rv;
833}
834
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700835static inline int
836vcom_socket_fds_2_sid_fds (
837 /* dest */
838 int *vcom_nsid_fds,
839 fd_set * __restrict vcom_rd_sid_fds,
840 fd_set * __restrict vcom_wr_sid_fds,
841 fd_set * __restrict vcom_ex_sid_fds,
842 /* src */
843 int vcom_nfds,
844 fd_set * __restrict vcom_readfds,
845 fd_set * __restrict vcom_writefds,
846 fd_set * __restrict vcom_exceptfds)
847{
848 int rv = 0;
849 int fd;
850 int sid;
851 /* invalid max_sid is -1 */
852 int max_sid = -1;
853 int nsid = 0;
854
855 /*
856 * set sid in sid sets corresponding to fd's in fd sets
857 * compute nsid and vcom_nsid_fds from sid sets
858 */
859
860 for (fd = 0; fd < vcom_nfds; fd++)
861 {
862 /*
863 * F fd set, src
864 * S sid set, dest
865 */
866#define _(S,F) \
867 if ((F) && (S) && FD_ISSET (fd, (F))) \
868 { \
869 sid = vcom_socket_get_sid (fd); \
870 if (sid != INVALID_SESSION_ID) \
871 { \
872 FD_SET (sid, (S)); \
873 if (sid > max_sid) \
874 { \
875 max_sid = sid; \
876 } \
877 ++nsid; \
878 } \
879 else \
880 { \
881 rv = -EBADFD; \
882 goto done; \
883 } \
884 }
885
886
887 _(vcom_rd_sid_fds, vcom_readfds);
888 _(vcom_wr_sid_fds, vcom_writefds);
889 _(vcom_ex_sid_fds, vcom_exceptfds);
890#undef _
891 }
892
893 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
894 rv = nsid;
895
896done:
897 return rv;
898}
899
900/*
901 * PRE: 00. sid sets were derived from fd sets
902 * 01. sid sets were updated with sids that actually changed
903 * status
904 * 02. fd sets still has watched fds
905 *
906 * This function will modify in place fd sets to indicate which fd's
907 * actually changed status(inferred from sid sets)
908 */
909static inline int
910vcom_socket_sid_fds_2_fds (
911 /* dest */
912 int *new_vcom_nfds,
913 int vcom_nfds,
914 fd_set * __restrict vcom_readfds,
915 fd_set * __restrict vcom_writefds,
916 fd_set * __restrict vcom_exceptfds,
917 /* src */
918 int vcom_nsid_fds,
919 fd_set * __restrict vcom_rd_sid_fds,
920 fd_set * __restrict vcom_wr_sid_fds,
921 fd_set * __restrict vcom_ex_sid_fds)
922{
923 int rv = 0;
924 int fd;
925 int sid;
926 /* invalid max_fd is -1 */
927 int max_fd = -1;
928 int nfd = 0;
929
930
931 /*
932 * modify in place fd sets to indicate which fd's
933 * actually changed status(inferred from sid sets)
934 */
935 for (fd = 0; fd < vcom_nfds; fd++)
936 {
937 /*
938 * F fd set, dest
939 * S sid set, src
940 */
941#define _(S,F) \
942 if ((F) && (S) && FD_ISSET (fd, (F))) \
943 { \
944 sid = vcom_socket_get_sid (fd); \
945 if (sid != INVALID_SESSION_ID) \
946 { \
947 if (!FD_ISSET (sid, (S))) \
948 { \
949 FD_CLR(fd, (F)); \
950 } \
951 } \
952 else \
953 { \
954 rv = -EBADFD; \
955 goto done; \
956 } \
957 }
958
959
960 _(vcom_rd_sid_fds, vcom_readfds);
961 _(vcom_wr_sid_fds, vcom_writefds);
962 _(vcom_ex_sid_fds, vcom_exceptfds);
963#undef _
964 }
965
966 /*
967 * compute nfd and new_vcom_nfds from fd sets
968 */
969 for (fd = 0; fd < vcom_nfds; fd++)
970 {
971
972#define _(F) \
973 if ((F) && FD_ISSET (fd, (F))) \
974 { \
975 if (fd > max_fd) \
976 { \
977 max_fd = fd; \
978 } \
979 ++nfd; \
980 }
981
982
983 _(vcom_readfds);
984 _(vcom_writefds);
985 _(vcom_exceptfds);
986#undef _
987
988 }
989
990 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
991 rv = nfd;
992
993done:
994 return rv;
995}
996
997/*
998 * PRE:
999 * vom_socket_select is always called with
1000 * timeout->tv_sec and timeout->tv_usec set to zero.
1001 * hence vppcom_select return immediately.
1002 */
1003/*
1004 * TBD: do{body;} while(timeout conditional); timeout loop
1005 */
1006int
1007vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1008 fd_set * __restrict vcom_writefds,
1009 fd_set * __restrict vcom_exceptfds,
1010 struct timeval *__restrict timeout)
1011{
Dave Wallacee22aa742017-10-20 12:30:38 -04001012 static unsigned long vcom_nsid_fds = 0;
1013 int vcom_nsid = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001014 int rv = -EBADF;
1015 pid_t pid = getpid ();
1016
1017 int new_vcom_nfds = 0;
1018 int new_vcom_nfd = 0;
1019
1020 /* vcom sid fds */
1021 fd_set vcom_rd_sid_fds;
1022 fd_set vcom_wr_sid_fds;
1023 fd_set vcom_ex_sid_fds;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001024
1025 /* in seconds eg. 3.123456789 seconds */
1026 double time_to_wait = (double) 0;
1027
1028 /* validate inputs */
1029 if (vcom_nfds < 0)
1030 {
1031 return -EINVAL;
1032 }
1033
1034 /* convert timeval timeout to double time_to_wait */
1035 if (timeout)
1036 {
1037 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1038 {
1039 /* polling: vppcom_select returns immediately */
1040 time_to_wait = (double) 0;
1041 }
1042 else
1043 {
1044 /*TBD: use timeval api */
1045 time_to_wait = (double) timeout->tv_sec +
1046 (double) timeout->tv_usec / (double) 1000000 +
1047 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1048 }
1049 }
1050 else
1051 {
1052 /*
1053 * no timeout: vppcom_select can block indefinitely
1054 * waiting for a file descriptor to become ready
1055 * */
1056 /* set to a phantom value */
1057 time_to_wait = ~0;
1058 }
1059
1060 /* zero the sid_sets */
1061 /*
1062 * F fd set
1063 * S sid set
1064 */
1065#define _(S,F) \
1066 if ((F)) \
1067 { \
1068 FD_ZERO ((S)); \
1069 }
1070
1071
1072 _(&vcom_rd_sid_fds, vcom_readfds);
1073 _(&vcom_wr_sid_fds, vcom_writefds);
1074 _(&vcom_ex_sid_fds, vcom_exceptfds);
1075#undef _
1076
Dave Wallacee22aa742017-10-20 12:30:38 -04001077 if (vcom_nfds == 0)
1078 {
1079 if (time_to_wait > 0)
1080 {
1081 if (VCOM_DEBUG > 0)
1082 fprintf (stderr,
1083 "[%d] vcom_socket_select called to "
1084 "emulate delay_ns()!\n", pid);
1085 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1086 }
1087 else
1088 {
1089 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1090 "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1091 }
1092 return 0;
1093 }
1094
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001095 /* populate read, write and except sid_sets */
1096 vcom_nsid = vcom_socket_fds_2_sid_fds (
1097 /* dest */
1098 vcom_readfds || vcom_writefds
1099 || vcom_exceptfds ? (int *)
1100 &vcom_nsid_fds : NULL,
1101 vcom_readfds ? &vcom_rd_sid_fds :
1102 NULL,
1103 vcom_writefds ? &vcom_wr_sid_fds :
1104 NULL,
1105 vcom_exceptfds ? &vcom_ex_sid_fds :
1106 NULL,
1107 /* src */
1108 vcom_nfds,
1109 vcom_readfds,
1110 vcom_writefds, vcom_exceptfds);
1111 if (vcom_nsid < 0)
1112 {
1113 return vcom_nsid;
1114 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001115
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
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001314 vppcom_endpt_t ep;
1315 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001316 rv = vcom_session_getsockname (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001317 if (rv == 0)
1318 {
1319 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1320 {
1321 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1322 switch (__addr->sa_family)
1323 {
1324 case AF_INET:
1325 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1326 *__len = sizeof (struct sockaddr_in);
1327 break;
1328
1329 case AF_INET6:
1330 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1331 *__len = sizeof (struct sockaddr_in6);
1332 break;
1333
1334 default:
1335 break;
1336 }
1337 }
1338 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001339
1340 return rv;
1341}
1342
1343int
1344vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1345{
1346 int rv = -1;
1347 vcom_socket_main_t *vsm = &vcom_socket_main;
1348 uword *p;
1349 vcom_socket_t *vsock;
1350
1351 vppcom_endpt_t ep;
1352
1353 p = hash_get (vsm->sockidx_by_fd, __fd);
1354 if (p)
1355 {
1356 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1357
1358 ep.vrf = VPPCOM_VRF_DEFAULT;
1359 switch (__addr->sa_family)
1360 {
1361 case AF_INET:
1362 ep.is_ip4 = VPPCOM_IS_IP4;
1363 ep.ip =
1364 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1365 ep.port =
1366 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1367 break;
1368
1369 case AF_INET6:
1370 ep.is_ip4 = VPPCOM_IS_IP6;
1371 ep.ip =
1372 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1373 ep.port =
1374 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1375 break;
1376
1377 default:
1378 return -1;
1379 break;
1380 }
1381
1382 rv = vppcom_session_connect (vsock->sid, &ep);
1383 }
1384 return rv;
1385}
1386
Dave Wallacee22aa742017-10-20 12:30:38 -04001387static inline int
1388vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001389{
Steven2199aab2017-10-15 20:18:47 -07001390 int rv;
1391 uint32_t size = sizeof (*ep);
1392
1393 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1394 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001395}
1396
1397int
1398vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1399 socklen_t * __restrict __len)
1400{
1401 int rv = -1;
1402 vcom_socket_main_t *vsm = &vcom_socket_main;
1403 uword *p;
1404 vcom_socket_t *vsock;
1405
1406
1407 p = hash_get (vsm->sockidx_by_fd, __fd);
1408 if (!p)
1409 return -EBADF;
1410
1411 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1412 if (!vsock)
1413 return -ENOTSOCK;
1414
1415 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1416 return -EINVAL;
1417
1418 if (!__addr || !__len)
1419 return -EFAULT;
1420
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001421 vppcom_endpt_t ep;
1422 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001423 rv = vcom_session_getpeername (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001424 if (rv == 0)
1425 {
1426 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1427 {
1428 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1429 switch (__addr->sa_family)
1430 {
1431 case AF_INET:
1432 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1433 *__len = sizeof (struct sockaddr_in);
1434 break;
1435
1436 case AF_INET6:
1437 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1438 *__len = sizeof (struct sockaddr_in6);
1439 break;
1440
1441 default:
1442 break;
1443 }
1444 }
1445 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001446
1447 return rv;
1448}
1449
1450ssize_t
1451vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1452{
1453 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1454}
1455
1456ssize_t
1457vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1458{
1459 int rv = -1;
1460 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1461 return rv;
1462}
1463
1464/*
1465 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1466 * 0 otherwise
1467 * */
1468int
1469vcom_socket_is_connection_mode_socket (int __fd)
1470{
1471 int rv = -1;
1472 /* TBD define new vppcom api */
1473 vcom_socket_main_t *vsm = &vcom_socket_main;
1474 uword *p;
1475 vcom_socket_t *vsock;
1476
1477 int type;
1478 socklen_t optlen;
1479
1480 p = hash_get (vsm->sockidx_by_fd, __fd);
1481
1482 if (p)
1483 {
1484 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1485 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1486 {
1487 optlen = sizeof (type);
1488 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1489 if (rv != 0)
1490 {
1491 return 0;
1492 }
1493 /* get socket type */
1494 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1495 {
1496 case SOCK_STREAM:
1497 case SOCK_SEQPACKET:
1498 return 1;
1499 break;
1500
1501 default:
1502 return 0;
1503 break;
1504 }
1505 }
1506 }
1507 return 0;
1508}
1509
Dave Wallacee22aa742017-10-20 12:30:38 -04001510static inline ssize_t
1511vcom_session_sendto (int __sid, void *__buf, size_t __n,
1512 int __flags, __CONST_SOCKADDR_ARG __addr,
1513 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001514{
Dave Wallace617dffa2017-10-26 14:47:06 -04001515 vppcom_endpt_t *ep = 0;
Stevenac1f96d2017-10-24 16:03:58 -07001516
Dave Wallace617dffa2017-10-26 14:47:06 -04001517 if (__addr)
Stevenac1f96d2017-10-24 16:03:58 -07001518 {
Dave Wallace617dffa2017-10-26 14:47:06 -04001519 vppcom_endpt_t _ep;
Stevenac1f96d2017-10-24 16:03:58 -07001520
Dave Wallace617dffa2017-10-26 14:47:06 -04001521 ep = &_ep;
1522 ep->vrf = VPPCOM_VRF_DEFAULT;
1523 switch (__addr->sa_family)
1524 {
1525 case AF_INET:
1526 ep->is_ip4 = VPPCOM_IS_IP4;
1527 ep->ip =
1528 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1529 ep->port =
1530 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1531 break;
Stevenac1f96d2017-10-24 16:03:58 -07001532
Dave Wallace617dffa2017-10-26 14:47:06 -04001533 case AF_INET6:
1534 ep->is_ip4 = VPPCOM_IS_IP6;
1535 ep->ip =
1536 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1537 ep->port =
1538 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1539 break;
1540
1541 default:
1542 return -EAFNOSUPPORT;
1543 }
Stevenac1f96d2017-10-24 16:03:58 -07001544 }
1545
Dave Wallace617dffa2017-10-26 14:47:06 -04001546 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001547}
1548
1549ssize_t
1550vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1551 int __flags, __CONST_SOCKADDR_ARG __addr,
1552 socklen_t __addr_len)
1553{
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001554 vcom_socket_main_t *vsm = &vcom_socket_main;
1555 uword *p;
1556 vcom_socket_t *vsock;
1557
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001558 if (!__buf)
1559 {
1560 return -EINVAL;
1561 }
1562
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001563 p = hash_get (vsm->sockidx_by_fd, __fd);
1564 if (!p)
1565 return -EBADF;
1566
1567 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1568 if (!vsock)
1569 return -ENOTSOCK;
1570
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001571 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001572 {
1573 return -EINVAL;
1574 }
1575
1576 if (vcom_socket_is_connection_mode_socket (__fd))
1577 {
1578 /* ignore __addr and _addr_len */
1579 /* and EISCONN may be returned when they are not NULL and 0 */
1580 if ((__addr != NULL) || (__addr_len != 0))
1581 {
1582 return -EISCONN;
1583 }
1584 }
1585 else
1586 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001587 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001588 {
1589 return -EDESTADDRREQ;
1590 }
1591 /* not a vppcom supported address family */
Dave Wallace60f54822017-10-24 20:47:45 -04001592 if (!((__addr->sa_family == AF_INET) ||
1593 (__addr->sa_family == AF_INET6)))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001594 {
1595 return -EINVAL;
1596 }
1597 }
1598
Dave Wallace617dffa2017-10-26 14:47:06 -04001599 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1600 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001601}
1602
Dave Wallacee22aa742017-10-20 12:30:38 -04001603static inline ssize_t
1604vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1605 int __flags, __SOCKADDR_ARG __addr,
1606 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001607{
Stevenac1f96d2017-10-24 16:03:58 -07001608 int rv;
1609 vppcom_endpt_t ep;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001610
Stevenac1f96d2017-10-24 16:03:58 -07001611 if (__addr)
1612 {
1613 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1614 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1615
1616 if (rv > 0)
1617 {
1618 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1619 {
1620 __addr->sa_family =
1621 ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1622 switch (__addr->sa_family)
1623 {
1624 case AF_INET:
1625 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1626 *__addr_len = sizeof (struct sockaddr_in);
1627 break;
1628
1629 case AF_INET6:
1630 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1631 *__addr_len = sizeof (struct sockaddr_in6);
1632 break;
1633
1634 default:
1635 rv = -1;
1636 break;
1637 }
1638 }
1639 else
1640 rv = -1;
1641 }
1642 }
1643 else
1644 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1645
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001646 return rv;
1647}
1648
1649ssize_t
1650vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1651 int __flags, __SOCKADDR_ARG __addr,
1652 socklen_t * __restrict __addr_len)
1653{
1654 int rv = -1;
1655 vcom_socket_main_t *vsm = &vcom_socket_main;
1656 uword *p;
1657 vcom_socket_t *vsock;
1658
Stevenac1f96d2017-10-24 16:03:58 -07001659 if (__addr && !__addr_len)
1660 return -EINVAL;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001661
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001662 p = hash_get (vsm->sockidx_by_fd, __fd);
1663 if (!p)
1664 return -EBADF;
1665
1666 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1667 if (!vsock)
1668 return -ENOTSOCK;
1669
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001670 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001671 {
1672 return -EINVAL;
1673 }
1674
Dave Wallacee22aa742017-10-20 12:30:38 -04001675 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1676 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001677 return rv;
1678}
1679
1680/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001681static inline ssize_t
1682vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001683{
1684 int rv = -1;
1685 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1686 (int)__n); */
1687 return rv;
1688}
1689
1690ssize_t
1691vcom_socket_sendmsg (int __fd, const 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 (vcom_socket_is_connection_mode_socket (__fd))
1707 {
1708 /* ignore __addr and _addr_len */
1709 /* and EISCONN may be returned when they are not NULL and 0 */
1710 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1711 {
1712 return -EISCONN;
1713 }
1714 }
1715 else
1716 {
1717 /* TBD: validate __message->msg_name and __message->msg_namelen
1718 * and return -EINVAL on validation error
1719 * */
1720 ;
1721 }
1722
Dave Wallacee22aa742017-10-20 12:30:38 -04001723 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001724
1725 return rv;
1726}
1727
1728#ifdef __USE_GNU
1729int
1730vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1731 unsigned int __vlen, int __flags)
1732{
1733
1734 /* TBD: define a new vppcom api */
1735 return 0;
1736}
1737#endif
1738
1739/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001740static inline ssize_t
1741vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001742{
1743 int rv = -1;
1744 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1745 (int)__n); */
1746 rv = -EOPNOTSUPP;
1747 return rv;
1748}
1749
1750ssize_t
1751vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1752{
1753 int rv = -1;
1754 vcom_socket_main_t *vsm = &vcom_socket_main;
1755 uword *p;
1756 vcom_socket_t *vsock;
1757
1758 p = hash_get (vsm->sockidx_by_fd, __fd);
1759 if (!p)
1760 return -EBADF;
1761
1762 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1763 if (!vsock)
1764 return -ENOTSOCK;
1765
1766 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1767 return -EINVAL;
1768
1769 if (!__message)
1770 {
1771 return -EINVAL;
1772 }
1773
1774 /* validate __flags */
1775
Dave Wallacee22aa742017-10-20 12:30:38 -04001776 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001777 return rv;
1778}
1779
1780#ifdef __USE_GNU
1781int
1782vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1783 unsigned int __vlen, int __flags,
1784 struct timespec *__tmo)
1785{
1786 /* TBD: define a new vppcom api */
1787 return 0;
1788}
1789#endif
1790
1791/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001792static inline int
1793vcom_session_get_sockopt (int __sid, int __level, int __optname,
1794 void *__restrict __optval,
1795 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001796{
Stevenac1f96d2017-10-24 16:03:58 -07001797 int rv = 0;
1798
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001799 /* 1. for socket level options that are NOT socket attributes
1800 * and that has corresponding vpp options get from vppcom */
Stevenac1f96d2017-10-24 16:03:58 -07001801 switch (__level)
1802 {
1803 case SOL_SOCKET:
1804 switch (__optname)
1805 {
1806 case SO_ERROR:
1807 *(int *) __optval = 0;
1808 break;
1809 default:
1810 break;
1811 }
1812 default:
1813 break;
1814 }
1815 /* 2. unhandled options */
1816 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001817}
1818
1819int
1820vcom_socket_getsockopt (int __fd, int __level, int __optname,
1821 void *__restrict __optval,
1822 socklen_t * __restrict __optlen)
1823{
1824 int rv = -1;
1825 vcom_socket_main_t *vsm = &vcom_socket_main;
1826 uword *p;
1827 vcom_socket_t *vsock;
1828
1829 p = hash_get (vsm->sockidx_by_fd, __fd);
1830 if (!p)
1831 return -EBADF;
1832
1833 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1834 if (!vsock)
1835 return -ENOTSOCK;
1836
1837 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1838 return -EINVAL;
1839
1840 if (!__optval && !__optlen)
1841 return -EFAULT;
1842
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001843 switch (__level)
1844 {
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001845 case SOL_SOCKET:
1846 switch (__optname)
1847 {
1848/*
1849 * 1. for socket level options that are socket attributes,
1850 * get from libc_getsockopt.
1851 * 2. for socket level options that are NOT socket
1852 * attributes and that has corresponding vpp options
1853 * get from vppcom.
1854 * 3. for socket level options unimplemented
1855 * return -ENOPROTOOPT */
1856 case SO_DEBUG:
1857 case SO_DONTROUTE:
1858 case SO_BROADCAST:
1859 case SO_SNDBUF:
1860 case SO_RCVBUF:
1861 case SO_REUSEADDR:
1862 case SO_REUSEPORT:
1863 case SO_KEEPALIVE:
1864 case SO_TYPE:
1865 case SO_PROTOCOL:
1866 case SO_DOMAIN:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001867 case SO_OOBINLINE:
1868 case SO_NO_CHECK:
1869 case SO_PRIORITY:
1870 case SO_LINGER:
1871 case SO_BSDCOMPAT:
1872 case SO_TIMESTAMP:
1873 case SO_TIMESTAMPNS:
1874 case SO_TIMESTAMPING:
1875 case SO_RCVTIMEO:
1876 case SO_SNDTIMEO:
1877 case SO_RCVLOWAT:
1878 case SO_SNDLOWAT:
1879 case SO_PASSCRED:
1880 case SO_PEERCRED:
1881 case SO_PEERNAME:
1882 case SO_ACCEPTCONN:
1883 case SO_PASSSEC:
1884 case SO_PEERSEC:
1885 case SO_MARK:
1886 case SO_RXQ_OVFL:
1887 case SO_WIFI_STATUS:
1888 case SO_PEEK_OFF:
1889 case SO_NOFCS:
1890 case SO_BINDTODEVICE:
1891 case SO_GET_FILTER:
1892 case SO_LOCK_FILTER:
1893 case SO_BPF_EXTENSIONS:
1894 case SO_SELECT_ERR_QUEUE:
1895#ifdef CONFIG_NET_RX_BUSY_POLL
1896 case SO_BUSY_POLL:
1897#endif
1898 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001899#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001900 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001901#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001902 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1903 if (rv != 0)
1904 {
1905 rv = -errno;
1906 return rv;
1907 }
1908 break;
1909
Stevenac1f96d2017-10-24 16:03:58 -07001910 case SO_ERROR:
1911 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1912 __optval, __optlen);
1913 break;
1914
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001915 default:
1916 /* We implement the SO_SNDLOWAT etc to not be settable
1917 * (1003.1g 7).
1918 */
1919 return -ENOPROTOOPT;
1920 }
1921
1922 break;
1923
1924 default:
1925 /* 1. handle options that are NOT socket level options,
1926 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04001927 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1928 __optval, __optlen);
1929 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001930 }
1931
1932 return rv;
1933}
1934
1935/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001936static inline int
1937vcom_session_setsockopt (int __sid, int __level, int __optname,
1938 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001939{
Stevenb59f2272017-10-12 17:10:33 -07001940 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001941
Stevenb59f2272017-10-12 17:10:33 -07001942 switch (__level)
1943 {
Stevenbd187a82017-10-13 12:52:28 -07001944 case SOL_TCP:
1945 switch (__optname)
1946 {
1947 case TCP_KEEPIDLE:
1948 rv =
1949 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1950 break;
1951 case TCP_KEEPINTVL:
1952 rv =
1953 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1954 break;
1955 default:
1956 break;
1957 }
1958 break;
Stevenb59f2272017-10-12 17:10:33 -07001959 case SOL_IPV6:
1960 switch (__optname)
1961 {
1962 case IPV6_V6ONLY:
1963 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001964 break;
Stevenb59f2272017-10-12 17:10:33 -07001965 default:
Stevenbd187a82017-10-13 12:52:28 -07001966 break;
Stevenb59f2272017-10-12 17:10:33 -07001967 }
1968 break;
1969 case SOL_SOCKET:
1970 switch (__optname)
1971 {
Stevenbd187a82017-10-13 12:52:28 -07001972 case SO_KEEPALIVE:
1973 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1974 break;
Stevenb59f2272017-10-12 17:10:33 -07001975 case SO_REUSEADDR:
1976 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001977 break;
Stevenb59f2272017-10-12 17:10:33 -07001978 case SO_BROADCAST:
1979 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001980 break;
Stevenb59f2272017-10-12 17:10:33 -07001981 default:
Stevenbd187a82017-10-13 12:52:28 -07001982 break;
Stevenb59f2272017-10-12 17:10:33 -07001983 }
1984 break;
1985 default:
Stevenbd187a82017-10-13 12:52:28 -07001986 break;
Stevenb59f2272017-10-12 17:10:33 -07001987 }
1988
1989 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001990}
1991
1992int
1993vcom_socket_setsockopt (int __fd, int __level, int __optname,
1994 const void *__optval, socklen_t __optlen)
1995{
1996 int rv = -1;
1997 vcom_socket_main_t *vsm = &vcom_socket_main;
1998 uword *p;
1999 vcom_socket_t *vsock;
2000
2001 p = hash_get (vsm->sockidx_by_fd, __fd);
2002 if (!p)
2003 return -EBADF;
2004
2005 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2006 if (!vsock)
2007 return -ENOTSOCK;
2008
2009 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2010 return -EINVAL;
2011
2012 /*
2013 * Options without arguments
2014 */
2015
2016 if (__optname == SO_BINDTODEVICE)
2017 {
2018 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2019 if (rv != 0)
2020 {
2021 rv = -errno;
2022 }
2023 return rv;
2024 }
2025
2026 if (!__optval)
2027 return -EFAULT;
2028
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002029 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002030 return -EINVAL;
2031
2032 switch (__level)
2033 {
Stevenb59f2272017-10-12 17:10:33 -07002034 case SOL_IPV6:
2035 switch (__optname)
2036 {
2037 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04002038 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2039 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002040 break;
Stevenb59f2272017-10-12 17:10:33 -07002041 default:
2042 return -EOPNOTSUPP;
2043 }
2044 break;
2045 case SOL_TCP:
2046 switch (__optname)
2047 {
2048 case TCP_NODELAY:
2049 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002050 case TCP_KEEPIDLE:
2051 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04002052 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2053 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002054 break;
Stevenb59f2272017-10-12 17:10:33 -07002055 default:
2056 return -EOPNOTSUPP;
2057 }
2058 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002059 /* handle options at socket level */
2060 case SOL_SOCKET:
2061 switch (__optname)
2062 {
Stevenb59f2272017-10-12 17:10:33 -07002063 case SO_REUSEADDR:
2064 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002065 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04002066 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2067 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002068 break;
Stevenb59f2272017-10-12 17:10:33 -07002069
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002070 /*
2071 * 1. for socket level options that are socket attributes,
2072 * set it from libc_getsockopt
2073 * 2. for socket level options that are NOT socket
2074 * attributes and that has corresponding vpp options
2075 * set it from vppcom
2076 * 3. for socket level options unimplemented
2077 * return -ENOPROTOOPT */
2078 case SO_DEBUG:
2079 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002080 case SO_SNDBUF:
2081 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002082 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002083 case SO_TYPE:
2084 case SO_PROTOCOL:
2085 case SO_DOMAIN:
2086 case SO_ERROR:
2087 case SO_OOBINLINE:
2088 case SO_NO_CHECK:
2089 case SO_PRIORITY:
2090 case SO_LINGER:
2091 case SO_BSDCOMPAT:
2092 case SO_TIMESTAMP:
2093 case SO_TIMESTAMPNS:
2094 case SO_TIMESTAMPING:
2095 case SO_RCVTIMEO:
2096 case SO_SNDTIMEO:
2097 case SO_RCVLOWAT:
2098 case SO_SNDLOWAT:
2099 case SO_PASSCRED:
2100 case SO_PEERCRED:
2101 case SO_PEERNAME:
2102 case SO_ACCEPTCONN:
2103 case SO_PASSSEC:
2104 case SO_PEERSEC:
2105 case SO_MARK:
2106 case SO_RXQ_OVFL:
2107 case SO_WIFI_STATUS:
2108 case SO_PEEK_OFF:
2109 case SO_NOFCS:
2110 /*
2111 * SO_BINDTODEVICE already handled as
2112 * "Options without arguments" */
2113 /* case SO_BINDTODEVICE: */
2114 case SO_GET_FILTER:
2115 case SO_LOCK_FILTER:
2116 case SO_BPF_EXTENSIONS:
2117 case SO_SELECT_ERR_QUEUE:
2118#ifdef CONFIG_NET_RX_BUSY_POLL
2119 case SO_BUSY_POLL:
2120#endif
2121 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002122#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002123 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002124#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002125 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2126 if (rv != 0)
2127 {
2128 rv = -errno;
2129 return rv;
2130 }
2131 break;
2132
2133 default:
2134 /* We implement the SO_SNDLOWAT etc to not be settable
2135 * (1003.1g 7).
2136 */
2137 return -ENOPROTOOPT;
2138 }
2139
2140 break;
2141
2142 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002143 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002144 }
2145
2146 return rv;
2147}
2148
2149int
2150vcom_socket_listen (int __fd, int __n)
2151{
2152 int rv = -1;
2153 vcom_socket_main_t *vsm = &vcom_socket_main;
2154 uword *p;
2155 vcom_socket_t *vsock;
2156
2157 p = hash_get (vsm->sockidx_by_fd, __fd);
2158 if (p)
2159 {
2160 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2161
2162 /* TBD vppcom to accept __n parameter */
2163 rv = vppcom_session_listen (vsock->sid, __n);
2164 }
2165
2166 return rv;
2167}
2168
2169static int
2170vcom_socket_connected_socket (int __fd, int __sid,
2171 int *__domain,
2172 int *__type, int *__protocol, int flags)
2173{
2174 int rv = -1;
2175 vcom_socket_main_t *vsm = &vcom_socket_main;
2176 vcom_socket_t *vsock;
2177
2178 i32 fd;
2179 i32 sockidx;
2180
2181 socklen_t optlen;
2182
2183 optlen = sizeof (*__domain);
2184 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2185 if (rv != 0)
2186 {
2187 rv = -errno;
2188 goto out;
2189 }
2190
2191 optlen = sizeof (*__type);
2192 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2193 if (rv != 0)
2194 {
2195 rv = -errno;
2196 goto out;
2197 }
2198
2199 optlen = sizeof (*__protocol);
2200 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2201 if (rv != 0)
2202 {
2203 rv = -errno;
2204 goto out;
2205 }
2206
2207 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2208 if (fd < 0)
2209 {
2210 rv = fd;
2211 goto out;
2212 }
2213
2214 pool_get (vsm->vsockets, vsock);
2215 vsocket_init (vsock);
2216
2217 sockidx = vsock - vsm->vsockets;
2218 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2219
2220 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2221 return fd;
2222
2223out:
2224 return rv;
2225}
2226
2227/* If flag is 0, then accept4() is the same as accept().
2228 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2229 */
2230static int
2231vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2232 socklen_t * __restrict __addr_len, int flags)
2233{
2234 int rv = -1;
2235 vcom_socket_main_t *vsm = &vcom_socket_main;
2236 uword *p;
2237 vcom_socket_t *vsock;
2238
2239 int fd;
2240 int sid;
2241 int domain;
2242 int type;
2243 int protocol;
2244
2245 uint8_t addr8[sizeof (struct in6_addr)];
2246 vppcom_endpt_t ep;
2247
2248 ep.ip = addr8;
2249
2250 /* validate flags */
2251
2252 /*
2253 * for documentation
2254 * switch (flags)
2255 * {
2256 * case 0:
2257 * case SOCK_NONBLOCK:
2258 * case SOCK_CLOEXEC:
2259 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2260 * break;
2261 *
2262 * default:
2263 * return -1;
2264 * }
2265 */
2266 /* flags can be 0 or can be bitwise OR
2267 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2268
2269 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2270 {
2271 /* TBD: return proper error code */
2272 return -1;
2273 }
2274
2275 /* TBD: return proper error code */
2276
2277 if (!vcom_socket_is_connection_mode_socket (__fd))
2278 {
2279 return -EOPNOTSUPP;
2280 }
2281
2282 p = hash_get (vsm->sockidx_by_fd, __fd);
2283 if (p)
2284 {
2285 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2286
2287
2288 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2289 if (rv < 0)
2290 {
2291 return rv;
2292 }
2293
2294 /* is blocking */
2295 if (!(rv & O_NONBLOCK))
2296 {
2297 /* socket is not marked as nonblocking
2298 * and no pending connections are present
2299 * on the queue, accept () blocks the caller
2300 * until a connection is present.
2301 */
2302 rv = vppcom_session_accept (vsock->sid, &ep,
2303 -1.0 /* wait forever */ );
2304 }
2305 else
2306 {
2307 /* The file descriptor refers to a socket and has been
2308 * marked nonblocking(O_NONBLOCK) and the accept would
2309 * block.
2310 * */
2311 /* is non blocking */
2312 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2313 /* If the socket is marked nonblocking and
2314 * no pending connections are present on the
2315 * queue, accept fails with the error
2316 * EAGAIN or EWOULDBLOCK
2317 */
2318 if (rv == VPPCOM_ETIMEDOUT)
2319 {
2320 rv = VPPCOM_EAGAIN;
2321 }
2322 }
2323 if (rv < 0)
2324 {
2325 return rv;
2326 }
2327
2328 sid = rv;
2329
2330 /* create a new connected socket resource and set flags
2331 * on the new file descriptor.
2332 * update vsockets and sockidx_by_fd table
2333 * */
2334 fd = vcom_socket_connected_socket (__fd, sid,
2335 &domain, &type, &protocol, flags);
2336 if (fd < 0)
2337 {
2338 return fd;
2339 }
2340
2341 rv = fd;
2342
2343 /* TBD populate __addr and __addr_len */
2344 /* TBD: The returned address is truncated if the buffer
2345 * provided is too small, in this case, __addr_len will
2346 * return a value greater than was supplied to the call.*/
2347 if (__addr)
2348 {
2349 if (ep.is_cut_thru)
2350 {
2351 /* TBD populate __addr and __addr_len */
2352 switch (domain)
2353 {
2354 case AF_INET:
2355 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2356 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2357 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2358 addr8, sizeof (struct in_addr));
2359 /* TBD: populate __addr_len */
2360 if (__addr_len)
2361 {
2362 *__addr_len = sizeof (struct sockaddr_in);
2363 }
2364 break;
2365
2366 case AF_INET6:
2367 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2368 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2369 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2370 __in6_u.__u6_addr8, addr8,
2371 sizeof (struct in6_addr));
2372 /* TBD: populate __addr_len */
2373 if (__addr_len)
2374 {
2375 *__addr_len = sizeof (struct sockaddr_in6);
2376 }
2377 break;
2378
2379 default:
2380 return -EAFNOSUPPORT;
2381 }
2382 }
2383 else
2384 {
2385 switch (ep.is_ip4)
2386 {
2387 case VPPCOM_IS_IP4:
2388 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2389 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2390 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2391 addr8, sizeof (struct in_addr));
2392 /* TBD: populate __addr_len */
2393 if (__addr_len)
2394 {
2395 *__addr_len = sizeof (struct sockaddr_in);
2396 }
2397 break;
2398
2399 case VPPCOM_IS_IP6:
2400 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2401 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2402 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2403 __in6_u.__u6_addr8, addr8,
2404 sizeof (struct in6_addr));
2405 /* TBD: populate __addr_len */
2406 if (__addr_len)
2407 {
2408 *__addr_len = sizeof (struct sockaddr_in6);
2409 }
2410 break;
2411
2412 default:
2413 return -EAFNOSUPPORT;
2414 }
2415 }
2416 }
2417 else
2418 {
2419 /* when __addr is NULL, nothing is filled in,
2420 * in this case, __addr_len is not used,
2421 * and should also be null
2422 * */
2423 if (__addr_len)
2424 {
2425 /* TBD: return proper error code */
2426 return -1;
2427 }
2428 }
2429 }
2430
2431 return rv;
2432}
2433
2434int
2435vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2436 socklen_t * __restrict __addr_len)
2437{
2438 /* set flags to 0 for accept() */
2439 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2440}
2441
2442#ifdef __USE_GNU
2443int
2444vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2445 socklen_t * __restrict __addr_len, int __flags)
2446{
2447 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2448 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2449}
2450#endif
2451
2452/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002453static inline int
2454vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002455{
2456 return 0;
2457}
2458
2459int
2460vcom_socket_shutdown (int __fd, int __how)
2461{
2462 int rv = -1;
2463 vcom_socket_main_t *vsm = &vcom_socket_main;
2464 uword *p;
2465 vcom_socket_t *vsock;
2466
2467 p = hash_get (vsm->sockidx_by_fd, __fd);
2468 if (p)
2469 {
2470 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2471 switch (__how)
2472 {
2473 case SHUT_RD:
2474 case SHUT_WR:
2475 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002476 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002477 return rv;
2478 break;
2479
2480 default:
2481 return -EINVAL;
2482 break;
2483 }
2484 }
2485
2486 return rv;
2487}
2488
2489int
2490vcom_socket_epoll_create1 (int __flags)
2491{
2492 int rv = -1;
2493 vcom_socket_main_t *vsm = &vcom_socket_main;
2494 vcom_epoll_t *vepoll;
2495
2496 i32 epfd;
2497 i32 vep_idx;
2498 i32 epollidx;
2499
2500 epfd = vcom_socket_open_epoll (__flags);
2501 if (epfd < 0)
2502 {
2503 rv = epfd;
2504 goto out;
2505 }
2506
2507 vep_idx = vppcom_epoll_create ();
2508 if (vep_idx < 0)
2509 {
2510 rv = vep_idx;
2511 goto out_close_epoll;
2512 }
2513
2514 pool_get (vsm->vepolls, vepoll);
2515 vepoll_init (vepoll);
2516
2517 epollidx = vepoll - vsm->vepolls;
2518 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2519
2520 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2521
2522 return epfd;
2523
2524out_close_epoll:
2525 vcom_socket_close_epoll (epfd);
2526out:
2527 return rv;
2528}
2529
2530/*
2531 * PRE: vppcom_epoll_ctl() is successful
2532 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2533 */
2534int
2535vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2536 struct epoll_event *__event,
2537 i32 vep_idx, vcom_epoll_t * vepoll,
2538 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2539 int free_vepitem_on_del)
2540{
2541 int rv = -1;
2542 vcom_socket_main_t *vsm = &vcom_socket_main;
2543 vcom_epitem_t *vepitem;
2544
2545 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2546 uword *p;
2547 i32 vepitemidx;
2548
2549 i32 *vepitemidxs = 0;
2550
2551 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2552
2553 i32 vec_idx;
2554
2555 /* perform control operations on the epoll instance */
2556 switch (__op)
2557 {
2558 case EPOLL_CTL_ADD:
2559 /*
2560 * supplied file descriptor is already
2561 * registered with this epoll instance
2562 * */
2563 /* vepitem exists */
2564 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2565 if (p)
2566 {
2567 rv = -EEXIST;
2568 goto out;
2569 }
2570
2571 /* add a new vepitem */
2572 pool_get (vsm->vepitems, vepitem);
2573 vepitem_init (vepitem);
2574
2575 vepitemidx = vepitem - vsm->vepitems;
2576 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2577 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2578
2579 /* update epitemidxs */
2580 /* by_epfd */
2581 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2582 if (!p) /* not exist */
2583 {
2584 vepitemidxs = 0;
2585 vec_add1 (vepitemidxs, vepitemidx);
2586 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2587 }
2588 else /* exists */
2589 {
2590 vepitemidxs = *(i32 **) p;
2591 vec_add1 (vepitemidxs, vepitemidx);
2592 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2593 }
2594 /* update epitemidxs */
2595 /* by_fd */
2596 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2597 if (!p) /* not exist */
2598 {
2599 vepitemidxs = 0;
2600 vec_add1 (vepitemidxs, vepitemidx);
2601 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2602 }
2603 else /* exists */
2604 {
2605 vepitemidxs = *(i32 **) p;
2606 vec_add1 (vepitemidxs, vepitemidx);
2607 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2608 }
2609
2610 /* increment vepoll fd count by 1 */
2611 vepoll->count += 1;
2612
2613 rv = 0;
2614 goto out;
2615 break;
2616
2617 case EPOLL_CTL_MOD:
2618 /*
2619 * supplied file descriptor is not
2620 * registered with this epoll instance
2621 * */
2622 /* vepitem not exist */
2623 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2624 if (!p)
2625 {
2626 rv = -ENOENT;
2627 goto out;
2628 }
2629 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2630 if (vepitem)
2631 {
2632 vepitem->event = *__event;
2633 vepitem->revent = revent;
2634 }
2635
2636 rv = 0;
2637 goto out;
2638 break;
2639
2640 case EPOLL_CTL_DEL:
2641 /*
2642 * supplied file descriptor is not
2643 * registered with this epoll instance
2644 * */
2645 /* vepitem not exist */
2646 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2647 if (!p)
2648 {
2649 rv = -ENOENT;
2650 goto out;
2651 }
2652 vepitemidx = *(i32 *) p;
2653 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2654
2655 /* update epitemidxs */
2656 /* by_epfd */
2657 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2658 if (!p) /* not exist */
2659 {
2660 rv = -ENOENT;
2661 goto out;
2662 }
2663 else /* exists */
2664 {
2665 vepitemidxs = *(i32 **) p;
2666 vec_idx = vec_search (vepitemidxs, vepitemidx);
2667 if (vec_idx != ~0)
2668 {
2669 vec_del1 (vepitemidxs, vec_idx);
2670 if (!vec_len (vepitemidxs))
2671 {
2672 vec_free (vepitemidxs);
2673 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2674 }
2675 }
2676 }
2677
2678 /* update epitemidxs */
2679 /* by_fd */
2680 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2681 if (!p) /* not exist */
2682 {
2683 rv = -ENOENT;
2684 goto out;
2685 }
2686 else /* exists */
2687 {
2688 vepitemidxs = *(i32 **) p;
2689 vec_idx = vec_search (vepitemidxs, vepitemidx);
2690 if (vec_idx != ~0)
2691 {
2692 vec_del1 (vepitemidxs, vec_idx);
2693 if (!vec_len (vepitemidxs))
2694 {
2695 vec_free (vepitemidxs);
2696 hash_unset (vsm->epitemidxs_by_fd, __fd);
2697 }
2698 }
2699 }
2700
2701 /* pool put vepitem */
2702 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2703 if (free_vepitem_on_del)
2704 {
2705 if (!vepitem)
2706 {
2707 rv = -ENOENT;
2708 goto out;
2709 }
2710 vepitem_init (vepitem);
2711 pool_put (vsm->vepitems, vepitem);
2712 }
2713 else
2714 {
2715 if (!vepitem)
2716 {
2717 vepitem_init (vepitem);
2718 }
2719 }
2720
2721 /* decrement vepoll fd count by 1 */
2722 vepoll->count -= 1;
2723
2724 rv = 0;
2725 goto out;
2726 break;
2727
2728 default:
2729 rv = -EINVAL;
2730 goto out;
2731 break;
2732 }
2733
2734out:
2735 return rv;
2736}
2737
2738/*
2739 * PRE: 00. null pointer check on __event
2740 * 01. all other parameters are validated
2741 */
2742
2743static int
2744vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2745 struct epoll_event *__event,
2746 int free_vepitem_on_del)
2747{
2748 int rv = -1;
2749
2750 /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2751 vcom_epoll_t *vepoll;
2752
2753 /*__fd could could be vcom socket or vcom epoll or kernel fd */
2754 void *vfd;
2755 vcom_epoll_t *vfd_vepoll;
2756 vcom_socket_t *vfd_vsock;
2757
2758 i32 vep_idx;
2759 i32 vfd_id;
2760
2761 vcom_fd_type_t type = FD_TYPE_INVALID;
2762
2763 /* validate __event */
2764
2765 /* get vep_idx and vepoll */
2766 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2767 if (vep_idx == INVALID_VEP_IDX)
2768 {
2769 return -EBADF;
2770 }
2771
2772 /* get vcom fd type, vfd_id and vfd */
2773 vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2774 if (vfd_id != INVALID_SESSION_ID)
2775 {
2776 type = FD_TYPE_VCOM_SOCKET;
2777 vfd = vfd_vsock;
2778 }
2779 else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2780 != INVALID_VEP_IDX)
2781 {
2782 type = FD_TYPE_EPOLL;
2783 vfd = vfd_vepoll;
2784 }
2785 else
2786 {
2787 /* FD_TYPE_KERNEL not supported by epoll instance */
2788 type = FD_TYPE_INVALID;
2789 return -EBADF;
2790 }
2791
2792
2793 /* vepoll and vsock are now valid */
2794 rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2795 if (rv < 0)
2796 {
2797 return rv;
2798 }
2799
2800 rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2801 __event,
2802 vep_idx, vepoll,
2803 vfd_id, vfd, type, free_vepitem_on_del);
2804 return rv;
2805}
2806
2807int
2808vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2809 struct epoll_event *__event)
2810{
2811 int rv = -1;
2812
2813 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2814 return rv;
2815}
2816
2817static int
2818vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2819 struct epoll_event *__event)
2820{
2821 int rv = -1;
2822
2823 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2824 return rv;
2825}
2826
2827int
2828vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2829 int __maxevents, int __timeout,
2830 const __sigset_t * __ss)
2831{
2832 int rv = -EBADF;
2833
2834 /* in seconds eg. 3.123456789 seconds */
2835 double time_to_wait = (double) 0;
2836
2837 i32 vep_idx;
2838
2839 /* validate __event */
2840 if (!__events)
2841 {
2842 rv = -EFAULT;
2843 goto out;
2844 }
2845
2846 /* validate __timeout */
2847 if (__timeout > 0)
2848 {
2849 time_to_wait = (double) __timeout / (double) 1000;
2850 }
2851 else if (__timeout == 0)
2852 {
2853 time_to_wait = (double) 0;
2854 }
2855 else if (__timeout == -1)
2856 {
2857 time_to_wait = ~0;
2858 }
2859 else
2860 {
2861 rv = -EBADF;
2862 goto out;
2863 }
2864
2865 /* get vep_idx */
2866 vep_idx = vcom_socket_get_vep_idx (__epfd);
2867 if (vep_idx != INVALID_VEP_IDX)
2868 {
2869 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2870 }
2871out:
2872 return rv;
2873}
2874
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002875static inline void
2876vcom_pollfds_2_selectfds (
2877 /* src */
2878 struct pollfd *__fds, nfds_t __nfds,
2879 /* dest */
2880 int vcom_nfds,
2881 fd_set * __restrict vcom_readfds,
2882 fd_set * __restrict vcom_writefds,
2883 fd_set * __restrict vcom_exceptfds)
2884{
2885 nfds_t fds_idx = 0;
2886
2887 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2888 {
2889 /* ignore negative fds */
2890 if (__fds[fds_idx].fd < 0)
2891 {
2892 continue;
2893 }
2894
2895 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2896 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2897
2898 /* requested events */
2899 if (__fds[fds_idx].events)
2900 {
2901 if (__fds[fds_idx].events & POLLIN)
2902 {
2903 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2904 }
2905 if (__fds[fds_idx].events & POLLPRI)
2906 {
2907 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2908 }
2909 if (__fds[fds_idx].events & POLLOUT)
2910 {
2911 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2912 }
2913#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2914 if (__fds[fds_idx].events & POLLRDNORM)
2915 {
2916 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2917 }
2918 if (__fds[fds_idx].events & POLLRDBAND)
2919 {
2920 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2921 }
2922 if (__fds[fds_idx].events & POLLWRNORM)
2923 {
2924 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2925 }
2926 if (__fds[fds_idx].events & POLLWRBAND)
2927 {
2928 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2929 }
2930#endif
2931 }
2932 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2933}
2934
2935static inline void
2936vcom_selectfds_2_pollfds (
2937 /* dest */
2938 struct pollfd *__fds, nfds_t __nfds, int *nfd,
2939 /* src */
2940 int vcom_nfds,
2941 fd_set * __restrict vcom_readfds,
2942 fd_set * __restrict vcom_writefds,
2943 fd_set * __restrict vcom_exceptfds)
2944{
2945 nfds_t fds_idx = 0;
2946
2947
2948 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2949 {
2950 /* ignore negative fds */
2951 if (__fds[fds_idx].fd < 0)
2952 {
2953 __fds[fds_idx].revents = 0;
2954 }
2955
2956 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2957 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2958 {
2959 /*
2960 * TBD: for now any select exception
2961 * is flagged as POLLERR
2962 * */
2963 __fds[fds_idx].revents |= POLLERR;
2964 }
2965
2966 /* requested events */
2967 if (__fds[fds_idx].events & POLLIN)
2968 {
2969 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2970 {
2971 __fds[fds_idx].revents |= POLLIN;
2972 }
2973 }
2974 if (__fds[fds_idx].events & POLLPRI)
2975 {
2976 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2977 {
2978 __fds[fds_idx].revents |= POLLIN;
2979 }
2980 }
2981 if (__fds[fds_idx].events & POLLOUT)
2982 {
2983 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2984 {
2985 __fds[fds_idx].revents |= POLLOUT;
2986 }
2987 }
2988#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2989 if (__fds[fds_idx].events & POLLRDNORM)
2990 {
2991 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2992 {
2993 __fds[fds_idx].revents |= POLLRDNORM;
2994 }
2995 }
2996 if (__fds[fds_idx].events & POLLRDBAND)
2997 {
2998 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2999 {
3000 __fds[fds_idx].revents |= POLLRDBAND;
3001 }
3002 }
3003 if (__fds[fds_idx].events & POLLWRNORM)
3004 {
3005 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3006 {
3007 __fds[fds_idx].revents |= POLLWRNORM;
3008 }
3009 }
3010 if (__fds[fds_idx].events & POLLWRBAND)
3011 {
3012 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3013 {
3014 __fds[fds_idx].revents |= POLLWRBAND;
3015 }
3016 }
3017#endif
3018 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3019
3020 /*
3021 * nfd:
3022 * the number of structures which have nonzero revents fields
3023 * (in other words, those descriptors with events or
3024 * errors reported)
3025 * */
3026 *nfd = 0;
3027 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3028 {
3029 /* ignore negative fds */
3030 if (__fds[fds_idx].fd < 0)
3031 {
3032 continue;
3033 }
3034
3035 if (__fds[fds_idx].revents)
3036 {
3037 (*nfd)++;
3038 }
3039 }
3040}
3041
3042/*
3043 * PRE: parameters are validated,
3044 * vcom_socket_poll is always called with __timeout set to zero
3045 * hence returns immediately
3046 *
3047 * ACTION: handle non negative validated vcom fds and ignore rest
3048 */
3049
3050/*
3051 * implements vcom_socket_poll () interface
3052 *
3053 * internally uses vcom_socket_select ()
3054 * to realize the behavior
3055 * */
3056int
3057vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3058 int __timeout)
3059{
3060 int rv;
3061 pid_t pid = getpid ();
3062
3063 nfds_t fds_idx = 0;
3064 int nfd = 0;
3065
3066 /* vcom */
3067 int vcom_nfds = 0;
3068 fd_set vcom_readfds;
3069 fd_set vcom_writefds;
3070 fd_set vcom_exceptfds;
3071 int vcom_nfd = -1;
3072 /* invalid max_vcom_fd is -1 */
3073 int max_vcom_fd = -1;
3074
3075 /* __timeout is zero to get ready events and return immediately */
3076 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3077
3078 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003079 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003080 {
3081 rv = -EINVAL;
3082 goto poll_done;
3083 }
3084
3085 /* zero vcom fd sets */
3086 /*
3087 * V vcom fd set
3088 */
3089#define _(V) \
3090 FD_ZERO ((V))
3091
3092 _(&vcom_readfds);
3093 _(&vcom_writefds);
3094 _(&vcom_exceptfds);
3095#undef _
3096
3097 vcom_nfds = 0;
3098 vcom_nfd = -1;
3099
3100
3101 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3102 {
3103 /* ignore negative fds */
3104 if (__fds[fds_idx].fd < 0)
3105 {
3106 continue;
3107 }
3108
3109 /* non negative validated vcom fds */
3110 if (__fds[fds_idx].fd > FD_SETSIZE)
3111 {
3112 rv = -EINVAL;
3113 goto poll_done;
3114 }
3115
3116 /* max_vcom_fd and vcom_nfd */
3117 if (__fds[fds_idx].fd > max_vcom_fd)
3118 {
3119 /* requested events */
3120 if (__fds[fds_idx].events)
3121 {
3122 max_vcom_fd = __fds[fds_idx].fd;
3123 }
3124 }
3125 ++vcom_nfd;
3126 }
3127
3128 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3129
3130 if (!vcom_nfds)
3131 {
3132 rv = vcom_nfds;
3133 goto poll_done;
3134 }
3135
3136 vcom_pollfds_2_selectfds (
3137 /* src */
3138 __fds, __nfds,
3139 /* dest */
3140 vcom_nfds,
3141 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3142
3143 /* select on vcom fds */
3144 vcom_nfd = vcom_socket_select (vcom_nfds,
3145 &vcom_readfds,
3146 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003147 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003148 fprintf (stderr,
3149 "[%d] vcom_socket_select: "
3150 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3151
3152 if (vcom_nfd < 0)
3153 {
3154 rv = vcom_nfd;
3155 goto poll_done;
3156 }
3157
3158 vcom_selectfds_2_pollfds (
3159 /* dest */
3160 __fds, __nfds, &nfd,
3161 /* src */
3162 vcom_nfds,
3163 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3164
3165 rv = nfd;
3166
3167poll_done:
3168 return rv;
3169}
3170
3171/*
3172 * TBD: remove this static function once vppcom
3173 * has an implementation in place
3174 *
3175 * ACTION:
3176 */
3177static int
3178vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3179{
3180 return -EOPNOTSUPP;
3181}
3182
3183int
3184vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3185 int __timeout)
3186{
3187 nfds_t fds_idx = 0;
3188
3189 /* in seconds eg. 3.123456789 seconds */
3190 double time_to_wait = (double) 0;
3191
3192 i32 sid;
3193 i32 vep_idx;
3194
3195 /* replace vcom fd with session idx */
3196 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3197 {
3198 /* ignore negative fds */
3199 if (__fds[fds_idx].fd < 0)
3200 {
3201 continue;
3202 }
3203
3204 /* non negative validated vcom fds */
3205 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3206 if (sid != INVALID_SESSION_ID)
3207 {
3208 __fds[fds_idx].fd = sid;
3209 }
3210 else
3211 {
3212 /* get vep_idx */
3213 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3214 if (vep_idx != INVALID_VEP_IDX)
3215 {
3216 __fds[fds_idx].fd = vep_idx;
3217 }
3218 else
3219 {
3220 return -EBADF;
3221 }
3222 }
3223 }
3224
3225 /* validate __timeout */
3226 if (__timeout > 0)
3227 {
3228 time_to_wait = (double) __timeout / (double) 1000;
3229 }
3230 else if (__timeout == 0)
3231 {
3232 time_to_wait = (double) 0;
3233 }
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003234 else
3235 {
Dave Wallace60f54822017-10-24 20:47:45 -04003236 time_to_wait = ~0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003237 }
3238
3239 return vppcom_poll (__fds, __nfds, time_to_wait);
3240}
3241
3242int
3243vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3244{
3245 /* select an implementation */
3246
3247 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3248 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3249}
3250
3251#ifdef __USE_GNU
3252int
3253vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3254 const struct timespec *__timeout, const __sigset_t * __ss)
3255{
3256 return -EOPNOTSUPP;
3257}
3258#endif
3259
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003260int
3261vcom_socket_main_init (void)
3262{
3263 vcom_socket_main_t *vsm = &vcom_socket_main;
3264
3265 if (VCOM_DEBUG > 0)
3266 printf ("vcom_socket_main_init\n");
3267
3268 if (!vsm->init)
3269 {
3270 /* TBD: define FD_MAXSIZE and use it here */
3271 pool_alloc (vsm->vsockets, FD_SETSIZE);
3272 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3273
3274 pool_alloc (vsm->vepolls, FD_SETSIZE);
3275 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3276
3277 pool_alloc (vsm->vepitems, FD_SETSIZE);
3278 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3279
3280 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3281 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3282
3283 vsm->init = 1;
3284 }
3285
3286 return 0;
3287}
3288
3289
3290void
3291vcom_socket_main_show (void)
3292{
3293 vcom_socket_main_t *vsm = &vcom_socket_main;
3294 vcom_socket_t *vsock;
3295
3296 vcom_epoll_t *vepoll;
3297
3298 vcom_epitem_t *vepitem;
3299
3300 i32 epfd;
3301 i32 fd;
3302 i32 *vepitemidxs, *vepitemidxs_var;
3303
3304 if (vsm->init)
3305 {
3306 /* from active list of vsockets show vsock */
3307
3308 /* *INDENT-OFF* */
3309 pool_foreach (vsock, vsm->vsockets,
3310 ({
3311 printf(
3312 "fd='%04d', sid='%08x',type='%-30s'\n",
3313 vsock->fd, vsock->sid,
3314 vcom_socket_type_str (vsock->type));
3315 }));
3316 /* *INDENT-ON* */
3317
3318 /* from active list of vepolls, show vepoll */
3319
3320 /* *INDENT-OFF* */
3321 pool_foreach (vepoll, vsm->vepolls,
3322 ({
3323 printf(
3324 "epfd='%04d', vep_idx='%08x', "
3325 "type='%-30s', "
3326 "flags='%d', count='%d', close='%d'\n",
3327 vepoll->epfd, vepoll->vep_idx,
3328 vcom_socket_epoll_type_str (vepoll->type),
3329 vepoll->flags, vepoll->count, vepoll->close);
3330 }));
3331 /* *INDENT-ON* */
3332
3333 /* from active list of vepitems, show vepitem */
3334
3335 /* *INDENT-OFF* */
3336 pool_foreach (vepitem, vsm->vepitems,
3337 ({
3338 printf(
3339 "epfd='%04d', fd='%04d', "
3340 "next_fd='%04d', prev_fd='%04d', "
3341 "type='%-30s', "
3342 "events='%04x', revents='%04x'\n",
3343 vepitem->epfd, vepitem->fd,
3344 vepitem->next_fd, vepitem->prev_fd,
3345 vcom_socket_vcom_fd_type_str (vepitem->type),
3346 vepitem->event.events, vepitem->revent.events);
3347 }));
3348
3349 /* *INDENT-ON* */
3350
3351 /* show epitemidxs for epfd */
3352 /* *INDENT-OFF* */
3353 hash_foreach (epfd, vepitemidxs,
3354 vsm->epitemidxs_by_epfd,
3355 ({
3356 printf("\n[ '%04d': ", epfd);
3357 vec_foreach (vepitemidxs_var,vepitemidxs)
3358 {
3359 printf("'%04d' ", (int)vepitemidxs_var[0]);
3360 }
3361 printf("]\n");
3362 }));
3363 /* *INDENT-ON* */
3364
3365 /* show epitemidxs for fd */
3366 /* *INDENT-OFF* */
3367 hash_foreach (fd, vepitemidxs,
3368 vsm->epitemidxs_by_fd,
3369 ({
3370 printf("\n{ '%04d': ", fd);
3371 vec_foreach (vepitemidxs_var,vepitemidxs)
3372 {
3373 printf("'%04d' ", (int)vepitemidxs_var[0]);
3374 }
3375 printf("}\n");
3376 }));
3377 /* *INDENT-ON* */
3378
3379 }
3380}
3381
3382void
3383vcom_socket_main_destroy (void)
3384{
3385 vcom_socket_main_t *vsm = &vcom_socket_main;
3386 vcom_socket_t *vsock;
3387
3388 vcom_epoll_t *vepoll;
3389
3390 vcom_epitem_t *vepitem;
3391
3392 i32 epfd;
3393 i32 fd;
3394 i32 *vepitemidxs;
3395
3396
3397 if (VCOM_DEBUG > 0)
3398 printf ("vcom_socket_main_destroy\n");
3399
3400 if (vsm->init)
3401 {
3402
3403 /*
3404 * from active list of vepitems,
3405 * remove all "vepitem" elements from the pool in a safe way
3406 * */
3407
3408 /* *INDENT-OFF* */
3409 pool_flush (vepitem, vsm->vepitems,
3410 ({
Dave Wallace60f54822017-10-24 20:47:45 -04003411 if ((vepitem->type == FD_TYPE_EPOLL) ||
3412 (vepitem->type == FD_TYPE_VCOM_SOCKET))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003413 {
Dave Wallace60f54822017-10-24 20:47:45 -04003414 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003415 vepitem->fd, NULL);
3416 vepitem_init (vepitem);
3417 }
3418 }));
3419 /* *INDENT-ON* */
3420
3421 pool_free (vsm->vepitems);
3422 hash_free (vsm->epitemidx_by_epfdfd);
3423
3424 /* free vepitemidxs for each epfd */
3425 /* *INDENT-OFF* */
3426 hash_foreach (epfd, vepitemidxs,
3427 vsm->epitemidxs_by_epfd,
3428 ({
3429 vec_free (vepitemidxs);
3430 }));
3431 /* *INDENT-ON* */
3432 hash_free (vsm->epitemidxs_by_epfd);
3433
3434 /* free vepitemidxs for each fd */
3435 /* *INDENT-OFF* */
3436 hash_foreach (fd, vepitemidxs,
3437 vsm->epitemidxs_by_fd,
3438 ({
3439 vec_free (vepitemidxs);
3440 }));
3441 /* *INDENT-ON* */
3442 hash_free (vsm->epitemidxs_by_fd);
3443
3444
3445 /*
3446 * from active list of vsockets,
3447 * close socket and vppcom session
3448 * */
3449
3450 /* *INDENT-OFF* */
3451 pool_foreach (vsock, vsm->vsockets,
3452 ({
3453 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3454 {
3455 vppcom_session_close (vsock->sid);
3456 vcom_socket_close_socket (vsock->fd);
3457 vsocket_init (vsock);
3458 }
3459 }));
3460 /* *INDENT-ON* */
3461
3462 /*
3463 * return vsocket element to the pool
3464 * */
3465
3466 /* *INDENT-OFF* */
3467 pool_flush (vsock, vsm->vsockets,
3468 ({
3469 // vsocket_init(vsock);
3470 ;
3471 }));
3472 /* *INDENT-ON* */
3473
3474 pool_free (vsm->vsockets);
3475 hash_free (vsm->sockidx_by_fd);
3476
3477 /*
3478 * from active list of vepolls,
3479 * close epoll and vppcom_epoll
3480 * */
3481
3482 /* *INDENT-OFF* */
3483 pool_foreach (vepoll, vsm->vepolls,
3484 ({
3485 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3486 {
3487 vppcom_session_close (vepoll->vep_idx);
3488 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3489 vepoll_init (vepoll);
3490 }
3491 }));
3492 /* *INDENT-ON* */
3493
3494 /*
3495 * return vepoll element to the pool
3496 * */
3497
3498 /* *INDENT-OFF* */
3499 pool_flush (vepoll, vsm->vepolls,
3500 ({
3501 // vepoll_init(vepoll);
3502 ;
3503 }));
3504 /* *INDENT-ON* */
3505
3506 pool_free (vsm->vepolls);
3507 hash_free (vsm->epollidx_by_epfd);
3508
3509 vsm->init = 0;
3510 }
3511}
3512
3513
3514/*
3515 * fd.io coding-style-patch-verification: ON
3516 *
3517 * Local Variables:
3518 * eval: (c-set-style "gnu")
3519 * End:
3520 */