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