[SCM] Socket Wrapper Repository - branch master updated

Andreas Schneider asn at samba.org
Thu May 8 08:01:40 MDT 2014


The branch, master has been updated
       via  b37783b tests: Add test to verify that the binded iface address is correct.
       via  06934c6 swrap: Correctly set the bind iface address on connect().
       via  0fa5690 swrap: use LIBC_SO from GNU libc, if available
      from  3d70059 Bump version to 1.0.2.

http://gitweb.samba.org/?p=socket_wrapper.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit b37783b6a6503b84363877023cb37618e7504d56
Author: Andreas Schneider <asn at samba.org>
Date:   Tue Apr 15 14:11:06 2014 +0200

    tests: Add test to verify that the binded iface address is correct.
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 06934c6f763a3cb12be6e02ba0823ce28534128d
Author: Andreas Schneider <asn at samba.org>
Date:   Wed May 7 18:31:00 2014 +0200

    swrap: Correctly set the bind iface address on connect().
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 0fa56909442c3cfea6a697681ea0e89ba5a0aa0f
Author: Pino Toscano <toscano.pino at tiscali.it>
Date:   Thu May 8 13:37:02 2014 +0200

    swrap: use LIBC_SO from GNU libc, if available
    
    Look for gnu/lib-names.h and use the LIBC_SO define to dlopen libc, so
    the right library is loaded without manually searching for libc.so.N.
    
    Signed-off-by: Pino Toscano <toscano.pino at tiscali.it>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 ConfigureChecks.cmake                    |    1 +
 config.h.cmake                           |    1 +
 src/socket_wrapper.c                     |   65 ++++++
 tests/CMakeLists.txt                     |    1 +
 tests/test_echo_tcp_get_peer_sock_name.c |  355 ++++++++++++++++++++++++++++++
 5 files changed, 423 insertions(+), 0 deletions(-)
 create mode 100644 tests/test_echo_tcp_get_peer_sock_name.c


Changeset truncated at 500 lines:

diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index c05cbb9..8db5162 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -51,6 +51,7 @@ check_include_file(sys/filio.h HAVE_SYS_FILIO_H)
 check_include_file(sys/signalfd.h HAVE_SYS_SIGNALFD_H)
 check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H)
 check_include_file(sys/timerfd.h HAVE_SYS_TIMERFD_H)
+check_include_file(gnu/lib-names.h HAVE_GNU_LIB_NAMES_H)
 
 # FUNCTIONS
 check_function_exists(strncpy HAVE_STRNCPY)
diff --git a/config.h.cmake b/config.h.cmake
index abbf133..efa519b 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -18,6 +18,7 @@
 #cmakedefine HAVE_SYS_SIGNALFD_H 1
 #cmakedefine HAVE_SYS_EVENTFD_H 1
 #cmakedefine HAVE_SYS_TIMERFD_H 1
+#cmakedefine HAVE_GNU_LIB_NAMES_H 1
 
 /************************ STRUCT MEMBERS *************************/
 
diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c
index 95643aa..4bca746 100644
--- a/src/socket_wrapper.c
+++ b/src/socket_wrapper.c
@@ -73,6 +73,9 @@
 #include <stdarg.h>
 #include <stdbool.h>
 #include <unistd.h>
+#ifdef HAVE_GNU_LIB_NAMES_H
+#include <gnu/lib-names.h>
+#endif
 
 enum swrap_dbglvl_e {
 	SWRAP_LOG_ERROR = 0,
@@ -199,6 +202,9 @@ struct socket_info
 
 	char *tmp_path;
 
+	struct sockaddr *bindname;
+	socklen_t bindname_len;
+
 	struct sockaddr *myname;
 	socklen_t myname_len;
 
@@ -418,6 +424,11 @@ static void *swrap_load_lib_handle(enum swrap_lib lib)
 		/* FALL TROUGH */
 	case SWRAP_LIBC:
 		handle = swrap.libc_handle;
+#ifdef LIBC_SO
+		if (handle == NULL) {
+			handle = dlopen(LIBC_SO, flags);
+		}
+#endif
 		if (handle == NULL) {
 			for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
 				char soname[256] = {0};
@@ -1099,6 +1110,21 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
 			errno = EADDRNOTAVAIL;
 			return -1;
 		}
+
+		/* Store the bind address for connect() */
+		if (si->bindname == NULL) {
+			struct sockaddr_in bind_in;
+			socklen_t blen = sizeof(struct sockaddr_in);
+
+			ZERO_STRUCT(bind_in);
+			bind_in.sin_family = in->sin_family;
+			bind_in.sin_port = in->sin_port;
+			bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface);
+
+			si->bindname = sockaddr_dup(&bind_in, blen);
+			si->bindname_len = blen;
+		}
+
 		break;
 	}
 #ifdef HAVE_IPV6
