blob: 6450eddc8958a326187ffcf2ede2df0294ec7af3 [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 {
1560 bytes_to_read = vppcom_session_attr (out_sid,
1561 VPPCOM_ATTR_GET_NWRITE, 0, 0);
1562 if (VCOM_DEBUG > 2)
1563 clib_warning ("[%d] results %ld, n_bytes_left %lu, "
1564 "bytes_to_read %lu", getpid (), results,
1565 n_bytes_left, bytes_to_read);
1566 if (bytes_to_read == 0)
1567 {
1568 u32 flags, flags_len = sizeof (flags);
1569 rv = vppcom_session_attr (out_sid, VPPCOM_ATTR_GET_FLAGS, &flags,
1570 &flags_len);
1571 ASSERT (rv == VPPCOM_OK);
1572
1573 if (flags & O_NONBLOCK)
1574 {
1575 if (!results)
1576 {
1577 if (VCOM_DEBUG > 2)
1578 clib_warning ("[%d] EAGAIN", getpid ());
1579 eagain = 1;
1580 }
1581 goto update_offset;
1582 }
1583 else
1584 continue;
1585 }
1586 bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1587 vec_validate (vsm->io_buffer, bytes_to_read);
1588 nbytes = libc_read (__in_fd, vsm->io_buffer, bytes_to_read);
1589 if (nbytes < 0)
1590 {
1591 errno_val = errno;
1592 perror ("read()");
1593 clib_warning ("[%d] ERROR: libc_read (__in_fd (%d), "
1594 "io_buffer %p, bytes_to_read %lu) returned "
1595 "errno %d",
1596 getpid (), __in_fd, vsm->io_buffer,
1597 bytes_to_read, errno_val);
1598 if (results == 0)
1599 {
1600 vec_reset_length (vsm->io_buffer);
1601 return -errno_val;
1602 }
1603 goto update_offset;
1604 }
1605 rv = vppcom_session_write (out_sid, vsm->io_buffer, nbytes);
1606 if (rv < 0)
1607 {
1608 clib_warning ("[%d] ERROR: vppcom_session_write ("
1609 "out_sid %u, io_buffer %p, nbytes %d) returned %d",
1610 getpid (), out_sid, vsm->io_buffer, nbytes, rv);
1611 if (results == 0)
1612 {
1613 vec_reset_length (vsm->io_buffer);
1614 return rv;
1615 }
1616 goto update_offset;
1617 }
1618
1619 results += nbytes;
1620 ASSERT (n_bytes_left >= nbytes);
1621 n_bytes_left = n_bytes_left - nbytes;
1622 }
1623 while (n_bytes_left > 0);
1624
1625update_offset:
1626 if (__offset)
1627 {
1628 off_t offset = lseek (__in_fd, *__offset, SEEK_SET);
1629 if (offset == -1)
1630 {
1631 errno_val = errno;
1632 perror ("lseek()");
1633 clib_warning ("[%d] ERROR: lseek (__in_fd %d, __offset %p "
1634 "(%ld), SEEK_SET) returned errno %d",
1635 getpid (), __in_fd, __offset, *__offset, errno_val);
1636 vec_reset_length (vsm->io_buffer);
1637 return -errno_val;
1638 }
1639
1640 *__offset += results + 1;
1641 }
1642
1643 vec_reset_length (vsm->io_buffer);
1644 return eagain ? -EAGAIN : results;
1645}
1646
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001647ssize_t
1648vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1649{
1650 int rv = -1;
1651 rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1652 return rv;
1653}
1654
1655/*
1656 * RETURN 1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1657 * 0 otherwise
1658 * */
1659int
1660vcom_socket_is_connection_mode_socket (int __fd)
1661{
1662 int rv = -1;
1663 /* TBD define new vppcom api */
1664 vcom_socket_main_t *vsm = &vcom_socket_main;
1665 uword *p;
1666 vcom_socket_t *vsock;
1667
1668 int type;
1669 socklen_t optlen;
1670
1671 p = hash_get (vsm->sockidx_by_fd, __fd);
1672
1673 if (p)
1674 {
1675 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1676 if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1677 {
1678 optlen = sizeof (type);
1679 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1680 if (rv != 0)
1681 {
1682 return 0;
1683 }
1684 /* get socket type */
1685 switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1686 {
1687 case SOCK_STREAM:
1688 case SOCK_SEQPACKET:
1689 return 1;
1690 break;
1691
1692 default:
1693 return 0;
1694 break;
1695 }
1696 }
1697 }
1698 return 0;
1699}
1700
Dave Wallacee22aa742017-10-20 12:30:38 -04001701static inline ssize_t
1702vcom_session_sendto (int __sid, void *__buf, size_t __n,
1703 int __flags, __CONST_SOCKADDR_ARG __addr,
1704 socklen_t __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001705{
Dave Wallace617dffa2017-10-26 14:47:06 -04001706 vppcom_endpt_t *ep = 0;
Steven8aa0d782017-10-27 09:34:57 -07001707 vppcom_endpt_t _ep;
Stevenac1f96d2017-10-24 16:03:58 -07001708
Dave Wallace617dffa2017-10-26 14:47:06 -04001709 if (__addr)
Stevenac1f96d2017-10-24 16:03:58 -07001710 {
Dave Wallace617dffa2017-10-26 14:47:06 -04001711 ep = &_ep;
1712 ep->vrf = VPPCOM_VRF_DEFAULT;
1713 switch (__addr->sa_family)
1714 {
1715 case AF_INET:
1716 ep->is_ip4 = VPPCOM_IS_IP4;
1717 ep->ip =
1718 (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1719 ep->port =
1720 (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1721 break;
Stevenac1f96d2017-10-24 16:03:58 -07001722
Dave Wallace617dffa2017-10-26 14:47:06 -04001723 case AF_INET6:
1724 ep->is_ip4 = VPPCOM_IS_IP6;
1725 ep->ip =
1726 (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1727 ep->port =
1728 (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1729 break;
1730
1731 default:
1732 return -EAFNOSUPPORT;
1733 }
Stevenac1f96d2017-10-24 16:03:58 -07001734 }
1735
Dave Wallace617dffa2017-10-26 14:47:06 -04001736 return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001737}
1738
1739ssize_t
1740vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1741 int __flags, __CONST_SOCKADDR_ARG __addr,
1742 socklen_t __addr_len)
1743{
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001744 vcom_socket_main_t *vsm = &vcom_socket_main;
1745 uword *p;
1746 vcom_socket_t *vsock;
1747
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001748 if (!__buf)
1749 {
1750 return -EINVAL;
1751 }
1752
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001753 p = hash_get (vsm->sockidx_by_fd, __fd);
1754 if (!p)
1755 return -EBADF;
1756
1757 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1758 if (!vsock)
1759 return -ENOTSOCK;
1760
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001761 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001762 {
1763 return -EINVAL;
1764 }
1765
1766 if (vcom_socket_is_connection_mode_socket (__fd))
1767 {
1768 /* ignore __addr and _addr_len */
1769 /* and EISCONN may be returned when they are not NULL and 0 */
1770 if ((__addr != NULL) || (__addr_len != 0))
1771 {
1772 return -EISCONN;
1773 }
1774 }
1775 else
1776 {
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001777 if (!__addr)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001778 {
1779 return -EDESTADDRREQ;
1780 }
1781 /* not a vppcom supported address family */
Dave Wallace60f54822017-10-24 20:47:45 -04001782 if (!((__addr->sa_family == AF_INET) ||
1783 (__addr->sa_family == AF_INET6)))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001784 {
1785 return -EINVAL;
1786 }
1787 }
1788
Dave Wallace617dffa2017-10-26 14:47:06 -04001789 return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1790 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001791}
1792
Dave Wallacee22aa742017-10-20 12:30:38 -04001793static inline ssize_t
1794vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1795 int __flags, __SOCKADDR_ARG __addr,
1796 socklen_t * __restrict __addr_len)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001797{
Stevenac1f96d2017-10-24 16:03:58 -07001798 int rv;
1799 vppcom_endpt_t ep;
Dave Wallacefaf9d772017-10-26 16:12:04 -04001800 u8 src_addr[sizeof (struct sockaddr_in6)];
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001801
Stevenac1f96d2017-10-24 16:03:58 -07001802 if (__addr)
1803 {
Dave Wallacefaf9d772017-10-26 16:12:04 -04001804 ep.ip = src_addr;
Stevenac1f96d2017-10-24 16:03:58 -07001805 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1806
1807 if (rv > 0)
Steven0cdd5bd2017-11-08 14:14:45 -08001808 rv = vcom_socket_copy_ep_to_sockaddr (__addr, __addr_len, &ep);
Stevenac1f96d2017-10-24 16:03:58 -07001809 }
1810 else
1811 rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1812
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001813 return rv;
1814}
1815
1816ssize_t
1817vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1818 int __flags, __SOCKADDR_ARG __addr,
1819 socklen_t * __restrict __addr_len)
1820{
1821 int rv = -1;
1822 vcom_socket_main_t *vsm = &vcom_socket_main;
1823 uword *p;
1824 vcom_socket_t *vsock;
1825
Stevenac1f96d2017-10-24 16:03:58 -07001826 if (__addr && !__addr_len)
1827 return -EINVAL;
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001828
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001829 p = hash_get (vsm->sockidx_by_fd, __fd);
1830 if (!p)
1831 return -EBADF;
1832
1833 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1834 if (!vsock)
1835 return -ENOTSOCK;
1836
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04001837 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001838 {
1839 return -EINVAL;
1840 }
1841
Dave Wallacee22aa742017-10-20 12:30:38 -04001842 rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1843 __flags, __addr, __addr_len);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001844 return rv;
1845}
1846
1847/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001848static inline ssize_t
1849vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001850{
1851 int rv = -1;
1852 /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1853 (int)__n); */
1854 return rv;
1855}
1856
1857ssize_t
1858vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1859{
1860 int rv = -1;
1861 vcom_socket_main_t *vsm = &vcom_socket_main;
1862 uword *p;
1863 vcom_socket_t *vsock;
1864
1865 p = hash_get (vsm->sockidx_by_fd, __fd);
1866 if (!p)
1867 return -EBADF;
1868
1869 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1870 if (!vsock)
1871 return -ENOTSOCK;
1872
1873 if (vcom_socket_is_connection_mode_socket (__fd))
1874 {
1875 /* ignore __addr and _addr_len */
1876 /* and EISCONN may be returned when they are not NULL and 0 */
1877 if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1878 {
1879 return -EISCONN;
1880 }
1881 }
1882 else
1883 {
1884 /* TBD: validate __message->msg_name and __message->msg_namelen
1885 * and return -EINVAL on validation error
1886 * */
1887 ;
1888 }
1889
Dave Wallacee22aa742017-10-20 12:30:38 -04001890 rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001891
1892 return rv;
1893}
1894
1895#ifdef __USE_GNU
1896int
1897vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1898 unsigned int __vlen, int __flags)
1899{
1900
1901 /* TBD: define a new vppcom api */
1902 return 0;
1903}
1904#endif
1905
1906/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001907static inline ssize_t
1908vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001909{
1910 int rv = -1;
1911 /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1912 (int)__n); */
1913 rv = -EOPNOTSUPP;
1914 return rv;
1915}
1916
1917ssize_t
1918vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1919{
1920 int rv = -1;
1921 vcom_socket_main_t *vsm = &vcom_socket_main;
1922 uword *p;
1923 vcom_socket_t *vsock;
1924
1925 p = hash_get (vsm->sockidx_by_fd, __fd);
1926 if (!p)
1927 return -EBADF;
1928
1929 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1930 if (!vsock)
1931 return -ENOTSOCK;
1932
1933 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1934 return -EINVAL;
1935
1936 if (!__message)
1937 {
1938 return -EINVAL;
1939 }
1940
1941 /* validate __flags */
1942
Dave Wallacee22aa742017-10-20 12:30:38 -04001943 rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001944 return rv;
1945}
1946
1947#ifdef __USE_GNU
1948int
1949vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1950 unsigned int __vlen, int __flags,
1951 struct timespec *__tmo)
1952{
1953 /* TBD: define a new vppcom api */
1954 return 0;
1955}
1956#endif
1957
1958/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04001959static inline int
1960vcom_session_get_sockopt (int __sid, int __level, int __optname,
1961 void *__restrict __optval,
1962 socklen_t * __restrict __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001963{
Stevenac1f96d2017-10-24 16:03:58 -07001964 int rv = 0;
1965
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001966 /* 1. for socket level options that are NOT socket attributes
1967 * and that has corresponding vpp options get from vppcom */
Stevenac1f96d2017-10-24 16:03:58 -07001968 switch (__level)
1969 {
1970 case SOL_SOCKET:
1971 switch (__optname)
1972 {
1973 case SO_ERROR:
1974 *(int *) __optval = 0;
1975 break;
1976 default:
1977 break;
1978 }
1979 default:
1980 break;
1981 }
1982 /* 2. unhandled options */
1983 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001984}
1985
1986int
1987vcom_socket_getsockopt (int __fd, int __level, int __optname,
1988 void *__restrict __optval,
1989 socklen_t * __restrict __optlen)
1990{
1991 int rv = -1;
1992 vcom_socket_main_t *vsm = &vcom_socket_main;
1993 uword *p;
1994 vcom_socket_t *vsock;
1995
Dave Wallacefaf9d772017-10-26 16:12:04 -04001996 if (!__optval || !__optlen)
1997 return -EINVAL;
1998
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001999 p = hash_get (vsm->sockidx_by_fd, __fd);
2000 if (!p)
2001 return -EBADF;
2002
2003 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2004 if (!vsock)
2005 return -ENOTSOCK;
2006
2007 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2008 return -EINVAL;
2009
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002010 switch (__level)
2011 {
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002012 case SOL_SOCKET:
2013 switch (__optname)
2014 {
2015/*
2016 * 1. for socket level options that are socket attributes,
2017 * get from libc_getsockopt.
2018 * 2. for socket level options that are NOT socket
2019 * attributes and that has corresponding vpp options
2020 * get from vppcom.
2021 * 3. for socket level options unimplemented
2022 * return -ENOPROTOOPT */
2023 case SO_DEBUG:
2024 case SO_DONTROUTE:
2025 case SO_BROADCAST:
2026 case SO_SNDBUF:
2027 case SO_RCVBUF:
2028 case SO_REUSEADDR:
2029 case SO_REUSEPORT:
2030 case SO_KEEPALIVE:
2031 case SO_TYPE:
2032 case SO_PROTOCOL:
2033 case SO_DOMAIN:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002034 case SO_OOBINLINE:
2035 case SO_NO_CHECK:
2036 case SO_PRIORITY:
2037 case SO_LINGER:
2038 case SO_BSDCOMPAT:
2039 case SO_TIMESTAMP:
2040 case SO_TIMESTAMPNS:
2041 case SO_TIMESTAMPING:
2042 case SO_RCVTIMEO:
2043 case SO_SNDTIMEO:
2044 case SO_RCVLOWAT:
2045 case SO_SNDLOWAT:
2046 case SO_PASSCRED:
2047 case SO_PEERCRED:
2048 case SO_PEERNAME:
2049 case SO_ACCEPTCONN:
2050 case SO_PASSSEC:
2051 case SO_PEERSEC:
2052 case SO_MARK:
2053 case SO_RXQ_OVFL:
2054 case SO_WIFI_STATUS:
2055 case SO_PEEK_OFF:
2056 case SO_NOFCS:
2057 case SO_BINDTODEVICE:
2058 case SO_GET_FILTER:
2059 case SO_LOCK_FILTER:
2060 case SO_BPF_EXTENSIONS:
2061 case SO_SELECT_ERR_QUEUE:
2062#ifdef CONFIG_NET_RX_BUSY_POLL
2063 case SO_BUSY_POLL:
2064#endif
2065 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002066#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002067 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002068#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002069 rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2070 if (rv != 0)
2071 {
2072 rv = -errno;
2073 return rv;
2074 }
2075 break;
2076
Stevenac1f96d2017-10-24 16:03:58 -07002077 case SO_ERROR:
2078 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
2079 __optval, __optlen);
2080 break;
2081
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002082 default:
2083 /* We implement the SO_SNDLOWAT etc to not be settable
2084 * (1003.1g 7).
2085 */
2086 return -ENOPROTOOPT;
2087 }
2088
2089 break;
2090
2091 default:
2092 /* 1. handle options that are NOT socket level options,
2093 * but have corresponding vpp otions. */
Dave Wallacee22aa742017-10-20 12:30:38 -04002094 rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
2095 __optval, __optlen);
2096 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002097 }
2098
2099 return rv;
2100}
2101
2102/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002103static inline int
2104vcom_session_setsockopt (int __sid, int __level, int __optname,
2105 const void *__optval, socklen_t __optlen)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002106{
Stevenb59f2272017-10-12 17:10:33 -07002107 int rv = -EOPNOTSUPP;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002108
Stevenb59f2272017-10-12 17:10:33 -07002109 switch (__level)
2110 {
Stevenbd187a82017-10-13 12:52:28 -07002111 case SOL_TCP:
2112 switch (__optname)
2113 {
2114 case TCP_KEEPIDLE:
2115 rv =
2116 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
2117 break;
2118 case TCP_KEEPINTVL:
2119 rv =
2120 vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
2121 break;
2122 default:
2123 break;
2124 }
2125 break;
Stevenb59f2272017-10-12 17:10:33 -07002126 case SOL_IPV6:
2127 switch (__optname)
2128 {
2129 case IPV6_V6ONLY:
2130 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002131 break;
Stevenb59f2272017-10-12 17:10:33 -07002132 default:
Stevenbd187a82017-10-13 12:52:28 -07002133 break;
Stevenb59f2272017-10-12 17:10:33 -07002134 }
2135 break;
2136 case SOL_SOCKET:
2137 switch (__optname)
2138 {
Stevenbd187a82017-10-13 12:52:28 -07002139 case SO_KEEPALIVE:
2140 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
2141 break;
Stevenb59f2272017-10-12 17:10:33 -07002142 case SO_REUSEADDR:
2143 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002144 break;
Stevenb59f2272017-10-12 17:10:33 -07002145 case SO_BROADCAST:
2146 rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
Stevenbd187a82017-10-13 12:52:28 -07002147 break;
Stevenb59f2272017-10-12 17:10:33 -07002148 default:
Stevenbd187a82017-10-13 12:52:28 -07002149 break;
Stevenb59f2272017-10-12 17:10:33 -07002150 }
2151 break;
2152 default:
Stevenbd187a82017-10-13 12:52:28 -07002153 break;
Stevenb59f2272017-10-12 17:10:33 -07002154 }
2155
2156 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002157}
2158
2159int
2160vcom_socket_setsockopt (int __fd, int __level, int __optname,
2161 const void *__optval, socklen_t __optlen)
2162{
2163 int rv = -1;
2164 vcom_socket_main_t *vsm = &vcom_socket_main;
2165 uword *p;
2166 vcom_socket_t *vsock;
2167
2168 p = hash_get (vsm->sockidx_by_fd, __fd);
2169 if (!p)
2170 return -EBADF;
2171
2172 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2173 if (!vsock)
2174 return -ENOTSOCK;
2175
2176 if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2177 return -EINVAL;
2178
2179 /*
2180 * Options without arguments
2181 */
2182
2183 if (__optname == SO_BINDTODEVICE)
2184 {
2185 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2186 if (rv != 0)
2187 {
2188 rv = -errno;
2189 }
2190 return rv;
2191 }
2192
2193 if (!__optval)
2194 return -EFAULT;
2195
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002196 if (__optlen < sizeof (int))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002197 return -EINVAL;
2198
2199 switch (__level)
2200 {
Stevenb59f2272017-10-12 17:10:33 -07002201 case SOL_IPV6:
2202 switch (__optname)
2203 {
2204 case IPV6_V6ONLY:
Dave Wallacee22aa742017-10-20 12:30:38 -04002205 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2206 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002207 break;
Stevenb59f2272017-10-12 17:10:33 -07002208 default:
2209 return -EOPNOTSUPP;
2210 }
2211 break;
2212 case SOL_TCP:
2213 switch (__optname)
2214 {
2215 case TCP_NODELAY:
2216 return 0;
Stevenbd187a82017-10-13 12:52:28 -07002217 case TCP_KEEPIDLE:
2218 case TCP_KEEPINTVL:
Dave Wallacee22aa742017-10-20 12:30:38 -04002219 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2220 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002221 break;
Stevenb59f2272017-10-12 17:10:33 -07002222 default:
2223 return -EOPNOTSUPP;
2224 }
2225 break;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002226 /* handle options at socket level */
2227 case SOL_SOCKET:
2228 switch (__optname)
2229 {
Stevenb59f2272017-10-12 17:10:33 -07002230 case SO_REUSEADDR:
2231 case SO_BROADCAST:
Stevenbd187a82017-10-13 12:52:28 -07002232 case SO_KEEPALIVE:
Dave Wallacee22aa742017-10-20 12:30:38 -04002233 rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2234 __optval, __optlen);
Stevenbd187a82017-10-13 12:52:28 -07002235 break;
Stevenb59f2272017-10-12 17:10:33 -07002236
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002237 /*
2238 * 1. for socket level options that are socket attributes,
2239 * set it from libc_getsockopt
2240 * 2. for socket level options that are NOT socket
2241 * attributes and that has corresponding vpp options
2242 * set it from vppcom
2243 * 3. for socket level options unimplemented
2244 * return -ENOPROTOOPT */
2245 case SO_DEBUG:
2246 case SO_DONTROUTE:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002247 case SO_SNDBUF:
2248 case SO_RCVBUF:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002249 case SO_REUSEPORT:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002250 case SO_TYPE:
2251 case SO_PROTOCOL:
2252 case SO_DOMAIN:
2253 case SO_ERROR:
2254 case SO_OOBINLINE:
2255 case SO_NO_CHECK:
2256 case SO_PRIORITY:
2257 case SO_LINGER:
2258 case SO_BSDCOMPAT:
2259 case SO_TIMESTAMP:
2260 case SO_TIMESTAMPNS:
2261 case SO_TIMESTAMPING:
2262 case SO_RCVTIMEO:
2263 case SO_SNDTIMEO:
2264 case SO_RCVLOWAT:
2265 case SO_SNDLOWAT:
2266 case SO_PASSCRED:
2267 case SO_PEERCRED:
2268 case SO_PEERNAME:
2269 case SO_ACCEPTCONN:
2270 case SO_PASSSEC:
2271 case SO_PEERSEC:
2272 case SO_MARK:
2273 case SO_RXQ_OVFL:
2274 case SO_WIFI_STATUS:
2275 case SO_PEEK_OFF:
2276 case SO_NOFCS:
2277 /*
2278 * SO_BINDTODEVICE already handled as
2279 * "Options without arguments" */
2280 /* case SO_BINDTODEVICE: */
2281 case SO_GET_FILTER:
2282 case SO_LOCK_FILTER:
2283 case SO_BPF_EXTENSIONS:
2284 case SO_SELECT_ERR_QUEUE:
2285#ifdef CONFIG_NET_RX_BUSY_POLL
2286 case SO_BUSY_POLL:
2287#endif
2288 case SO_MAX_PACING_RATE:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002289#ifdef SO_INCOMING_CPU
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002290 case SO_INCOMING_CPU:
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002291#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002292 rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2293 if (rv != 0)
2294 {
2295 rv = -errno;
2296 return rv;
2297 }
2298 break;
2299
2300 default:
2301 /* We implement the SO_SNDLOWAT etc to not be settable
2302 * (1003.1g 7).
2303 */
2304 return -ENOPROTOOPT;
2305 }
2306
2307 break;
2308
2309 default:
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002310 return -ENOPROTOOPT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002311 }
2312
2313 return rv;
2314}
2315
2316int
2317vcom_socket_listen (int __fd, int __n)
2318{
2319 int rv = -1;
2320 vcom_socket_main_t *vsm = &vcom_socket_main;
2321 uword *p;
2322 vcom_socket_t *vsock;
2323
2324 p = hash_get (vsm->sockidx_by_fd, __fd);
2325 if (p)
2326 {
2327 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2328
2329 /* TBD vppcom to accept __n parameter */
2330 rv = vppcom_session_listen (vsock->sid, __n);
2331 }
2332
2333 return rv;
2334}
2335
2336static int
2337vcom_socket_connected_socket (int __fd, int __sid,
2338 int *__domain,
2339 int *__type, int *__protocol, int flags)
2340{
2341 int rv = -1;
2342 vcom_socket_main_t *vsm = &vcom_socket_main;
2343 vcom_socket_t *vsock;
2344
2345 i32 fd;
2346 i32 sockidx;
2347
2348 socklen_t optlen;
2349
2350 optlen = sizeof (*__domain);
2351 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2352 if (rv != 0)
2353 {
2354 rv = -errno;
2355 goto out;
2356 }
2357
2358 optlen = sizeof (*__type);
2359 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2360 if (rv != 0)
2361 {
2362 rv = -errno;
2363 goto out;
2364 }
2365
2366 optlen = sizeof (*__protocol);
2367 rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2368 if (rv != 0)
2369 {
2370 rv = -errno;
2371 goto out;
2372 }
2373
2374 fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2375 if (fd < 0)
2376 {
2377 rv = fd;
2378 goto out;
2379 }
2380
2381 pool_get (vsm->vsockets, vsock);
2382 vsocket_init (vsock);
2383
2384 sockidx = vsock - vsm->vsockets;
2385 hash_set (vsm->sockidx_by_fd, fd, sockidx);
2386
2387 vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2388 return fd;
2389
2390out:
2391 return rv;
2392}
2393
2394/* If flag is 0, then accept4() is the same as accept().
2395 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2396 */
2397static int
2398vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2399 socklen_t * __restrict __addr_len, int flags)
2400{
2401 int rv = -1;
2402 vcom_socket_main_t *vsm = &vcom_socket_main;
2403 uword *p;
2404 vcom_socket_t *vsock;
2405
2406 int fd;
2407 int sid;
2408 int domain;
2409 int type;
2410 int protocol;
2411
2412 uint8_t addr8[sizeof (struct in6_addr)];
2413 vppcom_endpt_t ep;
2414
2415 ep.ip = addr8;
2416
2417 /* validate flags */
2418
2419 /*
2420 * for documentation
2421 * switch (flags)
2422 * {
2423 * case 0:
2424 * case SOCK_NONBLOCK:
2425 * case SOCK_CLOEXEC:
2426 * case SOCK_NONBLOCK | SOCK_CLOEXEC:
2427 * break;
2428 *
2429 * default:
2430 * return -1;
2431 * }
2432 */
2433 /* flags can be 0 or can be bitwise OR
2434 * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2435
Dave Wallace59179392017-11-07 02:20:07 -05002436 if (VCOM_DEBUG > 2)
2437 fprintf (stderr, "[%d] vcom_socket_accept_flags: "
2438 "fd = %d, __addr = %p, __addr_len = %p flags = %d (0x%x)\n",
2439 getpid (), __fd, __addr, __addr_len, flags, flags);
2440
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002441 if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2442 {
2443 /* TBD: return proper error code */
Dave Wallace59179392017-11-07 02:20:07 -05002444 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2445 "invalid flags = %d (0x%x)\n", getpid (), flags, flags);
2446
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002447 return -1;
2448 }
2449
2450 /* TBD: return proper error code */
2451
2452 if (!vcom_socket_is_connection_mode_socket (__fd))
2453 {
Dave Wallace59179392017-11-07 02:20:07 -05002454 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2455 "connection mode socket support TBD!\n", getpid ());
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002456 return -EOPNOTSUPP;
2457 }
2458
2459 p = hash_get (vsm->sockidx_by_fd, __fd);
2460 if (p)
2461 {
2462 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2463
2464
2465 rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2466 if (rv < 0)
2467 {
Dave Wallace59179392017-11-07 02:20:07 -05002468 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2469 "vcom_fcnt() returned %d!\n", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002470 return rv;
2471 }
2472
2473 /* is blocking */
2474 if (!(rv & O_NONBLOCK))
2475 {
2476 /* socket is not marked as nonblocking
2477 * and no pending connections are present
2478 * on the queue, accept () blocks the caller
2479 * until a connection is present.
2480 */
Dave Wallace227867f2017-11-13 21:21:53 -05002481 rv = vppcom_session_accept (vsock->sid, &ep, flags,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002482 -1.0 /* wait forever */ );
2483 }
2484 else
2485 {
2486 /* The file descriptor refers to a socket and has been
2487 * marked nonblocking(O_NONBLOCK) and the accept would
2488 * block.
2489 * */
2490 /* is non blocking */
Dave Wallace227867f2017-11-13 21:21:53 -05002491 rv = vppcom_session_accept (vsock->sid, &ep, flags, 0);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002492 /* If the socket is marked nonblocking and
2493 * no pending connections are present on the
2494 * queue, accept fails with the error
2495 * EAGAIN or EWOULDBLOCK
2496 */
2497 if (rv == VPPCOM_ETIMEDOUT)
2498 {
2499 rv = VPPCOM_EAGAIN;
2500 }
2501 }
2502 if (rv < 0)
2503 {
Dave Wallace59179392017-11-07 02:20:07 -05002504 if (rv != VPPCOM_EAGAIN)
2505 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2506 "vppcom_session_accept() returned %d!", getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002507 return rv;
2508 }
2509
2510 sid = rv;
2511
2512 /* create a new connected socket resource and set flags
2513 * on the new file descriptor.
2514 * update vsockets and sockidx_by_fd table
2515 * */
2516 fd = vcom_socket_connected_socket (__fd, sid,
2517 &domain, &type, &protocol, flags);
2518 if (fd < 0)
2519 {
Dave Wallace59179392017-11-07 02:20:07 -05002520 fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2521 "vcom_socket_connected_socket() returned %d!",
2522 getpid (), rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002523 return fd;
2524 }
2525
2526 rv = fd;
2527
2528 /* TBD populate __addr and __addr_len */
2529 /* TBD: The returned address is truncated if the buffer
2530 * provided is too small, in this case, __addr_len will
2531 * return a value greater than was supplied to the call.*/
2532 if (__addr)
2533 {
2534 if (ep.is_cut_thru)
2535 {
2536 /* TBD populate __addr and __addr_len */
2537 switch (domain)
2538 {
2539 case AF_INET:
2540 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2541 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2542 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2543 addr8, sizeof (struct in_addr));
2544 /* TBD: populate __addr_len */
2545 if (__addr_len)
2546 {
2547 *__addr_len = sizeof (struct sockaddr_in);
2548 }
2549 break;
2550
2551 case AF_INET6:
2552 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2553 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2554 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2555 __in6_u.__u6_addr8, addr8,
2556 sizeof (struct in6_addr));
2557 /* TBD: populate __addr_len */
2558 if (__addr_len)
2559 {
2560 *__addr_len = sizeof (struct sockaddr_in6);
2561 }
2562 break;
2563
2564 default:
2565 return -EAFNOSUPPORT;
2566 }
2567 }
2568 else
2569 {
2570 switch (ep.is_ip4)
2571 {
2572 case VPPCOM_IS_IP4:
2573 ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2574 ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2575 memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2576 addr8, sizeof (struct in_addr));
2577 /* TBD: populate __addr_len */
2578 if (__addr_len)
2579 {
2580 *__addr_len = sizeof (struct sockaddr_in);
2581 }
2582 break;
2583
2584 case VPPCOM_IS_IP6:
2585 ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2586 ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2587 memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2588 __in6_u.__u6_addr8, addr8,
2589 sizeof (struct in6_addr));
2590 /* TBD: populate __addr_len */
2591 if (__addr_len)
2592 {
2593 *__addr_len = sizeof (struct sockaddr_in6);
2594 }
2595 break;
2596
2597 default:
2598 return -EAFNOSUPPORT;
2599 }
2600 }
2601 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002602 }
2603
2604 return rv;
2605}
2606
2607int
2608vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2609 socklen_t * __restrict __addr_len)
2610{
2611 /* set flags to 0 for accept() */
2612 return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2613}
2614
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002615int
2616vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2617 socklen_t * __restrict __addr_len, int __flags)
2618{
2619 /* SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2620 return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2621}
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002622
2623/* TBD: move it to vppcom */
Dave Wallacee22aa742017-10-20 12:30:38 -04002624static inline int
2625vcom_session_shutdown (int __fd, int __how)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002626{
2627 return 0;
2628}
2629
2630int
2631vcom_socket_shutdown (int __fd, int __how)
2632{
2633 int rv = -1;
2634 vcom_socket_main_t *vsm = &vcom_socket_main;
2635 uword *p;
2636 vcom_socket_t *vsock;
2637
2638 p = hash_get (vsm->sockidx_by_fd, __fd);
2639 if (p)
2640 {
2641 vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2642 switch (__how)
2643 {
2644 case SHUT_RD:
2645 case SHUT_WR:
2646 case SHUT_RDWR:
Dave Wallacee22aa742017-10-20 12:30:38 -04002647 rv = vcom_session_shutdown (vsock->sid, __how);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002648 return rv;
2649 break;
2650
2651 default:
2652 return -EINVAL;
2653 break;
2654 }
2655 }
2656
2657 return rv;
2658}
2659
2660int
2661vcom_socket_epoll_create1 (int __flags)
2662{
2663 int rv = -1;
2664 vcom_socket_main_t *vsm = &vcom_socket_main;
2665 vcom_epoll_t *vepoll;
2666
2667 i32 epfd;
2668 i32 vep_idx;
2669 i32 epollidx;
2670
2671 epfd = vcom_socket_open_epoll (__flags);
2672 if (epfd < 0)
2673 {
2674 rv = epfd;
2675 goto out;
2676 }
2677
2678 vep_idx = vppcom_epoll_create ();
2679 if (vep_idx < 0)
2680 {
2681 rv = vep_idx;
2682 goto out_close_epoll;
2683 }
2684
2685 pool_get (vsm->vepolls, vepoll);
2686 vepoll_init (vepoll);
2687
2688 epollidx = vepoll - vsm->vepolls;
2689 hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2690
2691 vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2692
2693 return epfd;
2694
2695out_close_epoll:
2696 vcom_socket_close_epoll (epfd);
2697out:
2698 return rv;
2699}
2700
2701/*
2702 * PRE: vppcom_epoll_ctl() is successful
2703 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2704 */
2705int
2706vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2707 struct epoll_event *__event,
2708 i32 vep_idx, vcom_epoll_t * vepoll,
2709 i32 vfd_id, void *vfd, vcom_fd_type_t type,
2710 int free_vepitem_on_del)
2711{
2712 int rv = -1;
2713 vcom_socket_main_t *vsm = &vcom_socket_main;
2714 vcom_epitem_t *vepitem;
2715
2716 vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2717 uword *p;
2718 i32 vepitemidx;
2719
2720 i32 *vepitemidxs = 0;
2721
2722 struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2723
2724 i32 vec_idx;
2725
2726 /* perform control operations on the epoll instance */
2727 switch (__op)
2728 {
2729 case EPOLL_CTL_ADD:
2730 /*
2731 * supplied file descriptor is already
2732 * registered with this epoll instance
2733 * */
2734 /* vepitem exists */
2735 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2736 if (p)
2737 {
2738 rv = -EEXIST;
2739 goto out;
2740 }
2741
2742 /* add a new vepitem */
2743 pool_get (vsm->vepitems, vepitem);
2744 vepitem_init (vepitem);
2745
2746 vepitemidx = vepitem - vsm->vepitems;
2747 hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2748 vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2749
2750 /* update epitemidxs */
2751 /* by_epfd */
2752 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2753 if (!p) /* not exist */
2754 {
2755 vepitemidxs = 0;
2756 vec_add1 (vepitemidxs, vepitemidx);
2757 hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2758 }
2759 else /* exists */
2760 {
2761 vepitemidxs = *(i32 **) p;
2762 vec_add1 (vepitemidxs, vepitemidx);
2763 hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2764 }
2765 /* update epitemidxs */
2766 /* by_fd */
2767 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2768 if (!p) /* not exist */
2769 {
2770 vepitemidxs = 0;
2771 vec_add1 (vepitemidxs, vepitemidx);
2772 hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2773 }
2774 else /* exists */
2775 {
2776 vepitemidxs = *(i32 **) p;
2777 vec_add1 (vepitemidxs, vepitemidx);
2778 hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2779 }
2780
2781 /* increment vepoll fd count by 1 */
2782 vepoll->count += 1;
2783
2784 rv = 0;
2785 goto out;
2786 break;
2787
2788 case EPOLL_CTL_MOD:
2789 /*
2790 * supplied file descriptor is not
2791 * registered with this epoll instance
2792 * */
2793 /* vepitem not exist */
2794 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2795 if (!p)
2796 {
2797 rv = -ENOENT;
2798 goto out;
2799 }
2800 vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2801 if (vepitem)
2802 {
2803 vepitem->event = *__event;
2804 vepitem->revent = revent;
2805 }
2806
2807 rv = 0;
2808 goto out;
2809 break;
2810
2811 case EPOLL_CTL_DEL:
2812 /*
2813 * supplied file descriptor is not
2814 * registered with this epoll instance
2815 * */
2816 /* vepitem not exist */
2817 p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2818 if (!p)
2819 {
2820 rv = -ENOENT;
2821 goto out;
2822 }
2823 vepitemidx = *(i32 *) p;
2824 hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2825
2826 /* update epitemidxs */
2827 /* by_epfd */
2828 p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2829 if (!p) /* not exist */
2830 {
2831 rv = -ENOENT;
2832 goto out;
2833 }
2834 else /* exists */
2835 {
2836 vepitemidxs = *(i32 **) p;
2837 vec_idx = vec_search (vepitemidxs, vepitemidx);
2838 if (vec_idx != ~0)
2839 {
2840 vec_del1 (vepitemidxs, vec_idx);
2841 if (!vec_len (vepitemidxs))
2842 {
2843 vec_free (vepitemidxs);
2844 hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2845 }
2846 }
2847 }
2848
2849 /* update epitemidxs */
2850 /* by_fd */
2851 p = hash_get (vsm->epitemidxs_by_fd, __fd);
2852 if (!p) /* not exist */
2853 {
2854 rv = -ENOENT;
2855 goto out;
2856 }
2857 else /* exists */
2858 {
2859 vepitemidxs = *(i32 **) p;
2860 vec_idx = vec_search (vepitemidxs, vepitemidx);
2861 if (vec_idx != ~0)
2862 {
2863 vec_del1 (vepitemidxs, vec_idx);
2864 if (!vec_len (vepitemidxs))
2865 {
2866 vec_free (vepitemidxs);
2867 hash_unset (vsm->epitemidxs_by_fd, __fd);
2868 }
2869 }
2870 }
2871
2872 /* pool put vepitem */
2873 vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2874 if (free_vepitem_on_del)
2875 {
2876 if (!vepitem)
2877 {
2878 rv = -ENOENT;
2879 goto out;
2880 }
2881 vepitem_init (vepitem);
2882 pool_put (vsm->vepitems, vepitem);
2883 }
2884 else
2885 {
2886 if (!vepitem)
2887 {
2888 vepitem_init (vepitem);
2889 }
2890 }
2891
2892 /* decrement vepoll fd count by 1 */
2893 vepoll->count -= 1;
2894
2895 rv = 0;
2896 goto out;
2897 break;
2898
2899 default:
2900 rv = -EINVAL;
2901 goto out;
2902 break;
2903 }
2904
2905out:
2906 return rv;
2907}
2908
2909/*
2910 * PRE: 00. null pointer check on __event
2911 * 01. all other parameters are validated
2912 */
2913
2914static int
2915vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2916 struct epoll_event *__event,
2917 int free_vepitem_on_del)
2918{
2919 int rv = -1;
Dave Wallacee695cb42017-11-02 22:04:42 -04002920 i32 cnt;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002921 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002922 vcom_socket_t *vfd_vsock;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002923 i32 vep_idx;
Dave Wallacee695cb42017-11-02 22:04:42 -04002924 i32 sid;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002925
2926 /* get vep_idx and vepoll */
2927 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2928 if (vep_idx == INVALID_VEP_IDX)
2929 {
2930 return -EBADF;
2931 }
2932
2933 /* get vcom fd type, vfd_id and vfd */
Dave Wallacee695cb42017-11-02 22:04:42 -04002934 sid = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2935 if ((sid != INVALID_SESSION_ID) &&
2936 vcom_socket_type_is_vppcom_bound (vfd_vsock->type))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002937 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002938 rv = vppcom_epoll_ctl (vep_idx, __op, sid, __event);
2939 if (rv == VPPCOM_OK)
2940 {
2941 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2942 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2943 vepoll->count += cnt;
2944 vepoll->vcl_cnt += cnt;
2945 }
2946 if (VCOM_DEBUG > 0)
2947 fprintf (stderr,
2948 "[%d] vcom_socket_epoll_ctl_i: vppcom_epoll_ctl() "
2949 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2950 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002951 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002952 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002953 }
2954 else
2955 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002956 rv = libc_epoll_ctl (__epfd, __op, __fd, __event);
2957 if (rv == 0)
2958 {
2959 cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2960 (__op == EPOLL_CTL_DEL) ? -1 : 0);
2961 vepoll->count += cnt;
2962 vepoll->libc_cnt += cnt;
2963 }
2964 if (VCOM_DEBUG > 0)
2965 fprintf (stderr,
2966 "[%d] vcom_socket_epoll_ctl_i: libc_epoll_ctl() "
2967 "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2968 "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05002969 getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
Dave Wallacee695cb42017-11-02 22:04:42 -04002970 vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002971 }
2972
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002973 return rv;
2974}
2975
2976int
2977vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2978 struct epoll_event *__event)
2979{
2980 int rv = -1;
2981
2982 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2983 return rv;
2984}
2985
2986static int
2987vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2988 struct epoll_event *__event)
2989{
2990 int rv = -1;
2991
2992 rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2993 return rv;
2994}
2995
2996int
2997vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2998 int __maxevents, int __timeout,
2999 const __sigset_t * __ss)
3000{
Dave Wallacee695cb42017-11-02 22:04:42 -04003001 vcom_socket_main_t *vsm = &vcom_socket_main;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003002 int rv = -EBADF;
Dave Wallacee695cb42017-11-02 22:04:42 -04003003 int rv2;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003004 double time_to_wait = (double) 0;
Dave Wallace375e4682017-11-10 15:49:32 -05003005 double timeout, now = 0;
Dave Wallacee695cb42017-11-02 22:04:42 -04003006 vcom_epoll_t *vepoll;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003007 i32 vep_idx;
Dave Wallacee695cb42017-11-02 22:04:42 -04003008 static struct epoll_event *libc_ev = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003009
3010 /* validate __event */
Dave Wallacee695cb42017-11-02 22:04:42 -04003011 if (!__events || (__timeout < -1))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003012 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003013 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05003014 "Bad args __events %p, __timeout %d\n", getpid (),
Dave Wallacee695cb42017-11-02 22:04:42 -04003015 __events, __timeout);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003016 rv = -EFAULT;
3017 goto out;
3018 }
3019
Dave Wallace375e4682017-11-10 15:49:32 -05003020 time_to_wait = ((__timeout >= 0) ? (double) __timeout / (double) 1000 : 0);
Dave Wallacee695cb42017-11-02 22:04:42 -04003021
3022 vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
3023 if (vep_idx == INVALID_VEP_IDX)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003024 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003025 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
Dave Wallace59179392017-11-07 02:20:07 -05003026 "Bad epoll fd %d\n", getpid (), __epfd);
Dave Wallacee695cb42017-11-02 22:04:42 -04003027 return -EBADF;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003028 }
Dave Wallacee695cb42017-11-02 22:04:42 -04003029
3030 if (vepoll->count <= 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003031 {
Dave Wallacee695cb42017-11-02 22:04:42 -04003032 fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: No events"
3033 " in epfd!\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05003034 getpid (), vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
Dave Wallacee695cb42017-11-02 22:04:42 -04003035 rv = -EINVAL;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003036 goto out;
3037 }
3038
Dave Wallacee695cb42017-11-02 22:04:42 -04003039 if (vepoll->libc_cnt == 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003040 {
Dave Wallace59179392017-11-07 02:20:07 -05003041 if (VCOM_DEBUG > 2)
3042 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, "
Dave Wallace375e4682017-11-10 15:49:32 -05003043 "calling vppcom_epoll_wait() time_to_wait = %f\n",
3044 getpid (), time_to_wait);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003045 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
3046 }
Dave Wallacee695cb42017-11-02 22:04:42 -04003047 else if (vepoll->vcl_cnt == 0)
3048 {
Dave Wallace59179392017-11-07 02:20:07 -05003049 if (VCOM_DEBUG > 2)
3050 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = 0, "
3051 "calling libc_epoll_pwait()\n", getpid ());
Dave Wallacee695cb42017-11-02 22:04:42 -04003052 rv = libc_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
3053 }
3054 else
3055 {
Dave Wallace59179392017-11-07 02:20:07 -05003056 if (VCOM_DEBUG > 2)
3057 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, "
Dave Wallace375e4682017-11-10 15:49:32 -05003058 "libc_cnt = %d -> mixed polling (time_to_wait = %f, "
3059 "__timeout = %d)\n",
3060 getpid (), vepoll->vcl_cnt, vepoll->libc_cnt,
3061 time_to_wait, __timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04003062 vec_validate (libc_ev, __maxevents);
3063 timeout = clib_time_now (&vsm->clib_time) + time_to_wait;
3064 do
3065 {
3066 rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, 0);
3067 rv2 = libc_epoll_pwait (__epfd, libc_ev, __maxevents, 1, __ss);
Dave Wallace375e4682017-11-10 15:49:32 -05003068 if (VCOM_DEBUG == 666)
3069 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
3070 "rv = %d, rv2 = %d, timeout = %f, now = %f\n",
3071 getpid (), rv, rv2, timeout, now);
Dave Wallacee695cb42017-11-02 22:04:42 -04003072 if ((rv > 0) || (rv2 > 0))
3073 {
Dave Wallace59179392017-11-07 02:20:07 -05003074 if (VCOM_DEBUG > 2)
3075 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
3076 "rv = %d, rv2 = %d\n", getpid (), rv, rv2);
Dave Wallacee695cb42017-11-02 22:04:42 -04003077 int n = __maxevents - rv;
3078 n = rv2 <= n ? rv2 : n;
3079 rv = (rv > 0) ? rv : 0;
3080
3081 clib_memcpy (&__events[rv], libc_ev, n * sizeof (*libc_ev));
3082 rv += rv2;
3083 goto out;
3084 }
3085 else if ((rv < 0) || (rv2 < 0))
3086 {
3087 if (rv < 0)
3088 fprintf (stderr,
3089 "[%d] ERROR: vppcom_epoll_wait() returned %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05003090 getpid (), rv);
Dave Wallacee695cb42017-11-02 22:04:42 -04003091 if (rv2 < 0)
3092 {
3093 fprintf (stderr,
3094 "[%d] ERROR: libc_epoll_wait() failed, errno %d\n",
Dave Wallace59179392017-11-07 02:20:07 -05003095 getpid (), errno);
Dave Wallacee695cb42017-11-02 22:04:42 -04003096 rv = (rv < 0) ? rv : -errno;
3097 }
3098 goto out;
3099 }
Dave Wallace375e4682017-11-10 15:49:32 -05003100 if (__timeout != -1)
3101 now = clib_time_now (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04003102 }
Dave Wallace375e4682017-11-10 15:49:32 -05003103 while (now < timeout);
Dave Wallacee695cb42017-11-02 22:04:42 -04003104 }
3105
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003106out:
Dave Wallacee695cb42017-11-02 22:04:42 -04003107 vec_reset_length (libc_ev);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003108 return rv;
3109}
3110
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003111static inline void
3112vcom_pollfds_2_selectfds (
3113 /* src */
3114 struct pollfd *__fds, nfds_t __nfds,
3115 /* dest */
3116 int vcom_nfds,
3117 fd_set * __restrict vcom_readfds,
3118 fd_set * __restrict vcom_writefds,
3119 fd_set * __restrict vcom_exceptfds)
3120{
3121 nfds_t fds_idx = 0;
3122
3123 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3124 {
3125 /* ignore negative fds */
3126 if (__fds[fds_idx].fd < 0)
3127 {
3128 continue;
3129 }
3130
3131 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
3132 FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
3133
3134 /* requested events */
3135 if (__fds[fds_idx].events)
3136 {
3137 if (__fds[fds_idx].events & POLLIN)
3138 {
3139 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3140 }
3141 if (__fds[fds_idx].events & POLLPRI)
3142 {
3143 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3144 }
3145 if (__fds[fds_idx].events & POLLOUT)
3146 {
3147 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3148 }
3149#if defined __USE_XOPEN || defined __USE_XOPEN2K8
3150 if (__fds[fds_idx].events & POLLRDNORM)
3151 {
3152 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3153 }
3154 if (__fds[fds_idx].events & POLLRDBAND)
3155 {
3156 FD_SET (__fds[fds_idx].fd, vcom_readfds);
3157 }
3158 if (__fds[fds_idx].events & POLLWRNORM)
3159 {
3160 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3161 }
3162 if (__fds[fds_idx].events & POLLWRBAND)
3163 {
3164 FD_SET (__fds[fds_idx].fd, vcom_writefds);
3165 }
3166#endif
3167 }
3168 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3169}
3170
3171static inline void
3172vcom_selectfds_2_pollfds (
3173 /* dest */
3174 struct pollfd *__fds, nfds_t __nfds, int *nfd,
3175 /* src */
3176 int vcom_nfds,
3177 fd_set * __restrict vcom_readfds,
3178 fd_set * __restrict vcom_writefds,
3179 fd_set * __restrict vcom_exceptfds)
3180{
3181 nfds_t fds_idx = 0;
3182
3183
3184 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3185 {
3186 /* ignore negative fds */
3187 if (__fds[fds_idx].fd < 0)
3188 {
3189 __fds[fds_idx].revents = 0;
3190 }
3191
3192 /* for POLLRDHUP, POLLERR, POLLHUP and POLLNVAL */
3193 if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
3194 {
3195 /*
3196 * TBD: for now any select exception
3197 * is flagged as POLLERR
3198 * */
3199 __fds[fds_idx].revents |= POLLERR;
3200 }
3201
3202 /* requested events */
3203 if (__fds[fds_idx].events & POLLIN)
3204 {
3205 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3206 {
3207 __fds[fds_idx].revents |= POLLIN;
3208 }
3209 }
3210 if (__fds[fds_idx].events & POLLPRI)
3211 {
3212 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3213 {
3214 __fds[fds_idx].revents |= POLLIN;
3215 }
3216 }
3217 if (__fds[fds_idx].events & POLLOUT)
3218 {
3219 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3220 {
3221 __fds[fds_idx].revents |= POLLOUT;
3222 }
3223 }
3224#if defined __USE_XOPEN || defined __USE_XOPEN2K8
3225 if (__fds[fds_idx].events & POLLRDNORM)
3226 {
3227 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3228 {
3229 __fds[fds_idx].revents |= POLLRDNORM;
3230 }
3231 }
3232 if (__fds[fds_idx].events & POLLRDBAND)
3233 {
3234 if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3235 {
3236 __fds[fds_idx].revents |= POLLRDBAND;
3237 }
3238 }
3239 if (__fds[fds_idx].events & POLLWRNORM)
3240 {
3241 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3242 {
3243 __fds[fds_idx].revents |= POLLWRNORM;
3244 }
3245 }
3246 if (__fds[fds_idx].events & POLLWRBAND)
3247 {
3248 if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3249 {
3250 __fds[fds_idx].revents |= POLLWRBAND;
3251 }
3252 }
3253#endif
3254 } /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3255
3256 /*
3257 * nfd:
3258 * the number of structures which have nonzero revents fields
3259 * (in other words, those descriptors with events or
3260 * errors reported)
3261 * */
3262 *nfd = 0;
3263 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3264 {
3265 /* ignore negative fds */
3266 if (__fds[fds_idx].fd < 0)
3267 {
3268 continue;
3269 }
3270
3271 if (__fds[fds_idx].revents)
3272 {
3273 (*nfd)++;
3274 }
3275 }
3276}
3277
3278/*
3279 * PRE: parameters are validated,
3280 * vcom_socket_poll is always called with __timeout set to zero
3281 * hence returns immediately
3282 *
3283 * ACTION: handle non negative validated vcom fds and ignore rest
3284 */
3285
3286/*
3287 * implements vcom_socket_poll () interface
3288 *
3289 * internally uses vcom_socket_select ()
3290 * to realize the behavior
3291 * */
3292int
3293vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3294 int __timeout)
3295{
3296 int rv;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003297
3298 nfds_t fds_idx = 0;
3299 int nfd = 0;
3300
3301 /* vcom */
3302 int vcom_nfds = 0;
3303 fd_set vcom_readfds;
3304 fd_set vcom_writefds;
3305 fd_set vcom_exceptfds;
3306 int vcom_nfd = -1;
3307 /* invalid max_vcom_fd is -1 */
3308 int max_vcom_fd = -1;
3309
3310 /* __timeout is zero to get ready events and return immediately */
3311 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3312
3313 /* validate __nfds from select perspective */
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003314 if (__nfds > FD_SETSIZE)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003315 {
3316 rv = -EINVAL;
3317 goto poll_done;
3318 }
3319
3320 /* zero vcom fd sets */
3321 /*
3322 * V vcom fd set
3323 */
3324#define _(V) \
3325 FD_ZERO ((V))
3326
3327 _(&vcom_readfds);
3328 _(&vcom_writefds);
3329 _(&vcom_exceptfds);
3330#undef _
3331
3332 vcom_nfds = 0;
3333 vcom_nfd = -1;
3334
3335
3336 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3337 {
3338 /* ignore negative fds */
3339 if (__fds[fds_idx].fd < 0)
3340 {
3341 continue;
3342 }
3343
3344 /* non negative validated vcom fds */
3345 if (__fds[fds_idx].fd > FD_SETSIZE)
3346 {
3347 rv = -EINVAL;
3348 goto poll_done;
3349 }
3350
3351 /* max_vcom_fd and vcom_nfd */
3352 if (__fds[fds_idx].fd > max_vcom_fd)
3353 {
3354 /* requested events */
3355 if (__fds[fds_idx].events)
3356 {
3357 max_vcom_fd = __fds[fds_idx].fd;
3358 }
3359 }
3360 ++vcom_nfd;
3361 }
3362
3363 vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3364
3365 if (!vcom_nfds)
3366 {
3367 rv = vcom_nfds;
3368 goto poll_done;
3369 }
3370
3371 vcom_pollfds_2_selectfds (
3372 /* src */
3373 __fds, __nfds,
3374 /* dest */
3375 vcom_nfds,
3376 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3377
3378 /* select on vcom fds */
3379 vcom_nfd = vcom_socket_select (vcom_nfds,
3380 &vcom_readfds,
3381 &vcom_writefds, &vcom_exceptfds, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04003382 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003383 fprintf (stderr,
3384 "[%d] vcom_socket_select: "
Dave Wallace59179392017-11-07 02:20:07 -05003385 "'%04d'='%04d'\n", getpid (), vcom_nfd, vcom_nfds);
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003386
3387 if (vcom_nfd < 0)
3388 {
3389 rv = vcom_nfd;
3390 goto poll_done;
3391 }
3392
3393 vcom_selectfds_2_pollfds (
3394 /* dest */
3395 __fds, __nfds, &nfd,
3396 /* src */
3397 vcom_nfds,
3398 &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3399
3400 rv = nfd;
3401
3402poll_done:
3403 return rv;
3404}
3405
3406/*
3407 * TBD: remove this static function once vppcom
3408 * has an implementation in place
3409 *
3410 * ACTION:
3411 */
3412static int
3413vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3414{
3415 return -EOPNOTSUPP;
3416}
3417
3418int
3419vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3420 int __timeout)
3421{
3422 nfds_t fds_idx = 0;
3423
3424 /* in seconds eg. 3.123456789 seconds */
3425 double time_to_wait = (double) 0;
3426
3427 i32 sid;
3428 i32 vep_idx;
3429
3430 /* replace vcom fd with session idx */
3431 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3432 {
3433 /* ignore negative fds */
3434 if (__fds[fds_idx].fd < 0)
3435 {
3436 continue;
3437 }
3438
3439 /* non negative validated vcom fds */
3440 sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3441 if (sid != INVALID_SESSION_ID)
3442 {
3443 __fds[fds_idx].fd = sid;
3444 }
3445 else
3446 {
3447 /* get vep_idx */
3448 vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3449 if (vep_idx != INVALID_VEP_IDX)
3450 {
3451 __fds[fds_idx].fd = vep_idx;
3452 }
3453 else
3454 {
3455 return -EBADF;
3456 }
3457 }
3458 }
3459
3460 /* validate __timeout */
3461 if (__timeout > 0)
3462 {
3463 time_to_wait = (double) __timeout / (double) 1000;
3464 }
3465 else if (__timeout == 0)
3466 {
3467 time_to_wait = (double) 0;
3468 }
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003469 else
3470 {
Dave Wallace60f54822017-10-24 20:47:45 -04003471 time_to_wait = ~0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003472 }
3473
3474 return vppcom_poll (__fds, __nfds, time_to_wait);
3475}
3476
3477int
3478vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3479{
3480 /* select an implementation */
3481
3482 /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3483 return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3484}
3485
3486#ifdef __USE_GNU
3487int
3488vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3489 const struct timespec *__timeout, const __sigset_t * __ss)
3490{
3491 return -EOPNOTSUPP;
3492}
3493#endif
3494
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003495int
3496vcom_socket_main_init (void)
3497{
3498 vcom_socket_main_t *vsm = &vcom_socket_main;
3499
3500 if (VCOM_DEBUG > 0)
3501 printf ("vcom_socket_main_init\n");
3502
3503 if (!vsm->init)
3504 {
3505 /* TBD: define FD_MAXSIZE and use it here */
3506 pool_alloc (vsm->vsockets, FD_SETSIZE);
3507 vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3508
3509 pool_alloc (vsm->vepolls, FD_SETSIZE);
3510 vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3511
3512 pool_alloc (vsm->vepitems, FD_SETSIZE);
3513 vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3514
3515 vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3516 vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3517
Dave Wallacee695cb42017-11-02 22:04:42 -04003518 clib_time_init (&vsm->clib_time);
Dave Wallacee695cb42017-11-02 22:04:42 -04003519
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003520 vsm->init = 1;
3521 }
3522
3523 return 0;
3524}
3525
3526
3527void
3528vcom_socket_main_show (void)
3529{
3530 vcom_socket_main_t *vsm = &vcom_socket_main;
3531 vcom_socket_t *vsock;
3532
3533 vcom_epoll_t *vepoll;
3534
3535 vcom_epitem_t *vepitem;
3536
3537 i32 epfd;
3538 i32 fd;
3539 i32 *vepitemidxs, *vepitemidxs_var;
3540
3541 if (vsm->init)
3542 {
3543 /* from active list of vsockets show vsock */
3544
3545 /* *INDENT-OFF* */
3546 pool_foreach (vsock, vsm->vsockets,
3547 ({
3548 printf(
3549 "fd='%04d', sid='%08x',type='%-30s'\n",
3550 vsock->fd, vsock->sid,
3551 vcom_socket_type_str (vsock->type));
3552 }));
3553 /* *INDENT-ON* */
3554
3555 /* from active list of vepolls, show vepoll */
3556
3557 /* *INDENT-OFF* */
3558 pool_foreach (vepoll, vsm->vepolls,
3559 ({
3560 printf(
3561 "epfd='%04d', vep_idx='%08x', "
3562 "type='%-30s', "
3563 "flags='%d', count='%d', close='%d'\n",
3564 vepoll->epfd, vepoll->vep_idx,
3565 vcom_socket_epoll_type_str (vepoll->type),
3566 vepoll->flags, vepoll->count, vepoll->close);
3567 }));
3568 /* *INDENT-ON* */
3569
3570 /* from active list of vepitems, show vepitem */
3571
3572 /* *INDENT-OFF* */
3573 pool_foreach (vepitem, vsm->vepitems,
3574 ({
3575 printf(
3576 "epfd='%04d', fd='%04d', "
3577 "next_fd='%04d', prev_fd='%04d', "
3578 "type='%-30s', "
3579 "events='%04x', revents='%04x'\n",
3580 vepitem->epfd, vepitem->fd,
3581 vepitem->next_fd, vepitem->prev_fd,
3582 vcom_socket_vcom_fd_type_str (vepitem->type),
3583 vepitem->event.events, vepitem->revent.events);
3584 }));
3585
3586 /* *INDENT-ON* */
3587
3588 /* show epitemidxs for epfd */
3589 /* *INDENT-OFF* */
3590 hash_foreach (epfd, vepitemidxs,
3591 vsm->epitemidxs_by_epfd,
3592 ({
3593 printf("\n[ '%04d': ", epfd);
3594 vec_foreach (vepitemidxs_var,vepitemidxs)
3595 {
3596 printf("'%04d' ", (int)vepitemidxs_var[0]);
3597 }
3598 printf("]\n");
3599 }));
3600 /* *INDENT-ON* */
3601
3602 /* show epitemidxs for fd */
3603 /* *INDENT-OFF* */
3604 hash_foreach (fd, vepitemidxs,
3605 vsm->epitemidxs_by_fd,
3606 ({
3607 printf("\n{ '%04d': ", fd);
3608 vec_foreach (vepitemidxs_var,vepitemidxs)
3609 {
3610 printf("'%04d' ", (int)vepitemidxs_var[0]);
3611 }
3612 printf("}\n");
3613 }));
3614 /* *INDENT-ON* */
3615
3616 }
3617}
3618
3619void
3620vcom_socket_main_destroy (void)
3621{
3622 vcom_socket_main_t *vsm = &vcom_socket_main;
3623 vcom_socket_t *vsock;
3624
3625 vcom_epoll_t *vepoll;
3626
3627 vcom_epitem_t *vepitem;
3628
3629 i32 epfd;
3630 i32 fd;
3631 i32 *vepitemidxs;
3632
3633
3634 if (VCOM_DEBUG > 0)
3635 printf ("vcom_socket_main_destroy\n");
3636
3637 if (vsm->init)
3638 {
3639
3640 /*
3641 * from active list of vepitems,
3642 * remove all "vepitem" elements from the pool in a safe way
3643 * */
3644
3645 /* *INDENT-OFF* */
3646 pool_flush (vepitem, vsm->vepitems,
3647 ({
Dave Wallace60f54822017-10-24 20:47:45 -04003648 if ((vepitem->type == FD_TYPE_EPOLL) ||
3649 (vepitem->type == FD_TYPE_VCOM_SOCKET))
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003650 {
Dave Wallace60f54822017-10-24 20:47:45 -04003651 vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003652 vepitem->fd, NULL);
3653 vepitem_init (vepitem);
3654 }
3655 }));
3656 /* *INDENT-ON* */
3657
3658 pool_free (vsm->vepitems);
3659 hash_free (vsm->epitemidx_by_epfdfd);
3660
3661 /* free vepitemidxs for each epfd */
3662 /* *INDENT-OFF* */
3663 hash_foreach (epfd, vepitemidxs,
3664 vsm->epitemidxs_by_epfd,
3665 ({
3666 vec_free (vepitemidxs);
3667 }));
3668 /* *INDENT-ON* */
3669 hash_free (vsm->epitemidxs_by_epfd);
3670
3671 /* free vepitemidxs for each fd */
3672 /* *INDENT-OFF* */
3673 hash_foreach (fd, vepitemidxs,
3674 vsm->epitemidxs_by_fd,
3675 ({
3676 vec_free (vepitemidxs);
3677 }));
3678 /* *INDENT-ON* */
3679 hash_free (vsm->epitemidxs_by_fd);
3680
3681
3682 /*
3683 * from active list of vsockets,
3684 * close socket and vppcom session
3685 * */
3686
3687 /* *INDENT-OFF* */
3688 pool_foreach (vsock, vsm->vsockets,
3689 ({
3690 if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3691 {
3692 vppcom_session_close (vsock->sid);
3693 vcom_socket_close_socket (vsock->fd);
3694 vsocket_init (vsock);
3695 }
3696 }));
3697 /* *INDENT-ON* */
3698
3699 /*
3700 * return vsocket element to the pool
3701 * */
3702
3703 /* *INDENT-OFF* */
3704 pool_flush (vsock, vsm->vsockets,
3705 ({
3706 // vsocket_init(vsock);
3707 ;
3708 }));
3709 /* *INDENT-ON* */
3710
3711 pool_free (vsm->vsockets);
3712 hash_free (vsm->sockidx_by_fd);
3713
3714 /*
3715 * from active list of vepolls,
3716 * close epoll and vppcom_epoll
3717 * */
3718
3719 /* *INDENT-OFF* */
3720 pool_foreach (vepoll, vsm->vepolls,
3721 ({
3722 if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3723 {
3724 vppcom_session_close (vepoll->vep_idx);
3725 vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3726 vepoll_init (vepoll);
3727 }
3728 }));
3729 /* *INDENT-ON* */
3730
3731 /*
3732 * return vepoll element to the pool
3733 * */
3734
3735 /* *INDENT-OFF* */
3736 pool_flush (vepoll, vsm->vepolls,
3737 ({
3738 // vepoll_init(vepoll);
3739 ;
3740 }));
3741 /* *INDENT-ON* */
3742
3743 pool_free (vsm->vepolls);
3744 hash_free (vsm->epollidx_by_epfd);
3745
3746 vsm->init = 0;
3747 }
3748}
3749
3750
3751/*
3752 * fd.io coding-style-patch-verification: ON
3753 *
3754 * Local Variables:
3755 * eval: (c-set-style "gnu")
3756 * End:
3757 */