test_echo_tcp_sendmsg_recvmsg_fd: split out test_tcp_sendmsg_recvmsg_fd_array()
authorStefan Metzmacher <metze@samba.org>
Thu, 4 Feb 2021 16:04:30 +0000 (17:04 +0100)
committerAndreas Schneider <asn@samba.org>
Mon, 8 Feb 2021 18:29:57 +0000 (19:29 +0100)
This will allow us to test more combinations in order to
get better coverage. For now we just test a single fd.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
tests/test_echo_tcp_sendmsg_recvmsg_fd.c

index 8ae1a608d7864ea090471fc681d57933af618a88..b0156c9fd81cfd23489a6f7bd265a756b5dc310b 100644 (file)
@@ -33,33 +33,86 @@ static int teardown(void **state)
        return 0;
 }
 
-static void test_tcp_sendmsg_recvmsg_fd(void **state)
+struct test_fd {
+       int fd;
+       struct torture_address sock_addr;
+       struct torture_address peer_addr;
+};
+
+static int test_fill_test_fd(struct test_fd *tfd, int fd)
 {
-       struct torture_address addr = {
-               .sa_socklen = sizeof(struct sockaddr_in),
+       struct torture_address saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
        };
-       int pass_sock_fd;
-       int sv[2];
-       int child_fd, parent_fd;
-       pid_t pid;
-       int rc;
+       struct torture_address paddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
+       int ret;
 
-       (void) state; /* unused */
+       *tfd = (struct test_fd) { .fd = fd, };
 
-       /* create socket file descriptor to be passed */
-       pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       assert_int_not_equal(pass_sock_fd, -1);
+       ret = getsockname(fd, &saddr.sa.s, &saddr.sa_socklen);
+       if (ret == -1 && errno == ENOTSOCK) {
+               return 0;
+       }
+       if (ret == -1) {
+               return ret;
+       }
 
-       addr.sa.in.sin_family = AF_INET;
-       addr.sa.in.sin_port = htons(torture_server_port());
+       ret = getpeername(fd, &paddr.sa.s, &paddr.sa_socklen);
+       if (ret == -1) {
+               return ret;
+       }
 
-       rc = inet_pton(addr.sa.in.sin_family,
-                      torture_server_address(AF_INET),
-                      &addr.sa.in.sin_addr);
-       assert_int_equal(rc, 1);
+       tfd->sock_addr = saddr;
+       tfd->peer_addr = paddr;
+       return 0;
+}
 
-       rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen);
-       assert_int_equal(rc, 0);
+static void _assert_torture_address_equal(const struct torture_address *ga,
+                                         const struct torture_address *ea,
+                                         const char * const file,
+                                         const int line)
+{
+       _assert_int_equal(ga->sa_socklen, ea->sa_socklen, file, line);
+       if (ga->sa_socklen == 0) {
+               return;
+       }
+       _assert_memory_equal(&ga->sa, &ea->sa, ga->sa_socklen, file, line);
+}
+
+#define assert_test_fd_equal(gfd, efd) \
+       _assert_test_fd_equal(gfd, efd, __FILE__, __LINE__)
+
+static void _assert_test_fd_equal(const struct test_fd *gfd,
+                                 const struct test_fd *efd,
+                                 const char * const file,
+                                 const int line)
+{
+       if (efd->fd == -1) {
+               _assert_int_equal(gfd->fd, -1, file, line);
+               return;
+       }
+
+       _assert_int_not_equal(gfd->fd, -1, file, line);
+
+       _assert_torture_address_equal(&gfd->sock_addr, &efd->sock_addr, file, line);
+       _assert_torture_address_equal(&gfd->peer_addr, &efd->peer_addr, file, line);
+}
+
+static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds)
+{
+       struct test_fd tfds[num_fds];
+       size_t idx;
+       int sv[2];
+       int child_fd, parent_fd;
+       pid_t pid;
+       int rc;
+
+       for (idx = 0; idx < num_fds; idx++) {
+               rc = test_fill_test_fd(&tfds[idx], fds[idx]);
+               assert_int_equal(rc, 0);
+       }
 
        /* create unix domain socket stream */
        rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
@@ -73,17 +126,11 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state)
 
        if (pid == 0) {
                /* Child */
-               struct torture_address peer_addr = {
-                       .sa_socklen = sizeof(struct sockaddr_in),
-               };
                struct msghdr child_msg;
-               char cmsgbuf[CMSG_SPACE(sizeof(int))];
+               int recv_fd_array[num_fds];
+               char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)];
                struct cmsghdr *cmsg;
-               int rcv_sock_fd, port;
                ssize_t ret;
-               char send_buf[64] = {0};
-               char recv_buf[64] = {0};
-               char ipstr[INET_ADDRSTRLEN];
                char byte = { 0, };
                struct iovec iov;
 
@@ -104,45 +151,62 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state)
                assert_non_null(cmsg);
                assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS);
 
-               memcpy(&rcv_sock_fd, CMSG_DATA(cmsg), sizeof(rcv_sock_fd));
-               assert_int_not_equal(rcv_sock_fd, -1);
+               memcpy(recv_fd_array, CMSG_DATA(cmsg), sizeof(int)*num_fds);
+               for (idx = 0; idx < num_fds; idx++) {
+                       assert_int_not_equal(recv_fd_array[idx], -1);
+               }
 
