1/* $FreeBSD$ */
2
3#include <sys/poll.h>
4#include <sys/socket.h>
5#include <sys/stat.h>
6
7#include <err.h>
8#include <fcntl.h>
9#include <signal.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13
14static const char *
15decode_events(int events)
16{
17	char *ncresult;
18	const char *result;
19
20	switch (events) {
21	case POLLIN:
22		result = "POLLIN";
23		break;
24	case POLLOUT:
25		result = "POLLOUT";
26		break;
27	case POLLIN | POLLOUT:
28		result = "POLLIN | POLLOUT";
29		break;
30	case POLLHUP:
31		result = "POLLHUP";
32		break;
33	case POLLIN | POLLHUP:
34		result = "POLLIN | POLLHUP";
35		break;
36	case POLLOUT | POLLHUP:
37		result = "POLLOUT | POLLHUP";
38		break;
39	case POLLIN | POLLOUT | POLLHUP:
40		result = "POLLIN | POLLOUT | POLLHUP";
41		break;
42	default:
43		asprintf(&ncresult, "%#x", events);
44		result = ncresult;
45		break;
46	}
47	return (result);
48}
49
50static void
51report(int num, const char *state, int expected, int got)
52{
53	if (expected == got)
54		printf("ok %-2d    ", num);
55	else
56		printf("not ok %-2d", num);
57	printf(" state %s: expected %s; got %s\n",
58	    state, decode_events(expected), decode_events(got));
59	fflush(stdout);
60}
61
62static int
63set_nonblocking(int sck)
64{
65	int flags;
66
67	flags = fcntl(sck, F_GETFL, 0);
68	flags |= O_NONBLOCK;
69
70	if (fcntl(sck, F_SETFL, flags))
71		return -1;
72
73	return 0;
74}
75
76static char largeblock[1048576]; /* should be more than AF_UNIX sockbuf size */
77static int fd[2];
78static struct pollfd pfd0;
79static struct pollfd pfd1;
80
81void
82setup(void)
83{
84	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0)
85		err(1, "socketpair");
86	if (set_nonblocking(fd[0]) == -1)
87		err(1, "fcntl");
88	if (set_nonblocking(fd[1]) == -1)
89		err(1, "fcntl");
90	pfd0.fd = fd[0];
91	pfd0.events = POLLIN | POLLOUT;
92	pfd1.fd = fd[1];
93	pfd1.events = POLLIN | POLLOUT;
94}
95
96int
97main(void)
98{
99	int num;
100
101	num = 1;
102	printf("1..18\n");
103	fflush(stdout);
104
105	/* Large write with close */
106	setup();
107	if (poll(&pfd0, 1, 0) == -1)
108		err(1, "poll");
109	report(num++, "initial 0", POLLOUT, pfd0.revents);
110	if (poll(&pfd1, 1, 0) == -1)
111		err(1, "poll");
112	report(num++, "initial 1", POLLOUT, pfd1.revents);
113	if (write(fd[0], largeblock, sizeof(largeblock)) == -1)
114		err(1, "write");
115	if (poll(&pfd0, 1, 0) == -1)
116		err(1, "poll");
117	report(num++, "after large write", 0, pfd0.revents);
118	if (poll(&pfd1, 1, 0) == -1)
119		err(1, "poll");
120	report(num++, "other side after large write", POLLIN | POLLOUT, pfd1.revents);
121	close(fd[0]);
122	if (poll(&pfd1, 1, 0) == -1)
123		err(1, "poll");
124	report(num++, "other side after close", POLLIN | POLLHUP, pfd1.revents);
125	if (read(fd[1], largeblock, sizeof(largeblock)) == -1)
126		err(1, "read");
127	if (poll(&pfd1, 1, 0) == -1)
128		err(1, "poll");
129	report(num++, "other side after reading input", POLLHUP, pfd1.revents);
130	close(fd[1]);
131
132	/* With shutdown(SHUT_WR) */
133	setup();
134	if (shutdown(fd[0], SHUT_WR) == -1)
135		err(1, "shutdown");
136	if (poll(&pfd0, 1, 0) == -1)
137		err(1, "poll");
138	report(num++, "after shutdown(SHUT_WR)", POLLOUT, pfd0.revents);
139	if (poll(&pfd1, 1, 0) == -1)
140		err(1, "poll");
141	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
142	switch (read(fd[1], largeblock, sizeof(largeblock))) {
143		case 0:
144			break;
145		case -1:
146			err(1, "read after other side shutdown");
147			break;
148		default:
149			errx(1, "kernel made up data that was never written");
150	}
151	if (poll(&pfd1, 1, 0) == -1)
152		err(1, "poll");
153	report(num++, "other side after reading EOF", POLLIN | POLLOUT, pfd1.revents);
154	if (write(fd[1], largeblock, sizeof(largeblock)) == -1)
155		err(1, "write");
156	if (poll(&pfd0, 1, 0) == -1)
157		err(1, "poll");
158	report(num++, "after data from other side", POLLIN | POLLOUT, pfd0.revents);
159	if (poll(&pfd1, 1, 0) == -1)
160		err(1, "poll");
161	report(num++, "after writing", POLLIN, pfd1.revents);
162	if (shutdown(fd[1], SHUT_WR) == -1)
163		err(1, "shutdown second");
164	if (poll(&pfd0, 1, 0) == -1)
165		err(1, "poll");
166	report(num++, "after second shutdown", POLLIN | POLLHUP, pfd0.revents);
167	if (poll(&pfd1, 1, 0) == -1)
168		err(1, "poll");
169	report(num++, "after second shutdown", POLLHUP, pfd1.revents);
170	close(fd[0]);
171	if (poll(&pfd1, 1, 0) == -1)
172		err(1, "poll");
173	report(num++, "after close", POLLHUP, pfd1.revents);
174	close(fd[1]);
175
176	/*
177	 * With shutdown(SHUT_RD)
178	 * Note that shutdown(SHUT_WR) is passed to the peer, but
179	 * shutdown(SHUT_RD) is not.
180	 */
181	setup();
182	if (shutdown(fd[0], SHUT_RD) == -1)
183		err(1, "shutdown");
184	if (poll(&pfd0, 1, 0) == -1)
185		err(1, "poll");
186	report(num++, "after shutdown(SHUT_RD)", POLLIN | POLLOUT, pfd0.revents);
187	if (poll(&pfd1, 1, 0) == -1)
188		err(1, "poll");
189	report(num++, "other side after shutdown(SHUT_RD)", POLLOUT, pfd1.revents);
190	if (shutdown(fd[0], SHUT_WR) == -1)
191		err(1, "shutdown");
192	if (poll(&pfd0, 1, 0) == -1)
193		err(1, "poll");
194	report(num++, "after shutdown(SHUT_WR)", POLLHUP, pfd0.revents);
195	if (poll(&pfd1, 1, 0) == -1)
196		err(1, "poll");
197	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
198	close(fd[0]);
199	close(fd[1]);
200
201	return (0);
202}
203