1 /* 2 * Copyright 2023, Trung Nguyen, trungnt282910@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <errno.h> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <fcntl.h> 12 #include <sys/mman.h> 13 #include <sys/socket.h> 14 #include <sys/stat.h> 15 #include <sys/un.h> 16 #include <unistd.h> 17 18 19 #define REPORT_ERROR(msg, ...) \ 20 fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__) 21 22 23 int 24 connect_test() 25 { 26 unlink("test.sock"); 27 unlink("test1.sock"); 28 unlink("test2.sock"); 29 30 int status; 31 32 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 33 if (sock == -1) { 34 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 35 return 1; 36 } 37 38 struct sockaddr_un addr; 39 addr.sun_family = AF_UNIX; 40 strcpy(addr.sun_path, "test.sock"); 41 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 42 if (status == -1) { 43 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 44 return 1; 45 } 46 47 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 48 if (sock1 == -1) { 49 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 50 return 1; 51 } 52 53 struct sockaddr_un addr1; 54 addr1.sun_family = AF_UNIX; 55 strcpy(addr1.sun_path, "test1.sock"); 56 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 57 if (status == -1) { 58 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 59 return 1; 60 } 61 62 // Set non-blocking on both sockets 63 int flags1 = fcntl(sock, F_GETFL, 0); 64 if (flags1 == -1) { 65 REPORT_ERROR("fcntl() failed: %s\n", strerror(errno)); 66 return 1; 67 } 68 status = fcntl(sock, F_SETFL, flags1 | O_NONBLOCK); 69 if (status == -1) { 70 REPORT_ERROR("fcntl() failed: %s\n", strerror(errno)); 71 return 1; 72 } 73 status = fcntl(sock1, F_SETFL, flags1 | O_NONBLOCK); 74 if (status == -1) { 75 REPORT_ERROR("fcntl() failed: %s\n", strerror(errno)); 76 return 1; 77 } 78 79 status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1)); 80 if (status == -1) { 81 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 82 return 1; 83 } 84 85 // Connect in the opposite way 86 status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr)); 87 if (status == -1) { 88 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 89 return 1; 90 } 91 92 // Reconnect a connected DGRAM socket 93 status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1)); 94 if (status == -1) { 95 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 96 return 1; 97 } 98 99 int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0); 100 if (sock2 == -1) { 101 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 102 return 1; 103 } 104 105 struct sockaddr_un addr2; 106 addr2.sun_family = AF_UNIX; 107 strcpy(addr2.sun_path, "test2.sock"); 108 status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2)); 109 if (status == -1) { 110 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 111 return 1; 112 } 113 114 // Connect to a socket that are already connected 115 status = connect(sock2, (struct sockaddr*)&addr1, sizeof(addr1)); 116 if (status != -1) { 117 REPORT_ERROR("connect() succeeded unexpectedly\n"); 118 return 1; 119 } 120 if (errno != EPERM) { 121 REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno)); 122 return 1; 123 } 124 125 status = close(sock2); 126 if (status == -1) { 127 REPORT_ERROR("close() failed: %s\n", strerror(errno)); 128 return 1; 129 } 130 131 // Connect to a closed socket 132 status = connect(sock, (struct sockaddr*)&addr2, sizeof(addr2)); 133 if (status != -1) { 134 REPORT_ERROR("connect() succeeded unexpectedly\n"); 135 return 1; 136 } 137 if (errno != ECONNREFUSED) { 138 REPORT_ERROR("connect() failed with unexpected error: %s\n", strerror(errno)); 139 return 1; 140 } 141 142 close(sock); 143 close(sock1); 144 145 unlink("test.sock"); 146 unlink("test1.sock"); 147 unlink("test2.sock"); 148 149 return 0; 150 } 151 152 153 int 154 send_test() 155 { 156 unlink("test.sock"); 157 unlink("test1.sock"); 158 unlink("test2.sock"); 159 160 int status; 161 162 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 163 if (sock == -1) { 164 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 165 return 1; 166 } 167 168 struct sockaddr_un addr; 169 memset(&addr, 0, sizeof(addr)); 170 addr.sun_family = AF_UNIX; 171 strcpy(addr.sun_path, "test.sock"); 172 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 173 if (status == -1) { 174 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 175 return 1; 176 } 177 178 status = send(sock, "test", 4, 0); 179 if (status != -1) { 180 REPORT_ERROR("send() succeeded unexpectedly\n"); 181 return 1; 182 } 183 // if (errno != ENOTCONN) { 184 // REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 185 // return 1; 186 // } 187 188 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 189 if (sock1 == -1) { 190 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 191 return 1; 192 } 193 194 struct sockaddr_un addr1; 195 addr1.sun_family = AF_UNIX; 196 strcpy(addr1.sun_path, "test1.sock"); 197 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 198 if (status == -1) { 199 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 200 return 1; 201 } 202 203 // Set non-blocking on both sockets 204 status = fcntl(sock, F_SETFL, O_NONBLOCK); 205 if (status == -1) { 206 REPORT_ERROR("fcntl() failed: %s\n", strerror(errno)); 207 return 1; 208 } 209 status = fcntl(sock1, F_SETFL, O_NONBLOCK); 210 if (status == -1) { 211 REPORT_ERROR("fcntl() failed: %s\n", strerror(errno)); 212 return 1; 213 } 214 215 status = sendto(sock, "test1", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1)); 216 if (status == -1) { 217 REPORT_ERROR("sendto() failed: %s\n", strerror(errno)); 218 return 1; 219 } 220 221 status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1)); 222 if (status == -1) { 223 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 224 return 1; 225 } 226 status = connect(sock1, (struct sockaddr*)&addr, sizeof(addr)); 227 if (status == -1) { 228 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 229 return 1; 230 } 231 232 status = send(sock, "test2", 5, 0); 233 if (status == -1) { 234 REPORT_ERROR("send() failed: %s\n", strerror(errno)); 235 return 1; 236 } 237 238 int sock2 = socket(AF_UNIX, SOCK_DGRAM, 0); 239 if (sock2 == -1) { 240 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 241 return 1; 242 } 243 244 struct sockaddr_un addr2; 245 addr2.sun_family = AF_UNIX; 246 strcpy(addr2.sun_path, "test2.sock"); 247 status = bind(sock2, (struct sockaddr*)&addr2, sizeof(addr2)); 248 if (status == -1) { 249 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 250 return 1; 251 } 252 253 status = sendto(sock2, "test3", 5, 0, (struct sockaddr*)&addr1, sizeof(addr1)); 254 if (status != -1) { 255 REPORT_ERROR("sendto() succeeded unexpectedly\n"); 256 return 1; 257 } 258 if (errno != EPERM) { 259 REPORT_ERROR("sendto() failed with unexpected error: %s\n", strerror(errno)); 260 return 1; 261 } 262 263 char buf[16]; 264 memset(buf, 0, sizeof(buf)); 265 status = recv(sock1, buf, sizeof(buf), 0); 266 if (status == -1) { 267 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 268 return 1; 269 } 270 if (strcmp(buf, "test1") != 0) { 271 REPORT_ERROR("recv() received unexpected data: %s\n", buf); 272 return 1; 273 } 274 275 memset(buf, 0, sizeof(buf)); 276 struct sockaddr_un addr3; 277 memset(&addr3, 0, sizeof(addr3)); 278 socklen_t addrlen = sizeof(addr3); 279 status = recvfrom(sock1, buf, sizeof(buf), 0, (struct sockaddr*)&addr3, &addrlen); 280 if (status == -1) { 281 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 282 return 1; 283 } 284 if (strcmp(buf, "test2") != 0) { 285 REPORT_ERROR("recv() received unexpected data: %s\n", buf); 286 return 1; 287 } 288 if (strcmp(addr.sun_path, addr3.sun_path) != 0) { 289 REPORT_ERROR("recv() received unexpected address: %s\n", addr3.sun_path); 290 return 1; 291 } 292 293 status = send(sock, "test4", 4, 0); 294 if (status == -1) { 295 REPORT_ERROR("send() failed: %s\n", strerror(errno)); 296 return 1; 297 } 298 299 status = send(sock, "test5", 5, 0); 300 if (status == -1) { 301 REPORT_ERROR("send() failed: %s\n", strerror(errno)); 302 return 1; 303 } 304 305 memset(buf, 0, sizeof(buf)); 306 status = recv(sock1, buf, 4, 0); 307 if (status == -1) { 308 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 309 return 1; 310 } 311 if (strcmp(buf, "test") != 0) { 312 REPORT_ERROR("recv() received unexpected data: %s\n", buf); 313 return 1; 314 } 315 316 // The last byte of the previous datagram should be discarded. 317 memset(buf, 0, sizeof(buf)); 318 status = recv(sock1, buf, sizeof(buf), 0); 319 if (status == -1) { 320 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 321 return 1; 322 } 323 if (strcmp(buf, "test5") != 0) { 324 REPORT_ERROR("recv() received unexpected data: %s\n", buf); 325 return 1; 326 } 327 328 close(sock1); 329 status = send(sock, "test6", 5, 0); 330 if (status != -1) { 331 REPORT_ERROR("send() succeeded unexpectedly\n"); 332 return 1; 333 } 334 if (errno != ECONNREFUSED) { 335 REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 336 return 1; 337 } 338 339 close(sock); 340 close(sock2); 341 342 unlink("test.sock"); 343 unlink("test1.sock"); 344 unlink("test2.sock"); 345 346 return 0; 347 } 348 349 350 int 351 send_unbound_test() 352 { 353 unlink("test-socket-unix"); 354 int sock_server = socket(AF_UNIX, SOCK_DGRAM, 0); 355 if (sock_server == -1) { 356 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 357 return 1; 358 } 359 360 struct sockaddr_un addr; 361 addr.sun_family = AF_UNIX; 362 strcpy(addr.sun_path, "test-socket-unix"); 363 int status = bind(sock_server, (struct sockaddr*)&addr, sizeof(addr)); 364 if (status == -1) { 365 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 366 unlink("test-socket-unix"); 367 close(sock_server); 368 return 1; 369 } 370 371 int sock_client = socket(AF_UNIX, SOCK_DGRAM, 0); 372 if (sock_client == -1) { 373 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 374 unlink("test-socket-unix"); 375 close(sock_server); 376 return 1; 377 } 378 379 status = sendto(sock_client, "t", 1, 0, (struct sockaddr*)&addr, sizeof(addr)); 380 if (status != 1) { 381 REPORT_ERROR("sendto() failed: %s\n", strerror(errno)); 382 unlink("test-socket-unix"); 383 close(sock_server); 384 close(sock_client); 385 return 1; 386 } 387 388 char buf[1024]; 389 memset(buf, 0, sizeof(buf)); 390 struct sockaddr_un addr_sender; 391 memset(&addr_sender, 0, sizeof(addr_sender)); 392 socklen_t addrlen = sizeof(addr_sender); 393 status = recvfrom(sock_server, buf, sizeof(buf), 0, (struct sockaddr*)&addr_sender, &addrlen); 394 if (strcmp(addr_sender.sun_path, "") != 0 || status != 1 || strcmp(buf, "t") != 0) { 395 REPORT_ERROR("recvfrom() failed: %s\n", strerror(errno)); 396 unlink("test-socket-unix"); 397 close(sock_server); 398 close(sock_client); 399 return 1; 400 } 401 return 0; 402 } 403 404 405 int 406 shutdown_test() 407 { 408 unlink("test.sock"); 409 unlink("test1.sock"); 410 411 int status; 412 413 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 414 if (sock == -1) { 415 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 416 return 1; 417 } 418 419 struct sockaddr_un addr; 420 addr.sun_family = AF_UNIX; 421 strcpy(addr.sun_path, "test.sock"); 422 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 423 if (status == -1) { 424 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 425 return 1; 426 } 427 428 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 429 if (sock1 == -1) { 430 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 431 return 1; 432 } 433 434 struct sockaddr_un addr1; 435 addr1.sun_family = AF_UNIX; 436 strcpy(addr1.sun_path, "test1.sock"); 437 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 438 if (status == -1) { 439 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 440 return 1; 441 } 442 443 status = shutdown(sock, SHUT_WR); 444 if (status == -1) { 445 REPORT_ERROR("shutdown() failed: %s\n", strerror(errno)); 446 return 1; 447 } 448 449 status = sendto(sock, "test", 4, 0, (struct sockaddr*)&addr1, sizeof(addr1)); 450 if (status != -1) { 451 REPORT_ERROR("send() succeeded unexpectedly\n"); 452 return 1; 453 } 454 if (errno != EPIPE) { 455 REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 456 return 1; 457 } 458 459 status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr)); 460 if (status == -1) { 461 REPORT_ERROR("send() failed: %s\n", strerror(errno)); 462 return 1; 463 } 464 465 status = shutdown(sock, SHUT_RD); 466 if (status == -1) { 467 REPORT_ERROR("shutdown() failed: %s\n", strerror(errno)); 468 return 1; 469 } 470 471 status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr)); 472 if (status != -1) { 473 REPORT_ERROR("send() succeeded unexpectedly\n"); 474 return 1; 475 } 476 if (errno != EPIPE) { 477 REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 478 return 1; 479 } 480 481 char buf[16]; 482 memset(buf, 0, sizeof(buf)); 483 status = recv(sock, buf, sizeof(buf), 0); 484 if (status == -1) { 485 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 486 return 1; 487 } 488 if (status != 0) { 489 REPORT_ERROR("recv() received unexpected data\n"); 490 return 1; 491 } 492 493 close(sock); 494 close(sock1); 495 496 unlink("test.sock"); 497 unlink("test1.sock"); 498 499 return 0; 500 } 501 502 503 int 504 send_fd_test() 505 { 506 unlink("test.sock"); 507 unlink("test1.sock"); 508 509 int status; 510 511 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 512 if (sock == -1) { 513 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 514 return 1; 515 } 516 517 struct sockaddr_un addr; 518 addr.sun_family = AF_UNIX; 519 strcpy(addr.sun_path, "test.sock"); 520 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 521 if (status == -1) { 522 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 523 return 1; 524 } 525 526 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 527 if (sock1 == -1) { 528 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 529 return 1; 530 } 531 532 struct sockaddr_un addr1; 533 addr1.sun_family = AF_UNIX; 534 strcpy(addr1.sun_path, "test1.sock"); 535 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 536 if (status == -1) { 537 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 538 return 1; 539 } 540 541 status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1)); 542 if (status == -1) { 543 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 544 return 1; 545 } 546 547 int fd = shm_open("test_shm", O_CREAT | O_RDWR, 0666); 548 if (fd == -1) { 549 REPORT_ERROR("shm_open() failed: %s\n", strerror(errno)); 550 return 1; 551 } 552 shm_unlink("test_shm"); 553 554 // Send FD 555 char iobuf[] = "test"; 556 struct iovec iov { 557 .iov_base = iobuf, 558 .iov_len = sizeof(iobuf), 559 }; 560 561 struct msghdr msg; 562 memset(&msg, 0, sizeof(msg)); 563 564 struct cmsghdr *cmsg; 565 char buf[CMSG_SPACE(sizeof(fd))]; 566 memset(buf, 0, sizeof(buf)); 567 msg.msg_control = buf; 568 msg.msg_controllen = sizeof(buf); 569 msg.msg_iov = &iov; 570 msg.msg_iovlen = 1; 571 572 cmsg = CMSG_FIRSTHDR(&msg); 573 cmsg->cmsg_level = SOL_SOCKET; 574 cmsg->cmsg_type = SCM_RIGHTS; 575 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 576 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 577 msg.msg_controllen = cmsg->cmsg_len; 578 579 status = sendmsg(sock, &msg, 0); 580 if (status == -1) { 581 REPORT_ERROR("sendmsg() failed: %s\n", strerror(errno)); 582 return 1; 583 } 584 585 // Receive FD 586 memset(buf, 0, sizeof(buf)); 587 msg.msg_control = buf; 588 msg.msg_controllen = sizeof(buf); 589 msg.msg_iov = &iov; 590 msg.msg_iovlen = 1; 591 592 status = recvmsg(sock1, &msg, 0); 593 if (status == -1) { 594 REPORT_ERROR("recvmsg() failed: %s\n", strerror(errno)); 595 return 1; 596 } 597 598 cmsg = CMSG_FIRSTHDR(&msg); 599 if (cmsg == NULL) { 600 REPORT_ERROR("recvmsg() failed: no control message\n"); 601 return 1; 602 } 603 if (cmsg->cmsg_level != SOL_SOCKET) { 604 REPORT_ERROR("recvmsg() failed: unexpected level %d\n", cmsg->cmsg_level); 605 return 1; 606 } 607 if (cmsg->cmsg_type != SCM_RIGHTS) { 608 REPORT_ERROR("recvmsg() failed: unexpected type %d\n", cmsg->cmsg_type); 609 return 1; 610 } 611 if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) { 612 REPORT_ERROR("recvmsg() failed: unexpected length %ld\n", cmsg->cmsg_len); 613 return 1; 614 } 615 616 int fd1; 617 memcpy(&fd1, CMSG_DATA(cmsg), sizeof(fd1)); 618 if (fd1 == -1) { 619 REPORT_ERROR("recvmsg() failed: unexpected fd %d\n", fd1); 620 return 1; 621 } 622 623 // Check that the FD refers to the same file 624 struct stat statbuf; 625 status = fstat(fd, &statbuf); 626 if (status == -1) { 627 REPORT_ERROR("fstat() failed: %s\n", strerror(errno)); 628 return 1; 629 } 630 631 struct stat statbuf1; 632 status = fstat(fd1, &statbuf1); 633 if (status == -1) { 634 REPORT_ERROR("fstat() failed: %s\n", strerror(errno)); 635 return 1; 636 } 637 638 if (statbuf.st_dev != statbuf1.st_dev) { 639 REPORT_ERROR("recvmsg() failed: unexpected device %ld\n", (long)statbuf1.st_dev); 640 return 1; 641 } 642 if (statbuf.st_ino != statbuf1.st_ino) { 643 REPORT_ERROR("recvmsg() failed: unexpected inode %ld\n", (long)statbuf1.st_ino); 644 return 1; 645 } 646 647 close(sock); 648 close(sock1); 649 close(fd); 650 close(fd1); 651 652 unlink("test.sock"); 653 unlink("test1.sock"); 654 655 return 0; 656 } 657 658 659 int 660 main() 661 { 662 if (connect_test() != 0) 663 return 1; 664 665 if (send_test() != 0) 666 return 1; 667 668 if (send_unbound_test() != 0) 669 return 1; 670 671 if (shutdown_test() != 0) 672 return 1; 673 674 if (send_fd_test() != 0) 675 return 1; 676 677 return 0; 678 } 679