LD_PRELOAD: Refactor nomenclature (vcom -> ldp).
[vpp.git] / src / vcl / ldp_socket_wrapper.c
diff --git a/src/vcl/ldp_socket_wrapper.c b/src/vcl/ldp_socket_wrapper.c
new file mode 100644 (file)
index 0000000..9811258
--- /dev/null
@@ -0,0 +1,909 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
+ * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
+ * Copyright (C) 2013-2014 Andreas Schneider <asn@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+   Socket wrapper library. Passes all socket communication over
+   unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
+   is set.
+*/
+
+#include <signal.h>
+#include <dlfcn.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <vcl/ldp_socket_wrapper.h>
+
+
+enum swrap_dbglvl_e
+{
+  SWRAP_LOG_ERROR = 0,
+  SWRAP_LOG_WARN,
+  SWRAP_LOG_DEBUG,
+  SWRAP_LOG_TRACE
+};
+
+
+/* Macros for accessing mutexes */
+#define SWRAP_LOCK(m) do { \
+        pthread_mutex_lock(&(m ## _mutex)); \
+} while(0)
+
+#define SWRAP_UNLOCK(m) do { \
+        pthread_mutex_unlock(&(m ## _mutex)); \
+} while(0)
+
+/* Add new global locks here please */
+#define SWRAP_LOCK_ALL \
+        SWRAP_LOCK(libc_symbol_binding); \
+
+#define SWRAP_UNLOCK_ALL \
+        SWRAP_UNLOCK(libc_symbol_binding); \
+
+
+
+/* The mutex for accessing the global libc.symbols */
+static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Function prototypes */
+
+#ifdef NDEBUG
+#define SWRAP_LOG(...)
+#else
+static unsigned int swrap_log_lvl = SWRAP_LOG_WARN;
+
+static void
+swrap_log (enum swrap_dbglvl_e dbglvl, const char *func,
+          const char *format, ...)
+PRINTF_ATTRIBUTE (3, 4);
+#define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__)
+
+     static void
+       swrap_log (enum swrap_dbglvl_e dbglvl,
+                 const char *func, const char *format, ...)
+{
+  char buffer[1024];
+  va_list va;
+
+  va_start (va, format);
+  vsnprintf (buffer, sizeof (buffer), format, va);
+  va_end (va);
+
+  if (dbglvl <= swrap_log_lvl)
+    {
+      switch (dbglvl)
+       {
+       case SWRAP_LOG_ERROR:
+         fprintf (stderr,
+                  "SWRAP_ERROR(%d) - %s: %s\n",
+                  (int) getpid (), func, buffer);
+         break;
+       case SWRAP_LOG_WARN:
+         fprintf (stderr,
+                  "SWRAP_WARN(%d) - %s: %s\n",
+                  (int) getpid (), func, buffer);
+         break;
+       case SWRAP_LOG_DEBUG:
+         fprintf (stderr,
+                  "SWRAP_DEBUG(%d) - %s: %s\n",
+                  (int) getpid (), func, buffer);
+         break;
+       case SWRAP_LOG_TRACE:
+         fprintf (stderr,
+                  "SWRAP_TRACE(%d) - %s: %s\n",
+                  (int) getpid (), func, buffer);
+         break;
+       }
+    }
+}
+#endif
+
+
+/*********************************************************
+ * SWRAP LOADING LIBC FUNCTIONS
+ *********************************************************/
+
+typedef int (*__libc_accept4) (int sockfd,
+                              struct sockaddr * addr,
+                              socklen_t * addrlen, int flags);
+typedef int (*__libc_accept) (int sockfd,
+                             struct sockaddr * addr, socklen_t * addrlen);
+typedef int (*__libc_bind) (int sockfd,
+                           const struct sockaddr * addr, socklen_t addrlen);
+typedef int (*__libc_close) (int fd);
+typedef int (*__libc_connect) (int sockfd,
+                              const struct sockaddr * addr,
+                              socklen_t addrlen);
+
+#if 0
+/* TBD: dup and dup2 to be implemented later */
+typedef int (*__libc_dup) (int fd);
+typedef int (*__libc_dup2) (int oldfd, int newfd);
+#endif
+
+typedef int (*__libc_fcntl) (int fd, int cmd, ...);
+typedef FILE *(*__libc_fopen) (const char *name, const char *mode);
+#ifdef HAVE_FOPEN64
+typedef FILE *(*__libc_fopen64) (const char *name, const char *mode);
+#endif
+#ifdef HAVE_EVENTFD
+typedef int (*__libc_eventfd) (int count, int flags);
+#endif
+typedef int (*__libc_getpeername) (int sockfd,
+                                  struct sockaddr * addr,
+                                  socklen_t * addrlen);
+typedef int (*__libc_getsockname) (int sockfd,
+                                  struct sockaddr * addr,
+                                  socklen_t * addrlen);
+typedef int (*__libc_getsockopt) (int sockfd,
+                                 int level,
+                                 int optname,
+                                 void *optval, socklen_t * optlen);
+typedef int (*__libc_ioctl) (int d, unsigned long int request, ...);
+typedef int (*__libc_listen) (int sockfd, int backlog);
+typedef int (*__libc_open) (const char *pathname, int flags, mode_t mode);
+#ifdef HAVE_OPEN64
+typedef int (*__libc_open64) (const char *pathname, int flags, mode_t mode);
+#endif /* HAVE_OPEN64 */
+typedef int (*__libc_openat) (int dirfd, const char *path, int flags, ...);
+typedef int (*__libc_pipe) (int pipefd[2]);
+typedef int (*__libc_read) (int fd, void *buf, size_t count);
+typedef ssize_t (*__libc_readv) (int fd, const struct iovec * iov,
+                                int iovcnt);
+typedef int (*__libc_recv) (int sockfd, void *buf, size_t len, int flags);
+typedef int (*__libc_recvfrom) (int sockfd,
+                               void *buf,
+                               size_t len,
+                               int flags,
+                               struct sockaddr * src_addr,
+                               socklen_t * addrlen);
+typedef int (*__libc_recvmsg) (int sockfd, const struct msghdr * msg,
+                              int flags);
+typedef int (*__libc_send) (int sockfd, const void *buf, size_t len,
+                           int flags);
+typedef ssize_t (*__libc_sendfile) (int out_fd, int in_fd, off_t * offset,
+                                   size_t len);
+typedef int (*__libc_sendmsg) (int sockfd, const struct msghdr * msg,
+                              int flags);
+typedef int (*__libc_sendto) (int sockfd, const void *buf, size_t len,
+                             int flags, const struct sockaddr * dst_addr,
+                             socklen_t addrlen);
+typedef int (*__libc_setsockopt) (int sockfd, int level, int optname,
+                                 const void *optval, socklen_t optlen);
+#ifdef HAVE_SIGNALFD
+typedef int (*__libc_signalfd) (int fd, const sigset_t * mask, int flags);
+#endif
+typedef int (*__libc_socket) (int domain, int type, int protocol);
+typedef int (*__libc_socketpair) (int domain, int type, int protocol,
+                                 int sv[2]);
+#ifdef HAVE_TIMERFD_CREATE
+typedef int (*__libc_timerfd_create) (int clockid, int flags);
+#endif
+typedef ssize_t (*__libc_write) (int fd, const void *buf, size_t count);
+typedef ssize_t (*__libc_writev) (int fd, const struct iovec * iov,
+                                 int iovcnt);
+
+typedef int (*__libc_shutdown) (int fd, int how);
+
+typedef int (*__libc_select) (int __nfds, fd_set * __restrict __readfds,
+                             fd_set * __restrict __writefds,
+                             fd_set * __restrict __exceptfds,
+                             struct timeval * __restrict __timeout);
+
+#ifdef __USE_XOPEN2K
+typedef int (*__libc_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);
+#endif
+
+typedef int (*__libc_epoll_create) (int __size);
+
+typedef int (*__libc_epoll_create1) (int __flags);
+
+typedef int (*__libc_epoll_ctl) (int __epfd, int __op, int __fd,
+                                struct epoll_event * __event);
+
+typedef int (*__libc_epoll_wait) (int __epfd, struct epoll_event * __events,
+                                 int __maxevents, int __timeout);
+
+typedef int (*__libc_epoll_pwait) (int __epfd, struct epoll_event * __events,
+                                  int __maxevents, int __timeout,
+                                  const __sigset_t * __ss);
+
+typedef int (*__libc_poll) (struct pollfd * __fds, nfds_t __nfds,
+                           int __timeout);
+
+#ifdef __USE_GNU
+typedef int (*__libc_ppoll) (struct pollfd * __fds, nfds_t __nfds,
+                            const struct timespec * __timeout,
+                            const __sigset_t * __ss);
+#endif
+
+
+#define SWRAP_SYMBOL_ENTRY(i) \
+        union { \
+                __libc_##i f; \
+                void *obj; \
+        } _libc_##i
+
+struct swrap_libc_symbols
+{
+  SWRAP_SYMBOL_ENTRY (accept4);
+  SWRAP_SYMBOL_ENTRY (accept);
+  SWRAP_SYMBOL_ENTRY (bind);
+  SWRAP_SYMBOL_ENTRY (close);
+  SWRAP_SYMBOL_ENTRY (connect);
+#if 0
+  /* TBD: dup and dup2 to be implemented later */
+  SWRAP_SYMBOL_ENTRY (dup);
+  SWRAP_SYMBOL_ENTRY (dup2);
+#endif
+  SWRAP_SYMBOL_ENTRY (fcntl);
+  SWRAP_SYMBOL_ENTRY (fopen);
+#ifdef HAVE_FOPEN64
+  SWRAP_SYMBOL_ENTRY (fopen64);
+#endif
+#ifdef HAVE_EVENTFD
+  SWRAP_SYMBOL_ENTRY (eventfd);
+#endif
+  SWRAP_SYMBOL_ENTRY (getpeername);
+  SWRAP_SYMBOL_ENTRY (getsockname);
+  SWRAP_SYMBOL_ENTRY (getsockopt);
+  SWRAP_SYMBOL_ENTRY (ioctl);
+  SWRAP_SYMBOL_ENTRY (listen);
+  SWRAP_SYMBOL_ENTRY (open);
+#ifdef HAVE_OPEN64
+  SWRAP_SYMBOL_ENTRY (open64);
+#endif
+  SWRAP_SYMBOL_ENTRY (openat);
+  SWRAP_SYMBOL_ENTRY (pipe);
+  SWRAP_SYMBOL_ENTRY (read);
+  SWRAP_SYMBOL_ENTRY (readv);
+  SWRAP_SYMBOL_ENTRY (recv);
+  SWRAP_SYMBOL_ENTRY (recvfrom);
+  SWRAP_SYMBOL_ENTRY (recvmsg);
+  SWRAP_SYMBOL_ENTRY (send);
+  SWRAP_SYMBOL_ENTRY (sendfile);
+  SWRAP_SYMBOL_ENTRY (sendmsg);
+  SWRAP_SYMBOL_ENTRY (sendto);
+  SWRAP_SYMBOL_ENTRY (setsockopt);
+#ifdef HAVE_SIGNALFD
+  SWRAP_SYMBOL_ENTRY (signalfd);
+#endif
+  SWRAP_SYMBOL_ENTRY (socket);
+  SWRAP_SYMBOL_ENTRY (socketpair);
+#ifdef HAVE_TIMERFD_CREATE
+  SWRAP_SYMBOL_ENTRY (timerfd_create);
+#endif
+  SWRAP_SYMBOL_ENTRY (write);
+  SWRAP_SYMBOL_ENTRY (writev);
+
+  SWRAP_SYMBOL_ENTRY (shutdown);
+  SWRAP_SYMBOL_ENTRY (select);
+#ifdef __USE_XOPEN2K
+  SWRAP_SYMBOL_ENTRY (pselect);
+#endif
+  SWRAP_SYMBOL_ENTRY (epoll_create);
+  SWRAP_SYMBOL_ENTRY (epoll_create1);
+  SWRAP_SYMBOL_ENTRY (epoll_ctl);
+  SWRAP_SYMBOL_ENTRY (epoll_wait);
+  SWRAP_SYMBOL_ENTRY (epoll_pwait);
+  SWRAP_SYMBOL_ENTRY (poll);
+#ifdef __USE_GNU
+  SWRAP_SYMBOL_ENTRY (ppoll);
+#endif
+};
+
+struct swrap
+{
+  struct
+  {
+    void *handle;
+    void *socket_handle;
+    struct swrap_libc_symbols symbols;
+  } libc;
+};
+
+static struct swrap swrap;
+
+#define LIBC_NAME "libc.so"
+
+enum swrap_lib
+{
+  SWRAP_LIBC,
+};
+
+#ifndef NDEBUG
+static const char *
+swrap_str_lib (enum swrap_lib lib)
+{
+  switch (lib)
+    {
+    case SWRAP_LIBC:
+      return "libc";
+    }
+
+  /* Compiler would warn us about unhandled enum value if we get here */
+  return "unknown";
+}
+#endif
+
+static void *
+swrap_load_lib_handle (enum swrap_lib lib)
+{
+  int flags = RTLD_LAZY;
+  void *handle = NULL;
+  int i;
+
+#ifdef RTLD_DEEPBIND
+  flags |= RTLD_DEEPBIND;
+#endif
+
+  switch (lib)
+    {
+    case SWRAP_LIBC:
+      handle = swrap.libc.handle;
+#ifdef LIBC_SO
+      if (handle == NULL)
+       {
+         handle = dlopen (LIBC_SO, flags);
+
+         swrap.libc.handle = handle;
+       }
+#endif
+      if (handle == NULL)
+       {
+         for (i = 10; i >= 0; i--)
+           {
+             char soname[256] = { 0 };
+
+             snprintf (soname, sizeof (soname), "libc.so.%d", i);
+             handle = dlopen (soname, flags);
+             if (handle != NULL)
+               {
+                 break;
+               }
+           }
+
+         swrap.libc.handle = handle;
+       }
+      break;
+    }
+
+  if (handle == NULL)
+    {
+      SWRAP_LOG (SWRAP_LOG_ERROR,
+                "Failed to dlopen library: %s\n", dlerror ());
+      exit (-1);
+    }
+
+  return handle;
+}
+
+static void *
+_swrap_bind_symbol (enum swrap_lib lib, const char *fn_name)
+{
+  void *handle;
+  void *func;
+
+  handle = swrap_load_lib_handle (lib);
+
+  func = dlsym (handle, fn_name);
+  if (func == NULL)
+    {
+      SWRAP_LOG (SWRAP_LOG_ERROR,
+                "Failed to find %s: %s\n", fn_name, dlerror ());
+      exit (-1);
+    }
+
+  SWRAP_LOG (SWRAP_LOG_TRACE,
+            "Loaded %s from %s", fn_name, swrap_str_lib (lib));
+
+  return func;
+}
+
+#define swrap_bind_symbol_libc(sym_name) \
+        SWRAP_LOCK(libc_symbol_binding); \
+        if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+                swrap.libc.symbols._libc_##sym_name.obj = \
+                        _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
+        } \
+        SWRAP_UNLOCK(libc_symbol_binding)
+
+/*
+ * IMPORTANT
+ *
+ * Functions especially from libc need to be loaded individually, you can't load
+ * all at once or gdb will segfault at startup. The same applies to valgrind and
+ * has probably something todo with with the linker.
+ * So we need load each function at the point it is called the first time.
+ */
+int
+libc_accept4 (int sockfd,
+             struct sockaddr *addr, socklen_t * addrlen, int flags)
+{
+  swrap_bind_symbol_libc (accept4);
+
+  return swrap.libc.symbols._libc_accept4.f (sockfd, addr, addrlen, flags);
+}
+
+int
+libc_accept (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+  swrap_bind_symbol_libc (accept);
+
+  return swrap.libc.symbols._libc_accept.f (sockfd, addr, addrlen);
+}
+
+int
+libc_bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+  swrap_bind_symbol_libc (bind);
+
+  return swrap.libc.symbols._libc_bind.f (sockfd, addr, addrlen);
+}
+
+int
+libc_close (int fd)
+{
+  swrap_bind_symbol_libc (close);
+
+  return swrap.libc.symbols._libc_close.f (fd);
+}
+
+int
+libc_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+  swrap_bind_symbol_libc (connect);
+
+  return swrap.libc.symbols._libc_connect.f (sockfd, addr, addrlen);
+}
+
+#if 0
+/* TBD: dup and dup2 to be implemented later */
+int
+libc_dup (int fd)
+{
+  swrap_bind_symbol_libc (dup);
+
+  return swrap.libc.symbols._libc_dup.f (fd);
+}
+
+int
+libc_dup2 (int oldfd, int newfd)
+{
+  swrap_bind_symbol_libc (dup2);
+
+  return swrap.libc.symbols._libc_dup2.f (oldfd, newfd);
+}
+#endif
+
+#ifdef HAVE_EVENTFD
+int
+libc_eventfd (int count, int flags)
+{
+  swrap_bind_symbol_libc (eventfd);
+
+  return swrap.libc.symbols._libc_eventfd.f (count, flags);
+}
+#endif
+
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vfcntl (int fd, int cmd, va_list ap)
+{
+  long int args[4];
+  int rc;
+  int i;
+
+  swrap_bind_symbol_libc (fcntl);
+
+  for (i = 0; i < 4; i++)
+    {
+      args[i] = va_arg (ap, long int);
+    }
+
+  rc = swrap.libc.symbols._libc_fcntl.f (fd,
+                                        cmd,
+                                        args[0], args[1], args[2], args[3]);
+
+  return rc;
+}
+
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vioctl (int fd, int cmd, va_list ap)
+{
+  long int args[4];
+  int rc;
+  int i;
+
+  swrap_bind_symbol_libc (ioctl);
+
+  for (i = 0; i < 4; i++)
+    {
+      args[i] = va_arg (ap, long int);
+    }
+
+  rc = swrap.libc.symbols._libc_ioctl.f (fd,
+                                        cmd,
+                                        args[0], args[1], args[2], args[3]);
+
+  return rc;
+}
+
+int
+libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+  swrap_bind_symbol_libc (getpeername);
+
+  return swrap.libc.symbols._libc_getpeername.f (sockfd, addr, addrlen);
+}
+
+int
+libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
+{
+  swrap_bind_symbol_libc (getsockname);
+
+  return swrap.libc.symbols._libc_getsockname.f (sockfd, addr, addrlen);
+}
+
+int
+libc_getsockopt (int sockfd,
+                int level, int optname, void *optval, socklen_t * optlen)
+{
+  swrap_bind_symbol_libc (getsockopt);
+
+  return swrap.libc.symbols._libc_getsockopt.f (sockfd,
+                                               level,
+                                               optname, optval, optlen);
+}
+
+int
+libc_listen (int sockfd, int backlog)
+{
+  swrap_bind_symbol_libc (listen);
+
+  return swrap.libc.symbols._libc_listen.f (sockfd, backlog);
+}
+
+/* TBD: libc_read() should return ssize_t not an int */
+int
+libc_read (int fd, void *buf, size_t count)
+{
+  swrap_bind_symbol_libc (read);
+
+  return swrap.libc.symbols._libc_read.f (fd, buf, count);
+}
+
+ssize_t
+libc_readv (int fd, const struct iovec * iov, int iovcnt)
+{
+  swrap_bind_symbol_libc (readv);
+
+  return swrap.libc.symbols._libc_readv.f (fd, iov, iovcnt);
+}
+
+int
+libc_recv (int sockfd, void *buf, size_t len, int flags)
+{
+  swrap_bind_symbol_libc (recv);
+
+  return swrap.libc.symbols._libc_recv.f (sockfd, buf, len, flags);
+}
+
+int
+libc_recvfrom (int sockfd,
+              void *buf,
+              size_t len,
+              int flags, struct sockaddr *src_addr, socklen_t * addrlen)
+{
+  swrap_bind_symbol_libc (recvfrom);
+
+  return swrap.libc.symbols._libc_recvfrom.f (sockfd,
+                                             buf,
+                                             len, flags, src_addr, addrlen);
+}
+
+int
+libc_recvmsg (int sockfd, struct msghdr *msg, int flags)
+{
+  swrap_bind_symbol_libc (recvmsg);
+
+  return swrap.libc.symbols._libc_recvmsg.f (sockfd, msg, flags);
+}
+
+int
+libc_send (int sockfd, const void *buf, size_t len, int flags)
+{
+  swrap_bind_symbol_libc (send);
+
+  return swrap.libc.symbols._libc_send.f (sockfd, buf, len, flags);
+}
+
+ssize_t
+libc_sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
+{
+  swrap_bind_symbol_libc (sendfile);
+
+  return swrap.libc.symbols._libc_sendfile.f (out_fd, in_fd, offset, len);
+}
+
+int
+libc_sendmsg (int sockfd, const struct msghdr *msg, int flags)
+{
+  swrap_bind_symbol_libc (sendmsg);
+
+  return swrap.libc.symbols._libc_sendmsg.f (sockfd, msg, flags);
+}
+
+int
+libc_sendto (int sockfd,
+            const void *buf,
+            size_t len,
+            int flags, const struct sockaddr *dst_addr, socklen_t addrlen)
+{
+  swrap_bind_symbol_libc (sendto);
+
+  return swrap.libc.symbols._libc_sendto.f (sockfd,
+                                           buf,
+                                           len, flags, dst_addr, addrlen);
+}
+
+int
+libc_setsockopt (int sockfd,
+                int level, int optname, const void *optval, socklen_t optlen)
+{
+  swrap_bind_symbol_libc (setsockopt);
+
+  return swrap.libc.symbols._libc_setsockopt.f (sockfd,
+                                               level,
+                                               optname, optval, optlen);
+}
+
+int
+libc_socket (int domain, int type, int protocol)
+{
+  swrap_bind_symbol_libc (socket);
+
+  return swrap.libc.symbols._libc_socket.f (domain, type, protocol);
+}
+
+int
+libc_socketpair (int domain, int type, int protocol, int sv[2])
+{
+  swrap_bind_symbol_libc (socketpair);
+
+  return swrap.libc.symbols._libc_socketpair.f (domain, type, protocol, sv);
+}
+
+ssize_t
+libc_write (int fd, const void *buf, size_t count)
+{
+  swrap_bind_symbol_libc (write);
+
+  return swrap.libc.symbols._libc_write.f (fd, buf, count);
+}
+
+ssize_t
+libc_writev (int fd, const struct iovec * iov, int iovcnt)
+{
+  swrap_bind_symbol_libc (writev);
+
+  return swrap.libc.symbols._libc_writev.f (fd, iov, iovcnt);
+}
+
+int
+libc_shutdown (int fd, int how)
+{
+  swrap_bind_symbol_libc (shutdown);
+
+  return swrap.libc.symbols._libc_shutdown.f (fd, how);
+}
+
+int
+libc_select (int __nfds, fd_set * __restrict __readfds,
+            fd_set * __restrict __writefds,
+            fd_set * __restrict __exceptfds,
+            struct timeval *__restrict __timeout)
+{
+  swrap_bind_symbol_libc (select);
+
+  return swrap.libc.symbols._libc_select.f (__nfds, __readfds,
+                                           __writefds,
+                                           __exceptfds, __timeout);
+}
+
+#ifdef __USE_XOPEN2K
+int
+libc_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)
+{
+  swrap_bind_symbol_libc (pselect);
+
+  return swrap.libc.symbols._libc_pselect.f (__nfds, __readfds,
+                                            __writefds,
+                                            __exceptfds,
+                                            __timeout, __sigmask);
+}
+#endif
+
+int
+libc_epoll_create (int __size)
+{
+  swrap_bind_symbol_libc (epoll_create);
+
+  return swrap.libc.symbols._libc_epoll_create.f (__size);
+}
+
+int
+libc_epoll_create1 (int __flags)
+{
+  swrap_bind_symbol_libc (epoll_create1);
+
+  return swrap.libc.symbols._libc_epoll_create1.f (__flags);
+}
+
+int
+libc_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
+{
+  swrap_bind_symbol_libc (epoll_ctl);
+
+  return swrap.libc.symbols._libc_epoll_ctl.f (__epfd, __op, __fd, __event);
+}
+
+int
+libc_epoll_wait (int __epfd, struct epoll_event *__events,
+                int __maxevents, int __timeout)
+{
+  swrap_bind_symbol_libc (epoll_wait);
+
+  return swrap.libc.symbols._libc_epoll_wait.f (__epfd, __events,
+                                               __maxevents, __timeout);
+}
+
+int
+libc_epoll_pwait (int __epfd, struct epoll_event *__events,
+                 int __maxevents, int __timeout, const __sigset_t * __ss)
+{
+  swrap_bind_symbol_libc (epoll_pwait);
+
+  return swrap.libc.symbols._libc_epoll_pwait.f (__epfd, __events,
+                                                __maxevents, __timeout,
+                                                __ss);
+}
+
+int
+libc_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+  swrap_bind_symbol_libc (poll);
+
+  return swrap.libc.symbols._libc_poll.f (__fds, __nfds, __timeout);
+}
+
+#ifdef __USE_GNU
+int
+libc_ppoll (struct pollfd *__fds, nfds_t __nfds,
+           const struct timespec *__timeout, const __sigset_t * __ss)
+{
+  swrap_bind_symbol_libc (ppoll);
+
+  return swrap.libc.symbols._libc_ppoll.f (__fds, __nfds, __timeout, __ss);
+}
+#endif
+
+static void
+swrap_thread_prepare (void)
+{
+  SWRAP_LOCK_ALL;
+}
+
+static void
+swrap_thread_parent (void)
+{
+  SWRAP_UNLOCK_ALL;
+}
+
+static void
+swrap_thread_child (void)
+{
+  SWRAP_UNLOCK_ALL;
+}
+
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+void
+swrap_constructor (void)
+{
+  /*
+   * If we hold a lock and the application forks, then the child
+   * is not able to unlock the mutex and we are in a deadlock.
+   * This should prevent such deadlocks.
+   */
+  pthread_atfork (&swrap_thread_prepare,
+                 &swrap_thread_parent, &swrap_thread_child);
+}
+
+/****************************
+ * DESTRUCTOR
+ ***************************/
+
+/*
+ * This function is called when the library is unloaded and makes sure that
+ * sockets get closed and the unix file for the socket are unlinked.
+ */
+void
+swrap_destructor (void)
+{
+  if (swrap.libc.handle != NULL)
+    {
+      dlclose (swrap.libc.handle);
+    }
+  if (swrap.libc.socket_handle)
+    {
+      dlclose (swrap.libc.socket_handle);
+    }
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */