1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #define CARES_STATICLIB
24 #include "async-wrap.h"
25 #include "async-wrap-inl.h"
38 #if defined(__ANDROID__) || \
39 defined(__MINGW32__) || \
40 defined(__OpenBSD__) || \
45 # include <arpa/nameser.h>
50 namespace cares_wrap {
54 using v8::EscapableHandleScope;
56 using v8::FunctionCallbackInfo;
57 using v8::FunctionTemplate;
59 using v8::HandleScope;
68 class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
70 GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
73 GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
74 Local<Object> req_wrap_obj)
75 : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) {
76 Wrap(req_wrap_obj, this);
80 static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
81 CHECK(args.IsConstructCall());
85 class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> {
87 GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
90 GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env,
91 Local<Object> req_wrap_obj)
92 : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) {
93 Wrap(req_wrap_obj, this);
97 static void NewGetNameInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
98 CHECK(args.IsConstructCall());
102 static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
103 if (a->sock < b->sock)
105 if (a->sock > b->sock)
111 RB_GENERATE_STATIC(ares_task_list, ares_task_t, node, cmp_ares_tasks)
115 /* This is called once per second by loop->timer. It is used to constantly */
116 /* call back into c-ares for possibly processing timeouts. */
117 static void ares_timeout(uv_timer_t* handle) {
118 Environment* env = Environment::from_cares_timer_handle(handle);
119 CHECK_EQ(false, RB_EMPTY(env->cares_task_list()));
120 ares_process_fd(env->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
124 static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
125 ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher, watcher);
126 Environment* env = task->env;
128 /* Reset the idle timer */
129 uv_timer_again(env->cares_timer_handle());
132 /* An error happened. Just pretend that the socket is both readable and */
134 ares_process_fd(env->cares_channel(), task->sock, task->sock);
138 /* Process DNS responses */
139 ares_process_fd(env->cares_channel(),
140 events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
141 events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
145 static void ares_poll_close_cb(uv_handle_t* watcher) {
146 ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher,
147 reinterpret_cast<uv_poll_t*>(watcher));
152 /* Allocates and returns a new ares_task_t */
153 static ares_task_t* ares_task_create(Environment* env, ares_socket_t sock) {
154 ares_task_t* task = static_cast<ares_task_t*>(malloc(sizeof(*task)));
156 if (task == nullptr) {
164 if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
165 /* This should never happen. */
174 /* Callback from ares when socket operation is started */
175 static void ares_sockstate_cb(void* data,
179 Environment* env = static_cast<Environment*>(data);
182 ares_task_t lookup_task;
183 lookup_task.sock = sock;
184 task = RB_FIND(ares_task_list, env->cares_task_list(), &lookup_task);
190 /* If this is the first socket then start the timer. */
191 uv_timer_t* timer_handle = env->cares_timer_handle();
192 if (!uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle))) {
193 CHECK(RB_EMPTY(env->cares_task_list()));
194 uv_timer_start(timer_handle, ares_timeout, 1000, 1000);
197 task = ares_task_create(env, sock);
198 if (task == nullptr) {
199 /* This should never happen unless we're out of memory or something */
200 /* is seriously wrong. The socket won't be polled, but the the query */
201 /* will eventually time out. */
205 RB_INSERT(ares_task_list, env->cares_task_list(), task);
208 /* This should never fail. If it fails anyway, the query will eventually */
210 uv_poll_start(&task->poll_watcher,
211 (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
215 /* read == 0 and write == 0 this is c-ares's way of notifying us that */
216 /* the socket is now closed. We must free the data associated with */
219 "When an ares socket is closed we should have a handle for it");
221 RB_REMOVE(ares_task_list, env->cares_task_list(), task);
222 uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
225 if (RB_EMPTY(env->cares_task_list())) {
226 uv_timer_stop(env->cares_timer_handle());
232 static Local<Array> HostentToAddresses(Environment* env, struct hostent* host) {
233 EscapableHandleScope scope(env->isolate());
234 Local<Array> addresses = Array::New(env->isolate());
236 char ip[INET6_ADDRSTRLEN];
237 for (uint32_t i = 0; host->h_addr_list[i] != nullptr; ++i) {
238 uv_inet_ntop(host->h_addrtype, host->h_addr_list[i], ip, sizeof(ip));
239 Local<String> address = OneByteString(env->isolate(), ip);
240 addresses->Set(i, address);
243 return scope.Escape(addresses);
247 static Local<Array> HostentToNames(Environment* env, struct hostent* host) {
248 EscapableHandleScope scope(env->isolate());
249 Local<Array> names = Array::New(env->isolate());
251 for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i) {
252 Local<String> address = OneByteString(env->isolate(), host->h_aliases[i]);
253 names->Set(i, address);
256 return scope.Escape(names);
260 class QueryWrap : public AsyncWrap {
262 QueryWrap(Environment* env, Local<Object> req_wrap_obj)
263 : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP) {
264 if (env->in_domain())
265 req_wrap_obj->Set(env->domain_string(), env->domain_array()->Get(0));
268 virtual ~QueryWrap() override {
269 CHECK_EQ(false, persistent().IsEmpty());
270 persistent().Reset();
273 // Subclasses should implement the appropriate Send method.
274 virtual int Send(const char* name) {
279 virtual int Send(const char* name, int family) {
285 void* GetQueryArg() {
286 return static_cast<void*>(this);
289 static void Callback(void *arg, int status, int timeouts,
290 unsigned char* answer_buf, int answer_len) {
291 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
293 if (status != ARES_SUCCESS) {
294 wrap->ParseError(status);
296 wrap->Parse(answer_buf, answer_len);
302 static void Callback(void *arg, int status, int timeouts,
303 struct hostent* host) {
304 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
306 if (status != ARES_SUCCESS) {
307 wrap->ParseError(status);
315 void CallOnComplete(Local<Value> answer) {
316 HandleScope handle_scope(env()->isolate());
317 Context::Scope context_scope(env()->context());
318 Local<Value> argv[] = {
319 Integer::New(env()->isolate(), 0),
322 MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
325 void CallOnComplete(Local<Value> answer, Local<Value> family) {
326 HandleScope handle_scope(env()->isolate());
327 Context::Scope context_scope(env()->context());
328 Local<Value> argv[] = {
329 Integer::New(env()->isolate(), 0),
333 MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
336 void ParseError(int status) {
337 CHECK_NE(status, ARES_SUCCESS);
338 HandleScope handle_scope(env()->isolate());
339 Context::Scope context_scope(env()->context());
343 case ARES_ ## code: \
344 arg = FIXED_ONE_BYTE_STRING(env()->isolate(), #code); \
368 V(EADDRGETNETWORKPARAMS)
372 arg = FIXED_ONE_BYTE_STRING(env()->isolate(), "UNKNOWN_ARES_ERROR");
375 MakeCallback(env()->oncomplete_string(), 1, &arg);
378 // Subclasses should implement the appropriate Parse method.
379 virtual void Parse(unsigned char* buf, int len) {
383 virtual void Parse(struct hostent* host) {
389 class QueryAWrap: public QueryWrap {
391 QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
392 : QueryWrap(env, req_wrap_obj) {
395 int Send(const char* name) override {
396 ares_query(env()->cares_channel(),
406 void Parse(unsigned char* buf, int len) override {
407 HandleScope handle_scope(env()->isolate());
408 Context::Scope context_scope(env()->context());
410 struct hostent* host;
412 int status = ares_parse_a_reply(buf, len, &host, nullptr, nullptr);
413 if (status != ARES_SUCCESS) {
418 Local<Array> addresses = HostentToAddresses(env(), host);
419 ares_free_hostent(host);
421 this->CallOnComplete(addresses);
426 class QueryAaaaWrap: public QueryWrap {
428 QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
429 : QueryWrap(env, req_wrap_obj) {
432 int Send(const char* name) override {
433 ares_query(env()->cares_channel(),
443 void Parse(unsigned char* buf, int len) override {
444 HandleScope handle_scope(env()->isolate());
445 Context::Scope context_scope(env()->context());
447 struct hostent* host;
449 int status = ares_parse_aaaa_reply(buf, len, &host, nullptr, nullptr);
450 if (status != ARES_SUCCESS) {
455 Local<Array> addresses = HostentToAddresses(env(), host);
456 ares_free_hostent(host);
458 this->CallOnComplete(addresses);
463 class QueryCnameWrap: public QueryWrap {
465 QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
466 : QueryWrap(env, req_wrap_obj) {
469 int Send(const char* name) override {
470 ares_query(env()->cares_channel(),
480 void Parse(unsigned char* buf, int len) override {
481 HandleScope handle_scope(env()->isolate());
482 Context::Scope context_scope(env()->context());
483 struct hostent* host;
485 int status = ares_parse_a_reply(buf, len, &host, nullptr, nullptr);
486 if (status != ARES_SUCCESS) {
491 // A cname lookup always returns a single record but we follow the
493 Local<Array> result = Array::New(env()->isolate(), 1);
494 result->Set(0, OneByteString(env()->isolate(), host->h_name));
495 ares_free_hostent(host);
497 this->CallOnComplete(result);
502 class QueryMxWrap: public QueryWrap {
504 QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
505 : QueryWrap(env, req_wrap_obj) {
508 int Send(const char* name) override {
509 ares_query(env()->cares_channel(),
519 void Parse(unsigned char* buf, int len) override {
520 HandleScope handle_scope(env()->isolate());
521 Context::Scope context_scope(env()->context());
523 struct ares_mx_reply* mx_start;
524 int status = ares_parse_mx_reply(buf, len, &mx_start);
525 if (status != ARES_SUCCESS) {
530 Local<Array> mx_records = Array::New(env()->isolate());
531 Local<String> exchange_symbol = env()->exchange_string();
532 Local<String> priority_symbol = env()->priority_string();
534 ares_mx_reply* current = mx_start;
535 for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
536 Local<Object> mx_record = Object::New(env()->isolate());
537 mx_record->Set(exchange_symbol,
538 OneByteString(env()->isolate(), current->host));
539 mx_record->Set(priority_symbol,
540 Integer::New(env()->isolate(), current->priority));
541 mx_records->Set(i, mx_record);
544 ares_free_data(mx_start);
546 this->CallOnComplete(mx_records);
551 class QueryNsWrap: public QueryWrap {
553 QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
554 : QueryWrap(env, req_wrap_obj) {
557 int Send(const char* name) override {
558 ares_query(env()->cares_channel(),
568 void Parse(unsigned char* buf, int len) override {
569 HandleScope handle_scope(env()->isolate());
570 Context::Scope context_scope(env()->context());
571 struct hostent* host;
573 int status = ares_parse_ns_reply(buf, len, &host);
574 if (status != ARES_SUCCESS) {
579 Local<Array> names = HostentToNames(env(), host);
580 ares_free_hostent(host);
582 this->CallOnComplete(names);
587 class QueryTxtWrap: public QueryWrap {
589 QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
590 : QueryWrap(env, req_wrap_obj) {
593 int Send(const char* name) override {
594 ares_query(env()->cares_channel(),
604 void Parse(unsigned char* buf, int len) override {
605 HandleScope handle_scope(env()->isolate());
606 Context::Scope context_scope(env()->context());
607 struct ares_txt_reply* txt_out;
609 int status = ares_parse_txt_reply(buf, len, &txt_out);
610 if (status != ARES_SUCCESS) {
615 Local<Array> txt_records = Array::New(env()->isolate());
616 Local<Array> txt_chunk;
618 ares_txt_reply* current = txt_out;
620 for (uint32_t j = 0; current != nullptr; current = current->next) {
621 Local<String> txt = OneByteString(env()->isolate(), current->txt);
622 // New record found - write out the current chunk
623 if (current->record_start) {
624 if (!txt_chunk.IsEmpty())
625 txt_records->Set(i++, txt_chunk);
626 txt_chunk = Array::New(env()->isolate());
629 txt_chunk->Set(j++, txt);
632 txt_records->Set(i, txt_chunk);
634 ares_free_data(txt_out);
636 this->CallOnComplete(txt_records);
641 class QuerySrvWrap: public QueryWrap {
643 explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
644 : QueryWrap(env, req_wrap_obj) {
647 int Send(const char* name) override {
648 ares_query(env()->cares_channel(),
658 void Parse(unsigned char* buf, int len) override {
659 HandleScope handle_scope(env()->isolate());
660 Context::Scope context_scope(env()->context());
662 struct ares_srv_reply* srv_start;
663 int status = ares_parse_srv_reply(buf, len, &srv_start);
664 if (status != ARES_SUCCESS) {
669 Local<Array> srv_records = Array::New(env()->isolate());
670 Local<String> name_symbol = env()->name_string();
671 Local<String> port_symbol = env()->port_string();
672 Local<String> priority_symbol = env()->priority_string();
673 Local<String> weight_symbol = env()->weight_string();
675 ares_srv_reply* current = srv_start;
676 for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
677 Local<Object> srv_record = Object::New(env()->isolate());
678 srv_record->Set(name_symbol,
679 OneByteString(env()->isolate(), current->host));
680 srv_record->Set(port_symbol,
681 Integer::New(env()->isolate(), current->port));
682 srv_record->Set(priority_symbol,
683 Integer::New(env()->isolate(), current->priority));
684 srv_record->Set(weight_symbol,
685 Integer::New(env()->isolate(), current->weight));
686 srv_records->Set(i, srv_record);
689 ares_free_data(srv_start);
691 this->CallOnComplete(srv_records);
695 class QueryNaptrWrap: public QueryWrap {
697 explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
698 : QueryWrap(env, req_wrap_obj) {
701 int Send(const char* name) override {
702 ares_query(env()->cares_channel(),
712 void Parse(unsigned char* buf, int len) override {
713 HandleScope handle_scope(env()->isolate());
714 Context::Scope context_scope(env()->context());
716 ares_naptr_reply* naptr_start;
717 int status = ares_parse_naptr_reply(buf, len, &naptr_start);
719 if (status != ARES_SUCCESS) {
724 Local<Array> naptr_records = Array::New(env()->isolate());
725 Local<String> flags_symbol = env()->flags_string();
726 Local<String> service_symbol = env()->service_string();
727 Local<String> regexp_symbol = env()->regexp_string();
728 Local<String> replacement_symbol = env()->replacement_string();
729 Local<String> order_symbol = env()->order_string();
730 Local<String> preference_symbol = env()->preference_string();
732 ares_naptr_reply* current = naptr_start;
733 for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
734 Local<Object> naptr_record = Object::New(env()->isolate());
735 naptr_record->Set(flags_symbol,
736 OneByteString(env()->isolate(), current->flags));
737 naptr_record->Set(service_symbol,
738 OneByteString(env()->isolate(), current->service));
739 naptr_record->Set(regexp_symbol,
740 OneByteString(env()->isolate(), current->regexp));
741 naptr_record->Set(replacement_symbol,
742 OneByteString(env()->isolate(), current->replacement));
743 naptr_record->Set(order_symbol,
744 Integer::New(env()->isolate(), current->order));
745 naptr_record->Set(preference_symbol,
746 Integer::New(env()->isolate(), current->preference));
747 naptr_records->Set(i, naptr_record);
750 ares_free_data(naptr_start);
752 this->CallOnComplete(naptr_records);
757 class QuerySoaWrap: public QueryWrap {
759 QuerySoaWrap(Environment* env, Local<Object> req_wrap_obj)
760 : QueryWrap(env, req_wrap_obj) {
763 int Send(const char* name) override {
764 ares_query(env()->cares_channel(),
774 void Parse(unsigned char* buf, int len) override {
775 HandleScope handle_scope(env()->isolate());
776 Context::Scope context_scope(env()->context());
778 ares_soa_reply* soa_out;
779 int status = ares_parse_soa_reply(buf, len, &soa_out);
781 if (status != ARES_SUCCESS) {
786 Local<Object> soa_record = Object::New(env()->isolate());
788 soa_record->Set(env()->nsname_string(),
789 OneByteString(env()->isolate(), soa_out->nsname));
790 soa_record->Set(env()->hostmaster_string(),
791 OneByteString(env()->isolate(), soa_out->hostmaster));
792 soa_record->Set(env()->serial_string(),
793 Integer::New(env()->isolate(), soa_out->serial));
794 soa_record->Set(env()->refresh_string(),
795 Integer::New(env()->isolate(), soa_out->refresh));
796 soa_record->Set(env()->retry_string(),
797 Integer::New(env()->isolate(), soa_out->retry));
798 soa_record->Set(env()->expire_string(),
799 Integer::New(env()->isolate(), soa_out->expire));
800 soa_record->Set(env()->minttl_string(),
801 Integer::New(env()->isolate(), soa_out->minttl));
803 ares_free_data(soa_out);
805 this->CallOnComplete(soa_record);
810 class GetHostByAddrWrap: public QueryWrap {
812 explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
813 : QueryWrap(env, req_wrap_obj) {
816 int Send(const char* name) override {
818 char address_buffer[sizeof(struct in6_addr)];
820 if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) {
821 length = sizeof(struct in_addr);
823 } else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) {
824 length = sizeof(struct in6_addr);
827 return UV_EINVAL; // So errnoException() reports a proper error.
830 ares_gethostbyaddr(env()->cares_channel(),
840 void Parse(struct hostent* host) override {
841 HandleScope handle_scope(env()->isolate());
842 Context::Scope context_scope(env()->context());
843 this->CallOnComplete(HostentToNames(env(), host));
848 class GetHostByNameWrap: public QueryWrap {
850 explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
851 : QueryWrap(env, req_wrap_obj) {
854 int Send(const char* name, int family) override {
855 ares_gethostbyname(env()->cares_channel(),
864 void Parse(struct hostent* host) override {
865 HandleScope scope(env()->isolate());
867 Local<Array> addresses = HostentToAddresses(env(), host);
868 Local<Integer> family = Integer::New(env()->isolate(), host->h_addrtype);
870 this->CallOnComplete(addresses, family);
875 template <class Wrap>
876 static void Query(const FunctionCallbackInfo<Value>& args) {
877 Environment* env = Environment::GetCurrent(args);
879 CHECK_EQ(false, args.IsConstructCall());
880 CHECK(args[0]->IsObject());
881 CHECK(args[1]->IsString());
883 Local<Object> req_wrap_obj = args[0].As<Object>();
884 Local<String> string = args[1].As<String>();
885 Wrap* wrap = new Wrap(env, req_wrap_obj);
887 node::Utf8Value name(env->isolate(), string);
888 int err = wrap->Send(*name);
892 args.GetReturnValue().Set(err);
896 void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
897 GetAddrInfoReqWrap* req_wrap = static_cast<GetAddrInfoReqWrap*>(req->data);
898 Environment* env = req_wrap->env();
900 HandleScope handle_scope(env->isolate());
901 Context::Scope context_scope(env->context());
903 Local<Value> argv[] = {
904 Integer::New(env->isolate(), status),
910 struct addrinfo *address;
913 // Count the number of responses.
914 for (address = res; address; address = address->ai_next) {
918 // Create the response array.
919 Local<Array> results = Array::New(env->isolate(), n);
921 char ip[INET6_ADDRSTRLEN];
926 // Iterate over the IPv4 responses again this time creating javascript
927 // strings for each IP and filling the results array.
930 CHECK_EQ(address->ai_socktype, SOCK_STREAM);
932 // Ignore random ai_family types.
933 if (address->ai_family == AF_INET) {
935 addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in*>(
936 address->ai_addr)->sin_addr));
937 int err = uv_inet_ntop(address->ai_family,
944 // Create JavaScript string
945 Local<String> s = OneByteString(env->isolate(), ip);
951 address = address->ai_next;
954 // Iterate over the IPv6 responses putting them in the array.
957 CHECK_EQ(address->ai_socktype, SOCK_STREAM);
959 // Ignore random ai_family types.
960 if (address->ai_family == AF_INET6) {
962 addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in6*>(
963 address->ai_addr)->sin6_addr));
964 int err = uv_inet_ntop(address->ai_family,
971 // Create JavaScript string
972 Local<String> s = OneByteString(env->isolate(), ip);
978 address = address->ai_next;
985 uv_freeaddrinfo(res);
987 // Make the callback into JavaScript
988 req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
994 void AfterGetNameInfo(uv_getnameinfo_t* req,
996 const char* hostname,
997 const char* service) {
998 GetNameInfoReqWrap* req_wrap = static_cast<GetNameInfoReqWrap*>(req->data);
999 Environment* env = req_wrap->env();
1001 HandleScope handle_scope(env->isolate());
1002 Context::Scope context_scope(env->context());
1004 Local<Value> argv[] = {
1005 Integer::New(env->isolate(), status),
1006 Null(env->isolate()),
1007 Null(env->isolate())
1012 Local<String> js_hostname = OneByteString(env->isolate(), hostname);
1013 Local<String> js_service = OneByteString(env->isolate(), service);
1014 argv[1] = js_hostname;
1015 argv[2] = js_service;
1018 // Make the callback into JavaScript
1019 req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
1025 static void IsIP(const FunctionCallbackInfo<Value>& args) {
1026 node::Utf8Value ip(args.GetIsolate(), args[0]);
1027 char address_buffer[sizeof(struct in6_addr)];
1030 if (uv_inet_pton(AF_INET, *ip, &address_buffer) == 0)
1032 else if (uv_inet_pton(AF_INET6, *ip, &address_buffer) == 0)
1035 args.GetReturnValue().Set(rc);
1039 static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
1040 Environment* env = Environment::GetCurrent(args);
1042 CHECK(args[0]->IsObject());
1043 CHECK(args[1]->IsString());
1044 CHECK(args[2]->IsInt32());
1045 Local<Object> req_wrap_obj = args[0].As<Object>();
1046 node::Utf8Value hostname(env->isolate(), args[1]);
1048 int32_t flags = (args[3]->IsInt32()) ? args[3]->Int32Value() : 0;
1051 switch (args[2]->Int32Value()) {
1062 CHECK(0 && "bad address family");
1066 GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj);
1068 struct addrinfo hints;
1069 memset(&hints, 0, sizeof(struct addrinfo));
1070 hints.ai_family = family;
1071 hints.ai_socktype = SOCK_STREAM;
1072 hints.ai_flags = flags;
1074 int err = uv_getaddrinfo(env->event_loop(),
1080 req_wrap->Dispatched();
1084 args.GetReturnValue().Set(err);
1088 static void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
1089 Environment* env = Environment::GetCurrent(args);
1091 CHECK(args[0]->IsObject());
1092 CHECK(args[1]->IsString());
1093 CHECK(args[2]->IsUint32());
1094 Local<Object> req_wrap_obj = args[0].As<Object>();
1095 node::Utf8Value ip(env->isolate(), args[1]);
1096 const unsigned port = args[2]->Uint32Value();
1097 struct sockaddr_storage addr;
1099 CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 ||
1100 uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0);
1102 GetNameInfoReqWrap* req_wrap = new GetNameInfoReqWrap(env, req_wrap_obj);
1104 int err = uv_getnameinfo(env->event_loop(),
1107 (struct sockaddr*)&addr,
1109 req_wrap->Dispatched();
1113 args.GetReturnValue().Set(err);
1117 static void GetServers(const FunctionCallbackInfo<Value>& args) {
1118 Environment* env = Environment::GetCurrent(args);
1120 Local<Array> server_array = Array::New(env->isolate());
1122 ares_addr_node* servers;
1124 int r = ares_get_servers(env->cares_channel(), &servers);
1125 CHECK_EQ(r, ARES_SUCCESS);
1127 ares_addr_node* cur = servers;
1129 for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) {
1130 char ip[INET6_ADDRSTRLEN];
1132 const void* caddr = static_cast<const void*>(&cur->addr);
1133 int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
1136 Local<String> addr = OneByteString(env->isolate(), ip);
1137 server_array->Set(i, addr);
1140 ares_free_data(servers);
1142 args.GetReturnValue().Set(server_array);
1146 static void SetServers(const FunctionCallbackInfo<Value>& args) {
1147 Environment* env = Environment::GetCurrent(args);
1149 CHECK(args[0]->IsArray());
1151 Local<Array> arr = Local<Array>::Cast(args[0]);
1153 uint32_t len = arr->Length();
1156 int rv = ares_set_servers(env->cares_channel(), nullptr);
1157 return args.GetReturnValue().Set(rv);
1160 ares_addr_node* servers = new ares_addr_node[len];
1161 ares_addr_node* last = nullptr;
1165 for (uint32_t i = 0; i < len; i++) {
1166 CHECK(arr->Get(i)->IsArray());
1168 Local<Array> elm = Local<Array>::Cast(arr->Get(i));
1170 CHECK(elm->Get(0)->Int32Value());
1171 CHECK(elm->Get(1)->IsString());
1173 int fam = elm->Get(0)->Int32Value();
1174 node::Utf8Value ip(env->isolate(), elm->Get(1));
1176 ares_addr_node* cur = &servers[i];
1180 cur->family = AF_INET;
1181 err = uv_inet_pton(AF_INET, *ip, &cur->addr);
1184 cur->family = AF_INET6;
1185 err = uv_inet_pton(AF_INET6, *ip, &cur->addr);
1188 CHECK(0 && "Bad address family.");
1195 cur->next = nullptr;
1197 if (last != nullptr)
1204 err = ares_set_servers(env->cares_channel(), &servers[0]);
1210 args.GetReturnValue().Set(err);
1214 static void StrError(const FunctionCallbackInfo<Value>& args) {
1215 Environment* env = Environment::GetCurrent(args);
1216 const char* errmsg = ares_strerror(args[0]->Int32Value());
1217 args.GetReturnValue().Set(OneByteString(env->isolate(), errmsg));
1221 static void CaresTimerCloseCb(uv_handle_t* handle) {
1222 Environment* env = Environment::from_cares_timer_handle(
1223 reinterpret_cast<uv_timer_t*>(handle));
1224 env->FinishHandleCleanup(handle);
1228 static void CaresTimerClose(Environment* env,
1229 uv_handle_t* handle,
1231 uv_close(handle, CaresTimerCloseCb);
1235 static void Initialize(Handle<Object> target,
1236 Handle<Value> unused,
1237 Handle<Context> context) {
1238 Environment* env = Environment::GetCurrent(context);
1240 int r = ares_library_init(ARES_LIB_INIT_ALL);
1241 CHECK_EQ(r, ARES_SUCCESS);
1243 struct ares_options options;
1244 memset(&options, 0, sizeof(options));
1245 options.flags = ARES_FLAG_NOCHECKRESP;
1246 options.sock_state_cb = ares_sockstate_cb;
1247 options.sock_state_cb_data = env;
1249 /* We do the call to ares_init_option for caller. */
1250 r = ares_init_options(env->cares_channel_ptr(),
1252 ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
1253 CHECK_EQ(r, ARES_SUCCESS);
1255 /* Initialize the timeout timer. The timer won't be started until the */
1256 /* first socket is opened. */
1257 uv_timer_init(env->event_loop(), env->cares_timer_handle());
1258 env->RegisterHandleCleanup(
1259 reinterpret_cast<uv_handle_t*>(env->cares_timer_handle()),
1263 env->SetMethod(target, "queryA", Query<QueryAWrap>);
1264 env->SetMethod(target, "queryAaaa", Query<QueryAaaaWrap>);
1265 env->SetMethod(target, "queryCname", Query<QueryCnameWrap>);
1266 env->SetMethod(target, "queryMx", Query<QueryMxWrap>);
1267 env->SetMethod(target, "queryNs", Query<QueryNsWrap>);
1268 env->SetMethod(target, "queryTxt", Query<QueryTxtWrap>);
1269 env->SetMethod(target, "querySrv", Query<QuerySrvWrap>);
1270 env->SetMethod(target, "queryNaptr", Query<QueryNaptrWrap>);
1271 env->SetMethod(target, "querySoa", Query<QuerySoaWrap>);
1272 env->SetMethod(target, "getHostByAddr", Query<GetHostByAddrWrap>);
1274 env->SetMethod(target, "getaddrinfo", GetAddrInfo);
1275 env->SetMethod(target, "getnameinfo", GetNameInfo);
1276 env->SetMethod(target, "isIP", IsIP);
1278 env->SetMethod(target, "strerror", StrError);
1279 env->SetMethod(target, "getServers", GetServers);
1280 env->SetMethod(target, "setServers", SetServers);
1282 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"),
1283 Integer::New(env->isolate(), AF_INET));
1284 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"),
1285 Integer::New(env->isolate(), AF_INET6));
1286 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_UNSPEC"),
1287 Integer::New(env->isolate(), AF_UNSPEC));
1288 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_ADDRCONFIG"),
1289 Integer::New(env->isolate(), AI_ADDRCONFIG));
1290 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"),
1291 Integer::New(env->isolate(), AI_V4MAPPED));
1293 Local<FunctionTemplate> aiw =
1294 FunctionTemplate::New(env->isolate(), NewGetAddrInfoReqWrap);
1295 aiw->InstanceTemplate()->SetInternalFieldCount(1);
1297 FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"));
1298 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"),
1299 aiw->GetFunction());
1301 Local<FunctionTemplate> niw =
1302 FunctionTemplate::New(env->isolate(), NewGetNameInfoReqWrap);
1303 niw->InstanceTemplate()->SetInternalFieldCount(1);
1305 FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"));
1306 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"),
1307 niw->GetFunction());
1310 } // namespace cares_wrap
1313 NODE_MODULE_CONTEXT_AWARE_BUILTIN(cares_wrap, node::cares_wrap::Initialize)