1196554Sjilles/* $FreeBSD$ */
2196554Sjilles
3196554Sjilles#include <sys/poll.h>
4196554Sjilles#include <sys/socket.h>
5196554Sjilles#include <sys/stat.h>
6196554Sjilles
7196554Sjilles#include <err.h>
8196554Sjilles#include <fcntl.h>
9196554Sjilles#include <signal.h>
10196554Sjilles#include <stdio.h>
11196554Sjilles#include <stdlib.h>
12196554Sjilles#include <unistd.h>
13196554Sjilles
14196554Sjillesstatic const char *
15196554Sjillesdecode_events(int events)
16196554Sjilles{
17196554Sjilles	char *ncresult;
18196554Sjilles	const char *result;
19196554Sjilles
20196554Sjilles	switch (events) {
21196554Sjilles	case POLLIN:
22196554Sjilles		result = "POLLIN";
23196554Sjilles		break;
24196554Sjilles	case POLLOUT:
25196554Sjilles		result = "POLLOUT";
26196554Sjilles		break;
27196554Sjilles	case POLLIN | POLLOUT:
28196554Sjilles		result = "POLLIN | POLLOUT";
29196554Sjilles		break;
30196554Sjilles	case POLLHUP:
31196554Sjilles		result = "POLLHUP";
32196554Sjilles		break;
33196554Sjilles	case POLLIN | POLLHUP:
34196554Sjilles		result = "POLLIN | POLLHUP";
35196554Sjilles		break;
36196554Sjilles	case POLLOUT | POLLHUP:
37196554Sjilles		result = "POLLOUT | POLLHUP";
38196554Sjilles		break;
39196554Sjilles	case POLLIN | POLLOUT | POLLHUP:
40196554Sjilles		result = "POLLIN | POLLOUT | POLLHUP";
41196554Sjilles		break;
42196554Sjilles	default:
43196554Sjilles		asprintf(&ncresult, "%#x", events);
44196554Sjilles		result = ncresult;
45196554Sjilles		break;
46196554Sjilles	}
47196554Sjilles	return (result);
48196554Sjilles}
49196554Sjilles
50196554Sjillesstatic void
51196554Sjillesreport(int num, const char *state, int expected, int got)
52196554Sjilles{
53196554Sjilles	if (expected == got)
54196554Sjilles		printf("ok %-2d    ", num);
55196554Sjilles	else
56196554Sjilles		printf("not ok %-2d", num);
57196554Sjilles	printf(" state %s: expected %s; got %s\n",
58196554Sjilles	    state, decode_events(expected), decode_events(got));
59196554Sjilles	fflush(stdout);
60196554Sjilles}
61196554Sjilles
62196554Sjillesstatic int
63196554Sjillesset_nonblocking(int sck)
64196554Sjilles{
65196554Sjilles	int flags;
66196554Sjilles
67196554Sjilles	flags = fcntl(sck, F_GETFL, 0);
68196554Sjilles	flags |= O_NONBLOCK;
69196554Sjilles
70196554Sjilles	if (fcntl(sck, F_SETFL, flags))
71196554Sjilles		return -1;
72196554Sjilles
73196554Sjilles	return 0;
74196554Sjilles}
75196554Sjilles
76196554Sjillesstatic char largeblock[1048576]; /* should be more than AF_UNIX sockbuf size */
77196554Sjillesstatic int fd[2];
78196554Sjillesstatic struct pollfd pfd0;
79196554Sjillesstatic struct pollfd pfd1;
80196554Sjilles
81196554Sjillesvoid
82196554Sjillessetup(void)
83196554Sjilles{
84196554Sjilles	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0)
85196554Sjilles		err(1, "socketpair");
86196554Sjilles	if (set_nonblocking(fd[0]) == -1)
87196554Sjilles		err(1, "fcntl");
88196554Sjilles	if (set_nonblocking(fd[1]) == -1)
89196554Sjilles		err(1, "fcntl");
90196554Sjilles	pfd0.fd = fd[0];
91196554Sjilles	pfd0.events = POLLIN | POLLOUT;
92196554Sjilles	pfd1.fd = fd[1];
93196554Sjilles	pfd1.events = POLLIN | POLLOUT;
94196554Sjilles}
95196554Sjilles
96196554Sjillesint
97196554Sjillesmain(void)
98196554Sjilles{
99196554Sjilles	int num;
100196554Sjilles
101196554Sjilles	num = 1;
102196554Sjilles	printf("1..18\n");
103196554Sjilles	fflush(stdout);
104196554Sjilles
105196554Sjilles	/* Large write with close */
106196554Sjilles	setup();
107196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
108196554Sjilles		err(1, "poll");
109196554Sjilles	report(num++, "initial 0", POLLOUT, pfd0.revents);
110196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
111196554Sjilles		err(1, "poll");
112196554Sjilles	report(num++, "initial 1", POLLOUT, pfd1.revents);
113196554Sjilles	if (write(fd[0], largeblock, sizeof(largeblock)) == -1)
114196554Sjilles		err(1, "write");
115196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
116196554Sjilles		err(1, "poll");
117196554Sjilles	report(num++, "after large write", 0, pfd0.revents);
118196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
119196554Sjilles		err(1, "poll");
120196554Sjilles	report(num++, "other side after large write", POLLIN | POLLOUT, pfd1.revents);
121196554Sjilles	close(fd[0]);
122196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
123196554Sjilles		err(1, "poll");
124196554Sjilles	report(num++, "other side after close", POLLIN | POLLHUP, pfd1.revents);
125196554Sjilles	if (read(fd[1], largeblock, sizeof(largeblock)) == -1)
126196554Sjilles		err(1, "read");
127196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
128196554Sjilles		err(1, "poll");
129196554Sjilles	report(num++, "other side after reading input", POLLHUP, pfd1.revents);
130196554Sjilles	close(fd[1]);
131196554Sjilles
132196554Sjilles	/* With shutdown(SHUT_WR) */
133196554Sjilles	setup();
134196554Sjilles	if (shutdown(fd[0], SHUT_WR) == -1)
135196554Sjilles		err(1, "shutdown");
136196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
137196554Sjilles		err(1, "poll");
138196554Sjilles	report(num++, "after shutdown(SHUT_WR)", POLLOUT, pfd0.revents);
139196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
140196554Sjilles		err(1, "poll");
141196554Sjilles	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
142196554Sjilles	switch (read(fd[1], largeblock, sizeof(largeblock))) {
143196554Sjilles		case 0:
144196554Sjilles			break;
145196554Sjilles		case -1:
146196554Sjilles			err(1, "read after other side shutdown");
147196554Sjilles			break;
148196554Sjilles		default:
149196554Sjilles			errx(1, "kernel made up data that was never written");
150196554Sjilles	}
151196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
152196554Sjilles		err(1, "poll");
153196554Sjilles	report(num++, "other side after reading EOF", POLLIN | POLLOUT, pfd1.revents);
154196554Sjilles	if (write(fd[1], largeblock, sizeof(largeblock)) == -1)
155196554Sjilles		err(1, "write");
156196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
157196554Sjilles		err(1, "poll");
158196554Sjilles	report(num++, "after data from other side", POLLIN | POLLOUT, pfd0.revents);
159196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
160196554Sjilles		err(1, "poll");
161196554Sjilles	report(num++, "after writing", POLLIN, pfd1.revents);
162196554Sjilles	if (shutdown(fd[1], SHUT_WR) == -1)
163196554Sjilles		err(1, "shutdown second");
164196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
165196554Sjilles		err(1, "poll");
166196554Sjilles	report(num++, "after second shutdown", POLLIN | POLLHUP, pfd0.revents);
167196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
168196554Sjilles		err(1, "poll");
169196554Sjilles	report(num++, "after second shutdown", POLLHUP, pfd1.revents);
170196554Sjilles	close(fd[0]);
171196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
172196554Sjilles		err(1, "poll");
173196554Sjilles	report(num++, "after close", POLLHUP, pfd1.revents);
174196554Sjilles	close(fd[1]);
175196554Sjilles
176196554Sjilles	/*
177196554Sjilles	 * With shutdown(SHUT_RD)
178196554Sjilles	 * Note that shutdown(SHUT_WR) is passed to the peer, but
179196554Sjilles	 * shutdown(SHUT_RD) is not.
180196554Sjilles	 */
181196554Sjilles	setup();
182196554Sjilles	if (shutdown(fd[0], SHUT_RD) == -1)
183196554Sjilles		err(1, "shutdown");
184196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
185196554Sjilles		err(1, "poll");
186196554Sjilles	report(num++, "after shutdown(SHUT_RD)", POLLIN | POLLOUT, pfd0.revents);
187196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
188196554Sjilles		err(1, "poll");
189196554Sjilles	report(num++, "other side after shutdown(SHUT_RD)", POLLOUT, pfd1.revents);
190196554Sjilles	if (shutdown(fd[0], SHUT_WR) == -1)
191196554Sjilles		err(1, "shutdown");
192196554Sjilles	if (poll(&pfd0, 1, 0) == -1)
193196554Sjilles		err(1, "poll");
194196554Sjilles	report(num++, "after shutdown(SHUT_WR)", POLLHUP, pfd0.revents);
195196554Sjilles	if (poll(&pfd1, 1, 0) == -1)
196196554Sjilles		err(1, "poll");
197196554Sjilles	report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
198196554Sjilles	close(fd[0]);
199196554Sjilles	close(fd[1]);
200196554Sjilles
201196554Sjilles	return (0);
202196554Sjilles}
203