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 <a...@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 <a...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 06934c6f763a3cb12be6e02ba0823ce28534128d
Author: Andreas Schneider <a...@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 <a...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@samba.org>

commit 0fa56909442c3cfea6a697681ea0e89ba5a0aa0f
Author: Pino Toscano <toscano.p...@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.p...@tiscali.it>
    Reviewed-by: Andreas Schneider <a...@samba.org>
    Reviewed-by: Stefan Metzmacher <me...@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

Reply via email to