xref: /freebsd/tools/regression/poll/sockpoll.c (revision a64729f5077d77e13b9497cb33ecb3c82e606ee8)
1 
2 #define _GNU_SOURCE         /* expose POLLRDHUP when testing on Linux */
3 
4 #include <sys/socket.h>
5 #include <sys/stat.h>
6 
7 #include <err.h>
8 #include <fcntl.h>
9 #include <poll.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 
16 static void
17 append(char *out, size_t out_size, const char *s)
18 {
19 	size_t size = strlen(out);
20 
21 	snprintf(out + size, out_size - size, "%s", s);
22 }
23 
24 static void
25 decode_events(int events, char *out, size_t out_size)
26 {
27 	int unknown;
28 
29 	out[0] = 0;
30 
31 	if (events == 0) {
32 		append(out, out_size, "0");
33 		return;
34 	}
35 
36 #define DECODE_FLAG(x) \
37 	if (events & (x)) { \
38 		if (out[0] != 0) \
39 			append(out, out_size, " | "); \
40 		append(out, out_size, #x); \
41 	}
42 
43 	/* Show the expected flags by name. */
44 	DECODE_FLAG(POLLIN);
45 	DECODE_FLAG(POLLOUT);
46 	DECODE_FLAG(POLLHUP);
47 #ifndef POLLRDHUP
48 #define KNOWN_FLAGS (POLLIN | POLLOUT | POLLHUP)
49 #else
50 	DECODE_FLAG(POLLRDHUP);
51 #define KNOWN_FLAGS (POLLIN | POLLOUT | POLLHUP | POLLRDHUP);
52 #endif
53 
54 	/* Show any unexpected bits as hex. */
55 	unknown = events & ~KNOWN_FLAGS;
56 	if (unknown != 0) {
57 		char buf[80];
58 
59 		snprintf(buf, sizeof(buf), "%s%x", out[0] != 0 ? " | " : "",
60 			unknown);
61 		append(out, out_size, buf);
62 	}
63 }
64 
65 static void
66 report(int num, const char *state, int expected, int got)
67 {
68 	char expected_str[80];
69 	char got_str[80];
70 
71 	decode_events(expected, expected_str, sizeof(expected_str));
72 	decode_events(got, got_str, sizeof(got_str));
73 	if (expected == got)
74 		printf("ok %-2d    ", num);
75 	else
76 		printf("not ok %-2d", num);
77 	printf(" state %s: expected %s; got %s\n",
78 	    state, expected_str, got_str);
79 	fflush(stdout);
80 }
81 
82 static int
83 set_nonblocking(int sck)
84 {
85 	int flags;
86 
87 	flags = fcntl(sck, F_GETFL, 0);
88 	flags |= O_NONBLOCK;
89 
90 	if (fcntl(sck, F_SETFL, flags))
91 		return -1;
92 
93 	return 0;
94 }
95 
96 static char largeblock[1048576]; /* should be more than AF_UNIX sockbuf size */
97 static int fd[2];
98 static struct pollfd pfd0;
99 static struct pollfd pfd1;
100 
101 void
102 setup(void)
103 {
104 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0)
105 		err(1, "socketpair");
106 	if (set_nonblocking(fd[0]) == -1)
107 		err(1, "fcntl");
108 	if (set_nonblocking(fd[1]) == -1)
109 		err(1, "fcntl");
110 	pfd0.fd = fd[0];
111 	pfd0.events = POLLIN | POLLOUT;
112 	pfd1.fd = fd[1];
113 	pfd1.events = POLLIN | POLLOUT;
114 }
115 
116 int
117 main(void)
118 {
119 	int num;
120 
121 	num = 1;
122 	printf("1..18\n");
123 	fflush(stdout);
124 
125 	/* Large write with close */
126 	setup();
127 	if (poll(&pfd0, 1, 0) == -1)
128 		err(1, "poll");
129 	report(num++, "initial 0", POLLOUT, pfd0.revents);
130 	if (poll(&pfd1, 1, 0) == -1)
131 		err(1, "poll");
132 	report(num++, "initial 1", POLLOUT, pfd1.revents);
133 	if (write(fd[0], largeblock, sizeof(largeblock)) == -1)
134 		err(1, "write");
135 	if (poll(&pfd0, 1, 0) == -1)
136 		err(1, "poll");
137 	report(num++, "after large write", 0, pfd0.revents);
138 	if (poll(&pfd1, 1, 0) == -1)
139 		err(1, "poll");
140 	report(num++, "other side after large write", POLLIN | POLLOUT, pfd1.revents);
141 	close(fd[0]);
142 	if (poll(&pfd1, 1, 0) == -1)
143 		err(1, "poll");
144 	report(num++, "other side after close", POLLIN | POLLHUP, pfd1.revents);
145 	if (read(fd[1], largeblock, sizeof(largeblock)) == -1)
146 		err(1, "read");
147 	if (poll(&pfd1, 1, 0) == -1)
148 		err(1, "poll");
149 	report(num++, "other side after reading input", POLLHUP, pfd1.revents);
150 	close(fd[1]);
151 
152 	/* With shutdown(SHUT_WR) */
153 	setup();
154 	if (shutdown(fd[0], SHUT_WR) == -1)
155 		err(1, "shutdown");
156 	if (poll(&pfd0, 1, 0) == -1)
157 		err(1, "poll");
158 	report(num++, "after shutdown(SHUT_WR)", POLLOUT, pfd0.revents);
159 	if (poll(&pfd1, 1, 0) == -1)
160 		err(1, "poll");
161 	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
162 	switch (read(fd[1], largeblock, sizeof(largeblock))) {
163 		case 0:
164 			break;
165 		case -1:
166 			err(1, "read after other side shutdown");
167 			break;
168 		default:
169 			errx(1, "kernel made up data that was never written");
170 	}
171 	if (poll(&pfd1, 1, 0) == -1)
172 		err(1, "poll");
173 	report(num++, "other side after reading EOF", POLLIN | POLLOUT, pfd1.revents);
174 	if (write(fd[1], largeblock, sizeof(largeblock)) == -1)
175 		err(1, "write");
176 	if (poll(&pfd0, 1, 0) == -1)
177 		err(1, "poll");
178 	report(num++, "after data from other side", POLLIN | POLLOUT, pfd0.revents);
179 	if (poll(&pfd1, 1, 0) == -1)
180 		err(1, "poll");
181 	report(num++, "after writing", POLLIN, pfd1.revents);
182 	if (shutdown(fd[1], SHUT_WR) == -1)
183 		err(1, "shutdown second");
184 	if (poll(&pfd0, 1, 0) == -1)
185 		err(1, "poll");
186 	report(num++, "after second shutdown", POLLIN | POLLHUP, pfd0.revents);
187 	if (poll(&pfd1, 1, 0) == -1)
188 		err(1, "poll");
189 	report(num++, "after second shutdown", POLLHUP, pfd1.revents);
190 	close(fd[0]);
191 	if (poll(&pfd1, 1, 0) == -1)
192 		err(1, "poll");
193 	report(num++, "after close", POLLHUP, pfd1.revents);
194 	close(fd[1]);
195 
196 	/*
197 	 * With shutdown(SHUT_RD)
198 	 * Note that shutdown(SHUT_WR) is passed to the peer, but
199 	 * shutdown(SHUT_RD) is not.
200 	 */
201 	setup();
202 	if (shutdown(fd[0], SHUT_RD) == -1)
203 		err(1, "shutdown");
204 	if (poll(&pfd0, 1, 0) == -1)
205 		err(1, "poll");
206 	report(num++, "after shutdown(SHUT_RD)", POLLIN | POLLOUT, pfd0.revents);
207 	if (poll(&pfd1, 1, 0) == -1)
208 		err(1, "poll");
209 	report(num++, "other side after shutdown(SHUT_RD)", POLLOUT, pfd1.revents);
210 	if (shutdown(fd[0], SHUT_WR) == -1)
211 		err(1, "shutdown");
212 	if (poll(&pfd0, 1, 0) == -1)
213 		err(1, "poll");
214 	report(num++, "after shutdown(SHUT_WR)", POLLHUP, pfd0.revents);
215 	if (poll(&pfd1, 1, 0) == -1)
216 		err(1, "poll");
217 	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
218 	close(fd[0]);
219 	close(fd[1]);
220 
221 #ifdef POLLRDHUP
222 	setup();
223 	pfd1.events |= POLLRDHUP;
224 	if (shutdown(fd[0], SHUT_RD) == -1)
225 		err(1, "shutdown");
226 	if (poll(&pfd1, 1, 0) == -1)
227 		err(1, "poll");
228 	report(num++, "other side after shutdown(SHUT_RD)", POLLOUT, pfd1.revents);
229 	if (write(fd[0], "x", 1) != 1)
230 		err(1, "write");
231 	if (poll(&pfd1, 1, 0) == -1)
232 		err(1, "poll");
233 	report(num++, "other side after write", POLLIN | POLLOUT, pfd1.revents);
234 	if (shutdown(fd[0], SHUT_WR) == -1)
235 		err(1, "shutdown");
236 	if (poll(&pfd1, 1, 0) == -1)
237 		err(1, "poll");
238 	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT | POLLRDHUP, pfd1.revents);
239 	close(fd[0]);
240 	close(fd[1]);
241 #endif
242 
243 	return (0);
244 }
245