GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/cares_wrap.cc Lines: 778 1051 74.0 %
Date: 2021-05-02 04:12:27 Branches: 289 615 47.0 %

Line Branch Exec Source
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 "async_wrap-inl.h"
23
#include "base_object-inl.h"
24
#include "base64-inl.h"
25
#include "cares_wrap.h"
26
#include "env-inl.h"
27
#include "memory_tracker-inl.h"
28
#include "node.h"
29
#include "node_errors.h"
30
#include "req_wrap-inl.h"
31
#include "util-inl.h"
32
#include "v8.h"
33
#include "uv.h"
34
35
#include <cerrno>
36
#include <cstring>
37
#include <memory>
38
#include <vector>
39
#include <unordered_set>
40
41
namespace node {
42
namespace cares_wrap {
43
44
using v8::Array;
45
using v8::Context;
46
using v8::EscapableHandleScope;
47
using v8::FunctionCallbackInfo;
48
using v8::FunctionTemplate;
49
using v8::HandleScope;
50
using v8::Int32;
51
using v8::Integer;
52
using v8::Isolate;
53
using v8::Local;
54
using v8::Null;
55
using v8::Object;
56
using v8::String;
57
using v8::Value;
58
59
namespace {
60
61
4829
Mutex ares_library_mutex;
62
63
56
inline uint16_t cares_get_16bit(const unsigned char* p) {
64
56
  return static_cast<uint32_t>(p[0] << 8U) | (static_cast<uint32_t>(p[1]));
65
}
66
67
16
void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
68
16
  NodeAresTask* task = ContainerOf(&NodeAresTask::poll_watcher, watcher);
69
16
  ChannelWrap* channel = task->channel;
70
71
  /* Reset the idle timer */
72
16
  uv_timer_again(channel->timer_handle());
73
74
16
  if (status < 0) {
75
    /* An error happened. Just pretend that the socket is both readable and */
76
    /* writable. */
77
    ares_process_fd(channel->cares_channel(), task->sock, task->sock);
78
    return;
79
  }
80
81
  /* Process DNS responses */
82

32
  ares_process_fd(channel->cares_channel(),
83
16
                  events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
84
32
                  events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
85
}
86
87
88
29
void ares_poll_close_cb(uv_poll_t* watcher) {
89
  std::unique_ptr<NodeAresTask> free_me(
90
29
        ContainerOf(&NodeAresTask::poll_watcher, watcher));
91
29
}
92
93
94
/* Callback from ares when socket operation is started */
95
58
void ares_sockstate_cb(void* data, ares_socket_t sock, int read, int write) {
96
58
  ChannelWrap* channel = static_cast<ChannelWrap*>(data);
97
  NodeAresTask* task;
98
99
116
  NodeAresTask lookup_task;
100
58
  lookup_task.sock = sock;
101
58
  auto it = channel->task_list()->find(&lookup_task);
102
103
58
  task = (it == channel->task_list()->end()) ? nullptr : *it;
104
105

58
  if (read || write) {
106
29
    if (!task) {
107
      /* New socket */
108
29
      channel->StartTimer();
109
110
29
      task = NodeAresTask::Create(channel, sock);
111
29
      if (task == nullptr) {
112
        /* This should never happen unless we're out of memory or something */
113
        /* is seriously wrong. The socket won't be polled, but the query will */
114
        /* eventually time out. */
115
        return;
116
      }
117
118
29
      channel->task_list()->insert(task);
119
    }
120
121
    /* This should never fail. If it fails anyway, the query will eventually */
122
    /* time out. */
123
29
    uv_poll_start(&task->poll_watcher,
124

29
                  (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
125
29
                  ares_poll_cb);
126
127
  } else {
128
    /* read == 0 and write == 0 this is c-ares's way of notifying us that */
129
    /* the socket is now closed. We must free the data associated with */
130
    /* socket. */
131
29
    CHECK(task &&
132
          "When an ares socket is closed we should have a handle for it");
133
134
29
    channel->task_list()->erase(it);
135
29
    channel->env()->CloseHandle(&task->poll_watcher, ares_poll_close_cb);
136
137
29
    if (channel->task_list()->empty()) {
138
29
      channel->CloseTimer();
139
    }
140
  }
141
}
142
143
2
Local<Array> HostentToNames(Environment* env, struct hostent* host) {
144
2
  EscapableHandleScope scope(env->isolate());
145
146
4
  std::vector<Local<Value>> names;
147
148
2
  for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i)
149
    names.emplace_back(OneByteString(env->isolate(), host->h_aliases[i]));
150
151
2
  Local<Array> ret = Array::New(env->isolate(), names.data(), names.size());
152
153
2
  return scope.Escape(ret);
154
}
155
156
4
Local<Array> HostentToNames(Environment* env,
157
                            struct hostent* host,
158
                            Local<Array> names) {
159
4
  size_t offset = names->Length();
160
161
8
  for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i) {
162
8
    names->Set(
163
        env->context(),
164
        i + offset,
165
12
        OneByteString(env->isolate(), host->h_aliases[i])).Check();
166
  }
167
168
4
  return names;
169
}
170
171
template <typename T>
172
9
Local<Array> AddrTTLToArray(
173
    Environment* env,
174
    const T* addrttls,
175
    size_t naddrttls) {
176
18
  MaybeStackBuffer<Local<Value>, 8> ttls(naddrttls);
177

18
  for (size_t i = 0; i < naddrttls; i++)
178
18
    ttls[i] = Integer::NewFromUnsigned(env->isolate(), addrttls[i].ttl);
179
180
18
  return Array::New(env->isolate(), ttls.out(), naddrttls);
181
}
182
183
27
int ParseGeneralReply(
184
    Environment* env,
185
    const unsigned char* buf,
186
    int len,
187
    int* type,
188
    Local<Array> ret,
189
    void* addrttls = nullptr,
190
    int* naddrttls = nullptr) {
191
54
  HandleScope handle_scope(env->isolate());
192
  hostent* host;
193
194
  int status;
195

27
  switch (*type) {
196
    case ns_t_a:
197
    case ns_t_cname:
198
    case ns_t_cname_or_a:
199
      status = ares_parse_a_reply(buf,
200
                                  len,
201
                                  &host,
202
                                  static_cast<ares_addrttl*>(addrttls),
203
13
                                  naddrttls);
204
13
      break;
205
    case ns_t_aaaa:
206
      status = ares_parse_aaaa_reply(buf,
207
                                     len,
208
                                     &host,
209
                                     static_cast<ares_addr6ttl*>(addrttls),
210
6
                                     naddrttls);
211
6
      break;
212
    case ns_t_ns:
213
4
      status = ares_parse_ns_reply(buf, len, &host);
214
4
      break;
215
    case ns_t_ptr:
216
4
      status = ares_parse_ptr_reply(buf, len, nullptr, 0, AF_INET, &host);
217
4
      break;
218
    default:
219
      CHECK(0 && "Bad NS type");
220
      break;
221
  }
222
223
27
  if (status != ARES_SUCCESS)
224
2
    return status;
225
226
25
  CHECK_NOT_NULL(host);
227
50
  HostEntPointer ptr(host);
228
229
  /* If it's `CNAME`, return the CNAME value;
230
   * And if it's `CNAME_OR_A` and it has value in `h_name` and `h_aliases[0]`,
231
   * we consider it's a CNAME record, otherwise we consider it's an A record. */
232


50
  if ((*type == ns_t_cname_or_a && ptr->h_name && ptr->h_aliases[0]) ||
233
25
      *type == ns_t_cname) {
234
    // A cname lookup always returns a single record but we follow the
235
    // common API here.
236
    *type = ns_t_cname;
237
    ret->Set(env->context(),
238
             ret->Length(),
239
             OneByteString(env->isolate(), ptr->h_name)).Check();
240
    return ARES_SUCCESS;
241
  }
242
243
25
  if (*type == ns_t_cname_or_a)
244
4
    *type = ns_t_a;
245
246
25
  if (*type == ns_t_ns) {
247
4
    HostentToNames(env, ptr.get(), ret);
248
21
  } else if (*type == ns_t_ptr) {
249
4
    uint32_t offset = ret->Length();
250
8
    for (uint32_t i = 0; ptr->h_aliases[i] != nullptr; i++) {
251
4
      auto alias = OneByteString(env->isolate(), ptr->h_aliases[i]);
252
12
      ret->Set(env->context(), i + offset, alias).Check();
253
    }
254
  } else {
255
17
    uint32_t offset = ret->Length();
256
    char ip[INET6_ADDRSTRLEN];
257
34
    for (uint32_t i = 0; ptr->h_addr_list[i] != nullptr; ++i) {
258
17
      uv_inet_ntop(ptr->h_addrtype, ptr->h_addr_list[i], ip, sizeof(ip));
259
17
      auto address = OneByteString(env->isolate(), ip);
260
51
      ret->Set(env->context(), i + offset, address).Check();
261
    }
262
  }
263
264
25
  return ARES_SUCCESS;
265
}
266
267
4
int ParseMxReply(
268
    Environment* env,
269
    const unsigned char* buf,
270
    int len,
271
    Local<Array> ret,
272
    bool need_type = false) {
273
8
  HandleScope handle_scope(env->isolate());
274
275
  struct ares_mx_reply* mx_start;
276
4
  int status = ares_parse_mx_reply(buf, len, &mx_start);
277
4
  if (status != ARES_SUCCESS)
278
    return status;
279
280
4
  uint32_t offset = ret->Length();
281
4
  ares_mx_reply* current = mx_start;
282
8
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
283
4
    Local<Object> mx_record = Object::New(env->isolate());
284
8
    mx_record->Set(env->context(),
285
                   env->exchange_string(),
286
20
                   OneByteString(env->isolate(), current->host)).Check();
287
8
    mx_record->Set(env->context(),
288
                   env->priority_string(),
289
20
                   Integer::New(env->isolate(), current->priority)).Check();
290
4
    if (need_type)
291
8
      mx_record->Set(env->context(),
292
                     env->type_string(),
293
20
                     env->dns_mx_string()).Check();
294
295
12
    ret->Set(env->context(), i + offset, mx_record).Check();
296
  }
297
298
4
  ares_free_data(mx_start);
299
4
  return ARES_SUCCESS;
300
}
301
302
4
int ParseCaaReply(
303
    Environment* env,
304
    const unsigned char* buf,
305
    int len,
306
    Local<Array> ret,
307
    bool need_type = false) {
308
8
  HandleScope handle_scope(env->isolate());
309
310
  struct ares_caa_reply* caa_start;
311
4
  int status = ares_parse_caa_reply(buf, len, &caa_start);
312
4
  if (status != ARES_SUCCESS)
313
    return status;
314
315
4
  uint32_t offset = ret->Length();
316
4
  ares_caa_reply* current = caa_start;
317
6
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
318
2
    Local<Object> caa_record = Object::New(env->isolate());
319
320
4
    caa_record->Set(env->context(),
321
                    env->dns_critical_string(),
322
10
                    Integer::New(env->isolate(), current->critical)).Check();
323
4
    caa_record->Set(env->context(),
324
2
                    OneByteString(env->isolate(), current->property),
325
10
                    OneByteString(env->isolate(), current->value)).Check();
326
2
    if (need_type)
327
4
      caa_record->Set(env->context(),
328
                      env->type_string(),
329
10
                      env->dns_caa_string()).Check();
330
331
6
    ret->Set(env->context(), i + offset, caa_record).Check();
332
  }
333
334
4
  ares_free_data(caa_start);
335
4
  return ARES_SUCCESS;
336
}
337
338
4
int ParseTxtReply(
339
    Environment* env,
340
    const unsigned char* buf,
341
    int len,
342
    Local<Array> ret,
343
    bool need_type = false) {
344
8
  HandleScope handle_scope(env->isolate());
345
346
  struct ares_txt_ext* txt_out;
347
348
4
  int status = ares_parse_txt_reply_ext(buf, len, &txt_out);
349
4
  if (status != ARES_SUCCESS)
350
    return status;
351
352
  Local<Array> txt_chunk;
353
354
4
  struct ares_txt_ext* current = txt_out;
355
4
  uint32_t i = 0, j;
356
4
  uint32_t offset = ret->Length();
357
8
  for (j = 0; current != nullptr; current = current->next) {
358
    Local<String> txt =
359
4
        OneByteString(env->isolate(), current->txt, current->length);
360
361
    // New record found - write out the current chunk
362
4
    if (current->record_start) {
363
2
      if (!txt_chunk.IsEmpty()) {
364
        if (need_type) {
365
          Local<Object> elem = Object::New(env->isolate());
366
          elem->Set(env->context(), env->entries_string(), txt_chunk).Check();
367
          elem->Set(env->context(),
368
                    env->type_string(),
369
                    env->dns_txt_string()).Check();
370
          ret->Set(env->context(), offset + i++, elem).Check();
371
        } else {
372
          ret->Set(env->context(), offset + i++, txt_chunk).Check();
373
        }
374
      }
375
376
2
      txt_chunk = Array::New(env->isolate());
377
2
      j = 0;
378
    }
379
380
12
    txt_chunk->Set(env->context(), j++, txt).Check();
381
  }
382
383
  // Push last chunk if it isn't empty
384
4
  if (!txt_chunk.IsEmpty()) {
385
2
    if (need_type) {
386
2
      Local<Object> elem = Object::New(env->isolate());
387
8
      elem->Set(env->context(), env->entries_string(), txt_chunk).Check();
388
4
      elem->Set(env->context(),
389
                env->type_string(),
390
10
                env->dns_txt_string()).Check();
391
6
      ret->Set(env->context(), offset + i, elem).Check();
392
    } else {
393
      ret->Set(env->context(), offset + i, txt_chunk).Check();
394
    }
395
  }
396
397
4
  ares_free_data(txt_out);
398
4
  return ARES_SUCCESS;
399
}
400
401
402
4
int ParseSrvReply(
403
    Environment* env,
404
    const unsigned char* buf,
405
    int len,
406
    Local<Array> ret,
407
    bool need_type = false) {
408
8
  HandleScope handle_scope(env->isolate());
409
410
  struct ares_srv_reply* srv_start;
411
4
  int status = ares_parse_srv_reply(buf, len, &srv_start);
412
4
  if (status != ARES_SUCCESS)
413
    return status;
414
415
4
  ares_srv_reply* current = srv_start;
416
4
  int offset = ret->Length();
417
4
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
418
    Local<Object> srv_record = Object::New(env->isolate());
419
    srv_record->Set(env->context(),
420
                    env->name_string(),
421
                    OneByteString(env->isolate(), current->host)).Check();
422
    srv_record->Set(env->context(),
423
                    env->port_string(),
424
                    Integer::New(env->isolate(), current->port)).Check();
425
    srv_record->Set(env->context(),
426
                    env->priority_string(),
427
                    Integer::New(env->isolate(), current->priority)).Check();
428
    srv_record->Set(env->context(),
429
                    env->weight_string(),
430
                    Integer::New(env->isolate(), current->weight)).Check();
431
    if (need_type)
432
      srv_record->Set(env->context(),
433
                      env->type_string(),
434
                      env->dns_srv_string()).Check();
435
436
    ret->Set(env->context(), i + offset, srv_record).Check();
437
  }
