GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: cares_wrap.h Lines: 136 162 84.0 %
Date: 2022-05-22 04:15:48 Branches: 39 71 54.9 %

Line Branch Exec Source
1
#ifndef SRC_CARES_WRAP_H_
2
#define SRC_CARES_WRAP_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#define CARES_STATICLIB
7
8
#include "async_wrap.h"
9
#include "base_object.h"
10
#include "env.h"
11
#include "memory_tracker.h"
12
#include "util.h"
13
#include "node.h"
14
15
#include "ares.h"
16
#include "v8.h"
17
#include "uv.h"
18
19
#include <unordered_set>
20
21
#ifdef __POSIX__
22
# include <netdb.h>
23
#endif  // __POSIX__
24
25
# include <ares_nameser.h>
26
27
namespace node {
28
namespace cares_wrap {
29
30
constexpr int ns_t_cname_or_a = -1;
31
constexpr int DNS_ESETSRVPENDING = -1000;
32
33
class ChannelWrap;
34
35
inline void safe_free_hostent(struct hostent* host);
36
37
using HostEntPointer = DeleteFnPtr<hostent, ares_free_hostent>;
38
using SafeHostEntPointer = DeleteFnPtr<hostent, safe_free_hostent>;
39
40
33
inline const char* ToErrorCodeString(int status) {
41






33
  switch (status) {
42
#define V(code) case ARES_##code: return #code;
43
    V(EADDRGETNETWORKPARAMS)
44
    V(EBADFAMILY)
45
    V(EBADFLAGS)
46
    V(EBADHINTS)
47
    V(EBADNAME)
48
    V(EBADQUERY)
49
2
    V(EBADRESP)
50
    V(EBADSTR)
51
24
    V(ECANCELLED)
52
    V(ECONNREFUSED)
53
    V(EDESTRUCTION)
54
    V(EFILE)
55
    V(EFORMERR)
56
    V(ELOADIPHLPAPI)
57
    V(ENODATA)
58
    V(ENOMEM)
59
    V(ENONAME)
60
1
    V(ENOTFOUND)
61
    V(ENOTIMP)
62
    V(ENOTINITIALIZED)
63
    V(EOF)
64
    V(EREFUSED)
65
    V(ESERVFAIL)
66
6
    V(ETIMEOUT)
67
#undef V
68
  }
69
70
  return "UNKNOWN_ARES_ERROR";
71
}
72
73
2
inline void cares_wrap_hostent_cpy(
74
    struct hostent* dest,
75
    const struct hostent* src) {
76
2
  dest->h_addr_list = nullptr;
77
2
  dest->h_addrtype = 0;
78
2
  dest->h_aliases = nullptr;
79
2
  dest->h_length = 0;
80
2
  dest->h_name = nullptr;
81
82
  /* copy `h_name` */
83
2
  size_t name_size = strlen(src->h_name) + 1;
84
2
  dest->h_name = node::Malloc<char>(name_size);
85
2
  memcpy(dest->h_name, src->h_name, name_size);
86
87
  /* copy `h_aliases` */
88
  size_t alias_count;
89
2
  for (alias_count = 0;
90
2
      src->h_aliases[alias_count] != nullptr;
91
      alias_count++) {
92
  }
93
94
2
  dest->h_aliases = node::Malloc<char*>(alias_count + 1);
95
2
  for (size_t i = 0; i < alias_count; i++) {
96
    const size_t cur_alias_size = strlen(src->h_aliases[i]) + 1;
97
    dest->h_aliases[i] = node::Malloc(cur_alias_size);
98
    memcpy(dest->h_aliases[i], src->h_aliases[i], cur_alias_size);
99
  }
100
2
  dest->h_aliases[alias_count] = nullptr;
101
102
  /* copy `h_addr_list` */
103
  size_t list_count;
104
4
  for (list_count = 0;
105
4
      src->h_addr_list[list_count] != nullptr;
106
      list_count++) {
107
  }
108
109
2
  dest->h_addr_list = node::Malloc<char*>(list_count + 1);
110
4
  for (size_t i = 0; i < list_count; i++) {
111
2
    dest->h_addr_list[i] = node::Malloc(src->h_length);
112
2
    memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length);
113
  }
114
2
  dest->h_addr_list[list_count] = nullptr;
115
116
  /* work after work */
117
2
  dest->h_length = src->h_length;
118
2
  dest->h_addrtype = src->h_addrtype;
119
2
}
120
121
122
struct NodeAresTask final : public MemoryRetainer {
123
  ChannelWrap* channel;
124
  ares_socket_t sock;
125
  uv_poll_t poll_watcher;
126
127
  inline void MemoryInfo(MemoryTracker* trakcer) const override;
128
  SET_MEMORY_INFO_NAME(NodeAresTask)
129
  SET_SELF_SIZE(NodeAresTask)
130
131
  struct Hash {
132
87
    inline size_t operator()(NodeAresTask* a) const {
133
87
      return std::hash<ares_socket_t>()(a->sock);
134
    }
135
  };
136
137
  struct Equal {
138
29
    inline bool operator()(NodeAresTask* a, NodeAresTask* b) const {
139
29
      return a->sock == b->sock;
140
    }
141
  };
142
143
  static NodeAresTask* Create(ChannelWrap* channel, ares_socket_t sock);
144
145
  using List = std::unordered_set<NodeAresTask*, Hash, Equal>;
146
};
147
148
class ChannelWrap final : public AsyncWrap {
149
 public:
150
  ChannelWrap(
151
      Environment* env,
152
      v8::Local<v8::Object> object,
153
      int timeout,
154
      int tries);
155
  ~ChannelWrap() override;
156
157
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
158
159
  void Setup();
160
  void EnsureServers();
161
  void StartTimer();
162
  void CloseTimer();
163
164
  void ModifyActivityQueryCount(int count);
165
166
87
  inline uv_timer_t* timer_handle() { return timer_handle_; }
167
245
  inline ares_channel cares_channel() { return channel_; }
168
50
  inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; }
169
24
  inline void set_is_servers_default(bool is_default) {
170
24
    is_servers_default_ = is_default;
171
24
  }
172
28
  inline int active_query_count() { return active_query_count_; }
173
274
  inline NodeAresTask::List* task_list() { return &task_list_; }
174
175
  void MemoryInfo(MemoryTracker* tracker) const override;
176
4
  SET_MEMORY_INFO_NAME(ChannelWrap)
177
4
  SET_SELF_SIZE(ChannelWrap)
178
179
  static void AresTimeout(uv_timer_t* handle);
180
181
 private:
182
  uv_timer_t* timer_handle_ = nullptr;
183
  ares_channel channel_ = nullptr;
184
  bool query_last_ok_ = true;
185
  bool is_servers_default_ = true;
186
  bool library_inited_ = false;
187
  int timeout_;
188
  int tries_;
189
  int active_query_count_ = 0;
190
  NodeAresTask::List task_list_;
191
};
192
193
class GetAddrInfoReqWrap final : public ReqWrap<uv_getaddrinfo_t> {
194
 public:
195
  GetAddrInfoReqWrap(Environment* env,
196
                     v8::Local<v8::Object> req_wrap_obj,
197
                     bool verbatim);
198
199
1
  SET_NO_MEMORY_INFO()
200
1
  SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap)
