Skip to content

Commit 65366dd

Browse files
authored
Modify the Resolver (#75)
* Fix a bug in AresResolver; * Use the getaddrinfo() instead of the gethostbyname();
1 parent 4eee8e1 commit 65366dd

File tree

6 files changed

+153
-127
lines changed

6 files changed

+153
-127
lines changed

CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ set(TRANTOR_PATCH_VERSION 0)
1111
set(TRANTOR_VERSION
1212
${TRANTOR_MAJOR_VERSION}.${TRANTOR_MINOR_VERSION}.${TRANTOR_PATCH_VERSION})
1313

14-
1514
# Offer the user the choice of overriding the installation directories
1615
set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
1716
set(INSTALL_INCLUDE_DIR
@@ -86,7 +85,7 @@ find_path(CARES_INCLUDE_DIR ares.h)
8685
find_library(CARES_LIBRARY NAMES cares)
8786
if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
8887
target_include_directories(${PROJECT_NAME} PRIVATE ${CARES_INCLUDE_DIR})
89-
target_link_libraries(${PROJECT_NAME} INTERFACE ${CARES_LIBRARY})
88+
target_link_libraries(${PROJECT_NAME} PRIVATE ${CARES_LIBRARY})
9089
set(TRANTOR_SOURCES ${TRANTOR_SOURCES} trantor/net/inner/AresResolver.cc)
9190
else()
9291
set(TRANTOR_SOURCES ${TRANTOR_SOURCES} trantor/net/inner/NormalResolver.cc)

trantor/net/inner/AresResolver.cc

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ const char* getSocketType(int type)
4444

4545
} // namespace
4646

47+
AresResolver::LibraryInitializer::LibraryInitializer()
48+
{
49+
ares_library_init(ARES_LIB_INIT_ALL);
50+
}
51+
AresResolver::LibraryInitializer::~LibraryInitializer()
52+
{
53+
ares_library_cleanup();
54+
}
55+
56+
AresResolver::LibraryInitializer AresResolver::libraryInitializer_;
57+
4758
std::shared_ptr<Resolver> Resolver::newResolver(trantor::EventLoop* loop,
4859
size_t timeout)
4960
{
@@ -53,67 +64,49 @@ std::shared_ptr<Resolver> Resolver::newResolver(trantor::EventLoop* loop,
5364
AresResolver::AresResolver(EventLoop* loop, size_t timeout)
5465
: loop_(loop), timeout_(timeout)
5566
{
56-
assert(loop_);
57-
// static char lookups[] = "b";
58-
struct ares_options options;
59-
int optmask = ARES_OPT_FLAGS;
60-
options.flags = ARES_FLAG_NOCHECKRESP;
61-
options.flags |= ARES_FLAG_STAYOPEN;
62-
options.flags |= ARES_FLAG_IGNTC; // UDP only
63-
optmask |= ARES_OPT_SOCK_STATE_CB;
64-
options.sock_state_cb = &AresResolver::ares_sock_statecallback_;
65-
options.sock_state_cb_data = this;
66-
optmask |= ARES_OPT_TIMEOUT;
67-
options.timeout = 2;
68-
// optmask |= ARES_OPT_LOOKUPS;
69-
// options.lookups = lookups;
70-
71-
int status = ares_init_options(&ctx_, &options, optmask);
72-
if (status != ARES_SUCCESS)
67+
if (!loop)
7368
{
74-
assert(0);
69+
loop_ = getLoop();
70+
}
71+
}
72+
void AresResolver::init()
73+
{
74+
if (!ctx_)
75+
{
76+
struct ares_options options;
77+
int optmask = ARES_OPT_FLAGS;
78+
options.flags = ARES_FLAG_NOCHECKRESP;
79+
options.flags |= ARES_FLAG_STAYOPEN;
80+
options.flags |= ARES_FLAG_IGNTC; // UDP only
81+
optmask |= ARES_OPT_SOCK_STATE_CB;
82+
options.sock_state_cb = &AresResolver::ares_sock_statecallback_;
83+
options.sock_state_cb_data = this;
84+
optmask |= ARES_OPT_TIMEOUT;
85+
options.timeout = 2;
86+
// optmask |= ARES_OPT_LOOKUPS;
87+
// options.lookups = lookups;
88+
89+
int status = ares_init_options(&ctx_, &options, optmask);
90+
if (status != ARES_SUCCESS)
91+
{
92+
assert(0);
93+
}
94+
ares_set_socket_callback(ctx_,
95+
&AresResolver::ares_sock_createcallback_,
96+
this);
7597
}
76-
ares_set_socket_callback(ctx_,
77-
&AresResolver::ares_sock_createcallback_,
78-
this);
7998
}
80-
8199
AresResolver::~AresResolver()
82100
{
83-
ares_destroy(ctx_);
101+
if (ctx_)
102+
ares_destroy(ctx_);
84103
}
85104

86105
void AresResolver::resolveInLoop(const std::string& hostname,
87106
const Callback& cb)
88107
{
89108
loop_->assertInLoopThread();
90-
bool cached = false;
91-
InetAddress inet;
92-
{
93-
std::lock_guard<std::mutex> lock(globalMutex());
94-
auto iter = globalCache().find(hostname);
95-
if (iter != globalCache().end())
96-
{
97-
auto& cachedAddr = iter->second;
98-
if (timeout_ == 0 ||
99-
cachedAddr.second.after(timeout_) > trantor::Date::date())
100-
{
101-
struct sockaddr_in addr;
102-
memset(&addr, 0, sizeof addr);
103-
addr.sin_family = AF_INET;
104-
addr.sin_port = 0;
105-
addr.sin_addr = cachedAddr.first;
106-
inet = InetAddress(addr);
107-
cached = true;
108-
}
109-
}
110-
}
111-
if (cached)
112-
{
113-
cb(inet);
114-
return;
115-
}
116-
109+
init();
117110
QueryData* queryData = new QueryData(this, cb, hostname);
118111
ares_gethostbyname(ctx_,
119112
hostname.c_str(),
@@ -124,9 +117,10 @@ void AresResolver::resolveInLoop(const std::string& hostname,
124117
struct timeval* tvp = ares_timeout(ctx_, NULL, &tv);
125118
double timeout = getSeconds(tvp);
126119
// LOG_DEBUG << "timeout " << timeout << " active " << timerActive_;
127-
if (!timerActive_)
120+
if (!timerActive_ && timeout >= 0.0)
128121
{
129-
loop_->runAfter(timeout, std::bind(&AresResolver::onTimer, this));
122+
loop_->runAfter(timeout,
123+
std::bind(&AresResolver::onTimer, shared_from_this()));
130124
timerActive_ = true;
131125
}
132126
return;
@@ -151,7 +145,8 @@ void AresResolver::onTimer()
151145
}
152146
else
153147
{
154-
loop_->runAfter(timeout, std::bind(&AresResolver::onTimer, this));
148+
loop_->runAfter(timeout,
149+
std::bind(&AresResolver::onTimer, shared_from_this()));
155150
}
156151
}
157152

@@ -172,8 +167,9 @@ void AresResolver::onQueryResult(int status,
172167
InetAddress inet(addr);
173168
{
174169
std::lock_guard<std::mutex> lock(globalMutex());
175-
globalCache()[hostname].first = addr.sin_addr;
176-
globalCache()[hostname].second = trantor::Date::date();
170+
auto& addrItem = globalCache()[hostname];
171+
addrItem.first = addr.sin_addr;
172+
addrItem.second = trantor::Date::date();
177173
}
178174
callback(inet);
179175
}

trantor/net/inner/AresResolver.h

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
#pragma once
99
#include <trantor/net/Resolver.h>
1010
#include <trantor/utils/NonCopyable.h>
11+
#include <trantor/net/EventLoopThread.h>
1112
#include <map>
1213
#include <memory>
14+
#include <string.h>
1315

1416
extern "C"
1517
{
@@ -30,6 +32,32 @@ class AresResolver : public Resolver,
3032
virtual void resolve(const std::string& hostname,
3133
const Callback& cb) override
3234
{
35+
bool cached = false;
36+
InetAddress inet;
37+
{
38+
std::lock_guard<std::mutex> lock(globalMutex());
39+
auto iter = globalCache().find(hostname);
40+
if (iter != globalCache().end())
41+
{
42+
auto& cachedAddr = iter->second;
43+
if (timeout_ == 0 ||
44+
cachedAddr.second.after(timeout_) > trantor::Date::date())
45+
{
46+
struct sockaddr_in addr;
47+
memset(&addr, 0, sizeof addr);
48+
addr.sin_family = AF_INET;
49+
addr.sin_port = 0;
50+
addr.sin_addr = cachedAddr.first;
51+
inet = InetAddress(addr);
52+
cached = true;
53+
}
54+
}
55+
}
56+
if (cached)
57+
{
58+
cb(inet);
59+
return;
60+
}
3361
if (loop_->isInLoopThread())
3462
{
3563
resolveInLoop(hostname, cb);
@@ -56,7 +84,7 @@ class AresResolver : public Resolver,
5684
}
5785
};
5886
void resolveInLoop(const std::string& hostname, const Callback& cb);
59-
87+
void init();
6088
trantor::EventLoop* loop_;
6189
ares_channel ctx_{nullptr};
6290
bool timerActive_{false};
@@ -76,7 +104,12 @@ class AresResolver : public Resolver,
76104
static std::mutex mutex_;
77105
return mutex_;
78106
}
79-
107+
static EventLoop* getLoop()
108+
{
109+
static EventLoopThread loopThread;
110+
loopThread.run();
111+
return loopThread.getLoop();
112+
}
80113
const size_t timeout_{60};
81114

82115
void onRead(int sockfd);
@@ -107,5 +140,11 @@ class AresResolver : public Resolver,
107140
#endif
108141
int read,
109142
int write);
143+
struct LibraryInitializer
144+
{
145+
LibraryInitializer();
146+
~LibraryInitializer();
147+
};
148+
static LibraryInitializer libraryInitializer_;
110149
};
111150
} // namespace trantor

trantor/net/inner/Connector.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ void Connector::connect()
7373
case EADDRNOTAVAIL:
7474
case ECONNREFUSED:
7575
case ENETUNREACH:
76-
retry(sockfd);
76+
if (retry_)
77+
{
78+
retry(sockfd);
79+
}
7780
break;
7881

7982
case EACCES:

trantor/net/inner/NormalResolver.cc

Lines changed: 41 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifdef _WIN32
44
#include <ws2tcpip.h>
55
#else
6+
#include <sys/socket.h>
67
#include <netdb.h>
78
#include <netinet/in.h>
89
#include <netinet/tcp.h>
@@ -29,85 +30,63 @@ void NormalResolver::resolve(const std::string &hostname,
2930
if (timeout_ == 0 || cachedAddr.second.after(static_cast<double>(
3031
timeout_)) > trantor::Date::date())
3132
{
32-
struct sockaddr_in addr;
33-
memset(&addr, 0, sizeof addr);
34-
addr.sin_family = AF_INET;
35-
addr.sin_port = 0;
36-
addr.sin_addr = cachedAddr.first;
37-
InetAddress inet(addr);
38-
callback(inet);
33+
callback(cachedAddr.first);
3934
return;
4035
}
4136
}
4237
}
4338