438
439
4
  ares_free_data(srv_start);
440
4
  return ARES_SUCCESS;
441
}
442
443
444
4
int ParseNaptrReply(
445
    Environment* env,
446
    const unsigned char* buf,
447
    int len,
448
    Local<Array> ret,
449
    bool need_type = false) {
450
8
  HandleScope handle_scope(env->isolate());
451
452
  ares_naptr_reply* naptr_start;
453
4
  int status = ares_parse_naptr_reply(buf, len, &naptr_start);
454
455
4
  if (status != ARES_SUCCESS)
456
    return status;
457
458
4
  ares_naptr_reply* current = naptr_start;
459
4
  int offset = ret->Length();
460
4
  for (uint32_t i = 0; current != nullptr; ++i, current = current->next) {
461
    Local<Object> naptr_record = Object::New(env->isolate());
462
    naptr_record->Set(env->context(),
463
                      env->flags_string(),
464
                      OneByteString(env->isolate(), current->flags)).Check();
465
    naptr_record->Set(env->context(),
466
                      env->service_string(),
467
                      OneByteString(env->isolate(),
468
                                    current->service)).Check();
469
    naptr_record->Set(env->context(),
470
                      env->regexp_string(),
471
                      OneByteString(env->isolate(),
472
                                    current->regexp)).Check();
473
    naptr_record->Set(env->context(),
474
                      env->replacement_string(),
475
                      OneByteString(env->isolate(),
476
                                    current->replacement)).Check();
477
    naptr_record->Set(env->context(),
478
                      env->order_string(),
479
                      Integer::New(env->isolate(), current->order)).Check();
480
    naptr_record->Set(env->context(),
481
                      env->preference_string(),
482
                      Integer::New(env->isolate(),
483
                                   current->preference)).Check();
484
    if (need_type)
485
      naptr_record->Set(env->context(),
486
                        env->type_string(),
487
                        env->dns_naptr_string()).Check();
488
489
    ret->Set(env->context(), i + offset, naptr_record).Check();
490
  }
491
492
4
  ares_free_data(naptr_start);
493
4
  return ARES_SUCCESS;
494
}
495
496
497
4
int ParseSoaReply(
498
    Environment* env,
499
    unsigned char* buf,
500
    int len,
501
    Local<Object>* ret) {
502
4
  EscapableHandleScope handle_scope(env->isolate());
503
504
  // Manage memory using standardard smart pointer std::unique_tr
505
  struct AresDeleter {
506
38
    void operator()(char* ptr) const noexcept { ares_free_string(ptr); }
507
  };
508
  using ares_unique_ptr = std::unique_ptr<char[], AresDeleter>;
509
510
  // Can't use ares_parse_soa_reply() here which can only parse single record
511
4
  const unsigned int ancount = cares_get_16bit(buf + 6);
512
4
  unsigned char* ptr = buf + NS_HFIXEDSZ;
513
4
  char* name_temp = nullptr;
514
  long temp_len;  // NOLINT(runtime/int)
515
4
  int status = ares_expand_name(ptr, buf, len, &name_temp, &temp_len);
516
4
  if (status != ARES_SUCCESS) {
517
    // returns EBADRESP in case of invalid input
518
    return status == ARES_EBADNAME ? ARES_EBADRESP : status;
519
  }
520
521
8
  const ares_unique_ptr name(name_temp);
522
523
4
  if (ptr + temp_len + NS_QFIXEDSZ > buf + len) {
524
    return ARES_EBADRESP;
525
  }
526
4
  ptr += temp_len + NS_QFIXEDSZ;
527
528
26
  for (unsigned int i = 0; i < ancount; i++) {
529
26
    char* rr_name_temp = nullptr;
530
    long rr_temp_len;  // NOLINT(runtime/int)
531
26
    int status2 = ares_expand_name(ptr, buf, len, &rr_name_temp, &rr_temp_len);
532
533
26
    if (status2 != ARES_SUCCESS)
534
      return status2 == ARES_EBADNAME ? ARES_EBADRESP : status2;
535
536
48
    const ares_unique_ptr rr_name(rr_name_temp);
537
538
26
    ptr += rr_temp_len;
539
26
    if (ptr + NS_RRFIXEDSZ > buf + len) {
540
      return ARES_EBADRESP;
541
    }
542
543
26
    const int rr_type = cares_get_16bit(ptr);
544
26
    const int rr_len = cares_get_16bit(ptr + 8);
545
26
    ptr += NS_RRFIXEDSZ;
546
547
    // only need SOA
548
26
    if (rr_type == ns_t_soa) {
549
4
      char* nsname_temp = nullptr;
550
      long nsname_temp_len;  // NOLINT(runtime/int)
551
552
      int status3 = ares_expand_name(ptr, buf, len,
553
                                     &nsname_temp,
554
4
                                     &nsname_temp_len);
555
4
      if (status3 != ARES_SUCCESS) {
556
        return status3 == ARES_EBADNAME ? ARES_EBADRESP : status3;
557
      }
558
4
      const ares_unique_ptr nsname(nsname_temp);
559
4
      ptr += nsname_temp_len;
560
561
4
      char* hostmaster_temp = nullptr;
562
      long hostmaster_temp_len;  // NOLINT(runtime/int)
563
      int status4 = ares_expand_name(ptr, buf, len,
564
                                     &hostmaster_temp,
565
4
                                     &hostmaster_temp_len);
566
4
      if (status4 != ARES_SUCCESS) {
567
        return status4 == ARES_EBADNAME ? ARES_EBADRESP : status4;
568
      }
569
4
      const ares_unique_ptr hostmaster(hostmaster_temp);
570
4
      ptr += hostmaster_temp_len;
571
572
4
      if (ptr + 5 * 4 > buf + len) {
573
        return ARES_EBADRESP;
574
      }
575
576
4
      const unsigned int serial = ReadUint32BE(ptr + 0 * 4);
577
4
      const unsigned int refresh = ReadUint32BE(ptr + 1 * 4);
578
4
      const unsigned int retry = ReadUint32BE(ptr + 2 * 4);
579
4
      const unsigned int expire = ReadUint32BE(ptr + 3 * 4);
580
4
      const unsigned int minttl = ReadUint32BE(ptr + 4 * 4);
581
582
4
      Local<Object> soa_record = Object::New(env->isolate());
583
8
      soa_record->Set(env->context(),
584
                      env->nsname_string(),
585
20
                      OneByteString(env->isolate(), nsname.get())).Check();
586
8
      soa_record->Set(env->context(),
587
                      env->hostmaster_string(),
588
                      OneByteString(env->isolate(),
589
20
                                    hostmaster.get())).Check();
590
8
      soa_record->Set(env->context(),
591
                      env->serial_string(),
592
20
                      Integer::NewFromUnsigned(env->isolate(), serial)).Check();
593
8
      soa_record->Set(env->context(),
594
                      env->refresh_string(),
595
20
                      Integer::New(env->isolate(), refresh)).Check();
596
8
      soa_record->Set(env->context(),
597
                      env->retry_string(),
598
20
                      Integer::New(env->isolate(), retry)).Check();
599
8
      soa_record->Set(env->context(),
600
                      env->expire_string(),
601
20
                      Integer::New(env->isolate(), expire)).Check();
602
8
      soa_record->Set(env->context(),
603
                      env->minttl_string(),
604
20
                      Integer::NewFromUnsigned(env->isolate(), minttl)).Check();
605
8
      soa_record->Set(env->context(),
606
                      env->type_string(),
607
20
                      env->dns_soa_string()).Check();
608
609
610
4
      *ret = handle_scope.Escape(soa_record);
611

4
      break;
612
    }
613
614
22
    ptr += rr_len;
615
  }
616
617
4
  return ARES_SUCCESS;
618
}
619
}  // anonymous namespace
620
621
1107
ChannelWrap::ChannelWrap(Environment* env, Local<Object> object, int timeout)
622
    : AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
