blob: 454efa349d5619331241ad5d85b97ca015ad1c78 [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
5#include "net/third_party/quiche/src/quic/tools/quic_client.h"
6
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 teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050019#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
20#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
QUICHE team5015e2e2019-12-11 09:38:06 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022
23namespace quic {
24namespace test {
25namespace {
26
27const char* kPathToFds = "/proc/self/fd";
28
vasilvvc48c8712019-03-11 13:38:16 -070029std::string ReadLink(const std::string& path) {
30 std::string result(PATH_MAX, '\0');
QUICHE teama6ef0a62019-03-07 20:34:33 -050031 ssize_t result_size = readlink(path.c_str(), &result[0], result.size());
32 CHECK(result_size > 0 && static_cast<size_t>(result_size) < result.size());
33 result.resize(result_size);
34 return result;
35}
36
37// Counts the number of open sockets for the current process.
38size_t NumOpenSocketFDs() {
39 size_t socket_count = 0;
40 dirent* file;
41 std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds),
42 closedir);
43 while ((file = readdir(fd_directory.get())) != nullptr) {
vasilvv6c9e9c32020-10-08 08:16:57 -070044 absl::string_view name(file->d_name);
QUICHE teama6ef0a62019-03-07 20:34:33 -050045 if (name == "." || name == "..") {
46 continue;
47 }
48
vasilvv1ea0b542020-12-03 15:21:00 -080049 std::string fd_path = ReadLink(absl::StrCat(kPathToFds, "/", name));
vasilvv89fe24d2020-10-26 14:55:28 -070050 if (absl::StartsWith(fd_path, "socket:")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050051 socket_count++;
52 }
53 }
54 return socket_count;
55}
56
zhongyief8d1e92019-08-26 12:47:21 -070057class QuicClientTest : public QuicTest {
58 public:
59 QuicClientTest() {
60 // Creates and destroys a single client first which may open persistent
61 // sockets when initializing platform dependencies like certificate
62 // verifier. Future creation of addtional clients will deterministically
63 // open one socket per client.
64 CreateAndInitializeQuicClient();
65 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050066
zhongyief8d1e92019-08-26 12:47:21 -070067 // Creates a new QuicClient and Initializes it on an unused port.
68 // Caller is responsible for deletion.
69 std::unique_ptr<QuicClient> CreateAndInitializeQuicClient() {
rch13cfcae2019-08-26 14:48:08 -070070 uint16_t port = QuicPickServerPortForTestsOrDie();
zhongyief8d1e92019-08-26 12:47:21 -070071 QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
72 QuicServerId server_id("hostname", server_address.port(), false);
73 ParsedQuicVersionVector versions = AllSupportedVersions();
vasilvv0fc587f2019-09-06 13:33:08 -070074 auto client = std::make_unique<QuicClient>(
zhongyief8d1e92019-08-26 12:47:21 -070075 server_address, server_id, versions, &epoll_server_,
76 crypto_test_utils::ProofVerifierForTesting());
77 EXPECT_TRUE(client->Initialize());
78 return client;
79 }
80
81 private:
82 QuicEpollServer epoll_server_;
83};
QUICHE teama6ef0a62019-03-07 20:34:33 -050084
85TEST_F(QuicClientTest, DoNotLeakSocketFDs) {
86 // Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
87 // port exhaustion in long running processes which repeatedly create clients.
88
zhongyief8d1e92019-08-26 12:47:21 -070089 // Record the initial number of FDs.
QUICHE teama6ef0a62019-03-07 20:34:33 -050090 size_t number_of_open_fds = NumOpenSocketFDs();
91
92 // Create a number of clients, initialize them, and verify this has resulted
93 // in additional FDs being opened.
94 const int kNumClients = 50;
95 for (int i = 0; i < kNumClients; ++i) {
zhongyief8d1e92019-08-26 12:47:21 -070096 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
97 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
QUICHE teama6ef0a62019-03-07 20:34:33 -050098 // Initializing the client will create a new FD.
zhongyief8d1e92019-08-26 12:47:21 -070099 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100 }
101
102 // The FDs created by the QuicClients should now be closed.
103 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
104}
105
106TEST_F(QuicClientTest, CreateAndCleanUpUDPSockets) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500107 size_t number_of_open_fds = NumOpenSocketFDs();
108
zhongyief8d1e92019-08-26 12:47:21 -0700109 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
110 // Creating and initializing a client will result in one socket being opened.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
zhongyief8d1e92019-08-26 12:47:21 -0700112
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 // Create more UDP sockets.
114 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
115 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
116 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
117 EXPECT_EQ(number_of_open_fds + 3, NumOpenSocketFDs());
118
119 // Clean up UDP sockets.
120 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
121 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
122 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
123 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
124}
125
126} // namespace
127} // namespace test
128} // namespace quic