[PATCH] Update socket_wrapper to version 1.2.1 in Samba

Andreas Schneider asn at samba.org
Wed Nov 14 14:29:22 UTC 2018


Hello,

the attached patch updates socket_wrapper to version 1.2.1 in Samba.

Gitlab CI has passed here:
https://gitlab.com/samba-team/devel/samba/pipelines/36468406


Please review and comment. Push if OK.


Thanks,


	Andreas

-- 
Andreas Schneider                      asn at samba.org
Samba Team                             www.samba.org
GPG-ID:     8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D
-------------- next part --------------
>From 4b31186d01fa3dea921cf1afe4f79e674b21da5a Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Mon, 12 Nov 2018 11:51:17 +0100
Subject: [PATCH 1/2] s4:torture: Use 65520 for maxopenfiles

The socket_wrapper limit is 65535 open sockets.

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/torture/smb2/maxfid.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/source4/torture/smb2/maxfid.c b/source4/torture/smb2/maxfid.c
index dbe3fac9d39..853b13de6de 100644
--- a/source4/torture/smb2/maxfid.c
+++ b/source4/torture/smb2/maxfid.c
@@ -36,7 +36,15 @@ bool torture_smb2_maxfid(struct torture_context *tctx)
 	struct smb2_handle *handles,  dir_handle = { };
 	size_t max_handles;
 
-	max_handles = torture_setting_int(tctx, "maxopenfiles", 0x11000);
+	/*
+	 * We limited this to 65520 as socket_wrapper has a limit of
+	 * 65535 (0xfff0) open sockets.
+	 *
+	 * It could be increased by setting the following env variable:
+	 *
+	 * SOCKET_WRAPPER_MAX_SOCKETS=100000
+	 */
+	max_handles = torture_setting_int(tctx, "maxopenfiles", 65520);
 
 	if (!torture_smb2_connection(tctx, &tree)) {
 		return false;
-- 
2.19.1


>From c382f0527ac737771334b0569051e53399f0cb3d Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Wed, 2 May 2018 15:57:38 +0200
Subject: [PATCH 2/2] third_party: Update socket_wrapper to version 1.2.1

Signed-off-by: Andreas Schneider <asn at samba.org>
---
 buildtools/wafsamba/samba_third_party.py    |   2 +-
 third_party/socket_wrapper/socket_wrapper.c | 988 +++++++++++++-------
 third_party/socket_wrapper/wscript          |   2 +-
 3 files changed, 677 insertions(+), 315 deletions(-)

diff --git a/buildtools/wafsamba/samba_third_party.py b/buildtools/wafsamba/samba_third_party.py
index be73dbe4218..e0dd3e1b9a0 100644
--- a/buildtools/wafsamba/samba_third_party.py
+++ b/buildtools/wafsamba/samba_third_party.py
@@ -42,7 +42,7 @@ Build.BuildContext.CHECK_CMOCKA = CHECK_CMOCKA
 
 @conf
 def CHECK_SOCKET_WRAPPER(conf):
-    return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.1.9')
+    return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.2.1')
 Build.BuildContext.CHECK_SOCKET_WRAPPER = CHECK_SOCKET_WRAPPER
 
 @conf
diff --git a/third_party/socket_wrapper/socket_wrapper.c b/third_party/socket_wrapper/socket_wrapper.c
index 539d27dbc9d..df70df5008d 100644
--- a/third_party/socket_wrapper/socket_wrapper.c
+++ b/third_party/socket_wrapper/socket_wrapper.c
@@ -1,8 +1,11 @@
 /*
- * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer at samba.org>
- * Copyright (C) 2006-2014 Stefan Metzmacher <metze at samba.org>
- * Copyright (C) 2013-2014 Andreas Schneider <asn at samba.org>
+ * BSD 3-Clause License
  *
+ * Copyright (c) 2005-2008, Jelmer Vernooij <jelmer at samba.org>
+ * Copyright (c) 2006-2018, Stefan Metzmacher <metze at samba.org>
+ * Copyright (c) 2013-2018, Andreas Schneider <asn at samba.org>
+ * Copyright (c) 2014-2017, Michael Adam <obnox at samba.org>
+ * Copyright (c) 2016-2018, Anoop C S <anoopcs at redhat.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +34,6 @@
  * 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.
- *
  */
 
 /*
@@ -111,7 +113,7 @@ enum swrap_dbglvl_e {
 # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
 #  define FALL_THROUGH __attribute__ ((fallthrough))
 # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
-#  define FALL_THROUGH
+#  define FALL_THROUGH ((void)0)
 # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
 #endif /* FALL_THROUGH */
 
@@ -142,6 +144,10 @@ enum swrap_dbglvl_e {
 	} while(0)
 #endif
 
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
 #ifndef discard_const
 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
 #endif
@@ -169,67 +175,25 @@ enum swrap_dbglvl_e {
 # endif
 #endif
 
-/* 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); \
+	swrap_mutex_lock(&libc_symbol_binding_mutex); \
 
 # define SWRAP_UNLOCK_ALL \
-	SWRAP_UNLOCK(libc_symbol_binding); \
-
-
-#define SWRAP_DLIST_ADD(list,item) do { \
-	if (!(list)) { \
-		(item)->prev	= NULL; \
-		(item)->next	= NULL; \
-		(list)		= (item); \
-	} else { \
-		(item)->prev	= NULL; \
-		(item)->next	= (list); \
-		(list)->prev	= (item); \
-		(list)		= (item); \
-	} \
-} while (0)
-
-#define SWRAP_DLIST_REMOVE(list,item) do { \
-	if ((list) == (item)) { \
-		(list)		= (item)->next; \
-		if (list) { \
-			(list)->prev	= NULL; \
-		} \
-	} else { \
-		if ((item)->prev) { \
-			(item)->prev->next	= (item)->next; \
-		} \
-		if ((item)->next) { \
-			(item)->next->prev	= (item)->prev; \
-		} \
-	} \
-	(item)->prev	= NULL; \
-	(item)->next	= NULL; \
-} while (0)
-
-#define SWRAP_DLIST_ADD_AFTER(list, item, el) \
-do { \
-	if ((list) == NULL || (el) == NULL) { \
-		SWRAP_DLIST_ADD(list, item); \
-	} else { \
-		(item)->prev = (el); \
-		(item)->next = (el)->next; \
-		(el)->next = (item); \
-		if ((item)->next != NULL) { \
-			(item)->next->prev = (item); \
-		} \
-	} \
-} while (0)
+	swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+
+#define SOCKET_INFO_CONTAINER(si) \
+	(struct socket_info_container *)(si)
+
+#define SWRAP_LOCK_SI(si) do { \
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
+	swrap_mutex_lock(&sic->meta.mutex); \
+} while(0)
+
+#define SWRAP_UNLOCK_SI(si) do { \
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
+	swrap_mutex_unlock(&sic->meta.mutex); \
+} while(0)
 
 #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
 #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
@@ -259,7 +223,6 @@ do { \
 
 #define SOCKET_MAX_SOCKETS 1024
 
-
 /*
  * Maximum number of socket_info structures that can
  * be used. Can be overriden by the environment variable
@@ -267,7 +230,7 @@ do { \
  */
 #define SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT 65535
 
-#define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 256000
+#define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 262140
 
 /* This limit is to avoid broadcast sendto() needing to stat too many
  * files.  It may be raised (with a performance cost) to up to 254
@@ -287,25 +250,10 @@ struct swrap_address {
 	} sa;
 };
 
-struct socket_info_fd {
-	struct socket_info_fd *prev, *next;
-	int fd;
-
-	/*
-	 * Points to corresponding index in array of
-	 * socket_info structures
-	 */
-	int si_index;
-};
-
 int first_free;
 
 struct socket_info
 {
-	unsigned int refcount;
-
-	int next_free;
-
 	int family;
 	int type;
 	int protocol;
@@ -330,19 +278,54 @@ struct socket_info
 	} io;
 };
 
