blob: e58dd1dd2ac57d4c77a7dc5e200762fe8a2bbb37 [file] [log] [blame]
Junxiao Shi77dcadd2014-10-05 14:40:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoe1789892017-02-26 15:50:52 -05003 * Copyright (c) 2014-2017, Regents of the University of California,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +02004 * 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.
Junxiao Shi77dcadd2014-10-05 14:40:54 -070010 *
11 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
12 *
13 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
14 * terms of the GNU Lesser General Public License as published by the Free Software
15 * Foundation, either version 3 of the License, or (at your option) any later version.
16 *
17 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
20 *
21 * You should have received copies of the GNU General Public License and GNU Lesser
22 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
26 */
27
28#include "face-uri.hpp"
Junxiao Shi4083c8d2014-10-12 16:43:16 -070029#include "dns.hpp"
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050030#include "ethernet.hpp"
Junxiao Shi77dcadd2014-10-05 14:40:54 -070031
Junxiao Shie3ef6ee2014-10-05 14:40:54 -070032#include <boost/lexical_cast.hpp>
Junxiao Shi4083c8d2014-10-12 16:43:16 -070033#include <boost/mpl/vector.hpp>
34#include <boost/mpl/for_each.hpp>
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050035#include <boost/regex.hpp>
36#include <set>
Junxiao Shi77dcadd2014-10-05 14:40:54 -070037
38namespace ndn {
39namespace util {
40
41BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
42
43FaceUri::FaceUri()
44 : m_isV6(false)
45{
46}
47
48FaceUri::FaceUri(const std::string& uri)
49{
50 if (!parse(uri)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070051 BOOST_THROW_EXCEPTION(Error("Malformed URI: " + uri));
Junxiao Shi77dcadd2014-10-05 14:40:54 -070052 }
53}
54
55FaceUri::FaceUri(const char* uri)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050056 : FaceUri(std::string(uri))
Junxiao Shi77dcadd2014-10-05 14:40:54 -070057{
Junxiao Shi77dcadd2014-10-05 14:40:54 -070058}
59
60bool
61FaceUri::parse(const std::string& uri)
62{
63 m_scheme.clear();
64 m_host.clear();
Junxiao Shi77dcadd2014-10-05 14:40:54 -070065 m_port.clear();
66 m_path.clear();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050067 m_isV6 = false;
Junxiao Shi77dcadd2014-10-05 14:40:54 -070068
Weiwei Liud7f4fda2016-10-19 22:38:39 -070069 static const boost::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
Junxiao Shi77dcadd2014-10-05 14:40:54 -070070 boost::smatch protocolMatch;
71 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
72 return false;
73 }
74 m_scheme = protocolMatch[1];
Weiwei Liud7f4fda2016-10-19 22:38:39 -070075 const std::string& authority = protocolMatch[3];
76 m_path = protocolMatch[4];
Junxiao Shi77dcadd2014-10-05 14:40:54 -070077
78 // pattern for IPv6 address enclosed in [ ], with optional port number
79 static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
80 // pattern for Ethernet address in standard hex-digits-and-colons notation
81 static const boost::regex etherExp("^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
82 // pattern for IPv4-mapped IPv6 address, with optional port number
83 static const boost::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
84 // pattern for IPv4/hostname/fd/ifname, with optional port number
85 static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
86
87 if (authority.empty()) {
88 // UNIX, internal
89 }
90 else {
91 boost::smatch match;
92 m_isV6 = boost::regex_match(authority, match, v6Exp);
93 if (m_isV6 ||
94 boost::regex_match(authority, match, etherExp) ||
95 boost::regex_match(authority, match, v4MappedV6Exp) ||
96 boost::regex_match(authority, match, v4HostExp)) {
97 m_host = match[1];
98 m_port = match[2];
99 }
100 else {
101 return false;
102 }
103 }
104
105 return true;
106}
107
108FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint)
109{
110 m_isV6 = endpoint.address().is_v6();
111 m_scheme = m_isV6 ? "udp6" : "udp4";
112 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700113 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700114}
115
116FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint)
117{
118 m_isV6 = endpoint.address().is_v6();
119 m_scheme = m_isV6 ? "tcp6" : "tcp4";
120 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700121 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700122}
123
124FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700125{
126 m_isV6 = endpoint.address().is_v6();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500127 m_scheme = scheme;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700128 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700129 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700130}
131
132#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
133FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500134 : m_scheme("unix")
135 , m_path(endpoint.path())
136 , m_isV6(false)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700137{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700138}
139#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS
140
141FaceUri
142FaceUri::fromFd(int fd)
143{
144 FaceUri uri;
145 uri.m_scheme = "fd";
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700146 uri.m_host = to_string(fd);
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700147 return uri;
148}
149
150FaceUri::FaceUri(const ethernet::Address& address)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500151 : m_scheme("ether")
152 , m_host(address.toString())
153 , m_isV6(true)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700154{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700155}
156
157FaceUri
158FaceUri::fromDev(const std::string& ifname)
159{
160 FaceUri uri;
161 uri.m_scheme = "dev";
162 uri.m_host = ifname;
163 return uri;
164}
165
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700166FaceUri
167FaceUri::fromUdpDev(const boost::asio::ip::udp::endpoint& endpoint, const std::string& ifname)
168{
169 FaceUri uri;
170 uri.m_scheme = endpoint.address().is_v6() ? "udp6+dev" : "udp4+dev";
171 uri.m_host = ifname;
172 uri.m_port = to_string(endpoint.port());
173 return uri;
174}
175
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700176bool
177FaceUri::operator==(const FaceUri& rhs) const
178{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500179 return m_isV6 == rhs.m_isV6 &&
180 m_scheme == rhs.m_scheme &&
181 m_host == rhs.m_host &&
182 m_port == rhs.m_port &&
183 m_path == rhs.m_path;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700184}
185
186bool
187FaceUri::operator!=(const FaceUri& rhs) const
188{
189 return !(*this == rhs);
190}
191
192std::string
193FaceUri::toString() const
194{
195 std::ostringstream os;
196 os << *this;
197 return os.str();
198}
199
200std::ostream&
201operator<<(std::ostream& os, const FaceUri& uri)
202{
203 os << uri.m_scheme << "://";
204 if (uri.m_isV6) {
205 os << "[" << uri.m_host << "]";
206 }
207 else {
208 os << uri.m_host;
209 }
210 if (!uri.m_port.empty()) {
211 os << ":" << uri.m_port;
212 }
213 os << uri.m_path;
214 return os;
215}
216
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500217
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700218/** \brief a CanonizeProvider provides FaceUri canonization functionality for a group of schemes
219 */
220class CanonizeProvider : noncopyable
221{
222public:
223 virtual
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200224 ~CanonizeProvider() = default;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700225
226 virtual std::set<std::string>
227 getSchemes() const = 0;
228
229 virtual bool
230 isCanonical(const FaceUri& faceUri) const = 0;
231
232 virtual void
233 canonize(const FaceUri& faceUri,
234 const FaceUri::CanonizeSuccessCallback& onSuccess,
235 const FaceUri::CanonizeFailureCallback& onFailure,
236 boost::asio::io_service& io, const time::nanoseconds& timeout) const = 0;
237};
238
239template<typename Protocol>
240class IpHostCanonizeProvider : public CanonizeProvider
241{
242public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500243 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200244 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700245 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500246 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700247 }
248
Davide Pesavento57c07df2016-12-11 18:41:45 -0500249 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200250 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700251 {
252 if (faceUri.getPort().empty()) {
253 return false;
254 }
255 if (!faceUri.getPath().empty()) {
256 return false;
257 }
258
259 boost::system::error_code ec;
260 boost::asio::ip::address addr;
261 if (faceUri.getScheme() == m_v4Scheme) {
262 addr = boost::asio::ip::address_v4::from_string(faceUri.getHost(), ec);
263 }
264 else if (faceUri.getScheme() == m_v6Scheme) {
265 addr = boost::asio::ip::address_v6::from_string(faceUri.getHost(), ec);
266 }
267 else {
268 return false;
269 }
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500270
271 return !ec && addr.to_string() == faceUri.getHost() && checkAddress(addr).first;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700272 }
273
Davide Pesavento57c07df2016-12-11 18:41:45 -0500274 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700275 canonize(const FaceUri& faceUri,
276 const FaceUri::CanonizeSuccessCallback& onSuccess,
277 const FaceUri::CanonizeFailureCallback& onFailure,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200278 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700279 {
280 if (this->isCanonical(faceUri)) {
281 onSuccess(faceUri);
282 return;
283 }
284
285 dns::AddressSelector addressSelector;
286 if (faceUri.getScheme() == m_v4Scheme) {
287 addressSelector = dns::Ipv4Only();
288 }
289 else if (faceUri.getScheme() == m_v6Scheme) {
290 addressSelector = dns::Ipv6Only();
291 }
292 else {
293 BOOST_ASSERT(faceUri.getScheme() == m_baseScheme);
294 addressSelector = dns::AnyAddress();
295 }
296
297 // make a copy because caller may modify faceUri
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500298 auto uri = make_shared<FaceUri>(faceUri);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700299 dns::asyncResolve(faceUri.getHost(),
300 bind(&IpHostCanonizeProvider<Protocol>::onDnsSuccess, this, uri, onSuccess, onFailure, _1),
301 bind(&IpHostCanonizeProvider<Protocol>::onDnsFailure, this, uri, onFailure, _1),
302 io, addressSelector, timeout);
303 }
304
305protected:
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200306 explicit
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700307 IpHostCanonizeProvider(const std::string& baseScheme,
Davide Pesaventof78cb702016-12-11 14:42:40 -0500308 uint16_t defaultUnicastPort = 6363,
309 uint16_t defaultMulticastPort = 56363)
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700310 : m_baseScheme(baseScheme)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500311 , m_v4Scheme(baseScheme + '4')
312 , m_v6Scheme(baseScheme + '6')
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700313 , m_defaultUnicastPort(defaultUnicastPort)
314 , m_defaultMulticastPort(defaultMulticastPort)
315 {
316 }
317
318private:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700319 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500320 onDnsSuccess(const shared_ptr<FaceUri>& faceUri,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700321 const FaceUri::CanonizeSuccessCallback& onSuccess,
322 const FaceUri::CanonizeFailureCallback& onFailure,
323 const dns::IpAddress& ipAddress) const
324 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500325 bool isOk = false;
326 std::string reason;
327 std::tie(isOk, reason) = this->checkAddress(ipAddress);
328 if (!isOk) {
329 return onFailure(reason);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700330 }
331
Davide Pesaventof78cb702016-12-11 14:42:40 -0500332 uint16_t port = 0;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700333 if (faceUri->getPort().empty()) {
334 port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
335 }
336 else {
337 try {
Davide Pesaventof78cb702016-12-11 14:42:40 -0500338 port = boost::lexical_cast<uint16_t>(faceUri->getPort());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700339 }
Davide Pesaventof78cb702016-12-11 14:42:40 -0500340 catch (const boost::bad_lexical_cast&) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500341 return onFailure("invalid port number '" + faceUri->getPort() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700342 }
343 }
344
345 FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port));
346 BOOST_ASSERT(canonicalUri.isCanonical());
347 onSuccess(canonicalUri);
348 }
349
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700350 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500351 onDnsFailure(const shared_ptr<FaceUri>& faceUri,
352 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700353 const std::string& reason) const
354 {
355 onFailure(reason);
356 }
357
358 /** \brief when overriden in a subclass, check the IP address is allowable
359 * \return (true,ignored) if the address is allowable;
360 * (false,reason) if the address is not allowable.
361 */
362 virtual std::pair<bool, std::string>
363 checkAddress(const dns::IpAddress& ipAddress) const
364 {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200365 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700366 }
367
368private:
369 std::string m_baseScheme;
370 std::string m_v4Scheme;
371 std::string m_v6Scheme;
Davide Pesaventof78cb702016-12-11 14:42:40 -0500372 uint16_t m_defaultUnicastPort;
373 uint16_t m_defaultMulticastPort;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700374};
375
376class UdpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::udp>
377{
378public:
379 UdpCanonizeProvider()
380 : IpHostCanonizeProvider("udp")
381 {
382 }
383
384protected:
385 // checkAddress is not overriden:
386 // Although NFD doesn't support IPv6 multicast, it's an implementation limitation.
387 // FaceMgmt protocol allows IPv6 multicast address in UDP.
388};
389
390class TcpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::tcp>
391{
392public:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700393 TcpCanonizeProvider()
394 : IpHostCanonizeProvider("tcp")
395 {
396 }
397
398protected:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500399 std::pair<bool, std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200400 checkAddress(const dns::IpAddress& ipAddress) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700401 {
402 if (ipAddress.is_multicast()) {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200403 return {false, "cannot use multicast address"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700404 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200405 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700406 }
407};
408
409class EtherCanonizeProvider : public CanonizeProvider
410{
411public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500412 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200413 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700414 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500415 return {"ether"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700416 }
417
Davide Pesavento57c07df2016-12-11 18:41:45 -0500418 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200419 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700420 {
421 if (!faceUri.getPort().empty()) {
422 return false;
423 }
424 if (!faceUri.getPath().empty()) {
425 return false;
426 }
427
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500428 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700429 return addr.toString() == faceUri.getHost();
430 }
431
Davide Pesavento57c07df2016-12-11 18:41:45 -0500432 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700433 canonize(const FaceUri& faceUri,
434 const FaceUri::CanonizeSuccessCallback& onSuccess,
435 const FaceUri::CanonizeFailureCallback& onFailure,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200436 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700437 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500438 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700439 if (addr.isNull()) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500440 return onFailure("invalid ethernet address '" + faceUri.getHost() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700441 }
442
443 FaceUri canonicalUri(addr);
444 BOOST_ASSERT(canonicalUri.isCanonical());
445 onSuccess(canonicalUri);
446 }
447};
448
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700449class UdpDevCanonizeProvider : public CanonizeProvider
450{
451public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500452 std::set<std::string>
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700453 getSchemes() const override
454 {
455 return {"udp4+dev", "udp6+dev"};
456 }
457
Davide Pesavento57c07df2016-12-11 18:41:45 -0500458 bool
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700459 isCanonical(const FaceUri& faceUri) const override
460 {
461 if (faceUri.getPort().empty()) {
462 return false;
463 }
464 if (!faceUri.getPath().empty()) {
465 return false;
466 }
467 return true;
468 }
469
Davide Pesavento57c07df2016-12-11 18:41:45 -0500470 void
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700471 canonize(const FaceUri& faceUri,
472 const FaceUri::CanonizeSuccessCallback& onSuccess,
473 const FaceUri::CanonizeFailureCallback& onFailure,
474 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
475 {
476 if (this->isCanonical(faceUri)) {
477 onSuccess(faceUri);
478 }
479 else {
480 onFailure("cannot canonize " + faceUri.toString());
481 }
482 }
483};
484
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500485using CanonizeProviders = boost::mpl::vector<UdpCanonizeProvider*,
486 TcpCanonizeProvider*,
487 EtherCanonizeProvider*,
488 UdpDevCanonizeProvider*>;
489using CanonizeProviderTable = std::map<std::string, shared_ptr<CanonizeProvider>>;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700490
491class CanonizeProviderTableInitializer
492{
493public:
494 explicit
495 CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable)
496 : m_providerTable(providerTable)
497 {
498 }
499
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500500 template<typename CP>
501 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700502 operator()(CP*)
503 {
504 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500505 auto schemes = cp->getSchemes();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700506 BOOST_ASSERT(!schemes.empty());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500507
508 for (const auto& scheme : schemes) {
509 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
510 m_providerTable[scheme] = cp;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700511 }
512 }
513
514private:
515 CanonizeProviderTable& m_providerTable;
516};
517
518static const CanonizeProvider*
519getCanonizeProvider(const std::string& scheme)
520{
521 static CanonizeProviderTable providerTable;
522 if (providerTable.empty()) {
523 boost::mpl::for_each<CanonizeProviders>(CanonizeProviderTableInitializer(providerTable));
524 BOOST_ASSERT(!providerTable.empty());
525 }
526
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200527 auto it = providerTable.find(scheme);
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500528 return it == providerTable.end() ? nullptr : it->second.get();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700529}
530
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500531
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700532bool
533FaceUri::canCanonize(const std::string& scheme)
534{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500535 return getCanonizeProvider(scheme) != nullptr;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700536}
537
538bool
539FaceUri::isCanonical() const
540{
541 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500542 if (cp == nullptr) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700543 return false;
544 }
545
546 return cp->isCanonical(*this);
547}
548
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700549void
550FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
551 const CanonizeFailureCallback& onFailure,
552 boost::asio::io_service& io, const time::nanoseconds& timeout) const
553{
554 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200555 if (cp == nullptr) {
556 if (onFailure) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700557 onFailure("scheme not supported");
558 }
559 return;
560 }
561
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200562 static CanonizeSuccessCallback successNop = bind([]{});
563 static CanonizeFailureCallback failureNop = bind([]{});
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700564 cp->canonize(*this,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200565 onSuccess ? onSuccess : successNop,
566 onFailure ? onFailure : failureNop,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700567 io, timeout);
568}
569
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700570} // namespace util
571} // namespace ndn