@@ -1136,6 +1162,22 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
 			return -1;
 		}
 
+		/* Store the bind address for connect() */
+		if (si->bindname == NULL) {
+			struct sockaddr_in6 bind_in;
+			socklen_t blen = sizeof(struct sockaddr_in6);
+
+			ZERO_STRUCT(bind_in);
+			bind_in.sin6_family = in->sin6_family;
+			bind_in.sin6_port = in->sin6_port;
+
+			bind_in.sin6_addr = *swrap_ipv6();
+			bind_in.sin6_addr.s6_addr[15] = iface;
+
+			si->bindname = sockaddr_dup(&bind_in, blen);
+			si->bindname_len = blen;
+		}
+
 		break;
 	}
 #endif
@@ -1161,6 +1203,8 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
 			if (stat(un->sun_path, &st) == 0) continue;
 
 			set_port(si->family, prt, si->myname);
+			set_port(si->family, prt, si->bindname);
+
 			break;
 		}
 		if (prt == 10000) {
@@ -2575,6 +2619,23 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
 		si->peername = sockaddr_dup(serv_addr, addrlen);
 		si->connected = 1;
 
+		/*
+		 * When we connect() on a socket than we have to bind the
+		 * outgoing connection on the interface we use for the
+		 * transport. We already bound it on the right interface
+		 * but here we have to update the name so getsockname()
+		 * returns correct information.
+		 */
+		if (si->bindname != NULL) {
+			free(si->myname);
+
+			si->myname = si->bindname;
+			si->myname_len = si->bindname_len;
+
+			si->bindname = NULL;
+			si->bindname_len = 0;
+		}
+
 		swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
 		swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
 	} else {
@@ -3918,6 +3979,10 @@ static int swrap_close(int fd)
 		swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
 	}
 
