[PATCH] Update socket_wrapper to version 1.2.1 in Samba
Jeremy Allison
jra at samba.org
Wed Nov 14 20:50:17 UTC 2018
On Wed, Nov 14, 2018 at 03:29:22PM +0100, Andreas Schneider via samba-technical wrote:
> 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.
LGTM, thanks for the re-sync. RB+ and pushed !
Jeremy.
>
>
> Andreas
>
> --
> Andreas Schneider asn at samba.org
> Samba Team www.samba.org
> GPG-ID: 8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D
> 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