201
1
  SET_SELF_SIZE(GetAddrInfoReqWrap)
202
203
5383
  bool verbatim() const { return verbatim_; }
204
205
 private:
206
  const bool verbatim_;
207
};
208
209
class GetNameInfoReqWrap final : public ReqWrap<uv_getnameinfo_t> {
210
 public:
211
  GetNameInfoReqWrap(Environment* env, v8::Local<v8::Object> req_wrap_obj);
212
213
1
  SET_NO_MEMORY_INFO()
214
1
  SET_MEMORY_INFO_NAME(GetNameInfoReqWrap)
215
1
  SET_SELF_SIZE(GetNameInfoReqWrap)
216
};
217
218
struct ResponseData final {
219
  int status;
220
  bool is_host;
221
  SafeHostEntPointer host;
222
  MallocedBuffer<unsigned char> buf;
223
};
224
225
template <typename Traits>
226
class QueryWrap final : public AsyncWrap {
227
 public:
228
102
  QueryWrap(ChannelWrap* channel, v8::Local<v8::Object> req_wrap_obj)
229
      : AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP),
230
        channel_(channel),
231
102
        trace_name_(Traits::name) {}
232
233
204
  ~QueryWrap() {
234
102
    CHECK_EQ(false, persistent().IsEmpty());
235
236
    // Let Callback() know that this object no longer exists.
237
102
    if (callback_ptr_ != nullptr)
238
2
      *callback_ptr_ = nullptr;
239
  }
