Update stable to r5121.

git-svn-id: http://webrtc.googlecode.com/svn/stable/talk@5122 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/app/webrtc/datachannel.cc b/app/webrtc/datachannel.cc
index 6f30487..6c9e0bc 100644
--- a/app/webrtc/datachannel.cc
+++ b/app/webrtc/datachannel.cc
@@ -248,7 +248,9 @@
 void DataChannel::OnDataReceived(cricket::DataChannel* channel,
                                  const cricket::ReceiveDataParams& params,
                                  const talk_base::Buffer& payload) {
-  if (params.ssrc != receive_ssrc_) {
+  uint32 expected_ssrc =
+      (data_channel_type_ == cricket::DCT_RTP) ? receive_ssrc_ : config_.id;
+  if (params.ssrc != expected_ssrc) {
     return;
   }
 
@@ -307,7 +309,6 @@
       if (send_ssrc_set_ == receive_ssrc_set_) {
         if (data_channel_type_ == cricket::DCT_RTP && !connected_to_provider_) {
           connected_to_provider_ = provider_->ConnectDataChannel(this);
-          provider_->AddRtpDataStream(send_ssrc_, receive_ssrc_);
         }
         if (was_ever_writable_) {
           // TODO(jiayl): Do not transition to kOpen if we failed to send the
@@ -351,9 +352,7 @@
   provider_->DisconnectDataChannel(this);
   connected_to_provider_ = false;
 
-  if (data_channel_type_ == cricket::DCT_RTP) {
-    provider_->RemoveRtpDataStream(send_ssrc_, receive_ssrc_);
-  } else {
+  if (data_channel_type_ == cricket::DCT_SCTP) {
     provider_->RemoveSctpDataStream(config_.id);
   }
 }
@@ -429,11 +428,13 @@
     const DataBuffer& buffer, cricket::SendDataResult* send_result) {
   cricket::SendDataParams send_params;
 
-  send_params.ssrc = send_ssrc_;
   if (data_channel_type_ == cricket::DCT_SCTP) {
     send_params.ordered = config_.ordered;
     send_params.max_rtx_count = config_.maxRetransmits;
     send_params.max_rtx_ms = config_.maxRetransmitTime;
+    send_params.ssrc = config_.id;
+  } else {
+    send_params.ssrc = send_ssrc_;
   }
   send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT;
 
diff --git a/app/webrtc/datachannel.h b/app/webrtc/datachannel.h
index 5635e63..bf31aed 100644
--- a/app/webrtc/datachannel.h
+++ b/app/webrtc/datachannel.h
@@ -53,12 +53,8 @@
   virtual bool ConnectDataChannel(DataChannel* data_channel) = 0;
   // Disconnects from the transport signals.
   virtual void DisconnectDataChannel(DataChannel* data_channel) = 0;
-  // Adds the send and receive stream ssrc to the transport for RTP.
-  virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) = 0;
   // Adds the data channel SID to the transport for SCTP.
   virtual void AddSctpDataStream(uint32 sid) = 0;
-  // Removes the data channel ssrcs from the transport for RTP.
-  virtual void RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) = 0;
   // Removes the data channel SID from the transport for SCTP.
   virtual void RemoveSctpDataStream(uint32 sid) = 0;
   // Returns true if the transport channel is ready to send data.
@@ -149,6 +145,10 @@
   // underlying data engine.
   void SetReceiveSsrc(uint32 receive_ssrc);
 
+  cricket::DataChannelType data_channel_type() const {
+    return data_channel_type_;
+  }
+
  protected:
   DataChannel(DataChannelProviderInterface* client,
               cricket::DataChannelType dct,
diff --git a/app/webrtc/datachannel_unittest.cc b/app/webrtc/datachannel_unittest.cc
index dba24a2..fdcd2f2 100644
--- a/app/webrtc/datachannel_unittest.cc
+++ b/app/webrtc/datachannel_unittest.cc
@@ -28,9 +28,16 @@
 #include "talk/app/webrtc/datachannel.h"
 #include "talk/app/webrtc/test/fakedatachannelprovider.h"
 #include "talk/base/gunit.h"
+#include "testing/base/public/gmock.h"
 
 using webrtc::DataChannel;
 
+class FakeDataChannelObserver : public webrtc::DataChannelObserver {
+ public:
+  MOCK_METHOD0(OnStateChange, void());
+  MOCK_METHOD1(OnMessage, void(const webrtc::DataBuffer& buffer));
+};
+
 class SctpDataChannelTest : public testing::Test {
  protected:
   SctpDataChannelTest()
@@ -47,8 +54,14 @@
     provider_.set_ready_to_send(true);
   }
 
+  void AddObserver() {
+    observer_.reset(new FakeDataChannelObserver());
+    webrtc_data_channel_->RegisterObserver(observer_.get());
+  }
+
   webrtc::DataChannelInit init_;
   FakeDataChannelProvider provider_;
+  talk_base::scoped_ptr<FakeDataChannelObserver> observer_;
   talk_base::scoped_refptr<DataChannel> webrtc_data_channel_;
 };
 
@@ -148,3 +161,41 @@
   EXPECT_TRUE_WAIT(webrtc::DataChannelInterface::kOpen == dc->state(),
                    1000);
 }
+
+// Tests that messages are sent with the right ssrc.
+TEST_F(SctpDataChannelTest, SendDataSsrc) {
+  webrtc_data_channel_->SetSctpSid(1);
+  SetChannelReady();
+  webrtc::DataBuffer buffer("data");
+  EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
+  EXPECT_EQ(1U, provider_.last_send_data_params().ssrc);
+}
+
+// Tests that the incoming messages with wrong ssrcs are rejected.
+TEST_F(SctpDataChannelTest, ReceiveDataWithInvalidSsrc) {
+  webrtc_data_channel_->SetSctpSid(1);
+  SetChannelReady();
+
+  AddObserver();
+  EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(0);
+
+  cricket::ReceiveDataParams params;
+  params.ssrc = 0;
+  webrtc::DataBuffer buffer("abcd");
+  webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
+}
+
+// Tests that the incoming messages with right ssrcs are acceted.
+TEST_F(SctpDataChannelTest, ReceiveDataWithValidSsrc) {
+  webrtc_data_channel_->SetSctpSid(1);
+  SetChannelReady();
+
+  AddObserver();
+  EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(1);
+
+  cricket::ReceiveDataParams params;
+  params.ssrc = 1;
+  webrtc::DataBuffer buffer("abcd");
+
+  webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
+}
diff --git a/app/webrtc/mediastreamsignaling.cc b/app/webrtc/mediastreamsignaling.cc
index 8d25425..7586938 100644
--- a/app/webrtc/mediastreamsignaling.cc
+++ b/app/webrtc/mediastreamsignaling.cc
@@ -208,10 +208,10 @@
 bool MediaStreamSignaling::IsSctpSidAvailable(int sid) const {
   if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid))
     return false;
-  for (DataChannels::const_iterator iter = data_channels_.begin();
-       iter != data_channels_.end();
+  for (SctpDataChannels::const_iterator iter = sctp_data_channels_.begin();
+       iter != sctp_data_channels_.end();
        ++iter) {
-    if (iter->second->id() == sid) {
+    if ((*iter)->id() == sid) {
       return false;
     }
   }
@@ -240,17 +240,23 @@
 }
 
 bool MediaStreamSignaling::HasDataChannels() const {
-  return !data_channels_.empty();
+  return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
 }
 
 bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
   ASSERT(data_channel != NULL);
-  if (data_channels_.find(data_channel->label()) != data_channels_.end()) {
-    LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
-                  << " already exists.";
-    return false;
+  if (data_channel->data_channel_type() == cricket::DCT_RTP) {
+    if (rtp_data_channels_.find(data_channel->label()) !=
+        rtp_data_channels_.end()) {
+      LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
+                    << " already exists.";
+      return false;
+    }
+    rtp_data_channels_[data_channel->label()] = data_channel;
+  } else {
+    ASSERT(data_channel->data_channel_type() == cricket::DCT_SCTP);
+    sctp_data_channels_.push_back(data_channel);
   }
-  data_channels_[data_channel->label()] = data_channel;
   return true;
 }
 
@@ -262,19 +268,13 @@
                     << "are not supported.";
     return false;
   }
-
-  if (data_channels_.find(label) != data_channels_.end()) {
-    LOG(LS_ERROR) << "DataChannel with label " << label
-                  << " already exists.";
-    return false;
-  }
   scoped_refptr<DataChannel> channel(
       data_channel_factory_->CreateDataChannel(label, &config));
   if (!channel.get()) {
     LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
     return false;
   }
-  data_channels_[label] = channel;
+  sctp_data_channels_.push_back(channel);
   stream_observer_->OnAddDataChannel(channel);
   return true;
 }
