aboutsummaryrefslogtreecommitdiffstats
path: root/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c')
-rw-r--r--vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c772
1 files changed, 772 insertions, 0 deletions
diff --git a/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
new file mode 100644
index 0000000..8fe7e1d
--- /dev/null
+++ b/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
@@ -0,0 +1,772 @@
+/*
+ * 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 <libvcl-ldpreload/vcom_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 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;
+ unsigned int lvl = SWRAP_LOG_WARN;
+
+ va_start (va, format);
+ vsnprintf (buffer, sizeof (buffer), format, va);
+ va_end (va);
+
+ if (lvl >= dbglvl)
+ {
+ 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
+ *********************************************************/
+
+#ifdef HAVE_ACCEPT4
+typedef int (*__libc_accept4) (int sockfd,
+ struct sockaddr * addr,
+ socklen_t * addrlen, int flags);
+#else
+typedef int (*__libc_accept) (int sockfd,
+ struct sockaddr * addr, socklen_t * addrlen);
+#endif
+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 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
+
+#define SWRAP_SYMBOL_ENTRY(i) \
+ union { \
+ __libc_##i f; \
+ void *obj; \
+ } _libc_##i
+
+struct swrap_libc_symbols
+{
+#ifdef HAVE_ACCEPT4
+ SWRAP_SYMBOL_ENTRY (accept4);
+#else
+ SWRAP_SYMBOL_ENTRY (accept);
+#endif
+ 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 (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
+};
+
+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.
+ */
+#ifdef HAVE_ACCEPT4
+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);
+}
+
+#else /* HAVE_ACCEPT4 */
+
+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);
+}
+#endif /* HAVE_ACCEPT4 */
+
+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;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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
+
+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:
+ */