Allow dns request to be reattempted right away

This commit is contained in:
Ludvig Strigeus 2018-10-19 13:40:39 +02:00
parent 3c1647f72f
commit 0fa4ab3fc8
4 changed files with 44 additions and 8 deletions

View file

@ -195,6 +195,7 @@
<ClInclude Include="crypto\blake2s\blake2s.h" /> <ClInclude Include="crypto\blake2s\blake2s.h" />
<ClInclude Include="crypto\chacha20poly1305.h" /> <ClInclude Include="crypto\chacha20poly1305.h" />
<ClInclude Include="crypto\siphash\siphash.h" /> <ClInclude Include="crypto\siphash\siphash.h" />
<ClInclude Include="tunsafe_dnsresolve.h" />
<ClInclude Include="tunsafe_endian.h" /> <ClInclude Include="tunsafe_endian.h" />
<ClInclude Include="ipzip2\ipzip2.h" /> <ClInclude Include="ipzip2\ipzip2.h" />
<ClInclude Include="netapi.h" /> <ClInclude Include="netapi.h" />

View file

@ -123,6 +123,9 @@
<ClInclude Include="tunsafe_ipaddr.h"> <ClInclude Include="tunsafe_ipaddr.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="tunsafe_dnsresolve.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">

View file

@ -8,12 +8,14 @@ class DnsBlocker;
class DnsResolverCanceller { class DnsResolverCanceller {
public: public:
DnsResolverCanceller() : cancel_(false) {} DnsResolverCanceller() : cancel_(false), cancel_sleep_once_(false) {}
void Cancel(); void Cancel();
void CancelSleepOnce();
void Reset() { cancel_ = false; } void Reset() { cancel_ = false; }
bool is_cancelled() { return cancel_; } bool is_cancelled() { return cancel_; }
public: public:
bool cancel_; bool cancel_;
bool cancel_sleep_once_;
ConditionVariable condvar_; ConditionVariable condvar_;
}; };
@ -25,6 +27,7 @@ public:
bool Resolve(const char *hostname, IpAddr *result); bool Resolve(const char *hostname, IpAddr *result);
void ClearCache(); void ClearCache();
void RetryNow();
void Cancel() { token_.Cancel(); } void Cancel() { token_.Cancel(); }
void ResetCancel() { token_.Reset(); } void ResetCancel() { token_.Reset(); }
private: private:
@ -36,6 +39,7 @@ private:
std::vector<Entry> cache_; std::vector<Entry> cache_;
DnsBlocker *dns_blocker_; DnsBlocker *dns_blocker_;
DnsResolverCanceller token_; DnsResolverCanceller token_;
int retry_attempt_;
}; };
#endif // TUNSAFE_DNSRESOLVE_H_ #endif // TUNSAFE_DNSRESOLVE_H_

View file

@ -140,6 +140,15 @@ void DnsResolverCanceller::Cancel() {
g_dns_mutex.Release(); g_dns_mutex.Release();
} }
void DnsResolverCanceller::CancelSleepOnce() {
g_dns_mutex.Acquire();
cancel_sleep_once_ = true;
condvar_.Wake();
g_dns_mutex.Release();
}
bool DnsResolverThread::Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token) { bool DnsResolverThread::Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token) {
if (token->cancel_) if (token->cancel_)
return false; return false;
@ -188,15 +197,23 @@ void DnsResolverThread::ThreadMain() {
struct addrinfo hints = {0}; struct addrinfo hints = {0};
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
// AI_V4MAPPED doesn't work on Android?!
#if defined(OS_IOS)
hints.ai_flags = AI_DEFAULT; hints.ai_flags = AI_DEFAULT;
#else
hints.ai_flags = AI_ADDRCONFIG ;
#endif
ai = NULL; ai = NULL;
if (getaddrinfo(e->hostname, NULL, &hints, &ai) != 0) int r = getaddrinfo(e->hostname, NULL, &hints, &ai);
if (r != 0)
ai = NULL; ai = NULL;
// RINFO("r=%d errno=%d, %s", r, errno, gai_strerror(r));
// he = gethostbyname(e->hostname); // he = gethostbyname(e->hostname);
g_dns_mutex.Acquire(); g_dns_mutex.Acquire();
if (e->state == Entry::CANCELLED) { if (e->state == Entry::CANCELLED) {
delete e; delete e;
} else { } else {
// RINFO("ai=%p, family=%d", ai, ai ? ai->ai_family : -1);
if (ai) { if (ai) {
e->result->sin.sin_family = ai->ai_family; e->result->sin.sin_family = ai->ai_family;
e->result->sin.sin_port = 0; e->result->sin.sin_port = 0;
@ -228,6 +245,11 @@ static bool InterruptibleSleep(int delay, DnsResolverCanceller *token) {
g_dns_mutex.Acquire(); g_dns_mutex.Acquire();
uint32 time_at_start = (uint32)OsGetMilliseconds(); uint32 time_at_start = (uint32)OsGetMilliseconds();
while (delay > 0 && !token->cancel_) { while (delay > 0 && !token->cancel_) {
if (token->cancel_sleep_once_) {
token->cancel_sleep_once_ = false;
delay = 0;
break;
}
token->condvar_.WaitTimed(&g_dns_mutex, delay); token->condvar_.WaitTimed(&g_dns_mutex, delay);
uint32 now = (uint32)OsGetMilliseconds(); uint32 now = (uint32)OsGetMilliseconds();
delay -= (now - time_at_start); delay -= (now - time_at_start);
@ -249,10 +271,11 @@ void DnsResolver::ClearCache() {
} }
bool DnsResolver::Resolve(const char *hostname, IpAddr *result) { bool DnsResolver::Resolve(const char *hostname, IpAddr *result) {
int attempt = 0; static const uint8 retry_delays[] = {1, 2, 3, 5, 10, 20, 40, 60, 120, 180, 255};
static const uint8 retry_delays[] = {1, 2, 3, 5, 10};
char buf[kSizeOfAddress]; char buf[kSizeOfAddress];
retry_attempt_ = 0;
memset(result, 0, sizeof(IpAddr)); memset(result, 0, sizeof(IpAddr));
// First check cache // First check cache
@ -283,15 +306,20 @@ bool DnsResolver::Resolve(const char *hostname, IpAddr *result) {
if (token_.is_cancelled()) if (token_.is_cancelled())
return false; return false;
RINFO("Unable to resolve %s. Trying again in %d second(s)", hostname, retry_delays[attempt]); RINFO("Unable to resolve %s. Trying again in %d second(s)", hostname, retry_delays[retry_attempt_]);
if (!InterruptibleSleep(retry_delays[attempt] * 1000, &token_)) if (!InterruptibleSleep(retry_delays[retry_attempt_] * 1000, &token_))
return false; return false;
if (attempt != ARRAY_SIZE(retry_delays) - 1) if (retry_attempt_ != ARRAY_SIZE(retry_delays) - 1)
attempt++; retry_attempt_++;
} }
} }
void DnsResolver::RetryNow() {
retry_attempt_ = 0;
token_.CancelSleepOnce();
}
// Parse an IPV4 address into sin, doing NAT64 translation if applicable (on IOS) // Parse an IPV4 address into sin, doing NAT64 translation if applicable (on IOS)
static bool ParseIpv4WithNAT64Translation(const char *s, IpAddr *sin, int flags) { static bool ParseIpv4WithNAT64Translation(const char *s, IpAddr *sin, int flags) {
// First verify it's actually a valid ipv4 address to prevent getaddrinfo from doing a slow resolve // First verify it's actually a valid ipv4 address to prevent getaddrinfo from doing a slow resolve