VCL-LDPRELOAD: statically link vppcom into libvcl-ldpreload.so
[vpp.git] / src / vcl / vcom.c
1 /*
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>
22 #include <sys/resource.h>
23
24 #include <vcl/vcom_socket_wrapper.h>
25 #include <vcl/vcom.h>
26 #include <sys/time.h>
27
28 #include <vcl/vppcom.h>
29 #include <vcl/vcom_socket.h>
30
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
65 static char vcom_app_name[MAX_VCOM_APP_NAME];
66
67 /*
68  * RETURN:  0 on success or -1 on error.
69  * */
70 int
71 vcom_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
77 static char *
78 vcom_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  */
90 static 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  * */
100 static inline int
101 vcom_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
130 static inline void
131 vcom_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
144 static inline int
145 is_vcom_socket_fd (int fd)
146 {
147   return vcom_socket_is_vcom_fd (fd);
148 }
149
150 static inline int
151 is_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  * */
171 int
172 vcom_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  */
190 int
191 close (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.  */
220 ssize_t
221 vcom_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
231 ssize_t
232 read (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     {
240       if (VCOM_DEBUG > 2)
241         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);
247       if (VCOM_DEBUG > 2)
248         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
263 ssize_t
264 vcom_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
274 ssize_t
275 readv (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.  */
297 ssize_t
298 vcom_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
308 ssize_t
309 write (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     {
317       if (VCOM_DEBUG > 2)
318         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);
324       if (VCOM_DEBUG > 2)
325         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
340 ssize_t
341 vcom_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
351 ssize_t
352 writev (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.  */
375 int
376 vcom_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
386 int
387 vcom_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
401 int
402 fcntl (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
425 out:
426   va_end (ap);
427   return rv;
428 }
429
430 int
431 vcom_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
441 int
442 vcom_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
456 int
457 ioctl (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
480 out:
481   va_end (ap);
482   return rv;
483 }
484
485 /*
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  */
508 static inline int
509 vcom_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  */
580 static inline int
581 vcom_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  */
652 static inline void
653 vcom_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  */
740 static inline void
741 vcom_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  */
837 static inline int
838 fd_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  * */
864 typedef long int s64;
865 typedef unsigned long int u64;
866
867 typedef long long int __s64;
868 typedef unsigned long long int __u64;
869
870 typedef __s64 time64_t;
871 typedef __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
892 #ifdef VCOM_USE_TIMESPEC_EQUAL
893 static inline int
894 timespec_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 }
898 #endif
899
900 /*
901  * lhs < rhs:  return <0
902  * lhs == rhs: return 0
903  * lhs > rhs:  return >0
904  */
905 static inline int
906 timespec_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
915 #ifdef VCOM_USE_TIMEVAL_COMPARE
916 static inline int
917 timeval_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 }
925 #endif
926
927 extern void set_normalized_timespec (struct timespec *ts, time_t sec,
928                                      s64 nsec);
929
930 static inline struct timespec
931 timespec_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  */
942 static inline struct timespec
943 timespec_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  */
972 void
973 set_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
1008 static inline int
1009 vcom_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
1018 int
1019 vcom_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);
1225           if (VCOM_DEBUG > 2)
1226             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);
1243           if (VCOM_DEBUG > 2)
1244             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 */
1285                               __readfds || __writefds || __exceptfds ?
1286                               &new_nfds : NULL,
1287                               __readfds,
1288                               __writefds,
1289                               __exceptfds,
1290                               __readfds || __writefds || __exceptfds ?
1291                               &new_nfd : NULL,
1292                               /* src1, vcom sets */
1293                               vcom_nfds,
1294                               __readfds ? &vcom_readfds : NULL,
1295                               __writefds ? &vcom_writefds : NULL,
1296                               __exceptfds ? &vcom_exceptfds : NULL, vcom_nfd,
1297                               /* src2, libc sets */
1298                               libc_nfds,
1299                               __readfds ? &libc_readfds : NULL,
1300                               __writefds ? &libc_writefds : NULL,
1301                               __exceptfds ? &libc_exceptfds : NULL, libc_nfd);
1302           /*
1303            * return the number of file descriptors contained in the
1304            * three returned sets
1305            * */
1306           rv = 0;
1307           /*
1308            * for documentation
1309            *
1310            * if(vcom_nfd > 0)
1311            *   rv += vcom_nfd;
1312            * if(libc_nfd > 0)
1313            *   rv += libc_nfd;
1314            */
1315
1316           rv = new_nfd == -1 ? 0 : new_nfd;
1317           goto select_done;
1318         }
1319
1320       rv = clock_gettime (CLOCK_MONOTONIC, &now);
1321       if (rv == -1)
1322         {
1323           rv = -errno;
1324           goto select_done;
1325         }
1326     }
1327   while (no_timeout || timespec_compare (&now, &end_time) < 0);
1328
1329   /* timeout expired before anything interesting happened */
1330   timedout = 1;
1331   rv = 0;
1332
1333 select_done:
1334   if (VCOM_DEBUG > 2)
1335     fprintf (stderr, "[%d] vselect1: " "'%04d'='%04d'\n", pid, rv, __nfds);
1336   /*
1337    * modify timeout parameter to reflect the amount of time not slept
1338    * */
1339   if (__timeout)
1340     {
1341       if (vcom_timerisvalid (__timeout))
1342         {
1343           /* timeout expired */
1344           if (timedout)
1345             {
1346               timerclear (__timeout);
1347             }
1348           else if (!first_clock_gettime_failed)
1349             {
1350               rv2 = clock_gettime (CLOCK_MONOTONIC, &now);
1351               if (rv2 == -1)
1352                 {
1353                   rv = -errno;
1354                 }
1355               else
1356                 {
1357                   struct timespec ts_delta;
1358                   ts_delta = timespec_sub (end_time, now);
1359                   VCOM_TIMESPEC_TO_TIMEVAL (__timeout, &ts_delta);
1360                 }
1361             }
1362         }
1363     }
1364   if (VCOM_DEBUG > 2)
1365     fprintf (stderr, "[%d] vselect2: " "'%04d',='%04d'\n", pid, rv, __nfds);
1366
1367   return rv;
1368 }
1369
1370 int
1371 vcom_select_internal (int __nfds, fd_set * __restrict __readfds,
1372                       fd_set * __restrict __writefds,
1373                       fd_set * __restrict __exceptfds,
1374                       struct timeval *__restrict __timeout)
1375 {
1376   int rv;
1377   int new_nfds = 0;
1378   int nfd = 0;
1379   pid_t pid = getpid ();
1380
1381   fd_set saved_readfds;
1382   fd_set saved_writefds;
1383   fd_set saved_exceptfds;
1384
1385   /* validate __nfds */
1386   if (__nfds < 0)
1387     {
1388       errno = EINVAL;
1389       return -1;
1390     }
1391
1392   /* validate __timeout */
1393   if (__timeout)
1394     {
1395       /* validate tv_sec */
1396       /* bogus */
1397       if (__timeout->tv_sec < 0 || __timeout->tv_usec < 0)
1398         {
1399           errno = EINVAL;
1400           return -1;
1401         }
1402
1403       /* validate tv_usec */
1404       /* TBD: */
1405     }
1406
1407   /* init saved_x fds */
1408   if (__readfds)
1409     {
1410       saved_readfds = *__readfds;
1411       /*
1412          memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
1413        */
1414     }
1415   else
1416     {
1417       FD_ZERO (&saved_readfds);
1418     }
1419
1420   if (__writefds)
1421     {
1422       saved_writefds = *__writefds;
1423       /*
1424          memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
1425        */
1426
1427     }
1428   else
1429     {
1430       FD_ZERO (&saved_writefds);
1431     }
1432
1433   if (__exceptfds)
1434     {
1435       saved_exceptfds = *__exceptfds;
1436       /*
1437          memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
1438        */
1439
1440     }
1441   else
1442     {
1443       FD_ZERO (&saved_exceptfds);
1444     }
1445
1446   /* clear vcom fds */
1447   nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
1448
1449   /* set to an invalid value */
1450   rv = -2;
1451   /* have kernel fds */
1452   if (new_nfds)
1453     rv = libc_select (new_nfds, __readfds,
1454                       __writefds, __exceptfds, __timeout);
1455
1456   if (new_nfds && rv == -1)
1457     {
1458       /* on error, the file descriptor sets are unmodified */
1459       if (__readfds)
1460         *__readfds = saved_readfds;
1461       if (__writefds)
1462         *__writefds = saved_writefds;
1463       if (__exceptfds)
1464         *__exceptfds = saved_exceptfds;
1465       return rv;
1466     }
1467   else if ((new_nfds && rv != -1) || (rv == -2))
1468     {
1469       /* restore vcom fds */
1470       nfd = vcom_fd_set (__nfds,
1471                          &new_nfds,
1472                          __readfds,
1473                          __writefds,
1474                          __exceptfds,
1475                          &saved_readfds, &saved_writefds, &saved_exceptfds);
1476       rv = nfd;
1477     }
1478
1479   if (VCOM_DEBUG > 0)
1480     fprintf (stderr, "[%d] select: " "'%04d'='%04d'\n", pid, rv, __nfds);
1481   return rv;
1482 }
1483
1484 int
1485 select (int __nfds, fd_set * __restrict __readfds,
1486         fd_set * __restrict __writefds,
1487         fd_set * __restrict __exceptfds, struct timeval *__restrict __timeout)
1488 {
1489   int rv = 0;
1490   pid_t pid = getpid ();
1491
1492   if (VCOM_DEBUG > 2)
1493     fprintf (stderr, "[%d] select1: " "'%04d'='%04d'\n", pid, rv, __nfds);
1494   rv = vcom_select (__nfds, __readfds, __writefds, __exceptfds, __timeout);
1495   if (VCOM_DEBUG > 2)
1496     fprintf (stderr, "[%d] select2: " "'%04d'='%04d'\n", pid, rv, __nfds);
1497   if (rv < 0)
1498     {
1499       errno = -rv;
1500       return -1;
1501     }
1502   return rv;
1503 }
1504
1505 #ifdef __USE_XOPEN2K
1506 /*
1507  * Same as above only that the TIMEOUT value is given with higher
1508  * resolution and a sigmask which is been set temporarily.  This
1509  * version should be used.
1510  *
1511  * This function is a cancellation point and therefore not marked
1512  * with __THROW.
1513  * */
1514 int
1515 vcom_pselect (int __nfds, fd_set * __restrict __readfds,
1516               fd_set * __restrict __writefds,
1517               fd_set * __restrict __exceptfds,
1518               const struct timespec *__restrict __timeout,
1519               const __sigset_t * __restrict __sigmask)
1520 {
1521   int fd;
1522   int vcom_nfds = 0;
1523
1524   for (fd = 0; fd < __nfds; fd++)
1525     {
1526       if (__readfds && FD_ISSET (fd, __readfds))
1527         {
1528           if (is_vcom_socket_fd (fd))
1529             {
1530               vcom_nfds++;
1531             }
1532         }
1533
1534       if (__writefds && FD_ISSET (fd, __writefds))
1535         {
1536           if (is_vcom_socket_fd (fd))
1537             {
1538               vcom_nfds++;
1539             }
1540         }
1541       if (__exceptfds && FD_ISSET (fd, __exceptfds))
1542         {
1543           if (is_vcom_socket_fd (fd))
1544             {
1545               FD_CLR (fd, __exceptfds);
1546             }
1547         }
1548     }
1549   return vcom_nfds;
1550 }
1551
1552 int
1553 pselect (int __nfds, fd_set * __restrict __readfds,
1554          fd_set * __restrict __writefds,
1555          fd_set * __restrict __exceptfds,
1556          const struct timespec *__restrict __timeout,
1557          const __sigset_t * __restrict __sigmask)
1558 {
1559   int rv;
1560   int new_nfds = 0;
1561   int nfd = 0;
1562   pid_t pid = getpid ();
1563
1564   fd_set saved_readfds;
1565   fd_set saved_writefds;
1566   fd_set saved_exceptfds;
1567
1568   /* validate __nfds */
1569   if (__nfds < 0)
1570     {
1571       errno = EINVAL;
1572       return -1;
1573     }
1574
1575   /* validate __timeout */
1576   if (__timeout)
1577     {
1578       /* validate tv_sec */
1579       /* bogus */
1580       if (__timeout->tv_sec < 0 || __timeout->tv_nsec < 0)
1581         {
1582           errno = EINVAL;
1583           return -1;
1584         }
1585
1586       /* validate tv_usec */
1587       /* TBD: */
1588     }
1589
1590   /* init saved fds */
1591   if (__readfds)
1592     {
1593       saved_readfds = *__readfds;
1594       /*
1595          memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
1596        */
1597     }
1598   else
1599     {
1600       FD_ZERO (&saved_readfds);
1601     }
1602
1603   if (__writefds)
1604     {
1605       saved_writefds = *__writefds;
1606       /*
1607          memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
1608        */
1609
1610     }
1611   else
1612     {
1613       FD_ZERO (&saved_writefds);
1614     }
1615
1616   if (__exceptfds)
1617     {
1618       saved_exceptfds = *__exceptfds;
1619       /*
1620          memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
1621        */
1622
1623     }
1624   else
1625     {
1626       FD_ZERO (&saved_exceptfds);
1627     }
1628
1629   /* clear vcom fds */
1630   nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
1631
1632   /* set to an invalid value */
1633   rv = -2;
1634   if (new_nfds)
1635     rv = libc_pselect (new_nfds,
1636                        __readfds,
1637                        __writefds, __exceptfds, __timeout, __sigmask);
1638
1639   if (new_nfds && rv == -1)
1640     {
1641       /* on error, the file descriptor sets are unmodified */
1642       if (__readfds)
1643         *__readfds = saved_readfds;
1644       if (__writefds)
1645         *__writefds = saved_writefds;
1646       if (__exceptfds)
1647         *__exceptfds = saved_exceptfds;
1648       return rv;
1649     }
1650   else if ((new_nfds && rv != -1) || (rv == -2))
1651     {
1652       /* restore vcom fds */
1653       nfd = vcom_fd_set (__nfds,
1654                          &new_nfds,
1655                          __readfds,
1656                          __writefds,
1657                          __exceptfds,
1658                          &saved_readfds, &saved_writefds, &saved_exceptfds);
1659       rv = nfd;
1660     }
1661
1662   if (VCOM_DEBUG > 2)
1663     fprintf (stderr, "[%d] pselect: " "'%04d'='%04d'\n", pid, rv, __nfds);
1664   return rv;
1665 }
1666 #endif
1667
1668 /*
1669  *
1670  * Socket specific glibc api
1671  *
1672  */
1673
1674 /* Create a new socket of type TYPE in domain DOMAIN, using
1675  * protocol PROTOCOL.  If PROTOCOL is zero, one is chosen
1676  * automatically. Returns a file descriptor for the new socket,
1677  * or -1 for errors.
1678  * RETURN:  a valid file descriptor for the new socket,
1679  * or -1 for errors.
1680  * */
1681
1682 int
1683 vcom_socket (int __domain, int __type, int __protocol)
1684 {
1685   if (vcom_init () != 0)
1686     {
1687       return -1;
1688     }
1689
1690   return vcom_socket_socket (__domain, __type, __protocol);
1691 }
1692
1693 int
1694 socket (int __domain, int __type, int __protocol)
1695 {
1696   int rv;
1697   pid_t pid = getpid ();
1698   pthread_t tid = pthread_self ();
1699
1700   /* handle domains implemented by vpp */
1701   switch (__domain)
1702     {
1703     case AF_INET:
1704     case AF_INET6:
1705       /* handle types implemented by vpp */
1706       switch (__type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1707         {
1708         case SOCK_STREAM:
1709         case SOCK_DGRAM:
1710           if (VCOM_DEBUG > 0)
1711             vcom_socket_main_show ();
1712           rv = vcom_socket (__domain, __type, __protocol);
1713           if (VCOM_DEBUG > 0)
1714             fprintf (stderr,
1715                      "[%d][%lu (0x%lx)] socket: "
1716                      "'%04d'= D='%04d', T='%04d', P='%04d'\n",
1717                      pid, (unsigned long) tid, (unsigned long) tid,
1718                      rv, __domain, __type, __protocol);
1719           if (VCOM_DEBUG > 0)
1720             vcom_socket_main_show ();
1721           if (rv < 0)
1722             {
1723               errno = -rv;
1724               return -1;
1725             }
1726           return rv;
1727           break;
1728
1729         default:
1730           goto CALL_GLIBC_SOCKET_API;
1731           break;
1732         }
1733
1734       break;
1735
1736     default:
1737       goto CALL_GLIBC_SOCKET_API;
1738       break;
1739     }
1740
1741 CALL_GLIBC_SOCKET_API:
1742   return libc_socket (__domain, __type, __protocol);
1743 }
1744
1745 /*
1746  * Create two new sockets, of type TYPE in domain DOMAIN and using
1747  * protocol PROTOCOL, which are connected to each other, and put file
1748  * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
1749  * one will be chosen automatically.
1750  * Returns 0 on success, -1 for errors.
1751  * */
1752 int
1753 vcom_socketpair (int __domain, int __type, int __protocol, int __fds[2])
1754 {
1755   if (vcom_init () != 0)
1756     {
1757       return -1;
1758     }
1759
1760   return vcom_socket_socketpair (__domain, __type, __protocol, __fds);
1761 }
1762
1763 int
1764 socketpair (int __domain, int __type, int __protocol, int __fds[2])
1765 {
1766   int rv;
1767   pid_t pid = getpid ();
1768
1769   /* handle domains implemented by vpp */
1770   switch (__domain)
1771     {
1772     case AF_INET:
1773     case AF_INET6:
1774       /* handle types implemented by vpp */
1775       switch (__type)
1776         {
1777         case SOCK_STREAM:
1778         case SOCK_DGRAM:
1779           rv = vcom_socketpair (__domain, __type, __protocol, __fds);
1780           if (VCOM_DEBUG > 0)
1781             fprintf (stderr,
1782                      "[%d] socketpair: "
1783                      "'%04d'= D='%04d', T='%04d', P='%04d'\n",
1784                      pid, rv, __domain, __type, __protocol);
1785           if (rv < 0)
1786             {
1787               errno = -rv;
1788               return -1;
1789             }
1790           return 0;
1791           break;
1792
1793         default:
1794           goto CALL_GLIBC_SOCKET_API;
1795           break;
1796         }
1797
1798       break;
1799
1800     default:
1801       goto CALL_GLIBC_SOCKET_API;
1802       break;
1803     }
1804
1805 CALL_GLIBC_SOCKET_API:
1806   return libc_socketpair (__domain, __type, __protocol, __fds);
1807 }
1808
1809 /*
1810  * Give the socket FD the local address ADDR
1811  * (which is LEN bytes long).
1812  * */
1813 int
1814 vcom_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1815 {
1816   int rv;
1817
1818   if (vcom_init () != 0)
1819     {
1820       return -1;
1821     }
1822
1823   /* validate __len */
1824   switch (__addr->sa_family)
1825     {
1826     case AF_INET:
1827       if (__len != sizeof (struct sockaddr_in))
1828         return -EINVAL;
1829       break;
1830     case AF_INET6:
1831       if (__len != sizeof (struct sockaddr_in6))
1832         return -EINVAL;
1833       break;
1834
1835     default:
1836       return -1;
1837       break;
1838     }
1839
1840   /* handle domains implemented by vpp */
1841   switch (__addr->sa_family)
1842     {
1843     case AF_INET:
1844     case AF_INET6:
1845       rv = vcom_socket_bind (__fd, __addr, __len);
1846       return rv;
1847       break;
1848
1849     default:
1850       return -1;
1851       break;
1852     }
1853
1854   return -1;
1855 }
1856
1857 int
1858 bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1859 {
1860   int rv;
1861   pid_t pid = getpid ();
1862
1863   if (is_vcom_socket_fd (__fd))
1864     {
1865
1866       rv = vcom_bind (__fd, __addr, __len);
1867       if (VCOM_DEBUG > 0)
1868         fprintf (stderr,
1869                  "[%d] bind: "
1870                  "'%04d'='%04d', '%p', '%04d'\n",
1871                  pid, rv, __fd, __addr, __len);
1872       if (rv != 0)
1873         {
1874           errno = -rv;
1875           return -1;
1876         }
1877       return 0;
1878     }
1879   return libc_bind (__fd, __addr, __len);
1880 }
1881
1882 /*
1883  * Put the local address of FD into *ADDR and its length in *LEN.
1884  * */
1885 int
1886 vcom_getsockname (int __fd, __SOCKADDR_ARG __addr,
1887                   socklen_t * __restrict __len)
1888 {
1889   if (vcom_init () != 0)
1890     {
1891       return -1;
1892     }
1893
1894   return vcom_socket_getsockname (__fd, __addr, __len);
1895 }
1896
1897 int
1898 getsockname (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
1899 {
1900   int rv;
1901   pid_t pid = getpid ();
1902
1903   if (is_vcom_socket_fd (__fd))
1904     {
1905       rv = vcom_getsockname (__fd, __addr, __len);
1906       if (VCOM_DEBUG > 0)
1907         fprintf (stderr,
1908                  "[%d] getsockname: "
1909                  "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
1910       if (rv != 0)
1911         {
1912           errno = -rv;
1913           return -1;
1914         }
1915       return 0;
1916     }
1917   return libc_getsockname (__fd, __addr, __len);
1918 }
1919
1920 /*
1921  * Open a connection on socket FD to peer at ADDR
1922  * (which LEN bytes long). For connectionless socket types, just set
1923  * the default address to send to and the only address from which to
1924  * accept transmissions. Return 0 on success, -1 for errors.
1925  * This function is a cancellation point and therefore not marked
1926  * with __THROW.
1927  * */
1928 int
1929 vcom_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1930 {
1931   int rv = -1;
1932
1933   if (vcom_init () != 0)
1934     {
1935       return -1;
1936     }
1937
1938   /* validate __len */
1939   switch (__addr->sa_family)
1940     {
1941     case AF_INET:
1942       if (__len != INET_ADDRSTRLEN)
1943         return -1;
1944       break;
1945     case AF_INET6:
1946       if (__len != INET6_ADDRSTRLEN)
1947         return -1;
1948       break;
1949
1950     default:
1951       return -1;
1952       break;
1953     }
1954
1955   /* handle domains implemented by vpp */
1956   switch (__addr->sa_family)
1957     {
1958     case AF_INET:
1959     case AF_INET6:
1960       rv = vcom_socket_connect (__fd, __addr, __len);
1961       break;
1962
1963     default:
1964       return -1;
1965       break;
1966     }
1967
1968   return rv;
1969 }
1970
1971 int
1972 connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1973 {
1974   int rv;
1975   pid_t pid = getpid ();
1976   pthread_t tid = pthread_self ();
1977
1978   if (is_vcom_socket_fd (__fd))
1979     {
1980       rv = vcom_connect (__fd, __addr, __len);
1981       if (VCOM_DEBUG > 0)
1982         fprintf (stderr,
1983                  "[%d][%lu (0x%lx)] connect: "
1984                  "'%04d'='%04d', '%p', '%04d'\n",
1985                  pid, (unsigned long) tid, (unsigned long) tid,
1986                  rv, __fd, __addr, __len);
1987       if (rv != 0)
1988         {
1989           errno = -rv;
1990           return -1;
1991         }
1992       return 0;
1993     }
1994
1995   return libc_connect (__fd, __addr, __len);
1996 }
1997
1998 /*
1999  * Put the address of the peer connected to socket FD into *ADDR
2000  * (which is *LEN bytes long), and its actual length into *LEN.
2001  * */
2002 int
2003 vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
2004                   socklen_t * __restrict __len)
2005 {
2006   if (vcom_init () != 0)
2007     {
2008       return -1;
2009     }
2010
2011   return vcom_socket_getpeername (__fd, __addr, __len);
2012 }
2013
2014 int
2015 getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
2016 {
2017   int rv;
2018   pid_t pid = getpid ();
2019
2020   if (is_vcom_socket_fd (__fd))
2021     {
2022       rv = vcom_getpeername (__fd, __addr, __len);
2023       if (VCOM_DEBUG > 0)
2024         fprintf (stderr,
2025                  "[%d] getpeername: "
2026                  "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
2027       if (rv != 0)
2028         {
2029           errno = -rv;
2030           return -1;
2031         }
2032       return 0;
2033     }
2034   return libc_getpeername (__fd, __addr, __len);
2035 }
2036
2037 /*
2038  * Send N bytes of BUF to socket FD.  Returns the number sent or -1.
2039  * This function is a cancellation point and therefore not marked
2040  * with __THROW.
2041  * */
2042 ssize_t
2043 vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
2044 {
2045
2046   if (vcom_init () != 0)
2047     {
2048       return -1;
2049     }
2050
2051   return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
2052 }
2053
2054 ssize_t
2055 send (int __fd, const void *__buf, size_t __n, int __flags)
2056 {
2057   ssize_t size;
2058   pid_t pid = getpid ();
2059
2060   if (is_vcom_socket_fd (__fd))
2061     {
2062       size = vcom_send (__fd, __buf, __n, __flags);
2063       if (VCOM_DEBUG > 0)
2064         fprintf (stderr,
2065                  "[%d] send: "
2066                  "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2067                  pid, (int) size, __fd, __buf, (int) __n, __flags);
2068       if (size < 0)
2069         {
2070           errno = -size;
2071           return -1;
2072         }
2073       return size;
2074     }
2075   return libc_send (__fd, __buf, __n, __flags);
2076 }
2077
2078 /*
2079  * Read N bytes into BUF from socket FD.
2080  * Returns the number read or -1 for errors.
2081  * This function is a cancellation point and therefore not marked
2082  *  with __THROW.
2083  *  */
2084 ssize_t
2085 vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
2086 {
2087   if (vcom_init () != 0)
2088     {
2089       return -1;
2090     }
2091
2092   return vcom_socket_recv (__fd, __buf, __n, __flags);
2093 }
2094
2095 ssize_t
2096 recv (int __fd, void *__buf, size_t __n, int __flags)
2097 {
2098   ssize_t size;
2099   pid_t pid = getpid ();
2100
2101   if (is_vcom_socket_fd (__fd))
2102     {
2103       size = vcom_recv (__fd, __buf, __n, __flags);
2104       if (VCOM_DEBUG > 0)
2105         fprintf (stderr,
2106                  "[%d] recv: "
2107                  "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2108                  pid, (int) size, __fd, __buf, (int) __n, __flags);
2109       if (size < 0)
2110         {
2111           errno = -size;
2112           return -1;
2113         }
2114       return size;
2115     }
2116   return libc_recv (__fd, __buf, __n, __flags);
2117 }
2118
2119 /*
2120  * Send N bytes of BUF on socket FD to peer at address ADDR (which is
2121  * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.
2122  * This function is a cancellation point and therefore not marked
2123  * with __THROW.
2124  * */
2125 ssize_t
2126 vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
2127              __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2128 {
2129   if (vcom_init () != 0)
2130     {
2131       return -1;
2132     }
2133
2134   return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2135 }
2136
2137 ssize_t
2138 sendto (int __fd, const void *__buf, size_t __n, int __flags,
2139         __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
2140 {
2141   ssize_t size;
2142   pid_t pid = getpid ();
2143
2144   if (is_vcom_socket_fd (__fd))
2145     {
2146       size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2147       if (VCOM_DEBUG > 0)
2148         fprintf (stderr,
2149                  "[%d] sendto: "
2150                  "'%04d'='%04d', '%p', '%04d', '%04x', "
2151                  "'%p', '%04d'\n",
2152                  pid, (int) size, __fd, __buf, (int) __n, __flags,
2153                  __addr, __addr_len);
2154       if (size < 0)
2155         {
2156           errno = -size;
2157           return -1;
2158         }
2159       return size;
2160     }
2161   return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
2162 }
2163
2164 /*
2165  * Read N bytes into BUF through socket FD.
2166  * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
2167  * address of the sender, and store the actual size of the address
2168  * in *ADDR_LEN.
2169  * Returns the number of bytes read or -1 for errors.
2170  * This function is a cancellation point and therefore not marked
2171  * with __THROW.
2172  * */
2173 ssize_t
2174 vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
2175                int __flags,
2176                __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2177 {
2178   if (vcom_init () != 0)
2179     {
2180       return -1;
2181     }
2182
2183   return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2184 }
2185
2186 ssize_t
2187 recvfrom (int __fd, void *__restrict __buf, size_t __n,
2188           int __flags,
2189           __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2190 {
2191   ssize_t size;
2192   pid_t pid = getpid ();
2193
2194   if (is_vcom_socket_fd (__fd))
2195     {
2196       size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2197       if (VCOM_DEBUG > 0)
2198         fprintf (stderr,
2199                  "[%d] recvfrom: "
2200                  "'%04d'='%04d', '%p', '%04d', '%04x', "
2201                  "'%p', '%p'\n",
2202                  pid, (int) size, __fd, __buf, (int) __n, __flags,
2203                  __addr, __addr_len);
2204       if (size < 0)
2205         {
2206           errno = -size;
2207           return -1;
2208         }
2209       return size;
2210     }
2211   return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
2212 }
2213
2214 /*
2215  * Send a message described MESSAGE on socket FD.
2216  * Returns the number of bytes sent, or -1 for errors.
2217  * This function is a cancellation point and therefore not marked
2218  * with __THROW.
2219  * */
2220 ssize_t
2221 vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
2222 {
2223   if (vcom_init () != 0)
2224     {
2225       return -1;
2226     }
2227
2228   return vcom_socket_sendmsg (__fd, __message, __flags);
2229 }
2230
2231 ssize_t
2232 sendmsg (int __fd, const struct msghdr * __message, int __flags)
2233 {
2234   ssize_t size;
2235   pid_t pid = getpid ();
2236
2237   if (is_vcom_socket_fd (__fd))
2238     {
2239       size = vcom_sendmsg (__fd, __message, __flags);
2240       if (VCOM_DEBUG > 0)
2241         fprintf (stderr,
2242                  "[%d] sendmsg: "
2243                  "'%04d'='%04d', '%p', '%04x'\n",
2244                  pid, (int) size, __fd, __message, __flags);
2245       if (size < 0)
2246         {
2247           errno = -size;
2248           return -1;
2249         }
2250       return size;
2251     }
2252   return libc_sendmsg (__fd, __message, __flags);
2253 }
2254
2255 #ifdef __USE_GNU
2256 /*
2257  * Send a VLEN messages as described by VMESSAGES to socket FD.
2258  * Returns the number of datagrams successfully written
2259  * or -1 for errors.
2260  * This function is a cancellation point and therefore not marked
2261  * with __THROW.
2262  * */
2263 int
2264 vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
2265                unsigned int __vlen, int __flags)
2266 {
2267   if (vcom_init () != 0)
2268     {
2269       return -1;
2270     }
2271
2272   return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
2273 }
2274
2275 int
2276 sendmmsg (int __fd, struct mmsghdr *__vmessages,
2277           unsigned int __vlen, int __flags)
2278 {
2279   ssize_t size;
2280   pid_t pid = getpid ();
2281
2282   if (is_vcom_socket_fd (__fd))
2283     {
2284       size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
2285       if (VCOM_DEBUG > 0)
2286         fprintf (stderr,
2287                  "[%d] sendmmsg: "
2288                  "'%04d'='%04d', '%p', '%04d', '%04x'\n",
2289                  pid, (int) size, __fd, __vmessages, __vlen, __flags);
2290       if (size < 0)
2291         {
2292           errno = -size;
2293           return -1;
2294         }
2295       return size;
2296     }
2297   return libc_sendmmsg (__fd, __message, __vlen, __flags);
2298 }
2299
2300 #endif
2301
2302 /*
2303  * Receive a message as described by MESSAGE from socket FD.
2304  * Returns the number of bytes read or -1 for errors.
2305  * This function is a cancellation point and therefore not marked
2306  * with __THROW.
2307  * */
2308 ssize_t
2309 vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
2310 {
2311   if (vcom_init () != 0)
2312     {
2313       return -1;
2314     }
2315
2316   return vcom_socket_recvmsg (__fd, __message, __flags);
2317 }
2318
2319 ssize_t
2320 recvmsg (int __fd, struct msghdr * __message, int __flags)
2321 {
2322   ssize_t size;
2323   pid_t pid = getpid ();
2324
2325   if (is_vcom_socket_fd (__fd))
2326     {
2327       size = vcom_recvmsg (__fd, __message, __flags);
2328       if (VCOM_DEBUG > 0)
2329         fprintf (stderr,
2330                  "[%d] recvmsg: "
2331                  "'%04d'='%04d', '%p', '%04x'\n",
2332                  pid, (int) size, __fd, __message, __flags);
2333       if (size < 0)
2334         {
2335           errno = -size;
2336           return -1;
2337         }
2338       return size;
2339     }
2340   return libc_recvmsg (__fd, __message, __flags);
2341 }
2342
2343 #ifdef __USE_GNU
2344 /*
2345  * Receive up to VLEN messages as described by VMESSAGES from socket FD.
2346  * Returns the number of messages received or -1 for errors.
2347  * This function is a cancellation point and therefore not marked
2348  * with __THROW.
2349  * */
2350 int
2351 vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
2352                unsigned int __vlen, int __flags, struct timespec *__tmo)
2353 {
2354   if (vcom_init () != 0)
2355     {
2356       return -1;
2357     }
2358
2359   return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2360 }
2361
2362 int
2363 recvmmsg (int __fd, struct mmsghdr *__vmessages,
2364           unsigned int __vlen, int __flags, struct timespec *__tmo)
2365 {
2366   ssize_t size;
2367   pid_t pid = getpid ();
2368
2369   if (is_vcom_socket_fd (__fd))
2370     {
2371       size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2372       if (VCOM_DEBUG > 0)
2373         fprintf (stderr,
2374                  "[%d] recvmmsg: "
2375                  "'%04d'='%04d', '%p', "
2376                  "'%04d', '%04x', '%p'\n",
2377                  pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
2378       if (size < 0)
2379         {
2380           errno = -size;
2381           return -1;
2382         }
2383       return size;
2384     }
2385   return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
2386 }
2387
2388 #endif
2389
2390 /*
2391  * Put the current value for socket FD's option OPTNAME
2392  * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
2393  * and set *OPTLEN to the value's actual length.
2394  * Returns 0 on success, -1 for errors.
2395  * */
2396 int
2397 vcom_getsockopt (int __fd, int __level, int __optname,
2398                  void *__restrict __optval, socklen_t * __restrict __optlen)
2399 {
2400   if (vcom_init () != 0)
2401     {
2402       return -1;
2403     }
2404
2405   return vcom_socket_getsockopt (__fd, __level, __optname,
2406                                  __optval, __optlen);
2407 }
2408
2409 int
2410 getsockopt (int __fd, int __level, int __optname,
2411             void *__restrict __optval, socklen_t * __restrict __optlen)
2412 {
2413   int rv;
2414   pid_t pid = getpid ();
2415
2416   if (is_vcom_socket_fd (__fd))
2417     {
2418       rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
2419       if (VCOM_DEBUG > 2)
2420         fprintf (stderr,
2421                  "[%d] getsockopt: "
2422                  "'%04d'='%04d', '%04d', '%04d', "
2423                  "'%p', '%p'\n",
2424                  pid, rv, __fd, __level, __optname, __optval, __optlen);
2425       if (rv != 0)
2426         {
2427           errno = -rv;
2428           return -1;
2429         }
2430       return 0;
2431     }
2432   return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
2433 }
2434
2435 /*
2436  * Set socket FD's option OPTNAME at protocol level LEVEL
2437  * to *OPTVAL (which is OPTLEN bytes long).
2438  * Returns 0 on success, -1 for errors.
2439  * */
2440 int
2441 vcom_setsockopt (int __fd, int __level, int __optname,
2442                  const void *__optval, socklen_t __optlen)
2443 {
2444   if (vcom_init () != 0)
2445     {
2446       return -1;
2447     }
2448
2449   return vcom_socket_setsockopt (__fd, __level, __optname,
2450                                  __optval, __optlen);
2451 }
2452
2453 int
2454 setsockopt (int __fd, int __level, int __optname,
2455             const void *__optval, socklen_t __optlen)
2456 {
2457   int rv;
2458   pid_t pid = getpid ();
2459
2460   if (is_vcom_socket_fd (__fd))
2461     {
2462       rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
2463       if (VCOM_DEBUG > 0)
2464         fprintf (stderr,
2465                  "[%d] setsockopt: "
2466                  "'%04d'='%04d', '%04d', '%04d', "
2467                  "'%p', '%04d'\n",
2468                  pid, rv, __fd, __level, __optname, __optval, __optlen);
2469       if (rv != 0)
2470         {
2471           errno = -rv;
2472           return -1;
2473         }
2474       return 0;
2475     }
2476   return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2477 }
2478
2479 /*
2480  * Prepare to accept connections on socket FD.
2481  * N connection requests will be queued before further
2482  * requests are refused.
2483  * Returns 0 on success, -1 for errors.
2484  * */
2485 int
2486 vcom_listen (int __fd, int __n)
2487 {
2488   if (vcom_init () != 0)
2489     {
2490       return -1;
2491     }
2492
2493   return vcom_socket_listen (__fd, __n);
2494 }
2495
2496 int
2497 listen (int __fd, int __n)
2498 {
2499   int rv;
2500   pid_t pid = getpid ();
2501
2502   if (is_vcom_socket_fd (__fd))
2503     {
2504       rv = vcom_listen (__fd, __n);
2505       if (VCOM_DEBUG > 0)
2506         fprintf (stderr,
2507                  "[%d] listen: "
2508                  "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
2509       if (rv != 0)
2510         {
2511           errno = -rv;
2512           return -1;
2513         }
2514       return 0;
2515     }
2516   return libc_listen (__fd, __n);
2517 }
2518
2519 /*
2520  * Await a connection on socket FD.
2521  * When a connection arrives, open a new socket to communicate
2522  * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
2523  * of the connecting peer and *ADDR_LEN to the address's actual
2524  * length, and return the new socket's descriptor, or -1 for errors.
2525  * This function is a cancellation point and therefore not marked
2526  * with __THROW.
2527  * */
2528 int
2529 vcom_accept (int __fd, __SOCKADDR_ARG __addr,
2530              socklen_t * __restrict __addr_len)
2531 {
2532
2533   if (vcom_init () != 0)
2534     {
2535       return -1;
2536     }
2537   return vcom_socket_accept (__fd, __addr, __addr_len);
2538 }
2539
2540 int
2541 accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
2542 {
2543   int rv = -1;
2544   pid_t pid = getpid ();
2545   pthread_t tid = pthread_self ();
2546
2547   if (is_vcom_socket_fd (__fd))
2548     {
2549       if (VCOM_DEBUG > 0)
2550         vcom_socket_main_show ();
2551       if (VCOM_DEBUG > 0)
2552         fprintf (stderr,
2553                  "[%d][%lu (0x%lx)] accept1: "
2554                  "'%04d'='%04d', '%p', '%p'\n",
2555                  pid, (unsigned long) tid, (unsigned long) tid,
2556                  rv, __fd, __addr, __addr_len);
2557       rv = vcom_accept (__fd, __addr, __addr_len);
2558       if (VCOM_DEBUG > 0)
2559         fprintf (stderr,
2560                  "[%d][%lu (0x%lx)] accept2: "
2561                  "'%04d'='%04d', '%p', '%p'\n",
2562                  pid, (unsigned long) tid, (unsigned long) tid,
2563                  rv, __fd, __addr, __addr_len);
2564       if (VCOM_DEBUG > 0)
2565         vcom_socket_main_show ();
2566       if (rv < 0)
2567         {
2568           errno = -rv;
2569           return -1;
2570         }
2571       return rv;
2572     }
2573   return libc_accept (__fd, __addr, __addr_len);
2574 }
2575
2576 #ifdef __USE_GNU
2577 /*
2578  * Similar to 'accept' but takes an additional parameter to specify
2579  * flags.
2580  * This function is a cancellation point and therefore not marked
2581  * with __THROW.
2582  * */
2583 int
2584 vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
2585               socklen_t * __restrict __addr_len, int __flags)
2586 {
2587
2588   if (vcom_init () != 0)
2589     {
2590       return -1;
2591     }
2592
2593   return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
2594 }
2595
2596 int
2597 accept4 (int __fd, __SOCKADDR_ARG __addr,
2598          socklen_t * __restrict __addr_len, int __flags)
2599 {
2600   int rv;
2601   pid_t pid = getpid ();
2602
2603   if (is_vcom_socket_fd (__fd))
2604     {
2605       if (VCOM_DEBUG > 0)
2606         vcom_socket_main_show ();
2607       rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
2608       if (VCOM_DEBUG > 0)
2609         fprintf (stderr,
2610                  "[%d] accept4: "
2611                  "'%04d'='%04d', '%p', '%p', '%04x'\n",
2612                  pid, rv, __fd, __addr, __addr_len, __flags);
2613       if (VCOM_DEBUG > 0)
2614         vcom_socket_main_show ();
2615       if (rv < 0)
2616         {
2617           errno = -rv;
2618           return -1;
2619         }
2620       return rv;
2621     }
2622   return libc_accept4 (__fd, __addr, __addr_len, __flags);
2623 }
2624
2625 #endif
2626
2627 /*
2628  * Shut down all or part of the connection open on socket FD.
2629  * HOW determines what to shut down:
2630  *   SHUT_RD   = No more receptions;
2631  *   SHUT_WR   = No more transmissions;
2632  *   SHUT_RDWR = No more receptions or transmissions.
2633  * Returns 0 on success, -1 for errors.
2634  * */
2635 int
2636 vcom_shutdown (int __fd, int __how)
2637 {
2638   if (vcom_init () != 0)
2639     {
2640       return -1;
2641     }
2642   return vcom_socket_shutdown (__fd, __how);
2643 }
2644
2645 int
2646 shutdown (int __fd, int __how)
2647 {
2648   int rv;
2649   pid_t pid = getpid ();
2650
2651   if (is_vcom_socket_fd (__fd))
2652     {
2653       rv = vcom_shutdown (__fd, __how);
2654       if (VCOM_DEBUG > 0)
2655         fprintf (stderr,
2656                  "[%d] shutdown: "
2657                  "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
2658       if (rv != 0)
2659         {
2660           errno = -rv;
2661           return -1;
2662         }
2663       return 0;
2664     }
2665   return libc_shutdown (__fd, __how);
2666 }
2667
2668 int
2669 vcom_epoll_create (int __size)
2670 {
2671
2672   if (vcom_init () != 0)
2673     {
2674       return -1;
2675     }
2676
2677   if (__size <= 0)
2678     {
2679       return -EINVAL;
2680     }
2681
2682   /* __size argument is ignored "thereafter" */
2683   return vcom_epoll_create1 (0);
2684 }
2685
2686 /*
2687  * __size argument is ignored, but must be greater than zero
2688  */
2689 int
2690 epoll_create (int __size)
2691 {
2692   int rv = 0;
2693   pid_t pid = getpid ();
2694
2695   rv = vcom_epoll_create (__size);
2696   if (VCOM_DEBUG > 0)
2697     fprintf (stderr,
2698              "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
2699   if (rv < 0)
2700     {
2701       errno = -rv;
2702       return -1;
2703     }
2704   return rv;
2705 }
2706
2707 int
2708 vcom_epoll_create1 (int __flags)
2709 {
2710   if (vcom_init () != 0)
2711     {
2712       return -1;
2713     }
2714
2715   if (__flags < 0)
2716     {
2717       return -EINVAL;
2718     }
2719   if (__flags & ~EPOLL_CLOEXEC)
2720     {
2721       return -EINVAL;
2722     }
2723   /* __flags can be either zero or EPOLL_CLOEXEC */
2724   /* implementation */
2725   return vcom_socket_epoll_create1 (__flags);
2726 }
2727
2728 /*
2729  * __flags can be either zero or EPOLL_CLOEXEC
2730  * */
2731 int
2732 epoll_create1 (int __flags)
2733 {
2734   int rv = 0;
2735   pid_t pid = getpid ();
2736
2737   rv = vcom_epoll_create1 (__flags);
2738   if (VCOM_DEBUG > 0)
2739     fprintf (stderr,
2740              "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
2741   if (rv < 0)
2742     {
2743       errno = -rv;
2744       return -1;
2745     }
2746   return rv;
2747 }
2748
2749 static inline int
2750 ep_op_has_event (int op)
2751 {
2752   return op != EPOLL_CTL_DEL;
2753 }
2754
2755 int
2756 vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2757 {
2758   if (vcom_init () != 0)
2759     {
2760       return -1;
2761     }
2762
2763   /*
2764    * the requested operation __op is not supported
2765    * by this interface */
2766   if (!((__op == EPOLL_CTL_ADD) ||
2767         (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
2768     {
2769       return -EINVAL;
2770     }
2771
2772   /* op is ADD or MOD but event parameter is NULL */
2773   if ((ep_op_has_event (__op) && !__event))
2774     {
2775       return -EFAULT;
2776     }
2777
2778   /* fd is same as epfd */
2779   /* do not permit adding an epoll file descriptor inside itself */
2780   if (__epfd == __fd)
2781     {
2782       return -EINVAL;
2783     }
2784
2785   /* implementation */
2786   return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
2787 }
2788
2789 /*
2790  * implement the controller interface for epoll
2791  * that enables the insertion/removal/change of
2792  * file descriptors inside the interest set.
2793  */
2794 int
2795 epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
2796 {
2797   int rv;
2798   pid_t pid = getpid ();
2799
2800   if (is_vcom_epfd (__epfd))
2801     {
2802       /* TBD: currently limiting epoll to support only vcom fds */
2803       if (is_vcom_socket_fd (__fd))
2804         {
2805           rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
2806           if (VCOM_DEBUG > 0)
2807             fprintf (stderr,
2808                      "[%d] epoll_ctl: "
2809                      "'%04d'='%04d', '%04d', '%04d'\n",
2810                      pid, rv, __epfd, __op, __fd);
2811           if (rv != 0)
2812             {
2813               errno = -rv;
2814               return -1;
2815             }
2816           return 0;
2817         }
2818       else
2819         {
2820           /*
2821            * TBD: currently epoll does not support kernel fds
2822            * or epoll fds */
2823           errno = EBADF;
2824           return -1;
2825         }
2826     }
2827   else
2828     {
2829       /* epfd is not an epoll file descriptor */
2830       errno = EINVAL;
2831       return -1;
2832     }
2833   return 0;
2834 }
2835
2836 int
2837 vcom_epoll_wait (int __epfd, struct epoll_event *__events,
2838                  int __maxevents, int __timeout)
2839 {
2840   if (vcom_init () != 0)
2841     {
2842       return -1;
2843     }
2844
2845   return vcom_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
2846 }
2847
2848 int
2849 epoll_wait (int __epfd, struct epoll_event *__events,
2850             int __maxevents, int __timeout)
2851 {
2852   int rv;
2853   pid_t pid = getpid ();
2854
2855   if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2856     {
2857       errno = EINVAL;
2858       return -1;
2859     }
2860
2861   if (is_vcom_epfd (__epfd))
2862     {
2863       rv = vcom_epoll_wait (__epfd, __events, __maxevents, __timeout);
2864       if (VCOM_DEBUG > 0)
2865         fprintf (stderr,
2866                  "[%d] epoll_wait: "
2867                  "'%04d'='%04d', '%p', "
2868                  "'%04d', '%04d'\n",
2869                  pid, rv, __epfd, __events, __maxevents, __timeout);
2870       if (rv < 0)
2871         {
2872           errno = -rv;
2873           return -1;
2874         }
2875       return rv;
2876     }
2877   else
2878     {
2879       errno = EINVAL;
2880       return -1;
2881     }
2882   return 0;
2883 }
2884
2885
2886 int
2887 vcom_epoll_pwait (int __epfd, struct epoll_event *__events,
2888                   int __maxevents, int __timeout, const __sigset_t * __ss)
2889 {
2890   if (vcom_init () != 0)
2891     {
2892       return -1;
2893     }
2894
2895   /* implementation */
2896   return vcom_socket_epoll_pwait (__epfd, __events,
2897                                   __maxevents, __timeout, __ss);
2898 }
2899
2900 int
2901 epoll_pwait (int __epfd, struct epoll_event *__events,
2902              int __maxevents, int __timeout, const __sigset_t * __ss)
2903 {
2904   int rv;
2905   pid_t pid = getpid ();
2906
2907   if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
2908     {
2909       errno = EINVAL;
2910       return -1;
2911     }
2912
2913   if (is_vcom_epfd (__epfd))
2914     {
2915       rv = vcom_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
2916       if (VCOM_DEBUG > 0)
2917         fprintf (stderr,
2918                  "[%d] epoll_pwait: "
2919                  "'%04d'='%04d', '%p', "
2920                  "'%04d', '%04d', "
2921                  "'%p'\n",
2922                  pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
2923       if (rv < 0)
2924         {
2925           errno = -rv;
2926           return -1;
2927         }
2928       return rv;
2929     }
2930   else
2931     {
2932       errno = EINVAL;
2933       return -1;
2934     }
2935
2936   return 0;
2937 }
2938
2939 /* Poll the file descriptors described by the NFDS structures starting at
2940    FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
2941    an event to occur; if TIMEOUT is -1, block until an event occurs.
2942    Returns the number of file descriptors with events, zero if timed out,
2943    or -1 for errors.
2944
2945    This function is a cancellation point and therefore not marked with
2946    __THROW.  */
2947
2948 int
2949 vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2950 {
2951   int rv = 0;
2952   pid_t pid = getpid ();
2953
2954   struct rlimit nofile_limit;
2955   struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
2956   nfds_t fds_idx = 0;
2957
2958   /* actual set of file descriptors to be monitored */
2959   nfds_t libc_nfds = 0;
2960   nfds_t vcom_nfds = 0;
2961
2962   /* ready file descriptors
2963    *
2964    * number of structures which have nonzero revents  fields
2965    * in other words, descriptors  with events or errors reported.
2966    * */
2967   /* after call to libc_poll () */
2968   int rlibc_nfds = 0;
2969   /* after call to vcom_socket_poll () */
2970   int rvcom_nfds = 0;
2971
2972
2973   /* timeout value in units of timespec */
2974   struct timespec timeout_ts;
2975   struct timespec start_time, now, end_time;
2976
2977
2978   /* get start_time */
2979   rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
2980   if (rv == -1)
2981     {
2982       rv = -errno;
2983       goto poll_done;
2984     }
2985
2986   /* set timeout_ts & end_time */
2987   if (__timeout >= 0)
2988     {
2989       /* set timeout_ts */
2990       timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
2991       timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
2992       set_normalized_timespec (&timeout_ts,
2993                                timeout_ts.tv_sec, timeout_ts.tv_nsec);
2994       /* set end_time */
2995       if (__timeout)
2996         {
2997           end_time = timespec_add (start_time, timeout_ts);
2998         }
2999       else
3000         {
3001           end_time = start_time;
3002         }
3003     }
3004
3005   if (vcom_init () != 0)
3006     {
3007       rv = -1;
3008       goto poll_done;
3009     }
3010
3011   /* validate __fds */
3012   if (!__fds)
3013     {
3014       rv = -EFAULT;
3015       goto poll_done;
3016     }
3017
3018   /* validate __nfds */
3019   /*TBD: call getrlimit once when vcl-ldpreload library is init */
3020   rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
3021   if (rv != 0)
3022     {
3023       rv = -errno;
3024       goto poll_done;
3025     }
3026   if (__nfds >= nofile_limit.rlim_cur)
3027     {
3028       rv = -EINVAL;
3029       goto poll_done;
3030     }
3031
3032   /*
3033    * for the POC, it's fair to assume that nfds is less than 1024
3034    * */
3035   if (__nfds >= MAX_POLL_NFDS_DEFAULT)
3036     {
3037       rv = -EINVAL;
3038       goto poll_done;
3039     }
3040
3041   /* set revents field (output parameter)
3042    * to zero
3043    * */
3044   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3045     {
3046       __fds[fds_idx].revents = 0;
3047     }
3048
3049 #if 0
3050   /* set revents field (output parameter)
3051    * to zero for user ignored fds
3052    * */
3053   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3054     {
3055       /*
3056        * if negative fd, ignore events field
3057        * and set output parameter (revents field) to zero */
3058       if (__fds[fds_idx].fd < 0)
3059         {
3060           __fds[fds_idx].revents = 0;
3061         }
3062     }
3063 #endif
3064
3065   /*
3066    * 00. prepare __fds and vcom_fds for polling
3067    *     copy __fds to vcom_fds
3068    * 01. negate all except libc fds in __fds,
3069    *     ignore user negated fds
3070    * 02. negate all except vcom_fds in vocm fds,
3071    *     ignore user negated fds
3072    *     ignore fd 0 by setting it to negative number
3073    * */
3074   memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
3075   libc_nfds = 0;
3076   vcom_nfds = 0;
3077   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3078     {
3079       /* ignore negative fds */
3080       if (__fds[fds_idx].fd < 0)
3081         {
3082           continue;
3083         }
3084
3085       /*
3086        * 00. ignore vcom fds in __fds
3087        * 01. ignore libc fds in vcom_fds,
3088        *     ignore fd 0 by setting it to negative number.
3089        *     as fd 0 cannot be ignored.
3090        */
3091       if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
3092           is_vcom_epfd (__fds[fds_idx].fd))
3093         {
3094           __fds[fds_idx].fd = -__fds[fds_idx].fd;
3095           vcom_nfds++;
3096         }
3097       else
3098         {
3099           libc_nfds++;
3100           /* ignore fd 0 by setting it to negative number */
3101           if (!vcom_fds[fds_idx].fd)
3102             {
3103               vcom_fds[fds_idx].fd = -1;
3104             }
3105           vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
3106         }
3107     }
3108
3109   /*
3110    * polling loop
3111    *
3112    * poll on libc fds and vcom fds
3113    *
3114    * specifying a timeout of zero causes libc_poll() and
3115    * vcom_socket_poll() to return immediately, even if no
3116    * file descriptors are ready
3117    * */
3118   do
3119     {
3120       rlibc_nfds = 0;
3121       rvcom_nfds = 0;
3122
3123       /*
3124        * timeout parameter for libc_poll () set to zero
3125        * to poll on libc fds
3126        * */
3127
3128       /* poll on libc fds */
3129       if (libc_nfds)
3130         {
3131           /*
3132            * a timeout of zero causes libc_poll()
3133            * to return immediately
3134            * */
3135           rlibc_nfds = libc_poll (__fds, __nfds, 0);
3136           if (VCOM_DEBUG > 2)
3137             fprintf (stderr,
3138                      "[%d] poll libc: "
3139                      "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
3140
3141           if (rlibc_nfds < 0)
3142             {
3143               rv = -errno;
3144               goto poll_done_update_nfds;
3145             }
3146         }
3147
3148       /*
3149        * timeout parameter for vcom_socket_poll () set to zero
3150        * to poll on vcom fds
3151        * */
3152
3153       /* poll on vcom fds */
3154       if (vcom_nfds)
3155         {
3156           /*
3157            * a timeout of zero causes vcom_socket_poll()
3158            * to return immediately
3159            * */
3160           rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
3161           if (VCOM_DEBUG > 2)
3162             fprintf (stderr,
3163                      "[%d] poll vcom: "
3164                      "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
3165           if (rvcom_nfds < 0)
3166             {
3167               rv = rvcom_nfds;
3168               goto poll_done_update_nfds;
3169             }
3170         }
3171
3172       /* check if any file descriptors changed status */
3173       if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
3174         {
3175           /* something interesting happened */
3176           rv = rlibc_nfds + rvcom_nfds;
3177           goto poll_done_update_nfds;
3178         }
3179
3180       rv = clock_gettime (CLOCK_MONOTONIC, &now);
3181       if (rv == -1)
3182         {
3183           rv = -errno;
3184           goto poll_done_update_nfds;
3185         }
3186     }
3187
3188   /* block indefinitely || timeout elapsed  */
3189   while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
3190
3191   /* timeout expired before anything interesting happened */
3192   rv = 0;
3193
3194 poll_done_update_nfds:
3195   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3196     {
3197       /* ignore negative fds in vcom_fds
3198        * 00. user negated fds
3199        * 01. libc fds
3200        * */
3201       if (vcom_fds[fds_idx].fd < 0)
3202         {
3203           continue;
3204         }
3205
3206       /* from here on handle positive vcom fds */
3207       /*
3208        * restore vcom fds to positive number in __fds
3209        * and update revents in __fds with the events
3210        * that actually occurred in vcom fds
3211        * */
3212       __fds[fds_idx].fd = -__fds[fds_idx].fd;
3213       if (rvcom_nfds)
3214         {
3215           __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
3216         }
3217     }
3218
3219 poll_done:
3220   if (VCOM_DEBUG > 2)
3221     fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
3222   return rv;
3223 }
3224
3225 /*
3226  * 00. The  field  __fds[i].fd contains a file descriptor for an
3227  *     open file.
3228  *     If this field is negative, then the corresponding
3229  *     events field is ignored and the revents field returns zero.
3230  *     The field __fds[i].events is an input parameter.
3231  *     The field __fds[i].revents is an output parameter.
3232  * 01. Specifying a negative value in  timeout
3233  *     means  an infinite timeout.
3234  *     Specifying a timeout of zero causes poll() to return
3235  *     immediately, even if no file descriptors are ready.
3236  *
3237  * NOTE: observed __nfds is less than 128 from kubecon strace files
3238  */
3239
3240
3241 int
3242 poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3243 {
3244   int rv = 0;
3245   pid_t pid = getpid ();
3246
3247
3248   if (VCOM_DEBUG > 2)
3249     fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
3250              pid, rv, __nfds, __fds[0].fd, __fds[0].events);
3251   rv = vcom_poll (__fds, __nfds, __timeout);
3252   if (VCOM_DEBUG > 2)
3253     fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
3254              pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
3255   if (rv < 0)
3256     {
3257       errno = -rv;
3258       return -1;
3259     }
3260   return rv;
3261 }
3262
3263 #ifdef __USE_GNU
3264 /* Like poll, but before waiting the threads signal mask is replaced
3265    with that specified in the fourth parameter.  For better usability,
3266    the timeout value is specified using a TIMESPEC object.
3267
3268    This function is a cancellation point and therefore not marked with
3269    __THROW.  */
3270 int
3271 vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
3272             const struct timespec *__timeout, const __sigset_t * __ss)
3273 {
3274   if (vcom_init () != 0)
3275     {
3276       return -1;
3277     }
3278
3279   return -EOPNOTSUPP;
3280 }
3281
3282 int
3283 ppoll (struct pollfd *__fds, nfds_t __nfds,
3284        const struct timespec *__timeout, const __sigset_t * __ss)
3285 {
3286   int rv = 0;
3287
3288   errno = EOPNOTSUPP;
3289   rv = -1;
3290   return rv;
3291 }
3292 #endif
3293
3294 void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
3295
3296 void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
3297
3298 void
3299 vcom_constructor (void)
3300 {
3301   pid_t pid = getpid ();
3302
3303   swrap_constructor ();
3304   if (vcom_init () != 0)
3305     {
3306       printf ("\n[%d] vcom_constructor...failed!\n", pid);
3307     }
3308   else
3309     {
3310       printf ("\n[%d] vcom_constructor...done!\n", pid);
3311     }
3312 }
3313
3314 /*
3315  * This function is called when the library is unloaded
3316  */
3317 void
3318 vcom_destructor (void)
3319 {
3320   pid_t pid = getpid ();
3321
3322   vcom_destroy ();
3323   swrap_destructor ();
3324   printf ("\n[%d] vcom_destructor...done!\n", pid);
3325 }
3326
3327
3328 /*
3329  * fd.io coding-style-patch-verification: ON
3330  *
3331  * Local Variables:
3332  * eval: (c-set-style "gnu")
3333  * End:
3334  */