Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64
Your IP : 18.220.204.184
#ifndef SRC_CARES_WRAP_H_
#define SRC_CARES_WRAP_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#define CARES_STATICLIB
#include "async_wrap.h"
#include "base_object.h"
#include "env.h"
#include "memory_tracker.h"
#include "util.h"
#include "node.h"
#include "ares.h"
#include "v8.h"
#include "uv.h"
#include <unordered_set>
#ifdef __POSIX__
# include <netdb.h>
#endif // __POSIX__
# include <ares_nameser.h>
namespace node {
namespace cares_wrap {
constexpr int ns_t_cname_or_a = -1;
constexpr int DNS_ESETSRVPENDING = -1000;
class ChannelWrap;
inline void safe_free_hostent(struct hostent* host);
using HostEntPointer = DeleteFnPtr<hostent, ares_free_hostent>;
using SafeHostEntPointer = DeleteFnPtr<hostent, safe_free_hostent>;
inline const char* ToErrorCodeString(int status) {
switch (status) {
#define V(code) case ARES_##code: return #code;
V(EADDRGETNETWORKPARAMS)
V(EBADFAMILY)
V(EBADFLAGS)
V(EBADHINTS)
V(EBADNAME)
V(EBADQUERY)
V(EBADRESP)
V(EBADSTR)
V(ECANCELLED)
V(ECONNREFUSED)
V(EDESTRUCTION)
V(EFILE)
V(EFORMERR)
V(ELOADIPHLPAPI)
V(ENODATA)
V(ENOMEM)
V(ENONAME)
V(ENOTFOUND)
V(ENOTIMP)
V(ENOTINITIALIZED)
V(EOF)
V(EREFUSED)
V(ESERVFAIL)
V(ETIMEOUT)
#undef V
}
return "UNKNOWN_ARES_ERROR";
}
inline void cares_wrap_hostent_cpy(
struct hostent* dest,
const struct hostent* src) {
dest->h_addr_list = nullptr;
dest->h_addrtype = 0;
dest->h_aliases = nullptr;
dest->h_length = 0;
dest->h_name = nullptr;
/* copy `h_name` */
size_t name_size = strlen(src->h_name) + 1;
dest->h_name = node::Malloc<char>(name_size);
memcpy(dest->h_name, src->h_name, name_size);
/* copy `h_aliases` */
size_t alias_count;
for (alias_count = 0;
src->h_aliases[alias_count] != nullptr;
alias_count++) {
}
dest->h_aliases = node::Malloc<char*>(alias_count + 1);
for (size_t i = 0; i < alias_count; i++) {
const size_t cur_alias_size = strlen(src->h_aliases[i]) + 1;
dest->h_aliases[i] = node::Malloc(cur_alias_size);
memcpy(dest->h_aliases[i], src->h_aliases[i], cur_alias_size);
}
dest->h_aliases[alias_count] = nullptr;
/* copy `h_addr_list` */
size_t list_count;
for (list_count = 0;
src->h_addr_list[list_count] != nullptr;
list_count++) {
}
dest->h_addr_list = node::Malloc<char*>(list_count + 1);
for (size_t i = 0; i < list_count; i++) {
dest->h_addr_list[i] = node::Malloc(src->h_length);
memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length);
}
dest->h_addr_list[list_count] = nullptr;
/* work after work */
dest->h_length = src->h_length;
dest->h_addrtype = src->h_addrtype;
}
struct NodeAresTask final : public MemoryRetainer {
ChannelWrap* channel;
ares_socket_t sock;
uv_poll_t poll_watcher;
inline void MemoryInfo(MemoryTracker* trakcer) const override;
SET_MEMORY_INFO_NAME(NodeAresTask)
SET_SELF_SIZE(NodeAresTask)
struct Hash {
inline size_t operator()(NodeAresTask* a) const {
return std::hash<ares_socket_t>()(a->sock);
}
};
struct Equal {
inline bool operator()(NodeAresTask* a, NodeAresTask* b) const {
return a->sock == b->sock;
}
};
static NodeAresTask* Create(ChannelWrap* channel, ares_socket_t sock);
using List = std::unordered_set<NodeAresTask*, Hash, Equal>;
};
class ChannelWrap final : public AsyncWrap {
public:
ChannelWrap(Environment* env, v8::Local<v8::Object> object, int timeout);
~ChannelWrap() override;
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
void Setup();
void EnsureServers();
void StartTimer();
void CloseTimer();
void ModifyActivityQueryCount(int count);
inline uv_timer_t* timer_handle() { return timer_handle_; }
inline ares_channel cares_channel() { return channel_; }
inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; }
inline void set_is_servers_default(bool is_default) {
is_servers_default_ = is_default;
}
inline int active_query_count() { return active_query_count_; }
inline NodeAresTask::List* task_list() { return &task_list_; }
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(ChannelWrap)
SET_SELF_SIZE(ChannelWrap)
static void AresTimeout(uv_timer_t* handle);
private:
uv_timer_t* timer_handle_ = nullptr;
ares_channel channel_ = nullptr;
bool query_last_ok_ = true;
bool is_servers_default_ = true;
bool library_inited_ = false;
int timeout_;
int active_query_count_ = 0;
NodeAresTask::List task_list_;
};
class GetAddrInfoReqWrap final : public ReqWrap<uv_getaddrinfo_t> {
public:
GetAddrInfoReqWrap(Environment* env,
v8::Local<v8::Object> req_wrap_obj,
bool verbatim);
SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap)
SET_SELF_SIZE(GetAddrInfoReqWrap)
bool verbatim() const { return verbatim_; }
private:
const bool verbatim_;
};
class GetNameInfoReqWrap final : public ReqWrap<uv_getnameinfo_t> {
public:
GetNameInfoReqWrap(Environment* env, v8::Local<v8::Object> req_wrap_obj);
SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(GetNameInfoReqWrap)
SET_SELF_SIZE(GetNameInfoReqWrap)
};
struct ResponseData final {
int status;
bool is_host;
SafeHostEntPointer host;
MallocedBuffer<unsigned char> buf;
};
template <typename Traits>
class QueryWrap final : public AsyncWrap {
public:
QueryWrap(ChannelWrap* channel, v8::Local<v8::Object> req_wrap_obj)
: AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP),
channel_(channel),
trace_name_(Traits::name) {}
~QueryWrap() {
CHECK_EQ(false, persistent().IsEmpty());
// Let Callback() know that this object no longer exists.
if (callback_ptr_ != nullptr)
*callback_ptr_ = nullptr;
}
int Send(const char* name) {
return Traits::Send(this, name);
}
void AresQuery(const char* name, int dnsclass, int type) {
channel_->EnsureServers();
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
"name", TRACE_STR_COPY(name));
ares_query(
channel_->cares_channel(),
name,
dnsclass,
type,
Callback,
MakeCallbackPointer());
}
void ParseError(int status) {
CHECK_NE(status, ARES_SUCCESS);
v8::HandleScope handle_scope(env()->isolate());
v8::Context::Scope context_scope(env()->context());
const char* code = ToErrorCodeString(status);
v8::Local<v8::Value> arg = OneByteString(env()->isolate(), code);
TRACE_EVENT_NESTABLE_ASYNC_END1(
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this,
"error", status);
MakeCallback(env()->oncomplete_string(), 1, &arg);
}
const BaseObjectPtr<ChannelWrap>& channel() const { return channel_; }
void AfterResponse() {
CHECK(response_data_);
int status = response_data_->status;
if (status != ARES_SUCCESS)
return ParseError(status);
status = Traits::Parse(this, response_data_);
if (status != ARES_SUCCESS)
ParseError(status);
}
void* MakeCallbackPointer() {
CHECK_NULL(callback_ptr_);
callback_ptr_ = new QueryWrap<Traits>*(this);
return callback_ptr_;
}
static QueryWrap<Traits>* FromCallbackPointer(void* arg) {
std::unique_ptr<QueryWrap<Traits>*> wrap_ptr {
static_cast<QueryWrap<Traits>**>(arg)
};
QueryWrap<Traits>* wrap = *wrap_ptr.get();
if (wrap == nullptr) return nullptr;
wrap->callback_ptr_ = nullptr;
return wrap;
}
static void Callback(
void* arg,
int status,
int timeouts,
unsigned char* answer_buf,
int answer_len) {
QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
if (wrap == nullptr) return;
unsigned char* buf_copy = nullptr;
if (status == ARES_SUCCESS) {
buf_copy = node::Malloc<unsigned char>(answer_len);
memcpy(buf_copy, answer_buf, answer_len);
}
wrap->response_data_ = std::make_unique<ResponseData>();
ResponseData* data = wrap->response_data_.get();
data->status = status;
data->is_host = false;
data->buf = MallocedBuffer<unsigned char>(buf_copy, answer_len);
wrap->QueueResponseCallback(status);
}
static void Callback(
void* arg,
int status,
int timeouts,
struct hostent* host) {
QueryWrap<Traits>* wrap = FromCallbackPointer(arg);
if (wrap == nullptr) return;
struct hostent* host_copy = nullptr;
if (status == ARES_SUCCESS) {
host_copy = node::Malloc<hostent>(1);
cares_wrap_hostent_cpy(host_copy, host);
}
wrap->response_data_ = std::make_unique<ResponseData>();
ResponseData* data = wrap->response_data_.get();
data->status = status;
data->host.reset(host_copy);
data->is_host = true;
wrap->QueueResponseCallback(status);
}
void QueueResponseCallback(int status) {
BaseObjectPtr<QueryWrap<Traits>> strong_ref{this};
env()->SetImmediate([this, strong_ref](Environment*) {
AfterResponse();
// Delete once strong_ref goes out of scope.
Detach();
});
channel_->set_query_last_ok(status != ARES_ECONNREFUSED);
channel_->ModifyActivityQueryCount(-1);
}
void CallOnComplete(
v8::Local<v8::Value> answer,
v8::Local<v8::Value> extra = v8::Local<v8::Value>()) {
v8::HandleScope handle_scope(env()->isolate());
v8::Context::Scope context_scope(env()->context());
v8::Local<v8::Value> argv[] = {
v8::Integer::New(env()->isolate(), 0),
answer,
extra
};
const int argc = arraysize(argv) - extra.IsEmpty();
TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE2(dns, native), trace_name_, this);
MakeCallback(env()->oncomplete_string(), argc, argv);
}
void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackField("channel", channel_);
if (response_data_) {
tracker->TrackFieldWithSize("response", response_data_->buf.size);
}
}
SET_MEMORY_INFO_NAME(QueryWrap)
SET_SELF_SIZE(QueryWrap<Traits>)
private:
BaseObjectPtr<ChannelWrap> channel_;
std::unique_ptr<ResponseData> response_data_;
const char* trace_name_;
// Pointer to pointer to 'this' that can be reset from the destructor,
// in order to let Callback() know that 'this' no longer exists.
QueryWrap<Traits>** callback_ptr_ = nullptr;
};
struct AnyTraits final {
static constexpr const char* name = "resolveAny";
static int Send(QueryWrap<AnyTraits>* wrap, const char* name);
static int Parse(
QueryWrap<AnyTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct ATraits final {
static constexpr const char* name = "resolve4";
static int Send(QueryWrap<ATraits>* wrap, const char* name);
static int Parse(
QueryWrap<ATraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct AaaaTraits final {
static constexpr const char* name = "resolve6";
static int Send(QueryWrap<AaaaTraits>* wrap, const char* name);
static int Parse(
QueryWrap<AaaaTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct CaaTraits final {
static constexpr const char* name = "resolveCaa";
static int Send(QueryWrap<CaaTraits>* wrap, const char* name);
static int Parse(
QueryWrap<CaaTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct CnameTraits final {
static constexpr const char* name = "resolveCname";
static int Send(QueryWrap<CnameTraits>* wrap, const char* name);
static int Parse(
QueryWrap<CnameTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct MxTraits final {
static constexpr const char* name = "resolveMx";
static int Send(QueryWrap<MxTraits>* wrap, const char* name);
static int Parse(
QueryWrap<MxTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct NsTraits final {
static constexpr const char* name = "resolveNs";
static int Send(QueryWrap<NsTraits>* wrap, const char* name);
static int Parse(
QueryWrap<NsTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct TxtTraits final {
static constexpr const char* name = "resolveTxt";
static int Send(QueryWrap<TxtTraits>* wrap, const char* name);
static int Parse(
QueryWrap<TxtTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct SrvTraits final {
static constexpr const char* name = "resolveSrv";
static int Send(QueryWrap<SrvTraits>* wrap, const char* name);
static int Parse(
QueryWrap<SrvTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct PtrTraits final {
static constexpr const char* name = "resolvePtr";
static int Send(QueryWrap<PtrTraits>* wrap, const char* name);
static int Parse(
QueryWrap<PtrTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct NaptrTraits final {
static constexpr const char* name = "resolveNaptr";
static int Send(QueryWrap<NaptrTraits>* wrap, const char* name);
static int Parse(
QueryWrap<NaptrTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct SoaTraits final {
static constexpr const char* name = "resolveSoa";
static int Send(QueryWrap<SoaTraits>* wrap, const char* name);
static int Parse(
QueryWrap<SoaTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
struct ReverseTraits final {
static constexpr const char* name = "reverse";
static int Send(QueryWrap<ReverseTraits>* wrap, const char* name);
static int Parse(
QueryWrap<ReverseTraits>* wrap,
const std::unique_ptr<ResponseData>& response);
};
using QueryAnyWrap = QueryWrap<AnyTraits>;
using QueryAWrap = QueryWrap<ATraits>;
using QueryAaaaWrap = QueryWrap<AaaaTraits>;
using QueryCaaWrap = QueryWrap<CaaTraits>;
using QueryCnameWrap = QueryWrap<CnameTraits>;
using QueryMxWrap = QueryWrap<MxTraits>;
using QueryNsWrap = QueryWrap<NsTraits>;
using QueryTxtWrap = QueryWrap<TxtTraits>;
using QuerySrvWrap = QueryWrap<SrvTraits>;
using QueryPtrWrap = QueryWrap<PtrTraits>;
using QueryNaptrWrap = QueryWrap<NaptrTraits>;
using QuerySoaWrap = QueryWrap<SoaTraits>;
using GetHostByAddrWrap = QueryWrap<ReverseTraits>;
} // namespace cares_wrap
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_CARES_WRAP_H_
|