summaryrefslogtreecommitdiff
path: root/src/cares_wrap.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cares_wrap.cc')
-rw-r--r--src/cares_wrap.cc236
1 files changed, 147 insertions, 89 deletions
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index f09590e88e..00238788ad 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -21,6 +21,8 @@
#define CARES_STATICLIB
#include "ares.h"
+#include "env.h"
+#include "env-inl.h"
#include "node.h"
#include "req_wrap.h"
#include "tree.h"
@@ -45,6 +47,7 @@ namespace node {
namespace cares_wrap {
using v8::Array;
+using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Handle;
@@ -57,22 +60,8 @@ using v8::Persistent;
using v8::String;
using v8::Value;
-
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
-struct ares_task_t {
- uv_loop_t* loop;
- ares_socket_t sock;
- uv_poll_t poll_watcher;
- RB_ENTRY(ares_task_t) node;
-};
-
-
-static Cached<String> oncomplete_sym;
-static ares_channel ares_channel;
-static uv_timer_t ares_timer;
-static RB_HEAD(ares_task_list, ares_task_t) ares_tasks;
-
static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
if (a->sock < b->sock) return -1;
@@ -88,26 +77,28 @@ RB_GENERATE_STATIC(ares_task_list, ares_task_t, 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. */
static void ares_timeout(uv_timer_t* handle, int status) {
- assert(!RB_EMPTY(&ares_tasks));
- ares_process_fd(ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ Environment* env = Environment::from_cares_timer_handle(handle);
+ assert(!RB_EMPTY(env->cares_task_list()));
+ ares_process_fd(env->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
ares_task_t* task = container_of(watcher, ares_task_t, poll_watcher);
+ Environment* env = task->env;
/* Reset the idle timer */
- uv_timer_again(&ares_timer);
+ uv_timer_again(env->cares_timer_handle());
if (status < 0) {
/* An error happened. Just pretend that the socket is both readable and */
/* writable. */
- ares_process_fd(ares_channel, task->sock, task->sock);
+ ares_process_fd(env->cares_channel(), task->sock, task->sock);
return;
}
/* Process DNS responses */
- ares_process_fd(ares_channel,
+ ares_process_fd(env->cares_channel(),
events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
}
@@ -120,7 +111,7 @@ static void ares_poll_close_cb(uv_handle_t* watcher) {
/* Allocates and returns a new ares_task_t */
-static ares_task_t* ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
+static ares_task_t* ares_task_create(Environment* env, ares_socket_t sock) {
ares_task_t* task = static_cast<ares_task_t*>(malloc(sizeof(*task)));
if (task == NULL) {
@@ -128,10 +119,10 @@ static ares_task_t* ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
return NULL;
}
- task->loop = loop;
+ task->env = env;
task->sock = sock;
- if (uv_poll_init_socket(loop, &task->poll_watcher, sock) < 0) {
+ if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
/* This should never happen. */
free(task);
return NULL;
@@ -146,24 +137,25 @@ static void ares_sockstate_cb(void* data,
ares_socket_t sock,
int read,
int write) {
- uv_loop_t* loop = static_cast<uv_loop_t*>(data);
+ Environment* env = static_cast<Environment*>(data);
ares_task_t* task;
ares_task_t lookup_task;
lookup_task.sock = sock;
- task = RB_FIND(ares_task_list, &ares_tasks, &lookup_task);
+ task = RB_FIND(ares_task_list, env->cares_task_list(), &lookup_task);
if (read || write) {
if (!task) {
/* New socket */
/* If this is the first socket then start the timer. */
- if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&ares_timer))) {
- assert(RB_EMPTY(&ares_tasks));
- uv_timer_start(&ares_timer, ares_timeout, 1000, 1000);
+ uv_timer_t* timer_handle = env->cares_timer_handle();
+ if (!uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle))) {
+ assert(RB_EMPTY(env->cares_task_list()));
+ uv_timer_start(timer_handle, ares_timeout, 1000, 1000);
}
- task = ares_task_create(loop, sock);
+ task = ares_task_create(env, sock);
if (task == NULL) {
/* This should never happen unless we're out of memory or something */
/* is seriously wrong. The socket won't be polled, but the the query */
@@ -171,7 +163,7 @@ static void ares_sockstate_cb(void* data,
return;
}
- RB_INSERT(ares_task_list, &ares_tasks, task);
+ RB_INSERT(ares_task_list, env->cares_task_list(), task);
}
/* This should never fail. If it fails anyway, the query will eventually */
@@ -187,12 +179,12 @@ static void ares_sockstate_cb(void* data,
assert(task &&
"When an ares socket is closed we should have a handle for it");
- RB_REMOVE(ares_task_list, &ares_tasks, task);
+ RB_REMOVE(ares_task_list, env->cares_task_list(), task);
uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
ares_poll_close_cb);
- if (RB_EMPTY(&ares_tasks)) {
- uv_timer_stop(&ares_timer);
+ if (RB_EMPTY(env->cares_task_list())) {
+ uv_timer_stop(env->cares_timer_handle());
}
}
}
@@ -228,7 +220,7 @@ static Local<Array> HostentToNames(struct hostent* host) {
class QueryWrap {
public:
- explicit QueryWrap(Local<Object> req_wrap_obj) {
+ QueryWrap(Environment* env, Local<Object> req_wrap_obj) : env_(env) {
HandleScope scope(node_isolate);
persistent().Reset(node_isolate, req_wrap_obj);
}
@@ -289,24 +281,46 @@ class QueryWrap {
}
void CallOnComplete(Local<Value> answer) {
- HandleScope scope(node_isolate);
- Local<Value> argv[2] = { Integer::New(0, node_isolate), answer };
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
+ Local<Value> argv[] = {
+ Integer::New(0, env()->isolate()),
+ answer
+ };
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
void CallOnComplete(Local<Value> answer, Local<Value> family) {
- HandleScope scope(node_isolate);
- Local<Value> argv[3] = { Integer::New(0, node_isolate), answer, family };
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
+ Local<Value> argv[] = {
+ Integer::New(0, env()->isolate()),
+ answer,
+ family
+ };
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
void ParseError(int status) {
assert(status != ARES_SUCCESS);
- HandleScope scope(node_isolate);
+ Context::Scope context_scope(env()->context());
+ HandleScope handle_scope(env()->isolate());
Local<Value> argv[] = {
- Integer::New(status, node_isolate)
+ Integer::New(status, env()->isolate())
};
- MakeCallback(object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env(),
+ object(),
+ env()->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
}
// Subclasses should implement the appropriate Parse method.
@@ -318,18 +332,29 @@ class QueryWrap {
assert(0);
};
+ inline Environment* env() const {
+ return env_;
+ }
+
private:
Persistent<Object> object_;
+ Environment* const env_;
};
class QueryAWrap: public QueryWrap {
public:
- explicit QueryAWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_a, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_a,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -355,11 +380,12 @@ class QueryAWrap: public QueryWrap {
class QueryAaaaWrap: public QueryWrap {
public:
- explicit QueryAaaaWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_aaaa,
@@ -390,12 +416,12 @@ class QueryAaaaWrap: public QueryWrap {
class QueryCnameWrap: public QueryWrap {
public:
- explicit QueryCnameWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_cname,
@@ -429,11 +455,17 @@ class QueryCnameWrap: public QueryWrap {
class QueryMxWrap: public QueryWrap {
public:
- explicit QueryMxWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_mx,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -473,11 +505,17 @@ class QueryMxWrap: public QueryWrap {
class QueryNsWrap: public QueryWrap {
public:
- explicit QueryNsWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_ns,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -501,11 +539,17 @@ class QueryNsWrap: public QueryWrap {
class QueryTxtWrap: public QueryWrap {
public:
- explicit QueryTxtWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel, name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
+ ares_query(env()->cares_channel(),
+ name,
+ ns_c_in,
+ ns_t_txt,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -536,11 +580,12 @@ class QueryTxtWrap: public QueryWrap {
class QuerySrvWrap: public QueryWrap {
public:
- explicit QuerySrvWrap(Local<Object> req_wrap_obj) : QueryWrap(req_wrap_obj) {
+ explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_srv,
@@ -592,12 +637,12 @@ class QuerySrvWrap: public QueryWrap {
class QueryNaptrWrap: public QueryWrap {
public:
- explicit QueryNaptrWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
- ares_query(ares_channel,
+ ares_query(env()->cares_channel(),
name,
ns_c_in,
ns_t_naptr,
@@ -659,8 +704,8 @@ class QueryNaptrWrap: public QueryWrap {
class GetHostByAddrWrap: public QueryWrap {
public:
- explicit GetHostByAddrWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name) {
@@ -677,7 +722,7 @@ class GetHostByAddrWrap: public QueryWrap {
return UV_EINVAL; // So errnoException() reports a proper error.
}
- ares_gethostbyaddr(ares_channel,
+ ares_gethostbyaddr(env()->cares_channel(),
address_buffer,
length,
family,
@@ -697,12 +742,16 @@ class GetHostByAddrWrap: public QueryWrap {
class GetHostByNameWrap: public QueryWrap {
public:
- explicit GetHostByNameWrap(Local<Object> req_wrap_obj)
- : QueryWrap(req_wrap_obj) {
+ explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
+ : QueryWrap(env, req_wrap_obj) {
}
int Send(const char* name, int family) {
- ares_gethostbyname(ares_channel, name, family, Callback, GetQueryArg());
+ ares_gethostbyname(env()->cares_channel(),
+ name,
+ family,
+ Callback,
+ GetQueryArg());
return 0;
}
@@ -720,7 +769,8 @@ class GetHostByNameWrap: public QueryWrap {
template <class Wrap>
static void Query(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(!args.IsConstructCall());
assert(args[0]->IsObject());
@@ -728,7 +778,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(req_wrap_obj);
+ Wrap* wrap = new Wrap(env, req_wrap_obj);
String::Utf8Value name(string);
int err = wrap->Send(*name);
@@ -739,9 +789,11 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
- HandleScope scope(node_isolate);
-
GetAddrInfoReqWrap* req_wrap = static_cast<GetAddrInfoReqWrap*>(req->data);
+ Environment* env = req_wrap->env();
+
+ Context::Scope context_scope(env->context());
+ HandleScope handle_scope(env->isolate());
Local<Value> argv[] = {
Integer::New(status, node_isolate),
@@ -828,7 +880,11 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
uv_freeaddrinfo(res);
// Make the callback into JavaScript
- MakeCallback(req_wrap->object(), oncomplete_sym, ARRAY_SIZE(argv), argv);
+ MakeCallback(env,
+ req_wrap->object(),
+ env->oncomplete_string(),
+ ARRAY_SIZE(argv),
+ argv);
delete req_wrap;
}
@@ -851,7 +907,8 @@ static void IsIP(const FunctionCallbackInfo<Value>& args) {
static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(args[0]->IsObject());
assert(args[1]->IsString());
@@ -875,14 +932,14 @@ static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
abort();
}
- GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(req_wrap_obj);
+ GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
- int err = uv_getaddrinfo(uv_default_loop(),
+ int err = uv_getaddrinfo(env->event_loop(),
&req_wrap->req_,
AfterGetAddrInfo,
*hostname,
@@ -896,13 +953,14 @@ static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
static void GetServers(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
Local<Array> server_array = Array::New();
ares_addr_node* servers;
- int r = ares_get_servers(ares_channel, &servers);
+ int r = ares_get_servers(env->cares_channel(), &servers);
assert(r == ARES_SUCCESS);
ares_addr_node* cur = servers;
@@ -925,7 +983,8 @@ static void GetServers(const FunctionCallbackInfo<Value>& args) {
static void SetServers(const FunctionCallbackInfo<Value>& args) {
- HandleScope scope(node_isolate);
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(args.GetIsolate());
assert(args[0]->IsArray());
@@ -934,7 +993,7 @@ static void SetServers(const FunctionCallbackInfo<Value>& args) {
uint32_t len = arr->Length();
if (len == 0) {
- int rv = ares_set_servers(ares_channel, NULL);
+ int rv = ares_set_servers(env->cares_channel(), NULL);
return args.GetReturnValue().Set(rv);
}
@@ -982,7 +1041,7 @@ static void SetServers(const FunctionCallbackInfo<Value>& args) {
}
if (err == 0)
- err = ares_set_servers(ares_channel, &servers[0]);
+ err = ares_set_servers(env->cares_channel(), &servers[0]);
else
err = ARES_EBADSTR;
@@ -999,28 +1058,29 @@ static void StrError(const FunctionCallbackInfo<Value>& args) {
}
-static void Initialize(Handle<Object> target) {
- HandleScope scope(node_isolate);
- int r;
+static void Initialize(Handle<Object> target,
+ Handle<Value> unused,
+ Handle<Context> context) {
+ Environment* env = Environment::GetCurrent(context);
- r = ares_library_init(ARES_LIB_INIT_ALL);
+ int r = ares_library_init(ARES_LIB_INIT_ALL);
assert(r == ARES_SUCCESS);
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 = uv_default_loop();
+ options.sock_state_cb_data = env;
/* We do the call to ares_init_option for caller. */
- r = ares_init_options(&ares_channel,
+ r = ares_init_options(env->cares_channel_ptr(),
&options,
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
assert(r == ARES_SUCCESS);
/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
- uv_timer_init(uv_default_loop(), &ares_timer);
+ uv_timer_init(env->event_loop(), env->cares_timer_handle());
NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
NODE_SET_METHOD(target, "queryAaaa", Query<QueryAaaaWrap>);
@@ -1045,11 +1105,9 @@ static void Initialize(Handle<Object> target) {
Integer::New(AF_INET6, node_isolate));
target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "AF_UNSPEC"),
Integer::New(AF_UNSPEC, node_isolate));
-
- oncomplete_sym = FIXED_ONE_BYTE_STRING(node_isolate, "oncomplete");
}
} // namespace cares_wrap
} // namespace node
-NODE_MODULE(node_cares_wrap, node::cares_wrap::Initialize)
+NODE_MODULE_CONTEXT_AWARE(node_cares_wrap, node::cares_wrap::Initialize)