blob: 945f73cee3779f8cf25208e34539abb7e8be8c9f [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/tools/quic_client.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05006
7#include <dirent.h>
8#include <sys/types.h>
9
10#include <memory>
bnc463f2352019-10-10 04:49:34 -070011#include <utility>
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
vasilvv89fe24d2020-10-26 14:55:28 -070013#include "absl/strings/match.h"
vasilvv6c9e9c32020-10-08 08:16:57 -070014#include "absl/strings/string_view.h"
QUICHE team5be974e2020-12-29 18:35:24 -050015#include "quic/platform/api/quic_epoll.h"
QUICHE team5be974e2020-12-29 18:35:24 -050016#include "quic/platform/api/quic_test.h"
17#include "quic/platform/api/quic_test_loopback.h"
18#include "quic/test_tools/crypto_test_utils.h"
19#include "quic/test_tools/quic_client_peer.h"
bnc9de6abe2021-04-28 06:24:19 -070020#include "common/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021
22namespace quic {
23namespace test {
24namespace {
25
26const char* kPathToFds = "/proc/self/fd";
27
wubb5f75862022-03-02 08:35:58 -080028// Return the value of a symbolic link in |path|, if |path| is not found, return
29// an empty string.
vasilvvc48c8712019-03-11 13:38:16 -070030std::string ReadLink(const std::string& path) {
31 std::string result(PATH_MAX, '\0');
QUICHE teama6ef0a62019-03-07 20:34:33 -050032 ssize_t result_size = readlink(path.c_str(), &result[0], result.size());
wubb5f75862022-03-02 08:35:58 -080033 if (result_size < 0 && errno == ENOENT) {
34 return "";
35 }
vasilvvf8035162021-02-01 14:49:14 -080036 QUICHE_CHECK(result_size > 0 &&
wubb5f75862022-03-02 08:35:58 -080037 static_cast<size_t>(result_size) < result.size())
38 << "result_size:" << result_size << ", errno:" << errno
39 << ", path:" << path;
QUICHE teama6ef0a62019-03-07 20:34:33 -050040 result.resize(result_size);
41 return result;
42}
43
44// Counts the number of open sockets for the current process.
45size_t NumOpenSocketFDs() {
46 size_t socket_count = 0;
47 dirent* file;
48 std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds),
49 closedir);
50 while ((file = readdir(fd_directory.get())) != nullptr) {
vasilvv6c9e9c32020-10-08 08:16:57 -070051 absl::string_view name(file->d_name);
QUICHE teama6ef0a62019-03-07 20:34:33 -050052 if (name == "." || name == "..") {
53 continue;
54 }
55
vasilvv1ea0b542020-12-03 15:21:00 -080056 std::string fd_path = ReadLink(absl::StrCat(kPathToFds, "/", name));
vasilvv89fe24d2020-10-26 14:55:28 -070057 if (absl::StartsWith(fd_path, "socket:")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050058 socket_count++;
59 }
60 }
61 return socket_count;
62}
63
zhongyief8d1e92019-08-26 12:47:21 -070064class QuicClientTest : public QuicTest {
65 public:
66 QuicClientTest() {
67 // Creates and destroys a single client first which may open persistent
68 // sockets when initializing platform dependencies like certificate
69 // verifier. Future creation of addtional clients will deterministically
70 // open one socket per client.
71 CreateAndInitializeQuicClient();
72 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050073
zhongyief8d1e92019-08-26 12:47:21 -070074 // Creates a new QuicClient and Initializes it on an unused port.
75 // Caller is responsible for deletion.
76 std::unique_ptr<QuicClient> CreateAndInitializeQuicClient() {
rch2ba3b682022-03-21 06:55:34 -070077 QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), 0));
zhongyief8d1e92019-08-26 12:47:21 -070078 QuicServerId server_id("hostname", server_address.port(), false);
79 ParsedQuicVersionVector versions = AllSupportedVersions();
vasilvv0fc587f2019-09-06 13:33:08 -070080 auto client = std::make_unique<QuicClient>(
zhongyief8d1e92019-08-26 12:47:21 -070081 server_address, server_id, versions, &epoll_server_,
82 crypto_test_utils::ProofVerifierForTesting());
83 EXPECT_TRUE(client->Initialize());
84 return client;
85 }
86
87 private:
88 QuicEpollServer epoll_server_;
89};
QUICHE teama6ef0a62019-03-07 20:34:33 -050090
91TEST_F(QuicClientTest, DoNotLeakSocketFDs) {
92 // Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
93 // port exhaustion in long running processes which repeatedly create clients.
94
zhongyief8d1e92019-08-26 12:47:21 -070095 // Record the initial number of FDs.
QUICHE teama6ef0a62019-03-07 20:34:33 -050096 size_t number_of_open_fds = NumOpenSocketFDs();
97
98 // Create a number of clients, initialize them, and verify this has resulted
99 // in additional FDs being opened.
100 const int kNumClients = 50;
101 for (int i = 0; i < kNumClients; ++i) {
zhongyief8d1e92019-08-26 12:47:21 -0700102 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
103 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500104 // Initializing the client will create a new FD.
zhongyief8d1e92019-08-26 12:47:21 -0700105 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500106 }
107
108 // The FDs created by the QuicClients should now be closed.
109 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
110}
111
112TEST_F(QuicClientTest, CreateAndCleanUpUDPSockets) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 size_t number_of_open_fds = NumOpenSocketFDs();
114
zhongyief8d1e92019-08-26 12:47:21 -0700115 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
116 // Creating and initializing a client will result in one socket being opened.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
zhongyief8d1e92019-08-26 12:47:21 -0700118
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 // Create more UDP sockets.
120 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
121 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
122 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
123 EXPECT_EQ(number_of_open_fds + 3, NumOpenSocketFDs());
124
125 // Clean up UDP sockets.
126 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
127 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
128 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
129 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
130}
131
132} // namespace
133} // namespace test
134} // namespace quic