-static struct socket_info *sockets;
-static size_t max_sockets = 0;
+struct socket_info_meta
+{
+	unsigned int refcount;
+	int next_free;
+	pthread_mutex_t mutex;
+};
+
+struct socket_info_container
+{
+	struct socket_info info;
+	struct socket_info_meta meta;
+};
+
+static struct socket_info_container *sockets;
+
+static size_t socket_info_max = 0;
 
 /*
- * While socket file descriptors are passed among different processes, the
- * numerical value gets changed. So its better to store it locally to each
- * process rather than including it within socket_info which will be shared.
+ * Allocate the socket array always on the limit value. We want it to be
+ * at least bigger than the default so if we reach the limit we can
+ * still deal with duplicate fds pointing to the same socket_info.
  */
-static struct socket_info_fd *socket_fds;
+static size_t socket_fds_max = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT;
+
+/* Hash table to map fds to corresponding socket_info index */
+static int *socket_fds_idx;
 
-/* The mutex for accessing the global libc.symbols */
+/* Mutex to synchronize access to global libc.symbols */
 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+/* Mutex for syncronizing port selection during swrap_auto_bind() */
+static pthread_mutex_t autobind_start_mutex;
+
+/* Mutex to guard the initialization of array of socket_info structures */
+static pthread_mutex_t sockets_mutex;
+
+/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */
+static pthread_mutex_t socket_reset_mutex;
+
+/* Mutex to synchronize access to first free index in socket_info array */
+static pthread_mutex_t first_free_mutex;
+
+/* Mutex to synchronize access to packet capture dump file */
+static pthread_mutex_t pcap_dump_mutex;
+
+/* Mutex for synchronizing mtu value fetch*/
+static pthread_mutex_t mtu_update_mutex;
+
 /* Function prototypes */
 
 bool socket_wrapper_enabled(void);
@@ -350,6 +333,19 @@ bool socket_wrapper_enabled(void);
 void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
 void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
 
+#ifndef HAVE_GETPROGNAME
+static const char *getprogname(void)
+{
+#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+	return program_invocation_short_name;
+#elif defined(HAVE_GETEXECNAME)
+	return getexecname();
+#else
+	return NULL;
+#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+}
+#endif /* HAVE_GETPROGNAME */
+
 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__)
 
@@ -362,6 +358,7 @@ static void swrap_log(enum swrap_dbglvl_e dbglvl,
 	const char *d;
 	unsigned int lvl = 0;
 	const char *prefix = "SWRAP";
+	const char *progname = getprogname();
 
 	d = getenv("SOCKET_WRAPPER_DEBUGLEVEL");
 	if (d != NULL) {
@@ -391,9 +388,17 @@ static void swrap_log(enum swrap_dbglvl_e dbglvl,
 			break;
 	}
 
+	if (progname == NULL) {
+		progname = "<unknown>";
+	}
+
 	fprintf(stderr,
-		"%s(%d) - %s: %s\n",
-		prefix, (int)getpid(), func, buffer);
+		"%s[%s (%u)] - %s: %s\n",
+		prefix,
+		progname,
+		(unsigned int)getpid(),
+		func,
+		buffer);
 }
 
 /*********************************************************
@@ -582,7 +587,15 @@ static void *swrap_load_lib_handle(enum swrap_lib lib)
 	int i;
 
 #ifdef RTLD_DEEPBIND
-	flags |= RTLD_DEEPBIND;
+	const char *env = getenv("LD_PRELOAD");
+
+	/* Don't do a deepbind if we run with libasan */
+	if (env != NULL && strlen(env) < 1024) {
+		const char *p = strstr(env, "libasan.so");
+		if (p == NULL) {
+			flags |= RTLD_DEEPBIND;
+		}
+	}
 #endif
 
 	switch (lib) {
@@ -670,34 +683,62 @@ static void *_swrap_bind_symbol(enum swrap_lib lib, const char *fn_name)
 	return func;
 }
 
+static void swrap_mutex_lock(pthread_mutex_t *mutex)
+{
+	int ret;
+
+	ret = pthread_mutex_lock(mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't lock pthread mutex - %s",
+			  strerror(ret));
+	}
+}
+
+static void swrap_mutex_unlock(pthread_mutex_t *mutex)
+{
+	int ret;
+
+	ret = pthread_mutex_unlock(mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't unlock pthread mutex - %s",
+			  strerror(ret));
+	}
+}
+
+/*
+ * These macros have a thread race condition on purpose!
+ *
+ * This is an optimization to avoid locking each time we check if the symbol is
+ * bound.
+ */
 #define swrap_bind_symbol_libc(sym_name) \
 	if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
-		SWRAP_LOCK(libc_symbol_binding); \
+		swrap_mutex_lock(&libc_symbol_binding_mutex); \
 		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); \
+		swrap_mutex_unlock(&libc_symbol_binding_mutex); \
 	}
 
 #define swrap_bind_symbol_libsocket(sym_name) \
 	if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
-		SWRAP_LOCK(libc_symbol_binding); \
+		swrap_mutex_lock(&libc_symbol_binding_mutex); \
 		if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
 			swrap.libc.symbols._libc_##sym_name.obj = \
 				_swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \
 		} \
-		SWRAP_UNLOCK(libc_symbol_binding); \
+		swrap_mutex_unlock(&libc_symbol_binding_mutex); \
 	}
 
 #define swrap_bind_symbol_libnsl(sym_name) \
 	if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
-		SWRAP_LOCK(libc_symbol_binding); \
+		swrap_mutex_lock(&libc_symbol_binding_mutex); \
 		if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
 			swrap.libc.symbols._libc_##sym_name.obj = \
 				_swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \
 		} \
