xref: /freebsd/tools/regression/poll/sockpoll.c (revision d6b92ffa990dc57d8a969a98e3ca4e25ba39cbb2)
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 
14 static const char *
15 decode_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 
50 static void
51 report(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 
62 static int
63 set_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 
76 static char largeblock[1048576]; /* should be more than AF_UNIX sockbuf size */
77 static int fd[2];
78 static struct pollfd pfd0;
79 static struct pollfd pfd1;
80 
81 void
82 setup(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 
96 int
97 main(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