[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