44-
taskQueue_.runTaskInQueue(
39+
concurrentTaskQueue().runTaskInQueue(
4540
[thisPtr = shared_from_this(), callback, hostname]() {
46-
#ifdef __linux__
47-
struct hostent hent;
48-
struct hostent *he = NULL;
49-
int herrno = 0;
50-
memset(&hent, 0, sizeof(hent));
51-
int ret;
52-
while (1)
5341
{
54-
ret = gethostbyname_r(hostname.c_str(),
55-
&hent,
56-
thisPtr->resolveBuffer_.data(),
57-
thisPtr->resolveBuffer_.size(),
58-
&he,
59-
&herrno);
60-
if (ret == ERANGE)
61-
{
62-
thisPtr->resolveBuffer_.resize(
63-
thisPtr->resolveBuffer_.size() * 2);
64-
}
65-
else
42+
std::lock_guard<std::mutex> guard(thisPtr->globalMutex());
43+
auto iter = thisPtr->globalCache().find(hostname);
44+
if (iter != thisPtr->globalCache().end())
6645
{
67-
break;
46+
auto &cachedAddr = iter->second;
47+
if (thisPtr->timeout_ == 0 ||
48+
cachedAddr.second.after(static_cast<double>(
49+
thisPtr->timeout_)) > trantor::Date::date())
50+
{
51+
callback(cachedAddr.first);
52+
return;
53+
}
6854
}
6955
}
70-
if (ret == 0 && he != NULL)
71-
#else
72-
/// Multi-threads safety
73-
static std::mutex mutex_;
74-
struct hostent *he = NULL;
75-
struct hostent hent;
56+
struct addrinfo hints, *res;
57+
memset(&hints, 0, sizeof(hints));
58+
hints.ai_family = PF_UNSPEC;
59+
hints.ai_socktype = SOCK_STREAM;
60+
hints.ai_flags = AI_PASSIVE;
61+
auto error = getaddrinfo(hostname.data(), nullptr, &hints, &res);
62+
if (error == -1 || res == nullptr)
7663
{
77-
std::lock_guard<std::mutex> guard(mutex_);
78-
auto result = gethostbyname(hostname.c_str());
79-
if (result != NULL)
80-
{
81-
memcpy(&hent, result, sizeof(hent));
82-
he = &hent;
83-
}
64+
LOG_SYSERR << "InetAddress::resolve";
65+
callback(InetAddress{});
66+
return;
8467
}
85-
if (he != NULL)
86-
#endif
68+
InetAddress inet;
69+
if (res->ai_family == AF_INET)
8770
{
88-
assert(he->h_addrtype == AF_INET &&
89-
he->h_length == sizeof(uint32_t));
90-
9171
struct sockaddr_in addr;
9272
memset(&addr, 0, sizeof addr);
93-
addr.sin_family = AF_INET;
94-
addr.sin_port = 0;
95-
addr.sin_addr = *reinterpret_cast<struct in_addr *>(he->h_addr);
96-
InetAddress inet(addr);
97-
callback(inet);
98-
{
99-
std::lock_guard<std::mutex> guard(thisPtr->globalMutex());
100-
thisPtr->globalCache()[hostname].first = addr.sin_addr;
101-
thisPtr->globalCache()[hostname].second =
102-
trantor::Date::date();
103-
}
104-
return;
73+
addr = *reinterpret_cast<struct sockaddr_in *>(res->ai_addr);
74+
inet = InetAddress(addr);
10575
}
106-
else
76+
else if (res->ai_family == AF_INET6)
10777
{
108-
LOG_SYSERR << "InetAddress::resolve";
109-
callback(InetAddress{});
110-
return;
78+
struct sockaddr_in6 addr;
79+
memset(&addr, 0, sizeof addr);
80+
addr = *reinterpret_cast<struct sockaddr_in6 *>(res->ai_addr);
81+
inet = InetAddress(addr);
82+
}
83+
callback(inet);
84+
{
85+
std::lock_guard<std::mutex> guard(thisPtr->globalMutex());
86+
auto &addrItem = thisPtr->globalCache()[hostname];
87+
addrItem.first = inet;
88+
addrItem.second = trantor::Date::date();
11189
}
90+
return;
11291
});
11392
}

0 commit comments

Comments
 (0)