32 #include <boost/concept_check.hpp> 33 #include <boost/regex.hpp> 34 #include <boost/lexical_cast.hpp> 35 #include <boost/mpl/vector.hpp> 36 #include <boost/mpl/for_each.hpp> 41 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FaceUri>));
51 BOOST_THROW_EXCEPTION(
Error(
"Malformed URI: " + uri));
58 BOOST_THROW_EXCEPTION(
Error(
"Malformed URI: " + std::string(uri)));
71 static const boost::regex protocolExp(
"(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
72 boost::smatch protocolMatch;
73 if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
76 m_scheme = protocolMatch[1];
77 const std::string& authority = protocolMatch[3];
78 m_path = protocolMatch[4];
81 static const boost::regex v6Exp(
"^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
83 static const boost::regex etherExp(
"^\\[((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))\\]$");
85 static const boost::regex v4MappedV6Exp(
"^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
87 static const boost::regex v4HostExp(
"^([^:]+)(?:\\:(\\d+))?$");
89 if (authority.empty()) {
94 m_isV6 = boost::regex_match(authority, match, v6Exp);
96 boost::regex_match(authority, match, etherExp) ||
97 boost::regex_match(authority, match, v4MappedV6Exp) ||
98 boost::regex_match(authority, match, v4HostExp)) {
112 m_isV6 = endpoint.address().is_v6();
113 m_scheme = m_isV6 ?
"udp6" :
"udp4";
114 m_host = endpoint.address().to_string();
120 m_isV6 = endpoint.address().is_v6();
121 m_scheme = m_isV6 ?
"tcp6" :
"tcp4";
122 m_host = endpoint.address().to_string();
126 FaceUri::FaceUri(
const boost::asio::ip::tcp::endpoint& endpoint,
const std::string& scheme)
129 m_isV6 = endpoint.address().is_v6();
130 m_host = endpoint.address().to_string();
134 #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 135 FaceUri::FaceUri(
const boost::asio::local::stream_protocol::endpoint& endpoint)
139 m_path = endpoint.path();
141 #endif // BOOST_ASIO_HAS_LOCAL_SOCKETS 163 uri.m_scheme =
"dev";
172 uri.m_scheme = endpoint.address().is_v6() ?
"udp6+dev" :
"udp4+dev";
181 return (m_scheme == rhs.m_scheme &&
182 m_host == rhs.m_host &&
183 m_isV6 == rhs.m_isV6 &&
184 m_port == rhs.m_port &&
185 m_path == rhs.m_path);
191 return !(*
this == rhs);
197 std::ostringstream os;
205 os << uri.m_scheme <<
"://";
207 os <<
"[" << uri.m_host <<
"]";
212 if (!uri.m_port.empty()) {
213 os <<
":" << uri.m_port;
227 virtual std::set<std::string>
228 getSchemes()
const = 0;
237 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const = 0;
240 template<
typename Protocol>
244 virtual std::set<std::string>
247 std::set<std::string> schemes;
248 schemes.insert(m_baseScheme);
249 schemes.insert(m_v4Scheme);
250 schemes.insert(m_v6Scheme);
257 if (faceUri.
getPort().empty()) {
260 if (!faceUri.
getPath().empty()) {
264 boost::system::error_code ec;
265 boost::asio::ip::address addr;
267 addr = boost::asio::ip::address_v4::from_string(faceUri.
getHost(), ec);
269 else if (faceUri.
getScheme() == m_v6Scheme) {
270 addr = boost::asio::ip::address_v6::from_string(faceUri.
getHost(), ec);
275 return !
static_cast<bool>(ec) && addr.to_string() == faceUri.
getHost() &&
276 this->checkAddress(addr).first;
283 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override 294 else if (faceUri.
getScheme() == m_v6Scheme) {
298 BOOST_ASSERT(faceUri.
getScheme() == m_baseScheme);
303 shared_ptr<FaceUri> uri = make_shared<FaceUri>(faceUri);
307 io, addressSelector, timeout);
313 uint32_t defaultUnicastPort = 6363,
314 uint32_t defaultMulticastPort = 56363)
315 : m_baseScheme(baseScheme)
316 , m_v4Scheme(baseScheme +
"4")
317 , m_v6Scheme(baseScheme +
"6")
318 , m_defaultUnicastPort(defaultUnicastPort)
319 , m_defaultMulticastPort(defaultMulticastPort)
326 onDnsSuccess(shared_ptr<FaceUri> faceUri,
331 std::pair<bool, std::string> checkAddressRes = this->checkAddress(ipAddress);
332 if (!checkAddressRes.first) {
333 onFailure(checkAddressRes.second);
338 if (faceUri->getPort().empty()) {
339 port = ipAddress.is_multicast() ? m_defaultMulticastPort : m_defaultUnicastPort;
343 port = boost::lexical_cast<uint32_t>(faceUri->getPort());
345 catch (boost::bad_lexical_cast&) {
346 onFailure(
"invalid port number");
351 FaceUri canonicalUri(
typename Protocol::endpoint(ipAddress, port));
353 onSuccess(canonicalUri);
359 const std::string& reason)
const 368 virtual std::pair<bool, std::string>
375 std::string m_baseScheme;
376 std::string m_v4Scheme;
377 std::string m_v6Scheme;
378 uint32_t m_defaultUnicastPort;
379 uint32_t m_defaultMulticastPort;
405 virtual std::pair<bool, std::string>
408 if (ipAddress.is_multicast()) {
409 return {
false,
"cannot use multicast address"};
418 virtual std::set<std::string>
421 std::set<std::string> schemes;
422 schemes.insert(
"ether");
429 if (!faceUri.
getPort().empty()) {
432 if (!faceUri.
getPath().empty()) {
444 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override 448 onFailure(
"cannot parse address");
454 onSuccess(canonicalUri);
461 virtual std::set<std::string>
464 return {
"udp4+dev",
"udp6+dev"};
470 if (faceUri.
getPort().empty()) {
473 if (!faceUri.
getPath().empty()) {
483 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const override 489 onFailure(
"cannot canonize " + faceUri.
toString());
494 typedef boost::mpl::vector<
507 : m_providerTable(providerTable)
511 template<
typename CP>
void 514 shared_ptr<CanonizeProvider> cp = make_shared<CP>();
516 std::set<std::string> schemes = cp->getSchemes();
517 BOOST_ASSERT(!schemes.empty());
519 it != schemes.end(); ++it) {
520 BOOST_ASSERT(m_providerTable.count(*it) == 0);
521 m_providerTable[*it] = cp;
526 CanonizeProviderTable& m_providerTable;
532 static CanonizeProviderTable providerTable;
533 if (providerTable.empty()) {
535 BOOST_ASSERT(!providerTable.empty());
538 auto it = providerTable.find(scheme);
539 if (it == providerTable.end()) {
542 return it->second.get();
565 boost::asio::io_service& io,
const time::nanoseconds& timeout)
const 570 onFailure(
"scheme not supported");
579 onSuccess ? onSuccess : successNop,
580 onFailure ? onFailure : failureNop,
Copyright (c) 2011-2015 Regents of the University of California.
virtual bool isCanonical(const FaceUri &faceUri) const =0
bool parse(const std::string &uri)
exception-safe parsing
static bool canCanonize(const std::string &scheme)
virtual std::set< std::string > getSchemes() const override
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 bool isCanonical(const FaceUri &faceUri) const override
bool isCanonical() const
determine whether this FaceUri is in canonical form
std::string toString() const
write as a string
IpHostCanonizeProvider(const std::string &baseScheme, uint32_t defaultUnicastPort=6363, uint32_t defaultMulticastPort=56363)
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
static const CanonizeProvider * getCanonizeProvider(const std::string &scheme)
function< void(const FaceUri &)> CanonizeSuccessCallback
function< bool(const IpAddress &address)> AddressSelector
bool operator!=(const FaceUri &rhs) const
const std::string & getScheme() const
get scheme (protocol)
Table::const_iterator iterator
virtual std::set< std::string > getSchemes() const override
CanonizeProviderTableInitializer(CanonizeProviderTable &providerTable)
virtual void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override
friend std::ostream & operator<<(std::ostream &os, const FaceUri &uri)
const std::string & getPort() const
get port
std::map< std::string, shared_ptr< CanonizeProvider > > CanonizeProviderTable
virtual std::pair< bool, std::string > checkAddress(const dns::IpAddress &ipAddress) const override
when overriden in a subclass, check the IP address is allowable
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.
virtual bool isCanonical(const FaceUri &faceUri) const override
a CanonizeProvider provides FaceUri canonization functionality for a group of schemes ...
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
boost::mpl::vector< UdpCanonizeProvider *, TcpCanonizeProvider *, EtherCanonizeProvider *, UdpDevCanonizeProvider *> CanonizeProviders
boost::asio::ip::address IpAddress
static FaceUri fromDev(const std::string &ifname)
create dev FaceUri from network device name
virtual std::set< std::string > getSchemes() const override
bool operator==(const FaceUri &rhs) const
std::string to_string(const V &v)
bool isNull() const
True if this is a null address (00:00:00:00:00:00)
const std::string & getHost() const
get host (domain)
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
virtual bool isCanonical(const FaceUri &faceUri) const override
virtual void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override
const std::string & getPath() const
get path
function< void(const std::string &reason)> CanonizeFailureCallback
std::string toString(char sep=':') const
Converts the address to a human-readable string.
static FaceUri fromFd(int fd)
create fd FaceUri from file descriptor
virtual void canonize(const FaceUri &faceUri, const FaceUri::CanonizeSuccessCallback &onSuccess, const FaceUri::CanonizeFailureCallback &onFailure, boost::asio::io_service &io, const time::nanoseconds &timeout) const override