blob: 9d6a6cf2aaf5f6e51f26660a8fc0fb1c2d6d0536 [file] [log] [blame]
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "face/unix-stream-channel-factory.hpp"
8#include "core/scheduler.hpp"
9
10#include <ndn-cpp-dev/security/key-chain.hpp>
11
12#include <boost/test/unit_test.hpp>
13
14using namespace boost::asio::local;
15
16namespace nfd {
17
18BOOST_AUTO_TEST_SUITE(FaceUnixStream)
19
20BOOST_AUTO_TEST_CASE(ChannelMap)
21{
22 boost::asio::io_service io;
23 UnixStreamChannelFactory factory(io);
24
25 shared_ptr<UnixStreamChannel> channel1 = factory.create("foo");
26 shared_ptr<UnixStreamChannel> channel1a = factory.create("foo");
27 BOOST_CHECK_EQUAL(channel1, channel1a);
28
29 shared_ptr<UnixStreamChannel> channel2 = factory.create("bar");
30 BOOST_CHECK_NE(channel1, channel2);
31}
32
33class EndToEndFixture
34{
35public:
36 void
37 client_onConnect(const boost::system::error_code& error)
38 {
39 BOOST_CHECK_MESSAGE(!error, error.message());
40
41 this->afterIo();
42 }
43
44 void
45 channel1_onFaceCreated(const shared_ptr<UnixStreamFace>& newFace)
46 {
47 BOOST_CHECK(!static_cast<bool>(m_face1));
48 m_face1 = newFace;
49 m_face1->onReceiveInterest +=
50 bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
51 m_face1->onReceiveData +=
52 bind(&EndToEndFixture::face1_onReceiveData, this, _1);
53
54 this->afterIo();
55 }
56
57 void
58 channel1_onConnectFailed(const std::string& reason)
59 {
60 BOOST_CHECK_MESSAGE(false, reason);
61
62 this->afterIo();
63 }
Alexander Afanasyevbd220a02014-02-20 00:29:56 -080064
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010065 void
66 face1_onReceiveInterest(const Interest& interest)
67 {
68 m_face1_receivedInterests.push_back(interest);
69
70 this->afterIo();
71 }
Alexander Afanasyevbd220a02014-02-20 00:29:56 -080072
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010073 void
74 face1_onReceiveData(const Data& data)
75 {
76 m_face1_receivedDatas.push_back(data);
77
78 this->afterIo();
79 }
80
81 void
82 face2_onReceiveInterest(const Interest& interest)
83 {
84 m_face2_receivedInterests.push_back(interest);
85
86 this->afterIo();
87 }
Alexander Afanasyevbd220a02014-02-20 00:29:56 -080088
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010089 void
90 face2_onReceiveData(const Data& data)
91 {
92 m_face2_receivedDatas.push_back(data);
93
94 this->afterIo();
95 }
96
97 void
98 channel_onFaceCreated(const shared_ptr<UnixStreamFace>& newFace)
99 {
100 m_faces.push_back(newFace);
101
102 this->afterIo();
103 }
104
105 void
106 channel_onConnectFailed(const std::string& reason)
107 {
108 BOOST_CHECK_MESSAGE(false, reason);
109
110 this->afterIo();
111 }
112
113 void
114 abortTestCase(const std::string& message)
115 {
116 m_ioService.stop();
117 BOOST_FAIL(message);
118 }
119
120private:
121 void
122 afterIo()
123 {
124 if (--m_ioRemaining <= 0)
125 m_ioService.stop();
126 }
127
128protected:
129 boost::asio::io_service m_ioService;
130
131 int m_ioRemaining;
132
133 shared_ptr<UnixStreamFace> m_face1;
134 std::vector<Interest> m_face1_receivedInterests;
135 std::vector<Data> m_face1_receivedDatas;
136 shared_ptr<UnixStreamFace> m_face2;
137 std::vector<Interest> m_face2_receivedInterests;
138 std::vector<Data> m_face2_receivedDatas;
139
140 std::list< shared_ptr<UnixStreamFace> > m_faces;
141};
142
143
144BOOST_FIXTURE_TEST_CASE(EndToEnd, EndToEndFixture)
145{
146 UnixStreamChannelFactory factory(m_ioService);
147 Scheduler scheduler(m_ioService); // to limit the amount of time the test may take
148
149 EventId abortEvent =
150 scheduler.scheduleEvent(time::seconds(1),
151 bind(&EndToEndFixture::abortTestCase, this,
152 "UnixStreamChannel error: cannot connect or cannot accept connection"));
153
154 shared_ptr<UnixStreamChannel> channel1 = factory.create("foo");
155 channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated, this, _1),
156 bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
157
158 shared_ptr<stream_protocol::socket> client =
159 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
160 client->async_connect(stream_protocol::endpoint("foo"),
161 bind(&EndToEndFixture::client_onConnect, this, _1));
162
163 m_ioRemaining = 2;
164 m_ioService.run();
165 m_ioService.reset();
166 scheduler.cancelEvent(abortEvent);
167
168 BOOST_REQUIRE(static_cast<bool>(m_face1));
169
170 abortEvent =
171 scheduler.scheduleEvent(time::seconds(1),
172 bind(&EndToEndFixture::abortTestCase, this,
173 "UnixStreamChannel error: cannot send or receive Interest/Data packets"));
174
175 m_face2 = make_shared<UnixStreamFace>(client);
176 m_face2->onReceiveInterest +=
177 bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
178 m_face2->onReceiveData +=
179 bind(&EndToEndFixture::face2_onReceiveData, this, _1);
180
181 Interest interest1("ndn:/TpnzGvW9R");
182 Data data1 ("ndn:/KfczhUqVix");
183 data1.setContent(0, 0);
184 Interest interest2("ndn:/QWiIMfj5sL");
185 Data data2 ("ndn:/XNBV796f");
186 data2.setContent(0, 0);
187
188 ndn::SignatureSha256WithRsa fakeSignature;
189 fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
190
191 // set fake signature on data1 and data2
192 data1.setSignature(fakeSignature);
193 data2.setSignature(fakeSignature);
194
195 m_face1->sendInterest(interest1);
196 m_face1->sendData (data1 );
197 m_face2->sendInterest(interest2);
198 m_face2->sendData (data2 );
199
200 m_ioRemaining = 4;
201 m_ioService.run();
202 m_ioService.reset();
203
204 BOOST_REQUIRE_EQUAL(m_face1_receivedInterests.size(), 1);
205 BOOST_REQUIRE_EQUAL(m_face1_receivedDatas .size(), 1);
206 BOOST_REQUIRE_EQUAL(m_face2_receivedInterests.size(), 1);
207 BOOST_REQUIRE_EQUAL(m_face2_receivedDatas .size(), 1);
208
209 BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getName(), interest2.getName());
210 BOOST_CHECK_EQUAL(m_face1_receivedDatas [0].getName(), data2.getName());
211 BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getName(), interest1.getName());
212 BOOST_CHECK_EQUAL(m_face2_receivedDatas [0].getName(), data1.getName());
213}
214
215BOOST_FIXTURE_TEST_CASE(MultipleAccepts, EndToEndFixture)
216{
217 UnixStreamChannelFactory factory(m_ioService);
218 Scheduler scheduler(m_ioService); // to limit the amount of time the test may take
219
220 EventId abortEvent =
221 scheduler.scheduleEvent(time::seconds(1),
222 bind(&EndToEndFixture::abortTestCase, this,
223 "UnixStreamChannel error: cannot connect or cannot accept connection"));
224
225 shared_ptr<UnixStreamChannel> channel = factory.create("foo");
226 channel->listen(bind(&EndToEndFixture::channel_onFaceCreated, this, _1),
227 bind(&EndToEndFixture::channel_onConnectFailed, this, _1));
228
229 shared_ptr<stream_protocol::socket> client1 =
230 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
231 client1->async_connect(stream_protocol::endpoint("foo"),
232 bind(&EndToEndFixture::client_onConnect, this, _1));
233
234 m_ioRemaining = 2;
235 m_ioService.run();
236 m_ioService.reset();
237 scheduler.cancelEvent(abortEvent);
238
239 BOOST_CHECK_EQUAL(m_faces.size(), 1);
240
241 abortEvent =
242 scheduler.scheduleEvent(time::seconds(1),
243 bind(&EndToEndFixture::abortTestCase, this,
244 "UnixStreamChannel error: cannot accept multiple connections"));
245
246 shared_ptr<stream_protocol::socket> client2 =
247 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
248 client2->async_connect(stream_protocol::endpoint("foo"),
249 bind(&EndToEndFixture::client_onConnect, this, _1));
250
251 m_ioRemaining = 2;
252 m_ioService.run();
253 m_ioService.reset();
254 scheduler.cancelEvent(abortEvent);
255
256 BOOST_CHECK_EQUAL(m_faces.size(), 2);
257
258 // now close one of the faces
259 m_faces.front()->close();
260
261 // we should still be able to send/receive with the other one
262 m_face1 = m_faces.back();
263 m_face1->onReceiveInterest +=
264 bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
265 m_face1->onReceiveData +=
266 bind(&EndToEndFixture::face1_onReceiveData, this, _1);
267
268 m_face2 = make_shared<UnixStreamFace>(client2);
269 m_face2->onReceiveInterest +=
270 bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
271 m_face2->onReceiveData +=
272 bind(&EndToEndFixture::face2_onReceiveData, this, _1);
273
274 abortEvent =
275 scheduler.scheduleEvent(time::seconds(1),
276 bind(&EndToEndFixture::abortTestCase, this,
277 "UnixStreamChannel error: cannot send or receive Interest/Data packets"));
278
279 Interest interest1("ndn:/TpnzGvW9R");
280 Data data1 ("ndn:/KfczhUqVix");
281 data1.setContent(0, 0);
282 Interest interest2("ndn:/QWiIMfj5sL");
283 Data data2 ("ndn:/XNBV796f");
284 data2.setContent(0, 0);
285
286 ndn::SignatureSha256WithRsa fakeSignature;
287 fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
288
289 // set fake signature on data1 and data2
290 data1.setSignature(fakeSignature);
291 data2.setSignature(fakeSignature);
292
293 m_face1->sendInterest(interest1);
294 m_face1->sendData (data1 );
295 m_face2->sendInterest(interest2);
296 m_face2->sendData (data2 );
297
298 m_ioRemaining = 4;
299 m_ioService.run();
300 m_ioService.reset();
301
302 BOOST_REQUIRE_EQUAL(m_face1_receivedInterests.size(), 1);
303 BOOST_REQUIRE_EQUAL(m_face1_receivedDatas .size(), 1);
304 BOOST_REQUIRE_EQUAL(m_face2_receivedInterests.size(), 1);
305 BOOST_REQUIRE_EQUAL(m_face2_receivedDatas .size(), 1);
306
307 BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getName(), interest2.getName());
308 BOOST_CHECK_EQUAL(m_face1_receivedDatas [0].getName(), data2.getName());
309 BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getName(), interest1.getName());
310 BOOST_CHECK_EQUAL(m_face2_receivedDatas [0].getName(), data1.getName());
311}
312
Alexander Afanasyevbd220a02014-02-20 00:29:56 -0800313static inline void
314noOp()
315{
316}
317
318BOOST_FIXTURE_TEST_CASE(UnixStreamFaceLocalControlHeader, EndToEndFixture)
319{
320 UnixStreamChannelFactory factory(m_ioService);
321 Scheduler scheduler(m_ioService); // to limit the amount of time the test may take
322
323 EventId abortEvent =
324 scheduler.scheduleEvent(time::seconds(1),
325 bind(&EndToEndFixture::abortTestCase, this,
326 "UnixStreamChannel error: cannot connect or cannot accept connection"));
327
328 shared_ptr<UnixStreamChannel> channel1 = factory.create("foo");
329 channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated, this, _1),
330 bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
331
332 shared_ptr<stream_protocol::socket> client =
333 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
334 client->async_connect(stream_protocol::endpoint("foo"),
335 bind(&EndToEndFixture::client_onConnect, this, _1));
336
337 m_ioRemaining = 2;
338 m_ioService.run();
339 m_ioService.reset();
340 scheduler.cancelEvent(abortEvent);
341
342 BOOST_REQUIRE(static_cast<bool>(m_face1));
343
344 abortEvent =
345 scheduler.scheduleEvent(time::seconds(1),
346 bind(&EndToEndFixture::abortTestCase, this,
347 "UnixStreamChannel error: cannot send or receive Interest/Data packets"));
348
349 m_face2 = make_shared<UnixStreamFace>(client);
350 m_face2->onReceiveInterest +=
351 bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
352 m_face2->onReceiveData +=
353 bind(&EndToEndFixture::face2_onReceiveData, this, _1);
354
355 Interest interest1("ndn:/TpnzGvW9R");
356 Data data1 ("ndn:/KfczhUqVix");
357 data1.setContent(0, 0);
358 Interest interest2("ndn:/QWiIMfj5sL");
359 Data data2 ("ndn:/XNBV796f");
360 data2.setContent(0, 0);
361
362 ndn::SignatureSha256WithRsa fakeSignature;
363 fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
364
365 // set fake signature on data1 and data2
366 data1.setSignature(fakeSignature);
367 data2.setSignature(fakeSignature);
368
369 m_face1->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID);
370 m_face1->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID);
371
372 BOOST_CHECK(m_face1->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID));
373 BOOST_CHECK(m_face1->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
374
375 m_face2->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID);
376 m_face2->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID);
377
378 BOOST_CHECK(m_face2->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID));
379 BOOST_CHECK(m_face2->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
380
381 ////////////////////////////////////////////////////////
382
383 interest1.setIncomingFaceId(11);
384 interest1.setNextHopFaceId(111);
385
386 m_face1->sendInterest(interest1);
387
388 data1.setIncomingFaceId(22);
389 data1.getLocalControlHeader().setNextHopFaceId(222);
390
391 m_face1->sendData (data1);
392
393 //
394
395 m_ioRemaining = 2;
396 m_ioService.run();
397 m_ioService.reset();
398
399 BOOST_REQUIRE_EQUAL(m_face2_receivedInterests.size(), 1);
400 BOOST_REQUIRE_EQUAL(m_face2_receivedDatas .size(), 1);
401
402 // sending allows only IncomingFaceId, receiving allows only NextHopFaceId
403 BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getLocalControlHeader().hasIncomingFaceId(), false);
404 BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getLocalControlHeader().hasNextHopFaceId(), false);
405
406 BOOST_CHECK_EQUAL(m_face2_receivedDatas[0].getLocalControlHeader().hasIncomingFaceId(), false);
407 BOOST_CHECK_EQUAL(m_face2_receivedDatas[0].getLocalControlHeader().hasNextHopFaceId(), false);
408
409 ////////////////////////////////////////////////////////
410
411 using namespace boost::asio;
412
413 std::vector<const_buffer> interestWithHeader;
414 Block iHeader = interest1.getLocalControlHeader().wireEncode(interest1, true, true);
415 Block iPayload = interest1.wireEncode();
416 interestWithHeader.push_back(buffer(iHeader.wire(), iHeader.size()));
417 interestWithHeader.push_back(buffer(iPayload.wire(), iPayload.size()));
418
419 std::vector<const_buffer> dataWithHeader;
420 Block dHeader = data1.getLocalControlHeader().wireEncode(data1, true, true);
421 Block dPayload = data1.wireEncode();
422 dataWithHeader.push_back(buffer(dHeader.wire(), dHeader.size()));
423 dataWithHeader.push_back(buffer(dPayload.wire(), dPayload.size()));
424
425 //
426
427 client->async_send(interestWithHeader, bind(&noOp));
428 client->async_send(dataWithHeader, bind(&noOp));
429
430 m_ioRemaining = 2;
431 m_ioService.run();
432 m_ioService.reset();
433
434 BOOST_REQUIRE_EQUAL(m_face1_receivedInterests.size(), 1);
435 BOOST_REQUIRE_EQUAL(m_face1_receivedDatas .size(), 1);
436
437 BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getLocalControlHeader().hasIncomingFaceId(), false);
438 BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getLocalControlHeader().hasNextHopFaceId(), true);
439 BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getNextHopFaceId(), 111);
440
441 BOOST_CHECK_EQUAL(m_face1_receivedDatas[0].getLocalControlHeader().hasIncomingFaceId(), false);
442 BOOST_CHECK_EQUAL(m_face1_receivedDatas[0].getLocalControlHeader().hasNextHopFaceId(), false);
443}
444
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +0100445BOOST_AUTO_TEST_SUITE_END()
446
447} // namespace nfd