blob: 624f0247e4752ff7ff14cab07745e2240ec92534 [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
101vcom_init ()
102{
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
2071/*
2072 * Read N bytes into BUF from socket FD.
2073 * Returns the number read or -1 for errors.
2074 * This function is a cancellation point and therefore not marked
2075 * with __THROW.
2076 * */
2077ssize_t
2078vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
2079{
2080 if (vcom_init () != 0)
2081 {
2082 return -1;
2083 }
2084
2085 return vcom_socket_recv (__fd, __buf, __n, __flags);
2086}
2087
2088ssize_t
2089recv (int __fd, void *__buf, size_t __n, int __flags)
2090{
2091 ssize_t size;
2092 pid_t pid = getpid ();
2093
2094 if (is_vcom_socket_fd (__fd))
2095 {
2096 size = vcom_recv (__fd, __buf, __n, __flags);
2097 if (VCOM_DEBUG > 0)
2098 fprintf (stderr,
2099 "[%d] recv: "
2100 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2101 pid, (int) size, __fd, __buf, (int) __n, __flags);
2102 if (size < 0)
2103 {
2104 errno = -size;
2105 return -1;
2106 }
2107 return size;
2108 }
2109 return libc_recv (__fd, __buf, __n, __flags);
2110}
2111
2112/*
2113 * Send N bytes of BUF on socket FD to peer at address ADDR (which is
2114 * ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
2115 * This function is a cancellation point and therefore not marked
2116 * with __THROW.
2117 * */
2118ssize_t
2119vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
2120 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2121{
2122 if (vcom_init () != 0)
2123 {
2124 return -1;
2125 }
2126
2127 return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2128}
2129
2130ssize_t
2131sendto (int __fd, const void *__buf, size_t __n, int __flags,
2132 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2133{
2134 ssize_t size;
2135 pid_t pid = getpid ();
2136
2137 if (is_vcom_socket_fd (__fd))
2138 {
2139 size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2140 if (VCOM_DEBUG > 0)
2141 fprintf (stderr,
2142 "[%d] sendto: "
2143 "'%04d'='%04d', '%p', '%04d', '%04x', "
2144 "'%p', '%04d'\n",
2145 pid, (int) size, __fd, __buf, (int) __n, __flags,
2146 __addr, __addr_len);
2147 if (size < 0)
2148 {
2149 errno = -size;
2150 return -1;
2151 }
2152 return size;
2153 }
2154 return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2155}
2156
2157/*
2158 * Read N bytes into BUF through socket FD.
2159 * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
2160 * address of the sender, and store the actual size of the address
2161 * in *ADDR_LEN.
2162 * Returns the number of bytes read or -1 for errors.
2163 * This function is a cancellation point and therefore not marked
2164 * with __THROW.
2165 * */
2166ssize_t
2167vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
2168 int __flags,
2169 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2170{
2171 if (vcom_init () != 0)
2172 {
2173 return -1;
2174 }
2175
2176 return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2177}
2178
2179ssize_t
2180recvfrom (int __fd, void *__restrict __buf, size_t __n,
2181 int __flags,
2182 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2183{
2184 ssize_t size;
2185 pid_t pid = getpid ();
2186
2187 if (is_vcom_socket_fd (__fd))
2188 {
2189 size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2190 if (VCOM_DEBUG > 0)
2191 fprintf (stderr,
2192 "[%d] recvfrom: "
2193 "'%04d'='%04d', '%p', '%04d', '%04x', "
2194 "'%p', '%p'\n",
2195 pid, (int) size, __fd, __buf, (int) __n, __flags,
2196 __addr, __addr_len);
2197 if (size < 0)
2198 {
2199 errno = -size;
2200 return -1;
2201 }
2202 return size;
2203 }
2204 return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2205}
2206
2207/*
2208 * Send a message described MESSAGE on socket FD.
2209 * Returns the number of bytes sent, or -1 for errors.
2210 * This function is a cancellation point and therefore not marked
2211 * with __THROW.
2212 * */
2213ssize_t
2214vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
2215{
2216 if (vcom_init () != 0)
2217 {
2218 return -1;
2219 }
2220
2221 return vcom_socket_sendmsg (__fd, __message, __flags);
2222}
2223
2224ssize_t
2225sendmsg (int __fd, const struct msghdr * __message, int __flags)
2226{
2227 ssize_t size;
2228 pid_t pid = getpid ();
2229
2230 if (is_vcom_socket_fd (__fd))
2231 {
2232 size = vcom_sendmsg (__fd, __message, __flags);
2233 if (VCOM_DEBUG > 0)
2234 fprintf (stderr,
2235 "[%d] sendmsg: "
2236 "'%04d'='%04d', '%p', '%04x'\n",
2237 pid, (int) size, __fd, __message, __flags);
2238 if (size < 0)
2239 {
2240 errno = -size;
2241 return -1;
2242 }
2243 return size;
2244 }
2245 return libc_sendmsg (__fd, __message, __flags);
2246}
2247
2248#ifdef __USE_GNU
2249/*
2250 * Send a VLEN messages as described by VMESSAGES to socket FD.
2251 * Returns the number of datagrams successfully written
2252 * or -1 for errors.
2253 * This function is a cancellation point and therefore not marked
2254 * with __THROW.
2255 * */
2256int
2257vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
2258 unsigned int __vlen, int __flags)
2259{
2260 if (vcom_init () != 0)
2261 {
2262 return -1;
2263 }
2264
2265 return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
2266}
2267
2268int
2269sendmmsg (int __fd, struct mmsghdr *__vmessages,
2270 unsigned int __vlen, int __flags)
2271{
2272 ssize_t size;
2273 pid_t pid = getpid ();
2274
2275 if (is_vcom_socket_fd (__fd))
2276 {
2277 size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
2278 if (VCOM_DEBUG > 0)
2279 fprintf (stderr,
2280 "[%d] sendmmsg: "
2281 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2282 pid, (int) size, __fd, __vmessages, __vlen, __flags);
2283 if (size < 0)
2284 {
2285 errno = -size;
2286 return -1;
2287 }
2288 return size;
2289 }
2290 return libc_sendmmsg (__fd, __message, __vlen, __flags);
2291}
2292
2293#endif
2294
2295/*
2296 * Receive a message as described by MESSAGE from socket FD.
2297 * Returns the number of bytes read or -1 for errors.
2298 * This function is a cancellation point and therefore not marked
2299 * with __THROW.
2300 * */
2301ssize_t
2302vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
2303{
2304 if (vcom_init () != 0)
2305 {
2306 return -1;
2307 }
2308
2309 return vcom_socket_recvmsg (__fd, __message, __flags);
2310}
2311
2312ssize_t
2313recvmsg (int __fd, struct msghdr * __message, int __flags)
2314{
2315 ssize_t size;
2316 pid_t pid = getpid ();
2317
2318 if (is_vcom_socket_fd (__fd))
2319 {
2320 size = vcom_recvmsg (__fd, __message, __flags);
2321 if (VCOM_DEBUG > 0)
2322 fprintf (stderr,
2323 "[%d] recvmsg: "
2324 "'%04d'='%04d', '%p', '%04x'\n",
2325 pid, (int) size, __fd, __message, __flags);
2326 if (size < 0)
2327 {
2328 errno = -size;
2329 return -1;
2330 }
2331 return size;
2332 }
2333 return libc_recvmsg (__fd, __message, __flags);
2334}
2335
2336#ifdef __USE_GNU
2337/*
2338 * Receive up to VLEN messages as described by VMESSAGES from socket FD.
2339 * Returns the number of messages received or -1 for errors.
2340 * This function is a cancellation point and therefore not marked
2341 * with __THROW.
2342 * */
2343int
2344vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
2345 unsigned int __vlen, int __flags, struct timespec *__tmo)
2346{
2347 if (vcom_init () != 0)
2348 {
2349 return -1;
2350 }
2351
2352 return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2353}
2354
2355int
2356recvmmsg (int __fd, struct mmsghdr *__vmessages,
2357 unsigned int __vlen, int __flags, struct timespec *__tmo)
2358{
2359 ssize_t size;
2360 pid_t pid = getpid ();
2361
2362 if (is_vcom_socket_fd (__fd))
2363 {
2364 size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2365 if (VCOM_DEBUG > 0)
2366 fprintf (stderr,
2367 "[%d] recvmmsg: "
2368 "'%04d'='%04d', '%p', "
2369 "'%04d', '%04x', '%p'\n",
2370 pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
2371 if (size < 0)
2372 {
2373 errno = -size;
2374 return -1;
2375 }
2376 return size;
2377 }
2378 return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2379}
2380
2381#endif
2382
2383/*
2384 * Put the current value for socket FD's option OPTNAME
2385 * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
2386 * and set *OPTLEN to the value's actual length.
2387 * Returns 0 on success, -1 for errors.
2388 * */
2389int
2390vcom_getsockopt (int __fd, int __level, int __optname,
2391 void *__restrict __optval, socklen_t * __restrict __optlen)
2392{
2393 if (vcom_init () != 0)
2394 {
2395 return -1;
2396 }
2397
2398 return vcom_socket_getsockopt (__fd, __level, __optname,
2399 __optval, __optlen);
2400}
2401
2402int
2403getsockopt (int __fd, int __level, int __optname,
2404 void *__restrict __optval, socklen_t * __restrict __optlen)
2405{
2406 int rv;
2407 pid_t pid = getpid ();
2408
2409 if (is_vcom_socket_fd (__fd))
2410 {
2411 rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
Dave Wallacee22aa742017-10-20 12:30:38 -04002412 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002413 fprintf (stderr,
2414 "[%d] getsockopt: "
2415 "'%04d'='%04d', '%04d', '%04d', "
2416 "'%p', '%p'\n",
2417 pid, rv, __fd, __level, __optname, __optval, __optlen);
2418 if (rv != 0)
2419 {
2420 errno = -rv;
2421 return -1;
2422 }
2423 return 0;
2424 }
2425 return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2426}
2427
2428/*
2429 * Set socket FD's option OPTNAME at protocol level LEVEL
2430 * to *OPTVAL (which is OPTLEN bytes long).
2431 * Returns 0 on success, -1 for errors.
2432 * */
2433int
2434vcom_setsockopt (int __fd, int __level, int __optname,
2435 const void *__optval, socklen_t __optlen)
2436{
2437 if (vcom_init () != 0)
2438 {
2439 return -1;
2440 }
2441
2442 return vcom_socket_setsockopt (__fd, __level, __optname,
2443 __optval, __optlen);
2444}
2445
2446int
2447setsockopt (int __fd, int __level, int __optname,
2448 const void *__optval, socklen_t __optlen)
2449{
2450 int rv;
2451 pid_t pid = getpid ();
2452
2453 if (is_vcom_socket_fd (__fd))
2454 {
2455 rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
2456 if (VCOM_DEBUG > 0)
2457 fprintf (stderr,
2458 "[%d] setsockopt: "
2459 "'%04d'='%04d', '%04d', '%04d', "
2460 "'%p', '%04d'\n",
2461 pid, rv, __fd, __level, __optname, __optval, __optlen);
2462 if (rv != 0)
2463 {
2464 errno = -rv;
2465 return -1;
2466 }
2467 return 0;
2468 }
2469 return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2470}
2471
2472/*
2473 * Prepare to accept connections on socket FD.
2474 * N connection requests will be queued before further
2475 * requests are refused.
2476 * Returns 0 on success, -1 for errors.
2477 * */
2478int
2479vcom_listen (int __fd, int __n)
2480{
2481 if (vcom_init () != 0)
2482 {
2483 return -1;
2484 }
2485
2486 return vcom_socket_listen (__fd, __n);
2487}
2488
2489int
2490listen (int __fd, int __n)
2491{
2492 int rv;
2493 pid_t pid = getpid ();
2494
2495 if (is_vcom_socket_fd (__fd))
2496 {
2497 rv = vcom_listen (__fd, __n);
2498 if (VCOM_DEBUG > 0)
2499 fprintf (stderr,
2500 "[%d] listen: "
2501 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
2502 if (rv != 0)
2503 {
2504 errno = -rv;
2505 return -1;
2506 }
2507 return 0;
2508 }
2509 return libc_listen (__fd, __n);
2510}
2511
2512/*
2513 * Await a connection on socket FD.
2514 * When a connection arrives, open a new socket to communicate
2515 * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
2516 * of the connecting peer and *ADDR_LEN to the address's actual
2517 * length, and return the new socket's descriptor, or -1 for errors.
2518 * This function is a cancellation point and therefore not marked
2519 * with __THROW.
2520 * */
2521int
2522vcom_accept (int __fd, __SOCKADDR_ARG __addr,
2523 socklen_t * __restrict __addr_len)
2524{
2525
2526 if (vcom_init () != 0)
2527 {
2528 return -1;
2529 }
2530 return vcom_socket_accept (__fd, __addr, __addr_len);
2531}
2532
2533int
2534accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2535{
2536 int rv = -1;
2537 pid_t pid = getpid ();
2538 pthread_t tid = pthread_self ();
2539
2540 if (is_vcom_socket_fd (__fd))
2541 {
2542 if (VCOM_DEBUG > 0)
2543 vcom_socket_main_show ();
2544 if (VCOM_DEBUG > 0)
2545 fprintf (stderr,
2546 "[%d][%lu (0x%lx)] accept1: "
2547 "'%04d'='%04d', '%p', '%p'\n",
2548 pid, (unsigned long) tid, (unsigned long) tid,
2549 rv, __fd, __addr, __addr_len);
2550 rv = vcom_accept (__fd, __addr, __addr_len);
2551 if (VCOM_DEBUG > 0)
2552 fprintf (stderr,
2553 "[%d][%lu (0x%lx)] accept2: "
2554 "'%04d'='%04d', '%p', '%p'\n",
2555 pid, (unsigned long) tid, (unsigned long) tid,
2556 rv, __fd, __addr, __addr_len);
2557 if (VCOM_DEBUG > 0)
2558 vcom_socket_main_show ();
2559 if (rv < 0)
2560 {
2561 errno = -rv;
2562 return -1;
2563 }
2564 return rv;
2565 }
2566 return libc_accept (__fd, __addr, __addr_len);
2567}
2568
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002569/*
2570 * Similar to 'accept' but takes an additional parameter to specify
2571 * flags.
2572 * This function is a cancellation point and therefore not marked
2573 * with __THROW.
2574 * */
2575int
2576vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
2577 socklen_t * __restrict __addr_len, int __flags)
2578{
2579
2580 if (vcom_init () != 0)
2581 {
2582 return -1;
2583 }
2584
2585 return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
2586}
2587
2588int
2589accept4 (int __fd, __SOCKADDR_ARG __addr,
2590 socklen_t * __restrict __addr_len, int __flags)
2591{
Dave Wallace59179392017-11-07 02:20:07 -05002592 int rv = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002593 pid_t pid = getpid ();
2594
Dave Wallace59179392017-11-07 02:20:07 -05002595 fprintf (stderr,
2596 "[%d] accept4: in the beginning... "
2597 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2598 pid, rv, __fd, __addr, __addr_len, __flags);
2599
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002600 if (is_vcom_socket_fd (__fd))
2601 {
2602 if (VCOM_DEBUG > 0)
2603 vcom_socket_main_show ();
2604 rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
2605 if (VCOM_DEBUG > 0)
2606 fprintf (stderr,
Dave Wallace59179392017-11-07 02:20:07 -05002607 "[%d] accept4: VCL "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002608 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2609 pid, rv, __fd, __addr, __addr_len, __flags);
2610 if (VCOM_DEBUG > 0)
2611 vcom_socket_main_show ();
2612 if (rv < 0)
2613 {
2614 errno = -rv;
2615 return -1;
2616 }
2617 return rv;
2618 }
Dave Wallace59179392017-11-07 02:20:07 -05002619 fprintf (stderr,
2620 "[%d] accept4: libc "
2621 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2622 pid, rv, __fd, __addr, __addr_len, __flags);
2623
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002624 return libc_accept4 (__fd, __addr, __addr_len, __flags);
2625}
2626
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002627/*
2628 * Shut down all or part of the connection open on socket FD.
2629 * HOW determines what to shut down:
2630 * SHUT_RD = No more receptions;
2631 * SHUT_WR = No more transmissions;
2632 * SHUT_RDWR = No more receptions or transmissions.
2633 * Returns 0 on success, -1 for errors.
2634 * */
2635int
2636vcom_shutdown (int __fd, int __how)
2637{
2638 if (vcom_init () != 0)
2639 {
2640 return -1;
2641 }
2642 return vcom_socket_shutdown (__fd, __how);
2643}
2644
2645int
2646shutdown (int __fd, int __how)
2647{
2648 int rv;
2649 pid_t pid = getpid ();
2650
2651 if (is_vcom_socket_fd (__fd))
2652 {
2653 rv = vcom_shutdown (__fd, __how);
2654 if (VCOM_DEBUG > 0)
2655 fprintf (stderr,
2656 "[%d] shutdown: "
2657 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
2658 if (rv != 0)
2659 {
2660 errno = -rv;
2661 return -1;
2662 }
2663 return 0;
2664 }
2665 return libc_shutdown (__fd, __how);
2666}
2667
2668int
2669vcom_epoll_create (int __size)
2670{
2671
2672 if (vcom_init () != 0)
2673 {
2674 return -1;
2675 }
2676
2677 if (__size <= 0)
2678 {
2679 return -EINVAL;
2680 }
2681
2682 /* __size argument is ignored "thereafter" */
2683 return vcom_epoll_create1 (0);
2684}
2685
2686/*
2687 * __size argument is ignored, but must be greater than zero
2688 */
2689int
2690epoll_create (int __size)
2691{
2692 int rv = 0;
2693 pid_t pid = getpid ();
2694
2695 rv = vcom_epoll_create (__size);
2696 if (VCOM_DEBUG > 0)
2697 fprintf (stderr,
2698 "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
2699 if (rv < 0)
2700 {
2701 errno = -rv;
2702 return -1;
2703 }
2704 return rv;
2705}
2706
2707int
2708vcom_epoll_create1 (int __flags)
2709{
2710 if (vcom_init () != 0)
2711 {
2712 return -1;
2713 }
2714
2715 if (__flags < 0)
2716 {
2717 return -EINVAL;
2718 }
2719 if (__flags & ~EPOLL_CLOEXEC)
2720 {
2721 return -EINVAL;
2722 }
2723 /* __flags can be either zero or EPOLL_CLOEXEC */
2724 /* implementation */
2725 return vcom_socket_epoll_create1 (__flags);
2726}
2727
2728/*
2729 * __flags can be either zero or EPOLL_CLOEXEC
2730 * */
2731int
2732epoll_create1 (int __flags)
2733{
2734 int rv = 0;
2735 pid_t pid = getpid ();
2736
2737 rv = vcom_epoll_create1 (__flags);
2738 if (VCOM_DEBUG > 0)
2739 fprintf (stderr,
2740 "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
2741 if (rv < 0)
2742 {
2743 errno = -rv;
2744 return -1;
2745 }
2746 return rv;
2747}
2748
2749static inline int
2750ep_op_has_event (int op)
2751{
2752 return op != EPOLL_CTL_DEL;
2753}
2754
2755int
2756vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2757{
2758 if (vcom_init () != 0)
2759 {
2760 return -1;
2761 }
2762
2763 /*
2764 * the requested operation __op is not supported
2765 * by this interface */
2766 if (!((__op == EPOLL_CTL_ADD) ||
2767 (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
2768 {
2769 return -EINVAL;
2770 }
2771
2772 /* op is ADD or MOD but event parameter is NULL */
2773 if ((ep_op_has_event (__op) && !__event))
2774 {
2775 return -EFAULT;
2776 }
2777
2778 /* fd is same as epfd */
2779 /* do not permit adding an epoll file descriptor inside itself */
2780 if (__epfd == __fd)
2781 {
2782 return -EINVAL;
2783 }
2784
2785 /* implementation */
2786 return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
2787}
2788
2789/*
2790 * implement the controller interface for epoll
2791 * that enables the insertion/removal/change of
2792 * file descriptors inside the interest set.
2793 */
2794int
2795epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2796{
2797 int rv;
2798 pid_t pid = getpid ();
2799
Dave Wallacee695cb42017-11-02 22:04:42 -04002800 rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
2801 if (VCOM_DEBUG > 0)
2802 fprintf (stderr,
2803 "[%d] epoll_ctl: "
2804 "'%04d'='%04d', '%04d', '%04d'\n", pid, rv, __epfd, __op, __fd);
2805 if (rv != 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002806 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002807 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002808 return -1;
2809 }
2810 return 0;
2811}
2812
2813int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002814epoll_wait (int __epfd, struct epoll_event *__events,
2815 int __maxevents, int __timeout)
2816{
2817 int rv;
2818 pid_t pid = getpid ();
2819
2820 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2821 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002822 fprintf (stderr, "[%d] ERROR: epoll_wait() invalid maxevents %d\n",
2823 pid, __maxevents);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002824 errno = EINVAL;
2825 return -1;
2826 }
2827
Dave Wallacee695cb42017-11-02 22:04:42 -04002828 rv =
2829 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
Dave Wallace59179392017-11-07 02:20:07 -05002830 if (VCOM_DEBUG > 1)
Dave Wallacee695cb42017-11-02 22:04:42 -04002831 fprintf (stderr,
2832 "[%d] epoll_wait: "
2833 "'%04d'='%04d', '%p', "
2834 "'%04d', '%04d'\n",
2835 pid, rv, __epfd, __events, __maxevents, __timeout);
2836 if (rv < 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002837 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002838 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002839 return -1;
2840 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002841 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002842}
2843
2844
2845int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002846epoll_pwait (int __epfd, struct epoll_event *__events,
2847 int __maxevents, int __timeout, const __sigset_t * __ss)
2848{
2849 int rv;
2850 pid_t pid = getpid ();
2851
2852 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2853 {
2854 errno = EINVAL;
2855 return -1;
2856 }
2857
2858 if (is_vcom_epfd (__epfd))
2859 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002860 rv =
2861 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout,
2862 __ss);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002863 if (VCOM_DEBUG > 0)
2864 fprintf (stderr,
2865 "[%d] epoll_pwait: "
2866 "'%04d'='%04d', '%p', "
2867 "'%04d', '%04d', "
2868 "'%p'\n",
2869 pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
2870 if (rv < 0)
2871 {
2872 errno = -rv;
2873 return -1;
2874 }
2875 return rv;
2876 }
2877 else
2878 {
2879 errno = EINVAL;
2880 return -1;
2881 }
2882
2883 return 0;
2884}
2885
2886/* Poll the file descriptors described by the NFDS structures starting at
2887 FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
2888 an event to occur; if TIMEOUT is -1, block until an event occurs.
2889 Returns the number of file descriptors with events, zero if timed out,
2890 or -1 for errors.
2891
2892 This function is a cancellation point and therefore not marked with
2893 __THROW. */
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002894
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002895int
2896vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2897{
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002898 int rv = 0;
2899 pid_t pid = getpid ();
2900
2901 struct rlimit nofile_limit;
2902 struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
2903 nfds_t fds_idx = 0;
2904
2905 /* actual set of file descriptors to be monitored */
2906 nfds_t libc_nfds = 0;
2907 nfds_t vcom_nfds = 0;
2908
2909 /* ready file descriptors
2910 *
2911 * number of structures which have nonzero revents fields
2912 * in other words, descriptors with events or errors reported.
2913 * */
2914 /* after call to libc_poll () */
2915 int rlibc_nfds = 0;
2916 /* after call to vcom_socket_poll () */
2917 int rvcom_nfds = 0;
2918
2919
2920 /* timeout value in units of timespec */
2921 struct timespec timeout_ts;
2922 struct timespec start_time, now, end_time;
2923
2924
2925 /* get start_time */
2926 rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
2927 if (rv == -1)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002928 {
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002929 rv = -errno;
2930 goto poll_done;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002931 }
2932
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002933 /* set timeout_ts & end_time */
2934 if (__timeout >= 0)
2935 {
2936 /* set timeout_ts */
2937 timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
2938 timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
2939 set_normalized_timespec (&timeout_ts,
2940 timeout_ts.tv_sec, timeout_ts.tv_nsec);
2941 /* set end_time */
2942 if (__timeout)
2943 {
2944 end_time = timespec_add (start_time, timeout_ts);
2945 }
2946 else
2947 {
2948 end_time = start_time;
2949 }
2950 }
2951
2952 if (vcom_init () != 0)
2953 {
2954 rv = -1;
2955 goto poll_done;
2956 }
2957
2958 /* validate __fds */
2959 if (!__fds)
2960 {
2961 rv = -EFAULT;
2962 goto poll_done;
2963 }
2964
2965 /* validate __nfds */
2966 /*TBD: call getrlimit once when vcl-ldpreload library is init */
2967 rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
2968 if (rv != 0)
2969 {
2970 rv = -errno;
2971 goto poll_done;
2972 }
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04002973 if (__nfds >= nofile_limit.rlim_cur)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002974 {
2975 rv = -EINVAL;
2976 goto poll_done;
2977 }
2978
2979 /*
2980 * for the POC, it's fair to assume that nfds is less than 1024
2981 * */
2982 if (__nfds >= MAX_POLL_NFDS_DEFAULT)
2983 {
2984 rv = -EINVAL;
2985 goto poll_done;
2986 }
2987
2988 /* set revents field (output parameter)
2989 * to zero
2990 * */
2991 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2992 {
2993 __fds[fds_idx].revents = 0;
2994 }
2995
2996#if 0
2997 /* set revents field (output parameter)
2998 * to zero for user ignored fds
2999 * */
3000 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3001 {
3002 /*
3003 * if negative fd, ignore events field
3004 * and set output parameter (revents field) to zero */
3005 if (__fds[fds_idx].fd < 0)
3006 {
3007 __fds[fds_idx].revents = 0;
3008 }
3009 }
3010#endif
3011
3012 /*
3013 * 00. prepare __fds and vcom_fds for polling
3014 * copy __fds to vcom_fds
3015 * 01. negate all except libc fds in __fds,
3016 * ignore user negated fds
3017 * 02. negate all except vcom_fds in vocm fds,
3018 * ignore user negated fds
3019 * ignore fd 0 by setting it to negative number
3020 * */
3021 memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
3022 libc_nfds = 0;
3023 vcom_nfds = 0;
3024 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3025 {
3026 /* ignore negative fds */
3027 if (__fds[fds_idx].fd < 0)
3028 {
3029 continue;
3030 }
3031
3032 /*
3033 * 00. ignore vcom fds in __fds
3034 * 01. ignore libc fds in vcom_fds,
3035 * ignore fd 0 by setting it to negative number.
3036 * as fd 0 cannot be ignored.
3037 */
3038 if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
3039 is_vcom_epfd (__fds[fds_idx].fd))
3040 {
3041 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3042 vcom_nfds++;
3043 }
3044 else
3045 {
3046 libc_nfds++;
3047 /* ignore fd 0 by setting it to negative number */
3048 if (!vcom_fds[fds_idx].fd)
3049 {
3050 vcom_fds[fds_idx].fd = -1;
3051 }
3052 vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
3053 }
3054 }
3055
3056 /*
3057 * polling loop
3058 *
3059 * poll on libc fds and vcom fds
3060 *
3061 * specifying a timeout of zero causes libc_poll() and
3062 * vcom_socket_poll() to return immediately, even if no
3063 * file descriptors are ready
3064 * */
3065 do
3066 {
3067 rlibc_nfds = 0;
3068 rvcom_nfds = 0;
3069
3070 /*
3071 * timeout parameter for libc_poll () set to zero
3072 * to poll on libc fds
3073 * */
3074
3075 /* poll on libc fds */
3076 if (libc_nfds)
3077 {
3078 /*
3079 * a timeout of zero causes libc_poll()
3080 * to return immediately
3081 * */
3082 rlibc_nfds = libc_poll (__fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003083 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003084 fprintf (stderr,
3085 "[%d] poll libc: "
3086 "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
3087
3088 if (rlibc_nfds < 0)
3089 {
3090 rv = -errno;
3091 goto poll_done_update_nfds;
3092 }
3093 }
3094
3095 /*
3096 * timeout parameter for vcom_socket_poll () set to zero
3097 * to poll on vcom fds
3098 * */
3099
3100 /* poll on vcom fds */
3101 if (vcom_nfds)
3102 {
3103 /*
3104 * a timeout of zero causes vcom_socket_poll()
3105 * to return immediately
3106 * */
3107 rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003108 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003109 fprintf (stderr,
3110 "[%d] poll vcom: "
3111 "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
3112 if (rvcom_nfds < 0)
3113 {
3114 rv = rvcom_nfds;
3115 goto poll_done_update_nfds;
3116 }
3117 }
3118
3119 /* check if any file descriptors changed status */
3120 if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
3121 {
3122 /* something interesting happened */
3123 rv = rlibc_nfds + rvcom_nfds;
3124 goto poll_done_update_nfds;
3125 }
3126
3127 rv = clock_gettime (CLOCK_MONOTONIC, &now);
3128 if (rv == -1)
3129 {
3130 rv = -errno;
3131 goto poll_done_update_nfds;
3132 }
3133 }
3134
3135 /* block indefinitely || timeout elapsed */
3136 while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
3137
3138 /* timeout expired before anything interesting happened */
3139 rv = 0;
3140
3141poll_done_update_nfds:
3142 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3143 {
3144 /* ignore negative fds in vcom_fds
3145 * 00. user negated fds
3146 * 01. libc fds
3147 * */
3148 if (vcom_fds[fds_idx].fd < 0)
3149 {
3150 continue;
3151 }
3152
3153 /* from here on handle positive vcom fds */
3154 /*
3155 * restore vcom fds to positive number in __fds
3156 * and update revents in __fds with the events
3157 * that actually occurred in vcom fds
3158 * */
3159 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3160 if (rvcom_nfds)
3161 {
3162 __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
3163 }
3164 }
3165
3166poll_done:
Dave Wallacee22aa742017-10-20 12:30:38 -04003167 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003168 fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
3169 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003170}
3171
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003172/*
3173 * 00. The field __fds[i].fd contains a file descriptor for an
3174 * open file.
3175 * If this field is negative, then the corresponding
3176 * events field is ignored and the revents field returns zero.
3177 * The field __fds[i].events is an input parameter.
3178 * The field __fds[i].revents is an output parameter.
3179 * 01. Specifying a negative value in timeout
3180 * means an infinite timeout.
3181 * Specifying a timeout of zero causes poll() to return
3182 * immediately, even if no file descriptors are ready.
3183 *
3184 * NOTE: observed __nfds is less than 128 from kubecon strace files
3185 */
3186
3187
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003188int
3189poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3190{
3191 int rv = 0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003192 pid_t pid = getpid ();
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003193
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003194
Dave Wallacee22aa742017-10-20 12:30:38 -04003195 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003196 fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
3197 pid, rv, __nfds, __fds[0].fd, __fds[0].events);
3198 rv = vcom_poll (__fds, __nfds, __timeout);
Dave Wallacee22aa742017-10-20 12:30:38 -04003199 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003200 fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
3201 pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
3202 if (rv < 0)
3203 {
3204 errno = -rv;
3205 return -1;
3206 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003207 return rv;
3208}
3209
3210#ifdef __USE_GNU
3211/* Like poll, but before waiting the threads signal mask is replaced
3212 with that specified in the fourth parameter. For better usability,
3213 the timeout value is specified using a TIMESPEC object.
3214
3215 This function is a cancellation point and therefore not marked with
3216 __THROW. */
3217int
3218vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
3219 const struct timespec *__timeout, const __sigset_t * __ss)
3220{
3221 if (vcom_init () != 0)
3222 {
3223 return -1;
3224 }
3225
3226 return -EOPNOTSUPP;
3227}
3228
3229int
3230ppoll (struct pollfd *__fds, nfds_t __nfds,
3231 const struct timespec *__timeout, const __sigset_t * __ss)
3232{
3233 int rv = 0;
3234
3235 errno = EOPNOTSUPP;
3236 rv = -1;
3237 return rv;
3238}
3239#endif
3240
3241void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
3242
3243void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
3244
3245void
3246vcom_constructor (void)
3247{
3248 pid_t pid = getpid ();
3249
3250 swrap_constructor ();
3251 if (vcom_init () != 0)
3252 {
3253 printf ("\n[%d] vcom_constructor...failed!\n", pid);
3254 }
3255 else
3256 {
3257 printf ("\n[%d] vcom_constructor...done!\n", pid);
3258 }
3259}
3260
3261/*
3262 * This function is called when the library is unloaded
3263 */
3264void
3265vcom_destructor (void)
3266{
3267 pid_t pid = getpid ();
3268
3269 vcom_destroy ();
3270 swrap_destructor ();
3271 printf ("\n[%d] vcom_destructor...done!\n", pid);
3272}
3273
3274
3275/*
3276 * fd.io coding-style-patch-verification: ON
3277 *
3278 * Local Variables:
3279 * eval: (c-set-style "gnu")
3280 * End:
3281 */