# endif
#endif
+#define socket_wrapper_init_mutex(m) \
+ _socket_wrapper_init_mutex(m, #m)
+
/* Add new global locks here please */
-# define SWRAP_LOCK_ALL \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
+# define SWRAP_REINIT_ALL do { \
+ size_t __i; \
+ int ret; \
+ ret = socket_wrapper_init_mutex(&sockets_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&socket_reset_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&first_free_mutex); \
+ if (ret != 0) exit(-1); \
+ for (__i = 0; (sockets != NULL) && __i < socket_info_max; __i++) { \
+ ret = socket_wrapper_init_mutex(&sockets[__i].meta.mutex); \
+ if (ret != 0) exit(-1); \
+ } \
+ ret = socket_wrapper_init_mutex(&autobind_start_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&pcap_dump_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&mtu_update_mutex); \
+ if (ret != 0) exit(-1); \
+} while(0)
-# define SWRAP_UNLOCK_ALL \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+# define SWRAP_LOCK_ALL do { \
+ size_t __i; \
+ swrap_mutex_lock(&sockets_mutex); \
+ swrap_mutex_lock(&socket_reset_mutex); \
+ swrap_mutex_lock(&first_free_mutex); \
+ for (__i = 0; (sockets != NULL) && __i < socket_info_max; __i++) { \
+ swrap_mutex_lock(&sockets[__i].meta.mutex); \
+ } \
+ swrap_mutex_lock(&autobind_start_mutex); \
+ swrap_mutex_lock(&pcap_dump_mutex); \
+ swrap_mutex_lock(&mtu_update_mutex); \
+} while(0)
+
+# define SWRAP_UNLOCK_ALL do { \
+ size_t __s; \
+ swrap_mutex_unlock(&mtu_update_mutex); \
+ swrap_mutex_unlock(&pcap_dump_mutex); \
+ swrap_mutex_unlock(&autobind_start_mutex); \
+ for (__s = 0; (sockets != NULL) && __s < socket_info_max; __s++) { \
+ size_t __i = (socket_info_max - 1) - __s; \
+ swrap_mutex_unlock(&sockets[__i].meta.mutex); \
+ } \
+ swrap_mutex_unlock(&first_free_mutex); \
+ swrap_mutex_unlock(&socket_reset_mutex); \
+ swrap_mutex_unlock(&sockets_mutex); \
+} while(0)
#define SOCKET_INFO_CONTAINER(si) \
(struct socket_info_container *)(si)
} sa;
};
-int first_free;
+static int first_free;
struct socket_info
{
/* Hash table to map fds to corresponding socket_info index */
static int *socket_fds_idx;
-/* 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;
+static pthread_mutex_t autobind_start_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to guard the initialization of array of socket_info structures */
-static pthread_mutex_t sockets_mutex;
+static pthread_mutex_t sockets_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */
-static pthread_mutex_t socket_reset_mutex;
+static pthread_mutex_t socket_reset_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to synchronize access to first free index in socket_info array */
-static pthread_mutex_t first_free_mutex;
+static pthread_mutex_t first_free_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to synchronize access to packet capture dump file */
-static pthread_mutex_t pcap_dump_mutex;
+static pthread_mutex_t pcap_dump_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex for synchronizing mtu value fetch*/
-static pthread_mutex_t mtu_update_mutex;
+static pthread_mutex_t mtu_update_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Function prototypes */
bool socket_wrapper_enabled(void);
+#if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
+/* xlC and other oldschool compilers support (only) this */
+#pragma init (swrap_constructor)
+#endif
void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+#if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
+#pragma fini (swrap_destructor)
+#endif
void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
#ifndef HAVE_GETPROGNAME
enum swrap_lib {
SWRAP_LIBC,
- SWRAP_LIBNSL,
SWRAP_LIBSOCKET,
};
switch (lib) {
case SWRAP_LIBC:
return "libc";
- case SWRAP_LIBNSL:
- return "libnsl";
case SWRAP_LIBSOCKET:
return "libsocket";
}
#endif
switch (lib) {
- case SWRAP_LIBNSL:
case SWRAP_LIBSOCKET:
#ifdef HAVE_LIBSOCKET
handle = swrap.libc.socket_handle;
return func;
}
-static void swrap_mutex_lock(pthread_mutex_t *mutex)
+#define swrap_mutex_lock(m) _swrap_mutex_lock(m, #m, __func__, __LINE__)
+static void _swrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
{
int ret;
ret = pthread_mutex_lock(mutex);
if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't lock pthread mutex - %s",
- strerror(ret));
+ SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s",
+ getpid(), getppid(), caller, line, name, strerror(ret));
}
}
-static void swrap_mutex_unlock(pthread_mutex_t *mutex)
+#define swrap_mutex_unlock(m) _swrap_mutex_unlock(m, #m, __func__, __LINE__)
+static void _swrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
{
int ret;
ret = pthread_mutex_unlock(mutex);
if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't unlock pthread mutex - %s",
- strerror(ret));
+ SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s",
+ getpid(), getppid(), caller, line, name, strerror(ret));
}
}
* This is an optimization to avoid locking each time we check if the symbol is
* bound.
*/
+#define _swrap_bind_symbol_generic(lib, sym_name) do { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(lib, #sym_name); \
+} while(0);
+
#define swrap_bind_symbol_libc(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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_mutex_unlock(&libc_symbol_binding_mutex); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBC, sym_name)
#define swrap_bind_symbol_libsocket(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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_mutex_unlock(&libc_symbol_binding_mutex); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBSOCKET, sym_name)
-#define swrap_bind_symbol_libnsl(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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_mutex_unlock(&libc_symbol_binding_mutex); \
- }
+static void swrap_bind_symbol_all(void);
/****************************************************************************
* IMPORTANT
socklen_t *addrlen,
int flags)
{
- swrap_bind_symbol_libsocket(accept4);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept4.f(sockfd, addr, addrlen, flags);
}
static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(accept);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept.f(sockfd, addr, addrlen);
}
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(bind);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_bind.f(sockfd, addr, addrlen);
}
static int libc_close(int fd)
{
- swrap_bind_symbol_libc(close);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_close.f(fd);
}
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(connect);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_connect.f(sockfd, addr, addrlen);
}
static int libc_dup(int fd)
{
- swrap_bind_symbol_libc(dup);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup.f(fd);
}
static int libc_dup2(int oldfd, int newfd)
{
- swrap_bind_symbol_libc(dup2);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup2.f(oldfd, newfd);
}
#ifdef HAVE_EVENTFD
static int libc_eventfd(int count, int flags)
{
- swrap_bind_symbol_libc(eventfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_eventfd.f(count, flags);
}
void *arg;
int rc;
- swrap_bind_symbol_libc(fcntl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getpeername);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getpeername.f(sockfd, addr, addrlen);
}
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getsockname);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockname.f(sockfd, addr, addrlen);
}
void *optval,
socklen_t *optlen)
{
- swrap_bind_symbol_libsocket(getsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockopt.f(sockfd,
level,
void *arg;
int rc;
- swrap_bind_symbol_libc(ioctl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
static int libc_listen(int sockfd, int backlog)
{
- swrap_bind_symbol_libsocket(listen);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_listen.f(sockfd, backlog);
}
static FILE *libc_fopen(const char *name, const char *mode)
{
- swrap_bind_symbol_libc(fopen);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_fopen.f(name, mode);
}
#ifdef HAVE_FOPEN64
static FILE *libc_fopen64(const char *name, const char *mode)
{
- swrap_bind_symbol_libc(fopen64);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_fopen64.f(name, mode);
}
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open64);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
int mode = 0;
int fd;
- swrap_bind_symbol_libc(openat);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
static int libc_pipe(int pipefd[2])
{
- swrap_bind_symbol_libsocket(pipe);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_pipe.f(pipefd);
}
static int libc_read(int fd, void *buf, size_t count)
{
- swrap_bind_symbol_libc(read);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_read.f(fd, buf, count);
}
static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(readv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_readv.f(fd, iov, iovcnt);
}
static int libc_recv(int sockfd, void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(recv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recv.f(sockfd, buf, len, flags);
}
struct sockaddr *src_addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(recvfrom);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvfrom.f(sockfd,
buf,
static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(recvmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags);
}
static int libc_send(int sockfd, const void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(send);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_send.f(sockfd, buf, len, flags);
}
static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(sendmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags);
}
const struct sockaddr *dst_addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(sendto);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendto.f(sockfd,
buf,
const void *optval,
socklen_t optlen)
{
- swrap_bind_symbol_libsocket(setsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_setsockopt.f(sockfd,
level,
#ifdef HAVE_SIGNALFD
static int libc_signalfd(int fd, const sigset_t *mask, int flags)
{
- swrap_bind_symbol_libsocket(signalfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_signalfd.f(fd, mask, flags);
}
static int libc_socket(int domain, int type, int protocol)
{
- swrap_bind_symbol_libsocket(socket);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socket.f(domain, type, protocol);
}
static int libc_socketpair(int domain, int type, int protocol, int sv[2])
{
- swrap_bind_symbol_libsocket(socketpair);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socketpair.f(domain, type, protocol, sv);
}
#ifdef HAVE_TIMERFD_CREATE
static int libc_timerfd_create(int clockid, int flags)
{
- swrap_bind_symbol_libc(timerfd_create);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_timerfd_create.f(clockid, flags);
}
static ssize_t libc_write(int fd, const void *buf, size_t count)
{
- swrap_bind_symbol_libc(write);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_write.f(fd, buf, count);
}
static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(writev);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt);
}
/* DO NOT call this function during library initialization! */
-static void swrap_bind_symbol_all(void)
+static void __swrap_bind_symbol_all_once(void)
{
#ifdef HAVE_ACCEPT4
swrap_bind_symbol_libsocket(accept4);
swrap_bind_symbol_libsocket(writev);
}
+static void swrap_bind_symbol_all(void)
+{
+ static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&all_symbol_binding_once, __swrap_bind_symbol_all_once);
+}
+
/*********************************************************
* SWRAP HELPER FUNCTIONS
*********************************************************/
char *t;
bool ok;
- if (s == NULL) {
+ if (s == NULL || s[0] == '\0') {
SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set");
return NULL;
}
swrap_dir = realpath(s, NULL);
if (swrap_dir == NULL) {
SWRAP_LOG(SWRAP_LOG_ERROR,
- "Unable to resolve socket_wrapper dir path: %s",
+ "Unable to resolve socket_wrapper dir path: %s - %s",
+ s,
strerror(errno));
abort();
}
return max_mtu;
}
-static int socket_wrapper_init_mutex(pthread_mutex_t *m)
+static int _socket_wrapper_init_mutex(pthread_mutex_t *m, const char *name)
{
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);
+ bool need_destroy = false;
+ int ret = 0;
+
+#define __CHECK(cmd) do { \
+ ret = cmd; \
+ if (ret != 0) { \
+ SWRAP_LOG(SWRAP_LOG_ERROR, \
+ "%s: %s - failed %d", \
+ name, #cmd, ret); \
+ goto done; \
+ } \
+} while(0)
+ *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+ __CHECK(pthread_mutexattr_init(&ma));
+ need_destroy = true;
+ __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
+ __CHECK(pthread_mutex_init(m, &ma));
done:
- pthread_mutexattr_destroy(&ma);
-
+ if (need_destroy) {
+ pthread_mutexattr_destroy(&ma);
+ }
return ret;
}
{
size_t max_sockets;
size_t i;
- int ret;
+ int ret = 0;
+
+ swrap_bind_symbol_all();
swrap_mutex_lock(&sockets_mutex);
for (i = 0; i < max_sockets; i++) {
swrap_set_next_free(&sockets[i].info, i+1);
+ sockets[i].meta.mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+ }
+
+ for (i = 0; i < max_sockets; i++) {
ret = socket_wrapper_init_mutex(&sockets[i].meta.mutex);
if (ret != 0) {
SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
+ "Failed to initialize pthread mutex i=%zu", i);
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;
- }
-
- 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);
swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
}
break;
+#ifdef FIONWRITE
+ case FIONWRITE:
+ /* this is FreeBSD */
+ FALL_THROUGH; /* to TIOCOUTQ */
+#endif /* FIONWRITE */
+ case TIOCOUTQ: /* same as SIOCOUTQ on Linux */
+ /*
+ * This may return more bytes then the application
+ * sent into the socket, for tcp it should
+ * return the number of unacked bytes.
+ *
+ * On AF_UNIX, all bytes are immediately acked!
+ */
+ if (rc == 0) {
+ value_ptr = ((int *)va_arg(ap, int *));
+ *value_ptr = 0;
+ }
+ break;
}
va_end(ap);
static void swrap_thread_child(void)
{
- SWRAP_UNLOCK_ALL;
+ SWRAP_REINIT_ALL;
}
/****************************
***************************/
void swrap_constructor(void)
{
- int ret;
+ SWRAP_REINIT_ALL;
/*
* If we hold a lock and the application forks, then the child
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);
- }
}
/****************************