623
1107
      timeout_(timeout) {
624
1107
  MakeWeak();
625
626
1107
  Setup();
627
1107
}
628
629
4
void ChannelWrap::MemoryInfo(MemoryTracker* tracker) const {
630
4
  if (timer_handle_ != nullptr)
631
    tracker->TrackField("timer_handle", *timer_handle_);
632
4
  tracker->TrackField("task_list", task_list_, "NodeAresTask::List");
633
4
}
634
635
1107
void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
636
1107
  CHECK(args.IsConstructCall());
637
1107
  CHECK_EQ(args.Length(), 1);
638
2214
  CHECK(args[0]->IsInt32());
639
3321
  const int timeout = args[0].As<Int32>()->Value();
640
1107
  Environment* env = Environment::GetCurrent(args);
641
1107
  new ChannelWrap(env, args.This(), timeout);
642
1107
}
643
644
5149
GetAddrInfoReqWrap::GetAddrInfoReqWrap(
645
    Environment* env,
646
    Local<Object> req_wrap_obj,
647
5149
    bool verbatim)
648
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP),
649
5149
      verbatim_(verbatim) {}
650
651
4
GetNameInfoReqWrap::GetNameInfoReqWrap(
652
    Environment* env,
653
4
    Local<Object> req_wrap_obj)
654
4
    : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) {}
655
656
/* This is called once per second by loop->timer. It is used to constantly */
657
/* call back into c-ares for possibly processing timeouts. */
658
68
void ChannelWrap::AresTimeout(uv_timer_t* handle) {
659
68
  ChannelWrap* channel = static_cast<ChannelWrap*>(handle->data);
660
68
  CHECK_EQ(channel->timer_handle(), handle);
661
68
  CHECK_EQ(false, channel->task_list()->empty());
662
68
  ares_process_fd(channel->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
663
68
}
664
665
666
void NodeAresTask::MemoryInfo(MemoryTracker* tracker) const {
667
  tracker->TrackField("channel", channel);
668
}
669
670
/* Allocates and returns a new NodeAresTask */
671
29
NodeAresTask* NodeAresTask::Create(ChannelWrap* channel, ares_socket_t sock) {
672
29
  auto task = new NodeAresTask();
673
674
29
  task->channel = channel;
675
29
  task->sock = sock;
676
677
29
  if (uv_poll_init_socket(channel->env()->event_loop(),
678
                          &task->poll_watcher, sock) < 0) {
679
    /* This should never happen. */
680
    delete task;
681
    return nullptr;
682
  }
683
684
29
  return task;
685
}
686
687
1107
void ChannelWrap::Setup() {
688
  struct ares_options options;
689
1107
  memset(&options, 0, sizeof(options));
690
1107
  options.flags = ARES_FLAG_NOCHECKRESP;
691
1107
  options.sock_state_cb = ares_sockstate_cb;
692
1107
  options.sock_state_cb_data = this;
693
1107
  options.timeout = timeout_;
694
695
  int r;
696
1107
  if (!library_inited_) {
697
2214
    Mutex::ScopedLock lock(ares_library_mutex);
698
    // Multiple calls to ares_library_init() increase a reference counter,
699
    // so this is a no-op except for the first call to it.
700
1107
    r = ares_library_init(ARES_LIB_INIT_ALL);
701
1107
    if (r != ARES_SUCCESS)
702
      return env()->ThrowError(ToErrorCodeString(r));
703
  }
704
705
  /* We do the call to ares_init_option for caller. */
706
  const int optmask =
707
1107
      ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | ARES_OPT_SOCK_STATE_CB;
708
1107
  r = ares_init_options(&channel_, &options, optmask);
709
710
1107
  if (r != ARES_SUCCESS) {
711
    Mutex::ScopedLock lock(ares_library_mutex);
712
    ares_library_cleanup();
713
    return env()->ThrowError(ToErrorCodeString(r));
714
  }
715
716
1107
  library_inited_ = true;
717
}
718
719
29
void ChannelWrap::StartTimer() {
720
29
  if (timer_handle_ == nullptr) {
721
29
    timer_handle_ = new uv_timer_t();
722
29
    timer_handle_->data = static_cast<void*>(this);
723
29
    uv_timer_init(env()->event_loop(), timer_handle_);
724
  } else if (uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle_))) {
725
    return;
726
  }
727
29
  int timeout = timeout_;
728
29
  if (timeout == 0) timeout = 1;
729

29
  if (timeout < 0 || timeout > 1000) timeout = 1000;
730
29
  uv_timer_start(timer_handle_, AresTimeout, timeout, timeout);
731
}
732
733
1107
void ChannelWrap::CloseTimer() {
734
1107
  if (timer_handle_ == nullptr)
735
1078
    return;
736
737
58
  env()->CloseHandle(timer_handle_, [](uv_timer_t* handle) { delete handle; });
738
29
  timer_handle_ = nullptr;
739
}
740
741
3234
ChannelWrap::~ChannelWrap() {
742
1078
  ares_destroy(channel_);
743
744
1078
  if (library_inited_) {
745
2156
    Mutex::ScopedLock lock(ares_library_mutex);
746
    // This decreases the reference counter increased by ares_library_init().
747
1078
    ares_library_cleanup();
748
  }
749
750
1078
  CloseTimer();
751
2156
}
752
753
754
101
void ChannelWrap::ModifyActivityQueryCount(int count) {
755
101
  active_query_count_ += count;
756
101
  CHECK_GE(active_query_count_, 0);
757
101
}
758
759
760
/**
761
 * This function is to check whether current servers are fallback servers
762
 * when cares initialized.
763
 *
764
 * The fallback servers of cares is [ "127.0.0.1" ] with no user additional
765
 * setting.
766
 */
