34 #include <boost/algorithm/string.hpp> 35 #include <boost/lexical_cast.hpp> 36 #include <boost/mpl/vector.hpp> 37 #include <boost/mpl/for_each.hpp> 38 #include <boost/regex.hpp> 44 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
54 BOOST_THROW_EXCEPTION(
Error(
"Malformed URI: " + uri));
72 static const boost::regex protocolExp(
"(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
73 boost::smatch protocolMatch;
74 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
77 m_scheme = protocolMatch[1];
78 const std::string& authority = protocolMatch[3];
79 m_path = protocolMatch[4];
82 static const boost::regex v6LinkLocalExp(
"^\\[([a-fA-F0-9:]+)%([^\\s/:]+)\\](?:\\:(\\d+))?$");
84 static const boost::regex v6Exp(
"^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
86 static const boost::regex etherExp(
"^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
88 static const boost::regex v4MappedV6Exp(
"^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
90 static const boost::regex v4HostExp(
"^([^:]+)(?:\\:(\\d+))?$");
92 if (authority.empty()) {
97 if (boost::regex_match(authority, match, v6LinkLocalExp)) {
99 m_host = match[1] +
"%" + match[2];
104 m_isV6 = boost::regex_match(authority, match, v6Exp);
106 boost::regex_match(authority, match, etherExp) ||
107 boost::regex_match(authority, match, v4MappedV6Exp) ||
108 boost::regex_match(authority, match, v4HostExp)) {
122 m_isV6 = endpoint.address().is_v6();
123 m_scheme = m_isV6 ?
"udp6" :
"udp4";
124 m_host = endpoint.address().to_string();
130 m_isV6 = endpoint.address().is_v6();
131 m_scheme = m_isV6 ?
"tcp6" :
"tcp4";
132 m_host = endpoint.address().to_string();
136 FaceUri::FaceUri(
const boost::asio::ip::tcp::endpoint& endpoint,
const std::string& scheme)
138 m_isV6 = endpoint.address().is_v6();
140 m_host = endpoint.address().to_string();
144 #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 145 FaceUri::FaceUri(
const boost::asio::local::stream_protocol::endpoint& endpoint)
147 , m_path(endpoint.path())
151 #endif // BOOST_ASIO_HAS_LOCAL_SOCKETS 173 uri.m_scheme =
"dev";
182 uri.m_scheme = endpoint.address().is_v6() ?
"udp6+dev" :
"udp4+dev";
191 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;
201 return !(*
this == rhs);
207 std::ostringstream os;
215 os << uri.m_scheme <<
"://";
217 os <<
"[" << uri.m_host <<
"]";
222 if (!uri.m_port.empty()) {
223 os <<
":" << uri.m_port;
238 virtual std::set<std::string>
248 time::nanoseconds timeout)
const = 0;
251 template<
typename Protocol>
255 std::set<std::string>
258 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
264 BOOST_THROW_EXCEPTION(std::runtime_error(
"IP host canonization not supported"));
316 time::nanoseconds timeout)
const override 318 BOOST_THROW_EXCEPTION(std::runtime_error(
"IP host canonization not supported"));
360 uint16_t defaultUnicastPort = 6363,
361 uint16_t defaultMulticastPort = 56363)
362 : m_baseScheme(baseScheme)
363 , m_v4Scheme(baseScheme +
'4')
364 , m_v6Scheme(baseScheme +
'6')
365 , m_defaultUnicastPort(defaultUnicastPort)
366 , m_defaultMulticastPort(defaultMulticastPort)
421 unescapeHost(std::string host)
423 auto escapePos = host.find(
"%25");
424 if (escapePos != std::string::npos && escapePos < host.size() - 3) {
431 std::string m_baseScheme;
432 std::string m_v4Scheme;
433 std::string m_v6Scheme;
434 uint16_t m_defaultUnicastPort;
435 uint16_t m_defaultMulticastPort;
469 std::set<std::string>
478 if (!faceUri.
getPort().empty()) {
481 if (!faceUri.
getPath().empty()) {
493 time::nanoseconds timeout)
const override 497 return onFailure(
"invalid ethernet address '" + faceUri.
getHost() +
"'");
502 onSuccess(canonicalUri);
509 std::set<std::string>
525 time::nanoseconds timeout)
const override 527 if (faceUri.
getHost().empty()) {
528 onFailure(
"network interface name is missing");
531 if (!faceUri.
getPort().empty()) {
532 onFailure(
"port number is not allowed");
536 onFailure(
"path is not allowed");
542 onSuccess(canonicalUri);
549 std::set<std::string>
552 return {
"udp4+dev",
"udp6+dev"};
558 if (faceUri.
getPort().empty()) {
561 if (!faceUri.
getPath().empty()) {
571 time::nanoseconds timeout)
const override 577 onFailure(
"cannot canonize " + faceUri.
toString());
583 TcpCanonizeProvider*,
584 EtherCanonizeProvider*,
585 DevCanonizeProvider*,
594 : m_providerTable(providerTable)
598 template<
typename CP>
602 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
603 auto schemes = cp->getSchemes();
604 BOOST_ASSERT(!schemes.empty());
606 for (
const auto& scheme : schemes) {
607 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
608 m_providerTable[scheme] = cp;
616 static const CanonizeProvider*
620 if (providerTable.empty()) {
622 BOOST_ASSERT(!providerTable.empty());
625 auto it = providerTable.find(scheme);
626 return it == providerTable.end() ? nullptr : it->second.get();
650 time::nanoseconds timeout)
const 655 onFailure(
"scheme not supported");
663 onSuccess ? onSuccess : successNop,
664 onFailure ? onFailure : failureNop,
IpHostCanonizeProvider(const std::string &baseScheme, uint16_t defaultUnicastPort=6363, uint16_t defaultMulticastPort=56363)
std::set< std::string > getSchemes() const override
virtual ~CanonizeProvider()=default
static Address fromString(const std::string &str)
Creates an Address from a string containing an Ethernet address in hexadecimal notation, with colons or hyphens as separators.
Copyright (c) 2011-2015 Regents of the University of California.
function< void(const std::string &reason)> CanonizeFailureCallback
static FaceUri fromFd(int fd)
create fd FaceUri from file descriptor
bool isCanonical(const FaceUri &faceUri) const override
const std::string & getHost() const
get host (domain)
bool isCanonical(const FaceUri &faceUri) const override
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const override
bool operator!=(const FaceUri &rhs) const
function< void(const FaceUri &)> CanonizeSuccessCallback
std::ostream & operator<<(std::ostream &os, const Data &data)
static bool canCanonize(const std::string &scheme)
std::string toString() const
write as a string
virtual bool isCanonical(const FaceUri &faceUri) const =0
bool isCanonical(const FaceUri &faceUri) const override
static const CanonizeProvider * getCanonizeProvider(const std::string &scheme)
void canonize(const CanonizeSuccessCallback &onSuccess, const CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const
asynchronously convert this FaceUri to canonical form
const std::string & getPort() const
get port
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const override
std::string toString(char sep=':') const
Converts the address to a human-readable string.
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const override
bool isCanonical(const FaceUri &faceUri) const override
std::set< std::string > getSchemes() const override
static FaceUri fromUdpDev(const boost::asio::ip::udp::endpoint &endpoint, const std::string &ifname)
create udp4 or udp6 NIC-associated FaceUri from endpoint and network device name
std::string toString(const system_clock::TimePoint &timePoint, const std::string &format, const std::locale &locale)
Convert time point to string with specified format.
a CanonizeProvider provides FaceUri canonization functionality for a group of schemes ...
bool parse(const std::string &uri)
exception-safe parsing
std::string unescape(const std::string &str)
Decode a percent-encoded string.
std::set< std::string > getSchemes() const override
represents the underlying protocol and address used by a Face
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const override
represents an Ethernet hardware address
const std::string & getScheme() const
get scheme (protocol)
virtual void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, time::nanoseconds timeout) const =0
CanonizeProviderTableInitializer(CanonizeProviderTable &providerTable)
bool operator==(const FaceUri &rhs) const
std::set< std::string > getSchemes() const override
std::string to_string(const V &v)
bool isCanonical() const
determine whether this FaceUri is in canonical form
std::map< std::string, shared_ptr< CanonizeProvider > > CanonizeProviderTable
const std::string & getPath() const
get path
boost::mpl::vector< UdpCanonizeProvider *, TcpCanonizeProvider *, EtherCanonizeProvider *, DevCanonizeProvider *, UdpDevCanonizeProvider * > CanonizeProviders
static FaceUri fromDev(const std::string &ifname)
create dev FaceUri from network device name
virtual std::set< std::string > getSchemes() const =0