test_unix_oob.c (9249B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2#include <stdio.h> 3#include <stdlib.h> 4#include <sys/socket.h> 5#include <arpa/inet.h> 6#include <unistd.h> 7#include <string.h> 8#include <fcntl.h> 9#include <sys/ioctl.h> 10#include <errno.h> 11#include <netinet/tcp.h> 12#include <sys/un.h> 13#include <sys/signal.h> 14#include <sys/poll.h> 15 16static int pipefd[2]; 17static int signal_recvd; 18static pid_t producer_id; 19static char sock_name[32]; 20 21static void sig_hand(int sn, siginfo_t *si, void *p) 22{ 23 signal_recvd = sn; 24} 25 26static int set_sig_handler(int signal) 27{ 28 struct sigaction sa; 29 30 sa.sa_sigaction = sig_hand; 31 sigemptyset(&sa.sa_mask); 32 sa.sa_flags = SA_SIGINFO | SA_RESTART; 33 34 return sigaction(signal, &sa, NULL); 35} 36 37static void set_filemode(int fd, int set) 38{ 39 int flags = fcntl(fd, F_GETFL, 0); 40 41 if (set) 42 flags &= ~O_NONBLOCK; 43 else 44 flags |= O_NONBLOCK; 45 fcntl(fd, F_SETFL, flags); 46} 47 48static void signal_producer(int fd) 49{ 50 char cmd; 51 52 cmd = 'S'; 53 write(fd, &cmd, sizeof(cmd)); 54} 55 56static void wait_for_signal(int fd) 57{ 58 char buf[5]; 59 60 read(fd, buf, 5); 61} 62 63static void die(int status) 64{ 65 fflush(NULL); 66 unlink(sock_name); 67 kill(producer_id, SIGTERM); 68 exit(status); 69} 70 71int is_sioctatmark(int fd) 72{ 73 int ans = -1; 74 75 if (ioctl(fd, SIOCATMARK, &ans, sizeof(ans)) < 0) { 76#ifdef DEBUG 77 perror("SIOCATMARK Failed"); 78#endif 79 } 80 return ans; 81} 82 83void read_oob(int fd, char *c) 84{ 85 86 *c = ' '; 87 if (recv(fd, c, sizeof(*c), MSG_OOB) < 0) { 88#ifdef DEBUG 89 perror("Reading MSG_OOB Failed"); 90#endif 91 } 92} 93 94int read_data(int pfd, char *buf, int size) 95{ 96 int len = 0; 97 98 memset(buf, size, '0'); 99 len = read(pfd, buf, size); 100#ifdef DEBUG 101 if (len < 0) 102 perror("read failed"); 103#endif 104 return len; 105} 106 107static void wait_for_data(int pfd, int event) 108{ 109 struct pollfd pfds[1]; 110 111 pfds[0].fd = pfd; 112 pfds[0].events = event; 113 poll(pfds, 1, -1); 114} 115 116void producer(struct sockaddr_un *consumer_addr) 117{ 118 int cfd; 119 char buf[64]; 120 int i; 121 122 memset(buf, 'x', sizeof(buf)); 123 cfd = socket(AF_UNIX, SOCK_STREAM, 0); 124 125 wait_for_signal(pipefd[0]); 126 if (connect(cfd, (struct sockaddr *)consumer_addr, 127 sizeof(struct sockaddr)) != 0) { 128 perror("Connect failed"); 129 kill(0, SIGTERM); 130 exit(1); 131 } 132 133 for (i = 0; i < 2; i++) { 134 /* Test 1: Test for SIGURG and OOB */ 135 wait_for_signal(pipefd[0]); 136 memset(buf, 'x', sizeof(buf)); 137 buf[63] = '@'; 138 send(cfd, buf, sizeof(buf), MSG_OOB); 139 140 wait_for_signal(pipefd[0]); 141 142 /* Test 2: Test for OOB being overwitten */ 143 memset(buf, 'x', sizeof(buf)); 144 buf[63] = '%'; 145 send(cfd, buf, sizeof(buf), MSG_OOB); 146 147 memset(buf, 'x', sizeof(buf)); 148 buf[63] = '#'; 149 send(cfd, buf, sizeof(buf), MSG_OOB); 150 151 wait_for_signal(pipefd[0]); 152 153 /* Test 3: Test for SIOCATMARK */ 154 memset(buf, 'x', sizeof(buf)); 155 buf[63] = '@'; 156 send(cfd, buf, sizeof(buf), MSG_OOB); 157 158 memset(buf, 'x', sizeof(buf)); 159 buf[63] = '%'; 160 send(cfd, buf, sizeof(buf), MSG_OOB); 161 162 memset(buf, 'x', sizeof(buf)); 163 send(cfd, buf, sizeof(buf), 0); 164 165 wait_for_signal(pipefd[0]); 166 167 /* Test 4: Test for 1byte OOB msg */ 168 memset(buf, 'x', sizeof(buf)); 169 buf[0] = '@'; 170 send(cfd, buf, 1, MSG_OOB); 171 } 172} 173 174int 175main(int argc, char **argv) 176{ 177 int lfd, pfd; 178 struct sockaddr_un consumer_addr, paddr; 179 socklen_t len = sizeof(consumer_addr); 180 char buf[1024]; 181 int on = 0; 182 char oob; 183 int flags; 184 int atmark; 185 char *tmp_file; 186 187 lfd = socket(AF_UNIX, SOCK_STREAM, 0); 188 memset(&consumer_addr, 0, sizeof(consumer_addr)); 189 consumer_addr.sun_family = AF_UNIX; 190 sprintf(sock_name, "unix_oob_%d", getpid()); 191 unlink(sock_name); 192 strcpy(consumer_addr.sun_path, sock_name); 193 194 if ((bind(lfd, (struct sockaddr *)&consumer_addr, 195 sizeof(consumer_addr))) != 0) { 196 perror("socket bind failed"); 197 exit(1); 198 } 199 200 pipe(pipefd); 201 202 listen(lfd, 1); 203 204 producer_id = fork(); 205 if (producer_id == 0) { 206 producer(&consumer_addr); 207 exit(0); 208 } 209 210 set_sig_handler(SIGURG); 211 signal_producer(pipefd[1]); 212 213 pfd = accept(lfd, (struct sockaddr *) &paddr, &len); 214 fcntl(pfd, F_SETOWN, getpid()); 215 216 signal_recvd = 0; 217 signal_producer(pipefd[1]); 218 219 /* Test 1: 220 * veriyf that SIGURG is 221 * delivered, 63 bytes are 222 * read, oob is '@', and POLLPRI works. 223 */ 224 wait_for_data(pfd, POLLPRI); 225 read_oob(pfd, &oob); 226 len = read_data(pfd, buf, 1024); 227 if (!signal_recvd || len != 63 || oob != '@') { 228 fprintf(stderr, "Test 1 failed sigurg %d len %d %c\n", 229 signal_recvd, len, oob); 230 die(1); 231 } 232 233 signal_recvd = 0; 234 signal_producer(pipefd[1]); 235 236 /* Test 2: 237 * Verify that the first OOB is over written by 238 * the 2nd one and the first OOB is returned as 239 * part of the read, and sigurg is received. 240 */ 241 wait_for_data(pfd, POLLIN | POLLPRI); 242 len = 0; 243 while (len < 70) 244 len = recv(pfd, buf, 1024, MSG_PEEK); 245 len = read_data(pfd, buf, 1024); 246 read_oob(pfd, &oob); 247 if (!signal_recvd || len != 127 || oob != '#') { 248 fprintf(stderr, "Test 2 failed, sigurg %d len %d OOB %c\n", 249 signal_recvd, len, oob); 250 die(1); 251 } 252 253 signal_recvd = 0; 254 signal_producer(pipefd[1]); 255 256 /* Test 3: 257 * verify that 2nd oob over writes 258 * the first one and read breaks at 259 * oob boundary returning 127 bytes 260 * and sigurg is received and atmark 261 * is set. 262 * oob is '%' and second read returns 263 * 64 bytes. 264 */ 265 len = 0; 266 wait_for_data(pfd, POLLIN | POLLPRI); 267 while (len < 150) 268 len = recv(pfd, buf, 1024, MSG_PEEK); 269 len = read_data(pfd, buf, 1024); 270 atmark = is_sioctatmark(pfd); 271 read_oob(pfd, &oob); 272 273 if (!signal_recvd || len != 127 || oob != '%' || atmark != 1) { 274 fprintf(stderr, 275 "Test 3 failed, sigurg %d len %d OOB %c atmark %d\n", 276 signal_recvd, len, oob, atmark); 277 die(1); 278 } 279 280 signal_recvd = 0; 281 282 len = read_data(pfd, buf, 1024); 283 if (len != 64) { 284 fprintf(stderr, "Test 3.1 failed, sigurg %d len %d OOB %c\n", 285 signal_recvd, len, oob); 286 die(1); 287 } 288 289 signal_recvd = 0; 290 signal_producer(pipefd[1]); 291 292 /* Test 4: 293 * verify that a single byte 294 * oob message is delivered. 295 * set non blocking mode and 296 * check proper error is 297 * returned and sigurg is 298 * received and correct 299 * oob is read. 300 */ 301 302 set_filemode(pfd, 0); 303 304 wait_for_data(pfd, POLLIN | POLLPRI); 305 len = read_data(pfd, buf, 1024); 306 if ((len == -1) && (errno == 11)) 307 len = 0; 308 309 read_oob(pfd, &oob); 310 311 if (!signal_recvd || len != 0 || oob != '@') { 312 fprintf(stderr, "Test 4 failed, sigurg %d len %d OOB %c\n", 313 signal_recvd, len, oob); 314 die(1); 315 } 316 317 set_filemode(pfd, 1); 318 319 /* Inline Testing */ 320 321 on = 1; 322 if (setsockopt(pfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))) { 323 perror("SO_OOBINLINE"); 324 die(1); 325 } 326 327 signal_recvd = 0; 328 signal_producer(pipefd[1]); 329 330 /* Test 1 -- Inline: 331 * Check that SIGURG is 332 * delivered and 63 bytes are 333 * read and oob is '@' 334 */ 335 336 wait_for_data(pfd, POLLIN | POLLPRI); 337 len = read_data(pfd, buf, 1024); 338 339 if (!signal_recvd || len != 63) { 340 fprintf(stderr, "Test 1 Inline failed, sigurg %d len %d\n", 341 signal_recvd, len); 342 die(1); 343 } 344 345 len = read_data(pfd, buf, 1024); 346 347 if (len != 1) { 348 fprintf(stderr, 349 "Test 1.1 Inline failed, sigurg %d len %d oob %c\n", 350 signal_recvd, len, oob); 351 die(1); 352 } 353 354 signal_recvd = 0; 355 signal_producer(pipefd[1]); 356 357 /* Test 2 -- Inline: 358 * Verify that the first OOB is over written by 359 * the 2nd one and read breaks correctly on 360 * 2nd OOB boundary with the first OOB returned as 361 * part of the read, and sigurg is delivered and 362 * siocatmark returns true. 363 * next read returns one byte, the oob byte 364 * and siocatmark returns false. 365 */ 366 len = 0; 367 wait_for_data(pfd, POLLIN | POLLPRI); 368 while (len < 70) 369 len = recv(pfd, buf, 1024, MSG_PEEK); 370 len = read_data(pfd, buf, 1024); 371 atmark = is_sioctatmark(pfd); 372 if (len != 127 || atmark != 1 || !signal_recvd) { 373 fprintf(stderr, "Test 2 Inline failed, len %d atmark %d\n", 374 len, atmark); 375 die(1); 376 } 377 378 len = read_data(pfd, buf, 1024); 379 atmark = is_sioctatmark(pfd); 380 if (len != 1 || buf[0] != '#' || atmark == 1) { 381 fprintf(stderr, "Test 2.1 Inline failed, len %d data %c atmark %d\n", 382 len, buf[0], atmark); 383 die(1); 384 } 385 386 signal_recvd = 0; 387 signal_producer(pipefd[1]); 388 389 /* Test 3 -- Inline: 390 * verify that 2nd oob over writes 391 * the first one and read breaks at 392 * oob boundary returning 127 bytes 393 * and sigurg is received and siocatmark 394 * is true after the read. 395 * subsequent read returns 65 bytes 396 * because of oob which should be '%'. 397 */ 398 len = 0; 399 wait_for_data(pfd, POLLIN | POLLPRI); 400 while (len < 126) 401 len = recv(pfd, buf, 1024, MSG_PEEK); 402 len = read_data(pfd, buf, 1024); 403 atmark = is_sioctatmark(pfd); 404 if (!signal_recvd || len != 127 || !atmark) { 405 fprintf(stderr, 406 "Test 3 Inline failed, sigurg %d len %d data %c\n", 407 signal_recvd, len, buf[0]); 408 die(1); 409 } 410 411 len = read_data(pfd, buf, 1024); 412 atmark = is_sioctatmark(pfd); 413 if (len != 65 || buf[0] != '%' || atmark != 0) { 414 fprintf(stderr, 415 "Test 3.1 Inline failed, len %d oob %c atmark %d\n", 416 len, buf[0], atmark); 417 die(1); 418 } 419 420 signal_recvd = 0; 421 signal_producer(pipefd[1]); 422 423 /* Test 4 -- Inline: 424 * verify that a single 425 * byte oob message is delivered 426 * and read returns one byte, the oob 427 * byte and sigurg is received 428 */ 429 wait_for_data(pfd, POLLIN | POLLPRI); 430 len = read_data(pfd, buf, 1024); 431 if (!signal_recvd || len != 1 || buf[0] != '@') { 432 fprintf(stderr, 433 "Test 4 Inline failed, signal %d len %d data %c\n", 434 signal_recvd, len, buf[0]); 435 die(1); 436 } 437 die(0); 438}