Skip to content

Commit

Permalink
Fix bug when resolving thread timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
HanLee13 committed Dec 22, 2023
1 parent b5d2ed4 commit 9107c43
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
36 changes: 25 additions & 11 deletions net/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,33 +251,47 @@ bool Base64Decode(std::string_view in, std::string &out) {
}

class DefaultResolver : public Resolver {
protected:
struct IPAddrNode : public intrusive_list_node<IPAddrNode> {
IPAddr addr;
IPAddrNode(IPAddr addr) : addr(addr) {}
};
using IPAddrList = intrusive_list<IPAddrNode>;
public:
DefaultResolver(uint64_t cache_ttl, uint64_t resolve_timeout)
: dnscache_(cache_ttl), resolve_timeout_(resolve_timeout) {}
~DefaultResolver() { dnscache_.clear(); }

IPAddr resolve(const char *host) override {
auto ctr = [&]() -> std::list<IPAddr>* {
auto addrs = new std::list<IPAddr>();
auto ctr = [&]() -> IPAddrList* {
auto addrs = new IPAddrList();
photon::semaphore sem;
std::thread([&]() {
auto now = std::chrono::steady_clock::now();
gethostbyname(host, *addrs);
IPAddrList ret;
auto cb = [&](IPAddr addr) {
ret.push_back(new IPAddrNode(addr));
return 0;
};
_gethostbyname(host, cb);
auto time_elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - now).count();
if ((uint64_t)time_elapsed <= resolve_timeout_) sem.signal(1);
if ((uint64_t)time_elapsed <= resolve_timeout_) {
addrs->push_back(std::move(ret));
sem.signal(1);
}
}).detach();
sem.wait(1, resolve_timeout_);
return addrs;
};
auto ips = dnscache_.borrow(host, ctr);
if (ips->empty()) LOG_ERRNO_RETURN(0, IPAddr(), "Domain resolution for ` failed", host);
auto ret = ips->front();
if (ips->size() > 1) { // access in round robin order
ips->pop_front();
ips->push_back(ret);
if (!ret->single()) { // access in round robin order
auto front = ips->pop_front();
ips->push_back(front);
}
return ret;
return ret->addr;
}

void resolve(const char *host, Delegate<void, IPAddr> func) override { func(resolve(host)); }
Expand All @@ -286,8 +300,8 @@ class DefaultResolver : public Resolver {
auto ipaddr = dnscache_.borrow(host);
if (ip.undefined() || ipaddr->empty()) ipaddr.recycle(true);
else {
for (auto it = ipaddr->begin(); it != ipaddr->end(); ++it) {
if (*it == ip) {
for (auto it : *ipaddr) {
if (it->addr == ip) {
ipaddr->erase(it);
break;
}
Expand All @@ -296,7 +310,7 @@ class DefaultResolver : public Resolver {
}

private:
ObjectCache<std::string, std::list<IPAddr>*> dnscache_;
ObjectCache<std::string, IPAddrList*> dnscache_;
uint64_t resolve_timeout_;
};

Expand Down
4 changes: 2 additions & 2 deletions net/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ inline int gethostbyname(const char* name, IPAddr* buf, int bufsize = 1) {
* @param ret `std::vector<IPAddr>` reference to get results
* @return sum of resolved address number. -1 means error.
*/
template <typename Container>
inline int gethostbyname(const char* name, Container& ret) {
inline int gethostbyname(const char* name, std::vector<IPAddr>& ret) {
ret.clear();
auto cb = [&](IPAddr addr) {
ret.push_back(addr);
Expand Down Expand Up @@ -163,6 +162,7 @@ class Resolver : public Object {

/**
* @brief A non-blocking Resolver based on gethostbyname.
* Currently, it's not thread safe.
*
* @param cache_ttl cache's lifetime in microseconds.
* @param resolve_timeout timeout in microseconds for domain resolution.
Expand Down

0 comments on commit 9107c43

Please sign in to comment.