+	if (si->bindname != NULL) {
+		free(si->bindname);
+	}
+
 	if (si->myname) free(si->myname);
 	if (si->peername) free(si->peername);
 	if (si->tmp_path) {
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 988e60f..94e92c1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -23,6 +23,7 @@ set(SWRAP_TESTS
     test_echo_tcp_socket_options
     test_echo_tcp_write_read
     test_echo_tcp_writev_readv
+    test_echo_tcp_get_peer_sock_name
     test_echo_udp_sendto_recvfrom
     test_echo_udp_send_recv
     test_echo_udp_sendmsg_recvmsg)
diff --git a/tests/test_echo_tcp_get_peer_sock_name.c b/tests/test_echo_tcp_get_peer_sock_name.c
new file mode 100644
index 0000000..9be7a4b
--- /dev/null
+++ b/tests/test_echo_tcp_get_peer_sock_name.c
@@ -0,0 +1,355 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "config.h"
+#include "torture.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void setup_echo_srv_tcp_ipv4(void **state)
+{
+	torture_setup_echo_srv_tcp_ipv4(state);
+	setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "20", 1);
+}
+
+static void teardown(void **state)
+{
+	torture_teardown_echo_srv(state);
+}
+
+static void _assert_sockaddr_equal(struct sockaddr_storage *ss, const char *a,
+				   const char * const file, const int line)
+{
+	char ip[INET6_ADDRSTRLEN] = { 0 };
+	struct sockaddr_in *sinp = (struct sockaddr_in *)ss;
+	const char *p;
+
+	p = inet_ntop(ss->ss_family,
+		      &sinp->sin_addr,
+		      ip,
+		      sizeof(ip));
+	assert_non_null(p);
+
+	_assert_string_equal(ip, a, file, line);
+}
+
+#define assert_sockaddr_equal(ss, a) \
+	_assert_sockaddr_equal(ss, a, __FILE__, __LINE__)
+
+static void _assert_sockaddr_port_equal(struct sockaddr_storage *ss, const char *a,
+					uint16_t port,
+					const char * const file, const int line)
+{
+	struct sockaddr_in *sinp = (struct sockaddr_in *)ss;
+
+	_assert_sockaddr_equal(ss, a, file, line);
+
+	_assert_int_equal(ntohs(sinp->sin_port), port, file, line);
+}
+
+#define assert_sockaddr_port_equal(ss, a, prt) \
+	_assert_sockaddr_port_equal(ss, a, prt, __FILE__, __LINE__)
+
+static void _assert_sockaddr_port_range_equal(struct sockaddr_storage *ss, const char *a,
+					      uint16_t min_port, uint16_t max_port,
+					      const char * const file, const int line)
+{
+	struct sockaddr_in *sinp = (struct sockaddr_in *)ss;
+
+	_assert_sockaddr_equal(ss, a, file, line);
+
+	_assert_in_range(ntohs(sinp->sin_port),
+			 min_port,
+			 max_port,
+			 file,
+			 line);
+}
+
+#define assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt) \
+	_assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt, __FILE__, __LINE__)
+
+static void test_connect_getsockname_getpeername(void **state)
+{
+	struct sockaddr_in sin;
+	socklen_t slen = sizeof(struct sockaddr_in);
+	struct sockaddr_storage cli_ss1;
+	socklen_t cli_ss1_len;
+	struct sockaddr_storage srv_ss1;
+	socklen_t srv_ss1_len;
+	int rc;
+	int s;
+
+	(void) state; /* unused */
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	assert_return_code(s, errno);
+
+	/* Bind client address to wildcard address */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+
+	rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr);
+	assert_int_equal(rc, 1);
+
+	rc = bind(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOTCONN);
+
+	/* connect */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(torture_server_port());
+	rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
+	assert_int_equal(rc, 1);
+
+	/* Connect */
+	rc = connect(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7);
+
+	close(s);
+}
+
+static void test_connect_getsockname_getpeername_port(void **state)
+{
+	struct sockaddr_in sin;
+	socklen_t slen = sizeof(struct sockaddr_in);
+	struct sockaddr_storage cli_ss1;
+	socklen_t cli_ss1_len;
+	struct sockaddr_storage srv_ss1;
+	socklen_t srv_ss1_len;
+	int rc;
+	int s;
+
+	(void) state; /* unused */
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	assert_return_code(s, errno);
+
+	/* Bind client address to wildcard address */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+
+	rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr);
+	assert_int_equal(rc, 1);
+	sin.sin_port = htons(12345);
+
+	rc = bind(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOTCONN);
+
+	/* connect */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(torture_server_port());
+	rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
+	assert_int_equal(rc, 1);
+
+	/* Connect */
+	rc = connect(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7);
+
+	close(s);
+}
+
+static void test_connect_getsockname_getpeername_any(void **state)
+{
+	struct sockaddr_in sin;
+	socklen_t slen = sizeof(struct sockaddr_in);
+	struct sockaddr_storage cli_ss1;
+	socklen_t cli_ss1_len;
+	struct sockaddr_storage srv_ss1;
+	socklen_t srv_ss1_len;
+	int rc;
+	int s;
+
+	(void) state; /* unused */
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	assert_return_code(s, errno);
+
+	/* Bind client address to wildcard address */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	rc = bind(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_range_equal(&cli_ss1, "0.0.0.0", 1024, 65535);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOTCONN);
+
+	/* connect */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(torture_server_port());
+	rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
+	assert_int_equal(rc, 1);
+
+	/* Connect */
+	rc = connect(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_range_equal(&cli_ss1, "127.0.0.20", 1024, 65535);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7);
+
+	close(s);
+}
+
+static void test_connect_getsockname_getpeername_any_port(void **state)
+{
+	struct sockaddr_in sin;
+	socklen_t slen = sizeof(struct sockaddr_in);
+	struct sockaddr_storage cli_ss1;
+	socklen_t cli_ss1_len;
+	struct sockaddr_storage srv_ss1;
+	socklen_t srv_ss1_len;
+	int rc;
+	int s;
+
+	(void) state; /* unused */
+
+	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	assert_return_code(s, errno);
+
+	/* Bind client address to wildcard address */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = htonl(INADDR_ANY);
+	sin.sin_port = htons(12345);
+
+	rc = bind(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&cli_ss1, "0.0.0.0", 12345);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_int_equal(rc, -1);
+	assert_int_equal(errno, ENOTCONN);
+
+	/* connect */
+	ZERO_STRUCT(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(torture_server_port());
+	rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
+	assert_int_equal(rc, 1);
+
+	/* Connect */
+	rc = connect(s, (struct sockaddr *)&sin, slen);
+	assert_return_code(rc, errno);
+
+	ZERO_STRUCT(cli_ss1);
+	cli_ss1_len = sizeof(cli_ss1);
+	rc = getsockname(s, (struct sockaddr *)&cli_ss1, &cli_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&cli_ss1, "127.0.0.20", 12345);
+
+	ZERO_STRUCT(srv_ss1);
+	srv_ss1_len = sizeof(srv_ss1);
+	rc = getpeername(s, (struct sockaddr *)&srv_ss1, &srv_ss1_len);
+	assert_return_code(rc, errno);
+	assert_sockaddr_port_equal(&srv_ss1, "127.0.0.10", 7);
+
+	close(s);
+}
+


-- 
Socket Wrapper Repository


More information about the samba-cvs mailing list