767
48
void ChannelWrap::EnsureServers() {
768
  /* if last query is OK or servers are set by user self, do not check */
769

48
  if (query_last_ok_ || !is_servers_default_) {
770
96
    return;
771
  }
772
773
  ares_addr_port_node* servers = nullptr;
774
775
  ares_get_servers_ports(channel_, &servers);
776
777
  /* if no server or multi-servers, ignore */
778
  if (servers == nullptr) return;
779
  if (servers->next != nullptr) {
780
    ares_free_data(servers);
781
    is_servers_default_ = false;
782
    return;
783
  }
784
785
  /* if the only server is not 127.0.0.1, ignore */
786
  if (servers[0].family != AF_INET ||
787
      servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK) ||
788
      servers[0].tcp_port != 0 ||
789
      servers[0].udp_port != 0) {
790
    ares_free_data(servers);
791
    is_servers_default_ = false;
792
    return;
793
  }
794
795
  ares_free_data(servers);
796
  servers = nullptr;
797
798
  /* destroy channel and reset channel */
799
  ares_destroy(channel_);
800
801
  CloseTimer();
802
  Setup();
803
}
804
805
6
int AnyTraits::Send(QueryWrap<AnyTraits>* wrap, const char* name) {
806
6
  wrap->AresQuery(name, ns_c_in, ns_t_any);
807
6
  return 0;
808
}
809
810
36
int ATraits::Send(QueryWrap<ATraits>* wrap, const char* name) {
811
36
  wrap->AresQuery(name, ns_c_in, ns_t_a);
812
36
  return 0;
813
}
814
815
3
int AaaaTraits::Send(QueryWrap<AaaaTraits>* wrap, const char* name) {
816
3
  wrap->AresQuery(name, ns_c_in, ns_t_aaaa);
817
3
  return 0;
818
}
819
820
int CaaTraits::Send(QueryWrap<CaaTraits>* wrap, const char* name) {
821
  wrap->AresQuery(name, ns_c_in, T_CAA);
822
  return 0;
823
}
824
825
int CnameTraits::Send(QueryWrap<CnameTraits>* wrap, const char* name) {
826
  wrap->AresQuery(name, ns_c_in, ns_t_cname);
827
  return 0;
828
}
829
830
1
int MxTraits::Send(QueryWrap<MxTraits>* wrap, const char* name) {
831
1
  wrap->AresQuery(name, ns_c_in, ns_t_mx);
832
1
  return 0;
833
}
834
835
int NsTraits::Send(QueryWrap<NsTraits>* wrap, const char* name) {
836
  wrap->AresQuery(name, ns_c_in, ns_t_ns);
837
  return 0;
838
}
839
840
int TxtTraits::Send(QueryWrap<TxtTraits>* wrap, const char* name) {
841
  wrap->AresQuery(name, ns_c_in, ns_t_txt);
842
  return 0;
843
}
844
845
int SrvTraits::Send(QueryWrap<SrvTraits>* wrap, const char* name) {
846
  wrap->AresQuery(name, ns_c_in, ns_t_srv);
847
  return 0;
848
}
849
850
int PtrTraits::Send(QueryWrap<PtrTraits>* wrap, const char* name) {
851
  wrap->AresQuery(name, ns_c_in, ns_t_ptr);
852
  return 0;
853
}
854
855
int NaptrTraits::Send(QueryWrap<NaptrTraits>* wrap, const char* name) {
856
  wrap->AresQuery(name, ns_c_in, ns_t_naptr);
857
  return 0;
858
}
859
860
2
int SoaTraits::Send(QueryWrap<SoaTraits>* wrap, const char* name) {
861
2
  wrap->AresQuery(name, ns_c_in, ns_t_soa);
862
2
  return 0;
863
}
864
865
6
int AnyTraits::Parse(
866
    QueryAnyWrap* wrap,
867
    const std::unique_ptr<ResponseData>& response) {
868
6
  if (UNLIKELY(response->is_host))
869
    return ARES_EBADRESP;
870
871
6
  unsigned char* buf = response->buf.data;
872
6
  int len = response->buf.size;
873
874
6
  Environment* env = wrap->env();
875
12
  HandleScope handle_scope(env->isolate());
876
6
  Context::Scope context_scope(env->context());
877
878
6
  Local<Array> ret = Array::New(env->isolate());
879
  int type, status, old_count;
880
881
  /* Parse A records or CNAME records */
882
  ares_addrttl addrttls[256];
883
6
  int naddrttls = arraysize(addrttls);
884
885
6
  type = ns_t_cname_or_a;
886
  status = ParseGeneralReply(env,
887
                             buf,
888
                             len,
889
                             &type,
890
                             ret,
891
                             addrttls,
892
6
                             &naddrttls);
893
6
  uint32_t a_count = ret->Length();
894

6
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
895
2
    return status;
896
897
4
  if (type == ns_t_a) {
898
4
    CHECK_EQ(static_cast<uint32_t>(naddrttls), a_count);
899
8
    for (uint32_t i = 0; i < a_count; i++) {
900
4
      Local<Object> obj = Object::New(env->isolate());
901
8
      obj->Set(env->context(),
902
                env->address_string(),
903
24
                ret->Get(env->context(), i).ToLocalChecked()).Check();
904
8
      obj->Set(env->context(),
905
                env->ttl_string(),
906
                Integer::NewFromUnsigned(
907
20
                  env->isolate(), addrttls[i].ttl)).Check();
908
8
      obj->Set(env->context(),
909
                env->type_string(),
910
20
                env->dns_a_string()).Check();
911
12
      ret->Set(env->context(), i, obj).Check();
912
    }
913
  } else {
914
    for (uint32_t i = 0; i < a_count; i++) {
915
      Local<Object> obj = Object::New(env->isolate());
916
      obj->Set(env->context(),
917
                env->value_string(),
918
                ret->Get(env->context(), i).ToLocalChecked()).Check();
919
      obj->Set(env->context(),
920
                env->type_string(),
921
                env->dns_cname_string()).Check();
922
      ret->Set(env->context(), i, obj).Check();
923
    }
924
  }
925
926
  /* Parse AAAA records */
927
  ares_addr6ttl addr6ttls[256];
928
4
  int naddr6ttls = arraysize(addr6ttls);
929
930
4
  type = ns_t_aaaa;
931
  status = ParseGeneralReply(env,
932
                             buf,
933
                             len,
934
                             &type,
935
                             ret,
936
                             addr6ttls,
937
4
                             &naddr6ttls);
938
4
  uint32_t aaaa_count = ret->Length() - a_count;
939

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
940
    return status;
941
942
4
  CHECK_EQ(aaaa_count, static_cast<uint32_t>(naddr6ttls));
943
4
  CHECK_EQ(ret->Length(), a_count + aaaa_count);
944
16
  for (uint32_t i = a_count; i < ret->Length(); i++) {
945
4
    Local<Object> obj = Object::New(env->isolate());
946
8
    obj->Set(env->context(),
947
              env->address_string(),
948
24
              ret->Get(env->context(), i).ToLocalChecked()).Check();
949
8
    obj->Set(env->context(),
950
              env->ttl_string(),
951
              Integer::NewFromUnsigned(
952
20
                env->isolate(), addr6ttls[i - a_count].ttl)).Check();
953
8
    obj->Set(env->context(),
954
              env->type_string(),
955
20
              env->dns_aaaa_string()).Check();
956
12
    ret->Set(env->context(), i, obj).Check();
957
  }
958
959
  /* Parse MX records */
960
4
  status = ParseMxReply(env, buf, len, ret, true);
961

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
962
    return status;
963
964
  /* Parse NS records */
965
4
  type = ns_t_ns;
966
4
  old_count = ret->Length();
967
4
  status = ParseGeneralReply(env, buf, len, &type, ret);
968

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
969
    return status;
970
971
16
  for (uint32_t i = old_count; i < ret->Length(); i++) {
972
4
    Local<Object> obj = Object::New(env->isolate());
973
8
    obj->Set(env->context(),
974
             env->value_string(),
975
24
             ret->Get(env->context(), i).ToLocalChecked()).Check();
976
8
    obj->Set(env->context(),
977
              env->type_string(),
978
20
              env->dns_ns_string()).Check();
979
12
    ret->Set(env->context(), i, obj).Check();
980
  }
981
982
  /* Parse TXT records */
983
4
  status = ParseTxtReply(env, buf, len, ret, true);
984

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
985
    return status;
986
987
  /* Parse SRV records */
988
4
  status = ParseSrvReply(env, buf, len, ret, true);
989

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
990
    return status;
991
992
  /* Parse PTR records */
993
4
  type = ns_t_ptr;
994
4
  old_count = ret->Length();
995
4
  status = ParseGeneralReply(env, buf, len, &type, ret);
996

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
997
    return status;
998
16
  for (uint32_t i = old_count; i < ret->Length(); i++) {
999
4
    Local<Object> obj = Object::New(env->isolate());
1000
8
    obj->Set(env->context(),
1001
              env->value_string(),
1002
24
              ret->Get(env->context(), i).ToLocalChecked()).Check();
1003
8
    obj->Set(env->context(),
1004
              env->type_string(),
1005
20
              env->dns_ptr_string()).Check();
1006
12
    ret->Set(env->context(), i, obj).Check();
1007
  }
1008
1009
  /* Parse NAPTR records */
1010
4
  status = ParseNaptrReply(env, buf, len, ret, true);
1011

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
1012
    return status;
1013
1014
  /* Parse SOA records */
1015
  Local<Object> soa_record = Local<Object>();
1016
4
  status = ParseSoaReply(env, buf, len, &soa_record);
1017

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
1018
    return status;
1019
1020
4
  if (!soa_record.IsEmpty())
1021
12
    ret->Set(env->context(), ret->Length(), soa_record).Check();
1022
1023
  /* Parse CAA records */
1024
4
  status = ParseCaaReply(env, buf, len, ret, true);
1025

4
  if (status != ARES_SUCCESS && status != ARES_ENODATA)
1026
    return status;
1027
1028
4
  wrap->CallOnComplete(ret);
1029
4
  return 0;
1030
}
1031
1032
7
int ATraits::Parse(
1033
    QueryAWrap* wrap,
1034
    const std::unique_ptr<ResponseData>& response) {
1035
7
  if (UNLIKELY(response->is_host))
1036
    return ARES_EBADRESP;
1037
1038
7
  unsigned char* buf = response->buf.data;
1039
7
  int len = response->buf.size;
1040
1041
7
  Environment* env = wrap->env();
1042
14
  HandleScope handle_scope(env->isolate());
1043
7
  Context::Scope context_scope(env->context());
1044
1045
  ares_addrttl addrttls[256];
1046
7
  int naddrttls = arraysize(addrttls), status;
1047
7
  Local<Array> ret = Array::New(env->isolate());
1048
1049
7
  int type = ns_t_a;
1050
  status = ParseGeneralReply(env,
1051
                             buf,
1052
                             len,
1053
                             &type,
1054
                             ret,
1055
                             addrttls,
1056
7
                             &naddrttls);
1057
7
  if (status != ARES_SUCCESS)
1058
    return status;
1059
1060
7
  Local<Array> ttls = AddrTTLToArray<ares_addrttl>(env, addrttls, naddrttls);
1061
1062
7
  wrap->CallOnComplete(ret, ttls);
1063
7
  return 0;
1064
}
1065
1066
2
int AaaaTraits::Parse(
1067
    QueryAaaaWrap* wrap,
1068
    const std::unique_ptr<ResponseData>& response) {
1069
2
  if (UNLIKELY(response->is_host))
1070
    return ARES_EBADRESP;
1071
1072
2
  unsigned char* buf = response->buf.data;
1073
2
  int len = response->buf.size;
1074
1075
2
  Environment* env = wrap->env();
1076
4
  HandleScope handle_scope(env->isolate());
1077
2
  Context::Scope context_scope(env->context());
1078
1079
  ares_addr6ttl addrttls[256];
1080
2
  int naddrttls = arraysize(addrttls), status;
1081
2
  Local<Array> ret = Array::New(env->isolate());
1082
1083
2
  int type = ns_t_aaaa;
1084
  status = ParseGeneralReply(env,
1085
                             buf,
1086
                             len,
1087
                             &type,
1088
                             ret,
1089
                             addrttls,
1090
2
                             &naddrttls);
1091
2
  if (status != ARES_SUCCESS)
1092
    return status;
1093
1094
2
  Local<Array> ttls = AddrTTLToArray<ares_addr6ttl>(env, addrttls, naddrttls);
1095
1096
2
  wrap->CallOnComplete(ret, ttls);
1097
2
  return 0;
1098
}
1099
1100
int CaaTraits::Parse(
1101
    QueryCaaWrap* wrap,
1102
    const std::unique_ptr<ResponseData>& response) {
1103
  if (UNLIKELY(response->is_host))
1104
    return ARES_EBADRESP;
1105
1106
  unsigned char* buf = response->buf.data;
1107
  int len = response->buf.size;
1108
1109
  Environment* env = wrap->env();
1110
  HandleScope handle_scope(env->isolate());
1111
  Context::Scope context_scope(env->context());
1112
1113
  Local<Array> ret = Array::New(env->isolate());
1114
  int status = ParseCaaReply(env, buf, len, ret);
1115
  if (status != ARES_SUCCESS)
1116
    return status;
1117
1118
  wrap->CallOnComplete(ret);
1119
  return 0;
1120
}
1121
1122
int CnameTraits::Parse(
1123
    QueryCnameWrap* wrap,
1124
    const std::unique_ptr<ResponseData>& response) {
1125
  if (UNLIKELY(response->is_host))
1126
    return ARES_EBADRESP;
1127
1128
  unsigned char* buf = response->buf.data;
1129
  int len = response->buf.size;
1130
1131
  Environment* env = wrap->env();
1132
  HandleScope handle_scope(env->isolate());
1133
  Context::Scope context_scope(env->context());
1134
1135
  Local<Array> ret = Array::New(env->isolate());
1136
  int type = ns_t_cname;
1137
  int status = ParseGeneralReply(env, buf, len, &type, ret);
1138
  if (status != ARES_SUCCESS)
1139
    return status;
1140
1141
  wrap->CallOnComplete(ret);
1142
  return 0;
1143
}
1144
1145
int MxTraits::Parse(
1146
    QueryMxWrap* wrap,
1147
    const std::unique_ptr<ResponseData>& response) {
1148
  if (UNLIKELY(response->is_host))
1149
    return ARES_EBADRESP;
1150
1151
  unsigned char* buf = response->buf.data;
1152
  int len = response->buf.size;
1153
1154
  Environment* env = wrap->env();
1155
  HandleScope handle_scope(env->isolate());
1156
  Context::Scope context_scope(env->context());
1157
1158
  Local<Array> mx_records = Array::New(env->isolate());
1159
  int status = ParseMxReply(env, buf, len, mx_records);
1160
1161
  if (status != ARES_SUCCESS)
1162
    return status;
1163
1164
  wrap->CallOnComplete(mx_records);
1165
  return 0;
1166
}
1167
1168
int NsTraits::Parse(
1169
    QueryNsWrap* wrap,
1170
    const std::unique_ptr<ResponseData>& response) {
1171
  if (UNLIKELY(response->is_host))
1172
    return ARES_EBADRESP;
1173
1174
  unsigned char* buf = response->buf.data;
1175
  int len = response->buf.size;
1176
1177
  Environment* env = wrap->env();
1178
  HandleScope handle_scope(env->isolate());
1179
  Context::Scope context_scope(env->context());
1180
1181
  int type = ns_t_ns;
1182
  Local<Array> names = Array::New(env->isolate());
1183
  int status = ParseGeneralReply(env, buf, len, &type, names);
1184
  if (status != ARES_SUCCESS)
1185
    return status;
1186
1187
  wrap->CallOnComplete(names);
1188
  return 0;
1189
}
1190
1191
int TxtTraits::Parse(
1192
    QueryTxtWrap* wrap,
1193
    const std::unique_ptr<ResponseData>& response) {
1194
  if (UNLIKELY(response->is_host))
1195
    return ARES_EBADRESP;
1196
1197
  unsigned char* buf = response->buf.data;
1198
  int len = response->buf.size;
1199
1200
  Environment* env = wrap->env();
1201
  HandleScope handle_scope(env->isolate());
1202
  Context::Scope context_scope(env->context());
1203
1204
  Local<Array> txt_records = Array::New(env->isolate());
1205
  int status = ParseTxtReply(env, buf, len, txt_records);
1206
  if (status != ARES_SUCCESS)
1207
    return status;
1208
1209
  wrap->CallOnComplete(txt_records);
1210
  return 0;
1211
}
1212
1213
int SrvTraits::Parse(
1214
    QuerySrvWrap* wrap,
1215
    const std::unique_ptr<ResponseData>& response) {
1216
  if (UNLIKELY(response->is_host))
1217
    return ARES_EBADRESP;
1218
1219
  unsigned char* buf = response->buf.data;
1220
  int len = response->buf.size;
1221
1222
  Environment* env = wrap->env();
1223
  HandleScope handle_scope(env->isolate());
1224
  Context::Scope context_scope(env->context());
1225
1226
  Local<Array> srv_records = Array::New(env->isolate());
1227
  int status = ParseSrvReply(env, buf, len, srv_records);
1228
  if (status != ARES_SUCCESS)
1229
    return status;
1230
1231
  wrap->CallOnComplete(srv_records);
1232
  return 0;
1233
}
1234
1235
int PtrTraits::Parse(
1236
    QueryPtrWrap* wrap,
1237
    const std::unique_ptr<ResponseData>& response) {
1238
  if (UNLIKELY(response->is_host))
1239
    return ARES_EBADRESP;
1240
1241
  unsigned char* buf = response->buf.data;
1242
  int len = response->buf.size;
1243
1244
  Environment* env = wrap->env();
1245
  HandleScope handle_scope(env->isolate());
1246
  Context::Scope context_scope(env->context());
1247
1248
  int type = ns_t_ptr;
1249
  Local<Array> aliases = Array::New(env->isolate());
1250
1251
  int status = ParseGeneralReply(env, buf, len, &type, aliases);
1252
  if (status != ARES_SUCCESS)
1253
    return status;
1254
1255
  wrap->CallOnComplete(aliases);
1256
  return 0;
1257
}
1258
1259
int NaptrTraits::Parse(
1260
    QueryNaptrWrap* wrap,
1261
    const std::unique_ptr<ResponseData>& response) {
1262
  if (UNLIKELY(response->is_host))
1263
    return ARES_EBADRESP;
1264
1265
  unsigned char* buf = response->buf.data;
1266
  int len = response->buf.size;
1267
1268
  Environment* env = wrap->env();
1269
  HandleScope handle_scope(env->isolate());
1270
  Context::Scope context_scope(env->context());
1271
1272
  Local<Array> naptr_records = Array::New(env->isolate());
1273
  int status = ParseNaptrReply(env, buf, len, naptr_records);
1274
  if (status != ARES_SUCCESS)
1275
    return status;
1276
1277
  wrap->CallOnComplete(naptr_records);
1278
  return 0;
1279
}
1280
1281
2
int SoaTraits::Parse(
1282
    QuerySoaWrap* wrap,
1283
    const std::unique_ptr<ResponseData>& response) {
1284
2
  if (UNLIKELY(response->is_host))
1285
    return ARES_EBADRESP;
1286
1287
2
  unsigned char* buf = response->buf.data;
1288
2
  int len = response->buf.size;
1289
1290
2
  Environment* env = wrap->env();
1291
4
  HandleScope handle_scope(env->isolate());
1292
2
  Context::Scope context_scope(env->context());
1293
1294
  ares_soa_reply* soa_out;
1295
2
  int status = ares_parse_soa_reply(buf, len, &soa_out);
1296
1297
2
  if (status != ARES_SUCCESS)
1298
    return status;
1299
1300
2
  Local<Object> soa_record = Object::New(env->isolate());
1301
1302
4
  soa_record->Set(env->context(),
1303
                  env->nsname_string(),
1304
10
                  OneByteString(env->isolate(), soa_out->nsname)).Check();
1305
4
  soa_record->Set(env->context(),
1306
                  env->hostmaster_string(),
1307
10
                  OneByteString(env->isolate(), soa_out->hostmaster)).Check();
1308
4
  soa_record->Set(env->context(),
1309
                  env->serial_string(),
1310
                  Integer::NewFromUnsigned(
1311
10
                      env->isolate(), soa_out->serial)).Check();
1312
4
  soa_record->Set(env->context(),
1313
                  env->refresh_string(),
1314
10
                  Integer::New(env->isolate(), soa_out->refresh)).Check();
1315
4
  soa_record->Set(env->context(),
1316
                  env->retry_string(),
1317
10
                  Integer::New(env->isolate(), soa_out->retry)).Check();
1318
4
  soa_record->Set(env->context(),
1319
                  env->expire_string(),
1320
10
                  Integer::New(env->isolate(), soa_out->expire)).Check();
1321
4
  soa_record->Set(env->context(),
1322
                  env->minttl_string(),
1323
                  Integer::NewFromUnsigned(
1324
10
                      env->isolate(), soa_out->minttl)).Check();
1325
1326
2
  ares_free_data(soa_out);
1327
1328
2
  wrap->CallOnComplete(soa_record);
1329
2
  return 0;
1330
}
1331
1332
3
int ReverseTraits::Send(GetHostByAddrWrap* wrap, const char* name) {
1333
  int length, family;
1334
  char address_buffer[sizeof(struct in6_addr)];
1335
1336
3
  if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) {
1337
3
    length = sizeof(struct in_addr);
1338
3
    family = AF_INET;
1339
  } else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) {
1340
    length = sizeof(struct in6_addr);
1341
    family = AF_INET6;
1342
  } else {
1343
    return UV_EINVAL;  // So errnoException() reports a proper error.
1344
  }
