| //===-- Unittests for bind ------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "src/__support/CPP/scope.h" | |
| #include "src/arpa/inet/htonl.h" | |
| #include "src/stdio/remove.h" | |
| #include "src/sys/socket/bind.h" | |
| #include "src/sys/socket/getsockname.h" | |
| #include "src/sys/socket/socket.h" | |
| #include "src/unistd/close.h" | |
| #include "test/UnitTest/ErrnoCheckingTest.h" | |
| #include "test/UnitTest/ErrnoSetterMatcher.h" | |
| #include "test/UnitTest/Test.h" | |
| #include "test/src/sys/socket/linux/socket_test_support.h" | |
| #include "hdr/netinet_in_macros.h" | |
| #include "hdr/sys_socket_macros.h" | |
| #include "hdr/types/sa_family_t.h" | |
| #include "hdr/types/struct_sockaddr_in.h" | |
| #include "hdr/types/struct_sockaddr_in6.h" | |
| #include "hdr/types/struct_sockaddr_un.h" | |
| using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; | |
| using LlvmLibcBindTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; | |
| TEST_F(LlvmLibcBindTest, BindLocalSocket) { | |
| LIBC_NAMESPACE::testing::TestDirectoryScope dir_scope; | |
| constexpr char SOCK_PATH[] = "bind_file.test"; | |
| int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0); | |
| ASSERT_GE(sock, 0); | |
| ASSERT_ERRNO_SUCCESS(); | |
| LIBC_NAMESPACE::cpp::scope_exit close_sock( | |
| [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); }); | |
| struct sockaddr_un my_addr; | |
| ASSERT_TRUE(LIBC_NAMESPACE::testing::make_sockaddr_un(SOCK_PATH, my_addr)); | |
| ASSERT_THAT( | |
| LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr), | |
| sizeof(struct sockaddr_un)), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcBindTest, BindInetSocket) { | |
| int sock = LIBC_NAMESPACE::socket(AF_INET, SOCK_DGRAM, 0); | |
| ASSERT_GE(sock, 0); | |
| ASSERT_ERRNO_SUCCESS(); | |
| LIBC_NAMESPACE::cpp::scope_exit close_sock( | |
| [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); }); | |
| struct sockaddr_in my_addr; | |
| my_addr.sin_family = AF_INET; | |
| my_addr.sin_port = 0; | |
| // Avoid expanding the htonl macro in overlay mode. | |
| my_addr.sin_addr.s_addr = (LIBC_NAMESPACE::htonl)(INADDR_LOOPBACK); | |
| ASSERT_THAT( | |
| LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr), | |
| sizeof(struct sockaddr_in)), | |
| Succeeds(0)); | |
| my_addr = {}; | |
| socklen_t len = sizeof(my_addr); | |
| ASSERT_THAT(LIBC_NAMESPACE::getsockname( | |
| sock, reinterpret_cast<struct sockaddr *>(&my_addr), &len), | |
| Succeeds(0)); | |
| ASSERT_EQ(len, static_cast<socklen_t>(sizeof(struct sockaddr_in))); | |
| EXPECT_EQ(my_addr.sin_family, static_cast<sa_family_t>(AF_INET)); | |
| EXPECT_NE(my_addr.sin_port, static_cast<in_port_t>(0)); | |
| EXPECT_EQ(my_addr.sin_addr.s_addr, (LIBC_NAMESPACE::htonl)(INADDR_LOOPBACK)); | |
| } | |
| TEST_F(LlvmLibcBindTest, BindInet6Socket) { | |
| int sock = LIBC_NAMESPACE::socket(AF_INET6, SOCK_DGRAM, 0); | |
| ASSERT_GE(sock, 0); | |
| ASSERT_ERRNO_SUCCESS(); | |
| LIBC_NAMESPACE::cpp::scope_exit close_sock( | |
| [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); }); | |
| struct sockaddr_in6 my_addr = {}; | |
| my_addr.sin6_family = AF_INET6; | |
| my_addr.sin6_addr = IN6ADDR_LOOPBACK_INIT; | |
| int result = | |
| LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr), | |
| sizeof(struct sockaddr_in6)); | |
| if (result == -1) { | |
| ASSERT_ERRNO_EQ(EADDRNOTAVAIL); // Ipv6 not available on this host. | |
| return; | |
| } | |
| my_addr = {}; | |
| socklen_t len = sizeof(my_addr); | |
| ASSERT_THAT(LIBC_NAMESPACE::getsockname( | |
| sock, reinterpret_cast<struct sockaddr *>(&my_addr), &len), | |
| Succeeds(0)); | |
| ASSERT_EQ(len, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); | |
| EXPECT_EQ(my_addr.sin6_family, static_cast<sa_family_t>(AF_INET6)); | |
| EXPECT_NE(my_addr.sin6_port, static_cast<in_port_t>(0)); | |
| } |