blob: 873d6ca5497797cc5d3e3db0fdee7fcd503edc3f [file] [log] [blame]
Yukai Tu16aabbc2015-10-06 05:08:42 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * 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
26#include "face/tcp-transport.hpp"
Eric Newberry8717e872015-11-23 12:41:50 -070027#include "face/lp-face.hpp"
Yukai Tu16aabbc2015-10-06 05:08:42 -070028
Eric Newberry8717e872015-11-23 12:41:50 -070029#include "dummy-receive-link-service.hpp"
30#include "get-available-interface-ip.hpp"
31#include "transport-test-common.hpp"
32
33#include "tests/limited-io.hpp"
Yukai Tu16aabbc2015-10-06 05:08:42 -070034
35namespace nfd {
36namespace face {
37namespace tests {
38
39using namespace nfd::tests;
40namespace ip = boost::asio::ip;
41using ip::tcp;
42
43BOOST_AUTO_TEST_SUITE(Face)
Yukai Tu16aabbc2015-10-06 05:08:42 -070044
Eric Newberry8717e872015-11-23 12:41:50 -070045class TcpTransportFixture : public BaseFixture
Yukai Tu16aabbc2015-10-06 05:08:42 -070046{
Eric Newberry8717e872015-11-23 12:41:50 -070047protected:
48 TcpTransportFixture()
49 : transport(nullptr)
50 , remoteSocket(g_io)
51 , receivedPackets(nullptr)
52 , acceptor(g_io)
53 {
54 }
Yukai Tu16aabbc2015-10-06 05:08:42 -070055
Eric Newberry8717e872015-11-23 12:41:50 -070056 void
57 initialize(ip::address address = ip::address_v4::loopback())
58 {
59 tcp::endpoint remoteEp(address, 7070);
60 acceptor.open(remoteEp.protocol());
61 acceptor.set_option(tcp::acceptor::reuse_address(true));
62 acceptor.bind(remoteEp);
63 acceptor.listen(1);
64 acceptor.async_accept(remoteSocket, bind([]{}));
Yukai Tu16aabbc2015-10-06 05:08:42 -070065
Eric Newberry8717e872015-11-23 12:41:50 -070066 tcp::socket sock(g_io);
67 sock.async_connect(remoteEp, [this] (const boost::system::error_code& error) {
68 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
69 limitedIo.afterOp();
70 });
71
72 BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
73
74 localEp = sock.local_endpoint();
75 face = make_unique<LpFace>(make_unique<DummyReceiveLinkService>(),
76 make_unique<TcpTransport>(std::move(sock),
77 ndn::nfd::FACE_PERSISTENCY_PERSISTENT));
78 transport = static_cast<TcpTransport*>(face->getTransport());
79 receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
80
81 BOOST_REQUIRE_EQUAL(transport->getState(), TransportState::UP);
82 }
83
84 void
85 remoteWrite(const ndn::Buffer& buf)
86 {
87 // use write() because socket::send() does not guarantee that all data is written before returning
88 BOOST_REQUIRE_EQUAL(boost::asio::write(remoteSocket, boost::asio::buffer(buf)), buf.size());
89 limitedIo.defer(time::milliseconds(50));
90 }
91
92protected:
93 LimitedIo limitedIo;
94 TcpTransport* transport;
95 tcp::endpoint localEp;
96 tcp::socket remoteSocket;
97 std::vector<Transport::Packet>* receivedPackets;
98
99private:
100 tcp::acceptor acceptor;
101 unique_ptr<LpFace> face;
102};
103
104BOOST_FIXTURE_TEST_SUITE(TestTcpTransport, TcpTransportFixture)
105
106BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv4)
107{
108 initialize();
109
110 checkStaticPropertiesInitialized(*transport);
111
112 BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("tcp4://127.0.0.1:" + to_string(localEp.port())));
113 BOOST_CHECK_EQUAL(transport->getRemoteUri(), FaceUri("tcp4://127.0.0.1:7070"));
114 BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_LOCAL);
115 BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
116 BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
117 BOOST_CHECK_EQUAL(transport->getMtu(), MTU_UNLIMITED);
Yukai Tu16aabbc2015-10-06 05:08:42 -0700118}
119
Eric Newberry8717e872015-11-23 12:41:50 -0700120BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv6)
Yukai Tu16aabbc2015-10-06 05:08:42 -0700121{
Eric Newberry8717e872015-11-23 12:41:50 -0700122 initialize(ip::address_v6::loopback());
Yukai Tu16aabbc2015-10-06 05:08:42 -0700123
Eric Newberry8717e872015-11-23 12:41:50 -0700124 checkStaticPropertiesInitialized(*transport);
Yukai Tu16aabbc2015-10-06 05:08:42 -0700125
Eric Newberry8717e872015-11-23 12:41:50 -0700126 BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("tcp6://[::1]:" + to_string(localEp.port())));
127 BOOST_CHECK_EQUAL(transport->getRemoteUri(), FaceUri("tcp6://[::1]:7070"));
128 BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_LOCAL);
129 BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
130 BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
131 BOOST_CHECK_EQUAL(transport->getMtu(), MTU_UNLIMITED);
132}
133
134BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv4)
135{
136 auto address = getAvailableInterfaceIp<ip::address_v4>();
137 SKIP_IF_IP_UNAVAILABLE(address);
138 initialize(address);
139
140 checkStaticPropertiesInitialized(*transport);
141
142 BOOST_CHECK_EQUAL(transport->getLocalUri(),
143 FaceUri("tcp4://" + address.to_string() + ":" + to_string(localEp.port())));
144 BOOST_CHECK_EQUAL(transport->getRemoteUri(),
145 FaceUri("tcp4://" + address.to_string() + ":7070"));
146 BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
147 BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
148 BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
149 BOOST_CHECK_EQUAL(transport->getMtu(), MTU_UNLIMITED);
150}
151
152BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv6)
153{
154 auto address = getAvailableInterfaceIp<ip::address_v6>();
155 SKIP_IF_IP_UNAVAILABLE(address);
156 initialize(address);
157
158 checkStaticPropertiesInitialized(*transport);
159
160 BOOST_CHECK_EQUAL(transport->getLocalUri(),
161 FaceUri("tcp6://[" + address.to_string() + "]:" + to_string(localEp.port())));
162 BOOST_CHECK_EQUAL(transport->getRemoteUri(),
163 FaceUri("tcp6://[" + address.to_string() + "]:7070"));
164 BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
165 BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
166 BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
167 BOOST_CHECK_EQUAL(transport->getMtu(), MTU_UNLIMITED);
168}
169
170BOOST_AUTO_TEST_CASE(Send)
171{
172 initialize();
173
174 auto block1 = ndn::encoding::makeStringBlock(300, "hello");
175 transport->send(Transport::Packet{Block{block1}}); // make a copy of the block
176 BOOST_CHECK_EQUAL(transport->getCounters().nOutPackets, 1);
177 BOOST_CHECK_EQUAL(transport->getCounters().nOutBytes, block1.size());
178
179 auto block2 = ndn::encoding::makeStringBlock(301, "world");
180 transport->send(Transport::Packet{Block{block2}}); // make a copy of the block
181 BOOST_CHECK_EQUAL(transport->getCounters().nOutPackets, 2);
182 BOOST_CHECK_EQUAL(transport->getCounters().nOutBytes, block1.size() + block2.size());
183
184 std::vector<uint8_t> readBuf(block1.size() + block2.size());
185 boost::asio::async_read(remoteSocket, boost::asio::buffer(readBuf),
186 [this] (const boost::system::error_code& error, size_t) {
187 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
188 limitedIo.afterOp();
189 });
190
191 BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
192
193 BOOST_CHECK_EQUAL_COLLECTIONS(readBuf.begin(), readBuf.begin() + block1.size(), block1.begin(), block1.end());
194 BOOST_CHECK_EQUAL_COLLECTIONS(readBuf.begin() + block1.size(), readBuf.end(), block2.begin(), block2.end());
195 BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
196}
197
198BOOST_AUTO_TEST_CASE(ReceiveNormal)
199{
200 initialize();
201
202 Block pkt = ndn::encoding::makeStringBlock(300, "hello");
203 ndn::Buffer buf(pkt.begin(), pkt.end());
204 remoteWrite(buf);
205
206 BOOST_CHECK_EQUAL(transport->getCounters().nInPackets, 1);
207 BOOST_CHECK_EQUAL(transport->getCounters().nInBytes, pkt.size());
208 BOOST_CHECK_EQUAL(receivedPackets->size(), 1);
209 BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
210}
211
212BOOST_AUTO_TEST_CASE(ReceiveMultipleSegments)
213{
214 initialize();
215
216 Block pkt = ndn::encoding::makeStringBlock(300, "hello");
217 ndn::Buffer buf1(pkt.begin(), pkt.end() - 2);
218 ndn::Buffer buf2(pkt.end() - 2, pkt.end());
219
220 remoteWrite(buf1);
221
222 BOOST_CHECK_EQUAL(transport->getCounters().nInPackets, 0);
223 BOOST_CHECK_EQUAL(transport->getCounters().nInBytes, 0);
224 BOOST_CHECK_EQUAL(receivedPackets->size(), 0);
225 BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
226
227 remoteWrite(buf2);
228
229 BOOST_CHECK_EQUAL(transport->getCounters().nInPackets, 1);
230 BOOST_CHECK_EQUAL(transport->getCounters().nInBytes, pkt.size());
231 BOOST_CHECK_EQUAL(receivedPackets->size(), 1);
232 BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
233}
234
235BOOST_AUTO_TEST_CASE(ReceiveMultipleBlocks)
236{
237 initialize();
238
239 Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
240 Block pkt2 = ndn::encoding::makeStringBlock(301, "world");
241 ndn::Buffer buf(pkt1.size() + pkt2.size());
242 std::copy(pkt1.begin(), pkt1.end(), buf.buf());
243 std::copy(pkt2.begin(), pkt2.end(), buf.buf() + pkt1.size());
244
245 remoteWrite(buf);
246
247 BOOST_CHECK_EQUAL(transport->getCounters().nInPackets, 2);
248 BOOST_CHECK_EQUAL(transport->getCounters().nInBytes, buf.size());
249 BOOST_CHECK_EQUAL(receivedPackets->size(), 2);
250 BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
251}
252
253BOOST_AUTO_TEST_CASE(ReceiveTooLarge)
254{
255 initialize();
256
257 std::vector<uint8_t> bytes(ndn::MAX_NDN_PACKET_SIZE + 1, 0);
258 Block pkt = ndn::encoding::makeBinaryBlock(300, bytes.data(), bytes.size());
259 ndn::Buffer buf(pkt.begin(), pkt.end());
260
261 remoteWrite(buf);
262
263 BOOST_CHECK_EQUAL(transport->getCounters().nInPackets, 0);
264 BOOST_CHECK_EQUAL(transport->getCounters().nInBytes, 0);
265 BOOST_CHECK_EQUAL(receivedPackets->size(), 0);
266 BOOST_CHECK_EQUAL(transport->getState(), TransportState::CLOSED);
267}
268
269BOOST_AUTO_TEST_CASE(Close)
270{
271 initialize();
272
273 transport->close();
274 BOOST_CHECK_EQUAL(transport->getState(), TransportState::CLOSING);
275
276 g_io.poll();
277 BOOST_CHECK_EQUAL(transport->getState(), TransportState::CLOSED);
278}
279
280BOOST_AUTO_TEST_CASE(RemoteClose)
281{
282 initialize();
283
284 transport->afterStateChange.connectSingleShot([this] (TransportState oldState, TransportState newState) {
285 BOOST_CHECK_EQUAL(oldState, TransportState::UP);
286 BOOST_CHECK_EQUAL(newState, TransportState::FAILED);
287 limitedIo.afterOp();
288 });
289
290 remoteSocket.close();
291 BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
292
293 g_io.poll();
294 BOOST_CHECK_EQUAL(transport->getState(), TransportState::CLOSED);
Yukai Tu16aabbc2015-10-06 05:08:42 -0700295}
296
297BOOST_AUTO_TEST_SUITE_END() // TestTcpTransport
298BOOST_AUTO_TEST_SUITE_END() // Face
299
300} // namespace tests
301} // namespace face
302} // namespace nfd