1345
1346
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
1347
3
      TRACING_CATEGORY_NODE2(dns, native), "reverse", wrap,
1348
3
      "name", TRACE_STR_COPY(name),
1349
2
      "family", family == AF_INET ? "ipv4" : "ipv6");
1350
8
1351
9
  ares_gethostbyaddr(
1352
3
      wrap->channel()->cares_channel(),
1353
      address_buffer,
1354
      length,
1355
      family,
1356
      GetHostByAddrWrap::Callback,
1357
3
      wrap->MakeCallbackPointer());
1358
3
  return 0;
1359
}
1360
1361
2
int ReverseTraits::Parse(
1362
    GetHostByAddrWrap* wrap,
1363
    const std::unique_ptr<ResponseData>& response) {
1364
2
  if (UNLIKELY(!response->is_host))
1365
    return ARES_EBADRESP;
1366
1367
2
  struct hostent* host = response->host.get();
1368
1369
2
  Environment* env = wrap->env();
1370
4
  HandleScope handle_scope(env->isolate());
1371
2
  Context::Scope context_scope(env->context());
1372
4
  wrap->CallOnComplete(HostentToNames(env, host));
1373
2
  return 0;
1374
}
1375
1376
namespace {
1377
template <class Wrap>
1378
51
static void Query(const FunctionCallbackInfo<Value>& args) {
1379
51
  Environment* env = Environment::GetCurrent(args);
1380
  ChannelWrap* channel;
1381






51
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
1382
1383






51
  CHECK_EQ(false, args.IsConstructCall());
1384






102
  CHECK(args[0]->IsObject());
1385






153
  CHECK(args[1]->IsString());
1386
1387
102
  Local<Object> req_wrap_obj = args[0].As<Object>();
1388
102
  Local<String> string = args[1].As<String>();
1389
102
  auto wrap = std::make_unique<Wrap>(channel, req_wrap_obj);
1390
1391
102
  node::Utf8Value name(env->isolate(), string);
1392
51
  channel->ModifyActivityQueryCount(1);
1393
51
  int err = wrap->Send(*name);
1394






51
  if (err) {
1395
    channel->ModifyActivityQueryCount(-1);
1396
  } else {
1397
    // Release ownership of the pointer allowing the ownership to be transferred
1398
51
    USE(wrap.release());
1399
  }
1400
1401
102
  args.GetReturnValue().Set(err);
1402
}
1403
1404
1405
5148
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
1406
  std::unique_ptr<GetAddrInfoReqWrap> req_wrap {
1407
10296
      static_cast<GetAddrInfoReqWrap*>(req->data)};
1408
5148
  Environment* env = req_wrap->env();
1409
1410
10296
  HandleScope handle_scope(env->isolate());
1411
5148
  Context::Scope context_scope(env->context());
1412
1413
  Local<Value> argv[] = {
1414
    Integer::New(env->isolate(), status),
1415
    Null(env->isolate())
1416
15444
  };
1417
1418
5148
  uint32_t n = 0;
1419
5148
  const bool verbatim = req_wrap->verbatim();
1420
1421
5148
  if (status == 0) {
1422
5139
    Local<Array> results = Array::New(env->isolate());
1423
1424
10278
    auto add = [&] (bool want_ipv4, bool want_ipv6) {
1425
41810
      for (auto p = res; p != nullptr; p = p->ai_next) {
1426
31532
        CHECK_EQ(p->ai_socktype, SOCK_STREAM);
1427
1428
        const char* addr;
1429

31532
        if (want_ipv4 && p->ai_family == AF_INET) {
1430
5350
          addr = reinterpret_cast<char*>(
1431
10700
              &(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr));
1432

26182
        } else if (want_ipv6 && p->ai_family == AF_INET6) {
1433
10416
          addr = reinterpret_cast<char*>(
1434
20832
              &(reinterpret_cast<struct sockaddr_in6*>(p->ai_addr)->sin6_addr));
1435
        } else {
1436
31532
          continue;
1437
        }
1438
1439
        char ip[INET6_ADDRSTRLEN];
1440
15766
        if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip)))
1441
          continue;
1442
1443
31532
        Local<String> s = OneByteString(env->isolate(), ip);
1444
63064
        results->Set(env->context(), n, s).Check();
1445
15766
        n++;
1446
      }
