Initial push of vcl-ldpreload to extras
[vpp.git] / extras / vcl-ldpreload / src / libvcl-ldpreload / vcom.c
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
new file mode 100644 (file)
index 0000000..6245c5d
--- /dev/null
@@ -0,0 +1,2980 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdarg.h>
+
+#include <libvcl-ldpreload/vcom_socket_wrapper.h>
+#include <libvcl-ldpreload/vcom.h>
+#include <sys/time.h>
+
+#include <uri/vppcom.h>
+#include <libvcl-ldpreload/vcom_socket.h>
+
+/* GCC have printf type attribute check. */
+#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
+#define PRINTF_ATTRIBUTE(a,b)                       \
+    __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
+
+#define HAVE_CONSTRUCTOR_ATTRIBUTE
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE                       \
+    __attribute__ ((constructor))
+#else
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
+#define HAVE_DESTRUCTOR_ATTRIBUTE
+#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
+#define DESTRUCTOR_ATTRIBUTE                        \
+    __attribute__ ((destructor))
+#else
+#define DESTRUCTOR_ATTRIBUTE
+#endif
+
+#define HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE           \
+    __attribute__((no_sanitize_address))
+#else
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+#endif
+
+#define VCOM_SOCKET_FD_MAX  0x10000
+
+static char vcom_app_name[MAX_VCOM_APP_NAME];
+
+/*
+ * RETURN:  0 on success or -1 on error.
+ * */
+int
+vcom_set_app_name (char *__app_name)
+{
+  return snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-%s-%d",
+                  __app_name, getpid ()) < 0 ? -1 : 0;
+}
+
+static char *
+vcom_get_app_name ()
+{
+  if (vcom_app_name[0] == '\0')
+    {
+      snprintf (vcom_app_name, MAX_VCOM_APP_NAME, "vcom-app-%d", getpid ());
+    }
+  return vcom_app_name;
+}
+
+/*
+ * 1 if init, 0 otherwise
+ */
+static int is_vcom_init;
+
+/*
+ * TBD: Make it thread safe
+ */
+
+/*
+ * constructor function called before main is called
+ * RETURN: 0 on success -1 on failure
+ * */
+static inline int
+vcom_init ()
+{
+  pid_t pid = getpid ();
+
+  if (!is_vcom_init)
+    {
+      if (vppcom_app_create (vcom_get_app_name ()) != 0)
+       {
+         printf ("\n[%d] vcom_init...failed!\n", pid);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] vcom_init: vppcom_app_create failed!\n", pid);
+         return -1;
+       }
+      if (vcom_socket_main_init () != 0)
+       {
+         printf ("\n[%d] vcom_init...failed!\n", pid);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] vcom_init: vcom_socket_main_init failed!\n", pid);
+         return -1;
+       }
+
+      is_vcom_init = 1;
+      printf ("\n[%d] vcom_init...done!\n", pid);
+    }
+  return 0;
+}
+
+static inline void
+vcom_destroy (void)
+{
+  pid_t pid = getpid ();
+
+  if (is_vcom_init)
+    {
+      vcom_socket_main_destroy ();
+      vppcom_app_destroy ();
+      is_vcom_init = 0;
+      fprintf (stderr, "\n[%d] vcom_destroy...done!\n", pid);
+    }
+}
+
+static inline int
+is_vcom_socket_fd (int fd)
+{
+  return vcom_socket_is_vcom_fd (fd);
+}
+
+static inline int
+is_vcom_epfd (int epfd)
+{
+  return vcom_socket_is_vcom_epfd (epfd);
+}
+
+
+/*
+ *
+ * Generic glibc fd api
+ *
+ */
+
+/* Close the file descriptor FD.
+
+   This function is a cancellation point and therefore
+   not marked with __THROW.  */
+/*
+ * PRE:     is_vcom_socket_fd(__fd) == 1
+ * RETURN:  0 on success and -1 for errors.
+ * */
+int
+vcom_close (int __fd)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  if (vcom_socket_close (__fd) != 0)
+    {
+      return -1;
+    }
+
+  return 0;
+}
+
+/*
+ * RETURN:  0 on success, or -1 on error
+ */
+int
+close (int __fd)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd) || is_vcom_epfd (__fd))
+    {
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      rv = vcom_close (__fd);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr, "[%d] close: " "'%04d'='%04d'\n", pid, rv, __fd);
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_close (__fd);
+}
+
+/* Read NBYTES into BUF from FD.  Return the
+   number read, -1 for errors or 0 for EOF.
+
+   This function is a cancellation point and therefore
+   not marked with __THROW.  */
+ssize_t
+vcom_read (int __fd, void *__buf, size_t __nbytes)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_read (__fd, __buf, __nbytes);
+}
+
+ssize_t
+read (int __fd, void *__buf, size_t __nbytes)
+{
+  ssize_t size = 0;
+  pid_t pid = getpid ();
+  pthread_t tid = pthread_self ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] read:1 "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                (int) size, __fd, __buf, (int) __nbytes);
+      size = vcom_read (__fd, __buf, __nbytes);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] read:2 "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                (int) size, __fd, __buf, (int) __nbytes);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_read (__fd, __buf, __nbytes);
+}
+
+ssize_t
+vcom_readv (int __fd, const struct iovec * __iov, int __iovcnt)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_readv (__fd, __iov, __iovcnt);
+}
+
+ssize_t
+readv (int __fd, const struct iovec * __iov, int __iovcnt)
+{
+  ssize_t size = 0;
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_readv (__fd, __iov, __iovcnt);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  else
+    return libc_readv (__fd, __iov, __iovcnt);
+}
+
+/* Write N bytes of BUF to FD.  Return the number written, or -1.
+
+   This function is a cancellation point and therefore
+   not marked with __THROW.  */
+ssize_t
+vcom_write (int __fd, const void *__buf, size_t __n)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_write (__fd, (void *) __buf, __n);
+}
+
+ssize_t
+write (int __fd, const void *__buf, size_t __n)
+{
+  ssize_t size = 0;
+  pid_t pid = getpid ();
+  pthread_t tid = pthread_self ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] write:1 "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                (int) size, __fd, __buf, (int) __n);
+      size = vcom_write (__fd, __buf, __n);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] write:2 "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                (int) size, __fd, __buf, (int) __n);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_write (__fd, __buf, __n);
+}
+
+ssize_t
+vcom_writev (int __fd, const struct iovec * __iov, int __iovcnt)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_writev (__fd, __iov, __iovcnt);
+}
+
+ssize_t
+writev (int __fd, const struct iovec * __iov, int __iovcnt)
+{
+  ssize_t size = 0;
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_writev (__fd, __iov, __iovcnt);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  else
+    return libc_writev (__fd, __iov, __iovcnt);
+}
+
+/* Do the file control operation described by CMD on FD.
+   The remaining arguments are interpreted depending on CMD.
+
+   This function is a cancellation point and therefore
+   not marked with __THROW.  */
+int
+vcom_fcntl_va (int __fd, int __cmd, va_list __ap)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_fcntl_va (__fd, __cmd, __ap);
+}
+
+int
+vcom_fcntl (int __fd, int __cmd, ...)
+{
+  int rv = -1;
+  va_list ap;
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      va_start (ap, __cmd);
+      rv = vcom_fcntl_va (__fd, __cmd, ap);
+      va_end (ap);
+    }
+  return rv;
+}
+
+int
+fcntl (int __fd, int __cmd, ...)
+{
+  int rv;
+  va_list ap;
+  pid_t pid = getpid ();
+
+  va_start (ap, __cmd);
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_fcntl_va (__fd, __cmd, ap);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] fcntl: "
+                "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __cmd);
+      if (rv < 0)
+       {
+         errno = -rv;
+         rv = -1;
+       }
+      goto out;
+    }
+  rv = libc_vfcntl (__fd, __cmd, ap);
+
+out:
+  va_end (ap);
+  return rv;
+}
+
+/*
+ * Check the first NFDS descriptors each in READFDS (if not NULL) for
+ *  read readiness, in WRITEFDS (if not NULL) for write readiness,
+ *  and in EXCEPTFDS (if not NULL) for exceptional conditions.
+ *  If TIMEOUT is not NULL, time out after waiting the interval
+ *  specified therein.  Returns the number of ready descriptors,
+ *  or -1 for errors.
+ *
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+
+/*
+ * clear all vcom FDs from fd_sets __readfds, __writefds and
+ * __exceptfds and update the new nfds
+ *
+ * new nfds is the highest-numbered file descriptor
+ * in any of the three sets, plus 1
+ *
+ * Return the number of file descriptors contained in the
+ * three descriptor sets. ie. the total number of the bits
+ * that are set in  __readfds, __writefds and __exceptfds
+ */
+static inline int
+vcom_fd_clear (int __nfds,
+              int *__new_nfds,
+              fd_set * __restrict __readfds,
+              fd_set * __restrict __writefds,
+              fd_set * __restrict __exceptfds)
+{
+  int fd;
+  /* invalid max_fd is -1 */
+  int max_fd = -1;
+  int nfd = 0;
+
+
+  /* clear all vcom fd from the sets */
+  for (fd = 0; fd < __nfds; fd++)
+    {
+
+      /* clear vcom fd from set */
+      /*
+       * F fd set
+       */
+#define _(F)                                    \
+      if ((F) && FD_ISSET (fd, (F)))            \
+        {                                       \
+          if (is_vcom_socket_fd (fd))           \
+            {                                   \
+              FD_CLR (fd, (F));                 \
+            }                                   \
+        }
+
+
+      _(__readfds);
+      _(__writefds);
+      _(__exceptfds);
+#undef _
+    }
+
+  /*
+   *  compute nfd and __new_nfds
+   */
+  for (fd = 0; fd < __nfds; fd++)
+    {
+
+      /*
+       * F fd set
+       */
+#define _(F)                                    \
+      if ((F) && FD_ISSET (fd, (F)))            \
+        {                                       \
+          if (fd > max_fd)                      \
+            {                                   \
+              max_fd = fd;                      \
+            }                                   \
+          ++nfd;                                \
+        }
+
+
+      _(__readfds);
+      _(__writefds);
+      _(__exceptfds);
+#undef _
+    }
+
+  *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
+  return nfd;
+}
+
+/*
+ * Return the number of file descriptors contained in the
+ * three descriptor sets. ie. the total number of the bits
+ * that are set in  __readfds, __writefds and __exceptfds
+ */
+static inline int
+vcom_fd_set (int __nfds,
+            /* dest */
+            int *__new_nfds,
+            fd_set * __restrict __readfds,
+            fd_set * __restrict __writefds, fd_set * __restrict __exceptfds,
+            /* src */
+            fd_set * __restrict __saved_readfds,
+            fd_set * __restrict __saved_writefds,
+            fd_set * __restrict __saved_exceptfds)
+{
+  int fd;
+  /* invalid max_fd is -1 */
+  int max_fd = -1;
+  int nfd = 0;
+
+  for (fd = 0; fd < __nfds; fd++)
+    {
+      /*
+       * F fd set
+       * S saved fd set
+       */
+#define _(S,F)                                  \
+      if ((F) && (S) && FD_ISSET (fd, (S)))     \
+        {                                       \
+          if (is_vcom_socket_fd (fd))           \
+            {                                   \
+              FD_SET (fd, (F));                 \
+            }                                   \
+        }
+
+
+      _(__saved_readfds, __readfds);
+      _(__saved_writefds, __writefds);
+#undef _
+    }
+
+
+  /*
+   *  compute nfd and __new_nfds
+   */
+  for (fd = 0; fd < __nfds; fd++)
+    {
+
+      /*
+       * F fd set
+       */
+#define _(F)                                    \
+      if ((F) && FD_ISSET (fd, (F)))            \
+        {                                       \
+          if (fd > max_fd)                      \
+            {                                   \
+              max_fd = fd;                      \
+            }                                   \
+          ++nfd;                                \
+        }
+
+
+      _(__readfds);
+      _(__writefds);
+      _(__exceptfds);
+#undef _
+    }
+
+  *__new_nfds = max_fd != -1 ? max_fd + 1 : 0;
+  return nfd;
+}
+
+/*
+ * split select sets(src) into
+ * vcom sets(dest1) and libc sets(dest2)
+ */
+static inline void
+vcom_fd_set_split (
+                   /* src, select sets */
+                   int nfds,
+                   fd_set * __restrict readfds,
+                   fd_set * __restrict writefds,
+                   fd_set * __restrict exceptfds,
+                   /* dest1, vcom sets */
+                   int *vcom_nfds,
+                   fd_set * __restrict vcom_readfds,
+                   fd_set * __restrict vcom_writefds,
+                   fd_set * __restrict vcom_exceptfds, int *vcom_nfd,
+                   /* dest2, libc sets */
+                   int *libc_nfds,
+                   fd_set * __restrict libc_readfds,
+                   fd_set * __restrict libc_writefds,
+                   fd_set * __restrict libc_exceptfds, int *libc_nfd)
+{
+  int fd;
+
+  /* vcom */
+  /* invalid max_fd is -1 */
+  int vcom_max_fd = -1;
+  int vcom_nfd2 = 0;
+
+  /* libc */
+  /* invalid max_fd is -1 */
+  int libc_max_fd = -1;
+  int libc_nfd2 = 0;
+
+
+  for (fd = 0; fd < nfds; fd++)
+    {
+      /*
+       * S select fd set
+       * V vcom fd set
+       * L libc fd set
+       */
+#define _(S,V,L)                            \
+      if ((S) && FD_ISSET (fd, (S)))        \
+        {                                   \
+          if (is_vcom_socket_fd (fd))       \
+            {                               \
+              if ((V))                      \
+                {                           \
+                  FD_SET(fd, (V));          \
+                  if (fd > vcom_max_fd)     \
+                    {                       \
+                      vcom_max_fd = fd;     \
+                    }                       \
+                  ++vcom_nfd2;              \
+                }                           \
+            }                               \
+          else                              \
+            {                               \
+              if ((L))                      \
+                {                           \
+                  FD_SET(fd, (L));          \
+                  if (fd > libc_max_fd)     \
+                    {                       \
+                      libc_max_fd = fd;     \
+                    }                       \
+                  ++libc_nfd2;              \
+                }                           \
+            }                               \
+        }
+
+
+      _(readfds, vcom_readfds, libc_readfds);
+      _(writefds, vcom_writefds, libc_writefds);
+      _(exceptfds, vcom_exceptfds, libc_exceptfds);
+#undef _
+    }
+
+  if (vcom_nfds)
+    *vcom_nfds = vcom_max_fd != -1 ? vcom_max_fd + 1 : 0;
+  if (vcom_nfd)
+    *vcom_nfd = vcom_nfd2;
+  if (libc_nfds)
+    *libc_nfds = libc_max_fd != -1 ? libc_max_fd + 1 : 0;
+  if (libc_nfd)
+    *libc_nfd = libc_nfd2;
+}
+
+/*
+ * merge vcom sets(src1) and libc sets(src2)
+ * into select sets(dest)
+ */
+static inline void
+vcom_fd_set_merge (
+                   /* dest, select sets */
+                   int *nfds,
+                   fd_set * __restrict readfds,
+                   fd_set * __restrict writefds,
+                   fd_set * __restrict exceptfds, int *nfd,
+                   /* src1, vcom sets */
+                   int vcom_nfds,
+                   fd_set * __restrict vcom_readfds,
+                   fd_set * __restrict vcom_writefds,
+                   fd_set * __restrict vcom_exceptfds, int vcom_nfd,
+                   /* src2, libc sets */
+                   int libc_nfds,
+                   fd_set * __restrict libc_readfds,
+                   fd_set * __restrict libc_writefds,
+                   fd_set * __restrict libc_exceptfds, int libc_nfd)
+{
+  int fd;
+  /* invalid max_fd is -1 */
+  int max_fd = -1;
+  int nfd2 = 0;
+
+
+  /* FD_BIT_OR
+   *
+   * dest |= src at current bit index
+   * update MAX and NFD of dest fd set
+   *
+   *
+   * FS source fd set
+   * FD dest fd set
+   * BI bit index
+   * MAX current max_fd of dest fd sets
+   * NFD current nfd of dest fd sets
+   * N  nfds of source fd set
+   */
+#define FD_BIT_OR(FD,FS,BI,          \
+                  MAX,NFD)           \
+  if ((FS) && (FD) && FD_ISSET ((BI), (FS)))    \
+    {                                           \
+      FD_SET ((BI), (FD));                      \
+      if ((BI) > (MAX))                         \
+        {                                       \
+          (MAX) = (BI);                         \
+        }                                       \
+      ++(NFD);                                  \
+    }
+
+
+  /* FD_RWE_SET_OR */
+  /*
+   * SR,SW,SE source RWE fd sets
+   * DR,DW,DE dest RWE fd sets
+   * BI bit index
+   * NFDS  nfds of source fd sets
+   * MAX current max_fd of dest fd sets
+   * NFD current nfd of dest fd sets
+   */
+#define FD_RWE_SETS_OR(DR,DW,DE,      \
+                      SR,SW,SE,       \
+                      BI,NFDS,        \
+                      MAX,NFD)        \
+  do                                                      \
+    {                                                     \
+      for ((BI) = 0; (BI) < (NFDS); (BI)++)               \
+        {                                                 \
+          FD_BIT_OR((DR), (SR), (BI), (MAX), (NFD));      \
+          FD_BIT_OR((DW), (SW), (BI), (MAX), (NFD));      \
+          FD_BIT_OR((DE), (SE), (BI), (MAX), (NFD));      \
+        }                                                 \
+      }                                                   \
+    while (0);
+
+
+  /* source(vcom) to dest(select) rwe fd sets */
+  FD_RWE_SETS_OR (readfds, writefds, exceptfds,
+                 vcom_readfds, vcom_writefds, vcom_exceptfds,
+                 fd, vcom_nfds, max_fd, nfd2);
+
+  /* source(libc) to dest(select) rwe fd sets */
+  FD_RWE_SETS_OR (readfds, writefds, exceptfds,
+                 libc_readfds, libc_writefds, libc_exceptfds,
+                 fd, libc_nfds, max_fd, nfd2);
+
+#undef FD_RWE_SETS_OR
+#undef FD_BIT_OR
+
+  if (nfds)
+    *nfds = max_fd != -1 ? max_fd + 1 : 0;
+  if (nfd)
+    *nfd = nfd2;
+}
+
+/*
+ * RETURN 1 if fds is NULL or empty. 0 otherwise
+ */
+static inline int
+fd_set_iszero (fd_set * __restrict fds)
+{
+  int fd;
+
+  /* NULL fds */
+  if (!fds)
+    return 1;
+
+  for (fd = 0; fd < FD_SETSIZE; fd++)
+    {
+      if (FD_ISSET (fd, fds))
+       {
+         /* non-empty fds */
+         return 0;
+       }
+    }
+  /* empty fds */
+  return 1;
+}
+
+
+/*
+ * ################
+ * kernel time64.h
+ * ################
+ * */
+typedef long int s64;
+typedef unsigned long int u64;
+
+typedef long long int __s64;
+typedef unsigned long long int __u64;
+
+typedef __s64 time64_t;
+typedef __u64 timeu64_t;
+
+/* Parameters used to convert the timespec values: */
+#define MSEC_PER_SEC    1000L
+#define USEC_PER_MSEC   1000L
+#define NSEC_PER_USEC   1000L
+#define NSEC_PER_MSEC   1000000L
+#define USEC_PER_SEC    1000000L
+#define NSEC_PER_SEC    1000000000L
+#define FSEC_PER_SEC    1000000000000000LL
+
+
+/*
+ * ################
+ * kernel time.h
+ * ################
+ * */
+
+
+#define TIME_T_MAX      (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+
+static inline int
+timespec_equal (const struct timespec *a, const struct timespec *b)
+{
+  return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
+}
+
+/*
+ * lhs < rhs:  return <0
+ * lhs == rhs: return 0
+ * lhs > rhs:  return >0
+ */
+static inline int
+timespec_compare (const struct timespec *lhs, const struct timespec *rhs)
+{
+  if (lhs->tv_sec < rhs->tv_sec)
+    return -1;
+  if (lhs->tv_sec > rhs->tv_sec)
+    return 1;
+  return lhs->tv_nsec - rhs->tv_nsec;
+}
+
+static inline int
+timeval_compare (const struct timeval *lhs, const struct timeval *rhs)
+{
+  if (lhs->tv_sec < rhs->tv_sec)
+    return -1;
+  if (lhs->tv_sec > rhs->tv_sec)
+    return 1;
+  return lhs->tv_usec - rhs->tv_usec;
+}
+
+extern void set_normalized_timespec (struct timespec *ts, time_t sec,
+                                    s64 nsec);
+
+
+static inline struct timespec
+timespec_add (struct timespec lhs, struct timespec rhs)
+{
+  struct timespec ts_delta;
+  set_normalized_timespec (&ts_delta, lhs.tv_sec + rhs.tv_sec,
+                          lhs.tv_nsec + rhs.tv_nsec);
+  return ts_delta;
+}
+
+/*
+ * sub = lhs - rhs, in normalized form
+ */
+static inline struct timespec
+timespec_sub (struct timespec lhs, struct timespec rhs)
+{
+  struct timespec ts_delta;
+  set_normalized_timespec (&ts_delta, lhs.tv_sec - rhs.tv_sec,
+                          lhs.tv_nsec - rhs.tv_nsec);
+  return ts_delta;
+}
+
+/*
+ * ################
+ * kernel time.c
+ * ################
+ * */
+
+
+/**
+ * set_normalized_timespec - set timespec sec and nsec parts and normalize
+ *
+ * @ts:         pointer to timespec variable to be set
+ * @sec:        seconds to set
+ * @nsec:       nanoseconds to set
+ *
+ * Set seconds and nanoseconds field of a timespec variable and
+ * normalize to the timespec storage format
+ *
+ * Note: The tv_nsec part is always in the range of
+ *      0 <= tv_nsec < NSEC_PER_SEC
+ * For negative values only the tv_sec field is negative !
+ */
+void
+set_normalized_timespec (struct timespec *ts, time_t sec, s64 nsec)
+{
+  while (nsec >= NSEC_PER_SEC)
+    {
+      /*
+       * The following asm() prevents the compiler from
+       * optimising this loop into a modulo operation. See
+       * also __iter_div_u64_rem() in include/linux/time.h
+       */
+    asm ("":"+rm" (nsec));
+      nsec -= NSEC_PER_SEC;
+      ++sec;
+    }
+  while (nsec < 0)
+    {
+    asm ("":"+rm" (nsec));
+      nsec += NSEC_PER_SEC;
+      --sec;
+    }
+  ts->tv_sec = sec;
+  ts->tv_nsec = nsec;
+}
+
+#define vcom_timerisvalid(tvp)        (!((tvp)->tv_sec < 0 || (tvp)->tv_usec < 0))
+
+/* Macros for converting between `struct timeval' and `struct timespec'.  */
+#define VCOM_TIMEVAL_TO_TIMESPEC(tv, ts) {                             \
+        (ts)->tv_sec = (tv)->tv_sec;                                    \
+        (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
+}
+#define VCOM_TIMESPEC_TO_TIMEVAL(tv, ts) {                             \
+        (tv)->tv_sec = (ts)->tv_sec;                                    \
+        (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
+}
+
+static inline int
+vcom_select_impl (int vcom_nfds, fd_set * __restrict vcom_readfds,
+                 fd_set * __restrict vcom_writefds,
+                 fd_set * __restrict vcom_exceptfds,
+                 struct timeval *__restrict timeout)
+{
+  return vcom_socket_select (vcom_nfds, vcom_readfds,
+                            vcom_writefds, vcom_exceptfds, timeout);
+}
+
+int
+vcom_select (int __nfds, fd_set * __restrict __readfds,
+            fd_set * __restrict __writefds,
+            fd_set * __restrict __exceptfds,
+            struct timeval *__restrict __timeout)
+{
+  int rv;
+  int rv2 = 0;
+  pid_t pid = getpid ();
+
+  int timedout = 0;
+  /* block indefinitely */
+  int no_timeout = 0;
+  int first_clock_gettime_failed = 0;
+  /* timeout value in units of timespec */
+  struct timespec timeout_ts;
+  struct timespec start_time, now, end_time;
+
+  /* select sets attributes - after merge */
+  int new_nfds = 0;
+  int new_nfd = -1;
+
+  /* vcom */
+  int vcom_nfds = 0;
+  fd_set vcom_readfds;
+  fd_set vcom_writefds;
+  fd_set vcom_exceptfds;
+  int vcom_nfd = -1;
+
+  /* libc */
+  int libc_nfds = 0;
+  fd_set libc_readfds;
+  fd_set libc_writefds;
+  fd_set libc_exceptfds;
+  int libc_nfd = -1;
+
+  /* for polling */
+  struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
+
+  /* validate __timeout */
+  if (__timeout)
+    {
+      /* validate tv_sec */
+      /* bogus */
+      if (!vcom_timerisvalid (__timeout))
+       {
+         rv = -EINVAL;
+         goto select_done;
+       }
+
+      /* validate tv_usec */
+      /* TBD: */
+      /* init timeout_ts */
+      VCOM_TIMEVAL_TO_TIMESPEC (__timeout, &timeout_ts);
+      set_normalized_timespec (&timeout_ts,
+                              timeout_ts.tv_sec, timeout_ts.tv_nsec);
+    }
+
+  rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
+  if (rv == -1)
+    {
+      rv = -errno;
+      first_clock_gettime_failed = 1;
+      goto select_done;
+    }
+
+  /* init end_time */
+  if (__timeout)
+    {
+      if (timerisset (__timeout))
+       {
+         end_time = timespec_add (start_time, timeout_ts);
+       }
+      else
+       {
+         /*
+          * if both fields of the timeout structure are zero,
+          * then select returns immediately
+          * */
+         end_time = start_time;
+       }
+    }
+  else
+    {
+      /* block indefinitely */
+      no_timeout = 1;
+    }
+
+
+
+  if (vcom_init () != 0)
+    {
+      rv = -1;
+      goto select_done;
+    }
+
+  /* validate __nfds */
+  if (__nfds < 0 || __nfds > FD_SETSIZE)
+    {
+      rv = -EINVAL;
+      goto select_done;
+    }
+
+
+  /*
+   * usleep(3) emulation
+   * */
+
+  /* call libc_select() with a finite timeout and
+   * no file descriptors or empty fd sets and
+   * zero nfds */
+  if (__nfds == 0 &&
+      (!__readfds || fd_set_iszero (__readfds)) &&
+      (!__writefds || fd_set_iszero (__writefds)) &&
+      (!__exceptfds || fd_set_iszero (__exceptfds)))
+    {
+      if (__timeout)
+       {
+         rv = libc_select (__nfds,
+                           __readfds, __writefds, __exceptfds, __timeout);
+         if (rv == -1)
+           rv = -errno;
+       }
+      else
+       {
+         /* TBD: block indefinitely or return -EINVAL */
+         rv = -EINVAL;
+       }
+      goto select_done;
+    }
+
+  /* init once before the polling loop */
+
+  /* zero vcom and libc fd sets */
+  /*
+   * S select fd set
+   * V vcom fd set
+   * L libc fd set
+   */
+#define _(S,V,L)      \
+  if ((S))            \
+    {                 \
+      FD_ZERO ((V));  \
+      FD_ZERO ((L));  \
+    }
+
+
+  _(__readfds, &vcom_readfds, &libc_readfds);
+  _(__writefds, &vcom_writefds, &libc_writefds);
+  _(__exceptfds, &vcom_exceptfds, &libc_exceptfds);
+#undef _
+  new_nfds = 0;
+  new_nfd = -1;
+
+  vcom_nfds = 0;
+  vcom_nfd = -1;
+  libc_nfds = 0;
+  libc_nfd = -1;
+
+  vcom_fd_set_split (
+                     /* src, select sets */
+                     __nfds, __readfds, __writefds, __exceptfds,
+                     /* dest1, vcom sets */
+                     __readfds || __writefds || __exceptfds ?
+                     &vcom_nfds : NULL,
+                     __readfds ? &vcom_readfds : NULL,
+                     __writefds ? &vcom_writefds : NULL,
+                     __exceptfds ? &vcom_exceptfds : NULL,
+                     __readfds || __writefds || __exceptfds ?
+                     &vcom_nfd : NULL,
+                     /* dest2, libc sets */
+                     __readfds || __writefds || __exceptfds ?
+                     &libc_nfds : NULL,
+                     __readfds ? &libc_readfds : NULL,
+                     __writefds ? &libc_writefds : NULL,
+                     __exceptfds ? &libc_exceptfds : NULL,
+                     __readfds || __writefds || __exceptfds ?
+                     &libc_nfd : NULL);
+
+  /*
+   * polling loop
+   * */
+  do
+    {
+      new_nfd = -1;
+      vcom_nfd = -1;
+      libc_nfd = -1;
+
+      /*
+       * if both fields of timeval structure are zero,
+       * vcom_select_impl and libc_select returns immediately.
+       * useful for polling and ensure fairness among
+       * file descriptors watched.
+       */
+
+      /* for polling */
+      tv.tv_sec = 0;
+      tv.tv_usec = 0;
+
+      /* select on vcom fds */
+      if (vcom_nfds)
+       {
+         vcom_nfd = vcom_select_impl (vcom_nfds,
+                                      __readfds ? &vcom_readfds : NULL,
+                                      __writefds ? &vcom_writefds : NULL,
+                                      __exceptfds ? &vcom_exceptfds : NULL,
+                                      &tv);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] select vcom: "
+                    "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
+
+         if (vcom_nfd < 0)
+           {
+             rv = vcom_nfd;
+             goto select_done;
+           }
+       }
+      /* select on libc fds */
+      if (libc_nfds)
+       {
+         libc_nfd = libc_select (libc_nfds,
+                                 __readfds ? &libc_readfds : NULL,
+                                 __writefds ? &libc_writefds : NULL,
+                                 __exceptfds ? &libc_exceptfds : NULL, &tv);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] select libc: "
+                    "'%04d'='%04d'\n", pid, libc_nfd, libc_nfds);
+
+         if (libc_nfd < 0)
+           {
+             /* tv becomes undefined */
+             libc_nfd = errno;
+             rv = libc_nfd;
+             goto select_done;
+           }
+       }
+
+      /* check if any file descriptors changed status */
+      if ((vcom_nfds && vcom_nfd > 0) || (libc_nfds && libc_nfd > 0))
+       {
+         /* zero the sets before merge and exit */
+
+         /*
+          * F fd set
+          */
+#define _(F)                  \
+          if ((F))            \
+            {                 \
+              FD_ZERO ((F));  \
+            }
+
+
+         _(__readfds);
+         _(__writefds);
+         _(__exceptfds);
+#undef _
+         new_nfds = 0;
+         new_nfd = -1;
+
+         /*
+          * on exit, sets are modified in place to indicate which
+          * file descriptors actually changed status
+          * */
+         vcom_fd_set_merge (
+                             /* dest, select sets */
+                             __readfds || __writefds || __exceptfds ?
+                             &new_nfds : NULL,
+                             __readfds,
+                             __writefds,
+                             __exceptfds,
+                             __readfds || __writefds || __exceptfds ?
+                             &new_nfd : NULL,
+                             /* src1, vcom sets */
+                             vcom_nfds,
+                             __readfds ? &vcom_readfds : NULL,
+                             __writefds ? &vcom_writefds : NULL,
+                             __exceptfds ? &vcom_exceptfds : NULL, vcom_nfd,
+                             /* src2, libc sets */
+                             libc_nfds,
+                             __readfds ? &libc_readfds : NULL,
+                             __writefds ? &libc_writefds : NULL,
+                             __exceptfds ? &libc_exceptfds : NULL, libc_nfd);
+         /*
+          * return the number of file descriptors contained in the
+          * three returned sets
+          * */
+         rv = 0;
+         /*
+          * for documentation
+          *
+          * if(vcom_nfd > 0)
+          *   rv += vcom_nfd;
+          * if(libc_nfd > 0)
+          *   rv += libc_nfd;
+          */
+
+         rv = new_nfd == -1 ? 0 : new_nfd;
+         goto select_done;
+       }
+
+      rv = clock_gettime (CLOCK_MONOTONIC, &now);
+      if (rv == -1)
+       {
+         rv = -errno;
+         goto select_done;
+       }
+    }
+  while (no_timeout || timespec_compare (&now, &end_time) < 0);
+
+  /* timeout expired before anything interesting happened */
+  timedout = 1;
+  rv = 0;
+
+select_done:
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] vselect1: " "'%04d'='%04d'\n", pid, rv, __nfds);
+  /*
+   * modify timeout parameter to reflect the amount of time not slept
+   * */
+  if (__timeout)
+    {
+      if (vcom_timerisvalid (__timeout))
+       {
+         /* timeout expired */
+         if (timedout)
+           {
+             timerclear (__timeout);
+           }
+         else if (!first_clock_gettime_failed)
+           {
+             rv2 = clock_gettime (CLOCK_MONOTONIC, &now);
+             if (rv2 == -1)
+               {
+                 rv = -errno;
+               }
+             else
+               {
+                 struct timespec ts_delta;
+                 ts_delta = timespec_sub (end_time, now);
+                 VCOM_TIMESPEC_TO_TIMEVAL (__timeout, &ts_delta);
+               }
+           }
+       }
+    }
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] vselect2: " "'%04d',='%04d'\n", pid, rv, __nfds);
+
+  return rv;
+}
+
+int
+vcom_select_internal (int __nfds, fd_set * __restrict __readfds,
+                     fd_set * __restrict __writefds,
+                     fd_set * __restrict __exceptfds,
+                     struct timeval *__restrict __timeout)
+{
+  int rv;
+  int new_nfds = 0;
+  int nfd = 0;
+  pid_t pid = getpid ();
+
+  fd_set saved_readfds;
+  fd_set saved_writefds;
+  fd_set saved_exceptfds;
+
+  /* validate __nfds */
+  if (__nfds < 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* validate __timeout */
+  if (__timeout)
+    {
+      /* validate tv_sec */
+      /* bogus */
+      if (__timeout->tv_sec < 0 || __timeout->tv_usec < 0)
+       {
+         errno = EINVAL;
+         return -1;
+       }
+
+      /* validate tv_usec */
+      /* TBD: */
+    }
+
+  /* init saved_x fds */
+  if (__readfds)
+    {
+      saved_readfds = *__readfds;
+      /*
+         memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
+       */
+    }
+  else
+    {
+      FD_ZERO (&saved_readfds);
+    }
+
+  if (__writefds)
+    {
+      saved_writefds = *__writefds;
+      /*
+         memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
+       */
+
+    }
+  else
+    {
+      FD_ZERO (&saved_writefds);
+    }
+
+  if (__exceptfds)
+    {
+      saved_exceptfds = *__exceptfds;
+      /*
+         memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
+       */
+
+    }
+  else
+    {
+      FD_ZERO (&saved_exceptfds);
+    }
+
+  /* clear vcom fds */
+  nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
+
+  /* set to an invalid value */
+  rv = -2;
+  /* have kernel fds */
+  if (new_nfds)
+    rv = libc_select (new_nfds, __readfds,
+                     __writefds, __exceptfds, __timeout);
+
+  if (new_nfds && rv == -1)
+    {
+      /* on error, the file descriptor sets are unmodified */
+      if (__readfds)
+       *__readfds = saved_readfds;
+      if (__writefds)
+       *__writefds = saved_writefds;
+      if (__exceptfds)
+       *__exceptfds = saved_exceptfds;
+      return rv;
+    }
+  else if ((new_nfds && rv != -1) || (rv == -2))
+    {
+      /* restore vcom fds */
+      nfd = vcom_fd_set (__nfds,
+                        &new_nfds,
+                        __readfds,
+                        __writefds,
+                        __exceptfds,
+                        &saved_readfds, &saved_writefds, &saved_exceptfds);
+      rv = nfd;
+    }
+
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] select: " "'%04d'='%04d'\n", pid, rv, __nfds);
+  return rv;
+}
+
+int
+select (int __nfds, fd_set * __restrict __readfds,
+       fd_set * __restrict __writefds,
+       fd_set * __restrict __exceptfds, struct timeval *__restrict __timeout)
+{
+  int rv = 0;
+  pid_t pid = getpid ();
+
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] select1: " "'%04d'='%04d'\n", pid, rv, __nfds);
+  rv = vcom_select (__nfds, __readfds, __writefds, __exceptfds, __timeout);
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] select2: " "'%04d'='%04d'\n", pid, rv, __nfds);
+  if (rv < 0)
+    {
+      errno = -rv;
+      return -1;
+    }
+  return rv;
+}
+
+#ifdef __USE_XOPEN2K
+/*
+ * Same as above only that the TIMEOUT value is given with higher
+ * resolution and a sigmask which is been set temporarily.  This
+ * version should be used.
+ *
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_pselect (int __nfds, fd_set * __restrict __readfds,
+             fd_set * __restrict __writefds,
+             fd_set * __restrict __exceptfds,
+             const struct timespec *__restrict __timeout,
+             const __sigset_t * __restrict __sigmask)
+{
+  int fd;
+  int vcom_nfds = 0;
+
+  for (fd = 0; fd < __nfds; fd++)
+    {
+      if (__readfds && FD_ISSET (fd, __readfds))
+       {
+         if (is_vcom_socket_fd (fd))
+           {
+             vcom_nfds++;
+           }
+       }
+
+      if (__writefds && FD_ISSET (fd, __writefds))
+       {
+         if (is_vcom_socket_fd (fd))
+           {
+             vcom_nfds++;
+           }
+       }
+      if (__exceptfds && FD_ISSET (fd, __exceptfds))
+       {
+         if (is_vcom_socket_fd (fd))
+           {
+             FD_CLR (fd, __exceptfds);
+           }
+       }
+    }
+  return vcom_nfds;
+}
+
+int
+pselect (int __nfds, fd_set * __restrict __readfds,
+        fd_set * __restrict __writefds,
+        fd_set * __restrict __exceptfds,
+        const struct timespec *__restrict __timeout,
+        const __sigset_t * __restrict __sigmask)
+{
+  int rv;
+  int new_nfds = 0;
+  int nfd = 0;
+  pid_t pid = getpid ();
+
+  fd_set saved_readfds;
+  fd_set saved_writefds;
+  fd_set saved_exceptfds;
+
+  /* validate __nfds */
+  if (__nfds < 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* validate __timeout */
+  if (__timeout)
+    {
+      /* validate tv_sec */
+      /* bogus */
+      if (__timeout->tv_sec < 0 || __timeout->tv_nsec < 0)
+       {
+         errno = EINVAL;
+         return -1;
+       }
+
+      /* validate tv_usec */
+      /* TBD: */
+    }
+
+  /* init saved fds */
+  if (__readfds)
+    {
+      saved_readfds = *__readfds;
+      /*
+         memcpy (&saved_readfds, __readfds, sizeof (*__readfds));
+       */
+    }
+  else
+    {
+      FD_ZERO (&saved_readfds);
+    }
+
+  if (__writefds)
+    {
+      saved_writefds = *__writefds;
+      /*
+         memcpy (&saved_writefds, __writefds, sizeof (*__writefds));
+       */
+
+    }
+  else
+    {
+      FD_ZERO (&saved_writefds);
+    }
+
+  if (__exceptfds)
+    {
+      saved_exceptfds = *__exceptfds;
+      /*
+         memcpy (&saved_exceptfds, __exceptfds, sizeof (*__exceptfds));
+       */
+
+    }
+  else
+    {
+      FD_ZERO (&saved_exceptfds);
+    }
+
+  /* clear vcom fds */
+  nfd = vcom_fd_clear (__nfds, &new_nfds, __readfds, __writefds, __exceptfds);
+
+  /* set to an invalid value */
+  rv = -2;
+  if (new_nfds)
+    rv = libc_pselect (new_nfds,
+                      __readfds,
+                      __writefds, __exceptfds, __timeout, __sigmask);
+
+  if (new_nfds && rv == -1)
+    {
+      /* on error, the file descriptor sets are unmodified */
+      if (__readfds)
+       *__readfds = saved_readfds;
+      if (__writefds)
+       *__writefds = saved_writefds;
+      if (__exceptfds)
+       *__exceptfds = saved_exceptfds;
+      return rv;
+    }
+  else if ((new_nfds && rv != -1) || (rv == -2))
+    {
+      /* restore vcom fds */
+      nfd = vcom_fd_set (__nfds,
+                        &new_nfds,
+                        __readfds,
+                        __writefds,
+                        __exceptfds,
+                        &saved_readfds, &saved_writefds, &saved_exceptfds);
+      rv = nfd;
+    }
+
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] pselect: " "'%04d'='%04d'\n", pid, rv, __nfds);
+  return rv;
+}
+#endif
+
+/*
+ *
+ * Socket specific glibc api
+ *
+ */
+
+/* Create a new socket of type TYPE in domain DOMAIN, using
+ * protocol PROTOCOL.  If PROTOCOL is zero, one is chosen
+ * automatically. Returns a file descriptor for the new socket,
+ * or -1 for errors.
+ * RETURN:  a valid file descriptor for the new socket,
+ * or -1 for errors.
+ * */
+
+int
+vcom_socket (int __domain, int __type, int __protocol)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_socket (__domain, __type, __protocol);
+}
+
+int
+socket (int __domain, int __type, int __protocol)
+{
+  int rv;
+  pid_t pid = getpid ();
+  pthread_t tid = pthread_self ();
+
+  /* handle domains implemented by vpp */
+  switch (__domain)
+    {
+    case AF_INET:
+    case AF_INET6:
+      /* handle types implemented by vpp */
+      switch (__type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+       {
+       case SOCK_STREAM:
+       case SOCK_DGRAM:
+         if (VCOM_DEBUG > 0)
+           vcom_socket_main_show ();
+         rv = vcom_socket (__domain, __type, __protocol);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d][%lu (0x%lx)] socket: "
+                    "'%04d'= D='%04d', T='%04d', P='%04d'\n",
+                    pid, (unsigned long) tid, (unsigned long) tid,
+                    rv, __domain, __type, __protocol);
+         if (VCOM_DEBUG > 0)
+           vcom_socket_main_show ();
+         if (rv < 0)
+           {
+             errno = -rv;
+             return -1;
+           }
+         return rv;
+         break;
+
+       default:
+         goto CALL_GLIBC_SOCKET_API;
+         break;
+       }
+
+      break;
+
+    default:
+      goto CALL_GLIBC_SOCKET_API;
+      break;
+    }
+
+CALL_GLIBC_SOCKET_API:
+  return libc_socket (__domain, __type, __protocol);
+}
+
+/*
+ * Create two new sockets, of type TYPE in domain DOMAIN and using
+ * protocol PROTOCOL, which are connected to each other, and put file
+ * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
+ * one will be chosen automatically.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_socketpair (int __domain, int __type, int __protocol, int __fds[2])
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_socketpair (__domain, __type, __protocol, __fds);
+}
+
+int
+socketpair (int __domain, int __type, int __protocol, int __fds[2])
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  /* handle domains implemented by vpp */
+  switch (__domain)
+    {
+    case AF_INET:
+    case AF_INET6:
+      /* handle types implemented by vpp */
+      switch (__type)
+       {
+       case SOCK_STREAM:
+       case SOCK_DGRAM:
+         rv = vcom_socketpair (__domain, __type, __protocol, __fds);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] socketpair: "
+                    "'%04d'= D='%04d', T='%04d', P='%04d'\n",
+                    pid, rv, __domain, __type, __protocol);
+         if (rv < 0)
+           {
+             errno = -rv;
+             return -1;
+           }
+         return 0;
+         break;
+
+       default:
+         goto CALL_GLIBC_SOCKET_API;
+         break;
+       }
+
+      break;
+
+    default:
+      goto CALL_GLIBC_SOCKET_API;
+      break;
+    }
+
+CALL_GLIBC_SOCKET_API:
+  return libc_socketpair (__domain, __type, __protocol, __fds);
+}
+
+/*
+ * Give the socket FD the local address ADDR
+ * (which is LEN bytes long).
+ * */
+int
+vcom_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+  int rv;
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  /* validate __len */
+  switch (__addr->sa_family)
+    {
+    case AF_INET:
+      if (__len != sizeof (struct sockaddr_in))
+       return -EINVAL;
+      break;
+    case AF_INET6:
+      if (__len != sizeof (struct sockaddr_in6))
+       return -EINVAL;
+      break;
+
+    default:
+      return -1;
+      break;
+    }
+
+  /* handle domains implemented by vpp */
+  switch (__addr->sa_family)
+    {
+    case AF_INET:
+    case AF_INET6:
+      rv = vcom_socket_bind (__fd, __addr, __len);
+      return rv;
+      break;
+
+    default:
+      return -1;
+      break;
+    }
+
+  return -1;
+}
+
+int
+bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+
+      rv = vcom_bind (__fd, __addr, __len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] bind: "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, rv, __fd, __addr, __len);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_bind (__fd, __addr, __len);
+}
+
+/*
+ * Put the local address of FD into *ADDR and its length in *LEN.
+ * */
+int
+vcom_getsockname (int __fd, __SOCKADDR_ARG __addr,
+                 socklen_t * __restrict __len)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_getsockname (__fd, __addr, __len);
+}
+
+int
+getsockname (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_getsockname (__fd, __addr, __len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] getsockname: "
+                "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_getsockname (__fd, __addr, __len);
+}
+
+/*
+ * Open a connection on socket FD to peer at ADDR
+ * (which LEN bytes long). For connectionless socket types, just set
+ * the default address to send to and the only address from which to
+ * accept transmissions. Return 0 on success, -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+  int rv = -1;
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  /* validate __len */
+  switch (__addr->sa_family)
+    {
+    case AF_INET:
+      if (__len != INET_ADDRSTRLEN)
+       return -1;
+      break;
+    case AF_INET6:
+      if (__len != INET6_ADDRSTRLEN)
+       return -1;
+      break;
+
+    default:
+      return -1;
+      break;
+    }
+
+  /* handle domains implemented by vpp */
+  switch (__addr->sa_family)
+    {
+    case AF_INET:
+    case AF_INET6:
+      rv = vcom_socket_connect (__fd, __addr, __len);
+      break;
+
+    default:
+      return -1;
+      break;
+    }
+
+  return rv;
+}
+
+int
+connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
+{
+  int rv;
+  pid_t pid = getpid ();
+  pthread_t tid = pthread_self ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_connect (__fd, __addr, __len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] connect: "
+                "'%04d'='%04d', '%p', '%04d'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                rv, __fd, __addr, __len);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+
+  return libc_connect (__fd, __addr, __len);
+}
+
+/*
+ * Put the address of the peer connected to socket FD into *ADDR
+ * (which is *LEN bytes long), and its actual length into *LEN.
+ * */
+int
+vcom_getpeername (int __fd, __SOCKADDR_ARG __addr,
+                 socklen_t * __restrict __len)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_getpeername (__fd, __addr, __len);
+}
+
+int
+getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __len)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_getpeername (__fd, __addr, __len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] getpeername: "
+                "'%04d'='%04d', '%p', '%p'\n", pid, rv, __fd, __addr, __len);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_getpeername (__fd, __addr, __len);
+}
+
+/*
+ * Send N bytes of BUF to socket FD.  Returns the number sent or -1.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_send (int __fd, const void *__buf, size_t __n, int __flags)
+{
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_send (__fd, (void *) __buf, (int) __n, __flags);
+}
+
+ssize_t
+send (int __fd, const void *__buf, size_t __n, int __flags)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_send (__fd, __buf, __n, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] send: "
+                "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+                pid, (int) size, __fd, __buf, (int) __n, __flags);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_send (__fd, __buf, __n, __flags);
+}
+
+/*
+ * Read N bytes into BUF from socket FD.
+ * Returns the number read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ *  with __THROW.
+ *  */
+ssize_t
+vcom_recv (int __fd, void *__buf, size_t __n, int __flags)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_recv (__fd, __buf, __n, __flags);
+}
+
+ssize_t
+recv (int __fd, void *__buf, size_t __n, int __flags)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_recv (__fd, __buf, __n, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] recv: "
+                "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+                pid, (int) size, __fd, __buf, (int) __n, __flags);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_recv (__fd, __buf, __n, __flags);
+}
+
+/*
+ * Send N bytes of BUF on socket FD to peer at address ADDR (which is
+ * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_sendto (int __fd, const void *__buf, size_t __n, int __flags,
+            __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+ssize_t
+sendto (int __fd, const void *__buf, size_t __n, int __flags,
+       __CONST_SOCKADDR_ARG __addr, socklen_t __addr_len)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] sendto: "
+                "'%04d'='%04d', '%p', '%04d', '%04x', "
+                "'%p', '%04d'\n",
+                pid, (int) size, __fd, __buf, (int) __n, __flags,
+                __addr, __addr_len);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_sendto (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+/*
+ * Read N bytes into BUF through socket FD.
+ * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with the
+ * address of the sender, and store the actual size of the address
+ * in *ADDR_LEN.
+ * Returns the number of bytes read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_recvfrom (int __fd, void *__restrict __buf, size_t __n,
+              int __flags,
+              __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+ssize_t
+recvfrom (int __fd, void *__restrict __buf, size_t __n,
+         int __flags,
+         __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] recvfrom: "
+                "'%04d'='%04d', '%p', '%04d', '%04x', "
+                "'%p', '%p'\n",
+                pid, (int) size, __fd, __buf, (int) __n, __flags,
+                __addr, __addr_len);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_recvfrom (__fd, __buf, __n, __flags, __addr, __addr_len);
+}
+
+/*
+ * Send a message described MESSAGE on socket FD.
+ * Returns the number of bytes sent, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_sendmsg (int __fd, const struct msghdr * __message, int __flags)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_sendmsg (__fd, __message, __flags);
+}
+
+ssize_t
+sendmsg (int __fd, const struct msghdr * __message, int __flags)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_sendmsg (__fd, __message, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] sendmsg: "
+                "'%04d'='%04d', '%p', '%04x'\n",
+                pid, (int) size, __fd, __message, __flags);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_sendmsg (__fd, __message, __flags);
+}
+
+#ifdef __USE_GNU
+/*
+ * Send a VLEN messages as described by VMESSAGES to socket FD.
+ * Returns the number of datagrams successfully written
+ * or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_sendmmsg (int __fd, struct mmsghdr *__vmessages,
+              unsigned int __vlen, int __flags)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_sendmmsg (__fd, __message, __vlen, __flags);
+}
+
+int
+sendmmsg (int __fd, struct mmsghdr *__vmessages,
+         unsigned int __vlen, int __flags)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_sendmmsg (__fd, __message, __vlen, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] sendmmsg: "
+                "'%04d'='%04d', '%p', '%04d', '%04x'\n",
+                pid, (int) size, __fd, __vmessages, __vlen, __flags);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_sendmmsg (__fd, __message, __vlen, __flags);
+}
+
+#endif
+
+/*
+ * Receive a message as described by MESSAGE from socket FD.
+ * Returns the number of bytes read or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+ssize_t
+vcom_recvmsg (int __fd, struct msghdr * __message, int __flags)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_recvmsg (__fd, __message, __flags);
+}
+
+ssize_t
+recvmsg (int __fd, struct msghdr * __message, int __flags)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_recvmsg (__fd, __message, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] recvmsg: "
+                "'%04d'='%04d', '%p', '%04x'\n",
+                pid, (int) size, __fd, __message, __flags);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_recvmsg (__fd, __message, __flags);
+}
+
+#ifdef __USE_GNU
+/*
+ * Receive up to VLEN messages as described by VMESSAGES from socket FD.
+ * Returns the number of messages received or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_recvmmsg (int __fd, struct mmsghdr *__vmessages,
+              unsigned int __vlen, int __flags, struct timespec *__tmo)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+}
+
+int
+recvmmsg (int __fd, struct mmsghdr *__vmessages,
+         unsigned int __vlen, int __flags, struct timespec *__tmo)
+{
+  ssize_t size;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      size = vcom_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] recvmmsg: "
+                "'%04d'='%04d', '%p', "
+                "'%04d', '%04x', '%p'\n",
+                pid, (int) size, __fd, __vmessages, __vlen, __flags, __tmo);
+      if (size < 0)
+       {
+         errno = -size;
+         return -1;
+       }
+      return size;
+    }
+  return libc_recvmmsg (__fd, __message, __vlen, __flags, __tmo);
+}
+
+#endif
+
+/*
+ * Put the current value for socket FD's option OPTNAME
+ * at protocol level LEVEL into OPTVAL (which is *OPTLEN bytes long),
+ * and set *OPTLEN to the value's actual length.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_getsockopt (int __fd, int __level, int __optname,
+                void *__restrict __optval, socklen_t * __restrict __optlen)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_getsockopt (__fd, __level, __optname,
+                                __optval, __optlen);
+}
+
+int
+getsockopt (int __fd, int __level, int __optname,
+           void *__restrict __optval, socklen_t * __restrict __optlen)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_getsockopt (__fd, __level, __optname, __optval, __optlen);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] getsockopt: "
+                "'%04d'='%04d', '%04d', '%04d', "
+                "'%p', '%p'\n",
+                pid, rv, __fd, __level, __optname, __optval, __optlen);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
+}
+
+/*
+ * Set socket FD's option OPTNAME at protocol level LEVEL
+ * to *OPTVAL (which is OPTLEN bytes long).
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_setsockopt (int __fd, int __level, int __optname,
+                const void *__optval, socklen_t __optlen)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_setsockopt (__fd, __level, __optname,
+                                __optval, __optlen);
+}
+
+int
+setsockopt (int __fd, int __level, int __optname,
+           const void *__optval, socklen_t __optlen)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_setsockopt (__fd, __level, __optname, __optval, __optlen);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] setsockopt: "
+                "'%04d'='%04d', '%04d', '%04d', "
+                "'%p', '%04d'\n",
+                pid, rv, __fd, __level, __optname, __optval, __optlen);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
+}
+
+/*
+ * Prepare to accept connections on socket FD.
+ * N connection requests will be queued before further
+ * requests are refused.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_listen (int __fd, int __n)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_listen (__fd, __n);
+}
+
+int
+listen (int __fd, int __n)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_listen (__fd, __n);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] listen: "
+                "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __n);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_listen (__fd, __n);
+}
+
+/*
+ * Await a connection on socket FD.
+ * When a connection arrives, open a new socket to communicate
+ * with it, set *ADDR (which is *ADDR_LEN bytes long) to the address
+ * of the connecting peer and *ADDR_LEN to the address's actual
+ * length, and return the new socket's descriptor, or -1 for errors.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_accept (int __fd, __SOCKADDR_ARG __addr,
+            socklen_t * __restrict __addr_len)
+{
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+  return vcom_socket_accept (__fd, __addr, __addr_len);
+}
+
+int
+accept (int __fd, __SOCKADDR_ARG __addr, socklen_t * __restrict __addr_len)
+{
+  int rv = -1;
+  pid_t pid = getpid ();
+  pthread_t tid = pthread_self ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] accept1: "
+                "'%04d'='%04d', '%p', '%p'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                rv, __fd, __addr, __addr_len);
+      rv = vcom_accept (__fd, __addr, __addr_len);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d][%lu (0x%lx)] accept2: "
+                "'%04d'='%04d', '%p', '%p'\n",
+                pid, (unsigned long) tid, (unsigned long) tid,
+                rv, __fd, __addr, __addr_len);
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      if (rv < 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return rv;
+    }
+  return libc_accept (__fd, __addr, __addr_len);
+}
+
+#ifdef __USE_GNU
+/*
+ * Similar to 'accept' but takes an additional parameter to specify
+ * flags.
+ * This function is a cancellation point and therefore not marked
+ * with __THROW.
+ * */
+int
+vcom_accept4 (int __fd, __SOCKADDR_ARG __addr,
+             socklen_t * __restrict __addr_len, int __flags)
+{
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_accept4 (__fd, __addr, __addr_len, __flags);
+}
+
+int
+accept4 (int __fd, __SOCKADDR_ARG __addr,
+        socklen_t * __restrict __addr_len, int __flags)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      rv = vcom_accept4 (__fd, __addr, __addr_len, __flags);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] accept4: "
+                "'%04d'='%04d', '%p', '%p', '%04x'\n",
+                pid, rv, __fd, __addr, __addr_len, __flags);
+      if (VCOM_DEBUG > 0)
+       vcom_socket_main_show ();
+      if (rv < 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return rv;
+    }
+  return libc_accept4 (__fd, __addr, __addr_len, __flags);
+}
+
+#endif
+
+/*
+ * Shut down all or part of the connection open on socket FD.
+ * HOW determines what to shut down:
+ *   SHUT_RD   = No more receptions;
+ *   SHUT_WR   = No more transmissions;
+ *   SHUT_RDWR = No more receptions or transmissions.
+ * Returns 0 on success, -1 for errors.
+ * */
+int
+vcom_shutdown (int __fd, int __how)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+  return vcom_socket_shutdown (__fd, __how);
+}
+
+int
+shutdown (int __fd, int __how)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_shutdown (__fd, __how);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] shutdown: "
+                "'%04d'='%04d', '%04d'\n", pid, rv, __fd, __how);
+      if (rv != 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return 0;
+    }
+  return libc_shutdown (__fd, __how);
+}
+
+int
+vcom_epoll_create (int __size)
+{
+
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  if (__size <= 0)
+    {
+      return -EINVAL;
+    }
+
+  /* __size argument is ignored "thereafter" */
+  return vcom_epoll_create1 (0);
+}
+
+/*
+ * __size argument is ignored, but must be greater than zero
+ */
+int
+epoll_create (int __size)
+{
+  int rv = 0;
+  pid_t pid = getpid ();
+
+  rv = vcom_epoll_create (__size);
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr,
+            "[%d] epoll_create: " "'%04d'='%04d'\n", pid, rv, __size);
+  if (rv < 0)
+    {
+      errno = -rv;
+      return -1;
+    }
+  return rv;
+}
+
+int
+vcom_epoll_create1 (int __flags)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  if (__flags < 0)
+    {
+      return -EINVAL;
+    }
+  if (__flags & ~EPOLL_CLOEXEC)
+    {
+      return -EINVAL;
+    }
+  /* __flags can be either zero or EPOLL_CLOEXEC */
+  /* implementation */
+  return vcom_socket_epoll_create1 (__flags);
+}
+
+/*
+ * __flags can be either zero or EPOLL_CLOEXEC
+ * */
+int
+epoll_create1 (int __flags)
+{
+  int rv = 0;
+  pid_t pid = getpid ();
+
+  rv = vcom_epoll_create1 (__flags);
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr,
+            "[%d] epoll_create: " "'%04d'='%08x'\n", pid, rv, __flags);
+  if (rv < 0)
+    {
+      errno = -rv;
+      return -1;
+    }
+  return rv;
+}
+
+static inline int
+ep_op_has_event (int op)
+{
+  return op != EPOLL_CTL_DEL;
+}
+
+int
+vcom_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  /*
+   * the requested operation __op is not supported
+   * by this interface */
+  if (!((__op == EPOLL_CTL_ADD) ||
+       (__op == EPOLL_CTL_MOD) || (__op == EPOLL_CTL_DEL)))
+    {
+      return -EINVAL;
+    }
+
+  /* op is ADD or MOD but event parameter is NULL */
+  if ((ep_op_has_event (__op) && !__event))
+    {
+      return -EFAULT;
+    }
+
+  /* fd is same as epfd */
+  /* do not permit adding an epoll file descriptor inside itself */
+  if (__epfd == __fd)
+    {
+      return -EINVAL;
+    }
+
+  /* implementation */
+  return vcom_socket_epoll_ctl (__epfd, __op, __fd, __event);
+}
+
+/*
+ * implement the controller interface for epoll
+ * that enables the insertion/removal/change of
+ * file descriptors inside the interest set.
+ */
+int
+epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (is_vcom_epfd (__epfd))
+    {
+      /* TBD: currently limiting epoll to support only vcom fds */
+      if (is_vcom_socket_fd (__fd))
+       {
+         rv = vcom_epoll_ctl (__epfd, __op, __fd, __event);
+         if (VCOM_DEBUG > 0)
+           fprintf (stderr,
+                    "[%d] epoll_ctl: "
+                    "'%04d'='%04d', '%04d', '%04d'\n",
+                    pid, rv, __epfd, __op, __fd);
+         if (rv != 0)
+           {
+             errno = -rv;
+             return -1;
+           }
+         return 0;
+       }
+      else
+       {
+         /*
+          * TBD: currently epoll does not support kernel fds
+          * or epoll fds */
+         errno = EBADF;
+         return -1;
+       }
+    }
+  else
+    {
+      /* epfd is not an epoll file descriptor */
+      errno = EINVAL;
+      return -1;
+    }
+  return 0;
+}
+
+int
+vcom_epoll_wait (int __epfd, struct epoll_event *__events,
+                int __maxevents, int __timeout)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_epoll_pwait (__epfd, __events, __maxevents, __timeout, NULL);
+}
+
+int
+epoll_wait (int __epfd, struct epoll_event *__events,
+           int __maxevents, int __timeout)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (is_vcom_epfd (__epfd))
+    {
+      rv = vcom_epoll_wait (__epfd, __events, __maxevents, __timeout);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] epoll_wait: "
+                "'%04d'='%04d', '%p', "
+                "'%04d', '%04d'\n",
+                pid, rv, __epfd, __events, __maxevents, __timeout);
+      if (rv < 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return rv;
+    }
+  else
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  return 0;
+}
+
+
+int
+vcom_epoll_pwait (int __epfd, struct epoll_event *__events,
+                 int __maxevents, int __timeout, const __sigset_t * __ss)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  /* implementation */
+  return vcom_socket_epoll_pwait (__epfd, __events,
+                                 __maxevents, __timeout, __ss);
+}
+
+int
+epoll_pwait (int __epfd, struct epoll_event *__events,
+            int __maxevents, int __timeout, const __sigset_t * __ss)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  if (__maxevents <= 0 || __maxevents > EP_MAX_EVENTS)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (is_vcom_epfd (__epfd))
+    {
+      rv = vcom_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] epoll_pwait: "
+                "'%04d'='%04d', '%p', "
+                "'%04d', '%04d', "
+                "'%p'\n",
+                pid, rv, __epfd, __events, __maxevents, __timeout, __ss);
+      if (rv < 0)
+       {
+         errno = -rv;
+         return -1;
+       }
+      return rv;
+    }
+  else
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Poll the file descriptors described by the NFDS structures starting at
+   FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
+   an event to occur; if TIMEOUT is -1, block until an event occurs.
+   Returns the number of file descriptors with events, zero if timed out,
+   or -1 for errors.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+int
+vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return -EOPNOTSUPP;
+}
+
+int
+poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+  int rv = 0;
+
+  errno = EOPNOTSUPP;
+  rv = -1;
+  return rv;
+}
+
+#ifdef __USE_GNU
+/* Like poll, but before waiting the threads signal mask is replaced
+   with that specified in the fourth parameter.  For better usability,
+   the timeout value is specified using a TIMESPEC object.
+
+   This function is a cancellation point and therefore not marked with
+   __THROW.  */
+int
+vcom_ppoll (struct pollfd *__fds, nfds_t __nfds,
+           const struct timespec *__timeout, const __sigset_t * __ss)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return -EOPNOTSUPP;
+}
+
+int
+ppoll (struct pollfd *__fds, nfds_t __nfds,
+       const struct timespec *__timeout, const __sigset_t * __ss)
+{
+  int rv = 0;
+
+  errno = EOPNOTSUPP;
+  rv = -1;
+  return rv;
+}
+#endif
+
+void CONSTRUCTOR_ATTRIBUTE vcom_constructor (void);
+
+void DESTRUCTOR_ATTRIBUTE vcom_destructor (void);
+
+void
+vcom_constructor (void)
+{
+  pid_t pid = getpid ();
+
+  swrap_constructor ();
+  if (vcom_init () != 0)
+    {
+      printf ("\n[%d] vcom_constructor...failed!\n", pid);
+    }
+  else
+    {
+      printf ("\n[%d] vcom_constructor...done!\n", pid);
+    }
+}
+
+/*
+ * This function is called when the library is unloaded
+ */
+void
+vcom_destructor (void)
+{
+  pid_t pid = getpid ();
+
+  vcom_destroy ();
+  swrap_destructor ();
+  printf ("\n[%d] vcom_destructor...done!\n", pid);
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */