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 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 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 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 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 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 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