1447
15417
    };
1448
1449
5139
    add(true, verbatim);
1450
5139
    if (verbatim == false)
1451
5139
      add(false, true);
1452
1453
    // No responses were found to return
1454
5139
    if (n == 0) {
1455
      argv[0] = Integer::New(env->isolate(), UV_EAI_NODATA);
1456
    }
1457
1458
5139
    argv[1] = results;
1459
  }
1460
1461
5148
  uv_freeaddrinfo(res);
1462
1463
  TRACE_EVENT_NESTABLE_ASYNC_END2(
1464
5148
      TRACING_CATEGORY_NODE2(dns, native), "lookup", req_wrap.get(),
1465
5148
      "count", n, "verbatim", verbatim);
1466
791
1467
11087
  // Make the callback into JavaScript
1468
10296
  req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);
1469
5148
}
1470
1471
1472
4
void AfterGetNameInfo(uv_getnameinfo_t* req,
1473
                      int status,
1474
                      const char* hostname,
1475
                      const char* service) {
1476
  std::unique_ptr<GetNameInfoReqWrap> req_wrap {
1477
8
      static_cast<GetNameInfoReqWrap*>(req->data)};
1478
4
  Environment* env = req_wrap->env();
1479
1480
8
  HandleScope handle_scope(env->isolate());
1481
4
  Context::Scope context_scope(env->context());
1482
1483
  Local<Value> argv[] = {
1484
    Integer::New(env->isolate(), status),
1485
    Null(env->isolate()),
1486
    Null(env->isolate())
1487
16
  };
1488
1489
4
  if (status == 0) {
1490
    // Success
1491
3
    Local<String> js_hostname = OneByteString(env->isolate(), hostname);
1492
3
    Local<String> js_service = OneByteString(env->isolate(), service);
1493
3
    argv[1] = js_hostname;
1494
3
    argv[2] = js_service;
1495
  }
1496
1497
  TRACE_EVENT_NESTABLE_ASYNC_END2(
1498
4
      TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(),
1499
4
      "hostname", TRACE_STR_COPY(hostname),
1500
3
      "service", TRACE_STR_COPY(service));
1501
11
1502
4
  // Make the callback into JavaScript
1503
4
  req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);
