blob: b1923b67c7c4c1738afaffc3c38034e1cc50e46d [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
13#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
18#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
QUICHE team5015e2e2019-12-11 09:38:06 -080019#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
20#include "net/third_party/quiche/src/common/platform/api/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
vasilvvc48c8712019-03-11 13:38:16 -070028std::string ReadLink(const std::string& path) {
29 std::string result(PATH_MAX, '\0');
QUICHE teama6ef0a62019-03-07 20:34:33 -050030 ssize_t result_size = readlink(path.c_str(), &result[0], result.size());
31 CHECK(result_size > 0 && static_cast<size_t>(result_size) < result.size());
32 result.resize(result_size);
33 return result;
34}
35
36// Counts the number of open sockets for the current process.
37size_t NumOpenSocketFDs() {
38 size_t socket_count = 0;
39 dirent* file;
40 std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds),
41 closedir);
42 while ((file = readdir(fd_directory.get())) != nullptr) {
QUICHE team5015e2e2019-12-11 09:38:06 -080043 quiche::QuicheStringPiece name(file->d_name);
QUICHE teama6ef0a62019-03-07 20:34:33 -050044 if (name == "." || name == "..") {
45 continue;
46 }
47
QUICHE team5015e2e2019-12-11 09:38:06 -080048 std::string fd_path = ReadLink(quiche::QuicheStrCat(kPathToFds, "/", name));
49 if (quiche::QuicheTextUtils::StartsWith(fd_path, "socket:")) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050050 socket_count++;
51 }
52 }
53 return socket_count;
54}
55
zhongyief8d1e92019-08-26 12:47:21 -070056class QuicClientTest : public QuicTest {
57 public:
58 QuicClientTest() {
59 // Creates and destroys a single client first which may open persistent
60 // sockets when initializing platform dependencies like certificate
61 // verifier. Future creation of addtional clients will deterministically
62 // open one socket per client.
63 CreateAndInitializeQuicClient();
64 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050065
zhongyief8d1e92019-08-26 12:47:21 -070066 // Creates a new QuicClient and Initializes it on an unused port.
67 // Caller is responsible for deletion.
68 std::unique_ptr<QuicClient> CreateAndInitializeQuicClient() {
rch13cfcae2019-08-26 14:48:08 -070069 uint16_t port = QuicPickServerPortForTestsOrDie();
zhongyief8d1e92019-08-26 12:47:21 -070070 QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port));
71 QuicServerId server_id("hostname", server_address.port(), false);
72 ParsedQuicVersionVector versions = AllSupportedVersions();
vasilvv0fc587f2019-09-06 13:33:08 -070073 auto client = std::make_unique<QuicClient>(
zhongyief8d1e92019-08-26 12:47:21 -070074 server_address, server_id, versions, &epoll_server_,
75 crypto_test_utils::ProofVerifierForTesting());
76 EXPECT_TRUE(client->Initialize());
77 return client;
78 }
79
80 private:
81 QuicEpollServer epoll_server_;
82};
QUICHE teama6ef0a62019-03-07 20:34:33 -050083
84TEST_F(QuicClientTest, DoNotLeakSocketFDs) {
85 // Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause
86 // port exhaustion in long running processes which repeatedly create clients.
87
zhongyief8d1e92019-08-26 12:47:21 -070088 // Record the initial number of FDs.
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 size_t number_of_open_fds = NumOpenSocketFDs();
90
91 // Create a number of clients, initialize them, and verify this has resulted
92 // in additional FDs being opened.
93 const int kNumClients = 50;
94 for (int i = 0; i < kNumClients; ++i) {
zhongyief8d1e92019-08-26 12:47:21 -070095 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
96 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 // Initializing the client will create a new FD.
zhongyief8d1e92019-08-26 12:47:21 -070098 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
QUICHE teama6ef0a62019-03-07 20:34:33 -050099 }
100
101 // The FDs created by the QuicClients should now be closed.
102 EXPECT_EQ(number_of_open_fds, NumOpenSocketFDs());
103}
104
105TEST_F(QuicClientTest, CreateAndCleanUpUDPSockets) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500106 size_t number_of_open_fds = NumOpenSocketFDs();
107
zhongyief8d1e92019-08-26 12:47:21 -0700108 std::unique_ptr<QuicClient> client(CreateAndInitializeQuicClient());
109 // Creating and initializing a client will result in one socket being opened.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
zhongyief8d1e92019-08-26 12:47:21 -0700111
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 // Create more UDP sockets.
113 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
114 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
115 EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
116 EXPECT_EQ(number_of_open_fds + 3, NumOpenSocketFDs());
117
118 // Clean up UDP sockets.
119 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
120 EXPECT_EQ(number_of_open_fds + 2, NumOpenSocketFDs());
121 QuicClientPeer::CleanUpUDPSocket(client.get(), client->GetLatestFD());
122 EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs());
123}
124
125} // namespace
126} // namespace test
127} // namespace quic