blob: 81a4b76919db4641bc04b9910e484f0b70bff072 [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
Dave Wallace227867f2017-11-13 21:21:53 -050073 u8 *io_buffer;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070074} vcom_socket_main_t;
75
76vcom_socket_main_t vcom_socket_main;
77
78
79static int
80vcom_socket_open_socket (int domain, int type, int protocol)
81{
82 int rv = -1;
83
84 /* handle domains implemented by vpp */
85 switch (domain)
86 {
87 case AF_INET:
88 case AF_INET6:
89 /* get socket type and
90 * handle the socket types supported by vpp */
91 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
92 {
93 case SOCK_STREAM:
94 case SOCK_DGRAM:
95 /* the type argument serves a second purpose,
96 * in addition to specifying a socket type,
97 * it may include the bitwise OR of any of
98 * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
99 * the behavior of socket. */
100 rv = libc_socket (domain, type, protocol);
101 if (rv == -1)
102 rv = -errno;
103 break;
104
105 default:
106 break;
107 }
108
109 break;
110
111 default:
112 break;
113 }
114
115 return rv;
116}
117
118static int
119vcom_socket_open_epoll (int flags)
120{
121 int rv = -1;
122
123 if (flags < 0)
124 {
125 return -EINVAL;
126 }
127 if (flags && (flags & ~EPOLL_CLOEXEC))
128 {
129 return -EINVAL;
130 }
131
132 /* flags can be either zero or EPOLL_CLOEXEC */
133 rv = libc_epoll_create1 (flags);
134 if (rv == -1)
135 rv = -errno;
136
137 return rv;
138}
139
140static int
141vcom_socket_close_socket (int fd)
142{
143 int rv;
144
145 rv = libc_close (fd);
146 if (rv == -1)
147 rv = -errno;
148
149 return rv;
150}
151
152static int
153vcom_socket_close_epoll (int epfd)
154{
155 int rv;
156
157 rv = libc_close (epfd);
158 if (rv == -1)
159 rv = -errno;
160
161 return rv;
162}
163
164/*
165 * Public API functions
166 */
167
168
169int
170vcom_socket_is_vcom_fd (int fd)
171{
172 vcom_socket_main_t *vsm = &vcom_socket_main;
173 uword *p;
174 vcom_socket_t *vsock;
175
176 p = hash_get (vsm->sockidx_by_fd, fd);
177
178 if (p)
179 {
180 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
181 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
182 return 1;
183 }
184 return 0;
185}
186
187int
188vcom_socket_is_vcom_epfd (int epfd)
189{
190 vcom_socket_main_t *vsm = &vcom_socket_main;
191 uword *p;
192 vcom_epoll_t *vepoll;
193
194 p = hash_get (vsm->epollidx_by_epfd, epfd);
195
196 if (p)
197 {
198 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
199 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
200 return 1;
201 }
202 return 0;
203}
204
205static inline int
206vcom_socket_get_sid (int fd)
207{
208 vcom_socket_main_t *vsm = &vcom_socket_main;
209 uword *p;
210 vcom_socket_t *vsock;
211
212 p = hash_get (vsm->sockidx_by_fd, fd);
213
214 if (p)
215 {
216 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
217 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
218 return vsock->sid;
219 }
220 return INVALID_SESSION_ID;
221}
222
223static inline int
224vcom_socket_get_vep_idx (int epfd)
225{
226 vcom_socket_main_t *vsm = &vcom_socket_main;
227 uword *p;
228 vcom_epoll_t *vepoll;
229
230 p = hash_get (vsm->epollidx_by_epfd, epfd);
231
232 if (p)
233 {
234 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
235 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
236 return vepoll->vep_idx;
237 }
238 return INVALID_VEP_IDX;
239}
240
241static inline int
242vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
243{
244 vcom_socket_main_t *vsm = &vcom_socket_main;
245 uword *p;
246 vcom_socket_t *vsock;
247
248 p = hash_get (vsm->sockidx_by_fd, fd);
249
250 if (p)
251 {
252 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
253 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
254 {
255 *vsockp = vsock;
256 return vsock->sid;
257 }
258 }
259 return INVALID_SESSION_ID;
260}
261
262static inline int
263vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
264{
265 vcom_socket_main_t *vsm = &vcom_socket_main;
266 uword *p;
267 vcom_epoll_t *vepoll;
268
269 p = hash_get (vsm->epollidx_by_epfd, epfd);
270
271 if (p)
272 {
273 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
274 if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
275 {
276 *vepollp = vepoll;
277 return vepoll->vep_idx;
278 }
279 }
280 return INVALID_VEP_IDX;
281}
282
283
284static int
285vcom_socket_close_vepoll (int epfd)
286{
287 int rv = -1;
288 vcom_socket_main_t *vsm = &vcom_socket_main;
289 uword *p;
290 vcom_epoll_t *vepoll;
291
292 p = hash_get (vsm->epollidx_by_epfd, epfd);
293 if (!p)
294 return -EBADF;
295
296 vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
297 if (!vepoll)
298 return -EBADF;
299
300 if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
301 return -EINVAL;
302
303 if (vepoll->count)
304 {
305 if (!vepoll->close)
306 {
307 vepoll->close = 1;
308 return 0;
309 }
310 else
311 {
312 return -EBADF;
313 }
314 }
315
316 /* count is zero */
317 rv = vppcom_session_close (vepoll->vep_idx);
318 rv = vcom_socket_close_epoll (vepoll->epfd);
319
320 vepoll_init (vepoll);
321 hash_unset (vsm->epollidx_by_epfd, epfd);
322 pool_put (vsm->vepolls, vepoll);
323
324 return rv;
325}
326
327static int
328vcom_socket_close_vsock (int fd)
329{
330 int rv = -1;
331 vcom_socket_main_t *vsm = &vcom_socket_main;
332 uword *p;
333 vcom_socket_t *vsock;
334
335 vcom_epitem_t *vepitem;
336
337 i32 *vepitemidxs = 0;
338 i32 *vepitemidxs_var = 0;
339
340 p = hash_get (vsm->sockidx_by_fd, fd);
341 if (!p)
342 return -EBADF;
343
344 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
345 if (!vsock)
346 return -ENOTSOCK;
347
348 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
349 return -EINVAL;
350
351 rv = vppcom_session_close (vsock->sid);
352 rv = vcom_socket_close_socket (vsock->fd);
353
354 vsocket_init (vsock);
355 hash_unset (vsm->sockidx_by_fd, fd);
356 pool_put (vsm->vsockets, vsock);
357
358 /*
359 * NOTE:
360 * Before calling close(), user should remove
361 * this fd from the epoll-set of all epoll instances,
362 * otherwise resource(epitems) leaks ensues.
363 */
364
365 /*
366 * 00. close all epoll instances that are marked as "close"
367 * of which this fd is the "last" remaining member.
368 * 01. epitems associated with this fd are intentionally
369 * not removed, see NOTE: above.
370 * */
371
372 /* does this fd participate in epoll */
373 p = hash_get (vsm->epitemidxs_by_fd, fd);
374 if (p)
375 {
376 vepitemidxs = *(i32 **) p;
377 vec_foreach (vepitemidxs_var, vepitemidxs)
378 {
379 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
380 if (vepitem && vepitem->fd == fd &&
381 vepitem->type == FD_TYPE_VCOM_SOCKET)
382 {
383 i32 vep_idx;
384 vcom_epoll_t *vepoll;
385 if ((vep_idx =
386 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
387 &vepoll)) !=
388 INVALID_VEP_IDX)
389 {
390 if (vepoll->close)
391 {
392 if (vepoll->count == 1)
393 {
394 /*
395 * force count to zero and
396 * close this epoll instance
397 * */
398 vepoll->count = 0;
399 vcom_socket_close_vepoll (vepoll->epfd);
400 }
401 else
402 {
403 vepoll->count -= 1;
404 }
405 }
406 }
407 }
408
409 }
410 }
411
412 return rv;
413}
414
415int
416vcom_socket_close (int __fd)
417{
418 int rv;
419
420 if (vcom_socket_is_vcom_fd (__fd))
421 {
422 rv = vcom_socket_close_vsock (__fd);
423 }
424 else if (vcom_socket_is_vcom_epfd (__fd))
425 {
426 rv = vcom_socket_close_vepoll (__fd);
427 }
428 else
429 {
430 rv = -EBADF;
431 }
432
433 return rv;
434}
435
436ssize_t
437vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
438{
439 int rv = -1;
440 vcom_socket_main_t *vsm = &vcom_socket_main;
441 uword *p;
442 vcom_socket_t *vsock;
443
444 p = hash_get (vsm->sockidx_by_fd, __fd);
445 if (!p)
446 return -EBADF;
447
448 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
449 if (!vsock)
450 return -ENOTSOCK;
451
452 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
453 return -EINVAL;
454
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400455 if (!__buf)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700456 {
457 return -EINVAL;
458 }
459
460 rv = vcom_fcntl (__fd, F_GETFL, 0);
461 if (rv < 0)
462 {
463 return rv;
464
465 }
466
467 /* is blocking */
468 if (!(rv & O_NONBLOCK))
469 {
470 do
471 {
472 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
473 }
Dave Wallace60f54822017-10-24 20:47:45 -0400474 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700475 while (rv == -EAGAIN || rv == -EWOULDBLOCK);
476 return rv;
477 }
478 /* The file descriptor refers to a socket and has been
479 * marked nonblocking(O_NONBLOCK) and the read would
480 * block.
481 * */
482 /* is non blocking */
483 rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
484 return rv;
485}
486
487ssize_t
488vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
489{
490 int rv;
491 vcom_socket_main_t *vsm = &vcom_socket_main;
492 uword *p;
493 vcom_socket_t *vsock;
494 ssize_t total = 0, len = 0;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400495 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700496
497 p = hash_get (vsm->sockidx_by_fd, __fd);
498 if (!p)
499 return -EBADF;
500
501 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
502 if (!vsock)
503 return -ENOTSOCK;
504
505 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
506 return -EINVAL;
507
508 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
509 return -EINVAL;
510
511 /* Sanity check */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400512 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700513 {
514 if (SSIZE_MAX - len < __iov[i].iov_len)
515 return -EINVAL;
516 len += __iov[i].iov_len;
517 }
518
519 rv = vcom_fcntl (__fd, F_GETFL, 0);
520 if (rv < 0)
521 {
522 return rv;
523 }
524
525 /* is blocking */
526 if (!(rv & O_NONBLOCK))
527 {
528 do
529 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400530 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700531 {
532 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
533 __iov[i].iov_len);
534 if (rv < 0)
535 break;
536 else
537 {
538 total += rv;
539 if (rv < __iov[i].iov_len)
540 /* Read less than buffer provided, no point to continue */
541 break;
542 }
543 }
544 }
Dave Wallace60f54822017-10-24 20:47:45 -0400545 /* coverity[CONSTANT_EXPRESSION_RESULT] */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700546 while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
547 return total;
548 }
549
550 /* is non blocking */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400551 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700552 {
553 rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
554 __iov[i].iov_len);
555 if (rv < 0)
556 {
557 if (total > 0)
558 break;
559 else
560 {
561 errno = rv;
562 return rv;
563 }
564 }
565 else
566 {
567 total += rv;
568 if (rv < __iov[i].iov_len)
569 /* Read less than buffer provided, no point to continue */
570 break;
571 }
572 }
573 return total;
574}
575
576ssize_t
577vcom_socket_write (int __fd, const void *__buf, size_t __n)
578{
579 int rv = -1;
580 vcom_socket_main_t *vsm = &vcom_socket_main;
581 uword *p;
582 vcom_socket_t *vsock;
583
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400584 if (!__buf)
585 {
586 return -EINVAL;
587 }
588
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700589 p = hash_get (vsm->sockidx_by_fd, __fd);
590 if (!p)
591 return -EBADF;
592
593 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
594 if (!vsock)
595 return -ENOTSOCK;
596
597 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
598 return -EINVAL;
599
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700600 rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
601 return rv;
602}
603
604ssize_t
605vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
606{
607 int rv = -1;
608 ssize_t total = 0;
609 vcom_socket_main_t *vsm = &vcom_socket_main;
610 uword *p;
611 vcom_socket_t *vsock;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400612 int i;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700613
614 p = hash_get (vsm->sockidx_by_fd, __fd);
615 if (!p)
616 return -EBADF;
617
618 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
619 if (!vsock)
620 return -ENOTSOCK;
621
622 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
623 return -EINVAL;
624
625 if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
626 return -EINVAL;
627
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400628 for (i = 0; i < __iovcnt; ++i)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700629 {
630 rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
631 __iov[i].iov_len);
632 if (rv < 0)
633 {
634 if (total > 0)
635 break;
636 else
637 return rv;
638 }
639 else
640 total += rv;
641 }
642 return total;
643}
644
645/*
646 * RETURN: 0 - invalid cmd
647 * 1 - cmd not handled by vcom and vppcom
648 * 2 - cmd handled by vcom socket resource
649 * 3 - cmd handled by vppcom
650 * */
651/* TBD: incomplete list of cmd */
652static int
653vcom_socket_check_fcntl_cmd (int __cmd)
654{
655 switch (__cmd)
656 {
657 /*cmd not handled by vcom and vppcom */
658 /* Fallthrough */
659 case F_DUPFD:
660 case F_DUPFD_CLOEXEC:
661 return 1;
662
663 /* cmd handled by vcom socket resource */
664 /* Fallthrough */
665 case F_GETFD:
666 case F_SETFD:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700667 case F_GETLK:
668 case F_SETLK:
669 case F_SETLKW:
670 case F_GETOWN:
671 case F_SETOWN:
672 return 2;
673
Stevenb59f2272017-10-12 17:10:33 -0700674 /* cmd handled by vcom and vppcom */
675 case F_SETFL:
676 case F_GETFL:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700677 return 3;
Stevenb59f2272017-10-12 17:10:33 -0700678
679 /* cmd not handled by vcom and vppcom */
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700680 default:
Stevenb59f2272017-10-12 17:10:33 -0700681 return 1;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700682 }
683 return 0;
684}
685
Dave Wallacee22aa742017-10-20 12:30:38 -0400686static inline int
687vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700688{
Stevenb59f2272017-10-12 17:10:33 -0700689 int flags = va_arg (__ap, int);
690 int rv = -EOPNOTSUPP;
691 uint32_t size;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700692
Stevenb59f2272017-10-12 17:10:33 -0700693 size = sizeof (flags);
694 if (__cmd == F_SETFL)
695 {
696 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
697 }
698 else if (__cmd == F_GETFL)
699 {
700 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
701 if (rv == VPPCOM_OK)
702 rv = flags;
703 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700704
705 return rv;
706}
707
708int
709vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
710{
711 int rv = -EBADF;
712 vcom_socket_main_t *vsm = &vcom_socket_main;
713 uword *p;
714 vcom_socket_t *vsock;
715
716 p = hash_get (vsm->sockidx_by_fd, __fd);
717 if (!p)
718 return -EBADF;
719
720 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
721 if (!vsock)
722 return -ENOTSOCK;
723
724 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
725 return -EINVAL;
726
727 switch (vcom_socket_check_fcntl_cmd (__cmd))
728 {
729 /* invalid cmd */
730 case 0:
731 rv = -EBADF;
732 break;
733 /*cmd not handled by vcom and vppcom */
734 case 1:
Stevenb59f2272017-10-12 17:10:33 -0700735 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700736 break;
737 /* cmd handled by vcom socket resource */
738 case 2:
739 rv = libc_vfcntl (vsock->fd, __cmd, __ap);
740 break;
741 /* cmd handled by vppcom */
742 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400743 rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700744 break;
745
746 default:
747 rv = -EINVAL;
748 break;
749 }
750
751 return rv;
752}
753
Stevenb59f2272017-10-12 17:10:33 -0700754/*
755 * RETURN: 0 - invalid cmd
756 * 1 - cmd not handled by vcom and vppcom
757 * 2 - cmd handled by vcom socket resource
758 * 3 - cmd handled by vppcom
759 */
760static int
761vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
762{
763 int rc;
764
765 switch (__cmd)
766 {
767 /* cmd handled by vppcom */
768 case FIONREAD:
769 rc = 3;
770 break;
771
772 /* cmd not handled by vcom and vppcom */
773 default:
774 rc = 1;
775 break;
776 }
777 return rc;
778}
779
Dave Wallacee22aa742017-10-20 12:30:38 -0400780static inline int
781vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
Stevenb59f2272017-10-12 17:10:33 -0700782{
783 int rv;
784
Dave Wallace59179392017-11-07 02:20:07 -0500785 switch (__cmd)
786 {
787 case FIONREAD:
788 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
789 break;
790
791 case FIONBIO:
792 {
793 u32 flags = va_arg (__ap, int) ? O_NONBLOCK : 0;
794 u32 len = sizeof (flags);
795 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &len);
796 }
797 break;
798
799 default:
800 rv = -EOPNOTSUPP;
801 break;
802 }
Stevenb59f2272017-10-12 17:10:33 -0700803 return rv;
804}
805
806int
807vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
808{
809 int rv = -EBADF;
810 vcom_socket_main_t *vsm = &vcom_socket_main;
811 uword *p;
812 vcom_socket_t *vsock;
813
814 p = hash_get (vsm->sockidx_by_fd, __fd);
815 if (!p)
816 return -EBADF;
817
818 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
819 if (!vsock)
820 return -ENOTSOCK;
821
822 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
823 return -EINVAL;
824
825 switch (vcom_socket_check_ioctl_cmd (__cmd))
826 {
827 /* Not supported cmd */
828 case 0:
829 rv = -EOPNOTSUPP;
830 break;
831
832 /* cmd not handled by vcom and vppcom */
833 case 1:
834 rv = libc_vioctl (vsock->fd, __cmd, __ap);
835 break;
836
837 /* cmd handled by vcom socket resource */
838 case 2:
839 rv = libc_vioctl (vsock->fd, __cmd, __ap);
840 break;
841
842 /* cmd handled by vppcom */
843 case 3:
Dave Wallacee22aa742017-10-20 12:30:38 -0400844 rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
Stevenb59f2272017-10-12 17:10:33 -0700845 break;
846
847 default:
848 rv = -EINVAL;
849 break;
850 }
851
852 return rv;
853}
854
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700855static inline int
856vcom_socket_fds_2_sid_fds (
857 /* dest */
858 int *vcom_nsid_fds,
859 fd_set * __restrict vcom_rd_sid_fds,
860 fd_set * __restrict vcom_wr_sid_fds,
861 fd_set * __restrict vcom_ex_sid_fds,
862 /* src */
863 int vcom_nfds,
864 fd_set * __restrict vcom_readfds,
865 fd_set * __restrict vcom_writefds,
866 fd_set * __restrict vcom_exceptfds)
867{
868 int rv = 0;
869 int fd;
870 int sid;
871 /* invalid max_sid is -1 */
872 int max_sid = -1;
873 int nsid = 0;
874
875 /*
876 * set sid in sid sets corresponding to fd's in fd sets
877 * compute nsid and vcom_nsid_fds from sid sets
878 */
879
880 for (fd = 0; fd < vcom_nfds; fd++)
881 {
882 /*
883 * F fd set, src
884 * S sid set, dest
885 */
886#define _(S,F) \
887 if ((F) && (S) && FD_ISSET (fd, (F))) \
888 { \
889 sid = vcom_socket_get_sid (fd); \
890 if (sid != INVALID_SESSION_ID) \
891 { \
892 FD_SET (sid, (S)); \
893 if (sid > max_sid) \
894 { \
895 max_sid = sid; \
896 } \
897 ++nsid; \
898 } \
899 else \
900 { \
901 rv = -EBADFD; \
902 goto done; \
903 } \
904 }
905
906
907 _(vcom_rd_sid_fds, vcom_readfds);
908 _(vcom_wr_sid_fds, vcom_writefds);
909 _(vcom_ex_sid_fds, vcom_exceptfds);
910#undef _
911 }
912
913 *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
914 rv = nsid;
915
916done:
917 return rv;
918}
919
920/*
921 * PRE: 00. sid sets were derived from fd sets
922 * 01. sid sets were updated with sids that actually changed
923 * status
924 * 02. fd sets still has watched fds
925 *
926 * This function will modify in place fd sets to indicate which fd's
927 * actually changed status(inferred from sid sets)
928 */
929static inline int
930vcom_socket_sid_fds_2_fds (
931 /* dest */
932 int *new_vcom_nfds,
933 int vcom_nfds,
934 fd_set * __restrict vcom_readfds,
935 fd_set * __restrict vcom_writefds,
936 fd_set * __restrict vcom_exceptfds,
937 /* src */
938 int vcom_nsid_fds,
939 fd_set * __restrict vcom_rd_sid_fds,
940 fd_set * __restrict vcom_wr_sid_fds,
941 fd_set * __restrict vcom_ex_sid_fds)
942{
943 int rv = 0;
944 int fd;
945 int sid;
946 /* invalid max_fd is -1 */
947 int max_fd = -1;
948 int nfd = 0;
949
950
951 /*
952 * modify in place fd sets to indicate which fd's
953 * actually changed status(inferred from sid sets)
954 */
955 for (fd = 0; fd < vcom_nfds; fd++)
956 {
957 /*
958 * F fd set, dest
959 * S sid set, src
960 */
961#define _(S,F) \
962 if ((F) && (S) && FD_ISSET (fd, (F))) \
963 { \
964 sid = vcom_socket_get_sid (fd); \
965 if (sid != INVALID_SESSION_ID) \
966 { \
967 if (!FD_ISSET (sid, (S))) \
968 { \
969 FD_CLR(fd, (F)); \
970 } \
971 } \
972 else \
973 { \
974 rv = -EBADFD; \
975 goto done; \
976 } \
977 }
978
979
980 _(vcom_rd_sid_fds, vcom_readfds);
981 _(vcom_wr_sid_fds, vcom_writefds);
982 _(vcom_ex_sid_fds, vcom_exceptfds);
983#undef _
984 }
985
986 /*
987 * compute nfd and new_vcom_nfds from fd sets
988 */
989 for (fd = 0; fd < vcom_nfds; fd++)
990 {
991
992#define _(F) \
993 if ((F) && FD_ISSET (fd, (F))) \
994 { \
995 if (fd > max_fd) \
996 { \
997 max_fd = fd; \
998 } \
999 ++nfd; \
1000 }
1001
1002
1003 _(vcom_readfds);
1004 _(vcom_writefds);
1005 _(vcom_exceptfds);
1006#undef _
1007
1008 }
1009
1010 *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
1011 rv = nfd;
1012
1013done:
1014 return rv;
1015}
1016
1017/*
1018 * PRE:
1019 * vom_socket_select is always called with
1020 * timeout->tv_sec and timeout->tv_usec set to zero.
1021 * hence vppcom_select return immediately.
1022 */
1023/*
1024 * TBD: do{body;} while(timeout conditional); timeout loop
1025 */
1026int
1027vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1028 fd_set * __restrict vcom_writefds,
1029 fd_set * __restrict vcom_exceptfds,
1030 struct timeval *__restrict timeout)
1031{
Dave Wallacee22aa742017-10-20 12:30:38 -04001032 static unsigned long vcom_nsid_fds = 0;
1033 int vcom_nsid = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001034 int rv = -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001035
1036 int new_vcom_nfds = 0;
1037 int new_vcom_nfd = 0;
1038
1039 /* vcom sid fds */
1040 fd_set vcom_rd_sid_fds;
1041 fd_set vcom_wr_sid_fds;
1042 fd_set vcom_ex_sid_fds;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001043
1044 /* in seconds eg. 3.123456789 seconds */
1045 double time_to_wait = (double) 0;
1046
1047 /* validate inputs */
1048 if (vcom_nfds < 0)
1049 {
1050 return -EINVAL;
1051 }
1052
1053 /* convert timeval timeout to double time_to_wait */
1054 if (timeout)
1055 {
1056 if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1057 {
1058 /* polling: vppcom_select returns immediately */
1059 time_to_wait = (double) 0;
1060 }
1061 else
1062 {
1063 /*TBD: use timeval api */
1064 time_to_wait = (double) timeout->tv_sec +
1065 (double) timeout->tv_usec / (double) 1000000 +
1066 (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1067 }
1068 }
1069 else
1070 {
1071 /*
1072 * no timeout: vppcom_select can block indefinitely
1073 * waiting for a file descriptor to become ready
1074 * */
1075 /* set to a phantom value */
1076 time_to_wait = ~0;
1077 }
1078
1079 /* zero the sid_sets */
1080 /*
1081 * F fd set
1082 * S sid set
1083 */
1084#define _(S,F) \
1085 if ((F)) \
1086 { \
1087 FD_ZERO ((S)); \
1088 }
1089
1090
1091 _(&vcom_rd_sid_fds, vcom_readfds);
1092 _(&vcom_wr_sid_fds, vcom_writefds);
1093 _(&vcom_ex_sid_fds, vcom_exceptfds);
1094#undef _
1095
Dave Wallacee22aa742017-10-20 12:30:38 -04001096 if (vcom_nfds == 0)
1097 {
1098 if (time_to_wait > 0)
1099 {
1100 if (VCOM_DEBUG > 0)
1101 fprintf (stderr,
1102 "[%d] vcom_socket_select called to "
Dave Wallace59179392017-11-07 02:20:07 -05001103 "emulate delay_ns()!\n", getpid ());
Dave Wallacee22aa742017-10-20 12:30:38 -04001104 rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1105 }
1106 else
1107 {
1108 fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
Dave Wallacee695cb42017-11-02 22:04:42 -04001109 "and invalid time_to_wait (%f)!\n",
Dave Wallace59179392017-11-07 02:20:07 -05001110 getpid (), time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001111 }
1112 return 0;
1113 }
1114
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001115 /* populate read, write and except sid_sets */
1116 vcom_nsid = vcom_socket_fds_2_sid_fds (
1117 /* dest */
1118 vcom_readfds || vcom_writefds
1119 || vcom_exceptfds ? (int *)
1120 &vcom_nsid_fds : NULL,
1121 vcom_readfds ? &vcom_rd_sid_fds :
1122 NULL,
1123 vcom_writefds ? &vcom_wr_sid_fds :
1124 NULL,
1125 vcom_exceptfds ? &vcom_ex_sid_fds :
1126 NULL,
1127 /* src */
1128 vcom_nfds,
1129 vcom_readfds,
1130 vcom_writefds, vcom_exceptfds);
1131 if (vcom_nsid < 0)
1132 {
1133 return vcom_nsid;
1134 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001135
1136 rv = vppcom_select (vcom_nsid_fds,
1137 vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1138 NULL,
1139 vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1140 NULL,
1141 vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1142 NULL, time_to_wait);
Dave Wallacee22aa742017-10-20 12:30:38 -04001143 if (VCOM_DEBUG > 2)
1144 fprintf (stderr, "[%d] called vppcom_select(): "
Dave Wallace59179392017-11-07 02:20:07 -05001145 "'%04d'='%04d'\n", getpid (), rv, (int) vcom_nsid_fds);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001146
1147 /* check if any file descriptors changed status */
1148 if (rv > 0)
1149 {
1150 /*
1151 * on exit, sets are modified in place to indicate which
1152 * file descriptors actually changed status
1153 * */
1154
1155 /*
1156 * comply with pre-condition
1157 * do not clear vcom fd sets befor calling
1158 * vcom_socket_sid_fds_2_fds
1159 */
1160 new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1161 /* dest */
1162 &new_vcom_nfds,
1163 vcom_nfds,
1164 vcom_readfds,
1165 vcom_writefds,
1166 vcom_exceptfds,
1167 /* src */
1168 vcom_nsid_fds,
1169 vcom_readfds ?
1170 &vcom_rd_sid_fds : NULL,
1171 vcom_writefds ?
1172 &vcom_wr_sid_fds : NULL,
1173 vcom_exceptfds ?
1174 &vcom_ex_sid_fds : NULL);
1175 if (new_vcom_nfd < 0)
1176 {
1177 return new_vcom_nfd;
1178 }
1179 if (new_vcom_nfds < 0)
1180 {
1181 return -EINVAL;
1182 }
1183 rv = new_vcom_nfd;
1184 }
1185 return rv;
1186}
1187
1188
1189int
1190vcom_socket_socket (int __domain, int __type, int __protocol)
1191{
1192 int rv = -1;
1193 vcom_socket_main_t *vsm = &vcom_socket_main;
1194 vcom_socket_t *vsock;
1195
1196 i32 fd;
1197 i32 sid;
1198 i32 sockidx;
1199 u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1200 int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1201
1202 fd = vcom_socket_open_socket (__domain, __type, __protocol);
1203 if (fd < 0)
1204 {
1205 rv = fd;
1206 goto out;
1207 }
1208
1209 sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1210 (type == SOCK_DGRAM) ?
1211 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1212 is_nonblocking);
1213 if (sid < 0)
1214 {
1215 rv = sid;
1216 goto out_close_socket;
1217 }
1218
1219 pool_get (vsm->vsockets, vsock);
1220 vsocket_init (vsock);
1221
1222 sockidx = vsock - vsm->vsockets;
1223 hash_set (vsm->sockidx_by_fd, fd, sockidx);
1224
1225 vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1226 return fd;
1227
1228out_close_socket:
1229 vcom_socket_close_socket (fd);
1230out:
1231 return rv;
1232}
1233
1234int
1235vcom_socket_socketpair (int __domain, int __type, int __protocol,
1236 int __fds[2])
1237{
1238/* TBD: */
1239 return 0;
1240}
1241
1242int
1243vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1244{
1245 int rv = -1;
1246 vcom_socket_main_t *vsm = &vcom_socket_main;
1247 uword *p;
1248 vcom_socket_t *vsock;
1249
1250 vppcom_endpt_t ep;
1251
1252 p = hash_get (vsm->sockidx_by_fd, __fd);
1253 if (!p)
1254 return -EBADF;
1255
1256 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1257 if (!vsock)
1258 return -ENOTSOCK;
1259
1260 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1261 return -EINVAL;
1262
1263 if (!__addr)
1264 {
1265 return -EINVAL;
1266 }
1267
1268 ep.vrf = VPPCOM_VRF_DEFAULT;
1269 switch (__addr->sa_family)
1270 {
1271 case AF_INET:
1272 if (__len != sizeof (struct sockaddr_in))
1273 {
1274 return -EINVAL;
1275 }
1276 ep.is_ip4 = VPPCOM_IS_IP4;
1277 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1278 ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1279 break;
1280
1281 case AF_INET6:
1282 if (__len != sizeof (struct sockaddr_in6))
1283 {
1284 return -EINVAL;
1285 }
1286 ep.is_ip4 = VPPCOM_IS_IP6;
1287 ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1288 ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1289 break;
1290
1291 default:
1292 return -1;
1293 break;
1294 }
1295
1296 rv = vppcom_session_bind (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001297 return rv;
1298}
1299
Dave Wallacee22aa742017-10-20 12:30:38 -04001300static inline int
1301vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001302{
Steven2199aab2017-10-15 20:18:47 -07001303 int rv;
1304 uint32_t size = sizeof (*ep);
1305
1306 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1307 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001308}
1309
1310int
1311vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1312 socklen_t * __restrict __len)
1313{
1314 int rv = -1;
1315 vcom_socket_main_t *vsm = &vcom_socket_main;
1316 uword *p;
1317 vcom_socket_t *vsock;
1318
1319
1320 p = hash_get (vsm->sockidx_by_fd, __fd);
1321 if (!p)
1322 return -EBADF;
1323
1324 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1325 if (!vsock)
1326 return -ENOTSOCK;
1327
1328 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1329 return -EINVAL;
1330
1331 if (!__addr || !__len)
1332 return -EFAULT;
1333
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001334 vppcom_endpt_t ep;
1335 ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001336 rv = vcom_session_getsockname (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001337 if (rv == 0)
1338 {
1339 if (ep.vrf == VPPCOM_VRF_DEFAULT)
1340 {
1341 __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1342 switch (__addr->sa_family)
1343 {
1344 case AF_INET:
1345 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1346 *__len = sizeof (struct sockaddr_in);
1347 break;
1348
1349 case AF_INET6:
1350 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1351 *__len = sizeof (struct sockaddr_in6);
1352 break;
1353
1354 default:
1355 break;
1356 }
1357 }
1358 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001359
1360 return rv;
1361}
1362
1363int
1364vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1365{
1366 int rv = -1;
1367 vcom_socket_main_t *vsm = &vcom_socket_main;
1368 uword *p;
1369 vcom_socket_t *vsock;
1370
1371 vppcom_endpt_t ep;
1372
1373 p = hash_get (vsm->sockidx_by_fd, __fd);
1374 if (p)
1375 {
1376 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1377
1378 ep.vrf = VPPCOM_VRF_DEFAULT;
1379 switch (__addr->sa_family)
1380 {
1381 case AF_INET:
1382 ep.is_ip4 = VPPCOM_IS_IP4;
1383 ep.ip =
1384 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1385 ep.port =
1386 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1387 break;
1388
1389 case AF_INET6:
1390 ep.is_ip4 = VPPCOM_IS_IP6;
1391 ep.ip =
1392 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1393 ep.port =
1394 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1395 break;
1396
1397 default:
1398 return -1;
1399 break;
1400 }
1401
1402 rv = vppcom_session_connect (vsock->sid, &ep);
1403 }
1404 return rv;
1405}
1406
Dave Wallacee22aa742017-10-20 12:30:38 -04001407static inline int
1408vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001409{
Steven2199aab2017-10-15 20:18:47 -07001410 int rv;
1411 uint32_t size = sizeof (*ep);
1412
1413 rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1414 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001415}
1416
Steven0cdd5bd2017-11-08 14:14:45 -08001417static inline int
1418vcom_socket_copy_ep_to_sockaddr (__SOCKADDR_ARG __addr,
1419 socklen_t * __restrict __len,
1420 vppcom_endpt_t * ep)
1421{
1422 int rv = 0;
1423 int sa_len, copy_len;
1424
1425 __addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1426 switch (__addr->sa_family)
1427 {
1428 case AF_INET:
1429 ((struct sockaddr_in *) __addr)->sin_port = ep->port;
1430 if (*__len > sizeof (struct sockaddr_in))
1431 *__len = sizeof (struct sockaddr_in);
1432 sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1433 copy_len = *__len - sa_len;
1434 if (copy_len > 0)
1435 memcpy (&((struct sockaddr_in *) __addr)->sin_addr, ep->ip, copy_len);
1436 break;
1437
1438 case AF_INET6:
1439 ((struct sockaddr_in6 *) __addr)->sin6_port = ep->port;
1440 if (*__len > sizeof (struct sockaddr_in6))
1441 *__len = sizeof (struct sockaddr_in6);
1442 sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1443 copy_len = *__len - sa_len;
1444 if (copy_len > 0)
1445 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1446 __in6_u.__u6_addr8, ep->ip, copy_len);
1447 break;
1448
1449 default:
1450 /* Not possible */
1451 rv = -EAFNOSUPPORT;
1452 break;
1453 }
1454
1455 return rv;
1456}
1457
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001458int
1459vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1460 socklen_t * __restrict __len)
1461{
1462 int rv = -1;
1463 vcom_socket_main_t *vsm = &vcom_socket_main;
1464 uword *p;
1465 vcom_socket_t *vsock;
Steven0cdd5bd2017-11-08 14:14:45 -08001466 u8 src_addr[sizeof (struct sockaddr_in6)];
1467 vppcom_endpt_t ep;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001468
1469 p = hash_get (vsm->sockidx_by_fd, __fd);
1470 if (!p)
1471 return -EBADF;
1472
1473 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1474 if (!vsock)
1475 return -ENOTSOCK;
1476
1477 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1478 return -EINVAL;
1479
1480 if (!__addr || !__len)
1481 return -EFAULT;
1482
Steven0cdd5bd2017-11-08 14:14:45 -08001483 ep.ip = src_addr;
Dave Wallacee22aa742017-10-20 12:30:38 -04001484 rv = vcom_session_getpeername (vsock->sid, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001485 if (rv == 0)
Steven0cdd5bd2017-11-08 14:14:45 -08001486 rv = vcom_socket_copy_ep_to_sockaddr (__addr, __len, &ep);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001487
1488 return rv;
1489}
1490
1491ssize_t
1492vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1493{
1494 return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1495}
1496
Dave Wallace227867f2017-11-13 21:21:53 -05001497/* NOTE: this function is not thread safe or 32-bit friendly */
1498ssize_t
1499vcom_socket_sendfile (int __out_fd, int __in_fd, off_t * __offset,
1500 size_t __len)
1501{
1502 vcom_socket_main_t *vsm = &vcom_socket_main;
1503 uword *p;
1504 vcom_socket_t *vsock;
1505 size_t n_bytes_left = __len;
1506 u32 out_sockidx, out_sid = ~0;
1507 size_t bytes_to_read;
1508 int nbytes;
1509 int rv, errno_val;
1510 ssize_t results = 0;
1511 u8 eagain = 0;
1512
1513 if (VCOM_DEBUG > 2)
1514 clib_warning ("[%d] __out_fd %d, __in_fd %d, __offset %p, __len %lu",
1515 getpid (), __out_fd, __in_fd, __offset, __len);
1516
1517 p = hash_get (vsm->sockidx_by_fd, __out_fd);
1518 if (!p)
1519 {
1520 clib_warning ("[%d] ERROR: invalid __out_fd (%d), fd lookup failed!",
1521 getpid (), __len);
1522 return -EBADF;
1523 }
1524 out_sockidx = p[0];
1525 vsock = pool_elt_at_index (vsm->vsockets, out_sockidx);
1526 if (!vsock)
1527 {
1528 clib_warning ("[%d] ERROR: invalid __out_fd (%d) / out_sockidx %u, "
1529 "missing vsock pool element!",
1530 getpid (), __len, out_sockidx);
1531 return -ENOTSOCK;
1532 }
1533 out_sid = vsock->sid;
1534 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1535 {
1536 clib_warning ("[%d] ERROR: __out_fd (%d), socket (sid %u) "
1537 "is not VCL bound!", getpid (), __out_fd, out_sid);
1538 return -EINVAL;
1539 }
1540
1541 if (__offset)
1542 {
1543 off_t offset = lseek (__in_fd, *__offset, SEEK_SET);
1544 if (offset == -1)
1545 {
1546 errno_val = errno;
1547 perror ("lseek()");
1548 clib_warning ("[%d] ERROR: lseek SEEK_SET failed: "
1549 "in_fd %d, offset %p (%ld), rv %ld, errno %d",
1550 getpid (), __in_fd, __offset, *__offset, offset,
1551 errno_val);
1552 return -errno_val;
1553 }
1554
1555 ASSERT (offset == *__offset);
1556 }
1557
1558 do
1559 {
Dave Wallacee376f932017-11-19 11:20:02 -05001560 rv = vppcom_session_attr (out_sid, VPPCOM_ATTR_GET_NWRITE, 0, 0);
1561 if (rv < 0)
1562 {
1563 clib_warning ("[%d] ERROR: vppcom_session_attr (out_sid (%u), "
1564 "VPPCOM_ATTR_GET_NWRITE, 0, 0) returned %d (%s)!",
1565 getpid (), out_sid, rv, vppcom_retval_str (rv));
1566 vec_reset_length (vsm->io_buffer);
1567 return rv;
1568 }
1569
1570 bytes_to_read = (size_t) rv;
Dave Wallace227867f2017-11-13 21:21:53 -05001571 if (VCOM_DEBUG > 2)
1572 clib_warning ("[%d] results %ld, n_bytes_left %lu, "
1573 "bytes_to_read %lu", getpid (), results,
1574 n_bytes_left, bytes_to_read);
1575 if (bytes_to_read == 0)
1576 {
1577 u32 flags, flags_len = sizeof (flags);
1578 rv = vppcom_session_attr (out_sid, VPPCOM_ATTR_GET_FLAGS, &flags,
1579 &flags_len);
1580 ASSERT (rv == VPPCOM_OK);
1581
1582 if (flags & O_NONBLOCK)
1583 {
1584 if (!results)
1585 {
1586 if (VCOM_DEBUG > 2)
1587 clib_warning ("[%d] EAGAIN", getpid ());
1588 eagain = 1;
1589 }
1590 goto update_offset;
1591 }
1592 else
1593 continue;
1594 }
1595 bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1596 vec_validate (vsm->io_buffer, bytes_to_read);
1597 nbytes = libc_read (__in_fd, vsm->io_buffer, bytes_to_read);
1598 if (nbytes < 0)
1599 {
1600 errno_val = errno;
1601 perror ("read()");
1602 clib_warning ("[%d] ERROR: libc_read (__in_fd (%d), "
1603 "io_buffer %p, bytes_to_read %lu) returned "
1604 "errno %d",
1605 getpid (), __in_fd, vsm->io_buffer,
1606 bytes_to_read, errno_val);
1607 if (results == 0)
1608 {
1609 vec_reset_length (vsm->io_buffer);
1610 return -errno_val;
1611 }
1612 goto update_offset;
1613 }
1614 rv = vppcom_session_write (out_sid, vsm->io_buffer, nbytes);
1615 if (rv < 0)
1616 {
1617 clib_warning ("[%d] ERROR: vppcom_session_write ("
Dave Wallacee376f932017-11-19 11:20:02 -05001618 "out_sid %u, io_buffer %p, nbytes %d) "
1619 "returned %d (%s)",
1620 getpid (), out_sid, vsm->io_buffer, nbytes,
1621 rv, vppcom_retval_str (rv));
Dave Wallace227867f2017-11-13 21:21:53 -05001622 if (results == 0)
1623 {
1624 vec_reset_length (vsm->io_buffer);
1625 return rv;
1626 }
1627 goto update_offset;
1628 }
1629
1630 results += nbytes;
1631 ASSERT (n_bytes_left >= nbytes);
1632 n_bytes_left = n_bytes_left - nbytes;
1633 }
1634 while (n_bytes_left > 0);
1635
1636update_offset:
1637 if (__offset)
1638 {
1639 off_t offset = lseek (__in_fd, *__offset, SEEK_SET);
1640 if (offset == -1)
1641 {
1642 errno_val = errno;
1643 perror ("lseek()");
1644 clib_warning ("[%d] ERROR: lseek (__in_fd %d, __offset %p "
1645 "(%ld), SEEK_SET) returned errno %d",
1646 getpid (), __in_fd, __offset, *__offset, errno_val);
1647 vec_reset_length (vsm->io_buffer);
1648 return -errno_val;
1649 }
1650
1651 *__offset += results + 1;
1652 }
1653
1654 vec_reset_length (vsm->io_buffer);
1655 return eagain ? -EAGAIN : results;
1656}
1657
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001658ssize_t
1659vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1660{
1661 int rv = -1;
1662 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1663 return rv;
1664}
1665
1666/*
1667 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1668 * 0 otherwise
1669 * */
1670int
1671vcom_socket_is_connection_mode_socket (int __fd)
1672{
1673 int rv = -1;
1674 /* TBD define new vppcom api */
1675 vcom_socket_main_t *vsm = &vcom_socket_main;
1676 uword *p;
1677 vcom_socket_t *vsock;
1678
1679 int type;
1680 socklen_t optlen;
1681
1682 p = hash_get (vsm->sockidx_by_fd, __fd);
1683
1684 if (p)
1685 {
1686 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1687 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1688 {
1689 optlen = sizeof (type);
1690 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1691 if (rv != 0)
1692 {
1693 return 0;
1694 }
1695 /* get socket type */
1696 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1697 {
1698 case SOCK_STREAM:
1699 case SOCK_SEQPACKET:
1700 return 1;
1701 break;
1702
1703 default:
1704 return 0;
1705 break;
1706 }
1707 }
1708 }
1709 return 0;
1710}
1711
Dave Wallacee22aa742017-10-20 12:30:38 -04001712static inline ssize_t
1713vcom_session_sendto (int __sid, void *__buf, size_t __n,
1714 int __flags, __CONST_SOCKADDR_ARG __addr,
1715 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001716{
Dave Wallace617dffa2017-10-26 14:47:06 -04001717 vppcom_endpt_t *ep = 0;
Steven8aa0d782017-10-27 09:34:57 -07001718 vppcom_endpt_t _ep;
Stevenac1f96d2017-10-24 16:03:58 -07001719
Dave Wallace617dffa2017-10-26 14:47:06 -04001720 if (__addr)
Stevenac1f96d2017-10-24 16:03:58 -07001721 {
Dave Wallace617dffa2017-10-26 14:47:06 -04001722 ep = &_ep;
1723 ep->vrf = VPPCOM_VRF_DEFAULT;
1724 switch (__addr->sa_family)
1725 {
1726 case AF_INET:
1727 ep->is_ip4 = VPPCOM_IS_IP4;
1728 ep->ip =
1729 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1730 ep->port =
1731 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1732 break;
Stevenac1f96d2017-10-24 16:03:58 -07001733
Dave Wallace617dffa2017-10-26 14:47:06 -04001734 case AF_INET6:
1735 ep->is_ip4 = VPPCOM_IS_IP6;
1736 ep->ip =
1737 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1738 ep->port =
1739 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1740 break;
1741
1742 default:
1743 return -EAFNOSUPPORT;
1744 }
Stevenac1f96d2017-10-24 16:03:58 -07001745 }
1746
Dave Wallace617dffa2017-10-26 14:47:06 -04001747 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001748}
1749
1750ssize_t
1751vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1752 int __flags, __CONST_SOCKADDR_ARG __addr,
1753 socklen_t __addr_len)
1754{
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001755 vcom_socket_main_t *vsm = &vcom_socket_main;
1756 uword *p;
1757 vcom_socket_t *vsock;
1758
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001759 if (!__buf)
1760 {
1761 return -EINVAL;
1762 }
1763
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001764 p = hash_get (vsm->sockidx_by_fd, __fd);
1765 if (!p)
1766 return -EBADF;
1767
1768 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1769 if (!vsock)
1770 return -ENOTSOCK;
1771
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001772 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001773 {
1774 return -EINVAL;
1775 }
1776
1777 if (vcom_socket_is_connection_mode_socket (__fd))
1778 {
1779 /* ignore __addr and _addr_len */
1780 /* and EISCONN may be returned when they are not NULL and 0 */
1781 if ((__addr != NULL) || (__addr_len != 0))
1782 {
1783 return -EISCONN;
1784 }
1785 }
1786 else
1787 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001788 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001789 {
1790 return -EDESTADDRREQ;
1791 }
1792 /* not a vppcom supported address family */
Dave Wallace60f54822017-10-24 20:47:45 -04001793 if (!((__addr->sa_family == AF_INET) ||
1794 (__addr->sa_family == AF_INET6)))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001795 {
1796 return -EINVAL;
1797 }
1798 }
1799
Dave Wallace617dffa2017-10-26 14:47:06 -04001800 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1801 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001802}
1803
Dave Wallacee22aa742017-10-20 12:30:38 -04001804static inline ssize_t
1805vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1806 int __flags, __SOCKADDR_ARG __addr,
1807 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001808{
Stevenac1f96d2017-10-24 16:03:58 -07001809 int rv;
1810 vppcom_endpt_t ep;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001811 u8 src_addr[sizeof (struct sockaddr_in6)];
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001812
Stevenac1f96d2017-10-24 16:03:58 -07001813 if (__addr)
1814 {
Dave Wallacefaf9d772017-10-26 16:12:04 -04001815 ep.ip = src_addr;
Stevenac1f96d2017-10-24 16:03:58 -07001816 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1817
1818 if (rv > 0)
Steven0cdd5bd2017-11-08 14:14:45 -08001819 rv = vcom_socket_copy_ep_to_sockaddr (__addr, __addr_len, &ep);
Stevenac1f96d2017-10-24 16:03:58 -07001820 }
1821 else
1822 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1823
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001824 return rv;
1825}
1826
1827ssize_t
1828vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1829 int __flags, __SOCKADDR_ARG __addr,
1830 socklen_t * __restrict __addr_len)
1831{
1832 int rv = -1;
1833 vcom_socket_main_t *vsm = &vcom_socket_main;
1834 uword *p;
1835 vcom_socket_t *vsock;
1836
Stevenac1f96d2017-10-24 16:03:58 -07001837 if (__addr && !__addr_len)
1838 return -EINVAL;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001839
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001840 p = hash_get (vsm->sockidx_by_fd, __fd);
1841 if (!p)
1842 return -EBADF;
1843
1844 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1845 if (!vsock)
1846 return -ENOTSOCK;
1847
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001848 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001849 {
1850 return -EINVAL;
1851 }
1852
Dave Wallacee22aa742017-10-20 12:30:38 -04001853 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1854 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001855 return rv;
1856}
1857
1858/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001859static inline ssize_t
1860vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001861{
1862 int rv = -1;
1863 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1864 (int)__n); */
1865 return rv;
1866}
1867
1868ssize_t
1869vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1870{
1871 int rv = -1;
1872 vcom_socket_main_t *vsm = &vcom_socket_main;
1873 uword *p;
1874 vcom_socket_t *vsock;
1875
1876 p = hash_get (vsm->sockidx_by_fd, __fd);
1877 if (!p)
1878 return -EBADF;
1879
1880 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1881 if (!vsock)
1882 return -ENOTSOCK;
1883
1884 if (vcom_socket_is_connection_mode_socket (__fd))
1885 {
1886 /* ignore __addr and _addr_len */
1887 /* and EISCONN may be returned when they are not NULL and 0 */
1888 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1889 {
1890 return -EISCONN;
1891 }
1892 }
1893 else
1894 {
1895 /* TBD: validate __message->msg_name and __message->msg_namelen
1896 * and return -EINVAL on validation error
1897 * */
1898 ;
1899 }
1900
Dave Wallacee22aa742017-10-20 12:30:38 -04001901 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001902
1903 return rv;
1904}
1905
1906#ifdef __USE_GNU
1907int
1908vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1909 unsigned int __vlen, int __flags)
1910{
1911
1912 /* TBD: define a new vppcom api */
1913 return 0;
1914}
1915#endif
1916
1917/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001918static inline ssize_t
1919vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001920{
1921 int rv = -1;
1922 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1923 (int)__n); */
1924 rv = -EOPNOTSUPP;
1925 return rv;
1926}
1927
1928ssize_t
1929vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1930{
1931 int rv = -1;
1932 vcom_socket_main_t *vsm = &vcom_socket_main;
1933 uword *p;
1934 vcom_socket_t *vsock;
1935
1936 p = hash_get (vsm->sockidx_by_fd, __fd);
1937 if (!p)
1938 return -EBADF;
1939
1940 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1941 if (!vsock)
1942 return -ENOTSOCK;
1943
1944 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1945 return -EINVAL;
1946
1947 if (!__message)
1948 {
1949 return -EINVAL;
1950 }
1951
1952 /* validate __flags */
1953
Dave Wallacee22aa742017-10-20 12:30:38 -04001954 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001955 return rv;
1956}
1957
1958#ifdef __USE_GNU
1959int
1960vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1961 unsigned int __vlen, int __flags,
1962 struct timespec *__tmo)
1963{
1964 /* TBD: define a new vppcom api */
1965 return 0;
1966}
1967#endif
1968
1969/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001970static inline int
1971vcom_session_get_sockopt (int __sid, int __level, int __optname,
1972 void *__restrict __optval,
1973 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001974{
Stevenac1f96d2017-10-24 16:03:58 -07001975 int rv = 0;
1976
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001977 /* 1. for socket level options that are NOT socket attributes
1978 * and that has corresponding vpp options get from vppcom */
Stevenac1f96d2017-10-24 16:03:58 -07001979 switch (__level)
1980 {
1981 case SOL_SOCKET:
1982 switch (__optname)
1983 {
1984 case SO_ERROR:
1985 *(int *) __optval = 0;
1986 break;
1987 default:
1988 break;
1989 }
1990 default:
1991 break;
1992 }
1993 /* 2. unhandled options */
1994 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001995}
1996
1997int
1998vcom_socket_getsockopt (int __fd, int __level, int __optname,
1999 void *__restrict __optval,
2000 socklen_t * __restrict __optlen)
2001{
2002 int rv = -1;
2003 vcom_socket_main_t *vsm = &vcom_socket_main;
2004 uword *p;
2005 vcom_socket_t *vsock;
2006
Dave Wallacefaf9d772017-10-26 16:12:04 -04002007 if (!__optval || !__optlen)
2008 return -EINVAL;
2009
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002010 p = hash_get (vsm->sockidx_by_fd, __fd);
2011 if (!p)
2012 return -EBADF;
2013
2014 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2015 if (!vsock)
2016 return -ENOTSOCK;
2017
2018 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2019 return -EINVAL;
2020
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002021 switch (__level)
2022 {
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002023 case SOL_SOCKET:
2024 switch (__optname)
2025 {
2026/*
2027 * 1. for socket level options that are socket attributes,
2028 * get from libc_getsockopt.
2029 * 2. for socket level options that are NOT socket
2030 * attributes and that has corresponding vpp options
2031 * get from vppcom.
2032 * 3. for socket level options unimplemented
2033 * return -ENOPROTOOPT */
2034 case SO_DEBUG:
2035 case SO_DONTROUTE:
2036 case SO_BROADCAST:
2037 case SO_SNDBUF:
2038 case SO_RCVBUF:
2039 case SO_REUSEADDR:
2040 case SO_REUSEPORT:
2041 case SO_KEEPALIVE:
2042 case SO_TYPE:
2043 case SO_PROTOCOL:
2044 case SO_DOMAIN:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002045 case SO_OOBINLINE:
2046 case SO_NO_CHECK:
2047 case SO_PRIORITY:
2048 case SO_LINGER:
2049 case SO_BSDCOMPAT:
2050 case SO_TIMESTAMP:
2051 case SO_TIMESTAMPNS:
2052 case SO_TIMESTAMPING:
2053 case SO_RCVTIMEO:
2054 case SO_SNDTIMEO:
2055 case SO_RCVLOWAT:
2056 case SO_SNDLOWAT:
2057 case SO_PASSCRED:
2058 case SO_PEERCRED:
2059 case SO_PEERNAME:
2060 case SO_ACCEPTCONN:
2061 case SO_PASSSEC:
2062 case SO_PEERSEC:
2063 case SO_MARK:
2064 case SO_RXQ_OVFL:
2065 case SO_WIFI_STATUS:
2066 case SO_PEEK_OFF:
2067 case SO_NOFCS:
2068 case SO_BINDTODEVICE:
2069 case SO_GET_FILTER:
2070 case SO_LOCK_FILTER:
2071 case SO_BPF_EXTENSIONS:
2072 case SO_SELECT_ERR_QUEUE:
2073#ifdef CONFIG_NET_RX_BUSY_POLL
2074 case SO_BUSY_POLL:
2075#endif
2076 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002077#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002078 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002079#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002080 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2081 if (rv != 0)
2082 {
2083 rv = -errno;
2084 return rv;
2085 }
2086 break;
2087
Stevenac1f96d2017-10-24 16:03:58 -07002088 case SO_ERROR:
2089 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
2090 __optval, __optlen);
2091 break;
2092
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002093 default:
2094 /* We implement the SO_SNDLOWAT etc to not be settable
2095 * (1003.1g 7).
2096 */
2097 return -ENOPROTOOPT;
2098 }
2099
2100 break;
2101
2102 default:
2103 /* 1. handle options that are NOT socket level options,
2104 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04002105 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
2106 __optval, __optlen);
2107 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002108 }
2109
2110 return rv;
2111}
2112
2113/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002114static inline int
2115vcom_session_setsockopt (int __sid, int __level, int __optname,
2116 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002117{
Stevenb59f2272017-10-12 17:10:33 -07002118 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002119
Stevenb59f2272017-10-12 17:10:33 -07002120 switch (__level)
2121 {
Stevenbd187a82017-10-13 12:52:28 -07002122 case SOL_TCP:
2123 switch (__optname)
2124 {
2125 case TCP_KEEPIDLE:
2126 rv =
2127 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
2128 break;
2129 case TCP_KEEPINTVL:
2130 rv =
2131 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
2132 break;
2133 default:
2134 break;
2135 }
2136 break;
Stevenb59f2272017-10-12 17:10:33 -07002137 case SOL_IPV6:
2138 switch (__optname)
2139 {
2140 case IPV6_V6ONLY:
2141 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002142 break;
Stevenb59f2272017-10-12 17:10:33 -07002143 default:
Stevenbd187a82017-10-13 12:52:28 -07002144 break;
Stevenb59f2272017-10-12 17:10:33 -07002145 }
2146 break;
2147 case SOL_SOCKET:
2148 switch (__optname)
2149 {
Stevenbd187a82017-10-13 12:52:28 -07002150 case SO_KEEPALIVE:
2151 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
2152 break;
Stevenb59f2272017-10-12 17:10:33 -07002153 case SO_REUSEADDR:
2154 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002155 break;
Stevenb59f2272017-10-12 17:10:33 -07002156 case SO_BROADCAST:
2157 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002158 break;
Stevenb59f2272017-10-12 17:10:33 -07002159 default:
Stevenbd187a82017-10-13 12:52:28 -07002160 break;
Stevenb59f2272017-10-12 17:10:33 -07002161 }
2162 break;
2163 default:
Stevenbd187a82017-10-13 12:52:28 -07002164 break;
Stevenb59f2272017-10-12 17:10:33 -07002165 }
2166
2167 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002168}
2169
2170int
2171vcom_socket_setsockopt (int __fd, int __level, int __optname,
2172 const void *__optval, socklen_t __optlen)
2173{
2174 int rv = -1;
2175 vcom_socket_main_t *vsm = &vcom_socket_main;
2176 uword *p;
2177 vcom_socket_t *vsock;
2178
2179 p = hash_get (vsm->sockidx_by_fd, __fd);
2180 if (!p)
2181 return -EBADF;
2182
2183 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2184 if (!vsock)
2185 return -ENOTSOCK;
2186
2187 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2188 return -EINVAL;
2189
2190 /*
2191 * Options without arguments
2192 */
2193
2194 if (__optname == SO_BINDTODEVICE)
2195 {
2196 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2197 if (rv != 0)
2198 {
2199 rv = -errno;
2200 }
2201 return rv;
2202 }
2203
2204 if (!__optval)
2205 return -EFAULT;
2206
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002207 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002208 return -EINVAL;
2209
2210 switch (__level)
2211 {
Stevenb59f2272017-10-12 17:10:33 -07002212 case SOL_IPV6:
2213 switch (__optname)
2214 {
2215 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04002216 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2217 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002218 break;
Stevenb59f2272017-10-12 17:10:33 -07002219 default:
2220 return -EOPNOTSUPP;
2221 }
2222 break;
2223 case SOL_TCP:
2224 switch (__optname)
2225 {
2226 case TCP_NODELAY:
2227 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002228 case TCP_KEEPIDLE:
2229 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04002230 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2231 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002232 break;
Stevenb59f2272017-10-12 17:10:33 -07002233 default:
2234 return -EOPNOTSUPP;
2235 }
2236 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002237 /* handle options at socket level */
2238 case SOL_SOCKET:
2239 switch (__optname)
2240 {
Stevenb59f2272017-10-12 17:10:33 -07002241 case SO_REUSEADDR:
2242 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002243 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04002244 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2245 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002246 break;
Stevenb59f2272017-10-12 17:10:33 -07002247
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002248 /*
2249 * 1. for socket level options that are socket attributes,
2250 * set it from libc_getsockopt
2251 * 2. for socket level options that are NOT socket
2252 * attributes and that has corresponding vpp options
2253 * set it from vppcom
2254 * 3. for socket level options unimplemented
2255 * return -ENOPROTOOPT */
2256 case SO_DEBUG:
2257 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002258 case SO_SNDBUF:
2259 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002260 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002261 case SO_TYPE:
2262 case SO_PROTOCOL:
2263 case SO_DOMAIN:
2264 case SO_ERROR:
2265 case SO_OOBINLINE:
2266 case SO_NO_CHECK:
2267 case SO_PRIORITY:
2268 case SO_LINGER:
2269 case SO_BSDCOMPAT:
2270 case SO_TIMESTAMP:
2271 case SO_TIMESTAMPNS:
2272 case SO_TIMESTAMPING:
2273 case SO_RCVTIMEO:
2274 case SO_SNDTIMEO:
2275 case SO_RCVLOWAT:
2276 case SO_SNDLOWAT:
2277 case SO_PASSCRED:
2278 case SO_PEERCRED:
2279 case SO_PEERNAME:
2280 case SO_ACCEPTCONN:
2281 case SO_PASSSEC:
2282 case SO_PEERSEC:
2283 case SO_MARK:
2284 case SO_RXQ_OVFL:
2285 case SO_WIFI_STATUS:
2286 case SO_PEEK_OFF:
2287 case SO_NOFCS:
2288 /*
2289 * SO_BINDTODEVICE already handled as
2290 * "Options without arguments" */
2291 /* case SO_BINDTODEVICE: */
2292 case SO_GET_FILTER:
2293 case SO_LOCK_FILTER:
2294 case SO_BPF_EXTENSIONS:
2295 case SO_SELECT_ERR_QUEUE:
2296#ifdef CONFIG_NET_RX_BUSY_POLL
2297 case SO_BUSY_POLL:
2298#endif
2299 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002300#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002301 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002302#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002303 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2304 if (rv != 0)
2305 {
2306 rv = -errno;
2307 return rv;
2308 }
2309 break;
2310
2311 default:
2312 /* We implement the SO_SNDLOWAT etc to not be settable
2313 * (1003.1g 7).
2314 */
2315 return -ENOPROTOOPT;
2316 }
2317
2318 break;
2319
2320 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002321 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002322 }
2323
2324 return rv;
2325}
2326
2327int
2328vcom_socket_listen (int __fd, int __n)
2329{
2330 int rv = -1;
2331 vcom_socket_main_t *vsm = &vcom_socket_main;
2332 uword *p;
2333 vcom_socket_t *vsock;
2334
2335 p = hash_get (vsm->sockidx_by_fd, __fd);
2336 if (p)
2337 {
2338 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2339
2340 /* TBD vppcom to accept __n parameter */
2341 rv = vppcom_session_listen (vsock->sid, __n);
2342 }
2343
2344 return rv;
2345}
2346
2347static int
2348vcom_socket_connected_socket (int __fd, int __sid,
2349 int *__domain,
2350 int *__type, int *__protocol, int flags)
2351{
2352 int rv = -1;
2353 vcom_socket_main_t *vsm = &vcom_socket_main;
2354 vcom_socket_t *vsock;
2355
2356 i32 fd;
2357 i32 sockidx;
2358
2359 socklen_t optlen;
2360
2361 optlen = sizeof (*__domain);
2362 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2363 if (rv != 0)
2364 {
2365 rv = -errno;
2366 goto out;
2367 }
2368
2369 optlen = sizeof (*__type);
2370 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2371 if (rv != 0)
2372 {
2373 rv = -errno;
2374 goto out;
2375 }
2376
2377 optlen = sizeof (*__protocol);
2378 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2379 if (rv != 0)
2380 {
2381 rv = -errno;
2382 goto out;
2383 }
2384
2385 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2386 if (fd < 0)
2387 {
2388 rv = fd;
2389 goto out;
2390 }
2391
2392 pool_get (vsm->vsockets, vsock);
2393 vsocket_init (vsock);
2394
2395 sockidx = vsock - vsm->vsockets;
2396 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2397
2398 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2399 return fd;
2400
2401out:
2402 return rv;
2403}
2404
2405/* If flag is 0, then accept4() is the same as accept().
2406 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2407 */
2408static int
2409vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2410 socklen_t * __restrict __addr_len, int flags)
2411{
2412 int rv = -1;
2413 vcom_socket_main_t *vsm = &vcom_socket_main;
2414 uword *p;
2415 vcom_socket_t *vsock;
2416
2417 int fd;
2418 int sid;
2419 int domain;
2420 int type;
2421 int protocol;
2422
2423 uint8_t addr8[sizeof (struct in6_addr)];
2424 vppcom_endpt_t ep;
2425
2426 ep.ip = addr8;
2427
2428 /* validate flags */
2429
2430 /*
2431 * for documentation
2432 * switch (flags)
2433 * {
2434 * case 0:
2435 * case SOCK_NONBLOCK:
2436 * case SOCK_CLOEXEC:
2437 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2438 * break;
2439 *
2440 * default:
2441 * return -1;
2442 * }
2443 */
2444 /* flags can be 0 or can be bitwise OR
2445 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2446
Dave Wallace59179392017-11-07 02:20:07 -05002447 if (VCOM_DEBUG > 2)
2448 fprintf (stderr, "[%d] vcom_socket_accept_flags: "
2449 "fd = %d, __addr = %p, __addr_len = %p flags = %d (0x%x)\n",
2450 getpid (), __fd, __addr, __addr_len, flags, flags);
2451
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002452 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2453 {
2454 /* TBD: return proper error code */
Dave Wallace59179392017-11-07 02:20:07 -05002455 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2456 "invalid flags = %d (0x%x)\n", getpid (), flags, flags);
2457
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002458 return -1;
2459 }
2460
2461 /* TBD: return proper error code */
2462
2463 if (!vcom_socket_is_connection_mode_socket (__fd))
2464 {
Dave Wallace59179392017-11-07 02:20:07 -05002465 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2466 "connection mode socket support TBD!\n", getpid ());
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002467 return -EOPNOTSUPP;
2468 }
2469
2470 p = hash_get (vsm->sockidx_by_fd, __fd);
2471 if (p)
2472 {
2473 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2474
2475
2476 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2477 if (rv < 0)
2478 {
Dave Wallace59179392017-11-07 02:20:07 -05002479 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2480 "vcom_fcnt() returned %d!\n", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002481 return rv;
2482 }
2483
2484 /* is blocking */
2485 if (!(rv & O_NONBLOCK))
2486 {
2487 /* socket is not marked as nonblocking
2488 * and no pending connections are present
2489 * on the queue, accept () blocks the caller
2490 * until a connection is present.
2491 */
Dave Wallace227867f2017-11-13 21:21:53 -05002492 rv = vppcom_session_accept (vsock->sid, &ep, flags,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002493 -1.0 /* wait forever */ );
2494 }
2495 else
2496 {
2497 /* The file descriptor refers to a socket and has been
2498 * marked nonblocking(O_NONBLOCK) and the accept would
2499 * block.
2500 * */
2501 /* is non blocking */
Dave Wallace227867f2017-11-13 21:21:53 -05002502 rv = vppcom_session_accept (vsock->sid, &ep, flags, 0);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002503 /* If the socket is marked nonblocking and
2504 * no pending connections are present on the
2505 * queue, accept fails with the error
2506 * EAGAIN or EWOULDBLOCK
2507 */
2508 if (rv == VPPCOM_ETIMEDOUT)
2509 {
2510 rv = VPPCOM_EAGAIN;
2511 }
2512 }
2513 if (rv < 0)
2514 {
Dave Wallace59179392017-11-07 02:20:07 -05002515 if (rv != VPPCOM_EAGAIN)
2516 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2517 "vppcom_session_accept() returned %d!", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002518 return rv;
2519 }
2520
2521 sid = rv;
2522
2523 /* create a new connected socket resource and set flags
2524 * on the new file descriptor.
2525 * update vsockets and sockidx_by_fd table
2526 * */
2527 fd = vcom_socket_connected_socket (__fd, sid,
2528 &domain, &type, &protocol, flags);
2529 if (fd < 0)
2530 {
Dave Wallace59179392017-11-07 02:20:07 -05002531 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2532 "vcom_socket_connected_socket() returned %d!",
2533 getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002534 return fd;
2535 }
2536
2537 rv = fd;
2538
2539 /* TBD populate __addr and __addr_len */
2540 /* TBD: The returned address is truncated if the buffer
2541 * provided is too small, in this case, __addr_len will
2542 * return a value greater than was supplied to the call.*/
2543 if (__addr)
2544 {
2545 if (ep.is_cut_thru)
2546 {
2547 /* TBD populate __addr and __addr_len */
2548 switch (domain)
2549 {
2550 case AF_INET:
2551 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2552 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2553 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2554 addr8, sizeof (struct in_addr));
2555 /* TBD: populate __addr_len */
2556 if (__addr_len)
2557 {
2558 *__addr_len = sizeof (struct sockaddr_in);
2559 }
2560 break;
2561
2562 case AF_INET6:
2563 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2564 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2565 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2566 __in6_u.__u6_addr8, addr8,
2567 sizeof (struct in6_addr));
2568 /* TBD: populate __addr_len */
2569 if (__addr_len)
2570 {
2571 *__addr_len = sizeof (struct sockaddr_in6);
2572 }
2573 break;
2574
2575 default:
2576 return -EAFNOSUPPORT;
2577 }
2578 }
2579 else
2580 {
2581 switch (ep.is_ip4)
2582 {
2583 case VPPCOM_IS_IP4:
2584 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2585 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2586 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2587 addr8, sizeof (struct in_addr));
2588 /* TBD: populate __addr_len */
2589 if (__addr_len)
2590 {
2591 *__addr_len = sizeof (struct sockaddr_in);
2592 }
2593 break;
2594
2595 case VPPCOM_IS_IP6:
2596 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2597 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2598 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2599 __in6_u.__u6_addr8, addr8,
2600 sizeof (struct in6_addr));
2601 /* TBD: populate __addr_len */
2602 if (__addr_len)
2603 {
2604 *__addr_len = sizeof (struct sockaddr_in6);
2605 }
2606 break;
2607
2608 default:
2609 return -EAFNOSUPPORT;
2610 }
2611 }
2612 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002613 }
2614
2615 return rv;
2616}
2617
2618int
2619vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2620 socklen_t * __restrict __addr_len)
2621{
2622 /* set flags to 0 for accept() */
2623 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2624}
2625
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002626int
2627vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2628 socklen_t * __restrict __addr_len, int __flags)
2629{
2630 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2631 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2632}
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002633
2634/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002635static inline int
2636vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002637{
2638 return 0;
2639}
2640
2641int
2642vcom_socket_shutdown (int __fd, int __how)
2643{
2644 int rv = -1;
2645 vcom_socket_main_t *vsm = &vcom_socket_main;
2646 uword *p;
2647 vcom_socket_t *vsock;
2648
2649 p = hash_get (vsm->sockidx_by_fd, __fd);
2650 if (p)
2651 {
2652 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2653 switch (__how)
2654 {
2655 case SHUT_RD:
2656 case SHUT_WR:
2657 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002658 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002659 return rv;
2660 break;
2661
2662 default:
2663 return -EINVAL;
2664 break;
2665 }
2666 }
2667
2668 return rv;
2669}
2670
2671int
2672vcom_socket_epoll_create1 (int __flags)
2673{
2674 int rv = -1;
2675 vcom_socket_main_t *vsm = &vcom_socket_main;
2676 vcom_epoll_t *vepoll;
2677
2678 i32 epfd;
2679 i32 vep_idx;
2680 i32 epollidx;
2681
2682 epfd = vcom_socket_open_epoll (__flags);
2683 if (epfd < 0)
2684 {
2685 rv = epfd;
2686 goto out;
2687 }
2688
2689 vep_idx = vppcom_epoll_create ();
2690 if (vep_idx < 0)
2691 {
2692 rv = vep_idx;
2693 goto out_close_epoll;
2694 }
2695
2696 pool_get (vsm->vepolls, vepoll);
2697 vepoll_init (vepoll);
2698
2699 epollidx = vepoll - vsm->vepolls;
2700 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2701
2702 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2703
2704 return epfd;
2705
2706out_close_epoll:
2707 vcom_socket_close_epoll (epfd);
2708out:
2709 return rv;
2710}
2711
2712/*
2713 * PRE: vppcom_epoll_ctl() is successful
2714 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2715 */
2716int
2717vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2718 struct epoll_event *__event,
2719 i32 vep_idx, vcom_epoll_t * vepoll,
2720 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2721 int free_vepitem_on_del)
2722{
2723 int rv = -1;
2724 vcom_socket_main_t *vsm = &vcom_socket_main;
2725 vcom_epitem_t *vepitem;
2726
2727 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2728 uword *p;
2729 i32 vepitemidx;
2730
2731 i32 *vepitemidxs = 0;
2732
2733 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2734
2735 i32 vec_idx;
2736
2737 /* perform control operations on the epoll instance */
2738 switch (__op)
2739 {
2740 case EPOLL_CTL_ADD:
2741 /*
2742 * supplied file descriptor is already
2743 * registered with this epoll instance
2744 * */
2745 /* vepitem exists */
2746 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2747 if (p)
2748 {
2749 rv = -EEXIST;
2750 goto out;
2751 }
2752
2753 /* add a new vepitem */
2754 pool_get (vsm->vepitems, vepitem);
2755 vepitem_init (vepitem);
2756
2757 vepitemidx = vepitem - vsm->vepitems;
2758 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2759 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2760
2761 /* update epitemidxs */
2762 /* by_epfd */
2763 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2764 if (!p) /* not exist */
2765 {
2766 vepitemidxs = 0;
2767 vec_add1 (vepitemidxs, vepitemidx);
2768 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2769 }
2770 else /* exists */
2771 {
2772 vepitemidxs = *(i32 **) p;
2773 vec_add1 (vepitemidxs, vepitemidx);
2774 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2775 }
2776 /* update epitemidxs */
2777 /* by_fd */
2778 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2779 if (!p) /* not exist */
2780 {
2781 vepitemidxs = 0;
2782 vec_add1 (vepitemidxs, vepitemidx);
2783 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2784 }
2785 else /* exists */
2786 {
2787 vepitemidxs = *(i32 **) p;
2788 vec_add1 (vepitemidxs, vepitemidx);
2789 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2790 }
2791
2792 /* increment vepoll fd count by 1 */
2793 vepoll->count += 1;
2794
2795 rv = 0;
2796 goto out;
2797 break;
2798
2799 case EPOLL_CTL_MOD:
2800 /*
2801 * supplied file descriptor is not
2802 * registered with this epoll instance
2803 * */
2804 /* vepitem not exist */
2805 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2806 if (!p)
2807 {
2808 rv = -ENOENT;
2809 goto out;
2810 }
2811 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2812 if (vepitem)
2813 {
2814 vepitem->event = *__event;
2815 vepitem->revent = revent;
2816 }
2817
2818 rv = 0;
2819 goto out;
2820 break;
2821
2822 case EPOLL_CTL_DEL:
2823 /*
2824 * supplied file descriptor is not
2825 * registered with this epoll instance
2826 * */
2827 /* vepitem not exist */
2828 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2829 if (!p)
2830 {
2831 rv = -ENOENT;
2832 goto out;
2833 }
2834 vepitemidx = *(i32 *) p;
2835 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2836
2837 /* update epitemidxs */
2838 /* by_epfd */
2839 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2840 if (!p) /* not exist */
2841 {
2842 rv = -ENOENT;
2843 goto out;
2844 }
2845 else /* exists */
2846 {
2847 vepitemidxs = *(i32 **) p;
2848 vec_idx = vec_search (vepitemidxs, vepitemidx);
2849 if (vec_idx != ~0)
2850 {
2851 vec_del1 (vepitemidxs, vec_idx);
2852 if (!vec_len (vepitemidxs))
2853 {
2854 vec_free (vepitemidxs);
2855 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2856 }
2857 }
2858 }
2859
2860 /* update epitemidxs */
2861 /* by_fd */
2862 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2863 if (!p) /* not exist */
2864 {
2865 rv = -ENOENT;
2866 goto out;
2867 }
2868 else /* exists */
2869 {
2870 vepitemidxs = *(i32 **) p;
2871 vec_idx = vec_search (vepitemidxs, vepitemidx);
2872 if (vec_idx != ~0)
2873 {
2874 vec_del1 (vepitemidxs, vec_idx);
2875 if (!vec_len (vepitemidxs))
2876 {
2877 vec_free (vepitemidxs);
2878 hash_unset (vsm->epitemidxs_by_fd, __fd);
2879 }
2880 }
2881 }
2882
2883 /* pool put vepitem */
2884 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2885 if (free_vepitem_on_del)
2886 {
2887 if (!vepitem)
2888 {
2889 rv = -ENOENT;
2890 goto out;
2891 }
2892 vepitem_init (vepitem);
2893 pool_put (vsm->vepitems, vepitem);
2894 }
2895 else
2896 {
2897 if (!vepitem)
2898 {
2899 vepitem_init (vepitem);
2900 }
2901 }
2902
2903 /* decrement vepoll fd count by 1 */
2904 vepoll->count -= 1;
2905
2906 rv = 0;
2907 goto out;
2908 break;
2909
2910 default:
2911 rv = -EINVAL;
2912 goto out;
2913 break;
2914 }
2915
2916out:
2917 return rv;
2918}
2919
2920/*
2921 * PRE: 00. null pointer check on __event
2922 * 01. all other parameters are validated
2923 */
2924
2925static int
2926vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2927 struct epoll_event *__event,
2928 int free_vepitem_on_del)
2929{
2930 int rv = -1;
Dave Wallacee695cb42017-11-02 22:04:42 -04002931 i32 cnt;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002932 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002933 vcom_socket_t *vfd_vsock;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002934 i32 vep_idx;
Dave Wallacee695cb42017-11-02 22:04:42 -04002935 i32 sid;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002936
2937 /* get vep_idx and vepoll */
2938 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2939 if (vep_idx == INVALID_VEP_IDX)
2940 {
2941 return -EBADF;
2942 }
2943
2944 /* get vcom fd type, vfd_id and vfd */
Dave Wallacee695cb42017-11-02 22:04:42 -04002945 sid = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2946 if ((sid != INVALID_SESSION_ID) &&
2947 vcom_socket_type_is_vppcom_bound (vfd_vsock->type))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002948 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002949 rv = vppcom_epoll_ctl (vep_idx, __op, sid, __event);
2950 if (rv == VPPCOM_OK)
2951 {
2952 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2953 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2954 vepoll->count += cnt;
2955 vepoll->vcl_cnt += cnt;
2956 }
2957 if (VCOM_DEBUG > 0)
2958 fprintf (stderr,
2959 "[%d] vcom_socket_epoll_ctl_i: vppcom_epoll_ctl() "
2960 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2961 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002962 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002963 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002964 }
2965 else
2966 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002967 rv = libc_epoll_ctl (__epfd, __op, __fd, __event);
2968 if (rv == 0)
2969 {
2970 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2971 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2972 vepoll->count += cnt;
2973 vepoll->libc_cnt += cnt;
2974 }
2975 if (VCOM_DEBUG > 0)
2976 fprintf (stderr,
2977 "[%d] vcom_socket_epoll_ctl_i: libc_epoll_ctl() "
2978 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2979 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002980 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002981 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002982 }
2983
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002984 return rv;
2985}
2986
2987int
2988vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2989 struct epoll_event *__event)
2990{
2991 int rv = -1;
2992
2993 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2994 return rv;
2995}
2996
2997static int
2998vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2999 struct epoll_event *__event)
3000{
3001 int rv = -1;
3002
3003 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
3004 return rv;
3005}
3006
3007int
3008vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
3009 int __maxevents, int __timeout,
3010 const __sigset_t * __ss)
3011{
Dave Wallacee695cb42017-11-02 22:04:42 -04003012 vcom_socket_main_t *vsm = &vcom_socket_main;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003013 int rv = -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003014 double time_to_wait = (double) 0;
Dave Wallace375e4682017-11-10 15:49:32 -05003015 double timeout, now = 0;
Dave Wallacee695cb42017-11-02 22:04:42 -04003016 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003017 i32 vep_idx;
3018
3019 /* validate __event */
Dave Wallacee695cb42017-11-02 22:04:42 -04003020 if (!__events || (__timeout < -1))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003021 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003022 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05003023 "Bad args __events %p, __timeout %d\n", getpid (),
Dave Wallacee695cb42017-11-02 22:04:42 -04003024 __events, __timeout);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003025 rv = -EFAULT;
3026 goto out;
3027 }
3028
Dave Wallace375e4682017-11-10 15:49:32 -05003029 time_to_wait = ((__timeout >= 0) ? (double) __timeout / (double) 1000 : 0);
Dave Wallacee695cb42017-11-02 22:04:42 -04003030
3031 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
3032 if (vep_idx == INVALID_VEP_IDX)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003033 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003034 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05003035 "Bad epoll fd %d\n", getpid (), __epfd);
Dave Wallacee695cb42017-11-02 22:04:42 -04003036 return -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003037 }
Dave Wallacee695cb42017-11-02 22:04:42 -04003038
3039 if (vepoll->count <= 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003040 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003041 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: No events"
3042 " in epfd!\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05003043 getpid (), vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Dave Wallacee695cb42017-11-02 22:04:42 -04003044 rv = -EINVAL;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003045 goto out;
3046 }
3047
Dave Wallacee695cb42017-11-02 22:04:42 -04003048 if (vepoll->libc_cnt == 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003049 {
Dave Wallace59179392017-11-07 02:20:07 -05003050 if (VCOM_DEBUG > 2)
3051 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, "
Dave Wallace375e4682017-11-10 15:49:32 -05003052 "calling vppcom_epoll_wait() time_to_wait = %f\n",
3053 getpid (), time_to_wait);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003054 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
3055 }
Dave Wallacee695cb42017-11-02 22:04:42 -04003056 else if (vepoll->vcl_cnt == 0)
3057 {
Dave Wallace59179392017-11-07 02:20:07 -05003058 if (VCOM_DEBUG > 2)
3059 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = 0, "
3060 "calling libc_epoll_pwait()\n", getpid ());
Dave Wallacee695cb42017-11-02 22:04:42 -04003061 rv = libc_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
3062 }
3063 else
3064 {
Dave Wallace59179392017-11-07 02:20:07 -05003065 if (VCOM_DEBUG > 2)
3066 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, "
Dave Wallace375e4682017-11-10 15:49:32 -05003067 "libc_cnt = %d -> mixed polling (time_to_wait = %f, "
3068 "__timeout = %d)\n",
3069 getpid (), vepoll->vcl_cnt, vepoll->libc_cnt,
3070 time_to_wait, __timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04003071 timeout = clib_time_now (&vsm->clib_time) + time_to_wait;
3072 do
3073 {
3074 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, 0);
Dave Wallaceee45d412017-11-24 21:44:06 -05003075 if (rv > 0)
Dave Wallacee695cb42017-11-02 22:04:42 -04003076 {
Dave Wallace59179392017-11-07 02:20:07 -05003077 if (VCOM_DEBUG > 2)
3078 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
Dave Wallaceee45d412017-11-24 21:44:06 -05003079 "vppcom_epoll_wait() returned %d\n", getpid (), rv);
Dave Wallacee695cb42017-11-02 22:04:42 -04003080 goto out;
3081 }
Dave Wallaceee45d412017-11-24 21:44:06 -05003082 else if (rv < 0)
Dave Wallacee695cb42017-11-02 22:04:42 -04003083 {
Dave Wallaceee45d412017-11-24 21:44:06 -05003084 if (VCOM_DEBUG > 2)
3085 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
3086 "vppcom_epoll_wait() returned %d\n", getpid (), rv);
3087
3088 goto out;
3089 }
3090 rv = libc_epoll_pwait (__epfd, __events, __maxevents, 1, __ss);
3091 if (rv > 0)
3092 {
3093 if (VCOM_DEBUG > 2)
3094 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
3095 "libc_epoll_pwait() returned %d\n", getpid (), rv);
3096 goto out;
3097 }
3098 else if (rv < 0)
3099 {
3100 int errno_val = errno;
3101 perror ("libc_epoll_wait");
3102 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
3103 "libc_epoll_wait() failed, errno %d\n",
3104 getpid (), errno_val);
Dave Wallacee695cb42017-11-02 22:04:42 -04003105 goto out;
3106 }
Dave Wallace375e4682017-11-10 15:49:32 -05003107 if (__timeout != -1)
3108 now = clib_time_now (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04003109 }
Dave Wallace375e4682017-11-10 15:49:32 -05003110 while (now < timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04003111 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003112out:
3113 return rv;
3114}
3115
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003116static inline void
3117vcom_pollfds_2_selectfds (
3118 /* src */
3119 struct pollfd *__fds, nfds_t __nfds,
3120 /* dest */
3121 int vcom_nfds,
3122 fd_set * __restrict vcom_readfds,
3123 fd_set * __restrict vcom_writefds,
3124 fd_set * __restrict vcom_exceptfds)
3125{
3126 nfds_t fds_idx = 0;
3127
3128 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3129 {
3130 /* ignore negative fds */
3131 if (__fds[fds_idx].fd < 0)
3132 {
3133 continue;
3134 }
3135
3136 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
3137 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
3138
3139 /* requested events */
3140 if (__fds[fds_idx].events)
3141 {
3142 if (__fds[fds_idx].events & POLLIN)
3143 {
3144 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3145 }
3146 if (__fds[fds_idx].events & POLLPRI)
3147 {
3148 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3149 }
3150 if (__fds[fds_idx].events & POLLOUT)
3151 {
3152 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3153 }
3154#if defined __USE_XOPEN || defined __USE_XOPEN2K8
3155 if (__fds[fds_idx].events & POLLRDNORM)
3156 {
3157 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3158 }
3159 if (__fds[fds_idx].events & POLLRDBAND)
3160 {
3161 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3162 }
3163 if (__fds[fds_idx].events & POLLWRNORM)
3164 {
3165 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3166 }
3167 if (__fds[fds_idx].events & POLLWRBAND)
3168 {
3169 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3170 }
3171#endif
3172 }
3173 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3174}
3175
3176static inline void
3177vcom_selectfds_2_pollfds (
3178 /* dest */
3179 struct pollfd *__fds, nfds_t __nfds, int *nfd,
3180 /* src */
3181 int vcom_nfds,
3182 fd_set * __restrict vcom_readfds,
3183 fd_set * __restrict vcom_writefds,
3184 fd_set * __restrict vcom_exceptfds)
3185{
3186 nfds_t fds_idx = 0;
3187
3188
3189 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3190 {
3191 /* ignore negative fds */
3192 if (__fds[fds_idx].fd < 0)
3193 {
3194 __fds[fds_idx].revents = 0;
3195 }
3196
3197 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
3198 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
3199 {
3200 /*
3201 * TBD: for now any select exception
3202 * is flagged as POLLERR
3203 * */
3204 __fds[fds_idx].revents |= POLLERR;
3205 }
3206
3207 /* requested events */
3208 if (__fds[fds_idx].events & POLLIN)
3209 {
3210 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3211 {
3212 __fds[fds_idx].revents |= POLLIN;
3213 }
3214 }
3215 if (__fds[fds_idx].events & POLLPRI)
3216 {
3217 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3218 {
3219 __fds[fds_idx].revents |= POLLIN;
3220 }
3221 }
3222 if (__fds[fds_idx].events & POLLOUT)
3223 {
3224 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3225 {
3226 __fds[fds_idx].revents |= POLLOUT;
3227 }
3228 }
3229#if defined __USE_XOPEN || defined __USE_XOPEN2K8
3230 if (__fds[fds_idx].events & POLLRDNORM)
3231 {
3232 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3233 {
3234 __fds[fds_idx].revents |= POLLRDNORM;
3235 }
3236 }
3237 if (__fds[fds_idx].events & POLLRDBAND)
3238 {
3239 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3240 {
3241 __fds[fds_idx].revents |= POLLRDBAND;
3242 }
3243 }
3244 if (__fds[fds_idx].events & POLLWRNORM)
3245 {
3246 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3247 {
3248 __fds[fds_idx].revents |= POLLWRNORM;
3249 }
3250 }
3251 if (__fds[fds_idx].events & POLLWRBAND)
3252 {
3253 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3254 {
3255 __fds[fds_idx].revents |= POLLWRBAND;
3256 }
3257 }
3258#endif
3259 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3260
3261 /*
3262 * nfd:
3263 * the number of structures which have nonzero revents fields
3264 * (in other words, those descriptors with events or
3265 * errors reported)
3266 * */
3267 *nfd = 0;
3268 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3269 {
3270 /* ignore negative fds */
3271 if (__fds[fds_idx].fd < 0)
3272 {
3273 continue;
3274 }
3275
3276 if (__fds[fds_idx].revents)
3277 {
3278 (*nfd)++;
3279 }
3280 }
3281}
3282
3283/*
3284 * PRE: parameters are validated,
3285 * vcom_socket_poll is always called with __timeout set to zero
3286 * hence returns immediately
3287 *
3288 * ACTION: handle non negative validated vcom fds and ignore rest
3289 */
3290
3291/*
3292 * implements vcom_socket_poll () interface
3293 *
3294 * internally uses vcom_socket_select ()
3295 * to realize the behavior
3296 * */
3297int
3298vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3299 int __timeout)
3300{
3301 int rv;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003302
3303 nfds_t fds_idx = 0;
3304 int nfd = 0;
3305
3306 /* vcom */
3307 int vcom_nfds = 0;
3308 fd_set vcom_readfds;
3309 fd_set vcom_writefds;
3310 fd_set vcom_exceptfds;
3311 int vcom_nfd = -1;
3312 /* invalid max_vcom_fd is -1 */
3313 int max_vcom_fd = -1;
3314
3315 /* __timeout is zero to get ready events and return immediately */
3316 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3317
3318 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003319 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003320 {
3321 rv = -EINVAL;
3322 goto poll_done;
3323 }
3324
3325 /* zero vcom fd sets */
3326 /*
3327 * V vcom fd set
3328 */
3329#define _(V) \
3330 FD_ZERO ((V))
3331
3332 _(&vcom_readfds);
3333 _(&vcom_writefds);
3334 _(&vcom_exceptfds);
3335#undef _
3336
3337 vcom_nfds = 0;
3338 vcom_nfd = -1;
3339
3340
3341 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3342 {
3343 /* ignore negative fds */
3344 if (__fds[fds_idx].fd < 0)
3345 {
3346 continue;
3347 }
3348
3349 /* non negative validated vcom fds */
3350 if (__fds[fds_idx].fd > FD_SETSIZE)
3351 {
3352 rv = -EINVAL;
3353 goto poll_done;
3354 }
3355
3356 /* max_vcom_fd and vcom_nfd */
3357 if (__fds[fds_idx].fd > max_vcom_fd)
3358 {
3359 /* requested events */
3360 if (__fds[fds_idx].events)
3361 {
3362 max_vcom_fd = __fds[fds_idx].fd;
3363 }
3364 }
3365 ++vcom_nfd;
3366 }
3367
3368 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3369
3370 if (!vcom_nfds)
3371 {
3372 rv = vcom_nfds;
3373 goto poll_done;
3374 }
3375
3376 vcom_pollfds_2_selectfds (
3377 /* src */
3378 __fds, __nfds,
3379 /* dest */
3380 vcom_nfds,
3381 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3382
3383 /* select on vcom fds */
3384 vcom_nfd = vcom_socket_select (vcom_nfds,
3385 &vcom_readfds,
3386 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003387 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003388 fprintf (stderr,
3389 "[%d] vcom_socket_select: "
Dave Wallace59179392017-11-07 02:20:07 -05003390 "'%04d'='%04d'\n", getpid (), vcom_nfd, vcom_nfds);
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003391
3392 if (vcom_nfd < 0)
3393 {
3394 rv = vcom_nfd;
3395 goto poll_done;
3396 }
3397
3398 vcom_selectfds_2_pollfds (
3399 /* dest */
3400 __fds, __nfds, &nfd,
3401 /* src */
3402 vcom_nfds,
3403 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3404
3405 rv = nfd;
3406
3407poll_done:
3408 return rv;
3409}
3410
3411/*
3412 * TBD: remove this static function once vppcom
3413 * has an implementation in place
3414 *
3415 * ACTION:
3416 */
3417static int
3418vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3419{
3420 return -EOPNOTSUPP;
3421}
3422
3423int
3424vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3425 int __timeout)
3426{
3427 nfds_t fds_idx = 0;
3428
3429 /* in seconds eg. 3.123456789 seconds */
3430 double time_to_wait = (double) 0;
3431
3432 i32 sid;
3433 i32 vep_idx;
3434
3435 /* replace vcom fd with session idx */
3436 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3437 {
3438 /* ignore negative fds */
3439 if (__fds[fds_idx].fd < 0)
3440 {
3441 continue;
3442 }
3443
3444 /* non negative validated vcom fds */
3445 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3446 if (sid != INVALID_SESSION_ID)
3447 {
3448 __fds[fds_idx].fd = sid;
3449 }
3450 else
3451 {
3452 /* get vep_idx */
3453 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3454 if (vep_idx != INVALID_VEP_IDX)
3455 {
3456 __fds[fds_idx].fd = vep_idx;
3457 }
3458 else
3459 {
3460 return -EBADF;
3461 }
3462 }
3463 }
3464
3465 /* validate __timeout */
3466 if (__timeout > 0)
3467 {
3468 time_to_wait = (double) __timeout / (double) 1000;
3469 }
3470 else if (__timeout == 0)
3471 {
3472 time_to_wait = (double) 0;
3473 }
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003474 else
3475 {
Dave Wallace60f54822017-10-24 20:47:45 -04003476 time_to_wait = ~0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003477 }
3478
3479 return vppcom_poll (__fds, __nfds, time_to_wait);
3480}
3481
3482int
3483vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3484{
3485 /* select an implementation */
3486
3487 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3488 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3489}
3490
3491#ifdef __USE_GNU
3492int
3493vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3494 const struct timespec *__timeout, const __sigset_t * __ss)
3495{
3496 return -EOPNOTSUPP;
3497}
3498#endif
3499
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003500int
3501vcom_socket_main_init (void)
3502{
3503 vcom_socket_main_t *vsm = &vcom_socket_main;
3504
3505 if (VCOM_DEBUG > 0)
3506 printf ("vcom_socket_main_init\n");
3507
3508 if (!vsm->init)
3509 {
3510 /* TBD: define FD_MAXSIZE and use it here */
3511 pool_alloc (vsm->vsockets, FD_SETSIZE);
3512 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3513
3514 pool_alloc (vsm->vepolls, FD_SETSIZE);
3515 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3516
3517 pool_alloc (vsm->vepitems, FD_SETSIZE);
3518 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3519
3520 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3521 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3522
Dave Wallacee695cb42017-11-02 22:04:42 -04003523 clib_time_init (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04003524
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003525 vsm->init = 1;
3526 }
3527
3528 return 0;
3529}
3530
3531
3532void
3533vcom_socket_main_show (void)
3534{
3535 vcom_socket_main_t *vsm = &vcom_socket_main;
3536 vcom_socket_t *vsock;
3537
3538 vcom_epoll_t *vepoll;
3539
3540 vcom_epitem_t *vepitem;
3541
3542 i32 epfd;
3543 i32 fd;
3544 i32 *vepitemidxs, *vepitemidxs_var;
3545
3546 if (vsm->init)
3547 {
3548 /* from active list of vsockets show vsock */
3549
3550 /* *INDENT-OFF* */
3551 pool_foreach (vsock, vsm->vsockets,
3552 ({
3553 printf(
3554 "fd='%04d', sid='%08x',type='%-30s'\n",
3555 vsock->fd, vsock->sid,
3556 vcom_socket_type_str (vsock->type));
3557 }));
3558 /* *INDENT-ON* */
3559
3560 /* from active list of vepolls, show vepoll */
3561
3562 /* *INDENT-OFF* */
3563 pool_foreach (vepoll, vsm->vepolls,
3564 ({
3565 printf(
3566 "epfd='%04d', vep_idx='%08x', "
3567 "type='%-30s', "
3568 "flags='%d', count='%d', close='%d'\n",
3569 vepoll->epfd, vepoll->vep_idx,
3570 vcom_socket_epoll_type_str (vepoll->type),
3571 vepoll->flags, vepoll->count, vepoll->close);
3572 }));
3573 /* *INDENT-ON* */
3574
3575 /* from active list of vepitems, show vepitem */
3576
3577 /* *INDENT-OFF* */
3578 pool_foreach (vepitem, vsm->vepitems,
3579 ({
3580 printf(
3581 "epfd='%04d', fd='%04d', "
3582 "next_fd='%04d', prev_fd='%04d', "
3583 "type='%-30s', "
3584 "events='%04x', revents='%04x'\n",
3585 vepitem->epfd, vepitem->fd,
3586 vepitem->next_fd, vepitem->prev_fd,
3587 vcom_socket_vcom_fd_type_str (vepitem->type),
3588 vepitem->event.events, vepitem->revent.events);
3589 }));
3590
3591 /* *INDENT-ON* */
3592
3593 /* show epitemidxs for epfd */
3594 /* *INDENT-OFF* */
3595 hash_foreach (epfd, vepitemidxs,
3596 vsm->epitemidxs_by_epfd,
3597 ({
3598 printf("\n[ '%04d': ", epfd);
3599 vec_foreach (vepitemidxs_var,vepitemidxs)
3600 {
3601 printf("'%04d' ", (int)vepitemidxs_var[0]);
3602 }
3603 printf("]\n");
3604 }));
3605 /* *INDENT-ON* */
3606
3607 /* show epitemidxs for fd */
3608 /* *INDENT-OFF* */
3609 hash_foreach (fd, vepitemidxs,
3610 vsm->epitemidxs_by_fd,
3611 ({
3612 printf("\n{ '%04d': ", fd);
3613 vec_foreach (vepitemidxs_var,vepitemidxs)
3614 {
3615 printf("'%04d' ", (int)vepitemidxs_var[0]);
3616 }
3617 printf("}\n");
3618 }));
3619 /* *INDENT-ON* */
3620
3621 }
3622}
3623
3624void
3625vcom_socket_main_destroy (void)
3626{
3627 vcom_socket_main_t *vsm = &vcom_socket_main;
3628 vcom_socket_t *vsock;
3629
3630 vcom_epoll_t *vepoll;
3631
3632 vcom_epitem_t *vepitem;
3633
3634 i32 epfd;
3635 i32 fd;
3636 i32 *vepitemidxs;
3637
3638
3639 if (VCOM_DEBUG > 0)
3640 printf ("vcom_socket_main_destroy\n");
3641
3642 if (vsm->init)
3643 {
3644
3645 /*
3646 * from active list of vepitems,
3647 * remove all "vepitem" elements from the pool in a safe way
3648 * */
3649
3650 /* *INDENT-OFF* */
3651 pool_flush (vepitem, vsm->vepitems,
3652 ({
Dave Wallace60f54822017-10-24 20:47:45 -04003653 if ((vepitem->type == FD_TYPE_EPOLL) ||
3654 (vepitem->type == FD_TYPE_VCOM_SOCKET))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003655 {
Dave Wallace60f54822017-10-24 20:47:45 -04003656 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003657 vepitem->fd, NULL);
3658 vepitem_init (vepitem);
3659 }
3660 }));
3661 /* *INDENT-ON* */
3662
3663 pool_free (vsm->vepitems);
3664 hash_free (vsm->epitemidx_by_epfdfd);
3665
3666 /* free vepitemidxs for each epfd */
3667 /* *INDENT-OFF* */
3668 hash_foreach (epfd, vepitemidxs,
3669 vsm->epitemidxs_by_epfd,
3670 ({
3671 vec_free (vepitemidxs);
3672 }));
3673 /* *INDENT-ON* */
3674 hash_free (vsm->epitemidxs_by_epfd);
3675
3676 /* free vepitemidxs for each fd */
3677 /* *INDENT-OFF* */
3678 hash_foreach (fd, vepitemidxs,
3679 vsm->epitemidxs_by_fd,
3680 ({
3681 vec_free (vepitemidxs);
3682 }));
3683 /* *INDENT-ON* */
3684 hash_free (vsm->epitemidxs_by_fd);
3685
3686
3687 /*
3688 * from active list of vsockets,
3689 * close socket and vppcom session
3690 * */
3691
3692 /* *INDENT-OFF* */
3693 pool_foreach (vsock, vsm->vsockets,
3694 ({
3695 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3696 {
3697 vppcom_session_close (vsock->sid);
3698 vcom_socket_close_socket (vsock->fd);
3699 vsocket_init (vsock);
3700 }
3701 }));
3702 /* *INDENT-ON* */
3703
3704 /*
3705 * return vsocket element to the pool
3706 * */
3707
3708 /* *INDENT-OFF* */
3709 pool_flush (vsock, vsm->vsockets,
3710 ({
3711 // vsocket_init(vsock);
3712 ;
3713 }));
3714 /* *INDENT-ON* */
3715
3716 pool_free (vsm->vsockets);
3717 hash_free (vsm->sockidx_by_fd);
3718
3719 /*
3720 * from active list of vepolls,
3721 * close epoll and vppcom_epoll
3722 * */
3723
3724 /* *INDENT-OFF* */
3725 pool_foreach (vepoll, vsm->vepolls,
3726 ({
3727 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3728 {
3729 vppcom_session_close (vepoll->vep_idx);
3730 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3731 vepoll_init (vepoll);
3732 }
3733 }));
3734 /* *INDENT-ON* */
3735
3736 /*
3737 * return vepoll element to the pool
3738 * */
3739
3740 /* *INDENT-OFF* */
3741 pool_flush (vepoll, vsm->vepolls,
3742 ({
3743 // vepoll_init(vepoll);
3744 ;
3745 }));
3746 /* *INDENT-ON* */
3747
3748 pool_free (vsm->vepolls);
3749 hash_free (vsm->epollidx_by_epfd);
3750
3751 vsm->init = 0;
3752 }
3753}
3754
3755
3756/*
3757 * fd.io coding-style-patch-verification: ON
3758 *
3759 * Local Variables:
3760 * eval: (c-set-style "gnu")
3761 * End:
3762 */