SockAddr fallback to sync. dns lookup
This commit is contained in:
+42
-1
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
explicit SockAddr(int af = AF_UNSPEC);
|
||||
explicit SockAddr(const char *address, unsigned short port=0);
|
||||
explicit SockAddr(const sockaddr *addr);
|
||||
explicit SockAddr(const sockaddr *addr, socklen_t alen=0);
|
||||
inline explicit SockAddr(const std::string& address, unsigned short port=0) :SockAddr(address.c_str(), port) {}
|
||||
|
||||
size_t size() const noexcept;
|
||||
@@ -158,6 +158,47 @@ bool operator==(const SockEndpoint& lhs, const SockEndpoint& rhs);
|
||||
inline
|
||||
bool operator!=(const SockEndpoint& lhs, const SockEndpoint& rhs) { return !(lhs==rhs); }
|
||||
|
||||
struct GetAddrInfo {
|
||||
explicit GetAddrInfo(const char *name);
|
||||
inline explicit GetAddrInfo(const std::string& name) :GetAddrInfo(name.c_str()) {}
|
||||
GetAddrInfo(const GetAddrInfo&) = delete;
|
||||
inline
|
||||
GetAddrInfo(GetAddrInfo&& o) :info(o.info) {
|
||||
o.info = nullptr;
|
||||
}
|
||||
~GetAddrInfo();
|
||||
|
||||
struct iterator {
|
||||
evutil_addrinfo *pos = nullptr;
|
||||
inline iterator() = default;
|
||||
inline iterator(evutil_addrinfo *pos) :pos(pos) {}
|
||||
inline SockAddr operator*() const {
|
||||
return SockAddr(pos->ai_addr, pos->ai_addrlen);
|
||||
}
|
||||
inline iterator& operator++() {
|
||||
pos = pos->ai_next;
|
||||
return *this;
|
||||
}
|
||||
inline iterator operator++(int) {
|
||||
auto ret(*this);
|
||||
pos = pos->ai_next;
|
||||
return ret;
|
||||
}
|
||||
inline bool operator==(const iterator& o) const {
|
||||
return pos==o.pos;
|
||||
}
|
||||
inline bool operator!=(const iterator& o) const {
|
||||
return pos!=o.pos;
|
||||
}
|
||||
};
|
||||
|
||||
inline iterator begin() const { return iterator{info}; }
|
||||
inline iterator end() const { return iterator{}; }
|
||||
|
||||
private:
|
||||
evutil_addrinfo *info;
|
||||
};
|
||||
|
||||
struct recvfromx {
|
||||
evutil_socket_t sock;
|
||||
void *buf;
|
||||
|
||||
+38
-5
@@ -275,13 +275,16 @@ SockAddr::SockAddr(const char *address, unsigned short port)
|
||||
setAddress(address, port);
|
||||
}
|
||||
|
||||
SockAddr::SockAddr(const sockaddr *addr)
|
||||
SockAddr::SockAddr(const sockaddr *addr, socklen_t alen)
|
||||
:SockAddr(addr ? addr->sa_family : AF_UNSPEC)
|
||||
{
|
||||
if(!addr)
|
||||
return; // treat NULL as AF_UNSPEC
|
||||
|
||||
if(family()!=AF_UNSPEC && family()!=AF_INET && family()!=AF_INET6)
|
||||
if(family()==AF_UNSPEC) {}
|
||||
else if(family()==AF_INET && (!alen || alen>=sizeof(sockaddr_in))) {}
|
||||
else if(family()==AF_INET6 && (!alen || alen>=sizeof(sockaddr_in6))) {}
|
||||
else
|
||||
throw std::invalid_argument("Unsupported address family");
|
||||
|
||||
if(family()!=AF_UNSPEC)
|
||||
@@ -402,8 +405,26 @@ void SockAddr::setAddress(const char *name, unsigned short defport)
|
||||
throw std::runtime_error(SB()<<"Invalid IP address form \""<<escape(name)<<"\"");
|
||||
}
|
||||
|
||||
if(evutil_inet_pton(temp->sa.sa_family, addr, sockaddr)<=0)
|
||||
throw std::runtime_error(SB()<<"Not a valid IP address \""<<escape(name)<<"\"");
|
||||
if(evutil_inet_pton(temp->sa.sa_family, addr, sockaddr)<=0) {
|
||||
// not a plain IP4/6 address.
|
||||
// Fall back to synchronous DNS lookup (could be sloooow)
|
||||
|
||||
GetAddrInfo info(addr);
|
||||
|
||||
// We may get a mixture of IP v4 and/or v6 addresses.
|
||||
// For maximum compatibility, we always prefer IPv4
|
||||
|
||||
for(const auto addr : info) {
|
||||
if(addr.family()==AF_INET || (addr.family()==AF_INET6 && temp.family()==AF_UNSPEC)) {
|
||||
temp = addr;
|
||||
if(addr.family()==AF_INET)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(temp.family()==AF_UNSPEC) // lookup succeeded, but no addresses. Can this happen?
|
||||
throw std::runtime_error(SB()<<"Not a valid host name or IP address \""<<escape(name)<<"\"");
|
||||
}
|
||||
|
||||
if(port)
|
||||
temp.setPort(parseTo<uint64_t>(port));
|
||||
@@ -555,10 +576,22 @@ std::ostream& operator<<(std::ostream& strm, const SockAddr& addr)
|
||||
return strm;
|
||||
}
|
||||
|
||||
GetAddrInfo::GetAddrInfo(const char *name)
|
||||
{
|
||||
if(auto err = evutil_getaddrinfo(name, nullptr, nullptr, &info)) {
|
||||
throw std::runtime_error(SB()<<"Error resolving \""<<escape(name)<<"\" : "<<evutil_gai_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
GetAddrInfo::~GetAddrInfo()
|
||||
{
|
||||
if(info)
|
||||
evutil_freeaddrinfo(info);
|
||||
}
|
||||
|
||||
} // namespace pvxs
|
||||
|
||||
namespace pvxs {namespace impl {
|
||||
|
||||
struct onceArgs {
|
||||
EPICSTHREADFUNC fn;
|
||||
void *arg;
|
||||
|
||||
Reference in New Issue
Block a user