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