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