blob: 83ad2ebe9c24490af6ee8abeef7b2c18113e7bad [file] [log] [blame]
Junxiao Shi77dcadd2014-10-05 14:40:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shid5c2f0c2017-04-04 09:52:11 +00003 * Copyright (c) 2013-2017 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.
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,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000236 boost::asio::io_service& io, time::nanoseconds timeout) const = 0;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700237};
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,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000278 boost::asio::io_service& io, 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,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000436 boost::asio::io_service& io, 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
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000449class DevCanonizeProvider : public CanonizeProvider
450{
451public:
452 std::set<std::string>
453 getSchemes() const override
454 {
455 return {"dev"};
456 }
457
458 bool
459 isCanonical(const FaceUri& faceUri) const override
460 {
461 return !faceUri.getHost().empty() && faceUri.getPort().empty() && faceUri.getPath().empty();
462 }
463
464 void
465 canonize(const FaceUri& faceUri,
466 const FaceUri::CanonizeSuccessCallback& onSuccess,
467 const FaceUri::CanonizeFailureCallback& onFailure,
468 boost::asio::io_service& io, time::nanoseconds timeout) const override
469 {
470 if (faceUri.getHost().empty()) {
471 onFailure("network interface name is missing");
472 return;
473 }
474 if (!faceUri.getPort().empty()) {
475 onFailure("port number is not allowed");
476 return;
477 }
478 if (!faceUri.getPath().empty() && faceUri.getPath() != "/") { // permit trailing slash only
479 onFailure("path is not allowed");
480 return;
481 }
482
483 FaceUri canonicalUri = FaceUri::fromDev(faceUri.getHost());
484 BOOST_ASSERT(canonicalUri.isCanonical());
485 onSuccess(canonicalUri);
486 }
487};
488
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700489class UdpDevCanonizeProvider : public CanonizeProvider
490{
491public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500492 std::set<std::string>
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700493 getSchemes() const override
494 {
495 return {"udp4+dev", "udp6+dev"};
496 }
497
Davide Pesavento57c07df2016-12-11 18:41:45 -0500498 bool
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700499 isCanonical(const FaceUri& faceUri) const override
500 {
501 if (faceUri.getPort().empty()) {
502 return false;
503 }
504 if (!faceUri.getPath().empty()) {
505 return false;
506 }
507 return true;
508 }
509
Davide Pesavento57c07df2016-12-11 18:41:45 -0500510 void
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700511 canonize(const FaceUri& faceUri,
512 const FaceUri::CanonizeSuccessCallback& onSuccess,
513 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000514 boost::asio::io_service& io, time::nanoseconds timeout) const override
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700515 {
516 if (this->isCanonical(faceUri)) {
517 onSuccess(faceUri);
518 }
519 else {
520 onFailure("cannot canonize " + faceUri.toString());
521 }
522 }
523};
524
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500525using CanonizeProviders = boost::mpl::vector<UdpCanonizeProvider*,
526 TcpCanonizeProvider*,
527 EtherCanonizeProvider*,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000528 DevCanonizeProvider*,
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500529 UdpDevCanonizeProvider*>;
530using CanonizeProviderTable = std::map<std::string, shared_ptr<CanonizeProvider>>;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700531
532class CanonizeProviderTableInitializer
533{
534public:
535 explicit
536 CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable)
537 : m_providerTable(providerTable)
538 {
539 }
540
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500541 template<typename CP>
542 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700543 operator()(CP*)
544 {
545 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500546 auto schemes = cp->getSchemes();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700547 BOOST_ASSERT(!schemes.empty());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500548
549 for (const auto& scheme : schemes) {
550 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
551 m_providerTable[scheme] = cp;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700552 }
553 }
554
555private:
556 CanonizeProviderTable& m_providerTable;
557};
558
559static const CanonizeProvider*
560getCanonizeProvider(const std::string& scheme)
561{
562 static CanonizeProviderTable providerTable;
563 if (providerTable.empty()) {
564 boost::mpl::for_each<CanonizeProviders>(CanonizeProviderTableInitializer(providerTable));
565 BOOST_ASSERT(!providerTable.empty());
566 }
567
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200568 auto it = providerTable.find(scheme);
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500569 return it == providerTable.end() ? nullptr : it->second.get();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700570}
571
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500572
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700573bool
574FaceUri::canCanonize(const std::string& scheme)
575{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500576 return getCanonizeProvider(scheme) != nullptr;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700577}
578
579bool
580FaceUri::isCanonical() const
581{
582 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500583 if (cp == nullptr) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700584 return false;
585 }
586
587 return cp->isCanonical(*this);
588}
589
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700590void
591FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
592 const CanonizeFailureCallback& onFailure,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000593 boost::asio::io_service& io, time::nanoseconds timeout) const
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700594{
595 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200596 if (cp == nullptr) {
597 if (onFailure) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700598 onFailure("scheme not supported");
599 }
600 return;
601 }
602
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200603 static CanonizeSuccessCallback successNop = bind([]{});
604 static CanonizeFailureCallback failureNop = bind([]{});
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700605 cp->canonize(*this,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200606 onSuccess ? onSuccess : successNop,
607 onFailure ? onFailure : failureNop,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700608 io, timeout);
609}
610
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700611} // namespace util
612} // namespace ndn