-		SWRAP_UNLOCK(libc_symbol_binding); \
+		swrap_mutex_unlock(&libc_symbol_binding_mutex); \
 	}
 
 /****************************************************************************
@@ -1194,6 +1235,45 @@ static size_t socket_length(int family)
 	return 0;
 }
 
+static struct socket_info *swrap_get_socket_info(int si_index)
+{
+	return (struct socket_info *)(&(sockets[si_index].info));
+}
+
+static int swrap_get_refcount(struct socket_info *si)
+{
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+	return sic->meta.refcount;
+}
+
+static void swrap_inc_refcount(struct socket_info *si)
+{
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+	sic->meta.refcount += 1;
+}
+
+static void swrap_dec_refcount(struct socket_info *si)
+{
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+	sic->meta.refcount -= 1;
+}
+
+static int swrap_get_next_free(struct socket_info *si)
+{
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+	return sic->meta.next_free;
+}
+
+static void swrap_set_next_free(struct socket_info *si, int next_free)
+{
+	struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+	sic->meta.next_free = next_free;
+}
+
 static const char *socket_wrapper_dir(void)
 {
 	const char *s = getenv("SOCKET_WRAPPER_DIR");
@@ -1216,8 +1296,10 @@ static unsigned int socket_wrapper_mtu(void)
 	const char *s;
 	char *endp;
 
+	swrap_mutex_lock(&mtu_update_mutex);
+
 	if (max_mtu != 0) {
-		return max_mtu;
+		goto done;
 	}
 
 	max_mtu = SOCKET_WRAPPER_MTU_DEFAULT;
@@ -1238,20 +1320,44 @@ static unsigned int socket_wrapper_mtu(void)
 	max_mtu = tmp;
 
 done:
+	swrap_mutex_unlock(&mtu_update_mutex);
 	return max_mtu;
 }
 
+static int socket_wrapper_init_mutex(pthread_mutex_t *m)
+{
+	pthread_mutexattr_t ma;
+	int ret;
+
+	ret = pthread_mutexattr_init(&ma);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
+	if (ret != 0) {
+		goto done;
+	}
+
+	ret = pthread_mutex_init(m, &ma);
+
+done:
+	pthread_mutexattr_destroy(&ma);
+
+	return ret;
+}
+
 static size_t socket_wrapper_max_sockets(void)
 {
 	const char *s;
-	unsigned long tmp;
+	size_t tmp;
 	char *endp;
 
-	if (max_sockets != 0) {
-		return max_sockets;
+	if (socket_info_max != 0) {
+		return socket_info_max;
 	}
 
-	max_sockets = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
+	socket_info_max = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
 
 	s = getenv("SOCKET_WRAPPER_MAX_SOCKETS");
 	if (s == NULL || s[0] == '\0') {
@@ -1262,44 +1368,125 @@ static size_t socket_wrapper_max_sockets(void)
 	if (s == endp) {
 		goto done;
 	}
-	if (tmp == 0 || tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) {
+	if (tmp == 0) {
+		tmp = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
 		SWRAP_LOG(SWRAP_LOG_ERROR,
-			  "Invalid number of sockets specified, using default.");
-		goto done;
+			  "Invalid number of sockets specified, "
+			  "using default (%zu)",
+			  tmp);
+	}
+
+	if (tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) {
+		tmp = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT;
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Invalid number of sockets specified, "
+			  "using maximum (%zu).",
+			  tmp);
 	}
 
-	max_sockets = tmp;
+	socket_info_max = tmp;
 
 done:
-	return max_sockets;
+	return socket_info_max;
+}
+
+static void socket_wrapper_init_fds_idx(void)
+{
+	int *tmp = NULL;
+	size_t i;
+
+	if (socket_fds_idx != NULL) {
+		return;
+	}
+
+	tmp = (int *)calloc(socket_fds_max, sizeof(int));
+	if (tmp == NULL) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to allocate socket fds index array: %s",
+			  strerror(errno));
+		exit(-1);
+	}
+
+	for (i = 0; i < socket_fds_max; i++) {
+		tmp[i] = -1;
+	}
+
+	socket_fds_idx = tmp;
 }
 
 static void socket_wrapper_init_sockets(void)
 {
+	size_t max_sockets;
 	size_t i;
+	int ret;
+
+	swrap_mutex_lock(&sockets_mutex);
 
 	if (sockets != NULL) {
+		swrap_mutex_unlock(&sockets_mutex);
 		return;
 	}
 
+	socket_wrapper_init_fds_idx();
+
+	/* Needs to be called inside the sockets_mutex lock here. */
 	max_sockets = socket_wrapper_max_sockets();
 
-	sockets = (struct socket_info *)calloc(max_sockets,
-					       sizeof(struct socket_info));
+	sockets = (struct socket_info_container *)calloc(max_sockets,
+					sizeof(struct socket_info_container));
 
 	if (sockets == NULL) {
 		SWRAP_LOG(SWRAP_LOG_ERROR,
-			  "Failed to allocate sockets array.\n");
+			  "Failed to allocate sockets array: %s",
+			  strerror(errno));
+		swrap_mutex_unlock(&sockets_mutex);
 		exit(-1);
 	}
 
+	swrap_mutex_lock(&first_free_mutex);
+
 	first_free = 0;
 
 	for (i = 0; i < max_sockets; i++) {
-		sockets[i].next_free = i+1;
+		swrap_set_next_free(&sockets[i].info, i+1);
+		ret = socket_wrapper_init_mutex(&sockets[i].meta.mutex);
+		if (ret != 0) {
+			SWRAP_LOG(SWRAP_LOG_ERROR,
+				  "Failed to initialize pthread mutex");
+			goto done;
+		}
+	}
+
+	/* mark the end of the free list */
+	swrap_set_next_free(&sockets[max_sockets-1].info, -1);
+
+	ret = socket_wrapper_init_mutex(&autobind_start_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		goto done;
+	}
+
+	ret = socket_wrapper_init_mutex(&pcap_dump_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		goto done;
 	}
 
-	sockets[max_sockets-1].next_free = -1;
+	ret = socket_wrapper_init_mutex(&mtu_update_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		goto done;
+	}
+
+done:
+	swrap_mutex_unlock(&first_free_mutex);
+	swrap_mutex_unlock(&sockets_mutex);
+	if (ret != 0) {
+		exit(-1);
+	}
 }
 
 bool socket_wrapper_enabled(void)
@@ -1330,23 +1517,108 @@ static unsigned int socket_wrapper_default_iface(void)
 	return 1;/* 127.0.0.1 */
 }
 