-               /* extract peer info from received socket fd */
-               ret = getpeername(rcv_sock_fd, &peer_addr.sa.s, &peer_addr.sa_socklen);
-               assert_int_not_equal(ret, -1);
+               for (idx = 0; idx < num_fds; idx++) {
+                       struct test_fd recv_tfd = { .fd = -1, };
 
-               port = ntohs(peer_addr.sa.in.sin_port);
-               inet_ntop(AF_INET, &peer_addr.sa.in.sin_addr, ipstr, sizeof(ipstr));
+                       ret = test_fill_test_fd(&recv_tfd, recv_fd_array[idx]);
+                       assert_int_equal(ret, 0);
 
-               /* check whether it is the same socket previously connected */
-               assert_string_equal(ipstr, torture_server_address(AF_INET));
-               assert_int_equal(port, torture_server_port());
+                       assert_test_fd_equal(&recv_tfd, &tfds[idx]);
+               }
 
-               snprintf(send_buf, sizeof(send_buf), "packet");
+               for (idx = 0; idx < num_fds; idx++) {
+                       int recv_fd = recv_fd_array[idx];
+                       char send_buf[64] = {0,};
+                       char recv_buf[64] = {0,};
 
-               ret = write(rcv_sock_fd,
-                           send_buf,
-                           sizeof(send_buf));
-               assert_int_not_equal(ret, -1);
+                       if (tfds[idx].sock_addr.sa_socklen == 0) {
+                               /*
+                                * skip fds not belonging to
+                                * a socket.
+                                */
+                               continue;
+                       }
 
-               ret = read(rcv_sock_fd,
-                          recv_buf,
-                          sizeof(recv_buf));
-               assert_int_not_equal(ret, -1);
+                       snprintf(send_buf, sizeof(send_buf), "packet");
 
-               assert_memory_equal(send_buf, recv_buf, sizeof(send_buf));
+                       ret = write(recv_fd,
+                                   send_buf,
+                                   sizeof(send_buf));
+                       assert_int_not_equal(ret, -1);
+
+                       ret = read(recv_fd,
+                                  recv_buf,
+                                  sizeof(recv_buf));
+                       assert_int_not_equal(ret, -1);
+
+                       assert_memory_equal(send_buf, recv_buf, sizeof(send_buf));
+               }
 
                exit(0);
        } else {
                /* Parent */
                struct msghdr parent_msg;
                struct cmsghdr *cmsg;
-               char cmsgbuf[CMSG_SPACE(sizeof(pass_sock_fd))];
+               char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)];
+               int pass_fd_array[num_fds];
                char byte = '!';
                struct iovec iov;
                int cs;
 
-               (void) state; /* unused */
+               for (idx = 0; idx < num_fds; idx++) {
+                       pass_fd_array[idx] = tfds[idx].fd;
+               }
 
                iov.iov_base = &byte;
                iov.iov_len = 1;
@@ -156,10 +220,10 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state)
                cmsg = CMSG_FIRSTHDR(&parent_msg);
                cmsg->cmsg_level = SOL_SOCKET;
                cmsg->cmsg_type = SCM_RIGHTS;
-               cmsg->cmsg_len = CMSG_LEN(sizeof(pass_sock_fd));
+               cmsg->cmsg_len = CMSG_LEN(sizeof(int)*num_fds);
 
                /* place previously connected socket fd as ancillary data */
-               memcpy(CMSG_DATA(cmsg), &pass_sock_fd, sizeof(pass_sock_fd));
+               memcpy(CMSG_DATA(cmsg), pass_fd_array, sizeof(int)*num_fds);
                parent_msg.msg_controllen = cmsg->cmsg_len;
 
                rc = sendmsg(parent_fd, &parent_msg, 0);
@@ -173,11 +237,39 @@ static void test_tcp_sendmsg_recvmsg_fd(void **state)
        }
 }
 
+static void test_tcp_sendmsg_recvmsg_fd_1(void **state)
+{
+       struct torture_address addr = {
+               .sa_socklen = sizeof(struct sockaddr_in),
+       };
+       int pass_sock_fd;
+       int rc;
+
+       (void) state; /* unused */
+
+       /* create socket file descriptor to be passed */
+       pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       assert_int_not_equal(pass_sock_fd, -1);
+
+       addr.sa.in.sin_family = AF_INET;
+       addr.sa.in.sin_port = htons(torture_server_port());
+
+       rc = inet_pton(addr.sa.in.sin_family,
+                      torture_server_address(AF_INET),
+                      &addr.sa.in.sin_addr);
+       assert_int_equal(rc, 1);
+
+       rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen);
+       assert_int_equal(rc, 0);
+
+       test_tcp_sendmsg_recvmsg_fd_array(&pass_sock_fd, 1);
+}
+
 int main(void) {
        int rc;
 
        const struct CMUnitTest tests[] = {
-               cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd,
+               cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1,
                                 setup_echo_srv_tcp_ipv4,
                                 teardown)
        };