1504
4
}
1505
1506
using ParseIPResult =
1507
    decltype(static_cast<ares_addr_port_node*>(nullptr)->addr);
1508
1509
26
int ParseIP(const char* ip, ParseIPResult* result = nullptr) {
1510
  ParseIPResult tmp;
1511
26
  if (result == nullptr) result = &tmp;
1512
26
  if (0 == uv_inet_pton(AF_INET, ip, result)) return 4;
1513
10
  if (0 == uv_inet_pton(AF_INET6, ip, result)) return 6;
1514
1
  return 0;
1515
}
1516
1517
26
void CanonicalizeIP(const FunctionCallbackInfo<Value>& args) {
1518
26
  Isolate* isolate = args.GetIsolate();
1519
51
  node::Utf8Value ip(isolate, args[0]);
1520
1521
  ParseIPResult result;
1522
26
  const int rc = ParseIP(*ip, &result);
1523
26
  if (rc == 0) return;
1524
1525
  char canonical_ip[INET6_ADDRSTRLEN];
1526
25
  const int af = (rc == 4 ? AF_INET : AF_INET6);
1527
25
  CHECK_EQ(0, uv_inet_ntop(af, &result, canonical_ip, sizeof(canonical_ip)));
1528
50
  Local<String> val = String::NewFromUtf8(isolate, canonical_ip)
1529
25
      .ToLocalChecked();
1530
50
  args.GetReturnValue().Set(val);
1531
}
1532
1533
5149
void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
1534
5149
  Environment* env = Environment::GetCurrent(args);
1535
1536
10298
  CHECK(args[0]->IsObject());
1537
15447
  CHECK(args[1]->IsString());
1538
10298
  CHECK(args[2]->IsInt32());
1539
10298
  CHECK(args[4]->IsBoolean());
1540
10298
  Local<Object> req_wrap_obj = args[0].As<Object>();
1541
10298
  node::Utf8Value hostname(env->isolate(), args[1]);
1542
1543
5149
  int32_t flags = 0;
1544
10298
  if (args[3]->IsInt32()) {
1545
15447
    flags = args[3].As<Int32>()->Value();
1546
  }
1547
1548
  int family;
1549
1550

15447
  switch (args[2].As<Int32>()->Value()) {
1551
    case 0:
1552
5133
      family = AF_UNSPEC;
1553
5133
      break;
1554
    case 4:
1555
14
      family = AF_INET;
1556
14
      break;
1557
    case 6:
1558
2
      family = AF_INET6;
1559
2
      break;
1560
    default:
1561
      CHECK(0 && "bad address family");
1562
  }
1563
1564
  auto req_wrap = std::make_unique<GetAddrInfoReqWrap>(env,
1565
                                                       req_wrap_obj,
1566
15447
                                                       args[4]->IsTrue());
1567
1568
  struct addrinfo hints;
1569
5149
  memset(&hints, 0, sizeof(hints));
1570
5149
  hints.ai_family = family;
1571
5149
  hints.ai_socktype = SOCK_STREAM;
1572
5149
  hints.ai_flags = flags;
1573
1574
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
1575
5149
      TRACING_CATEGORY_NODE2(dns, native), "lookup", req_wrap.get(),
1576
5149
      "hostname", TRACE_STR_COPY(*hostname),
1577
792
      "family",
1578
11090
      family == AF_INET ? "ipv4" : family == AF_INET6 ? "ipv6" : "unspec");
1579
5149
1580
5149
  int err = req_wrap->Dispatch(uv_getaddrinfo,
1581
                               AfterGetAddrInfo,
1582
                               *hostname,
1583
                               nullptr,
1584
5149
                               &hints);
1585
5149
  if (err == 0)
1586
    // Release ownership of the pointer allowing the ownership to be transferred
1587
5149
    USE(req_wrap.release());
1588
1589
10298
  args.GetReturnValue().Set(err);
1590
5149
}
1591
1592
1593
4
void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
1594
4
  Environment* env = Environment::GetCurrent(args);
1595
1596
8
  CHECK(args[0]->IsObject());
1597
12
  CHECK(args[1]->IsString());
1598
8
  CHECK(args[2]->IsUint32());
1599
8
  Local<Object> req_wrap_obj = args[0].As<Object>();
1600
8
  node::Utf8Value ip(env->isolate(), args[1]);
1601
16
  const unsigned port = args[2]->Uint32Value(env->context()).FromJust();
1602
  struct sockaddr_storage addr;
1603
1604

4
  CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 ||
1605
        uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0);
1606
1607
8
  auto req_wrap = std::make_unique<GetNameInfoReqWrap>(env, req_wrap_obj);
1608
1609
4
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
1610
      TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(),
1611
4
      "ip", TRACE_STR_COPY(*ip), "port", port);
1612
3
1613
15
  int err = req_wrap->Dispatch(uv_getnameinfo,
1614
4
                               AfterGetNameInfo,
1615
                               reinterpret_cast<struct sockaddr*>(&addr),
1616
4
                               NI_NAMEREQD);
1617
4
  if (err == 0)
1618
    // Release ownership of the pointer allowing the ownership to be transferred
1619
4
    USE(req_wrap.release());
1620
1621
8
  args.GetReturnValue().Set(err);
1622
4
}
1623
1624
1625
65
void GetServers(const FunctionCallbackInfo<Value>& args) {
1626
65
  Environment* env = Environment::GetCurrent(args);
1627
  ChannelWrap* channel;
1628
65
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
1629
1630
65
  Local<Array> server_array = Array::New(env->isolate());
1631
1632
  ares_addr_port_node* servers;
1633
1634
65
  int r = ares_get_servers_ports(channel->cares_channel(), &servers);
1635
65
  CHECK_EQ(r, ARES_SUCCESS);
1636
195
  auto cleanup = OnScopeLeave([&]() { ares_free_data(servers); });
1637
1638
65
  ares_addr_port_node* cur = servers;
1639
1640
141
  for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) {
1641
    char ip[INET6_ADDRSTRLEN];
1642
1643
76
    const void* caddr = static_cast<const void*>(&cur->addr);
1644
76
    int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
1645
76
    CHECK_EQ(err, 0);
1646
1647
    Local<Value> ret[] = {
1648
      OneByteString(env->isolate(), ip),
1649
      Integer::New(env->isolate(), cur->udp_port)
1650
228
    };
1651
1652
228
    if (server_array->Set(env->context(), i,
1653
228
                          Array::New(env->isolate(), ret, arraysize(ret)))
1654
          .IsNothing()) {
1655
      return;
1656
    }
1657
  }
1658
1659
130
  args.GetReturnValue().Set(server_array);
1660
}
1661
1662
1663
28
void SetServers(const FunctionCallbackInfo<Value>& args) {
1664
28
  Environment* env = Environment::GetCurrent(args);
1665
  ChannelWrap* channel;
1666
32
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
1667
1668
28
  if (channel->active_query_count()) {
1669
4
    return args.GetReturnValue().Set(DNS_ESETSRVPENDING);
1670
  }
1671
1672
52
  CHECK(args[0]->IsArray());
1673
1674
26
  Local<Array> arr = Local<Array>::Cast(args[0]);
1675
1676
26
  uint32_t len = arr->Length();
1677
1678
26
  if (len == 0) {
1679
2
    int rv = ares_set_servers(channel->cares_channel(), nullptr);
1680
4
    return args.GetReturnValue().Set(rv);
1681
  }
1682
1683
48
  std::vector<ares_addr_port_node> servers(len);
1684
24
  ares_addr_port_node* last = nullptr;
1685
1686
  int err;
1687
1688
59
  for (uint32_t i = 0; i < len; i++) {
1689
140
    CHECK(arr->Get(env->context(), i).ToLocalChecked()->IsArray());
1690
1691
    Local<Array> elm =
1692
105
        Local<Array>::Cast(arr->Get(env->context(), i).ToLocalChecked());
1693
1694
175
    CHECK(elm->Get(env->context(),
1695
                   0).ToLocalChecked()->Int32Value(env->context()).FromJust());
1696
175
    CHECK(elm->Get(env->context(), 1).ToLocalChecked()->IsString());
1697
175
    CHECK(elm->Get(env->context(),
1698
                   2).ToLocalChecked()->Int32Value(env->context()).FromJust());
1699
1700
105
    int fam = elm->Get(env->context(), 0)
1701
140
        .ToLocalChecked()->Int32Value(env->context()).FromJust();
1702
    node::Utf8Value ip(env->isolate(),
1703
140
                       elm->Get(env->context(), 1).ToLocalChecked());
1704
105
    int port = elm->Get(env->context(), 2)
1705
140
        .ToLocalChecked()->Int32Value(env->context()).FromJust();
1706
1707
35
    ares_addr_port_node* cur = &servers[i];
1708
1709
35
    cur->tcp_port = cur->udp_port = port;
1710
35
    switch (fam) {
1711
      case 4:
1712
28
        cur->family = AF_INET;
1713
28
        err = uv_inet_pton(AF_INET, *ip, &cur->addr);
1714
28
        break;
1715
      case 6:
1716
7
        cur->family = AF_INET6;
1717
7
        err = uv_inet_pton(AF_INET6, *ip, &cur->addr);
1718
7
        break;
1719
      default:
1720
        CHECK(0 && "Bad address family.");
1721
    }
1722
1723
35
    if (err)
1724
      break;
1725
1726
35
    cur->next = nullptr;
1727
1728
35
    if (last != nullptr)
1729
11
      last->next = cur;
1730
1731
35
    last = cur;
1732
  }
1733
1734
24
  if (err == 0)
1735
24
    err = ares_set_servers_ports(channel->cares_channel(), &servers[0]);
1736
  else
1737
    err = ARES_EBADSTR;
1738
1739
24
  if (err == ARES_SUCCESS)
1740
24
    channel->set_is_servers_default(false);
1741
1742
48
  args.GetReturnValue().Set(err);
1743
}
1744
1745
7
void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
1746
7
  Environment* env = Environment::GetCurrent(args);