-/*
- * Return the first free entry (if any) and make
- * it re-usable again (by nulling it out)
- */
-static int socket_wrapper_first_free_index(void)
+static void set_socket_info_index(int fd, int idx)
 {
-	int next_free;
+	socket_fds_idx[fd] = idx;
+	/* This builtin issues a full memory barrier. */
+	__sync_synchronize();
+}
+
+static void reset_socket_info_index(int fd)
+{
+	set_socket_info_index(fd, -1);
+}
+
+static int find_socket_info_index(int fd)
+{
+	if (fd < 0) {
+		return -1;
+	}
+
+	if (socket_fds_idx == NULL) {
+		return -1;
+	}
 
+	if ((size_t)fd >= socket_fds_max) {
+		/*
+		 * Do not add a log here as some applications do stupid things
+		 * like:
+		 *
+		 *     for (fd = 0; fd <= getdtablesize(); fd++) {
+		 *         close(fd)
+		 *     };
+		 *
+		 * This would produce millions of lines of debug messages.
+		 */
+#if 0
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Looking for a socket info for the fd %d is over the "
+			  "max socket index limit of %zu.",
+			  fd,
+			  socket_fds_max);
+#endif
+		return -1;
+	}
+
+	/* This builtin issues a full memory barrier. */
+	__sync_synchronize();
+	return socket_fds_idx[fd];
+}
+
+static int swrap_add_socket_info(struct socket_info *si_input)
+{
+	struct socket_info *si = NULL;
+	int si_index = -1;
+
+	if (si_input == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	swrap_mutex_lock(&first_free_mutex);
 	if (first_free == -1) {
+		errno = ENFILE;
+		goto out;
+	}
+
+	si_index = first_free;
+	si = swrap_get_socket_info(si_index);
+
+	SWRAP_LOCK_SI(si);
+
+	first_free = swrap_get_next_free(si);
+	*si = *si_input;
+	swrap_inc_refcount(si);
+
+	SWRAP_UNLOCK_SI(si);
+
+out:
+	swrap_mutex_unlock(&first_free_mutex);
+
+	return si_index;
+}
+
+static int swrap_create_socket(struct socket_info *si, int fd)
+{
+	int idx;
+
+	if ((size_t)fd >= socket_fds_max) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "The max socket index limit of %zu has been reached, "
+			  "trying to add %d",
+			  socket_fds_max,
+			  fd);
+		return -1;
+	}
+
+	idx = swrap_add_socket_info(si);
+	if (idx == -1) {
 		return -1;
 	}
 
-	next_free = sockets[first_free].next_free;
-	ZERO_STRUCT(sockets[first_free]);
-	sockets[first_free].next_free = next_free;
+	set_socket_info_index(fd, idx);
 
-	return first_free;
+	return idx;
 }
 
 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
@@ -1716,30 +1988,6 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
 	return 0;
 }
 
-static struct socket_info_fd *find_socket_info_fd(int fd)
-{
-	struct socket_info_fd *f;
-
-	for (f = socket_fds; f; f = f->next) {
-		if (f->fd == fd) {
-			return f;
-		}
-	}
-
-	return NULL;
-}
-
-static int find_socket_info_index(int fd)
-{
-	struct socket_info_fd *fi = find_socket_info_fd(fd);
-
-	if (fi == NULL) {
-		return -1;
-	}
-
-	return fi->si_index;
-}
-
 static struct socket_info *find_socket_info(int fd)
 {
 	int idx = find_socket_info_index(fd);
@@ -1748,7 +1996,7 @@ static struct socket_info *find_socket_info(int fd)
 		return NULL;
 	}
 
-	return &sockets[idx];
+	return swrap_get_socket_info(idx);
 }
 
 #if 0 /* FIXME */
