blob: 9e52dfd493c26593f500bfc8384ce58ca06fb4dd [file] [log] [blame]
Yukai Tu16aabbc2015-10-06 05:08:42 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi84d62cb2017-07-12 16:15:18 +00002/*
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -04003 * Copyright (c) 2014-2022, Regents of the University of California,
Yukai Tu16aabbc2015-10-06 05:08:42 -07004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Eric Newberryf68f3782015-12-11 00:31:32 -070026#include "tcp-transport-fixture.hpp"
Yukai Tu16aabbc2015-10-06 05:08:42 -070027
Davide Pesavento22fba352017-10-17 15:53:51 -040028#include <boost/mpl/vector.hpp>
29
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040030namespace nfd::tests {
31
32using namespace nfd::face;
Yukai Tu16aabbc2015-10-06 05:08:42 -070033
Yukai Tu16aabbc2015-10-06 05:08:42 -070034BOOST_AUTO_TEST_SUITE(Face)
Davide Pesavento22fba352017-10-17 15:53:51 -040035BOOST_FIXTURE_TEST_SUITE(TestTcpTransport, IpTransportFixture<TcpTransportFixture>)
Eric Newberry8717e872015-11-23 12:41:50 -070036
Davide Pesavento22fba352017-10-17 15:53:51 -040037using TcpTransportFixtures = boost::mpl::vector<
38 GENERATE_IP_TRANSPORT_FIXTURE_INSTANTIATIONS(TcpTransportFixture)
39>;
40
41BOOST_FIXTURE_TEST_CASE_TEMPLATE(StaticProperties, T, TcpTransportFixtures, T)
Eric Newberry8717e872015-11-23 12:41:50 -070042{
Davide Pesavento22fba352017-10-17 15:53:51 -040043 TRANSPORT_TEST_INIT();
Eric Newberry8717e872015-11-23 12:41:50 -070044
Davide Pesavento22fba352017-10-17 15:53:51 -040045 checkStaticPropertiesInitialized(*this->transport);
Eric Newberry8717e872015-11-23 12:41:50 -070046
Davide Pesavento22fba352017-10-17 15:53:51 -040047 BOOST_CHECK_EQUAL(this->transport->getLocalUri(), FaceUri(tcp::endpoint(this->address, this->localEp.port())));
48 BOOST_CHECK_EQUAL(this->transport->getRemoteUri(), FaceUri(tcp::endpoint(this->address, 7070)));
49 BOOST_CHECK_EQUAL(this->transport->getScope(),
50 this->addressScope == AddressScope::Loopback ? ndn::nfd::FACE_SCOPE_LOCAL
51 : ndn::nfd::FACE_SCOPE_NON_LOCAL);
52 BOOST_CHECK_EQUAL(this->transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
53 BOOST_CHECK_EQUAL(this->transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
54 BOOST_CHECK_EQUAL(this->transport->getMtu(), MTU_UNLIMITED);
Eric Newberryb49313d2017-12-24 20:22:27 -070055 BOOST_CHECK_EQUAL(this->transport->getSendQueueCapacity(), QUEUE_UNSUPPORTED);
Eric Newberry8717e872015-11-23 12:41:50 -070056}
57
Davide Pesavento32065652017-01-15 01:52:21 -050058BOOST_AUTO_TEST_CASE(PersistencyChange)
59{
Davide Pesavento22fba352017-10-17 15:53:51 -040060 TRANSPORT_TEST_INIT();
Davide Pesavento32065652017-01-15 01:52:21 -050061
62 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), true);
63 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), true);
64 BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
65}
66
Weiwei Liudcdf6212016-08-31 14:34:22 -070067BOOST_AUTO_TEST_CASE(ChangePersistencyFromPermanentWhenDown)
68{
69 // when persistency is changed out of permanent while transport is DOWN,
70 // the transport immediately goes into FAILED state
71
Davide Pesavento22fba352017-10-17 15:53:51 -040072 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Weiwei Liudcdf6212016-08-31 14:34:22 -070073
Davide Pesavento22fba352017-10-17 15:53:51 -040074 transport->afterStateChange.connectSingleShot(
Davide Pesaventob3a23ca2019-05-04 20:40:21 -040075 [this] (auto oldState, auto newState) {
Davide Pesavento22fba352017-10-17 15:53:51 -040076 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
77 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
Davide Pesaventob3a23ca2019-05-04 20:40:21 -040078 this->limitedIo.afterOp();
Davide Pesavento22fba352017-10-17 15:53:51 -040079 });
Weiwei Liudcdf6212016-08-31 14:34:22 -070080 remoteSocket.close();
Davide Pesavento00335782018-02-10 22:31:33 -050081 BOOST_REQUIRE_EQUAL(limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -070082
83 bool didStateChange = false;
84 transport->afterStateChange.connectSingleShot(
Davide Pesaventob3a23ca2019-05-04 20:40:21 -040085 [&didStateChange] (auto oldState, auto newState) {
Weiwei Liudcdf6212016-08-31 14:34:22 -070086 didStateChange = true;
87 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
88 BOOST_CHECK_EQUAL(newState, TransportState::FAILED);
89 });
90 transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
91 BOOST_CHECK(didStateChange);
92}
93
Davide Pesavento22fba352017-10-17 15:53:51 -040094BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnect, T, TcpTransportFixtures, T)
95{
96 TRANSPORT_TEST_INIT(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
97
98 this->transport->afterStateChange.connectSingleShot(
Davide Pesaventob3a23ca2019-05-04 20:40:21 -040099 [this] (auto oldState, auto newState) {
Davide Pesavento22fba352017-10-17 15:53:51 -0400100 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
101 BOOST_CHECK_EQUAL(newState, TransportState::DOWN);
102 this->limitedIo.afterOp();
103 });
104 this->remoteSocket.close();
Davide Pesavento00335782018-02-10 22:31:33 -0500105 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesavento22fba352017-10-17 15:53:51 -0400106
107 this->transport->afterStateChange.connectSingleShot(
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400108 [this] (auto oldState, auto newState) {
Davide Pesavento22fba352017-10-17 15:53:51 -0400109 BOOST_CHECK_EQUAL(oldState, TransportState::DOWN);
110 BOOST_CHECK_EQUAL(newState, TransportState::UP);
111 this->limitedIo.afterOp();
112 });
Davide Pesavento00335782018-02-10 22:31:33 -0500113 BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesavento22fba352017-10-17 15:53:51 -0400114}
115
Weiwei Liudcdf6212016-08-31 14:34:22 -0700116class PermanentTcpTransportReconnectObserver : public TcpTransport
117{
118public:
119 PermanentTcpTransportReconnectObserver(protocol::socket&& socket, LimitedIo& io)
Alexander Afanasyevded17422018-04-03 19:00:23 -0400120 : TcpTransport(std::move(socket), ndn::nfd::FACE_PERSISTENCY_PERMANENT, ndn::nfd::FACE_SCOPE_LOCAL)
Weiwei Liudcdf6212016-08-31 14:34:22 -0700121 , m_io(io)
122 {
123 }
124
125protected:
126 void
127 reconnect() final
128 {
129 TcpTransport::reconnect();
130 m_io.afterOp();
131 }
132
133 void
134 handleReconnect(const boost::system::error_code& error) final
135 {
136 TcpTransport::handleReconnect(error);
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400137
138 // don't count this invocation as an "op" if the reconnection attempt failed,
139 // because in that case we will instead count the handleReconnectTimeout()
140 // that will eventually be called as well
141 if (getState() == TransportState::UP)
142 m_io.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700143 }
144
145 void
146 handleReconnectTimeout() final
147 {
148 TcpTransport::handleReconnectTimeout();
149 m_io.afterOp();
150 }
151
152private:
153 LimitedIo& m_io;
154};
155
156static double
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400157asFloatMilliseconds(time::nanoseconds t)
Weiwei Liudcdf6212016-08-31 14:34:22 -0700158{
159 return static_cast<double>(t.count()) / 1000000.0;
160}
161
Davide Pesavento22fba352017-10-17 15:53:51 -0400162BOOST_FIXTURE_TEST_CASE_TEMPLATE(PermanentReconnectWithExponentialBackoff, T, TcpTransportFixtures, T)
Weiwei Liudcdf6212016-08-31 14:34:22 -0700163{
Davide Pesavento22fba352017-10-17 15:53:51 -0400164 TRANSPORT_TEST_CHECK_PRECONDITIONS();
165 // do not initialize
Weiwei Liudcdf6212016-08-31 14:34:22 -0700166
Davide Pesavento22fba352017-10-17 15:53:51 -0400167 tcp::endpoint remoteEp(this->address, 7070);
168 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700169
Davide Pesavento22fba352017-10-17 15:53:51 -0400170 tcp::socket sock(this->g_io);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700171 sock.async_connect(remoteEp, [this] (const boost::system::error_code& error) {
172 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
Davide Pesavento22fba352017-10-17 15:53:51 -0400173 this->limitedIo.afterOp();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700174 });
Davide Pesavento00335782018-02-10 22:31:33 -0500175 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700176
Davide Pesavento22fba352017-10-17 15:53:51 -0400177 auto transportObserver =
Alexander Afanasyeva6bd7da2019-04-25 17:26:11 -0400178 make_unique<PermanentTcpTransportReconnectObserver>(std::move(sock), this->limitedIo);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700179 BOOST_REQUIRE_EQUAL(transportObserver->getState(), TransportState::UP);
180
181 // break the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400182 this->stopAccept();
183 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700184
185 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700186 auto retryTime1 = time::steady_clock::now();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700187
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400188 auto expectedWait1 = TcpTransport::INITIAL_RECONNECT_DELAY;
Davide Pesavento00335782018-02-10 22:31:33 -0500189 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400190 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700191 auto retryTime2 = time::steady_clock::now();
192 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
193
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400194 auto expectedWait2 = time::duration_cast<time::nanoseconds>(expectedWait1 *
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400195 TcpTransport::RECONNECT_DELAY_MULTIPLIER);
Davide Pesavento00335782018-02-10 22:31:33 -0500196 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait2 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400197 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700198 auto retryTime3 = time::steady_clock::now();
199 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
200
201 // check that the backoff algorithm works
202 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime2 - retryTime1),
Davide Pesavento00335782018-02-10 22:31:33 -0500203 asFloatMilliseconds(expectedWait1), 20.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700204 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime3 - retryTime2),
Davide Pesavento00335782018-02-10 22:31:33 -0500205 asFloatMilliseconds(expectedWait2), 10.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700206
207 // reestablish the TCP connection
Davide Pesavento22fba352017-10-17 15:53:51 -0400208 this->startAccept(remoteEp);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700209
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400210 auto expectedWait3 = time::duration_cast<time::nanoseconds>(expectedWait2 *
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400211 TcpTransport::RECONNECT_DELAY_MULTIPLIER);
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400212 BOOST_REQUIRE_EQUAL(this->limitedIo.run(3, // reconnect, handleReconnect, async_accept
Davide Pesavento00335782018-02-10 22:31:33 -0500213 expectedWait3 + 1_s), LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700214 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::UP);
215
216 // break the TCP connection again
Davide Pesavento22fba352017-10-17 15:53:51 -0400217 this->stopAccept();
218 this->remoteSocket.close();
Weiwei Liudcdf6212016-08-31 14:34:22 -0700219
220 // measure retry intervals
Weiwei Liudcdf6212016-08-31 14:34:22 -0700221 auto retryTime4 = time::steady_clock::now();
Davide Pesavento00335782018-02-10 22:31:33 -0500222 BOOST_REQUIRE_EQUAL(this->limitedIo.run(2, expectedWait1 + 1_s), // add some slack
Davide Pesaventobc79bd62017-10-28 01:52:16 -0400223 LimitedIo::EXCEED_OPS);
Weiwei Liudcdf6212016-08-31 14:34:22 -0700224 auto retryTime5 = time::steady_clock::now();
225 BOOST_CHECK_EQUAL(transportObserver->getState(), TransportState::DOWN);
226
227 // check that the timeout restarts from the initial value after a successful reconnection
228 BOOST_CHECK_CLOSE(asFloatMilliseconds(retryTime5 - retryTime4),
Davide Pesavento00335782018-02-10 22:31:33 -0500229 asFloatMilliseconds(expectedWait1), 20.0); // 200ms tolerance
Weiwei Liudcdf6212016-08-31 14:34:22 -0700230}
231
Yukai Tu16aabbc2015-10-06 05:08:42 -0700232BOOST_AUTO_TEST_SUITE_END() // TestTcpTransport
233BOOST_AUTO_TEST_SUITE_END() // Face
234
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400235} // namespace nfd::tests