@@ -407,14 +407,11 @@ void safe_free_hostent(struct hostent* host) {
407
407
host->h_aliases = nullptr ;
408
408
}
409
409
410
- if (host->h_name != nullptr ) {
411
- free (host->h_name );
412
- }
413
-
414
- host->h_addrtype = host->h_length = 0 ;
410
+ free (host->h_name );
411
+ free (host);
415
412
}
416
413
417
- void cares_wrap_hostent_cpy (struct hostent * dest, struct hostent * src) {
414
+ void cares_wrap_hostent_cpy (struct hostent * dest, const struct hostent * src) {
418
415
dest->h_addr_list = nullptr ;
419
416
dest->h_addrtype = 0 ;
420
417
dest->h_aliases = nullptr ;
@@ -461,18 +458,6 @@ void cares_wrap_hostent_cpy(struct hostent* dest, struct hostent* src) {
461
458
}
462
459
463
460
class QueryWrap ;
464
- struct CaresAsyncData {
465
- QueryWrap* wrap;
466
- int status;
467
- bool is_host;
468
- union {
469
- hostent* host;
470
- unsigned char * buf;
471
- } data;
472
- int len;
473
-
474
- uv_async_t async_handle;
475
- };
476
461
477
462
void ChannelWrap::Setup () {
478
463
struct ares_options options;
@@ -525,20 +510,21 @@ void ChannelWrap::CloseTimer() {
525
510
}
526
511
527
512
ChannelWrap::~ChannelWrap () {
513
+ ares_destroy (channel_);
514
+
528
515
if (library_inited_) {
529
516
Mutex::ScopedLock lock (ares_library_mutex);
530
517
// This decreases the reference counter increased by ares_library_init().
531
518
ares_library_cleanup ();
532
519
}
533
520
534
- ares_destroy (channel_);
535
521
CloseTimer ();
536
522
}
537
523
538
524
539
525
void ChannelWrap::ModifyActivityQueryCount (int count) {
540
526
active_query_count_ += count;
541
- if (active_query_count_ < 0 ) active_query_count_ = 0 ;
527
+ CHECK_GE (active_query_count_, 0 ) ;
542
528
}
543
529
544
530
@@ -602,6 +588,10 @@ class QueryWrap : public AsyncWrap {
602
588
603
589
~QueryWrap () override {
604
590
CHECK_EQ (false , persistent ().IsEmpty ());
591
+
592
+ // Let Callback() know that this object no longer exists.
593
+ if (callback_ptr_ != nullptr )
594
+ *callback_ptr_ = nullptr ;
605
595
}
606
596
607
597
// Subclasses should implement the appropriate Send method.
@@ -624,89 +614,93 @@ class QueryWrap : public AsyncWrap {
624
614
TRACING_CATEGORY_NODE2 (dns, native), trace_name_, this ,
625
615
" name" , TRACE_STR_COPY (name));
626
616
ares_query (channel_->cares_channel (), name, dnsclass, type, Callback,
627
- static_cast < void *>( this ));
617
+ MakeCallbackPointer ( ));
628
618
}
629
619
630
- static void CaresAsyncClose (uv_async_t * async) {
631
- auto data = static_cast <struct CaresAsyncData *>(async->data );
632
- delete data->wrap ;
633
- delete data;
634
- }
620
+ struct ResponseData {
621
+ int status;
622
+ bool is_host;
623
+ DeleteFnPtr<hostent, safe_free_hostent> host;
624
+ MallocedBuffer<unsigned char > buf;
625
+ };
635
626
636
- static void CaresAsyncCb ( uv_async_t * handle ) {
637
- auto data = static_cast < struct CaresAsyncData *>(handle-> data );
627
+ void AfterResponse ( ) {
628
+ CHECK (response_data_ );
638
629
639
- QueryWrap* wrap = data->wrap ;
640
- int status = data->status ;
630
+ const int status = response_data_->status ;
641
631
642
632
if (status != ARES_SUCCESS) {
643
- wrap->ParseError (status);
644
- } else if (!data->is_host ) {
645
- unsigned char * buf = data->data .buf ;
646
- wrap->Parse (buf, data->len );
647
- free (buf);
633
+ ParseError (status);
634
+ } else if (!response_data_->is_host ) {
635
+ Parse (response_data_->buf .data , response_data_->buf .size );
648
636
} else {
649
- hostent* host = data->data .host ;
650
- wrap->Parse (host);
651
- safe_free_hostent (host);
652
- free (host);
637
+ Parse (response_data_->host .get ());
653
638
}
654
639
655
- wrap->env ()->CloseHandle (handle, CaresAsyncClose);
640
+ delete this ;
641
+ }
642
+
643
+ void * MakeCallbackPointer () {
644
+ CHECK_NULL (callback_ptr_);
645
+ callback_ptr_ = new QueryWrap*(this );
646
+ return callback_ptr_;
647
+ }
648
+
649
+ static QueryWrap* FromCallbackPointer (void * arg) {
650
+ std::unique_ptr<QueryWrap*> wrap_ptr { static_cast <QueryWrap**>(arg) };
651
+ QueryWrap* wrap = *wrap_ptr.get ();
652
+ if (wrap == nullptr ) return nullptr ;
653
+ wrap->callback_ptr_ = nullptr ;
654
+ return wrap;
656
655
}
657
656
658
657
static void Callback (void * arg, int status, int timeouts,
659
658
unsigned char * answer_buf, int answer_len) {
660
- QueryWrap* wrap = static_cast <QueryWrap*>(arg);
659
+ QueryWrap* wrap = FromCallbackPointer (arg);
660
+ if (wrap == nullptr ) return ;
661
661
662
662
unsigned char * buf_copy = nullptr ;
663
663
if (status == ARES_SUCCESS) {
664
664
buf_copy = node::Malloc<unsigned char >(answer_len);
665
665
memcpy (buf_copy, answer_buf, answer_len);
666
666
}
667
667
668
- CaresAsyncData* data = new CaresAsyncData ();
668
+ wrap->response_data_ .reset (new ResponseData ());
669
+ ResponseData* data = wrap->response_data_ .get ();
669
670
data->status = status;
670
- data->wrap = wrap;
671
671
data->is_host = false ;
672
- data->data .buf = buf_copy;
673
- data->len = answer_len;
674
-
675
- uv_async_t * async_handle = &data->async_handle ;
676
- CHECK_EQ (0 , uv_async_init (wrap->env ()->event_loop (),
677
- async_handle,
678
- CaresAsyncCb));
672
+ data->buf = MallocedBuffer<unsigned char >(buf_copy, answer_len);
679
673
680
- wrap->channel_ ->set_query_last_ok (status != ARES_ECONNREFUSED);
681
- wrap->channel_ ->ModifyActivityQueryCount (-1 );
682
- async_handle->data = data;
683
- uv_async_send (async_handle);
674
+ wrap->QueueResponseCallback (status);
684
675
}
685
676
686
677
static void Callback (void * arg, int status, int timeouts,
687
678
struct hostent * host) {
688
- QueryWrap* wrap = static_cast <QueryWrap*>(arg);
679
+ QueryWrap* wrap = FromCallbackPointer (arg);
680
+ if (wrap == nullptr ) return ;
689
681
690
682
struct hostent * host_copy = nullptr ;
691
683
if (status == ARES_SUCCESS) {
692
684
host_copy = node::Malloc<hostent>(1 );
693
685
cares_wrap_hostent_cpy (host_copy, host);
694
686
}
695
687
696
- CaresAsyncData* data = new CaresAsyncData ();
688
+ wrap->response_data_ .reset (new ResponseData ());
689
+ ResponseData* data = wrap->response_data_ .get ();
697
690
data->status = status;
698
- data->data .host = host_copy;
699
- data->wrap = wrap;
691
+ data->host .reset (host_copy);
700
692
data->is_host = true ;
701
693
702
- uv_async_t * async_handle = &data->async_handle ;
703
- CHECK_EQ (0 , uv_async_init (wrap->env ()->event_loop (),
704
- async_handle,
705
- CaresAsyncCb));
694
+ wrap->QueueResponseCallback (status);
695
+ }
696
+
697
+ void QueueResponseCallback (int status) {
698
+ env ()->SetImmediate ([](Environment*, void * data) {
699
+ static_cast <QueryWrap*>(data)->AfterResponse ();
700
+ }, this , object ());
706
701
707
- wrap->channel_ ->set_query_last_ok (status != ARES_ECONNREFUSED);
708
- async_handle->data = data;
709
- uv_async_send (async_handle);
702
+ channel_->set_query_last_ok (status != ARES_ECONNREFUSED);
703
+ channel_->ModifyActivityQueryCount (-1 );
710
704
}
711
705
712
706
void CallOnComplete (Local<Value> answer,
@@ -749,7 +743,11 @@ class QueryWrap : public AsyncWrap {
749
743
ChannelWrap* channel_;
750
744
751
745
private:
746
+ std::unique_ptr<ResponseData> response_data_;
752
747
const char * trace_name_;
748
+ // Pointer to pointer to 'this' that can be reset from the destructor,
749
+ // in order to let Callback() know that 'this' no longer exists.
750
+ QueryWrap** callback_ptr_ = nullptr ;
753
751
};
754
752
755
753
@@ -1768,7 +1766,7 @@ class GetHostByAddrWrap: public QueryWrap {
1768
1766
length,
1769
1767
family,
1770
1768
Callback,
1771
- static_cast < void *>( static_cast <QueryWrap*>( this ) ));
1769
+ MakeCallbackPointer ( ));
1772
1770
return 0 ;
1773
1771
}
1774
1772
0 commit comments