@@ -1777,7 +2025,7 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
 	}
 
 	for (f = socket_fds; f; f = f->next) {
-		struct socket_info *s = &sockets[f->si_index];
+		struct socket_info *s = swrap_get_socket_info(f->si_index);
 
 		if (s == last_s) {
 			continue;
@@ -1845,33 +2093,43 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
 
 static void swrap_remove_stale(int fd)
 {
-	struct socket_info_fd *fi = find_socket_info_fd(fd);
 	struct socket_info *si;
 	int si_index;
 
-	if (fi == NULL) {
+	SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
+
+	swrap_mutex_lock(&socket_reset_mutex);
+
+	si_index = find_socket_info_index(fd);
+	if (si_index == -1) {
+		swrap_mutex_unlock(&socket_reset_mutex);
 		return;
 	}
 
-	si_index = fi->si_index;
+	reset_socket_info_index(fd);
 
-	SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
-	SWRAP_DLIST_REMOVE(socket_fds, fi);
-	free(fi);
+	si = swrap_get_socket_info(si_index);
 
-	si = &sockets[si_index];
-	si->refcount--;
+	swrap_mutex_lock(&first_free_mutex);
+	SWRAP_LOCK_SI(si);
 
-	if (si->refcount > 0) {
-		return;
+	swrap_dec_refcount(si);
+
+	if (swrap_get_refcount(si) > 0) {
+		goto out;
 	}
 
 	if (si->un_addr.sun_path[0] != '\0') {
 		unlink(si->un_addr.sun_path);
 	}
 
-	si->next_free = first_free;
+	swrap_set_next_free(si, first_free);
 	first_free = si_index;
+
+out:
+	SWRAP_UNLOCK_SI(si);
+	swrap_mutex_unlock(&first_free_mutex);
+	swrap_mutex_unlock(&socket_reset_mutex);
 }
 
 static int sockaddr_convert_to_un(struct socket_info *si,
@@ -2729,9 +2987,11 @@ static void swrap_pcap_dump_packet(struct socket_info *si,
 	size_t packet_len = 0;
 	int fd;
 
+	swrap_mutex_lock(&pcap_dump_mutex);
+
 	file_name = swrap_pcap_init_file();
 	if (!file_name) {
-		return;
+		goto done;
 	}
 
 	packet = swrap_pcap_marshall_packet(si,
@@ -2741,18 +3001,21 @@ static void swrap_pcap_dump_packet(struct socket_info *si,
 					    len,
 					    &packet_len);
 	if (packet == NULL) {
-		return;
+		goto done;
 	}
 
 	fd = swrap_pcap_get_fd(file_name);
 	if (fd != -1) {
 		if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
 			free(packet);
-			return;
+			goto done;
 		}
 	}
 
 	free(packet);
+
+done:
+	swrap_mutex_unlock(&pcap_dump_mutex);
 }
 
 /****************************************************************************
@@ -2784,10 +3047,10 @@ int signalfd(int fd, const sigset_t *mask, int flags)
 
 static int swrap_socket(int family, int type, int protocol)
 {
-	struct socket_info *si;
-	struct socket_info_fd *fi;
+	struct socket_info *si = NULL;
+	struct socket_info _si = { 0 };
 	int fd;
-	int idx;
+	int ret;
 	int real_type = type;
 
 	/*
@@ -2866,14 +3129,7 @@ static int swrap_socket(int family, int type, int protocol)
 	/* Check if we have a stale fd and remove it */
 	swrap_remove_stale(fd);
 
-	idx = socket_wrapper_first_free_index();
-	if (idx == -1) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	si = &sockets[idx];
-
+	si = &_si;
 	si->family = family;
 
 	/* however, the rest of the socket_wrapper code expects just
@@ -2895,6 +3151,7 @@ static int swrap_socket(int family, int type, int protocol)
 		memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen);
 		break;
 	}
+#ifdef HAVE_IPV6
 	case AF_INET6: {
 		struct sockaddr_in6 sin6 = {
 			.sin6_family = AF_INET6,
@@ -2904,30 +3161,22 @@ static int swrap_socket(int family, int type, int protocol)
 		memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen);
 		break;
 	}
+#endif
 	default:
 		errno = EINVAL;
 		return -1;
 	}
 
-	fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
-	if (fi == NULL) {
-		errno = ENOMEM;
+	ret = swrap_create_socket(si, fd);
+	if (ret == -1) {
 		return -1;
 	}
 
-	si->refcount = 1;
-	first_free = si->next_free;
-	si->next_free = 0;
-
-	fi->fd = fd;
-	fi->si_index = idx;
-
-	SWRAP_DLIST_ADD(socket_fds, fi);
-
 	SWRAP_LOG(SWRAP_LOG_TRACE,
-		  "Created %s socket for protocol %s",
-		  si->family == AF_INET ? "IPv4" : "IPv6",
-		  si->type == SOCK_DGRAM ? "UDP" : "TCP");
+		  "Created %s socket for protocol %s, fd=%d",
+		  family == AF_INET ? "IPv4" : "IPv6",
+		  real_type == SOCK_DGRAM ? "UDP" : "TCP",
+		  fd);
 
 	return fd;
 }
@@ -3014,7 +3263,7 @@ static int swrap_accept(int s,
 			int flags)
 {
 	struct socket_info *parent_si, *child_si;
-	struct socket_info_fd *child_fi;
+	struct socket_info new_si = { 0 };
 	int fd;
 	int idx;
 	struct swrap_address un_addr = {
@@ -3041,16 +3290,26 @@ static int swrap_accept(int s,
 #endif
 	}
 
+
+	/*
+	 * prevent parent_si from being altered / closed
+	 * while we read it
+	 */
+	SWRAP_LOCK_SI(parent_si);
+
 	/*
 	 * assume out sockaddr have the same size as the in parent
 	 * socket family
 	 */
 	in_addr.sa_socklen = socket_length(parent_si->family);
 	if (in_addr.sa_socklen <= 0) {
+		SWRAP_UNLOCK_SI(parent_si);
 		errno = EINVAL;
 		return -1;
 	}
 
+	SWRAP_UNLOCK_SI(parent_si);
+
 #ifdef HAVE_ACCEPT4
 	ret = libc_accept4(s, &un_addr.sa.s, &un_addr.sa_socklen, flags);
 #else
@@ -3067,6 +3326,8 @@ static int swrap_accept(int s,
 
 	fd = ret;
 
+	SWRAP_LOCK_SI(parent_si);
+
 	ret = sockaddr_convert_from_un(parent_si,
 				       &un_addr.sa.un,
 				       un_addr.sa_socklen,
@@ -3074,26 +3335,12 @@ static int swrap_accept(int s,
 				       &in_addr.sa.s,
 				       &in_addr.sa_socklen);
 	if (ret == -1) {
+		SWRAP_UNLOCK_SI(parent_si);
 		close(fd);
 		return ret;
 	}
 
-	idx = socket_wrapper_first_free_index();
-	if (idx == -1) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	child_si = &sockets[idx];
-
-	child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
-	if (child_fi == NULL) {
-		close(fd);
-		errno = ENOMEM;
-		return -1;
-	}
-
-	child_fi->fd = fd;
+	child_si = &new_si;
 
 	child_si->family = parent_si->family;
 	child_si->type = parent_si->type;
@@ -3102,6 +3349,8 @@ static int swrap_accept(int s,
 	child_si->is_server = 1;
 	child_si->connected = 1;
 
+	SWRAP_UNLOCK_SI(parent_si);
+
 	child_si->peername = (struct swrap_address) {
 		.sa_socklen = in_addr.sa_socklen,
 	};
@@ -3119,7 +3368,6 @@ static int swrap_accept(int s,
 			       &un_my_addr.sa.s,
 			       &un_my_addr.sa_socklen);
 	if (ret == -1) {
-		free(child_fi);
 		close(fd);
 		return ret;
 	}
@@ -3131,7 +3379,6 @@ static int swrap_accept(int s,
 				       &in_my_addr.sa.s,
 				       &in_my_addr.sa_socklen);
 	if (ret == -1) {
-		free(child_fi);
 		close(fd);
 		return ret;
 	}
@@ -3145,18 +3392,20 @@ static int swrap_accept(int s,
 	};
 	memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
 
-	child_si->refcount = 1;
-	first_free = child_si->next_free;
-	child_si->next_free = 0;
-
-	child_fi->si_index = idx;
-
-	SWRAP_DLIST_ADD(socket_fds, child_fi);
+	idx = swrap_create_socket(&new_si, fd);
+	if (idx == -1) {
+		close (fd);
+		return -1;
+	}
 
 	if (addr != NULL) {
-		swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
-		swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
-		swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+		struct socket_info *si = swrap_get_socket_info(idx);
+
+		SWRAP_LOCK_SI(si);
+		swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+		swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+		swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+		SWRAP_UNLOCK_SI(si);
 	}
 
 	return fd;
@@ -3198,6 +3447,8 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
 	int port;
 	struct stat st;
 
+	swrap_mutex_lock(&autobind_start_mutex);
+
 	if (autobind_start_init != 1) {
 		autobind_start_init = 1;
 		autobind_start = getpid();
@@ -3316,6 +3567,7 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
 	ret = 0;
 
 done:
+	swrap_mutex_unlock(&autobind_start_mutex);
 	return ret;
 }
 
@@ -3337,6 +3589,8 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
 		return libc_connect(s, serv_addr, addrlen);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	if (si->bound == 0) {
 		ret = swrap_auto_bind(s, si, serv_addr->sa_family);
 		if (ret == -1) {
@@ -3420,6 +3674,7 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
 	}
 
 done:
+	SWRAP_UNLOCK_SI(si);
 	return ret;
 }
 
@@ -3448,6 +3703,8 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 		return libc_bind(s, myaddr, addrlen);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	switch (si->family) {
 	case AF_INET: {
 		const struct sockaddr_in *sin;
@@ -3495,14 +3752,16 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 
 	if (bind_error != 0) {
 		errno = bind_error;
-		return -1;
+		ret = -1;
+		goto out;
 	}
 
 #if 0 /* FIXME */
 	in_use = check_addr_port_in_use(myaddr, addrlen);
 	if (in_use) {
 		errno = EADDRINUSE;
-		return -1;
+		ret = -1;
+		goto out;
 	}
 #endif
 
@@ -3516,7 +3775,7 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 				     1,
 				     &si->bcast);
 	if (ret == -1) {
-		return -1;
+		goto out;
 	}
 
 	unlink(un_addr.sa.un.sun_path);
@@ -3531,6 +3790,9 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 		si->bound = 1;
 	}
 
+out:
+	SWRAP_UNLOCK_SI(si);
+
 	return ret;
 }
 
@@ -3634,16 +3896,21 @@ static int swrap_listen(int s, int backlog)
 		return libc_listen(s, backlog);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	if (si->bound == 0) {
 		ret = swrap_auto_bind(s, si, si->family);
 		if (ret == -1) {
 			errno = EADDRINUSE;
-			return ret;
+			goto out;
 		}
 	}
 
 	ret = libc_listen(s, backlog);
 
+out:
+	SWRAP_UNLOCK_SI(si);
+
 	return ret;
 }
 
@@ -3810,26 +4077,34 @@ static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
 {
 	struct socket_info *si = find_socket_info(s);
 	socklen_t len;
+	int ret = -1;
 
 	if (!si) {
 		return libc_getpeername(s, name, addrlen);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	if (si->peername.sa_socklen == 0)
 	{
 		errno = ENOTCONN;
-		return -1;
+		goto out;
 	}
 
 	len = MIN(*addrlen, si->peername.sa_socklen);
 	if (len == 0) {
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	memcpy(name, &si->peername.sa.ss, len);
 	*addrlen = si->peername.sa_socklen;
 
-	return 0;
+	ret = 0;
+out:
+	SWRAP_UNLOCK_SI(si);
+
+	return ret;
 }
 
 #ifdef HAVE_ACCEPT_PSOCKLEN_T
@@ -3849,20 +4124,28 @@ static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
 {
 	struct socket_info *si = find_socket_info(s);
 	socklen_t len;
+	int ret = -1;
 
 	if (!si) {
 		return libc_getsockname(s, name, addrlen);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	len = MIN(*addrlen, si->myname.sa_socklen);
 	if (len == 0) {
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	memcpy(name, &si->myname.sa.ss, len);
 	*addrlen = si->myname.sa_socklen;
 
-	return 0;
+	ret = 0;
+out:
+	SWRAP_UNLOCK_SI(si);
+
+	return ret;
 }
 
 #ifdef HAVE_ACCEPT_PSOCKLEN_T
@@ -3898,6 +4181,8 @@ static int swrap_getsockopt(int s, int level, int optname,
 				       optlen);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	if (level == SOL_SOCKET) {
 		switch (optname) {
 #ifdef SO_DOMAIN
@@ -3980,6 +4265,7 @@ static int swrap_getsockopt(int s, int level, int optname,
 	ret = -1;
 
 done:
+	SWRAP_UNLOCK_SI(si);
 	return ret;
 }
 
@@ -4016,7 +4302,11 @@ static int swrap_setsockopt(int s, int level, int optname,
 				       optname,
 				       optval,
 				       optlen);
-	} else if (level == IPPROTO_TCP) {
+	}
+
+	SWRAP_LOCK_SI(si);
+
+	if (level == IPPROTO_TCP) {
 		switch (optname) {
 #ifdef TCP_NODELAY
 		case TCP_NODELAY: {
@@ -4080,6 +4370,7 @@ static int swrap_setsockopt(int s, int level, int optname,
 	}
 
 done:
+	SWRAP_UNLOCK_SI(si);
 	return ret;
 }
 
@@ -4104,6 +4395,8 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va)
 		return libc_vioctl(s, r, va);
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	va_copy(ap, va);
 
 	rc = libc_vioctl(s, r, va);
@@ -4122,6 +4415,7 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va)
 
 	va_end(ap);
 
+	SWRAP_UNLOCK_SI(si);
 	return rc;
 }
 
@@ -4427,7 +4721,7 @@ static ssize_t swrap_sendmsg_before(int fd,
 				    int *bcast)
 {
 	size_t i, len = 0;
-	ssize_t ret;
+	ssize_t ret = -1;
 
 	if (to_un) {
 		*to_un = NULL;
@@ -4439,13 +4733,15 @@ static ssize_t swrap_sendmsg_before(int fd,
 		*bcast = 0;
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	switch (si->type) {
 	case SOCK_STREAM: {
 		unsigned long mtu;
 
 		if (!si->connected) {
 			errno = ENOTCONN;
-			return -1;
+			goto out;
 		}
 
 		if (msg->msg_iovlen == 0) {
@@ -4488,14 +4784,14 @@ static ssize_t swrap_sendmsg_before(int fd,
 
 			if (msg_name == NULL) {
 				errno = ENOTCONN;
-				return -1;
+				goto out;
 			}
 
 
 			ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
 						     tmp_un, 0, bcast);
 			if (ret == -1) {
-				return -1;
+				goto out;
 			}
 
 			if (to_un) {
@@ -4511,13 +4807,14 @@ static ssize_t swrap_sendmsg_before(int fd,
 		if (si->bound == 0) {
 			ret = swrap_auto_bind(fd, si, si->family);
 			if (ret == -1) {
+				SWRAP_UNLOCK_SI(si);
 				if (errno == ENOTSOCK) {
 					swrap_remove_stale(fd);
-					return -ENOTSOCK;
+					ret = -ENOTSOCK;
 				} else {
 					SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed");
-					return -1;
 				}
+				return ret;
 			}
 		}
 
@@ -4532,7 +4829,7 @@ static ssize_t swrap_sendmsg_before(int fd,
 					     0,
 					     NULL);
 		if (ret == -1) {
-			return -1;
+			goto out;
 		}
 
 		ret = libc_connect(fd,
@@ -4545,14 +4842,14 @@ static ssize_t swrap_sendmsg_before(int fd,
 		}
 
 		if (ret == -1) {
-			return ret;
+			goto out;
 		}
 
 		si->defer_connect = 0;
 		break;
 	default:
 		errno = EHOSTUNREACH;
-		return -1;
+		goto out;
 	}
 
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
@@ -4563,7 +4860,7 @@ static ssize_t swrap_sendmsg_before(int fd,
 		ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
 		if (ret < 0) {
 			free(cmbuf);
-			return -1;
+			goto out;
 		}
 
 		if (cmlen == 0) {
@@ -4577,7 +4874,11 @@ static ssize_t swrap_sendmsg_before(int fd,
 	}
 #endif
 
-	return 0;
+	ret = 0;
+out:
+	SWRAP_UNLOCK_SI(si);
+
+	return ret;
 }
 
 static void swrap_sendmsg_after(int fd,
@@ -4631,6 +4932,8 @@ static void swrap_sendmsg_after(int fd,
 	}
 	len = ofs;
 
+	SWRAP_LOCK_SI(si);
+
 	switch (si->type) {
 	case SOCK_STREAM:
 		if (ret == -1) {
@@ -4654,6 +4957,8 @@ static void swrap_sendmsg_after(int fd,
 		break;
 	}
 
+	SWRAP_UNLOCK_SI(si);
+
 	free(buf);
 	errno = saved_errno;
 }
@@ -4664,7 +4969,9 @@ static int swrap_recvmsg_before(int fd,
 				struct iovec *tmp_iov)
 {
 	size_t i, len = 0;
-	ssize_t ret;
+	int ret = -1;
+
+	SWRAP_LOCK_SI(si);
 
 	(void)fd; /* unused */
 
@@ -4673,7 +4980,7 @@ static int swrap_recvmsg_before(int fd,
 		unsigned int mtu;
 		if (!si->connected) {
 			errno = ENOTCONN;
-			return -1;
+			goto out;
 		}
 
 		if (msg->msg_iovlen == 0) {
@@ -4701,7 +5008,7 @@ static int swrap_recvmsg_before(int fd,
 	case SOCK_DGRAM:
 		if (msg->msg_name == NULL) {
 			errno = EINVAL;
-			return -1;
+			goto out;
 		}
 
 		if (msg->msg_iovlen == 0) {
@@ -4711,6 +5018,7 @@ static int swrap_recvmsg_before(int fd,
 		if (si->bound == 0) {
 			ret = swrap_auto_bind(fd, si, si->family);
 			if (ret == -1) {
+				SWRAP_UNLOCK_SI(si);
 				/*
 				 * When attempting to read or write to a
 				 * descriptor, if an underlying autobind fails
@@ -4719,21 +5027,25 @@ static int swrap_recvmsg_before(int fd,
 				 */
 				if (errno == ENOTSOCK) {
 					swrap_remove_stale(fd);
-					return -ENOTSOCK;
+					ret = -ENOTSOCK;
 				} else {
 					SWRAP_LOG(SWRAP_LOG_ERROR,
 						  "swrap_recvmsg_before failed");
-					return -1;
 				}
+				return ret;
 			}
 		}
 		break;
 	default:
 		errno = EHOSTUNREACH;
-		return -1;
+		goto out;
 	}
 
-	return 0;
+	ret = 0;
+out:
+	SWRAP_UNLOCK_SI(si);
+
+	return ret;
 }
 
 static int swrap_recvmsg_after(int fd,
@@ -4765,6 +5077,8 @@ static int swrap_recvmsg_after(int fd,
 		avail += msg->msg_iov[i].iov_len;
 	}
 
+	SWRAP_LOCK_SI(si);
+
 	/* Convert the socket address before we leave */
 	if (si->type == SOCK_DGRAM && un_addr != NULL) {
 		rc = sockaddr_convert_from_un(si,
@@ -4793,6 +5107,7 @@ static int swrap_recvmsg_after(int fd,
 	buf = (uint8_t *)malloc(remain);
 	if (buf == NULL) {
 		/* we just not capture the packet */
+		SWRAP_UNLOCK_SI(si);
 		errno = saved_errno;
 		return -1;
 	}
@@ -4850,11 +5165,13 @@ done:
 	    msg->msg_control != NULL) {
 		rc = swrap_msghdr_add_socket_info(si, msg);
 		if (rc < 0) {
+			SWRAP_UNLOCK_SI(si);
 			return -1;
 		}
 	}
 #endif
 
+	SWRAP_UNLOCK_SI(si);
 	return rc;
 }
 
@@ -5026,11 +5343,16 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
 				    un_addr.sa_socklen);
 		}
 
+		SWRAP_LOCK_SI(si);
+
 		swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
 
+		SWRAP_UNLOCK_SI(si);
+
 		return len;
 	}
 
+	SWRAP_LOCK_SI(si);
 	/*
 	 * If it is a dgram socket and we are connected, don't include the
 	 * 'to' address.
@@ -5051,6 +5373,8 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
 				  msg.msg_namelen);
 	}
 
+	SWRAP_UNLOCK_SI(si);
+
 	swrap_sendmsg_after(s, si, &msg, to, ret);
 
 	return ret;
@@ -5382,6 +5706,8 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 #endif
 	omsg->msg_iovlen = msg.msg_iovlen;
 
+	SWRAP_LOCK_SI(si);
+
 	/*
 	 * From the manpage:
 	 *
@@ -5401,6 +5727,8 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 		omsg->msg_namelen = msg.msg_namelen;
 	}
 
+	SWRAP_UNLOCK_SI(si);
+
 	return ret;
 }
 
@@ -5436,12 +5764,17 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
 
 	ZERO_STRUCT(msg);
 
+	SWRAP_LOCK_SI(si);
+
 	if (si->connected == 0) {
 		msg.msg_name = omsg->msg_name;             /* optional address */
 		msg.msg_namelen = omsg->msg_namelen;       /* size of address */
 	}
 	msg.msg_iov = omsg->msg_iov;               /* scatter/gather array */
 	msg.msg_iovlen = omsg->msg_iovlen;         /* # elements in msg_iov */
+
+	SWRAP_UNLOCK_SI(si);
+
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
 	if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
 		/* omsg is a const so use a local buffer for modifications */
@@ -5507,9 +5840,13 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
 			libc_sendmsg(s, &msg, flags);
 		}
 
+		SWRAP_LOCK_SI(si);
+
 		swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
 		free(buf);
 
+		SWRAP_UNLOCK_SI(si);
+
 		return len;
 	}
 
@@ -5639,28 +5976,32 @@ ssize_t writev(int s, const struct iovec *vector, int count)
 
 static int swrap_close(int fd)
 {
-	struct socket_info_fd *fi = find_socket_info_fd(fd);
 	struct socket_info *si = NULL;
 	int si_index;
 	int ret;
 
-	if (fi == NULL) {
+	swrap_mutex_lock(&socket_reset_mutex);
+
+	si_index = find_socket_info_index(fd);
+	if (si_index == -1) {
+		swrap_mutex_unlock(&socket_reset_mutex);
 		return libc_close(fd);
 	}
 
-	si_index = fi->si_index;
+	reset_socket_info_index(fd);
 
-	SWRAP_DLIST_REMOVE(socket_fds, fi);
-	free(fi);
+	si = swrap_get_socket_info(si_index);
+
+	swrap_mutex_lock(&first_free_mutex);
+	SWRAP_LOCK_SI(si);
 
 	ret = libc_close(fd);
 
-	si = &sockets[si_index];
-	si->refcount--;
+	swrap_dec_refcount(si);
 
-	if (si->refcount > 0) {
+	if (swrap_get_refcount(si) > 0) {
 		/* there are still references left */
-		return ret;
+		goto out;
 	}
 
 	if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
@@ -5676,9 +6017,14 @@ static int swrap_close(int fd)
 		unlink(si->un_addr.sun_path);
 	}
 
-	si->next_free = first_free;
+	swrap_set_next_free(si, first_free);
 	first_free = si_index;
 
+out:
+	SWRAP_UNLOCK_SI(si);
+	swrap_mutex_unlock(&first_free_mutex);
+	swrap_mutex_unlock(&socket_reset_mutex);
+
 	return ret;
 }
 
@@ -5694,37 +6040,34 @@ int close(int fd)
 static int swrap_dup(int fd)
 {
 	struct socket_info *si;
-	struct socket_info_fd *src_fi, *fi;
+	int dup_fd, idx;
 
-	src_fi = find_socket_info_fd(fd);
-	if (src_fi == NULL) {
+	idx = find_socket_info_index(fd);
+	if (idx == -1) {
 		return libc_dup(fd);
 	}
 
-	si = &sockets[src_fi->si_index];
-
-	fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
-	if (fi == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
+	si = swrap_get_socket_info(idx);
 
-	fi->fd = libc_dup(fd);
-	if (fi->fd == -1) {
+	dup_fd = libc_dup(fd);
+	if (dup_fd == -1) {
 		int saved_errno = errno;
-		free(fi);
 		errno = saved_errno;
 		return -1;
 	}
 
-	si->refcount++;
-	fi->si_index = src_fi->si_index;
+	SWRAP_LOCK_SI(si);
+
+	swrap_inc_refcount(si);
+
+	SWRAP_UNLOCK_SI(si);
 
 	/* Make sure we don't have an entry for the fd */
-	swrap_remove_stale(fi->fd);
+	swrap_remove_stale(dup_fd);
 
-	SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
-	return fi->fd;
+	set_socket_info_index(dup_fd, idx);
+
+	return dup_fd;
 }
 
 int dup(int fd)
@@ -5739,14 +6082,14 @@ int dup(int fd)
 static int swrap_dup2(int fd, int newfd)
 {
 	struct socket_info *si;
-	struct socket_info_fd *src_fi, *fi;
+	int dup_fd, idx;
 
-	src_fi = find_socket_info_fd(fd);
-	if (src_fi == NULL) {
+	idx = find_socket_info_index(fd);
+	if (idx == -1) {
 		return libc_dup2(fd, newfd);
 	}
 
-	si = &sockets[src_fi->si_index];
+	si = swrap_get_socket_info(idx);
 
 	if (fd == newfd) {
 		/*
@@ -5764,28 +6107,25 @@ static int swrap_dup2(int fd, int newfd)
 		swrap_close(newfd);
 	}
 
-	fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
-	if (fi == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	fi->fd = libc_dup2(fd, newfd);
-	if (fi->fd == -1) {
+	dup_fd = libc_dup2(fd, newfd);
+	if (dup_fd == -1) {
 		int saved_errno = errno;
-		free(fi);
 		errno = saved_errno;
 		return -1;
 	}
 
-	si->refcount++;
-	fi->si_index = src_fi->si_index;
+	SWRAP_LOCK_SI(si);
+
+	swrap_inc_refcount(si);
+
+	SWRAP_UNLOCK_SI(si);
 
 	/* Make sure we don't have an entry for the fd */
-	swrap_remove_stale(fi->fd);
+	swrap_remove_stale(dup_fd);
+
+	set_socket_info_index(dup_fd, idx);
 
-	SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
-	return fi->fd;
+	return dup_fd;
 }
 
 int dup2(int fd, int newfd)
@@ -5799,42 +6139,37 @@ int dup2(int fd, int newfd)
 
 static int swrap_vfcntl(int fd, int cmd, va_list va)
 {
-	struct socket_info_fd *src_fi, *fi;
 	struct socket_info *si;
-	int rc;
+	int rc, dup_fd, idx;
 
-	src_fi = find_socket_info_fd(fd);
-	if (src_fi == NULL) {
+	idx = find_socket_info_index(fd);
+	if (idx == -1) {
 		return libc_vfcntl(fd, cmd, va);
 	}
 
-	si = &sockets[src_fi->si_index];
+	si = swrap_get_socket_info(idx);
 
 	switch (cmd) {
 	case F_DUPFD:
-		fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
-		if (fi == NULL) {
-			errno = ENOMEM;
-			return -1;
-		}
-
-		fi->fd = libc_vfcntl(fd, cmd, va);
-		if (fi->fd == -1) {
+		dup_fd = libc_vfcntl(fd, cmd, va);
+		if (dup_fd == -1) {
 			int saved_errno = errno;
-			free(fi);
 			errno = saved_errno;
 			return -1;
 		}
 
-		si->refcount++;
-		fi->si_index = src_fi->si_index;
+		SWRAP_LOCK_SI(si);
+
+		swrap_inc_refcount(si);
+
+		SWRAP_UNLOCK_SI(si);
 
 		/* Make sure we don't have an entry for the fd */
-		swrap_remove_stale(fi->fd);
+		swrap_remove_stale(dup_fd);
 
-		SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
+		set_socket_info_index(dup_fd, idx);
 
-		rc = fi->fd;
+		rc = dup_fd;
 		break;
 	default:
 		rc = libc_vfcntl(fd, cmd, va);
@@ -5924,6 +6259,8 @@ static void swrap_thread_child(void)
  ***************************/
 void swrap_constructor(void)
 {
+	int ret;
+
 	/*
 	* 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.
@@ -5932,6 +6269,27 @@ void swrap_constructor(void)
 	pthread_atfork(&swrap_thread_prepare,
 		       &swrap_thread_parent,
 		       &swrap_thread_child);
+
+	ret = socket_wrapper_init_mutex(&sockets_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		exit(-1);
+	}
+
+	ret = socket_wrapper_init_mutex(&socket_reset_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		exit(-1);
+	}
+
+	ret = socket_wrapper_init_mutex(&first_free_mutex);
+	if (ret != 0) {
+		SWRAP_LOG(SWRAP_LOG_ERROR,
+			  "Failed to initialize pthread mutex");
+		exit(-1);
+	}
 }
 
 /****************************
@@ -5944,14 +6302,18 @@ void swrap_constructor(void)
  */
 void swrap_destructor(void)
 {
-	struct socket_info_fd *s = socket_fds;
+	size_t i;
 
-	while (s != NULL) {
-		swrap_close(s->fd);
-		s = socket_fds;
+	if (socket_fds_idx != NULL) {
+		for (i = 0; i < socket_fds_max; ++i) {
+			if (socket_fds_idx[i] != -1) {
+				swrap_close(i);
+			}
+		}
+		SAFE_FREE(socket_fds_idx);
 	}
 
-	free(sockets);
+	SAFE_FREE(sockets);
 
 	if (swrap.libc.handle != NULL) {
 		dlclose(swrap.libc.handle);
diff --git a/third_party/socket_wrapper/wscript b/third_party/socket_wrapper/wscript
index ffaba913e84..3cca13cc6fb 100644
--- a/third_party/socket_wrapper/wscript
+++ b/third_party/socket_wrapper/wscript
@@ -2,7 +2,7 @@
 
 import os
 
-VERSION="1.1.9"
+VERSION="1.2.1"
 
 def configure(conf):
     if conf.CHECK_SOCKET_WRAPPER():
-- 
2.19.1



More information about the samba-technical mailing list