xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/tools/quic_default_client_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This unit test relies on /proc, which is not available on non-Linux based
6 // OSes that we support.
7 #if defined(__linux__)
8 
9 #include "quiche/quic/tools/quic_default_client.h"
10 
11 #include <dirent.h>
12 #include <sys/types.h>
13 
14 #include <memory>
15 #include <utility>
16 
17 #include "absl/strings/match.h"
18 #include "absl/strings/string_view.h"
19 #include "quiche/quic/core/io/quic_default_event_loop.h"
20 #include "quiche/quic/core/io/quic_event_loop.h"
21 #include "quiche/quic/core/quic_default_clock.h"
22 #include "quiche/quic/platform/api/quic_test.h"
23 #include "quiche/quic/platform/api/quic_test_loopback.h"
24 #include "quiche/quic/test_tools/crypto_test_utils.h"
25 #include "quiche/common/quiche_text_utils.h"
26 
27 namespace quic {
28 namespace test {
29 namespace {
30 
31 const char* kPathToFds = "/proc/self/fd";
32 
33 // Return the value of a symbolic link in |path|, if |path| is not found, return
34 // an empty string.
ReadLink(const std::string & path)35 std::string ReadLink(const std::string& path) {
36   std::string result(PATH_MAX, '\0');
37   ssize_t result_size = readlink(path.c_str(), &result[0], result.size());
38   if (result_size < 0 && errno == ENOENT) {
39     return "";
40   }
41   QUICHE_CHECK(result_size > 0 &&
42                static_cast<size_t>(result_size) < result.size())
43       << "result_size:" << result_size << ", errno:" << errno
44       << ", path:" << path;
45   result.resize(result_size);
46   return result;
47 }
48 
49 // Counts the number of open sockets for the current process.
NumOpenSocketFDs()50 size_t NumOpenSocketFDs() {
51   size_t socket_count = 0;
52   dirent* file;
53   std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds),
54                                                    closedir);
55   while ((file = readdir(fd_directory.get())) != nullptr) {
56     absl::string_view name(file->d_name);
57     if (name == "." || name == "..") {
58       continue;
59     }
60 
61     std::string fd_path = ReadLink(absl::StrCat(kPathToFds, "/", name));
62     if (absl::StartsWith(fd_path, "socket:")) {
63       socket_count++;
64     }
65   }
66   return socket_count;
67 }
68 
69 class QuicDefaultClientTest : public QuicTest {
70  public:
QuicDefaultClientTest()71   QuicDefaultClientTest()
72       : event_loop_(GetDefaultEventLoop()->Create(QuicDefaultClock::Get())) {
73     // Creates and destroys a single client first which may open persistent
74     // sockets when initializing platform dependencies like certificate
75     // verifier. Future creation of addtional clients will deterministically
76     // open one socket per client.
77     CreateAndInitializeQuicClient();
78   }
79 
80   // Creates a new QuicClient and Initializes it on an unused port.
81   // Caller is responsible for deletion.
CreateAndInitializeQuicClient()82   std::unique_ptr<QuicDefaultClient> CreateAndInitializeQuicClient() {
83     QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), 0));
84     QuicServerId server_id("hostname", server_address.port(), false);
85     ParsedQuicVersionVector versions = AllSupportedVersions();
86     auto client = std::make_unique<QuicDefaultClient>(
87         server_address, server_id, versions, event_loop_.get(),
88         crypto_test_utils::ProofVerifierForTesting());
89     EXPECT_TRUE(client->Initialize());
90     return client;
91   }
92 
93  private:
94   std::unique_ptr<QuicEventLoop> event_loop_;
95 };
96 
TEST_F(QuicDefaultClientTest,DoNotLeakSocketFDs)97 TEST_F(QuicDefaultClientTest, DoNotLeakSocketFDs) {
98   // Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
99   // port exhaustion in long running processes which repeatedly create clients.
100 
101   // Record the initial number of FDs.
102   size_t number_of_open_fds = NumOpenSocketFDs();
103 
104   // Create a number of clients, initialize them, and verify this has resulted
105   // in additional FDs being opened.
106   const int kNumClients = 50;
107   for (int i = 0; i < kNumClients; ++i) {
108     EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
109     std::unique_ptr<QuicDefaultClient> client(CreateAndInitializeQuicClient());
110     // Initializing the client will create a new FD.
111     EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
112   }
113 
114   // The FDs created by the QuicClients should now be closed.
115   EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
116 }
117 
TEST_F(QuicDefaultClientTest,CreateAndCleanUpUDPSockets)118 TEST_F(QuicDefaultClientTest, CreateAndCleanUpUDPSockets) {
119   size_t number_of_open_fds = NumOpenSocketFDs();
120 
121   std::unique_ptr<QuicDefaultClient> client(CreateAndInitializeQuicClient());
122   // Creating and initializing a client will result in one socket being opened.
123   EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
124 
125   // Create more UDP sockets.
126   EXPECT_TRUE(client->default_network_helper()->CreateUDPSocketAndBind(
127       client->server_address(), client->bind_to_address(),
128       client->local_port()));
129   EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
130   EXPECT_TRUE(client->default_network_helper()->CreateUDPSocketAndBind(
131       client->server_address(), client->bind_to_address(),
132       client->local_port()));
133   EXPECT_EQ(number_of_open_fds + 3, NumOpenSocketFDs());
134 
135   // Clean up UDP sockets.
136   client->default_network_helper()->CleanUpUDPSocket(client->GetLatestFD());
137   EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
138   client->default_network_helper()->CleanUpUDPSocket(client->GetLatestFD());
139   EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
140 }
141 
142 }  // namespace
143 }  // namespace test
144 }  // namespace quic
145 
146 #endif  // defined(__linux__)
147