github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/socket_generic_stress.cc (about) 1 // Copyright 2020 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/ioctl.h> 18 #include <sys/socket.h> 19 #include <sys/un.h> 20 #include <unistd.h> 21 22 #include <array> 23 #include <string> 24 25 #include "gtest/gtest.h" 26 #include "absl/strings/numbers.h" 27 #include "absl/strings/str_split.h" 28 #include "absl/strings/string_view.h" 29 #include "absl/time/clock.h" 30 #include "absl/time/time.h" 31 #include "test/syscalls/linux/ip_socket_test_util.h" 32 #include "test/syscalls/linux/socket_test_util.h" 33 #include "test/util/file_descriptor.h" 34 #include "test/util/test_util.h" 35 #include "test/util/thread_util.h" 36 37 namespace gvisor { 38 namespace testing { 39 40 // Test fixture for tests that apply to pairs of connected sockets. 41 using ConnectStressTest = SocketPairTest; 42 43 TEST_P(ConnectStressTest, Reset) { 44 const int nports = ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 45 for (int i = 0; i < nports * 2; i++) { 46 const std::unique_ptr<SocketPair> sockets = 47 ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 48 49 // Send some data to ensure that the connection gets reset and the port gets 50 // released immediately. This avoids either end entering TIME-WAIT. 51 char sent_data[100] = {}; 52 ASSERT_THAT(write(sockets->first_fd(), sent_data, sizeof(sent_data)), 53 SyscallSucceedsWithValue(sizeof(sent_data))); 54 // Poll the other FD to make sure that the data is in the receive buffer 55 // before closing it to ensure a RST is triggered. 56 const int kTimeout = 10000; 57 struct pollfd pfd = { 58 .fd = sockets->second_fd(), 59 .events = POLL_IN, 60 }; 61 ASSERT_THAT(poll(&pfd, 1, kTimeout), SyscallSucceedsWithValue(1)); 62 } 63 } 64 65 // Tests that opening too many connections -- without closing them -- does lead 66 // to port exhaustion. 67 TEST_P(ConnectStressTest, TooManyOpen) { 68 const int nports = ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 69 int err_num = 0; 70 std::vector<std::unique_ptr<SocketPair>> sockets = 71 std::vector<std::unique_ptr<SocketPair>>(nports); 72 for (int i = 0; i < nports * 2; i++) { 73 PosixErrorOr<std::unique_ptr<SocketPair>> socks = NewSocketPair(); 74 if (!socks.ok()) { 75 err_num = socks.error().errno_value(); 76 break; 77 } 78 sockets.push_back(std::move(socks).ValueOrDie()); 79 } 80 ASSERT_EQ(err_num, EADDRINUSE); 81 } 82 83 INSTANTIATE_TEST_SUITE_P( 84 AllConnectedSockets, ConnectStressTest, 85 ::testing::Values(IPv6UDPBidirectionalBindSocketPair(0), 86 IPv4UDPBidirectionalBindSocketPair(0), 87 DualStackUDPBidirectionalBindSocketPair(0), 88 89 // Without REUSEADDR, we get port exhaustion on Linux. 90 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, 91 &kSockOptOn)(IPv6TCPAcceptBindSocketPair(0)), 92 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, 93 &kSockOptOn)(IPv4TCPAcceptBindSocketPair(0)), 94 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &kSockOptOn)( 95 DualStackTCPAcceptBindSocketPair(0)))); 96 97 // Test fixture for tests that apply to pairs of connected sockets created with 98 // a persistent listener (if applicable). 99 class PersistentListenerConnectStressTest : public SocketPairTest { 100 protected: 101 PersistentListenerConnectStressTest() : slept_{false} {} 102 103 // NewSocketSleep is the same as NewSocketPair, but will sleep once (over the 104 // lifetime of the fixture) and retry if creation fails due to EADDRNOTAVAIL. 105 PosixErrorOr<std::unique_ptr<SocketPair>> NewSocketSleep() { 106 // We can't reuse a connection too close in time to its last use, as TCP 107 // uses the timestamp difference to disambiguate connections. With a 108 // sufficiently small port range, we'll cycle through too quickly, and TCP 109 // won't allow for connection reuse. Thus, we sleep the first time 110 // encountering EADDRINUSE to allow for that difference (1 second in 111 // gVisor). 112 PosixErrorOr<std::unique_ptr<SocketPair>> socks = NewSocketPair(); 113 if (socks.ok()) { 114 return socks; 115 } 116 if (!slept_ && socks.error().errno_value() == EADDRNOTAVAIL) { 117 absl::SleepFor(absl::Milliseconds(1500)); 118 slept_ = true; 119 return NewSocketPair(); 120 } 121 return socks; 122 } 123 124 private: 125 bool slept_; 126 }; 127 128 TEST_P(PersistentListenerConnectStressTest, ShutdownCloseFirst) { 129 const int nports = ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 130 for (int i = 0; i < nports * 2; i++) { 131 std::unique_ptr<SocketPair> sockets = 132 ASSERT_NO_ERRNO_AND_VALUE(NewSocketSleep()); 133 ASSERT_THAT(shutdown(sockets->first_fd(), SHUT_RDWR), SyscallSucceeds()); 134 if (GetParam().type == SOCK_STREAM) { 135 // Poll the other FD to make sure that we see the FIN from the other 136 // side before closing the second_fd. This ensures that the first_fd 137 // enters TIME-WAIT and not second_fd. 138 const int kTimeout = 10000; 139 struct pollfd pfd = { 140 .fd = sockets->second_fd(), 141 .events = POLL_IN, 142 }; 143 ASSERT_THAT(poll(&pfd, 1, kTimeout), SyscallSucceedsWithValue(1)); 144 } 145 ASSERT_THAT(shutdown(sockets->second_fd(), SHUT_RDWR), SyscallSucceeds()); 146 } 147 } 148 149 TEST_P(PersistentListenerConnectStressTest, ShutdownCloseSecond) { 150 const int nports = ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 151 for (int i = 0; i < nports * 2; i++) { 152 const std::unique_ptr<SocketPair> sockets = 153 ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 154 ASSERT_THAT(shutdown(sockets->second_fd(), SHUT_RDWR), SyscallSucceeds()); 155 if (GetParam().type == SOCK_STREAM) { 156 // Poll the other FD to make sure that we see the FIN from the other 157 // side before closing the first_fd. This ensures that the second_fd 158 // enters TIME-WAIT and not first_fd. 159 const int kTimeout = 10000; 160 struct pollfd pfd = { 161 .fd = sockets->first_fd(), 162 .events = POLL_IN, 163 }; 164 ASSERT_THAT(poll(&pfd, 1, kTimeout), SyscallSucceedsWithValue(1)); 165 } 166 ASSERT_THAT(shutdown(sockets->first_fd(), SHUT_RDWR), SyscallSucceeds()); 167 } 168 } 169 170 TEST_P(PersistentListenerConnectStressTest, Close) { 171 const int nports = ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 172 for (int i = 0; i < nports * 2; i++) { 173 std::unique_ptr<SocketPair> sockets = 174 ASSERT_NO_ERRNO_AND_VALUE(NewSocketSleep()); 175 } 176 } 177 178 INSTANTIATE_TEST_SUITE_P( 179 AllConnectedSockets, PersistentListenerConnectStressTest, 180 ::testing::Values( 181 IPv6UDPBidirectionalBindSocketPair(0), 182 IPv4UDPBidirectionalBindSocketPair(0), 183 DualStackUDPBidirectionalBindSocketPair(0), 184 185 // Without REUSEADDR, we get port exhaustion on Linux. 186 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &kSockOptOn)( 187 IPv6TCPAcceptBindPersistentListenerSocketPair(0)), 188 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &kSockOptOn)( 189 IPv4TCPAcceptBindPersistentListenerSocketPair(0)), 190 SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &kSockOptOn)( 191 DualStackTCPAcceptBindPersistentListenerSocketPair(0)))); 192 193 using DataTransferStressTest = SocketPairTest; 194 195 TEST_P(DataTransferStressTest, BigDataTransfer) { 196 // TODO(b/165912341): These are too slow on KVM platform with nested virt. 197 SKIP_IF(GvisorPlatform() == Platform::kKVM); 198 199 const std::unique_ptr<SocketPair> sockets = 200 ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 201 int client_fd = sockets->first_fd(); 202 int server_fd = sockets->second_fd(); 203 204 ScopedThread echo([server_fd]() { 205 std::array<uint8_t, 1024> buf; 206 for (;;) { 207 ssize_t r = read(server_fd, buf.data(), buf.size()); 208 ASSERT_THAT(r, SyscallSucceeds()); 209 if (r == 0) { 210 break; 211 } 212 for (size_t i = 0; i < r;) { 213 ssize_t w = write(server_fd, buf.data() + i, r - i); 214 ASSERT_GE(w, 0); 215 i += w; 216 } 217 } 218 ASSERT_THAT(shutdown(server_fd, SHUT_WR), SyscallSucceeds()); 219 }); 220 221 const std::string chunk = "Though this upload be but little, it is fierce."; 222 std::string big_string; 223 while (big_string.size() < 31 << 20) { 224 big_string += chunk; 225 } 226 absl::string_view data = big_string; 227 228 ScopedThread writer([client_fd, data]() { 229 absl::string_view view = data; 230 while (!view.empty()) { 231 ssize_t n = write(client_fd, view.data(), view.size()); 232 ASSERT_GE(n, 0); 233 view = view.substr(n); 234 } 235 ASSERT_THAT(shutdown(client_fd, SHUT_WR), SyscallSucceeds()); 236 }); 237 238 std::string buf; 239 buf.resize(1 << 20); 240 while (!data.empty()) { 241 ssize_t n = read(client_fd, buf.data(), buf.size()); 242 ASSERT_GE(n, 0); 243 for (size_t i = 0; i < n; i += chunk.size()) { 244 size_t c = std::min(chunk.size(), n - i); 245 ASSERT_EQ(buf.substr(i, c), data.substr(i, c)) << "offset " << i; 246 } 247 data = data.substr(n); 248 } 249 // Should read EOF now. 250 ASSERT_THAT(read(client_fd, buf.data(), buf.size()), 251 SyscallSucceedsWithValue(0)); 252 } 253 254 INSTANTIATE_TEST_SUITE_P( 255 AllConnectedSockets, DataTransferStressTest, 256 ::testing::Values(IPv6TCPAcceptBindPersistentListenerSocketPair(0), 257 IPv4TCPAcceptBindPersistentListenerSocketPair(0), 258 DualStackTCPAcceptBindPersistentListenerSocketPair(0))); 259 260 } // namespace testing 261 } // namespace gvisor