@@ -464,10 +464,13 @@
 }
 
 void MediaStreamSignaling::OnDataChannelClose() {
-  DataChannels::iterator it = data_channels_.begin();
-  for (; it != data_channels_.end(); ++it) {
-    DataChannel* data_channel = it->second;
-    data_channel->OnDataEngineClose();
+  RtpDataChannels::iterator it1 = rtp_data_channels_.begin();
+  for (; it1 != rtp_data_channels_.end(); ++it1) {
+    it1->second->OnDataEngineClose();
+  }
+  SctpDataChannels::iterator it2 = sctp_data_channels_.begin();
+  for (; it2 != sctp_data_channels_.end(); ++it2) {
+    (*it2)->OnDataEngineClose();
   }
 }
 
@@ -525,8 +528,8 @@
   }
 
   // Check for data channels.
-  DataChannels::const_iterator data_channel_it = data_channels_.begin();
-  for (; data_channel_it != data_channels_.end(); ++data_channel_it) {
+  RtpDataChannels::const_iterator data_channel_it = rtp_data_channels_.begin();
+  for (; data_channel_it != rtp_data_channels_.end(); ++data_channel_it) {
     const DataChannel* channel = data_channel_it->second;
     if (channel->state() == DataChannel::kConnecting ||
         channel->state() == DataChannel::kOpen) {
@@ -843,8 +846,9 @@
     // For MediaStreams, the sync_label is the MediaStream label and the
     // track label is the same as |streamid|.
     const std::string& channel_label = it->sync_label;
-    DataChannels::iterator data_channel_it = data_channels_.find(channel_label);
-    if (!VERIFY(data_channel_it != data_channels_.end())) {
+    RtpDataChannels::iterator data_channel_it =
+        rtp_data_channels_.find(channel_label);
+    if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
       continue;
     }
     // Set the SSRC the data channel should use for sending.
@@ -866,9 +870,9 @@
     // does not exist. Ex a=ssrc:444330170 mslabel:test1.
     std::string label = it->sync_label.empty() ?
         talk_base::ToString(it->first_ssrc()) : it->sync_label;
-    DataChannels::iterator data_channel_it =
-        data_channels_.find(label);
-    if (data_channel_it == data_channels_.end()) {
+    RtpDataChannels::iterator data_channel_it =
+        rtp_data_channels_.find(label);
+    if (data_channel_it == rtp_data_channels_.end()) {
       // This is a new data channel.
       CreateRemoteDataChannel(label, it->first_ssrc());
     } else {
@@ -882,8 +886,8 @@
 
 void MediaStreamSignaling::UpdateClosingDataChannels(
     const std::vector<std::string>& active_channels, bool is_local_update) {
-  DataChannels::iterator it = data_channels_.begin();
-  while (it != data_channels_.end()) {
+  RtpDataChannels::iterator it = rtp_data_channels_.begin();
+  while (it != rtp_data_channels_.end()) {
     DataChannel* data_channel = it->second;
     if (std::find(active_channels.begin(), active_channels.end(),
                   data_channel->label()) != active_channels.end()) {
@@ -897,8 +901,8 @@
       data_channel->RemotePeerRequestClose();
 
     if (data_channel->state() == DataChannel::kClosed) {
-      data_channels_.erase(it);
-      it = data_channels_.begin();
+      rtp_data_channels_.erase(it);
+      it = rtp_data_channels_.begin();
     } else {
       ++it;
     }
@@ -914,29 +918,32 @@
   }
   scoped_refptr<DataChannel> channel(
       data_channel_factory_->CreateDataChannel(label, NULL));
+  if (!channel.get()) {
+    LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
+                    << "CreateDataChannel failed.";
+    return;
+  }
   channel->SetReceiveSsrc(remote_ssrc);
   stream_observer_->OnAddDataChannel(channel);
 }
 
 void MediaStreamSignaling::OnDataTransportCreatedForSctp() {
-  DataChannels::iterator it = data_channels_.begin();
-  for (; it != data_channels_.end(); ++it) {
-    DataChannel* data_channel = it->second;
-    data_channel->OnTransportChannelCreated();
+  SctpDataChannels::iterator it = sctp_data_channels_.begin();
+  for (; it != sctp_data_channels_.end(); ++it) {
+    (*it)->OnTransportChannelCreated();
   }
 }
 
 void MediaStreamSignaling::OnDtlsRoleReadyForSctp(talk_base::SSLRole role) {
-  DataChannels::iterator it = data_channels_.begin();
-  for (; it != data_channels_.end(); ++it) {
-    DataChannel* data_channel = it->second;
-    if (data_channel->id() < 0) {
+  SctpDataChannels::iterator it = sctp_data_channels_.begin();
+  for (; it != sctp_data_channels_.end(); ++it) {
+    if ((*it)->id() < 0) {
       int sid;
       if (!AllocateSctpSid(role, &sid)) {
         LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
         continue;
       }
-      data_channel->SetSctpSid(sid);
+      (*it)->SetSctpSid(sid);
     }
   }
 }
diff --git a/app/webrtc/mediastreamsignaling.h b/app/webrtc/mediastreamsignaling.h
index a0ed619..c600f06 100644
--- a/app/webrtc/mediastreamsignaling.h
+++ b/app/webrtc/mediastreamsignaling.h
@@ -384,8 +384,10 @@
   int last_allocated_sctp_odd_sid_;
 
   typedef std::map<std::string, talk_base::scoped_refptr<DataChannel> >
-      DataChannels;
-  DataChannels data_channels_;
+      RtpDataChannels;
+  typedef std::vector<talk_base::scoped_refptr<DataChannel> > SctpDataChannels;
+  RtpDataChannels rtp_data_channels_;
+  SctpDataChannels sctp_data_channels_;
 };
 
 }  // namespace webrtc
diff --git a/app/webrtc/mediastreamsignaling_unittest.cc b/app/webrtc/mediastreamsignaling_unittest.cc
index df4b1f5..5b88aa0 100644
--- a/app/webrtc/mediastreamsignaling_unittest.cc
+++ b/app/webrtc/mediastreamsignaling_unittest.cc
@@ -238,6 +238,23 @@
   return true;
 }
 
+class FakeDataChannelFactory : public webrtc::DataChannelFactory {
+ public:
+  FakeDataChannelFactory(FakeDataChannelProvider* provider,
+                         cricket::DataChannelType dct)
+      : provider_(provider), type_(dct) {}
+
+  virtual talk_base::scoped_refptr<webrtc::DataChannel> CreateDataChannel(
+      const std::string& label,
+      const webrtc::DataChannelInit* config) {
+    return webrtc::DataChannel::Create(provider_, type_, label, config);
+  }
+
+ private:
+  FakeDataChannelProvider* provider_;
+  cricket::DataChannelType type_;
+};
+
 class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
  public:
   MockSignalingObserver()
@@ -418,6 +435,7 @@
                                     talk_base::Thread::Current()));
     signaling_.reset(new MediaStreamSignalingForTest(observer_.get(),
                                                      channel_manager_.get()));
+    data_channel_provider_.reset(new FakeDataChannelProvider());
   }
 
   // Create a collection of streams.
@@ -508,12 +526,25 @@
     ASSERT_TRUE(stream->AddTrack(video_track));
   }
 
+  talk_base::scoped_refptr<webrtc::DataChannel> AddDataChannel(
+      cricket::DataChannelType type, const std::string& label, int id) {
+    webrtc::DataChannelInit config;
+    config.id = id;
+    talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
+        webrtc::DataChannel::Create(
+            data_channel_provider_.get(), type, label, &config));
+    EXPECT_TRUE(data_channel.get() != NULL);
+    EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+    return data_channel;
+  }
+
   // ChannelManager is used by VideoSource, so it should be released after all
   // the video tracks. Put it as the first private variable should ensure that.
   talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
   talk_base::scoped_refptr<StreamCollection> reference_collection_;
   talk_base::scoped_ptr<MockSignalingObserver> observer_;
   talk_base::scoped_ptr<MediaStreamSignalingForTest> signaling_;
+  talk_base::scoped_ptr<FakeDataChannelProvider> data_channel_provider_;
 };
 
 // Test that a MediaSessionOptions is created for an offer if
@@ -1029,27 +1060,46 @@
 
 // Verifies that SCTP ids of existing DataChannels are not reused.
 TEST_F(MediaStreamSignalingTest, SctpIdAllocationNoReuse) {
-  talk_base::scoped_ptr<FakeDataChannelProvider> provider(
-      new FakeDataChannelProvider());
-  // Creates a DataChannel with id 1.
-  webrtc::DataChannelInit config;
-  config.id = 1;
-  talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
-      webrtc::DataChannel::Create(
-          provider.get(), cricket::DCT_SCTP, "a", &config));
-  ASSERT_TRUE(data_channel.get() != NULL);
-  ASSERT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+  int old_id = 1;
+  AddDataChannel(cricket::DCT_SCTP, "a", old_id);
 
   int new_id;
   ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_SERVER, &new_id));
