10 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
22 static int setup_echo_srv_tcp_ipv4(void **state)
24 torture_setup_echo_srv_tcp_ipv4(state);
29 static int teardown(void **state)
31 torture_teardown_echo_srv(state);
38 struct torture_address sock_addr;
39 struct torture_address peer_addr;
42 static int test_fill_test_fd(struct test_fd *tfd, int fd)
44 struct torture_address saddr = {
45 .sa_socklen = sizeof(struct sockaddr_storage),
47 struct torture_address paddr = {
48 .sa_socklen = sizeof(struct sockaddr_storage),
52 *tfd = (struct test_fd) { .fd = fd, };
54 ret = getsockname(fd, &saddr.sa.s, &saddr.sa_socklen);
55 if (ret == -1 && errno == ENOTSOCK) {
62 ret = getpeername(fd, &paddr.sa.s, &paddr.sa_socklen);
67 tfd->sock_addr = saddr;
68 tfd->peer_addr = paddr;
72 static void _assert_torture_address_equal(const struct torture_address *ga,
73 const struct torture_address *ea,
74 const char * const file,
77 _assert_int_equal(ga->sa_socklen, ea->sa_socklen, file, line);
78 if (ga->sa_socklen == 0) {
81 _assert_memory_equal(&ga->sa, &ea->sa, ga->sa_socklen, file, line);
84 #define assert_test_fd_equal(gfd, efd) \
85 _assert_test_fd_equal(gfd, efd, __FILE__, __LINE__)
87 static void _assert_test_fd_equal(const struct test_fd *gfd,
88 const struct test_fd *efd,
89 const char * const file,
93 _assert_int_equal(gfd->fd, -1, file, line);
97 _assert_int_not_equal(gfd->fd, -1, file, line);
99 _assert_torture_address_equal(&gfd->sock_addr, &efd->sock_addr, file, line);
100 _assert_torture_address_equal(&gfd->peer_addr, &efd->peer_addr, file, line);
103 static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds)
105 struct test_fd tfds[num_fds];
108 int child_fd, parent_fd;
112 for (idx = 0; idx < num_fds; idx++) {
113 rc = test_fill_test_fd(&tfds[idx], fds[idx]);
114 assert_int_equal(rc, 0);
117 /* create unix domain socket stream */
118 rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
119 assert_int_not_equal(rc, -1);
125 assert_int_not_equal(pid, -1);
129 struct msghdr child_msg;
130 int recv_fd_array[num_fds];
131 char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)];
132 struct cmsghdr *cmsg;
137 iov.iov_base = &byte;
140 memset(&child_msg, 0, sizeof(child_msg));
141 child_msg.msg_iov = &iov;
142 child_msg.msg_iovlen = 1;
143 child_msg.msg_control = cmsgbuf;
144 child_msg.msg_controllen = sizeof(cmsgbuf);
146 rc = recvmsg(child_fd, &child_msg, 0);
147 assert_int_equal(rc, iov.iov_len);
148 assert_int_equal(byte, '!');
150 cmsg = CMSG_FIRSTHDR(&child_msg);
151 assert_non_null(cmsg);
152 assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS);
154 memcpy(recv_fd_array, CMSG_DATA(cmsg), sizeof(int)*num_fds);
155 for (idx = 0; idx < num_fds; idx++) {
156 assert_int_not_equal(recv_fd_array[idx], -1);
159 for (idx = 0; idx < num_fds; idx++) {
160 struct test_fd recv_tfd = { .fd = -1, };
162 ret = test_fill_test_fd(&recv_tfd, recv_fd_array[idx]);
163 assert_int_equal(ret, 0);
165 assert_test_fd_equal(&recv_tfd, &tfds[idx]);
168 for (idx = 0; idx < num_fds; idx++) {
169 int recv_fd = recv_fd_array[idx];
170 char send_buf[64] = {0,};
171 char recv_buf[64] = {0,};
173 if (tfds[idx].sock_addr.sa_socklen == 0) {
175 * skip fds not belonging to
181 snprintf(send_buf, sizeof(send_buf), "packet");
186 assert_int_not_equal(ret, -1);
191 assert_int_not_equal(ret, -1);
193 assert_memory_equal(send_buf, recv_buf, sizeof(send_buf));
199 struct msghdr parent_msg;
200 struct cmsghdr *cmsg;
201 char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)];
202 int pass_fd_array[num_fds];
207 for (idx = 0; idx < num_fds; idx++) {
208 pass_fd_array[idx] = tfds[idx].fd;
211 iov.iov_base = &byte;
214 memset(&parent_msg, 0, sizeof(parent_msg));
215 parent_msg.msg_iov = &iov;
216 parent_msg.msg_iovlen = 1;
217 parent_msg.msg_control = cmsgbuf;
218 parent_msg.msg_controllen = sizeof(cmsgbuf);
220 cmsg = CMSG_FIRSTHDR(&parent_msg);
221 cmsg->cmsg_level = SOL_SOCKET;
222 cmsg->cmsg_type = SCM_RIGHTS;
223 cmsg->cmsg_len = CMSG_LEN(sizeof(int)*num_fds);
225 /* place previously connected socket fd as ancillary data */
226 memcpy(CMSG_DATA(cmsg), pass_fd_array, sizeof(int)*num_fds);
227 parent_msg.msg_controllen = cmsg->cmsg_len;
229 rc = sendmsg(parent_fd, &parent_msg, 0);
230 assert_int_not_equal(rc, -1);
232 alarm(5); /* 5 seconds timeout for the child */
233 waitpid(pid, &cs, 0);
235 assert_int_equal(WEXITSTATUS(cs), 0);
240 static void test_tcp_sendmsg_recvmsg_fd_same(size_t num_fds)
242 struct torture_address addr = {
243 .sa_socklen = sizeof(struct sockaddr_in),
246 int fd_array[num_fds];
250 /* create socket file descriptor to be passed */
251 pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
252 assert_int_not_equal(pass_sock_fd, -1);
254 addr.sa.in.sin_family = AF_INET;
255 addr.sa.in.sin_port = htons(torture_server_port());
257 rc = inet_pton(addr.sa.in.sin_family,
258 torture_server_address(AF_INET),
259 &addr.sa.in.sin_addr);
260 assert_int_equal(rc, 1);
262 rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen);
263 assert_int_equal(rc, 0);
265 for (idx = 0; idx < num_fds; idx++) {
266 fd_array[idx] = pass_sock_fd;
269 test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds);
274 static void test_tcp_sendmsg_recvmsg_fd_1(void **state)
276 (void) state; /* unused */
277 test_tcp_sendmsg_recvmsg_fd_same(1);
280 static void test_tcp_sendmsg_recvmsg_fd_2s(void **state)
282 (void) state; /* unused */
283 test_tcp_sendmsg_recvmsg_fd_same(2);
286 static void test_tcp_sendmsg_recvmsg_fd_3s(void **state)
288 (void) state; /* unused */
289 test_tcp_sendmsg_recvmsg_fd_same(3);
292 static void test_tcp_sendmsg_recvmsg_fd_4s(void **state)
294 (void) state; /* unused */
295 test_tcp_sendmsg_recvmsg_fd_same(4);
298 static void test_tcp_sendmsg_recvmsg_fd_5s(void **state)
300 (void) state; /* unused */
301 test_tcp_sendmsg_recvmsg_fd_same(5);
304 static void test_tcp_sendmsg_recvmsg_fd_6s(void **state)
306 (void) state; /* unused */
307 test_tcp_sendmsg_recvmsg_fd_same(6);
310 static void test_tcp_sendmsg_recvmsg_fd_different(size_t num_fds)
312 int fd_array[num_fds];
315 for (idx = 0; idx < num_fds; idx++) {
316 struct torture_address addr = {
317 .sa_socklen = sizeof(struct sockaddr_in),
322 /* create socket file descriptor to be passed */
323 pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
324 assert_int_not_equal(pass_sock_fd, -1);
326 addr.sa.in.sin_family = AF_INET;
327 addr.sa.in.sin_port = htons(torture_server_port());
329 rc = inet_pton(addr.sa.in.sin_family,
330 torture_server_address(AF_INET),
331 &addr.sa.in.sin_addr);
332 assert_int_equal(rc, 1);
334 rc = connect(pass_sock_fd, &addr.sa.s, addr.sa_socklen);
335 assert_int_equal(rc, 0);
337 fd_array[idx] = pass_sock_fd;
340 test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds);
342 for (idx = 0; idx < num_fds; idx++) {
343 close(fd_array[idx]);
347 static void test_tcp_sendmsg_recvmsg_fd_2d(void **state)
349 (void) state; /* unused */
350 test_tcp_sendmsg_recvmsg_fd_different(2);
353 static void test_tcp_sendmsg_recvmsg_fd_3d(void **state)
355 (void) state; /* unused */
356 test_tcp_sendmsg_recvmsg_fd_different(3);
359 static void test_tcp_sendmsg_recvmsg_fd_4d(void **state)
361 (void) state; /* unused */
362 test_tcp_sendmsg_recvmsg_fd_different(4);
365 static void test_tcp_sendmsg_recvmsg_fd_5d(void **state)
367 (void) state; /* unused */
368 test_tcp_sendmsg_recvmsg_fd_different(5);
371 static void test_tcp_sendmsg_recvmsg_fd_6d(void **state)
373 (void) state; /* unused */
374 test_tcp_sendmsg_recvmsg_fd_different(6);
380 const struct CMUnitTest tests[] = {
381 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1,
382 setup_echo_srv_tcp_ipv4,
384 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2s,
385 setup_echo_srv_tcp_ipv4,
387 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3s,
388 setup_echo_srv_tcp_ipv4,
390 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4s,
391 setup_echo_srv_tcp_ipv4,
393 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5s,
394 setup_echo_srv_tcp_ipv4,
396 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6s,
397 setup_echo_srv_tcp_ipv4,
399 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2d,
400 setup_echo_srv_tcp_ipv4,
402 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3d,
403 setup_echo_srv_tcp_ipv4,
405 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4d,
406 setup_echo_srv_tcp_ipv4,
408 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5d,
409 setup_echo_srv_tcp_ipv4,
411 cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6d,
412 setup_echo_srv_tcp_ipv4,
416 rc = cmocka_run_group_tests(tests, NULL, NULL);