diff options
Diffstat (limited to 'src/cares_wrap.cc')
-rw-r--r-- | src/cares_wrap.cc | 236 |
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) |