GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
#define CARES_STATICLIB |
||
23 |
#include "ares.h" |
||
24 |
#include "async_wrap-inl.h" |
||
25 |
#include "env-inl.h" |
||
26 |
#include "memory_tracker-inl.h" |
||
27 |
#include "node.h" |
||
28 |
#include "req_wrap-inl.h" |
||
29 |
#include "util-inl.h" |
||
30 |
#include "uv.h" |
||
31 |
|||
32 |
#include <cerrno> |
||
33 |
#include <cstring> |
||
34 |
#include <memory> |
||
35 |
#include <vector> |
||
36 |
#include <unordered_set> |
||
37 |
|||
38 |
#ifdef __POSIX__ |
||
39 |
# include <netdb.h> |
||
40 |
#endif // __POSIX__ |
||
41 |
|||
42 |
#if defined(__ANDROID__) || \ |
||
43 |
defined(__MINGW32__) || \ |
||
44 |
defined(__OpenBSD__) || \ |
||
45 |
defined(_MSC_VER) |
||
46 |
|||
47 |
# include <nameser.h> |
||
48 |
#else |
||
49 |
# include <arpa/nameser.h> |
||
50 |
#endif |
||
51 |
|||
52 |
#if defined(__OpenBSD__) |
||
53 |
# define AI_V4MAPPED 0 |
||
54 |
#endif |
||
55 |
|||
56 |
namespace node { |
||
57 |
namespace cares_wrap { |
||
58 |
|||
59 |
using v8::Array; |
||
60 |
using v8::Context; |
||
61 |
using v8::EscapableHandleScope; |
||
62 |
using v8::FunctionCallbackInfo; |
||
63 |
using v8::FunctionTemplate; |
||
64 |
using v8::HandleScope; |
||
65 |
using v8::Int32; |
||
66 |
using v8::Integer; |
||
67 |
using v8::Local; |
||
68 |
using v8::Null; |
||
69 |
using v8::Object; |
||
70 |
using v8::String; |
||
71 |
using v8::Value; |
||
72 |
|||
73 |
namespace { |
||
74 |
|||
75 |
4982 |
Mutex ares_library_mutex; |
|
76 |
|||
77 |
179 |
inline uint16_t cares_get_16bit(const unsigned char* p) { |
|
78 |
179 |
return static_cast<uint32_t>(p[0] << 8U) | (static_cast<uint32_t>(p[1])); |
|
79 |
} |
||
80 |
|||
81 |
40 |
inline uint32_t cares_get_32bit(const unsigned char* p) { |
|
82 |
80 |
return static_cast<uint32_t>(p[0] << 24U) | |
|
83 |
80 |
static_cast<uint32_t>(p[1] << 16U) | |
|
84 |
80 |
static_cast<uint32_t>(p[2] << 8U) | |
|
85 |
80 |
static_cast<uint32_t>(p[3]); |
|
86 |
} |
||
87 |
|||
88 |
const int ns_t_cname_or_a = -1; |
||
89 |
|||
90 |
#define DNS_ESETSRVPENDING -1000 |
||
91 |
34 |
inline const char* ToErrorCodeString(int status) { |
|
92 |
✗✗✗✗ ✗✗✓✗ ✓✗✗✗ ✗✗✓✗ ✗✓✗✗ ✗✗✗✗ ✗ |
34 |
switch (status) { |
93 |
#define V(code) case ARES_##code: return #code; |
||
94 |
V(EADDRGETNETWORKPARAMS) |
||
95 |
V(EBADFAMILY) |
||
96 |
V(EBADFLAGS) |
||
97 |
V(EBADHINTS) |
||
98 |
V(EBADNAME) |
||
99 |
V(EBADQUERY) |
||
100 |
2 |
V(EBADRESP) |
|
101 |
V(EBADSTR) |
||
102 |
3 |
V(ECANCELLED) |
|
103 |
V(ECONNREFUSED) |
||
104 |
V(EDESTRUCTION) |
||
105 |
V(EFILE) |
||
106 |
V(EFORMERR) |
||
107 |
V(ELOADIPHLPAPI) |
||
108 |
8 |
V(ENODATA) |
|
109 |
V(ENOMEM) |
||
110 |
V(ENONAME) |
||
111 |
21 |
V(ENOTFOUND) |
|
112 |
V(ENOTIMP) |
||
113 |
V(ENOTINITIALIZED) |
||
114 |
V(EOF) |
||
115 |
V(EREFUSED) |
||
116 |
V(ESERVFAIL) |
||
117 |
V(ETIMEOUT) |
||
118 |
#undef V |
||
119 |
} |
||
120 |
|||
121 |
return "UNKNOWN_ARES_ERROR"; |
||
122 |
} |
||
123 |
|||
124 |
class ChannelWrap; |
||
125 |
|||
126 |
✗✓ | 453 |
struct node_ares_task : public MemoryRetainer { |
127 |
ChannelWrap* channel; |
||
128 |
ares_socket_t sock; |
||
129 |
uv_poll_t poll_watcher; |
||
130 |
|||
131 |
inline void MemoryInfo(MemoryTracker* tracker) const override; |
||
132 |
2 |
SET_MEMORY_INFO_NAME(node_ares_task) |
|
133 |
2 |
SET_SELF_SIZE(node_ares_task) |
|
134 |
}; |
||
135 |
|||
136 |
struct TaskHash { |
||
137 |
195 |
size_t operator()(node_ares_task* a) const { |
|
138 |
195 |
return std::hash<ares_socket_t>()(a->sock); |
|
139 |
} |
||
140 |
}; |
||
141 |
|||
142 |
struct TaskEqual { |
||
143 |
69 |
inline bool operator()(node_ares_task* a, node_ares_task* b) const { |
|
144 |
69 |
return a->sock == b->sock; |
|
145 |
} |
||
146 |
}; |
||
147 |
|||
148 |
using node_ares_task_list = |
||
149 |
std::unordered_set<node_ares_task*, TaskHash, TaskEqual>; |
||
150 |
|||
151 |
class ChannelWrap : public AsyncWrap { |
||
152 |
public: |
||
153 |
ChannelWrap(Environment* env, Local<Object> object); |
||
154 |
~ChannelWrap() override; |
||
155 |
|||
156 |
static void New(const FunctionCallbackInfo<Value>& args); |
||
157 |
|||
158 |
void Setup(); |
||
159 |
void EnsureServers(); |
||
160 |
void StartTimer(); |
||
161 |
void CloseTimer(); |
||
162 |
|||
163 |
void ModifyActivityQueryCount(int count); |
||
164 |
|||
165 |
114 |
inline uv_timer_t* timer_handle() { return timer_handle_; } |
|
166 |
304 |
inline ares_channel cares_channel() { return channel_; } |
|
167 |
109 |
inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; } |
|
168 |
19 |
inline void set_is_servers_default(bool is_default) { |
|
169 |
19 |
is_servers_default_ = is_default; |
|
170 |
19 |
} |
|
171 |
23 |
inline int active_query_count() { return active_query_count_; } |
|
172 |
464 |
inline node_ares_task_list* task_list() { return &task_list_; } |
|
173 |
|||
174 |
12 |
void MemoryInfo(MemoryTracker* tracker) const override { |
|
175 |
✓✓ | 12 |
if (timer_handle_ != nullptr) |
176 |
2 |
tracker->TrackField("timer_handle", *timer_handle_); |
|
177 |
12 |
tracker->TrackField("task_list", task_list_, "node_ares_task_list"); |
|
178 |
12 |
} |
|
179 |
|||
180 |
12 |
SET_MEMORY_INFO_NAME(ChannelWrap) |
|
181 |
12 |
SET_SELF_SIZE(ChannelWrap) |
|
182 |
|||
183 |
static void AresTimeout(uv_timer_t* handle); |
||
184 |
|||
185 |
private: |
||
186 |
uv_timer_t* timer_handle_; |
||
187 |
ares_channel channel_; |
||
188 |
bool query_last_ok_; |
||
189 |
bool is_servers_default_; |
||
190 |
bool library_inited_; |
||
191 |
int active_query_count_; |
||
192 |
node_ares_task_list task_list_; |
||
193 |
}; |
||
194 |
|||
195 |
1101 |
ChannelWrap::ChannelWrap(Environment* env, |
|
196 |
Local<Object> object) |
||
197 |
: AsyncWrap(env, object, PROVIDER_DNSCHANNEL), |
||
198 |
timer_handle_(nullptr), |
||
199 |
channel_(nullptr), |
||
200 |
query_last_ok_(true), |
||
201 |
is_servers_default_(true), |
||
202 |
library_inited_(false), |
||
203 |
1101 |
active_query_count_(0) { |
|
204 |
1101 |
MakeWeak(); |
|
205 |
|||
206 |
1101 |
Setup(); |
|
207 |
1101 |
} |
|
208 |
|||
209 |
1101 |
void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) { |
|
210 |
✗✓ | 1101 |
CHECK(args.IsConstructCall()); |
211 |
✗✓ | 1101 |
CHECK_EQ(args.Length(), 0); |
212 |
|||
213 |
1101 |
Environment* env = Environment::GetCurrent(args); |
|
214 |
1101 |
new ChannelWrap(env, args.This()); |
|
215 |
1101 |
} |
|
216 |
|||
217 |
✗✓ | 10498 |
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> { |
218 |
public: |
||
219 |
GetAddrInfoReqWrap(Environment* env, |
||
220 |
Local<Object> req_wrap_obj, |
||
221 |
bool verbatim); |
||
222 |
|||
223 |
3 |
SET_NO_MEMORY_INFO() |
|
224 |
3 |
SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap) |
|
225 |
3 |
SET_SELF_SIZE(GetAddrInfoReqWrap) |
|
226 |
|||
227 |
5249 |
bool verbatim() const { return verbatim_; } |
|
228 |
|||
229 |
private: |
||
230 |
const bool verbatim_; |
||
231 |
}; |
||
232 |
|||
233 |
5250 |
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, |
|
234 |
Local<Object> req_wrap_obj, |
||
235 |
bool verbatim) |
||
236 |
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) |
||
237 |
5250 |
, verbatim_(verbatim) { |
|
238 |
5250 |
} |
|
239 |
|||
240 |
|||
241 |
✗✓ | 22 |
class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> { |
242 |
public: |
||
243 |
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj); |
||
244 |
|||
245 |
1 |
SET_NO_MEMORY_INFO() |
|
246 |
1 |
SET_MEMORY_INFO_NAME(GetNameInfoReqWrap) |
|
247 |
1 |
SET_SELF_SIZE(GetNameInfoReqWrap) |
|
248 |
}; |
||
249 |
|||
250 |
11 |
GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, |
|
251 |
Local<Object> req_wrap_obj) |
||
252 |
11 |
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) { |
|
253 |
11 |
} |
|
254 |
|||
255 |
|||
256 |
/* This is called once per second by loop->timer. It is used to constantly */ |
||
257 |
/* call back into c-ares for possibly processing timeouts. */ |
||
258 |
11 |
void ChannelWrap::AresTimeout(uv_timer_t* handle) { |
|
259 |
11 |
ChannelWrap* channel = static_cast<ChannelWrap*>(handle->data); |
|
260 |
✗✓ | 11 |
CHECK_EQ(channel->timer_handle(), handle); |
261 |
✗✓ | 11 |
CHECK_EQ(false, channel->task_list()->empty()); |
262 |
11 |
ares_process_fd(channel->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD); |
|
263 |
11 |
} |
|
264 |
|||
265 |
|||
266 |
103 |
void ares_poll_cb(uv_poll_t* watcher, int status, int events) { |
|
267 |
103 |
node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher); |
|
268 |
103 |
ChannelWrap* channel = task->channel; |
|
269 |
|||
270 |
/* Reset the idle timer */ |
||
271 |
103 |
uv_timer_again(channel->timer_handle()); |
|
272 |
|||
273 |
✗✓ | 103 |
if (status < 0) { |
274 |
/* An error happened. Just pretend that the socket is both readable and */ |
||
275 |
/* writable. */ |
||
276 |
ares_process_fd(channel->cares_channel(), task->sock, task->sock); |
||
277 |
103 |
return; |
|
278 |
} |
||
279 |
|||
280 |
/* Process DNS responses */ |
||
281 |
ares_process_fd(channel->cares_channel(), |
||
282 |
103 |
events & UV_READABLE ? task->sock : ARES_SOCKET_BAD, |
|
283 |
✓✓✓✓ |
206 |
events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD); |
284 |
} |
||
285 |
|||
286 |
|||
287 |
63 |
void ares_poll_close_cb(uv_poll_t* watcher) { |
|
288 |
63 |
node_ares_task* task = ContainerOf(&node_ares_task::poll_watcher, watcher); |
|
289 |
✓✗ | 63 |
delete task; |
290 |
63 |
} |
|
291 |
|||
292 |
2 |
void node_ares_task::MemoryInfo(MemoryTracker* tracker) const { |
|
293 |
2 |
tracker->TrackField("channel", channel); |
|
294 |
2 |
} |
|
295 |
|||
296 |
/* Allocates and returns a new node_ares_task */ |
||
297 |
63 |
node_ares_task* ares_task_create(ChannelWrap* channel, ares_socket_t sock) { |
|
298 |
63 |
auto task = new node_ares_task(); |
|
299 |
|||
300 |
63 |
task->channel = channel; |
|
301 |
63 |
task->sock = sock; |
|
302 |
|||
303 |
✗✓ | 63 |
if (uv_poll_init_socket(channel->env()->event_loop(), |
304 |
63 |
&task->poll_watcher, sock) < 0) { |
|
305 |
/* This should never happen. */ |
||
306 |
delete task; |
||
307 |
return nullptr; |
||
308 |
} |
||
309 |
|||
310 |
63 |
return task; |
|
311 |
} |
||
312 |
|||
313 |
|||
314 |
/* Callback from ares when socket operation is started */ |
||
315 |
132 |
void ares_sockstate_cb(void* data, |
|
316 |
ares_socket_t sock, |
||
317 |
int read, |
||
318 |
int write) { |
||
319 |
132 |
ChannelWrap* channel = static_cast<ChannelWrap*>(data); |
|
320 |
node_ares_task* task; |
||
321 |
|||
322 |
132 |
node_ares_task lookup_task; |
|
323 |
132 |
lookup_task.sock = sock; |
|
324 |
132 |
auto it = channel->task_list()->find(&lookup_task); |
|
325 |
|||
326 |
✓✓ | 132 |
task = (it == channel->task_list()->end()) ? nullptr : *it; |
327 |
|||
328 |
✓✓✗✓ |
132 |
if (read || write) { |
329 |
✓✓ | 69 |
if (!task) { |
330 |
/* New socket */ |
||
331 |
63 |
channel->StartTimer(); |
|
332 |
|||
333 |
63 |
task = ares_task_create(channel, sock); |
|
334 |
✗✓ | 63 |
if (task == nullptr) { |
335 |
/* This should never happen unless we're out of memory or something */ |
||
336 |
/* is seriously wrong. The socket won't be polled, but the query will */ |
||
337 |
/* eventually time out. */ |
||
338 |
132 |
return; |
|
339 |
} |
||
340 |
|||
341 |
63 |
channel->task_list()->insert(task); |
|
342 |
} |
||
343 |
|||
344 |
/* This should never fail. If it fails anyway, the query will eventually */ |
||
345 |
/* time out. */ |
||
346 |
uv_poll_start(&task->poll_watcher, |
||
347 |
(read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0), |
||
348 |
✓✗✓✓ |
69 |
ares_poll_cb); |
349 |
|||
350 |
} else { |
||
351 |
/* read == 0 and write == 0 this is c-ares's way of notifying us that */ |
||
352 |
/* the socket is now closed. We must free the data associated with */ |
||
353 |
/* socket. */ |
||
354 |
✗✓ | 63 |
CHECK(task && |
355 |
"When an ares socket is closed we should have a handle for it"); |
||
356 |
|||
357 |
63 |
channel->task_list()->erase(it); |
|
358 |
63 |
channel->env()->CloseHandle(&task->poll_watcher, ares_poll_close_cb); |
|
359 |
|||
360 |
✓✓ | 63 |
if (channel->task_list()->empty()) { |
361 |
✓✗ | 58 |
channel->CloseTimer(); |
362 |
} |
||
363 |
132 |
} |
|
364 |
} |
||
365 |
|||
366 |
|||
367 |
20 |
Local<Array> HostentToNames(Environment* env, |
|
368 |
struct hostent* host, |
||
369 |
Local<Array> append_to = Local<Array>()) { |
||
370 |
20 |
EscapableHandleScope scope(env->isolate()); |
|
371 |
20 |
auto context = env->context(); |
|
372 |
20 |
bool append = !append_to.IsEmpty(); |
|
373 |
✓✓ | 20 |
Local<Array> names = append ? append_to : Array::New(env->isolate()); |
374 |
20 |
size_t offset = names->Length(); |
|
375 |
|||
376 |
✓✓ | 53 |
for (uint32_t i = 0; host->h_aliases[i] != nullptr; ++i) { |
377 |
33 |
Local<String> address = OneByteString(env->isolate(), host->h_aliases[i]); |
|
378 |
99 |
names->Set(context, i + offset, address).Check(); |
|
379 |
} |
||
380 |
|||
381 |
✓✓ | 60 |
return append ? names : scope.Escape(names); |
382 |
} |
||
383 |
|||
384 |
7 |
void safe_free_hostent(struct hostent* host) { |
|
385 |
int idx; |
||
386 |
|||
387 |
✓✗ | 7 |
if (host->h_addr_list != nullptr) { |
388 |
7 |
idx = 0; |
|
389 |
✓✓ | 21 |
while (host->h_addr_list[idx]) { |
390 |
7 |
free(host->h_addr_list[idx++]); |
|
391 |
} |
||
392 |
7 |
free(host->h_addr_list); |
|
393 |
7 |
host->h_addr_list = nullptr; |
|
394 |
} |
||
395 |
|||
396 |
✓✗ | 7 |
if (host->h_aliases != nullptr) { |
397 |
7 |
idx = 0; |
|
398 |
✓✓ | 19 |
while (host->h_aliases[idx]) { |
399 |
5 |
free(host->h_aliases[idx++]); |
|
400 |
} |
||
401 |
7 |
free(host->h_aliases); |
|
402 |
7 |
host->h_aliases = nullptr; |
|
403 |
} |
||
404 |
|||
405 |
7 |
free(host->h_name); |
|
406 |
7 |
free(host); |
|
407 |
7 |
} |
|
408 |
|||
409 |
7 |
void cares_wrap_hostent_cpy(struct hostent* dest, const struct hostent* src) { |
|
410 |
7 |
dest->h_addr_list = nullptr; |
|
411 |
7 |
dest->h_addrtype = 0; |
|
412 |
7 |
dest->h_aliases = nullptr; |
|
413 |
7 |
dest->h_length = 0; |
|
414 |
7 |
dest->h_name = nullptr; |
|
415 |
|||
416 |
/* copy `h_name` */ |
||
417 |
7 |
size_t name_size = strlen(src->h_name) + 1; |
|
418 |
7 |
dest->h_name = node::Malloc<char>(name_size); |
|
419 |
7 |
memcpy(dest->h_name, src->h_name, name_size); |
|
420 |
|||
421 |
/* copy `h_aliases` */ |
||
422 |
size_t alias_count; |
||
423 |
✓✓ | 19 |
for (alias_count = 0; |
424 |
12 |
src->h_aliases[alias_count] != nullptr; |
|
425 |
alias_count++) { |
||
426 |
} |
||
427 |
|||
428 |
7 |
dest->h_aliases = node::Malloc<char*>(alias_count + 1); |
|
429 |
✓✓ | 12 |
for (size_t i = 0; i < alias_count; i++) { |
430 |
5 |
const size_t cur_alias_size = strlen(src->h_aliases[i]) + 1; |
|
431 |
5 |
dest->h_aliases[i] = node::Malloc(cur_alias_size); |
|
432 |
5 |
memcpy(dest->h_aliases[i], src->h_aliases[i], cur_alias_size); |
|
433 |
} |
||
434 |
7 |
dest->h_aliases[alias_count] = nullptr; |
|
435 |
|||
436 |
/* copy `h_addr_list` */ |
||
437 |
size_t list_count; |
||
438 |
✓✓ | 21 |
for (list_count = 0; |
439 |
14 |
src->h_addr_list[list_count] != nullptr; |
|
440 |
list_count++) { |
||
441 |
} |
||
442 |
|||
443 |
7 |
dest->h_addr_list = node::Malloc<char*>(list_count + 1); |
|
444 |
✓✓ | 14 |
for (size_t i = 0; i < list_count; i++) { |
445 |
7 |
dest->h_addr_list[i] = node::Malloc(src->h_length); |
|
446 |
7 |
memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length); |
|
447 |
} |
||
448 |
7 |
dest->h_addr_list[list_count] = nullptr; |
|
449 |
|||
450 |
/* work after work */ |
||
451 |
7 |
dest->h_length = src->h_length; |
|
452 |
7 |
dest->h_addrtype = src->h_addrtype; |
|
453 |
7 |
} |
|
454 |
|||
455 |
class QueryWrap; |
||
456 |
|||
457 |
1101 |
void ChannelWrap::Setup() { |
|
458 |
struct ares_options options; |
||
459 |
1101 |
memset(&options, 0, sizeof(options)); |
|
460 |
1101 |
options.flags = ARES_FLAG_NOCHECKRESP; |
|
461 |
1101 |
options.sock_state_cb = ares_sockstate_cb; |
|
462 |
1101 |
options.sock_state_cb_data = this; |
|
463 |
|||
464 |
int r; |
||
465 |
✓✗ | 1101 |
if (!library_inited_) { |
466 |
1101 |
Mutex::ScopedLock lock(ares_library_mutex); |
|
467 |
// Multiple calls to ares_library_init() increase a reference counter, |
||
468 |
// so this is a no-op except for the first call to it. |
||
469 |
1101 |
r = ares_library_init(ARES_LIB_INIT_ALL); |
|
470 |
✗✓ | 1101 |
if (r != ARES_SUCCESS) |
471 |
return env()->ThrowError(ToErrorCodeString(r)); |
||
472 |
} |
||
473 |
|||
474 |
/* We do the call to ares_init_option for caller. */ |
||
475 |
r = ares_init_options(&channel_, |
||
476 |
&options, |
||
477 |
1101 |
ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB); |
|
478 |
|||
479 |
✗✓ | 1101 |
if (r != ARES_SUCCESS) { |
480 |
Mutex::ScopedLock lock(ares_library_mutex); |
||
481 |
ares_library_cleanup(); |
||
482 |
return env()->ThrowError(ToErrorCodeString(r)); |
||
483 |
} |
||
484 |
|||
485 |
1101 |
library_inited_ = true; |
|
486 |
} |
||
487 |
|||
488 |
63 |
void ChannelWrap::StartTimer() { |
|
489 |
✓✓ | 63 |
if (timer_handle_ == nullptr) { |
490 |
58 |
timer_handle_ = new uv_timer_t(); |
|
491 |
58 |
timer_handle_->data = static_cast<void*>(this); |
|
492 |
58 |
uv_timer_init(env()->event_loop(), timer_handle_); |
|
493 |
✓✗ | 5 |
} else if (uv_is_active(reinterpret_cast<uv_handle_t*>(timer_handle_))) { |
494 |
68 |
return; |
|
495 |
} |
||
496 |
58 |
uv_timer_start(timer_handle_, AresTimeout, 1000, 1000); |
|
497 |
} |
||
498 |
|||
499 |
1113 |
void ChannelWrap::CloseTimer() { |
|
500 |
✓✓ | 1113 |
if (timer_handle_ == nullptr) |
501 |
2168 |
return; |
|
502 |
|||
503 |
116 |
env()->CloseHandle(timer_handle_, [](uv_timer_t* handle) { delete handle; }); |
|
504 |
58 |
timer_handle_ = nullptr; |
|
505 |
} |
||
506 |
|||
507 |
3165 |
ChannelWrap::~ChannelWrap() { |
|
508 |
1055 |
ares_destroy(channel_); |
|
509 |
|||
510 |
✓✗ | 1055 |
if (library_inited_) { |
511 |
1055 |
Mutex::ScopedLock lock(ares_library_mutex); |
|
512 |
// This decreases the reference counter increased by ares_library_init(). |
||
513 |
1055 |
ares_library_cleanup(); |
|
514 |
} |
||
515 |
|||
516 |
1055 |
CloseTimer(); |
|
517 |
✗✓ | 2110 |
} |
518 |
|||
519 |
|||
520 |
223 |
void ChannelWrap::ModifyActivityQueryCount(int count) { |
|
521 |
223 |
active_query_count_ += count; |
|
522 |
✗✓ | 223 |
CHECK_GE(active_query_count_, 0); |
523 |
223 |
} |
|
524 |
|||
525 |
|||
526 |
/** |
||
527 |
* This function is to check whether current servers are fallback servers |
||
528 |
* when cares initialized. |
||
529 |
* |
||
530 |
* The fallback servers of cares is [ "127.0.0.1" ] with no user additional |
||
531 |
* setting. |
||
532 |
*/ |
||
533 |
100 |
void ChannelWrap::EnsureServers() { |
|
534 |
/* if last query is OK or servers are set by user self, do not check */ |
||
535 |
✗✓✗✗ |
100 |
if (query_last_ok_ || !is_servers_default_) { |
536 |
200 |
return; |
|
537 |
} |
||
538 |
|||
539 |
ares_addr_port_node* servers = nullptr; |
||
540 |
|||
541 |
ares_get_servers_ports(channel_, &servers); |
||
542 |
|||
543 |
/* if no server or multi-servers, ignore */ |
||
544 |
if (servers == nullptr) return; |
||
545 |
if (servers->next != nullptr) { |
||
546 |
ares_free_data(servers); |
||
547 |
is_servers_default_ = false; |
||
548 |
return; |
||
549 |
} |
||
550 |
|||
551 |
/* if the only server is not 127.0.0.1, ignore */ |
||
552 |
if (servers[0].family != AF_INET || |
||
553 |
servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK) || |
||
554 |
servers[0].tcp_port != 0 || |
||
555 |
servers[0].udp_port != 0) { |
||
556 |
ares_free_data(servers); |
||
557 |
is_servers_default_ = false; |
||
558 |
return; |
||
559 |
} |
||
560 |
|||
561 |
ares_free_data(servers); |
||
562 |
servers = nullptr; |
||
563 |
|||
564 |
/* destroy channel and reset channel */ |
||
565 |
ares_destroy(channel_); |
||
566 |
|||
567 |
CloseTimer(); |
||
568 |
Setup(); |
||
569 |
} |
||
570 |
|||
571 |
|||
572 |
class QueryWrap : public AsyncWrap { |
||
573 |
public: |
||
574 |
112 |
QueryWrap(ChannelWrap* channel, Local<Object> req_wrap_obj, const char* name) |
|
575 |
: AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP), |
||
576 |
channel_(channel), |
||
577 |
112 |
trace_name_(name) { |
|
578 |
// Make sure the channel object stays alive during the query lifetime. |
||
579 |
req_wrap_obj->Set(env()->context(), |
||
580 |
env()->channel_string(), |
||
581 |
560 |
channel->object()).Check(); |
|
582 |
112 |
} |
|
583 |
|||
584 |
224 |
~QueryWrap() override { |
|
585 |
✗✓ | 224 |
CHECK_EQ(false, persistent().IsEmpty()); |
586 |
|||
587 |
// Let Callback() know that this object no longer exists. |
||
588 |
✓✓ | 112 |
if (callback_ptr_ != nullptr) |
589 |
1 |
*callback_ptr_ = nullptr; |
|
590 |
✗✓ | 112 |
} |
591 |
|||
592 |
// Subclasses should implement the appropriate Send method. |
||
593 |
virtual int Send(const char* name) { |
||
594 |
UNREACHABLE(); |
||
595 |
return 0; |
||
596 |
} |
||
597 |
|||
598 |
virtual int Send(const char* name, int family) { |
||
599 |
UNREACHABLE(); |
||
600 |
return 0; |
||
601 |
} |
||
602 |
|||
603 |
protected: |
||
604 |
100 |
void AresQuery(const char* name, |
|
605 |
int dnsclass, |
||
606 |
int type) { |
||
607 |
100 |
channel_->EnsureServers(); |
|
608 |
✓✓✓✓ |
200 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( |
609 |
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this, |
||
610 |
"name", TRACE_STR_COPY(name)); |
||
611 |
ares_query(channel_->cares_channel(), name, dnsclass, type, Callback, |
||
612 |
100 |
MakeCallbackPointer()); |
|
613 |
100 |
} |
|
614 |
|||
615 |
218 |
struct ResponseData { |
|
616 |
int status; |
||
617 |
bool is_host; |
||
618 |
DeleteFnPtr<hostent, safe_free_hostent> host; |
||
619 |
MallocedBuffer<unsigned char> buf; |
||
620 |
}; |
||
621 |
|||
622 |
109 |
void AfterResponse() { |
|
623 |
✗✓ | 109 |
CHECK(response_data_); |
624 |
|||
625 |
109 |
const int status = response_data_->status; |
|
626 |
|||
627 |
✓✓ | 109 |
if (status != ARES_SUCCESS) { |
628 |
32 |
ParseError(status); |
|
629 |
✓✓ | 77 |
} else if (!response_data_->is_host) { |
630 |
70 |
Parse(response_data_->buf.data, response_data_->buf.size); |
|
631 |
} else { |
||
632 |
7 |
Parse(response_data_->host.get()); |
|
633 |
} |
||
634 |
|||
635 |
✓✗ | 109 |
delete this; |
636 |
109 |
} |
|
637 |
|||
638 |
110 |
void* MakeCallbackPointer() { |
|
639 |
✗✓ | 110 |
CHECK_NULL(callback_ptr_); |
640 |
110 |
callback_ptr_ = new QueryWrap*(this); |
|
641 |
110 |
return callback_ptr_; |
|
642 |
} |
||
643 |
|||
644 |
110 |
static QueryWrap* FromCallbackPointer(void* arg) { |
|
645 |
110 |
std::unique_ptr<QueryWrap*> wrap_ptr { static_cast<QueryWrap**>(arg) }; |
|
646 |
110 |
QueryWrap* wrap = *wrap_ptr.get(); |
|
647 |
✓✓ | 110 |
if (wrap == nullptr) return nullptr; |
648 |
109 |
wrap->callback_ptr_ = nullptr; |
|
649 |
109 |
return wrap; |
|
650 |
} |
||
651 |
|||
652 |
100 |
static void Callback(void* arg, int status, int timeouts, |
|
653 |
unsigned char* answer_buf, int answer_len) { |
||
654 |
100 |
QueryWrap* wrap = FromCallbackPointer(arg); |
|
655 |
✓✓ | 200 |
if (wrap == nullptr) return; |
656 |
|||
657 |
99 |
unsigned char* buf_copy = nullptr; |
|
658 |
✓✓ | 99 |
if (status == ARES_SUCCESS) { |
659 |
70 |
buf_copy = node::Malloc<unsigned char>(answer_len); |
|
660 |
70 |
memcpy(buf_copy, answer_buf, answer_len); |
|
661 |
} |
||
662 |
|||
663 |
99 |
wrap->response_data_ = std::make_unique<ResponseData>(); |
|
664 |
99 |
ResponseData* data = wrap->response_data_.get(); |
|
665 |
99 |
data->status = status; |
|
666 |
99 |
data->is_host = false; |
|
667 |
99 |
data->buf = MallocedBuffer<unsigned char>(buf_copy, answer_len); |
|
668 |
|||
669 |
99 |
wrap->QueueResponseCallback(status); |
|
670 |
} |
||
671 |
|||
672 |
10 |
static void Callback(void* arg, int status, int timeouts, |
|
673 |
struct hostent* host) { |
||
674 |
10 |
QueryWrap* wrap = FromCallbackPointer(arg); |
|
675 |
✗✓ | 20 |
if (wrap == nullptr) return; |
676 |
|||
677 |
10 |
struct hostent* host_copy = nullptr; |
|
678 |
✓✓ | 10 |
if (status == ARES_SUCCESS) { |
679 |
7 |
host_copy = node::Malloc<hostent>(1); |
|
680 |
7 |
cares_wrap_hostent_cpy(host_copy, host); |
|
681 |
} |
||
682 |
|||
683 |
10 |
wrap->response_data_ = std::make_unique<ResponseData>(); |
|
684 |
10 |
ResponseData* data = wrap->response_data_.get(); |
|
685 |
10 |
data->status = status; |
|
686 |
10 |
data->host.reset(host_copy); |
|
687 |
10 |
data->is_host = true; |
|
688 |
|||
689 |
10 |
wrap->QueueResponseCallback(status); |
|
690 |
} |
||
691 |
|||
692 |
109 |
void QueueResponseCallback(int status) { |
|
693 |
109 |
env()->SetImmediate([this](Environment*) { |
|
694 |
109 |
AfterResponse(); |
|
695 |
218 |
}, object()); |
|
696 |
|||
697 |
109 |
channel_->set_query_last_ok(status != ARES_ECONNREFUSED); |
|
698 |
109 |
channel_->ModifyActivityQueryCount(-1); |
|
699 |
109 |
} |
|
700 |
|||
701 |
75 |
void CallOnComplete(Local<Value> answer, |
|
702 |
Local<Value> extra = Local<Value>()) { |
||
703 |
75 |
HandleScope handle_scope(env()->isolate()); |
|
704 |
75 |
Context::Scope context_scope(env()->context()); |
|
705 |
Local<Value> argv[] = { |
||
706 |
Integer::New(env()->isolate(), 0), |
||
707 |
answer, |
||
708 |
extra |
||
709 |
150 |
}; |
|
710 |
150 |
const int argc = arraysize(argv) - extra.IsEmpty(); |
|
711 |
✓✓✓✓ |
150 |
TRACE_EVENT_NESTABLE_ASYNC_END0( |
712 |
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this); |
||
713 |
|||
714 |
150 |
MakeCallback(env()->oncomplete_string(), argc, argv); |
|
715 |
75 |
} |
|
716 |
|||
717 |
34 |
void ParseError(int status) { |
|
718 |
✗✓ | 34 |
CHECK_NE(status, ARES_SUCCESS); |
719 |
34 |
HandleScope handle_scope(env()->isolate()); |
|
720 |
34 |
Context::Scope context_scope(env()->context()); |
|
721 |
34 |
const char* code = ToErrorCodeString(status); |
|
722 |
34 |
Local<Value> arg = OneByteString(env()->isolate(), code); |
|
723 |
✓✓✓✓ |
68 |
TRACE_EVENT_NESTABLE_ASYNC_END1( |
724 |
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this, |
||
725 |
"error", status); |
||
726 |
68 |
MakeCallback(env()->oncomplete_string(), 1, &arg); |
|
727 |
34 |
} |
|
728 |
|||
729 |
// Subclasses should implement the appropriate Parse method. |
||
730 |
virtual void Parse(unsigned char* buf, int len) { |
||
731 |
UNREACHABLE(); |
||
732 |
} |
||
733 |
|||
734 |
virtual void Parse(struct hostent* host) { |
||
735 |
UNREACHABLE(); |
||
736 |
} |
||
737 |
|||
738 |
ChannelWrap* channel_; |
||
739 |
|||
740 |
private: |
||
741 |
std::unique_ptr<ResponseData> response_data_; |
||
742 |
const char* trace_name_; |
||
743 |
// Pointer to pointer to 'this' that can be reset from the destructor, |
||
744 |
// in order to let Callback() know that 'this' no longer exists. |
||
745 |
QueryWrap** callback_ptr_ = nullptr; |
||
746 |
}; |
||
747 |
|||
748 |
|||
749 |
template <typename T> |
||
750 |
27 |
Local<Array> AddrTTLToArray(Environment* env, |
|
751 |
const T* addrttls, |
||
752 |
size_t naddrttls) { |
||
753 |
27 |
auto isolate = env->isolate(); |
|
754 |
27 |
EscapableHandleScope escapable_handle_scope(isolate); |
|
755 |
27 |
auto context = env->context(); |
|
756 |
|||
757 |
27 |
Local<Array> ttls = Array::New(isolate, naddrttls); |
|
758 |
✓✓✓✓ |
66 |
for (size_t i = 0; i < naddrttls; i++) { |
759 |
39 |
auto value = Integer::NewFromUnsigned(isolate, addrttls[i].ttl); |
|
760 |
117 |
ttls->Set(context, i, value).Check(); |
|
761 |
} |
||
762 |
|||
763 |
27 |
return escapable_handle_scope.Escape(ttls); |
|
764 |
} |
||
765 |
|||
766 |
|||
767 |
89 |
int ParseGeneralReply(Environment* env, |
|
768 |
const unsigned char* buf, |
||
769 |
int len, |
||
770 |
int* type, |
||
771 |
Local<Array> ret, |
||
772 |
void* addrttls = nullptr, |
||
773 |
int* naddrttls = nullptr) { |
||
774 |
89 |
HandleScope handle_scope(env->isolate()); |
|
775 |
89 |
auto context = env->context(); |
|
776 |
hostent* host; |
||
777 |
|||
778 |
int status; |
||
779 |
✓✓✓✓ ✗ |
89 |
switch (*type) { |
780 |
case ns_t_a: |
||
781 |
case ns_t_cname: |
||
782 |
case ns_t_cname_or_a: |
||
783 |
status = ares_parse_a_reply(buf, |
||
784 |
len, |
||
785 |
&host, |
||
786 |
static_cast<ares_addrttl*>(addrttls), |
||
787 |
36 |
naddrttls); |
|
788 |
36 |
break; |
|
789 |
case ns_t_aaaa: |
||
790 |
status = ares_parse_aaaa_reply(buf, |
||
791 |
len, |
||
792 |
&host, |
||
793 |
static_cast<ares_addr6ttl*>(addrttls), |
||
794 |
21 |
naddrttls); |
|
795 |
21 |
break; |
|
796 |
case ns_t_ns: |
||
797 |
17 |
status = ares_parse_ns_reply(buf, len, &host); |
|
798 |
17 |
break; |
|
799 |
case ns_t_ptr: |
||
800 |
15 |
status = ares_parse_ptr_reply(buf, len, nullptr, 0, AF_INET, &host); |
|
801 |
15 |
break; |
|
802 |
default: |
||
803 |
CHECK(0 && "Bad NS type"); |
||
804 |
break; |
||
805 |
} |
||
806 |
|||
807 |
✓✓ | 89 |
if (status != ARES_SUCCESS) |
808 |
24 |
return status; |
|
809 |
|||
810 |
/* If it's `CNAME`, return the CNAME value; |
||
811 |
* And if it's `CNAME_OR_A` and it has value in `h_name` and `h_aliases[0]`, |
||
812 |
* we consider it's a CNAME record, otherwise we consider it's an A record. */ |
||
813 |
✓✓✓✗ ✓✗✓✓ |
130 |
if ((*type == ns_t_cname_or_a && host->h_name && host->h_aliases[0]) || |
814 |
65 |
*type == ns_t_cname) { |
|
815 |
// A cname lookup always returns a single record but we follow the |
||
816 |
// common API here. |
||
817 |
2 |
*type = ns_t_cname; |
|
818 |
2 |
ret->Set(context, |
|
819 |
ret->Length(), |
||
820 |
8 |
OneByteString(env->isolate(), host->h_name)).Check(); |
|
821 |
2 |
ares_free_hostent(host); |
|
822 |
2 |
return ARES_SUCCESS; |
|
823 |
} |
||
824 |
|||
825 |
✓✓ | 63 |
if (*type == ns_t_cname_or_a) |
826 |
9 |
*type = ns_t_a; |
|
827 |
|||
828 |
✓✓ | 63 |
if (*type == ns_t_ns) { |
829 |
13 |
HostentToNames(env, host, ret); |
|
830 |
✓✓ | 50 |
} else if (*type == ns_t_ptr) { |
831 |
8 |
uint32_t offset = ret->Length(); |
|
832 |
✓✓ | 16 |
for (uint32_t i = 0; host->h_aliases[i] != nullptr; i++) { |
833 |
8 |
auto alias = OneByteString(env->isolate(), host->h_aliases[i]); |
|
834 |
24 |
ret->Set(context, i + offset, alias).Check(); |
|
835 |
} |
||
836 |
} else { |
||
837 |
42 |
uint32_t offset = ret->Length(); |
|
838 |
char ip[INET6_ADDRSTRLEN]; |
||
839 |
✓✓ | 98 |
for (uint32_t i = 0; host->h_addr_list[i] != nullptr; ++i) { |
840 |
56 |
uv_inet_ntop(host->h_addrtype, host->h_addr_list[i], ip, sizeof(ip)); |
|
841 |
56 |
auto address = OneByteString(env->isolate(), ip); |
|
842 |
168 |
ret->Set(context, i + offset, address).Check(); |
|
843 |
} |
||
844 |
} |
||
845 |
|||
846 |
63 |
ares_free_hostent(host); |
|
847 |
|||
848 |
63 |
return ARES_SUCCESS; |
|
849 |
} |
||
850 |
|||
851 |
|||
852 |
17 |
int ParseMxReply(Environment* env, |
|
853 |
const unsigned char* buf, |
||
854 |
int len, |
||
855 |
Local<Array> ret, |
||
856 |
bool need_type = false) { |
||
857 |
17 |
HandleScope handle_scope(env->isolate()); |
|
858 |
17 |
auto context = env->context(); |
|
859 |
|||
860 |
struct ares_mx_reply* mx_start; |
||
861 |
17 |
int status = ares_parse_mx_reply(buf, len, &mx_start); |
|
862 |
✗✓ | 17 |
if (status != ARES_SUCCESS) { |
863 |
return status; |
||
864 |
} |
||
865 |
|||
866 |
17 |
uint32_t offset = ret->Length(); |
|
867 |
17 |
ares_mx_reply* current = mx_start; |
|
868 |
✓✓ | 48 |
for (uint32_t i = 0; current != nullptr; ++i, current = current->next) { |
869 |
31 |
Local<Object> mx_record = Object::New(env->isolate()); |
|
870 |
mx_record->Set(context, |
||
871 |
env->exchange_string(), |
||
872 |
124 |
OneByteString(env->isolate(), current->host)).Check(); |
|
873 |
mx_record->Set(context, |
||
874 |
env->priority_string(), |
||
875 |
124 |
Integer::New(env->isolate(), current->priority)).Check(); |
|
876 |
✓✓ | 31 |
if (need_type) |
877 |
mx_record->Set(context, |
||
878 |
env->type_string(), |
||
879 |
60 |
env->dns_mx_string()).Check(); |
|
880 |
|||
881 |
93 |
ret->Set(context, i + offset, mx_record).Check(); |
|
882 |
} |
||
883 |
|||
884 |
17 |
ares_free_data(mx_start); |
|
885 |
17 |
return ARES_SUCCESS; |
|
886 |
} |
||
887 |
|||
888 |
19 |
int ParseTxtReply(Environment* env, |
|
889 |
const unsigned char* buf, |
||
890 |
int len, |
||
891 |
Local<Array> ret, |
||
892 |
bool need_type = false) { |
||
893 |
19 |
HandleScope handle_scope(env->isolate()); |
|
894 |
19 |
auto context = env->context(); |
|
895 |
|||
896 |
struct ares_txt_ext* txt_out; |
||
897 |
|||
898 |
19 |
int status = ares_parse_txt_reply_ext(buf, len, &txt_out); |
|
899 |
✗✓ | 19 |
if (status != ARES_SUCCESS) { |
900 |
return status; |
||
901 |
} |
||
902 |
|||
903 |
Local<Array> txt_chunk; |
||
904 |
|||
905 |
19 |
struct ares_txt_ext* current = txt_out; |
|
906 |
19 |
uint32_t i = 0, j; |
|
907 |
19 |
uint32_t offset = ret->Length(); |
|
908 |
✓✓ | 39 |
for (j = 0; current != nullptr; current = current->next) { |
909 |
20 |
Local<String> txt = OneByteString(env->isolate(), current->txt); |
|
910 |
|||
911 |
// New record found - write out the current chunk |
||
912 |
✓✓ | 20 |
if (current->record_start) { |
913 |
✓✓ | 18 |
if (!txt_chunk.IsEmpty()) { |
914 |
✓✗ | 8 |
if (need_type) { |
915 |
8 |
Local<Object> elem = Object::New(env->isolate()); |
|
916 |
24 |
elem->Set(context, env->entries_string(), txt_chunk).Check(); |
|
917 |
elem->Set(context, |
||
918 |
env->type_string(), |
||
919 |
32 |
env->dns_txt_string()).Check(); |
|
920 |
24 |
ret->Set(context, offset + i++, elem).Check(); |
|
921 |
} else { |
||
922 |
ret->Set(context, offset + i++, txt_chunk).Check(); |
||
923 |
} |
||
924 |
} |
||
925 |
|||
926 |
18 |
txt_chunk = Array::New(env->isolate()); |
|
927 |
18 |
j = 0; |
|
928 |
} |
||
929 |
|||
930 |
60 |
txt_chunk->Set(context, j++, txt).Check(); |
|
931 |
} |
||
932 |
|||
933 |
// Push last chunk if it isn't empty |
||
934 |
✓✓ | 19 |
if (!txt_chunk.IsEmpty()) { |
935 |
✓✓ | 10 |
if (need_type) { |
936 |
6 |
Local<Object> elem = Object::New(env->isolate()); |
|
937 |
18 |
elem->Set(context, env->entries_string(), txt_chunk).Check(); |
|
938 |
elem->Set(context, |
||
939 |
env->type_string(), |
||
940 |
24 |
env->dns_txt_string()).Check(); |
|
941 |
18 |
ret->Set(context, offset + i, elem).Check(); |
|
942 |
} else { |
||
943 |
12 |
ret->Set(context, offset + i, txt_chunk).Check(); |
|
944 |
} |
||
945 |
} |
||
946 |
|||
947 |
19 |
ares_free_data(txt_out); |
|
948 |
19 |
return ARES_SUCCESS; |
|
949 |
} |
||
950 |
|||
951 |
|||
952 |
15 |
int ParseSrvReply(Environment* env, |
|
953 |
const unsigned char* buf, |
||
954 |
int len, |
||
955 |
Local<Array> ret, |
||
956 |
bool need_type = false) { |
||
957 |
15 |
HandleScope handle_scope(env->isolate()); |
|
958 |
15 |
auto context = env->context(); |
|
959 |
|||
960 |
struct ares_srv_reply* srv_start; |
||
961 |
15 |
int status = ares_parse_srv_reply(buf, len, &srv_start); |
|
962 |
✗✓ | 15 |
if (status != ARES_SUCCESS) { |
963 |
return status; |
||
964 |
} |
||
965 |
|||
966 |
15 |
ares_srv_reply* current = srv_start; |
|
967 |
15 |
int offset = ret->Length(); |
|
968 |
✓✓ | 35 |
for (uint32_t i = 0; current != nullptr; ++i, current = current->next) { |
969 |
20 |
Local<Object> srv_record = Object::New(env->isolate()); |
|
970 |
srv_record->Set(context, |
||
971 |
env->name_string(), |
||
972 |
80 |
OneByteString(env->isolate(), current->host)).Check(); |
|
973 |
srv_record->Set(context, |
||
974 |
env->port_string(), |
||
975 |
80 |
Integer::New(env->isolate(), current->port)).Check(); |
|
976 |
srv_record->Set(context, |
||
977 |
env->priority_string(), |
||
978 |
80 |
Integer::New(env->isolate(), current->priority)).Check(); |
|
979 |
srv_record->Set(context, |
||
980 |
env->weight_string(), |
||
981 |
80 |
Integer::New(env->isolate(), current->weight)).Check(); |
|
982 |
✓✓ | 20 |
if (need_type) |
983 |
srv_record->Set(context, |
||
984 |
env->type_string(), |
||
985 |
40 |
env->dns_srv_string()).Check(); |
|
986 |
|||
987 |
60 |
ret->Set(context, i + offset, srv_record).Check(); |
|
988 |
} |
||
989 |
|||
990 |
15 |
ares_free_data(srv_start); |
|
991 |
15 |
return ARES_SUCCESS; |
|
992 |
} |
||
993 |
|||
994 |
|||
995 |
15 |
int ParseNaptrReply(Environment* env, |
|
996 |
const unsigned char* buf, |
||
997 |
int len, |
||
998 |
Local<Array> ret, |
||
999 |
bool need_type = false) { |
||
1000 |
15 |
HandleScope handle_scope(env->isolate()); |
|
1001 |
15 |
auto context = env->context(); |
|
1002 |
|||
1003 |
ares_naptr_reply* naptr_start; |
||
1004 |
15 |
int status = ares_parse_naptr_reply(buf, len, &naptr_start); |
|
1005 |
|||
1006 |
✗✓ | 15 |
if (status != ARES_SUCCESS) { |
1007 |
return status; |
||
1008 |
} |
||
1009 |
|||
1010 |
15 |
ares_naptr_reply* current = naptr_start; |
|
1011 |
15 |
int offset = ret->Length(); |
|
1012 |
✓✓ | 27 |
for (uint32_t i = 0; current != nullptr; ++i, current = current->next) { |
1013 |
12 |
Local<Object> naptr_record = Object::New(env->isolate()); |
|
1014 |
naptr_record->Set(context, |
||
1015 |
env->flags_string(), |
||
1016 |
48 |
OneByteString(env->isolate(), current->flags)).Check(); |
|
1017 |
naptr_record->Set(context, |
||
1018 |
env->service_string(), |
||
1019 |
OneByteString(env->isolate(), |
||
1020 |
48 |
current->service)).Check(); |
|
1021 |
naptr_record->Set(context, |
||
1022 |
env->regexp_string(), |
||
1023 |
OneByteString(env->isolate(), |
||
1024 |
48 |
current->regexp)).Check(); |
|
1025 |
naptr_record->Set(context, |
||
1026 |
env->replacement_string(), |
||
1027 |
OneByteString(env->isolate(), |
||
1028 |
48 |
current->replacement)).Check(); |
|
1029 |
naptr_record->Set(context, |
||
1030 |
env->order_string(), |
||
1031 |
48 |
Integer::New(env->isolate(), current->order)).Check(); |
|
1032 |
naptr_record->Set(context, |
||
1033 |
env->preference_string(), |
||
1034 |
Integer::New(env->isolate(), |
||
1035 |
48 |
current->preference)).Check(); |
|
1036 |
✓✓ | 12 |
if (need_type) |
1037 |
naptr_record->Set(context, |
||
1038 |
env->type_string(), |
||
1039 |
24 |
env->dns_naptr_string()).Check(); |
|
1040 |
|||
1041 |
36 |
ret->Set(context, i + offset, naptr_record).Check(); |
|
1042 |
} |
||
1043 |
|||
1044 |
15 |
ares_free_data(naptr_start); |
|
1045 |
15 |
return ARES_SUCCESS; |
|
1046 |
} |
||
1047 |
|||
1048 |
|||
1049 |
13 |
int ParseSoaReply(Environment* env, |
|
1050 |
unsigned char* buf, |
||
1051 |
int len, |
||
1052 |
Local<Object>* ret) { |
||
1053 |
13 |
EscapableHandleScope handle_scope(env->isolate()); |
|
1054 |
13 |
auto context = env->context(); |
|
1055 |
|||
1056 |
// Manage memory using standardard smart pointer std::unique_tr |
||
1057 |
struct AresDeleter { |
||
1058 |
112 |
void operator()(char* ptr) const noexcept { ares_free_string(ptr); } |
|
1059 |
}; |
||
1060 |
using ares_unique_ptr = std::unique_ptr<char[], AresDeleter>; |
||
1061 |
|||
1062 |
// Can't use ares_parse_soa_reply() here which can only parse single record |
||
1063 |
13 |
const unsigned int ancount = cares_get_16bit(buf + 6); |
|
1064 |
13 |
unsigned char* ptr = buf + NS_HFIXEDSZ; |
|
1065 |
char* name_temp; |
||
1066 |
long temp_len; // NOLINT(runtime/int) |
||
1067 |
13 |
int status = ares_expand_name(ptr, buf, len, &name_temp, &temp_len); |
|
1068 |
26 |
const ares_unique_ptr name(name_temp); |
|
1069 |
✗✓ | 13 |
if (status != ARES_SUCCESS) { |
1070 |
// returns EBADRESP in case of invalid input |
||
1071 |
return status == ARES_EBADNAME ? ARES_EBADRESP : status; |
||
1072 |
} |
||
1073 |
|||
1074 |
✗✓ | 13 |
if (ptr + temp_len + NS_QFIXEDSZ > buf + len) { |
1075 |
return ARES_EBADRESP; |
||
1076 |
} |
||
1077 |
13 |
ptr += temp_len + NS_QFIXEDSZ; |
|
1078 |
|||
1079 |
✓✓ | 88 |
for (unsigned int i = 0; i < ancount; i++) { |
1080 |
char* rr_name_temp; |
||
1081 |
long rr_temp_len; // NOLINT(runtime/int) |
||
1082 |
83 |
int status2 = ares_expand_name(ptr, buf, len, &rr_name_temp, &rr_temp_len); |
|
1083 |
83 |
const ares_unique_ptr rr_name(rr_name_temp); |
|
1084 |
|||
1085 |
✗✓ | 83 |
if (status2 != ARES_SUCCESS) |
1086 |
return status2 == ARES_EBADNAME ? ARES_EBADRESP : status2; |
||
1087 |
|||
1088 |
83 |
ptr += rr_temp_len; |
|
1089 |
✗✓ | 83 |
if (ptr + NS_RRFIXEDSZ > buf + len) { |
1090 |
return ARES_EBADRESP; |
||
1091 |
} |
||
1092 |
|||
1093 |
83 |
const int rr_type = cares_get_16bit(ptr); |
|
1094 |
83 |
const int rr_len = cares_get_16bit(ptr + 8); |
|
1095 |
83 |
ptr += NS_RRFIXEDSZ; |
|
1096 |
|||
1097 |
// only need SOA |
||
1098 |
✓✓ | 83 |
if (rr_type == ns_t_soa) { |
1099 |
char* nsname_temp; |
||
1100 |
long nsname_temp_len; // NOLINT(runtime/int) |
||
1101 |
|||
1102 |
int status3 = ares_expand_name(ptr, buf, len, |
||
1103 |
&nsname_temp, |
||
1104 |
8 |
&nsname_temp_len); |
|
1105 |
8 |
const ares_unique_ptr nsname(nsname_temp); |
|
1106 |
✗✓ | 8 |
if (status3 != ARES_SUCCESS) { |
1107 |
return status3 == ARES_EBADNAME ? ARES_EBADRESP : status3; |
||
1108 |
} |
||
1109 |
8 |
ptr += nsname_temp_len; |
|
1110 |
|||
1111 |
char* hostmaster_temp; |
||
1112 |
long hostmaster_temp_len; // NOLINT(runtime/int) |
||
1113 |
int status4 = ares_expand_name(ptr, buf, len, |
||
1114 |
&hostmaster_temp, |
||
1115 |
8 |
&hostmaster_temp_len); |
|
1116 |
8 |
const ares_unique_ptr hostmaster(hostmaster_temp); |
|
1117 |
✗✓ | 8 |
if (status4 != ARES_SUCCESS) { |
1118 |
return status4 == ARES_EBADNAME ? ARES_EBADRESP : status4; |
||
1119 |
} |
||
1120 |
8 |
ptr += hostmaster_temp_len; |
|
1121 |
|||
1122 |
✗✓ | 8 |
if (ptr + 5 * 4 > buf + len) { |
1123 |
return ARES_EBADRESP; |
||
1124 |
} |
||
1125 |
|||
1126 |
8 |
const unsigned int serial = cares_get_32bit(ptr + 0 * 4); |
|
1127 |
8 |
const unsigned int refresh = cares_get_32bit(ptr + 1 * 4); |
|
1128 |
8 |
const unsigned int retry = cares_get_32bit(ptr + 2 * 4); |
|
1129 |
8 |
const unsigned int expire = cares_get_32bit(ptr + 3 * 4); |
|
1130 |
8 |
const unsigned int minttl = cares_get_32bit(ptr + 4 * 4); |
|
1131 |
|||
1132 |
8 |
Local<Object> soa_record = Object::New(env->isolate()); |
|
1133 |
soa_record->Set(context, |
||
1134 |
env->nsname_string(), |
||
1135 |
32 |
OneByteString(env->isolate(), nsname.get())).Check(); |
|
1136 |
soa_record->Set(context, |
||
1137 |
env->hostmaster_string(), |
||
1138 |
OneByteString(env->isolate(), |
||
1139 |
32 |
hostmaster.get())).Check(); |
|
1140 |
soa_record->Set(context, |
||
1141 |
env->serial_string(), |
||
1142 |
32 |
Integer::NewFromUnsigned(env->isolate(), serial)).Check(); |
|
1143 |
soa_record->Set(context, |
||
1144 |
env->refresh_string(), |
||
1145 |
32 |
Integer::New(env->isolate(), refresh)).Check(); |
|
1146 |
soa_record->Set(context, |
||
1147 |
env->retry_string(), |
||
1148 |
32 |
Integer::New(env->isolate(), retry)).Check(); |
|
1149 |
soa_record->Set(context, |
||
1150 |
env->expire_string(), |
||
1151 |
32 |
Integer::New(env->isolate(), expire)).Check(); |
|
1152 |
soa_record->Set(context, |
||
1153 |
env->minttl_string(), |
||
1154 |
32 |
Integer::NewFromUnsigned(env->isolate(), minttl)).Check(); |
|
1155 |
soa_record->Set(context, |
||
1156 |
env->type_string(), |
||
1157 |
32 |
env->dns_soa_string()).Check(); |
|
1158 |
|||
1159 |
|||
1160 |
8 |
*ret = handle_scope.Escape(soa_record); |
|
1161 |
✗✓✗✓ |
8 |
break; |
1162 |
} |
||
1163 |
|||
1164 |
✓✗✓ | 75 |
ptr += rr_len; |
1165 |
75 |
} |
|
1166 |
|||
1167 |
13 |
return ARES_SUCCESS; |
|
1168 |
} |
||
1169 |
|||
1170 |
|||
1171 |
✗✓ | 30 |
class QueryAnyWrap: public QueryWrap { |
1172 |
public: |
||
1173 |
15 |
QueryAnyWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1174 |
15 |
: QueryWrap(channel, req_wrap_obj, "resolveAny") { |
|
1175 |
15 |
} |
|
1176 |
|||
1177 |
15 |
int Send(const char* name) override { |
|
1178 |
15 |
AresQuery(name, ns_c_in, ns_t_any); |
|
1179 |
15 |
return 0; |
|
1180 |
} |
||
1181 |
|||
1182 |
SET_NO_MEMORY_INFO() |
||
1183 |
SET_MEMORY_INFO_NAME(QueryAnyWrap) |
||
1184 |
SET_SELF_SIZE(QueryAnyWrap) |
||
1185 |
|||
1186 |
protected: |
||
1187 |
15 |
void Parse(unsigned char* buf, int len) override { |
|
1188 |
15 |
HandleScope handle_scope(env()->isolate()); |
|
1189 |
15 |
auto context = env()->context(); |
|
1190 |
✓✓ | 13 |
Context::Scope context_scope(context); |
1191 |
|||
1192 |
15 |
Local<Array> ret = Array::New(env()->isolate()); |
|
1193 |
int type, status, old_count; |
||
1194 |
|||
1195 |
/* Parse A records or CNAME records */ |
||
1196 |
ares_addrttl addrttls[256]; |
||
1197 |
15 |
int naddrttls = arraysize(addrttls); |
|
1198 |
|||
1199 |
15 |
type = ns_t_cname_or_a; |
|
1200 |
status = ParseGeneralReply(env(), |
||
1201 |
buf, |
||
1202 |
len, |
||
1203 |
&type, |
||
1204 |
ret, |
||
1205 |
addrttls, |
||
1206 |
15 |
&naddrttls); |
|
1207 |
15 |
uint32_t a_count = ret->Length(); |
|
1208 |
✓✓✓✓ |
15 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1209 |
2 |
ParseError(status); |
|
1210 |
2 |
return; |
|
1211 |
} |
||
1212 |
|||
1213 |
✓✓ | 13 |
if (type == ns_t_a) { |
1214 |
✗✓ | 9 |
CHECK_EQ(static_cast<uint32_t>(naddrttls), a_count); |
1215 |
✓✓ | 20 |
for (uint32_t i = 0; i < a_count; i++) { |
1216 |
11 |
Local<Object> obj = Object::New(env()->isolate()); |
|
1217 |
obj->Set(context, |
||
1218 |
env()->address_string(), |
||
1219 |
44 |
ret->Get(context, i).ToLocalChecked()).Check(); |
|
1220 |
obj->Set(context, |
||
1221 |
env()->ttl_string(), |
||
1222 |
Integer::NewFromUnsigned( |
||
1223 |
44 |
env()->isolate(), addrttls[i].ttl)).Check(); |
|
1224 |
obj->Set(context, |
||
1225 |
env()->type_string(), |
||
1226 |
44 |
env()->dns_a_string()).Check(); |
|
1227 |
22 |
ret->Set(context, i, obj).Check(); |
|
1228 |
} |
||
1229 |
} else { |
||
1230 |
✗✓ | 4 |
for (uint32_t i = 0; i < a_count; i++) { |
1231 |
Local<Object> obj = Object::New(env()->isolate()); |
||
1232 |
obj->Set(context, |
||
1233 |
env()->value_string(), |
||
1234 |
ret->Get(context, i).ToLocalChecked()).Check(); |
||
1235 |
obj->Set(context, |
||
1236 |
env()->type_string(), |
||
1237 |
env()->dns_cname_string()).Check(); |
||
1238 |
ret->Set(context, i, obj).Check(); |
||
1239 |
} |
||
1240 |
} |
||
1241 |
|||
1242 |
/* Parse AAAA records */ |
||
1243 |
ares_addr6ttl addr6ttls[256]; |
||
1244 |
13 |
int naddr6ttls = arraysize(addr6ttls); |
|
1245 |
|||
1246 |
13 |
type = ns_t_aaaa; |
|
1247 |
status = ParseGeneralReply(env(), |
||
1248 |
buf, |
||
1249 |
len, |
||
1250 |
&type, |
||
1251 |
ret, |
||
1252 |
addr6ttls, |
||
1253 |
13 |
&naddr6ttls); |
|
1254 |
13 |
uint32_t aaaa_count = ret->Length() - a_count; |
|
1255 |
✓✓✗✓ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1256 |
ParseError(status); |
||
1257 |
return; |
||
1258 |
} |
||
1259 |
|||
1260 |
✗✓ | 13 |
CHECK_EQ(aaaa_count, static_cast<uint32_t>(naddr6ttls)); |
1261 |
✗✓ | 13 |
CHECK_EQ(ret->Length(), a_count + aaaa_count); |
1262 |
✓✓ | 38 |
for (uint32_t i = a_count; i < ret->Length(); i++) { |
1263 |
6 |
Local<Object> obj = Object::New(env()->isolate()); |
|
1264 |
obj->Set(context, |
||
1265 |
env()->address_string(), |
||
1266 |
24 |
ret->Get(context, i).ToLocalChecked()).Check(); |
|
1267 |
obj->Set(context, |
||
1268 |
env()->ttl_string(), |
||
1269 |
Integer::NewFromUnsigned( |
||
1270 |
24 |
env()->isolate(), addr6ttls[i - a_count].ttl)).Check(); |
|
1271 |
obj->Set(context, |
||
1272 |
env()->type_string(), |
||
1273 |
24 |
env()->dns_aaaa_string()).Check(); |
|
1274 |
12 |
ret->Set(context, i, obj).Check(); |
|
1275 |
} |
||
1276 |
|||
1277 |
/* Parse MX records */ |
||
1278 |
13 |
status = ParseMxReply(env(), buf, len, ret, true); |
|
1279 |
✗✓✗✗ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1280 |
ParseError(status); |
||
1281 |
return; |
||
1282 |
} |
||
1283 |
|||
1284 |
/* Parse NS records */ |
||
1285 |
13 |
type = ns_t_ns; |
|
1286 |
13 |
old_count = ret->Length(); |
|
1287 |
13 |
status = ParseGeneralReply(env(), buf, len, &type, ret); |
|
1288 |
✓✓✗✓ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1289 |
ParseError(status); |
||
1290 |
return; |
||
1291 |
} |
||
1292 |
✓✓ | 66 |
for (uint32_t i = old_count; i < ret->Length(); i++) { |
1293 |
20 |
Local<Object> obj = Object::New(env()->isolate()); |
|
1294 |
obj->Set(context, |
||
1295 |
env()->value_string(), |
||
1296 |
80 |
ret->Get(context, i).ToLocalChecked()).Check(); |
|
1297 |
obj->Set(context, |
||
1298 |
env()->type_string(), |
||
1299 |
80 |
env()->dns_ns_string()).Check(); |
|
1300 |
40 |
ret->Set(context, i, obj).Check(); |
|
1301 |
} |
||
1302 |
|||
1303 |
/* Parse TXT records */ |
||
1304 |
13 |
status = ParseTxtReply(env(), buf, len, ret, true); |
|
1305 |
✗✓✗✗ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1306 |
ParseError(status); |
||
1307 |
return; |
||
1308 |
} |
||
1309 |
|||
1310 |
/* Parse SRV records */ |
||
1311 |
13 |
status = ParseSrvReply(env(), buf, len, ret, true); |
|
1312 |
✗✓✗✗ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1313 |
return; |
||
1314 |
} |
||
1315 |
|||
1316 |
/* Parse PTR records */ |
||
1317 |
13 |
type = ns_t_ptr; |
|
1318 |
13 |
old_count = ret->Length(); |
|
1319 |
13 |
status = ParseGeneralReply(env(), buf, len, &type, ret); |
|
1320 |
✓✓ | 38 |
for (uint32_t i = old_count; i < ret->Length(); i++) { |
1321 |
6 |
Local<Object> obj = Object::New(env()->isolate()); |
|
1322 |
obj->Set(context, |
||
1323 |
env()->value_string(), |
||
1324 |
24 |
ret->Get(context, i).ToLocalChecked()).Check(); |
|
1325 |
obj->Set(context, |
||
1326 |
env()->type_string(), |
||
1327 |
24 |
env()->dns_ptr_string()).Check(); |
|
1328 |
12 |
ret->Set(context, i, obj).Check(); |
|
1329 |
} |
||
1330 |
|||
1331 |
/* Parse NAPTR records */ |
||
1332 |
13 |
status = ParseNaptrReply(env(), buf, len, ret, true); |
|
1333 |
✗✓✗✗ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1334 |
ParseError(status); |
||
1335 |
return; |
||
1336 |
} |
||
1337 |
|||
1338 |
/* Parse SOA records */ |
||
1339 |
Local<Object> soa_record = Local<Object>(); |
||
1340 |
13 |
status = ParseSoaReply(env(), buf, len, &soa_record); |
|
1341 |
✗✓✗✗ |
13 |
if (status != ARES_SUCCESS && status != ARES_ENODATA) { |
1342 |
ParseError(status); |
||
1343 |
return; |
||
1344 |
} |
||
1345 |
✓✓ | 13 |
if (!soa_record.IsEmpty()) |
1346 |
24 |
ret->Set(context, ret->Length(), soa_record).Check(); |
|
1347 |
|||
1348 |
26 |
CallOnComplete(ret); |
|
1349 |
} |
||
1350 |
}; |
||
1351 |
|||
1352 |
|||
1353 |
✗✓ | 46 |
class QueryAWrap: public QueryWrap { |
1354 |
public: |
||
1355 |
23 |
QueryAWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1356 |
23 |
: QueryWrap(channel, req_wrap_obj, "resolve4") { |
|
1357 |
23 |
} |
|
1358 |
|||
1359 |
23 |
int Send(const char* name) override { |
|
1360 |
23 |
AresQuery(name, ns_c_in, ns_t_a); |
|
1361 |
23 |
return 0; |
|
1362 |
} |
||
1363 |
|||
1364 |
2 |
SET_NO_MEMORY_INFO() |
|
1365 |
2 |
SET_MEMORY_INFO_NAME(QueryAWrap) |
|
1366 |
2 |
SET_SELF_SIZE(QueryAWrap) |
|
1367 |
|||
1368 |
protected: |
||
1369 |
19 |
void Parse(unsigned char* buf, int len) override { |
|
1370 |
19 |
HandleScope handle_scope(env()->isolate()); |
|
1371 |
✓✗ | 38 |
Context::Scope context_scope(env()->context()); |
1372 |
|||
1373 |
ares_addrttl addrttls[256]; |
||
1374 |
19 |
int naddrttls = arraysize(addrttls), status; |
|
1375 |
19 |
Local<Array> ret = Array::New(env()->isolate()); |
|
1376 |
|||
1377 |
19 |
int type = ns_t_a; |
|
1378 |
status = ParseGeneralReply(env(), |
||
1379 |
buf, |
||
1380 |
len, |
||
1381 |
&type, |
||
1382 |
ret, |
||
1383 |
addrttls, |
||
1384 |
19 |
&naddrttls); |
|
1385 |
✗✓ | 19 |
if (status != ARES_SUCCESS) { |
1386 |
ParseError(status); |
||
1387 |
19 |
return; |
|
1388 |
} |
||
1389 |
|||
1390 |
Local<Array> ttls = AddrTTLToArray<ares_addrttl>(env(), |
||
1391 |
addrttls, |
||
1392 |
19 |
naddrttls); |
|
1393 |
|||
1394 |
38 |
CallOnComplete(ret, ttls); |
|
1395 |
} |
||
1396 |
}; |
||
1397 |
|||
1398 |
|||
1399 |
✗✓ | 18 |
class QueryAaaaWrap: public QueryWrap { |
1400 |
public: |
||
1401 |
9 |
QueryAaaaWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1402 |
9 |
: QueryWrap(channel, req_wrap_obj, "resolve6") { |
|
1403 |
9 |
} |
|
1404 |
|||
1405 |
9 |
int Send(const char* name) override { |
|
1406 |
9 |
AresQuery(name, ns_c_in, ns_t_aaaa); |
|
1407 |
9 |
return 0; |
|
1408 |
} |
||
1409 |
|||
1410 |
1 |
SET_NO_MEMORY_INFO() |
|
1411 |
1 |
SET_MEMORY_INFO_NAME(QueryAaaaWrap) |
|
1412 |
1 |
SET_SELF_SIZE(QueryAaaaWrap) |
|
1413 |
|||
1414 |
protected: |
||
1415 |
8 |
void Parse(unsigned char* buf, int len) override { |
|
1416 |
8 |
HandleScope handle_scope(env()->isolate()); |
|
1417 |
✓✗ | 16 |
Context::Scope context_scope(env()->context()); |
1418 |
|||
1419 |
ares_addr6ttl addrttls[256]; |
||
1420 |
8 |
int naddrttls = arraysize(addrttls), status; |
|
1421 |
8 |
Local<Array> ret = Array::New(env()->isolate()); |
|
1422 |
|||
1423 |
8 |
int type = ns_t_aaaa; |
|
1424 |
status = ParseGeneralReply(env(), |
||
1425 |
buf, |
||
1426 |
len, |
||
1427 |
&type, |
||
1428 |
ret, |
||
1429 |
addrttls, |
||
1430 |
8 |
&naddrttls); |
|
1431 |
✗✓ | 8 |
if (status != ARES_SUCCESS) { |
1432 |
ParseError(status); |
||
1433 |
8 |
return; |
|
1434 |
} |
||
1435 |
|||
1436 |
Local<Array> ttls = AddrTTLToArray<ares_addr6ttl>(env(), |
||
1437 |
addrttls, |
||
1438 |
8 |
naddrttls); |
|
1439 |
|||
1440 |
16 |
CallOnComplete(ret, ttls); |
|
1441 |
} |
||
1442 |
}; |
||
1443 |
|||
1444 |
|||
1445 |
✗✓ | 12 |
class QueryCnameWrap: public QueryWrap { |
1446 |
public: |
||
1447 |
6 |
QueryCnameWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1448 |
6 |
: QueryWrap(channel, req_wrap_obj, "resolveCname") { |
|
1449 |
6 |
} |
|
1450 |
|||
1451 |
6 |
int Send(const char* name) override { |
|
1452 |
6 |
AresQuery(name, ns_c_in, ns_t_cname); |
|
1453 |
6 |
return 0; |
|
1454 |
} |
||
1455 |
|||
1456 |
SET_NO_MEMORY_INFO() |
||
1457 |
SET_MEMORY_INFO_NAME(QueryCnameWrap) |
||
1458 |
SET_SELF_SIZE(QueryCnameWrap) |
||
1459 |
|||
1460 |
protected: |
||
1461 |
2 |
void Parse(unsigned char* buf, int len) override { |
|
1462 |
2 |
HandleScope handle_scope(env()->isolate()); |
|
1463 |
✓✗ | 4 |
Context::Scope context_scope(env()->context()); |
1464 |
|||
1465 |
2 |
Local<Array> ret = Array::New(env()->isolate()); |
|
1466 |
2 |
int type = ns_t_cname; |
|
1467 |
2 |
int status = ParseGeneralReply(env(), buf, len, &type, ret); |
|
1468 |
✗✓ | 2 |
if (status != ARES_SUCCESS) { |
1469 |
ParseError(status); |
||
1470 |
2 |
return; |
|
1471 |
} |
||
1472 |
|||
1473 |
4 |
this->CallOnComplete(ret); |
|
1474 |
} |
||
1475 |
}; |
||
1476 |
|||
1477 |
|||
1478 |
✗✓ | 14 |
class QueryMxWrap: public QueryWrap { |
1479 |
public: |
||
1480 |
7 |
QueryMxWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1481 |
7 |
: QueryWrap(channel, req_wrap_obj, "resolveMx") { |
|
1482 |
7 |
} |
|
1483 |
|||
1484 |
7 |
int Send(const char* name) override { |
|
1485 |
7 |
AresQuery(name, ns_c_in, ns_t_mx); |
|
1486 |
7 |
return 0; |
|
1487 |
} |
||
1488 |
|||
1489 |
SET_NO_MEMORY_INFO() |
||
1490 |
SET_MEMORY_INFO_NAME(QueryMxWrap) |
||
1491 |
SET_SELF_SIZE(QueryMxWrap) |
||
1492 |
|||
1493 |
protected: |
||
1494 |
4 |
void Parse(unsigned char* buf, int len) override { |
|
1495 |
4 |
HandleScope handle_scope(env()->isolate()); |
|
1496 |
✓✗ | 8 |
Context::Scope context_scope(env()->context()); |
1497 |
|||
1498 |
4 |
Local<Array> mx_records = Array::New(env()->isolate()); |
|
1499 |
4 |
int status = ParseMxReply(env(), buf, len, mx_records); |
|
1500 |
|||
1501 |
✗✓ | 4 |
if (status != ARES_SUCCESS) { |
1502 |
ParseError(status); |
||
1503 |
4 |
return; |
|
1504 |
} |
||
1505 |
|||
1506 |
8 |
this->CallOnComplete(mx_records); |
|
1507 |
} |
||
1508 |
}; |
||
1509 |
|||
1510 |
|||
1511 |
✗✓ | 12 |
class QueryNsWrap: public QueryWrap { |
1512 |
public: |
||
1513 |
6 |
QueryNsWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1514 |
6 |
: QueryWrap(channel, req_wrap_obj, "resolveNs") { |
|
1515 |
6 |
} |
|
1516 |
|||
1517 |
6 |
int Send(const char* name) override { |
|
1518 |
6 |
AresQuery(name, ns_c_in, ns_t_ns); |
|
1519 |
6 |
return 0; |
|
1520 |
} |
||
1521 |
|||
1522 |
SET_NO_MEMORY_INFO() |
||
1523 |
SET_MEMORY_INFO_NAME(QueryNsWrap) |
||
1524 |
SET_SELF_SIZE(QueryNsWrap) |
||
1525 |
|||
1526 |
protected: |
||
1527 |
4 |
void Parse(unsigned char* buf, int len) override { |
|
1528 |
4 |
HandleScope handle_scope(env()->isolate()); |
|
1529 |
✓✗ | 8 |
Context::Scope context_scope(env()->context()); |
1530 |
|||
1531 |
4 |
int type = ns_t_ns; |
|
1532 |
4 |
Local<Array> names = Array::New(env()->isolate()); |
|
1533 |
4 |
int status = ParseGeneralReply(env(), buf, len, &type, names); |
|
1534 |
✗✓ | 4 |
if (status != ARES_SUCCESS) { |
1535 |
ParseError(status); |
||
1536 |
4 |
return; |
|
1537 |
} |
||
1538 |
|||
1539 |
8 |
this->CallOnComplete(names); |
|
1540 |
} |
||
1541 |
}; |
||
1542 |
|||
1543 |
|||
1544 |
✗✓ | 16 |
class QueryTxtWrap: public QueryWrap { |
1545 |
public: |
||
1546 |
8 |
QueryTxtWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1547 |
8 |
: QueryWrap(channel, req_wrap_obj, "resolveTxt") { |
|
1548 |
8 |
} |
|
1549 |
|||
1550 |
8 |
int Send(const char* name) override { |
|
1551 |
8 |
AresQuery(name, ns_c_in, ns_t_txt); |
|
1552 |
8 |
return 0; |
|
1553 |
} |
||
1554 |
|||
1555 |
SET_NO_MEMORY_INFO() |
||
1556 |
SET_MEMORY_INFO_NAME(QueryTxtWrap) |
||
1557 |
SET_SELF_SIZE(QueryTxtWrap) |
||
1558 |
|||
1559 |
protected: |
||
1560 |
6 |
void Parse(unsigned char* buf, int len) override { |
|
1561 |
6 |
HandleScope handle_scope(env()->isolate()); |
|
1562 |
✓✗ | 12 |
Context::Scope context_scope(env()->context()); |
1563 |
|||
1564 |
6 |
Local<Array> txt_records = Array::New(env()->isolate()); |
|
1565 |
6 |
int status = ParseTxtReply(env(), buf, len, txt_records); |
|
1566 |
✗✓ | 6 |
if (status != ARES_SUCCESS) { |
1567 |
ParseError(status); |
||
1568 |
6 |
return; |
|
1569 |
} |
||
1570 |
|||
1571 |
12 |
this->CallOnComplete(txt_records); |
|
1572 |
} |
||
1573 |
}; |
||
1574 |
|||
1575 |
|||
1576 |
✗✓ | 12 |
class QuerySrvWrap: public QueryWrap { |
1577 |
public: |
||
1578 |
6 |
explicit QuerySrvWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1579 |
6 |
: QueryWrap(channel, req_wrap_obj, "resolveSrv") { |
|
1580 |
6 |
} |
|
1581 |
|||
1582 |
6 |
int Send(const char* name) override { |
|
1583 |
6 |
AresQuery(name, ns_c_in, ns_t_srv); |
|
1584 |
6 |
return 0; |
|
1585 |
} |
||
1586 |
|||
1587 |
SET_NO_MEMORY_INFO() |
||
1588 |
SET_MEMORY_INFO_NAME(QuerySrvWrap) |
||
1589 |
SET_SELF_SIZE(QuerySrvWrap) |
||
1590 |
|||
1591 |
protected: |
||
1592 |
2 |
void Parse(unsigned char* buf, int len) override { |
|
1593 |
2 |
HandleScope handle_scope(env()->isolate()); |
|
1594 |
✓✗ | 4 |
Context::Scope context_scope(env()->context()); |
1595 |
|||
1596 |
2 |
Local<Array> srv_records = Array::New(env()->isolate()); |
|
1597 |
2 |
int status = ParseSrvReply(env(), buf, len, srv_records); |
|
1598 |
✗✓ | 2 |
if (status != ARES_SUCCESS) { |
1599 |
ParseError(status); |
||
1600 |
2 |
return; |
|
1601 |
} |
||
1602 |
|||
1603 |
4 |
this->CallOnComplete(srv_records); |
|
1604 |
} |
||
1605 |
}; |
||
1606 |
|||
1607 |
✗✓ | 12 |
class QueryPtrWrap: public QueryWrap { |
1608 |
public: |
||
1609 |
6 |
explicit QueryPtrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1610 |
6 |
: QueryWrap(channel, req_wrap_obj, "resolvePtr") { |
|
1611 |
6 |
} |
|
1612 |
|||
1613 |
6 |
int Send(const char* name) override { |
|
1614 |
6 |
AresQuery(name, ns_c_in, ns_t_ptr); |
|
1615 |
6 |
return 0; |
|
1616 |
} |
||
1617 |
|||
1618 |
SET_NO_MEMORY_INFO() |
||
1619 |
SET_MEMORY_INFO_NAME(QueryPtrWrap) |
||
1620 |
SET_SELF_SIZE(QueryPtrWrap) |
||
1621 |
|||
1622 |
protected: |
||
1623 |
2 |
void Parse(unsigned char* buf, int len) override { |
|
1624 |
2 |
HandleScope handle_scope(env()->isolate()); |
|
1625 |
✓✗ | 4 |
Context::Scope context_scope(env()->context()); |
1626 |
|||
1627 |
2 |
int type = ns_t_ptr; |
|
1628 |
2 |
Local<Array> aliases = Array::New(env()->isolate()); |
|
1629 |
|||
1630 |
2 |
int status = ParseGeneralReply(env(), buf, len, &type, aliases); |
|
1631 |
✗✓ | 2 |
if (status != ARES_SUCCESS) { |
1632 |
ParseError(status); |
||
1633 |
2 |
return; |
|
1634 |
} |
||
1635 |
|||
1636 |
4 |
this->CallOnComplete(aliases); |
|
1637 |
} |
||
1638 |
}; |
||
1639 |
|||
1640 |
✗✓ | 12 |
class QueryNaptrWrap: public QueryWrap { |
1641 |
public: |
||
1642 |
6 |
explicit QueryNaptrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1643 |
6 |
: QueryWrap(channel, req_wrap_obj, "resolveNaptr") { |
|
1644 |
6 |
} |
|
1645 |
|||
1646 |
6 |
int Send(const char* name) override { |
|
1647 |
6 |
AresQuery(name, ns_c_in, ns_t_naptr); |
|
1648 |
6 |
return 0; |
|
1649 |
} |
||
1650 |
|||
1651 |
SET_NO_MEMORY_INFO() |
||
1652 |
SET_MEMORY_INFO_NAME(QueryNaptrWrap) |
||
1653 |
SET_SELF_SIZE(QueryNaptrWrap) |
||
1654 |
|||
1655 |
protected: |
||
1656 |
2 |
void Parse(unsigned char* buf, int len) override { |
|
1657 |
2 |
HandleScope handle_scope(env()->isolate()); |
|
1658 |
✓✗ | 4 |
Context::Scope context_scope(env()->context()); |
1659 |
|||
1660 |
2 |
Local<Array> naptr_records = Array::New(env()->isolate()); |
|
1661 |
2 |
int status = ParseNaptrReply(env(), buf, len, naptr_records); |
|
1662 |
✗✓ | 2 |
if (status != ARES_SUCCESS) { |
1663 |
ParseError(status); |
||
1664 |
2 |
return; |
|
1665 |
} |
||
1666 |
|||
1667 |
4 |
this->CallOnComplete(naptr_records); |
|
1668 |
} |
||
1669 |
}; |
||
1670 |
|||
1671 |
|||
1672 |
✗✓ | 16 |
class QuerySoaWrap: public QueryWrap { |
1673 |
public: |
||
1674 |
8 |
QuerySoaWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1675 |
8 |
: QueryWrap(channel, req_wrap_obj, "resolveSoa") { |
|
1676 |
8 |
} |
|
1677 |
|||
1678 |
8 |
int Send(const char* name) override { |
|
1679 |
8 |
AresQuery(name, ns_c_in, ns_t_soa); |
|
1680 |
8 |
return 0; |
|
1681 |
} |
||
1682 |
|||
1683 |
SET_NO_MEMORY_INFO() |
||
1684 |
SET_MEMORY_INFO_NAME(QuerySoaWrap) |
||
1685 |
SET_SELF_SIZE(QuerySoaWrap) |
||
1686 |
|||
1687 |
protected: |
||
1688 |
6 |
void Parse(unsigned char* buf, int len) override { |
|
1689 |
6 |
HandleScope handle_scope(env()->isolate()); |
|
1690 |
6 |
auto context = env()->context(); |
|
1691 |
✓✗ | 6 |
Context::Scope context_scope(context); |
1692 |
|||
1693 |
ares_soa_reply* soa_out; |
||
1694 |
6 |
int status = ares_parse_soa_reply(buf, len, &soa_out); |
|
1695 |
|||
1696 |
✗✓ | 6 |
if (status != ARES_SUCCESS) { |
1697 |
ParseError(status); |
||
1698 |
6 |
return; |
|
1699 |
} |
||
1700 |
|||
1701 |
6 |
Local<Object> soa_record = Object::New(env()->isolate()); |
|
1702 |
|||
1703 |
soa_record->Set(context, |
||
1704 |
env()->nsname_string(), |
||
1705 |
OneByteString(env()->isolate(), |
||
1706 |
24 |
soa_out->nsname)).Check(); |
|
1707 |
soa_record->Set(context, |
||
1708 |
env()->hostmaster_string(), |
||
1709 |
OneByteString(env()->isolate(), |
||
1710 |
24 |
soa_out->hostmaster)).Check(); |
|
1711 |
soa_record->Set(context, |
||
1712 |
env()->serial_string(), |
||
1713 |
Integer::NewFromUnsigned( |
||
1714 |
24 |
env()->isolate(), soa_out->serial)).Check(); |
|
1715 |
soa_record->Set(context, |
||
1716 |
env()->refresh_string(), |
||
1717 |
Integer::New(env()->isolate(), |
||
1718 |
24 |
soa_out->refresh)).Check(); |
|
1719 |
soa_record->Set(context, |
||
1720 |
env()->retry_string(), |
||
1721 |
24 |
Integer::New(env()->isolate(), soa_out->retry)).Check(); |
|
1722 |
soa_record->Set(context, |
||
1723 |
env()->expire_string(), |
||
1724 |
24 |
Integer::New(env()->isolate(), soa_out->expire)).Check(); |
|
1725 |
soa_record->Set(context, |
||
1726 |
env()->minttl_string(), |
||
1727 |
Integer::NewFromUnsigned( |
||
1728 |
24 |
env()->isolate(), soa_out->minttl)).Check(); |
|
1729 |
|||
1730 |
6 |
ares_free_data(soa_out); |
|
1731 |
|||
1732 |
12 |
this->CallOnComplete(soa_record); |
|
1733 |
} |
||
1734 |
}; |
||
1735 |
|||
1736 |
|||
1737 |
✗✓ | 24 |
class GetHostByAddrWrap: public QueryWrap { |
1738 |
public: |
||
1739 |
12 |
explicit GetHostByAddrWrap(ChannelWrap* channel, Local<Object> req_wrap_obj) |
|
1740 |
12 |
: QueryWrap(channel, req_wrap_obj, "reverse") { |
|
1741 |
12 |
} |
|
1742 |
|||
1743 |
12 |
int Send(const char* name) override { |
|
1744 |
int length, family; |
||
1745 |
char address_buffer[sizeof(struct in6_addr)]; |
||
1746 |
|||
1747 |
✓✓ | 12 |
if (uv_inet_pton(AF_INET, name, &address_buffer) == 0) { |
1748 |
8 |
length = sizeof(struct in_addr); |
|
1749 |
8 |
family = AF_INET; |
|
1750 |
✓✓ | 4 |
} else if (uv_inet_pton(AF_INET6, name, &address_buffer) == 0) { |
1751 |
2 |
length = sizeof(struct in6_addr); |
|
1752 |
2 |
family = AF_INET6; |
|
1753 |
} else { |
||
1754 |
2 |
return UV_EINVAL; // So errnoException() reports a proper error. |
|
1755 |
} |
||
1756 |
|||
1757 |
✓✓✓✓ ✓✗ |
20 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( |
1758 |
TRACING_CATEGORY_NODE2(dns, native), "reverse", this, |
||
1759 |
"name", TRACE_STR_COPY(name), |
||
1760 |
"family", family == AF_INET ? "ipv4" : "ipv6"); |
||
1761 |
|||
1762 |
ares_gethostbyaddr(channel_->cares_channel(), |
||
1763 |
address_buffer, |
||
1764 |
length, |
||
1765 |
family, |
||
1766 |
Callback, |
||
1767 |
10 |
MakeCallbackPointer()); |
|
1768 |
10 |
return 0; |
|
1769 |
} |
||
1770 |
|||
1771 |
SET_NO_MEMORY_INFO() |
||
1772 |
SET_MEMORY_INFO_NAME(GetHostByAddrWrap) |
||
1773 |
SET_SELF_SIZE(GetHostByAddrWrap) |
||
1774 |
|||
1775 |
protected: |
||
1776 |
7 |
void Parse(struct hostent* host) override { |
|
1777 |
7 |
HandleScope handle_scope(env()->isolate()); |
|
1778 |
7 |
Context::Scope context_scope(env()->context()); |
|
1779 |
21 |
this->CallOnComplete(HostentToNames(env(), host)); |
|
1780 |
7 |
} |
|
1781 |
}; |
||
1782 |
|||
1783 |
|||
1784 |
template <class Wrap> |
||
1785 |
112 |
static void Query(const FunctionCallbackInfo<Value>& args) { |
|
1786 |
112 |
Environment* env = Environment::GetCurrent(args); |
|
1787 |
ChannelWrap* channel; |
||
1788 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
224 |
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder()); |
1789 |
|||
1790 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
112 |
CHECK_EQ(false, args.IsConstructCall()); |
1791 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
224 |
CHECK(args[0]->IsObject()); |
1792 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
336 |
CHECK(args[1]->IsString()); |
1793 |
|||
1794 |
224 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
1795 |
224 |
Local<String> string = args[1].As<String>(); |
|
1796 |
112 |
auto wrap = std::make_unique<Wrap>(channel, req_wrap_obj); |
|
1797 |
|||
1798 |
224 |
node::Utf8Value name(env->isolate(), string); |
|
1799 |
112 |
channel->ModifyActivityQueryCount(1); |
|
1800 |
112 |
int err = wrap->Send(*name); |
|
1801 |
✓✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ |
112 |
if (err) { |
1802 |
2 |
channel->ModifyActivityQueryCount(-1); |
|
1803 |
} else { |
||
1804 |
// Release ownership of the pointer allowing the ownership to be transferred |
||
1805 |
110 |
USE(wrap.release()); |
|
1806 |
} |
||
1807 |
|||
1808 |
336 |
args.GetReturnValue().Set(err); |
|
1809 |
} |
||
1810 |
|||
1811 |
|||
1812 |
5249 |
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { |
|
1813 |
std::unique_ptr<GetAddrInfoReqWrap> req_wrap { |
||
1814 |
5249 |
static_cast<GetAddrInfoReqWrap*>(req->data)}; |
|
1815 |
5249 |
Environment* env = req_wrap->env(); |
|
1816 |
|||
1817 |
10498 |
HandleScope handle_scope(env->isolate()); |
|
1818 |
5249 |
Context::Scope context_scope(env->context()); |
|
1819 |
|||
1820 |
Local<Value> argv[] = { |
||
1821 |
Integer::New(env->isolate(), status), |
||
1822 |
Null(env->isolate()) |
||
1823 |
15747 |
}; |
|
1824 |
|||
1825 |
5249 |
uint64_t n = 0; |
|
1826 |
5249 |
const bool verbatim = req_wrap->verbatim(); |
|
1827 |
|||
1828 |
✓✓ | 5249 |
if (status == 0) { |
1829 |
5129 |
Local<Array> results = Array::New(env->isolate()); |
|
1830 |
|||
1831 |
10257 |
auto add = [&] (bool want_ipv4, bool want_ipv6) { |
|
1832 |
✓✓ | 41291 |
for (auto p = res; p != nullptr; p = p->ai_next) { |
1833 |
✗✓ | 31034 |
CHECK_EQ(p->ai_socktype, SOCK_STREAM); |
1834 |
|||
1835 |
const char* addr; |
||
1836 |
✓✓✓✓ |
31034 |
if (want_ipv4 && p->ai_family == AF_INET) { |
1837 |
addr = reinterpret_cast<char*>( |
||
1838 |
5301 |
&(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr)); |
|
1839 |
✓✓✓✓ |
25733 |
} else if (want_ipv6 && p->ai_family == AF_INET6) { |
1840 |
addr = reinterpret_cast<char*>( |
||
1841 |
10217 |
&(reinterpret_cast<struct sockaddr_in6*>(p->ai_addr)->sin6_addr)); |
|
1842 |
} else { |
||
1843 |
31032 |
continue; |
|
1844 |
} |
||
1845 |
|||
1846 |
char ip[INET6_ADDRSTRLEN]; |
||
1847 |
✗✓ | 15518 |
if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip))) |
1848 |
continue; |
||
1849 |
|||
1850 |
15518 |
Local<String> s = OneByteString(env->isolate(), ip); |
|
1851 |
46554 |
results->Set(env->context(), n, s).Check(); |
|
1852 |
15518 |
n++; |
|
1853 |
} |
||
1854 |
15386 |
}; |
|
1855 |
|||
1856 |
5129 |
add(true, verbatim); |
|
1857 |
✓✓ | 5129 |
if (verbatim == false) |
1858 |
5128 |
add(false, true); |
|
1859 |
|||
1860 |
// No responses were found to return |
||
1861 |
✗✓ | 5129 |
if (n == 0) { |
1862 |
argv[0] = Integer::New(env->isolate(), UV_EAI_NODATA); |
||
1863 |
} |
||
1864 |
|||
1865 |
5129 |
argv[1] = results; |
|
1866 |
} |
||
1867 |
|||
1868 |
5249 |
uv_freeaddrinfo(res); |
|
1869 |
|||
1870 |
✓✓✓✓ |
10498 |
TRACE_EVENT_NESTABLE_ASYNC_END2( |
1871 |
TRACING_CATEGORY_NODE2(dns, native), "lookup", req_wrap.get(), |
||
1872 |
"count", n, "verbatim", verbatim); |
||
1873 |
|||
1874 |
// Make the callback into JavaScript |
||
1875 |
10498 |
req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); |
|
1876 |
5249 |
} |
|
1877 |
|||
1878 |
|||
1879 |
11 |
void AfterGetNameInfo(uv_getnameinfo_t* req, |
|
1880 |
int status, |
||
1881 |
const char* hostname, |
||
1882 |
const char* service) { |
||
1883 |
std::unique_ptr<GetNameInfoReqWrap> req_wrap { |
||
1884 |
11 |
static_cast<GetNameInfoReqWrap*>(req->data)}; |
|
1885 |
11 |
Environment* env = req_wrap->env(); |
|
1886 |
|||
1887 |
22 |
HandleScope handle_scope(env->isolate()); |
|
1888 |
11 |
Context::Scope context_scope(env->context()); |
|
1889 |
|||
1890 |
Local<Value> argv[] = { |
||
1891 |
Integer::New(env->isolate(), status), |
||
1892 |
Null(env->isolate()), |
||
1893 |
Null(env->isolate()) |
||
1894 |
44 |
}; |
|
1895 |
|||
1896 |
✓✓ | 11 |
if (status == 0) { |
1897 |
// Success |
||
1898 |
7 |
Local<String> js_hostname = OneByteString(env->isolate(), hostname); |
|
1899 |
7 |
Local<String> js_service = OneByteString(env->isolate(), service); |
|
1900 |
7 |
argv[1] = js_hostname; |
|
1901 |
7 |
argv[2] = js_service; |
|
1902 |
} |
||
1903 |
|||
1904 |
✓✓✓✓ |
22 |
TRACE_EVENT_NESTABLE_ASYNC_END2( |
1905 |
TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(), |
||
1906 |
"hostname", TRACE_STR_COPY(hostname), |
||
1907 |
"service", TRACE_STR_COPY(service)); |
||
1908 |
|||
1909 |
// Make the callback into JavaScript |
||
1910 |
22 |
req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); |
|
1911 |
11 |
} |
|
1912 |
|||
1913 |
using ParseIPResult = |
||
1914 |
decltype(static_cast<ares_addr_port_node*>(nullptr)->addr); |
||
1915 |
|||
1916 |
24 |
int ParseIP(const char* ip, ParseIPResult* result = nullptr) { |
|
1917 |
ParseIPResult tmp; |
||
1918 |
✗✓ | 24 |
if (result == nullptr) result = &tmp; |
1919 |
✓✓ | 24 |
if (0 == uv_inet_pton(AF_INET, ip, result)) return 4; |
1920 |
✓✓ | 10 |
if (0 == uv_inet_pton(AF_INET6, ip, result)) return 6; |
1921 |
1 |
return 0; |
|
1922 |
} |
||
1923 |
|||
1924 |
24 |
void CanonicalizeIP(const FunctionCallbackInfo<Value>& args) { |
|
1925 |
24 |
v8::Isolate* isolate = args.GetIsolate(); |
|
1926 |
24 |
node::Utf8Value ip(isolate, args[0]); |
|
1927 |
|||
1928 |
ParseIPResult result; |
||
1929 |
24 |
const int rc = ParseIP(*ip, &result); |
|
1930 |
✓✓ | 48 |
if (rc == 0) return; |
1931 |
|||
1932 |
char canonical_ip[INET6_ADDRSTRLEN]; |
||
1933 |
✓✓ | 23 |
const int af = (rc == 4 ? AF_INET : AF_INET6); |
1934 |
✗✓ | 23 |
CHECK_EQ(0, uv_inet_ntop(af, &result, canonical_ip, sizeof(canonical_ip))); |
1935 |
v8::Local<String> val = String::NewFromUtf8(isolate, canonical_ip, |
||
1936 |
46 |
v8::NewStringType::kNormal).ToLocalChecked(); |
|
1937 |
✓✓ | 46 |
args.GetReturnValue().Set(val); |
1938 |
} |
||
1939 |
|||
1940 |
5250 |
void GetAddrInfo(const FunctionCallbackInfo<Value>& args) { |
|
1941 |
5250 |
Environment* env = Environment::GetCurrent(args); |
|
1942 |
|||
1943 |
✗✓ | 10500 |
CHECK(args[0]->IsObject()); |
1944 |
✗✓ | 15750 |
CHECK(args[1]->IsString()); |
1945 |
✗✓ | 10500 |
CHECK(args[2]->IsInt32()); |
1946 |
✗✓ | 10500 |
CHECK(args[4]->IsBoolean()); |
1947 |
10500 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
1948 |
5250 |
node::Utf8Value hostname(env->isolate(), args[1]); |
|
1949 |
|||
1950 |
5250 |
int32_t flags = 0; |
|
1951 |
✓✗ | 10500 |
if (args[3]->IsInt32()) { |
1952 |
15750 |
flags = args[3].As<Int32>()->Value(); |
|
1953 |
} |
||
1954 |
|||
1955 |
int family; |
||
1956 |
|||
1957 |
✓✓✓✗ |
15750 |
switch (args[2].As<Int32>()->Value()) { |
1958 |
case 0: |
||
1959 |
5211 |
family = AF_UNSPEC; |
|
1960 |
5211 |
break; |
|
1961 |
case 4: |
||
1962 |
28 |
family = AF_INET; |
|
1963 |
28 |
break; |
|
1964 |
case 6: |
||
1965 |
11 |
family = AF_INET6; |
|
1966 |
11 |
break; |
|
1967 |
default: |
||
1968 |
CHECK(0 && "bad address family"); |
||
1969 |
} |
||
1970 |
|||
1971 |
auto req_wrap = std::make_unique<GetAddrInfoReqWrap>(env, |
||
1972 |
req_wrap_obj, |
||
1973 |
15750 |
args[4]->IsTrue()); |
|
1974 |
|||
1975 |
struct addrinfo hints; |
||
1976 |
5250 |
memset(&hints, 0, sizeof(hints)); |
|
1977 |
5250 |
hints.ai_family = family; |
|
1978 |
5250 |
hints.ai_socktype = SOCK_STREAM; |
|
1979 |
5250 |
hints.ai_flags = flags; |
|
1980 |
|||
1981 |
✓✓✓✓ ✗✓✗✗ |
10500 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( |
1982 |
TRACING_CATEGORY_NODE2(dns, native), "lookup", req_wrap.get(), |
||
1983 |
"hostname", TRACE_STR_COPY(*hostname), |
||
1984 |
"family", |
||
1985 |
family == AF_INET ? "ipv4" : family == AF_INET6 ? "ipv6" : "unspec"); |
||
1986 |
|||
1987 |
5250 |
int err = req_wrap->Dispatch(uv_getaddrinfo, |
|
1988 |
AfterGetAddrInfo, |
||
1989 |
*hostname, |
||
1990 |
nullptr, |
||
1991 |
10500 |
&hints); |
|
1992 |
✓✗ | 5250 |
if (err == 0) |
1993 |
// Release ownership of the pointer allowing the ownership to be transferred |
||
1994 |
5250 |
USE(req_wrap.release()); |
|
1995 |
|||
1996 |
15750 |
args.GetReturnValue().Set(err); |
|
1997 |
5250 |
} |
|
1998 |
|||
1999 |
|||
2000 |
11 |
void GetNameInfo(const FunctionCallbackInfo<Value>& args) { |
|
2001 |
11 |
Environment* env = Environment::GetCurrent(args); |
|
2002 |
|||
2003 |
✗✓ | 22 |
CHECK(args[0]->IsObject()); |
2004 |
✗✓ | 33 |
CHECK(args[1]->IsString()); |
2005 |
✗✓ | 22 |
CHECK(args[2]->IsUint32()); |
2006 |
22 |
Local<Object> req_wrap_obj = args[0].As<Object>(); |
|
2007 |
11 |
node::Utf8Value ip(env->isolate(), args[1]); |
|
2008 |
44 |
const unsigned port = args[2]->Uint32Value(env->context()).FromJust(); |
|
2009 |
struct sockaddr_storage addr; |
||
2010 |
|||
2011 |
✓✓✗✓ ✗✓ |
11 |
CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 || |
2012 |
uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0); |
||
2013 |
|||
2014 |
22 |
auto req_wrap = std::make_unique<GetNameInfoReqWrap>(env, req_wrap_obj); |
|
2015 |
|||
2016 |
✓✓✓✓ |
22 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( |
2017 |
TRACING_CATEGORY_NODE2(dns, native), "lookupService", req_wrap.get(), |
||
2018 |
"ip", TRACE_STR_COPY(*ip), "port", port); |
||
2019 |
|||
2020 |
11 |
int err = req_wrap->Dispatch(uv_getnameinfo, |
|
2021 |
AfterGetNameInfo, |
||
2022 |
reinterpret_cast<struct sockaddr*>(&addr), |
||
2023 |
11 |
NI_NAMEREQD); |
|
2024 |
✓✗ | 11 |
if (err == 0) |
2025 |
// Release ownership of the pointer allowing the ownership to be transferred |
||
2026 |
11 |
USE(req_wrap.release()); |
|
2027 |
|||
2028 |
33 |
args.GetReturnValue().Set(err); |
|
2029 |
11 |
} |
|
2030 |
|||
2031 |
|||
2032 |
56 |
void GetServers(const FunctionCallbackInfo<Value>& args) { |
|
2033 |
56 |
Environment* env = Environment::GetCurrent(args); |
|
2034 |
ChannelWrap* channel; |
||
2035 |
✗✓ | 112 |
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder()); |
2036 |
|||
2037 |
56 |
Local<Array> server_array = Array::New(env->isolate()); |
|
2038 |
|||
2039 |
ares_addr_port_node* servers; |
||
2040 |
|||
2041 |
56 |
int r = ares_get_servers_ports(channel->cares_channel(), &servers); |
|
2042 |
✗✓ | 56 |
CHECK_EQ(r, ARES_SUCCESS); |
2043 |
|||
2044 |
56 |
ares_addr_port_node* cur = servers; |
|
2045 |
|||
2046 |
✓✓ | 171 |
for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) { |
2047 |
char ip[INET6_ADDRSTRLEN]; |
||
2048 |
|||
2049 |
115 |
const void* caddr = static_cast<const void*>(&cur->addr); |
|
2050 |
115 |
int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip)); |
|
2051 |
✗✓ | 115 |
CHECK_EQ(err, 0); |
2052 |
|||
2053 |
115 |
Local<Array> ret = Array::New(env->isolate(), 2); |
|
2054 |
460 |
ret->Set(env->context(), 0, OneByteString(env->isolate(), ip)).Check(); |
|
2055 |
115 |
ret->Set(env->context(), |
|
2056 |
1, |
||
2057 |
460 |
Integer::New(env->isolate(), cur->udp_port)).Check(); |
|
2058 |
|||
2059 |
345 |
server_array->Set(env->context(), i, ret).Check(); |
|
2060 |
} |
||
2061 |
|||
2062 |
56 |
ares_free_data(servers); |
|
2063 |
|||
2064 |
112 |
args.GetReturnValue().Set(server_array); |
|
2065 |
} |
||
2066 |
|||
2067 |
|||
2068 |
23 |
void SetServers(const FunctionCallbackInfo<Value>& args) { |
|
2069 |
23 |
Environment* env = Environment::GetCurrent(args); |
|
2070 |
ChannelWrap* channel; |
||
2071 |
✗✓ | 27 |
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder()); |
2072 |
|||
2073 |
✓✓ | 23 |
if (channel->active_query_count()) { |
2074 |
4 |
return args.GetReturnValue().Set(DNS_ESETSRVPENDING); |
|
2075 |
} |
||
2076 |
|||
2077 |
✗✓ | 42 |
CHECK(args[0]->IsArray()); |
2078 |
|||
2079 |
21 |
Local<Array> arr = Local<Array>::Cast(args[0]); |
|
2080 |
|||
2081 |
21 |
uint32_t len = arr->Length(); |
|
2082 |
|||
2083 |
✓✓ | 21 |
if (len == 0) { |
2084 |
2 |
int rv = ares_set_servers(channel->cares_channel(), nullptr); |
|
2085 |
4 |
return args.GetReturnValue().Set(rv); |
|
2086 |
} |
||
2087 |
|||
2088 |
19 |
std::vector<ares_addr_port_node> servers(len); |
|
2089 |
19 |
ares_addr_port_node* last = nullptr; |
|
2090 |
|||
2091 |
int err; |
||
2092 |
|||
2093 |
✓✓ | 50 |
for (uint32_t i = 0; i < len; i++) { |
2094 |
✗✓ | 124 |
CHECK(arr->Get(env->context(), i).ToLocalChecked()->IsArray()); |
2095 |
|||
2096 |
Local<Array> elm = |
||
2097 |
93 |
Local<Array>::Cast(arr->Get(env->context(), i).ToLocalChecked()); |
|
2098 |
|||
2099 |
✗✓ | 155 |
CHECK(elm->Get(env->context(), |
2100 |
0).ToLocalChecked()->Int32Value(env->context()).FromJust()); |
||
2101 |
✗✓ | 155 |
CHECK(elm->Get(env->context(), 1).ToLocalChecked()->IsString()); |
2102 |
✗✓ | 155 |
CHECK(elm->Get(env->context(), |
2103 |
2).ToLocalChecked()->Int32Value(env->context()).FromJust()); |
||
2104 |
|||
2105 |
62 |
int fam = elm->Get(env->context(), 0) |
|
2106 |
155 |
.ToLocalChecked()->Int32Value(env->context()).FromJust(); |
|
2107 |
node::Utf8Value ip(env->isolate(), |
||
2108 |
93 |
elm->Get(env->context(), 1).ToLocalChecked()); |
|
2109 |
62 |
int port = elm->Get(env->context(), 2) |
|
2110 |
155 |
.ToLocalChecked()->Int32Value(env->context()).FromJust(); |
|
2111 |
|||
2112 |
31 |
ares_addr_port_node* cur = &servers[i]; |
|
2113 |
|||
2114 |
31 |
cur->tcp_port = cur->udp_port = port; |
|
2115 |
✓✓✗ | 31 |
switch (fam) { |
2116 |
case 4: |
||
2117 |
24 |
cur->family = AF_INET; |
|
2118 |
24 |
err = uv_inet_pton(AF_INET, *ip, &cur->addr); |
|
2119 |
24 |
break; |
|
2120 |
case 6: |
||
2121 |
7 |
cur->family = AF_INET6; |
|
2122 |
7 |
err = uv_inet_pton(AF_INET6, *ip, &cur->addr); |
|
2123 |
7 |
break; |
|
2124 |
default: |
||
2125 |
CHECK(0 && "Bad address family."); |
||
2126 |
} |
||
2127 |
|||
2128 |
✗✓ | 31 |
if (err) |
2129 |
break; |
||
2130 |
|||
2131 |
31 |
cur->next = nullptr; |
|
2132 |
|||
2133 |
✓✓ | 31 |
if (last != nullptr) |
2134 |
12 |
last->next = cur; |
|
2135 |
|||
2136 |
✓✗ | 31 |
last = cur; |
2137 |
31 |
} |
|
2138 |
|||
2139 |
✓✗ | 19 |
if (err == 0) |
2140 |
19 |
err = ares_set_servers_ports(channel->cares_channel(), &servers[0]); |
|
2141 |
else |
||
2142 |
err = ARES_EBADSTR; |
||
2143 |
|||
2144 |
✓✗ | 19 |
if (err == ARES_SUCCESS) |
2145 |
19 |
channel->set_is_servers_default(false); |
|
2146 |
|||
2147 |
38 |
args.GetReturnValue().Set(err); |
|
2148 |
} |
||
2149 |
|||
2150 |
3 |
void Cancel(const FunctionCallbackInfo<Value>& args) { |
|
2151 |
ChannelWrap* channel; |
||
2152 |
✗✓ | 6 |
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder()); |
2153 |
|||
2154 |
✓✗✗✓ |
6 |
TRACE_EVENT_INSTANT0(TRACING_CATEGORY_NODE2(dns, native), |
2155 |
"cancel", TRACE_EVENT_SCOPE_THREAD); |
||
2156 |
|||
2157 |
3 |
ares_cancel(channel->cares_channel()); |
|
2158 |
} |
||
2159 |
|||
2160 |
const char EMSG_ESETSRVPENDING[] = "There are pending queries."; |
||
2161 |
1 |
void StrError(const FunctionCallbackInfo<Value>& args) { |
|
2162 |
1 |
Environment* env = Environment::GetCurrent(args); |
|
2163 |
4 |
int code = args[0]->Int32Value(env->context()).FromJust(); |
|
2164 |
const char* errmsg = (code == DNS_ESETSRVPENDING) ? |
||
2165 |
EMSG_ESETSRVPENDING : |
||
2166 |
✗✓ | 1 |
ares_strerror(code); |
2167 |
3 |
args.GetReturnValue().Set(OneByteString(env->isolate(), errmsg)); |
|
2168 |
1 |
} |
|
2169 |
|||
2170 |
|||
2171 |
1162 |
void Initialize(Local<Object> target, |
|
2172 |
Local<Value> unused, |
||
2173 |
Local<Context> context, |
||
2174 |
void* priv) { |
||
2175 |
1162 |
Environment* env = Environment::GetCurrent(context); |
|
2176 |
|||
2177 |
1162 |
env->SetMethod(target, "getaddrinfo", GetAddrInfo); |
|
2178 |
1162 |
env->SetMethod(target, "getnameinfo", GetNameInfo); |
|
2179 |
1162 |
env->SetMethodNoSideEffect(target, "canonicalizeIP", CanonicalizeIP); |
|
2180 |
|||
2181 |
1162 |
env->SetMethod(target, "strerror", StrError); |
|
2182 |
|||
2183 |
target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), |
||
2184 |
5810 |
Integer::New(env->isolate(), AF_INET)).Check(); |
|
2185 |
target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"), |
||
2186 |
5810 |
Integer::New(env->isolate(), AF_INET6)).Check(); |
|
2187 |
target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), |
||
2188 |
"AF_UNSPEC"), |
||
2189 |
5810 |
Integer::New(env->isolate(), AF_UNSPEC)).Check(); |
|
2190 |
target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), |
||
2191 |
"AI_ADDRCONFIG"), |
||
2192 |
5810 |
Integer::New(env->isolate(), AI_ADDRCONFIG)).Check(); |
|
2193 |
target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), |
||
2194 |
"AI_V4MAPPED"), |
||
2195 |
5810 |
Integer::New(env->isolate(), AI_V4MAPPED)).Check(); |
|
2196 |
|||
2197 |
Local<FunctionTemplate> aiw = |
||
2198 |
1162 |
BaseObject::MakeLazilyInitializedJSTemplate(env); |
|
2199 |
2324 |
aiw->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
2200 |
Local<String> addrInfoWrapString = |
||
2201 |
1162 |
FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"); |
|
2202 |
1162 |
aiw->SetClassName(addrInfoWrapString); |
|
2203 |
target->Set(env->context(), |
||
2204 |
addrInfoWrapString, |
||
2205 |
4648 |
aiw->GetFunction(context).ToLocalChecked()).Check(); |
|
2206 |
|||
2207 |
Local<FunctionTemplate> niw = |
||
2208 |
1162 |
BaseObject::MakeLazilyInitializedJSTemplate(env); |
|
2209 |
2324 |
niw->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
2210 |
Local<String> nameInfoWrapString = |
||
2211 |
1162 |
FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"); |
|
2212 |
1162 |
niw->SetClassName(nameInfoWrapString); |
|
2213 |
target->Set(env->context(), |
||
2214 |
nameInfoWrapString, |
||
2215 |
4648 |
niw->GetFunction(context).ToLocalChecked()).Check(); |
|
2216 |
|||
2217 |
Local<FunctionTemplate> qrw = |
||
2218 |
1162 |
BaseObject::MakeLazilyInitializedJSTemplate(env); |
|
2219 |
2324 |
qrw->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
2220 |
Local<String> queryWrapString = |
||
2221 |
1162 |
FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"); |
|
2222 |
1162 |
qrw->SetClassName(queryWrapString); |
|
2223 |
target->Set(env->context(), |
||
2224 |
queryWrapString, |
||
2225 |
4648 |
qrw->GetFunction(context).ToLocalChecked()).Check(); |
|
2226 |
|||
2227 |
Local<FunctionTemplate> channel_wrap = |
||
2228 |
1162 |
env->NewFunctionTemplate(ChannelWrap::New); |
|
2229 |
2324 |
channel_wrap->InstanceTemplate()->SetInternalFieldCount(1); |
|
2230 |
2324 |
channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
2231 |
|||
2232 |
1162 |
env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>); |
|
2233 |
1162 |
env->SetProtoMethod(channel_wrap, "queryA", Query<QueryAWrap>); |
|
2234 |
1162 |
env->SetProtoMethod(channel_wrap, "queryAaaa", Query<QueryAaaaWrap>); |
|
2235 |
1162 |
env->SetProtoMethod(channel_wrap, "queryCname", Query<QueryCnameWrap>); |
|
2236 |
1162 |
env->SetProtoMethod(channel_wrap, "queryMx", Query<QueryMxWrap>); |
|
2237 |
1162 |
env->SetProtoMethod(channel_wrap, "queryNs", Query<QueryNsWrap>); |
|
2238 |
1162 |
env->SetProtoMethod(channel_wrap, "queryTxt", Query<QueryTxtWrap>); |
|
2239 |
1162 |
env->SetProtoMethod(channel_wrap, "querySrv", Query<QuerySrvWrap>); |
|
2240 |
1162 |
env->SetProtoMethod(channel_wrap, "queryPtr", Query<QueryPtrWrap>); |
|
2241 |
1162 |
env->SetProtoMethod(channel_wrap, "queryNaptr", Query<QueryNaptrWrap>); |
|
2242 |
1162 |
env->SetProtoMethod(channel_wrap, "querySoa", Query<QuerySoaWrap>); |
|
2243 |
1162 |
env->SetProtoMethod(channel_wrap, "getHostByAddr", Query<GetHostByAddrWrap>); |
|
2244 |
|||
2245 |
1162 |
env->SetProtoMethodNoSideEffect(channel_wrap, "getServers", GetServers); |
|
2246 |
1162 |
env->SetProtoMethod(channel_wrap, "setServers", SetServers); |
|
2247 |
1162 |
env->SetProtoMethod(channel_wrap, "cancel", Cancel); |
|
2248 |
|||
2249 |
Local<String> channelWrapString = |
||
2250 |
1162 |
FIXED_ONE_BYTE_STRING(env->isolate(), "ChannelWrap"); |
|
2251 |
1162 |
channel_wrap->SetClassName(channelWrapString); |
|
2252 |
target->Set(env->context(), channelWrapString, |
||
2253 |
4648 |
channel_wrap->GetFunction(context).ToLocalChecked()).Check(); |
|
2254 |
1162 |
} |
|
2255 |
|||
2256 |
} // anonymous namespace |
||
2257 |
} // namespace cares_wrap |
||
2258 |
} // namespace node |
||
2259 |
|||
2260 |
✓✗✓✗ |
19927 |
NODE_MODULE_CONTEXT_AWARE_INTERNAL(cares_wrap, node::cares_wrap::Initialize) |
Generated by: GCOVR (Version 3.4) |