xref: /dragonfly/test/unix/passdesc/passdesc.c (revision 02b66c54)
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/stat.h>
4 #include <sys/un.h>
5 #include <sys/wait.h>
6 
7 #include <err.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #define TEST_FILENAME	"/tmp/passdesc"
15 
16 static void
17 test_send_desc(int s, int fd)
18 {
19 	struct msghdr msg;
20 	struct iovec iov;
21 	union {
22 		struct cmsghdr cm;
23 		uint8_t data[CMSG_SPACE(sizeof(int))];
24 	} ctrl;
25 	struct cmsghdr *cm;
26 	int n;
27 
28 	iov.iov_base = &fd;
29 	iov.iov_len = sizeof(fd);
30 
31 	memset(&msg, 0, sizeof(msg));
32 	msg.msg_iov = &iov;
33 	msg.msg_iovlen = 1;
34 	msg.msg_control = ctrl.data;
35 	msg.msg_controllen = sizeof(ctrl.data);
36 
37 	memset(&ctrl, 0, sizeof(ctrl));
38 	cm = CMSG_FIRSTHDR(&msg);
39 	cm->cmsg_len = CMSG_LEN(sizeof(int));
40 	cm->cmsg_level = SOL_SOCKET;
41 	cm->cmsg_type = SCM_RIGHTS;
42 	*((int *)CMSG_DATA(cm)) = fd;
43 
44 	n = sendmsg(s, &msg, 0);
45 	if (n < 0)
46 		err(1, "sendmsg failed");
47 	else if (n != sizeof(fd))
48 		errx(1, "sendmsg sent %d", n);
49 	close(fd);
50 }
51 
52 static void
53 test_recv_desc(int s)
54 {
55 	struct msghdr msg;
56 	struct iovec iov;
57 	union {
58 		struct cmsghdr cm;
59 		uint8_t data[CMSG_SPACE(sizeof(int))];
60 	} ctrl;
61 	struct cmsghdr *cm;
62 	int buf, n, fd;
63 	char data[16];
64 
65 	iov.iov_base = &buf;
66 	iov.iov_len = sizeof(buf);
67 
68 	memset(&msg, 0, sizeof(msg));
69 	msg.msg_iov = &iov;
70 	msg.msg_iovlen = 1;
71 	msg.msg_control = ctrl.data;
72 	msg.msg_controllen = sizeof(ctrl.data);
73 
74 	n = recvmsg(s, &msg, 0);
75 	if (n < 0)
76 		err(1, "recvmsg failed");
77 	else if (n != sizeof(buf))
78 		errx(1, "recvmsg received %d", n);
79 
80 	cm = CMSG_FIRSTHDR(&msg);
81 	if (cm == NULL)
82 		errx(1, "no cmsg");
83 	if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
84 		errx(1, "cmsg len mismatch");
85 	if (cm->cmsg_level != SOL_SOCKET)
86 		errx(1, "cmsg level mismatch");
87 	if (cm->cmsg_type != SCM_RIGHTS)
88 		errx(1, "cmsg type mismatch");
89 
90 	fd = *((int *)CMSG_DATA(cm));
91 
92 	n = read(fd, data, sizeof(data) - 1);
93 	if (n < 0)
94 		err(1, "read failed");
95 	data[n] = '\0';
96 
97 	fprintf(stderr, "fd content: %s\n", data);
98 }
99 
100 static void
101 usage(const char *cmd)
102 {
103 	fprintf(stderr, "%s [-d] [-s]\n", cmd);
104 	exit(1);
105 }
106 
107 int
108 main(int argc, char *argv[])
109 {
110 	int s[2], fd, status, n, discard, skipfd;
111 	int opt;
112 	off_t ofs;
113 
114 	discard = 0;
115 	skipfd = 0;
116 	while ((opt = getopt(argc, argv, "ds")) != -1) {
117 		switch (opt) {
118 		case 'd':
119 			discard = 1;
120 			break;
121 
122 		case 's':
123 			skipfd = 1;
124 			break;
125 
126 		default:
127 			usage(argv[0]);
128 		}
129 	}
130 
131 	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) < 0)
132 		err(1, "socketpair(LOCAL, STREAM) failed");
133 
134 	if (fork() == 0) {
135 		close(s[0]);
136 		if (!discard && !skipfd) {
137 			test_recv_desc(s[1]);
138 		} else if (skipfd) {
139 			int buf;
140 
141 			fprintf(stderr, "skipfd\n");
142 			n = read(s[1], &buf, sizeof(buf));
143 			if (n < 0)
144 				err(1, "read failed");
145 		} else {
146 			fprintf(stderr, "discard msg\n");
147 			sleep(5);
148 		}
149 		exit(0);
150 	}
151 	close(s[1]);
152 
153 	fd = open(TEST_FILENAME, O_RDWR | O_TRUNC | O_CREAT,
154 	    S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
155 	if (fd < 0)
156 		err(1, "open " TEST_FILENAME " failed");
157 
158 	n = write(fd, TEST_FILENAME, strlen(TEST_FILENAME));
159 	if (n < 0)
160 		err(1, "write failed");
161 	else if (n != strlen(TEST_FILENAME))
162 		errx(1, "write %d", n);
163 
164 	ofs = lseek(fd, 0, SEEK_SET);
165 	if (ofs < 0)
166 		err(1, "lseek failed");
167 	else if (ofs != 0)
168 		errx(1, "lseek offset %jd", (intmax_t)ofs);
169 
170 	test_send_desc(s[0], fd);
171 
172 	wait(&status);
173 	exit(0);
174 }
175