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 shutdown_test() 352 { 353 unlink("test.sock"); 354 unlink("test1.sock"); 355 356 int status; 357 358 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 359 if (sock == -1) { 360 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 361 return 1; 362 } 363 364 struct sockaddr_un addr; 365 addr.sun_family = AF_UNIX; 366 strcpy(addr.sun_path, "test.sock"); 367 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 368 if (status == -1) { 369 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 370 return 1; 371 } 372 373 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 374 if (sock1 == -1) { 375 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 376 return 1; 377 } 378 379 struct sockaddr_un addr1; 380 addr1.sun_family = AF_UNIX; 381 strcpy(addr1.sun_path, "test1.sock"); 382 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 383 if (status == -1) { 384 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 385 return 1; 386 } 387 388 status = shutdown(sock, SHUT_WR); 389 if (status == -1) { 390 REPORT_ERROR("shutdown() failed: %s\n", strerror(errno)); 391 return 1; 392 } 393 394 status = sendto(sock, "test", 4, 0, (struct sockaddr*)&addr1, sizeof(addr1)); 395 if (status != -1) { 396 REPORT_ERROR("send() succeeded unexpectedly\n"); 397 return 1; 398 } 399 if (errno != EPIPE) { 400 REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 401 return 1; 402 } 403 404 status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr)); 405 if (status == -1) { 406 REPORT_ERROR("send() failed: %s\n", strerror(errno)); 407 return 1; 408 } 409 410 status = shutdown(sock, SHUT_RD); 411 if (status == -1) { 412 REPORT_ERROR("shutdown() failed: %s\n", strerror(errno)); 413 return 1; 414 } 415 416 status = sendto(sock1, "test", 4, 0, (struct sockaddr*)&addr, sizeof(addr)); 417 if (status != -1) { 418 REPORT_ERROR("send() succeeded unexpectedly\n"); 419 return 1; 420 } 421 if (errno != EPIPE) { 422 REPORT_ERROR("send() failed with unexpected error: %s\n", strerror(errno)); 423 return 1; 424 } 425 426 char buf[16]; 427 memset(buf, 0, sizeof(buf)); 428 status = recv(sock, buf, sizeof(buf), 0); 429 if (status == -1) { 430 REPORT_ERROR("recv() failed: %s\n", strerror(errno)); 431 return 1; 432 } 433 if (status != 0) { 434 REPORT_ERROR("recv() received unexpected data\n"); 435 return 1; 436 } 437 438 close(sock); 439 close(sock1); 440 441 unlink("test.sock"); 442 unlink("test1.sock"); 443 444 return 0; 445 } 446 447 448 int 449 send_fd_test() 450 { 451 unlink("test.sock"); 452 unlink("test1.sock"); 453 454 int status; 455 456 int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 457 if (sock == -1) { 458 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 459 return 1; 460 } 461 462 struct sockaddr_un addr; 463 addr.sun_family = AF_UNIX; 464 strcpy(addr.sun_path, "test.sock"); 465 status = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 466 if (status == -1) { 467 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 468 return 1; 469 } 470 471 int sock1 = socket(AF_UNIX, SOCK_DGRAM, 0); 472 if (sock1 == -1) { 473 REPORT_ERROR("socket() failed: %s\n", strerror(errno)); 474 return 1; 475 } 476 477 struct sockaddr_un addr1; 478 addr1.sun_family = AF_UNIX; 479 strcpy(addr1.sun_path, "test1.sock"); 480 status = bind(sock1, (struct sockaddr*)&addr1, sizeof(addr1)); 481 if (status == -1) { 482 REPORT_ERROR("bind() failed: %s\n", strerror(errno)); 483 return 1; 484 } 485 486 status = connect(sock, (struct sockaddr*)&addr1, sizeof(addr1)); 487 if (status == -1) { 488 REPORT_ERROR("connect() failed: %s\n", strerror(errno)); 489 return 1; 490 } 491 492 int fd = shm_open("test_shm", O_CREAT | O_RDWR, 0666); 493 if (fd == -1) { 494 REPORT_ERROR("shm_open() failed: %s\n", strerror(errno)); 495 return 1; 496 } 497 shm_unlink("test_shm"); 498 499 // Send FD 500 char iobuf[] = "test"; 501 struct iovec iov { 502 .iov_base = iobuf, 503 .iov_len = sizeof(iobuf), 504 }; 505 506 struct msghdr msg; 507 memset(&msg, 0, sizeof(msg)); 508 509 struct cmsghdr *cmsg; 510 char buf[CMSG_SPACE(sizeof(fd))]; 511 memset(buf, 0, sizeof(buf)); 512 msg.msg_control = buf; 513 msg.msg_controllen = sizeof(buf); 514 msg.msg_iov = &iov; 515 msg.msg_iovlen = 1; 516 517 cmsg = CMSG_FIRSTHDR(&msg); 518 cmsg->cmsg_level = SOL_SOCKET; 519 cmsg->cmsg_type = SCM_RIGHTS; 520 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 521 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 522 msg.msg_controllen = cmsg->cmsg_len; 523 524 status = sendmsg(sock, &msg, 0); 525 if (status == -1) { 526 REPORT_ERROR("sendmsg() failed: %s\n", strerror(errno)); 527 return 1; 528 } 529 530 // Receive FD 531 memset(buf, 0, sizeof(buf)); 532 msg.msg_control = buf; 533 msg.msg_controllen = sizeof(buf); 534 msg.msg_iov = &iov; 535 msg.msg_iovlen = 1; 536 537 status = recvmsg(sock1, &msg, 0); 538 if (status == -1) { 539 REPORT_ERROR("recvmsg() failed: %s\n", strerror(errno)); 540 return 1; 541 } 542 543 cmsg = CMSG_FIRSTHDR(&msg); 544 if (cmsg == NULL) { 545 REPORT_ERROR("recvmsg() failed: no control message\n"); 546 return 1; 547 } 548 if (cmsg->cmsg_level != SOL_SOCKET) { 549 REPORT_ERROR("recvmsg() failed: unexpected level %d\n", cmsg->cmsg_level); 550 return 1; 551 } 552 if (cmsg->cmsg_type != SCM_RIGHTS) { 553 REPORT_ERROR("recvmsg() failed: unexpected type %d\n", cmsg->cmsg_type); 554 return 1; 555 } 556 if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) { 557 REPORT_ERROR("recvmsg() failed: unexpected length %ld\n", cmsg->cmsg_len); 558 return 1; 559 } 560 561 int fd1; 562 memcpy(&fd1, CMSG_DATA(cmsg), sizeof(fd1)); 563 if (fd1 == -1) { 564 REPORT_ERROR("recvmsg() failed: unexpected fd %d\n", fd1); 565 return 1; 566 } 567 568 // Check that the FD refers to the same file 569 struct stat statbuf; 570 status = fstat(fd, &statbuf); 571 if (status == -1) { 572 REPORT_ERROR("fstat() failed: %s\n", strerror(errno)); 573 return 1; 574 } 575 576 struct stat statbuf1; 577 status = fstat(fd1, &statbuf1); 578 if (status == -1) { 579 REPORT_ERROR("fstat() failed: %s\n", strerror(errno)); 580 return 1; 581 } 582 583 if (statbuf.st_dev != statbuf1.st_dev) { 584 REPORT_ERROR("recvmsg() failed: unexpected device %ld\n", (long)statbuf1.st_dev); 585 return 1; 586 } 587 if (statbuf.st_ino != statbuf1.st_ino) { 588 REPORT_ERROR("recvmsg() failed: unexpected inode %ld\n", (long)statbuf1.st_ino); 589 return 1; 590 } 591 592 close(sock); 593 close(sock1); 594 close(fd); 595 close(fd1); 596 597 unlink("test.sock"); 598 unlink("test1.sock"); 599 600 return 0; 601 } 602 603 604 int 605 main() 606 { 607 if (connect_test() != 0) 608 return 1; 609 610 if (send_test() != 0) 611 return 1; 612 613 if (shutdown_test() != 0) 614 return 1; 615 616 if (send_fd_test() != 0) 617 return 1; 618 619 return 0; 620 } 621