1747
  ChannelWrap* channel;
1748
10
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
1749
1750
7
  CHECK_EQ(args.Length(), 2);
1751
21
  CHECK(args[0]->IsString());
1752
1753
7
  Isolate* isolate = args.GetIsolate();
1754
11
  node::Utf8Value ip0(isolate, args[0]);
1755
1756
  unsigned char addr0[sizeof(struct in6_addr)];
1757
  unsigned char addr1[sizeof(struct in6_addr)];
1758
7
  int type0 = 0;
1759
1760
  // This function accepts 2 arguments.  The first may be either an IPv4
1761
  // address or an IPv6 address.  If present, the second argument must be the
1762
  // other type of address.  Otherwise, the unspecified type of IP is set
1763
  // to 0 (any).
1764
1765
7
  if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) {
1766
4
    ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr0));
1767
4
    type0 = 4;
1768
3
  } else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) {
1769
2
    ares_set_local_ip6(channel->cares_channel(), addr0);
1770
2
    type0 = 6;
1771
  } else {
1772
1
    THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
1773
1
    return;
1774
  }
1775
1776
18
  if (!args[1]->IsUndefined()) {
1777
12
    CHECK(args[1]->IsString());
1778
6
    node::Utf8Value ip1(isolate, args[1]);
1779
1780
4
    if (uv_inet_pton(AF_INET, *ip1, &addr1) == 0) {
1781
1
      if (type0 == 4) {
1782
1
        THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses.");
1783
1
        return;
1784
      } else {
1785
        ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr1));
1786
      }
1787
3
    } else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) {
1788
3
      if (type0 == 6) {
1789
1
        THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv6 addresses.");
1790
1
        return;
1791
      } else {
1792
2
        ares_set_local_ip6(channel->cares_channel(), addr1);
1793
      }
1794
    } else {
1795
      THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
1796
      return;
1797
    }
1798
  } else {
1799
    // No second arg specifed
1800
2
    if (type0 == 4) {
1801
1
      memset(&addr1, 0, sizeof(addr1));
1802
1
      ares_set_local_ip6(channel->cares_channel(), addr1);
1803
    } else {
1804
1
      ares_set_local_ip4(channel->cares_channel(), 0);
1805
    }
1806
  }
1807
}
1808
1809
6
void Cancel(const FunctionCallbackInfo<Value>& args) {
1810
  ChannelWrap* channel;
1811
6
  ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
1812
1813
6
  TRACE_EVENT_INSTANT0(TRACING_CATEGORY_NODE2(dns, native),
1814
      "cancel", TRACE_EVENT_SCOPE_THREAD);
1815
6
1816
10
  ares_cancel(channel->cares_channel());
1817
16
}
1818
6
1819
const char EMSG_ESETSRVPENDING[] = "There are pending queries.";
1820
1
void StrError(const FunctionCallbackInfo<Value>& args) {
1821
1
  Environment* env = Environment::GetCurrent(args);
1822
4
  int code = args[0]->Int32Value(env->context()).FromJust();
1823
1
  const char* errmsg = (code == DNS_ESETSRVPENDING) ?
1824
    EMSG_ESETSRVPENDING :
1825
1
    ares_strerror(code);
1826
3
  args.GetReturnValue().Set(OneByteString(env->isolate(), errmsg));
1827
1
}
1828
1829
}  // namespace
1830
1831
2
inline void safe_free_hostent(struct hostent* host) {
1832
  int idx;
1833
1834
2
  if (host->h_addr_list != nullptr) {
1835
2
    idx = 0;
1836
6
    while (host->h_addr_list[idx]) {
1837
2
      free(host->h_addr_list[idx++]);
1838
    }
1839
2
    free(host->h_addr_list);
1840
2
    host->h_addr_list = nullptr;
1841
  }
1842
1843
2
  if (host->h_aliases != nullptr) {
1844
2
    idx = 0;
1845
2
    while (host->h_aliases[idx]) {
1846
      free(host->h_aliases[idx++]);
1847
    }
1848
2
    free(host->h_aliases);
1849
2
    host->h_aliases = nullptr;
1850
  }
1851
1852
2
  free(host->h_name);
1853
2
  free(host);
1854
2
}
1855
1856
1155
void Initialize(Local<Object> target,
1857
                Local<Value> unused,
1858
                Local<Context> context,
1859
                void* priv) {
1860
1155
  Environment* env = Environment::GetCurrent(context);
1861
1862
1155
  env->SetMethod(target, "getaddrinfo", GetAddrInfo);
1863
1155
  env->SetMethod(target, "getnameinfo", GetNameInfo);
1864
1155
  env->SetMethodNoSideEffect(target, "canonicalizeIP", CanonicalizeIP);
1865
1866
1155
  env->SetMethod(target, "strerror", StrError);
1867
1868
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"),
1869
5775
              Integer::New(env->isolate(), AF_INET)).Check();
1870
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"),
1871
5775
              Integer::New(env->isolate(), AF_INET6)).Check();
1872
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(),
1873
                                                    "AF_UNSPEC"),
1874
5775
              Integer::New(env->isolate(), AF_UNSPEC)).Check();
1875
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(),
1876
                                                    "AI_ADDRCONFIG"),
1877
5775
              Integer::New(env->isolate(), AI_ADDRCONFIG)).Check();
1878
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(),
1879
                                                    "AI_ALL"),
1880
5775
              Integer::New(env->isolate(), AI_ALL)).Check();
1881
2310
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(),
1882
                                                    "AI_V4MAPPED"),
1883
5775
              Integer::New(env->isolate(), AI_V4MAPPED)).Check();
1884
1885
  Local<FunctionTemplate> aiw =
1886
1155
      BaseObject::MakeLazilyInitializedJSTemplate(env);
1887
2310
  aiw->Inherit(AsyncWrap::GetConstructorTemplate(env));
1888
1155
  env->SetConstructorFunction(target, "GetAddrInfoReqWrap", aiw);
1889
1890
  Local<FunctionTemplate> niw =
1891
1155
      BaseObject::MakeLazilyInitializedJSTemplate(env);
1892
2310
  niw->Inherit(AsyncWrap::GetConstructorTemplate(env));
1893
1155
  env->SetConstructorFunction(target, "GetNameInfoReqWrap", niw);
1894
1895
  Local<FunctionTemplate> qrw =
1896
1155
      BaseObject::MakeLazilyInitializedJSTemplate(env);
1897
2310
  qrw->Inherit(AsyncWrap::GetConstructorTemplate(env));
1898
1155
  env->SetConstructorFunction(target, "QueryReqWrap", qrw);
1899
1900
  Local<FunctionTemplate> channel_wrap =
1901
1155
      env->NewFunctionTemplate(ChannelWrap::New);
1902
3465
  channel_wrap->InstanceTemplate()->SetInternalFieldCount(
1903
1155
      ChannelWrap::kInternalFieldCount);
1904
2310
  channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env));
1905
1906
1155
  env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>);
1907
1155
  env->SetProtoMethod(channel_wrap, "queryA", Query<QueryAWrap>);
1908
1155
  env->SetProtoMethod(channel_wrap, "queryAaaa", Query<QueryAaaaWrap>);
1909
1155
  env->SetProtoMethod(channel_wrap, "queryCaa", Query<QueryCaaWrap>);
1910
1155
  env->SetProtoMethod(channel_wrap, "queryCname", Query<QueryCnameWrap>);
1911
1155
  env->SetProtoMethod(channel_wrap, "queryMx", Query<QueryMxWrap>);
1912
1155
  env->SetProtoMethod(channel_wrap, "queryNs", Query<QueryNsWrap>);
1913
1155
  env->SetProtoMethod(channel_wrap, "queryTxt", Query<QueryTxtWrap>);
1914
1155
  env->SetProtoMethod(channel_wrap, "querySrv", Query<QuerySrvWrap>);
1915
1155
  env->SetProtoMethod(channel_wrap, "queryPtr", Query<QueryPtrWrap>);
1916
1155
  env->SetProtoMethod(channel_wrap, "queryNaptr", Query<QueryNaptrWrap>);
1917
1155
  env->SetProtoMethod(channel_wrap, "querySoa", Query<QuerySoaWrap>);
1918
1155
  env->SetProtoMethod(channel_wrap, "getHostByAddr", Query<GetHostByAddrWrap>);
1919
1920
1155
  env->SetProtoMethodNoSideEffect(channel_wrap, "getServers", GetServers);
1921
1155
  env->SetProtoMethod(channel_wrap, "setServers", SetServers);
1922
1155
  env->SetProtoMethod(channel_wrap, "setLocalAddress", SetLocalAddress);
1923
1155
  env->SetProtoMethod(channel_wrap, "cancel", Cancel);
1924
1925
1155
  env->SetConstructorFunction(target, "ChannelWrap", channel_wrap);
1926
1155
}
1927
1928
}  // namespace cares_wrap
1929
}  // namespace node
1930
1931

19308
NODE_MODULE_CONTEXT_AWARE_INTERNAL(cares_wrap, node::cares_wrap::Initialize)