blob: 1a3e41f126fb6a2ab5e146f8f41eb7e98408586e [file] [log] [blame]
Alexander Afanasyev3ecec502014-04-16 13:42:44 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014 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 "rib-manager.hpp"
27
28namespace nfd {
29namespace rib {
30
31const Name RibManager::COMMAND_PREFIX = "/localhost/nrd";
32const Name RibManager::REMOTE_COMMAND_PREFIX = "/localhop/nrd";
33
34const size_t RibManager::COMMAND_UNSIGNED_NCOMPS =
35 RibManager::COMMAND_PREFIX.size() +
36 1 + // verb
37 1; // verb options
38
39const size_t RibManager::COMMAND_SIGNED_NCOMPS =
40 RibManager::COMMAND_UNSIGNED_NCOMPS +
41 4; // (timestamp, nonce, signed info tlv, signature tlv)
42
43const RibManager::VerbAndProcessor RibManager::COMMAND_VERBS[] =
44 {
45 VerbAndProcessor(
46 Name::Component("register"),
47 &RibManager::insertEntry
48 ),
49
50 VerbAndProcessor(
51 Name::Component("unregister"),
52 &RibManager::deleteEntry
53 ),
54 };
55
56RibManager::RibManager()
57 : m_face(new ndn::Face())
58 , m_nfdController(new ndn::nfd::Controller(*m_face))
59 , m_validator(m_face)
60 , m_faceMonitor(*m_face)
61 , m_verbDispatch(COMMAND_VERBS,
62 COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
63{
64}
65
66void
67RibManager::registerWithNfd()
68{
69 //check whether the components of localhop and localhost prefixes are same
70 BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
71
72 std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
73 m_face->setController(m_nfdController);
74 m_face->setInterestFilter(COMMAND_PREFIX.toUri(),
75 bind(&RibManager::onRibRequest, this, _2),
76 bind(&RibManager::setInterestFilterFailed, this, _1, _2));
77
78 std::cerr << "Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri() << std::endl;
79 m_face->setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
80 bind(&RibManager::onRibRequest, this, _2),
81 bind(&RibManager::setInterestFilterFailed, this, _1, _2));
82
83 std::cerr << "Monitoring faces" << std::endl;
84 m_faceMonitor.addSubscriber(boost::bind(&RibManager::onNotification, this, _1));
85 m_faceMonitor.startNotifications();
86}
87
88void
89RibManager::setConfigFile(ConfigFile& configFile)
90{
91 configFile.addSectionHandler("security",
92 bind(&RibManager::onConfig, this, _1, _2, _3));
93}
94
95void
96RibManager::onConfig(const ConfigSection& configSection,
97 bool isDryRun,
98 const std::string& filename)
99{
100 /// \todo remove check after validator-conf replaces settings on each load
101 if (!isDryRun)
102 m_validator.load(configSection, filename);
103}
104
105void
106RibManager::setInterestFilterFailed(const Name& name, const std::string& msg)
107{
108 std::cerr << "Error in setting interest filter (" << name << "): " << msg << std::endl;
109 m_face->shutdown();
110}
111
112void
113RibManager::sendResponse(const Name& name,
114 const ControlResponse& response)
115{
116 const Block& encodedControl = response.wireEncode();
117
118 Data responseData(name);
119 responseData.setContent(encodedControl);
120
121 m_keyChain.sign(responseData);
122 m_face->put(responseData);
123}
124
125void
126RibManager::sendResponse(const Name& name,
127 uint32_t code,
128 const std::string& text)
129{
130 ControlResponse response(code, text);
131 sendResponse(name, response);
132}
133
134void
135RibManager::onRibRequest(const Interest& request)
136{
137 m_validator.validate(request,
138 bind(&RibManager::onRibRequestValidated, this, _1),
139 bind(&RibManager::onRibRequestValidationFailed, this, _1, _2));
140}
141
142void
143RibManager::onRibRequestValidated(const shared_ptr<const Interest>& request)
144{
145 const Name& command = request->getName();
146
147 //REMOTE_COMMAND_PREFIX number of componenets are same as
148 // NRD_COMMAND_PREFIX's so no extra checks are required.
149 const Name::Component& verb = command.get(COMMAND_PREFIX.size());
150 VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
151
152 if (verbProcessor != m_verbDispatch.end())
153 {
154 PrefixRegOptions options;
155 if (!extractOptions(*request, options))
156 {
157 sendResponse(command, 400, "Malformed command");
158 return;
159 }
160
161 /// \todo authorize command
162 if (false)
163 {
164 sendResponse(request->getName(), 403, "Unauthorized command");
165 return;
166 }
167
168 // \todo add proper log support
169 std::cout << "Received options (name, faceid, cost): " << options.getName() <<
170 ", " << options.getFaceId() << ", " << options.getCost() << std::endl;
171
172 ControlResponse response;
173 (verbProcessor->second)(this, *request, options);
174 }
175 else
176 {
177 sendResponse(request->getName(), 501, "Unsupported command");
178 }
179}
180
181void
182RibManager::onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
183 const std::string& failureInfo)
184{
185 sendResponse(request->getName(), 403, failureInfo);
186}
187
188bool
189RibManager::extractOptions(const Interest& request,
190 PrefixRegOptions& extractedOptions)
191{
192 // const Name& command = request.getName();
193 //REMOTE_COMMAND_PREFIX is same in size of NRD_COMMAND_PREFIX
194 //so no extra processing is required.
195 const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
196
197 try
198 {
199 Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
200 extractedOptions.wireDecode(rawOptions);
201 }
202 catch (const ndn::Tlv::Error& e)
203 {
204 return false;
205 }
206
207 if (extractedOptions.getFaceId() == 0)
208 {
209 std::cout <<"IncomingFaceId: " << request.getIncomingFaceId() << std::endl;
210 extractedOptions.setFaceId(request.getIncomingFaceId());
211 }
212 return true;
213}
214
215void
216RibManager::onCommandError(uint32_t code, const std::string& error,
217 const Interest& request,
218 const PrefixRegOptions& options)
219{
220 std::cout << "NFD Error: " << error << " (code: " << code << ")" << std::endl;
221
222 ControlResponse response;
223
224 if (code == 404)
225 {
226 response.setCode(code);
227 response.setText(error);
228 }
229 else
230 {
231 response.setCode(533);
232 std::ostringstream os;
233 os << "Failure to update NFD " << "(NFD Error: " << code << " " << error << ")";
234 response.setText(os.str());
235 }
236
237 sendResponse(request.getName(), response);
238 m_managedRib.erase(options);
239}
240
241void
242RibManager::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
243{
244 ControlResponse response;
245
246 response.setCode(200);
247 response.setText("Success");
248 response.setBody(options.wireEncode());
249
250 std::cout << "Success: Name unregistered (" <<
251 options.getName() << ", " <<
252 options.getFaceId() << ")" << std::endl;
253 sendResponse(request.getName(), response);
254 m_managedRib.erase(options);
255}
256
257void
258RibManager::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
259{
260 ControlResponse response;
261
262 response.setCode(200);
263 response.setText("Success");
264 response.setBody(options.wireEncode());
265
266 std::cout << "Success: Name registered (" << options.getName() << ", " <<
267 options.getFaceId() << ")" << std::endl;
268 sendResponse(request.getName(), response);
269}
270
271void
272RibManager::insertEntry(const Interest& request, const PrefixRegOptions& options)
273{
274 // For right now, just pass the options to fib as it is,
275 // without processing flags. Later options will be first added to
276 // Rib tree, then nrd will generate fib updates based on flags and then
277 // will add next hops one by one..
278 m_managedRib.insert(options);
279 m_nfdController->start<ndn::nfd::FibAddNextHopCommand>(
280 ControlParameters()
281 .setName(options.getName())
282 .setFaceId(options.getFaceId())
283 .setCost(options.getCost()),
284 bind(&RibManager::onRegSuccess, this, request, options),
285 bind(&RibManager::onCommandError, this, _1, _2, request, options));
286}
287
288void
289RibManager::deleteEntry(const Interest& request, const PrefixRegOptions& options)
290{
291 m_nfdController->start<ndn::nfd::FibRemoveNextHopCommand>(
292 ControlParameters()
293 .setName(options.getName())
294 .setFaceId(options.getFaceId()),
295 bind(&RibManager::onUnRegSuccess, this, request, options),
296 bind(&RibManager::onCommandError, this, _1, _2, request, options));
297}
298
299boost::asio::io_service&
300RibManager::getIoService()
301{
302 /// \todo Switch face to use global io service (needs library update)
303 return *m_face->ioService();
304}
305
306void
307RibManager::onControlHeaderSuccess()
308{
309 std::cout << "Local control header enabled" << std::endl;
310}
311
312void
313RibManager::onControlHeaderError(uint32_t code, const std::string& reason)
314{
315 std::cout << "Error: couldn't enable local control header "
316 << "(code: " << code << ", info: " << reason << ")" << std::endl;
317 m_face->shutdown();
318}
319
320void
321RibManager::enableLocalControlHeader()
322{
323 m_nfdController->start<ndn::nfd::FaceEnableLocalControlCommand>(
324 ControlParameters()
325 .setLocalControlFeature(ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
326 bind(&RibManager::onControlHeaderSuccess, this),
327 bind(&RibManager::onControlHeaderError, this, _1, _2));
328}
329
330void
331RibManager::onNotification(const FaceEventNotification& notification)
332{
333 /// \todo A notification can be missed, in this case check Facelist
334 std::cerr << "Notification Rcvd: " << notification << std::endl;
335 if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
336 m_managedRib.erase(notification.getFaceId());
337 }
338}
339
340} // namespace rib
341} // namespace nfd