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