blob: 24b8f2985ebd0a8378dff577557dd19caad47ffd [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 <signal.h>
18#include <dlfcn.h>
19#include <pthread.h>
20#include <time.h>
21#include <stdarg.h>
shrinivasan ganapathy1d359632017-10-15 15:46:09 -070022#include <sys/resource.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070023
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040024#include <vcl/vcom_socket_wrapper.h>
25#include <vcl/vcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070026#include <sys/time.h>
27
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040028#include <vcl/vppcom.h>
29#include <vcl/vcom_socket.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070030
31/* GCC have printf type attribute check. */
32#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
33#define PRINTF_ATTRIBUTE(a,b) \
34 __attribute__ ((__format__ (__printf__, a, b)))
35#else
36#define PRINTF_ATTRIBUTE(a,b)
37#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
38
39#define HAVE_CONSTRUCTOR_ATTRIBUTE
40#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
41#define CONSTRUCTOR_ATTRIBUTE \
42 __attribute__ ((constructor))
43#else
44#define CONSTRUCTOR_ATTRIBUTE
45#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
46
47#define HAVE_DESTRUCTOR_ATTRIBUTE
48#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
49#define DESTRUCTOR_ATTRIBUTE \
50 __attribute__ ((destructor))
51#else
52#define DESTRUCTOR_ATTRIBUTE
53#endif
54
55#define HAVE_ADDRESS_SANITIZER_ATTRIBUTE
56#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
57#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE \
58 __attribute__((no_sanitize_address))
59#else
60#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
61#endif
62
63#define VCOM_SOCKET_FD_MAX 0x10000
64
65static char vcom_app_name[MAX_VCOM_APP_NAME];
66
67/*
68 * RETURN: 0 on success or -1 on error.
69 * */
70int
71vcom_set_app_name (char *__app_name)
72{
73 return snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-%s-%d",
74 __app_name, getpid ()) < 0 ? -1 : 0;
75}
76
77static char *
78vcom_get_app_name ()
79{
80 if (vcom_app_name[0] == '\0')
81 {
82 snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-app-%d", getpid ());
83 }
84 return vcom_app_name;
85}
86
87/*
88 * 1 if init, 0 otherwise
89 */
90static int is_vcom_init;
91
92/*
93 * TBD: Make it thread safe
94 */
95
96/*
97 * constructor function called before main is called
98 * RETURN: 0 on success -1 on failure
99 * */
100static inline int
Dave Wallace227867f2017-11-13 21:21:53 -0500101vcom_init (void)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700102{
103 pid_t pid = getpid ();
104
105 if (!is_vcom_init)
106 {
107 if (vppcom_app_create (vcom_get_app_name ()) != 0)
108 {
109 printf ("\n[%d] vcom_init...failed!\n", pid);
110 if (VCOM_DEBUG > 0)
111 fprintf (stderr,
112 "[%d] vcom_init: vppcom_app_create failed!\n", pid);
113 return -1;
114 }
115 if (vcom_socket_main_init () != 0)
116 {
117 printf ("\n[%d] vcom_init...failed!\n", pid);
118 if (VCOM_DEBUG > 0)
119 fprintf (stderr,
120 "[%d] vcom_init: vcom_socket_main_init failed!\n", pid);
121 return -1;
122 }
123
124 is_vcom_init = 1;
125 printf ("\n[%d] vcom_init...done!\n", pid);
126 }
127 return 0;
128}
129
130static inline void
131vcom_destroy (void)
132{
133 pid_t pid = getpid ();
134
135 if (is_vcom_init)
136 {
137 vcom_socket_main_destroy ();
138 vppcom_app_destroy ();
139 is_vcom_init = 0;
140 fprintf (stderr, "\n[%d] vcom_destroy...done!\n", pid);
141 }
142}
143
144static inline int
145is_vcom_socket_fd (int fd)
146{
147 return vcom_socket_is_vcom_fd (fd);
148}
149
150static inline int
151is_vcom_epfd (int epfd)
152{
153 return vcom_socket_is_vcom_epfd (epfd);
154}
155
156
157/*
158 *
159 * Generic glibc fd api
160 *
161 */
162
163/* Close the file descriptor FD.
164
165 This function is a cancellation point and therefore
166 not marked with __THROW. */
167/*
168 * PRE: is_vcom_socket_fd(__fd) == 1
169 * RETURN: 0 on success and -1 for errors.
170 * */
171int
172vcom_close (int __fd)
173{
174 if (vcom_init () != 0)
175 {
176 return -1;
177 }
178
179 if (vcom_socket_close (__fd) != 0)
180 {
181 return -1;
182 }
183
184 return 0;
185}
186
187/*
188 * RETURN: 0 on success, or -1 on error
189 */
190int
191close (int __fd)
192{
193 int rv;
194 pid_t pid = getpid ();
195
196 if (is_vcom_socket_fd (__fd) || is_vcom_epfd (__fd))
197 {
198 if (VCOM_DEBUG > 0)
Dave Wallace375e4682017-11-10 15:49:32 -0500199 fprintf (stderr, "[%d] close: fd %d\n", pid, __fd);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700200 rv = vcom_close (__fd);
201 if (VCOM_DEBUG > 0)
Dave Wallace375e4682017-11-10 15:49:32 -0500202 fprintf (stderr, "[%d] close: vcom_close() returned %d\n", pid, rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700203 if (rv != 0)
204 {
205 errno = -rv;
206 return -1;
207 }
208 return 0;
209 }
210 return libc_close (__fd);
211}
212
213/* Read NBYTES into BUF from FD. Return the
214 number read, -1 for errors or 0 for EOF.
215
216 This function is a cancellation point and therefore
217 not marked with __THROW. */
218ssize_t
219vcom_read (int __fd, void *__buf, size_t __nbytes)
220{
221 if (vcom_init () != 0)
222 {
223 return -1;
224 }
225
226 return vcom_socket_read (__fd, __buf, __nbytes);
227}
228
229ssize_t
230read (int __fd, void *__buf, size_t __nbytes)
231{
232 ssize_t size = 0;
233 pid_t pid = getpid ();
234 pthread_t tid = pthread_self ();
235
236 if (is_vcom_socket_fd (__fd))
237 {
Dave Wallacee22aa742017-10-20 12:30:38 -0400238 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700239 fprintf (stderr,
240 "[%d][%lu (0x%lx)] read:1 "
241 "'%04d'='%04d', '%p', '%04d'\n",
242 pid, (unsigned long) tid, (unsigned long) tid,
243 (int) size, __fd, __buf, (int) __nbytes);
244 size = vcom_read (__fd, __buf, __nbytes);
Dave Wallacee22aa742017-10-20 12:30:38 -0400245 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700246 fprintf (stderr,
247 "[%d][%lu (0x%lx)] read:2 "
248 "'%04d'='%04d', '%p', '%04d'\n",
249 pid, (unsigned long) tid, (unsigned long) tid,
250 (int) size, __fd, __buf, (int) __nbytes);
251 if (size < 0)
252 {
253 errno = -size;
254 return -1;
255 }
256 return size;
257 }
258 return libc_read (__fd, __buf, __nbytes);
259}
260
261ssize_t
262vcom_readv (int __fd, const struct iovec * __iov, int __iovcnt)
263{
264 if (vcom_init () != 0)
265 {
266 return -1;
267 }
268
269 return vcom_socket_readv (__fd, __iov, __iovcnt);
270}
271
272ssize_t
273readv (int __fd, const struct iovec * __iov, int __iovcnt)
274{
275 ssize_t size = 0;
276
277 if (is_vcom_socket_fd (__fd))
278 {
279 size = vcom_readv (__fd, __iov, __iovcnt);
280 if (size < 0)
281 {
282 errno = -size;
283 return -1;
284 }
285 return size;
286 }
287 else
288 return libc_readv (__fd, __iov, __iovcnt);
289}
290
291/* Write N bytes of BUF to FD. Return the number written, or -1.
292
293 This function is a cancellation point and therefore
294 not marked with __THROW. */
295ssize_t
296vcom_write (int __fd, const void *__buf, size_t __n)
297{
298 if (vcom_init () != 0)
299 {
300 return -1;
301 }
302
303 return vcom_socket_write (__fd, (void *) __buf, __n);
304}
305
306ssize_t
307write (int __fd, const void *__buf, size_t __n)
308{
309 ssize_t size = 0;
310 pid_t pid = getpid ();
311 pthread_t tid = pthread_self ();
312
313 if (is_vcom_socket_fd (__fd))
314 {
Dave Wallacee22aa742017-10-20 12:30:38 -0400315 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700316 fprintf (stderr,
317 "[%d][%lu (0x%lx)] write:1 "
318 "'%04d'='%04d', '%p', '%04d'\n",
319 pid, (unsigned long) tid, (unsigned long) tid,
320 (int) size, __fd, __buf, (int) __n);
321 size = vcom_write (__fd, __buf, __n);
Dave Wallacee22aa742017-10-20 12:30:38 -0400322 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700323 fprintf (stderr,
324 "[%d][%lu (0x%lx)] write:2 "
325 "'%04d'='%04d', '%p', '%04d'\n",
326 pid, (unsigned long) tid, (unsigned long) tid,
327 (int) size, __fd, __buf, (int) __n);
328 if (size < 0)
329 {
330 errno = -size;
331 return -1;
332 }
333 return size;
334 }
335 return libc_write (__fd, __buf, __n);
336}
337
338ssize_t
339vcom_writev (int __fd, const struct iovec * __iov, int __iovcnt)
340{
341 if (vcom_init () != 0)
342 {
343 return -1;
344 }
345
346 return vcom_socket_writev (__fd, __iov, __iovcnt);
347}
348
349ssize_t
350writev (int __fd, const struct iovec * __iov, int __iovcnt)
351{
352 ssize_t size = 0;
353
354 if (is_vcom_socket_fd (__fd))
355 {
356 size = vcom_writev (__fd, __iov, __iovcnt);
357 if (size < 0)
358 {
359 errno = -size;
360 return -1;
361 }
362 return size;
363 }
364 else
365 return libc_writev (__fd, __iov, __iovcnt);
366}
367
368/* Do the file control operation described by CMD on FD.
369 The remaining arguments are interpreted depending on CMD.
370
371 This function is a cancellation point and therefore
372 not marked with __THROW. */
373int
374vcom_fcntl_va (int __fd, int __cmd, va_list __ap)
375{
376 if (vcom_init () != 0)
377 {
378 return -1;
379 }
380
381 return vcom_socket_fcntl_va (__fd, __cmd, __ap);
382}
383
384int
385vcom_fcntl (int __fd, int __cmd, ...)
386{
387 int rv = -1;
388 va_list ap;
389
390 if (is_vcom_socket_fd (__fd))
391 {
392 va_start (ap, __cmd);
393 rv = vcom_fcntl_va (__fd, __cmd, ap);
394 va_end (ap);
395 }
396 return rv;
397}
398
399int
400fcntl (int __fd, int __cmd, ...)
401{
402 int rv;
403 va_list ap;
404 pid_t pid = getpid ();
405
406 va_start (ap, __cmd);
407 if (is_vcom_socket_fd (__fd))
408 {
409 rv = vcom_fcntl_va (__fd, __cmd, ap);
410 if (VCOM_DEBUG > 0)
411 fprintf (stderr,
412 "[%d] fcntl: "
413 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __cmd);
414 if (rv < 0)
415 {
416 errno = -rv;
417 rv = -1;
418 }
419 goto out;
420 }
421 rv = libc_vfcntl (__fd, __cmd, ap);
422
423out:
424 va_end (ap);
425 return rv;
426}
427
Stevenb59f2272017-10-12 17:10:33 -0700428int
429vcom_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
430{
431 if (vcom_init () != 0)
432 {
433 return -1;
434 }
435
436 return vcom_socket_ioctl_va (__fd, __cmd, __ap);
437}
438
439int
440vcom_ioctl (int __fd, unsigned long int __cmd, ...)
441{
442 int rv = -1;
443 va_list ap;
444
445 if (is_vcom_socket_fd (__fd))
446 {
447 va_start (ap, __cmd);
448 rv = vcom_ioctl_va (__fd, __cmd, ap);
449 va_end (ap);
450 }
451 return rv;
452}
453
454int
455ioctl (int __fd, unsigned long int __cmd, ...)
456{
457 int rv;
458 va_list ap;
459 pid_t pid = getpid ();
460
461 va_start (ap, __cmd);
462 if (is_vcom_socket_fd (__fd))
463 {
464 rv = vcom_ioctl_va (__fd, __cmd, ap);
465 if (VCOM_DEBUG > 0)
466 fprintf (stderr,
467 "[%d] ioctl: "
468 "'%04d'='%04d', '%04ld'\n", pid, rv, __fd, __cmd);
469 if (rv < 0)
470 {
471 errno = -rv;
472 rv = -1;
473 }
474 goto out;
475 }
476 rv = libc_vioctl (__fd, __cmd, ap);
477
478out:
479 va_end (ap);
480 return rv;
481}
482
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700483/*
484 * Check the first NFDS descriptors each in READFDS (if not NULL) for
485 * read readiness, in WRITEFDS (if not NULL) for write readiness,
486 * and in EXCEPTFDS (if not NULL) for exceptional conditions.
487 * If TIMEOUT is not NULL, time out after waiting the interval
488 * specified therein. Returns the number of ready descriptors,
489 * or -1 for errors.
490 *
491 * This function is a cancellation point and therefore not marked
492 * with __THROW.
493 * */
494
495/*
496 * clear all vcom FDs from fd_sets __readfds, __writefds and
497 * __exceptfds and update the new nfds
498 *
499 * new nfds is the highest-numbered file descriptor
500 * in any of the three sets, plus 1
501 *
502 * Return the number of file descriptors contained in the
503 * three descriptor sets. ie. the total number of the bits
504 * that are set in __readfds, __writefds and __exceptfds
505 */
506static inline int
507vcom_fd_clear (int __nfds,
508 int *__new_nfds,
509 fd_set * __restrict __readfds,
510 fd_set * __restrict __writefds,
511 fd_set * __restrict __exceptfds)
512{
513 int fd;
514 /* invalid max_fd is -1 */
515 int max_fd = -1;
516 int nfd = 0;
517
518
519 /* clear all vcom fd from the sets */
520 for (fd = 0; fd < __nfds; fd++)
521 {
522
523 /* clear vcom fd from set */
524 /*
525 * F fd set
526 */
527#define _(F) \
528 if ((F) && FD_ISSET (fd, (F))) \
529 { \
530 if (is_vcom_socket_fd (fd)) \
531 { \
532 FD_CLR (fd, (F)); \
533 } \
534 }
535
536
537 _(__readfds);
538 _(__writefds);
539 _(__exceptfds);
540#undef _
541 }
542
543 /*
544 * compute nfd and __new_nfds
545 */
546 for (fd = 0; fd < __nfds; fd++)
547 {
548
549 /*
550 * F fd set
551 */
552#define _(F) \
553 if ((F) && FD_ISSET (fd, (F))) \
554 { \
555 if (fd > max_fd) \
556 { \
557 max_fd = fd; \
558 } \
559 ++nfd; \
560 }
561
562
563 _(__readfds);
564 _(__writefds);
565 _(__exceptfds);
566#undef _
567 }
568
569 *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
570 return nfd;
571}
572
573/*
574 * Return the number of file descriptors contained in the
575 * three descriptor sets. ie. the total number of the bits
576 * that are set in __readfds, __writefds and __exceptfds
577 */
578static inline int
579vcom_fd_set (int __nfds,
580 /* dest */
581 int *__new_nfds,
582 fd_set * __restrict __readfds,
583 fd_set * __restrict __writefds, fd_set * __restrict __exceptfds,
584 /* src */
585 fd_set * __restrict __saved_readfds,
586 fd_set * __restrict __saved_writefds,
587 fd_set * __restrict __saved_exceptfds)
588{
589 int fd;
590 /* invalid max_fd is -1 */
591 int max_fd = -1;
592 int nfd = 0;
593
594 for (fd = 0; fd < __nfds; fd++)
595 {
596 /*
597 * F fd set
598 * S saved fd set
599 */
600#define _(S,F) \
601 if ((F) && (S) && FD_ISSET (fd, (S))) \
602 { \
603 if (is_vcom_socket_fd (fd)) \
604 { \
605 FD_SET (fd, (F)); \
606 } \
607 }
608
609
610 _(__saved_readfds, __readfds);
611 _(__saved_writefds, __writefds);
612#undef _
613 }
614
615
616 /*
617 * compute nfd and __new_nfds
618 */
619 for (fd = 0; fd < __nfds; fd++)
620 {
621
622 /*
623 * F fd set
624 */
625#define _(F) \
626 if ((F) && FD_ISSET (fd, (F))) \
627 { \
628 if (fd > max_fd) \
629 { \
630 max_fd = fd; \
631 } \
632 ++nfd; \
633 }
634
635
636 _(__readfds);
637 _(__writefds);
638 _(__exceptfds);
639#undef _
640 }
641
642 *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
643 return nfd;
644}
645
646/*
647 * split select sets(src) into
648 * vcom sets(dest1) and libc sets(dest2)
649 */
650static inline void
651vcom_fd_set_split (
652 /* src, select sets */
653 int nfds,
654 fd_set * __restrict readfds,
655 fd_set * __restrict writefds,
656 fd_set * __restrict exceptfds,
657 /* dest1, vcom sets */
658 int *vcom_nfds,
659 fd_set * __restrict vcom_readfds,
660 fd_set * __restrict vcom_writefds,
661 fd_set * __restrict vcom_exceptfds, int *vcom_nfd,
662 /* dest2, libc sets */
663 int *libc_nfds,
664 fd_set * __restrict libc_readfds,
665 fd_set * __restrict libc_writefds,
666 fd_set * __restrict libc_exceptfds, int *libc_nfd)
667{
668 int fd;
669
670 /* vcom */
671 /* invalid max_fd is -1 */
672 int vcom_max_fd = -1;
673 int vcom_nfd2 = 0;
674
675 /* libc */
676 /* invalid max_fd is -1 */
677 int libc_max_fd = -1;
678 int libc_nfd2 = 0;
679
680
681 for (fd = 0; fd < nfds; fd++)
682 {
683 /*
684 * S select fd set
685 * V vcom fd set
686 * L libc fd set
687 */
688#define _(S,V,L) \
689 if ((S) && FD_ISSET (fd, (S))) \
690 { \
691 if (is_vcom_socket_fd (fd)) \
692 { \
693 if ((V)) \
694 { \
695 FD_SET(fd, (V)); \
696 if (fd > vcom_max_fd) \
697 { \
698 vcom_max_fd = fd; \
699 } \
700 ++vcom_nfd2; \
701 } \
702 } \
703 else \
704 { \
705 if ((L)) \
706 { \
707 FD_SET(fd, (L)); \
708 if (fd > libc_max_fd) \
709 { \
710 libc_max_fd = fd; \
711 } \
712 ++libc_nfd2; \
713 } \
714 } \
715 }
716
717
718 _(readfds, vcom_readfds, libc_readfds);
719 _(writefds, vcom_writefds, libc_writefds);
720 _(exceptfds, vcom_exceptfds, libc_exceptfds);
721#undef _
722 }
723
724 if (vcom_nfds)
725 *vcom_nfds = vcom_max_fd != -1 ? vcom_max_fd + 1 : 0;
726 if (vcom_nfd)
727 *vcom_nfd = vcom_nfd2;
728 if (libc_nfds)
729 *libc_nfds = libc_max_fd != -1 ? libc_max_fd + 1 : 0;
730 if (libc_nfd)
731 *libc_nfd = libc_nfd2;
732}
733
734/*
735 * merge vcom sets(src1) and libc sets(src2)
736 * into select sets(dest)
737 */
738static inline void
739vcom_fd_set_merge (
740 /* dest, select sets */
741 int *nfds,
742 fd_set * __restrict readfds,
743 fd_set * __restrict writefds,
744 fd_set * __restrict exceptfds, int *nfd,
745 /* src1, vcom sets */
746 int vcom_nfds,
747 fd_set * __restrict vcom_readfds,
748 fd_set * __restrict vcom_writefds,
749 fd_set * __restrict vcom_exceptfds, int vcom_nfd,
750 /* src2, libc sets */
751 int libc_nfds,
752 fd_set * __restrict libc_readfds,
753 fd_set * __restrict libc_writefds,
754 fd_set * __restrict libc_exceptfds, int libc_nfd)
755{
756 int fd;
757 /* invalid max_fd is -1 */
758 int max_fd = -1;
759 int nfd2 = 0;
760
761
762 /* FD_BIT_OR
763 *
764 * dest |= src at current bit index
765 * update MAX and NFD of dest fd set
766 *
767 *
768 * FS source fd set
769 * FD dest fd set
770 * BI bit index
771 * MAX current max_fd of dest fd sets
772 * NFD current nfd of dest fd sets
773 * N nfds of source fd set
774 */
775#define FD_BIT_OR(FD,FS,BI, \
776 MAX,NFD) \
777 if ((FS) && (FD) && FD_ISSET ((BI), (FS))) \
778 { \
779 FD_SET ((BI), (FD)); \
780 if ((BI) > (MAX)) \
781 { \
782 (MAX) = (BI); \
783 } \
784 ++(NFD); \
785 }
786
787
788 /* FD_RWE_SET_OR */
789 /*
790 * SR,SW,SE source RWE fd sets
791 * DR,DW,DE dest RWE fd sets
792 * BI bit index
793 * NFDS nfds of source fd sets
794 * MAX current max_fd of dest fd sets
795 * NFD current nfd of dest fd sets
796 */
797#define FD_RWE_SETS_OR(DR,DW,DE, \
798 SR,SW,SE, \
799 BI,NFDS, \
800 MAX,NFD) \
801 do \
802 { \
803 for ((BI) = 0; (BI) < (NFDS); (BI)++) \
804 { \
805 FD_BIT_OR((DR), (SR), (BI), (MAX), (NFD)); \
806 FD_BIT_OR((DW), (SW), (BI), (MAX), (NFD)); \
807 FD_BIT_OR((DE), (SE), (BI), (MAX), (NFD)); \
808 } \
809 } \
810 while (0);
811
812
813 /* source(vcom) to dest(select) rwe fd sets */
814 FD_RWE_SETS_OR (readfds, writefds, exceptfds,
815 vcom_readfds, vcom_writefds, vcom_exceptfds,
816 fd, vcom_nfds, max_fd, nfd2);
817
818 /* source(libc) to dest(select) rwe fd sets */
819 FD_RWE_SETS_OR (readfds, writefds, exceptfds,
820 libc_readfds, libc_writefds, libc_exceptfds,
821 fd, libc_nfds, max_fd, nfd2);
822
823#undef FD_RWE_SETS_OR
824#undef FD_BIT_OR
825
826 if (nfds)
827 *nfds = max_fd != -1 ? max_fd + 1 : 0;
828 if (nfd)
829 *nfd = nfd2;
830}
831
832/*
833 * RETURN 1 if fds is NULL or empty. 0 otherwise
834 */
835static inline int
836fd_set_iszero (fd_set * __restrict fds)
837{
838 int fd;
839
840 /* NULL fds */
841 if (!fds)
842 return 1;
843
844 for (fd = 0; fd < FD_SETSIZE; fd++)
845 {
846 if (FD_ISSET (fd, fds))
847 {
848 /* non-empty fds */
849 return 0;
850 }
851 }
852 /* empty fds */
853 return 1;
854}
855
856
857/*
858 * ################
859 * kernel time64.h
860 * ################
861 * */
862typedef long int s64;
863typedef unsigned long int u64;
864
865typedef long long int __s64;
866typedef unsigned long long int __u64;
867
868typedef __s64 time64_t;
869typedef __u64 timeu64_t;
870
871/* Parameters used to convert the timespec values: */
872#define MSEC_PER_SEC 1000L
873#define USEC_PER_MSEC 1000L
874#define NSEC_PER_USEC 1000L
875#define NSEC_PER_MSEC 1000000L
876#define USEC_PER_SEC 1000000L
877#define NSEC_PER_SEC 1000000000L
878#define FSEC_PER_SEC 1000000000000000LL
879
880
881/*
882 * ################
883 * kernel time.h
884 * ################
885 * */
886
887
888#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
889
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400890#ifdef VCOM_USE_TIMESPEC_EQUAL
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700891static inline int
892timespec_equal (const struct timespec *a, const struct timespec *b)
893{
894 return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
895}
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400896#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700897
898/*
899 * lhs < rhs: return <0
900 * lhs == rhs: return 0
901 * lhs > rhs: return >0
902 */
903static inline int
904timespec_compare (const struct timespec *lhs, const struct timespec *rhs)
905{
906 if (lhs->tv_sec < rhs->tv_sec)
907 return -1;
908 if (lhs->tv_sec > rhs->tv_sec)
909 return 1;
910 return lhs->tv_nsec - rhs->tv_nsec;
911}
912
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400913#ifdef VCOM_USE_TIMEVAL_COMPARE
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700914static inline int
915timeval_compare (const struct timeval *lhs, const struct timeval *rhs)
916{
917 if (lhs->tv_sec < rhs->tv_sec)
918 return -1;
919 if (lhs->tv_sec > rhs->tv_sec)
920 return 1;
921 return lhs->tv_usec - rhs->tv_usec;
922}
Dave Wallace5c7cf1c2017-10-24 04:12:18 -0400923#endif
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700924
925extern void set_normalized_timespec (struct timespec *ts, time_t sec,
926 s64 nsec);
927
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700928static inline struct timespec
929timespec_add (struct timespec lhs, struct timespec rhs)
930{
931 struct timespec ts_delta;
932 set_normalized_timespec (&ts_delta, lhs.tv_sec + rhs.tv_sec,
933 lhs.tv_nsec + rhs.tv_nsec);
934 return ts_delta;
935}
936
937/*
938 * sub = lhs - rhs, in normalized form
939 */
940static inline struct timespec
941timespec_sub (struct timespec lhs, struct timespec rhs)
942{
943 struct timespec ts_delta;
944 set_normalized_timespec (&ts_delta, lhs.tv_sec - rhs.tv_sec,
945 lhs.tv_nsec - rhs.tv_nsec);
946 return ts_delta;
947}
948
949/*
950 * ################
951 * kernel time.c
952 * ################
953 * */
954
955
956/**
957 * set_normalized_timespec - set timespec sec and nsec parts and normalize
958 *
959 * @ts: pointer to timespec variable to be set
960 * @sec: seconds to set
961 * @nsec: nanoseconds to set
962 *
963 * Set seconds and nanoseconds field of a timespec variable and
964 * normalize to the timespec storage format
965 *
966 * Note: The tv_nsec part is always in the range of
967 * 0 <= tv_nsec < NSEC_PER_SEC
968 * For negative values only the tv_sec field is negative !
969 */
970void
971set_normalized_timespec (struct timespec *ts, time_t sec, s64 nsec)
972{
973 while (nsec >= NSEC_PER_SEC)
974 {
975 /*
976 * The following asm() prevents the compiler from
977 * optimising this loop into a modulo operation. See
978 * also __iter_div_u64_rem() in include/linux/time.h
979 */
980 asm ("":"+rm" (nsec));
981 nsec -= NSEC_PER_SEC;
982 ++sec;
983 }
984 while (nsec < 0)
985 {
986 asm ("":"+rm" (nsec));
987 nsec += NSEC_PER_SEC;
988 --sec;
989 }
990 ts->tv_sec = sec;
991 ts->tv_nsec = nsec;
992}
993
994#define vcom_timerisvalid(tvp) (!((tvp)->tv_sec < 0 || (tvp)->tv_usec < 0))
995
996/* Macros for converting between `struct timeval' and `struct timespec'. */
997#define VCOM_TIMEVAL_TO_TIMESPEC(tv, ts) { \
998 (ts)->tv_sec = (tv)->tv_sec; \
999 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
1000}
1001#define VCOM_TIMESPEC_TO_TIMEVAL(tv, ts) { \
1002 (tv)->tv_sec = (ts)->tv_sec; \
1003 (tv)->tv_usec = (ts)->tv_nsec / 1000; \
1004}
1005
1006static inline int
1007vcom_select_impl (int vcom_nfds, fd_set * __restrict vcom_readfds,
1008 fd_set * __restrict vcom_writefds,
1009 fd_set * __restrict vcom_exceptfds,
1010 struct timeval *__restrict timeout)
1011{
1012 return vcom_socket_select (vcom_nfds, vcom_readfds,
1013 vcom_writefds, vcom_exceptfds, timeout);
1014}
1015
1016int
1017vcom_select (int __nfds, fd_set * __restrict __readfds,
1018 fd_set * __restrict __writefds,
1019 fd_set * __restrict __exceptfds,
1020 struct timeval *__restrict __timeout)
1021{
1022 int rv;
1023 int rv2 = 0;
1024 pid_t pid = getpid ();
1025
1026 int timedout = 0;
1027 /* block indefinitely */
1028 int no_timeout = 0;
1029 int first_clock_gettime_failed = 0;
1030 /* timeout value in units of timespec */
1031 struct timespec timeout_ts;
1032 struct timespec start_time, now, end_time;
1033
1034 /* select sets attributes - after merge */
1035 int new_nfds = 0;
1036 int new_nfd = -1;
1037
1038 /* vcom */
1039 int vcom_nfds = 0;
1040 fd_set vcom_readfds;
1041 fd_set vcom_writefds;
1042 fd_set vcom_exceptfds;
1043 int vcom_nfd = -1;
1044
1045 /* libc */
1046 int libc_nfds = 0;
1047 fd_set libc_readfds;
1048 fd_set libc_writefds;
1049 fd_set libc_exceptfds;
1050 int libc_nfd = -1;
1051
1052 /* for polling */
1053 struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
1054
1055 /* validate __timeout */
1056 if (__timeout)
1057 {
1058 /* validate tv_sec */
1059 /* bogus */
1060 if (!vcom_timerisvalid (__timeout))
1061 {
1062 rv = -EINVAL;
1063 goto select_done;
1064 }
1065
1066 /* validate tv_usec */
1067 /* TBD: */
1068 /* init timeout_ts */
1069 VCOM_TIMEVAL_TO_TIMESPEC (__timeout, &timeout_ts);
1070 set_normalized_timespec (&timeout_ts,
1071 timeout_ts.tv_sec, timeout_ts.tv_nsec);
1072 }
1073
1074 rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
1075 if (rv == -1)
1076 {
1077 rv = -errno;
1078 first_clock_gettime_failed = 1;
1079 goto select_done;
1080 }
1081
1082 /* init end_time */
1083 if (__timeout)
1084 {
1085 if (timerisset (__timeout))
1086 {
1087 end_time = timespec_add (start_time, timeout_ts);
1088 }
1089 else
1090 {
1091 /*
1092 * if both fields of the timeout structure are zero,
1093 * then select returns immediately
1094 * */
1095 end_time = start_time;
1096 }
1097 }
1098 else
1099 {
1100 /* block indefinitely */
1101 no_timeout = 1;
1102 }
1103
1104
1105
1106 if (vcom_init () != 0)
1107 {
1108 rv = -1;
1109 goto select_done;
1110 }
1111
1112 /* validate __nfds */
1113 if (__nfds < 0 || __nfds > FD_SETSIZE)
1114 {
1115 rv = -EINVAL;
1116 goto select_done;
1117 }
1118
1119
1120 /*
1121 * usleep(3) emulation
1122 * */
1123
1124 /* call libc_select() with a finite timeout and
1125 * no file descriptors or empty fd sets and
1126 * zero nfds */
1127 if (__nfds == 0 &&
1128 (!__readfds || fd_set_iszero (__readfds)) &&
1129 (!__writefds || fd_set_iszero (__writefds)) &&
1130 (!__exceptfds || fd_set_iszero (__exceptfds)))
1131 {
1132 if (__timeout)
1133 {
1134 rv = libc_select (__nfds,
1135 __readfds, __writefds, __exceptfds, __timeout);
1136 if (rv == -1)
1137 rv = -errno;
1138 }
1139 else
1140 {
1141 /* TBD: block indefinitely or return -EINVAL */
1142 rv = -EINVAL;
1143 }
1144 goto select_done;
1145 }
1146
1147 /* init once before the polling loop */
1148
1149 /* zero vcom and libc fd sets */
1150 /*
1151 * S select fd set
1152 * V vcom fd set
1153 * L libc fd set
1154 */
1155#define _(S,V,L) \
1156 if ((S)) \
1157 { \
1158 FD_ZERO ((V)); \
1159 FD_ZERO ((L)); \
1160 }
1161
1162
1163 _(__readfds, &vcom_readfds, &libc_readfds);
1164 _(__writefds, &vcom_writefds, &libc_writefds);
1165 _(__exceptfds, &vcom_exceptfds, &libc_exceptfds);
1166#undef _
1167 new_nfds = 0;
1168 new_nfd = -1;
1169
1170 vcom_nfds = 0;
1171 vcom_nfd = -1;
1172 libc_nfds = 0;
1173 libc_nfd = -1;
1174
1175 vcom_fd_set_split (
1176 /* src, select sets */
1177 __nfds, __readfds, __writefds, __exceptfds,
1178 /* dest1, vcom sets */
1179 __readfds || __writefds || __exceptfds ?
1180 &vcom_nfds : NULL,
1181 __readfds ? &vcom_readfds : NULL,
1182 __writefds ? &vcom_writefds : NULL,
1183 __exceptfds ? &vcom_exceptfds : NULL,
1184 __readfds || __writefds || __exceptfds ?
1185 &vcom_nfd : NULL,
1186 /* dest2, libc sets */
1187 __readfds || __writefds || __exceptfds ?
1188 &libc_nfds : NULL,
1189 __readfds ? &libc_readfds : NULL,
1190 __writefds ? &libc_writefds : NULL,
1191 __exceptfds ? &libc_exceptfds : NULL,
1192 __readfds || __writefds || __exceptfds ?
1193 &libc_nfd : NULL);
1194
1195 /*
1196 * polling loop
1197 * */
1198 do
1199 {
1200 new_nfd = -1;
1201 vcom_nfd = -1;
1202 libc_nfd = -1;
1203
1204 /*
1205 * if both fields of timeval structure are zero,
1206 * vcom_select_impl and libc_select returns immediately.
1207 * useful for polling and ensure fairness among
1208 * file descriptors watched.
1209 */
1210
1211 /* for polling */
1212 tv.tv_sec = 0;
1213 tv.tv_usec = 0;
1214
1215 /* select on vcom fds */
1216 if (vcom_nfds)
1217 {
1218 vcom_nfd = vcom_select_impl (vcom_nfds,
1219 __readfds ? &vcom_readfds : NULL,
1220 __writefds ? &vcom_writefds : NULL,
1221 __exceptfds ? &vcom_exceptfds : NULL,
1222 &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04001223 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001224 fprintf (stderr,
1225 "[%d] select vcom: "
1226 "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
1227
1228 if (vcom_nfd < 0)
1229 {
1230 rv = vcom_nfd;
1231 goto select_done;
1232 }
1233 }
1234 /* select on libc fds */
1235 if (libc_nfds)
1236 {
1237 libc_nfd = libc_select (libc_nfds,
1238 __readfds ? &libc_readfds : NULL,
1239 __writefds ? &libc_writefds : NULL,
1240 __exceptfds ? &libc_exceptfds : NULL, &tv);
Dave Wallacee22aa742017-10-20 12:30:38 -04001241 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001242 fprintf (stderr,
1243 "[%d] select libc: "
1244 "'%04d'='%04d'\n", pid, libc_nfd, libc_nfds);
1245
1246 if (libc_nfd < 0)
1247 {
1248 /* tv becomes undefined */
1249 libc_nfd = errno;
1250 rv = libc_nfd;
1251 goto select_done;
1252 }
1253 }
1254
1255 /* check if any file descriptors changed status */
1256 if ((vcom_nfds && vcom_nfd > 0) || (libc_nfds && libc_nfd > 0))
1257 {
1258 /* zero the sets before merge and exit */
1259
1260 /*
1261 * F fd set
1262 */
1263#define _(F) \
1264 if ((F)) \
1265 { \
1266 FD_ZERO ((F)); \
1267 }
1268
1269
1270 _(__readfds);
1271 _(__writefds);
1272 _(__exceptfds);
1273#undef _
1274 new_nfds = 0;
1275 new_nfd = -1;
1276
1277 /*
1278 * on exit, sets are modified in place to indicate which
1279 * file descriptors actually changed status
1280 * */
1281 vcom_fd_set_merge (
1282 /* dest, select sets */
Dave Wallace60f54822017-10-24 20:47:45 -04001283 &new_nfds,
Dave Wallacefaf9d772017-10-26 16:12:04 -04001284 __readfds, __writefds, __exceptfds, &new_nfd,
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001285 /* src1, vcom sets */
1286 vcom_nfds,
1287 __readfds ? &vcom_readfds : NULL,
1288 __writefds ? &vcom_writefds : NULL,
1289 __exceptfds ? &vcom_exceptfds : NULL, vcom_nfd,
1290 /* src2, libc sets */
1291 libc_nfds,
1292 __readfds ? &libc_readfds : NULL,
1293 __writefds ? &libc_writefds : NULL,
1294 __exceptfds ? &libc_exceptfds : NULL, libc_nfd);
1295 /*
1296 * return the number of file descriptors contained in the
1297 * three returned sets
1298 * */
1299 rv = 0;
1300 /*
1301 * for documentation
1302 *
1303 * if(vcom_nfd > 0)
1304 * rv += vcom_nfd;
1305 * if(libc_nfd > 0)
1306 * rv += libc_nfd;
1307 */
1308
1309 rv = new_nfd == -1 ? 0 : new_nfd;
1310 goto select_done;
1311 }
1312
1313 rv = clock_gettime (CLOCK_MONOTONIC, &now);
1314 if (rv == -1)
1315 {
1316 rv = -errno;
1317 goto select_done;
1318 }
1319 }
1320 while (no_timeout || timespec_compare (&now, &end_time) < 0);
1321
1322 /* timeout expired before anything interesting happened */
1323 timedout = 1;
1324 rv = 0;
1325
1326select_done:
Dave Wallacee22aa742017-10-20 12:30:38 -04001327 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001328 fprintf (stderr, "[%d] vselect1: " "'%04d'='%04d'\n", pid, rv, __nfds);
1329 /*
1330 * modify timeout parameter to reflect the amount of time not slept
1331 * */
1332 if (__timeout)
1333 {
1334 if (vcom_timerisvalid (__timeout))
1335 {
1336 /* timeout expired */
1337 if (timedout)
1338 {
1339 timerclear (__timeout);
1340 }
1341 else if (!first_clock_gettime_failed)
1342 {
1343 rv2 = clock_gettime (CLOCK_MONOTONIC, &now);
1344 if (rv2 == -1)
1345 {
1346 rv = -errno;
1347 }
1348 else
1349 {
1350 struct timespec ts_delta;
1351 ts_delta = timespec_sub (end_time, now);
1352 VCOM_TIMESPEC_TO_TIMEVAL (__timeout, &ts_delta);
1353 }
1354 }
1355 }
1356 }
Dave Wallacee22aa742017-10-20 12:30:38 -04001357 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001358 fprintf (stderr, "[%d] vselect2: " "'%04d',='%04d'\n", pid, rv, __nfds);
1359
1360 return rv;
1361}
1362
1363int
1364vcom_select_internal (int __nfds, fd_set * __restrict __readfds,
1365 fd_set * __restrict __writefds,
1366 fd_set * __restrict __exceptfds,
1367 struct timeval *__restrict __timeout)
1368{
1369 int rv;
1370 int new_nfds = 0;
1371 int nfd = 0;
1372 pid_t pid = getpid ();
1373
1374 fd_set saved_readfds;
1375 fd_set saved_writefds;
1376 fd_set saved_exceptfds;
1377
1378 /* validate __nfds */
1379 if (__nfds < 0)
1380 {
1381 errno = EINVAL;
1382 return -1;
1383 }
1384
1385 /* validate __timeout */
1386 if (__timeout)
1387 {
1388 /* validate tv_sec */
1389 /* bogus */
1390 if (__timeout->tv_sec < 0 || __timeout->tv_usec < 0)
1391 {
1392 errno = EINVAL;
1393 return -1;
1394 }
1395
1396 /* validate tv_usec */
1397 /* TBD: */
1398 }
1399
1400 /* init saved_x fds */
1401 if (__readfds)
1402 {
1403 saved_readfds = *__readfds;
1404 /*
1405 memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
1406 */
1407 }
1408 else
1409 {
1410 FD_ZERO (&saved_readfds);
1411 }
1412
1413 if (__writefds)
1414 {
1415 saved_writefds = *__writefds;
1416 /*
1417 memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
1418 */
1419
1420 }
1421 else
1422 {
1423 FD_ZERO (&saved_writefds);
1424 }
1425
1426 if (__exceptfds)
1427 {
1428 saved_exceptfds = *__exceptfds;
1429 /*
1430 memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
1431 */
1432
1433 }
1434 else
1435 {
1436 FD_ZERO (&saved_exceptfds);
1437 }
1438
1439 /* clear vcom fds */
1440 nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
1441
1442 /* set to an invalid value */
1443 rv = -2;
1444 /* have kernel fds */
1445 if (new_nfds)
1446 rv = libc_select (new_nfds, __readfds,
1447 __writefds, __exceptfds, __timeout);
1448
1449 if (new_nfds && rv == -1)
1450 {
1451 /* on error, the file descriptor sets are unmodified */
1452 if (__readfds)
1453 *__readfds = saved_readfds;
1454 if (__writefds)
1455 *__writefds = saved_writefds;
1456 if (__exceptfds)
1457 *__exceptfds = saved_exceptfds;
1458 return rv;
1459 }
1460 else if ((new_nfds && rv != -1) || (rv == -2))
1461 {
1462 /* restore vcom fds */
1463 nfd = vcom_fd_set (__nfds,
1464 &new_nfds,
1465 __readfds,
1466 __writefds,
1467 __exceptfds,
1468 &saved_readfds, &saved_writefds, &saved_exceptfds);
1469 rv = nfd;
1470 }
1471
1472 if (VCOM_DEBUG > 0)
1473 fprintf (stderr, "[%d] select: " "'%04d'='%04d'\n", pid, rv, __nfds);
1474 return rv;
1475}
1476
1477int
1478select (int __nfds, fd_set * __restrict __readfds,
1479 fd_set * __restrict __writefds,
1480 fd_set * __restrict __exceptfds, struct timeval *__restrict __timeout)
1481{
1482 int rv = 0;
1483 pid_t pid = getpid ();
1484
Dave Wallacee22aa742017-10-20 12:30:38 -04001485 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001486 fprintf (stderr, "[%d] select1: " "'%04d'='%04d'\n", pid, rv, __nfds);
1487 rv = vcom_select (__nfds, __readfds, __writefds, __exceptfds, __timeout);
Dave Wallacee22aa742017-10-20 12:30:38 -04001488 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001489 fprintf (stderr, "[%d] select2: " "'%04d'='%04d'\n", pid, rv, __nfds);
1490 if (rv < 0)
1491 {
1492 errno = -rv;
1493 return -1;
1494 }
1495 return rv;
1496}
1497
1498#ifdef __USE_XOPEN2K
1499/*
1500 * Same as above only that the TIMEOUT value is given with higher
1501 * resolution and a sigmask which is been set temporarily. This
1502 * version should be used.
1503 *
1504 * This function is a cancellation point and therefore not marked
1505 * with __THROW.
1506 * */
1507int
1508vcom_pselect (int __nfds, fd_set * __restrict __readfds,
1509 fd_set * __restrict __writefds,
1510 fd_set * __restrict __exceptfds,
1511 const struct timespec *__restrict __timeout,
1512 const __sigset_t * __restrict __sigmask)
1513{
1514 int fd;
1515 int vcom_nfds = 0;
1516
1517 for (fd = 0; fd < __nfds; fd++)
1518 {
1519 if (__readfds && FD_ISSET (fd, __readfds))
1520 {
1521 if (is_vcom_socket_fd (fd))
1522 {
1523 vcom_nfds++;
1524 }
1525 }
1526
1527 if (__writefds && FD_ISSET (fd, __writefds))
1528 {
1529 if (is_vcom_socket_fd (fd))
1530 {
1531 vcom_nfds++;
1532 }
1533 }
1534 if (__exceptfds && FD_ISSET (fd, __exceptfds))
1535 {
1536 if (is_vcom_socket_fd (fd))
1537 {
1538 FD_CLR (fd, __exceptfds);
1539 }
1540 }
1541 }
1542 return vcom_nfds;
1543}
1544
1545int
1546pselect (int __nfds, fd_set * __restrict __readfds,
1547 fd_set * __restrict __writefds,
1548 fd_set * __restrict __exceptfds,
1549 const struct timespec *__restrict __timeout,
1550 const __sigset_t * __restrict __sigmask)
1551{
1552 int rv;
1553 int new_nfds = 0;
1554 int nfd = 0;
1555 pid_t pid = getpid ();
1556
1557 fd_set saved_readfds;
1558 fd_set saved_writefds;
1559 fd_set saved_exceptfds;
1560
1561 /* validate __nfds */
1562 if (__nfds < 0)
1563 {
1564 errno = EINVAL;
1565 return -1;
1566 }
1567
1568 /* validate __timeout */
1569 if (__timeout)
1570 {
1571 /* validate tv_sec */
1572 /* bogus */
1573 if (__timeout->tv_sec < 0 || __timeout->tv_nsec < 0)
1574 {
1575 errno = EINVAL;
1576 return -1;
1577 }
1578
1579 /* validate tv_usec */
1580 /* TBD: */
1581 }
1582
1583 /* init saved fds */
1584 if (__readfds)
1585 {
1586 saved_readfds = *__readfds;
1587 /*
1588 memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
1589 */
1590 }
1591 else
1592 {
1593 FD_ZERO (&saved_readfds);
1594 }
1595
1596 if (__writefds)
1597 {
1598 saved_writefds = *__writefds;
1599 /*
1600 memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
1601 */
1602
1603 }
1604 else
1605 {
1606 FD_ZERO (&saved_writefds);
1607 }
1608
1609 if (__exceptfds)
1610 {
1611 saved_exceptfds = *__exceptfds;
1612 /*
1613 memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
1614 */
1615
1616 }
1617 else
1618 {
1619 FD_ZERO (&saved_exceptfds);
1620 }
1621
1622 /* clear vcom fds */
1623 nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
1624
1625 /* set to an invalid value */
1626 rv = -2;
1627 if (new_nfds)
1628 rv = libc_pselect (new_nfds,
1629 __readfds,
1630 __writefds, __exceptfds, __timeout, __sigmask);
1631
1632 if (new_nfds && rv == -1)
1633 {
1634 /* on error, the file descriptor sets are unmodified */
1635 if (__readfds)
1636 *__readfds = saved_readfds;
1637 if (__writefds)
1638 *__writefds = saved_writefds;
1639 if (__exceptfds)
1640 *__exceptfds = saved_exceptfds;
1641 return rv;
1642 }
1643 else if ((new_nfds && rv != -1) || (rv == -2))
1644 {
1645 /* restore vcom fds */
1646 nfd = vcom_fd_set (__nfds,
1647 &new_nfds,
1648 __readfds,
1649 __writefds,
1650 __exceptfds,
1651 &saved_readfds, &saved_writefds, &saved_exceptfds);
1652 rv = nfd;
1653 }
1654
Dave Wallacee22aa742017-10-20 12:30:38 -04001655 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001656 fprintf (stderr, "[%d] pselect: " "'%04d'='%04d'\n", pid, rv, __nfds);
1657 return rv;
1658}
1659#endif
1660
1661/*
1662 *
1663 * Socket specific glibc api
1664 *
1665 */
1666
1667/* Create a new socket of type TYPE in domain DOMAIN, using
1668 * protocol PROTOCOL. If PROTOCOL is zero, one is chosen
1669 * automatically. Returns a file descriptor for the new socket,
1670 * or -1 for errors.
1671 * RETURN: a valid file descriptor for the new socket,
1672 * or -1 for errors.
1673 * */
1674
1675int
1676vcom_socket (int __domain, int __type, int __protocol)
1677{
1678 if (vcom_init () != 0)
1679 {
1680 return -1;
1681 }
1682
1683 return vcom_socket_socket (__domain, __type, __protocol);
1684}
1685
1686int
1687socket (int __domain, int __type, int __protocol)
1688{
1689 int rv;
1690 pid_t pid = getpid ();
1691 pthread_t tid = pthread_self ();
1692
1693 /* handle domains implemented by vpp */
1694 switch (__domain)
1695 {
1696 case AF_INET:
1697 case AF_INET6:
1698 /* handle types implemented by vpp */
1699 switch (__type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1700 {
1701 case SOCK_STREAM:
1702 case SOCK_DGRAM:
1703 if (VCOM_DEBUG > 0)
1704 vcom_socket_main_show ();
1705 rv = vcom_socket (__domain, __type, __protocol);
1706 if (VCOM_DEBUG > 0)
1707 fprintf (stderr,
1708 "[%d][%lu (0x%lx)] socket: "
1709 "'%04d'= D='%04d', T='%04d', P='%04d'\n",
1710 pid, (unsigned long) tid, (unsigned long) tid,
1711 rv, __domain, __type, __protocol);
1712 if (VCOM_DEBUG > 0)
1713 vcom_socket_main_show ();
1714 if (rv < 0)
1715 {
1716 errno = -rv;
1717 return -1;
1718 }
1719 return rv;
1720 break;
1721
1722 default:
1723 goto CALL_GLIBC_SOCKET_API;
1724 break;
1725 }
1726
1727 break;
1728
1729 default:
1730 goto CALL_GLIBC_SOCKET_API;
1731 break;
1732 }
1733
1734CALL_GLIBC_SOCKET_API:
1735 return libc_socket (__domain, __type, __protocol);
1736}
1737
1738/*
1739 * Create two new sockets, of type TYPE in domain DOMAIN and using
1740 * protocol PROTOCOL, which are connected to each other, and put file
1741 * descriptors for them in FDS[0] and FDS[1]. If PROTOCOL is zero,
1742 * one will be chosen automatically.
1743 * Returns 0 on success, -1 for errors.
1744 * */
1745int
1746vcom_socketpair (int __domain, int __type, int __protocol, int __fds[2])
1747{
1748 if (vcom_init () != 0)
1749 {
1750 return -1;
1751 }
1752
1753 return vcom_socket_socketpair (__domain, __type, __protocol, __fds);
1754}
1755
1756int
1757socketpair (int __domain, int __type, int __protocol, int __fds[2])
1758{
1759 int rv;
1760 pid_t pid = getpid ();
1761
1762 /* handle domains implemented by vpp */
1763 switch (__domain)
1764 {
1765 case AF_INET:
1766 case AF_INET6:
1767 /* handle types implemented by vpp */
1768 switch (__type)
1769 {
1770 case SOCK_STREAM:
1771 case SOCK_DGRAM:
1772 rv = vcom_socketpair (__domain, __type, __protocol, __fds);
1773 if (VCOM_DEBUG > 0)
1774 fprintf (stderr,
1775 "[%d] socketpair: "
1776 "'%04d'= D='%04d', T='%04d', P='%04d'\n",
1777 pid, rv, __domain, __type, __protocol);
1778 if (rv < 0)
1779 {
1780 errno = -rv;
1781 return -1;
1782 }
1783 return 0;
1784 break;
1785
1786 default:
1787 goto CALL_GLIBC_SOCKET_API;
1788 break;
1789 }
1790
1791 break;
1792
1793 default:
1794 goto CALL_GLIBC_SOCKET_API;
1795 break;
1796 }
1797
1798CALL_GLIBC_SOCKET_API:
1799 return libc_socketpair (__domain, __type, __protocol, __fds);
1800}
1801
1802/*
1803 * Give the socket FD the local address ADDR
1804 * (which is LEN bytes long).
1805 * */
1806int
1807vcom_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1808{
1809 int rv;
1810
1811 if (vcom_init () != 0)
1812 {
1813 return -1;
1814 }
1815
1816 /* validate __len */
1817 switch (__addr->sa_family)
1818 {
1819 case AF_INET:
1820 if (__len != sizeof (struct sockaddr_in))
1821 return -EINVAL;
1822 break;
1823 case AF_INET6:
1824 if (__len != sizeof (struct sockaddr_in6))
1825 return -EINVAL;
1826 break;
1827
1828 default:
1829 return -1;
1830 break;
1831 }
1832
1833 /* handle domains implemented by vpp */
1834 switch (__addr->sa_family)
1835 {
1836 case AF_INET:
1837 case AF_INET6:
1838 rv = vcom_socket_bind (__fd, __addr, __len);
1839 return rv;
1840 break;
1841
1842 default:
1843 return -1;
1844 break;
1845 }
1846
1847 return -1;
1848}
1849
1850int
1851bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1852{
1853 int rv;
1854 pid_t pid = getpid ();
1855
1856 if (is_vcom_socket_fd (__fd))
1857 {
1858
1859 rv = vcom_bind (__fd, __addr, __len);
1860 if (VCOM_DEBUG > 0)
1861 fprintf (stderr,
1862 "[%d] bind: "
1863 "'%04d'='%04d', '%p', '%04d'\n",
1864 pid, rv, __fd, __addr, __len);
1865 if (rv != 0)
1866 {
1867 errno = -rv;
1868 return -1;
1869 }
1870 return 0;
1871 }
1872 return libc_bind (__fd, __addr, __len);
1873}
1874
1875/*
1876 * Put the local address of FD into *ADDR and its length in *LEN.
1877 * */
1878int
1879vcom_getsockname (int __fd, __SOCKADDR_ARG __addr,
1880 socklen_t * __restrict __len)
1881{
1882 if (vcom_init () != 0)
1883 {
1884 return -1;
1885 }
1886
1887 return vcom_socket_getsockname (__fd, __addr, __len);
1888}
1889
1890int
1891getsockname (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
1892{
1893 int rv;
1894 pid_t pid = getpid ();
1895
1896 if (is_vcom_socket_fd (__fd))
1897 {
1898 rv = vcom_getsockname (__fd, __addr, __len);
1899 if (VCOM_DEBUG > 0)
1900 fprintf (stderr,
1901 "[%d] getsockname: "
1902 "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
1903 if (rv != 0)
1904 {
1905 errno = -rv;
1906 return -1;
1907 }
1908 return 0;
1909 }
1910 return libc_getsockname (__fd, __addr, __len);
1911}
1912
1913/*
1914 * Open a connection on socket FD to peer at ADDR
1915 * (which LEN bytes long). For connectionless socket types, just set
1916 * the default address to send to and the only address from which to
1917 * accept transmissions. Return 0 on success, -1 for errors.
1918 * This function is a cancellation point and therefore not marked
1919 * with __THROW.
1920 * */
1921int
1922vcom_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1923{
1924 int rv = -1;
1925
1926 if (vcom_init () != 0)
1927 {
1928 return -1;
1929 }
1930
1931 /* validate __len */
1932 switch (__addr->sa_family)
1933 {
1934 case AF_INET:
1935 if (__len != INET_ADDRSTRLEN)
1936 return -1;
1937 break;
1938 case AF_INET6:
1939 if (__len != INET6_ADDRSTRLEN)
1940 return -1;
1941 break;
1942
1943 default:
1944 return -1;
1945 break;
1946 }
1947
1948 /* handle domains implemented by vpp */
1949 switch (__addr->sa_family)
1950 {
1951 case AF_INET:
1952 case AF_INET6:
1953 rv = vcom_socket_connect (__fd, __addr, __len);
Dave Wallaceee45d412017-11-24 21:44:06 -05001954 if (!rv)
1955 {
1956 errno = -rv;
1957 return -1;
1958
1959 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001960 break;
1961
1962 default:
1963 return -1;
1964 break;
1965 }
1966
1967 return rv;
1968}
1969
1970int
1971connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1972{
1973 int rv;
1974 pid_t pid = getpid ();
1975 pthread_t tid = pthread_self ();
1976
1977 if (is_vcom_socket_fd (__fd))
1978 {
1979 rv = vcom_connect (__fd, __addr, __len);
1980 if (VCOM_DEBUG > 0)
1981 fprintf (stderr,
1982 "[%d][%lu (0x%lx)] connect: "
1983 "'%04d'='%04d', '%p', '%04d'\n",
1984 pid, (unsigned long) tid, (unsigned long) tid,
1985 rv, __fd, __addr, __len);
Dave Wallaceee45d412017-11-24 21:44:06 -05001986 if (!rv)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001987 {
1988 errno = -rv;
1989 return -1;
1990 }
1991 return 0;
1992 }
1993
1994 return libc_connect (__fd, __addr, __len);
1995}
1996
1997/*
1998 * Put the address of the peer connected to socket FD into *ADDR
1999 * (which is *LEN bytes long), and its actual length into *LEN.
2000 * */
2001int
2002vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
2003 socklen_t * __restrict __len)
2004{
2005 if (vcom_init () != 0)
2006 {
2007 return -1;
2008 }
2009
2010 return vcom_socket_getpeername (__fd, __addr, __len);
2011}
2012
2013int
2014getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
2015{
2016 int rv;
2017 pid_t pid = getpid ();
2018
2019 if (is_vcom_socket_fd (__fd))
2020 {
2021 rv = vcom_getpeername (__fd, __addr, __len);
2022 if (VCOM_DEBUG > 0)
2023 fprintf (stderr,
2024 "[%d] getpeername: "
2025 "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
2026 if (rv != 0)
2027 {
2028 errno = -rv;
2029 return -1;
2030 }
2031 return 0;
2032 }
2033 return libc_getpeername (__fd, __addr, __len);
2034}
2035
2036/*
2037 * Send N bytes of BUF to socket FD. Returns the number sent or -1.
2038 * This function is a cancellation point and therefore not marked
2039 * with __THROW.
2040 * */
2041ssize_t
2042vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
2043{
2044
2045 if (vcom_init () != 0)
2046 {
2047 return -1;
2048 }
2049
2050 return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
2051}
2052
2053ssize_t
2054send (int __fd, const void *__buf, size_t __n, int __flags)
2055{
2056 ssize_t size;
2057 pid_t pid = getpid ();
2058
2059 if (is_vcom_socket_fd (__fd))
2060 {
2061 size = vcom_send (__fd, __buf, __n, __flags);
2062 if (VCOM_DEBUG > 0)
2063 fprintf (stderr,
2064 "[%d] send: "
2065 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2066 pid, (int) size, __fd, __buf, (int) __n, __flags);
2067 if (size < 0)
2068 {
2069 errno = -size;
2070 return -1;
2071 }
2072 return size;
2073 }
2074 return libc_send (__fd, __buf, __n, __flags);
2075}
2076
Dave Wallace227867f2017-11-13 21:21:53 -05002077ssize_t
2078sendfile (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2079{
2080 ssize_t size;
2081
2082 if (VCOM_DEBUG > 2)
2083 clib_warning ("[%d] __out_fd %d, __in_fd %d, __offset %p, __len %ld",
2084 getpid (), __out_fd, __in_fd, __offset, __len);
2085
2086 if (is_vcom_socket_fd (__out_fd))
2087 {
2088 /* TBD: refactor this check to be part of is_vcom_socket_fd() */
2089 if (vcom_init () != 0)
2090 return -1;
2091
2092 size = vcom_socket_sendfile (__out_fd, __in_fd, __offset, __len);
2093 if (VCOM_DEBUG > 2)
2094 clib_warning ("[%d] vcom_socket_sendfile (out_fd %d, in_fd %d, "
2095 "offset %p (%ld), len %lu) returned %ld",
2096 getpid (), __out_fd, __in_fd, __offset,
2097 __offset ? *__offset : -1, __len, size);
2098 if (size < 0)
2099 {
2100 errno = -size;
2101 return -1;
2102 }
2103 return size;
2104 }
2105 if (VCOM_DEBUG > 2)
2106 clib_warning ("[%d] calling libc_sendfile!", getpid ());
2107 return libc_sendfile (__out_fd, __in_fd, __offset, __len);
2108}
2109
2110ssize_t
2111sendfile64 (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2112{
2113 return sendfile (__out_fd, __in_fd, __offset, __len);
2114}
2115
2116
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002117/*
2118 * Read N bytes into BUF from socket FD.
2119 * Returns the number read or -1 for errors.
2120 * This function is a cancellation point and therefore not marked
2121 * with __THROW.
2122 * */
2123ssize_t
2124vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
2125{
2126 if (vcom_init () != 0)
2127 {
2128 return -1;
2129 }
2130
2131 return vcom_socket_recv (__fd, __buf, __n, __flags);
2132}
2133
2134ssize_t
2135recv (int __fd, void *__buf, size_t __n, int __flags)
2136{
2137 ssize_t size;
2138 pid_t pid = getpid ();
2139
2140 if (is_vcom_socket_fd (__fd))
2141 {
2142 size = vcom_recv (__fd, __buf, __n, __flags);
2143 if (VCOM_DEBUG > 0)
2144 fprintf (stderr,
2145 "[%d] recv: "
2146 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2147 pid, (int) size, __fd, __buf, (int) __n, __flags);
2148 if (size < 0)
2149 {
2150 errno = -size;
2151 return -1;
2152 }
2153 return size;
2154 }
2155 return libc_recv (__fd, __buf, __n, __flags);
2156}
2157
2158/*
2159 * Send N bytes of BUF on socket FD to peer at address ADDR (which is
2160 * ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
2161 * This function is a cancellation point and therefore not marked
2162 * with __THROW.
2163 * */
2164ssize_t
2165vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
2166 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2167{
2168 if (vcom_init () != 0)
2169 {
2170 return -1;
2171 }
2172
2173 return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2174}
2175
2176ssize_t
2177sendto (int __fd, const void *__buf, size_t __n, int __flags,
2178 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2179{
2180 ssize_t size;
2181 pid_t pid = getpid ();
2182
2183 if (is_vcom_socket_fd (__fd))
2184 {
2185 size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2186 if (VCOM_DEBUG > 0)
2187 fprintf (stderr,
2188 "[%d] sendto: "
2189 "'%04d'='%04d', '%p', '%04d', '%04x', "
2190 "'%p', '%04d'\n",
2191 pid, (int) size, __fd, __buf, (int) __n, __flags,
2192 __addr, __addr_len);
2193 if (size < 0)
2194 {
2195 errno = -size;
2196 return -1;
2197 }
2198 return size;
2199 }
2200 return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2201}
2202
2203/*
2204 * Read N bytes into BUF through socket FD.
2205 * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
2206 * address of the sender, and store the actual size of the address
2207 * in *ADDR_LEN.
2208 * Returns the number of bytes read or -1 for errors.
2209 * This function is a cancellation point and therefore not marked
2210 * with __THROW.
2211 * */
2212ssize_t
2213vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
2214 int __flags,
2215 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2216{
2217 if (vcom_init () != 0)
2218 {
2219 return -1;
2220 }
2221
2222 return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2223}
2224
2225ssize_t
2226recvfrom (int __fd, void *__restrict __buf, size_t __n,
2227 int __flags,
2228 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2229{
2230 ssize_t size;
2231 pid_t pid = getpid ();
2232
2233 if (is_vcom_socket_fd (__fd))
2234 {
2235 size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2236 if (VCOM_DEBUG > 0)
2237 fprintf (stderr,
2238 "[%d] recvfrom: "
2239 "'%04d'='%04d', '%p', '%04d', '%04x', "
2240 "'%p', '%p'\n",
2241 pid, (int) size, __fd, __buf, (int) __n, __flags,
2242 __addr, __addr_len);
2243 if (size < 0)
2244 {
2245 errno = -size;
2246 return -1;
2247 }
2248 return size;
2249 }
2250 return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2251}
2252
2253/*
2254 * Send a message described MESSAGE on socket FD.
2255 * Returns the number of bytes sent, or -1 for errors.
2256 * This function is a cancellation point and therefore not marked
2257 * with __THROW.
2258 * */
2259ssize_t
2260vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
2261{
2262 if (vcom_init () != 0)
2263 {
2264 return -1;
2265 }
2266
2267 return vcom_socket_sendmsg (__fd, __message, __flags);
2268}
2269
2270ssize_t
2271sendmsg (int __fd, const struct msghdr * __message, int __flags)
2272{
2273 ssize_t size;
2274 pid_t pid = getpid ();
2275
2276 if (is_vcom_socket_fd (__fd))
2277 {
2278 size = vcom_sendmsg (__fd, __message, __flags);
2279 if (VCOM_DEBUG > 0)
2280 fprintf (stderr,
2281 "[%d] sendmsg: "
2282 "'%04d'='%04d', '%p', '%04x'\n",
2283 pid, (int) size, __fd, __message, __flags);
2284 if (size < 0)
2285 {
2286 errno = -size;
2287 return -1;
2288 }
2289 return size;
2290 }
2291 return libc_sendmsg (__fd, __message, __flags);
2292}
2293
2294#ifdef __USE_GNU
2295/*
2296 * Send a VLEN messages as described by VMESSAGES to socket FD.
2297 * Returns the number of datagrams successfully written
2298 * or -1 for errors.
2299 * This function is a cancellation point and therefore not marked
2300 * with __THROW.
2301 * */
2302int
2303vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
2304 unsigned int __vlen, int __flags)
2305{
2306 if (vcom_init () != 0)
2307 {
2308 return -1;
2309 }
2310
2311 return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
2312}
2313
2314int
2315sendmmsg (int __fd, struct mmsghdr *__vmessages,
2316 unsigned int __vlen, int __flags)
2317{
2318 ssize_t size;
2319 pid_t pid = getpid ();
2320
2321 if (is_vcom_socket_fd (__fd))
2322 {
2323 size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
2324 if (VCOM_DEBUG > 0)
2325 fprintf (stderr,
2326 "[%d] sendmmsg: "
2327 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2328 pid, (int) size, __fd, __vmessages, __vlen, __flags);
2329 if (size < 0)
2330 {
2331 errno = -size;
2332 return -1;
2333 }
2334 return size;
2335 }
2336 return libc_sendmmsg (__fd, __message, __vlen, __flags);
2337}
2338
2339#endif
2340
2341/*
2342 * Receive a message as described by MESSAGE from socket FD.
2343 * Returns the number of bytes read or -1 for errors.
2344 * This function is a cancellation point and therefore not marked
2345 * with __THROW.
2346 * */
2347ssize_t
2348vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
2349{
2350 if (vcom_init () != 0)
2351 {
2352 return -1;
2353 }
2354
2355 return vcom_socket_recvmsg (__fd, __message, __flags);
2356}
2357
2358ssize_t
2359recvmsg (int __fd, struct msghdr * __message, int __flags)
2360{
2361 ssize_t size;
2362 pid_t pid = getpid ();
2363
2364 if (is_vcom_socket_fd (__fd))
2365 {
2366 size = vcom_recvmsg (__fd, __message, __flags);
2367 if (VCOM_DEBUG > 0)
2368 fprintf (stderr,
2369 "[%d] recvmsg: "
2370 "'%04d'='%04d', '%p', '%04x'\n",
2371 pid, (int) size, __fd, __message, __flags);
2372 if (size < 0)
2373 {
2374 errno = -size;
2375 return -1;
2376 }
2377 return size;
2378 }
2379 return libc_recvmsg (__fd, __message, __flags);
2380}
2381
2382#ifdef __USE_GNU
2383/*
2384 * Receive up to VLEN messages as described by VMESSAGES from socket FD.
2385 * Returns the number of messages received or -1 for errors.
2386 * This function is a cancellation point and therefore not marked
2387 * with __THROW.
2388 * */
2389int
2390vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
2391 unsigned int __vlen, int __flags, struct timespec *__tmo)
2392{
2393 if (vcom_init () != 0)
2394 {
2395 return -1;
2396 }
2397
2398 return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2399}
2400
2401int
2402recvmmsg (int __fd, struct mmsghdr *__vmessages,
2403 unsigned int __vlen, int __flags, struct timespec *__tmo)
2404{
2405 ssize_t size;
2406 pid_t pid = getpid ();
2407
2408 if (is_vcom_socket_fd (__fd))
2409 {
2410 size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2411 if (VCOM_DEBUG > 0)
2412 fprintf (stderr,
2413 "[%d] recvmmsg: "
2414 "'%04d'='%04d', '%p', "
2415 "'%04d', '%04x', '%p'\n",
2416 pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
2417 if (size < 0)
2418 {
2419 errno = -size;
2420 return -1;
2421 }
2422 return size;
2423 }
2424 return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2425}
2426
2427#endif
2428
2429/*
2430 * Put the current value for socket FD's option OPTNAME
2431 * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
2432 * and set *OPTLEN to the value's actual length.
2433 * Returns 0 on success, -1 for errors.
2434 * */
2435int
2436vcom_getsockopt (int __fd, int __level, int __optname,
2437 void *__restrict __optval, socklen_t * __restrict __optlen)
2438{
2439 if (vcom_init () != 0)
2440 {
2441 return -1;
2442 }
2443
2444 return vcom_socket_getsockopt (__fd, __level, __optname,
2445 __optval, __optlen);
2446}
2447
2448int
2449getsockopt (int __fd, int __level, int __optname,
2450 void *__restrict __optval, socklen_t * __restrict __optlen)
2451{
2452 int rv;
2453 pid_t pid = getpid ();
2454
2455 if (is_vcom_socket_fd (__fd))
2456 {
2457 rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
Dave Wallacee22aa742017-10-20 12:30:38 -04002458 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002459 fprintf (stderr,
2460 "[%d] getsockopt: "
2461 "'%04d'='%04d', '%04d', '%04d', "
2462 "'%p', '%p'\n",
2463 pid, rv, __fd, __level, __optname, __optval, __optlen);
2464 if (rv != 0)
2465 {
2466 errno = -rv;
2467 return -1;
2468 }
2469 return 0;
2470 }
2471 return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2472}
2473
2474/*
2475 * Set socket FD's option OPTNAME at protocol level LEVEL
2476 * to *OPTVAL (which is OPTLEN bytes long).
2477 * Returns 0 on success, -1 for errors.
2478 * */
2479int
2480vcom_setsockopt (int __fd, int __level, int __optname,
2481 const void *__optval, socklen_t __optlen)
2482{
2483 if (vcom_init () != 0)
2484 {
2485 return -1;
2486 }
2487
2488 return vcom_socket_setsockopt (__fd, __level, __optname,
2489 __optval, __optlen);
2490}
2491
2492int
2493setsockopt (int __fd, int __level, int __optname,
2494 const void *__optval, socklen_t __optlen)
2495{
2496 int rv;
2497 pid_t pid = getpid ();
2498
2499 if (is_vcom_socket_fd (__fd))
2500 {
2501 rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
2502 if (VCOM_DEBUG > 0)
2503 fprintf (stderr,
2504 "[%d] setsockopt: "
2505 "'%04d'='%04d', '%04d', '%04d', "
2506 "'%p', '%04d'\n",
2507 pid, rv, __fd, __level, __optname, __optval, __optlen);
2508 if (rv != 0)
2509 {
2510 errno = -rv;
2511 return -1;
2512 }
2513 return 0;
2514 }
2515 return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2516}
2517
2518/*
2519 * Prepare to accept connections on socket FD.
2520 * N connection requests will be queued before further
2521 * requests are refused.
2522 * Returns 0 on success, -1 for errors.
2523 * */
2524int
2525vcom_listen (int __fd, int __n)
2526{
2527 if (vcom_init () != 0)
2528 {
2529 return -1;
2530 }
2531
2532 return vcom_socket_listen (__fd, __n);
2533}
2534
2535int
2536listen (int __fd, int __n)
2537{
2538 int rv;
2539 pid_t pid = getpid ();
2540
2541 if (is_vcom_socket_fd (__fd))
2542 {
2543 rv = vcom_listen (__fd, __n);
2544 if (VCOM_DEBUG > 0)
2545 fprintf (stderr,
2546 "[%d] listen: "
2547 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
2548 if (rv != 0)
2549 {
2550 errno = -rv;
2551 return -1;
2552 }
2553 return 0;
2554 }
2555 return libc_listen (__fd, __n);
2556}
2557
2558/*
2559 * Await a connection on socket FD.
2560 * When a connection arrives, open a new socket to communicate
2561 * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
2562 * of the connecting peer and *ADDR_LEN to the address's actual
2563 * length, and return the new socket's descriptor, or -1 for errors.
2564 * This function is a cancellation point and therefore not marked
2565 * with __THROW.
2566 * */
2567int
2568vcom_accept (int __fd, __SOCKADDR_ARG __addr,
2569 socklen_t * __restrict __addr_len)
2570{
2571
2572 if (vcom_init () != 0)
2573 {
2574 return -1;
2575 }
2576 return vcom_socket_accept (__fd, __addr, __addr_len);
2577}
2578
2579int
2580accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2581{
2582 int rv = -1;
2583 pid_t pid = getpid ();
2584 pthread_t tid = pthread_self ();
2585
2586 if (is_vcom_socket_fd (__fd))
2587 {
2588 if (VCOM_DEBUG > 0)
2589 vcom_socket_main_show ();
2590 if (VCOM_DEBUG > 0)
2591 fprintf (stderr,
2592 "[%d][%lu (0x%lx)] accept1: "
2593 "'%04d'='%04d', '%p', '%p'\n",
2594 pid, (unsigned long) tid, (unsigned long) tid,
2595 rv, __fd, __addr, __addr_len);
2596 rv = vcom_accept (__fd, __addr, __addr_len);
2597 if (VCOM_DEBUG > 0)
2598 fprintf (stderr,
2599 "[%d][%lu (0x%lx)] accept2: "
2600 "'%04d'='%04d', '%p', '%p'\n",
2601 pid, (unsigned long) tid, (unsigned long) tid,
2602 rv, __fd, __addr, __addr_len);
2603 if (VCOM_DEBUG > 0)
2604 vcom_socket_main_show ();
2605 if (rv < 0)
2606 {
2607 errno = -rv;
2608 return -1;
2609 }
2610 return rv;
2611 }
2612 return libc_accept (__fd, __addr, __addr_len);
2613}
2614
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002615/*
2616 * Similar to 'accept' but takes an additional parameter to specify
2617 * flags.
2618 * This function is a cancellation point and therefore not marked
2619 * with __THROW.
2620 * */
2621int
2622vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
2623 socklen_t * __restrict __addr_len, int __flags)
2624{
2625
2626 if (vcom_init () != 0)
2627 {
2628 return -1;
2629 }
2630
2631 return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
2632}
2633
2634int
2635accept4 (int __fd, __SOCKADDR_ARG __addr,
2636 socklen_t * __restrict __addr_len, int __flags)
2637{
Dave Wallace59179392017-11-07 02:20:07 -05002638 int rv = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002639 pid_t pid = getpid ();
2640
Dave Wallace59179392017-11-07 02:20:07 -05002641 fprintf (stderr,
2642 "[%d] accept4: in the beginning... "
2643 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2644 pid, rv, __fd, __addr, __addr_len, __flags);
2645
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002646 if (is_vcom_socket_fd (__fd))
2647 {
2648 if (VCOM_DEBUG > 0)
2649 vcom_socket_main_show ();
2650 rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
2651 if (VCOM_DEBUG > 0)
2652 fprintf (stderr,
Dave Wallace59179392017-11-07 02:20:07 -05002653 "[%d] accept4: VCL "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002654 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2655 pid, rv, __fd, __addr, __addr_len, __flags);
2656 if (VCOM_DEBUG > 0)
2657 vcom_socket_main_show ();
2658 if (rv < 0)
2659 {
2660 errno = -rv;
2661 return -1;
2662 }
2663 return rv;
2664 }
Dave Wallace59179392017-11-07 02:20:07 -05002665 fprintf (stderr,
2666 "[%d] accept4: libc "
2667 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2668 pid, rv, __fd, __addr, __addr_len, __flags);
2669
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002670 return libc_accept4 (__fd, __addr, __addr_len, __flags);
2671}
2672
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002673/*
2674 * Shut down all or part of the connection open on socket FD.
2675 * HOW determines what to shut down:
2676 * SHUT_RD = No more receptions;
2677 * SHUT_WR = No more transmissions;
2678 * SHUT_RDWR = No more receptions or transmissions.
2679 * Returns 0 on success, -1 for errors.
2680 * */
2681int
2682vcom_shutdown (int __fd, int __how)
2683{
2684 if (vcom_init () != 0)
2685 {
2686 return -1;
2687 }
2688 return vcom_socket_shutdown (__fd, __how);
2689}
2690
2691int
2692shutdown (int __fd, int __how)
2693{
2694 int rv;
2695 pid_t pid = getpid ();
2696
2697 if (is_vcom_socket_fd (__fd))
2698 {
2699 rv = vcom_shutdown (__fd, __how);
2700 if (VCOM_DEBUG > 0)
2701 fprintf (stderr,
2702 "[%d] shutdown: "
2703 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
2704 if (rv != 0)
2705 {
2706 errno = -rv;
2707 return -1;
2708 }
2709 return 0;
2710 }
2711 return libc_shutdown (__fd, __how);
2712}
2713
2714int
2715vcom_epoll_create (int __size)
2716{
2717
2718 if (vcom_init () != 0)
2719 {
2720 return -1;
2721 }
2722
2723 if (__size <= 0)
2724 {
2725 return -EINVAL;
2726 }
2727
2728 /* __size argument is ignored "thereafter" */
2729 return vcom_epoll_create1 (0);
2730}
2731
2732/*
2733 * __size argument is ignored, but must be greater than zero
2734 */
2735int
2736epoll_create (int __size)
2737{
2738 int rv = 0;
2739 pid_t pid = getpid ();
2740
2741 rv = vcom_epoll_create (__size);
2742 if (VCOM_DEBUG > 0)
2743 fprintf (stderr,
2744 "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
2745 if (rv < 0)
2746 {
2747 errno = -rv;
2748 return -1;
2749 }
2750 return rv;
2751}
2752
2753int
2754vcom_epoll_create1 (int __flags)
2755{
2756 if (vcom_init () != 0)
2757 {
2758 return -1;
2759 }
2760
2761 if (__flags < 0)
2762 {
2763 return -EINVAL;
2764 }
2765 if (__flags & ~EPOLL_CLOEXEC)
2766 {
2767 return -EINVAL;
2768 }
2769 /* __flags can be either zero or EPOLL_CLOEXEC */
2770 /* implementation */
2771 return vcom_socket_epoll_create1 (__flags);
2772}
2773
2774/*
2775 * __flags can be either zero or EPOLL_CLOEXEC
2776 * */
2777int
2778epoll_create1 (int __flags)
2779{
2780 int rv = 0;
2781 pid_t pid = getpid ();
2782
2783 rv = vcom_epoll_create1 (__flags);
2784 if (VCOM_DEBUG > 0)
2785 fprintf (stderr,
2786 "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
2787 if (rv < 0)
2788 {
2789 errno = -rv;
2790 return -1;
2791 }
2792 return rv;
2793}
2794
2795static inline int
2796ep_op_has_event (int op)
2797{
2798 return op != EPOLL_CTL_DEL;
2799}
2800
2801int
2802vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2803{
2804 if (vcom_init () != 0)
2805 {
2806 return -1;
2807 }
2808
2809 /*
2810 * the requested operation __op is not supported
2811 * by this interface */
2812 if (!((__op == EPOLL_CTL_ADD) ||
2813 (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
2814 {
2815 return -EINVAL;
2816 }
2817
2818 /* op is ADD or MOD but event parameter is NULL */
2819 if ((ep_op_has_event (__op) && !__event))
2820 {
2821 return -EFAULT;
2822 }
2823
2824 /* fd is same as epfd */
2825 /* do not permit adding an epoll file descriptor inside itself */
2826 if (__epfd == __fd)
2827 {
2828 return -EINVAL;
2829 }
2830
2831 /* implementation */
2832 return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
2833}
2834
2835/*
2836 * implement the controller interface for epoll
2837 * that enables the insertion/removal/change of
2838 * file descriptors inside the interest set.
2839 */
2840int
2841epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2842{
2843 int rv;
2844 pid_t pid = getpid ();
2845
Dave Wallacee695cb42017-11-02 22:04:42 -04002846 rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
2847 if (VCOM_DEBUG > 0)
2848 fprintf (stderr,
2849 "[%d] epoll_ctl: "
2850 "'%04d'='%04d', '%04d', '%04d'\n", pid, rv, __epfd, __op, __fd);
2851 if (rv != 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002852 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002853 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002854 return -1;
2855 }
2856 return 0;
2857}
2858
2859int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002860epoll_wait (int __epfd, struct epoll_event *__events,
2861 int __maxevents, int __timeout)
2862{
2863 int rv;
2864 pid_t pid = getpid ();
2865
2866 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2867 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002868 fprintf (stderr, "[%d] ERROR: epoll_wait() invalid maxevents %d\n",
2869 pid, __maxevents);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002870 errno = EINVAL;
2871 return -1;
2872 }
2873
Dave Wallacee695cb42017-11-02 22:04:42 -04002874 rv =
2875 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
Dave Wallace227867f2017-11-13 21:21:53 -05002876 if (VCOM_DEBUG > 2)
Dave Wallacee695cb42017-11-02 22:04:42 -04002877 fprintf (stderr,
2878 "[%d] epoll_wait: "
2879 "'%04d'='%04d', '%p', "
2880 "'%04d', '%04d'\n",
2881 pid, rv, __epfd, __events, __maxevents, __timeout);
2882 if (rv < 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002883 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002884 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002885 return -1;
2886 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002887 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002888}
2889
2890
2891int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002892epoll_pwait (int __epfd, struct epoll_event *__events,
2893 int __maxevents, int __timeout, const __sigset_t * __ss)
2894{
2895 int rv;
2896 pid_t pid = getpid ();
2897
2898 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2899 {
2900 errno = EINVAL;
2901 return -1;
2902 }
2903
2904 if (is_vcom_epfd (__epfd))
2905 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002906 rv =
2907 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout,
2908 __ss);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002909 if (VCOM_DEBUG > 0)
2910 fprintf (stderr,
2911 "[%d] epoll_pwait: "
2912 "'%04d'='%04d', '%p', "
2913 "'%04d', '%04d', "
2914 "'%p'\n",
2915 pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
2916 if (rv < 0)
2917 {
2918 errno = -rv;
2919 return -1;
2920 }
2921 return rv;
2922 }
2923 else
2924 {
2925 errno = EINVAL;
2926 return -1;
2927 }
2928
2929 return 0;
2930}
2931
2932/* Poll the file descriptors described by the NFDS structures starting at
2933 FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
2934 an event to occur; if TIMEOUT is -1, block until an event occurs.
2935 Returns the number of file descriptors with events, zero if timed out,
2936 or -1 for errors.
2937
2938 This function is a cancellation point and therefore not marked with
2939 __THROW. */
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002940
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002941int
2942vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2943{
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002944 int rv = 0;
2945 pid_t pid = getpid ();
2946
2947 struct rlimit nofile_limit;
2948 struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
2949 nfds_t fds_idx = 0;
2950
2951 /* actual set of file descriptors to be monitored */
2952 nfds_t libc_nfds = 0;
2953 nfds_t vcom_nfds = 0;
2954
2955 /* ready file descriptors
2956 *
2957 * number of structures which have nonzero revents fields
2958 * in other words, descriptors with events or errors reported.
2959 * */
2960 /* after call to libc_poll () */
2961 int rlibc_nfds = 0;
2962 /* after call to vcom_socket_poll () */
2963 int rvcom_nfds = 0;
2964
2965
2966 /* timeout value in units of timespec */
2967 struct timespec timeout_ts;
2968 struct timespec start_time, now, end_time;
2969
2970
2971 /* get start_time */
2972 rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
2973 if (rv == -1)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002974 {
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002975 rv = -errno;
2976 goto poll_done;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002977 }
2978
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002979 /* set timeout_ts & end_time */
2980 if (__timeout >= 0)
2981 {
2982 /* set timeout_ts */
2983 timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
2984 timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
2985 set_normalized_timespec (&timeout_ts,
2986 timeout_ts.tv_sec, timeout_ts.tv_nsec);
2987 /* set end_time */
2988 if (__timeout)
2989 {
2990 end_time = timespec_add (start_time, timeout_ts);
2991 }
2992 else
2993 {
2994 end_time = start_time;
2995 }
2996 }
2997
2998 if (vcom_init () != 0)
2999 {
3000 rv = -1;
3001 goto poll_done;
3002 }
3003
3004 /* validate __fds */
3005 if (!__fds)
3006 {
3007 rv = -EFAULT;
3008 goto poll_done;
3009 }
3010
3011 /* validate __nfds */
3012 /*TBD: call getrlimit once when vcl-ldpreload library is init */
3013 rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
3014 if (rv != 0)
3015 {
3016 rv = -errno;
3017 goto poll_done;
3018 }
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003019 if (__nfds >= nofile_limit.rlim_cur)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003020 {
3021 rv = -EINVAL;
3022 goto poll_done;
3023 }
3024
3025 /*
3026 * for the POC, it's fair to assume that nfds is less than 1024
3027 * */
3028 if (__nfds >= MAX_POLL_NFDS_DEFAULT)
3029 {
3030 rv = -EINVAL;
3031 goto poll_done;
3032 }
3033
3034 /* set revents field (output parameter)
3035 * to zero
3036 * */
3037 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3038 {
3039 __fds[fds_idx].revents = 0;
3040 }
3041
3042#if 0
3043 /* set revents field (output parameter)
3044 * to zero for user ignored fds
3045 * */
3046 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3047 {
3048 /*
3049 * if negative fd, ignore events field
3050 * and set output parameter (revents field) to zero */
3051 if (__fds[fds_idx].fd < 0)
3052 {
3053 __fds[fds_idx].revents = 0;
3054 }
3055 }
3056#endif
3057
3058 /*
3059 * 00. prepare __fds and vcom_fds for polling
3060 * copy __fds to vcom_fds
3061 * 01. negate all except libc fds in __fds,
3062 * ignore user negated fds
3063 * 02. negate all except vcom_fds in vocm fds,
3064 * ignore user negated fds
3065 * ignore fd 0 by setting it to negative number
3066 * */
3067 memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
3068 libc_nfds = 0;
3069 vcom_nfds = 0;
3070 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3071 {
3072 /* ignore negative fds */
3073 if (__fds[fds_idx].fd < 0)
3074 {
3075 continue;
3076 }
3077
3078 /*
3079 * 00. ignore vcom fds in __fds
3080 * 01. ignore libc fds in vcom_fds,
3081 * ignore fd 0 by setting it to negative number.
3082 * as fd 0 cannot be ignored.
3083 */
3084 if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
3085 is_vcom_epfd (__fds[fds_idx].fd))
3086 {
3087 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3088 vcom_nfds++;
3089 }
3090 else
3091 {
3092 libc_nfds++;
3093 /* ignore fd 0 by setting it to negative number */
3094 if (!vcom_fds[fds_idx].fd)
3095 {
3096 vcom_fds[fds_idx].fd = -1;
3097 }
3098 vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
3099 }
3100 }
3101
3102 /*
3103 * polling loop
3104 *
3105 * poll on libc fds and vcom fds
3106 *
3107 * specifying a timeout of zero causes libc_poll() and
3108 * vcom_socket_poll() to return immediately, even if no
3109 * file descriptors are ready
3110 * */
3111 do
3112 {
3113 rlibc_nfds = 0;
3114 rvcom_nfds = 0;
3115
3116 /*
3117 * timeout parameter for libc_poll () set to zero
3118 * to poll on libc fds
3119 * */
3120
3121 /* poll on libc fds */
3122 if (libc_nfds)
3123 {
3124 /*
3125 * a timeout of zero causes libc_poll()
3126 * to return immediately
3127 * */
3128 rlibc_nfds = libc_poll (__fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003129 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003130 fprintf (stderr,
3131 "[%d] poll libc: "
3132 "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
3133
3134 if (rlibc_nfds < 0)
3135 {
3136 rv = -errno;
3137 goto poll_done_update_nfds;
3138 }
3139 }
3140
3141 /*
3142 * timeout parameter for vcom_socket_poll () set to zero
3143 * to poll on vcom fds
3144 * */
3145
3146 /* poll on vcom fds */
3147 if (vcom_nfds)
3148 {
3149 /*
3150 * a timeout of zero causes vcom_socket_poll()
3151 * to return immediately
3152 * */
3153 rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003154 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003155 fprintf (stderr,
3156 "[%d] poll vcom: "
3157 "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
3158 if (rvcom_nfds < 0)
3159 {
3160 rv = rvcom_nfds;
3161 goto poll_done_update_nfds;
3162 }
3163 }
3164
3165 /* check if any file descriptors changed status */
3166 if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
3167 {
3168 /* something interesting happened */
3169 rv = rlibc_nfds + rvcom_nfds;
3170 goto poll_done_update_nfds;
3171 }
3172
3173 rv = clock_gettime (CLOCK_MONOTONIC, &now);
3174 if (rv == -1)
3175 {
3176 rv = -errno;
3177 goto poll_done_update_nfds;
3178 }
3179 }
3180
3181 /* block indefinitely || timeout elapsed */
3182 while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
3183
3184 /* timeout expired before anything interesting happened */
3185 rv = 0;
3186
3187poll_done_update_nfds:
3188 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3189 {
3190 /* ignore negative fds in vcom_fds
3191 * 00. user negated fds
3192 * 01. libc fds
3193 * */
3194 if (vcom_fds[fds_idx].fd < 0)
3195 {
3196 continue;
3197 }
3198
3199 /* from here on handle positive vcom fds */
3200 /*
3201 * restore vcom fds to positive number in __fds
3202 * and update revents in __fds with the events
3203 * that actually occurred in vcom fds
3204 * */
3205 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3206 if (rvcom_nfds)
3207 {
3208 __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
3209 }
3210 }
3211
3212poll_done:
Dave Wallacee22aa742017-10-20 12:30:38 -04003213 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003214 fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
3215 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003216}
3217
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003218/*
3219 * 00. The field __fds[i].fd contains a file descriptor for an
3220 * open file.
3221 * If this field is negative, then the corresponding
3222 * events field is ignored and the revents field returns zero.
3223 * The field __fds[i].events is an input parameter.
3224 * The field __fds[i].revents is an output parameter.
3225 * 01. Specifying a negative value in timeout
3226 * means an infinite timeout.
3227 * Specifying a timeout of zero causes poll() to return
3228 * immediately, even if no file descriptors are ready.
3229 *
3230 * NOTE: observed __nfds is less than 128 from kubecon strace files
3231 */
3232
3233
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003234int
3235poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3236{
3237 int rv = 0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003238 pid_t pid = getpid ();
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003239
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003240
Dave Wallacee22aa742017-10-20 12:30:38 -04003241 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003242 fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
3243 pid, rv, __nfds, __fds[0].fd, __fds[0].events);
3244 rv = vcom_poll (__fds, __nfds, __timeout);
Dave Wallacee22aa742017-10-20 12:30:38 -04003245 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003246 fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
3247 pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
3248 if (rv < 0)
3249 {
3250 errno = -rv;
3251 return -1;
3252 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003253 return rv;
3254}
3255
3256#ifdef __USE_GNU
3257/* Like poll, but before waiting the threads signal mask is replaced
3258 with that specified in the fourth parameter. For better usability,
3259 the timeout value is specified using a TIMESPEC object.
3260
3261 This function is a cancellation point and therefore not marked with
3262 __THROW. */
3263int
3264vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
3265 const struct timespec *__timeout, const __sigset_t * __ss)
3266{
3267 if (vcom_init () != 0)
3268 {
3269 return -1;
3270 }
3271
3272 return -EOPNOTSUPP;
3273}
3274
3275int
3276ppoll (struct pollfd *__fds, nfds_t __nfds,
3277 const struct timespec *__timeout, const __sigset_t * __ss)
3278{
3279 int rv = 0;
3280
3281 errno = EOPNOTSUPP;
3282 rv = -1;
3283 return rv;
3284}
3285#endif
3286
3287void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
3288
3289void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
3290
3291void
3292vcom_constructor (void)
3293{
3294 pid_t pid = getpid ();
3295
3296 swrap_constructor ();
3297 if (vcom_init () != 0)
3298 {
3299 printf ("\n[%d] vcom_constructor...failed!\n", pid);
3300 }
3301 else
3302 {
3303 printf ("\n[%d] vcom_constructor...done!\n", pid);
3304 }
3305}
3306
3307/*
3308 * This function is called when the library is unloaded
3309 */
3310void
3311vcom_destructor (void)
3312{
3313 pid_t pid = getpid ();
3314
3315 vcom_destroy ();
3316 swrap_destructor ();
3317 printf ("\n[%d] vcom_destructor...done!\n", pid);
3318}
3319
3320
3321/*
3322 * fd.io coding-style-patch-verification: ON
3323 *
3324 * Local Variables:
3325 * eval: (c-set-style "gnu")
3326 * End:
3327 */