Browse Source

src,dns: refactor cares_wrap to avoid global state

PR-URL: https://github.com/nodejs/node/pull/14518
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
v6
Anna Henningsen 8 years ago
parent
commit
727b2911ec
No known key found for this signature in database GPG Key ID: D8B9F5AEAE84E4CF
  1. 25
      lib/dns.js
  2. 1
      src/async-wrap.h
  3. 383
      src/cares_wrap.cc
  4. 40
      src/env-inl.h
  5. 24
      src/env.h
  6. 1
      test/parallel/test-async-wrap-getasyncid.js

25
lib/dns.js

@ -29,11 +29,16 @@ const internalNet = require('internal/net');
const { customPromisifyArgs } = require('internal/util');
const errors = require('internal/errors');
const GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap;
const GetNameInfoReqWrap = cares.GetNameInfoReqWrap;
const QueryReqWrap = cares.QueryReqWrap;
const {
GetAddrInfoReqWrap,
GetNameInfoReqWrap,
QueryReqWrap,
ChannelWrap,
isIP
} = cares;
const defaultChannel = new ChannelWrap();
const isIP = cares.isIP;
const isLegalPort = internalNet.isLegalPort;
@ -241,8 +246,6 @@ function onresolve(err, result, ttls) {
function resolver(bindingName) {
var binding = cares[bindingName];
return function query(name, /* options, */ callback) {
var options;
if (arguments.length > 2) {
@ -263,7 +266,7 @@ function resolver(bindingName) {
req.hostname = name;
req.oncomplete = onresolve;
req.ttl = !!(options && options.ttl);
var err = binding(req, name);
var err = defaultChannel[bindingName](req, name);
if (err) throw errnoException(err, bindingName);
return req;
};
@ -305,7 +308,7 @@ function resolve(hostname, rrtype, callback) {
function getServers() {
const ret = cares.getServers();
const ret = defaultChannel.getServers();
return ret.map((val) => {
if (!val[1] || val[1] === IANA_DNS_PORT) return val[0];
@ -318,7 +321,7 @@ function getServers() {
function setServers(servers) {
// cache the original servers because in the event of an error setting the
// servers cares won't have any servers available for resolution
const orig = cares.getServers();
const orig = defaultChannel.getServers();
const newSet = [];
const IPv6RE = /\[(.*)\]/;
const addrSplitRE = /(^.+?)(?::(\d+))?$/;
@ -350,11 +353,11 @@ function setServers(servers) {
throw new errors.Error('ERR_INVALID_IP_ADDRESS', serv);
});
const errorNumber = cares.setServers(newSet);
const errorNumber = defaultChannel.setServers(newSet);
if (errorNumber !== 0) {
// reset the servers to the old servers, because ares probably unset them
cares.setServers(orig.join(','));
defaultChannel.setServers(orig.join(','));
var err = cares.strerror(errorNumber);
throw new errors.Error('ERR_DNS_SET_SERVERS_FAILED', err, servers);

1
src/async-wrap.h

@ -35,6 +35,7 @@ namespace node {
#define NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \
V(NONE) \
V(DNSCHANNEL) \
V(FSEVENTWRAP) \
V(FSREQWRAP) \
V(GETADDRINFOREQWRAP) \

383
src/cares_wrap.cc

@ -36,6 +36,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#if defined(__ANDROID__) || \
defined(__MINGW32__) || \
@ -115,6 +116,72 @@ inline const char* ToErrorCodeString(int status) {
return "UNKNOWN_ARES_ERROR";
}
class ChannelWrap;
struct node_ares_task {
ChannelWrap* channel;
ares_socket_t sock;
uv_poll_t poll_watcher;
RB_ENTRY(node_ares_task) node;
};
RB_HEAD(node_ares_task_list, node_ares_task);
class ChannelWrap : public AsyncWrap {
public:
ChannelWrap(Environment* env, Local<Object> object);
~ChannelWrap();
static void New(const FunctionCallbackInfo<Value>& args);
void Setup();
void EnsureServers();
inline uv_timer_t* timer_handle() { return &timer_handle_; }
inline ares_channel cares_channel() { return channel_; }
inline bool query_last_ok() const { return query_last_ok_; }
inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; }
inline bool is_servers_default() const { return is_servers_default_; }
inline void set_is_servers_default(bool is_default) {
is_servers_default_ = is_default;
}
inline node_ares_task_list* task_list() { return &task_list_; }
size_t self_size() const override { return sizeof(this); }
static void AresTimeout(uv_timer_t* handle);
private:
uv_timer_t timer_handle_;
ares_channel channel_;
bool query_last_ok_;
bool is_servers_default_;
bool library_inited_;
node_ares_task_list task_list_;
};
ChannelWrap::ChannelWrap(Environment* env,
Local<Object> object)
: AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
channel_(nullptr),
query_last_ok_(true),
is_servers_default_(true),
library_inited_(false) {
RB_INIT(&task_list_);
MakeWeak<ChannelWrap>(this);
Setup();
}
void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
CHECK_EQ(args.Length(), 0);
Environment* env = Environment::GetCurrent(args);
new ChannelWrap(env, args.This());
}
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
public:
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
@ -168,29 +235,29 @@ RB_GENERATE_STATIC(node_ares_task_list, node_ares_task, node, cmp_ares_tasks)
/* This is called once per second by loop->timer. It is used to constantly */
/* call back into c-ares for possibly processing timeouts. */
void ares_timeout(uv_timer_t* handle) {
Environment* env = Environment::from_cares_timer_handle(handle);
CHECK_EQ(false, RB_EMPTY(env->cares_task_list()));
ares_process_fd(env->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
void ChannelWrap::AresTimeout(uv_timer_t* handle) {
ChannelWrap* channel = ContainerOf(&ChannelWrap::timer_handle_, handle);
CHECK_EQ(false, RB_EMPTY(channel->task_list()));
ares_process_fd(channel->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher);
Environment* env = task->env;
ChannelWrap* channel = task->channel;
/* Reset the idle timer */
uv_timer_again(env->cares_timer_handle());
uv_timer_again(channel->timer_handle());
if (status < 0) {
/* An error happened. Just pretend that the socket is both readable and */
/* writable. */
ares_process_fd(env->cares_channel(), task->sock, task->sock);
ares_process_fd(channel->cares_channel(), task->sock, task->sock);
return;
}
/* Process DNS responses */
ares_process_fd(env->cares_channel(),
ares_process_fd(channel->cares_channel(),
events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
}
@ -204,7 +271,7 @@ void ares_poll_close_cb(uv_handle_t* watcher) {
/* Allocates and returns a new node_ares_task */
node_ares_task* ares_task_create(Environment* env, ares_socket_t sock) {
node_ares_task* ares_task_create(ChannelWrap* channel, ares_socket_t sock) {
auto task = node::UncheckedMalloc<node_ares_task>(1);
if (task == nullptr) {
@ -212,10 +279,11 @@ node_ares_task* ares_task_create(Environment* env, ares_socket_t sock) {
return nullptr;
}
task->env = env;
task->channel = channel;
task->sock = sock;
if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
if (uv_poll_init_socket(channel->env()->event_loop(),
&task->poll_watcher, sock) < 0) {
/* This should never happen. */
free(task);
return nullptr;
@ -230,25 +298,25 @@ void ares_sockstate_cb(void* data,
ares_socket_t sock,
int read,
int write) {
Environment* env = static_cast<Environment*>(data);
ChannelWrap* channel = static_cast<ChannelWrap*>(data);
node_ares_task* task;
node_ares_task lookup_task;
lookup_task.sock = sock;
task = RB_FIND(node_ares_task_list, env->cares_task_list(), &lookup_task);
task = RB_FIND(node_ares_task_list, channel->task_list(), &lookup_task);
if (read || write) {
if (!task) {
/* New socket */
/* If this is the first socket then start the timer. */
uv_timer_t* timer_handle = env->cares_timer_handle();
uv_timer_t* timer_handle = channel->timer_handle();
if (!uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle))) {
CHECK(RB_EMPTY(env->cares_task_list()));
uv_timer_start(timer_handle, ares_timeout, 1000, 1000);
CHECK(RB_EMPTY(channel->task_list()));
uv_timer_start(timer_handle, ChannelWrap::AresTimeout, 1000, 1000);
}
task = ares_task_create(env, sock);
task = ares_task_create(channel, sock);
if (task == nullptr) {
/* This should never happen unless we're out of memory or something */
/* is seriously wrong. The socket won't be polled, but the query will */
@ -256,7 +324,7 @@ void ares_sockstate_cb(void* data,
return;
}
RB_INSERT(node_ares_task_list, env->cares_task_list(), task);
RB_INSERT(node_ares_task_list, channel->task_list(), task);
}
/* This should never fail. If it fails anyway, the query will eventually */
@ -272,12 +340,12 @@ void ares_sockstate_cb(void* data,
CHECK(task &&
"When an ares socket is closed we should have a handle for it");
RB_REMOVE(node_ares_task_list, env->cares_task_list(), task);
RB_REMOVE(node_ares_task_list, channel->task_list(), task);
uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
ares_poll_close_cb);
if (RB_EMPTY(env->cares_task_list())) {
uv_timer_stop(env->cares_timer_handle());
if (RB_EMPTY(channel->task_list())) {
uv_timer_stop(channel->timer_handle());
}
}
}
@ -409,22 +477,53 @@ struct CaresAsyncData {
uv_async_t async_handle;
};
void SetupCaresChannel(Environment* env) {
void ChannelWrap::Setup() {
struct ares_options options;
memset(&options, 0, sizeof(options));
options.flags = ARES_FLAG_NOCHECKRESP;
options.sock_state_cb = ares_sockstate_cb;
options.sock_state_cb_data = env;
options.sock_state_cb_data = this;
int r;
if (!library_inited_) {
r = ares_library_init(ARES_LIB_INIT_ALL);
if (r != ARES_SUCCESS)
return env()->ThrowError(ToErrorCodeString(r));
}
/* We do the call to ares_init_option for caller. */
int r = ares_init_options(env->cares_channel_ptr(),
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
r = ares_init_options(&channel_,
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
if (r != ARES_SUCCESS) {
ares_library_cleanup();
return env->ThrowError(ToErrorCodeString(r));
return env()->ThrowError(ToErrorCodeString(r));
}
library_inited_ = true;
/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
uv_timer_init(env()->event_loop(), &timer_handle_);
env()->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(&timer_handle_),
[](Environment* env, uv_handle_t* handle, void* arg) {
uv_close(handle, [](uv_handle_t* handle) {
ChannelWrap* channel = ContainerOf(
&ChannelWrap::timer_handle_,
reinterpret_cast<uv_timer_t*>(handle));
channel->env()->FinishHandleCleanup(handle);
});
},
nullptr);
}
ChannelWrap::~ChannelWrap() {
if (library_inited_)
ares_library_cleanup();
ares_destroy(channel_);
}
@ -435,22 +534,21 @@ void SetupCaresChannel(Environment* env) {
* The fallback servers of cares is [ "127.0.0.1" ] with no user additional
* setting.
*/
void AresEnsureServers(Environment* env) {
void ChannelWrap::EnsureServers() {
/* if last query is OK or servers are set by user self, do not check */
if (env->cares_query_last_ok() || !env->cares_is_servers_default()) {
if (query_last_ok_ || !is_servers_default_) {
return;
}
ares_channel channel = env->cares_channel();
ares_addr_port_node* servers = nullptr;
ares_get_servers_ports(channel, &servers);
ares_get_servers_ports(channel_, &servers);
/* if no server or multi-servers, ignore */
if (servers == nullptr) return;
if (servers->next != nullptr) {
ares_free_data(servers);
env->set_cares_is_servers_default(false);
is_servers_default_ = false;
return;
}
@ -460,7 +558,7 @@ void AresEnsureServers(Environment* env) {
servers[0].tcp_port != 0 ||
servers[0].udp_port != 0) {
ares_free_data(servers);
env->set_cares_is_servers_default(false);
is_servers_default_ = false;
return;
}
@ -468,19 +566,29 @@ void AresEnsureServers(Environment* env) {
servers = nullptr;
/* destroy channel and reset channel */
ares_destroy(channel);
ares_destroy(channel_);
SetupCaresChannel(env);
Setup();
}
class QueryWrap : public AsyncWrap {
public:
QueryWrap(Environment* env, Local<Object> req_wrap_obj)
: AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP) {
if (env->in_domain())
req_wrap_obj->Set(env->domain_string(), env->domain_array()->Get(0));
QueryWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP),
channel_(channel) {
if (env()->in_domain()) {
req_wrap_obj->Set(env()->domain_string(),
env()->domain_array()->Get(env()->context(), 0)
.ToLocalChecked());
}
Wrap(req_wrap_obj, this);
// Make sure the channel object stays alive during the query lifetime.
req_wrap_obj->Set(env()->context(),
env()->channel_string(),
channel->object()).FromJust();
}
~QueryWrap() override {
@ -501,15 +609,12 @@ class QueryWrap : public AsyncWrap {
}
protected:
void* GetQueryArg() {
return static_cast<void*>(this);
}
static void AresQuery(Environment* env, const char* name,
int dnsclass, int type, ares_callback callback,
void* arg) {
AresEnsureServers(env);
ares_query(env->cares_channel(), name, dnsclass, type, callback, arg);
void AresQuery(const char* name,
int dnsclass,
int type) {
channel_->EnsureServers();
ares_query(channel_->cares_channel(), name, dnsclass, type, Callback,
static_cast<void*>(this));
}
static void CaresAsyncClose(uv_handle_t* handle) {
@ -563,7 +668,7 @@ class QueryWrap : public AsyncWrap {
async_handle,
CaresAsyncCb));
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
wrap->channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
async_handle->data = data;
uv_async_send(async_handle);
}
@ -589,7 +694,7 @@ class QueryWrap : public AsyncWrap {
async_handle,
CaresAsyncCb));
wrap->env()->set_cares_query_last_ok(status != ARES_ECONNREFUSED);
wrap->channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
async_handle->data = data;
uv_async_send(async_handle);
}
@ -624,6 +729,8 @@ class QueryWrap : public AsyncWrap {
virtual void Parse(struct hostent* host) {
UNREACHABLE();
}
ChannelWrap* channel_;
};
@ -1063,17 +1170,12 @@ int ParseSoaReply(Environment* env,
class QueryAnyWrap: public QueryWrap {
public:
QueryAnyWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryAnyWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_any,
Callback,
GetQueryArg());
AresQuery(name, ns_c_in, ns_t_any);
return 0;
}
@ -1235,12 +1337,12 @@ class QueryAnyWrap: public QueryWrap {
class QueryAWrap: public QueryWrap {
public:
QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryAWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_a, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_a);
return 0;
}
@ -1279,12 +1381,12 @@ class QueryAWrap: public QueryWrap {
class QueryAaaaWrap: public QueryWrap {
public:
QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryAaaaWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_aaaa, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_aaaa);
return 0;
}
@ -1323,12 +1425,12 @@ class QueryAaaaWrap: public QueryWrap {
class QueryCnameWrap: public QueryWrap {
public:
QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryCnameWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_cname, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_cname);
return 0;
}
@ -1354,12 +1456,12 @@ class QueryCnameWrap: public QueryWrap {
class QueryMxWrap: public QueryWrap {
public:
QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryMxWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_mx);
return 0;
}
@ -1385,12 +1487,12 @@ class QueryMxWrap: public QueryWrap {
class QueryNsWrap: public QueryWrap {
public:
QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryNsWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_ns);
return 0;
}
@ -1416,12 +1518,12 @@ class QueryNsWrap: public QueryWrap {
class QueryTxtWrap: public QueryWrap {
public:
QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QueryTxtWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_txt);
return 0;
}
@ -1446,12 +1548,12 @@ class QueryTxtWrap: public QueryWrap {
class QuerySrvWrap: public QueryWrap {
public:
explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
explicit QuerySrvWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_srv, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_srv);
return 0;
}
@ -1475,12 +1577,12 @@ class QuerySrvWrap: public QueryWrap {
class QueryPtrWrap: public QueryWrap {
public:
explicit QueryPtrWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
explicit QueryPtrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_ptr, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_ptr);
return 0;
}
@ -1506,12 +1608,12 @@ class QueryPtrWrap: public QueryWrap {
class QueryNaptrWrap: public QueryWrap {
public:
explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
explicit QueryNaptrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_naptr, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_naptr);
return 0;
}
@ -1536,12 +1638,12 @@ class QueryNaptrWrap: public QueryWrap {
class QuerySoaWrap: public QueryWrap {
public:
QuerySoaWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
QuerySoaWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
AresQuery(env(), name, ns_c_in, ns_t_soa, Callback, GetQueryArg());
AresQuery(name, ns_c_in, ns_t_soa);
return 0;
}
@ -1597,8 +1699,8 @@ class QuerySoaWrap: public QueryWrap {
class GetHostByAddrWrap: public QueryWrap {
public:
explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
explicit GetHostByAddrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name) override {
@ -1615,12 +1717,12 @@ class GetHostByAddrWrap: public QueryWrap {
return UV_EINVAL; // So errnoException() reports a proper error.
}
ares_gethostbyaddr(env()->cares_channel(),
ares_gethostbyaddr(channel_->cares_channel(),
address_buffer,
length,
family,
Callback,
GetQueryArg());
static_cast<void*>(static_cast<QueryWrap*>(this)));
return 0;
}
@ -1637,16 +1739,16 @@ class GetHostByAddrWrap: public QueryWrap {
class GetHostByNameWrap: public QueryWrap {
public:
explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
: QueryWrap(env, req_wrap_obj) {
explicit GetHostByNameWrap(ChannelWrap* channel, Local<Object> req_wrap_obj)
: QueryWrap(channel, req_wrap_obj) {
}
int Send(const char* name, int family) override {
ares_gethostbyname(env()->cares_channel(),
ares_gethostbyname(channel_->cares_channel(),
name,
family,
Callback,
GetQueryArg());
static_cast<void*>(static_cast<QueryWrap*>(this)));
return 0;
}
@ -1665,6 +1767,8 @@ class GetHostByNameWrap: public QueryWrap {
template <class Wrap>
static void Query(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
ChannelWrap* channel;
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
CHECK_EQ(false, args.IsConstructCall());
CHECK(args[0]->IsObject());
@ -1672,7 +1776,7 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
Local<Object> req_wrap_obj = args[0].As<Object>();
Local<String> string = args[1].As<String>();
Wrap* wrap = new Wrap(env, req_wrap_obj);
Wrap* wrap = new Wrap(channel, req_wrap_obj);
node::Utf8Value name(env->isolate(), string);
int err = wrap->Send(*name);
@ -1923,12 +2027,14 @@ void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
void GetServers(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
ChannelWrap* channel;
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
Local<Array> server_array = Array::New(env->isolate());
ares_addr_port_node* servers;
int r = ares_get_servers_ports(env->cares_channel(), &servers);
int r = ares_get_servers_ports(channel->cares_channel(), &servers);
CHECK_EQ(r, ARES_SUCCESS);
ares_addr_port_node* cur = servers;
@ -1955,6 +2061,8 @@ void GetServers(const FunctionCallbackInfo<Value>& args) {
void SetServers(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
ChannelWrap* channel;
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
CHECK(args[0]->IsArray());
@ -1963,11 +2071,11 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
uint32_t len = arr->Length();
if (len == 0) {
int rv = ares_set_servers(env->cares_channel(), nullptr);
int rv = ares_set_servers(channel->cares_channel(), nullptr);
return args.GetReturnValue().Set(rv);
}
ares_addr_port_node* servers = new ares_addr_port_node[len];
std::vector<ares_addr_port_node> servers(len);
ares_addr_port_node* last = nullptr;
int err;
@ -2013,14 +2121,12 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
}
if (err == 0)
err = ares_set_servers_ports(env->cares_channel(), &servers[0]);
err = ares_set_servers_ports(channel->cares_channel(), &servers[0]);
else
err = ARES_EBADSTR;
delete[] servers;
if (err == ARES_SUCCESS)
env->set_cares_is_servers_default(false);
channel->set_is_servers_default(false);
args.GetReturnValue().Set(err);
}
@ -2033,52 +2139,11 @@ void StrError(const FunctionCallbackInfo<Value>& args) {
}
void CaresTimerCloseCb(uv_handle_t* handle) {
Environment* env = Environment::from_cares_timer_handle(
reinterpret_cast<uv_timer_t*>(handle));
env->FinishHandleCleanup(handle);
}
void CaresTimerClose(Environment* env,
uv_handle_t* handle,
void* arg) {
uv_close(handle, CaresTimerCloseCb);
}
void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
int r = ares_library_init(ARES_LIB_INIT_ALL);
if (r != ARES_SUCCESS)
return env->ThrowError(ToErrorCodeString(r));
SetupCaresChannel(env);
/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
uv_timer_init(env->event_loop(), env->cares_timer_handle());
env->RegisterHandleCleanup(
reinterpret_cast<uv_handle_t*>(env->cares_timer_handle()),
CaresTimerClose,
nullptr);
env->SetMethod(target, "queryAny", Query<QueryAnyWrap>);
env->SetMethod(target, "queryA", Query<QueryAWrap>);
env->SetMethod(target, "queryAaaa", Query<QueryAaaaWrap>);
env->SetMethod(target, "queryCname", Query<QueryCnameWrap>);
env->SetMethod(target, "queryMx", Query<QueryMxWrap>);
env->SetMethod(target, "queryNs", Query<QueryNsWrap>);
env->SetMethod(target, "queryTxt", Query<QueryTxtWrap>);
env->SetMethod(target, "querySrv", Query<QuerySrvWrap>);
env->SetMethod(target, "queryPtr", Query<QueryPtrWrap>);
env->SetMethod(target, "queryNaptr", Query<QueryNaptrWrap>);
env->SetMethod(target, "querySoa", Query<QuerySoaWrap>);
env->SetMethod(target, "getHostByAddr", Query<GetHostByAddrWrap>);
env->SetMethod(target, "getaddrinfo", GetAddrInfo);
env->SetMethod(target, "getnameinfo", GetNameInfo);
env->SetMethod(target, "isIP", IsIP);
@ -2086,8 +2151,6 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "isIPv6", IsIPv6);
env->SetMethod(target, "strerror", StrError);
env->SetMethod(target, "getServers", GetServers);
env->SetMethod(target, "setServers", SetServers);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"),
Integer::New(env->isolate(), AF_INET));
@ -2131,6 +2194,32 @@ void Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"),
qrw->GetFunction());
Local<FunctionTemplate> channel_wrap =
env->NewFunctionTemplate(ChannelWrap::New);
channel_wrap->InstanceTemplate()->SetInternalFieldCount(1);
env->SetProtoMethod(channel_wrap, "getAsyncId", AsyncWrap::GetAsyncId);
env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>);
env->SetProtoMethod(channel_wrap, "queryA", Query<QueryAWrap>);
env->SetProtoMethod(channel_wrap, "queryAaaa", Query<QueryAaaaWrap>);
env->SetProtoMethod(channel_wrap, "queryCname", Query<QueryCnameWrap>);
env->SetProtoMethod(channel_wrap, "queryMx", Query<QueryMxWrap>);
env->SetProtoMethod(channel_wrap, "queryNs", Query<QueryNsWrap>);
env->SetProtoMethod(channel_wrap, "queryTxt", Query<QueryTxtWrap>);
env->SetProtoMethod(channel_wrap, "querySrv", Query<QuerySrvWrap>);
env->SetProtoMethod(channel_wrap, "queryPtr", Query<QueryPtrWrap>);
env->SetProtoMethod(channel_wrap, "queryNaptr", Query<QueryNaptrWrap>);
env->SetProtoMethod(channel_wrap, "querySoa", Query<QuerySoaWrap>);
env->SetProtoMethod(channel_wrap, "getHostByAddr", Query<GetHostByAddrWrap>);
env->SetProtoMethod(channel_wrap, "getServers", GetServers);
env->SetProtoMethod(channel_wrap, "setServers", SetServers);
channel_wrap->SetClassName(
FIXED_ONE_BYTE_STRING(env->isolate(), "ChannelWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ChannelWrap"),
channel_wrap->GetFunction());
}
} // anonymous namespace

40
src/env-inl.h

@ -292,8 +292,6 @@ inline Environment::Environment(IsolateData* isolate_data,
isolate_data_(isolate_data),
async_hooks_(context->GetIsolate()),
timer_base_(uv_now(isolate_data->event_loop())),
cares_query_last_ok_(true),
cares_is_servers_default_(true),
using_domains_(false),
printed_error_(false),
trace_sync_io_(false),
@ -313,7 +311,6 @@ inline Environment::Environment(IsolateData* isolate_data,
set_binding_cache_object(v8::Object::New(isolate()));
set_module_load_list_array(v8::Array::New(isolate()));
RB_INIT(&cares_task_list_);
AssignToContext(context);
destroy_ids_list_.reserve(512);
@ -490,43 +487,6 @@ inline void Environment::set_fs_stats_field_array(double* fields) {
fs_stats_field_array_ = fields;
}
inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
return ContainerOf(&Environment::cares_timer_handle_, handle);
}
inline uv_timer_t* Environment::cares_timer_handle() {
return &cares_timer_handle_;
}
inline ares_channel Environment::cares_channel() {
return cares_channel_;
}
// Only used in the call to ares_init_options().
inline ares_channel* Environment::cares_channel_ptr() {
return &cares_channel_;
}
inline bool Environment::cares_query_last_ok() {
return cares_query_last_ok_;
}
inline void Environment::set_cares_query_last_ok(bool ok) {
cares_query_last_ok_ = ok;
}
inline bool Environment::cares_is_servers_default() {
return cares_is_servers_default_;
}
inline void Environment::set_cares_is_servers_default(bool is_default) {
cares_is_servers_default_ = is_default;
}
inline node_ares_task_list* Environment::cares_task_list() {
return &cares_task_list_;
}
inline IsolateData* Environment::isolate_data() const {
return isolate_data_;
}

24
src/env.h

@ -97,6 +97,7 @@ namespace node {
V(cached_data_rejected_string, "cachedDataRejected") \
V(callback_string, "callback") \
V(change_string, "change") \
V(channel_string, "channel") \
V(oncertcb_string, "oncertcb") \
V(onclose_string, "_onclose") \
V(code_string, "code") \
@ -298,20 +299,11 @@ namespace node {
class Environment;
struct node_ares_task {
Environment* env;
ares_socket_t sock;
uv_poll_t poll_watcher;
RB_ENTRY(node_ares_task) node;
};
struct node_async_ids {
double async_id;
double trigger_id;
};
RB_HEAD(node_ares_task_list, node_ares_task);
class IsolateData {
public:
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
@ -557,15 +549,6 @@ class Environment {
inline TickInfo* tick_info();
inline uint64_t timer_base() const;
static inline Environment* from_cares_timer_handle(uv_timer_t* handle);
inline uv_timer_t* cares_timer_handle();
inline ares_channel cares_channel();
inline ares_channel* cares_channel_ptr();
inline bool cares_query_last_ok();
inline void set_cares_query_last_ok(bool ok);
inline bool cares_is_servers_default();
inline void set_cares_is_servers_default(bool is_default);
inline node_ares_task_list* cares_task_list();
inline IsolateData* isolate_data() const;
inline bool using_domains() const;
@ -685,11 +668,6 @@ class Environment {
DomainFlag domain_flag_;
TickInfo tick_info_;
const uint64_t timer_base_;
uv_timer_t cares_timer_handle_;
ares_channel cares_channel_;
bool cares_query_last_ok_;
bool cares_is_servers_default_;
node_ares_task_list cares_task_list_;
bool using_domains_;
bool printed_error_;
bool trace_sync_io_;

1
test/parallel/test-async-wrap-getasyncid.js

@ -51,6 +51,7 @@ function testInitialized(req, ctor_name) {
testInitialized(dns.lookup('www.google.com', () => {}), 'GetAddrInfoReqWrap');
testInitialized(dns.lookupService('::1', 22, () => {}), 'GetNameInfoReqWrap');
testInitialized(dns.resolve6('::1', () => {}), 'QueryReqWrap');
testInitialized(new cares.ChannelWrap(), 'ChannelWrap');
}

Loading…
Cancel
Save