blob: 7e62fe4a2c2ca1bc1325603635ed930401915c1f [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -07005 * See COPYING for copyright and distribution information.
6 */
7
Alexander Afanasyev0222fba2014-02-09 23:16:02 -08008#include "common.hpp"
9
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080010#include "face.hpp"
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -070011
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080012#include "security/signature-sha256-with-rsa.hpp"
13
14#include "util/time.hpp"
15#include "util/random.hpp"
16
17#include "management/ndnd-controller.hpp"
18#include "management/nfd-controller.hpp"
Jeff Thompsonb982b6d2013-07-15 18:15:45 -070019
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -070020namespace ndn {
Alexander Afanasyevb790d952014-01-24 12:07:53 -080021
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080022Face::Face(bool nfdMode/* = false*/)
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070023{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080024 construct(shared_ptr<Transport>(new UnixTransport()),
25 make_shared<boost::asio::io_service>(), nfdMode);
26}
27
28Face::Face(const shared_ptr<boost::asio::io_service> &ioService, bool nfdMode/* = false*/)
29{
30 construct(shared_ptr<Transport>(new UnixTransport()),
31 ioService, nfdMode);
32}
33
34Face::Face(const std::string &host, const std::string &port/* = "6363"*/, bool nfdMode/* = false*/)
35{
36 construct(shared_ptr<Transport>(new TcpTransport(host, port)),
37 make_shared<boost::asio::io_service>(), nfdMode);
38}
39
40Face::Face(const shared_ptr<Transport>& transport, bool nfdMode/* = false*/)
41{
42 construct(transport,
43 make_shared<boost::asio::io_service>(), nfdMode);
44}
45
46Face::Face(const shared_ptr<Transport>& transport,
47 const shared_ptr<boost::asio::io_service> &ioService,
48 bool nfdMode/* = false*/)
49{
50 construct(transport, ioService, nfdMode);
51}
52
53void
54Face::construct(const shared_ptr<Transport>& transport,
55 const shared_ptr<boost::asio::io_service> &ioService,
56 bool nfdMode)
57{
58 pitTimeoutCheckTimerActive_ = false;
59 transport_ = transport;
60 ioService_ = ioService;
61
62 pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
63 processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
64
65 if (nfdMode)
66 m_fwController = make_shared<nfd::Controller>(boost::ref(*this));
Jeff Thompsonfb29cda2013-08-24 10:26:54 -070067 else
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080068 m_fwController = make_shared<ndnd::Controller>(boost::ref(*this));
69}
70
71
72const PendingInterestId*
73Face::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
74{
75 if (!transport_->isConnected())
76 transport_->connect(*ioService_,
77 bind(&Face::onReceiveElement, this, _1));
78
79 shared_ptr<const Interest> interestToExpress(new Interest(interest));
80
81 ioService_->post(bind(&Face::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
82
83 return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
84}
85
86const PendingInterestId*
87Face::expressInterest(const Name& name,
88 const Interest &tmpl,
89 const OnData& onData, const OnTimeout& onTimeout/* = OnTimeout()*/)
90{
91 return expressInterest(Interest(name,
92 tmpl.getMinSuffixComponents(),
93 tmpl.getMaxSuffixComponents(),
94 tmpl.getExclude(),
95 tmpl.getChildSelector(),
96 tmpl.getMustBeFresh(),
97 tmpl.getScope(),
98 tmpl.getInterestLifetime()),
99 onData, onTimeout);
100}
101
102void
103Face::asyncExpressInterest(const shared_ptr<const Interest> &interest,
104 const OnData& onData, const OnTimeout& onTimeout)
105{
106 pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
107 (interest, onData, onTimeout)));
108
109 transport_->send(interest->wireEncode());
110
111 if (!pitTimeoutCheckTimerActive_) {
112 pitTimeoutCheckTimerActive_ = true;
113 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
114 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
115 }
116}
117
118void
119Face::put(const Data &data)
120{
121 if (!transport_->isConnected())
122 transport_->connect(*ioService_,
123 bind(&Face::onReceiveElement, this, _1));
124
125 transport_->send(data.wireEncode());
126}
127
128
129void
130Face::removePendingInterest(const PendingInterestId *pendingInterestId)
131{
132 ioService_->post(bind(&Face::asyncRemovePendingInterest, this, pendingInterestId));
133}
134
135
136void
137Face::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
138{
139 pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
140}
141
142const RegisteredPrefixId*
143Face::setInterestFilter(const Name& prefix,
144 const OnInterest& onInterest,
145 const OnSetInterestFilterFailed& onSetInterestFilterFailed)
146{
147 shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
148
149 m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
150 bind(&RegisteredPrefixTable::push_back, &registeredPrefixTable_, prefixToRegister),
151 bind(onSetInterestFilterFailed, prefixToRegister->getPrefix(), _1));
152
153 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
154}
155
156void
157Face::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
158{
159 ioService_->post(bind(&Face::asyncUnsetInterestFilter, this, registeredPrefixId));
160}
161
162void
163Face::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
164{
165 RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
166 MatchRegisteredPrefixId(registeredPrefixId));
167 if (i != registeredPrefixTable_.end())
168 {
169 m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
170 bind(&RegisteredPrefixTable::erase, &registeredPrefixTable_, i),
171 Controller::FailCallback());
172 }
173
174 // there cannot be two registered prefixes with the same id. if there are, then something is broken
175}
176
177void
178Face::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
179{
180 try
181 {
182 if (timeout < 0)
183 {
184 // do not block if timeout is negative, but process pending events
185 ioService_->poll();
186 return;
187 }
188
189 if (timeout > 0)
190 {
191 processEventsTimeoutTimer_->expires_from_now(boost::posix_time::milliseconds(timeout));
192 processEventsTimeoutTimer_->async_wait(&fireProcessEventsTimeout);
193 }
194
195 if (keepThread) {
196 // work will ensure that ioService_ is running until work object exists
197 ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
198 }
199
200 ioService_->run();
201 ioService_->reset(); // so it is possible to run processEvents again (if necessary)
202 }
203 catch(Face::ProcessEventsTimeout &)
204 {
205 // break
206 ioService_->reset();
207 }
208 catch(const std::exception &)
209 {
210 ioService_->reset();
211 pendingInterestTable_.clear();
212 registeredPrefixTable_.clear();
213 throw;
214 }
Jeff Thompsonfb29cda2013-08-24 10:26:54 -0700215}
216
Jeff Thompson0050abe2013-09-17 12:50:25 -0700217void
218Face::shutdown()
Jeff Thompson517ffa82013-08-05 16:04:34 -0700219{
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800220 pendingInterestTable_.clear();
221 registeredPrefixTable_.clear();
222
223 transport_->close();
224 pitTimeoutCheckTimer_->cancel();
225 processEventsTimeoutTimer_->cancel();
226 pitTimeoutCheckTimerActive_ = false;
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700227}
228
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800229void
230Face::fireProcessEventsTimeout(const boost::system::error_code& error)
231{
232 if (!error) // can fire for some other reason, e.g., cancelled
233 throw Face::ProcessEventsTimeout();
Jeff Thompsonaa4e6db2013-07-15 17:25:23 -0700234}
Alexander Afanasyev0222fba2014-02-09 23:16:02 -0800235
236void
237Face::checkPitExpire()
238{
239 // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
240 MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
241
242 PendingInterestTable::iterator i = pendingInterestTable_.begin();
243 while (i != pendingInterestTable_.end())
244 {
245 if ((*i)->isTimedOut(nowMilliseconds))
246 {
247 // Save the PendingInterest and remove it from the PIT. Then call the callback.
248 shared_ptr<PendingInterest> pendingInterest = *i;
249
250 i = pendingInterestTable_.erase(i);
251
252 pendingInterest->callTimeout();
253 }
254 else
255 ++i;
256 }
257
258 if (!pendingInterestTable_.empty()) {
259 pitTimeoutCheckTimerActive_ = true;
260
261 pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
262 pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
263 }
264 else {
265 pitTimeoutCheckTimerActive_ = false;
266
267 if (registeredPrefixTable_.empty()) {
268 transport_->close();
269 if (!ioServiceWork_) {
270 processEventsTimeoutTimer_->cancel();
271 }
272 }
273 }
274}
275
276
277void
278Face::onReceiveElement(const Block &block)
279{
280 if (block.type() == Tlv::Interest)
281 {
282 shared_ptr<Interest> interest(new Interest());
283 interest->wireDecode(block);
284
285 RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
286 if (entry != registeredPrefixTable_.end()) {
287 (*entry)->getOnInterest()((*entry)->getPrefix(), *interest);
288 }
289 }
290 else if (block.type() == Tlv::Data)
291 {
292 shared_ptr<Data> data(new Data());
293 data->wireDecode(block);
294
295 PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
296 if (entry != pendingInterestTable_.end()) {
297 // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
298 const OnData onData = (*entry)->getOnData();
299 const shared_ptr<const Interest> interest = (*entry)->getInterest();
300 pendingInterestTable_.erase(entry);
301
302 if (onData) {
303 onData(*interest, *data);
304 }
305
306 if (pendingInterestTable_.empty()) {
307 pitTimeoutCheckTimer_->cancel(); // this will cause checkPitExpire invocation
308 }
309 }
310 }
311}
312
313Face::PendingInterestTable::iterator
314Face::getEntryIndexForExpressedInterest(const Name& name)
315{
316 for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
317 i != pendingInterestTable_.end(); ++i)
318 {
319 if ((*i)->getInterest()->matchesName(name))
320 {
321 return i;
322 }
323 }
324
325 return pendingInterestTable_.end();
326}
327
328Face::RegisteredPrefixTable::iterator
329Face::getEntryForRegisteredPrefix(const Name& name)
330{
331 RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
332
333 for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
334 i != registeredPrefixTable_.end();
335 ++i)
336 {
337 if (longestPrefix == registeredPrefixTable_.end() ||
338 (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
339 {
340 longestPrefix = i;
341 }
342 }
343 return longestPrefix;
344}
345
346} // namespace ndn