blob: 4f8435f41bfcbcfc197a89d40203d38fc6c498d8 [file] [log] [blame]
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <unistd.h>
16#include <stdio.h>
17#include <signal.h>
18#include <dlfcn.h>
19#include <pthread.h>
20#include <time.h>
21#include <stdarg.h>
shrinivasan ganapathy1d359632017-10-15 15:46:09 -070022#include <sys/resource.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070023
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040024#include <vcl/vcom_socket_wrapper.h>
25#include <vcl/vcom.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070026#include <sys/time.h>
27
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040028#include <vcl/vppcom.h>
29#include <vcl/vcom_socket.h>
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -070030
31/* GCC have printf type attribute check. */
32#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
33#define PRINTF_ATTRIBUTE(a,b) \
34 __attribute__ ((__format__ (__printf__, a, b)))
35#else
36#define PRINTF_ATTRIBUTE(a,b)
37#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
38
39#define HAVE_CONSTRUCTOR_ATTRIBUTE
40#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
41#define CONSTRUCTOR_ATTRIBUTE \
42 __attribute__ ((constructor))
43#else
44#define CONSTRUCTOR_ATTRIBUTE
45#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
46
47#define HAVE_DESTRUCTOR_ATTRIBUTE
48#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
49#define DESTRUCTOR_ATTRIBUTE \
50 __attribute__ ((destructor))
51#else
52#define DESTRUCTOR_ATTRIBUTE
53#endif
54
55#define HAVE_ADDRESS_SANITIZER_ATTRIBUTE
56#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
57#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE \
58 __attribute__((no_sanitize_address))
59#else
60#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
61#endif
62
63#define VCOM_SOCKET_FD_MAX 0x10000
64
65static char vcom_app_name[MAX_VCOM_APP_NAME];
66
67/*
68 * RETURN: 0 on success or -1 on error.
69 * */
70int
71vcom_set_app_name (char *__app_name)
72{
73 return snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-%s-%d",
74 __app_name, getpid ()) < 0 ? -1 : 0;
75}
76
77static char *
78vcom_get_app_name ()
79{
80 if (vcom_app_name[0] == '\0')
81 {
82 snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-app-%d", getpid ());
83 }
84 return vcom_app_name;
85}
86
87/*
88 * 1 if init, 0 otherwise
89 */
90static int is_vcom_init;
91
92/*
93 * TBD: Make it thread safe
94 */
95
96/*
97 * constructor function called before main is called
98 * RETURN: 0 on success -1 on failure
99 * */
100static inline int
Dave Wallace227867f2017-11-13 21:21:53 -0500101vcom_init (void)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700102{
103 pid_t pid = getpid ();
Dave Wallace4adccc92017-11-27 17:07:51 -0500104 int rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700105
106 if (!is_vcom_init)
107 {
Dave Wallace4adccc92017-11-27 17:07:51 -0500108 rv = vppcom_app_create (vcom_get_app_name ());
109 if (rv)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700110 {
111 printf ("\n[%d] vcom_init...failed!\n", pid);
112 if (VCOM_DEBUG > 0)
113 fprintf (stderr,
114 "[%d] vcom_init: vppcom_app_create failed!\n", pid);
Dave Wallace4adccc92017-11-27 17:07:51 -0500115 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700116 }
117 if (vcom_socket_main_init () != 0)
118 {
119 printf ("\n[%d] vcom_init...failed!\n", pid);
120 if (VCOM_DEBUG > 0)
121 fprintf (stderr,
122 "[%d] vcom_init: vcom_socket_main_init failed!\n", pid);
123 return -1;
124 }
125
126 is_vcom_init = 1;
127 printf ("\n[%d] vcom_init...done!\n", pid);
128 }
129 return 0;
130}
131
132static inline void
133vcom_destroy (void)
134{
135 pid_t pid = getpid ();
136
137 if (is_vcom_init)
138 {
139 vcom_socket_main_destroy ();
140 vppcom_app_destroy ();
141 is_vcom_init = 0;
142 fprintf (stderr, "\n[%d] vcom_destroy...done!\n", pid);
143 }
144}
145
146static inline int
147is_vcom_socket_fd (int fd)
148{
149 return vcom_socket_is_vcom_fd (fd);
150}
151
152static inline int
153is_vcom_epfd (int epfd)
154{
155 return vcom_socket_is_vcom_epfd (epfd);
156}
157
158
159/*
160 *
161 * Generic glibc fd api
162 *
163 */
164
165/* Close the file descriptor FD.
166
167 This function is a cancellation point and therefore
168 not marked with __THROW. */
169/*
170 * PRE: is_vcom_socket_fd(__fd) == 1
171 * RETURN: 0 on success and -1 for errors.
172 * */
173int
174vcom_close (int __fd)
175{
176 if (vcom_init () != 0)
177 {
178 return -1;
179 }
180
181 if (vcom_socket_close (__fd) != 0)
182 {
183 return -1;
184 }
185
186 return 0;
187}
188
189/*
190 * RETURN: 0 on success, or -1 on error
191 */
192int
193close (int __fd)
194{
195 int rv;
196 pid_t pid = getpid ();
197
198 if (is_vcom_socket_fd (__fd) || is_vcom_epfd (__fd))
199 {
200 if (VCOM_DEBUG > 0)
Dave Wallace375e4682017-11-10 15:49:32 -0500201 fprintf (stderr, "[%d] close: fd %d\n", pid, __fd);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700202 rv = vcom_close (__fd);
203 if (VCOM_DEBUG > 0)
Dave Wallace375e4682017-11-10 15:49:32 -0500204 fprintf (stderr, "[%d] close: vcom_close() returned %d\n", pid, rv);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -0700205 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{
Dave Wallace4adccc92017-11-27 17:07:51 -05001926 int rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001927
Dave Wallace4adccc92017-11-27 17:07:51 -05001928 rv = vcom_init ();
1929 if (rv)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001930 {
Dave Wallace4adccc92017-11-27 17:07:51 -05001931 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001932 }
1933
1934 /* validate __len */
1935 switch (__addr->sa_family)
1936 {
1937 case AF_INET:
1938 if (__len != INET_ADDRSTRLEN)
Dave Wallace4adccc92017-11-27 17:07:51 -05001939 return -EINVAL;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001940 break;
1941 case AF_INET6:
1942 if (__len != INET6_ADDRSTRLEN)
Dave Wallace4adccc92017-11-27 17:07:51 -05001943 return -EINVAL;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001944 break;
1945
1946 default:
Dave Wallace4adccc92017-11-27 17:07:51 -05001947 return -EAFNOSUPPORT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001948 break;
1949 }
1950
1951 /* handle domains implemented by vpp */
1952 switch (__addr->sa_family)
1953 {
1954 case AF_INET:
1955 case AF_INET6:
1956 rv = vcom_socket_connect (__fd, __addr, __len);
1957 break;
1958
1959 default:
Dave Wallace4adccc92017-11-27 17:07:51 -05001960 return -EPFNOSUPPORT;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001961 break;
1962 }
1963
1964 return rv;
1965}
1966
1967int
1968connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1969{
1970 int rv;
1971 pid_t pid = getpid ();
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001972
1973 if (is_vcom_socket_fd (__fd))
1974 {
1975 rv = vcom_connect (__fd, __addr, __len);
1976 if (VCOM_DEBUG > 0)
1977 fprintf (stderr,
Dave Wallace4adccc92017-11-27 17:07:51 -05001978 "[%d] connect: "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001979 "'%04d'='%04d', '%p', '%04d'\n",
Dave Wallace4adccc92017-11-27 17:07:51 -05001980 pid, rv, __fd, __addr, __len);
1981 if (rv)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07001982 {
1983 errno = -rv;
1984 return -1;
1985 }
1986 return 0;
1987 }
1988
1989 return libc_connect (__fd, __addr, __len);
1990}
1991
1992/*
1993 * Put the address of the peer connected to socket FD into *ADDR
1994 * (which is *LEN bytes long), and its actual length into *LEN.
1995 * */
1996int
1997vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
1998 socklen_t * __restrict __len)
1999{
2000 if (vcom_init () != 0)
2001 {
2002 return -1;
2003 }
2004
2005 return vcom_socket_getpeername (__fd, __addr, __len);
2006}
2007
2008int
2009getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
2010{
2011 int rv;
2012 pid_t pid = getpid ();
2013
2014 if (is_vcom_socket_fd (__fd))
2015 {
2016 rv = vcom_getpeername (__fd, __addr, __len);
2017 if (VCOM_DEBUG > 0)
2018 fprintf (stderr,
2019 "[%d] getpeername: "
2020 "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
2021 if (rv != 0)
2022 {
2023 errno = -rv;
2024 return -1;
2025 }
2026 return 0;
2027 }
2028 return libc_getpeername (__fd, __addr, __len);
2029}
2030
2031/*
2032 * Send N bytes of BUF to socket FD. Returns the number sent or -1.
2033 * This function is a cancellation point and therefore not marked
2034 * with __THROW.
2035 * */
2036ssize_t
2037vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
2038{
2039
2040 if (vcom_init () != 0)
2041 {
2042 return -1;
2043 }
2044
2045 return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
2046}
2047
2048ssize_t
2049send (int __fd, const void *__buf, size_t __n, int __flags)
2050{
2051 ssize_t size;
2052 pid_t pid = getpid ();
2053
2054 if (is_vcom_socket_fd (__fd))
2055 {
2056 size = vcom_send (__fd, __buf, __n, __flags);
2057 if (VCOM_DEBUG > 0)
2058 fprintf (stderr,
2059 "[%d] send: "
2060 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2061 pid, (int) size, __fd, __buf, (int) __n, __flags);
2062 if (size < 0)
2063 {
2064 errno = -size;
2065 return -1;
2066 }
2067 return size;
2068 }
2069 return libc_send (__fd, __buf, __n, __flags);
2070}
2071
Dave Wallace227867f2017-11-13 21:21:53 -05002072ssize_t
2073sendfile (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2074{
2075 ssize_t size;
2076
2077 if (VCOM_DEBUG > 2)
2078 clib_warning ("[%d] __out_fd %d, __in_fd %d, __offset %p, __len %ld",
2079 getpid (), __out_fd, __in_fd, __offset, __len);
2080
2081 if (is_vcom_socket_fd (__out_fd))
2082 {
2083 /* TBD: refactor this check to be part of is_vcom_socket_fd() */
2084 if (vcom_init () != 0)
2085 return -1;
2086
2087 size = vcom_socket_sendfile (__out_fd, __in_fd, __offset, __len);
2088 if (VCOM_DEBUG > 2)
2089 clib_warning ("[%d] vcom_socket_sendfile (out_fd %d, in_fd %d, "
2090 "offset %p (%ld), len %lu) returned %ld",
2091 getpid (), __out_fd, __in_fd, __offset,
2092 __offset ? *__offset : -1, __len, size);
2093 if (size < 0)
2094 {
2095 errno = -size;
2096 return -1;
2097 }
2098 return size;
2099 }
2100 if (VCOM_DEBUG > 2)
2101 clib_warning ("[%d] calling libc_sendfile!", getpid ());
2102 return libc_sendfile (__out_fd, __in_fd, __offset, __len);
2103}
2104
2105ssize_t
2106sendfile64 (int __out_fd, int __in_fd, off_t * __offset, size_t __len)
2107{
2108 return sendfile (__out_fd, __in_fd, __offset, __len);
2109}
2110
2111
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002112/*
2113 * Read N bytes into BUF from socket FD.
2114 * Returns the number read or -1 for errors.
2115 * This function is a cancellation point and therefore not marked
2116 * with __THROW.
2117 * */
2118ssize_t
2119vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
2120{
2121 if (vcom_init () != 0)
2122 {
2123 return -1;
2124 }
2125
2126 return vcom_socket_recv (__fd, __buf, __n, __flags);
2127}
2128
2129ssize_t
2130recv (int __fd, void *__buf, size_t __n, int __flags)
2131{
2132 ssize_t size;
2133 pid_t pid = getpid ();
2134
2135 if (is_vcom_socket_fd (__fd))
2136 {
2137 size = vcom_recv (__fd, __buf, __n, __flags);
2138 if (VCOM_DEBUG > 0)
2139 fprintf (stderr,
2140 "[%d] recv: "
2141 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2142 pid, (int) size, __fd, __buf, (int) __n, __flags);
2143 if (size < 0)
2144 {
2145 errno = -size;
2146 return -1;
2147 }
2148 return size;
2149 }
2150 return libc_recv (__fd, __buf, __n, __flags);
2151}
2152
2153/*
2154 * Send N bytes of BUF on socket FD to peer at address ADDR (which is
2155 * ADDR_LEN bytes long). Returns the number sent, or -1 for errors.
2156 * This function is a cancellation point and therefore not marked
2157 * with __THROW.
2158 * */
2159ssize_t
2160vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
2161 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2162{
2163 if (vcom_init () != 0)
2164 {
2165 return -1;
2166 }
2167
2168 return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2169}
2170
2171ssize_t
2172sendto (int __fd, const void *__buf, size_t __n, int __flags,
2173 __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2174{
2175 ssize_t size;
2176 pid_t pid = getpid ();
2177
2178 if (is_vcom_socket_fd (__fd))
2179 {
2180 size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2181 if (VCOM_DEBUG > 0)
2182 fprintf (stderr,
2183 "[%d] sendto: "
2184 "'%04d'='%04d', '%p', '%04d', '%04x', "
2185 "'%p', '%04d'\n",
2186 pid, (int) size, __fd, __buf, (int) __n, __flags,
2187 __addr, __addr_len);
2188 if (size < 0)
2189 {
2190 errno = -size;
2191 return -1;
2192 }
2193 return size;
2194 }
2195 return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2196}
2197
2198/*
2199 * Read N bytes into BUF through socket FD.
2200 * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
2201 * address of the sender, and store the actual size of the address
2202 * in *ADDR_LEN.
2203 * Returns the number of bytes read or -1 for errors.
2204 * This function is a cancellation point and therefore not marked
2205 * with __THROW.
2206 * */
2207ssize_t
2208vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
2209 int __flags,
2210 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2211{
2212 if (vcom_init () != 0)
2213 {
2214 return -1;
2215 }
2216
2217 return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2218}
2219
2220ssize_t
2221recvfrom (int __fd, void *__restrict __buf, size_t __n,
2222 int __flags,
2223 __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2224{
2225 ssize_t size;
2226 pid_t pid = getpid ();
2227
2228 if (is_vcom_socket_fd (__fd))
2229 {
2230 size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2231 if (VCOM_DEBUG > 0)
2232 fprintf (stderr,
2233 "[%d] recvfrom: "
2234 "'%04d'='%04d', '%p', '%04d', '%04x', "
2235 "'%p', '%p'\n",
2236 pid, (int) size, __fd, __buf, (int) __n, __flags,
2237 __addr, __addr_len);
2238 if (size < 0)
2239 {
2240 errno = -size;
2241 return -1;
2242 }
2243 return size;
2244 }
2245 return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2246}
2247
2248/*
2249 * Send a message described MESSAGE on socket FD.
2250 * Returns the number of bytes sent, or -1 for errors.
2251 * This function is a cancellation point and therefore not marked
2252 * with __THROW.
2253 * */
2254ssize_t
2255vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
2256{
2257 if (vcom_init () != 0)
2258 {
2259 return -1;
2260 }
2261
2262 return vcom_socket_sendmsg (__fd, __message, __flags);
2263}
2264
2265ssize_t
2266sendmsg (int __fd, const struct msghdr * __message, int __flags)
2267{
2268 ssize_t size;
2269 pid_t pid = getpid ();
2270
2271 if (is_vcom_socket_fd (__fd))
2272 {
2273 size = vcom_sendmsg (__fd, __message, __flags);
2274 if (VCOM_DEBUG > 0)
2275 fprintf (stderr,
2276 "[%d] sendmsg: "
2277 "'%04d'='%04d', '%p', '%04x'\n",
2278 pid, (int) size, __fd, __message, __flags);
2279 if (size < 0)
2280 {
2281 errno = -size;
2282 return -1;
2283 }
2284 return size;
2285 }
2286 return libc_sendmsg (__fd, __message, __flags);
2287}
2288
2289#ifdef __USE_GNU
2290/*
2291 * Send a VLEN messages as described by VMESSAGES to socket FD.
2292 * Returns the number of datagrams successfully written
2293 * or -1 for errors.
2294 * This function is a cancellation point and therefore not marked
2295 * with __THROW.
2296 * */
2297int
2298vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
2299 unsigned int __vlen, int __flags)
2300{
2301 if (vcom_init () != 0)
2302 {
2303 return -1;
2304 }
2305
2306 return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
2307}
2308
2309int
2310sendmmsg (int __fd, struct mmsghdr *__vmessages,
2311 unsigned int __vlen, int __flags)
2312{
2313 ssize_t size;
2314 pid_t pid = getpid ();
2315
2316 if (is_vcom_socket_fd (__fd))
2317 {
2318 size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
2319 if (VCOM_DEBUG > 0)
2320 fprintf (stderr,
2321 "[%d] sendmmsg: "
2322 "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2323 pid, (int) size, __fd, __vmessages, __vlen, __flags);
2324 if (size < 0)
2325 {
2326 errno = -size;
2327 return -1;
2328 }
2329 return size;
2330 }
2331 return libc_sendmmsg (__fd, __message, __vlen, __flags);
2332}
2333
2334#endif
2335
2336/*
2337 * Receive a message as described by MESSAGE from socket FD.
2338 * Returns the number of bytes read or -1 for errors.
2339 * This function is a cancellation point and therefore not marked
2340 * with __THROW.
2341 * */
2342ssize_t
2343vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
2344{
2345 if (vcom_init () != 0)
2346 {
2347 return -1;
2348 }
2349
2350 return vcom_socket_recvmsg (__fd, __message, __flags);
2351}
2352
2353ssize_t
2354recvmsg (int __fd, struct msghdr * __message, int __flags)
2355{
2356 ssize_t size;
2357 pid_t pid = getpid ();
2358
2359 if (is_vcom_socket_fd (__fd))
2360 {
2361 size = vcom_recvmsg (__fd, __message, __flags);
2362 if (VCOM_DEBUG > 0)
2363 fprintf (stderr,
2364 "[%d] recvmsg: "
2365 "'%04d'='%04d', '%p', '%04x'\n",
2366 pid, (int) size, __fd, __message, __flags);
2367 if (size < 0)
2368 {
2369 errno = -size;
2370 return -1;
2371 }
2372 return size;
2373 }
2374 return libc_recvmsg (__fd, __message, __flags);
2375}
2376
2377#ifdef __USE_GNU
2378/*
2379 * Receive up to VLEN messages as described by VMESSAGES from socket FD.
2380 * Returns the number of messages received or -1 for errors.
2381 * This function is a cancellation point and therefore not marked
2382 * with __THROW.
2383 * */
2384int
2385vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
2386 unsigned int __vlen, int __flags, struct timespec *__tmo)
2387{
2388 if (vcom_init () != 0)
2389 {
2390 return -1;
2391 }
2392
2393 return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2394}
2395
2396int
2397recvmmsg (int __fd, struct mmsghdr *__vmessages,
2398 unsigned int __vlen, int __flags, struct timespec *__tmo)
2399{
2400 ssize_t size;
2401 pid_t pid = getpid ();
2402
2403 if (is_vcom_socket_fd (__fd))
2404 {
2405 size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2406 if (VCOM_DEBUG > 0)
2407 fprintf (stderr,
2408 "[%d] recvmmsg: "
2409 "'%04d'='%04d', '%p', "
2410 "'%04d', '%04x', '%p'\n",
2411 pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
2412 if (size < 0)
2413 {
2414 errno = -size;
2415 return -1;
2416 }
2417 return size;
2418 }
2419 return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2420}
2421
2422#endif
2423
2424/*
2425 * Put the current value for socket FD's option OPTNAME
2426 * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
2427 * and set *OPTLEN to the value's actual length.
2428 * Returns 0 on success, -1 for errors.
2429 * */
2430int
2431vcom_getsockopt (int __fd, int __level, int __optname,
2432 void *__restrict __optval, socklen_t * __restrict __optlen)
2433{
2434 if (vcom_init () != 0)
2435 {
2436 return -1;
2437 }
2438
2439 return vcom_socket_getsockopt (__fd, __level, __optname,
2440 __optval, __optlen);
2441}
2442
2443int
2444getsockopt (int __fd, int __level, int __optname,
2445 void *__restrict __optval, socklen_t * __restrict __optlen)
2446{
2447 int rv;
2448 pid_t pid = getpid ();
2449
2450 if (is_vcom_socket_fd (__fd))
2451 {
2452 rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
Dave Wallacee22aa742017-10-20 12:30:38 -04002453 if (VCOM_DEBUG > 2)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002454 fprintf (stderr,
2455 "[%d] getsockopt: "
2456 "'%04d'='%04d', '%04d', '%04d', "
2457 "'%p', '%p'\n",
2458 pid, rv, __fd, __level, __optname, __optval, __optlen);
2459 if (rv != 0)
2460 {
2461 errno = -rv;
2462 return -1;
2463 }
2464 return 0;
2465 }
2466 return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2467}
2468
2469/*
2470 * Set socket FD's option OPTNAME at protocol level LEVEL
2471 * to *OPTVAL (which is OPTLEN bytes long).
2472 * Returns 0 on success, -1 for errors.
2473 * */
2474int
2475vcom_setsockopt (int __fd, int __level, int __optname,
2476 const void *__optval, socklen_t __optlen)
2477{
2478 if (vcom_init () != 0)
2479 {
2480 return -1;
2481 }
2482
2483 return vcom_socket_setsockopt (__fd, __level, __optname,
2484 __optval, __optlen);
2485}
2486
2487int
2488setsockopt (int __fd, int __level, int __optname,
2489 const void *__optval, socklen_t __optlen)
2490{
2491 int rv;
2492 pid_t pid = getpid ();
2493
2494 if (is_vcom_socket_fd (__fd))
2495 {
2496 rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
2497 if (VCOM_DEBUG > 0)
2498 fprintf (stderr,
2499 "[%d] setsockopt: "
2500 "'%04d'='%04d', '%04d', '%04d', "
2501 "'%p', '%04d'\n",
2502 pid, rv, __fd, __level, __optname, __optval, __optlen);
2503 if (rv != 0)
2504 {
2505 errno = -rv;
2506 return -1;
2507 }
2508 return 0;
2509 }
2510 return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2511}
2512
2513/*
2514 * Prepare to accept connections on socket FD.
2515 * N connection requests will be queued before further
2516 * requests are refused.
2517 * Returns 0 on success, -1 for errors.
2518 * */
2519int
2520vcom_listen (int __fd, int __n)
2521{
2522 if (vcom_init () != 0)
2523 {
2524 return -1;
2525 }
2526
2527 return vcom_socket_listen (__fd, __n);
2528}
2529
2530int
2531listen (int __fd, int __n)
2532{
2533 int rv;
2534 pid_t pid = getpid ();
2535
2536 if (is_vcom_socket_fd (__fd))
2537 {
2538 rv = vcom_listen (__fd, __n);
2539 if (VCOM_DEBUG > 0)
2540 fprintf (stderr,
2541 "[%d] listen: "
2542 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
2543 if (rv != 0)
2544 {
2545 errno = -rv;
2546 return -1;
2547 }
2548 return 0;
2549 }
2550 return libc_listen (__fd, __n);
2551}
2552
2553/*
2554 * Await a connection on socket FD.
2555 * When a connection arrives, open a new socket to communicate
2556 * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
2557 * of the connecting peer and *ADDR_LEN to the address's actual
2558 * length, and return the new socket's descriptor, or -1 for errors.
2559 * This function is a cancellation point and therefore not marked
2560 * with __THROW.
2561 * */
2562int
2563vcom_accept (int __fd, __SOCKADDR_ARG __addr,
2564 socklen_t * __restrict __addr_len)
2565{
2566
2567 if (vcom_init () != 0)
2568 {
2569 return -1;
2570 }
2571 return vcom_socket_accept (__fd, __addr, __addr_len);
2572}
2573
2574int
2575accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2576{
2577 int rv = -1;
2578 pid_t pid = getpid ();
2579 pthread_t tid = pthread_self ();
2580
2581 if (is_vcom_socket_fd (__fd))
2582 {
2583 if (VCOM_DEBUG > 0)
2584 vcom_socket_main_show ();
2585 if (VCOM_DEBUG > 0)
2586 fprintf (stderr,
2587 "[%d][%lu (0x%lx)] accept1: "
2588 "'%04d'='%04d', '%p', '%p'\n",
2589 pid, (unsigned long) tid, (unsigned long) tid,
2590 rv, __fd, __addr, __addr_len);
2591 rv = vcom_accept (__fd, __addr, __addr_len);
2592 if (VCOM_DEBUG > 0)
2593 fprintf (stderr,
2594 "[%d][%lu (0x%lx)] accept2: "
2595 "'%04d'='%04d', '%p', '%p'\n",
2596 pid, (unsigned long) tid, (unsigned long) tid,
2597 rv, __fd, __addr, __addr_len);
2598 if (VCOM_DEBUG > 0)
2599 vcom_socket_main_show ();
2600 if (rv < 0)
2601 {
2602 errno = -rv;
2603 return -1;
2604 }
2605 return rv;
2606 }
2607 return libc_accept (__fd, __addr, __addr_len);
2608}
2609
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002610/*
2611 * Similar to 'accept' but takes an additional parameter to specify
2612 * flags.
2613 * This function is a cancellation point and therefore not marked
2614 * with __THROW.
2615 * */
2616int
2617vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
2618 socklen_t * __restrict __addr_len, int __flags)
2619{
2620
2621 if (vcom_init () != 0)
2622 {
2623 return -1;
2624 }
2625
2626 return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
2627}
2628
2629int
2630accept4 (int __fd, __SOCKADDR_ARG __addr,
2631 socklen_t * __restrict __addr_len, int __flags)
2632{
Dave Wallace59179392017-11-07 02:20:07 -05002633 int rv = 0;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002634 pid_t pid = getpid ();
2635
Dave Wallace59179392017-11-07 02:20:07 -05002636 fprintf (stderr,
2637 "[%d] accept4: in the beginning... "
2638 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2639 pid, rv, __fd, __addr, __addr_len, __flags);
2640
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002641 if (is_vcom_socket_fd (__fd))
2642 {
2643 if (VCOM_DEBUG > 0)
2644 vcom_socket_main_show ();
2645 rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
2646 if (VCOM_DEBUG > 0)
2647 fprintf (stderr,
Dave Wallace59179392017-11-07 02:20:07 -05002648 "[%d] accept4: VCL "
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002649 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2650 pid, rv, __fd, __addr, __addr_len, __flags);
2651 if (VCOM_DEBUG > 0)
2652 vcom_socket_main_show ();
2653 if (rv < 0)
2654 {
2655 errno = -rv;
2656 return -1;
2657 }
2658 return rv;
2659 }
Dave Wallace59179392017-11-07 02:20:07 -05002660 fprintf (stderr,
2661 "[%d] accept4: libc "
2662 "'%04d'='%04d', '%p', '%p', '%04x'\n",
2663 pid, rv, __fd, __addr, __addr_len, __flags);
2664
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002665 return libc_accept4 (__fd, __addr, __addr_len, __flags);
2666}
2667
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002668/*
2669 * Shut down all or part of the connection open on socket FD.
2670 * HOW determines what to shut down:
2671 * SHUT_RD = No more receptions;
2672 * SHUT_WR = No more transmissions;
2673 * SHUT_RDWR = No more receptions or transmissions.
2674 * Returns 0 on success, -1 for errors.
2675 * */
2676int
2677vcom_shutdown (int __fd, int __how)
2678{
2679 if (vcom_init () != 0)
2680 {
2681 return -1;
2682 }
2683 return vcom_socket_shutdown (__fd, __how);
2684}
2685
2686int
2687shutdown (int __fd, int __how)
2688{
2689 int rv;
2690 pid_t pid = getpid ();
2691
2692 if (is_vcom_socket_fd (__fd))
2693 {
2694 rv = vcom_shutdown (__fd, __how);
2695 if (VCOM_DEBUG > 0)
2696 fprintf (stderr,
2697 "[%d] shutdown: "
2698 "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
2699 if (rv != 0)
2700 {
2701 errno = -rv;
2702 return -1;
2703 }
2704 return 0;
2705 }
2706 return libc_shutdown (__fd, __how);
2707}
2708
2709int
2710vcom_epoll_create (int __size)
2711{
2712
2713 if (vcom_init () != 0)
2714 {
2715 return -1;
2716 }
2717
2718 if (__size <= 0)
2719 {
2720 return -EINVAL;
2721 }
2722
2723 /* __size argument is ignored "thereafter" */
2724 return vcom_epoll_create1 (0);
2725}
2726
2727/*
2728 * __size argument is ignored, but must be greater than zero
2729 */
2730int
2731epoll_create (int __size)
2732{
2733 int rv = 0;
2734 pid_t pid = getpid ();
2735
2736 rv = vcom_epoll_create (__size);
2737 if (VCOM_DEBUG > 0)
2738 fprintf (stderr,
2739 "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
2740 if (rv < 0)
2741 {
2742 errno = -rv;
2743 return -1;
2744 }
2745 return rv;
2746}
2747
2748int
2749vcom_epoll_create1 (int __flags)
2750{
2751 if (vcom_init () != 0)
2752 {
2753 return -1;
2754 }
2755
2756 if (__flags < 0)
2757 {
2758 return -EINVAL;
2759 }
2760 if (__flags & ~EPOLL_CLOEXEC)
2761 {
2762 return -EINVAL;
2763 }
2764 /* __flags can be either zero or EPOLL_CLOEXEC */
2765 /* implementation */
2766 return vcom_socket_epoll_create1 (__flags);
2767}
2768
2769/*
2770 * __flags can be either zero or EPOLL_CLOEXEC
2771 * */
2772int
2773epoll_create1 (int __flags)
2774{
2775 int rv = 0;
2776 pid_t pid = getpid ();
2777
2778 rv = vcom_epoll_create1 (__flags);
2779 if (VCOM_DEBUG > 0)
2780 fprintf (stderr,
2781 "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
2782 if (rv < 0)
2783 {
2784 errno = -rv;
2785 return -1;
2786 }
2787 return rv;
2788}
2789
2790static inline int
2791ep_op_has_event (int op)
2792{
2793 return op != EPOLL_CTL_DEL;
2794}
2795
2796int
2797vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2798{
2799 if (vcom_init () != 0)
2800 {
2801 return -1;
2802 }
2803
2804 /*
2805 * the requested operation __op is not supported
2806 * by this interface */
2807 if (!((__op == EPOLL_CTL_ADD) ||
2808 (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
2809 {
2810 return -EINVAL;
2811 }
2812
2813 /* op is ADD or MOD but event parameter is NULL */
2814 if ((ep_op_has_event (__op) && !__event))
2815 {
2816 return -EFAULT;
2817 }
2818
2819 /* fd is same as epfd */
2820 /* do not permit adding an epoll file descriptor inside itself */
2821 if (__epfd == __fd)
2822 {
2823 return -EINVAL;
2824 }
2825
2826 /* implementation */
2827 return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
2828}
2829
2830/*
2831 * implement the controller interface for epoll
2832 * that enables the insertion/removal/change of
2833 * file descriptors inside the interest set.
2834 */
2835int
2836epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2837{
2838 int rv;
2839 pid_t pid = getpid ();
2840
Dave Wallacee695cb42017-11-02 22:04:42 -04002841 rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
2842 if (VCOM_DEBUG > 0)
2843 fprintf (stderr,
2844 "[%d] epoll_ctl: "
2845 "'%04d'='%04d', '%04d', '%04d'\n", pid, rv, __epfd, __op, __fd);
2846 if (rv != 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002847 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002848 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002849 return -1;
2850 }
2851 return 0;
2852}
2853
2854int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002855epoll_wait (int __epfd, struct epoll_event *__events,
2856 int __maxevents, int __timeout)
2857{
2858 int rv;
2859 pid_t pid = getpid ();
2860
2861 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2862 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002863 fprintf (stderr, "[%d] ERROR: epoll_wait() invalid maxevents %d\n",
2864 pid, __maxevents);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002865 errno = EINVAL;
2866 return -1;
2867 }
2868
Dave Wallacee695cb42017-11-02 22:04:42 -04002869 rv =
2870 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
Dave Wallace227867f2017-11-13 21:21:53 -05002871 if (VCOM_DEBUG > 2)
Dave Wallacee695cb42017-11-02 22:04:42 -04002872 fprintf (stderr,
2873 "[%d] epoll_wait: "
2874 "'%04d'='%04d', '%p', "
2875 "'%04d', '%04d'\n",
2876 pid, rv, __epfd, __events, __maxevents, __timeout);
2877 if (rv < 0)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002878 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002879 errno = -rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002880 return -1;
2881 }
Dave Wallacee695cb42017-11-02 22:04:42 -04002882 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002883}
2884
2885
2886int
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002887epoll_pwait (int __epfd, struct epoll_event *__events,
2888 int __maxevents, int __timeout, const __sigset_t * __ss)
2889{
2890 int rv;
2891 pid_t pid = getpid ();
2892
2893 if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2894 {
2895 errno = EINVAL;
2896 return -1;
2897 }
2898
2899 if (is_vcom_epfd (__epfd))
2900 {
Dave Wallacee695cb42017-11-02 22:04:42 -04002901 rv =
2902 vcom_socket_epoll_pwait (__epfd, __events, __maxevents, __timeout,
2903 __ss);
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002904 if (VCOM_DEBUG > 0)
2905 fprintf (stderr,
2906 "[%d] epoll_pwait: "
2907 "'%04d'='%04d', '%p', "
2908 "'%04d', '%04d', "
2909 "'%p'\n",
2910 pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
2911 if (rv < 0)
2912 {
2913 errno = -rv;
2914 return -1;
2915 }
2916 return rv;
2917 }
2918 else
2919 {
2920 errno = EINVAL;
2921 return -1;
2922 }
2923
2924 return 0;
2925}
2926
2927/* Poll the file descriptors described by the NFDS structures starting at
2928 FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
2929 an event to occur; if TIMEOUT is -1, block until an event occurs.
2930 Returns the number of file descriptors with events, zero if timed out,
2931 or -1 for errors.
2932
2933 This function is a cancellation point and therefore not marked with
2934 __THROW. */
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002935
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002936int
2937vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2938{
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002939 int rv = 0;
2940 pid_t pid = getpid ();
2941
2942 struct rlimit nofile_limit;
2943 struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
2944 nfds_t fds_idx = 0;
2945
2946 /* actual set of file descriptors to be monitored */
2947 nfds_t libc_nfds = 0;
2948 nfds_t vcom_nfds = 0;
2949
2950 /* ready file descriptors
2951 *
2952 * number of structures which have nonzero revents fields
2953 * in other words, descriptors with events or errors reported.
2954 * */
2955 /* after call to libc_poll () */
2956 int rlibc_nfds = 0;
2957 /* after call to vcom_socket_poll () */
2958 int rvcom_nfds = 0;
2959
2960
2961 /* timeout value in units of timespec */
2962 struct timespec timeout_ts;
2963 struct timespec start_time, now, end_time;
2964
2965
2966 /* get start_time */
2967 rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
2968 if (rv == -1)
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002969 {
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002970 rv = -errno;
2971 goto poll_done;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07002972 }
2973
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07002974 /* set timeout_ts & end_time */
2975 if (__timeout >= 0)
2976 {
2977 /* set timeout_ts */
2978 timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
2979 timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
2980 set_normalized_timespec (&timeout_ts,
2981 timeout_ts.tv_sec, timeout_ts.tv_nsec);
2982 /* set end_time */
2983 if (__timeout)
2984 {
2985 end_time = timespec_add (start_time, timeout_ts);
2986 }
2987 else
2988 {
2989 end_time = start_time;
2990 }
2991 }
2992
2993 if (vcom_init () != 0)
2994 {
2995 rv = -1;
2996 goto poll_done;
2997 }
2998
2999 /* validate __fds */
3000 if (!__fds)
3001 {
3002 rv = -EFAULT;
3003 goto poll_done;
3004 }
3005
3006 /* validate __nfds */
3007 /*TBD: call getrlimit once when vcl-ldpreload library is init */
3008 rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
3009 if (rv != 0)
3010 {
3011 rv = -errno;
3012 goto poll_done;
3013 }
Dave Wallace5c7cf1c2017-10-24 04:12:18 -04003014 if (__nfds >= nofile_limit.rlim_cur)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003015 {
3016 rv = -EINVAL;
3017 goto poll_done;
3018 }
3019
3020 /*
3021 * for the POC, it's fair to assume that nfds is less than 1024
3022 * */
3023 if (__nfds >= MAX_POLL_NFDS_DEFAULT)
3024 {
3025 rv = -EINVAL;
3026 goto poll_done;
3027 }
3028
3029 /* set revents field (output parameter)
3030 * to zero
3031 * */
3032 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3033 {
3034 __fds[fds_idx].revents = 0;
3035 }
3036
3037#if 0
3038 /* set revents field (output parameter)
3039 * to zero for user ignored fds
3040 * */
3041 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3042 {
3043 /*
3044 * if negative fd, ignore events field
3045 * and set output parameter (revents field) to zero */
3046 if (__fds[fds_idx].fd < 0)
3047 {
3048 __fds[fds_idx].revents = 0;
3049 }
3050 }
3051#endif
3052
3053 /*
3054 * 00. prepare __fds and vcom_fds for polling
3055 * copy __fds to vcom_fds
3056 * 01. negate all except libc fds in __fds,
3057 * ignore user negated fds
3058 * 02. negate all except vcom_fds in vocm fds,
3059 * ignore user negated fds
3060 * ignore fd 0 by setting it to negative number
3061 * */
3062 memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
3063 libc_nfds = 0;
3064 vcom_nfds = 0;
3065 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3066 {
3067 /* ignore negative fds */
3068 if (__fds[fds_idx].fd < 0)
3069 {
3070 continue;
3071 }
3072
3073 /*
3074 * 00. ignore vcom fds in __fds
3075 * 01. ignore libc fds in vcom_fds,
3076 * ignore fd 0 by setting it to negative number.
3077 * as fd 0 cannot be ignored.
3078 */
3079 if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
3080 is_vcom_epfd (__fds[fds_idx].fd))
3081 {
3082 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3083 vcom_nfds++;
3084 }
3085 else
3086 {
3087 libc_nfds++;
3088 /* ignore fd 0 by setting it to negative number */
3089 if (!vcom_fds[fds_idx].fd)
3090 {
3091 vcom_fds[fds_idx].fd = -1;
3092 }
3093 vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
3094 }
3095 }
3096
3097 /*
3098 * polling loop
3099 *
3100 * poll on libc fds and vcom fds
3101 *
3102 * specifying a timeout of zero causes libc_poll() and
3103 * vcom_socket_poll() to return immediately, even if no
3104 * file descriptors are ready
3105 * */
3106 do
3107 {
3108 rlibc_nfds = 0;
3109 rvcom_nfds = 0;
3110
3111 /*
3112 * timeout parameter for libc_poll () set to zero
3113 * to poll on libc fds
3114 * */
3115
3116 /* poll on libc fds */
3117 if (libc_nfds)
3118 {
3119 /*
3120 * a timeout of zero causes libc_poll()
3121 * to return immediately
3122 * */
3123 rlibc_nfds = libc_poll (__fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003124 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003125 fprintf (stderr,
3126 "[%d] poll libc: "
3127 "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
3128
3129 if (rlibc_nfds < 0)
3130 {
3131 rv = -errno;
3132 goto poll_done_update_nfds;
3133 }
3134 }
3135
3136 /*
3137 * timeout parameter for vcom_socket_poll () set to zero
3138 * to poll on vcom fds
3139 * */
3140
3141 /* poll on vcom fds */
3142 if (vcom_nfds)
3143 {
3144 /*
3145 * a timeout of zero causes vcom_socket_poll()
3146 * to return immediately
3147 * */
3148 rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
Dave Wallacee22aa742017-10-20 12:30:38 -04003149 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003150 fprintf (stderr,
3151 "[%d] poll vcom: "
3152 "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
3153 if (rvcom_nfds < 0)
3154 {
3155 rv = rvcom_nfds;
3156 goto poll_done_update_nfds;
3157 }
3158 }
3159
3160 /* check if any file descriptors changed status */
3161 if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
3162 {
3163 /* something interesting happened */
3164 rv = rlibc_nfds + rvcom_nfds;
3165 goto poll_done_update_nfds;
3166 }
3167
3168 rv = clock_gettime (CLOCK_MONOTONIC, &now);
3169 if (rv == -1)
3170 {
3171 rv = -errno;
3172 goto poll_done_update_nfds;
3173 }
3174 }
3175
3176 /* block indefinitely || timeout elapsed */
3177 while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
3178
3179 /* timeout expired before anything interesting happened */
3180 rv = 0;
3181
3182poll_done_update_nfds:
3183 for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3184 {
3185 /* ignore negative fds in vcom_fds
3186 * 00. user negated fds
3187 * 01. libc fds
3188 * */
3189 if (vcom_fds[fds_idx].fd < 0)
3190 {
3191 continue;
3192 }
3193
3194 /* from here on handle positive vcom fds */
3195 /*
3196 * restore vcom fds to positive number in __fds
3197 * and update revents in __fds with the events
3198 * that actually occurred in vcom fds
3199 * */
3200 __fds[fds_idx].fd = -__fds[fds_idx].fd;
3201 if (rvcom_nfds)
3202 {
3203 __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
3204 }
3205 }
3206
3207poll_done:
Dave Wallacee22aa742017-10-20 12:30:38 -04003208 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003209 fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
3210 return rv;
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003211}
3212
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003213/*
3214 * 00. The field __fds[i].fd contains a file descriptor for an
3215 * open file.
3216 * If this field is negative, then the corresponding
3217 * events field is ignored and the revents field returns zero.
3218 * The field __fds[i].events is an input parameter.
3219 * The field __fds[i].revents is an output parameter.
3220 * 01. Specifying a negative value in timeout
3221 * means an infinite timeout.
3222 * Specifying a timeout of zero causes poll() to return
3223 * immediately, even if no file descriptors are ready.
3224 *
3225 * NOTE: observed __nfds is less than 128 from kubecon strace files
3226 */
3227
3228
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003229int
3230poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3231{
3232 int rv = 0;
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003233 pid_t pid = getpid ();
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003234
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003235
Dave Wallacee22aa742017-10-20 12:30:38 -04003236 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003237 fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
3238 pid, rv, __nfds, __fds[0].fd, __fds[0].events);
3239 rv = vcom_poll (__fds, __nfds, __timeout);
Dave Wallacee22aa742017-10-20 12:30:38 -04003240 if (VCOM_DEBUG > 2)
shrinivasan ganapathy1d359632017-10-15 15:46:09 -07003241 fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
3242 pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
3243 if (rv < 0)
3244 {
3245 errno = -rv;
3246 return -1;
3247 }
Keith Burns (alagalah)b327c2b2017-10-09 08:52:59 -07003248 return rv;
3249}
3250
3251#ifdef __USE_GNU
3252/* Like poll, but before waiting the threads signal mask is replaced
3253 with that specified in the fourth parameter. For better usability,
3254 the timeout value is specified using a TIMESPEC object.
3255
3256 This function is a cancellation point and therefore not marked with
3257 __THROW. */
3258int
3259vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
3260 const struct timespec *__timeout, const __sigset_t * __ss)
3261{
3262 if (vcom_init () != 0)
3263 {
3264 return -1;
3265 }
3266
3267 return -EOPNOTSUPP;
3268}
3269
3270int
3271ppoll (struct pollfd *__fds, nfds_t __nfds,
3272 const struct timespec *__timeout, const __sigset_t * __ss)
3273{
3274 int rv = 0;
3275
3276 errno = EOPNOTSUPP;
3277 rv = -1;
3278 return rv;
3279}
3280#endif
3281
3282void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
3283
3284void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
3285
3286void
3287vcom_constructor (void)
3288{
3289 pid_t pid = getpid ();
3290
3291 swrap_constructor ();
3292 if (vcom_init () != 0)
3293 {
3294 printf ("\n[%d] vcom_constructor...failed!\n", pid);
3295 }
3296 else
3297 {
3298 printf ("\n[%d] vcom_constructor...done!\n", pid);
3299 }
3300}
3301
3302/*
3303 * This function is called when the library is unloaded
3304 */
3305void
3306vcom_destructor (void)
3307{
3308 pid_t pid = getpid ();
3309
3310 vcom_destroy ();
3311 swrap_destructor ();
3312 printf ("\n[%d] vcom_destructor...done!\n", pid);
3313}
3314
3315
3316/*
3317 * fd.io coding-style-patch-verification: ON
3318 *
3319 * Local Variables:
3320 * eval: (c-set-style "gnu")
3321 * End:
3322 */