/* * Copyright 2018 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "p2p/base/basic_async_resolver_factory.h" #include #include #include "absl/memory/memory.h" #include "api/async_dns_resolver.h" #include "rtc_base/async_resolver.h" #include "rtc_base/logging.h" namespace webrtc { rtc::AsyncResolverInterface* BasicAsyncResolverFactory::Create() { return new rtc::AsyncResolver(); } class WrappingAsyncDnsResolver; class WrappingAsyncDnsResolverResult : public AsyncDnsResolverResult { public: explicit WrappingAsyncDnsResolverResult(WrappingAsyncDnsResolver* owner) : owner_(owner) {} ~WrappingAsyncDnsResolverResult() {} // Note: Inline declaration not possible, since it refers to // WrappingAsyncDnsResolver. bool GetResolvedAddress(int family, rtc::SocketAddress* addr) const override; int GetError() const override; private: WrappingAsyncDnsResolver* const owner_; }; class WrappingAsyncDnsResolver : public AsyncDnsResolverInterface, public sigslot::has_slots<> { public: explicit WrappingAsyncDnsResolver(rtc::AsyncResolverInterface* wrapped) : wrapped_(absl::WrapUnique(wrapped)), result_(this) {} ~WrappingAsyncDnsResolver() override { // Workaround to get around the fact that sigslot-using objects can't be // destroyed from within their callback: Alert class users early. // TODO(bugs.webrtc.org/12651): Delete this class once the sigslot users are // gone. RTC_CHECK(!within_resolve_result_); wrapped_.release()->Destroy(false); } void Start(const rtc::SocketAddress& addr, std::function callback) override { RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_EQ(State::kNotStarted, state_); state_ = State::kStarted; callback_ = callback; wrapped_->SignalDone.connect(this, &WrappingAsyncDnsResolver::OnResolveResult); wrapped_->Start(addr); } const AsyncDnsResolverResult& result() const override { RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_EQ(State::kResolved, state_); return result_; } private: enum class State { kNotStarted, kStarted, kResolved }; friend class WrappingAsyncDnsResolverResult; // For use by WrappingAsyncDnsResolverResult rtc::AsyncResolverInterface* wrapped() const { RTC_DCHECK_RUN_ON(&sequence_checker_); return wrapped_.get(); } void OnResolveResult(rtc::AsyncResolverInterface* ref) { RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK(state_ == State::kStarted); RTC_DCHECK_EQ(ref, wrapped_.get()); state_ = State::kResolved; within_resolve_result_ = true; callback_(); within_resolve_result_ = false; } // The class variables need to be accessed on a single thread. SequenceChecker sequence_checker_; std::function callback_ RTC_GUARDED_BY(sequence_checker_); std::unique_ptr wrapped_ RTC_GUARDED_BY(sequence_checker_); State state_ RTC_GUARDED_BY(sequence_checker_) = State::kNotStarted; WrappingAsyncDnsResolverResult result_ RTC_GUARDED_BY(sequence_checker_); bool within_resolve_result_ RTC_GUARDED_BY(sequence_checker_) = false; }; bool WrappingAsyncDnsResolverResult::GetResolvedAddress( int family, rtc::SocketAddress* addr) const { if (!owner_->wrapped()) { return false; } return owner_->wrapped()->GetResolvedAddress(family, addr); } int WrappingAsyncDnsResolverResult::GetError() const { if (!owner_->wrapped()) { return -1; // FIXME: Find a code that makes sense. } return owner_->wrapped()->GetError(); } std::unique_ptr WrappingAsyncDnsResolverFactory::Create() { return std::make_unique(wrapped_factory_->Create()); } std::unique_ptr WrappingAsyncDnsResolverFactory::CreateAndResolve( const rtc::SocketAddress& addr, std::function callback) { std::unique_ptr resolver = Create(); resolver->Start(addr, callback); return resolver; } } // namespace webrtc