blob: fb6642ac7e1601a51496a03f01fec23b54084264 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07002/**
Alexander Afanasyev9d158f02015-02-17 21:30:19 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070020 */
21
22#ifndef NDN_DETAIL_FACE_IMPL_HPP
23#define NDN_DETAIL_FACE_IMPL_HPP
24
25#include "../common.hpp"
26#include "../face.hpp"
27
28#include "registered-prefix.hpp"
29#include "pending-interest.hpp"
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080030#include "container-with-on-empty-signal.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070031
32#include "../util/scheduler.hpp"
33#include "../util/config-file.hpp"
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080034#include "../util/signal.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070035
Junxiao Shi0fa28452014-12-13 22:02:36 -070036#include "../transport/transport.hpp"
37#include "../transport/unix-transport.hpp"
38#include "../transport/tcp-transport.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070039
Junxiao Shi0fa28452014-12-13 22:02:36 -070040#include "../management/nfd-controller.hpp"
41#include "../management/nfd-command-options.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070042
43namespace ndn {
44
45class Face::Impl : noncopyable
46{
47public:
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080048 typedef ContainerWithOnEmptySignal<shared_ptr<PendingInterest>> PendingInterestTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070049 typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080050 typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070051
52 explicit
53 Impl(Face& face)
54 : m_face(face)
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080055 , m_scheduler(m_face.getIoService())
56 , m_processEventsTimeoutEvent(m_scheduler)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070057 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080058 auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
59 this->m_face.getIoService().post(bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this));
60 // without this extra "post", transport can get paused (-async_read) and then resumed
61 // (+async_read) from within onInterest/onData callback. After onInterest/onData
62 // finishes, there is another +async_read with the same memory block. A few of such
63 // async_read duplications can cause various effects and result in segfault.
64 };
65
66 m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
67 m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070068 }
69
70 /////////////////////////////////////////////////////////////////////////////////////////////////
71 /////////////////////////////////////////////////////////////////////////////////////////////////
72
73 void
74 satisfyPendingInterests(Data& data)
75 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080076 for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
77 if ((*entry)->getInterest().matchesData(data)) {
78 shared_ptr<PendingInterest> matchedEntry = *entry;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070079
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080080 entry = m_pendingInterestTable.erase(entry);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070081
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080082 matchedEntry->invokeDataCallback(data);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070083 }
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080084 else
85 ++entry;
86 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070087 }
88
89 void
90 processInterestFilters(Interest& interest)
91 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080092 for (const auto& filter : m_interestFilterTable) {
93 if (filter->doesMatch(interest.getName())) {
94 filter->invokeInterestCallback(interest);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070095 }
Alexander Afanasyev9d158f02015-02-17 21:30:19 -080096 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070097 }
98
99 /////////////////////////////////////////////////////////////////////////////////////////////////
100 /////////////////////////////////////////////////////////////////////////////////////////////////
101
102 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800103 ensureConnected(bool wantResume)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700104 {
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700105 if (!m_face.m_transport->isConnected())
Junxiao Shi2cced062014-11-02 21:27:38 -0700106 m_face.m_transport->connect(m_face.m_ioService,
Alexander Afanasyev407e9492014-07-10 18:50:44 -0700107 bind(&Face::onReceiveElement, &m_face, _1));
108
Junxiao Shia1ea5062014-12-27 22:33:39 -0700109 if (wantResume && !m_face.m_transport->isExpectingData())
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700110 m_face.m_transport->resume();
Junxiao Shia1ea5062014-12-27 22:33:39 -0700111 }
112
113 void
114 asyncExpressInterest(const shared_ptr<const Interest>& interest,
115 const OnData& onData, const OnTimeout& onTimeout)
116 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800117 this->ensureConnected(true);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700118
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800119 auto entry =
120 m_pendingInterestTable.insert(make_shared<PendingInterest>(interest,
121 onData, onTimeout,
122 ref(m_scheduler))).first;
123 (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700124
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800125 if (!interest->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_NEXT_HOP)) {
126 // encode only NextHopFaceId towards the forwarder
127 m_face.m_transport->send(interest->getLocalControlHeader()
128 .wireEncode(*interest, nfd::LocalControlHeader::ENCODE_NEXT_HOP),
129 interest->wireEncode());
130 }
131 else {
132 m_face.m_transport->send(interest->wireEncode());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700133 }
134 }
135
136 void
137 asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
138 {
139 m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
140 }
141
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700142 void
143 asyncPutData(const shared_ptr<const Data>& data)
144 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800145 this->ensureConnected(true);
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700146
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800147 if (!data->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_CACHING_POLICY)) {
148 m_face.m_transport->send(
149 data->getLocalControlHeader().wireEncode(*data,
150 nfd::LocalControlHeader::ENCODE_CACHING_POLICY),
151 data->wireEncode());
152 }
153 else {
154 m_face.m_transport->send(data->wireEncode());
155 }
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700156 }
157
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700158 /////////////////////////////////////////////////////////////////////////////////////////////////
159 /////////////////////////////////////////////////////////////////////////////////////////////////
160
161 void
162 asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
163 {
164 m_interestFilterTable.push_back(interestFilterRecord);
165 }
166
167 void
168 asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
169 {
170 InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
171 m_interestFilterTable.end(),
172 MatchInterestFilterId(interestFilterId));
173 if (i != m_interestFilterTable.end())
174 {
175 m_interestFilterTable.erase(i);
176 }
177 }
178
179 /////////////////////////////////////////////////////////////////////////////////////////////////
180 /////////////////////////////////////////////////////////////////////////////////////////////////
181
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700182 const RegisteredPrefixId*
183 registerPrefix(const Name& prefix,
184 const shared_ptr<InterestFilterRecord>& filter,
185 const RegisterPrefixSuccessCallback& onSuccess,
186 const RegisterPrefixFailureCallback& onFailure,
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700187 uint64_t flags,
Junxiao Shi388ec252014-11-02 15:19:57 -0700188 const nfd::CommandOptions& options)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700189 {
190 using namespace nfd;
191
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400192 ControlParameters params;
193 params.setName(prefix);
194 params.setFlags(flags);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700195
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400196 auto prefixToRegister = make_shared<RegisteredPrefix>(prefix, filter, options);
Alexander Afanasyev0866f512014-08-11 13:25:09 -0700197
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400198 m_face.m_nfdController->start<RibRegisterCommand>(params,
199 bind(&Impl::afterPrefixRegistered, this,
200 prefixToRegister, onSuccess),
201 bind(onFailure, prefixToRegister->getPrefix(), _2),
202 options);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700203
204 return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
205 }
206
207 void
208 afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
209 const RegisterPrefixSuccessCallback& onSuccess)
210 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800211 m_registeredPrefixTable.insert(registeredPrefix);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700212
213 if (static_cast<bool>(registeredPrefix->getFilter())) {
214 // it was a combined operation
215 m_interestFilterTable.push_back(registeredPrefix->getFilter());
216 }
217
218 if (static_cast<bool>(onSuccess)) {
219 onSuccess(registeredPrefix->getPrefix());
220 }
221 }
222
223 void
224 asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
225 const UnregisterPrefixSuccessCallback& onSuccess,
226 const UnregisterPrefixFailureCallback& onFailure)
227 {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400228 using namespace nfd;
229 auto i = std::find_if(m_registeredPrefixTable.begin(),
230 m_registeredPrefixTable.end(),
231 MatchRegisteredPrefixId(registeredPrefixId));
232 if (i != m_registeredPrefixTable.end()) {
233 RegisteredPrefix& record = **i;
234
235 const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
236
237 if (filter != nullptr) {
238 // it was a combined operation
239 m_interestFilterTable.remove(filter);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700240 }
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400241
242 ControlParameters params;
243 params.setName(record.getPrefix());
244 m_face.m_nfdController->start<RibUnregisterCommand>(params,
245 bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
246 bind(onFailure, _2),
247 record.getCommandOptions());
248 }
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400249 else {
Joao Pereiraba1e3b92015-06-01 17:50:37 -0400250 if (onFailure != nullptr) {
Alexander Afanasyev851228a2014-10-20 15:55:28 -0400251 onFailure("Unrecognized PrefixId");
252 }
253 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700254
255 // there cannot be two registered prefixes with the same id
256 }
257
258 void
259 finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
260 const UnregisterPrefixSuccessCallback& onSuccess)
261 {
262 m_registeredPrefixTable.erase(item);
263
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700264 if (static_cast<bool>(onSuccess)) {
265 onSuccess();
266 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700267 }
268
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700269 void
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800270 onEmptyPitOrNoRegisteredPrefixes()
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700271 {
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800272 if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
273 m_face.m_transport->pause();
274 if (!m_ioServiceWork) {
275 m_processEventsTimeoutEvent.cancel();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700276 }
277 }
278 }
279
280private:
281 Face& m_face;
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800282 util::Scheduler m_scheduler;
283 util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700284
285 PendingInterestTable m_pendingInterestTable;
286 InterestFilterTable m_interestFilterTable;
287 RegisteredPrefixTable m_registeredPrefixTable;
288
Alexander Afanasyev9d158f02015-02-17 21:30:19 -0800289 unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700290
291 friend class Face;
292};
293
294} // namespace ndn
295
296#endif // NDN_DETAIL_FACE_IMPL_HPP