Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 994 lines (777 sloc) 25.961 kb
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
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 #include <assert.h>
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #define CARES_STATICLIB
28 #include "ares.h"
ff4a9d3 @bnoordhuis core: use proper #include directives
bnoordhuis authored
29 #include "node.h"
30 #include "req_wrap.h"
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
31 #include "tree.h"
ff4a9d3 @bnoordhuis core: use proper #include directives
bnoordhuis authored
32 #include "uv.h"
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
33
13d6a1f @DrPizza Basic VC++ compatibility work.
DrPizza authored
34 #if defined(__OpenBSD__) || defined(__MINGW32__) || defined(_MSC_VER)
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
35 # include <nameser.h>
36 #else
37 # include <arpa/nameser.h>
38 #endif
39
40
41 namespace node {
42
43 namespace cares_wrap {
44
45 using v8::Arguments;
46 using v8::Array;
47 using v8::Context;
48 using v8::Function;
49 using v8::Handle;
50 using v8::HandleScope;
51 using v8::Integer;
52 using v8::Local;
53 using v8::Null;
54 using v8::Object;
55 using v8::Persistent;
56 using v8::String;
57 using v8::Value;
58
be2320d @ry Add binding to uv_getaddrinfo
ry authored
59
60 typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
61
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
62 struct ares_task_t {
63 UV_HANDLE_FIELDS
64 ares_socket_t sock;
65 uv_poll_t poll_watcher;
66 RB_ENTRY(ares_task_t) node;
67 };
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
68
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
69
70 static Persistent<String> oncomplete_sym;
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
71 static ares_channel ares_channel;
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
72 static uv_timer_t ares_timer;
73 static RB_HEAD(ares_task_list, ares_task_t) ares_tasks;
74
75
76 static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
77 if (a->sock < b->sock) return -1;
78 if (a->sock > b->sock) return 1;
79 return 0;
80 }
81
82
83 RB_GENERATE_STATIC(ares_task_list, ares_task_t, node, cmp_ares_tasks)
84
85
86
87 /* This is called once per second by loop->timer. It is used to constantly */
88 /* call back into c-ares for possibly processing timeouts. */
89 static void ares_timeout(uv_timer_t* handle, int status) {
90 assert(!RB_EMPTY(&ares_tasks));
91 ares_process_fd(ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
92 }
93
94
95 static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
96 ares_task_t* task = container_of(watcher, ares_task_t, poll_watcher);
97
98 /* Reset the idle timer */
99 uv_timer_again(&ares_timer);
100
101 if (status < 0) {
102 /* An error happened. Just pretend that the socket is both readable and */
103 /* writable. */
104 ares_process_fd(ares_channel, task->sock, task->sock);
105 return;
106 }
107
108 /* Process DNS responses */
109 ares_process_fd(ares_channel,
110 events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
111 events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
112 }
113
114
115 static void ares_poll_close_cb(uv_handle_t* watcher) {
116 ares_task_t* task = container_of(watcher, ares_task_t, poll_watcher);
117 free(task);
118 }
119
120
121 /* Allocates and returns a new ares_task_t */
122 static ares_task_t* ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
123 ares_task_t* task = (ares_task_t*) malloc(sizeof *task);
124
125 if (task == NULL) {
126 /* Out of memory. */
127 return NULL;
128 }
129
130 task->loop = loop;
131 task->sock = sock;
132
133 if (uv_poll_init_socket(loop, &task->poll_watcher, sock) < 0) {
134 /* This should never happen. */
135 free(task);
136 return NULL;
137 }
138
139 return task;
140 }
141
142
143 /* Callback from ares when socket operation is started */
144 static void ares_sockstate_cb(void* data, ares_socket_t sock,
145 int read, int write) {
146 uv_loop_t* loop = (uv_loop_t*) data;
147 ares_task_t* task;
148
149 ares_task_t lookup_task;
150 lookup_task.sock = sock;
151 task = RB_FIND(ares_task_list, &ares_tasks, &lookup_task);
152
153 if (read || write) {
154 if (!task) {
155 /* New socket */
156
157 /* If this is the first socket then start the timer. */
158 if (!uv_is_active((uv_handle_t*) &ares_timer)) {
159 assert(RB_EMPTY(&ares_tasks));
160 uv_timer_start(&ares_timer, ares_timeout, 1000, 1000);
161 }
162
163 task = ares_task_create(loop, sock);
164 if (task == NULL) {
165 /* This should never happen unless we're out of memory or something */
166 /* is seriously wrong. The socket won't be polled, but the the query */
167 /* will eventually time out. */
168 return;
169 }
170
171 RB_INSERT(ares_task_list, &ares_tasks, task);
172 }
173
174 /* This should never fail. If it fails anyway, the query will eventually */
175 /* time out. */
176 uv_poll_start(&task->poll_watcher,
177 (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
178 ares_poll_cb);
179
180 } else {
181 /* read == 0 and write == 0 this is c-ares's way of notifying us that */
182 /* the socket is now closed. We must free the data associated with */
183 /* socket. */
184 assert(task &&
185 "When an ares socket is closed we should have a handle for it");
186
187 RB_REMOVE(ares_task_list, &ares_tasks, task);
188 uv_close((uv_handle_t*) &task->poll_watcher, ares_poll_close_cb);
189
190 if (RB_EMPTY(&ares_tasks)) {
191 uv_timer_stop(&ares_timer);
192 }
193 }
194 }
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
195
196
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
197 static Local<Array> HostentToAddresses(struct hostent* host) {
198 HandleScope scope;
199 Local<Array> addresses = Array::New();
200
201 char ip[INET6_ADDRSTRLEN];
202 for (int i = 0; host->h_addr_list[i]; ++i) {
203 uv_inet_ntop(host->h_addrtype, host->h_addr_list[i], ip, sizeof(ip));
204
205 Local<String> address = String::New(ip);
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
206 addresses->Set(Integer::New(i), address);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
207 }
208
209 return scope.Close(addresses);
210 }
211
212
213 static Local<Array> HostentToNames(struct hostent* host) {
214 HandleScope scope;
215 Local<Array> names = Array::New();
216
217 for (int i = 0; host->h_aliases[i]; ++i) {
218 Local<String> address = String::New(host->h_aliases[i]);
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
219 names->Set(Integer::New(i), address);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
220 }
221
222 return scope.Close(names);
223 }
224
225
226 static const char* AresErrnoString(int errorno) {
227 switch (errorno) {
228 #define ERRNO_CASE(e) case ARES_##e: return #e;
229 ERRNO_CASE(SUCCESS)
230 ERRNO_CASE(ENODATA)
231 ERRNO_CASE(EFORMERR)
232 ERRNO_CASE(ESERVFAIL)
233 ERRNO_CASE(ENOTFOUND)
234 ERRNO_CASE(ENOTIMP)
235 ERRNO_CASE(EREFUSED)
236 ERRNO_CASE(EBADQUERY)
237 ERRNO_CASE(EBADNAME)
238 ERRNO_CASE(EBADFAMILY)
239 ERRNO_CASE(EBADRESP)
240 ERRNO_CASE(ECONNREFUSED)
241 ERRNO_CASE(ETIMEOUT)
242 ERRNO_CASE(EOF)
243 ERRNO_CASE(EFILE)
244 ERRNO_CASE(ENOMEM)
245 ERRNO_CASE(EDESTRUCTION)
246 ERRNO_CASE(EBADSTR)
247 ERRNO_CASE(EBADFLAGS)
248 ERRNO_CASE(ENONAME)
249 ERRNO_CASE(EBADHINTS)
250 ERRNO_CASE(ENOTINITIALIZED)
251 ERRNO_CASE(ELOADIPHLPAPI)
252 ERRNO_CASE(EADDRGETNETWORKPARAMS)
253 ERRNO_CASE(ECANCELLED)
254 #undef ERRNO_CASE
255 default:
256 assert(0 && "Unhandled c-ares error");
257 return "(UNKNOWN)";
258 }
259 }
260
261
262 static void SetAresErrno(int errorno) {
263 HandleScope scope;
74784b6 @isaacs cares: Set process._errno, not global.errno
isaacs authored
264 Local<Value> key = String::NewSymbol("_errno");
265 Local<Value> value = String::NewSymbol(AresErrnoString(errorno));
266 node::process->Set(key, value);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
267 }
268
269
270 class QueryWrap {
271 public:
272 QueryWrap() {
273 HandleScope scope;
274
275 object_ = Persistent<Object>::New(Object::New());
276 }
277
f1d3ae7 @bnoordhuis cares_wrap: make destructor virtual
bnoordhuis authored
278 virtual ~QueryWrap() {
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
279 assert(!object_.IsEmpty());
280
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
281 object_->Delete(oncomplete_sym);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
282
283 object_.Dispose();
284 object_.Clear();
285 }
286
287 Handle<Object> GetObject() {
288 return object_;
289 }
290
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
291 void SetOnComplete(Handle<Value> oncomplete) {
292 assert(oncomplete->IsFunction());
293 object_->Set(oncomplete_sym, oncomplete);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
294 }
295
296 // Subclasses should implement the appropriate Send method.
297 virtual int Send(const char* name) {
298 assert(0);
13d6a1f @DrPizza Basic VC++ compatibility work.
DrPizza authored
299 return 0;
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
300 }
301
302 virtual int Send(const char* name, int family) {
303 assert(0);
13d6a1f @DrPizza Basic VC++ compatibility work.
DrPizza authored
304 return 0;
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
305 }
306
307 protected:
308 void* GetQueryArg() {
309 return static_cast<void*>(this);
310 }
311
312 static void Callback(void *arg, int status, int timeouts,
313 unsigned char* answer_buf, int answer_len) {
5664dd2 @bnoordhuis src: use static_cast where appropriate
bnoordhuis authored
314 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
315
316 if (status != ARES_SUCCESS) {
317 wrap->ParseError(status);
318 } else {
319 wrap->Parse(answer_buf, answer_len);
320 }
321
322 delete wrap;
323 }
324
325 static void Callback(void *arg, int status, int timeouts,
326 struct hostent* host) {
5664dd2 @bnoordhuis src: use static_cast where appropriate
bnoordhuis authored
327 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
328
329 if (status != ARES_SUCCESS) {
330 wrap->ParseError(status);
331 } else {
332 wrap->Parse(host);
333 }
334
335 delete wrap;
336 }
337
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
338 void CallOnComplete(Local<Value> answer) {
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
339 HandleScope scope;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
340 Local<Value> argv[2] = { Integer::New(0), answer };
a26bee8 @isaacs MakeCallback: Consistent symbol usage
isaacs authored
341 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
342 }
343
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
344 void CallOnComplete(Local<Value> answer, Local<Value> family) {
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
345 HandleScope scope;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
346 Local<Value> argv[3] = { Integer::New(0), answer, family };
a26bee8 @isaacs MakeCallback: Consistent symbol usage
isaacs authored
347 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
348 }
349
350 void ParseError(int status) {
351 assert(status != ARES_SUCCESS);
352 SetAresErrno(status);
353
354 HandleScope scope;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
355 Local<Value> argv[1] = { Integer::New(-1) };
a26bee8 @isaacs MakeCallback: Consistent symbol usage
isaacs authored
356 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
357 }
358
359 // Subclasses should implement the appropriate Parse method.
360 virtual void Parse(unsigned char* buf, int len) {
361 assert(0);
362 };
363
364 virtual void Parse(struct hostent* host) {
365 assert(0);
366 };
367
368 private:
369 Persistent<Object> object_;
370 };
371
372
373 class QueryAWrap: public QueryWrap {
374 public:
375 int Send(const char* name) {
376 ares_query(ares_channel, name, ns_c_in, ns_t_a, Callback, GetQueryArg());
377 return 0;
378 }
379
380 protected:
381 void Parse(unsigned char* buf, int len) {
382 HandleScope scope;
383
384 struct hostent* host;
385
386 int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
387 if (status != ARES_SUCCESS) {
388 this->ParseError(status);
389 return;
390 }
391
392 Local<Array> addresses = HostentToAddresses(host);
393 ares_free_hostent(host);
394
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
395 this->CallOnComplete(addresses);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
396 }
397 };
398
399
400 class QueryAaaaWrap: public QueryWrap {
401 public:
402 int Send(const char* name) {
403 ares_query(ares_channel,
404 name,
405 ns_c_in,
406 ns_t_aaaa,
407 Callback,
408 GetQueryArg());
409 return 0;
410 }
411
412 protected:
413 void Parse(unsigned char* buf, int len) {
414 HandleScope scope;
415
416 struct hostent* host;
417
418 int status = ares_parse_aaaa_reply(buf, len, &host, NULL, NULL);
419 if (status != ARES_SUCCESS) {
420 this->ParseError(status);
421 return;
422 }
423
424 Local<Array> addresses = HostentToAddresses(host);
425 ares_free_hostent(host);
426
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
427 this->CallOnComplete(addresses);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
428 }
429 };
430
431
432 class QueryCnameWrap: public QueryWrap {
433 public:
434 int Send(const char* name) {
435 ares_query(ares_channel,
436 name,
437 ns_c_in,
438 ns_t_cname,
439 Callback,
440 GetQueryArg());
441 return 0;
442 }
443
444 protected:
445 void Parse(unsigned char* buf, int len) {
446 HandleScope scope;
447
448 struct hostent* host;
449
450 int status = ares_parse_a_reply(buf, len, &host, NULL, NULL);
451 if (status != ARES_SUCCESS) {
452 this->ParseError(status);
453 return;
454 }
455
456 // A cname lookup always returns a single record but we follow the
457 // common API here.
458 Local<Array> result = Array::New(1);
459 result->Set(0, String::New(host->h_name));
460 ares_free_hostent(host);
461
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
462 this->CallOnComplete(result);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
463 }
464 };
465
466
467 class QueryMxWrap: public QueryWrap {
468 public:
469 int Send(const char* name) {
470 ares_query(ares_channel, name, ns_c_in, ns_t_mx, Callback, GetQueryArg());
471 return 0;
472 }
473
474 protected:
475 void Parse(unsigned char* buf, int len) {
476 HandleScope scope;
477
478 struct ares_mx_reply* mx_start;
479 int status = ares_parse_mx_reply(buf, len, &mx_start);
480 if (status != ARES_SUCCESS) {
481 this->ParseError(status);
482 return;
483 }
484
485 Local<Array> mx_records = Array::New();
486 Local<String> exchange_symbol = String::NewSymbol("exchange");
487 Local<String> priority_symbol = String::NewSymbol("priority");
488 int i = 0;
489 for (struct ares_mx_reply* mx_current = mx_start;
490 mx_current;
491 mx_current = mx_current->next) {
492 Local<Object> mx_record = Object::New();
493 mx_record->Set(exchange_symbol, String::New(mx_current->host));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
494 mx_record->Set(priority_symbol,
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
495 Integer::New(mx_current->priority));
496 mx_records->Set(Integer::New(i++), mx_record);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
497 }
498
499 ares_free_data(mx_start);
500
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
501 this->CallOnComplete(mx_records);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
502 }
503 };
504
505
506 class QueryNsWrap: public QueryWrap {
507 public:
508 int Send(const char* name) {
509 ares_query(ares_channel, name, ns_c_in, ns_t_ns, Callback, GetQueryArg());
510 return 0;
511 }
512
513 protected:
514 void Parse(unsigned char* buf, int len) {
515 struct hostent* host;
516
517 int status = ares_parse_ns_reply(buf, len, &host);
518 if (status != ARES_SUCCESS) {
519 this->ParseError(status);
520 return;
521 }
522
523 Local<Array> names = HostentToNames(host);
524 ares_free_hostent(host);
525
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
526 this->CallOnComplete(names);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
527 }
528 };
529
530
d9c67ae @tellnes dns: implement resolveTxt()
tellnes authored
531 class QueryTxtWrap: public QueryWrap {
532 public:
533 int Send(const char* name) {
534 ares_query(ares_channel, name, ns_c_in, ns_t_txt, Callback, GetQueryArg());
535 return 0;
536 }
537
538 protected:
539 void Parse(unsigned char* buf, int len) {
540 struct ares_txt_reply* txt_out;
541
542 int status = ares_parse_txt_reply(buf, len, &txt_out);
543 if (status != ARES_SUCCESS) {
544 this->ParseError(status);
545 return;
546 }
547
548 Local<Array> txt_records = Array::New();
549
550 struct ares_txt_reply *current = txt_out;
551 for (int i = 0; current; ++i, current = current->next) {
552 Local<String> txt = String::New(reinterpret_cast<char*>(current->txt));
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
553 txt_records->Set(Integer::New(i), txt);
d9c67ae @tellnes dns: implement resolveTxt()
tellnes authored
554 }
555
556 ares_free_data(txt_out);
557
558 this->CallOnComplete(txt_records);
559 }
560 };
561
562
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
563 class QuerySrvWrap: public QueryWrap {
564 public:
565 int Send(const char* name) {
566 ares_query(ares_channel,
567 name,
568 ns_c_in,
569 ns_t_srv,
570 Callback,
571 GetQueryArg());
572 return 0;
573 }
574
575 protected:
576 void Parse(unsigned char* buf, int len) {
577 HandleScope scope;
578
579 struct ares_srv_reply* srv_start;
580 int status = ares_parse_srv_reply(buf, len, &srv_start);
581 if (status != ARES_SUCCESS) {
582 this->ParseError(status);
583 return;
584 }
585
586 Local<Array> srv_records = Array::New();
72e18d7 dns_uv: match the old api better, fix tests
Bert Belder authored
587 Local<String> name_symbol = String::NewSymbol("name");
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
588 Local<String> port_symbol = String::NewSymbol("port");
589 Local<String> priority_symbol = String::NewSymbol("priority");
590 Local<String> weight_symbol = String::NewSymbol("weight");
591 int i = 0;
592 for (struct ares_srv_reply* srv_current = srv_start;
593 srv_current;
594 srv_current = srv_current->next) {
595 Local<Object> srv_record = Object::New();
72e18d7 dns_uv: match the old api better, fix tests
Bert Belder authored
596 srv_record->Set(name_symbol, String::New(srv_current->host));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
597 srv_record->Set(port_symbol,
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
598 Integer::New(srv_current->port));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
599 srv_record->Set(priority_symbol,
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
600 Integer::New(srv_current->priority));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
601 srv_record->Set(weight_symbol,
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
602 Integer::New(srv_current->weight));
603 srv_records->Set(Integer::New(i++), srv_record);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
604 }
605
606 ares_free_data(srv_start);
607
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
608 this->CallOnComplete(srv_records);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
609 }
610 };
611
2ad9872 @langpavel DNS: Support NAPTR queries
langpavel authored
612 class QueryNaptrWrap: public QueryWrap {
613 public:
614 int Send(const char* name) {
615 ares_query(ares_channel,
616 name,
617 ns_c_in,
618 ns_t_naptr,
619 Callback,
620 GetQueryArg());
621 return 0;
622 }
623
624 protected:
625 void Parse(unsigned char* buf, int len) {
626 HandleScope scope;
627
628 ares_naptr_reply* naptr_start;
629 int status = ares_parse_naptr_reply(buf, len, &naptr_start);
630
631 if (status != ARES_SUCCESS) {
632 this->ParseError(status);
633 return;
634 }
635
636 Local<Array> naptr_records = Array::New();
637 Local<String> flags_symbol = String::NewSymbol("flags");
638 Local<String> service_symbol = String::NewSymbol("service");
639 Local<String> regexp_symbol = String::NewSymbol("regexp");
640 Local<String> replacement_symbol = String::NewSymbol("replacement");
641 Local<String> order_symbol = String::NewSymbol("order");
642 Local<String> preference_symbol = String::NewSymbol("preference");
643
644 int i = 0;
645 for (ares_naptr_reply* naptr_current = naptr_start;
646 naptr_current;
647 naptr_current = naptr_current->next) {
648
649 Local<Object> naptr_record = Object::New();
650
651 naptr_record->Set(flags_symbol,
652 String::New(reinterpret_cast<char*>(naptr_current->flags)));
653 naptr_record->Set(service_symbol,
654 String::New(reinterpret_cast<char*>(naptr_current->service)));
655 naptr_record->Set(regexp_symbol,
656 String::New(reinterpret_cast<char*>(naptr_current->regexp)));
657 naptr_record->Set(replacement_symbol,
658 String::New(naptr_current->replacement));
659 naptr_record->Set(order_symbol, Integer::New(naptr_current->order));
660 naptr_record->Set(preference_symbol,
661 Integer::New(naptr_current->preference));
662
663 naptr_records->Set(Integer::New(i++), naptr_record);
664 }
665
666 ares_free_data(naptr_start);
667
668 this->CallOnComplete(naptr_records);
669 }
670 };
671
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
672
673 class GetHostByAddrWrap: public QueryWrap {
674 public:
675 int Send(const char* name) {
676 int length, family;
677 char address_buffer[sizeof(struct in6_addr)];
678
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
679 if (uv_inet_pton(AF_INET, name, &address_buffer).code == UV_OK) {
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
680 length = sizeof(struct in_addr);
681 family = AF_INET;
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
682 } else if (uv_inet_pton(AF_INET6, name, &address_buffer).code == UV_OK) {
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
683 length = sizeof(struct in6_addr);
684 family = AF_INET6;
685 } else {
686 return ARES_ENOTIMP;
687 }
688
689 ares_gethostbyaddr(ares_channel,
690 address_buffer,
691 length,
692 family,
693 Callback,
694 GetQueryArg());
695 return 0;
696 }
697
698 protected:
699 void Parse(struct hostent* host) {
700 HandleScope scope;
701
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
702 this->CallOnComplete(HostentToNames(host));
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
703 }
704 };
705
706
707 class GetHostByNameWrap: public QueryWrap {
708 public:
709 int Send(const char* name, int family) {
710 ares_gethostbyname(ares_channel, name, family, Callback, GetQueryArg());
711 return 0;
712 }
713
714 protected:
715 void Parse(struct hostent* host) {
716 HandleScope scope;
717
718 Local<Array> addresses = HostentToAddresses(host);
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
719 Local<Integer> family = Integer::New(host->h_addrtype);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
720
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
721 this->CallOnComplete(addresses, family);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
722 }
723 };
724
725
726 template <class Wrap>
727 static Handle<Value> Query(const Arguments& args) {
728 HandleScope scope;
729
730 assert(!args.IsConstructCall());
731 assert(args.Length() >= 2);
732 assert(args[1]->IsFunction());
733
734 Wrap* wrap = new Wrap();
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
735 wrap->SetOnComplete(args[1]);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
736
737 // We must cache the wrap's js object here, because cares might make the
738 // callback from the wrap->Send stack. This will destroy the wrap's internal
739 // object reference, causing wrap->GetObject() to return undefined.
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
740 Local<Object> object = Local<Object>::New(wrap->GetObject());
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
741
249c3c1 Avoiding unnecessary ToString() calls
ssuda authored
742 String::Utf8Value name(args[0]);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
743
744 int r = wrap->Send(*name);
745 if (r) {
746 SetAresErrno(r);
747 delete wrap;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
748 return scope.Close(v8::Null());
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
749 } else {
750 return scope.Close(object);
751 }
752 }
753
754
755 template <class Wrap>
756 static Handle<Value> QueryWithFamily(const Arguments& args) {
757 HandleScope scope;
758
759 assert(!args.IsConstructCall());
760 assert(args.Length() >= 3);
761 assert(args[2]->IsFunction());
762
763 Wrap* wrap = new Wrap();
12798c6 @ry dns callbacks should go through MakeCallback
ry authored
764 wrap->SetOnComplete(args[2]);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
765
766 // We must cache the wrap's js object here, because cares might make the
767 // callback from the wrap->Send stack. This will destroy the wrap's internal
768 // object reference, causing wrap->GetObject() to return undefined.
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
769 Local<Object> object = Local<Object>::New(wrap->GetObject());
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
770
249c3c1 Avoiding unnecessary ToString() calls
ssuda authored
771 String::Utf8Value name(args[0]);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
772 int family = args[1]->Int32Value();
773
774 int r = wrap->Send(*name, family);
775 if (r) {
776 SetAresErrno(r);
777 delete wrap;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
778 return scope.Close(v8::Null());
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
779 } else {
780 return scope.Close(object);
781 }
782 }
783
784
be2320d @ry Add binding to uv_getaddrinfo
ry authored
785 void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
786 HandleScope scope;
787
788 GetAddrInfoReqWrap* req_wrap = (GetAddrInfoReqWrap*) req->data;
789
790 Local<Value> argv[1];
791
792 if (status) {
793 // Error
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
794 SetErrno(uv_last_error(uv_default_loop()));
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
795 argv[0] = Local<Value>::New(Null());
be2320d @ry Add binding to uv_getaddrinfo
ry authored
796 } else {
797 // Success
798 struct addrinfo *address;
799 int n = 0;
800
801 // Count the number of responses.
802 for (address = res; address; address = address->ai_next) {
803 n++;
804 }
805
806 // Create the response array.
807 Local<Array> results = Array::New(n);
808
809 char ip[INET6_ADDRSTRLEN];
810 const char *addr;
811
812 n = 0;
813
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
814 // Iterate over the IPv4 responses again this time creating javascript
be2320d @ry Add binding to uv_getaddrinfo
ry authored
815 // strings for each IP and filling the results array.
816 address = res;
817 while (address) {
818 assert(address->ai_socktype == SOCK_STREAM);
819
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
820 // Ignore random ai_family types.
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
821 if (address->ai_family == AF_INET) {
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
822 // Juggle pointers
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
823 addr = (char*) &((struct sockaddr_in*) address->ai_addr)->sin_addr;
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
824 uv_err_t err = uv_inet_ntop(address->ai_family,
825 addr,
826 ip,
827 INET6_ADDRSTRLEN);
828 if (err.code != UV_OK)
829 continue;
be2320d @ry Add binding to uv_getaddrinfo
ry authored
830
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
831 // Create JavaScript string
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
832 Local<String> s = String::New(ip);
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
833 results->Set(n, s);
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
834 n++;
835 }
836
837 // Increment
838 address = address->ai_next;
839 }
840
841 // Iterate over the IPv6 responses putting them in the array.
842 address = res;
843 while (address) {
844 assert(address->ai_socktype == SOCK_STREAM);
845
846 // Ignore random ai_family types.
847 if (address->ai_family == AF_INET6) {
848 // Juggle pointers
849 addr = (char*) &((struct sockaddr_in6*) address->ai_addr)->sin6_addr;
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
850 uv_err_t err = uv_inet_ntop(address->ai_family,
851 addr,
852 ip,
853 INET6_ADDRSTRLEN);
854 if (err.code != UV_OK)
855 continue;
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
856
857 // Create JavaScript string
acea4c4 @piscisaureus dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
piscisaureus authored
858 Local<String> s = String::New(ip);
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
859 results->Set(n, s);
860 n++;
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
861 }
be2320d @ry Add binding to uv_getaddrinfo
ry authored
862
863 // Increment
864 address = address->ai_next;
865 }
866
194511f @ry Return IPv4 addresses before IPv6 addresses from getaddrinfo
ry authored
867
be2320d @ry Add binding to uv_getaddrinfo
ry authored
868 argv[0] = results;
869 }
870
871 uv_freeaddrinfo(res);
872
873 // Make the callback into JavaScript
a26bee8 @isaacs MakeCallback: Consistent symbol usage
isaacs authored
874 MakeCallback(req_wrap->object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
be2320d @ry Add binding to uv_getaddrinfo
ry authored
875
876 delete req_wrap;
877 }
878
879
fb6377e @snoj net: More accurate IP address validation and IPv6 dotted notation.
snoj authored
880 static Handle<Value> IsIP(const Arguments& args) {
881 HandleScope scope;
882
883 String::AsciiValue ip(args[0]);
884 char address_buffer[sizeof(struct in6_addr)];
885
886 if (uv_inet_pton(AF_INET, *ip, &address_buffer).code == UV_OK) {
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
887 return scope.Close(v8::Integer::New(4));
fb6377e @snoj net: More accurate IP address validation and IPv6 dotted notation.
snoj authored
888 }
889
890 if (uv_inet_pton(AF_INET6, *ip, &address_buffer).code == UV_OK) {
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
891 return scope.Close(v8::Integer::New(6));
fb6377e @snoj net: More accurate IP address validation and IPv6 dotted notation.
snoj authored
892 }
893
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
894 return scope.Close(v8::Integer::New(0));
fb6377e @snoj net: More accurate IP address validation and IPv6 dotted notation.
snoj authored
895 }
896
897
be2320d @ry Add binding to uv_getaddrinfo
ry authored
898 static Handle<Value> GetAddrInfo(const Arguments& args) {
899 HandleScope scope;
900
249c3c1 Avoiding unnecessary ToString() calls
ssuda authored
901 String::Utf8Value hostname(args[0]);
be2320d @ry Add binding to uv_getaddrinfo
ry authored
902
c83dda8 @ry dns.lookup uses cares_wrap::GetAddrInfo
ry authored
903 int fam = AF_UNSPEC;
904 if (args[1]->IsInt32()) {
905 switch (args[1]->Int32Value()) {
906 case 6:
907 fam = AF_INET6;
908 break;
909
910 case 4:
911 fam = AF_INET;
912 break;
913 }
be2320d @ry Add binding to uv_getaddrinfo
ry authored
914 }
915
916 GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap();
917
918 struct addrinfo hints;
919 memset(&hints, 0, sizeof(struct addrinfo));
920 hints.ai_family = fam;
921 hints.ai_socktype = SOCK_STREAM;
922
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
923 int r = uv_getaddrinfo(uv_default_loop(),
be2320d @ry Add binding to uv_getaddrinfo
ry authored
924 &req_wrap->req_,
925 AfterGetAddrInfo,
926 *hostname,
927 NULL,
928 &hints);
929 req_wrap->Dispatched();
930
931 if (r) {
74a8215 @bnoordhuis Revert support for isolates.
bnoordhuis authored
932 SetErrno(uv_last_error(uv_default_loop()));
be2320d @ry Add binding to uv_getaddrinfo
ry authored
933 delete req_wrap;
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
934 return scope.Close(v8::Null());
be2320d @ry Add binding to uv_getaddrinfo
ry authored
935 } else {
936 return scope.Close(req_wrap->object_);
937 }
938 }
939
940
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
941 static void Initialize(Handle<Object> target) {
942 HandleScope scope;
943 int r;
944
945 r = ares_library_init(ARES_LIB_INIT_ALL);
946 assert(r == ARES_SUCCESS);
947
948 struct ares_options options;
6aed61f @bnoordhuis dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL
bnoordhuis authored
949 memset(&options, 0, sizeof(options));
950 options.flags = ARES_FLAG_NOCHECKRESP;
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
951 options.sock_state_cb = ares_sockstate_cb;
952 options.sock_state_cb_data = uv_default_loop();
953
954 /* We do the call to ares_init_option for caller. */
6aed61f @bnoordhuis dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL
bnoordhuis authored
955 r = ares_init_options(&ares_channel,
956 &options,
957 ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
9e55ba7 @piscisaureus dns: don't rely on libuv for c-ares integration
piscisaureus authored
958 assert(r == ARES_SUCCESS);
959
960 /* Initialize the timeout timer. The timer won't be started until the */
961 /* first socket is opened. */
962 uv_timer_init(uv_default_loop(), &ares_timer);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
963
964 NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
965 NODE_SET_METHOD(target, "queryAaaa", Query<QueryAaaaWrap>);
966 NODE_SET_METHOD(target, "queryCname", Query<QueryCnameWrap>);
967 NODE_SET_METHOD(target, "queryMx", Query<QueryMxWrap>);
968 NODE_SET_METHOD(target, "queryNs", Query<QueryNsWrap>);
d9c67ae @tellnes dns: implement resolveTxt()
tellnes authored
969 NODE_SET_METHOD(target, "queryTxt", Query<QueryTxtWrap>);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
970 NODE_SET_METHOD(target, "querySrv", Query<QuerySrvWrap>);
2ad9872 @langpavel DNS: Support NAPTR queries
langpavel authored
971 NODE_SET_METHOD(target, "queryNaptr", Query<QueryNaptrWrap>);
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
972 NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>);
973 NODE_SET_METHOD(target, "getHostByName", QueryWithFamily<GetHostByNameWrap>);
974
be2320d @ry Add binding to uv_getaddrinfo
ry authored
975 NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
fb6377e @snoj net: More accurate IP address validation and IPv6 dotted notation.
snoj authored
976 NODE_SET_METHOD(target, "isIP", IsIP);
be2320d @ry Add binding to uv_getaddrinfo
ry authored
977
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
978 target->Set(String::NewSymbol("AF_INET"),
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
979 Integer::New(AF_INET));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
980 target->Set(String::NewSymbol("AF_INET6"),
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
981 Integer::New(AF_INET6));
6573fc3 @bnoordhuis src: pass node_isolate to Integer::New
bnoordhuis authored
982 target->Set(String::NewSymbol("AF_UNSPEC"),
51f6e6a @bnoordhuis src, test: downgrade to v8 3.14 api
bnoordhuis authored
983 Integer::New(AF_UNSPEC));
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
984
a26bee8 @isaacs MakeCallback: Consistent symbol usage
isaacs authored
985 oncomplete_sym = NODE_PSYMBOL("oncomplete");
858f230 @piscisaureus Bindings for libuv-integrated c-ares
piscisaureus authored
986 }
987
988
989 } // namespace cares_wrap
990
991 } // namespace node
992
cdcb111 @bnoordhuis Remove stray NODE_MODULE() semi-colons.
bnoordhuis authored
993 NODE_MODULE(node_cares_wrap, node::cares_wrap::Initialize)
Something went wrong with that request. Please try again.