240
241
102
  int Send(const char* name) {
242
102
    return Traits::Send(this, name);
243
  }
244
245
96
  void AresQuery(const char* name, int dnsclass, int type) {
246
96
    channel_->EnsureServers();
247

126
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
248
      TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
249
      "name", TRACE_STR_COPY(name));
250
96
    ares_query(
251
        channel_->cares_channel(),
252
        name,
253
        dnsclass,
254
        type,
255
        Callback,
256
        MakeCallbackPointer());
257
  }
258
259
66
  void ParseError(int status) {
260
66
    CHECK_NE(status, ARES_SUCCESS);
261
132
    v8::HandleScope handle_scope(env()->isolate());
262
66
    v8::Context::Scope context_scope(env()->context());
263
66
    const char* code = ToErrorCodeString(status);
264
132
    v8::Local<v8::Value> arg = OneByteString(env()->isolate(), code);
265

80
    TRACE_EVENT_NESTABLE_ASYNC_END1(
266
        TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
267
        "error", status);
268
66
    MakeCallback(env()->oncomplete_string(), 1, &arg);
269
  }
270
271
3
  const BaseObjectPtr<ChannelWrap>& channel() const { return channel_; }
272
273
100
  void AfterResponse() {
274
100
    CHECK(response_data_);
275
276
100
    int status = response_data_->status;
277
278
100
    if (status != ARES_SUCCESS)
279
62
      return ParseError(status);
280
281
38
    status = Traits::Parse(this, response_data_);
282
283
38
    if (status != ARES_SUCCESS)
284
4
      ParseError(status);
285
  }
286
287
102
  void* MakeCallbackPointer() {
288
102
    CHECK_NULL(callback_ptr_);
289
102
    callback_ptr_ = new QueryWrap<Traits>*(this);
290
102
    return callback_ptr_;
291
  }
292
293
102
  static QueryWrap<Traits>* FromCallbackPointer(void* arg) {
294
204
    std::unique_ptr<QueryWrap<Traits>*> wrap_ptr {
295
        static_cast<QueryWrap<Traits>**>(arg)
296
    };
297
102
    QueryWrap<Traits>* wrap = *wrap_ptr.get();
298
102
    if (wrap == nullptr) return nullptr;
299
100
    wrap->callback_ptr_ = nullptr;
300
100
    return wrap;
301
  }
302
303
96
  static void Callback(
304
      void* arg,
305
      int status,
306
      int timeouts,
307
      unsigned char* answer_buf,
308
      int answer_len) {
309
96
    QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
310
96
    if (wrap == nullptr) return;
311
312
94
    unsigned char* buf_copy = nullptr;
313
94
    if (status == ARES_SUCCESS) {
314
34
      buf_copy = node::Malloc<unsigned char>(answer_len);
315
34
      memcpy(buf_copy, answer_buf, answer_len);
316
    }
317
318
94
    wrap->response_data_ = std::make_unique<ResponseData>();
319
94
    ResponseData* data = wrap->response_data_.get();
320
94
    data->status = status;
321
94
    data->is_host = false;
322
94
    data->buf = MallocedBuffer<unsigned char>(buf_copy, answer_len);
323
324
94
    wrap->QueueResponseCallback(status);
325
  }
