gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_unix_stream.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <poll.h> 16 #include <stdio.h> 17 #include <sys/un.h> 18 19 #include "gtest/gtest.h" 20 #include "absl/time/clock.h" 21 #include "absl/time/time.h" 22 #include "test/syscalls/linux/unix_domain_socket_test_util.h" 23 #include "test/util/socket_util.h" 24 #include "test/util/test_util.h" 25 26 namespace gvisor { 27 namespace testing { 28 29 namespace { 30 31 // Test fixture for tests that apply to pairs of connected stream unix sockets. 32 using StreamUnixSocketPairTest = SocketPairTest; 33 34 TEST_P(StreamUnixSocketPairTest, WriteOneSideClosed) { 35 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 36 ASSERT_THAT(close(sockets->release_first_fd()), SyscallSucceeds()); 37 constexpr char kStr[] = "abc"; 38 ASSERT_THAT(write(sockets->second_fd(), kStr, 3), 39 SyscallFailsWithErrno(EPIPE)); 40 } 41 42 TEST_P(StreamUnixSocketPairTest, ReadOneSideClosed) { 43 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 44 ASSERT_THAT(close(sockets->release_first_fd()), SyscallSucceeds()); 45 char data[10] = {}; 46 ASSERT_THAT(read(sockets->second_fd(), data, sizeof(data)), 47 SyscallSucceedsWithValue(0)); 48 } 49 50 TEST_P(StreamUnixSocketPairTest, RecvmsgOneSideClosed) { 51 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 52 53 // Set timeout so that it will not wait for ever. 54 struct timeval tv { 55 .tv_sec = 0, .tv_usec = 10 56 }; 57 EXPECT_THAT(setsockopt(sockets->second_fd(), SOL_SOCKET, SO_RCVTIMEO, &tv, 58 sizeof(tv)), 59 SyscallSucceeds()); 60 61 ASSERT_THAT(close(sockets->release_first_fd()), SyscallSucceeds()); 62 63 char received_data[10] = {}; 64 struct iovec iov; 65 iov.iov_base = received_data; 66 iov.iov_len = sizeof(received_data); 67 struct msghdr msg = {}; 68 msg.msg_flags = -1; 69 msg.msg_iov = &iov; 70 msg.msg_iovlen = 1; 71 72 ASSERT_THAT(recvmsg(sockets->second_fd(), &msg, MSG_WAITALL), 73 SyscallSucceedsWithValue(0)); 74 } 75 76 TEST_P(StreamUnixSocketPairTest, ReadOneSideClosedWithUnreadData) { 77 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 78 79 char buf[10] = {}; 80 ASSERT_THAT(RetryEINTR(write)(sockets->second_fd(), buf, sizeof(buf)), 81 SyscallSucceedsWithValue(sizeof(buf))); 82 83 ASSERT_THAT(shutdown(sockets->first_fd(), SHUT_RDWR), SyscallSucceeds()); 84 85 ASSERT_THAT(RetryEINTR(read)(sockets->second_fd(), buf, sizeof(buf)), 86 SyscallSucceedsWithValue(0)); 87 88 ASSERT_THAT(close(sockets->release_first_fd()), SyscallSucceeds()); 89 90 ASSERT_THAT(RetryEINTR(read)(sockets->second_fd(), buf, sizeof(buf)), 91 SyscallFailsWithErrno(ECONNRESET)); 92 } 93 94 TEST_P(StreamUnixSocketPairTest, Sendto) { 95 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 96 97 struct sockaddr_un addr = {}; 98 addr.sun_family = AF_UNIX; 99 constexpr char kPath[] = "\0nonexistent"; 100 memcpy(addr.sun_path, kPath, sizeof(kPath)); 101 102 constexpr char kStr[] = "abc"; 103 ASSERT_THAT(sendto(sockets->second_fd(), kStr, 3, 0, (struct sockaddr*)&addr, 104 sizeof(addr)), 105 SyscallFailsWithErrno(EISCONN)); 106 } 107 108 TEST_P(StreamUnixSocketPairTest, SetAndGetSocketLinger) { 109 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 110 111 struct linger sl = {1, 5}; 112 EXPECT_THAT( 113 setsockopt(sockets->first_fd(), SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)), 114 SyscallSucceedsWithValue(0)); 115 116 struct linger got_linger = {}; 117 socklen_t length = sizeof(sl); 118 EXPECT_THAT(getsockopt(sockets->first_fd(), SOL_SOCKET, SO_LINGER, 119 &got_linger, &length), 120 SyscallSucceedsWithValue(0)); 121 122 ASSERT_EQ(length, sizeof(got_linger)); 123 EXPECT_EQ(0, memcmp(&got_linger, &sl, length)); 124 } 125 126 TEST_P(StreamUnixSocketPairTest, GetSocketAcceptConn) { 127 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 128 129 int got = -1; 130 socklen_t length = sizeof(got); 131 ASSERT_THAT( 132 getsockopt(sockets->first_fd(), SOL_SOCKET, SO_ACCEPTCONN, &got, &length), 133 SyscallSucceedsWithValue(0)); 134 135 ASSERT_EQ(length, sizeof(got)); 136 EXPECT_EQ(got, 0); 137 } 138 139 TEST_P(StreamUnixSocketPairTest, SetSocketSendBuf) { 140 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 141 auto s = sockets->first_fd(); 142 int max = 0; 143 int min = 0; 144 { 145 // Discover maxmimum buffer size by setting to a really large value. 146 constexpr int kRcvBufSz = INT_MAX; 147 ASSERT_THAT( 148 setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kRcvBufSz, sizeof(kRcvBufSz)), 149 SyscallSucceeds()); 150 151 max = 0; 152 socklen_t max_len = sizeof(max); 153 ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &max, &max_len), 154 SyscallSucceeds()); 155 } 156 157 { 158 // Discover minimum buffer size by setting it to zero. 159 constexpr int kRcvBufSz = 0; 160 ASSERT_THAT( 161 setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kRcvBufSz, sizeof(kRcvBufSz)), 162 SyscallSucceeds()); 163 164 socklen_t min_len = sizeof(min); 165 ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &min, &min_len), 166 SyscallSucceeds()); 167 } 168 169 int quarter_sz = min + (max - min) / 4; 170 ASSERT_THAT( 171 setsockopt(s, SOL_SOCKET, SO_SNDBUF, &quarter_sz, sizeof(quarter_sz)), 172 SyscallSucceeds()); 173 174 int val = 0; 175 socklen_t val_len = sizeof(val); 176 ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &val, &val_len), 177 SyscallSucceeds()); 178 179 // Linux doubles the value set by SO_SNDBUF/SO_SNDBUF. 180 quarter_sz *= 2; 181 ASSERT_EQ(quarter_sz, val); 182 } 183 184 TEST_P(StreamUnixSocketPairTest, SendBufferOverflow) { 185 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 186 auto s = sockets->first_fd(); 187 188 constexpr int kBufSz = 4096; 189 std::vector<char> buf(kBufSz * 4); 190 ASSERT_THAT(RetryEINTR(send)(s, buf.data(), buf.size(), MSG_DONTWAIT), 191 SyscallSucceeds()); 192 // The new buffer size should be smaller that the amount of data in the queue. 193 ASSERT_THAT(setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kBufSz, sizeof(kBufSz)), 194 SyscallSucceeds()); 195 ASSERT_THAT(RetryEINTR(send)(s, buf.data(), buf.size(), MSG_DONTWAIT), 196 SyscallFailsWithErrno(EAGAIN)); 197 } 198 199 TEST_P(StreamUnixSocketPairTest, IncreasedSocketSendBufUnblocksWrites) { 200 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 201 int sock = sockets->first_fd(); 202 int buf_size = 0; 203 socklen_t buf_size_len = sizeof(buf_size); 204 ASSERT_THAT(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, &buf_size_len), 205 SyscallSucceeds()); 206 int opts; 207 ASSERT_THAT(opts = fcntl(sock, F_GETFL), SyscallSucceeds()); 208 opts |= O_NONBLOCK; 209 ASSERT_THAT(fcntl(sock, F_SETFL, opts), SyscallSucceeds()); 210 211 std::vector<char> buf(buf_size / 4); 212 // Write till the socket buffer is full. 213 while (RetryEINTR(send)(sock, buf.data(), buf.size(), 0) != -1) { 214 // Sleep to give linux a chance to move data from the send buffer to the 215 // receive buffer. 216 absl::SleepFor(absl::Milliseconds(10)); // 10ms. 217 } 218 // The last error should have been EWOULDBLOCK. 219 ASSERT_EQ(errno, EWOULDBLOCK); 220 221 // Now increase the socket send buffer. 222 buf_size = buf_size * 2; 223 ASSERT_THAT( 224 setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)), 225 SyscallSucceeds()); 226 227 // The send should succeed again. 228 ASSERT_THAT(RetryEINTR(send)(sock, buf.data(), buf.size(), 0), 229 SyscallSucceeds()); 230 } 231 232 TEST_P(StreamUnixSocketPairTest, GetAcceptConn) { 233 auto bound = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, SOCK_STREAM, 0)); 234 struct sockaddr_un bind_addr = 235 ASSERT_NO_ERRNO_AND_VALUE(UniqueUnixAddr(true, AF_UNIX)); 236 ASSERT_THAT(bind(bound.get(), AsSockAddr(&bind_addr), sizeof(bind_addr)), 237 SyscallSucceeds()); 238 int opt = 0; 239 socklen_t opt_len = sizeof(opt); 240 ASSERT_THAT( 241 getsockopt(bound.get(), SOL_SOCKET, SO_ACCEPTCONN, &opt, &opt_len), 242 SyscallSucceeds()); 243 ASSERT_EQ(opt, 0); 244 ASSERT_THAT(listen(bound.get(), 245 /* backlog = */ 5), // NOLINT(bugprone-argument-comment) 246 SyscallSucceeds()); 247 ASSERT_THAT( 248 getsockopt(bound.get(), SOL_SOCKET, SO_ACCEPTCONN, &opt, &opt_len), 249 SyscallSucceeds()); 250 ASSERT_EQ(opt, 1); 251 } 252 253 INSTANTIATE_TEST_SUITE_P( 254 AllUnixDomainSockets, StreamUnixSocketPairTest, 255 ::testing::ValuesIn(IncludeReversals(VecCat<SocketPairKind>( 256 ApplyVec<SocketPairKind>(UnixDomainSocketPair, 257 AllBitwiseCombinations(List<int>{SOCK_STREAM}, 258 List<int>{ 259 0, SOCK_NONBLOCK})), 260 ApplyVec<SocketPairKind>(FilesystemBoundUnixDomainSocketPair, 261 AllBitwiseCombinations(List<int>{SOCK_STREAM}, 262 List<int>{ 263 0, SOCK_NONBLOCK})), 264 ApplyVec<SocketPairKind>( 265 AbstractBoundUnixDomainSocketPair, 266 AllBitwiseCombinations(List<int>{SOCK_STREAM}, 267 List<int>{0, SOCK_NONBLOCK})))))); 268 269 } // namespace 270 271 } // namespace testing 272 } // namespace gvisor