cmake: Export cmake config for socket_wrapper_noop
[socket_wrapper.git] / tests / test_sendmsg_recvmsg_fd.c
1 #include <stdarg.h>
2 #include <stddef.h>
3 #include <setjmp.h>
4 #include <cmocka.h>
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/wait.h>
9
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16
17 static void test_sendmsg_recvmsg_fd(void **state)
18 {
19         int sv[2];
20         int child_fd, parent_fd;
21         int rc;
22         pid_t pid;
23
24         (void) state; /* unused */
25
26         rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
27         assert_int_not_equal(rc, -1);
28
29         parent_fd = sv[0];
30         child_fd = sv[1];
31
32         pid = fork();
33         assert_int_not_equal(pid, -1);
34
35         if (pid == 0) {
36                 /* Child */
37                 struct msghdr child_msg;
38                 char cmsgbuf[CMSG_SPACE(sizeof(int))];
39                 struct cmsghdr *cmsg;
40                 int rcv_fd;
41                 char buf[8];
42                 int i;
43
44                 memset(&child_msg, 0, sizeof(child_msg));
45                 child_msg.msg_control = cmsgbuf;
46                 child_msg.msg_controllen = sizeof(cmsgbuf);
47
48                 do {
49                         errno = 0;
50                         rc = recvmsg(child_fd, &child_msg, 0);
51                 } while (errno == EAGAIN || errno == EWOULDBLOCK);
52                 assert_int_not_equal(rc, -1);
53
54                 cmsg = CMSG_FIRSTHDR(&child_msg);
55                 assert_non_null(cmsg);
56                 assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS);
57
58                 memcpy(&rcv_fd, CMSG_DATA(cmsg), sizeof(rcv_fd));
59                 assert_int_not_equal(rcv_fd, -1);
60
61                 rc = read(rcv_fd, buf, sizeof(buf));
62                 assert_int_not_equal(rc, -1);
63                 for (i = 0; i < 8; i++) {
64                         assert_int_equal(buf[i], 0);
65                 }
66                 exit(0);
67         } else {
68                 /* Parent */
69                 int pass_fd;
70                 struct msghdr parent_msg;
71                 struct cmsghdr *cmsg;
72                 char cmsgbuf[CMSG_SPACE(sizeof(pass_fd))];
73                 char byte = '!';
74                 struct iovec iov;
75                 int cs;
76
77                 pass_fd = open("/dev/zero", O_RDONLY);
78                 assert_int_not_equal(pass_fd, -1);
79
80                 iov.iov_base = &byte;
81                 iov.iov_len = 1;
82
83                 memset(&parent_msg, 0, sizeof(parent_msg));
84                 parent_msg.msg_iov = &iov;
85                 parent_msg.msg_iovlen = 1;
86                 parent_msg.msg_control = cmsgbuf;
87                 parent_msg.msg_controllen = sizeof(cmsgbuf);
88
89                 cmsg = CMSG_FIRSTHDR(&parent_msg);
90                 cmsg->cmsg_level = SOL_SOCKET;
91                 cmsg->cmsg_type = SCM_RIGHTS;
92                 cmsg->cmsg_len = CMSG_LEN(sizeof(pass_fd));
93
94                 memcpy(CMSG_DATA(cmsg), &pass_fd, sizeof(pass_fd));
95                 parent_msg.msg_controllen = cmsg->cmsg_len;
96
97                 rc = sendmsg(parent_fd, &parent_msg, 0);
98                 assert_int_not_equal(rc, -1);
99
100                 alarm(5);           /* 5 seconds timeout for the child */
101                 rc = waitpid(pid, &cs, 0);
102                 assert_int_not_equal(rc, -1);
103         }
104 }
105
106 int main(void) {
107         int rc;
108
109         const struct CMUnitTest tests[] = {
110                 cmocka_unit_test(test_sendmsg_recvmsg_fd),
111         };
112
113         rc = cmocka_run_group_tests(tests, NULL, NULL);
114
115         return rc;
116 }