1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * Test Name: recvmsg01 22 * 23 * Test Description: 24 * Verify that recvmsg() returns the proper errno for various failure cases 25 * 26 * Usage: <for command-line> 27 * recvmsg01 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 28 * where, -c n : Run n copies concurrently. 29 * -e : Turn on errno logging. 30 * -i n : Execute test n times. 31 * -I x : Execute test for x seconds. 32 * -P x : Pause for x seconds between iterations. 33 * -t : Turn on syscall timing. 34 * 35 * HISTORY 36 * 07/2001 Ported by Wayne Boyer 37 * 38 * RESTRICTIONS: 39 * None. 40 * 41 */ 42 43 #include <stdio.h> 44 #include <unistd.h> 45 #include <string.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 49 #include <sys/types.h> 50 #include <sys/socket.h> 51 #include <sys/signal.h> 52 #include <sys/uio.h> 53 #include <sys/un.h> 54 #include <sys/file.h> 55 56 #include <netinet/in.h> 57 58 #include "test.h" 59 #include "safe_macros.h" 60 61 char *TCID = "recvmsg01"; 62 int testno; 63 64 char buf[1024], cbuf[1024]; 65 int s; /* socket descriptor */ 66 int passed_fd = -1; /* rights-passing test descriptor */ 67 struct sockaddr_in sin1, from; 68 struct sockaddr_un sun1; 69 struct msghdr msgdat; 70 struct cmsghdr *control = 0; 71 int controllen = 0; 72 struct iovec iov[1]; 73 static int sfd; /* shared between do_child and start_server */ 74 static int ufd; /* shared between do_child and start_server */ 75 76 void setup(void); 77 void setup0(void); 78 void setup1(void); 79 void setup2(void); 80 void setup3(void); 81 void setup4(void); 82 void cleanup(void); 83 void cleanup0(void); 84 void cleanup1(void); 85 void cleanup2(void); 86 void do_child(void); 87 88 void sender(int); 89 pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); 90 91 struct test_case_t { /* test case structure */ 92 int domain; /* PF_INET, PF_UNIX, ... */ 93 int type; /* SOCK_STREAM, SOCK_DGRAM ... */ 94 int proto; /* protocol number (usually 0 = default) */ 95 struct iovec *iov; 96 int iovcnt; 97 void *buf; /* recv data buffer */ 98 int buflen; /* recv buffer length */ 99 struct msghdr *msg; 100 unsigned flags; 101 struct sockaddr *from; /* from address */ 102 int fromlen; /* from address value/result buffer length */ 103 int retval; /* syscall return value */ 104 int experrno; /* expected errno */ 105 void (*setup) (void); 106 void (*cleanup) (void); 107 char *desc; 108 } tdat[] = { 109 /* 1 */ 110 { 111 PF_INET, SOCK_STREAM, 0, iov, 1, buf, sizeof(buf), &msgdat, 0, 112 (struct sockaddr *)&from, sizeof(from), 113 -1, EBADF, setup0, cleanup0, "bad file descriptor"} 114 , 115 /* 2 */ 116 { 117 0, 0, 0, iov, 1, (void *)buf, sizeof(buf), &msgdat, 0, 118 (struct sockaddr *)&from, sizeof(from), 119 -1, ENOTSOCK, setup0, cleanup0, "invalid socket"} 120 , 121 /* 3 */ 122 { 123 PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 124 &msgdat, 0, (struct sockaddr *)-1, sizeof(from), 0, 125 ENOTSOCK, setup1, cleanup1, "invalid socket buffer"} 126 , 127 /* 4 */ 128 { 129 PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 130 &msgdat, -1, (struct sockaddr *)&from, -1, -1, 131 EINVAL, setup1, cleanup1, "invalid socket length"}, 132 /* 5 */ 133 { 134 PF_INET, SOCK_STREAM, 0, iov, 1, (void *)-1, sizeof(buf), 135 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 136 -1, EFAULT, setup1, cleanup1, "invalid recv buffer"} 137 , 138 /* 6 */ 139 { 140 PF_INET, SOCK_STREAM, 0, 0, 1, (void *)buf, sizeof(buf), 141 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 142 -1, EFAULT, setup1, cleanup1, "invalid iovec buffer"} 143 , 144 /* 7 */ 145 { 146 PF_INET, SOCK_STREAM, 0, iov, -1, (void *)buf, sizeof(buf), 147 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 148 -1, EMSGSIZE, setup1, cleanup1, "invalid iovec count"} 149 , 150 /* 8 */ 151 { 152 PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 153 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 154 0, 0, setup2, cleanup2, "rights reception"} 155 , 156 /* 9 */ 157 { 158 PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 159 &msgdat, MSG_OOB, (struct sockaddr *)&from, 160 sizeof(from), -1, EINVAL, setup1, cleanup1, 161 "invalid MSG_OOB flag set"} 162 , 163 /* 10 */ 164 { 165 PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 166 &msgdat, MSG_ERRQUEUE, (struct sockaddr *)&from, 167 sizeof(from), -1, EAGAIN, setup1, cleanup1, 168 "invalid MSG_ERRQUEUE flag set"} 169 , 170 /* 11 */ 171 { 172 PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 173 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 174 0, EINVAL, setup3, cleanup2, "invalid cmsg length"} 175 , 176 /* 12 */ 177 { 178 PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), 179 &msgdat, 0, (struct sockaddr *)&from, sizeof(from), 180 0, 0, setup4, cleanup2, "large cmesg length"} 181 ,}; 182 183 int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); 184 185 #ifdef UCLINUX 186 static char *argv0; 187 #endif 188 189 int main(int argc, char *argv[]) 190 { 191 int lc; 192 193 tst_parse_opts(argc, argv, NULL, NULL); 194 #ifdef UCLINUX 195 argv0 = argv[0]; 196 maybe_run_child(&do_child, "dd", &sfd, &ufd); 197 #endif 198 199 setup(); 200 201 for (lc = 0; TEST_LOOPING(lc); ++lc) { 202 tst_count = 0; 203 for (testno = 0; testno < TST_TOTAL; ++testno) { 204 if ((tst_kvercmp(3, 17, 0) < 0) 205 && (tdat[testno].flags & MSG_ERRQUEUE) 206 && (tdat[testno].type & SOCK_STREAM)) { 207 tst_resm(TCONF, "skip MSG_ERRQUEUE test, " 208 "it's supported from 3.17"); 209 continue; 210 } 211 212 tdat[testno].setup(); 213 214 /* setup common to all tests */ 215 iov[0].iov_base = tdat[testno].buf; 216 iov[0].iov_len = tdat[testno].buflen; 217 msgdat.msg_name = tdat[testno].from; 218 msgdat.msg_namelen = tdat[testno].fromlen; 219 msgdat.msg_iov = tdat[testno].iov; 220 msgdat.msg_iovlen = tdat[testno].iovcnt; 221 msgdat.msg_control = control; 222 msgdat.msg_controllen = controllen; 223 msgdat.msg_flags = 0; 224 225 TEST(recvmsg(s, tdat[testno].msg, tdat[testno].flags)); 226 if (TEST_RETURN >= 0) 227 TEST_RETURN = 0; /* all nonzero equal here */ 228 if (TEST_RETURN != tdat[testno].retval || 229 (TEST_RETURN < 0 && 230 TEST_ERRNO != tdat[testno].experrno)) { 231 tst_resm(TFAIL, "%s ; returned" 232 " %ld (expected %d), errno %d (expected" 233 " %d)", tdat[testno].desc, 234 TEST_RETURN, tdat[testno].retval, 235 TEST_ERRNO, tdat[testno].experrno); 236 } else { 237 tst_resm(TPASS, "%s successful", 238 tdat[testno].desc); 239 } 240 tdat[testno].cleanup(); 241 } 242 } 243 cleanup(); 244 245 tst_exit(); 246 } 247 248 pid_t pid; 249 char tmpsunpath[1024]; 250 251 void setup(void) 252 { 253 int tfd; 254 TEST_PAUSE; 255 256 tst_tmpdir(); 257 (void)strcpy(tmpsunpath, "udsockXXXXXX"); 258 tfd = mkstemp(tmpsunpath); 259 close(tfd); 260 unlink(tmpsunpath); 261 sun1.sun_family = AF_UNIX; 262 (void)strcpy(sun1.sun_path, tmpsunpath); 263 264 signal(SIGPIPE, SIG_IGN); 265 266 pid = start_server(&sin1, &sun1); 267 } 268 269 void cleanup(void) 270 { 271 if (pid > 0) 272 (void)kill(pid, SIGKILL); /* kill server */ 273 if (tmpsunpath[0] != '\0') 274 (void)unlink(tmpsunpath); 275 tst_rmdir(); 276 277 } 278 279 void setup0(void) 280 { 281 if (tdat[testno].experrno == EBADF) 282 s = 400; /* anything not an open file */ 283 else if ((s = open("/dev/null", O_WRONLY)) == -1) 284 tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed"); 285 } 286 287 void cleanup0(void) 288 { 289 s = -1; 290 } 291 292 void setup1(void) 293 { 294 fd_set rdfds; 295 struct timeval timeout; 296 int n; 297 298 s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, 299 tdat[testno].proto); 300 if (tdat[testno].type == SOCK_STREAM) { 301 if (tdat[testno].domain == PF_INET) { 302 SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, 303 sizeof(sin1)); 304 /* Wait for something to be readable, else we won't detect EFAULT on recv */ 305 FD_ZERO(&rdfds); 306 FD_SET(s, &rdfds); 307 timeout.tv_sec = 2; 308 timeout.tv_usec = 0; 309 n = select(s + 1, &rdfds, 0, 0, &timeout); 310 if (n != 1 || !FD_ISSET(s, &rdfds)) 311 tst_brkm(TBROK, cleanup, 312 "client setup1 failed - no message ready in 2 sec"); 313 } else if (tdat[testno].domain == PF_UNIX) { 314 SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sun1, 315 sizeof(sun1)); 316 } 317 } 318 } 319 320 void setup2(void) 321 { 322 setup1(); 323 if (write(s, "R", 1) < 0) 324 tst_brkm(TBROK | TERRNO, cleanup, "test setup failed: write:"); 325 control = (struct cmsghdr *)cbuf; 326 controllen = control->cmsg_len = sizeof(cbuf); 327 } 328 329 void setup3(void) 330 { 331 setup2(); 332 controllen = sizeof(struct cmsghdr) - 1; 333 } 334 335 void setup4(void) 336 { 337 setup2(); 338 controllen = 128 * 1024; 339 } 340 341 void cleanup1(void) 342 { 343 (void)close(s); 344 close(ufd); 345 close(sfd); 346 s = -1; 347 } 348 349 void cleanup2(void) 350 { 351 close(ufd); 352 close(sfd); 353 (void)close(s); 354 s = -1; 355 356 if (passed_fd >= 0) 357 (void)close(passed_fd); 358 passed_fd = -1; 359 control = 0; 360 controllen = 0; 361 } 362 363 pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) 364 { 365 pid_t pid; 366 socklen_t slen = sizeof(*ssin); 367 368 ssin->sin_family = AF_INET; 369 ssin->sin_port = 0; /* pick random free port */ 370 ssin->sin_addr.s_addr = INADDR_ANY; 371 372 /* set up inet socket */ 373 sfd = socket(PF_INET, SOCK_STREAM, 0); 374 if (sfd < 0) { 375 tst_brkm(TBROK | TERRNO, cleanup, "server socket failed"); 376 return -1; 377 } 378 if (bind(sfd, (struct sockaddr *)ssin, sizeof(*ssin)) < 0) { 379 tst_brkm(TBROK | TERRNO, cleanup, "server bind failed"); 380 return -1; 381 } 382 if (listen(sfd, 10) < 0) { 383 tst_brkm(TBROK | TERRNO, cleanup, "server listen failed"); 384 return -1; 385 } 386 SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)ssin, &slen); 387 388 /* set up UNIX-domain socket */ 389 ufd = socket(PF_UNIX, SOCK_STREAM, 0); 390 if (ufd < 0) { 391 tst_brkm(TBROK | TERRNO, cleanup, "server UD socket failed"); 392 return -1; 393 } 394 if (bind(ufd, (struct sockaddr *)ssun, sizeof(*ssun))) { 395 tst_brkm(TBROK | TERRNO, cleanup, "server UD bind failed"); 396 return -1; 397 } 398 if (listen(ufd, 10) < 0) { 399 tst_brkm(TBROK | TERRNO, cleanup, "server UD listen failed"); 400 return -1; 401 } 402 403 switch ((pid = FORK_OR_VFORK())) { 404 case 0: /* child */ 405 #ifdef UCLINUX 406 if (self_exec(argv0, "dd", sfd, ufd) < 0) 407 tst_brkm(TBROK | TERRNO, cleanup, 408 "server self_exec failed"); 409 #else 410 do_child(); 411 #endif 412 break; 413 case -1: 414 tst_brkm(TBROK | TERRNO, cleanup, "server fork failed"); 415 /* fall through */ 416 default: /* parent */ 417 (void)close(sfd); 418 (void)close(ufd); 419 return pid; 420 } 421 exit(1); 422 } 423 424 void do_child(void) 425 { 426 struct sockaddr_in fsin; 427 struct sockaddr_un fsun; 428 fd_set afds, rfds; 429 int nfds, cc, fd; 430 431 FD_ZERO(&afds); 432 FD_SET(sfd, &afds); 433 FD_SET(ufd, &afds); 434 435 nfds = MAX(sfd + 1, ufd + 1); 436 437 /* accept connections until killed */ 438 while (1) { 439 socklen_t fromlen; 440 441 memcpy(&rfds, &afds, sizeof(rfds)); 442 443 if (select(nfds, &rfds, NULL, NULL, 444 NULL) < 0) { 445 if (errno != EINTR) { 446 perror("server select"); 447 exit(1); 448 } 449 continue; 450 } 451 if (FD_ISSET(sfd, &rfds)) { 452 int newfd; 453 454 fromlen = sizeof(fsin); 455 newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen); 456 if (newfd >= 0) { 457 FD_SET(newfd, &afds); 458 nfds = MAX(nfds, newfd + 1); 459 /* send something back */ 460 (void)write(newfd, "hoser\n", 6); 461 } 462 } 463 if (FD_ISSET(ufd, &rfds)) { 464 int newfd; 465 466 fromlen = sizeof(fsun); 467 newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen); 468 if (newfd >= 0) { 469 FD_SET(newfd, &afds); 470 nfds = MAX(nfds, newfd + 1); 471 } 472 } 473 for (fd = 0; fd < nfds; ++fd) 474 if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { 475 char rbuf[1024]; 476 477 cc = read(fd, rbuf, sizeof(rbuf)); 478 if (cc && rbuf[0] == 'R') 479 sender(fd); 480 if (cc == 0 || (cc < 0 && errno != EINTR)) { 481 (void)close(fd); 482 FD_CLR(fd, &afds); 483 } 484 } 485 } 486 } 487 488 #define TM "from recvmsg01 server" 489 490 /* special for rights-passing test */ 491 void sender(int fd) 492 { 493 struct msghdr mh; 494 struct cmsghdr *control; 495 char tmpfn[1024], snd_cbuf[1024]; 496 int tfd; 497 498 (void)strcpy(tmpfn, "smtXXXXXX"); 499 tfd = mkstemp(tmpfn); 500 if (tfd < 0) 501 return; 502 503 memset(&mh, 0x00, sizeof(mh)); 504 505 /* set up cmsghdr */ 506 control = (struct cmsghdr *)snd_cbuf; 507 memset(control, 0x00, sizeof(struct cmsghdr)); 508 control->cmsg_len = sizeof(struct cmsghdr) + 4; 509 control->cmsg_level = SOL_SOCKET; 510 control->cmsg_type = SCM_RIGHTS; 511 *(int *)CMSG_DATA(control) = tfd; 512 513 /* set up msghdr */ 514 iov[0].iov_base = TM; 515 iov[0].iov_len = sizeof(TM); 516 mh.msg_iov = iov; 517 mh.msg_iovlen = 1; 518 mh.msg_flags = 0; 519 mh.msg_control = control; 520 mh.msg_controllen = control->cmsg_len; 521 522 /* do it */ 523 (void)sendmsg(fd, &mh, 0); 524 (void)close(tfd); 525 (void)unlink(tmpfn); 526 } 527