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__) || \
44 # include <arpa/nameser.h>
49 namespace cares_wrap {
53 using v8::EscapableHandleScope;
55 using v8::FunctionCallbackInfo;
57 using v8::HandleScope;
65 typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
68 static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
69 if (a->sock < b->sock)
71 if (a->sock > b->sock)
77 RB_GENERATE_STATIC(ares_task_list, ares_task_t, node, cmp_ares_tasks)
81 /* This is called once per second by loop->timer. It is used to constantly */
82 /* call back into c-ares for possibly processing timeouts. */
83 static void ares_timeout(uv_timer_t* handle, int status) {
84 Environment* env = Environment::from_cares_timer_handle(handle);
85 assert(!RB_EMPTY(env->cares_task_list()));
86 ares_process_fd(env->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
90 static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
91 ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher);
92 Environment* env = task->env;
94 /* Reset the idle timer */
95 uv_timer_again(env->cares_timer_handle());
98 /* An error happened. Just pretend that the socket is both readable and */
100 ares_process_fd(env->cares_channel(), task->sock, task->sock);
104 /* Process DNS responses */
105 ares_process_fd(env->cares_channel(),
106 events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
107 events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
111 static void ares_poll_close_cb(uv_handle_t* watcher) {
112 ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher);
117 /* Allocates and returns a new ares_task_t */
118 static ares_task_t* ares_task_create(Environment* env, ares_socket_t sock) {
119 ares_task_t* task = static_cast<ares_task_t*>(malloc(sizeof(*task)));
129 if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
130 /* This should never happen. */
139 /* Callback from ares when socket operation is started */
140 static void ares_sockstate_cb(void* data,
144 Environment* env = static_cast<Environment*>(data);
147 ares_task_t lookup_task;
148 lookup_task.sock = sock;
149 task = RB_FIND(ares_task_list, env->cares_task_list(), &lookup_task);
155 /* If this is the first socket then start the timer. */
156 uv_timer_t* timer_handle = env->cares_timer_handle();
157 if (!uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle))) {
158 assert(RB_EMPTY(env->cares_task_list()));
159 uv_timer_start(timer_handle, ares_timeout, 1000, 1000);
162 task = ares_task_create(env, sock);
164 /* This should never happen unless we're out of memory or something */
165 /* is seriously wrong. The socket won't be polled, but the the query */
166 /* will eventually time out. */
170 RB_INSERT(ares_task_list, env->cares_task_list(), task);
173 /* This should never fail. If it fails anyway, the query will eventually */
175 uv_poll_start(&task->poll_watcher,
176 (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
180 /* read == 0 and write == 0 this is c-ares's way of notifying us that */
181 /* the socket is now closed. We must free the data associated with */
184 "When an ares socket is closed we should have a handle for it");
186 RB_REMOVE(ares_task_list, env->cares_task_list(), task);
187 uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
190 if (RB_EMPTY(env->cares_task_list())) {
191 uv_timer_stop(env->cares_timer_handle());
197 static Local<Array> HostentToAddresses(Environment* env, struct hostent* host) {
198 EscapableHandleScope scope(env->isolate());
199 Local<Array> addresses = Array::New(env->isolate());
201 char ip[INET6_ADDRSTRLEN];
202 for (uint32_t i = 0; host->h_addr_list[i] != NULL; ++i) {
203 uv_inet_ntop(host->h_addrtype, host->h_addr_list[i], ip, sizeof(ip));
204 Local<String> address = OneByteString(env->isolate(), ip);
205 addresses->Set(i, address);
208 return scope.Escape(addresses);
212 static Local<Array> HostentToNames(Environment* env, struct hostent* host) {
213 EscapableHandleScope scope(env->isolate());
214 Local<Array> names = Array::New(env->isolate());
216 for (uint32_t i = 0; host->h_aliases[i] != NULL; ++i) {
217 Local<String> address = OneByteString(env->isolate(), host->h_aliases[i]);
218 names->Set(i, address);
221 return scope.Escape(names);
225 class QueryWrap : public AsyncWrap {
227 QueryWrap(Environment* env, Local<Object> req_wrap_obj)
228 : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_CARES) {
231 virtual ~QueryWrap() {
232 assert(!persistent().IsEmpty());
233 persistent().Reset();
236 // Subclasses should implement the appropriate Send method.
237 virtual int Send(const char* name) {
242 virtual int Send(const char* name, int family) {
248 void* GetQueryArg() {
249 return static_cast<void*>(this);
252 static void Callback(void *arg, int status, int timeouts,
253 unsigned char* answer_buf, int answer_len) {
254 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
256 if (status != ARES_SUCCESS) {
257 wrap->ParseError(status);
259 wrap->Parse(answer_buf, answer_len);
265 static void Callback(void *arg, int status, int timeouts,
266 struct hostent* host) {
267 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
269 if (status != ARES_SUCCESS) {
270 wrap->ParseError(status);
278 void CallOnComplete(Local<Value> answer) {
279 HandleScope handle_scope(env()->isolate());
280 Context::Scope context_scope(env()->context());
281 Local<Value> argv[] = {
282 Integer::New(env()->isolate(), 0),
285 MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
288 void CallOnComplete(Local<Value> answer, Local<Value> family) {
289 HandleScope handle_scope(env()->isolate());
290 Context::Scope context_scope(env()->context());
291 Local<Value> argv[] = {
292 Integer::New(env()->isolate(), 0),
296 MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
299 void ParseError(int status) {
300 assert(status != ARES_SUCCESS);
301 HandleScope handle_scope(env()->isolate());
302 Context::Scope context_scope(env()->context());
306 case ARES_ ## code: \
307 arg = FIXED_ONE_BYTE_STRING(env()->isolate(), #code); \
331 V(EADDRGETNETWORKPARAMS)
335 arg = FIXED_ONE_BYTE_STRING(env()->isolate(), "UNKNOWN_ARES_ERROR");
338 MakeCallback(env()->oncomplete_string(), 1, &arg);
341 // Subclasses should implement the appropriate Parse method.
342 virtual void Parse(unsigned char* buf, int len) {
346 virtual void Parse(struct hostent* host) {
352 class QueryAWrap: public QueryWrap {
354 QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
355 : QueryWrap(env, req_wrap_obj) {
358 int Send(const char* name) {
359 ares_query(env()->cares_channel(),
369 void Parse(unsigned char* buf, int len) {
370 HandleScope handle_scope(env()->isolate());
371 Context::Scope context_scope(env()->context());
373 struct hostent* host;
375 int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
376 if (status != ARES_SUCCESS) {
381 Local<Array> addresses = HostentToAddresses(env(), host);
382 ares_free_hostent(host);
384 this->CallOnComplete(addresses);
389 class QueryAaaaWrap: public QueryWrap {
391 QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
392 : QueryWrap(env, req_wrap_obj) {
395 int Send(const char* name) {
396 ares_query(env()->cares_channel(),
406 void Parse(unsigned char* buf, int len) {
407 HandleScope handle_scope(env()->isolate());
408 Context::Scope context_scope(env()->context());
410 struct hostent* host;
412 int status = ares_parse_aaaa_reply(buf, len, &host, NULL, NULL);
413 if (status != ARES_SUCCESS) {
418 Local<Array> addresses = HostentToAddresses(env(), host);
419 ares_free_hostent(host);
421 this->CallOnComplete(addresses);
426 class QueryCnameWrap: public QueryWrap {
428 QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
429 : QueryWrap(env, req_wrap_obj) {
432 int Send(const char* name) {
433 ares_query(env()->cares_channel(),
443 void Parse(unsigned char* buf, int len) {
444 HandleScope handle_scope(env()->isolate());
445 Context::Scope context_scope(env()->context());
446 struct hostent* host;
448 int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
449 if (status != ARES_SUCCESS) {
454 // A cname lookup always returns a single record but we follow the
456 Local<Array> result = Array::New(env()->isolate(), 1);
457 result->Set(0, OneByteString(env()->isolate(), host->h_name));
458 ares_free_hostent(host);
460 this->CallOnComplete(result);
465 class QueryMxWrap: public QueryWrap {
467 QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
468 : QueryWrap(env, req_wrap_obj) {
471 int Send(const char* name) {
472 ares_query(env()->cares_channel(),
482 void Parse(unsigned char* buf, int len) {
483 HandleScope handle_scope(env()->isolate());
484 Context::Scope context_scope(env()->context());
486 struct ares_mx_reply* mx_start;
487 int status = ares_parse_mx_reply(buf, len, &mx_start);
488 if (status != ARES_SUCCESS) {
493 Local<Array> mx_records = Array::New(env()->isolate());
494 Local<String> exchange_symbol = env()->exchange_string();
495 Local<String> priority_symbol = env()->priority_string();
497 ares_mx_reply* current = mx_start;
498 for (uint32_t i = 0; current != NULL; ++i, current = current->next) {
499 Local<Object> mx_record = Object::New(env()->isolate());
500 mx_record->Set(exchange_symbol,
501 OneByteString(env()->isolate(), current->host));
502 mx_record->Set(priority_symbol,
503 Integer::New(env()->isolate(), current->priority));
504 mx_records->Set(i, mx_record);
507 ares_free_data(mx_start);
509 this->CallOnComplete(mx_records);
514 class QueryNsWrap: public QueryWrap {
516 QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
517 : QueryWrap(env, req_wrap_obj) {
520 int Send(const char* name) {
521 ares_query(env()->cares_channel(),
531 void Parse(unsigned char* buf, int len) {
532 HandleScope handle_scope(env()->isolate());
533 Context::Scope context_scope(env()->context());
534 struct hostent* host;
536 int status = ares_parse_ns_reply(buf, len, &host);
537 if (status != ARES_SUCCESS) {
542 Local<Array> names = HostentToNames(env(), host);
543 ares_free_hostent(host);
545 this->CallOnComplete(names);
550 class QueryTxtWrap: public QueryWrap {
552 QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
553 : QueryWrap(env, req_wrap_obj) {
556 int Send(const char* name) {
557 ares_query(env()->cares_channel(),
567 void Parse(unsigned char* buf, int len) {
568 HandleScope handle_scope(env()->isolate());
569 Context::Scope context_scope(env()->context());
570 struct ares_txt_reply* txt_out;
572 int status = ares_parse_txt_reply(buf, len, &txt_out);
573 if (status != ARES_SUCCESS) {
578 Local<Array> txt_records = Array::New(env()->isolate());
580 ares_txt_reply* current = txt_out;
581 for (uint32_t i = 0; current != NULL; ++i, current = current->next) {
582 Local<String> txt = OneByteString(env()->isolate(), current->txt);
583 txt_records->Set(i, txt);
586 ares_free_data(txt_out);
588 this->CallOnComplete(txt_records);
593 class QuerySrvWrap: public QueryWrap {
595 explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
596 : QueryWrap(env, req_wrap_obj) {
599 int Send(const char* name) {
600 ares_query(env()->cares_channel(),
610 void Parse(unsigned char* buf, int len) {
611 HandleScope handle_scope(env()->isolate());
612 Context::Scope context_scope(env()->context());
614 struct ares_srv_reply* srv_start;
615 int status = ares_parse_srv_reply(buf, len, &srv_start);
616 if (status != ARES_SUCCESS) {
621 Local<Array> srv_records = Array::New(env()->isolate());
622 Local<String> name_symbol = env()->name_string();
623 Local<String> port_symbol = env()->port_string();
624 Local<String> priority_symbol = env()->priority_string();
625 Local<String> weight_symbol = env()->weight_string();
627 ares_srv_reply* current = srv_start;
628 for (uint32_t i = 0; current != NULL; ++i, current = current->next) {
629 Local<Object> srv_record = Object::New(env()->isolate());
630 srv_record->Set(name_symbol,
631 OneByteString(env()->isolate(), current->host));
632 srv_record->Set(port_symbol,
633 Integer::New(env()->isolate(), current->port));
634 srv_record->Set(priority_symbol,
635 Integer::New(env()->isolate(), current->priority));
636 srv_record->Set(weight_symbol,
637 Integer::New(env()->isolate(), current->weight));
638 srv_records->Set(i, srv_record);
641 ares_free_data(srv_start);
643 this->CallOnComplete(srv_records);
647 class QueryNaptrWrap: public QueryWrap {
649 explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
650 : QueryWrap(env, req_wrap_obj) {
653 int Send(const char* name) {
654 ares_query(env()->cares_channel(),
664 void Parse(unsigned char* buf, int len) {
665 HandleScope handle_scope(env()->isolate());
666 Context::Scope context_scope(env()->context());
668 ares_naptr_reply* naptr_start;
669 int status = ares_parse_naptr_reply(buf, len, &naptr_start);
671 if (status != ARES_SUCCESS) {
676 Local<Array> naptr_records = Array::New(env()->isolate());
677 Local<String> flags_symbol = env()->flags_string();
678 Local<String> service_symbol = env()->service_string();
679 Local<String> regexp_symbol = env()->regexp_string();
680 Local<String> replacement_symbol = env()->replacement_string();
681 Local<String> order_symbol = env()->order_string();
682 Local<String> preference_symbol = env()->preference_string();
684 ares_naptr_reply* current = naptr_start;
685 for (uint32_t i = 0; current != NULL; ++i, current = current->next) {
686 Local<Object> naptr_record = Object::New(env()->isolate());
687 naptr_record->Set(flags_symbol,
688 OneByteString(env()->isolate(), current->flags));
689 naptr_record->Set(service_symbol,
690 OneByteString(env()->isolate(), current->service));
691 naptr_record->Set(regexp_symbol,
692 OneByteString(env()->isolate(), current->regexp));
693 naptr_record->Set(replacement_symbol,
694 OneByteString(env()->isolate(), current->replacement));
695 naptr_record->Set(order_symbol,
696 Integer::New(env()->isolate(), current->order));
697 naptr_record->Set(preference_symbol,
698 Integer::New(env()->isolate(), current->preference));
699 naptr_records->Set(i, naptr_record);
702 ares_free_data(naptr_start);
704 this->CallOnComplete(naptr_records);
709 class QuerySoaWrap: public QueryWrap {
711 QuerySoaWrap(Environment* env, Local<Object> req_wrap_obj)
712 : QueryWrap(env, req_wrap_obj) {
715 int Send(const char* name) {
716 ares_query(env()->cares_channel(),
726 void Parse(unsigned char* buf, int len) {
727 HandleScope handle_scope(env()->isolate());
728 Context::Scope context_scope(env()->context());
730 ares_soa_reply* soa_out;
731 int status = ares_parse_soa_reply(buf, len, &soa_out);
733 if (status != ARES_SUCCESS) {
738 Local<Object> soa_record = Object::New(env()->isolate());
740 soa_record->Set(env()->nsname_string(),
741 OneByteString(env()->isolate(), soa_out->nsname));
742 soa_record->Set(env()->hostmaster_string(),
743 OneByteString(env()->isolate(), soa_out->hostmaster));
744 soa_record->Set(env()->serial_string(),
745 Integer::New(env()->isolate(), soa_out->serial));
746 soa_record->Set(env()->refresh_string(),
747 Integer::New(env()->isolate(), soa_out->refresh));
748 soa_record->Set(env()->retry_string(),
749 Integer::New(env()->isolate(), soa_out->retry));
750 soa_record->Set(env()->expire_string(),
751 Integer::New(env()->isolate(), soa_out->expire));
752 soa_record->Set(env()->minttl_string(),
753 Integer::New(env()->isolate(), soa_out->minttl));
755 ares_free_data(soa_out);
757 this->CallOnComplete(soa_record);
762 class GetHostByAddrWrap: public QueryWrap {
764 explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
765 : QueryWrap(env, req_wrap_obj) {
768 int Send(const char* name) {
770 char address_buffer[sizeof(struct in6_addr)];
772 if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) {
773 length = sizeof(struct in_addr);
775 } else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) {
776 length = sizeof(struct in6_addr);
779 return UV_EINVAL; // So errnoException() reports a proper error.
782 ares_gethostbyaddr(env()->cares_channel(),
792 void Parse(struct hostent* host) {
793 HandleScope handle_scope(env()->isolate());
794 Context::Scope context_scope(env()->context());
795 this->CallOnComplete(HostentToNames(env(), host));
800 class GetHostByNameWrap: public QueryWrap {
802 explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
803 : QueryWrap(env, req_wrap_obj) {
806 int Send(const char* name, int family) {
807 ares_gethostbyname(env()->cares_channel(),
816 void Parse(struct hostent* host) {
817 HandleScope scope(env()->isolate());
819 Local<Array> addresses = HostentToAddresses(env(), host);
820 Local<Integer> family = Integer::New(env()->isolate(), host->h_addrtype);
822 this->CallOnComplete(addresses, family);
827 template <class Wrap>
828 static void Query(const FunctionCallbackInfo<Value>& args) {
829 HandleScope handle_scope(args.GetIsolate());
830 Environment* env = Environment::GetCurrent(args.GetIsolate());
832 assert(!args.IsConstructCall());
833 assert(args[0]->IsObject());
834 assert(args[1]->IsString());
836 Local<Object> req_wrap_obj = args[0].As<Object>();
837 Local<String> string = args[1].As<String>();
838 Wrap* wrap = new Wrap(env, req_wrap_obj);
840 String::Utf8Value name(string);
841 int err = wrap->Send(*name);
845 args.GetReturnValue().Set(err);
849 void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
850 GetAddrInfoReqWrap* req_wrap = static_cast<GetAddrInfoReqWrap*>(req->data);
851 Environment* env = req_wrap->env();
853 HandleScope handle_scope(env->isolate());
854 Context::Scope context_scope(env->context());
856 Local<Value> argv[] = {
857 Integer::New(env->isolate(), status),
863 struct addrinfo *address;
866 // Count the number of responses.
867 for (address = res; address; address = address->ai_next) {
871 // Create the response array.
872 Local<Array> results = Array::New(env->isolate(), n);
874 char ip[INET6_ADDRSTRLEN];
879 // Iterate over the IPv4 responses again this time creating javascript
880 // strings for each IP and filling the results array.
883 assert(address->ai_socktype == SOCK_STREAM);
885 // Ignore random ai_family types.
886 if (address->ai_family == AF_INET) {
888 addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in*>(
889 address->ai_addr)->sin_addr));
890 int err = uv_inet_ntop(address->ai_family,
897 // Create JavaScript string
898 Local<String> s = OneByteString(env->isolate(), ip);
904 address = address->ai_next;
907 // Iterate over the IPv6 responses putting them in the array.
910 assert(address->ai_socktype == SOCK_STREAM);
912 // Ignore random ai_family types.
913 if (address->ai_family == AF_INET6) {
915 addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in6*>(
916 address->ai_addr)->sin6_addr));
917 int err = uv_inet_ntop(address->ai_family,
924 // Create JavaScript string
925 Local<String> s = OneByteString(env->isolate(), ip);
931 address = address->ai_next;
938 uv_freeaddrinfo(res);
940 // Make the callback into JavaScript
941 req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
947 static void IsIP(const FunctionCallbackInfo<Value>& args) {
948 Environment* env = Environment::GetCurrent(args.GetIsolate());
949 HandleScope scope(env->isolate());
951 String::Utf8Value ip(args[0]);
952 char address_buffer[sizeof(struct in6_addr)];
955 if (uv_inet_pton(AF_INET, *ip, &address_buffer) == 0)
957 else if (uv_inet_pton(AF_INET6, *ip, &address_buffer) == 0)
960 args.GetReturnValue().Set(rc);
964 static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
965 HandleScope handle_scope(args.GetIsolate());
966 Environment* env = Environment::GetCurrent(args.GetIsolate());
968 assert(args[0]->IsObject());
969 assert(args[1]->IsString());
970 assert(args[2]->IsInt32());
971 Local<Object> req_wrap_obj = args[0].As<Object>();
972 String::Utf8Value hostname(args[1]);
975 switch (args[2]->Int32Value()) {
986 assert(0 && "bad address family");
990 GetAddrInfoReqWrap* req_wrap =
991 new GetAddrInfoReqWrap(env,
993 AsyncWrap::PROVIDER_GETADDRINFOREQWRAP);
995 struct addrinfo hints;
996 memset(&hints, 0, sizeof(struct addrinfo));
997 hints.ai_family = family;
998 hints.ai_socktype = SOCK_STREAM;
1000 int err = uv_getaddrinfo(env->event_loop(),
1006 req_wrap->Dispatched();
1010 args.GetReturnValue().Set(err);
1014 static void GetServers(const FunctionCallbackInfo<Value>& args) {
1015 HandleScope handle_scope(args.GetIsolate());
1016 Environment* env = Environment::GetCurrent(args.GetIsolate());
1018 Local<Array> server_array = Array::New(env->isolate());
1020 ares_addr_node* servers;
1022 int r = ares_get_servers(env->cares_channel(), &servers);
1023 assert(r == ARES_SUCCESS);
1025 ares_addr_node* cur = servers;
1027 for (uint32_t i = 0; cur != NULL; ++i, cur = cur->next) {
1028 char ip[INET6_ADDRSTRLEN];
1030 const void* caddr = static_cast<const void*>(&cur->addr);
1031 int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
1034 Local<String> addr = OneByteString(env->isolate(), ip);
1035 server_array->Set(i, addr);
1038 ares_free_data(servers);
1040 args.GetReturnValue().Set(server_array);
1044 static void SetServers(const FunctionCallbackInfo<Value>& args) {
1045 HandleScope handle_scope(args.GetIsolate());
1046 Environment* env = Environment::GetCurrent(args.GetIsolate());
1048 assert(args[0]->IsArray());
1050 Local<Array> arr = Local<Array>::Cast(args[0]);
1052 uint32_t len = arr->Length();
1055 int rv = ares_set_servers(env->cares_channel(), NULL);
1056 return args.GetReturnValue().Set(rv);
1059 ares_addr_node* servers = new ares_addr_node[len];
1060 ares_addr_node* last = NULL;
1064 for (uint32_t i = 0; i < len; i++) {
1065 assert(arr->Get(i)->IsArray());
1067 Local<Array> elm = Local<Array>::Cast(arr->Get(i));
1069 assert(elm->Get(0)->Int32Value());
1070 assert(elm->Get(1)->IsString());
1072 int fam = elm->Get(0)->Int32Value();
1073 String::Utf8Value ip(elm->Get(1));
1075 ares_addr_node* cur = &servers[i];
1079 cur->family = AF_INET;
1080 err = uv_inet_pton(AF_INET, *ip, &cur->addr);
1083 cur->family = AF_INET6;
1084 err = uv_inet_pton(AF_INET6, *ip, &cur->addr);
1087 assert(0 && "Bad address family.");
1103 err = ares_set_servers(env->cares_channel(), &servers[0]);
1109 args.GetReturnValue().Set(err);
1113 static void StrError(const FunctionCallbackInfo<Value>& args) {
1114 Environment* env = Environment::GetCurrent(args.GetIsolate());
1115 HandleScope scope(env->isolate());
1116 const char* errmsg = ares_strerror(args[0]->Int32Value());
1117 args.GetReturnValue().Set(OneByteString(env->isolate(), errmsg));
1121 static void Initialize(Handle<Object> target,
1122 Handle<Value> unused,
1123 Handle<Context> context) {
1124 Environment* env = Environment::GetCurrent(context);
1126 int r = ares_library_init(ARES_LIB_INIT_ALL);
1127 assert(r == ARES_SUCCESS);
1129 struct ares_options options;
1130 memset(&options, 0, sizeof(options));
1131 options.flags = ARES_FLAG_NOCHECKRESP;
1132 options.sock_state_cb = ares_sockstate_cb;
1133 options.sock_state_cb_data = env;
1135 /* We do the call to ares_init_option for caller. */
1136 r = ares_init_options(env->cares_channel_ptr(),
1138 ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
1139 assert(r == ARES_SUCCESS);
1141 /* Initialize the timeout timer. The timer won't be started until the */
1142 /* first socket is opened. */
1143 uv_timer_init(env->event_loop(), env->cares_timer_handle());
1145 NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
1146 NODE_SET_METHOD(target, "queryAaaa", Query<QueryAaaaWrap>);
1147 NODE_SET_METHOD(target, "queryCname", Query<QueryCnameWrap>);
1148 NODE_SET_METHOD(target, "queryMx", Query<QueryMxWrap>);
1149 NODE_SET_METHOD(target, "queryNs", Query<QueryNsWrap>);
1150 NODE_SET_METHOD(target, "queryTxt", Query<QueryTxtWrap>);
1151 NODE_SET_METHOD(target, "querySrv", Query<QuerySrvWrap>);
1152 NODE_SET_METHOD(target, "queryNaptr", Query<QueryNaptrWrap>);
1153 NODE_SET_METHOD(target, "querySoa", Query<QuerySoaWrap>);
1154 NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>);
1156 NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
1157 NODE_SET_METHOD(target, "isIP", IsIP);
1159 NODE_SET_METHOD(target, "strerror", StrError);
1160 NODE_SET_METHOD(target, "getServers", GetServers);
1161 NODE_SET_METHOD(target, "setServers", SetServers);
1163 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"),
1164 Integer::New(env->isolate(), AF_INET));
1165 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"),
1166 Integer::New(env->isolate(), AF_INET6));
1167 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_UNSPEC"),
1168 Integer::New(env->isolate(), AF_UNSPEC));
1171 } // namespace cares_wrap
1174 NODE_MODULE_CONTEXT_AWARE_BUILTIN(cares_wrap, node::cares_wrap::Initialize)