32 #include <boost/concept_check.hpp>
33 #include <boost/lexical_cast.hpp>
34 #include <boost/mpl/vector.hpp>
35 #include <boost/mpl/for_each.hpp>
36 #include <boost/regex.hpp>
42 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
52 BOOST_THROW_EXCEPTION(
Error(
"Malformed URI: " + uri));
70 static const boost::regex protocolExp(
"(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
71 boost::smatch protocolMatch;
72 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
75 m_scheme = protocolMatch[1];
76 const std::string& authority = protocolMatch[3];
77 m_path = protocolMatch[4];
80 static const boost::regex v6Exp(
"^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
82 static const boost::regex etherExp(
"^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
84 static const boost::regex v4MappedV6Exp(
"^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
86 static const boost::regex v4HostExp(
"^([^:]+)(?:\\:(\\d+))?$");
88 if (authority.empty()) {
93 m_isV6 = boost::regex_match(authority, match, v6Exp);
95 boost::regex_match(authority, match, etherExp) ||
96 boost::regex_match(authority, match, v4MappedV6Exp) ||
97 boost::regex_match(authority, match, v4HostExp)) {
111 m_isV6 = endpoint.address().is_v6();
112 m_scheme = m_isV6 ?
"udp6" :
"udp4";
113 m_host = endpoint.address().to_string();
119 m_isV6 = endpoint.address().is_v6();
120 m_scheme = m_isV6 ?
"tcp6" :
"tcp4";
121 m_host = endpoint.address().to_string();
125 FaceUri::FaceUri(
const boost::asio::ip::tcp::endpoint& endpoint,
const std::string& scheme)
127 m_isV6 = endpoint.address().is_v6();
129 m_host = endpoint.address().to_string();
133 #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS
134 FaceUri::FaceUri(
const boost::asio::local::stream_protocol::endpoint& endpoint)
136 , m_path(endpoint.path())
140 #endif // BOOST_ASIO_HAS_LOCAL_SOCKETS
162 uri.m_scheme =
"dev";
171 uri.m_scheme = endpoint.address().is_v6() ?
"udp6+dev" :
"udp4+dev";
180 return m_isV6 == rhs.m_isV6 &&
181 m_scheme == rhs.m_scheme &&
182 m_host == rhs.m_host &&
183 m_port == rhs.m_port &&
184 m_path == rhs.m_path;
190 return !(*
this == rhs);
196 std::ostringstream os;
204 os << uri.m_scheme <<
"://";
206 os <<
"[" << uri.m_host <<
"]";
211 if (!uri.m_port.empty()) {
212 os <<
":" << uri.m_port;
227 virtual std::set<std::string>
237 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const = 0;
240 template<
typename Protocol>
244 std::set<std::string>
247 return {m_baseScheme, m_v4Scheme, m_v6Scheme};
253 if (faceUri.
getPort().empty()) {
256 if (!faceUri.
getPath().empty()) {
260 boost::system::error_code ec;
261 boost::asio::ip::address addr;
263 addr = boost::asio::ip::address_v4::from_string(faceUri.
getHost(), ec);
265 else if (faceUri.
getScheme() == m_v6Scheme) {
266 addr = boost::asio::ip::address_v6::from_string(faceUri.
getHost(), ec);
272 return !ec && addr.to_string() == faceUri.
getHost() && checkAddress(addr).first;
279 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override
290 else if (faceUri.
getScheme() == m_v6Scheme) {
294 BOOST_ASSERT(faceUri.
getScheme() == m_baseScheme);
299 auto uri = make_shared<FaceUri>(faceUri);
303 io, addressSelector, timeout);
309 uint16_t defaultUnicastPort = 6363,
310 uint16_t defaultMulticastPort = 56363)
311 : m_baseScheme(baseScheme)
312 , m_v4Scheme(baseScheme +
'4')
313 , m_v6Scheme(baseScheme +
'6')
314 , m_defaultUnicastPort(defaultUnicastPort)
315 , m_defaultMulticastPort(defaultMulticastPort)
321 onDnsSuccess(
const shared_ptr<FaceUri>& faceUri,
328 std::tie(isOk, reason) = this->checkAddress(ipAddress);
330 return onFailure(reason);
334 if (faceUri->getPort().empty()) {
335 port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
339 port = boost::lexical_cast<uint16_t>(faceUri->getPort());
341 catch (
const boost::bad_lexical_cast&) {
342 return onFailure(
"invalid port number '" + faceUri->getPort() +
"'");
346 FaceUri canonicalUri(
typename Protocol::endpoint(ipAddress, port));
347 BOOST_ASSERT(canonicalUri.isCanonical());
348 onSuccess(canonicalUri);
352 onDnsFailure(
const shared_ptr<FaceUri>& faceUri,
354 const std::string& reason)
const
363 virtual std::pair<bool, std::string>
370 std::string m_baseScheme;
371 std::string m_v4Scheme;
372 std::string m_v6Scheme;
373 uint16_t m_defaultUnicastPort;
374 uint16_t m_defaultMulticastPort;
400 std::pair<bool, std::string>
403 if (ipAddress.is_multicast()) {
404 return {
false,
"cannot use multicast address"};
413 std::set<std::string>
422 if (!faceUri.
getPort().empty()) {
425 if (!faceUri.
getPath().empty()) {
437 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override
441 return onFailure(
"invalid ethernet address '" + faceUri.
getHost() +
"'");
446 onSuccess(canonicalUri);
453 std::set<std::string>
456 return {
"udp4+dev",
"udp6+dev"};
462 if (faceUri.
getPort().empty()) {
465 if (!faceUri.
getPath().empty()) {
475 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override
481 onFailure(
"cannot canonize " + faceUri.
toString());
487 TcpCanonizeProvider*,
488 EtherCanonizeProvider*,
497 : m_providerTable(providerTable)
501 template<
typename CP>
505 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
506 auto schemes = cp->getSchemes();
507 BOOST_ASSERT(!schemes.empty());
509 for (
const auto& scheme : schemes) {
510 BOOST_ASSERT(m_providerTable.count(scheme) == 0);
511 m_providerTable[scheme] = cp;
519 static const CanonizeProvider*
523 if (providerTable.empty()) {
525 BOOST_ASSERT(!providerTable.empty());
528 auto it = providerTable.find(scheme);
529 return it == providerTable.end() ?
nullptr : it->second.get();
553 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const
558 onFailure(
"scheme not supported");
566 onSuccess ? onSuccess : successNop,
567 onFailure ? onFailure : failureNop,
virtual bool isCanonical(const FaceUri &faceUri) const =0
std::map< std::string, shared_ptr< CanonizeProvider >> CanonizeProviderTable
virtual ~CanonizeProvider()=default
Copyright (c) 2013-2016 Regents of the University of California.
bool isCanonical(const FaceUri &faceUri) const override
const std::string & getPath() const
get path
bool parse(const std::string &uri)
exception-safe parsing
static bool canCanonize(const std::string &scheme)
bool isCanonical(const FaceUri &faceUri) const override
bool operator==(const FaceUri &rhs) const
represents an Ethernet hardware address
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.
represents the underlying protocol and address used by a Face
virtual std::set< std::string > getSchemes() const =0
bool isCanonical(const FaceUri &faceUri) const override
static const CanonizeProvider * getCanonizeProvider(const std::string &scheme)
function< void(const FaceUri &)> CanonizeSuccessCallback
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override
function< bool(const IpAddress &address)> AddressSelector
std::string toString(char sep= ':') const
Converts the address to a human-readable string.
std::set< std::string > getSchemes() const override
const std::string & getPort() const
get port
boost::mpl::vector< UdpCanonizeProvider *, TcpCanonizeProvider *, EtherCanonizeProvider *, UdpDevCanonizeProvider * > CanonizeProviders
CanonizeProviderTableInitializer(CanonizeProviderTable &providerTable)
std::string toString(const system_clock::TimePoint &timePoint, const std::string &format, const std::locale &locale)
Convert time point to string with specified format.
bool isCanonical() const
determine whether this FaceUri is in canonical form
virtual void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const =0
const std::string & getScheme() const
get scheme (protocol)
void asyncResolve(const std::string &host, const SuccessCallback &onSuccess, const ErrorCallback &onError, boost::asio::io_service &ioService, const AddressSelector &addressSelector, time::nanoseconds timeout)
Asynchronously resolve host.
IpHostCanonizeProvider(const std::string &baseScheme, uint16_t defaultUnicastPort=6363, uint16_t defaultMulticastPort=56363)
std::ostream & operator<<(std::ostream &os, Digest< Hash > &digest)
bool operator!=(const FaceUri &rhs) const
std::set< std::string > getSchemes() const override
a CanonizeProvider provides FaceUri canonization functionality for a group of schemes ...
const std::string & getHost() const
get host (domain)
boost::asio::ip::address IpAddress
static FaceUri fromDev(const std::string &ifname)
create dev FaceUri from network device name
std::string to_string(const V &v)
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
write as a string
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override
std::pair< bool, std::string > checkAddress(const dns::IpAddress &ipAddress) const override
when overriden in a subclass, check the IP address is allowable
function< void(const std::string &reason)> CanonizeFailureCallback
static FaceUri fromFd(int fd)
create fd FaceUri from file descriptor
void canonize(const CanonizeSuccessCallback &onSuccess, const CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const
asynchronously convert this FaceUri to canonical form
void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override