Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/cares_wrap.h
1 #ifndef SRC_CARES_WRAP_H_ 2 #define SRC_CARES_WRAP_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 #define CARES_STATICLIB 7 8 #include "async_wrap.h" 9 #include "base_object.h" 10 #include "env.h" 11 #include "memory_tracker.h" 12 #include "node.h" 13 #include "node_internals.h" 14 #include "util.h" 15 16 #include "ares.h" 17 #include "v8.h" 18 #include "uv.h" 19 20 #include <unordered_set> 21 22 #ifdef __POSIX__ 23 # include <netdb.h> 24 #endif // __POSIX__ 25 26 #if defined(__ANDROID__) || \ 27 defined(__MINGW32__) || \ 28 defined(__OpenBSD__) || \ 29 defined(_MSC_VER) 30 # include <nameser.h> 31 #else 32 # include <arpa/nameser.h> 33 #endif 34 35 36 namespace node { 37 namespace cares_wrap { 38 39 constexpr int ns_t_cname_or_a = -1; 40 constexpr int DNS_ESETSRVPENDING = -1000; 41 constexpr uint8_t DNS_ORDER_VERBATIM = 0; 42 constexpr uint8_t DNS_ORDER_IPV4_FIRST = 1; 43 constexpr uint8_t DNS_ORDER_IPV6_FIRST = 2; 44 45 class ChannelWrap; 46 47 inline void safe_free_hostent(struct hostent* host); 48 49 using HostEntPointer = DeleteFnPtr<hostent, ares_free_hostent>; 50 using SafeHostEntPointer = DeleteFnPtr<hostent, safe_free_hostent>; 51 52 inline const char* ToErrorCodeString(int status) { 53 switch (status) { 54 #define V(code) case ARES_##code: return #code; 55 V(EADDRGETNETWORKPARAMS) 56 V(EBADFAMILY) 57 V(EBADFLAGS) 58 V(EBADHINTS) 59 V(EBADNAME) 60 V(EBADQUERY) 61 V(EBADRESP) 62 V(EBADSTR) 63 V(ECANCELLED) 64 V(ECONNREFUSED) 65 V(EDESTRUCTION) 66 V(EFILE) 67 V(EFORMERR) 68 V(ELOADIPHLPAPI) 69 V(ENODATA) 70 V(ENOMEM) 71 V(ENONAME) 72 V(ENOTFOUND) 73 V(ENOTIMP) 74 V(ENOTINITIALIZED) 75 V(EOF) 76 V(EREFUSED) 77 V(ESERVFAIL) 78 V(ETIMEOUT) 79 #undef V 80 } 81 82 return "UNKNOWN_ARES_ERROR"; 83 } 84 85 inline void cares_wrap_hostent_cpy( 86 struct hostent* dest, 87 const struct hostent* src) { 88 dest->h_addr_list = nullptr; 89 dest->h_addrtype = 0; 90 dest->h_aliases = nullptr; 91 dest->h_length = 0; 92 dest->h_name = nullptr; 93 94 /* copy `h_name` */ 95 size_t name_size = strlen(src->h_name) + 1; 96 dest->h_name = node::Malloc<char>(name_size); 97 memcpy(dest->h_name, src->h_name, name_size); 98 99 /* copy `h_aliases` */ 100 size_t alias_count; 101 for (alias_count = 0; 102 src->h_aliases[alias_count] != nullptr; 103 alias_count++) { 104 } 105 106 dest->h_aliases = node::Malloc<char*>(alias_count + 1); 107 for (size_t i = 0; i < alias_count; i++) { 108 const size_t cur_alias_size = strlen(src->h_aliases[i]) + 1; 109 dest->h_aliases[i] = node::Malloc(cur_alias_size); 110 memcpy(dest->h_aliases[i], src->h_aliases[i], cur_alias_size); 111 } 112 dest->h_aliases[alias_count] = nullptr; 113 114 /* copy `h_addr_list` */ 115 size_t list_count; 116 for (list_count = 0; 117 src->h_addr_list[list_count] != nullptr; 118 list_count++) { 119 } 120 121 dest->h_addr_list = node::Malloc<char*>(list_count + 1); 122 for (size_t i = 0; i < list_count; i++) { 123 dest->h_addr_list[i] = node::Malloc(src->h_length); 124 memcpy(dest->h_addr_list[i], src->h_addr_list[i], src->h_length); 125 } 126 dest->h_addr_list[list_count] = nullptr; 127 128 /* work after work */ 129 dest->h_length = src->h_length; 130 dest->h_addrtype = src->h_addrtype; 131 } 132 133 134 struct NodeAresTask final : public MemoryRetainer { 135 ChannelWrap* channel; 136 ares_socket_t sock; 137 uv_poll_t poll_watcher; 138 139 inline void MemoryInfo(MemoryTracker* trakcer) const override; 140 SET_MEMORY_INFO_NAME(NodeAresTask) 141 SET_SELF_SIZE(NodeAresTask) 142 143 struct Hash { 144 inline size_t operator()(NodeAresTask* a) const { 145 return std::hash<ares_socket_t>()(a->sock); 146 } 147 }; 148 149 struct Equal { 150 inline bool operator()(NodeAresTask* a, NodeAresTask* b) const { 151 return a->sock == b->sock; 152 } 153 }; 154 155 static NodeAresTask* Create(ChannelWrap* channel, ares_socket_t sock); 156 157 using List = std::unordered_set<NodeAresTask*, Hash, Equal>; 158 }; 159 160 class ChannelWrap final : public AsyncWrap { 161 public: 162 ChannelWrap(Environment* env, 163 v8::Local<v8::Object> object, 164 int timeout, 165 int tries, 166 int max_timeout); 167 ~ChannelWrap() override; 168 169 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 170 171 void Setup(); 172 void EnsureServers(); 173 void StartTimer(); 174 void CloseTimer(); 175 176 void ModifyActivityQueryCount(int count); 177 178 inline uv_timer_t* timer_handle() { return timer_handle_; } 179 inline ares_channel cares_channel() { return channel_; } 180 inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; } 181 inline void set_is_servers_default(bool is_default) { 182 is_servers_default_ = is_default; 183 } 184 inline int active_query_count() { return active_query_count_; } 185 inline NodeAresTask::List* task_list() { return &task_list_; } 186 187 void MemoryInfo(MemoryTracker* tracker) const override; 188 SET_MEMORY_INFO_NAME(ChannelWrap) 189 SET_SELF_SIZE(ChannelWrap) 190 191 static void AresTimeout(uv_timer_t* handle); 192 193 private: 194 uv_timer_t* timer_handle_ = nullptr; 195 ares_channel channel_ = nullptr; 196 bool query_last_ok_ = true; 197 bool is_servers_default_ = true; 198 bool library_inited_ = false; 199 int timeout_; 200 int tries_; 201 int max_timeout_; 202 int active_query_count_ = 0; 203 NodeAresTask::List task_list_; 204 }; 205 206 class GetAddrInfoReqWrap final : public ReqWrap<uv_getaddrinfo_t> { 207 public: 208 GetAddrInfoReqWrap(Environment* env, 209 v8::Local<v8::Object> req_wrap_obj, 210 uint8_t order); 211 212 SET_NO_MEMORY_INFO() 213 SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap) 214 SET_SELF_SIZE(GetAddrInfoReqWrap) 215 216 uint8_t order() const { return order_; } 217 218 private: 219 const uint8_t order_; 220 }; 221 222 class GetNameInfoReqWrap final : public ReqWrap<uv_getnameinfo_t> { 223 public: 224 GetNameInfoReqWrap(Environment* env, v8::Local<v8::Object> req_wrap_obj); 225 226 SET_NO_MEMORY_INFO() 227 SET_MEMORY_INFO_NAME(GetNameInfoReqWrap) 228 SET_SELF_SIZE(GetNameInfoReqWrap) 229 }; 230 231 struct ResponseData final { 232 int status; 233 bool is_host; 234 SafeHostEntPointer host; 235 MallocedBuffer<unsigned char> buf; 236 }; 237 238 template <typename Traits> 239 class QueryWrap final : public AsyncWrap { 240 public: 241 QueryWrap(ChannelWrap* channel, v8::Local<v8::Object> req_wrap_obj) 242 : AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP), 243 channel_(channel), 244 trace_name_(Traits::name) {} 245 246 ~QueryWrap() { 247 CHECK_EQ(false, persistent().IsEmpty()); 248 249 // Let Callback() know that this object no longer exists. 250 if (callback_ptr_ != nullptr) 251 *callback_ptr_ = nullptr; 252 } 253 254 int Send(const char* name) { 255 return Traits::Send(this, name); 256 } 257 258 void AresQuery(const char* name, 259 ares_dns_class_t dnsclass, 260 ares_dns_rec_type_t type) { 261 channel_->EnsureServers(); 262 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( 263 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this, 264 "name", TRACE_STR_COPY(name)); 265 ares_query_dnsrec(channel_->cares_channel(), 266 name, 267 dnsclass, 268 type, 269 Callback, 270 MakeCallbackPointer(), 271 nullptr); 272 } 273 274 void ParseError(int status) { 275 CHECK_NE(status, ARES_SUCCESS); 276 v8::HandleScope handle_scope(env()->isolate()); 277 v8::Context::Scope context_scope(env()->context()); 278 const char* code = ToErrorCodeString(status); 279 v8::Local<v8::Value> arg = OneByteString(env()->isolate(), code); 280 TRACE_EVENT_NESTABLE_ASYNC_END1( 281 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this, 282 "error", status); 283 MakeCallback(env()->oncomplete_string(), 1, &arg); 284 } 285 286 const BaseObjectPtr<ChannelWrap>& channel() const { return channel_; } 287 288 void AfterResponse() { 289 CHECK(response_data_); 290 291 int status = response_data_->status; 292 293 if (status != ARES_SUCCESS) 294 return ParseError(status); 295 296 if (!Traits::Parse(this, response_data_).To(&status)) { 297 return ParseError(ARES_ECANCELLED); 298 } 299 300 if (status != ARES_SUCCESS) 301 ParseError(status); 302 } 303 304 void* MakeCallbackPointer() { 305 CHECK_NULL(callback_ptr_); 306 callback_ptr_ = new QueryWrap<Traits>*(this); 307 return callback_ptr_; 308 } 309 310 static QueryWrap<Traits>* FromCallbackPointer(void* arg) { 311 std::unique_ptr<QueryWrap<Traits>*> wrap_ptr { 312 static_cast<QueryWrap<Traits>**>(arg) 313 }; 314 QueryWrap<Traits>* wrap = *wrap_ptr.get(); 315 if (wrap == nullptr) return nullptr; 316 wrap->callback_ptr_ = nullptr; 317 return wrap; 318 } 319 320 static void Callback(void* arg, 321 ares_status_t status, 322 size_t timeouts, 323 const ares_dns_record_t* dnsrec) { 324 QueryWrap<Traits>* wrap = FromCallbackPointer(arg); 325 if (wrap == nullptr) return; 326 327 unsigned char* buf_copy = nullptr; 328 size_t answer_len = 0; 329 if (status == ARES_SUCCESS) { 330 // No need to explicitly call ares_free_string here, 331 // as it is a wrapper around free, which is already 332 // invoked when MallocedBuffer is destructed. 333 ares_dns_write(dnsrec, &buf_copy, &answer_len); 334 } 335 336 wrap->response_data_ = std::make_unique<ResponseData>(); 337 ResponseData* data = wrap->response_data_.get(); 338 data->status = status; 339 data->is_host = false; 340 data->buf = MallocedBuffer<unsigned char>(buf_copy, answer_len); 341 342 wrap->QueueResponseCallback(status); 343 } 344 345 static void Callback( 346 void* arg, 347 int status, 348 int timeouts, 349 struct hostent* host) { 350 QueryWrap<Traits>* wrap = FromCallbackPointer(arg); 351 if (wrap == nullptr) return; 352 353 struct hostent* host_copy = nullptr; 354 if (status == ARES_SUCCESS) { 355 host_copy = node::Malloc<hostent>(1); 356 cares_wrap_hostent_cpy(host_copy, host); 357 } 358 359 wrap->response_data_ = std::make_unique<ResponseData>(); 360 ResponseData* data = wrap->response_data_.get(); 361 data->status = status; 362 data->host.reset(host_copy); 363 data->is_host = true; 364 365 wrap->QueueResponseCallback(status); 366 } 367 368 void QueueResponseCallback(int status) { 369 BaseObjectPtr<QueryWrap<Traits>> strong_ref{this}; 370 env()->SetImmediate([this, strong_ref](Environment*) { 371 AfterResponse(); 372 373 // Delete once strong_ref goes out of scope. 374 Detach(); 375 }); 376 377 channel_->set_query_last_ok(status != ARES_ECONNREFUSED); 378 channel_->ModifyActivityQueryCount(-1); 379 } 380 381 void CallOnComplete( 382 v8::Local<v8::Value> answer, 383 v8::Local<v8::Value> extra = v8::Local<v8::Value>()) { 384 v8::HandleScope handle_scope(env()->isolate()); 385 v8::Context::Scope context_scope(env()->context()); 386 v8::Local<v8::Value> argv[] = { 387 v8::Integer::New(env()->isolate(), 0), 388 answer, 389 extra 390 }; 391 const int argc = arraysize(argv) - extra.IsEmpty(); 392 TRACE_EVENT_NESTABLE_ASYNC_END0( 393 TRACING_CATEGORY_NODE2(dns, native), trace_name_, this); 394 395 MakeCallback(env()->oncomplete_string(), argc, argv); 396 } 397 398 void MemoryInfo(MemoryTracker* tracker) const override { 399 tracker->TrackField("channel", channel_); 400 if (response_data_) { 401 tracker->TrackFieldWithSize("response", response_data_->buf.size); 402 } 403 } 404 405 SET_MEMORY_INFO_NAME(QueryWrap) 406 SET_SELF_SIZE(QueryWrap<Traits>) 407 408 private: 409 BaseObjectPtr<ChannelWrap> channel_; 410 411 std::unique_ptr<ResponseData> response_data_; 412 const char* trace_name_; 413 // Pointer to pointer to 'this' that can be reset from the destructor, 414 // in order to let Callback() know that 'this' no longer exists. 415 QueryWrap<Traits>** callback_ptr_ = nullptr; 416 }; 417 418 #define QUERY_TYPES(V) \ 419 V(Reverse, reverse, getHostByAddr) \ 420 V(A, resolve4, queryA) \ 421 V(Any, resolveAny, queryAny) \ 422 V(Aaaa, resolve6, queryAaaa) \ 423 V(Caa, resolveCaa, queryCaa) \ 424 V(Cname, resolveCname, queryCname) \ 425 V(Mx, resolveMx, queryMx) \ 426 V(Naptr, resolveNaptr, queryNaptr) \ 427 V(Ns, resolveNs, queryNs) \ 428 V(Ptr, resolvePtr, queryPtr) \ 429 V(Srv, resolveSrv, querySrv) \ 430 V(Soa, resolveSoa, querySoa) \ 431 V(Tlsa, resolveTlsa, queryTlsa) \ 432 V(Txt, resolveTxt, queryTxt) 433 434 // All query type handlers share the same basic structure, so we can simplify 435 // the code a bit by using a macro to define that structure. 436 #define TYPE_TRAITS(Name, label) \ 437 struct Name##Traits final { \ 438 static constexpr const char* name = #label; \ 439 static int Send(QueryWrap<Name##Traits>* wrap, const char* name); \ 440 static v8::Maybe<int> Parse( \ 441 QueryWrap<Name##Traits>* wrap, \ 442 const std::unique_ptr<ResponseData>& response); \ 443 }; \ 444 using Query##Name##Wrap = QueryWrap<Name##Traits>; 445 446 #define V(NAME, LABEL, _) TYPE_TRAITS(NAME, LABEL) 447 QUERY_TYPES(V) 448 #undef V 449 #undef TYPE_TRAITS 450 } // namespace cares_wrap 451 } // namespace node 452 453 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 454 455 #endif // SRC_CARES_WRAP_H_