Skip to content
This repository
Newer
Older
100644 932 lines (727 sloc) 24.361 kb
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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>
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #define CARES_STATICLIB
28 #include "ares.h"
ff4a9d38 » bnoordhuis
2012-03-10 core: use proper #include directives
29 #include "node.h"
30 #include "req_wrap.h"
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
31 #include "tree.h"
ff4a9d38 » bnoordhuis
2012-03-10 core: use proper #include directives
32 #include "uv.h"
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
33
13d6a1f6 » DrPizza
2011-08-06 Basic VC++ compatibility work.
34 #if defined(__OpenBSD__) || defined(__MINGW32__) || defined(_MSC_VER)
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
59
60 typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
61
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
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 };
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
68
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
69
70 static Persistent<String> oncomplete_sym;
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
71 static ares_channel ares_channel;
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
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 }
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
195
196
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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);
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
206 addresses->Set(Integer::New(i, node_isolate), address);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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]);
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
219 names->Set(Integer::New(i, node_isolate), address);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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;
264 Handle<Value> key = String::NewSymbol("errno");
265 Handle<Value> value = String::NewSymbol(AresErrnoString(errorno));
266 Context::GetCurrent()->Global()->Set(key, value);
267 }
268
269
270 class QueryWrap {
271 public:
272 QueryWrap() {
273 HandleScope scope;
274
275 object_ = Persistent<Object>::New(Object::New());
276 }
277
f1d3ae77 » bnoordhuis
2011-10-14 cares_wrap: make destructor virtual
278 virtual ~QueryWrap() {
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
279 assert(!object_.IsEmpty());
280
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
281 object_->Delete(oncomplete_sym);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
282
283 object_.Dispose();
284 object_.Clear();
285 }
286
287 Handle<Object> GetObject() {
288 return object_;
289 }
290
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
291 void SetOnComplete(Handle<Value> oncomplete) {
292 assert(oncomplete->IsFunction());
293 object_->Set(oncomplete_sym, oncomplete);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
294 }
295
296 // Subclasses should implement the appropriate Send method.
297 virtual int Send(const char* name) {
298 assert(0);
13d6a1f6 » DrPizza
2011-08-06 Basic VC++ compatibility work.
299 return 0;
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
300 }
301
302 virtual int Send(const char* name, int family) {
303 assert(0);
13d6a1f6 » DrPizza
2011-08-06 Basic VC++ compatibility work.
304 return 0;
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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) {
5664dd2f » bnoordhuis
2013-01-05 src: use static_cast where appropriate
314 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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) {
5664dd2f » bnoordhuis
2013-01-05 src: use static_cast where appropriate
327 QueryWrap* wrap = static_cast<QueryWrap*>(arg);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
328
329 if (status != ARES_SUCCESS) {
330 wrap->ParseError(status);
331 } else {
332 wrap->Parse(host);
333 }
334
335 delete wrap;
336 }
337
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
338 void CallOnComplete(Local<Value> answer) {
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
339 HandleScope scope;
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
340 Local<Value> argv[2] = { Integer::New(0, node_isolate), answer };
a26bee8f » isaacs
2012-04-12 MakeCallback: Consistent symbol usage
341 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
342 }
343
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
344 void CallOnComplete(Local<Value> answer, Local<Value> family) {
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
345 HandleScope scope;
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
346 Local<Value> argv[3] = { Integer::New(0, node_isolate), answer, family };
a26bee8f » isaacs
2012-04-12 MakeCallback: Consistent symbol usage
347 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
348 }
349
350 void ParseError(int status) {
351 assert(status != ARES_SUCCESS);
352 SetAresErrno(status);
353
354 HandleScope scope;
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
355 Local<Value> argv[1] = { Integer::New(-1, node_isolate) };
a26bee8f » isaacs
2012-04-12 MakeCallback: Consistent symbol usage
356 MakeCallback(object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
395 this->CallOnComplete(addresses);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
427 this->CallOnComplete(addresses);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
462 this->CallOnComplete(result);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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));
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
494 mx_record->Set(priority_symbol,
495 Integer::New(mx_current->priority, node_isolate));
496 mx_records->Set(Integer::New(i++, node_isolate), mx_record);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
497 }
498
499 ares_free_data(mx_start);
500
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
501 this->CallOnComplete(mx_records);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
526 this->CallOnComplete(names);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
527 }
528 };
529
530
d9c67aeb » tellnes
2011-10-03 dns: implement resolveTxt()
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));
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
553 txt_records->Set(Integer::New(i, node_isolate), txt);
d9c67aeb » tellnes
2011-10-03 dns: implement resolveTxt()
554 }
555
556 ares_free_data(txt_out);
557
558 this->CallOnComplete(txt_records);
559 }
560 };
561
562
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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();
72e18d7f » Bert Belder
2011-07-05 dns_uv: match the old api better, fix tests
587 Local<String> name_symbol = String::NewSymbol("name");
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
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();
72e18d7f » Bert Belder
2011-07-05 dns_uv: match the old api better, fix tests
596 srv_record->Set(name_symbol, String::New(srv_current->host));
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
597 srv_record->Set(port_symbol,
598 Integer::New(srv_current->port, node_isolate));
599 srv_record->Set(priority_symbol,
600 Integer::New(srv_current->priority, node_isolate));
601 srv_record->Set(weight_symbol,
602 Integer::New(srv_current->weight, node_isolate));
603 srv_records->Set(Integer::New(i++, node_isolate), srv_record);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
604 }
605
606 ares_free_data(srv_start);
607
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
608 this->CallOnComplete(srv_records);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
609 }
610 };
611
612
613 class GetHostByAddrWrap: public QueryWrap {
614 public:
615 int Send(const char* name) {
616 int length, family;
617 char address_buffer[sizeof(struct in6_addr)];
618
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
619 if (uv_inet_pton(AF_INET, name, &address_buffer).code == UV_OK) {
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
620 length = sizeof(struct in_addr);
621 family = AF_INET;
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
622 } else if (uv_inet_pton(AF_INET6, name, &address_buffer).code == UV_OK) {
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
623 length = sizeof(struct in6_addr);
624 family = AF_INET6;
625 } else {
626 return ARES_ENOTIMP;
627 }
628
629 ares_gethostbyaddr(ares_channel,
630 address_buffer,
631 length,
632 family,
633 Callback,
634 GetQueryArg());
635 return 0;
636 }
637
638 protected:
639 void Parse(struct hostent* host) {
640 HandleScope scope;
641
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
642 this->CallOnComplete(HostentToNames(host));
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
643 }
644 };
645
646
647 class GetHostByNameWrap: public QueryWrap {
648 public:
649 int Send(const char* name, int family) {
650 ares_gethostbyname(ares_channel, name, family, Callback, GetQueryArg());
651 return 0;
652 }
653
654 protected:
655 void Parse(struct hostent* host) {
656 HandleScope scope;
657
658 Local<Array> addresses = HostentToAddresses(host);
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
659 Local<Integer> family = Integer::New(host->h_addrtype, node_isolate);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
660
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
661 this->CallOnComplete(addresses, family);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
662 }
663 };
664
665
666 template <class Wrap>
667 static Handle<Value> Query(const Arguments& args) {
668 HandleScope scope;
669
670 assert(!args.IsConstructCall());
671 assert(args.Length() >= 2);
672 assert(args[1]->IsFunction());
673
674 Wrap* wrap = new Wrap();
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
675 wrap->SetOnComplete(args[1]);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
676
677 // We must cache the wrap's js object here, because cares might make the
678 // callback from the wrap->Send stack. This will destroy the wrap's internal
679 // object reference, causing wrap->GetObject() to return undefined.
01c3d0aa » bnoordhuis
2013-01-06 src: pass node_isolate to Local<>::New
680 Local<Object> object = Local<Object>::New(node_isolate, wrap->GetObject());
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
681
249c3c16 » ssuda
2012-03-21 Avoiding unnecessary ToString() calls
682 String::Utf8Value name(args[0]);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
683
684 int r = wrap->Send(*name);
685 if (r) {
686 SetAresErrno(r);
687 delete wrap;
c7d7ae1f » bnoordhuis
2013-01-06 src: pass node_isolate to Null()
688 return scope.Close(v8::Null(node_isolate));
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
689 } else {
690 return scope.Close(object);
691 }
692 }
693
694
695 template <class Wrap>
696 static Handle<Value> QueryWithFamily(const Arguments& args) {
697 HandleScope scope;
698
699 assert(!args.IsConstructCall());
700 assert(args.Length() >= 3);
701 assert(args[2]->IsFunction());
702
703 Wrap* wrap = new Wrap();
12798c62 » ry
2011-09-18 dns callbacks should go through MakeCallback
704 wrap->SetOnComplete(args[2]);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
705
706 // We must cache the wrap's js object here, because cares might make the
707 // callback from the wrap->Send stack. This will destroy the wrap's internal
708 // object reference, causing wrap->GetObject() to return undefined.
01c3d0aa » bnoordhuis
2013-01-06 src: pass node_isolate to Local<>::New
709 Local<Object> object = Local<Object>::New(node_isolate, wrap->GetObject());
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
710
249c3c16 » ssuda
2012-03-21 Avoiding unnecessary ToString() calls
711 String::Utf8Value name(args[0]);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
712 int family = args[1]->Int32Value();
713
714 int r = wrap->Send(*name, family);
715 if (r) {
716 SetAresErrno(r);
717 delete wrap;
c7d7ae1f » bnoordhuis
2013-01-06 src: pass node_isolate to Null()
718 return scope.Close(v8::Null(node_isolate));
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
719 } else {
720 return scope.Close(object);
721 }
722 }
723
724
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
725 void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
726 HandleScope scope;
727
728 GetAddrInfoReqWrap* req_wrap = (GetAddrInfoReqWrap*) req->data;
729
730 Local<Value> argv[1];
731
732 if (status) {
733 // Error
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
734 SetErrno(uv_last_error(uv_default_loop()));
c7d7ae1f » bnoordhuis
2013-01-06 src: pass node_isolate to Null()
735 argv[0] = Local<Value>::New(node_isolate, Null(node_isolate));
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
736 } else {
737 // Success
738 struct addrinfo *address;
739 int n = 0;
740
741 // Count the number of responses.
742 for (address = res; address; address = address->ai_next) {
743 n++;
744 }
745
746 // Create the response array.
747 Local<Array> results = Array::New(n);
748
749 char ip[INET6_ADDRSTRLEN];
750 const char *addr;
751
752 n = 0;
753
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
754 // Iterate over the IPv4 responses again this time creating javascript
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
755 // strings for each IP and filling the results array.
756 address = res;
757 while (address) {
758 assert(address->ai_socktype == SOCK_STREAM);
759
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
760 // Ignore random ai_family types.
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
761 if (address->ai_family == AF_INET) {
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
762 // Juggle pointers
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
763 addr = (char*) &((struct sockaddr_in*) address->ai_addr)->sin_addr;
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
764 uv_err_t err = uv_inet_ntop(address->ai_family,
765 addr,
766 ip,
767 INET6_ADDRSTRLEN);
768 if (err.code != UV_OK)
769 continue;
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
770
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
771 // Create JavaScript string
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
772 Local<String> s = String::New(ip);
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
773 results->Set(n, s);
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
774 n++;
775 }
776
777 // Increment
778 address = address->ai_next;
779 }
780
781 // Iterate over the IPv6 responses putting them in the array.
782 address = res;
783 while (address) {
784 assert(address->ai_socktype == SOCK_STREAM);
785
786 // Ignore random ai_family types.
787 if (address->ai_family == AF_INET6) {
788 // Juggle pointers
789 addr = (char*) &((struct sockaddr_in6*) address->ai_addr)->sin6_addr;
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
790 uv_err_t err = uv_inet_ntop(address->ai_family,
791 addr,
792 ip,
793 INET6_ADDRSTRLEN);
794 if (err.code != UV_OK)
795 continue;
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
796
797 // Create JavaScript string
acea4c41 » piscisaureus
2012-08-07 dns: use uv_inet_ntop/uv_inet_pton instead of c-ares equivalents
798 Local<String> s = String::New(ip);
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
799 results->Set(n, s);
800 n++;
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
801 }
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
802
803 // Increment
804 address = address->ai_next;
805 }
806
194511ff » ry
2011-10-26 Return IPv4 addresses before IPv6 addresses from getaddrinfo
807
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
808 argv[0] = results;
809 }
810
811 uv_freeaddrinfo(res);
812
813 // Make the callback into JavaScript
a26bee8f » isaacs
2012-04-12 MakeCallback: Consistent symbol usage
814 MakeCallback(req_wrap->object_, oncomplete_sym, ARRAY_SIZE(argv), argv);
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
815
816 delete req_wrap;
817 }
818
819
fb6377eb » snoj
2012-10-08 net: More accurate IP address validation and IPv6 dotted notation.
820 static Handle<Value> IsIP(const Arguments& args) {
821 HandleScope scope;
822
823 String::AsciiValue ip(args[0]);
824 char address_buffer[sizeof(struct in6_addr)];
825
826 if (uv_inet_pton(AF_INET, *ip, &address_buffer).code == UV_OK) {
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
827 return scope.Close(v8::Integer::New(4, node_isolate));
fb6377eb » snoj
2012-10-08 net: More accurate IP address validation and IPv6 dotted notation.
828 }
829
830 if (uv_inet_pton(AF_INET6, *ip, &address_buffer).code == UV_OK) {
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
831 return scope.Close(v8::Integer::New(6, node_isolate));
fb6377eb » snoj
2012-10-08 net: More accurate IP address validation and IPv6 dotted notation.
832 }
833
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
834 return scope.Close(v8::Integer::New(0, node_isolate));
fb6377eb » snoj
2012-10-08 net: More accurate IP address validation and IPv6 dotted notation.
835 }
836
837
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
838 static Handle<Value> GetAddrInfo(const Arguments& args) {
839 HandleScope scope;
840
249c3c16 » ssuda
2012-03-21 Avoiding unnecessary ToString() calls
841 String::Utf8Value hostname(args[0]);
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
842
c83dda89 » ry
2011-10-20 dns.lookup uses cares_wrap::GetAddrInfo
843 int fam = AF_UNSPEC;
844 if (args[1]->IsInt32()) {
845 switch (args[1]->Int32Value()) {
846 case 6:
847 fam = AF_INET6;
848 break;
849
850 case 4:
851 fam = AF_INET;
852 break;
853 }
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
854 }
855
856 GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap();
857
858 struct addrinfo hints;
859 memset(&hints, 0, sizeof(struct addrinfo));
860 hints.ai_family = fam;
861 hints.ai_socktype = SOCK_STREAM;
862
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
863 int r = uv_getaddrinfo(uv_default_loop(),
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
864 &req_wrap->req_,
865 AfterGetAddrInfo,
866 *hostname,
867 NULL,
868 &hints);
869 req_wrap->Dispatched();
870
871 if (r) {
74a8215a » bnoordhuis
2012-02-03 Revert support for isolates.
872 SetErrno(uv_last_error(uv_default_loop()));
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
873 delete req_wrap;
c7d7ae1f » bnoordhuis
2013-01-06 src: pass node_isolate to Null()
874 return scope.Close(v8::Null(node_isolate));
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
875 } else {
876 return scope.Close(req_wrap->object_);
877 }
878 }
879
880
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
881 static void Initialize(Handle<Object> target) {
882 HandleScope scope;
883 int r;
884
885 r = ares_library_init(ARES_LIB_INIT_ALL);
886 assert(r == ARES_SUCCESS);
887
888 struct ares_options options;
6aed61f1 » bnoordhuis
2013-02-01 dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL
889 memset(&options, 0, sizeof(options));
890 options.flags = ARES_FLAG_NOCHECKRESP;
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
891 options.sock_state_cb = ares_sockstate_cb;
892 options.sock_state_cb_data = uv_default_loop();
893
894 /* We do the call to ares_init_option for caller. */
6aed61f1 » bnoordhuis
2013-02-01 dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL
895 r = ares_init_options(&ares_channel,
896 &options,
897 ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB);
9e55ba7d » piscisaureus
2012-08-06 dns: don't rely on libuv for c-ares integration
898 assert(r == ARES_SUCCESS);
899
900 /* Initialize the timeout timer. The timer won't be started until the */
901 /* first socket is opened. */
902 uv_timer_init(uv_default_loop(), &ares_timer);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
903
904 NODE_SET_METHOD(target, "queryA", Query<QueryAWrap>);
905 NODE_SET_METHOD(target, "queryAaaa", Query<QueryAaaaWrap>);
906 NODE_SET_METHOD(target, "queryCname", Query<QueryCnameWrap>);
907 NODE_SET_METHOD(target, "queryMx", Query<QueryMxWrap>);
908 NODE_SET_METHOD(target, "queryNs", Query<QueryNsWrap>);
d9c67aeb » tellnes
2011-10-03 dns: implement resolveTxt()
909 NODE_SET_METHOD(target, "queryTxt", Query<QueryTxtWrap>);
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
910 NODE_SET_METHOD(target, "querySrv", Query<QuerySrvWrap>);
911 NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>);
912 NODE_SET_METHOD(target, "getHostByName", QueryWithFamily<GetHostByNameWrap>);
913
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
914 NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
fb6377eb » snoj
2012-10-08 net: More accurate IP address validation and IPv6 dotted notation.
915 NODE_SET_METHOD(target, "isIP", IsIP);
be2320d4 » ry
2011-10-20 Add binding to uv_getaddrinfo
916
6573fc35 » bnoordhuis
2013-01-06 src: pass node_isolate to Integer::New
917 target->Set(String::NewSymbol("AF_INET"),
918 Integer::New(AF_INET, node_isolate));
919 target->Set(String::NewSymbol("AF_INET6"),
920 Integer::New(AF_INET6, node_isolate));
921 target->Set(String::NewSymbol("AF_UNSPEC"),
922 Integer::New(AF_UNSPEC, node_isolate));
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
923
a26bee8f » isaacs
2012-04-12 MakeCallback: Consistent symbol usage
924 oncomplete_sym = NODE_PSYMBOL("oncomplete");
858f2309 » piscisaureus
2011-07-05 Bindings for libuv-integrated c-ares
925 }
926
927
928 } // namespace cares_wrap
929
930 } // namespace node
931
cdcb1118 » bnoordhuis
2011-11-09 Remove stray NODE_MODULE() semi-colons.
932 NODE_MODULE(node_cares_wrap, node::cares_wrap::Initialize)
Something went wrong with that request. Please try again.