GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: cares_wrap.h Lines: 137 162 84.6 %
Date: 2022-12-31 04:22:30 Branches: 40 71 56.3 %

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 "node.h"
13
#include "node_internals.h"
14
#include "util.h"
15
16
#include "ares.h"
17
#include "v8.h"
18
#include "uv.h"
19
20
#include <unordered_set>
21
22
#ifdef __POSIX__
23
# include <netdb.h>
24
#endif  // __POSIX__
25
26
# include <ares_nameser.h>
27
28
namespace node {
29
namespace cares_wrap {
30
31
constexpr int ns_t_cname_or_a = -1;
32
constexpr int DNS_ESETSRVPENDING = -1000;
33
34
class ChannelWrap;
35
36
inline void safe_free_hostent(struct hostent* host);
37
38
using HostEntPointer = DeleteFnPtr<hostent, ares_free_hostent>;
39
using SafeHostEntPointer = DeleteFnPtr<hostent, safe_free_hostent>;
40
41
35
inline const char* ToErrorCodeString(int status) {
42






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

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

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

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