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