blob: c09da8a9ebdb0bf1fca5175d13b99f76bc659a48 [file] [log] [blame]
Junxiao Shi77dcadd2014-10-05 14:40:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoe1081cd2016-12-19 23:58:15 -05003 * Copyright (c) 2014-2016, 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
32#include <boost/concept_check.hpp>
Junxiao Shie3ef6ee2014-10-05 14:40:54 -070033#include <boost/lexical_cast.hpp>
Junxiao Shi4083c8d2014-10-12 16:43:16 -070034#include <boost/mpl/vector.hpp>
35#include <boost/mpl/for_each.hpp>
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050036#include <boost/regex.hpp>
37#include <set>
Junxiao Shi77dcadd2014-10-05 14:40:54 -070038
39namespace ndn {
40namespace util {
41
42BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
43
44FaceUri::FaceUri()
45 : m_isV6(false)
46{
47}
48
49FaceUri::FaceUri(const std::string& uri)
50{
51 if (!parse(uri)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070052 BOOST_THROW_EXCEPTION(Error("Malformed URI: " + uri));
Junxiao Shi77dcadd2014-10-05 14:40:54 -070053 }
54}
55
56FaceUri::FaceUri(const char* uri)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050057 : FaceUri(std::string(uri))
Junxiao Shi77dcadd2014-10-05 14:40:54 -070058{
Junxiao Shi77dcadd2014-10-05 14:40:54 -070059}
60
61bool
62FaceUri::parse(const std::string& uri)
63{
64 m_scheme.clear();
65 m_host.clear();
Junxiao Shi77dcadd2014-10-05 14:40:54 -070066 m_port.clear();
67 m_path.clear();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050068 m_isV6 = false;
Junxiao Shi77dcadd2014-10-05 14:40:54 -070069
Weiwei Liud7f4fda2016-10-19 22:38:39 -070070 static const boost::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
Junxiao Shi77dcadd2014-10-05 14:40:54 -070071 boost::smatch protocolMatch;
72 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
73 return false;
74 }
75 m_scheme = protocolMatch[1];
Weiwei Liud7f4fda2016-10-19 22:38:39 -070076 const std::string& authority = protocolMatch[3];
77 m_path = protocolMatch[4];
Junxiao Shi77dcadd2014-10-05 14:40:54 -070078
79 // pattern for IPv6 address enclosed in [ ], with optional port number
80 static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
81 // pattern for Ethernet address in standard hex-digits-and-colons notation
82 static const boost::regex etherExp("^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
83 // pattern for IPv4-mapped IPv6 address, with optional port number
84 static const boost::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
85 // pattern for IPv4/hostname/fd/ifname, with optional port number
86 static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
87
88 if (authority.empty()) {
89 // UNIX, internal
90 }
91 else {
92 boost::smatch match;
93 m_isV6 = boost::regex_match(authority, match, v6Exp);
94 if (m_isV6 ||
95 boost::regex_match(authority, match, etherExp) ||
96 boost::regex_match(authority, match, v4MappedV6Exp) ||
97 boost::regex_match(authority, match, v4HostExp)) {
98 m_host = match[1];
99 m_port = match[2];
100 }
101 else {
102 return false;
103 }
104 }
105
106 return true;
107}
108
109FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint)
110{
111 m_isV6 = endpoint.address().is_v6();
112 m_scheme = m_isV6 ? "udp6" : "udp4";
113 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700114 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700115}
116
117FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint)
118{
119 m_isV6 = endpoint.address().is_v6();
120 m_scheme = m_isV6 ? "tcp6" : "tcp4";
121 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700122 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700123}
124
125FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700126{
127 m_isV6 = endpoint.address().is_v6();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500128 m_scheme = scheme;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700129 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700130 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700131}
132
133#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
134FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500135 : m_scheme("unix")
136 , m_path(endpoint.path())
137 , m_isV6(false)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700138{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700139}
140#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS
141
142FaceUri
143FaceUri::fromFd(int fd)
144{
145 FaceUri uri;
146 uri.m_scheme = "fd";
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700147 uri.m_host = to_string(fd);
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700148 return uri;
149}
150
151FaceUri::FaceUri(const ethernet::Address& address)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500152 : m_scheme("ether")
153 , m_host(address.toString())
154 , m_isV6(true)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700155{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700156}
157
158FaceUri
159FaceUri::fromDev(const std::string& ifname)
160{
161 FaceUri uri;
162 uri.m_scheme = "dev";
163 uri.m_host = ifname;
164 return uri;
165}
166
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700167FaceUri
168FaceUri::fromUdpDev(const boost::asio::ip::udp::endpoint& endpoint, const std::string& ifname)
169{
170 FaceUri uri;
171 uri.m_scheme = endpoint.address().is_v6() ? "udp6+dev" : "udp4+dev";
172 uri.m_host = ifname;
173 uri.m_port = to_string(endpoint.port());
174 return uri;
175}
176
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700177bool
178FaceUri::operator==(const FaceUri& rhs) const
179{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500180 return m_isV6 == rhs.m_isV6 &&
181 m_scheme == rhs.m_scheme &&
182 m_host == rhs.m_host &&
183 m_port == rhs.m_port &&
184 m_path == rhs.m_path;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700185}
186
187bool
188FaceUri::operator!=(const FaceUri& rhs) const
189{
190 return !(*this == rhs);
191}
192
193std::string
194FaceUri::toString() const
195{
196 std::ostringstream os;
197 os << *this;
198 return os.str();
199}
200
201std::ostream&
202operator<<(std::ostream& os, const FaceUri& uri)
203{
204 os << uri.m_scheme << "://";
205 if (uri.m_isV6) {
206 os << "[" << uri.m_host << "]";
207 }
208 else {
209 os << uri.m_host;
210 }
211 if (!uri.m_port.empty()) {
212 os << ":" << uri.m_port;
213 }
214 os << uri.m_path;
215 return os;
216}
217
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500218
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700219/** \brief a CanonizeProvider provides FaceUri canonization functionality for a group of schemes
220 */
221class CanonizeProvider : noncopyable
222{
223public:
224 virtual
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200225 ~CanonizeProvider() = default;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700226
227 virtual std::set<std::string>
228 getSchemes() const = 0;
229
230 virtual bool
231 isCanonical(const FaceUri& faceUri) const = 0;
232
233 virtual void
234 canonize(const FaceUri& faceUri,
235 const FaceUri::CanonizeSuccessCallback& onSuccess,
236 const FaceUri::CanonizeFailureCallback& onFailure,
237 boost::asio::io_service& io, const time::nanoseconds& timeout) const = 0;
238};
239
240template<typename Protocol>
241class IpHostCanonizeProvider : public CanonizeProvider
242{
243public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500244 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200245 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700246 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500247 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700248 }
249
Davide Pesavento57c07df2016-12-11 18:41:45 -0500250 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200251 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700252 {
253 if (faceUri.getPort().empty()) {
254 return false;
255 }
256 if (!faceUri.getPath().empty()) {
257 return false;
258 }
259
260 boost::system::error_code ec;
261 boost::asio::ip::address addr;
262 if (faceUri.getScheme() == m_v4Scheme) {
263 addr = boost::asio::ip::address_v4::from_string(faceUri.getHost(), ec);
264 }
265 else if (faceUri.getScheme() == m_v6Scheme) {
266 addr = boost::asio::ip::address_v6::from_string(faceUri.getHost(), ec);
267 }
268 else {
269 return false;
270 }
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500271
272 return !ec && addr.to_string() == faceUri.getHost() && checkAddress(addr).first;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700273 }
274
Davide Pesavento57c07df2016-12-11 18:41:45 -0500275 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700276 canonize(const FaceUri& faceUri,
277 const FaceUri::CanonizeSuccessCallback& onSuccess,
278 const FaceUri::CanonizeFailureCallback& onFailure,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200279 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700280 {
281 if (this->isCanonical(faceUri)) {
282 onSuccess(faceUri);
283 return;
284 }
285
286 dns::AddressSelector addressSelector;
287 if (faceUri.getScheme() == m_v4Scheme) {
288 addressSelector = dns::Ipv4Only();
289 }
290 else if (faceUri.getScheme() == m_v6Scheme) {
291 addressSelector = dns::Ipv6Only();
292 }
293 else {
294 BOOST_ASSERT(faceUri.getScheme() == m_baseScheme);
295 addressSelector = dns::AnyAddress();
296 }
297
298 // make a copy because caller may modify faceUri
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500299 auto uri = make_shared<FaceUri>(faceUri);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700300 dns::asyncResolve(faceUri.getHost(),
301 bind(&IpHostCanonizeProvider<Protocol>::onDnsSuccess, this, uri, onSuccess, onFailure, _1),
302 bind(&IpHostCanonizeProvider<Protocol>::onDnsFailure, this, uri, onFailure, _1),
303 io, addressSelector, timeout);
304 }
305
306protected:
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200307 explicit
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700308 IpHostCanonizeProvider(const std::string& baseScheme,
Davide Pesaventof78cb702016-12-11 14:42:40 -0500309 uint16_t defaultUnicastPort = 6363,
310 uint16_t defaultMulticastPort = 56363)
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700311 : m_baseScheme(baseScheme)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500312 , m_v4Scheme(baseScheme + '4')
313 , m_v6Scheme(baseScheme + '6')
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700314 , m_defaultUnicastPort(defaultUnicastPort)
315 , m_defaultMulticastPort(defaultMulticastPort)
316 {
317 }
318
319private:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700320 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500321 onDnsSuccess(const shared_ptr<FaceUri>& faceUri,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700322 const FaceUri::CanonizeSuccessCallback& onSuccess,
323 const FaceUri::CanonizeFailureCallback& onFailure,
324 const dns::IpAddress& ipAddress) const
325 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500326 bool isOk = false;
327 std::string reason;
328 std::tie(isOk, reason) = this->checkAddress(ipAddress);
329 if (!isOk) {
330 return onFailure(reason);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700331 }
332
Davide Pesaventof78cb702016-12-11 14:42:40 -0500333 uint16_t port = 0;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700334 if (faceUri->getPort().empty()) {
335 port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
336 }
337 else {
338 try {
Davide Pesaventof78cb702016-12-11 14:42:40 -0500339 port = boost::lexical_cast<uint16_t>(faceUri->getPort());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700340 }
Davide Pesaventof78cb702016-12-11 14:42:40 -0500341 catch (const boost::bad_lexical_cast&) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500342 return onFailure("invalid port number '" + faceUri->getPort() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700343 }
344 }
345
346 FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port));
347 BOOST_ASSERT(canonicalUri.isCanonical());
348 onSuccess(canonicalUri);
349 }
350
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700351 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500352 onDnsFailure(const shared_ptr<FaceUri>& faceUri,
353 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700354 const std::string& reason) const
355 {
356 onFailure(reason);
357 }
358
359 /** \brief when overriden in a subclass, check the IP address is allowable
360 * \return (true,ignored) if the address is allowable;
361 * (false,reason) if the address is not allowable.
362 */
363 virtual std::pair<bool, std::string>
364 checkAddress(const dns::IpAddress& ipAddress) const
365 {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200366 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700367 }
368
369private:
370 std::string m_baseScheme;
371 std::string m_v4Scheme;
372 std::string m_v6Scheme;
Davide Pesaventof78cb702016-12-11 14:42:40 -0500373 uint16_t m_defaultUnicastPort;
374 uint16_t m_defaultMulticastPort;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700375};
376
377class UdpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::udp>
378{
379public:
380 UdpCanonizeProvider()
381 : IpHostCanonizeProvider("udp")
382 {
383 }
384
385protected:
386 // checkAddress is not overriden:
387 // Although NFD doesn't support IPv6 multicast, it's an implementation limitation.
388 // FaceMgmt protocol allows IPv6 multicast address in UDP.
389};
390
391class TcpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::tcp>
392{
393public:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700394 TcpCanonizeProvider()
395 : IpHostCanonizeProvider("tcp")
396 {
397 }
398
399protected:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500400 std::pair<bool, std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200401 checkAddress(const dns::IpAddress& ipAddress) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700402 {
403 if (ipAddress.is_multicast()) {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200404 return {false, "cannot use multicast address"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700405 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200406 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700407 }
408};
409
410class EtherCanonizeProvider : public CanonizeProvider
411{
412public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500413 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200414 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700415 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500416 return {"ether"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700417 }
418
Davide Pesavento57c07df2016-12-11 18:41:45 -0500419 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200420 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700421 {
422 if (!faceUri.getPort().empty()) {
423 return false;
424 }
425 if (!faceUri.getPath().empty()) {
426 return false;
427 }
428
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500429 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700430 return addr.toString() == faceUri.getHost();
431 }
432
Davide Pesavento57c07df2016-12-11 18:41:45 -0500433 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700434 canonize(const FaceUri& faceUri,
435 const FaceUri::CanonizeSuccessCallback& onSuccess,
436 const FaceUri::CanonizeFailureCallback& onFailure,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200437 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700438 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500439 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700440 if (addr.isNull()) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500441 return onFailure("invalid ethernet address '" + faceUri.getHost() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700442 }
443
444 FaceUri canonicalUri(addr);
445 BOOST_ASSERT(canonicalUri.isCanonical());
446 onSuccess(canonicalUri);
447 }
448};
449
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700450class UdpDevCanonizeProvider : public CanonizeProvider
451{
452public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500453 std::set<std::string>
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700454 getSchemes() const override
455 {
456 return {"udp4+dev", "udp6+dev"};
457 }
458
Davide Pesavento57c07df2016-12-11 18:41:45 -0500459 bool
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700460 isCanonical(const FaceUri& faceUri) const override
461 {
462 if (faceUri.getPort().empty()) {
463 return false;
464 }
465 if (!faceUri.getPath().empty()) {
466 return false;
467 }
468 return true;
469 }
470
Davide Pesavento57c07df2016-12-11 18:41:45 -0500471 void
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700472 canonize(const FaceUri& faceUri,
473 const FaceUri::CanonizeSuccessCallback& onSuccess,
474 const FaceUri::CanonizeFailureCallback& onFailure,
475 boost::asio::io_service& io, const time::nanoseconds& timeout) const override
476 {
477 if (this->isCanonical(faceUri)) {
478 onSuccess(faceUri);
479 }
480 else {
481 onFailure("cannot canonize " + faceUri.toString());
482 }
483 }
484};
485
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500486using CanonizeProviders = boost::mpl::vector<UdpCanonizeProvider*,
487 TcpCanonizeProvider*,
488 EtherCanonizeProvider*,
489 UdpDevCanonizeProvider*>;
490using CanonizeProviderTable = std::map<std::string, shared_ptr<CanonizeProvider>>;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700491
492class CanonizeProviderTableInitializer
493{
494public:
495 explicit
496 CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable)
497 : m_providerTable(providerTable)
498 {
499 }
500
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500501 template<typename CP>
502 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700503 operator()(CP*)
504 {
505 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500506 auto schemes = cp->getSchemes();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700507 BOOST_ASSERT(!schemes.empty());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500508
509 for (const auto& scheme : schemes) {
510 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
511 m_providerTable[scheme] = cp;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700512 }
513 }
514
515private:
516 CanonizeProviderTable& m_providerTable;
517};
518
519static const CanonizeProvider*
520getCanonizeProvider(const std::string& scheme)
521{
522 static CanonizeProviderTable providerTable;
523 if (providerTable.empty()) {
524 boost::mpl::for_each<CanonizeProviders>(CanonizeProviderTableInitializer(providerTable));
525 BOOST_ASSERT(!providerTable.empty());
526 }
527
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200528 auto it = providerTable.find(scheme);
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500529 return it == providerTable.end() ? nullptr : it->second.get();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700530}
531
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500532
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700533bool
534FaceUri::canCanonize(const std::string& scheme)
535{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500536 return getCanonizeProvider(scheme) != nullptr;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700537}
538
539bool
540FaceUri::isCanonical() const
541{
542 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500543 if (cp == nullptr) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700544 return false;
545 }
546
547 return cp->isCanonical(*this);
548}
549
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700550void
551FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
552 const CanonizeFailureCallback& onFailure,
553 boost::asio::io_service& io, const time::nanoseconds& timeout) const
554{
555 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200556 if (cp == nullptr) {
557 if (onFailure) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700558 onFailure("scheme not supported");
559 }
560 return;
561 }
562
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200563 static CanonizeSuccessCallback successNop = bind([]{});
564 static CanonizeFailureCallback failureNop = bind([]{});
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700565 cp->canonize(*this,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200566 onSuccess ? onSuccess : successNop,
567 onFailure ? onFailure : failureNop,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700568 io, timeout);
569}
570
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700571} // namespace util
572} // namespace ndn