-  EXPECT_NE(config.id, new_id);
+  EXPECT_NE(old_id, new_id);
 
   // Creates a DataChannel with id 0.
-  config.id = 0;
-  data_channel = webrtc::DataChannel::Create(
-      provider.get(), cricket::DCT_SCTP, "b", &config);
-  ASSERT_TRUE(data_channel.get() != NULL);
-  ASSERT_TRUE(signaling_->AddDataChannel(data_channel.get()));
+  old_id = 0;
+  AddDataChannel(cricket::DCT_SCTP, "a", old_id);
   ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_CLIENT, &new_id));
-  EXPECT_NE(config.id, new_id);
+  EXPECT_NE(old_id, new_id);
+}
+
+// Verifies that duplicated label is not allowed for RTP data channel.
+TEST_F(MediaStreamSignalingTest, RtpDuplicatedLabelNotAllowed) {
+  AddDataChannel(cricket::DCT_RTP, "a", -1);
+
+  webrtc::DataChannelInit config;
+  talk_base::scoped_refptr<webrtc::DataChannel> data_channel =
+      webrtc::DataChannel::Create(
+          data_channel_provider_.get(), cricket::DCT_RTP, "a", &config);
+  ASSERT_TRUE(data_channel.get() != NULL);
+  EXPECT_FALSE(signaling_->AddDataChannel(data_channel.get()));
+}
+
+// Verifies that duplicated label is allowed for SCTP data channel.
+TEST_F(MediaStreamSignalingTest, SctpDuplicatedLabelAllowed) {
+  AddDataChannel(cricket::DCT_SCTP, "a", -1);
+  AddDataChannel(cricket::DCT_SCTP, "a", -1);
+}
+
+// Verifies that duplicated label from OPEN message is allowed.
+TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
+  AddDataChannel(cricket::DCT_SCTP, "a", -1);
+
+  FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
+                                      cricket::DCT_SCTP);
+  signaling_->SetDataChannelFactory(&fake_factory);
+  webrtc::DataChannelInit config;
+  config.id = 0;
+  EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage("a", config));
 }
diff --git a/app/webrtc/peerconnection.cc b/app/webrtc/peerconnection.cc
index bc69d48..17f187d 100644
--- a/app/webrtc/peerconnection.cc
+++ b/app/webrtc/peerconnection.cc
@@ -42,8 +42,6 @@
 
 using webrtc::PeerConnectionInterface;
 
-// The min number of tokens in the ice uri.
-static const size_t kMinIceUriTokens = 2;
 // The min number of tokens must present in Turn host uri.
 // e.g. user@turn.example.org
 static const size_t kTurnHostTokensNum = 2;
@@ -103,6 +101,73 @@
   talk_base::scoped_refptr<webrtc::StatsObserver> observer;
 };
 
+// |in_str| should be of format
+// stunURI       = scheme ":" stun-host [ ":" stun-port ]
+// scheme        = "stun" / "stuns"
+// stun-host     = IP-literal / IPv4address / reg-name
+// stun-port     = *DIGIT
+
+// draft-petithuguenin-behave-turn-uris-01
+// turnURI       = scheme ":" turn-host [ ":" turn-port ]
+// turn-host     = username@IP-literal / IPv4address / reg-name
+bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
+                                      ServiceType* service_type,
+                                      std::string* hostname) {
+  std::string::size_type colonpos = in_str.find(':');
+  if (colonpos == std::string::npos) {
+    return false;
+  }
+  std::string type = in_str.substr(0, colonpos);
+  for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
+    if (type.compare(kValidIceServiceTypes[i]) == 0) {
+      *service_type = static_cast<ServiceType>(i);
+      break;
+    }
+  }
+  if (*service_type == INVALID) {
+    return false;
+  }
+  *hostname = in_str.substr(colonpos + 1, std::string::npos);
+  return true;
+}
+
+// This method parses IPv6 and IPv4 literal strings, along with hostnames in
+// standard hostname:port format.
+// Consider following formats as correct.
+// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
+// |hostname|, |[IPv6 address]|, |IPv4 address|
+bool ParseHostnameAndPortFromString(const std::string& in_str,
+                                    std::string* host,
+                                    int* port) {
+  if (in_str.at(0) == '[') {
+    std::string::size_type closebracket = in_str.rfind(']');
+    if (closebracket != std::string::npos) {
+      *host = in_str.substr(1, closebracket - 1);
+      std::string::size_type colonpos = in_str.find(':', closebracket);
+      if (std::string::npos != colonpos) {
+        if (!talk_base::FromString(
+            in_str.substr(closebracket + 2, std::string::npos), port)) {
+          return false;
+        }
+      }
+    } else {
+      return false;
+    }
+  } else {
+    std::string::size_type colonpos = in_str.find(':');
+    if (std::string::npos != colonpos) {
+      *host = in_str.substr(0, colonpos);
+      if (!talk_base::FromString(
+          in_str.substr(colonpos + 1, std::string::npos), port)) {
+        return false;
+      }
+    } else {
+      *host = in_str;
+    }
+  }
+  return true;
+}
+
 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
     StunConfiguration;
 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
@@ -125,8 +190,6 @@
   // transport-ext = 1*unreserved
   // turn-host     = IP-literal / IPv4address / reg-name
   // turn-port     = *DIGIT
-
-  // TODO(ronghuawu): Handle IPV6 address
   for (size_t i = 0; i < configuration.size(); ++i) {
     webrtc::PeerConnectionInterface::IceServer server = configuration[i];
     if (server.uri.empty()) {
@@ -152,41 +215,40 @@
       }
     }
 
-    tokens.clear();
-    talk_base::tokenize(uri_without_transport, ':', &tokens);
-    if (tokens.size() < kMinIceUriTokens) {
-      LOG(WARNING) << "Invalid uri: " << server.uri;
-      continue;
-    }
+    std::string hoststring;
     ServiceType service_type = INVALID;
-    const std::string& type = tokens[0];
-    for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
-      if (type.compare(kValidIceServiceTypes[i]) == 0) {
-        service_type = static_cast<ServiceType>(i);
-        break;
-      }
-    }
-    if (service_type == INVALID) {
-      LOG(WARNING) << "Invalid service type: " << type;
+    if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
+                                         &service_type,
+                                         &hoststring)) {
+      LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
+                      << uri_without_transport;
       continue;
     }
-    std::string address = tokens[1];
+
+    // Let's break hostname.
+    tokens.clear();
+    talk_base::tokenize(hoststring, '@', &tokens);
+    hoststring = tokens[0];
+    if (tokens.size() == kTurnHostTokensNum) {
+      server.username = talk_base::s_url_decode(tokens[0]);
+      hoststring = tokens[1];
+    }
+
     int port = kDefaultStunPort;
+    std::string address;
+    if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
+      LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
+      continue;
+    }
+
     if (service_type == TURNS) {
       port = kDefaultStunTlsPort;
       turn_transport_type = kTcpTransportType;
     }
 
