src: deduplicate CHECK_EQ/CHECK_NE macros
[platform/upstream/nodejs.git] / src / cares_wrap.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
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.
21
22 #define CARES_STATICLIB
23 #include "ares.h"
24 #include "async-wrap.h"
25 #include "async-wrap-inl.h"
26 #include "env.h"
27 #include "env-inl.h"
28 #include "node.h"
29 #include "req_wrap.h"
30 #include "tree.h"
31 #include "uv.h"
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #if defined(__ANDROID__) || \
39     defined(__MINGW32__) || \
40     defined(__OpenBSD__) || \
41     defined(_MSC_VER)
42 # include <nameser.h>
43 #else
44 # include <arpa/nameser.h>
45 #endif
46
47
48 namespace node {
49 namespace cares_wrap {
50
51 using v8::Array;
52 using v8::Context;
53 using v8::EscapableHandleScope;
54 using v8::Function;
55 using v8::FunctionCallbackInfo;
56 using v8::Handle;
57 using v8::HandleScope;
58 using v8::Integer;
59 using v8::Local;
60 using v8::Null;
61 using v8::Object;
62 using v8::String;
63 using v8::Value;
64
65 typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
66
67
68 static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
69   if (a->sock < b->sock)
70     return -1;
71   if (a->sock > b->sock)
72     return 1;
73   return 0;
74 }
75
76
77 RB_GENERATE_STATIC(ares_task_list, ares_task_t, node, cmp_ares_tasks)
78
79
80
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);
87 }
88
89
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;
93
94   /* Reset the idle timer */
95   uv_timer_again(env->cares_timer_handle());
96
97   if (status < 0) {
98     /* An error happened. Just pretend that the socket is both readable and */
99     /* writable. */
100     ares_process_fd(env->cares_channel(), task->sock, task->sock);
101     return;
102   }
103
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);
108 }
109
110
111 static void ares_poll_close_cb(uv_handle_t* watcher) {
112   ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher);
113   free(task);
114 }
115
116
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)));
120
121   if (task == NULL) {
122     /* Out of memory. */
123     return NULL;
124   }
125
126   task->env = env;
127   task->sock = sock;
128
129   if (uv_poll_init_socket(env->event_loop(), &task->poll_watcher, sock) < 0) {
130     /* This should never happen. */
131     free(task);
132     return NULL;
133   }
134
135   return task;
136 }
137
138
139 /* Callback from ares when socket operation is started */
140 static void ares_sockstate_cb(void* data,
141                               ares_socket_t sock,
142                               int read,
143                               int write) {
144   Environment* env = static_cast<Environment*>(data);
145   ares_task_t* task;
146
147   ares_task_t lookup_task;
148   lookup_task.sock = sock;
149   task = RB_FIND(ares_task_list, env->cares_task_list(), &lookup_task);
150
151   if (read || write) {
152     if (!task) {
153       /* New socket */
154
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);
160       }
161
162       task = ares_task_create(env, sock);
163       if (task == NULL) {
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. */
167         return;
168       }
169
170       RB_INSERT(ares_task_list, env->cares_task_list(), task);
171     }
172
173     /* This should never fail. If it fails anyway, the query will eventually */
174     /* time out. */
175     uv_poll_start(&task->poll_watcher,
176                   (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
177                   ares_poll_cb);
178
179   } else {
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 */
182     /* socket. */
183     assert(task &&
184            "When an ares socket is closed we should have a handle for it");
185
186     RB_REMOVE(ares_task_list, env->cares_task_list(), task);
187     uv_close(reinterpret_cast<uv_handle_t*>(&task->poll_watcher),
188              ares_poll_close_cb);
189
190     if (RB_EMPTY(env->cares_task_list())) {
191       uv_timer_stop(env->cares_timer_handle());
192     }
193   }
194 }
195
196
197 static Local<Array> HostentToAddresses(Environment* env, struct hostent* host) {
198   EscapableHandleScope scope(env->isolate());
199   Local<Array> addresses = Array::New(env->isolate());
200
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);
206   }
207
208   return scope.Escape(addresses);
209 }
210
211
212 static Local<Array> HostentToNames(Environment* env, struct hostent* host) {
213   EscapableHandleScope scope(env->isolate());
214   Local<Array> names = Array::New(env->isolate());
215
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);
219   }
220
221   return scope.Escape(names);
222 }
223
224
225 class QueryWrap : public AsyncWrap {
226  public:
227   QueryWrap(Environment* env, Local<Object> req_wrap_obj)
228       : AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_CARES) {
229   }
230
231   virtual ~QueryWrap() {
232     assert(!persistent().IsEmpty());
233     persistent().Reset();
234   }
235
236   // Subclasses should implement the appropriate Send method.
237   virtual int Send(const char* name) {
238     assert(0);
239     return 0;
240   }
241
242   virtual int Send(const char* name, int family) {
243     assert(0);
244     return 0;
245   }
246
247  protected:
248   void* GetQueryArg() {
249     return static_cast<void*>(this);
250   }
251
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);
255
256     if (status != ARES_SUCCESS) {
257       wrap->ParseError(status);
258     } else {
259       wrap->Parse(answer_buf, answer_len);
260     }
261
262     delete wrap;
263   }
264
265   static void Callback(void *arg, int status, int timeouts,
266       struct hostent* host) {
267     QueryWrap* wrap = static_cast<QueryWrap*>(arg);
268
269     if (status != ARES_SUCCESS) {
270       wrap->ParseError(status);
271     } else {
272       wrap->Parse(host);
273     }
274
275     delete wrap;
276   }
277
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),
283       answer
284     };
285     MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
286   }
287
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),
293       answer,
294       family
295     };
296     MakeCallback(env()->oncomplete_string(), ARRAY_SIZE(argv), argv);
297   }
298
299   void ParseError(int status) {
300     assert(status != ARES_SUCCESS);
301     HandleScope handle_scope(env()->isolate());
302     Context::Scope context_scope(env()->context());
303     Local<Value> arg;
304     switch (status) {
305 #define V(code)                                                               \
306       case ARES_ ## code:                                                     \
307         arg = FIXED_ONE_BYTE_STRING(env()->isolate(), #code);                 \
308         break;
309       V(ENODATA)
310       V(EFORMERR)
311       V(ESERVFAIL)
312       V(ENOTFOUND)
313       V(ENOTIMP)
314       V(EREFUSED)
315       V(EBADQUERY)
316       V(EBADNAME)
317       V(EBADFAMILY)
318       V(EBADRESP)
319       V(ECONNREFUSED)
320       V(ETIMEOUT)
321       V(EOF)
322       V(EFILE)
323       V(ENOMEM)
324       V(EDESTRUCTION)
325       V(EBADSTR)
326       V(EBADFLAGS)
327       V(ENONAME)
328       V(EBADHINTS)
329       V(ENOTINITIALIZED)
330       V(ELOADIPHLPAPI)
331       V(EADDRGETNETWORKPARAMS)
332       V(ECANCELLED)
333 #undef V
334       default:
335         arg = FIXED_ONE_BYTE_STRING(env()->isolate(), "UNKNOWN_ARES_ERROR");
336         break;
337     }
338     MakeCallback(env()->oncomplete_string(), 1, &arg);
339   }
340
341   // Subclasses should implement the appropriate Parse method.
342   virtual void Parse(unsigned char* buf, int len) {
343     assert(0);
344   };
345
346   virtual void Parse(struct hostent* host) {
347     assert(0);
348   };
349 };
350
351
352 class QueryAWrap: public QueryWrap {
353  public:
354   QueryAWrap(Environment* env, Local<Object> req_wrap_obj)
355       : QueryWrap(env, req_wrap_obj) {
356   }
357
358   int Send(const char* name) {
359     ares_query(env()->cares_channel(),
360                name,
361                ns_c_in,
362                ns_t_a,
363                Callback,
364                GetQueryArg());
365     return 0;
366   }
367
368  protected:
369   void Parse(unsigned char* buf, int len) {
370     HandleScope handle_scope(env()->isolate());
371     Context::Scope context_scope(env()->context());
372
373     struct hostent* host;
374
375     int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
376     if (status != ARES_SUCCESS) {
377       ParseError(status);
378       return;
379     }
380
381     Local<Array> addresses = HostentToAddresses(env(), host);
382     ares_free_hostent(host);
383
384     this->CallOnComplete(addresses);
385   }
386 };
387
388
389 class QueryAaaaWrap: public QueryWrap {
390  public:
391   QueryAaaaWrap(Environment* env, Local<Object> req_wrap_obj)
392       : QueryWrap(env, req_wrap_obj) {
393   }
394
395   int Send(const char* name) {
396     ares_query(env()->cares_channel(),
397                name,
398                ns_c_in,
399                ns_t_aaaa,
400                Callback,
401                GetQueryArg());
402     return 0;
403   }
404
405  protected:
406   void Parse(unsigned char* buf, int len) {
407     HandleScope handle_scope(env()->isolate());
408     Context::Scope context_scope(env()->context());
409
410     struct hostent* host;
411
412     int status = ares_parse_aaaa_reply(buf, len, &host, NULL, NULL);
413     if (status != ARES_SUCCESS) {
414       ParseError(status);
415       return;
416     }
417
418     Local<Array> addresses = HostentToAddresses(env(), host);
419     ares_free_hostent(host);
420
421     this->CallOnComplete(addresses);
422   }
423 };
424
425
426 class QueryCnameWrap: public QueryWrap {
427  public:
428   QueryCnameWrap(Environment* env, Local<Object> req_wrap_obj)
429       : QueryWrap(env, req_wrap_obj) {
430   }
431
432   int Send(const char* name) {
433     ares_query(env()->cares_channel(),
434                name,
435                ns_c_in,
436                ns_t_cname,
437                Callback,
438                GetQueryArg());
439     return 0;
440   }
441
442  protected:
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;
447
448     int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
449     if (status != ARES_SUCCESS) {
450       ParseError(status);
451       return;
452     }
453
454     // A cname lookup always returns a single record but we follow the
455     // common API here.
456     Local<Array> result = Array::New(env()->isolate(), 1);
457     result->Set(0, OneByteString(env()->isolate(), host->h_name));
458     ares_free_hostent(host);
459
460     this->CallOnComplete(result);
461   }
462 };
463
464
465 class QueryMxWrap: public QueryWrap {
466  public:
467   QueryMxWrap(Environment* env, Local<Object> req_wrap_obj)
468       : QueryWrap(env, req_wrap_obj) {
469   }
470
471   int Send(const char* name) {
472     ares_query(env()->cares_channel(),
473                name,
474                ns_c_in,
475                ns_t_mx,
476                Callback,
477                GetQueryArg());
478     return 0;
479   }
480
481  protected:
482   void Parse(unsigned char* buf, int len) {
483     HandleScope handle_scope(env()->isolate());
484     Context::Scope context_scope(env()->context());
485
486     struct ares_mx_reply* mx_start;
487     int status = ares_parse_mx_reply(buf, len, &mx_start);
488     if (status != ARES_SUCCESS) {
489       ParseError(status);
490       return;
491     }
492
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();
496
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);
505     }
506
507     ares_free_data(mx_start);
508
509     this->CallOnComplete(mx_records);
510   }
511 };
512
513
514 class QueryNsWrap: public QueryWrap {
515  public:
516   QueryNsWrap(Environment* env, Local<Object> req_wrap_obj)
517       : QueryWrap(env, req_wrap_obj) {
518   }
519
520   int Send(const char* name) {
521     ares_query(env()->cares_channel(),
522                name,
523                ns_c_in,
524                ns_t_ns,
525                Callback,
526                GetQueryArg());
527     return 0;
528   }
529
530  protected:
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;
535
536     int status = ares_parse_ns_reply(buf, len, &host);
537     if (status != ARES_SUCCESS) {
538       ParseError(status);
539       return;
540     }
541
542     Local<Array> names = HostentToNames(env(), host);
543     ares_free_hostent(host);
544
545     this->CallOnComplete(names);
546   }
547 };
548
549
550 class QueryTxtWrap: public QueryWrap {
551  public:
552   QueryTxtWrap(Environment* env, Local<Object> req_wrap_obj)
553       : QueryWrap(env, req_wrap_obj) {
554   }
555
556   int Send(const char* name) {
557     ares_query(env()->cares_channel(),
558                name,
559                ns_c_in,
560                ns_t_txt,
561                Callback,
562                GetQueryArg());
563     return 0;
564   }
565
566  protected:
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;
571
572     int status = ares_parse_txt_reply(buf, len, &txt_out);
573     if (status != ARES_SUCCESS) {
574       ParseError(status);
575       return;
576     }
577
578     Local<Array> txt_records = Array::New(env()->isolate());
579
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);
584     }
585
586     ares_free_data(txt_out);
587
588     this->CallOnComplete(txt_records);
589   }
590 };
591
592
593 class QuerySrvWrap: public QueryWrap {
594  public:
595   explicit QuerySrvWrap(Environment* env, Local<Object> req_wrap_obj)
596       : QueryWrap(env, req_wrap_obj) {
597   }
598
599   int Send(const char* name) {
600     ares_query(env()->cares_channel(),
601                name,
602                ns_c_in,
603                ns_t_srv,
604                Callback,
605                GetQueryArg());
606     return 0;
607   }
608
609  protected:
610   void Parse(unsigned char* buf, int len) {
611     HandleScope handle_scope(env()->isolate());
612     Context::Scope context_scope(env()->context());
613
614     struct ares_srv_reply* srv_start;
615     int status = ares_parse_srv_reply(buf, len, &srv_start);
616     if (status != ARES_SUCCESS) {
617       ParseError(status);
618       return;
619     }
620
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();
626
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);
639     }
640
641     ares_free_data(srv_start);
642
643     this->CallOnComplete(srv_records);
644   }
645 };
646
647 class QueryNaptrWrap: public QueryWrap {
648  public:
649   explicit QueryNaptrWrap(Environment* env, Local<Object> req_wrap_obj)
650       : QueryWrap(env, req_wrap_obj) {
651   }
652
653   int Send(const char* name) {
654     ares_query(env()->cares_channel(),
655                name,
656                ns_c_in,
657                ns_t_naptr,
658                Callback,
659                GetQueryArg());
660     return 0;
661   }
662
663  protected:
664   void Parse(unsigned char* buf, int len) {
665     HandleScope handle_scope(env()->isolate());
666     Context::Scope context_scope(env()->context());
667
668     ares_naptr_reply* naptr_start;
669     int status = ares_parse_naptr_reply(buf, len, &naptr_start);
670
671     if (status != ARES_SUCCESS) {
672       ParseError(status);
673       return;
674     }
675
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();
683
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);
700     }
701
702     ares_free_data(naptr_start);
703
704     this->CallOnComplete(naptr_records);
705   }
706 };
707
708
709 class QuerySoaWrap: public QueryWrap {
710  public:
711   QuerySoaWrap(Environment* env, Local<Object> req_wrap_obj)
712       : QueryWrap(env, req_wrap_obj) {
713   }
714
715   int Send(const char* name) {
716     ares_query(env()->cares_channel(),
717                name,
718                ns_c_in,
719                ns_t_soa,
720                Callback,
721                GetQueryArg());
722     return 0;
723   }
724
725  protected:
726   void Parse(unsigned char* buf, int len) {
727     HandleScope handle_scope(env()->isolate());
728     Context::Scope context_scope(env()->context());
729
730     ares_soa_reply* soa_out;
731     int status = ares_parse_soa_reply(buf, len, &soa_out);
732
733     if (status != ARES_SUCCESS) {
734       ParseError(status);
735       return;
736     }
737
738     Local<Object> soa_record = Object::New(env()->isolate());
739
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));
754
755     ares_free_data(soa_out);
756
757     this->CallOnComplete(soa_record);
758   }
759 };
760
761
762 class GetHostByAddrWrap: public QueryWrap {
763  public:
764   explicit GetHostByAddrWrap(Environment* env, Local<Object> req_wrap_obj)
765       : QueryWrap(env, req_wrap_obj) {
766   }
767
768   int Send(const char* name) {
769     int length, family;
770     char address_buffer[sizeof(struct in6_addr)];
771
772     if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) {
773       length = sizeof(struct in_addr);
774       family = AF_INET;
775     } else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) {
776       length = sizeof(struct in6_addr);
777       family = AF_INET6;
778     } else {
779       return UV_EINVAL;  // So errnoException() reports a proper error.
780     }
781
782     ares_gethostbyaddr(env()->cares_channel(),
783                        address_buffer,
784                        length,
785                        family,
786                        Callback,
787                        GetQueryArg());
788     return 0;
789   }
790
791  protected:
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));
796   }
797 };
798
799
800 class GetHostByNameWrap: public QueryWrap {
801  public:
802   explicit GetHostByNameWrap(Environment* env, Local<Object> req_wrap_obj)
803       : QueryWrap(env, req_wrap_obj) {
804   }
805
806   int Send(const char* name, int family) {
807     ares_gethostbyname(env()->cares_channel(),
808                        name,
809                        family,
810                        Callback,
811                        GetQueryArg());
812     return 0;
813   }
814
815  protected:
816   void Parse(struct hostent* host) {
817     HandleScope scope(env()->isolate());
818
819     Local<Array> addresses = HostentToAddresses(env(), host);
820     Local<Integer> family = Integer::New(env()->isolate(), host->h_addrtype);
821
822     this->CallOnComplete(addresses, family);
823   }
824 };
825
826
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());
831
832   assert(!args.IsConstructCall());
833   assert(args[0]->IsObject());
834   assert(args[1]->IsString());
835
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);
839
840   String::Utf8Value name(string);
841   int err = wrap->Send(*name);
842   if (err)
843     delete wrap;
844
845   args.GetReturnValue().Set(err);
846 }
847
848
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();
852
853   HandleScope handle_scope(env->isolate());
854   Context::Scope context_scope(env->context());
855
856   Local<Value> argv[] = {
857     Integer::New(env->isolate(), status),
858     Null(env->isolate())
859   };
860
861   if (status == 0) {
862     // Success
863     struct addrinfo *address;
864     int n = 0;
865
866     // Count the number of responses.
867     for (address = res; address; address = address->ai_next) {
868       n++;
869     }
870
871     // Create the response array.
872     Local<Array> results = Array::New(env->isolate(), n);
873
874     char ip[INET6_ADDRSTRLEN];
875     const char *addr;
876
877     n = 0;
878
879     // Iterate over the IPv4 responses again this time creating javascript
880     // strings for each IP and filling the results array.
881     address = res;
882     while (address) {
883       assert(address->ai_socktype == SOCK_STREAM);
884
885       // Ignore random ai_family types.
886       if (address->ai_family == AF_INET) {
887         // Juggle pointers
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,
891                                addr,
892                                ip,
893                                INET6_ADDRSTRLEN);
894         if (err)
895           continue;
896
897         // Create JavaScript string
898         Local<String> s = OneByteString(env->isolate(), ip);
899         results->Set(n, s);
900         n++;
901       }
902
903       // Increment
904       address = address->ai_next;
905     }
906
907     // Iterate over the IPv6 responses putting them in the array.
908     address = res;
909     while (address) {
910       assert(address->ai_socktype == SOCK_STREAM);
911
912       // Ignore random ai_family types.
913       if (address->ai_family == AF_INET6) {
914         // Juggle pointers
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,
918                                addr,
919                                ip,
920                                INET6_ADDRSTRLEN);
921         if (err)
922           continue;
923
924         // Create JavaScript string
925         Local<String> s = OneByteString(env->isolate(), ip);
926         results->Set(n, s);
927         n++;
928       }
929
930       // Increment
931       address = address->ai_next;
932     }
933
934
935     argv[1] = results;
936   }
937
938   uv_freeaddrinfo(res);
939
940   // Make the callback into JavaScript
941   req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
942
943   delete req_wrap;
944 }
945
946
947 static void IsIP(const FunctionCallbackInfo<Value>& args) {
948   Environment* env = Environment::GetCurrent(args.GetIsolate());
949   HandleScope scope(env->isolate());
950
951   String::Utf8Value ip(args[0]);
952   char address_buffer[sizeof(struct in6_addr)];
953
954   int rc = 0;
955   if (uv_inet_pton(AF_INET, *ip, &address_buffer) == 0)
956     rc = 4;
957   else if (uv_inet_pton(AF_INET6, *ip, &address_buffer) == 0)
958     rc = 6;
959
960   args.GetReturnValue().Set(rc);
961 }
962
963
964 static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
965   HandleScope handle_scope(args.GetIsolate());
966   Environment* env = Environment::GetCurrent(args.GetIsolate());
967
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]);
973
974   int family;
975   switch (args[2]->Int32Value()) {
976   case 0:
977     family = AF_UNSPEC;
978     break;
979   case 4:
980     family = AF_INET;
981     break;
982   case 6:
983     family = AF_INET6;
984     break;
985   default:
986     assert(0 && "bad address family");
987     abort();
988   }
989
990   GetAddrInfoReqWrap* req_wrap =
991     new GetAddrInfoReqWrap(env,
992                            req_wrap_obj,
993                            AsyncWrap::PROVIDER_GETADDRINFOREQWRAP);
994
995   struct addrinfo hints;
996   memset(&hints, 0, sizeof(struct addrinfo));
997   hints.ai_family = family;
998   hints.ai_socktype = SOCK_STREAM;
999
1000   int err = uv_getaddrinfo(env->event_loop(),
1001                            &req_wrap->req_,
1002                            AfterGetAddrInfo,
1003                            *hostname,
1004                            NULL,
1005                            &hints);
1006   req_wrap->Dispatched();
1007   if (err)
1008     delete req_wrap;
1009
1010   args.GetReturnValue().Set(err);
1011 }
1012
1013
1014 static void GetServers(const FunctionCallbackInfo<Value>& args) {
1015   HandleScope handle_scope(args.GetIsolate());
1016   Environment* env = Environment::GetCurrent(args.GetIsolate());
1017
1018   Local<Array> server_array = Array::New(env->isolate());
1019
1020   ares_addr_node* servers;
1021
1022   int r = ares_get_servers(env->cares_channel(), &servers);
1023   assert(r == ARES_SUCCESS);
1024
1025   ares_addr_node* cur = servers;
1026
1027   for (uint32_t i = 0; cur != NULL; ++i, cur = cur->next) {
1028     char ip[INET6_ADDRSTRLEN];
1029
1030     const void* caddr = static_cast<const void*>(&cur->addr);
1031     int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
1032     assert(err == 0);
1033
1034     Local<String> addr = OneByteString(env->isolate(), ip);
1035     server_array->Set(i, addr);
1036   }
1037
1038   ares_free_data(servers);
1039
1040   args.GetReturnValue().Set(server_array);
1041 }
1042
1043
1044 static void SetServers(const FunctionCallbackInfo<Value>& args) {
1045   HandleScope handle_scope(args.GetIsolate());
1046   Environment* env = Environment::GetCurrent(args.GetIsolate());
1047
1048   assert(args[0]->IsArray());
1049
1050   Local<Array> arr = Local<Array>::Cast(args[0]);
1051
1052   uint32_t len = arr->Length();
1053
1054   if (len == 0) {
1055     int rv = ares_set_servers(env->cares_channel(), NULL);
1056     return args.GetReturnValue().Set(rv);
1057   }
1058
1059   ares_addr_node* servers = new ares_addr_node[len];
1060   ares_addr_node* last = NULL;
1061
1062   int err;
1063
1064   for (uint32_t i = 0; i < len; i++) {
1065     assert(arr->Get(i)->IsArray());
1066
1067     Local<Array> elm = Local<Array>::Cast(arr->Get(i));
1068
1069     assert(elm->Get(0)->Int32Value());
1070     assert(elm->Get(1)->IsString());
1071
1072     int fam = elm->Get(0)->Int32Value();
1073     String::Utf8Value ip(elm->Get(1));
1074
1075     ares_addr_node* cur = &servers[i];
1076
1077     switch (fam) {
1078       case 4:
1079         cur->family = AF_INET;
1080         err = uv_inet_pton(AF_INET, *ip, &cur->addr);
1081         break;
1082       case 6:
1083         cur->family = AF_INET6;
1084         err = uv_inet_pton(AF_INET6, *ip, &cur->addr);
1085         break;
1086       default:
1087         assert(0 && "Bad address family.");
1088         abort();
1089     }
1090
1091     if (err)
1092       break;
1093
1094     cur->next = NULL;
1095
1096     if (last != NULL)
1097       last->next = cur;
1098
1099     last = cur;
1100   }
1101
1102   if (err == 0)
1103     err = ares_set_servers(env->cares_channel(), &servers[0]);
1104   else
1105     err = ARES_EBADSTR;
1106
1107   delete[] servers;
1108
1109   args.GetReturnValue().Set(err);
1110 }
1111
1112
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));
1118 }
1119
1120
1121 static void Initialize(Handle<Object> target,
1122                        Handle<Value> unused,
1123                        Handle<Context> context) {
1124   Environment* env = Environment::GetCurrent(context);
1125
1126   int r = ares_library_init(ARES_LIB_INIT_ALL);
1127   assert(r == ARES_SUCCESS);
1128
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;
1134
1135   /* We do the call to ares_init_option for caller. */
1136   r = ares_init_options(env->cares_channel_ptr(),
1137                         &options,
1138                         ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
1139   assert(r == ARES_SUCCESS);
1140
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());
1144
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>);
1155
1156   NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
1157   NODE_SET_METHOD(target, "isIP", IsIP);
1158
1159   NODE_SET_METHOD(target, "strerror", StrError);
1160   NODE_SET_METHOD(target, "getServers", GetServers);
1161   NODE_SET_METHOD(target, "setServers", SetServers);
1162
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));
1169 }
1170
1171 }  // namespace cares_wrap
1172 }  // namespace node
1173
1174 NODE_MODULE_CONTEXT_AWARE_BUILTIN(cares_wrap, node::cares_wrap::Initialize)