32 #include <boost/algorithm/string.hpp>
33 #include <boost/lexical_cast.hpp>
34 #include <boost/mpl/vector.hpp>
35 #include <boost/mpl/for_each.hpp>
43 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
71 static const std::regex protocolExp(
"(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
72 std::smatch protocolMatch;
73 if (!std::regex_match(uri, protocolMatch, protocolExp)) {
76 m_scheme = protocolMatch[1];
77 std::string authority = protocolMatch[3];
78 m_path = protocolMatch[4];
81 static const std::regex v6LinkLocalExp(
"^\\[([a-fA-F0-9:]+)%([^\\s/:]+)\\](?:\\:(\\d+))?$");
83 static const std::regex v6Exp(
"^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
85 static const std::regex etherExp(
"^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
87 static const std::regex v4MappedV6Exp(
"^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
89 static const std::regex v4HostExp(
"^([^:]+)(?:\\:(\\d+))?$");
91 if (authority.empty()) {
96 if (std::regex_match(authority, match, v6LinkLocalExp)) {
98 m_host = match[1].str() +
"%" + match[2].str();
103 m_isV6 = std::regex_match(authority, match, v6Exp);
105 std::regex_match(authority, match, etherExp) ||
106 std::regex_match(authority, match, v4MappedV6Exp) ||
107 std::regex_match(authority, match, v4HostExp)) {
121 m_isV6 = endpoint.address().is_v6();
122 m_scheme = m_isV6 ?
"udp6" :
"udp4";
123 m_host = endpoint.address().to_string();
129 m_isV6 = endpoint.address().is_v6();
130 m_scheme = m_isV6 ?
"tcp6" :
"tcp4";
131 m_host = endpoint.address().to_string();
135 FaceUri::FaceUri(
const boost::asio::ip::tcp::endpoint& endpoint,
const std::string& scheme)
137 m_isV6 = endpoint.address().is_v6();
139 m_host = endpoint.address().to_string();
143 #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
144 FaceUri::FaceUri(
const boost::asio::local::stream_protocol::endpoint& endpoint)
146 , m_path(endpoint.path())
150 #endif // BOOST_ASIO_HAS_LOCAL_SOCKETS
172 uri.m_scheme =
"dev";
181 uri.m_scheme = endpoint.address().is_v6() ?
"udp6+dev" :
"udp4+dev";
190 std::ostringstream os;
198 os << uri.m_scheme <<
"://";
200 os <<
"[" << uri.m_host <<
"]";
205 if (!uri.m_port.empty()) {
206 os <<
":" << uri.m_port;
221 virtual std::set<std::string>
231 time::nanoseconds timeout)
const = 0;
234 template<
typename Protocol>
238 std::set<std::string>
241 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
247 BOOST_THROW_EXCEPTION(std::runtime_error(
"IP host canonization not supported"));
299 time::nanoseconds timeout)
const override
301 BOOST_THROW_EXCEPTION(std::runtime_error(
"IP host canonization not supported"));
343 uint16_t defaultUnicastPort = 6363,
344 uint16_t defaultMulticastPort = 56363)
345 : m_baseScheme(baseScheme)
346 , m_v4Scheme(baseScheme +
'4')
347 , m_v6Scheme(baseScheme +
'6')
348 , m_defaultUnicastPort(defaultUnicastPort)
349 , m_defaultMulticastPort(defaultMulticastPort)
404 unescapeHost(std::string host)
406 auto escapePos = host.find(
"%25");
407 if (escapePos != std::string::npos && escapePos < host.size() - 3) {
414 std::string m_baseScheme;
415 std::string m_v4Scheme;
416 std::string m_v6Scheme;
417 uint16_t m_defaultUnicastPort;
418 uint16_t m_defaultMulticastPort;
452 std::set<std::string>
461 if (!faceUri.
getPort().empty()) {
464 if (!faceUri.
getPath().empty()) {
469 return addr.toString() == faceUri.
getHost();
476 time::nanoseconds timeout)
const override
480 return onFailure(
"invalid ethernet address '" + faceUri.
getHost() +
"'");
485 onSuccess(canonicalUri);
492 std::set<std::string>
508 time::nanoseconds timeout)
const override
510 if (faceUri.
getHost().empty()) {
511 onFailure(
"network interface name is missing");
514 if (!faceUri.
getPort().empty()) {
515 onFailure(
"port number is not allowed");
519 onFailure(
"path is not allowed");
525 onSuccess(canonicalUri);
532 std::set<std::string>
535 return {
"udp4+dev",
"udp6+dev"};
541 if (faceUri.
getPort().empty()) {
544 if (!faceUri.
getPath().empty()) {
554 time::nanoseconds timeout)
const override
560 onFailure(
"cannot canonize " + faceUri.
toString());
577 : m_providerTable(providerTable)
581 template<
typename CP>
585 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
586 auto schemes = cp->getSchemes();
587 BOOST_ASSERT(!schemes.empty());
589 for (
const auto& scheme : schemes) {
590 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
591 m_providerTable[scheme] = cp;
599 static const CanonizeProvider*
603 if (providerTable.empty()) {
605 BOOST_ASSERT(!providerTable.empty());
608 auto it = providerTable.find(scheme);
609 return it == providerTable.end() ? nullptr : it->second.get();
633 time::nanoseconds timeout)
const
638 onFailure(
"scheme not supported");
644 onSuccess ? onSuccess : [] (
auto&&) {},
645 onFailure ? onFailure : [] (
auto&&) {},