%PDF- %PDF-
Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/ |
Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/cares_wrap.h |
#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 "node.h" #include "node_internals.h" #include "util.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, int tries); ~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 tries_; 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_