-    if (tokens.size() > kMinIceUriTokens) {
-      if (!talk_base::FromString(tokens[2], &port)) {
-        LOG(LS_WARNING)  << "Failed to parse port string: " << tokens[2];
-        continue;
-      }
-
-      if (port <= 0 || port > 0xffff) {
-        LOG(WARNING) << "Invalid port: " << port;
-        continue;
-      }
+    if (port <= 0 || port > 0xffff) {
+      LOG(WARNING) << "Invalid port: " << port;
+      continue;
     }
 
     switch (service_type) {
diff --git a/app/webrtc/peerconnectionfactory_unittest.cc b/app/webrtc/peerconnectionfactory_unittest.cc
index e3def6c..4f0b729 100644
--- a/app/webrtc/peerconnectionfactory_unittest.cc
+++ b/app/webrtc/peerconnectionfactory_unittest.cc
@@ -69,6 +69,15 @@
 static const int kDefaultStunPort = 3478;
 static const int kDefaultStunTlsPort = 5349;
 static const char kTurnUsername[] = "test";
+static const char kStunIceServerWithIPv4Address[] = "stun:1.2.3.4:1234";
+static const char kStunIceServerWithIPv4AddressWithoutPort[] = "stun:1.2.3.4";
+static const char kStunIceServerWithIPv6Address[] = "stun:[2401:fa00:4::]:1234";
+static const char kStunIceServerWithIPv6AddressWithoutPort[] =
+    "stun:[2401:fa00:4::]";
+static const char kStunIceServerWithInvalidIPv6Address[] =
+    "stun:[2401:fa00:4:::3478";
+static const char kTurnIceServerWithIPv6Address[] =
+    "turn:test@[2401:fa00:4::]:1234";
 
 class NullPeerConnectionObserver : public PeerConnectionObserver {
  public:
@@ -265,6 +274,51 @@
   VerifyTurnConfigurations(turn_configs);
 }
 
+TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) {
+  webrtc::PeerConnectionInterface::IceServers ice_servers;
+  webrtc::PeerConnectionInterface::IceServer ice_server;
+  ice_server.uri = kStunIceServerWithIPv4Address;
+  ice_servers.push_back(ice_server);
+  ice_server.uri = kStunIceServerWithIPv4AddressWithoutPort;
+  ice_servers.push_back(ice_server);
+  ice_server.uri = kStunIceServerWithIPv6Address;
+  ice_servers.push_back(ice_server);
+  ice_server.uri = kStunIceServerWithIPv6AddressWithoutPort;
+  ice_servers.push_back(ice_server);
+  ice_server.uri = kStunIceServerWithInvalidIPv6Address;
+  ice_servers.push_back(ice_server);
+  ice_server.uri = kTurnIceServerWithIPv6Address;
+  ice_server.password = kTurnPassword;
+  ice_servers.push_back(ice_server);
+  talk_base::scoped_refptr<PeerConnectionInterface> pc(
+      factory_->CreatePeerConnection(ice_servers, NULL,
+                                     allocator_factory_.get(),
+                                     NULL,
+                                     &observer_));
+  EXPECT_TRUE(pc.get() != NULL);
+  StunConfigurations stun_configs;
+  webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1(
+      "1.2.3.4", 1234);
+  stun_configs.push_back(stun1);
+  webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2(
+      "1.2.3.4", 3478);
+  stun_configs.push_back(stun2);  // Default port
+  webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3(
+      "2401:fa00:4::", 1234);
+  stun_configs.push_back(stun3);
+  webrtc::PortAllocatorFactoryInterface::StunConfiguration stun4(
+      "2401:fa00:4::", 3478);
+  stun_configs.push_back(stun4);  // Default port
+  // Turn Address has the same host information as |stun3|.
+  stun_configs.push_back(stun3);
+  VerifyStunConfigurations(stun_configs);
+  TurnConfigurations turn_configs;
+  webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1(
+      "2401:fa00:4::", 1234, "test", kTurnPassword, "udp", false);
+  turn_configs.push_back(turn1);
+  VerifyTurnConfigurations(turn_configs);
+}
+
 // This test verifies the captured stream is rendered locally using a
 // local video track.
 TEST_F(PeerConnectionFactoryTest, LocalRendering) {
diff --git a/app/webrtc/peerconnectioninterface_unittest.cc b/app/webrtc/peerconnectioninterface_unittest.cc
index ea94ee1..093b842 100644
--- a/app/webrtc/peerconnectioninterface_unittest.cc
+++ b/app/webrtc/peerconnectioninterface_unittest.cc
@@ -37,6 +37,7 @@
 #include "talk/app/webrtc/videosource.h"
 #include "talk/base/gunit.h"
 #include "talk/base/scoped_ptr.h"
+#include "talk/base/ssladapter.h"
 #include "talk/base/sslstreamadapter.h"
 #include "talk/base/stringutils.h"
 #include "talk/base/thread.h"
@@ -227,12 +228,17 @@
 class PeerConnectionInterfaceTest : public testing::Test {
  protected:
   virtual void SetUp() {
+    talk_base::InitializeSSL(NULL);
     pc_factory_ = webrtc::CreatePeerConnectionFactory(
         talk_base::Thread::Current(), talk_base::Thread::Current(), NULL, NULL,
         NULL);
     ASSERT_TRUE(pc_factory_.get() != NULL);
   }
 
+  virtual void TearDown() {
+    talk_base::CleanupSSL();
+  }
+
   void CreatePeerConnection() {
     CreatePeerConnection("", "", NULL);
   }
@@ -1070,9 +1076,7 @@
 // Test that we can create a session description from an SDP string from
 // FireFox, use it as a remote session description, generate an answer and use
 // the answer as a local description.
-// TODO(mallinath): re-enable per
-// https://code.google.com/p/webrtc/issues/detail?id=2574
-TEST_F(PeerConnectionInterfaceTest, DISABLED_ReceiveFireFoxOffer) {
+TEST_F(PeerConnectionInterfaceTest, ReceiveFireFoxOffer) {
   MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
   FakeConstraints constraints;
   constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
@@ -1096,11 +1100,12 @@
       cricket::GetFirstVideoContent(pc_->local_description()->description());
   ASSERT_TRUE(content != NULL);
   EXPECT_FALSE(content->rejected);
-
+#ifdef HAVE_SCTP
   content =
       cricket::GetFirstDataContent(pc_->local_description()->description());
   ASSERT_TRUE(content != NULL);
   EXPECT_TRUE(content->rejected);
+#endif
 }
 
 // Test that we can create an audio only offer and receive an answer with a
diff --git a/app/webrtc/test/fakedatachannelprovider.h b/app/webrtc/test/fakedatachannelprovider.h
index 429f4df..5b19698 100644
--- a/app/webrtc/test/fakedatachannelprovider.h
+++ b/app/webrtc/test/fakedatachannelprovider.h
@@ -64,29 +64,17 @@
     connected_channels_.erase(data_channel);
   }
 
-  virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE {
-    if (!transport_available_) {
-      return;
-    }
-    send_ssrcs_.insert(send_ssrc);
-    recv_ssrcs_.insert(recv_ssrc);
-  }
-
   virtual void AddSctpDataStream(uint32 sid) OVERRIDE {
     if (!transport_available_) {
       return;
     }
-    AddRtpDataStream(sid, sid);
-  }
-
-  virtual void RemoveRtpDataStream(
-      uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE {
-    send_ssrcs_.erase(send_ssrc);
-    recv_ssrcs_.erase(recv_ssrc);
+    send_ssrcs_.insert(sid);
+    recv_ssrcs_.insert(sid);
   }
 
   virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE {
-    RemoveRtpDataStream(sid, sid);
+    send_ssrcs_.erase(sid);
+    recv_ssrcs_.erase(sid);
   }
 
   virtual bool ReadyToSendData() const OVERRIDE {
diff --git a/app/webrtc/test/testsdpstrings.h b/app/webrtc/test/testsdpstrings.h
index 9f95d36..d6e9c22 100644
--- a/app/webrtc/test/testsdpstrings.h
+++ b/app/webrtc/test/testsdpstrings.h
@@ -75,6 +75,7 @@
     "a=candidate:4 2 UDP 2113667326 10.0.254.2 58890 typ host\r\n"
     "a=candidate:5 2 UDP 1694302206 74.95.2.170 33611 typ srflx raddr"
     " 10.0.254.2 rport 58890\r\n"
+#ifdef HAVE_SCTP
     "m=application 45536 SCTP/DTLS 5000\r\n"
     "c=IN IP4 74.95.2.170\r\n"
     "a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n"
@@ -88,7 +89,9 @@
     "a=candidate:2 2 UDP 2112487678 172.16.131.1 59635 typ host\r\n"
     "a=candidate:4 2 UDP 2113667326 10.0.254.2 61232 typ host\r\n"
     "a=candidate:5 2 UDP 1694302206 74.95.2.170 45468 typ srflx raddr"
-    " 10.0.254.2 rport 61232\r\n";
+    " 10.0.254.2 rport 61232\r\n"
+#endif
+    ;
 
 // Audio SDP with a limited set of audio codecs.
 static const char kAudioSdp[] =
diff --git a/app/webrtc/webrtcsession.cc b/app/webrtc/webrtcsession.cc
index 5935ea0..565eee3 100644
--- a/app/webrtc/webrtcsession.cc
+++ b/app/webrtc/webrtcsession.cc
@@ -997,31 +997,23 @@
   data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
 }
 
-void WebRtcSession::AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) {
+void WebRtcSession::AddSctpDataStream(uint32 sid) {
   if (!data_channel_.get()) {
     LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL.";
     return;
   }
-  data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(recv_ssrc));
-  data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(send_ssrc));
+  data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid));
+  data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid));
 }
 
