Skip to content

HTTPS clone URL

Subversion checkout URL

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