Add a new API to DNS resolution

This API should allow existing factories to be used unmodified, but
offers a new API that documents ownership better and does not use
sigslot.

Bug: webrtc:12598
Change-Id: I0f68371059cd4a18ab07b87fc0e7526dcc0ac669
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/212609
Reviewed-by: Tommi <tommi@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33553}
diff --git a/p2p/base/basic_async_resolver_factory.cc b/p2p/base/basic_async_resolver_factory.cc
index 027358b..67dd18f 100644
--- a/p2p/base/basic_async_resolver_factory.cc
+++ b/p2p/base/basic_async_resolver_factory.cc
@@ -10,6 +10,11 @@
 
 #include "p2p/base/basic_async_resolver_factory.h"
 
+#include <memory>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "api/async_dns_resolver.h"
 #include "rtc_base/async_resolver.h"
 
 namespace webrtc {
@@ -18,4 +23,93 @@
   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 { wrapped_.release()->Destroy(false); }
+
+  void Start(const rtc::SocketAddress& addr,
+             std::function<void()> callback) override {
+    RTC_DCHECK(state_ == State::kNotStarted);
+    state_ = State::kStarted;
+    callback_ = callback;
+    wrapped_->SignalDone.connect(this,
+                                 &WrappingAsyncDnsResolver::OnResolveResult);
+    wrapped_->Start(addr);
+  }
+
+  const AsyncDnsResolverResult& result() const override {
+    RTC_DCHECK(state_ == State::kResolved);
+    return result_;
+  }
+
+  // For use by WrappingAsyncDnsResolverResult
+  rtc::AsyncResolverInterface* wrapped() const { return wrapped_.get(); }
+
+ private:
+  enum class State { kNotStarted, kStarted, kResolved };
+
+  void OnResolveResult(rtc::AsyncResolverInterface* ref) {
+    RTC_DCHECK(state_ == State::kStarted);
+    RTC_DCHECK_EQ(ref, wrapped_.get());
+    state_ = State::kResolved;
+    callback_();
+  }
+
+  std::function<void()> callback_;
+  std::unique_ptr<rtc::AsyncResolverInterface> wrapped_;
+  State state_ = State::kNotStarted;
+  WrappingAsyncDnsResolverResult result_;
+};
+
+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<webrtc::AsyncDnsResolverInterface>
+WrappingAsyncDnsResolverFactory::Create() {
+  return std::make_unique<WrappingAsyncDnsResolver>(wrapped_factory_->Create());
+}
+
+std::unique_ptr<webrtc::AsyncDnsResolverInterface>
+WrappingAsyncDnsResolverFactory::CreateAndResolve(
+    const rtc::SocketAddress& addr,
+    std::function<void()> callback) {
+  std::unique_ptr<webrtc::AsyncDnsResolverInterface> resolver = Create();
+  resolver->Start(addr, callback);
+  return resolver;
+}
+
 }  // namespace webrtc