-void WebRtcSession::AddSctpDataStream(uint32 sid) {
-  AddRtpDataStream(sid, sid);
-}
-
-void WebRtcSession::RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) {
+void WebRtcSession::RemoveSctpDataStream(uint32 sid) {
   if (!data_channel_.get()) {
     LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
                   << "NULL.";
     return;
   }
-  data_channel_->RemoveRecvStream(recv_ssrc);
-  data_channel_->RemoveSendStream(send_ssrc);
-}
-
-void WebRtcSession::RemoveSctpDataStream(uint32 sid) {
-  RemoveRtpDataStream(sid, sid);
+  data_channel_->RemoveRecvStream(sid);
+  data_channel_->RemoveSendStream(sid);
 }
 
 bool WebRtcSession::ReadyToSendData() const {
diff --git a/app/webrtc/webrtcsession.h b/app/webrtc/webrtcsession.h
index 4a39a11..da994c5 100644
--- a/app/webrtc/webrtcsession.h
+++ b/app/webrtc/webrtcsession.h
@@ -190,9 +190,7 @@
                         cricket::SendDataResult* result) OVERRIDE;
   virtual bool ConnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE;
   virtual void DisconnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE;
-  virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE;
   virtual void AddSctpDataStream(uint32 sid) OVERRIDE;
-  virtual void RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE;
   virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE;
   virtual bool ReadyToSendData() const OVERRIDE;
 
diff --git a/base/asyncresolverinterface.h b/base/asyncresolverinterface.h
new file mode 100644
index 0000000..4d77c4f
--- /dev/null
+++ b/base/asyncresolverinterface.h
@@ -0,0 +1,64 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_BASE_ASYNCRESOLVERINTERFACE_H_
+#define TALK_BASE_ASYNCRESOLVERINTERFACE_H_
+
+#include "talk/base/sigslot.h"
+#include "talk/base/socketaddress.h"
+
+namespace talk_base {
+
+// This interface defines the methods to resolve the address asynchronously.
+class AsyncResolverInterface {
+ public:
+  AsyncResolverInterface() {}
+  virtual ~AsyncResolverInterface() {}
+
+  // Start address resolve process.
+  virtual void Start(const SocketAddress& addr) = 0;
+  // Returns top most resolved address of |family|
+  virtual bool GetResolvedAddress(int family, SocketAddress* addr) const = 0;
+  // Returns error from resolver.
+  virtual int GetError() const = 0;
+  // Delete the resolver.
+  virtual void Destroy(bool wait) = 0;
+  // Returns top most resolved IPv4 address if address is resolved successfully.
+  // Otherwise returns address set in SetAddress.
+  SocketAddress address() const {
+    SocketAddress addr;
+    GetResolvedAddress(AF_INET, &addr);
+    return addr;
+  }
+
+  // This signal is fired when address resolve process is completed.
+  sigslot::signal1<AsyncResolverInterface*> SignalDone;
+};
+
+}  // namespace talk_base
+
+#endif
diff --git a/base/autodetectproxy.cc b/base/autodetectproxy.cc
index 02cbaad..a32043c 100644
--- a/base/autodetectproxy.cc
+++ b/base/autodetectproxy.cc
@@ -82,7 +82,10 @@
 }
 
 void AutoDetectProxy::OnMessage(Message *msg) {
-  if (MSG_TIMEOUT == msg->message_id) {
+  if (MSG_UNRESOLVABLE == msg->message_id) {
+    // If we can't resolve the proxy, skip straight to failure.
+    Complete(PROXY_UNKNOWN);
+  } else if (MSG_TIMEOUT == msg->message_id) {
     OnCloseEvent(socket_, ETIMEDOUT);
   } else {
     // This must be the ST_MSG_WORKER_DONE message that deletes the
@@ -136,22 +139,24 @@
   }
 }
 
-void AutoDetectProxy::OnResolveResult(SignalThread* thread) {
-  if (thread != resolver_) {
+void AutoDetectProxy::OnResolveResult(AsyncResolverInterface* resolver) {
+  if (resolver != resolver_) {
     return;
   }
-  int error = resolver_->error();
+  int error = resolver_->GetError();
   if (error == 0) {
     LOG(LS_VERBOSE) << "Resolved " << proxy_.address << " to "
                     << resolver_->address();
     proxy_.address = resolver_->address();
-    DoConnect();
+    if (!DoConnect()) {
+      Thread::Current()->Post(this, MSG_TIMEOUT);
+    }
   } else {
     LOG(LS_INFO) << "Failed to resolve " << resolver_->address();
     resolver_->Destroy(false);
     resolver_ = NULL;
     proxy_.address = SocketAddress();
-    Thread::Current()->Post(this, MSG_TIMEOUT);
+    Thread::Current()->Post(this, MSG_UNRESOLVABLE);
   }
 }
 
@@ -166,6 +171,7 @@
 
   if (socket_) {
     Thread::Current()->Clear(this, MSG_TIMEOUT);
+    Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
     socket_->Close();
     Thread::Current()->Dispose(socket_);
     socket_ = NULL;
@@ -177,17 +183,18 @@
     if (!resolver_) {
       resolver_ = new AsyncResolver();
     }
-    resolver_->set_address(proxy_.address);
-    resolver_->SignalWorkDone.connect(this,
-                                      &AutoDetectProxy::OnResolveResult);
-    resolver_->Start();
+    resolver_->SignalDone.connect(this, &AutoDetectProxy::OnResolveResult);
+    resolver_->Start(proxy_.address);
   } else {
-    DoConnect();
+    if (!DoConnect()) {
+      Thread::Current()->Post(this, MSG_TIMEOUT);
+      return;
+    }
   }
   Thread::Current()->PostDelayed(timeout, this, MSG_TIMEOUT);
 }
 
-void AutoDetectProxy::DoConnect() {
+bool AutoDetectProxy::DoConnect() {
   if (resolver_) {
     resolver_->Destroy(false);
     resolver_ = NULL;
@@ -197,16 +204,18 @@
           proxy_.address.family(), SOCK_STREAM);
   if (!socket_) {
     LOG(LS_VERBOSE) << "Unable to create socket for " << proxy_.address;
-    return;
+    return false;
   }
   socket_->SignalConnectEvent.connect(this, &AutoDetectProxy::OnConnectEvent);
   socket_->SignalReadEvent.connect(this, &AutoDetectProxy::OnReadEvent);
   socket_->SignalCloseEvent.connect(this, &AutoDetectProxy::OnCloseEvent);
   socket_->Connect(proxy_.address);
+  return true;
 }
 
 void AutoDetectProxy::Complete(ProxyType type) {
   Thread::Current()->Clear(this, MSG_TIMEOUT);
+  Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
   if (socket_) {
     socket_->Close();
   }
diff --git a/base/autodetectproxy.h b/base/autodetectproxy.h
index a6ad3d1..2cbeb82 100644
--- a/base/autodetectproxy.h
+++ b/base/autodetectproxy.h
@@ -42,7 +42,7 @@
 // AutoDetectProxy
 ///////////////////////////////////////////////////////////////////////////////
 
-class AsyncResolver;
+class AsyncResolverInterface;
 class AsyncSocket;
 
 class AutoDetectProxy : public SignalThread {
@@ -72,6 +72,7 @@
     return GetProxySettingsForUrl(agent, url, proxy, true);
   }
   enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
+         MSG_UNRESOLVABLE,
          ADP_MSG_FIRST_AVAILABLE};
 
  protected:
@@ -87,14 +88,14 @@
   void OnConnectEvent(AsyncSocket * socket);
   void OnReadEvent(AsyncSocket * socket);
   void OnCloseEvent(AsyncSocket * socket, int error);
-  void OnResolveResult(SignalThread* thread);
-  void DoConnect();
+  void OnResolveResult(AsyncResolverInterface* resolver);
+  bool DoConnect();
 
  private:
   std::string agent_;
   std::string server_url_;
   ProxyInfo proxy_;
-  AsyncResolver* resolver_;
+  AsyncResolverInterface* resolver_;
   AsyncSocket* socket_;
   int next_;
 
diff --git a/base/autodetectproxy_unittest.cc b/base/autodetectproxy_unittest.cc
index 3fca4c6..18241a3 100644
--- a/base/autodetectproxy_unittest.cc
+++ b/base/autodetectproxy_unittest.cc
@@ -37,9 +37,16 @@
 static const char kHost[] = "relay.google.com";
 static const uint16 kPort = 443;
 static const bool kSecure = true;
-// Each of the two stages in AutoDetectProxy has a 2-second time-out, so 5
-// seconds total should be enough.
-static const int kTimeoutMs = 5000;
+// At most, AutoDetectProxy should take ~6 seconds. Each connect step is
+// allotted 2 seconds, with the initial resolution + connect given an
+// extra 2 seconds. The slowest case is:
+// 1) Resolution + HTTPS takes full 4 seconds and fails (but resolution
+// succeeds).
+// 2) SOCKS5 takes the full 2 seconds.
+// Socket creation time seems unbounded, and has been observed to take >1 second
+// on a linux machine under load. As such, we allow for 10 seconds for timeout,
+// though could still end up with some flakiness.
+static const int kTimeoutMs = 10000;
 
 class AutoDetectProxyTest : public testing::Test, public sigslot::has_slots<> {
  public:
diff --git a/base/httpclient.cc b/base/httpclient.cc
index 5a16676..5bee911 100644
--- a/base/httpclient.cc
+++ b/base/httpclient.cc
@@ -316,11 +316,11 @@
   base_.abort(HE_OPERATION_CANCELLED);
 }
 
-void HttpClient::OnResolveResult(SignalThread* thread) {
-  if (thread != resolver_) {
+void HttpClient::OnResolveResult(AsyncResolverInterface* resolver) {
+  if (resolver != resolver_) {
     return;
   }
-  int error = resolver_->error();
+  int error = resolver_->GetError();
   server_ = resolver_->address();
   resolver_->Destroy(false);
   resolver_ = NULL;
@@ -335,9 +335,8 @@
 
 void HttpClient::StartDNSLookup() {
   resolver_ = new AsyncResolver();
-  resolver_->set_address(server_);
-  resolver_->SignalWorkDone.connect(this, &HttpClient::OnResolveResult);
-  resolver_->Start();
+  resolver_->SignalDone.connect(this, &HttpClient::OnResolveResult);
+  resolver_->Start(server_);
 }
 
 void HttpClient::set_server(const SocketAddress& address) {
diff --git a/base/httpclient.h b/base/httpclient.h
index 2e77b0d..03deb22 100644
--- a/base/httpclient.h
+++ b/base/httpclient.h
@@ -175,7 +175,7 @@
   HttpError OnHeaderAvailable(bool ignore_data, bool chunked, size_t data_size);
 
   void StartDNSLookup();
-  void OnResolveResult(SignalThread* thread);
+  void OnResolveResult(AsyncResolverInterface* resolver);
 
   // IHttpNotify Interface
   virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size);
@@ -199,7 +199,7 @@
   scoped_ptr<HttpAuthContext> context_;
   DiskCache* cache_;
   CacheState cache_state_;
-  AsyncResolver* resolver_;
+  AsyncResolverInterface* resolver_;
 };
 
 //////////////////////////////////////////////////////////////////////
diff --git a/base/latebindingsymboltable.cc b/base/latebindingsymboltable.cc
index 2226219..433844e 100644
--- a/base/latebindingsymboltable.cc
+++ b/base/latebindingsymboltable.cc
@@ -109,7 +109,23 @@
   }
 
 #ifdef POSIX
-  handle_ = dlopen(dll_path, RTLD_NOW);
+  handle_ = dlopen(dll_path,
+                   // RTLD_NOW front-loads symbol resolution so that errors are
+                   // caught early instead of causing a process abort later.
+                   // RTLD_LOCAL prevents other modules from automatically
+                   // seeing symbol definitions in the newly-loaded tree. This
+                   // is necessary for same-named symbols in different ABI
+                   // versions of the same library to not explode.
+                   RTLD_NOW|RTLD_LOCAL
+#ifdef LINUX
+                   // RTLD_DEEPBIND makes symbol dependencies in the
+                   // newly-loaded tree prefer to resolve to definitions within
+                   // that tree (the default on OS X). This is necessary for
+                   // same-named symbols in different ABI versions of the same
+                   // library to not explode.
+                   |RTLD_DEEPBIND
+#endif
+                   );  // NOLINT
 #else
 #error Not implemented
 #endif
diff --git a/base/libdbusglibsymboltable.cc b/base/libdbusglibsymboltable.cc
index 9c4be7f..6a3ebf3 100644
--- a/base/libdbusglibsymboltable.cc
+++ b/base/libdbusglibsymboltable.cc
@@ -33,7 +33,7 @@
 
 #define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBDBUS_GLIB_CLASS_NAME
 #define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST LIBDBUS_GLIB_SYMBOLS_LIST
-#define LATE_BINDING_SYMBOL_TABLE_DLL_NAME "libdbus-glib-1.so"
+#define LATE_BINDING_SYMBOL_TABLE_DLL_NAME "libdbus-glib-1.so.2"
 #include "talk/base/latebindingsymboltable.cc.def"
 
 }  // namespace talk_base
diff --git a/base/macasyncsocket.cc b/base/macasyncsocket.cc
index 54ad604..7841b4b 100644
--- a/base/macasyncsocket.cc
+++ b/base/macasyncsocket.cc
@@ -87,7 +87,7 @@
   if (thread != resolver_) {
     return;
   }
-  int error = resolver_->error();
+  int error = resolver_->GetError();
   if (error == 0) {
     error = DoConnect(resolver_->address());
   } else {
@@ -109,10 +109,9 @@
   if (addr.IsUnresolved()) {
     LOG(LS_VERBOSE) << "Resolving addr in MacAsyncSocket::Connect";
     resolver_ = new AsyncResolver();
-    resolver_->set_address(addr);
     resolver_->SignalWorkDone.connect(this,
                                       &MacAsyncSocket::OnResolveResult);
-    resolver_->Start();
+    resolver_->Start(addr);
     state_ = CS_CONNECTING;
     return 0;
   }
diff --git a/base/nethelpers.cc b/base/nethelpers.cc
index 05e02c9..e6310ac 100644
--- a/base/nethelpers.cc
+++ b/base/nethelpers.cc
@@ -67,7 +67,27 @@
 }
 
 // AsyncResolver
-AsyncResolver::AsyncResolver() : error_(0) {
+AsyncResolver::AsyncResolver() : error_(-1) {
+}
+
+void AsyncResolver::Start(const SocketAddress& addr) {
+  addr_ = addr;
+  // SignalThred Start will kickoff the resolve process.
+  SignalThread::Start();
+}
+
+bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
+  if (error_ != 0 || addresses_.empty())
+    return false;
+
+  *addr = addr_;
+  for (size_t i = 0; i < addresses_.size(); ++i) {
+    if (family == addresses_[i].family()) {
+      addr->SetIP(addresses_[i]);
+      return true;
+    }
+  }
+  return false;
 }
 
 void AsyncResolver::DoWork() {
@@ -76,9 +96,7 @@
 }
 
 void AsyncResolver::OnWorkDone() {
-  if (addresses_.size() > 0) {
-    addr_.SetIP(addresses_[0]);
-  }
+  SignalDone(this);
 }
 
 const char* inet_ntop(int af, const void *src, char* dst, socklen_t size) {
diff --git a/base/nethelpers.h b/base/nethelpers.h
index 66f7910..a49f48a 100644
--- a/base/nethelpers.h
+++ b/base/nethelpers.h
@@ -37,25 +37,30 @@
 
 #include <list>
 
+#include "talk/base/asyncresolverinterface.h"
 #include "talk/base/signalthread.h"
 #include "talk/base/sigslot.h"
 #include "talk/base/socketaddress.h"
 
 namespace talk_base {
 
+class AsyncResolverTest;
+
 // AsyncResolver will perform async DNS resolution, signaling the result on
-// the inherited SignalWorkDone when the operation completes.
-class AsyncResolver : public SignalThread {
+// the SignalDone from AsyncResolverInterface when the operation completes.
+class AsyncResolver : public SignalThread, public AsyncResolverInterface {
  public:
   AsyncResolver();
+  virtual ~AsyncResolver() {}
 
-  const SocketAddress& address() const { return addr_; }
+  virtual void Start(const SocketAddress& addr);
+  virtual bool GetResolvedAddress(int family, SocketAddress* addr) const;
+  virtual int GetError() const { return error_; }
+  virtual void Destroy(bool wait) { SignalThread::Destroy(wait); }
+
   const std::vector<IPAddress>& addresses() const { return addresses_; }
-  void set_address(const SocketAddress& addr) { addr_ = addr; }
-  int error() const { return error_; }
   void set_error(int error) { error_ = error; }
 
-
  protected:
   virtual void DoWork();
   virtual void OnWorkDone();
diff --git a/base/physicalsocketserver.cc b/base/physicalsocketserver.cc
index 58a22fa..43be440 100644
--- a/base/physicalsocketserver.cc
+++ b/base/physicalsocketserver.cc
@@ -200,9 +200,8 @@
     if (addr.IsUnresolved()) {
       LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect";
       resolver_ = new AsyncResolver();
-      resolver_->set_address(addr);
-      resolver_->SignalWorkDone.connect(this, &PhysicalSocket::OnResolveResult);
-      resolver_->Start();
+      resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult);
+      resolver_->Start(addr);
       state_ = CS_CONNECTING;
       return 0;
     }
@@ -476,12 +475,12 @@
   SocketServer* socketserver() { return ss_; }
 
  protected:
-  void OnResolveResult(SignalThread* thread) {
-    if (thread != resolver_) {
+  void OnResolveResult(AsyncResolverInterface* resolver) {
+    if (resolver != resolver_) {
       return;
     }
 
-    int error = resolver_->error();
+    int error = resolver_->GetError();
     if (error == 0) {
       error = DoConnect(resolver_->address());
     } else {
diff --git a/examples/peerconnection/client/peer_connection_client.cc b/examples/peerconnection/client/peer_connection_client.cc
index 403fabd..9cdaedc 100644
--- a/examples/peerconnection/client/peer_connection_client.cc
+++ b/examples/peerconnection/client/peer_connection_client.cc
@@ -134,17 +134,16 @@
   if (server_address_.IsUnresolved()) {
     state_ = RESOLVING;
     resolver_ = new talk_base::AsyncResolver();
-    resolver_->SignalWorkDone.connect(this,
-                                      &PeerConnectionClient::OnResolveResult);
-    resolver_->set_address(server_address_);
-    resolver_->Start();
+    resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult);
+    resolver_->Start(server_address_);
   } else {
     DoConnect();
   }
 }
 
-void PeerConnectionClient::OnResolveResult(talk_base::SignalThread *t) {
-  if (resolver_->error() != 0) {
+void PeerConnectionClient::OnResolveResult(
+    talk_base::AsyncResolverInterface* resolver) {
+  if (resolver_->GetError() != 0) {
     callback_->OnServerConnectionFailure();
     resolver_->Destroy(false);
     resolver_ = NULL;
diff --git a/examples/peerconnection/client/peer_connection_client.h b/examples/peerconnection/client/peer_connection_client.h
index d31262b..43fee34 100644
--- a/examples/peerconnection/client/peer_connection_client.h
+++ b/examples/peerconnection/client/peer_connection_client.h
@@ -121,7 +121,7 @@
 
   void OnClose(talk_base::AsyncSocket* socket, int err);
 
-  void OnResolveResult(talk_base::SignalThread *t);
+  void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
 
   PeerConnectionClientObserver* callback_;
   talk_base::SocketAddress server_address_;
diff --git a/libjingle.gyp b/libjingle.gyp
index 16044b5..4cbeaa3 100755
--- a/libjingle.gyp
+++ b/libjingle.gyp
@@ -257,6 +257,7 @@
         'base/asynchttprequest.cc',
         'base/asynchttprequest.h',
         'base/asyncpacketsocket.h',
+        'base/asyncresolverinterface.h',
         'base/asyncsocket.cc',
         'base/asyncsocket.h',
         'base/asynctcpsocket.cc',
diff --git a/libjingle_tests.gyp b/libjingle_tests.gyp
index 80e1e96..44fa8f7 100755
--- a/libjingle_tests.gyp
+++ b/libjingle_tests.gyp
@@ -375,7 +375,7 @@
       ],
       # TODO(ronghuawu): Reenable below unit tests that require gmock.
       'sources': [
-        'app/webrtc/datachannel_unittest.cc',
+        # 'app/webrtc/datachannel_unittest.cc',
         'app/webrtc/dtmfsender_unittest.cc',
         'app/webrtc/jsepsessiondescription_unittest.cc',
         'app/webrtc/localaudiosource_unittest.cc',
diff --git a/media/devices/libudevsymboltable.cc b/media/devices/libudevsymboltable.cc
index 9620cd2..20154e1 100644
--- a/media/devices/libudevsymboltable.cc
+++ b/media/devices/libudevsymboltable.cc
@@ -42,7 +42,8 @@
 #undef LATE_BINDING_SYMBOL_TABLE_DLL_NAME
 
 bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0) {
-  talk_base::DllHandle libudev_1 = dlopen("libudev.so.1", RTLD_NOW|RTLD_NOLOAD);
+  talk_base::DllHandle libudev_1 = dlopen("libudev.so.1",
+                                          RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD);
   bool unsafe_symlink = (libudev_0 == libudev_1);
   if (unsafe_symlink) {
     // .0 and .1 are distinct ABIs, so if they point to the same thing then one
@@ -55,7 +56,8 @@
     // system library loaded the new ABI separately. This is not a problem for
     // LateBindingSymbolTable because its symbol look-ups are restricted to its
     // DllHandle, but having libudev.so.0 resident may cause problems for that
-    // system library because symbol names are not namespaced by DLL.
+    // system library because symbol names are not namespaced by DLL. (Although
+    // our use of RTLD_LOCAL should avoid most problems.)
     LOG(LS_WARNING)
         << "libudev.so.1 is resident but distinct from libudev.so.0";
   }
diff --git a/media/webrtc/webrtcvideoengine.cc b/media/webrtc/webrtcvideoengine.cc
index ec38eea..6032134 100644
--- a/media/webrtc/webrtcvideoengine.cc
+++ b/media/webrtc/webrtcvideoengine.cc
@@ -3219,7 +3219,8 @@
       LOG_RTCERR1(SetNACKStatus, channel_id);
       return false;
     }
-    LOG(LS_INFO) << "NACK enabled for channel " << channel_id;
+    std::string enabled = nack_enabled ? "enabled" : "disabled";
+    LOG(LS_INFO) << "NACK " << enabled << " for channel " << channel_id;
   }
   return true;
 }
diff --git a/media/webrtc/webrtcvoiceengine.cc b/media/webrtc/webrtcvoiceengine.cc
index ac8e067..4911c59 100644
--- a/media/webrtc/webrtcvoiceengine.cc
+++ b/media/webrtc/webrtcvoiceengine.cc
@@ -3065,9 +3065,12 @@
             static_cast<float>(ns.currentExpandRate) / (1 << 14);
       }
       if (engine()->voe()->sync()) {
+        int jitter_buffer_delay_ms = 0;
         int playout_buffer_delay_ms = 0;
         engine()->voe()->sync()->GetDelayEstimate(
-            *it, &rinfo.delay_estimate_ms, &playout_buffer_delay_ms);
+            *it, &jitter_buffer_delay_ms, &playout_buffer_delay_ms);
+        rinfo.delay_estimate_ms = jitter_buffer_delay_ms +
+            playout_buffer_delay_ms;
       }
 
       // Get speech level.
diff --git a/p2p/base/basicpacketsocketfactory.cc b/p2p/base/basicpacketsocketfactory.cc
index 565aed3..758d492 100644
--- a/p2p/base/basicpacketsocketfactory.cc
+++ b/p2p/base/basicpacketsocketfactory.cc
@@ -30,6 +30,9 @@
 #include "talk/base/asyncudpsocket.h"
 #include "talk/base/asynctcpsocket.h"
 #include "talk/base/logging.h"
+#include "talk/base/nethelpers.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/scoped_ptr.h"
 #include "talk/base/socketadapters.h"
 #include "talk/base/thread.h"
 #include "talk/p2p/base/asyncstuntcpsocket.h"
@@ -174,6 +177,10 @@
   return tcp_socket;
 }
 
+AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
+  return new talk_base::AsyncResolver();
+}
+
 int BasicPacketSocketFactory::BindSocket(
     AsyncSocket* socket, const SocketAddress& local_address,
     int min_port, int max_port) {
diff --git a/p2p/base/basicpacketsocketfactory.h b/p2p/base/basicpacketsocketfactory.h
index d4e76e7..27963c9 100644
--- a/p2p/base/basicpacketsocketfactory.h
+++ b/p2p/base/basicpacketsocketfactory.h
@@ -51,6 +51,8 @@
       const SocketAddress& local_address, const SocketAddress& remote_address,
       const ProxyInfo& proxy_info, const std::string& user_agent, int opts);
 
+  virtual AsyncResolverInterface* CreateAsyncResolver();
+
  private:
   int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
                  int min_port, int max_port);
diff --git a/p2p/base/packetsocketfactory.h b/p2p/base/packetsocketfactory.h
index 882a974..e985b37 100644
--- a/p2p/base/packetsocketfactory.h
+++ b/p2p/base/packetsocketfactory.h
@@ -33,6 +33,7 @@
 namespace talk_base {
 
 class AsyncPacketSocket;
+class AsyncResolverInterface;
 
 class PacketSocketFactory {
  public:
@@ -57,6 +58,8 @@
       const SocketAddress& local_address, const SocketAddress& remote_address,
       const ProxyInfo& proxy_info, const std::string& user_agent, int opts) = 0;
 
+  virtual AsyncResolverInterface* CreateAsyncResolver() = 0;
+
  private:
   DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
 };
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 6e688da..7d52386 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -162,11 +162,11 @@
   return talk_base::ToString<uint32>(talk_base::ComputeCrc32(ost.str()));
 }
 
-Port::Port(talk_base::Thread* thread, talk_base::Network* network,
-           const talk_base::IPAddress& ip,
+Port::Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
+           talk_base::Network* network, const talk_base::IPAddress& ip,
            const std::string& username_fragment, const std::string& password)
     : thread_(thread),
-      factory_(NULL),
+      factory_(factory),
       send_retransmit_count_attribute_(false),
       network_(network),
       ip_(ip),
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 7b89e55..ab7fded 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -118,8 +118,8 @@
 class Port : public PortInterface, public talk_base::MessageHandler,
              public sigslot::has_slots<> {
  public:
-  Port(talk_base::Thread* thread, talk_base::Network* network,
-       const talk_base::IPAddress& ip,
+  Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
+       talk_base::Network* network, const talk_base::IPAddress& ip,
        const std::string& username_fragment, const std::string& password);
   Port(talk_base::Thread* thread, const std::string& type,
        talk_base::PacketSocketFactory* factory,
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
index 1cc3049..a527155 100644
--- a/p2p/base/port_unittest.cc
+++ b/p2p/base/port_unittest.cc
@@ -766,6 +766,9 @@
   void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) {
     next_client_tcp_socket_ = next_client_tcp_socket;
   }
+  talk_base::AsyncResolverInterface* CreateAsyncResolver() {
+    return NULL;
+  }
 
  private:
   AsyncPacketSocket* next_udp_socket_;
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index b440bf4..283eade 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -125,10 +125,11 @@
 };
 
 UDPPort::UDPPort(talk_base::Thread* thread,
+                 talk_base::PacketSocketFactory* factory,
                  talk_base::Network* network,
                  talk_base::AsyncPacketSocket* socket,
                  const std::string& username, const std::string& password)
-    : Port(thread, network, socket->GetLocalAddress().ipaddr(),
+    : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
            username, password),
       requests_(thread),
       socket_(socket),
@@ -139,10 +140,10 @@
 }
 
 UDPPort::UDPPort(talk_base::Thread* thread,
-                   talk_base::PacketSocketFactory* factory,
-                   talk_base::Network* network,
-                   const talk_base::IPAddress& ip, int min_port, int max_port,
-                   const std::string& username, const std::string& password)
+                 talk_base::PacketSocketFactory* factory,
+                 talk_base::Network* network,
+                 const talk_base::IPAddress& ip, int min_port, int max_port,
+                 const std::string& username, const std::string& password)
     : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
            username, password),
       requests_(thread),
