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