326
327
3
  static void Callback(
328
      void* arg,
329
      int status,
330
      int timeouts,
331
      struct hostent* host) {
332
3
    QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
333
3
    if (wrap == nullptr) return;
334
335
3
    struct hostent* host_copy = nullptr;
336
3
    if (status == ARES_SUCCESS) {
337
2
      host_copy = node::Malloc<hostent>(1);
338
2
      cares_wrap_hostent_cpy(host_copy, host);
339
    }
340
341
3
    wrap->response_data_ = std::make_unique<ResponseData>();
342
3
    ResponseData* data = wrap->response_data_.get();
343
3
    data->status = status;
344
3
    data->host.reset(host_copy);
345
3
    data->is_host = true;
346
347
3
    wrap->QueueResponseCallback(status);
348
  }
349
350
100
  void QueueResponseCallback(int status) {
351
200
    BaseObjectPtr<QueryWrap<Traits>> strong_ref{this};
352
250
    env()->SetImmediate([this, strong_ref](Environment*) {
353
50
      AfterResponse();
354
355
      // Delete once strong_ref goes out of scope.
356
50
      Detach();
357
    });
358
359
100
    channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
360
100
    channel_->ModifyActivityQueryCount(-1);
361
  }
362
363
34
  void CallOnComplete(
364
      v8::Local<v8::Value> answer,
365
      v8::Local<v8::Value> extra = v8::Local<v8::Value>()) {
366
68
    v8::HandleScope handle_scope(env()->isolate());
367
34
    v8::Context::Scope context_scope(env()->context());
368
34
    v8::Local<v8::Value> argv[] = {
369
      v8::Integer::New(env()->isolate(), 0),
370
      answer,
371
      extra
372
    };
373
34
    const int argc = arraysize(argv) - extra.IsEmpty();
374

52
    TRACE_EVENT_NESTABLE_ASYNC_END0(
375
        TRACING_CATEGORY_NODE2(dns, native), trace_name_, this);
376
377
34
    MakeCallback(env()->oncomplete_string(), argc, argv);
378
  }
379
380
2
  void MemoryInfo(MemoryTracker* tracker) const override {
381
2
    tracker->TrackField("channel", channel_);
382
2
    if (response_data_) {
383
2
      tracker->TrackFieldWithSize("response", response_data_->buf.size);
384
    }
385
  }
386
387
2
  SET_MEMORY_INFO_NAME(QueryWrap)
388
1
  SET_SELF_SIZE(QueryWrap<Traits>)
389
390
 private:
391
  BaseObjectPtr<ChannelWrap> channel_;
392
393
  std::unique_ptr<ResponseData> response_data_;
394
  const char* trace_name_;
395
  // Pointer to pointer to 'this' that can be reset from the destructor,
396
  // in order to let Callback() know that 'this' no longer exists.
397
  QueryWrap<Traits>** callback_ptr_ = nullptr;
