blob: c91add4e975b9ebd646b4c4290e5f14c89aec147 [file] [log] [blame]
Junxiao Shi77dcadd2014-10-05 14:40:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa84f4642017-08-23 16:14:51 -04002/*
Davide Pesaventob984e322018-01-24 19:40:07 -05003 * Copyright (c) 2013-2018 Regents of the University of California,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +00004 * 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"
29
Yanbiao Liac8b4ca2017-07-10 02:27:50 -070030#include "address-converter.hpp"
Alexander Afanasyevc37bf162018-05-08 19:54:16 -040031// #include "dns.hpp"
Yanbiao Liac8b4ca2017-07-10 02:27:50 -070032#include "util/string-helper.hpp"
33
34#include <boost/algorithm/string.hpp>
Junxiao Shie3ef6ee2014-10-05 14:40:54 -070035#include <boost/lexical_cast.hpp>
Junxiao Shi4083c8d2014-10-12 16:43:16 -070036#include <boost/mpl/vector.hpp>
37#include <boost/mpl/for_each.hpp>
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050038#include <boost/regex.hpp>
39#include <set>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040040#include <sstream>
Junxiao Shi77dcadd2014-10-05 14:40:54 -070041
42namespace ndn {
Junxiao Shi77dcadd2014-10-05 14:40:54 -070043
44BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
45
46FaceUri::FaceUri()
47 : m_isV6(false)
48{
49}
50
51FaceUri::FaceUri(const std::string& uri)
52{
53 if (!parse(uri)) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070054 BOOST_THROW_EXCEPTION(Error("Malformed URI: " + uri));
Junxiao Shi77dcadd2014-10-05 14:40:54 -070055 }
56}
57
58FaceUri::FaceUri(const char* uri)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050059 : FaceUri(std::string(uri))
Junxiao Shi77dcadd2014-10-05 14:40:54 -070060{
Junxiao Shi77dcadd2014-10-05 14:40:54 -070061}
62
63bool
64FaceUri::parse(const std::string& uri)
65{
66 m_scheme.clear();
67 m_host.clear();
Junxiao Shi77dcadd2014-10-05 14:40:54 -070068 m_port.clear();
69 m_path.clear();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -050070 m_isV6 = false;
Junxiao Shi77dcadd2014-10-05 14:40:54 -070071
Weiwei Liud7f4fda2016-10-19 22:38:39 -070072 static const boost::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
Junxiao Shi77dcadd2014-10-05 14:40:54 -070073 boost::smatch protocolMatch;
74 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
75 return false;
76 }
77 m_scheme = protocolMatch[1];
Weiwei Liud7f4fda2016-10-19 22:38:39 -070078 const std::string& authority = protocolMatch[3];
79 m_path = protocolMatch[4];
Junxiao Shi77dcadd2014-10-05 14:40:54 -070080
Yanbiao Liac8b4ca2017-07-10 02:27:50 -070081 // pattern for IPv6 link local address enclosed in [ ], with optional port number
Davide Pesaventob984e322018-01-24 19:40:07 -050082 static const boost::regex v6LinkLocalExp("^\\[([a-fA-F0-9:]+)%([^\\s/:]+)\\](?:\\:(\\d+))?$");
Junxiao Shi77dcadd2014-10-05 14:40:54 -070083 // pattern for IPv6 address enclosed in [ ], with optional port number
84 static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
85 // pattern for Ethernet address in standard hex-digits-and-colons notation
86 static const boost::regex etherExp("^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
87 // pattern for IPv4-mapped IPv6 address, with optional port number
88 static const boost::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
89 // pattern for IPv4/hostname/fd/ifname, with optional port number
90 static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
91
92 if (authority.empty()) {
93 // UNIX, internal
94 }
95 else {
96 boost::smatch match;
Yanbiao Liac8b4ca2017-07-10 02:27:50 -070097 if (boost::regex_match(authority, match, v6LinkLocalExp)) {
98 m_isV6 = true;
99 m_host = match[1] + "%" + match[2];
100 m_port = match[3];
101 return true;
102 }
103
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700104 m_isV6 = boost::regex_match(authority, match, v6Exp);
105 if (m_isV6 ||
106 boost::regex_match(authority, match, etherExp) ||
107 boost::regex_match(authority, match, v4MappedV6Exp) ||
108 boost::regex_match(authority, match, v4HostExp)) {
109 m_host = match[1];
110 m_port = match[2];
111 }
112 else {
113 return false;
114 }
115 }
116
117 return true;
118}
119
120FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint)
121{
122 m_isV6 = endpoint.address().is_v6();
123 m_scheme = m_isV6 ? "udp6" : "udp4";
124 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700125 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700126}
127
128FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint)
129{
130 m_isV6 = endpoint.address().is_v6();
131 m_scheme = m_isV6 ? "tcp6" : "tcp4";
132 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700133 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700134}
135
136FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint, const std::string& scheme)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700137{
138 m_isV6 = endpoint.address().is_v6();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500139 m_scheme = scheme;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700140 m_host = endpoint.address().to_string();
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700141 m_port = to_string(endpoint.port());
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700142}
143
144#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
145FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500146 : m_scheme("unix")
147 , m_path(endpoint.path())
148 , m_isV6(false)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700149{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700150}
151#endif // BOOST_ASIO_HAS_LOCAL_SOCKETS
152
153FaceUri
154FaceUri::fromFd(int fd)
155{
156 FaceUri uri;
157 uri.m_scheme = "fd";
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700158 uri.m_host = to_string(fd);
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700159 return uri;
160}
161
162FaceUri::FaceUri(const ethernet::Address& address)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500163 : m_scheme("ether")
164 , m_host(address.toString())
165 , m_isV6(true)
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700166{
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700167}
168
169FaceUri
170FaceUri::fromDev(const std::string& ifname)
171{
172 FaceUri uri;
173 uri.m_scheme = "dev";
174 uri.m_host = ifname;
175 return uri;
176}
177
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700178FaceUri
179FaceUri::fromUdpDev(const boost::asio::ip::udp::endpoint& endpoint, const std::string& ifname)
180{
181 FaceUri uri;
182 uri.m_scheme = endpoint.address().is_v6() ? "udp6+dev" : "udp4+dev";
183 uri.m_host = ifname;
184 uri.m_port = to_string(endpoint.port());
185 return uri;
186}
187
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700188bool
189FaceUri::operator==(const FaceUri& rhs) const
190{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500191 return m_isV6 == rhs.m_isV6 &&
192 m_scheme == rhs.m_scheme &&
193 m_host == rhs.m_host &&
194 m_port == rhs.m_port &&
195 m_path == rhs.m_path;
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700196}
197
198bool
199FaceUri::operator!=(const FaceUri& rhs) const
200{
201 return !(*this == rhs);
202}
203
204std::string
205FaceUri::toString() const
206{
207 std::ostringstream os;
208 os << *this;
209 return os.str();
210}
211
212std::ostream&
213operator<<(std::ostream& os, const FaceUri& uri)
214{
215 os << uri.m_scheme << "://";
216 if (uri.m_isV6) {
217 os << "[" << uri.m_host << "]";
218 }
219 else {
220 os << uri.m_host;
221 }
222 if (!uri.m_port.empty()) {
223 os << ":" << uri.m_port;
224 }
225 os << uri.m_path;
226 return os;
227}
228
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500229
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700230/** \brief a CanonizeProvider provides FaceUri canonization functionality for a group of schemes
231 */
232class CanonizeProvider : noncopyable
233{
234public:
235 virtual
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200236 ~CanonizeProvider() = default;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700237
238 virtual std::set<std::string>
239 getSchemes() const = 0;
240
241 virtual bool
242 isCanonical(const FaceUri& faceUri) const = 0;
243
244 virtual void
245 canonize(const FaceUri& faceUri,
246 const FaceUri::CanonizeSuccessCallback& onSuccess,
247 const FaceUri::CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400248 time::nanoseconds timeout) const = 0;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700249};
250
251template<typename Protocol>
252class IpHostCanonizeProvider : public CanonizeProvider
253{
254public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500255 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200256 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700257 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500258 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700259 }
260
Davide Pesavento57c07df2016-12-11 18:41:45 -0500261 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200262 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700263 {
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400264 BOOST_THROW_EXCEPTION(std::runtime_error("IP host canonization not supported"));
265 // if (faceUri.getPort().empty()) {
266 // return false;
267 // }
268 // if (!faceUri.getPath().empty()) {
269 // return false;
270 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700271
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400272 // boost::system::error_code ec;
273 // auto addr = ip::addressFromString(unescapeHost(faceUri.getHost()), ec);
274 // if (ec) {
275 // return false;
276 // }
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500277
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400278 // bool hasCorrectScheme = (faceUri.getScheme() == m_v4Scheme && addr.is_v4()) ||
279 // (faceUri.getScheme() == m_v6Scheme && addr.is_v6());
280 // if (!hasCorrectScheme) {
281 // return false;
282 // }
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700283
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400284 // auto checkAddressWithUri = [] (const boost::asio::ip::address& addr,
285 // const FaceUri& faceUri) -> bool {
286 // if (addr.is_v4() || !addr.to_v6().is_link_local()) {
287 // return addr.to_string() == faceUri.getHost();
288 // }
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700289
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400290 // std::vector<std::string> addrFields, faceUriFields;
291 // std::string addrString = addr.to_string();
292 // std::string faceUriString = faceUri.getHost();
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700293
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400294 // boost::algorithm::split(addrFields, addrString, boost::is_any_of("%"));
295 // boost::algorithm::split(faceUriFields, faceUriString, boost::is_any_of("%"));
296 // if (addrFields.size() != 2 || faceUriFields.size() != 2) {
297 // return false;
298 // }
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700299
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400300 // if (faceUriFields[1].size() > 2 && faceUriFields[1].compare(0, 2, "25") == 0) {
301 // // %25... is accepted, but not a canonical form
302 // return false;
303 // }
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700304
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400305 // return addrFields[0] == faceUriFields[0] &&
306 // addrFields[1] == faceUriFields[1];
307 // };
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700308
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400309 // return checkAddressWithUri(addr, faceUri) && checkAddress(addr).first;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700310 }
311
Davide Pesavento57c07df2016-12-11 18:41:45 -0500312 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700313 canonize(const FaceUri& faceUri,
314 const FaceUri::CanonizeSuccessCallback& onSuccess,
315 const FaceUri::CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400316 time::nanoseconds timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700317 {
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400318 BOOST_THROW_EXCEPTION(std::runtime_error("IP host canonization not supported"));
319 // if (this->isCanonical(faceUri)) {
320 // onSuccess(faceUri);
321 // return;
322 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700323
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400324 // // make a copy because caller may modify faceUri
325 // auto uri = make_shared<FaceUri>(faceUri);
326 // boost::system::error_code ec;
327 // auto ipAddress = ip::addressFromString(unescapeHost(faceUri.getHost()), ec);
328 // if (!ec) {
329 // // No need to resolve IP address if host is already an IP
330 // if ((faceUri.getScheme() == m_v4Scheme && !ipAddress.is_v4()) ||
331 // (faceUri.getScheme() == m_v6Scheme && !ipAddress.is_v6())) {
332 // return onFailure("IPv4/v6 mismatch");
333 // }
Eric Newberry71aecae2017-05-29 00:22:39 -0700334
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400335 // onDnsSuccess(uri, onSuccess, onFailure, ipAddress);
336 // }
337 // else {
338 // dns::AddressSelector addressSelector;
339 // if (faceUri.getScheme() == m_v4Scheme) {
340 // addressSelector = dns::Ipv4Only();
341 // }
342 // else if (faceUri.getScheme() == m_v6Scheme) {
343 // addressSelector = dns::Ipv6Only();
344 // }
345 // else {
346 // BOOST_ASSERT(faceUri.getScheme() == m_baseScheme);
347 // addressSelector = dns::AnyAddress();
348 // }
Eric Newberry71aecae2017-05-29 00:22:39 -0700349
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400350 // dns::asyncResolve(unescapeHost(faceUri.getHost()),
351 // bind(&IpHostCanonizeProvider<Protocol>::onDnsSuccess, this, uri, onSuccess, onFailure, _1),
352 // bind(&IpHostCanonizeProvider<Protocol>::onDnsFailure, this, uri, onFailure, _1),
353 // io, addressSelector, timeout);
354 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700355 }
356
357protected:
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200358 explicit
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700359 IpHostCanonizeProvider(const std::string& baseScheme,
Davide Pesaventof78cb702016-12-11 14:42:40 -0500360 uint16_t defaultUnicastPort = 6363,
361 uint16_t defaultMulticastPort = 56363)
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700362 : m_baseScheme(baseScheme)
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500363 , m_v4Scheme(baseScheme + '4')
364 , m_v6Scheme(baseScheme + '6')
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700365 , m_defaultUnicastPort(defaultUnicastPort)
366 , m_defaultMulticastPort(defaultMulticastPort)
367 {
368 }
369
370private:
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400371 // void
372 // onDnsSuccess(const shared_ptr<FaceUri>& faceUri,
373 // const FaceUri::CanonizeSuccessCallback& onSuccess,
374 // const FaceUri::CanonizeFailureCallback& onFailure,
375 // const dns::IpAddress& ipAddress) const
376 // {
377 // bool isOk = false;
378 // std::string reason;
379 // std::tie(isOk, reason) = this->checkAddress(ipAddress);
380 // if (!isOk) {
381 // return onFailure(reason);
382 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700383
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400384 // uint16_t port = 0;
385 // if (faceUri->getPort().empty()) {
386 // port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
387 // }
388 // else {
389 // try {
390 // port = boost::lexical_cast<uint16_t>(faceUri->getPort());
391 // }
392 // catch (const boost::bad_lexical_cast&) {
393 // return onFailure("invalid port number '" + faceUri->getPort() + "'");
394 // }
395 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700396
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400397 // FaceUri canonicalUri(typename Protocol::endpoint(ipAddress, port));
398 // BOOST_ASSERT(canonicalUri.isCanonical());
399 // onSuccess(canonicalUri);
400 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700401
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400402 // void
403 // onDnsFailure(const shared_ptr<FaceUri>& faceUri,
404 // const FaceUri::CanonizeFailureCallback& onFailure,
405 // const std::string& reason) const
406 // {
407 // onFailure(reason);
408 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700409
410 /** \brief when overriden in a subclass, check the IP address is allowable
411 * \return (true,ignored) if the address is allowable;
412 * (false,reason) if the address is not allowable.
413 */
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400414 // virtual std::pair<bool, std::string>
415 // checkAddress(const dns::IpAddress& ipAddress) const
416 // {
417 // return {true, ""};
418 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700419
Yanbiao Liac8b4ca2017-07-10 02:27:50 -0700420 static std::string
421 unescapeHost(std::string host)
422 {
423 auto escapePos = host.find("%25");
424 if (escapePos != std::string::npos && escapePos < host.size() - 3) {
425 host = unescape(host);
426 }
427 return host;
428 }
429
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700430private:
431 std::string m_baseScheme;
432 std::string m_v4Scheme;
433 std::string m_v6Scheme;
Davide Pesaventof78cb702016-12-11 14:42:40 -0500434 uint16_t m_defaultUnicastPort;
435 uint16_t m_defaultMulticastPort;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700436};
437
438class UdpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::udp>
439{
440public:
441 UdpCanonizeProvider()
442 : IpHostCanonizeProvider("udp")
443 {
444 }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700445};
446
447class TcpCanonizeProvider : public IpHostCanonizeProvider<boost::asio::ip::tcp>
448{
449public:
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700450 TcpCanonizeProvider()
451 : IpHostCanonizeProvider("tcp")
452 {
453 }
454
455protected:
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400456 // std::pair<bool, std::string>
457 // checkAddress(const dns::IpAddress& ipAddress) const override
458 // {
459 // if (ipAddress.is_multicast()) {
460 // return {false, "cannot use multicast address"};
461 // }
462 // return {true, ""};
463 // }
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700464};
465
466class EtherCanonizeProvider : public CanonizeProvider
467{
468public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500469 std::set<std::string>
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200470 getSchemes() const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700471 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500472 return {"ether"};
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700473 }
474
Davide Pesavento57c07df2016-12-11 18:41:45 -0500475 bool
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200476 isCanonical(const FaceUri& faceUri) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700477 {
478 if (!faceUri.getPort().empty()) {
479 return false;
480 }
481 if (!faceUri.getPath().empty()) {
482 return false;
483 }
484
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500485 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700486 return addr.toString() == faceUri.getHost();
487 }
488
Davide Pesavento57c07df2016-12-11 18:41:45 -0500489 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700490 canonize(const FaceUri& faceUri,
491 const FaceUri::CanonizeSuccessCallback& onSuccess,
492 const FaceUri::CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400493 time::nanoseconds timeout) const override
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700494 {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500495 auto addr = ethernet::Address::fromString(faceUri.getHost());
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700496 if (addr.isNull()) {
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500497 return onFailure("invalid ethernet address '" + faceUri.getHost() + "'");
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700498 }
499
500 FaceUri canonicalUri(addr);
501 BOOST_ASSERT(canonicalUri.isCanonical());
502 onSuccess(canonicalUri);
503 }
504};
505
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000506class DevCanonizeProvider : public CanonizeProvider
507{
508public:
509 std::set<std::string>
510 getSchemes() const override
511 {
512 return {"dev"};
513 }
514
515 bool
516 isCanonical(const FaceUri& faceUri) const override
517 {
518 return !faceUri.getHost().empty() && faceUri.getPort().empty() && faceUri.getPath().empty();
519 }
520
521 void
522 canonize(const FaceUri& faceUri,
523 const FaceUri::CanonizeSuccessCallback& onSuccess,
524 const FaceUri::CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400525 time::nanoseconds timeout) const override
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000526 {
527 if (faceUri.getHost().empty()) {
528 onFailure("network interface name is missing");
529 return;
530 }
531 if (!faceUri.getPort().empty()) {
532 onFailure("port number is not allowed");
533 return;
534 }
535 if (!faceUri.getPath().empty() && faceUri.getPath() != "/") { // permit trailing slash only
536 onFailure("path is not allowed");
537 return;
538 }
539
540 FaceUri canonicalUri = FaceUri::fromDev(faceUri.getHost());
541 BOOST_ASSERT(canonicalUri.isCanonical());
542 onSuccess(canonicalUri);
543 }
544};
545
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700546class UdpDevCanonizeProvider : public CanonizeProvider
547{
548public:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500549 std::set<std::string>
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700550 getSchemes() const override
551 {
552 return {"udp4+dev", "udp6+dev"};
553 }
554
Davide Pesavento57c07df2016-12-11 18:41:45 -0500555 bool
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700556 isCanonical(const FaceUri& faceUri) const override
557 {
558 if (faceUri.getPort().empty()) {
559 return false;
560 }
561 if (!faceUri.getPath().empty()) {
562 return false;
563 }
564 return true;
565 }
566
Davide Pesavento57c07df2016-12-11 18:41:45 -0500567 void
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700568 canonize(const FaceUri& faceUri,
569 const FaceUri::CanonizeSuccessCallback& onSuccess,
570 const FaceUri::CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400571 time::nanoseconds timeout) const override
Weiwei Liud7f4fda2016-10-19 22:38:39 -0700572 {
573 if (this->isCanonical(faceUri)) {
574 onSuccess(faceUri);
575 }
576 else {
577 onFailure("cannot canonize " + faceUri.toString());
578 }
579 }
580};
581
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500582using CanonizeProviders = boost::mpl::vector<UdpCanonizeProvider*,
583 TcpCanonizeProvider*,
584 EtherCanonizeProvider*,
Junxiao Shid5c2f0c2017-04-04 09:52:11 +0000585 DevCanonizeProvider*,
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500586 UdpDevCanonizeProvider*>;
587using CanonizeProviderTable = std::map<std::string, shared_ptr<CanonizeProvider>>;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700588
589class CanonizeProviderTableInitializer
590{
591public:
592 explicit
593 CanonizeProviderTableInitializer(CanonizeProviderTable& providerTable)
594 : m_providerTable(providerTable)
595 {
596 }
597
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500598 template<typename CP>
599 void
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700600 operator()(CP*)
601 {
602 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500603 auto schemes = cp->getSchemes();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700604 BOOST_ASSERT(!schemes.empty());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500605
606 for (const auto& scheme : schemes) {
607 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
608 m_providerTable[scheme] = cp;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700609 }
610 }
611
612private:
613 CanonizeProviderTable& m_providerTable;
614};
615
616static const CanonizeProvider*
617getCanonizeProvider(const std::string& scheme)
618{
619 static CanonizeProviderTable providerTable;
620 if (providerTable.empty()) {
621 boost::mpl::for_each<CanonizeProviders>(CanonizeProviderTableInitializer(providerTable));
622 BOOST_ASSERT(!providerTable.empty());
623 }
624
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200625 auto it = providerTable.find(scheme);
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500626 return it == providerTable.end() ? nullptr : it->second.get();
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700627}
628
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500629
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700630bool
631FaceUri::canCanonize(const std::string& scheme)
632{
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500633 return getCanonizeProvider(scheme) != nullptr;
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700634}
635
636bool
637FaceUri::isCanonical() const
638{
639 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoe1081cd2016-12-19 23:58:15 -0500640 if (cp == nullptr) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700641 return false;
642 }
643
644 return cp->isCanonical(*this);
645}
646
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700647void
648FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
649 const CanonizeFailureCallback& onFailure,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400650 time::nanoseconds timeout) const
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700651{
652 const CanonizeProvider* cp = getCanonizeProvider(this->getScheme());
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200653 if (cp == nullptr) {
654 if (onFailure) {
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700655 onFailure("scheme not supported");
656 }
657 return;
658 }
659
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200660 static CanonizeSuccessCallback successNop = bind([]{});
661 static CanonizeFailureCallback failureNop = bind([]{});
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700662 cp->canonize(*this,
Davide Pesaventoaeeb3fc2016-08-14 03:40:02 +0200663 onSuccess ? onSuccess : successNop,
664 onFailure ? onFailure : failureNop,
Alexander Afanasyevc37bf162018-05-08 19:54:16 -0400665 timeout);
Junxiao Shi4083c8d2014-10-12 16:43:16 -0700666}
667
Junxiao Shi77dcadd2014-10-05 14:40:54 -0700668} // namespace ndn