blob: a84359e84179616ed18345fb4467040815ea47d7 [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>
Dave Wallacee695cb42017-11-02 22:04:42 -040024#include <vppinfra/time.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070025#include <vppinfra/hash.h>
26#include <vppinfra/pool.h>
27
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040028#include <vcl/vcom_socket.h>
29#include <vcl/vcom_socket_wrapper.h>
30#include <vcl/vcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070031
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040032#include <vcl/vppcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070033
Damjan Marionc981b092017-10-29 19:28:31 +010034#ifndef IOV_MAX
35#define IOV_MAX __IOV_MAX
36#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070037
38/*
39 * VCOM_SOCKET Private definitions and functions.
40 */
41
42typedef struct vcom_socket_main_t_
43{
44 u8 init;
Dave Wallacee695cb42017-11-02 22:04:42 -040045 clib_time_t clib_time;
46 pid_t my_pid;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070047
48 /* vcom_socket pool */
49 vcom_socket_t *vsockets;
50
51 /* Hash table for socketidx to fd mapping */
52 uword *sockidx_by_fd;
53
54 /* vcom_epoll pool */
55 vcom_epoll_t *vepolls;
56
57 /* Hash table for epollidx to epfd mapping */
58 uword *epollidx_by_epfd;
59
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070060 /* common epitem poll for all epfd */
61 /* TBD: epitem poll per epfd */
62 /* vcom_epitem pool */
63 vcom_epitem_t *vepitems;
64
65 /* Hash table for epitemidx to epfdfd mapping */
66 uword *epitemidx_by_epfdfd;
67
68 /* Hash table - key:epfd, value:vec of epitemidx */
69 uword *epitemidxs_by_epfd;
70 /* Hash table - key:fd, value:vec of epitemidx */
71 uword *epitemidxs_by_fd;
72
73} vcom_socket_main_t;
74
75vcom_socket_main_t vcom_socket_main;
76
77
78static int
79vcom_socket_open_socket (int domain, int type, int protocol)
80{
81 int rv = -1;
82
83 /* handle domains implemented by vpp */
84 switch (domain)
85 {
86 case AF_INET:
87 case AF_INET6:
88 /* get socket type and
89 * handle the socket types supported by vpp */
90 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
91 {
92 case SOCK_STREAM:
93 case SOCK_DGRAM:
94 /* the type argument serves a second purpose,
95 * in addition to specifying a socket type,
96 * it may include the bitwise OR of any of
97 * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
98 * the behavior of socket. */
99 rv = libc_socket (domain, type, protocol);
100 if (rv == -1)
101 rv = -errno;
102 break;
103
104 default:
105 break;
106 }
107
108 break;
109
110 default:
111 break;
112 }
113
114 return rv;
115}
116
117static int
118vcom_socket_open_epoll (int flags)
119{
120 int rv = -1;
121
122 if (flags < 0)
123 {
124 return -EINVAL;
125 }
126 if (flags && (flags & ~EPOLL_CLOEXEC))
127 {
128 return -EINVAL;
129 }
130
131 /* flags can be either zero or EPOLL_CLOEXEC */
132 rv = libc_epoll_create1 (flags);
133 if (rv == -1)
134 rv = -errno;
135
136 return rv;
137}
138
139static int
140vcom_socket_close_socket (int fd)
141{
142 int rv;
143
144 rv = libc_close (fd);
145 if (rv == -1)
146 rv = -errno;
147
148 return rv;
149}
150
151static int
152vcom_socket_close_epoll (int epfd)
153{
154 int rv;
155
156 rv = libc_close (epfd);
157 if (rv == -1)
158 rv = -errno;
159
160 return rv;
161}
162
163/*
164 * Public API functions
165 */
166
167
168int
169vcom_socket_is_vcom_fd (int fd)
170{
171 vcom_socket_main_t *vsm = &vcom_socket_main;
172 uword *p;
173 vcom_socket_t *vsock;
174
175 p = hash_get (vsm->sockidx_by_fd, fd);
176
177 if (p)
178 {
179 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
180 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
181 return 1;
182 }
183 return 0;
184}
185
186int
187vcom_socket_is_vcom_epfd (int epfd)
188{
189 vcom_socket_main_t *vsm = &vcom_socket_main;
190 uword *p;
191 vcom_epoll_t *vepoll;
192
193 p = hash_get (vsm->epollidx_by_epfd, epfd);
194
195 if (p)
196 {
197 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
198 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
199 return 1;
200 }
201 return 0;
202}
203
204static inline int
205vcom_socket_get_sid (int fd)
206{
207 vcom_socket_main_t *vsm = &vcom_socket_main;
208 uword *p;
209 vcom_socket_t *vsock;
210
211 p = hash_get (vsm->sockidx_by_fd, fd);
212
213 if (p)
214 {
215 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
216 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
217 return vsock->sid;
218 }
219 return INVALID_SESSION_ID;
220}
221
222static inline int
223vcom_socket_get_vep_idx (int epfd)
224{
225 vcom_socket_main_t *vsm = &vcom_socket_main;
226 uword *p;
227 vcom_epoll_t *vepoll;
228
229 p = hash_get (vsm->epollidx_by_epfd, epfd);
230
231 if (p)
232 {
233 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
234 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
235 return vepoll->vep_idx;
236 }
237 return INVALID_VEP_IDX;
238}
239
240static inline int
241vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
242{
243 vcom_socket_main_t *vsm = &vcom_socket_main;
244 uword *p;
245 vcom_socket_t *vsock;
246
247 p = hash_get (vsm->sockidx_by_fd, fd);
248
249 if (p)
250 {
251 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
252 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
253 {
254 *vsockp = vsock;
255 return vsock->sid;
256 }
257 }
258 return INVALID_SESSION_ID;
259}
260
261static inline int
262vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
263{
264 vcom_socket_main_t *vsm = &vcom_socket_main;
265 uword *p;
266 vcom_epoll_t *vepoll;
267
268 p = hash_get (vsm->epollidx_by_epfd, epfd);
269
270 if (p)
271 {
272 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
273 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
274 {
275 *vepollp = vepoll;
276 return vepoll->vep_idx;
277 }
278 }
279 return INVALID_VEP_IDX;
280}
281
282
283static int
284vcom_socket_close_vepoll (int epfd)
285{
286 int rv = -1;
287 vcom_socket_main_t *vsm = &vcom_socket_main;
288 uword *p;
289 vcom_epoll_t *vepoll;
290
291 p = hash_get (vsm->epollidx_by_epfd, epfd);
292 if (!p)
293 return -EBADF;
294
295 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
296 if (!vepoll)
297 return -EBADF;
298
299 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
300 return -EINVAL;
301
302 if (vepoll->count)
303 {
304 if (!vepoll->close)
305 {
306 vepoll->close = 1;
307 return 0;
308 }
309 else
310 {
311 return -EBADF;
312 }
313 }
314
315 /* count is zero */
316 rv = vppcom_session_close (vepoll->vep_idx);
317 rv = vcom_socket_close_epoll (vepoll->epfd);
318
319 vepoll_init (vepoll);
320 hash_unset (vsm->epollidx_by_epfd, epfd);
321 pool_put (vsm->vepolls, vepoll);
322
323 return rv;
324}
325
326static int
327vcom_socket_close_vsock (int fd)
328{
329 int rv = -1;
330 vcom_socket_main_t *vsm = &vcom_socket_main;
331 uword *p;
332 vcom_socket_t *vsock;
333
334 vcom_epitem_t *vepitem;
335
336 i32 *vepitemidxs = 0;
337 i32 *vepitemidxs_var = 0;
338
339 p = hash_get (vsm->sockidx_by_fd, fd);
340 if (!p)
341 return -EBADF;
342
343 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
344 if (!vsock)
345 return -ENOTSOCK;
346
347 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
348 return -EINVAL;
349
350 rv = vppcom_session_close (vsock->sid);
351 rv = vcom_socket_close_socket (vsock->fd);
352
353 vsocket_init (vsock);
354 hash_unset (vsm->sockidx_by_fd, fd);
355 pool_put (vsm->vsockets, vsock);
356
357 /*
358 * NOTE:
359 * Before calling close(), user should remove
360 * this fd from the epoll-set of all epoll instances,
361 * otherwise resource(epitems) leaks ensues.
362 */
363
364 /*
365 * 00. close all epoll instances that are marked as "close"
366 * of which this fd is the "last" remaining member.
367 * 01. epitems associated with this fd are intentionally
368 * not removed, see NOTE: above.
369 * */
370
371 /* does this fd participate in epoll */
372 p = hash_get (vsm->epitemidxs_by_fd, fd);
373 if (p)
374 {
375 vepitemidxs = *(i32 **) p;
376 vec_foreach (vepitemidxs_var, vepitemidxs)
377 {
378 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
379 if (vepitem && vepitem->fd == fd &&
380 vepitem->type == FD_TYPE_VCOM_SOCKET)
381 {
382 i32 vep_idx;
383 vcom_epoll_t *vepoll;
384 if ((vep_idx =
385 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
386 &vepoll)) !=
387 INVALID_VEP_IDX)
388 {
389 if (vepoll->close)
390 {
391 if (vepoll->count == 1)
392 {
393 /*
394 * force count to zero and
395 * close this epoll instance
396 * */
397 vepoll->count = 0;
398 vcom_socket_close_vepoll (vepoll->epfd);
399 }
400 else
401 {
402 vepoll->count -= 1;
403 }
404 }
405 }
406 }
407
408 }
409 }
410
411 return rv;
412}
413
414int
415vcom_socket_close (int __fd)
416{
417 int rv;
418
419 if (vcom_socket_is_vcom_fd (__fd))
420 {
421 rv = vcom_socket_close_vsock (__fd);
422 }
423 else if (vcom_socket_is_vcom_epfd (__fd))
424 {
425 rv = vcom_socket_close_vepoll (__fd);
426 }
427 else
428 {
429 rv = -EBADF;
430 }
431
432 return rv;
433}
434
435ssize_t
436vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
437{
438 int rv = -1;
439 vcom_socket_main_t *vsm = &vcom_socket_main;
440 uword *p;
441 vcom_socket_t *vsock;
442
443 p = hash_get (vsm->sockidx_by_fd, __fd);
444 if (!p)
445 return -EBADF;
446
447 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
448 if (!vsock)
449 return -ENOTSOCK;
450
451 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
452 return -EINVAL;
453
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400454 if (!__buf)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700455 {
456 return -EINVAL;
457 }
458
459 rv = vcom_fcntl (__fd, F_GETFL, 0);
460 if (rv < 0)
461 {
462 return rv;
463
464 }
465
466 /* is blocking */
467 if (!(rv & O_NONBLOCK))
468 {
469 do
470 {
471 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
472 }
Dave Wallace60f54822017-10-24 20:47:45 -0400473 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700474 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
475 return rv;
476 }
477 /* The file descriptor refers to a socket and has been
478 * marked nonblocking(O_NONBLOCK) and the read would
479 * block.
480 * */
481 /* is non blocking */
482 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
483 return rv;
484}
485
486ssize_t
487vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
488{
489 int rv;
490 vcom_socket_main_t *vsm = &vcom_socket_main;
491 uword *p;
492 vcom_socket_t *vsock;
493 ssize_t total = 0, len = 0;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400494 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700495
496 p = hash_get (vsm->sockidx_by_fd, __fd);
497 if (!p)
498 return -EBADF;
499
500 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
501 if (!vsock)
502 return -ENOTSOCK;
503
504 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
505 return -EINVAL;
506
507 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
508 return -EINVAL;
509
510 /* Sanity check */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400511 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700512 {
513 if (SSIZE_MAX - len < __iov[i].iov_len)
514 return -EINVAL;
515 len += __iov[i].iov_len;
516 }
517
518 rv = vcom_fcntl (__fd, F_GETFL, 0);
519 if (rv < 0)
520 {
521 return rv;
522 }
523
524 /* is blocking */
525 if (!(rv & O_NONBLOCK))
526 {
527 do
528 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400529 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700530 {
531 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
532 __iov[i].iov_len);
533 if (rv < 0)
534 break;
535 else
536 {
537 total += rv;
538 if (rv < __iov[i].iov_len)
539 /* Read less than buffer provided, no point to continue */
540 break;
541 }
542 }
543 }
Dave Wallace60f54822017-10-24 20:47:45 -0400544 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700545 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
546 return total;
547 }
548
549 /* is non blocking */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400550 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700551 {
552 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
553 __iov[i].iov_len);
554 if (rv < 0)
555 {
556 if (total > 0)
557 break;
558 else
559 {
560 errno = rv;
561 return rv;
562 }
563 }
564 else
565 {
566 total += rv;
567 if (rv < __iov[i].iov_len)
568 /* Read less than buffer provided, no point to continue */
569 break;
570 }
571 }
572 return total;
573}
574
575ssize_t
576vcom_socket_write (int __fd, const void *__buf, size_t __n)
577{
578 int rv = -1;
579 vcom_socket_main_t *vsm = &vcom_socket_main;
580 uword *p;
581 vcom_socket_t *vsock;
582
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400583 if (!__buf)
584 {
585 return -EINVAL;
586 }
587
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700588 p = hash_get (vsm->sockidx_by_fd, __fd);
589 if (!p)
590 return -EBADF;
591
592 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
593 if (!vsock)
594 return -ENOTSOCK;
595
596 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
597 return -EINVAL;
598
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700599 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
600 return rv;
601}
602
603ssize_t
604vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
605{
606 int rv = -1;
607 ssize_t total = 0;
608 vcom_socket_main_t *vsm = &vcom_socket_main;
609 uword *p;
610 vcom_socket_t *vsock;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400611 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700612
613 p = hash_get (vsm->sockidx_by_fd, __fd);
614 if (!p)
615 return -EBADF;
616
617 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
618 if (!vsock)
619 return -ENOTSOCK;
620
621 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
622 return -EINVAL;
623
624 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
625 return -EINVAL;
626
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400627 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700628 {
629 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
630 __iov[i].iov_len);
631 if (rv < 0)
632 {
633 if (total > 0)
634 break;
635 else
636 return rv;
637 }
638 else
639 total += rv;
640 }
641 return total;
642}
643
644/*
645 * RETURN: 0 - invalid cmd
646 * 1 - cmd not handled by vcom and vppcom
647 * 2 - cmd handled by vcom socket resource
648 * 3 - cmd handled by vppcom
649 * */
650/* TBD: incomplete list of cmd */
651static int
652vcom_socket_check_fcntl_cmd (int __cmd)
653{
654 switch (__cmd)
655 {
656 /*cmd not handled by vcom and vppcom */
657 /* Fallthrough */
658 case F_DUPFD:
659 case F_DUPFD_CLOEXEC:
660 return 1;
661
662 /* cmd handled by vcom socket resource */
663 /* Fallthrough */
664 case F_GETFD:
665 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700666 case F_GETLK:
667 case F_SETLK:
668 case F_SETLKW:
669 case F_GETOWN:
670 case F_SETOWN:
671 return 2;
672
Stevenb59f2272017-10-12 17:10:33 -0700673 /* cmd handled by vcom and vppcom */
674 case F_SETFL:
675 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700676 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700677
678 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700679 default:
Stevenb59f2272017-10-12 17:10:33 -0700680 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700681 }
682 return 0;
683}
684
Dave Wallacee22aa742017-10-20 12:30:38 -0400685static inline int
686vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700687{
Stevenb59f2272017-10-12 17:10:33 -0700688 int flags = va_arg (__ap, int);
689 int rv = -EOPNOTSUPP;
690 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700691
Stevenb59f2272017-10-12 17:10:33 -0700692 size = sizeof (flags);
693 if (__cmd == F_SETFL)
694 {
695 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
696 }
697 else if (__cmd == F_GETFL)
698 {
699 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
700 if (rv == VPPCOM_OK)
701 rv = flags;
702 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700703
704 return rv;
705}
706
707int
708vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
709{
710 int rv = -EBADF;
711 vcom_socket_main_t *vsm = &vcom_socket_main;
712 uword *p;
713 vcom_socket_t *vsock;
714
715 p = hash_get (vsm->sockidx_by_fd, __fd);
716 if (!p)
717 return -EBADF;
718
719 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
720 if (!vsock)
721 return -ENOTSOCK;
722
723 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
724 return -EINVAL;
725
726 switch (vcom_socket_check_fcntl_cmd (__cmd))
727 {
728 /* invalid cmd */
729 case 0:
730 rv = -EBADF;
731 break;
732 /*cmd not handled by vcom and vppcom */
733 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700734 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700735 break;
736 /* cmd handled by vcom socket resource */
737 case 2:
738 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
739 break;
740 /* cmd handled by vppcom */
741 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400742 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700743 break;
744
745 default:
746 rv = -EINVAL;
747 break;
748 }
749
750 return rv;
751}
752
Stevenb59f2272017-10-12 17:10:33 -0700753/*
754 * RETURN: 0 - invalid cmd
755 * 1 - cmd not handled by vcom and vppcom
756 * 2 - cmd handled by vcom socket resource
757 * 3 - cmd handled by vppcom
758 */
759static int
760vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
761{
762 int rc;
763
764 switch (__cmd)
765 {
766 /* cmd handled by vppcom */
767 case FIONREAD:
768 rc = 3;
769 break;
770
771 /* cmd not handled by vcom and vppcom */
772 default:
773 rc = 1;
774 break;
775 }
776 return rc;
777}
778
Dave Wallacee22aa742017-10-20 12:30:38 -0400779static inline int
780vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
Stevenb59f2272017-10-12 17:10:33 -0700781{
782 int rv;
783
Dave Wallace59179392017-11-07 02:20:07 -0500784 switch (__cmd)
785 {
786 case FIONREAD:
787 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
788 break;
789
790 case FIONBIO:
791 {
792 u32 flags = va_arg (__ap, int) ? O_NONBLOCK : 0;
793 u32 len = sizeof (flags);
794 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &len);
795 }
796 break;
797
798 default:
799 rv = -EOPNOTSUPP;
800 break;
801 }
Stevenb59f2272017-10-12 17:10:33 -0700802 return rv;
803}
804
805int
806vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
807{
808 int rv = -EBADF;
809 vcom_socket_main_t *vsm = &vcom_socket_main;
810 uword *p;
811 vcom_socket_t *vsock;
812
813 p = hash_get (vsm->sockidx_by_fd, __fd);
814 if (!p)
815 return -EBADF;
816
817 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
818 if (!vsock)
819 return -ENOTSOCK;
820
821 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
822 return -EINVAL;
823
824 switch (vcom_socket_check_ioctl_cmd (__cmd))
825 {
826 /* Not supported cmd */
827 case 0:
828 rv = -EOPNOTSUPP;
829 break;
830
831 /* cmd not handled by vcom and vppcom */
832 case 1:
833 rv = libc_vioctl (vsock->fd, __cmd, __ap);
834 break;
835
836 /* cmd handled by vcom socket resource */
837 case 2:
838 rv = libc_vioctl (vsock->fd, __cmd, __ap);
839 break;
840
841 /* cmd handled by vppcom */
842 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400843 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
Stevenb59f2272017-10-12 17:10:33 -0700844 break;
845
846 default:
847 rv = -EINVAL;
848 break;
849 }
850
851 return rv;
852}
853
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700854static inline int
855vcom_socket_fds_2_sid_fds (
856 /* dest */
857 int *vcom_nsid_fds,
858 fd_set * __restrict vcom_rd_sid_fds,
859 fd_set * __restrict vcom_wr_sid_fds,
860 fd_set * __restrict vcom_ex_sid_fds,
861 /* src */
862 int vcom_nfds,
863 fd_set * __restrict vcom_readfds,
864 fd_set * __restrict vcom_writefds,
865 fd_set * __restrict vcom_exceptfds)
866{
867 int rv = 0;
868 int fd;
869 int sid;
870 /* invalid max_sid is -1 */
871 int max_sid = -1;
872 int nsid = 0;
873
874 /*
875 * set sid in sid sets corresponding to fd's in fd sets
876 * compute nsid and vcom_nsid_fds from sid sets
877 */
878
879 for (fd = 0; fd < vcom_nfds; fd++)
880 {
881 /*
882 * F fd set, src
883 * S sid set, dest
884 */
885#define _(S,F) \
886 if ((F) && (S) && FD_ISSET (fd, (F))) \
887 { \
888 sid = vcom_socket_get_sid (fd); \
889 if (sid != INVALID_SESSION_ID) \
890 { \
891 FD_SET (sid, (S)); \
892 if (sid > max_sid) \
893 { \
894 max_sid = sid; \
895 } \
896 ++nsid; \
897 } \
898 else \
899 { \
900 rv = -EBADFD; \
901 goto done; \
902 } \
903 }
904
905
906 _(vcom_rd_sid_fds, vcom_readfds);
907 _(vcom_wr_sid_fds, vcom_writefds);
908 _(vcom_ex_sid_fds, vcom_exceptfds);
909#undef _
910 }
911
912 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
913 rv = nsid;
914
915done:
916 return rv;
917}
918
919/*
920 * PRE: 00. sid sets were derived from fd sets
921 * 01. sid sets were updated with sids that actually changed
922 * status
923 * 02. fd sets still has watched fds
924 *
925 * This function will modify in place fd sets to indicate which fd's
926 * actually changed status(inferred from sid sets)
927 */
928static inline int
929vcom_socket_sid_fds_2_fds (
930 /* dest */
931 int *new_vcom_nfds,
932 int vcom_nfds,
933 fd_set * __restrict vcom_readfds,
934 fd_set * __restrict vcom_writefds,
935 fd_set * __restrict vcom_exceptfds,
936 /* src */
937 int vcom_nsid_fds,
938 fd_set * __restrict vcom_rd_sid_fds,
939 fd_set * __restrict vcom_wr_sid_fds,
940 fd_set * __restrict vcom_ex_sid_fds)
941{
942 int rv = 0;
943 int fd;
944 int sid;
945 /* invalid max_fd is -1 */
946 int max_fd = -1;
947 int nfd = 0;
948
949
950 /*
951 * modify in place fd sets to indicate which fd's
952 * actually changed status(inferred from sid sets)
953 */
954 for (fd = 0; fd < vcom_nfds; fd++)
955 {
956 /*
957 * F fd set, dest
958 * S sid set, src
959 */
960#define _(S,F) \
961 if ((F) && (S) && FD_ISSET (fd, (F))) \
962 { \
963 sid = vcom_socket_get_sid (fd); \
964 if (sid != INVALID_SESSION_ID) \
965 { \
966 if (!FD_ISSET (sid, (S))) \
967 { \
968 FD_CLR(fd, (F)); \
969 } \
970 } \
971 else \
972 { \
973 rv = -EBADFD; \
974 goto done; \
975 } \
976 }
977
978
979 _(vcom_rd_sid_fds, vcom_readfds);
980 _(vcom_wr_sid_fds, vcom_writefds);
981 _(vcom_ex_sid_fds, vcom_exceptfds);
982#undef _
983 }
984
985 /*
986 * compute nfd and new_vcom_nfds from fd sets
987 */
988 for (fd = 0; fd < vcom_nfds; fd++)
989 {
990
991#define _(F) \
992 if ((F) && FD_ISSET (fd, (F))) \
993 { \
994 if (fd > max_fd) \
995 { \
996 max_fd = fd; \
997 } \
998 ++nfd; \
999 }
1000
1001
1002 _(vcom_readfds);
1003 _(vcom_writefds);
1004 _(vcom_exceptfds);
1005#undef _
1006
1007 }
1008
1009 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
1010 rv = nfd;
1011
1012done:
1013 return rv;
1014}
1015
1016/*
1017 * PRE:
1018 * vom_socket_select is always called with
1019 * timeout->tv_sec and timeout->tv_usec set to zero.
1020 * hence vppcom_select return immediately.
1021 */
1022/*
1023 * TBD: do{body;} while(timeout conditional); timeout loop
1024 */
1025int
1026vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1027 fd_set * __restrict vcom_writefds,
1028 fd_set * __restrict vcom_exceptfds,
1029 struct timeval *__restrict timeout)
1030{
Dave Wallacee22aa742017-10-20 12:30:38 -04001031 static unsigned long vcom_nsid_fds = 0;
1032 int vcom_nsid = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001033 int rv = -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001034
1035 int new_vcom_nfds = 0;
1036 int new_vcom_nfd = 0;
1037
1038 /* vcom sid fds */
1039 fd_set vcom_rd_sid_fds;
1040 fd_set vcom_wr_sid_fds;
1041 fd_set vcom_ex_sid_fds;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001042
1043 /* in seconds eg. 3.123456789 seconds */
1044 double time_to_wait = (double) 0;
1045
1046 /* validate inputs */
1047 if (vcom_nfds < 0)
1048 {
1049 return -EINVAL;
1050 }
1051
1052 /* convert timeval timeout to double time_to_wait */
1053 if (timeout)
1054 {
1055 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1056 {
1057 /* polling: vppcom_select returns immediately */
1058 time_to_wait = (double) 0;
1059 }
1060 else
1061 {
1062 /*TBD: use timeval api */
1063 time_to_wait = (double) timeout->tv_sec +
1064 (double) timeout->tv_usec / (double) 1000000 +
1065 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1066 }
1067 }
1068 else
1069 {
1070 /*
1071 * no timeout: vppcom_select can block indefinitely
1072 * waiting for a file descriptor to become ready
1073 * */
1074 /* set to a phantom value */
1075 time_to_wait = ~0;
1076 }
1077
1078 /* zero the sid_sets */
1079 /*
1080 * F fd set
1081 * S sid set
1082 */
1083#define _(S,F) \
1084 if ((F)) \
1085 { \
1086 FD_ZERO ((S)); \
1087 }
1088
1089
1090 _(&vcom_rd_sid_fds, vcom_readfds);
1091 _(&vcom_wr_sid_fds, vcom_writefds);
1092 _(&vcom_ex_sid_fds, vcom_exceptfds);
1093#undef _
1094
Dave Wallacee22aa742017-10-20 12:30:38 -04001095 if (vcom_nfds == 0)
1096 {
1097 if (time_to_wait > 0)
1098 {
1099 if (VCOM_DEBUG > 0)
1100 fprintf (stderr,
1101 "[%d] vcom_socket_select called to "
Dave Wallace59179392017-11-07 02:20:07 -05001102 "emulate delay_ns()!\n", getpid ());
Dave Wallacee22aa742017-10-20 12:30:38 -04001103 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1104 }
1105 else
1106 {
1107 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
Dave Wallacee695cb42017-11-02 22:04:42 -04001108 "and invalid time_to_wait (%f)!\n",
Dave Wallace59179392017-11-07 02:20:07 -05001109 getpid (), time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001110 }
1111 return 0;
1112 }
1113
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001114 /* populate read, write and except sid_sets */
1115 vcom_nsid = vcom_socket_fds_2_sid_fds (
1116 /* dest */
1117 vcom_readfds || vcom_writefds
1118 || vcom_exceptfds ? (int *)
1119 &vcom_nsid_fds : NULL,
1120 vcom_readfds ? &vcom_rd_sid_fds :
1121 NULL,
1122 vcom_writefds ? &vcom_wr_sid_fds :
1123 NULL,
1124 vcom_exceptfds ? &vcom_ex_sid_fds :
1125 NULL,
1126 /* src */
1127 vcom_nfds,
1128 vcom_readfds,
1129 vcom_writefds, vcom_exceptfds);
1130 if (vcom_nsid < 0)
1131 {
1132 return vcom_nsid;
1133 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001134
1135 rv = vppcom_select (vcom_nsid_fds,
1136 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1137 NULL,
1138 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1139 NULL,
1140 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1141 NULL, time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001142 if (VCOM_DEBUG > 2)
1143 fprintf (stderr, "[%d] called vppcom_select(): "
Dave Wallace59179392017-11-07 02:20:07 -05001144 "'%04d'='%04d'\n", getpid (), rv, (int) vcom_nsid_fds);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001145
1146 /* check if any file descriptors changed status */
1147 if (rv > 0)
1148 {
1149 /*
1150 * on exit, sets are modified in place to indicate which
1151 * file descriptors actually changed status
1152 * */
1153
1154 /*
1155 * comply with pre-condition
1156 * do not clear vcom fd sets befor calling
1157 * vcom_socket_sid_fds_2_fds
1158 */
1159 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1160 /* dest */
1161 &new_vcom_nfds,
1162 vcom_nfds,
1163 vcom_readfds,
1164 vcom_writefds,
1165 vcom_exceptfds,
1166 /* src */
1167 vcom_nsid_fds,
1168 vcom_readfds ?
1169 &vcom_rd_sid_fds : NULL,
1170 vcom_writefds ?
1171 &vcom_wr_sid_fds : NULL,
1172 vcom_exceptfds ?
1173 &vcom_ex_sid_fds : NULL);
1174 if (new_vcom_nfd < 0)
1175 {
1176 return new_vcom_nfd;
1177 }
1178 if (new_vcom_nfds < 0)
1179 {
1180 return -EINVAL;
1181 }
1182 rv = new_vcom_nfd;
1183 }
1184 return rv;
1185}
1186
1187
1188int
1189vcom_socket_socket (int __domain, int __type, int __protocol)
1190{
1191 int rv = -1;
1192 vcom_socket_main_t *vsm = &vcom_socket_main;
1193 vcom_socket_t *vsock;
1194
1195 i32 fd;
1196 i32 sid;
1197 i32 sockidx;
1198 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1199 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1200
1201 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1202 if (fd < 0)
1203 {
1204 rv = fd;
1205 goto out;
1206 }
1207
1208 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1209 (type == SOCK_DGRAM) ?
1210 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1211 is_nonblocking);
1212 if (sid < 0)
1213 {
1214 rv = sid;
1215 goto out_close_socket;
1216 }
1217
1218 pool_get (vsm->vsockets, vsock);
1219 vsocket_init (vsock);
1220
1221 sockidx = vsock - vsm->vsockets;
1222 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1223
1224 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1225 return fd;
1226
1227out_close_socket:
1228 vcom_socket_close_socket (fd);
1229out:
1230 return rv;
1231}
1232
1233int
1234vcom_socket_socketpair (int __domain, int __type, int __protocol,
1235 int __fds[2])
1236{
1237/* TBD: */
1238 return 0;
1239}
1240
1241int
1242vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1243{
1244 int rv = -1;
1245 vcom_socket_main_t *vsm = &vcom_socket_main;
1246 uword *p;
1247 vcom_socket_t *vsock;
1248
1249 vppcom_endpt_t ep;
1250
1251 p = hash_get (vsm->sockidx_by_fd, __fd);
1252 if (!p)
1253 return -EBADF;
1254
1255 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1256 if (!vsock)
1257 return -ENOTSOCK;
1258
1259 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1260 return -EINVAL;
1261
1262 if (!__addr)
1263 {
1264 return -EINVAL;
1265 }
1266
1267 ep.vrf = VPPCOM_VRF_DEFAULT;
1268 switch (__addr->sa_family)
1269 {
1270 case AF_INET:
1271 if (__len != sizeof (struct sockaddr_in))
1272 {
1273 return -EINVAL;
1274 }
1275 ep.is_ip4 = VPPCOM_IS_IP4;
1276 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1277 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1278 break;
1279
1280 case AF_INET6:
1281 if (__len != sizeof (struct sockaddr_in6))
1282 {
1283 return -EINVAL;
1284 }
1285 ep.is_ip4 = VPPCOM_IS_IP6;
1286 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1287 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1288 break;
1289
1290 default:
1291 return -1;
1292 break;
1293 }
1294
1295 rv = vppcom_session_bind (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001296 return rv;
1297}
1298
Dave Wallacee22aa742017-10-20 12:30:38 -04001299static inline int
1300vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001301{
Steven2199aab2017-10-15 20:18:47 -07001302 int rv;
1303 uint32_t size = sizeof (*ep);
1304
1305 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1306 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001307}
1308
1309int
1310vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1311 socklen_t * __restrict __len)
1312{
1313 int rv = -1;
1314 vcom_socket_main_t *vsm = &vcom_socket_main;
1315 uword *p;
1316 vcom_socket_t *vsock;
1317
1318
1319 p = hash_get (vsm->sockidx_by_fd, __fd);
1320 if (!p)
1321 return -EBADF;
1322
1323 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1324 if (!vsock)
1325 return -ENOTSOCK;
1326
1327 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1328 return -EINVAL;
1329
1330 if (!__addr || !__len)
1331 return -EFAULT;
1332
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001333 vppcom_endpt_t ep;
1334 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001335 rv = vcom_session_getsockname (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001336 if (rv == 0)
1337 {
1338 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1339 {
1340 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1341 switch (__addr->sa_family)
1342 {
1343 case AF_INET:
1344 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1345 *__len = sizeof (struct sockaddr_in);
1346 break;
1347
1348 case AF_INET6:
1349 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1350 *__len = sizeof (struct sockaddr_in6);
1351 break;
1352
1353 default:
1354 break;
1355 }
1356 }
1357 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001358
1359 return rv;
1360}
1361
1362int
1363vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1364{
1365 int rv = -1;
1366 vcom_socket_main_t *vsm = &vcom_socket_main;
1367 uword *p;
1368 vcom_socket_t *vsock;
1369
1370 vppcom_endpt_t ep;
1371
1372 p = hash_get (vsm->sockidx_by_fd, __fd);
1373 if (p)
1374 {
1375 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1376
1377 ep.vrf = VPPCOM_VRF_DEFAULT;
1378 switch (__addr->sa_family)
1379 {
1380 case AF_INET:
1381 ep.is_ip4 = VPPCOM_IS_IP4;
1382 ep.ip =
1383 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1384 ep.port =
1385 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1386 break;
1387
1388 case AF_INET6:
1389 ep.is_ip4 = VPPCOM_IS_IP6;
1390 ep.ip =
1391 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1392 ep.port =
1393 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1394 break;
1395
1396 default:
1397 return -1;
1398 break;
1399 }
1400
1401 rv = vppcom_session_connect (vsock->sid, &ep);
1402 }
1403 return rv;
1404}
1405
Dave Wallacee22aa742017-10-20 12:30:38 -04001406static inline int
1407vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001408{
Steven2199aab2017-10-15 20:18:47 -07001409 int rv;
1410 uint32_t size = sizeof (*ep);
1411
1412 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1413 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001414}
1415
Steven0cdd5bd2017-11-08 14:14:45 -08001416static inline int
1417vcom_socket_copy_ep_to_sockaddr (__SOCKADDR_ARG __addr,
1418 socklen_t * __restrict __len,
1419 vppcom_endpt_t * ep)
1420{
1421 int rv = 0;
1422 int sa_len, copy_len;
1423
1424 __addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1425 switch (__addr->sa_family)
1426 {
1427 case AF_INET:
1428 ((struct sockaddr_in *) __addr)->sin_port = ep->port;
1429 if (*__len > sizeof (struct sockaddr_in))
1430 *__len = sizeof (struct sockaddr_in);
1431 sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1432 copy_len = *__len - sa_len;
1433 if (copy_len > 0)
1434 memcpy (&((struct sockaddr_in *) __addr)->sin_addr, ep->ip, copy_len);
1435 break;
1436
1437 case AF_INET6:
1438 ((struct sockaddr_in6 *) __addr)->sin6_port = ep->port;
1439 if (*__len > sizeof (struct sockaddr_in6))
1440 *__len = sizeof (struct sockaddr_in6);
1441 sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1442 copy_len = *__len - sa_len;
1443 if (copy_len > 0)
1444 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1445 __in6_u.__u6_addr8, ep->ip, copy_len);
1446 break;
1447
1448 default:
1449 /* Not possible */
1450 rv = -EAFNOSUPPORT;
1451 break;
1452 }
1453
1454 return rv;
1455}
1456
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001457int
1458vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1459 socklen_t * __restrict __len)
1460{
1461 int rv = -1;
1462 vcom_socket_main_t *vsm = &vcom_socket_main;
1463 uword *p;
1464 vcom_socket_t *vsock;
Steven0cdd5bd2017-11-08 14:14:45 -08001465 u8 src_addr[sizeof (struct sockaddr_in6)];
1466 vppcom_endpt_t ep;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001467
1468 p = hash_get (vsm->sockidx_by_fd, __fd);
1469 if (!p)
1470 return -EBADF;
1471
1472 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1473 if (!vsock)
1474 return -ENOTSOCK;
1475
1476 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1477 return -EINVAL;
1478
1479 if (!__addr || !__len)
1480 return -EFAULT;
1481
Steven0cdd5bd2017-11-08 14:14:45 -08001482 ep.ip = src_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001483 rv = vcom_session_getpeername (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001484 if (rv == 0)
Steven0cdd5bd2017-11-08 14:14:45 -08001485 rv = vcom_socket_copy_ep_to_sockaddr (__addr, __len, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001486
1487 return rv;
1488}
1489
1490ssize_t
1491vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1492{
1493 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1494}
1495
1496ssize_t
1497vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1498{
1499 int rv = -1;
1500 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1501 return rv;
1502}
1503
1504/*
1505 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1506 * 0 otherwise
1507 * */
1508int
1509vcom_socket_is_connection_mode_socket (int __fd)
1510{
1511 int rv = -1;
1512 /* TBD define new vppcom api */
1513 vcom_socket_main_t *vsm = &vcom_socket_main;
1514 uword *p;
1515 vcom_socket_t *vsock;
1516
1517 int type;
1518 socklen_t optlen;
1519
1520 p = hash_get (vsm->sockidx_by_fd, __fd);
1521
1522 if (p)
1523 {
1524 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1525 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1526 {
1527 optlen = sizeof (type);
1528 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1529 if (rv != 0)
1530 {
1531 return 0;
1532 }
1533 /* get socket type */
1534 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1535 {
1536 case SOCK_STREAM:
1537 case SOCK_SEQPACKET:
1538 return 1;
1539 break;
1540
1541 default:
1542 return 0;
1543 break;
1544 }
1545 }
1546 }
1547 return 0;
1548}
1549
Dave Wallacee22aa742017-10-20 12:30:38 -04001550static inline ssize_t
1551vcom_session_sendto (int __sid, void *__buf, size_t __n,
1552 int __flags, __CONST_SOCKADDR_ARG __addr,
1553 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001554{
Dave Wallace617dffa2017-10-26 14:47:06 -04001555 vppcom_endpt_t *ep = 0;
Steven8aa0d782017-10-27 09:34:57 -07001556 vppcom_endpt_t _ep;
Stevenac1f96d2017-10-24 16:03:58 -07001557
Dave Wallace617dffa2017-10-26 14:47:06 -04001558 if (__addr)
Stevenac1f96d2017-10-24 16:03:58 -07001559 {
Dave Wallace617dffa2017-10-26 14:47:06 -04001560 ep = &_ep;
1561 ep->vrf = VPPCOM_VRF_DEFAULT;
1562 switch (__addr->sa_family)
1563 {
1564 case AF_INET:
1565 ep->is_ip4 = VPPCOM_IS_IP4;
1566 ep->ip =
1567 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1568 ep->port =
1569 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1570 break;
Stevenac1f96d2017-10-24 16:03:58 -07001571
Dave Wallace617dffa2017-10-26 14:47:06 -04001572 case AF_INET6:
1573 ep->is_ip4 = VPPCOM_IS_IP6;
1574 ep->ip =
1575 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1576 ep->port =
1577 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1578 break;
1579
1580 default:
1581 return -EAFNOSUPPORT;
1582 }
Stevenac1f96d2017-10-24 16:03:58 -07001583 }
1584
Dave Wallace617dffa2017-10-26 14:47:06 -04001585 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001586}
1587
1588ssize_t
1589vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1590 int __flags, __CONST_SOCKADDR_ARG __addr,
1591 socklen_t __addr_len)
1592{
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001593 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)
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
1615 if (vcom_socket_is_connection_mode_socket (__fd))
1616 {
1617 /* ignore __addr and _addr_len */
1618 /* and EISCONN may be returned when they are not NULL and 0 */
1619 if ((__addr != NULL) || (__addr_len != 0))
1620 {
1621 return -EISCONN;
1622 }
1623 }
1624 else
1625 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001626 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001627 {
1628 return -EDESTADDRREQ;
1629 }
1630 /* not a vppcom supported address family */
Dave Wallace60f54822017-10-24 20:47:45 -04001631 if (!((__addr->sa_family == AF_INET) ||
1632 (__addr->sa_family == AF_INET6)))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001633 {
1634 return -EINVAL;
1635 }
1636 }
1637
Dave Wallace617dffa2017-10-26 14:47:06 -04001638 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1639 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001640}
1641
Dave Wallacee22aa742017-10-20 12:30:38 -04001642static inline ssize_t
1643vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1644 int __flags, __SOCKADDR_ARG __addr,
1645 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001646{
Stevenac1f96d2017-10-24 16:03:58 -07001647 int rv;
1648 vppcom_endpt_t ep;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001649 u8 src_addr[sizeof (struct sockaddr_in6)];
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001650
Stevenac1f96d2017-10-24 16:03:58 -07001651 if (__addr)
1652 {
Dave Wallacefaf9d772017-10-26 16:12:04 -04001653 ep.ip = src_addr;
Stevenac1f96d2017-10-24 16:03:58 -07001654 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1655
1656 if (rv > 0)
Steven0cdd5bd2017-11-08 14:14:45 -08001657 rv = vcom_socket_copy_ep_to_sockaddr (__addr, __addr_len, &ep);
Stevenac1f96d2017-10-24 16:03:58 -07001658 }
1659 else
1660 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1661
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001662 return rv;
1663}
1664
1665ssize_t
1666vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1667 int __flags, __SOCKADDR_ARG __addr,
1668 socklen_t * __restrict __addr_len)
1669{
1670 int rv = -1;
1671 vcom_socket_main_t *vsm = &vcom_socket_main;
1672 uword *p;
1673 vcom_socket_t *vsock;
1674
Stevenac1f96d2017-10-24 16:03:58 -07001675 if (__addr && !__addr_len)
1676 return -EINVAL;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001677
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001678 p = hash_get (vsm->sockidx_by_fd, __fd);
1679 if (!p)
1680 return -EBADF;
1681
1682 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1683 if (!vsock)
1684 return -ENOTSOCK;
1685
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001686 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001687 {
1688 return -EINVAL;
1689 }
1690
Dave Wallacee22aa742017-10-20 12:30:38 -04001691 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1692 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001693 return rv;
1694}
1695
1696/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001697static inline ssize_t
1698vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001699{
1700 int rv = -1;
1701 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1702 (int)__n); */
1703 return rv;
1704}
1705
1706ssize_t
1707vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1708{
1709 int rv = -1;
1710 vcom_socket_main_t *vsm = &vcom_socket_main;
1711 uword *p;
1712 vcom_socket_t *vsock;
1713
1714 p = hash_get (vsm->sockidx_by_fd, __fd);
1715 if (!p)
1716 return -EBADF;
1717
1718 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1719 if (!vsock)
1720 return -ENOTSOCK;
1721
1722 if (vcom_socket_is_connection_mode_socket (__fd))
1723 {
1724 /* ignore __addr and _addr_len */
1725 /* and EISCONN may be returned when they are not NULL and 0 */
1726 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1727 {
1728 return -EISCONN;
1729 }
1730 }
1731 else
1732 {
1733 /* TBD: validate __message->msg_name and __message->msg_namelen
1734 * and return -EINVAL on validation error
1735 * */
1736 ;
1737 }
1738
Dave Wallacee22aa742017-10-20 12:30:38 -04001739 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001740
1741 return rv;
1742}
1743
1744#ifdef __USE_GNU
1745int
1746vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1747 unsigned int __vlen, int __flags)
1748{
1749
1750 /* TBD: define a new vppcom api */
1751 return 0;
1752}
1753#endif
1754
1755/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001756static inline ssize_t
1757vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001758{
1759 int rv = -1;
1760 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1761 (int)__n); */
1762 rv = -EOPNOTSUPP;
1763 return rv;
1764}
1765
1766ssize_t
1767vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1768{
1769 int rv = -1;
1770 vcom_socket_main_t *vsm = &vcom_socket_main;
1771 uword *p;
1772 vcom_socket_t *vsock;
1773
1774 p = hash_get (vsm->sockidx_by_fd, __fd);
1775 if (!p)
1776 return -EBADF;
1777
1778 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1779 if (!vsock)
1780 return -ENOTSOCK;
1781
1782 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1783 return -EINVAL;
1784
1785 if (!__message)
1786 {
1787 return -EINVAL;
1788 }
1789
1790 /* validate __flags */
1791
Dave Wallacee22aa742017-10-20 12:30:38 -04001792 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001793 return rv;
1794}
1795
1796#ifdef __USE_GNU
1797int
1798vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1799 unsigned int __vlen, int __flags,
1800 struct timespec *__tmo)
1801{
1802 /* TBD: define a new vppcom api */
1803 return 0;
1804}
1805#endif
1806
1807/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001808static inline int
1809vcom_session_get_sockopt (int __sid, int __level, int __optname,
1810 void *__restrict __optval,
1811 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001812{
Stevenac1f96d2017-10-24 16:03:58 -07001813 int rv = 0;
1814
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001815 /* 1. for socket level options that are NOT socket attributes
1816 * and that has corresponding vpp options get from vppcom */
Stevenac1f96d2017-10-24 16:03:58 -07001817 switch (__level)
1818 {
1819 case SOL_SOCKET:
1820 switch (__optname)
1821 {
1822 case SO_ERROR:
1823 *(int *) __optval = 0;
1824 break;
1825 default:
1826 break;
1827 }
1828 default:
1829 break;
1830 }
1831 /* 2. unhandled options */
1832 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001833}
1834
1835int
1836vcom_socket_getsockopt (int __fd, int __level, int __optname,
1837 void *__restrict __optval,
1838 socklen_t * __restrict __optlen)
1839{
1840 int rv = -1;
1841 vcom_socket_main_t *vsm = &vcom_socket_main;
1842 uword *p;
1843 vcom_socket_t *vsock;
1844
Dave Wallacefaf9d772017-10-26 16:12:04 -04001845 if (!__optval || !__optlen)
1846 return -EINVAL;
1847
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001848 p = hash_get (vsm->sockidx_by_fd, __fd);
1849 if (!p)
1850 return -EBADF;
1851
1852 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1853 if (!vsock)
1854 return -ENOTSOCK;
1855
1856 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1857 return -EINVAL;
1858
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001859 switch (__level)
1860 {
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001861 case SOL_SOCKET:
1862 switch (__optname)
1863 {
1864/*
1865 * 1. for socket level options that are socket attributes,
1866 * get from libc_getsockopt.
1867 * 2. for socket level options that are NOT socket
1868 * attributes and that has corresponding vpp options
1869 * get from vppcom.
1870 * 3. for socket level options unimplemented
1871 * return -ENOPROTOOPT */
1872 case SO_DEBUG:
1873 case SO_DONTROUTE:
1874 case SO_BROADCAST:
1875 case SO_SNDBUF:
1876 case SO_RCVBUF:
1877 case SO_REUSEADDR:
1878 case SO_REUSEPORT:
1879 case SO_KEEPALIVE:
1880 case SO_TYPE:
1881 case SO_PROTOCOL:
1882 case SO_DOMAIN:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001883 case SO_OOBINLINE:
1884 case SO_NO_CHECK:
1885 case SO_PRIORITY:
1886 case SO_LINGER:
1887 case SO_BSDCOMPAT:
1888 case SO_TIMESTAMP:
1889 case SO_TIMESTAMPNS:
1890 case SO_TIMESTAMPING:
1891 case SO_RCVTIMEO:
1892 case SO_SNDTIMEO:
1893 case SO_RCVLOWAT:
1894 case SO_SNDLOWAT:
1895 case SO_PASSCRED:
1896 case SO_PEERCRED:
1897 case SO_PEERNAME:
1898 case SO_ACCEPTCONN:
1899 case SO_PASSSEC:
1900 case SO_PEERSEC:
1901 case SO_MARK:
1902 case SO_RXQ_OVFL:
1903 case SO_WIFI_STATUS:
1904 case SO_PEEK_OFF:
1905 case SO_NOFCS:
1906 case SO_BINDTODEVICE:
1907 case SO_GET_FILTER:
1908 case SO_LOCK_FILTER:
1909 case SO_BPF_EXTENSIONS:
1910 case SO_SELECT_ERR_QUEUE:
1911#ifdef CONFIG_NET_RX_BUSY_POLL
1912 case SO_BUSY_POLL:
1913#endif
1914 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001915#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001916 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001917#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001918 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1919 if (rv != 0)
1920 {
1921 rv = -errno;
1922 return rv;
1923 }
1924 break;
1925
Stevenac1f96d2017-10-24 16:03:58 -07001926 case SO_ERROR:
1927 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1928 __optval, __optlen);
1929 break;
1930
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001931 default:
1932 /* We implement the SO_SNDLOWAT etc to not be settable
1933 * (1003.1g 7).
1934 */
1935 return -ENOPROTOOPT;
1936 }
1937
1938 break;
1939
1940 default:
1941 /* 1. handle options that are NOT socket level options,
1942 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04001943 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1944 __optval, __optlen);
1945 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001946 }
1947
1948 return rv;
1949}
1950
1951/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001952static inline int
1953vcom_session_setsockopt (int __sid, int __level, int __optname,
1954 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001955{
Stevenb59f2272017-10-12 17:10:33 -07001956 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001957
Stevenb59f2272017-10-12 17:10:33 -07001958 switch (__level)
1959 {
Stevenbd187a82017-10-13 12:52:28 -07001960 case SOL_TCP:
1961 switch (__optname)
1962 {
1963 case TCP_KEEPIDLE:
1964 rv =
1965 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1966 break;
1967 case TCP_KEEPINTVL:
1968 rv =
1969 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1970 break;
1971 default:
1972 break;
1973 }
1974 break;
Stevenb59f2272017-10-12 17:10:33 -07001975 case SOL_IPV6:
1976 switch (__optname)
1977 {
1978 case IPV6_V6ONLY:
1979 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 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 case SOL_SOCKET:
1986 switch (__optname)
1987 {
Stevenbd187a82017-10-13 12:52:28 -07001988 case SO_KEEPALIVE:
1989 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1990 break;
Stevenb59f2272017-10-12 17:10:33 -07001991 case SO_REUSEADDR:
1992 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001993 break;
Stevenb59f2272017-10-12 17:10:33 -07001994 case SO_BROADCAST:
1995 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07001996 break;
Stevenb59f2272017-10-12 17:10:33 -07001997 default:
Stevenbd187a82017-10-13 12:52:28 -07001998 break;
Stevenb59f2272017-10-12 17:10:33 -07001999 }
2000 break;
2001 default:
Stevenbd187a82017-10-13 12:52:28 -07002002 break;
Stevenb59f2272017-10-12 17:10:33 -07002003 }
2004
2005 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002006}
2007
2008int
2009vcom_socket_setsockopt (int __fd, int __level, int __optname,
2010 const void *__optval, socklen_t __optlen)
2011{
2012 int rv = -1;
2013 vcom_socket_main_t *vsm = &vcom_socket_main;
2014 uword *p;
2015 vcom_socket_t *vsock;
2016
2017 p = hash_get (vsm->sockidx_by_fd, __fd);
2018 if (!p)
2019 return -EBADF;
2020
2021 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2022 if (!vsock)
2023 return -ENOTSOCK;
2024
2025 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2026 return -EINVAL;
2027
2028 /*
2029 * Options without arguments
2030 */
2031
2032 if (__optname == SO_BINDTODEVICE)
2033 {
2034 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2035 if (rv != 0)
2036 {
2037 rv = -errno;
2038 }
2039 return rv;
2040 }
2041
2042 if (!__optval)
2043 return -EFAULT;
2044
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002045 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002046 return -EINVAL;
2047
2048 switch (__level)
2049 {
Stevenb59f2272017-10-12 17:10:33 -07002050 case SOL_IPV6:
2051 switch (__optname)
2052 {
2053 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04002054 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2055 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002056 break;
Stevenb59f2272017-10-12 17:10:33 -07002057 default:
2058 return -EOPNOTSUPP;
2059 }
2060 break;
2061 case SOL_TCP:
2062 switch (__optname)
2063 {
2064 case TCP_NODELAY:
2065 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002066 case TCP_KEEPIDLE:
2067 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04002068 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2069 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002070 break;
Stevenb59f2272017-10-12 17:10:33 -07002071 default:
2072 return -EOPNOTSUPP;
2073 }
2074 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002075 /* handle options at socket level */
2076 case SOL_SOCKET:
2077 switch (__optname)
2078 {
Stevenb59f2272017-10-12 17:10:33 -07002079 case SO_REUSEADDR:
2080 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002081 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04002082 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2083 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002084 break;
Stevenb59f2272017-10-12 17:10:33 -07002085
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002086 /*
2087 * 1. for socket level options that are socket attributes,
2088 * set it from libc_getsockopt
2089 * 2. for socket level options that are NOT socket
2090 * attributes and that has corresponding vpp options
2091 * set it from vppcom
2092 * 3. for socket level options unimplemented
2093 * return -ENOPROTOOPT */
2094 case SO_DEBUG:
2095 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002096 case SO_SNDBUF:
2097 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002098 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002099 case SO_TYPE:
2100 case SO_PROTOCOL:
2101 case SO_DOMAIN:
2102 case SO_ERROR:
2103 case SO_OOBINLINE:
2104 case SO_NO_CHECK:
2105 case SO_PRIORITY:
2106 case SO_LINGER:
2107 case SO_BSDCOMPAT:
2108 case SO_TIMESTAMP:
2109 case SO_TIMESTAMPNS:
2110 case SO_TIMESTAMPING:
2111 case SO_RCVTIMEO:
2112 case SO_SNDTIMEO:
2113 case SO_RCVLOWAT:
2114 case SO_SNDLOWAT:
2115 case SO_PASSCRED:
2116 case SO_PEERCRED:
2117 case SO_PEERNAME:
2118 case SO_ACCEPTCONN:
2119 case SO_PASSSEC:
2120 case SO_PEERSEC:
2121 case SO_MARK:
2122 case SO_RXQ_OVFL:
2123 case SO_WIFI_STATUS:
2124 case SO_PEEK_OFF:
2125 case SO_NOFCS:
2126 /*
2127 * SO_BINDTODEVICE already handled as
2128 * "Options without arguments" */
2129 /* case SO_BINDTODEVICE: */
2130 case SO_GET_FILTER:
2131 case SO_LOCK_FILTER:
2132 case SO_BPF_EXTENSIONS:
2133 case SO_SELECT_ERR_QUEUE:
2134#ifdef CONFIG_NET_RX_BUSY_POLL
2135 case SO_BUSY_POLL:
2136#endif
2137 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002138#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002139 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002140#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002141 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2142 if (rv != 0)
2143 {
2144 rv = -errno;
2145 return rv;
2146 }
2147 break;
2148
2149 default:
2150 /* We implement the SO_SNDLOWAT etc to not be settable
2151 * (1003.1g 7).
2152 */
2153 return -ENOPROTOOPT;
2154 }
2155
2156 break;
2157
2158 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002159 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002160 }
2161
2162 return rv;
2163}
2164
2165int
2166vcom_socket_listen (int __fd, int __n)
2167{
2168 int rv = -1;
2169 vcom_socket_main_t *vsm = &vcom_socket_main;
2170 uword *p;
2171 vcom_socket_t *vsock;
2172
2173 p = hash_get (vsm->sockidx_by_fd, __fd);
2174 if (p)
2175 {
2176 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2177
2178 /* TBD vppcom to accept __n parameter */
2179 rv = vppcom_session_listen (vsock->sid, __n);
2180 }
2181
2182 return rv;
2183}
2184
2185static int
2186vcom_socket_connected_socket (int __fd, int __sid,
2187 int *__domain,
2188 int *__type, int *__protocol, int flags)
2189{
2190 int rv = -1;
2191 vcom_socket_main_t *vsm = &vcom_socket_main;
2192 vcom_socket_t *vsock;
2193
2194 i32 fd;
2195 i32 sockidx;
2196
2197 socklen_t optlen;
2198
2199 optlen = sizeof (*__domain);
2200 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2201 if (rv != 0)
2202 {
2203 rv = -errno;
2204 goto out;
2205 }
2206
2207 optlen = sizeof (*__type);
2208 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2209 if (rv != 0)
2210 {
2211 rv = -errno;
2212 goto out;
2213 }
2214
2215 optlen = sizeof (*__protocol);
2216 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2217 if (rv != 0)
2218 {
2219 rv = -errno;
2220 goto out;
2221 }
2222
2223 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2224 if (fd < 0)
2225 {
2226 rv = fd;
2227 goto out;
2228 }
2229
2230 pool_get (vsm->vsockets, vsock);
2231 vsocket_init (vsock);
2232
2233 sockidx = vsock - vsm->vsockets;
2234 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2235
2236 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2237 return fd;
2238
2239out:
2240 return rv;
2241}
2242
2243/* If flag is 0, then accept4() is the same as accept().
2244 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2245 */
2246static int
2247vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2248 socklen_t * __restrict __addr_len, int flags)
2249{
2250 int rv = -1;
2251 vcom_socket_main_t *vsm = &vcom_socket_main;
2252 uword *p;
2253 vcom_socket_t *vsock;
2254
2255 int fd;
2256 int sid;
2257 int domain;
2258 int type;
2259 int protocol;
2260
2261 uint8_t addr8[sizeof (struct in6_addr)];
2262 vppcom_endpt_t ep;
2263
2264 ep.ip = addr8;
2265
2266 /* validate flags */
2267
2268 /*
2269 * for documentation
2270 * switch (flags)
2271 * {
2272 * case 0:
2273 * case SOCK_NONBLOCK:
2274 * case SOCK_CLOEXEC:
2275 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2276 * break;
2277 *
2278 * default:
2279 * return -1;
2280 * }
2281 */
2282 /* flags can be 0 or can be bitwise OR
2283 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2284
Dave Wallace59179392017-11-07 02:20:07 -05002285 if (VCOM_DEBUG > 2)
2286 fprintf (stderr, "[%d] vcom_socket_accept_flags: "
2287 "fd = %d, __addr = %p, __addr_len = %p flags = %d (0x%x)\n",
2288 getpid (), __fd, __addr, __addr_len, flags, flags);
2289
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002290 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2291 {
2292 /* TBD: return proper error code */
Dave Wallace59179392017-11-07 02:20:07 -05002293 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2294 "invalid flags = %d (0x%x)\n", getpid (), flags, flags);
2295
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002296 return -1;
2297 }
2298
2299 /* TBD: return proper error code */
2300
2301 if (!vcom_socket_is_connection_mode_socket (__fd))
2302 {
Dave Wallace59179392017-11-07 02:20:07 -05002303 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2304 "connection mode socket support TBD!\n", getpid ());
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002305 return -EOPNOTSUPP;
2306 }
2307
2308 p = hash_get (vsm->sockidx_by_fd, __fd);
2309 if (p)
2310 {
2311 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2312
2313
2314 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2315 if (rv < 0)
2316 {
Dave Wallace59179392017-11-07 02:20:07 -05002317 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2318 "vcom_fcnt() returned %d!\n", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002319 return rv;
2320 }
2321
2322 /* is blocking */
2323 if (!(rv & O_NONBLOCK))
2324 {
2325 /* socket is not marked as nonblocking
2326 * and no pending connections are present
2327 * on the queue, accept () blocks the caller
2328 * until a connection is present.
2329 */
2330 rv = vppcom_session_accept (vsock->sid, &ep,
2331 -1.0 /* wait forever */ );
2332 }
2333 else
2334 {
2335 /* The file descriptor refers to a socket and has been
2336 * marked nonblocking(O_NONBLOCK) and the accept would
2337 * block.
2338 * */
2339 /* is non blocking */
2340 rv = vppcom_session_accept (vsock->sid, &ep, 0);
2341 /* If the socket is marked nonblocking and
2342 * no pending connections are present on the
2343 * queue, accept fails with the error
2344 * EAGAIN or EWOULDBLOCK
2345 */
2346 if (rv == VPPCOM_ETIMEDOUT)
2347 {
2348 rv = VPPCOM_EAGAIN;
2349 }
2350 }
2351 if (rv < 0)
2352 {
Dave Wallace59179392017-11-07 02:20:07 -05002353 if (rv != VPPCOM_EAGAIN)
2354 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2355 "vppcom_session_accept() returned %d!", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002356 return rv;
2357 }
2358
2359 sid = rv;
2360
2361 /* create a new connected socket resource and set flags
2362 * on the new file descriptor.
2363 * update vsockets and sockidx_by_fd table
2364 * */
2365 fd = vcom_socket_connected_socket (__fd, sid,
2366 &domain, &type, &protocol, flags);
2367 if (fd < 0)
2368 {
Dave Wallace59179392017-11-07 02:20:07 -05002369 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2370 "vcom_socket_connected_socket() returned %d!",
2371 getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002372 return fd;
2373 }
2374
2375 rv = fd;
2376
2377 /* TBD populate __addr and __addr_len */
2378 /* TBD: The returned address is truncated if the buffer
2379 * provided is too small, in this case, __addr_len will
2380 * return a value greater than was supplied to the call.*/
2381 if (__addr)
2382 {
2383 if (ep.is_cut_thru)
2384 {
2385 /* TBD populate __addr and __addr_len */
2386 switch (domain)
2387 {
2388 case AF_INET:
2389 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2390 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2391 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2392 addr8, sizeof (struct in_addr));
2393 /* TBD: populate __addr_len */
2394 if (__addr_len)
2395 {
2396 *__addr_len = sizeof (struct sockaddr_in);
2397 }
2398 break;
2399
2400 case AF_INET6:
2401 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2402 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2403 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2404 __in6_u.__u6_addr8, addr8,
2405 sizeof (struct in6_addr));
2406 /* TBD: populate __addr_len */
2407 if (__addr_len)
2408 {
2409 *__addr_len = sizeof (struct sockaddr_in6);
2410 }
2411 break;
2412
2413 default:
2414 return -EAFNOSUPPORT;
2415 }
2416 }
2417 else
2418 {
2419 switch (ep.is_ip4)
2420 {
2421 case VPPCOM_IS_IP4:
2422 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2423 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2424 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2425 addr8, sizeof (struct in_addr));
2426 /* TBD: populate __addr_len */
2427 if (__addr_len)
2428 {
2429 *__addr_len = sizeof (struct sockaddr_in);
2430 }
2431 break;
2432
2433 case VPPCOM_IS_IP6:
2434 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2435 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2436 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2437 __in6_u.__u6_addr8, addr8,
2438 sizeof (struct in6_addr));
2439 /* TBD: populate __addr_len */
2440 if (__addr_len)
2441 {
2442 *__addr_len = sizeof (struct sockaddr_in6);
2443 }
2444 break;
2445
2446 default:
2447 return -EAFNOSUPPORT;
2448 }
2449 }
2450 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002451 }
2452
2453 return rv;
2454}
2455
2456int
2457vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2458 socklen_t * __restrict __addr_len)
2459{
2460 /* set flags to 0 for accept() */
2461 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2462}
2463
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002464int
2465vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2466 socklen_t * __restrict __addr_len, int __flags)
2467{
2468 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2469 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2470}
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002471
2472/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002473static inline int
2474vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002475{
2476 return 0;
2477}
2478
2479int
2480vcom_socket_shutdown (int __fd, int __how)
2481{
2482 int rv = -1;
2483 vcom_socket_main_t *vsm = &vcom_socket_main;
2484 uword *p;
2485 vcom_socket_t *vsock;
2486
2487 p = hash_get (vsm->sockidx_by_fd, __fd);
2488 if (p)
2489 {
2490 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2491 switch (__how)
2492 {
2493 case SHUT_RD:
2494 case SHUT_WR:
2495 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002496 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002497 return rv;
2498 break;
2499
2500 default:
2501 return -EINVAL;
2502 break;
2503 }
2504 }
2505
2506 return rv;
2507}
2508
2509int
2510vcom_socket_epoll_create1 (int __flags)
2511{
2512 int rv = -1;
2513 vcom_socket_main_t *vsm = &vcom_socket_main;
2514 vcom_epoll_t *vepoll;
2515
2516 i32 epfd;
2517 i32 vep_idx;
2518 i32 epollidx;
2519
2520 epfd = vcom_socket_open_epoll (__flags);
2521 if (epfd < 0)
2522 {
2523 rv = epfd;
2524 goto out;
2525 }
2526
2527 vep_idx = vppcom_epoll_create ();
2528 if (vep_idx < 0)
2529 {
2530 rv = vep_idx;
2531 goto out_close_epoll;
2532 }
2533
2534 pool_get (vsm->vepolls, vepoll);
2535 vepoll_init (vepoll);
2536
2537 epollidx = vepoll - vsm->vepolls;
2538 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2539
2540 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2541
2542 return epfd;
2543
2544out_close_epoll:
2545 vcom_socket_close_epoll (epfd);
2546out:
2547 return rv;
2548}
2549
2550/*
2551 * PRE: vppcom_epoll_ctl() is successful
2552 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2553 */
2554int
2555vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2556 struct epoll_event *__event,
2557 i32 vep_idx, vcom_epoll_t * vepoll,
2558 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2559 int free_vepitem_on_del)
2560{
2561 int rv = -1;
2562 vcom_socket_main_t *vsm = &vcom_socket_main;
2563 vcom_epitem_t *vepitem;
2564
2565 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2566 uword *p;
2567 i32 vepitemidx;
2568
2569 i32 *vepitemidxs = 0;
2570
2571 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2572
2573 i32 vec_idx;
2574
2575 /* perform control operations on the epoll instance */
2576 switch (__op)
2577 {
2578 case EPOLL_CTL_ADD:
2579 /*
2580 * supplied file descriptor is already
2581 * registered with this epoll instance
2582 * */
2583 /* vepitem exists */
2584 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2585 if (p)
2586 {
2587 rv = -EEXIST;
2588 goto out;
2589 }
2590
2591 /* add a new vepitem */
2592 pool_get (vsm->vepitems, vepitem);
2593 vepitem_init (vepitem);
2594
2595 vepitemidx = vepitem - vsm->vepitems;
2596 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2597 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2598
2599 /* update epitemidxs */
2600 /* by_epfd */
2601 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2602 if (!p) /* not exist */
2603 {
2604 vepitemidxs = 0;
2605 vec_add1 (vepitemidxs, vepitemidx);
2606 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2607 }
2608 else /* exists */
2609 {
2610 vepitemidxs = *(i32 **) p;
2611 vec_add1 (vepitemidxs, vepitemidx);
2612 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2613 }
2614 /* update epitemidxs */
2615 /* by_fd */
2616 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2617 if (!p) /* not exist */
2618 {
2619 vepitemidxs = 0;
2620 vec_add1 (vepitemidxs, vepitemidx);
2621 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2622 }
2623 else /* exists */
2624 {
2625 vepitemidxs = *(i32 **) p;
2626 vec_add1 (vepitemidxs, vepitemidx);
2627 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2628 }
2629
2630 /* increment vepoll fd count by 1 */
2631 vepoll->count += 1;
2632
2633 rv = 0;
2634 goto out;
2635 break;
2636
2637 case EPOLL_CTL_MOD:
2638 /*
2639 * supplied file descriptor is not
2640 * registered with this epoll instance
2641 * */
2642 /* vepitem not exist */
2643 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2644 if (!p)
2645 {
2646 rv = -ENOENT;
2647 goto out;
2648 }
2649 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2650 if (vepitem)
2651 {
2652 vepitem->event = *__event;
2653 vepitem->revent = revent;
2654 }
2655
2656 rv = 0;
2657 goto out;
2658 break;
2659
2660 case EPOLL_CTL_DEL:
2661 /*
2662 * supplied file descriptor is not
2663 * registered with this epoll instance
2664 * */
2665 /* vepitem not exist */
2666 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2667 if (!p)
2668 {
2669 rv = -ENOENT;
2670 goto out;
2671 }
2672 vepitemidx = *(i32 *) p;
2673 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2674
2675 /* update epitemidxs */
2676 /* by_epfd */
2677 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2678 if (!p) /* not exist */
2679 {
2680 rv = -ENOENT;
2681 goto out;
2682 }
2683 else /* exists */
2684 {
2685 vepitemidxs = *(i32 **) p;
2686 vec_idx = vec_search (vepitemidxs, vepitemidx);
2687 if (vec_idx != ~0)
2688 {
2689 vec_del1 (vepitemidxs, vec_idx);
2690 if (!vec_len (vepitemidxs))
2691 {
2692 vec_free (vepitemidxs);
2693 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2694 }
2695 }
2696 }
2697
2698 /* update epitemidxs */
2699 /* by_fd */
2700 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2701 if (!p) /* not exist */
2702 {
2703 rv = -ENOENT;
2704 goto out;
2705 }
2706 else /* exists */
2707 {
2708 vepitemidxs = *(i32 **) p;
2709 vec_idx = vec_search (vepitemidxs, vepitemidx);
2710 if (vec_idx != ~0)
2711 {
2712 vec_del1 (vepitemidxs, vec_idx);
2713 if (!vec_len (vepitemidxs))
2714 {
2715 vec_free (vepitemidxs);
2716 hash_unset (vsm->epitemidxs_by_fd, __fd);
2717 }
2718 }
2719 }
2720
2721 /* pool put vepitem */
2722 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2723 if (free_vepitem_on_del)
2724 {
2725 if (!vepitem)
2726 {
2727 rv = -ENOENT;
2728 goto out;
2729 }
2730 vepitem_init (vepitem);
2731 pool_put (vsm->vepitems, vepitem);
2732 }
2733 else
2734 {
2735 if (!vepitem)
2736 {
2737 vepitem_init (vepitem);
2738 }
2739 }
2740
2741 /* decrement vepoll fd count by 1 */
2742 vepoll->count -= 1;
2743
2744 rv = 0;
2745 goto out;
2746 break;
2747
2748 default:
2749 rv = -EINVAL;
2750 goto out;
2751 break;
2752 }
2753
2754out:
2755 return rv;
2756}
2757
2758/*
2759 * PRE: 00. null pointer check on __event
2760 * 01. all other parameters are validated
2761 */
2762
2763static int
2764vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2765 struct epoll_event *__event,
2766 int free_vepitem_on_del)
2767{
2768 int rv = -1;
Dave Wallacee695cb42017-11-02 22:04:42 -04002769 i32 cnt;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002770 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002771 vcom_socket_t *vfd_vsock;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002772 i32 vep_idx;
Dave Wallacee695cb42017-11-02 22:04:42 -04002773 i32 sid;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002774
2775 /* get vep_idx and vepoll */
2776 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2777 if (vep_idx == INVALID_VEP_IDX)
2778 {
2779 return -EBADF;
2780 }
2781
2782 /* get vcom fd type, vfd_id and vfd */
Dave Wallacee695cb42017-11-02 22:04:42 -04002783 sid = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2784 if ((sid != INVALID_SESSION_ID) &&
2785 vcom_socket_type_is_vppcom_bound (vfd_vsock->type))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002786 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002787 rv = vppcom_epoll_ctl (vep_idx, __op, sid, __event);
2788 if (rv == VPPCOM_OK)
2789 {
2790 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2791 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2792 vepoll->count += cnt;
2793 vepoll->vcl_cnt += cnt;
2794 }
2795 if (VCOM_DEBUG > 0)
2796 fprintf (stderr,
2797 "[%d] vcom_socket_epoll_ctl_i: vppcom_epoll_ctl() "
2798 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2799 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002800 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002801 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002802 }
2803 else
2804 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002805 rv = libc_epoll_ctl (__epfd, __op, __fd, __event);
2806 if (rv == 0)
2807 {
2808 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2809 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2810 vepoll->count += cnt;
2811 vepoll->libc_cnt += cnt;
2812 }
2813 if (VCOM_DEBUG > 0)
2814 fprintf (stderr,
2815 "[%d] vcom_socket_epoll_ctl_i: libc_epoll_ctl() "
2816 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2817 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002818 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002819 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002820 }
2821
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002822 return rv;
2823}
2824
2825int
2826vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2827 struct epoll_event *__event)
2828{
2829 int rv = -1;
2830
2831 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2832 return rv;
2833}
2834
2835static int
2836vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2837 struct epoll_event *__event)
2838{
2839 int rv = -1;
2840
2841 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2842 return rv;
2843}
2844
2845int
2846vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2847 int __maxevents, int __timeout,
2848 const __sigset_t * __ss)
2849{
Dave Wallacee695cb42017-11-02 22:04:42 -04002850 vcom_socket_main_t *vsm = &vcom_socket_main;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002851 int rv = -EBADF;
Dave Wallacee695cb42017-11-02 22:04:42 -04002852 int rv2;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002853 double time_to_wait = (double) 0;
Dave Wallace375e4682017-11-10 15:49:32 -05002854 double timeout, now = 0;
Dave Wallacee695cb42017-11-02 22:04:42 -04002855 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002856 i32 vep_idx;
Dave Wallacee695cb42017-11-02 22:04:42 -04002857 static struct epoll_event *libc_ev = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002858
2859 /* validate __event */
Dave Wallacee695cb42017-11-02 22:04:42 -04002860 if (!__events || (__timeout < -1))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002861 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002862 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05002863 "Bad args __events %p, __timeout %d\n", getpid (),
Dave Wallacee695cb42017-11-02 22:04:42 -04002864 __events, __timeout);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002865 rv = -EFAULT;
2866 goto out;
2867 }
2868
Dave Wallace375e4682017-11-10 15:49:32 -05002869 time_to_wait = ((__timeout >= 0) ? (double) __timeout / (double) 1000 : 0);
Dave Wallacee695cb42017-11-02 22:04:42 -04002870
2871 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2872 if (vep_idx == INVALID_VEP_IDX)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002873 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002874 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05002875 "Bad epoll fd %d\n", getpid (), __epfd);
Dave Wallacee695cb42017-11-02 22:04:42 -04002876 return -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002877 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002878
2879 if (vepoll->count <= 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002880 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002881 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: No events"
2882 " in epfd!\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002883 getpid (), vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Dave Wallacee695cb42017-11-02 22:04:42 -04002884 rv = -EINVAL;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002885 goto out;
2886 }
2887
Dave Wallacee695cb42017-11-02 22:04:42 -04002888 if (vepoll->libc_cnt == 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002889 {
Dave Wallace59179392017-11-07 02:20:07 -05002890 if (VCOM_DEBUG > 2)
2891 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, "
Dave Wallace375e4682017-11-10 15:49:32 -05002892 "calling vppcom_epoll_wait() time_to_wait = %f\n",
2893 getpid (), time_to_wait);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002894 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2895 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002896 else if (vepoll->vcl_cnt == 0)
2897 {
Dave Wallace59179392017-11-07 02:20:07 -05002898 if (VCOM_DEBUG > 2)
2899 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = 0, "
2900 "calling libc_epoll_pwait()\n", getpid ());
Dave Wallacee695cb42017-11-02 22:04:42 -04002901 rv = libc_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
2902 }
2903 else
2904 {
Dave Wallace59179392017-11-07 02:20:07 -05002905 if (VCOM_DEBUG > 2)
2906 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, "
Dave Wallace375e4682017-11-10 15:49:32 -05002907 "libc_cnt = %d -> mixed polling (time_to_wait = %f, "
2908 "__timeout = %d)\n",
2909 getpid (), vepoll->vcl_cnt, vepoll->libc_cnt,
2910 time_to_wait, __timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04002911 vec_validate (libc_ev, __maxevents);
2912 timeout = clib_time_now (&vsm->clib_time) + time_to_wait;
2913 do
2914 {
2915 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, 0);
2916 rv2 = libc_epoll_pwait (__epfd, libc_ev, __maxevents, 1, __ss);
Dave Wallace375e4682017-11-10 15:49:32 -05002917 if (VCOM_DEBUG == 666)
2918 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
2919 "rv = %d, rv2 = %d, timeout = %f, now = %f\n",
2920 getpid (), rv, rv2, timeout, now);
Dave Wallacee695cb42017-11-02 22:04:42 -04002921 if ((rv > 0) || (rv2 > 0))
2922 {
Dave Wallace59179392017-11-07 02:20:07 -05002923 if (VCOM_DEBUG > 2)
2924 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
2925 "rv = %d, rv2 = %d\n", getpid (), rv, rv2);
Dave Wallacee695cb42017-11-02 22:04:42 -04002926 int n = __maxevents - rv;
2927 n = rv2 <= n ? rv2 : n;
2928 rv = (rv > 0) ? rv : 0;
2929
2930 clib_memcpy (&__events[rv], libc_ev, n * sizeof (*libc_ev));
2931 rv += rv2;
2932 goto out;
2933 }
2934 else if ((rv < 0) || (rv2 < 0))
2935 {
2936 if (rv < 0)
2937 fprintf (stderr,
2938 "[%d] ERROR: vppcom_epoll_wait() returned %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002939 getpid (), rv);
Dave Wallacee695cb42017-11-02 22:04:42 -04002940 if (rv2 < 0)
2941 {
2942 fprintf (stderr,
2943 "[%d] ERROR: libc_epoll_wait() failed, errno %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002944 getpid (), errno);
Dave Wallacee695cb42017-11-02 22:04:42 -04002945 rv = (rv < 0) ? rv : -errno;
2946 }
2947 goto out;
2948 }
Dave Wallace375e4682017-11-10 15:49:32 -05002949 if (__timeout != -1)
2950 now = clib_time_now (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04002951 }
Dave Wallace375e4682017-11-10 15:49:32 -05002952 while (now < timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04002953 }
2954
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002955out:
Dave Wallacee695cb42017-11-02 22:04:42 -04002956 vec_reset_length (libc_ev);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002957 return rv;
2958}
2959
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002960static inline void
2961vcom_pollfds_2_selectfds (
2962 /* src */
2963 struct pollfd *__fds, nfds_t __nfds,
2964 /* dest */
2965 int vcom_nfds,
2966 fd_set * __restrict vcom_readfds,
2967 fd_set * __restrict vcom_writefds,
2968 fd_set * __restrict vcom_exceptfds)
2969{
2970 nfds_t fds_idx = 0;
2971
2972 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2973 {
2974 /* ignore negative fds */
2975 if (__fds[fds_idx].fd < 0)
2976 {
2977 continue;
2978 }
2979
2980 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
2981 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2982
2983 /* requested events */
2984 if (__fds[fds_idx].events)
2985 {
2986 if (__fds[fds_idx].events & POLLIN)
2987 {
2988 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2989 }
2990 if (__fds[fds_idx].events & POLLPRI)
2991 {
2992 FD_SET (__fds[fds_idx].fd, vcom_readfds);
2993 }
2994 if (__fds[fds_idx].events & POLLOUT)
2995 {
2996 FD_SET (__fds[fds_idx].fd, vcom_writefds);
2997 }
2998#if defined __USE_XOPEN || defined __USE_XOPEN2K8
2999 if (__fds[fds_idx].events & POLLRDNORM)
3000 {
3001 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3002 }
3003 if (__fds[fds_idx].events & POLLRDBAND)
3004 {
3005 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3006 }
3007 if (__fds[fds_idx].events & POLLWRNORM)
3008 {
3009 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3010 }
3011 if (__fds[fds_idx].events & POLLWRBAND)
3012 {
3013 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3014 }
3015#endif
3016 }
3017 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3018}
3019
3020static inline void
3021vcom_selectfds_2_pollfds (
3022 /* dest */
3023 struct pollfd *__fds, nfds_t __nfds, int *nfd,
3024 /* src */
3025 int vcom_nfds,
3026 fd_set * __restrict vcom_readfds,
3027 fd_set * __restrict vcom_writefds,
3028 fd_set * __restrict vcom_exceptfds)
3029{
3030 nfds_t fds_idx = 0;
3031
3032
3033 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3034 {
3035 /* ignore negative fds */
3036 if (__fds[fds_idx].fd < 0)
3037 {
3038 __fds[fds_idx].revents = 0;
3039 }
3040
3041 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
3042 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
3043 {
3044 /*
3045 * TBD: for now any select exception
3046 * is flagged as POLLERR
3047 * */
3048 __fds[fds_idx].revents |= POLLERR;
3049 }
3050
3051 /* requested events */
3052 if (__fds[fds_idx].events & POLLIN)
3053 {
3054 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3055 {
3056 __fds[fds_idx].revents |= POLLIN;
3057 }
3058 }
3059 if (__fds[fds_idx].events & POLLPRI)
3060 {
3061 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3062 {
3063 __fds[fds_idx].revents |= POLLIN;
3064 }
3065 }
3066 if (__fds[fds_idx].events & POLLOUT)
3067 {
3068 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3069 {
3070 __fds[fds_idx].revents |= POLLOUT;
3071 }
3072 }
3073#if defined __USE_XOPEN || defined __USE_XOPEN2K8
3074 if (__fds[fds_idx].events & POLLRDNORM)
3075 {
3076 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3077 {
3078 __fds[fds_idx].revents |= POLLRDNORM;
3079 }
3080 }
3081 if (__fds[fds_idx].events & POLLRDBAND)
3082 {
3083 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3084 {
3085 __fds[fds_idx].revents |= POLLRDBAND;
3086 }
3087 }
3088 if (__fds[fds_idx].events & POLLWRNORM)
3089 {
3090 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3091 {
3092 __fds[fds_idx].revents |= POLLWRNORM;
3093 }
3094 }
3095 if (__fds[fds_idx].events & POLLWRBAND)
3096 {
3097 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3098 {
3099 __fds[fds_idx].revents |= POLLWRBAND;
3100 }
3101 }
3102#endif
3103 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3104
3105 /*
3106 * nfd:
3107 * the number of structures which have nonzero revents fields
3108 * (in other words, those descriptors with events or
3109 * errors reported)
3110 * */
3111 *nfd = 0;
3112 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3113 {
3114 /* ignore negative fds */
3115 if (__fds[fds_idx].fd < 0)
3116 {
3117 continue;
3118 }
3119
3120 if (__fds[fds_idx].revents)
3121 {
3122 (*nfd)++;
3123 }
3124 }
3125}
3126
3127/*
3128 * PRE: parameters are validated,
3129 * vcom_socket_poll is always called with __timeout set to zero
3130 * hence returns immediately
3131 *
3132 * ACTION: handle non negative validated vcom fds and ignore rest
3133 */
3134
3135/*
3136 * implements vcom_socket_poll () interface
3137 *
3138 * internally uses vcom_socket_select ()
3139 * to realize the behavior
3140 * */
3141int
3142vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3143 int __timeout)
3144{
3145 int rv;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003146
3147 nfds_t fds_idx = 0;
3148 int nfd = 0;
3149
3150 /* vcom */
3151 int vcom_nfds = 0;
3152 fd_set vcom_readfds;
3153 fd_set vcom_writefds;
3154 fd_set vcom_exceptfds;
3155 int vcom_nfd = -1;
3156 /* invalid max_vcom_fd is -1 */
3157 int max_vcom_fd = -1;
3158
3159 /* __timeout is zero to get ready events and return immediately */
3160 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3161
3162 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003163 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003164 {
3165 rv = -EINVAL;
3166 goto poll_done;
3167 }
3168
3169 /* zero vcom fd sets */
3170 /*
3171 * V vcom fd set
3172 */
3173#define _(V) \
3174 FD_ZERO ((V))
3175
3176 _(&vcom_readfds);
3177 _(&vcom_writefds);
3178 _(&vcom_exceptfds);
3179#undef _
3180
3181 vcom_nfds = 0;
3182 vcom_nfd = -1;
3183
3184
3185 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3186 {
3187 /* ignore negative fds */
3188 if (__fds[fds_idx].fd < 0)
3189 {
3190 continue;
3191 }
3192
3193 /* non negative validated vcom fds */
3194 if (__fds[fds_idx].fd > FD_SETSIZE)
3195 {
3196 rv = -EINVAL;
3197 goto poll_done;
3198 }
3199
3200 /* max_vcom_fd and vcom_nfd */
3201 if (__fds[fds_idx].fd > max_vcom_fd)
3202 {
3203 /* requested events */
3204 if (__fds[fds_idx].events)
3205 {
3206 max_vcom_fd = __fds[fds_idx].fd;
3207 }
3208 }
3209 ++vcom_nfd;
3210 }
3211
3212 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3213
3214 if (!vcom_nfds)
3215 {
3216 rv = vcom_nfds;
3217 goto poll_done;
3218 }
3219
3220 vcom_pollfds_2_selectfds (
3221 /* src */
3222 __fds, __nfds,
3223 /* dest */
3224 vcom_nfds,
3225 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3226
3227 /* select on vcom fds */
3228 vcom_nfd = vcom_socket_select (vcom_nfds,
3229 &vcom_readfds,
3230 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003231 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003232 fprintf (stderr,
3233 "[%d] vcom_socket_select: "
Dave Wallace59179392017-11-07 02:20:07 -05003234 "'%04d'='%04d'\n", getpid (), vcom_nfd, vcom_nfds);
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003235
3236 if (vcom_nfd < 0)
3237 {
3238 rv = vcom_nfd;
3239 goto poll_done;
3240 }
3241
3242 vcom_selectfds_2_pollfds (
3243 /* dest */
3244 __fds, __nfds, &nfd,
3245 /* src */
3246 vcom_nfds,
3247 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3248
3249 rv = nfd;
3250
3251poll_done:
3252 return rv;
3253}
3254
3255/*
3256 * TBD: remove this static function once vppcom
3257 * has an implementation in place
3258 *
3259 * ACTION:
3260 */
3261static int
3262vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3263{
3264 return -EOPNOTSUPP;
3265}
3266
3267int
3268vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3269 int __timeout)
3270{
3271 nfds_t fds_idx = 0;
3272
3273 /* in seconds eg. 3.123456789 seconds */
3274 double time_to_wait = (double) 0;
3275
3276 i32 sid;
3277 i32 vep_idx;
3278
3279 /* replace vcom fd with session idx */
3280 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3281 {
3282 /* ignore negative fds */
3283 if (__fds[fds_idx].fd < 0)
3284 {
3285 continue;
3286 }
3287
3288 /* non negative validated vcom fds */
3289 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3290 if (sid != INVALID_SESSION_ID)
3291 {
3292 __fds[fds_idx].fd = sid;
3293 }
3294 else
3295 {
3296 /* get vep_idx */
3297 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3298 if (vep_idx != INVALID_VEP_IDX)
3299 {
3300 __fds[fds_idx].fd = vep_idx;
3301 }
3302 else
3303 {
3304 return -EBADF;
3305 }
3306 }
3307 }
3308
3309 /* validate __timeout */
3310 if (__timeout > 0)
3311 {
3312 time_to_wait = (double) __timeout / (double) 1000;
3313 }
3314 else if (__timeout == 0)
3315 {
3316 time_to_wait = (double) 0;
3317 }
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003318 else
3319 {
Dave Wallace60f54822017-10-24 20:47:45 -04003320 time_to_wait = ~0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003321 }
3322
3323 return vppcom_poll (__fds, __nfds, time_to_wait);
3324}
3325
3326int
3327vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3328{
3329 /* select an implementation */
3330
3331 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3332 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3333}
3334
3335#ifdef __USE_GNU
3336int
3337vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3338 const struct timespec *__timeout, const __sigset_t * __ss)
3339{
3340 return -EOPNOTSUPP;
3341}
3342#endif
3343
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003344int
3345vcom_socket_main_init (void)
3346{
3347 vcom_socket_main_t *vsm = &vcom_socket_main;
3348
3349 if (VCOM_DEBUG > 0)
3350 printf ("vcom_socket_main_init\n");
3351
3352 if (!vsm->init)
3353 {
3354 /* TBD: define FD_MAXSIZE and use it here */
3355 pool_alloc (vsm->vsockets, FD_SETSIZE);
3356 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3357
3358 pool_alloc (vsm->vepolls, FD_SETSIZE);
3359 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3360
3361 pool_alloc (vsm->vepitems, FD_SETSIZE);
3362 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3363
3364 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3365 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3366
Dave Wallacee695cb42017-11-02 22:04:42 -04003367 clib_time_init (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04003368
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003369 vsm->init = 1;
3370 }
3371
3372 return 0;
3373}
3374
3375
3376void
3377vcom_socket_main_show (void)
3378{
3379 vcom_socket_main_t *vsm = &vcom_socket_main;
3380 vcom_socket_t *vsock;
3381
3382 vcom_epoll_t *vepoll;
3383
3384 vcom_epitem_t *vepitem;
3385
3386 i32 epfd;
3387 i32 fd;
3388 i32 *vepitemidxs, *vepitemidxs_var;
3389
3390 if (vsm->init)
3391 {
3392 /* from active list of vsockets show vsock */
3393
3394 /* *INDENT-OFF* */
3395 pool_foreach (vsock, vsm->vsockets,
3396 ({
3397 printf(
3398 "fd='%04d', sid='%08x',type='%-30s'\n",
3399 vsock->fd, vsock->sid,
3400 vcom_socket_type_str (vsock->type));
3401 }));
3402 /* *INDENT-ON* */
3403
3404 /* from active list of vepolls, show vepoll */
3405
3406 /* *INDENT-OFF* */
3407 pool_foreach (vepoll, vsm->vepolls,
3408 ({
3409 printf(
3410 "epfd='%04d', vep_idx='%08x', "
3411 "type='%-30s', "
3412 "flags='%d', count='%d', close='%d'\n",
3413 vepoll->epfd, vepoll->vep_idx,
3414 vcom_socket_epoll_type_str (vepoll->type),
3415 vepoll->flags, vepoll->count, vepoll->close);
3416 }));
3417 /* *INDENT-ON* */
3418
3419 /* from active list of vepitems, show vepitem */
3420
3421 /* *INDENT-OFF* */
3422 pool_foreach (vepitem, vsm->vepitems,
3423 ({
3424 printf(
3425 "epfd='%04d', fd='%04d', "
3426 "next_fd='%04d', prev_fd='%04d', "
3427 "type='%-30s', "
3428 "events='%04x', revents='%04x'\n",
3429 vepitem->epfd, vepitem->fd,
3430 vepitem->next_fd, vepitem->prev_fd,
3431 vcom_socket_vcom_fd_type_str (vepitem->type),
3432 vepitem->event.events, vepitem->revent.events);
3433 }));
3434
3435 /* *INDENT-ON* */
3436
3437 /* show epitemidxs for epfd */
3438 /* *INDENT-OFF* */
3439 hash_foreach (epfd, vepitemidxs,
3440 vsm->epitemidxs_by_epfd,
3441 ({
3442 printf("\n[ '%04d': ", epfd);
3443 vec_foreach (vepitemidxs_var,vepitemidxs)
3444 {
3445 printf("'%04d' ", (int)vepitemidxs_var[0]);
3446 }
3447 printf("]\n");
3448 }));
3449 /* *INDENT-ON* */
3450
3451 /* show epitemidxs for fd */
3452 /* *INDENT-OFF* */
3453 hash_foreach (fd, vepitemidxs,
3454 vsm->epitemidxs_by_fd,
3455 ({
3456 printf("\n{ '%04d': ", fd);
3457 vec_foreach (vepitemidxs_var,vepitemidxs)
3458 {
3459 printf("'%04d' ", (int)vepitemidxs_var[0]);
3460 }
3461 printf("}\n");
3462 }));
3463 /* *INDENT-ON* */
3464
3465 }
3466}
3467
3468void
3469vcom_socket_main_destroy (void)
3470{
3471 vcom_socket_main_t *vsm = &vcom_socket_main;
3472 vcom_socket_t *vsock;
3473
3474 vcom_epoll_t *vepoll;
3475
3476 vcom_epitem_t *vepitem;
3477
3478 i32 epfd;
3479 i32 fd;
3480 i32 *vepitemidxs;
3481
3482
3483 if (VCOM_DEBUG > 0)
3484 printf ("vcom_socket_main_destroy\n");
3485
3486 if (vsm->init)
3487 {
3488
3489 /*
3490 * from active list of vepitems,
3491 * remove all "vepitem" elements from the pool in a safe way
3492 * */
3493
3494 /* *INDENT-OFF* */
3495 pool_flush (vepitem, vsm->vepitems,
3496 ({
Dave Wallace60f54822017-10-24 20:47:45 -04003497 if ((vepitem->type == FD_TYPE_EPOLL) ||
3498 (vepitem->type == FD_TYPE_VCOM_SOCKET))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003499 {
Dave Wallace60f54822017-10-24 20:47:45 -04003500 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003501 vepitem->fd, NULL);
3502 vepitem_init (vepitem);
3503 }
3504 }));
3505 /* *INDENT-ON* */
3506
3507 pool_free (vsm->vepitems);
3508 hash_free (vsm->epitemidx_by_epfdfd);
3509
3510 /* free vepitemidxs for each epfd */
3511 /* *INDENT-OFF* */
3512 hash_foreach (epfd, vepitemidxs,
3513 vsm->epitemidxs_by_epfd,
3514 ({
3515 vec_free (vepitemidxs);
3516 }));
3517 /* *INDENT-ON* */
3518 hash_free (vsm->epitemidxs_by_epfd);
3519
3520 /* free vepitemidxs for each fd */
3521 /* *INDENT-OFF* */
3522 hash_foreach (fd, vepitemidxs,
3523 vsm->epitemidxs_by_fd,
3524 ({
3525 vec_free (vepitemidxs);
3526 }));
3527 /* *INDENT-ON* */
3528 hash_free (vsm->epitemidxs_by_fd);
3529
3530
3531 /*
3532 * from active list of vsockets,
3533 * close socket and vppcom session
3534 * */
3535
3536 /* *INDENT-OFF* */
3537 pool_foreach (vsock, vsm->vsockets,
3538 ({
3539 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3540 {
3541 vppcom_session_close (vsock->sid);
3542 vcom_socket_close_socket (vsock->fd);
3543 vsocket_init (vsock);
3544 }
3545 }));
3546 /* *INDENT-ON* */
3547
3548 /*
3549 * return vsocket element to the pool
3550 * */
3551
3552 /* *INDENT-OFF* */
3553 pool_flush (vsock, vsm->vsockets,
3554 ({
3555 // vsocket_init(vsock);
3556 ;
3557 }));
3558 /* *INDENT-ON* */
3559
3560 pool_free (vsm->vsockets);
3561 hash_free (vsm->sockidx_by_fd);
3562
3563 /*
3564 * from active list of vepolls,
3565 * close epoll and vppcom_epoll
3566 * */
3567
3568 /* *INDENT-OFF* */
3569 pool_foreach (vepoll, vsm->vepolls,
3570 ({
3571 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3572 {
3573 vppcom_session_close (vepoll->vep_idx);
3574 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3575 vepoll_init (vepoll);
3576 }
3577 }));
3578 /* *INDENT-ON* */
3579
3580 /*
3581 * return vepoll element to the pool
3582 * */
3583
3584 /* *INDENT-OFF* */
3585 pool_flush (vepoll, vsm->vepolls,
3586 ({
3587 // vepoll_init(vepoll);
3588 ;
3589 }));
3590 /* *INDENT-ON* */
3591
3592 pool_free (vsm->vepolls);
3593 hash_free (vsm->epollidx_by_epfd);
3594
3595 vsm->init = 0;
3596 }
3597}
3598
3599
3600/*
3601 * fd.io coding-style-patch-verification: ON
3602 *
3603 * Local Variables:
3604 * eval: (c-set-style "gnu")
3605 * End:
3606 */