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
append(char * out,size_t out_size,const char * s)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
decode_events(int events,char * out,size_t out_size)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
report(int num,const char * state,int expected,int got)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
set_nonblocking(int sck)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
setup(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
main(void)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