@@ -302,21 +303,21 @@
   if (resolver_)
     return;
 
-  resolver_ = new talk_base::AsyncResolver();
-  resolver_->SignalWorkDone.connect(this, &UDPPort::OnResolveResult);
-  resolver_->set_address(server_addr_);
-  resolver_->Start();
+  resolver_ = socket_factory()->CreateAsyncResolver();
+  resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
+  resolver_->Start(server_addr_);
 }
 
-void UDPPort::OnResolveResult(talk_base::SignalThread* t) {
-  ASSERT(t == resolver_);
-  if (resolver_->error() != 0) {
+void UDPPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
+  ASSERT(resolver == resolver_);
+  if (resolver_->GetError() != 0 ||
+      !resolver_->GetResolvedAddress(ip().family(), &server_addr_))  {
     LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
-                            << resolver_->error();
+                            << resolver_->GetError();
     OnStunBindingOrResolveRequestFailed();
+    return;
   }
 
-  server_addr_ = resolver_->address();
   SendStunBindingRequest();
 }
 
diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h
index 7cfed4b..8f72556 100644
--- a/p2p/base/stunport.h
+++ b/p2p/base/stunport.h
@@ -46,11 +46,13 @@
 class UDPPort : public Port {
  public:
   static UDPPort* Create(talk_base::Thread* thread,
+                         talk_base::PacketSocketFactory* factory,
                          talk_base::Network* network,
                          talk_base::AsyncPacketSocket* socket,
                          const std::string& username,
                          const std::string& password) {
-    UDPPort* port = new UDPPort(thread, network, socket, username, password);
+    UDPPort* port = new UDPPort(thread, factory, network, socket,
+                                username, password);
     if (!port->Init()) {
       delete port;
       port = NULL;
@@ -66,8 +68,8 @@
                          const std::string& username,
                          const std::string& password) {
     UDPPort* port = new UDPPort(thread, factory, network,
-                                 ip, min_port, max_port,
-                                 username, password);
+                                ip, min_port, max_port,
+                                username, password);
     if (!port->Init()) {
       delete port;
       port = NULL;
@@ -114,8 +116,8 @@
           int min_port, int max_port,
           const std::string& username, const std::string& password);
 
-  UDPPort(talk_base::Thread* thread, talk_base::Network* network,
-          talk_base::AsyncPacketSocket* socket,
+  UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
+          talk_base::Network* network, talk_base::AsyncPacketSocket* socket,
           const std::string& username, const std::string& password);
 
   bool Init();
@@ -141,7 +143,7 @@
  private:
   // DNS resolution of the STUN server.
   void ResolveStunAddress();
-  void OnResolveResult(talk_base::SignalThread* thread);
+  void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
 
   // Below methods handles binding request responses.
   void OnStunBindingRequestSucceeded(const talk_base::SocketAddress& stun_addr);
@@ -158,7 +160,7 @@
   StunRequestManager requests_;
   talk_base::AsyncPacketSocket* socket_;
   int error_;
-  talk_base::AsyncResolver* resolver_;
+  talk_base::AsyncResolverInterface* resolver_;
   bool ready_;
   int stun_keepalive_delay_;
 
diff --git a/p2p/base/stunport_unittest.cc b/p2p/base/stunport_unittest.cc
index 3c1c683..12b32db 100644
--- a/p2p/base/stunport_unittest.cc
+++ b/p2p/base/stunport_unittest.cc
@@ -27,7 +27,10 @@
 
 #include "talk/base/gunit.h"
 #include "talk/base/helpers.h"
+#include "talk/base/physicalsocketserver.h"
+#include "talk/base/scoped_ptr.h"
 #include "talk/base/socketaddress.h"
+#include "talk/base/virtualsocketserver.h"
 #include "talk/p2p/base/basicpacketsocketfactory.h"
 #include "talk/p2p/base/stunport.h"
 #include "talk/p2p/base/teststunserver.h"
@@ -48,7 +51,10 @@
                      public sigslot::has_slots<> {
  public:
   StunPortTest()
-      : network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
+      : pss_(new talk_base::PhysicalSocketServer),
+        ss_(new talk_base::VirtualSocketServer(pss_.get())),
+        ss_scope_(ss_.get()),
+        network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
         socket_factory_(talk_base::Thread::Current()),
         stun_server_(new cricket::TestStunServer(
           talk_base::Thread::Current(), kStunAddr)),
@@ -77,7 +83,8 @@
     ASSERT_TRUE(socket_ != NULL);
     socket_->SignalReadPacket.connect(this, &StunPortTest::OnReadPacket);
     stun_port_.reset(cricket::UDPPort::Create(
-        talk_base::Thread::Current(), &network_, socket_.get(),
+        talk_base::Thread::Current(), &socket_factory_,
+        &network_, socket_.get(),
         talk_base::CreateRandomString(16), talk_base::CreateRandomString(22)));
     ASSERT_TRUE(stun_port_ != NULL);
     stun_port_->set_server_addr(server_addr);
@@ -120,6 +127,9 @@
   }
 
  private:
+  talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
+  talk_base::scoped_ptr<talk_base::VirtualSocketServer> ss_;
+  talk_base::SocketServerScope ss_scope_;
   talk_base::Network network_;
   talk_base::BasicPacketSocketFactory socket_factory_;
   talk_base::scoped_ptr<cricket::UDPPort> stun_port_;
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index 880af83..14388e3 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -399,22 +399,21 @@
   if (resolver_)
     return;
 
-  resolver_ = new talk_base::AsyncResolver();
-  resolver_->SignalWorkDone.connect(this, &TurnPort::OnResolveResult);
-  resolver_->set_address(address);
-  resolver_->Start();
+  resolver_ = socket_factory()->CreateAsyncResolver();
+  resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
+  resolver_->Start(address);
 }
 
-void TurnPort::OnResolveResult(talk_base::SignalThread* signal_thread) {
-  ASSERT(signal_thread == resolver_);
-  if (resolver_->error() != 0) {
+void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
+  ASSERT(resolver == resolver_);
+  if (resolver_->GetError() != 0 ||
+      !resolver_->GetResolvedAddress(ip().family(), &server_address_.address)) {
     LOG_J(LS_WARNING, this) << "TURN host lookup received error "
-                            << resolver_->error();
+                            << resolver_->GetError();
     OnAllocateError();
     return;
   }
 
-  server_address_.address = resolver_->address();
   PrepareAddress();
 }
 
diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h
index 4462b0c..e5c03da 100644
--- a/p2p/base/turnport.h
+++ b/p2p/base/turnport.h
@@ -123,7 +123,7 @@
   }
 
   void ResolveTurnAddress(const talk_base::SocketAddress& address);
-  void OnResolveResult(talk_base::SignalThread* signal_thread);
+  void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
 
   void AddRequestAuthInfo(StunMessage* msg);
   void OnSendStunPacket(const void* data, size_t size, StunRequest* request);
@@ -157,7 +157,7 @@
 
   talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
   SocketOptionsMap socket_options_;
-  talk_base::AsyncResolver* resolver_;
+  talk_base::AsyncResolverInterface* resolver_;
   int error_;
 
   StunRequestManager request_manager_;
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
index 9f10d33..a5310b7 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -857,7 +857,8 @@
   // is enabled completely.
   UDPPort* port = NULL;
   if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
-    port = UDPPort::Create(session_->network_thread(), network_,
+    port = UDPPort::Create(session_->network_thread(),
+                           session_->socket_factory(), network_,
                            udp_socket_.get(),
                            session_->username(), session_->password());
   } else {