blob: d1a26df3d48d6a2b9f5caea4046b369d6708c00b [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
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700285 // make a copy because caller may modify faceUri
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500286 auto uri = make_shared<FaceUri>(faceUri);
Eric Newberry71aecae2017-05-29 00:22:39 -0700287 boost::system::error_code ec;
288 auto ipAddress = boost::asio::ip::address::from_string(faceUri.getHost(), ec);
289 if (!ec) {
290 // No need to resolve IP address if host is already an IP
291 if ((faceUri.getScheme() == m_v4Scheme && !ipAddress.is_v4()) ||
292 (faceUri.getScheme() == m_v6Scheme && !ipAddress.is_v6())) {
293 return onFailure("IPv4/v6 mismatch");
294 }
295
296 onDnsSuccess(uri, onSuccess, onFailure, ipAddress);
297 }
298 else {
299 dns::AddressSelector addressSelector;
300 if (faceUri.getScheme() == m_v4Scheme) {
301 addressSelector = dns::Ipv4Only();
302 }
303 else if (faceUri.getScheme() == m_v6Scheme) {
304 addressSelector = dns::Ipv6Only();
305 }
306 else {
307 BOOST_ASSERT(faceUri.getScheme() == m_baseScheme);
308 addressSelector = dns::AnyAddress();
309 }
310
311 dns::asyncResolve(faceUri.getHost(),
312 bind(&IpHostCanonizeProvider<Protocol>::onDnsSuccess, this, uri, onSuccess, onFailure, _1),
313 bind(&IpHostCanonizeProvider<Protocol>::onDnsFailure, this, uri, onFailure, _1),
314 io, addressSelector, timeout);
315 }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700316 }
317
318protected:
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200319 explicit
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700320 IpHostCanonizeProvider(const std::string& baseScheme,
Davide Pesaventof78cb702016-12-11 14:42:40 -0500321 uint16_t defaultUnicastPort = 6363,
322 uint16_t defaultMulticastPort = 56363)
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700323 : m_baseScheme(baseScheme)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500324 , m_v4Scheme(baseScheme + '4')
325 , m_v6Scheme(baseScheme + '6')
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700326 , m_defaultUnicastPort(defaultUnicastPort)
327 , m_defaultMulticastPort(defaultMulticastPort)
328 {
329 }
330
331private:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700332 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500333 onDnsSuccess(const shared_ptr<FaceUri>& faceUri,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700334 const FaceUri::CanonizeSuccessCallback& onSuccess,
335 const FaceUri::CanonizeFailureCallback& onFailure,
336 const dns::IpAddress& ipAddress) const
337 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500338 bool isOk = false;
339 std::string reason;
340 std::tie(isOk, reason) = this->checkAddress(ipAddress);
341 if (!isOk) {
342 return onFailure(reason);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700343 }
344
Davide Pesaventof78cb702016-12-11 14:42:40 -0500345 uint16_t port = 0;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700346 if (faceUri->getPort().empty()) {
347 port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
348 }
349 else {
350 try {
Davide Pesaventof78cb702016-12-11 14:42:40 -0500351 port = boost::lexical_cast<uint16_t>(faceUri->getPort());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700352 }
Davide Pesaventof78cb702016-12-11 14:42:40 -0500353 catch (const boost::bad_lexical_cast&) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500354 return onFailure("invalid port number '" + faceUri->getPort() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700355 }
356 }
357
358 FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port));
359 BOOST_ASSERT(canonicalUri.isCanonical());
360 onSuccess(canonicalUri);
361 }
362
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700363 void
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500364 onDnsFailure(const shared_ptr<FaceUri>& faceUri,
365 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700366 const std::string& reason) const
367 {
368 onFailure(reason);
369 }
370
371 /** \brief when overriden in a subclass, check the IP address is allowable
372 * \return (true,ignored) if the address is allowable;
373 * (false,reason) if the address is not allowable.
374 */
375 virtual std::pair<bool, std::string>
376 checkAddress(const dns::IpAddress& ipAddress) const
377 {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200378 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700379 }
380
381private:
382 std::string m_baseScheme;
383 std::string m_v4Scheme;
384 std::string m_v6Scheme;
Davide Pesaventof78cb702016-12-11 14:42:40 -0500385 uint16_t m_defaultUnicastPort;
386 uint16_t m_defaultMulticastPort;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700387};
388
389class UdpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::udp>
390{
391public:
392 UdpCanonizeProvider()
393 : IpHostCanonizeProvider("udp")
394 {
395 }
396
397protected:
398 // checkAddress is not overriden:
399 // Although NFD doesn't support IPv6 multicast, it's an implementation limitation.
400 // FaceMgmt protocol allows IPv6 multicast address in UDP.
401};
402
403class TcpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::tcp>
404{
405public:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700406 TcpCanonizeProvider()
407 : IpHostCanonizeProvider("tcp")
408 {
409 }
410
411protected:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500412 std::pair<bool, std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200413 checkAddress(const dns::IpAddress& ipAddress) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700414 {
415 if (ipAddress.is_multicast()) {
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200416 return {false, "cannot use multicast address"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700417 }
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200418 return {true, ""};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700419 }
420};
421
422class EtherCanonizeProvider : public CanonizeProvider
423{
424public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500425 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200426 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700427 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500428 return {"ether"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700429 }
430
Davide Pesavento57c07df2016-12-11 18:41:45 -0500431 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200432 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700433 {
434 if (!faceUri.getPort().empty()) {
435 return false;
436 }
437 if (!faceUri.getPath().empty()) {
438 return false;
439 }
440
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500441 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700442 return addr.toString() == faceUri.getHost();
443 }
444
Davide Pesavento57c07df2016-12-11 18:41:45 -0500445 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700446 canonize(const FaceUri& faceUri,
447 const FaceUri::CanonizeSuccessCallback& onSuccess,
448 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000449 boost::asio::io_service& io, time::nanoseconds timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700450 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500451 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700452 if (addr.isNull()) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500453 return onFailure("invalid ethernet address '" + faceUri.getHost() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700454 }
455
456 FaceUri canonicalUri(addr);
457 BOOST_ASSERT(canonicalUri.isCanonical());
458 onSuccess(canonicalUri);
459 }
460};
461
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000462class DevCanonizeProvider : public CanonizeProvider
463{
464public:
465 std::set<std::string>
466 getSchemes() const override
467 {
468 return {"dev"};
469 }
470
471 bool
472 isCanonical(const FaceUri& faceUri) const override
473 {
474 return !faceUri.getHost().empty() && faceUri.getPort().empty() && faceUri.getPath().empty();
475 }
476
477 void
478 canonize(const FaceUri& faceUri,
479 const FaceUri::CanonizeSuccessCallback& onSuccess,
480 const FaceUri::CanonizeFailureCallback& onFailure,
481 boost::asio::io_service& io, time::nanoseconds timeout) const override
482 {
483 if (faceUri.getHost().empty()) {
484 onFailure("network interface name is missing");
485 return;
486 }
487 if (!faceUri.getPort().empty()) {
488 onFailure("port number is not allowed");
489 return;
490 }
491 if (!faceUri.getPath().empty() && faceUri.getPath() != "/") { // permit trailing slash only
492 onFailure("path is not allowed");
493 return;
494 }
495
496 FaceUri canonicalUri = FaceUri::fromDev(faceUri.getHost());
497 BOOST_ASSERT(canonicalUri.isCanonical());
498 onSuccess(canonicalUri);
499 }
500};
501
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700502class UdpDevCanonizeProvider : public CanonizeProvider
503{
504public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500505 std::set<std::string>
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700506 getSchemes() const override
507 {
508 return {"udp4+dev", "udp6+dev"};
509 }
510
Davide Pesavento57c07df2016-12-11 18:41:45 -0500511 bool
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700512 isCanonical(const FaceUri& faceUri) const override
513 {
514 if (faceUri.getPort().empty()) {
515 return false;
516 }
517 if (!faceUri.getPath().empty()) {
518 return false;
519 }
520 return true;
521 }
522
Davide Pesavento57c07df2016-12-11 18:41:45 -0500523 void
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700524 canonize(const FaceUri& faceUri,
525 const FaceUri::CanonizeSuccessCallback& onSuccess,
526 const FaceUri::CanonizeFailureCallback& onFailure,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000527 boost::asio::io_service& io, time::nanoseconds timeout) const override
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700528 {
529 if (this->isCanonical(faceUri)) {
530 onSuccess(faceUri);
531 }
532 else {
533 onFailure("cannot canonize " + faceUri.toString());
534 }
535 }
536};
537
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500538using CanonizeProviders = boost::mpl::vector<UdpCanonizeProvider*,
539 TcpCanonizeProvider*,
540 EtherCanonizeProvider*,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000541 DevCanonizeProvider*,
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500542 UdpDevCanonizeProvider*>;
543using CanonizeProviderTable = std::map<std::string, shared_ptr<CanonizeProvider>>;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700544
545class CanonizeProviderTableInitializer
546{
547public:
548 explicit
549 CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable)
550 : m_providerTable(providerTable)
551 {
552 }
553
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500554 template<typename CP>
555 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700556 operator()(CP*)
557 {
558 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500559 auto schemes = cp->getSchemes();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700560 BOOST_ASSERT(!schemes.empty());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500561
562 for (const auto& scheme : schemes) {
563 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
564 m_providerTable[scheme] = cp;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700565 }
566 }
567
568private:
569 CanonizeProviderTable& m_providerTable;
570};
571
572static const CanonizeProvider*
573getCanonizeProvider(const std::string& scheme)
574{
575 static CanonizeProviderTable providerTable;
576 if (providerTable.empty()) {
577 boost::mpl::for_each<CanonizeProviders>(CanonizeProviderTableInitializer(providerTable));
578 BOOST_ASSERT(!providerTable.empty());
579 }
580
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200581 auto it = providerTable.find(scheme);
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500582 return it == providerTable.end() ? nullptr : it->second.get();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700583}
584
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500585
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700586bool
587FaceUri::canCanonize(const std::string& scheme)
588{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500589 return getCanonizeProvider(scheme) != nullptr;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700590}
591
592bool
593FaceUri::isCanonical() const
594{
595 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500596 if (cp == nullptr) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700597 return false;
598 }
599
600 return cp->isCanonical(*this);
601}
602
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700603void
604FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
605 const CanonizeFailureCallback& onFailure,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000606 boost::asio::io_service& io, time::nanoseconds timeout) const
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700607{
608 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200609 if (cp == nullptr) {
610 if (onFailure) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700611 onFailure("scheme not supported");
612 }
613 return;
614 }
615
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200616 static CanonizeSuccessCallback successNop = bind([]{});
617 static CanonizeFailureCallback failureNop = bind([]{});
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700618 cp->canonize(*this,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200619 onSuccess ? onSuccess : successNop,
620 onFailure ? onFailure : failureNop,
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700621 io, timeout);
622}
623
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700624} // namespace util
625} // namespace ndn