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