blob: 26948d518400d57c52aee7bf78cba2f3270fe089 [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);
1954 break;
1955
1956 default:
1957 return -1;
1958 break;
1959 }
1960
1961 return rv;
1962}
1963
1964int
1965connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1966{
1967 int rv;
1968 pid_t pid = getpid ();
1969 pthread_t tid = pthread_self ();
1970
1971 if (is_vcom_socket_fd (__fd))
1972 {
1973 rv = vcom_connect (__fd, __addr, __len);
1974 if (VCOM_DEBUG > 0)
1975 fprintf (stderr,
1976 "[%d][%lu (0x%lx)] connect: "
1977 "'%04d'='%04d', '%p', '%04d'\n",
1978 pid, (unsigned long) tid, (unsigned long) tid,
1979 rv, __fd, __addr, __len);
1980 if (rv != 0)
1981 {
1982 errno = -rv;
1983 return -1;
1984 }
1985 return 0;
1986 }
1987
1988 return libc_connect (__fd, __addr, __len);
1989}
1990
1991/*
1992 * Put the address of the peer connected to socket FD into *ADDR
1993 * (which is *LEN bytes long), and its actual length into *LEN.
1994 * */
1995int
1996vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
1997 socklen_t * __restrict __len)
1998{
1999 if (vcom_init () != 0)
2000 {
2001 return -1;
2002 }
2003
2004 return vcom_socket_getpeername (__fd, __addr, __len);
2005}
2006
2007int
2008getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
2009{
2010 int rv;
2011 pid_t pid = getpid ();
2012
2013 if (is_vcom_socket_fd (__fd))
2014 {
2015 rv = vcom_getpeername (__fd, __addr, __len);
2016 if (VCOM_DEBUG > 0)
2017 fprintf (stderr,
2018 "[%d] getpeername: "
2019 "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
2020 if (rv != 0)
2021 {
2022 errno = -rv;
2023 return -1;
2024 }
2025 return 0;
2026 }
2027 return libc_getpeername (__fd, __addr, __len);
2028}
2029
2030/*
2031 * Send N bytes of BUF to socket FD. Returns the number sent or -1.
2032 * This function is a cancellation point and therefore not marked
2033 * with __THROW.
2034 * */
2035ssize_t
2036vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
2037{
2038
2039 if (vcom_init () != 0)
2040 {
2041 return -1;
2042 }
2043
2044 return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
2045}
2046
2047ssize_t
2048send (int __fd, const void *__buf, size_t __n, int __flags)
2049{
2050 ssize_t size;
2051 pid_t pid = getpid ();
2052
2053 if (is_vcom_socket_fd (__fd))
2054 {
2055 size = vcom_send (__fd, __buf, __n, __flags);
2056 if (VCOM_DEBUG > 0)
2057 fprintf (stderr,
2058 "[%d] send: "
2059 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2060 pid, (int) size, __fd, __buf, (int) __n, __flags);
2061 if (size < 0)
2062 {
2063 errno = -size;
2064 return -1;
2065 }
2066 return size;
2067 }
2068 return libc_send (__fd, __buf, __n, __flags);
2069}
2070
Dave Wallace227867f2017-11-13 21:21:53 -05002071ssize_t
2072sendfile (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2073{
2074 ssize_t size;
2075
2076 if (VCOM_DEBUG > 2)
2077 clib_warning ("[%d] __out_fd %d, __in_fd %d, __offset %p, __len %ld",
2078 getpid (), __out_fd, __in_fd, __offset, __len);
2079
2080 if (is_vcom_socket_fd (__out_fd))
2081 {
2082 /* TBD: refactor this check to be part of is_vcom_socket_fd() */
2083 if (vcom_init () != 0)
2084 return -1;
2085
2086 size = vcom_socket_sendfile (__out_fd, __in_fd, __offset, __len);
2087 if (VCOM_DEBUG > 2)
2088 clib_warning ("[%d] vcom_socket_sendfile (out_fd %d, in_fd %d, "
2089 "offset %p (%ld), len %lu) returned %ld",
2090 getpid (), __out_fd, __in_fd, __offset,
2091 __offset ? *__offset : -1, __len, size);
2092 if (size < 0)
2093 {
2094 errno = -size;
2095 return -1;
2096 }
2097 return size;
2098 }
2099 if (VCOM_DEBUG > 2)
2100 clib_warning ("[%d] calling libc_sendfile!", getpid ());
2101 return libc_sendfile (__out_fd, __in_fd, __offset, __len);
2102}
2103
2104ssize_t
2105sendfile64 (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2106{
2107 return sendfile (__out_fd, __in_fd, __offset, __len);
2108}
2109
2110
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002111/*
2112 * Read N bytes into BUF from socket FD.
2113 * Returns the number read or -1 for errors.
2114 * This function is a cancellation point and therefore not marked
2115 * with __THROW.
2116 * */
2117ssize_t
2118vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
2119{
2120 if (vcom_init () != 0)
2121 {
2122 return -1;
2123 }
2124
2125 return vcom_socket_recv (__fd, __buf, __n, __flags);
2126}
2127
2128ssize_t
2129recv (int __fd, void *__buf, size_t __n, int __flags)
2130{
2131 ssize_t size;
2132 pid_t pid = getpid ();
2133
2134 if (is_vcom_socket_fd (__fd))
2135 {
2136 size = vcom_recv (__fd, __buf, __n, __flags);
2137 if (VCOM_DEBUG > 0)
2138 fprintf (stderr,
2139 "[%d] recv: "
2140 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2141 pid, (int) size, __fd, __buf, (int) __n, __flags);
2142 if (size < 0)
2143 {
2144 errno = -size;
2145 return -1;
2146 }
2147 return size;
2148 }
2149 return libc_recv (__fd, __buf, __n, __flags);
2150}
2151
2152/*
2153 * Send N bytes of BUF on socket FD to peer at address ADDR (which is
2154 * ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
2155 * This function is a cancellation point and therefore not marked
2156 * with __THROW.
2157 * */
2158ssize_t
2159vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
2160 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2161{
2162 if (vcom_init () != 0)
2163 {
2164 return -1;
2165 }
2166
2167 return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2168}
2169
2170ssize_t
2171sendto (int __fd, const void *__buf, size_t __n, int __flags,
2172 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2173{
2174 ssize_t size;
2175 pid_t pid = getpid ();
2176
2177 if (is_vcom_socket_fd (__fd))
2178 {
2179 size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2180 if (VCOM_DEBUG > 0)
2181 fprintf (stderr,
2182 "[%d] sendto: "
2183 "'%04d'='%04d', '%p', '%04d', '%04x', "
2184 "'%p', '%04d'\n",
2185 pid, (int) size, __fd, __buf, (int) __n, __flags,
2186 __addr, __addr_len);
2187 if (size < 0)
2188 {
2189 errno = -size;
2190 return -1;
2191 }
2192 return size;
2193 }
2194 return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2195}
2196
2197/*
2198 * Read N bytes into BUF through socket FD.
2199 * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
2200 * address of the sender, and store the actual size of the address
2201 * in *ADDR_LEN.
2202 * Returns the number of bytes read or -1 for errors.
2203 * This function is a cancellation point and therefore not marked
2204 * with __THROW.
2205 * */
2206ssize_t
2207vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
2208 int __flags,
2209 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2210{
2211 if (vcom_init () != 0)
2212 {
2213 return -1;
2214 }
2215
2216 return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2217}
2218
2219ssize_t
2220recvfrom (int __fd, void *__restrict __buf, size_t __n,
2221 int __flags,
2222 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2223{
2224 ssize_t size;
2225 pid_t pid = getpid ();
2226
2227 if (is_vcom_socket_fd (__fd))
2228 {
2229 size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2230 if (VCOM_DEBUG > 0)
2231 fprintf (stderr,
2232 "[%d] recvfrom: "
2233 "'%04d'='%04d', '%p', '%04d', '%04x', "
2234 "'%p', '%p'\n",
2235 pid, (int) size, __fd, __buf, (int) __n, __flags,
2236 __addr, __addr_len);
2237 if (size < 0)
2238 {
2239 errno = -size;
2240 return -1;
2241 }
2242 return size;
2243 }
2244 return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2245}
2246
2247/*
2248 * Send a message described MESSAGE on socket FD.
2249 * Returns the number of bytes sent, or -1 for errors.
2250 * This function is a cancellation point and therefore not marked
2251 * with __THROW.
2252 * */
2253ssize_t
2254vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
2255{
2256 if (vcom_init () != 0)
2257 {
2258 return -1;
2259 }
2260
2261 return vcom_socket_sendmsg (__fd, __message, __flags);
2262}
2263
2264ssize_t
2265sendmsg (int __fd, const struct msghdr * __message, int __flags)
2266{
2267 ssize_t size;
2268 pid_t pid = getpid ();
2269
2270 if (is_vcom_socket_fd (__fd))
2271 {
2272 size = vcom_sendmsg (__fd, __message, __flags);
2273 if (VCOM_DEBUG > 0)
2274 fprintf (stderr,
2275 "[%d] sendmsg: "
2276 "'%04d'='%04d', '%p', '%04x'\n",
2277 pid, (int) size, __fd, __message, __flags);
2278 if (size < 0)
2279 {
2280 errno = -size;
2281 return -1;
2282 }
2283 return size;
2284 }
2285 return libc_sendmsg (__fd, __message, __flags);
2286}
2287
2288#ifdef __USE_GNU
2289/*
2290 * Send a VLEN messages as described by VMESSAGES to socket FD.
2291 * Returns the number of datagrams successfully written
2292 * or -1 for errors.
2293 * This function is a cancellation point and therefore not marked
2294 * with __THROW.
2295 * */
2296int
2297vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
2298 unsigned int __vlen, int __flags)
2299{
2300 if (vcom_init () != 0)
2301 {
2302 return -1;
2303 }
2304
2305 return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
2306}
2307
2308int
2309sendmmsg (int __fd, struct mmsghdr *__vmessages,
2310 unsigned int __vlen, int __flags)
2311{
2312 ssize_t size;
2313 pid_t pid = getpid ();
2314
2315 if (is_vcom_socket_fd (__fd))
2316 {
2317 size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
2318 if (VCOM_DEBUG > 0)
2319 fprintf (stderr,
2320 "[%d] sendmmsg: "
2321 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2322 pid, (int) size, __fd, __vmessages, __vlen, __flags);
2323 if (size < 0)
2324 {
2325 errno = -size;
2326 return -1;
2327 }
2328 return size;
2329 }
2330 return libc_sendmmsg (__fd, __message, __vlen, __flags);
2331}
2332
2333#endif
2334
2335/*
2336 * Receive a message as described by MESSAGE from socket FD.
2337 * Returns the number of bytes read or -1 for errors.
2338 * This function is a cancellation point and therefore not marked
2339 * with __THROW.
2340 * */
2341ssize_t
2342vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
2343{
2344 if (vcom_init () != 0)
2345 {
2346 return -1;
2347 }
2348
2349 return vcom_socket_recvmsg (__fd, __message, __flags);
2350}
2351
2352ssize_t
2353recvmsg (int __fd, struct msghdr * __message, int __flags)
2354{
2355 ssize_t size;
2356 pid_t pid = getpid ();
2357
2358 if (is_vcom_socket_fd (__fd))
2359 {
2360 size = vcom_recvmsg (__fd, __message, __flags);
2361 if (VCOM_DEBUG > 0)
2362 fprintf (stderr,
2363 "[%d] recvmsg: "
2364 "'%04d'='%04d', '%p', '%04x'\n",
2365 pid, (int) size, __fd, __message, __flags);
2366 if (size < 0)
2367 {
2368 errno = -size;
2369 return -1;
2370 }
2371 return size;
2372 }
2373 return libc_recvmsg (__fd, __message, __flags);
2374}
2375
2376#ifdef __USE_GNU
2377/*
2378 * Receive up to VLEN messages as described by VMESSAGES from socket FD.
2379 * Returns the number of messages received or -1 for errors.
2380 * This function is a cancellation point and therefore not marked
2381 * with __THROW.
2382 * */
2383int
2384vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
2385 unsigned int __vlen, int __flags, struct timespec *__tmo)
2386{
2387 if (vcom_init () != 0)
2388 {
2389 return -1;
2390 }
2391
2392 return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2393}
2394
2395int
2396recvmmsg (int __fd, struct mmsghdr *__vmessages,
2397 unsigned int __vlen, int __flags, struct timespec *__tmo)
2398{
2399 ssize_t size;
2400 pid_t pid = getpid ();
2401
2402 if (is_vcom_socket_fd (__fd))
2403 {
2404 size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2405 if (VCOM_DEBUG > 0)
2406 fprintf (stderr,
2407 "[%d] recvmmsg: "
2408 "'%04d'='%04d', '%p', "
2409 "'%04d', '%04x', '%p'\n",
2410 pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
2411 if (size < 0)
2412 {
2413 errno = -size;
2414 return -1;
2415 }
2416 return size;
2417 }
2418 return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2419}
2420
2421#endif
2422
2423/*
2424 * Put the current value for socket FD's option OPTNAME
2425 * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
2426 * and set *OPTLEN to the value's actual length.
2427 * Returns 0 on success, -1 for errors.
2428 * */
2429int
2430vcom_getsockopt (int __fd, int __level, int __optname,
2431 void *__restrict __optval, socklen_t * __restrict __optlen)
2432{
2433 if (vcom_init () != 0)
2434 {
2435 return -1;
2436 }
2437
2438 return vcom_socket_getsockopt (__fd, __level, __optname,
2439 __optval, __optlen);
2440}
2441
2442int
2443getsockopt (int __fd, int __level, int __optname,
2444 void *__restrict __optval, socklen_t * __restrict __optlen)
2445{
2446 int rv;
2447 pid_t pid = getpid ();
2448
2449 if (is_vcom_socket_fd (__fd))
2450 {
2451 rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
Dave Wallacee22aa742017-10-20 12:30:38 -04002452 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002453 fprintf (stderr,
2454 "[%d] getsockopt: "
2455 "'%04d'='%04d', '%04d', '%04d', "
2456 "'%p', '%p'\n",
2457 pid, rv, __fd, __level, __optname, __optval, __optlen);
2458 if (rv != 0)
2459 {
2460 errno = -rv;
2461 return -1;
2462 }
2463 return 0;
2464 }
2465 return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2466}
2467
2468/*
2469 * Set socket FD's option OPTNAME at protocol level LEVEL
2470 * to *OPTVAL (which is OPTLEN bytes long).
2471 * Returns 0 on success, -1 for errors.
2472 * */
2473int
2474vcom_setsockopt (int __fd, int __level, int __optname,
2475 const void *__optval, socklen_t __optlen)
2476{
2477 if (vcom_init () != 0)
2478 {
2479 return -1;
2480 }
2481
2482 return vcom_socket_setsockopt (__fd, __level, __optname,
2483 __optval, __optlen);
2484}
2485
2486int
2487setsockopt (int __fd, int __level, int __optname,
2488 const void *__optval, socklen_t __optlen)
2489{
2490 int rv;
2491 pid_t pid = getpid ();
2492
2493 if (is_vcom_socket_fd (__fd))
2494 {
2495 rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
2496 if (VCOM_DEBUG > 0)
2497 fprintf (stderr,
2498 "[%d] setsockopt: "
2499 "'%04d'='%04d', '%04d', '%04d', "
2500 "'%p', '%04d'\n",
2501 pid, rv, __fd, __level, __optname, __optval, __optlen);
2502 if (rv != 0)
2503 {
2504 errno = -rv;
2505 return -1;
2506 }
2507 return 0;
2508 }
2509 return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2510}
2511
2512/*
2513 * Prepare to accept connections on socket FD.
2514 * N connection requests will be queued before further
2515 * requests are refused.
2516 * Returns 0 on success, -1 for errors.
2517 * */
2518int
2519vcom_listen (int __fd, int __n)
2520{
2521 if (vcom_init () != 0)
2522 {
2523 return -1;
2524 }
2525
2526 return vcom_socket_listen (__fd, __n);
2527}
2528
2529int
2530listen (int __fd, int __n)
2531{
2532 int rv;
2533 pid_t pid = getpid ();
2534
2535 if (is_vcom_socket_fd (__fd))
2536 {
2537 rv = vcom_listen (__fd, __n);
2538 if (VCOM_DEBUG > 0)
2539 fprintf (stderr,
2540 "[%d] listen: "
2541 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
2542 if (rv != 0)
2543 {
2544 errno = -rv;
2545 return -1;
2546 }
2547 return 0;
2548 }
2549 return libc_listen (__fd, __n);
2550}
2551
2552/*
2553 * Await a connection on socket FD.
2554 * When a connection arrives, open a new socket to communicate
2555 * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
2556 * of the connecting peer and *ADDR_LEN to the address's actual
2557 * length, and return the new socket's descriptor, or -1 for errors.
2558 * This function is a cancellation point and therefore not marked
2559 * with __THROW.
2560 * */
2561int
2562vcom_accept (int __fd, __SOCKADDR_ARG __addr,
2563 socklen_t * __restrict __addr_len)
2564{
2565
2566 if (vcom_init () != 0)
2567 {
2568 return -1;
2569 }
2570 return vcom_socket_accept (__fd, __addr, __addr_len);
2571}
2572
2573int
2574accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2575{
2576 int rv = -1;
2577 pid_t pid = getpid ();
2578 pthread_t tid = pthread_self ();
2579
2580 if (is_vcom_socket_fd (__fd))
2581 {
2582 if (VCOM_DEBUG > 0)
2583 vcom_socket_main_show ();
2584 if (VCOM_DEBUG > 0)
2585 fprintf (stderr,
2586 "[%d][%lu (0x%lx)] accept1: "
2587 "'%04d'='%04d', '%p', '%p'\n",
2588 pid, (unsigned long) tid, (unsigned long) tid,
2589 rv, __fd, __addr, __addr_len);
2590 rv = vcom_accept (__fd, __addr, __addr_len);
2591 if (VCOM_DEBUG > 0)
2592 fprintf (stderr,
2593 "[%d][%lu (0x%lx)] accept2: "
2594 "'%04d'='%04d', '%p', '%p'\n",
2595 pid, (unsigned long) tid, (unsigned long) tid,
2596 rv, __fd, __addr, __addr_len);
2597 if (VCOM_DEBUG > 0)
2598 vcom_socket_main_show ();
2599 if (rv < 0)
2600 {
2601 errno = -rv;
2602 return -1;
2603 }
2604 return rv;
2605 }
2606 return libc_accept (__fd, __addr, __addr_len);
2607}
2608
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002609/*
2610 * Similar to 'accept' but takes an additional parameter to specify
2611 * flags.
2612 * This function is a cancellation point and therefore not marked
2613 * with __THROW.
2614 * */
2615int
2616vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
2617 socklen_t * __restrict __addr_len, int __flags)
2618{
2619
2620 if (vcom_init () != 0)
2621 {
2622 return -1;
2623 }
2624
2625 return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
2626}
2627
2628int
2629accept4 (int __fd, __SOCKADDR_ARG __addr,
2630 socklen_t * __restrict __addr_len, int __flags)
2631{
Dave Wallace59179392017-11-07 02:20:07 -05002632 int rv = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002633 pid_t pid = getpid ();
2634
Dave Wallace59179392017-11-07 02:20:07 -05002635 fprintf (stderr,
2636 "[%d] accept4: in the beginning... "
2637 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2638 pid, rv, __fd, __addr, __addr_len, __flags);
2639
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002640 if (is_vcom_socket_fd (__fd))
2641 {
2642 if (VCOM_DEBUG > 0)
2643 vcom_socket_main_show ();
2644 rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
2645 if (VCOM_DEBUG > 0)
2646 fprintf (stderr,
Dave Wallace59179392017-11-07 02:20:07 -05002647 "[%d] accept4: VCL "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002648 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2649 pid, rv, __fd, __addr, __addr_len, __flags);
2650 if (VCOM_DEBUG > 0)
2651 vcom_socket_main_show ();
2652 if (rv < 0)
2653 {
2654 errno = -rv;
2655 return -1;
2656 }
2657 return rv;
2658 }
Dave Wallace59179392017-11-07 02:20:07 -05002659 fprintf (stderr,
2660 "[%d] accept4: libc "
2661 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2662 pid, rv, __fd, __addr, __addr_len, __flags);
2663
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002664 return libc_accept4 (__fd, __addr, __addr_len, __flags);
2665}
2666
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002667/*
2668 * Shut down all or part of the connection open on socket FD.
2669 * HOW determines what to shut down:
2670 * SHUT_RD = No more receptions;
2671 * SHUT_WR = No more transmissions;
2672 * SHUT_RDWR = No more receptions or transmissions.
2673 * Returns 0 on success, -1 for errors.
2674 * */
2675int
2676vcom_shutdown (int __fd, int __how)
2677{
2678 if (vcom_init () != 0)
2679 {
2680 return -1;
2681 }
2682 return vcom_socket_shutdown (__fd, __how);
2683}
2684
2685int
2686shutdown (int __fd, int __how)
2687{
2688 int rv;
2689 pid_t pid = getpid ();
2690
2691 if (is_vcom_socket_fd (__fd))
2692 {
2693 rv = vcom_shutdown (__fd, __how);
2694 if (VCOM_DEBUG > 0)
2695 fprintf (stderr,
2696 "[%d] shutdown: "
2697 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
2698 if (rv != 0)
2699 {
2700 errno = -rv;
2701 return -1;
2702 }
2703 return 0;
2704 }
2705 return libc_shutdown (__fd, __how);
2706}
2707
2708int
2709vcom_epoll_create (int __size)
2710{
2711
2712 if (vcom_init () != 0)
2713 {
2714 return -1;
2715 }
2716
2717 if (__size <= 0)
2718 {
2719 return -EINVAL;
2720 }
2721
2722 /* __size argument is ignored "thereafter" */
2723 return vcom_epoll_create1 (0);
2724}
2725
2726/*
2727 * __size argument is ignored, but must be greater than zero
2728 */
2729int
2730epoll_create (int __size)
2731{
2732 int rv = 0;
2733 pid_t pid = getpid ();
2734
2735 rv = vcom_epoll_create (__size);
2736 if (VCOM_DEBUG > 0)
2737 fprintf (stderr,
2738 "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
2739 if (rv < 0)
2740 {
2741 errno = -rv;
2742 return -1;
2743 }
2744 return rv;
2745}
2746
2747int
2748vcom_epoll_create1 (int __flags)
2749{
2750 if (vcom_init () != 0)
2751 {
2752 return -1;
2753 }
2754
2755 if (__flags < 0)
2756 {
2757 return -EINVAL;
2758 }
2759 if (__flags & ~EPOLL_CLOEXEC)
2760 {
2761 return -EINVAL;
2762 }
2763 /* __flags can be either zero or EPOLL_CLOEXEC */
2764 /* implementation */
2765 return vcom_socket_epoll_create1 (__flags);
2766}
2767
2768/*
2769 * __flags can be either zero or EPOLL_CLOEXEC
2770 * */
2771int
2772epoll_create1 (int __flags)
2773{
2774 int rv = 0;
2775 pid_t pid = getpid ();
2776
2777 rv = vcom_epoll_create1 (__flags);
2778 if (VCOM_DEBUG > 0)
2779 fprintf (stderr,
2780 "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
2781 if (rv < 0)
2782 {
2783 errno = -rv;
2784 return -1;
2785 }
2786 return rv;
2787}
2788
2789static inline int
2790ep_op_has_event (int op)
2791{
2792 return op != EPOLL_CTL_DEL;
2793}
2794
2795int
2796vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2797{
2798 if (vcom_init () != 0)
2799 {
2800 return -1;
2801 }
2802
2803 /*
2804 * the requested operation __op is not supported
2805 * by this interface */
2806 if (!((__op == EPOLL_CTL_ADD) ||
2807 (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
2808 {
2809 return -EINVAL;
2810 }
2811
2812 /* op is ADD or MOD but event parameter is NULL */
2813 if ((ep_op_has_event (__op) && !__event))
2814 {
2815 return -EFAULT;
2816 }
2817
2818 /* fd is same as epfd */
2819 /* do not permit adding an epoll file descriptor inside itself */
2820 if (__epfd == __fd)
2821 {
2822 return -EINVAL;
2823 }
2824
2825 /* implementation */
2826 return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
2827}
2828
2829/*
2830 * implement the controller interface for epoll
2831 * that enables the insertion/removal/change of
2832 * file descriptors inside the interest set.
2833 */
2834int
2835epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2836{
2837 int rv;
2838 pid_t pid = getpid ();
2839
Dave Wallacee695cb42017-11-02 22:04:42 -04002840 rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
2841 if (VCOM_DEBUG > 0)
2842 fprintf (stderr,
2843 "[%d] epoll_ctl: "
2844 "'%04d'='%04d', '%04d', '%04d'\n", pid, rv, __epfd, __op, __fd);
2845 if (rv != 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002846 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002847 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002848 return -1;
2849 }
2850 return 0;
2851}
2852
2853int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002854epoll_wait (int __epfd, struct epoll_event *__events,
2855 int __maxevents, int __timeout)
2856{
2857 int rv;
2858 pid_t pid = getpid ();
2859
2860 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2861 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002862 fprintf (stderr, "[%d] ERROR: epoll_wait() invalid maxevents %d\n",
2863 pid, __maxevents);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002864 errno = EINVAL;
2865 return -1;
2866 }
2867
Dave Wallacee695cb42017-11-02 22:04:42 -04002868 rv =
2869 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
Dave Wallace227867f2017-11-13 21:21:53 -05002870 if (VCOM_DEBUG > 2)
Dave Wallacee695cb42017-11-02 22:04:42 -04002871 fprintf (stderr,
2872 "[%d] epoll_wait: "
2873 "'%04d'='%04d', '%p', "
2874 "'%04d', '%04d'\n",
2875 pid, rv, __epfd, __events, __maxevents, __timeout);
2876 if (rv < 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002877 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002878 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002879 return -1;
2880 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002881 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002882}
2883
2884
2885int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002886epoll_pwait (int __epfd, struct epoll_event *__events,
2887 int __maxevents, int __timeout, const __sigset_t * __ss)
2888{
2889 int rv;
2890 pid_t pid = getpid ();
2891
2892 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2893 {
2894 errno = EINVAL;
2895 return -1;
2896 }
2897
2898 if (is_vcom_epfd (__epfd))
2899 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002900 rv =
2901 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout,
2902 __ss);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002903 if (VCOM_DEBUG > 0)
2904 fprintf (stderr,
2905 "[%d] epoll_pwait: "
2906 "'%04d'='%04d', '%p', "
2907 "'%04d', '%04d', "
2908 "'%p'\n",
2909 pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
2910 if (rv < 0)
2911 {
2912 errno = -rv;
2913 return -1;
2914 }
2915 return rv;
2916 }
2917 else
2918 {
2919 errno = EINVAL;
2920 return -1;
2921 }
2922
2923 return 0;
2924}
2925
2926/* Poll the file descriptors described by the NFDS structures starting at
2927 FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
2928 an event to occur; if TIMEOUT is -1, block until an event occurs.
2929 Returns the number of file descriptors with events, zero if timed out,
2930 or -1 for errors.
2931
2932 This function is a cancellation point and therefore not marked with
2933 __THROW. */
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002934
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002935int
2936vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2937{
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002938 int rv = 0;
2939 pid_t pid = getpid ();
2940
2941 struct rlimit nofile_limit;
2942 struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
2943 nfds_t fds_idx = 0;
2944
2945 /* actual set of file descriptors to be monitored */
2946 nfds_t libc_nfds = 0;
2947 nfds_t vcom_nfds = 0;
2948
2949 /* ready file descriptors
2950 *
2951 * number of structures which have nonzero revents fields
2952 * in other words, descriptors with events or errors reported.
2953 * */
2954 /* after call to libc_poll () */
2955 int rlibc_nfds = 0;
2956 /* after call to vcom_socket_poll () */
2957 int rvcom_nfds = 0;
2958
2959
2960 /* timeout value in units of timespec */
2961 struct timespec timeout_ts;
2962 struct timespec start_time, now, end_time;
2963
2964
2965 /* get start_time */
2966 rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
2967 if (rv == -1)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002968 {
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002969 rv = -errno;
2970 goto poll_done;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002971 }
2972
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002973 /* set timeout_ts & end_time */
2974 if (__timeout >= 0)
2975 {
2976 /* set timeout_ts */
2977 timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
2978 timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
2979 set_normalized_timespec (&timeout_ts,
2980 timeout_ts.tv_sec, timeout_ts.tv_nsec);
2981 /* set end_time */
2982 if (__timeout)
2983 {
2984 end_time = timespec_add (start_time, timeout_ts);
2985 }
2986 else
2987 {
2988 end_time = start_time;
2989 }
2990 }
2991
2992 if (vcom_init () != 0)
2993 {
2994 rv = -1;
2995 goto poll_done;
2996 }
2997
2998 /* validate __fds */
2999 if (!__fds)
3000 {
3001 rv = -EFAULT;
3002 goto poll_done;
3003 }
3004
3005 /* validate __nfds */
3006 /*TBD: call getrlimit once when vcl-ldpreload library is init */
3007 rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
3008 if (rv != 0)
3009 {
3010 rv = -errno;
3011 goto poll_done;
3012 }
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003013 if (__nfds >= nofile_limit.rlim_cur)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003014 {
3015 rv = -EINVAL;
3016 goto poll_done;
3017 }
3018
3019 /*
3020 * for the POC, it's fair to assume that nfds is less than 1024
3021 * */
3022 if (__nfds >= MAX_POLL_NFDS_DEFAULT)
3023 {
3024 rv = -EINVAL;
3025 goto poll_done;
3026 }
3027
3028 /* set revents field (output parameter)
3029 * to zero
3030 * */
3031 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3032 {
3033 __fds[fds_idx].revents = 0;
3034 }
3035
3036#if 0
3037 /* set revents field (output parameter)
3038 * to zero for user ignored fds
3039 * */
3040 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3041 {
3042 /*
3043 * if negative fd, ignore events field
3044 * and set output parameter (revents field) to zero */
3045 if (__fds[fds_idx].fd < 0)
3046 {
3047 __fds[fds_idx].revents = 0;
3048 }
3049 }
3050#endif
3051
3052 /*
3053 * 00. prepare __fds and vcom_fds for polling
3054 * copy __fds to vcom_fds
3055 * 01. negate all except libc fds in __fds,
3056 * ignore user negated fds
3057 * 02. negate all except vcom_fds in vocm fds,
3058 * ignore user negated fds
3059 * ignore fd 0 by setting it to negative number
3060 * */
3061 memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
3062 libc_nfds = 0;
3063 vcom_nfds = 0;
3064 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3065 {
3066 /* ignore negative fds */
3067 if (__fds[fds_idx].fd < 0)
3068 {
3069 continue;
3070 }
3071
3072 /*
3073 * 00. ignore vcom fds in __fds
3074 * 01. ignore libc fds in vcom_fds,
3075 * ignore fd 0 by setting it to negative number.
3076 * as fd 0 cannot be ignored.
3077 */
3078 if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
3079 is_vcom_epfd (__fds[fds_idx].fd))
3080 {
3081 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3082 vcom_nfds++;
3083 }
3084 else
3085 {
3086 libc_nfds++;
3087 /* ignore fd 0 by setting it to negative number */
3088 if (!vcom_fds[fds_idx].fd)
3089 {
3090 vcom_fds[fds_idx].fd = -1;
3091 }
3092 vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
3093 }
3094 }
3095
3096 /*
3097 * polling loop
3098 *
3099 * poll on libc fds and vcom fds
3100 *
3101 * specifying a timeout of zero causes libc_poll() and
3102 * vcom_socket_poll() to return immediately, even if no
3103 * file descriptors are ready
3104 * */
3105 do
3106 {
3107 rlibc_nfds = 0;
3108 rvcom_nfds = 0;
3109
3110 /*
3111 * timeout parameter for libc_poll () set to zero
3112 * to poll on libc fds
3113 * */
3114
3115 /* poll on libc fds */
3116 if (libc_nfds)
3117 {
3118 /*
3119 * a timeout of zero causes libc_poll()
3120 * to return immediately
3121 * */
3122 rlibc_nfds = libc_poll (__fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003123 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003124 fprintf (stderr,
3125 "[%d] poll libc: "
3126 "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
3127
3128 if (rlibc_nfds < 0)
3129 {
3130 rv = -errno;
3131 goto poll_done_update_nfds;
3132 }
3133 }
3134
3135 /*
3136 * timeout parameter for vcom_socket_poll () set to zero
3137 * to poll on vcom fds
3138 * */
3139
3140 /* poll on vcom fds */
3141 if (vcom_nfds)
3142 {
3143 /*
3144 * a timeout of zero causes vcom_socket_poll()
3145 * to return immediately
3146 * */
3147 rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003148 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003149 fprintf (stderr,
3150 "[%d] poll vcom: "
3151 "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
3152 if (rvcom_nfds < 0)
3153 {
3154 rv = rvcom_nfds;
3155 goto poll_done_update_nfds;
3156 }
3157 }
3158
3159 /* check if any file descriptors changed status */
3160 if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
3161 {
3162 /* something interesting happened */
3163 rv = rlibc_nfds + rvcom_nfds;
3164 goto poll_done_update_nfds;
3165 }
3166
3167 rv = clock_gettime (CLOCK_MONOTONIC, &now);
3168 if (rv == -1)
3169 {
3170 rv = -errno;
3171 goto poll_done_update_nfds;
3172 }
3173 }
3174
3175 /* block indefinitely || timeout elapsed */
3176 while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
3177
3178 /* timeout expired before anything interesting happened */
3179 rv = 0;
3180
3181poll_done_update_nfds:
3182 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3183 {
3184 /* ignore negative fds in vcom_fds
3185 * 00. user negated fds
3186 * 01. libc fds
3187 * */
3188 if (vcom_fds[fds_idx].fd < 0)
3189 {
3190 continue;
3191 }
3192
3193 /* from here on handle positive vcom fds */
3194 /*
3195 * restore vcom fds to positive number in __fds
3196 * and update revents in __fds with the events
3197 * that actually occurred in vcom fds
3198 * */
3199 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3200 if (rvcom_nfds)
3201 {
3202 __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
3203 }
3204 }
3205
3206poll_done:
Dave Wallacee22aa742017-10-20 12:30:38 -04003207 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003208 fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
3209 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003210}
3211
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003212/*
3213 * 00. The field __fds[i].fd contains a file descriptor for an
3214 * open file.
3215 * If this field is negative, then the corresponding
3216 * events field is ignored and the revents field returns zero.
3217 * The field __fds[i].events is an input parameter.
3218 * The field __fds[i].revents is an output parameter.
3219 * 01. Specifying a negative value in timeout
3220 * means an infinite timeout.
3221 * Specifying a timeout of zero causes poll() to return
3222 * immediately, even if no file descriptors are ready.
3223 *
3224 * NOTE: observed __nfds is less than 128 from kubecon strace files
3225 */
3226
3227
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003228int
3229poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3230{
3231 int rv = 0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003232 pid_t pid = getpid ();
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003233
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003234
Dave Wallacee22aa742017-10-20 12:30:38 -04003235 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003236 fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
3237 pid, rv, __nfds, __fds[0].fd, __fds[0].events);
3238 rv = vcom_poll (__fds, __nfds, __timeout);
Dave Wallacee22aa742017-10-20 12:30:38 -04003239 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003240 fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
3241 pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
3242 if (rv < 0)
3243 {
3244 errno = -rv;
3245 return -1;
3246 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003247 return rv;
3248}
3249
3250#ifdef __USE_GNU
3251/* Like poll, but before waiting the threads signal mask is replaced
3252 with that specified in the fourth parameter. For better usability,
3253 the timeout value is specified using a TIMESPEC object.
3254
3255 This function is a cancellation point and therefore not marked with
3256 __THROW. */
3257int
3258vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
3259 const struct timespec *__timeout, const __sigset_t * __ss)
3260{
3261 if (vcom_init () != 0)
3262 {
3263 return -1;
3264 }
3265
3266 return -EOPNOTSUPP;
3267}
3268
3269int
3270ppoll (struct pollfd *__fds, nfds_t __nfds,
3271 const struct timespec *__timeout, const __sigset_t * __ss)
3272{
3273 int rv = 0;
3274
3275 errno = EOPNOTSUPP;
3276 rv = -1;
3277 return rv;
3278}
3279#endif
3280
3281void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
3282
3283void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
3284
3285void
3286vcom_constructor (void)
3287{
3288 pid_t pid = getpid ();
3289
3290 swrap_constructor ();
3291 if (vcom_init () != 0)
3292 {
3293 printf ("\n[%d] vcom_constructor...failed!\n", pid);
3294 }
3295 else
3296 {
3297 printf ("\n[%d] vcom_constructor...done!\n", pid);
3298 }
3299}
3300
3301/*
3302 * This function is called when the library is unloaded
3303 */
3304void
3305vcom_destructor (void)
3306{
3307 pid_t pid = getpid ();
3308
3309 vcom_destroy ();
3310 swrap_destructor ();
3311 printf ("\n[%d] vcom_destructor...done!\n", pid);
3312}
3313
3314
3315/*
3316 * fd.io coding-style-patch-verification: ON
3317 *
3318 * Local Variables:
3319 * eval: (c-set-style "gnu")
3320 * End:
3321 */