From: Stefan Metzmacher Date: Thu, 4 Feb 2021 16:04:30 +0000 (+0100) Subject: test_echo_tcp_sendmsg_recvmsg_fd: split out test_tcp_sendmsg_recvmsg_fd_array() X-Git-Tag: socket_wrapper-1.3.1~5 X-Git-Url: http://git.samba.org/?p=socket_wrapper.git;a=commitdiff_plain;h=cbd5910b1814cad1f1c4e9c9e8515f217edcd4d2 test_echo_tcp_sendmsg_recvmsg_fd: split out test_tcp_sendmsg_recvmsg_fd_array() 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 Reviewed-by: Andreas Schneider --- diff --git a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c index 8ae1a60..b0156c9 100644 --- a/tests/test_echo_tcp_sendmsg_recvmsg_fd.c +++ b/tests/test_echo_tcp_sendmsg_recvmsg_fd.c @@ -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) };