398
};
399
400
struct AnyTraits final {
401
  static constexpr const char* name = "resolveAny";
402
  static int Send(QueryWrap<AnyTraits>* wrap, const char* name);
403
  static int Parse(
404
      QueryWrap<AnyTraits>* wrap,
405
      const std::unique_ptr<ResponseData>& response);
406
};
407
408
struct ATraits final {
409
  static constexpr const char* name = "resolve4";
410
  static int Send(QueryWrap<ATraits>* wrap, const char* name);
411
  static int Parse(
412
      QueryWrap<ATraits>* wrap,
413
      const std::unique_ptr<ResponseData>& response);
414
};
415
416
struct AaaaTraits final {
417
  static constexpr const char* name = "resolve6";
418
  static int Send(QueryWrap<AaaaTraits>* wrap, const char* name);
419
  static int Parse(
420
      QueryWrap<AaaaTraits>* wrap,
421
      const std::unique_ptr<ResponseData>& response);
422
};
423
424
struct CaaTraits final {
425
  static constexpr const char* name = "resolveCaa";
426
  static int Send(QueryWrap<CaaTraits>* wrap, const char* name);
427
  static int Parse(
428
      QueryWrap<CaaTraits>* wrap,
429
      const std::unique_ptr<ResponseData>& response);
430
};
431
432
struct CnameTraits final {
433
  static constexpr const char* name = "resolveCname";
434
  static int Send(QueryWrap<CnameTraits>* wrap, const char* name);
435
  static int Parse(
436
      QueryWrap<CnameTraits>* wrap,
437
      const std::unique_ptr<ResponseData>& response);
438
};
439
440
struct MxTraits final {
441
  static constexpr const char* name = "resolveMx";
442
  static int Send(QueryWrap<MxTraits>* wrap, const char* name);
443
  static int Parse(
444
      QueryWrap<MxTraits>* wrap,
445
      const std::unique_ptr<ResponseData>& response);
446
};
447
448
struct NsTraits final {
449
  static constexpr const char* name = "resolveNs";
450
  static int Send(QueryWrap<NsTraits>* wrap, const char* name);
451
  static int Parse(
452
      QueryWrap<NsTraits>* wrap,
453
      const std::unique_ptr<ResponseData>& response);
454
};
455
456
struct TxtTraits final {
457
  static constexpr const char* name = "resolveTxt";
458
  static int Send(QueryWrap<TxtTraits>* wrap, const char* name);
459
  static int Parse(
460
      QueryWrap<TxtTraits>* wrap,
461
      const std::unique_ptr<ResponseData>& response);
462
};
463
464
struct SrvTraits final {
465
  static constexpr const char* name = "resolveSrv";
466
  static int Send(QueryWrap<SrvTraits>* wrap, const char* name);
467
  static int Parse(
468
      QueryWrap<SrvTraits>* wrap,
469
      const std::unique_ptr<ResponseData>& response);
470
};
471
472
struct PtrTraits final {
473
  static constexpr const char* name = "resolvePtr";
474
  static int Send(QueryWrap<PtrTraits>* wrap, const char* name);
475
  static int Parse(
476
      QueryWrap<PtrTraits>* wrap,
477
      const std::unique_ptr<ResponseData>& response);
478
};
479
480
struct NaptrTraits final {
481
  static constexpr const char* name = "resolveNaptr";
482
  static int Send(QueryWrap<NaptrTraits>* wrap, const char* name);
483
  static int Parse(
484
      QueryWrap<NaptrTraits>* wrap,
485
      const std::unique_ptr<ResponseData>& response);
486
};
487
488
struct SoaTraits final {
489
  static constexpr const char* name = "resolveSoa";
490
  static int Send(QueryWrap<SoaTraits>* wrap, const char* name);
491
  static int Parse(
492
      QueryWrap<SoaTraits>* wrap,
493
      const std::unique_ptr<ResponseData>& response);
494
};
495
496
struct ReverseTraits final {
497
  static constexpr const char* name = "reverse";
498
  static int Send(QueryWrap<ReverseTraits>* wrap, const char* name);
499
  static int Parse(
500
      QueryWrap<ReverseTraits>* wrap,
501
      const std::unique_ptr<ResponseData>& response);
502
};
503
504
using QueryAnyWrap = QueryWrap<AnyTraits>;
505
using QueryAWrap = QueryWrap<ATraits>;
506
using QueryAaaaWrap = QueryWrap<AaaaTraits>;
507
using QueryCaaWrap = QueryWrap<CaaTraits>;
508
using QueryCnameWrap = QueryWrap<CnameTraits>;
509
using QueryMxWrap = QueryWrap<MxTraits>;
510
using QueryNsWrap = QueryWrap<NsTraits>;
511
using QueryTxtWrap = QueryWrap<TxtTraits>;
512
using QuerySrvWrap = QueryWrap<SrvTraits>;
513
using QueryPtrWrap = QueryWrap<PtrTraits>;
514
using QueryNaptrWrap = QueryWrap<NaptrTraits>;
515
using QuerySoaWrap = QueryWrap<SoaTraits>;
516
using GetHostByAddrWrap = QueryWrap<ReverseTraits>;
517
518
}  // namespace cares_wrap
519
}  // namespace node
520
521
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
522
523
#endif  // SRC_CARES_WRAP_H_