Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / base / turnport.cc
index eeaa3af..2908d71 100644 (file)
 
 #include <functional>
 
-#include "talk/base/asyncpacketsocket.h"
-#include "talk/base/byteorder.h"
-#include "talk/base/common.h"
-#include "talk/base/logging.h"
-#include "talk/base/nethelpers.h"
-#include "talk/base/socketaddress.h"
-#include "talk/base/stringencode.h"
 #include "talk/p2p/base/common.h"
 #include "talk/p2p/base/stun.h"
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/socketaddress.h"
+#include "webrtc/base/stringencode.h"
 
 namespace cricket {
 
@@ -51,6 +51,10 @@ static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000;  // 5 minutes
 
 static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
 
+// Retry at most twice (i.e. three different ALLOCATE requests) on
+// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
+static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
+
 inline bool IsTurnChannelData(uint16 msg_type) {
   return ((msg_type & 0xC000) == 0x4000);  // MSB are 0b01
 }
@@ -78,6 +82,7 @@ class TurnAllocateRequest : public StunRequest {
  private:
   // Handles authentication challenge from the server.
   void OnAuthChallenge(StunMessage* response, int code);
+  void OnTryAlternate(StunMessage* response, int code);
   void OnUnknownAttribute(StunMessage* response);
 
   TurnPort* port_;
@@ -99,7 +104,7 @@ class TurnCreatePermissionRequest : public StunRequest,
                                     public sigslot::has_slots<> {
  public:
   TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry,
-                              const talk_base::SocketAddress& ext_addr);
+                              const rtc::SocketAddress& ext_addr);
   virtual void Prepare(StunMessage* request);
   virtual void OnResponse(StunMessage* response);
   virtual void OnErrorResponse(StunMessage* response);
@@ -110,14 +115,14 @@ class TurnCreatePermissionRequest : public StunRequest,
 
   TurnPort* port_;
   TurnEntry* entry_;
-  talk_base::SocketAddress ext_addr_;
+  rtc::SocketAddress ext_addr_;
 };
 
 class TurnChannelBindRequest : public StunRequest,
                                public sigslot::has_slots<> {
  public:
   TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id,
-                         const talk_base::SocketAddress& ext_addr);
+                         const rtc::SocketAddress& ext_addr);
   virtual void Prepare(StunMessage* request);
   virtual void OnResponse(StunMessage* response);
   virtual void OnErrorResponse(StunMessage* response);
@@ -129,7 +134,7 @@ class TurnChannelBindRequest : public StunRequest,
   TurnPort* port_;
   TurnEntry* entry_;
   int channel_id_;
-  talk_base::SocketAddress ext_addr_;
+  rtc::SocketAddress ext_addr_;
 };
 
 // Manages a "connection" to a remote destination. We will attempt to bring up
@@ -138,12 +143,12 @@ class TurnEntry : public sigslot::has_slots<> {
  public:
   enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND };
   TurnEntry(TurnPort* port, int channel_id,
-            const talk_base::SocketAddress& ext_addr);
+            const rtc::SocketAddress& ext_addr);
 
   TurnPort* port() { return port_; }
 
   int channel_id() const { return channel_id_; }
-  const talk_base::SocketAddress& address() const { return ext_addr_; }
+  const rtc::SocketAddress& address() const { return ext_addr_; }
   BindState state() const { return state_; }
 
   // Helper methods to send permission and channel bind requests.
@@ -152,7 +157,7 @@ class TurnEntry : public sigslot::has_slots<> {
   // Sends a packet to the given destination address.
   // This will wrap the packet in STUN if necessary.
   int Send(const void* data, size_t size, bool payload,
-           const talk_base::PacketOptions& options);
+           const rtc::PacketOptions& options);
 
   void OnCreatePermissionSuccess();
   void OnCreatePermissionError(StunMessage* response, int code);
@@ -164,28 +169,56 @@ class TurnEntry : public sigslot::has_slots<> {
  private:
   TurnPort* port_;
   int channel_id_;
-  talk_base::SocketAddress ext_addr_;
+  rtc::SocketAddress ext_addr_;
   BindState state_;
 };
 
-TurnPort::TurnPort(talk_base::Thread* thread,
-                   talk_base::PacketSocketFactory* factory,
-                   talk_base::Network* network,
-                   const talk_base::IPAddress& ip,
+TurnPort::TurnPort(rtc::Thread* thread,
+                   rtc::PacketSocketFactory* factory,
+                   rtc::Network* network,
+                   rtc::AsyncPacketSocket* socket,
+                   const std::string& username,
+                   const std::string& password,
+                   const ProtocolAddress& server_address,
+                   const RelayCredentials& credentials,
+                   int server_priority)
+    : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
+           username, password),
+      server_address_(server_address),
+      credentials_(credentials),
+      socket_(socket),
+      resolver_(NULL),
+      error_(0),
+      request_manager_(thread),
+      next_channel_number_(TURN_CHANNEL_NUMBER_START),
+      connected_(false),
+      server_priority_(server_priority),
+      allocate_mismatch_retries_(0) {
+  request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
+}
+
+TurnPort::TurnPort(rtc::Thread* thread,
+                   rtc::PacketSocketFactory* factory,
+                   rtc::Network* network,
+                   const rtc::IPAddress& ip,
                    int min_port, int max_port,
                    const std::string& username,
                    const std::string& password,
                    const ProtocolAddress& server_address,
-                   const RelayCredentials& credentials)
+                   const RelayCredentials& credentials,
+                   int server_priority)
     : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port,
            username, password),
       server_address_(server_address),
       credentials_(credentials),
+      socket_(NULL),
       resolver_(NULL),
       error_(0),
       request_manager_(thread),
       next_channel_number_(TURN_CHANNEL_NUMBER_START),
-      connected_(false) {
+      connected_(false),
+      server_priority_(server_priority),
+      allocate_mismatch_retries_(0) {
   request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
 }
 
@@ -197,6 +230,9 @@ TurnPort::~TurnPort() {
   if (resolver_) {
     resolver_->Destroy(false);
   }
+  if (!SharedSocket()) {
+    delete socket_;
+  }
 }
 
 void TurnPort::PrepareAddress() {
@@ -224,62 +260,117 @@ void TurnPort::PrepareAddress() {
       return;
     }
 
+    // Insert the current address to prevent redirection pingpong.
+    attempted_server_addresses_.insert(server_address_.address);
+
     LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
                          << ProtoToString(server_address_.proto) << " @ "
                          << server_address_.address.ToSensitiveString();
-    if (server_address_.proto == PROTO_UDP) {
-      socket_.reset(socket_factory()->CreateUdpSocket(
-          talk_base::SocketAddress(ip(), 0), min_port(), max_port()));
-    } else if (server_address_.proto == PROTO_TCP) {
-      int opts = talk_base::PacketSocketFactory::OPT_STUN;
-      // If secure bit is enabled in server address, use TLS over TCP.
-      if (server_address_.secure) {
-        opts |= talk_base::PacketSocketFactory::OPT_TLS;
-      }
-
-      socket_.reset(socket_factory()->CreateClientTcpSocket(
-          talk_base::SocketAddress(ip(), 0), server_address_.address,
-          proxy(), user_agent(), opts));
-    }
-
-    if (!socket_) {
+    if (!CreateTurnClientSocket()) {
       OnAllocateError();
-      return;
+    } else if (server_address_.proto == PROTO_UDP) {
+      // If its UDP, send AllocateRequest now.
+      // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
+      SendRequest(new TurnAllocateRequest(this), 0);
     }
+  }
+}
+
+bool TurnPort::CreateTurnClientSocket() {
+  ASSERT(!socket_ || SharedSocket());
 
-    // Apply options if any.
-    for (SocketOptionsMap::iterator iter = socket_options_.begin();
-         iter != socket_options_.end(); ++iter) {
-      socket_->SetOption(iter->first, iter->second);
+  if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
+    socket_ = socket_factory()->CreateUdpSocket(
+        rtc::SocketAddress(ip(), 0), min_port(), max_port());
+  } else if (server_address_.proto == PROTO_TCP) {
+    ASSERT(!SharedSocket());
+    int opts = rtc::PacketSocketFactory::OPT_STUN;
+    // If secure bit is enabled in server address, use TLS over TCP.
+    if (server_address_.secure) {
+      opts |= rtc::PacketSocketFactory::OPT_TLS;
     }
+    socket_ = socket_factory()->CreateClientTcpSocket(
+        rtc::SocketAddress(ip(), 0), server_address_.address,
+        proxy(), user_agent(), opts);
+  }
 
+  if (!socket_) {
+    error_ = SOCKET_ERROR;
+    return false;
+  }
+
+  // Apply options if any.
+  for (SocketOptionsMap::iterator iter = socket_options_.begin();
+       iter != socket_options_.end(); ++iter) {
+    socket_->SetOption(iter->first, iter->second);
+  }
+
+  if (!SharedSocket()) {
+    // If socket is shared, AllocationSequence will receive the packet.
     socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
-    socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
+  }
 
-    if (server_address_.proto == PROTO_TCP) {
-      socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
-      socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
-    } else {
-      // If its UDP, send AllocateRequest now.
-      // For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
-      SendRequest(new TurnAllocateRequest(this), 0);
-    }
+  socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
+
+  if (server_address_.proto == PROTO_TCP) {
+    socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
+    socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
   }
+  return true;
 }
 
-void TurnPort::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
+void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
+  ASSERT(server_address_.proto == PROTO_TCP);
+  // Do not use this port if the socket bound to a different address than
+  // the one we asked for. This is seen in Chrome, where TCP sockets cannot be
+  // given a binding address, and the platform is expected to pick the
+  // correct local address.
+  if (socket->GetLocalAddress().ipaddr() != ip()) {
+    LOG(LS_WARNING) << "Socket is bound to a different address then the "
+                    << "local port. Discarding TURN port.";
+    OnAllocateError();
+    return;
+  }
+
+  if (server_address_.address.IsUnresolved()) {
+    server_address_.address = socket_->GetRemoteAddress();
+  }
+
   LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress()
                << " using tcp.";
   SendRequest(new TurnAllocateRequest(this), 0);
 }
 
-void TurnPort::OnSocketClose(talk_base::AsyncPacketSocket* socket, int error) {
+void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
   LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
   if (!connected_) {
     OnAllocateError();
   }
 }
 
+void TurnPort::OnAllocateMismatch() {
+  if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) {
+    LOG_J(LS_WARNING, this) << "Giving up on the port after "
+                            << allocate_mismatch_retries_
+                            << " retries for STUN_ERROR_ALLOCATION_MISMATCH";
+    OnAllocateError();
+    return;
+  }
+
+  LOG_J(LS_INFO, this) << "Allocating a new socket after "
+                       << "STUN_ERROR_ALLOCATION_MISMATCH, retry = "
+                       << allocate_mismatch_retries_ + 1;
+  if (SharedSocket()) {
+    ResetSharedSocket();
+  } else {
+    delete socket_;
+  }
+  socket_ = NULL;
+
+  PrepareAddress();
+  ++allocate_mismatch_retries_;
+}
+
 Connection* TurnPort::CreateConnection(const Candidate& address,
                                        CandidateOrigin origin) {
   // TURN-UDP can only connect to UDP candidates.
@@ -294,15 +385,21 @@ Connection* TurnPort::CreateConnection(const Candidate& address,
   // Create an entry, if needed, so we can get our permissions set up correctly.
   CreateEntry(address.address());
 
-  // TODO(juberti): The '0' index will need to change if we start gathering STUN
-  // candidates on this port.
-  ProxyConnection* conn = new ProxyConnection(this, 0, address);
-  conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
-  AddConnection(conn);
-  return conn;
+  // A TURN port will have two candiates, STUN and TURN. STUN may not
+  // present in all cases. If present stun candidate will be added first
+  // and TURN candidate later.
+  for (size_t index = 0; index < Candidates().size(); ++index) {
+    if (Candidates()[index].type() == RELAY_PORT_TYPE) {
+      ProxyConnection* conn = new ProxyConnection(this, index, address);
+      conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
+      AddConnection(conn);
+      return conn;
+    }
+  }
+  return NULL;
 }
 
-int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
+int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
   if (!socket_) {
     // If socket is not created yet, these options will be applied during socket
     // creation.
@@ -312,7 +409,7 @@ int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
   return socket_->SetOption(opt, value);
 }
 
-int TurnPort::GetOption(talk_base::Socket::Option opt, int* value) {
+int TurnPort::GetOption(rtc::Socket::Option opt, int* value) {
   if (!socket_) {
     SocketOptionsMap::const_iterator it = socket_options_.find(opt);
     if (it == socket_options_.end()) {
@@ -330,8 +427,8 @@ int TurnPort::GetError() {
 }
 
 int TurnPort::SendTo(const void* data, size_t size,
-                     const talk_base::SocketAddress& addr,
-                     const talk_base::PacketOptions& options,
+                     const rtc::SocketAddress& addr,
+                     const rtc::PacketOptions& options,
                      bool payload) {
   // Try to find an entry for this specific address; we should have one.
   TurnEntry* entry = FindEntry(addr);
@@ -357,10 +454,10 @@ int TurnPort::SendTo(const void* data, size_t size,
 }
 
 void TurnPort::OnReadPacket(
-    talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
-    const talk_base::SocketAddress& remote_addr,
-    const talk_base::PacketTime& packet_time) {
-  ASSERT(socket == socket_.get());
+    rtc::AsyncPacketSocket* socket, const char* data, size_t size,
+    const rtc::SocketAddress& remote_addr,
+    const rtc::PacketTime& packet_time) {
+  ASSERT(socket == socket_);
   ASSERT(remote_addr == server_address_.address);
 
   // The message must be at least the size of a channel header.
@@ -372,7 +469,7 @@ void TurnPort::OnReadPacket(
   // Check the message type, to see if is a Channel Data message.
   // The message will either be channel data, a TURN data indication, or
   // a response to a previous request.
-  uint16 msg_type = talk_base::GetBE16(data);
+  uint16 msg_type = rtc::GetBE16(data);
   if (IsTurnChannelData(msg_type)) {
     HandleChannelData(msg_type, data, size, packet_time);
   } else if (msg_type == TURN_DATA_INDICATION) {
@@ -390,13 +487,45 @@ void TurnPort::OnReadPacket(
   }
 }
 
-void TurnPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
+void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
   if (connected_) {
     Port::OnReadyToSend();
   }
 }
 
-void TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) {
+
+// Update current server address port with the alternate server address port.
+bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) {
+  // Check if we have seen this address before and reject if we did.
+  AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address);
+  if (iter != attempted_server_addresses_.end()) {
+    LOG_J(LS_WARNING, this) << "Redirection to ["
+                            << address.ToSensitiveString()
+                            << "] ignored, allocation failed.";
+    return false;
+  }
+
+  // If protocol family of server address doesn't match with local, return.
+  if (!IsCompatibleAddress(address)) {
+    LOG(LS_WARNING) << "Server IP address family does not match with "
+                    << "local host address family type";
+    return false;
+  }
+
+  LOG_J(LS_INFO, this) << "Redirecting from TURN server ["
+                       << server_address_.address.ToSensitiveString()
+                       << "] to TURN server ["
+                       << address.ToSensitiveString()
+                       << "]";
+  server_address_ = ProtocolAddress(address, server_address_.proto,
+                                    server_address_.secure);
+
+  // Insert the current address to prevent redirection pingpong.
+  attempted_server_addresses_.insert(server_address_.address);
+  return true;
+}
+
+void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) {
   if (resolver_)
     return;
 
@@ -405,40 +534,69 @@ void TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) {
   resolver_->Start(address);
 }
 
-void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
+void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) {
   ASSERT(resolver == resolver_);
+  // If DNS resolve is failed when trying to connect to the server using TCP,
+  // one of the reason could be due to DNS queries blocked by firewall.
+  // In such cases we will try to connect to the server with hostname, assuming
+  // socket layer will resolve the hostname through a HTTP proxy (if any).
+  if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) {
+    if (!CreateTurnClientSocket()) {
+      OnAllocateError();
+    }
+    return;
+  }
+
+  // Copy the original server address in |resolved_address|. For TLS based
+  // sockets we need hostname along with resolved address.
+  rtc::SocketAddress resolved_address = server_address_.address;
   if (resolver_->GetError() != 0 ||
-      !resolver_->GetResolvedAddress(ip().family(), &server_address_.address)) {
+      !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) {
     LOG_J(LS_WARNING, this) << "TURN host lookup received error "
                             << resolver_->GetError();
+    error_ = resolver_->GetError();
     OnAllocateError();
     return;
   }
-
+  // Signal needs both resolved and unresolved address. After signal is sent
+  // we can copy resolved address back into |server_address_|.
+  SignalResolvedServerAddress(this, server_address_.address,
+                              resolved_address);
+  server_address_.address = resolved_address;
   PrepareAddress();
 }
 
 void TurnPort::OnSendStunPacket(const void* data, size_t size,
                                 StunRequest* request) {
-  talk_base::PacketOptions options(DefaultDscpValue());
+  rtc::PacketOptions options(DefaultDscpValue());
   if (Send(data, size, options) < 0) {
     LOG_J(LS_ERROR, this) << "Failed to send TURN message, err="
                           << socket_->GetError();
   }
 }
 
-void TurnPort::OnStunAddress(const talk_base::SocketAddress& address) {
-  // For relay, mapped address is rel-addr.
-  set_related_address(address);
+void TurnPort::OnStunAddress(const rtc::SocketAddress& address) {
+  // STUN Port will discover STUN candidate, as it's supplied with first TURN
+  // server address.
+  // Why not using this address? - P2PTransportChannel will start creating
+  // connections after first candidate, which means it could start creating the
+  // connections before TURN candidate added. For that to handle, we need to
+  // supply STUN candidate from this port to UDPPort, and TurnPort should have
+  // handle to UDPPort to pass back the address.
 }
 
-void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address) {
+void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,
+                                 const rtc::SocketAddress& stun_address) {
   connected_ = true;
-  AddAddress(address,
-             socket_->GetLocalAddress(),
-             "udp",
+  // For relayed candidate, Base is the candidate itself.
+  AddAddress(address,  // Candidate address.
+             address,  // Base address.
+             stun_address,  // Related address.
+             UDP_PROTOCOL_NAME,
+             "",  // TCP canddiate type, empty for turn candidates.
              RELAY_PORT_TYPE,
              GetRelayPreference(server_address_.proto, server_address_.secure),
+             server_priority_,
              true);
 }
 
@@ -449,10 +607,13 @@ void TurnPort::OnAllocateError() {
   thread()->Post(this, MSG_ERROR);
 }
 
-void TurnPort::OnMessage(talk_base::Message* message) {
+void TurnPort::OnMessage(rtc::Message* message) {
   if (message->message_id == MSG_ERROR) {
     SignalPortError(this);
     return;
+  } else if (message->message_id == MSG_ALLOCATE_MISMATCH) {
+    OnAllocateMismatch();
+    return;
   }
 
   Port::OnMessage(message);
@@ -463,9 +624,9 @@ void TurnPort::OnAllocateRequestTimeout() {
 }
 
 void TurnPort::HandleDataIndication(const char* data, size_t size,
-                                    const talk_base::PacketTime& packet_time) {
+                                    const rtc::PacketTime& packet_time) {
   // Read in the message, and process according to RFC5766, Section 10.4.
-  talk_base::ByteBuffer buf(data, size);
+  rtc::ByteBuffer buf(data, size);
   TurnMessage msg;
   if (!msg.Read(&buf)) {
     LOG_J(LS_WARNING, this) << "Received invalid TURN data indication";
@@ -490,7 +651,7 @@ void TurnPort::HandleDataIndication(const char* data, size_t size,
   }
 
   // Verify that the data came from somewhere we think we have a permission for.
-  talk_base::SocketAddress ext_addr(addr_attr->GetAddress());
+  rtc::SocketAddress ext_addr(addr_attr->GetAddress());
   if (!HasPermission(ext_addr.ipaddr())) {
     LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid "
                             << "peer address, addr="
@@ -504,7 +665,7 @@ void TurnPort::HandleDataIndication(const char* data, size_t size,
 
 void TurnPort::HandleChannelData(int channel_id, const char* data,
                                  size_t size,
-                                 const talk_base::PacketTime& packet_time) {
+                                 const rtc::PacketTime& packet_time) {
   // Read the message, and process according to RFC5766, Section 11.6.
   //    0                   1                   2                   3
   //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -520,7 +681,7 @@ void TurnPort::HandleChannelData(int channel_id, const char* data,
   //   +-------------------------------+
 
   // Extract header fields from the message.
-  uint16 len = talk_base::GetBE16(data + 2);
+  uint16 len = rtc::GetBE16(data + 2);
   if (len > size - TURN_CHANNEL_HEADER_SIZE) {
     LOG_J(LS_WARNING, this) << "Received TURN channel data message with "
                             << "incorrect length, len=" << len;
@@ -540,8 +701,8 @@ void TurnPort::HandleChannelData(int channel_id, const char* data,
 }
 
 void TurnPort::DispatchPacket(const char* data, size_t size,
-    const talk_base::SocketAddress& remote_addr,
-    ProtocolType proto, const talk_base::PacketTime& packet_time) {
+    const rtc::SocketAddress& remote_addr,
+    ProtocolType proto, const rtc::PacketTime& packet_time) {
   if (Connection* conn = GetConnection(remote_addr)) {
     conn->OnReadPacket(data, size, packet_time);
   } else {
@@ -578,7 +739,7 @@ void TurnPort::AddRequestAuthInfo(StunMessage* msg) {
 }
 
 int TurnPort::Send(const void* data, size_t len,
-                   const talk_base::PacketOptions& options) {
+                   const rtc::PacketOptions& options) {
   return socket_->SendTo(data, len, server_address_.address, options);
 }
 
@@ -611,18 +772,18 @@ bool TurnPort::UpdateNonce(StunMessage* response) {
   return true;
 }
 
-static bool MatchesIP(TurnEntry* e, talk_base::IPAddress ipaddr) {
+static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) {
   return e->address().ipaddr() == ipaddr;
 }
-bool TurnPort::HasPermission(const talk_base::IPAddress& ipaddr) const {
+bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const {
   return (std::find_if(entries_.begin(), entries_.end(),
       std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end());
 }
 
-static bool MatchesAddress(TurnEntry* e, talk_base::SocketAddress addr) {
+static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) {
   return e->address() == addr;
 }
-TurnEntry* TurnPort::FindEntry(const talk_base::SocketAddress& addr) const {
+TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const {
   EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(),
       std::bind2nd(std::ptr_fun(MatchesAddress), addr));
   return (it != entries_.end()) ? *it : NULL;
@@ -637,14 +798,14 @@ TurnEntry* TurnPort::FindEntry(int channel_id) const {
   return (it != entries_.end()) ? *it : NULL;
 }
 
-TurnEntry* TurnPort::CreateEntry(const talk_base::SocketAddress& addr) {
+TurnEntry* TurnPort::CreateEntry(const rtc::SocketAddress& addr) {
   ASSERT(FindEntry(addr) == NULL);
   TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr);
   entries_.push_back(entry);
   return entry;
 }
 
-void TurnPort::DestroyEntry(const talk_base::SocketAddress& addr) {
+void TurnPort::DestroyEntry(const rtc::SocketAddress& addr) {
   TurnEntry* entry = FindEntry(addr);
   ASSERT(entry != NULL);
   entry->SignalDestroyed(entry);
@@ -683,8 +844,7 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
                              << "attribute in allocate success response";
     return;
   }
-
-  // TODO(mallinath) - Use mapped address for STUN candidate.
+  // Using XOR-Mapped-Address for stun.
   port_->OnStunAddress(mapped_attr->GetAddress());
 
   const StunAddressAttribute* relayed_attr =
@@ -703,7 +863,8 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
     return;
   }
   // Notify the port the allocate succeeded, and schedule a refresh request.
-  port_->OnAllocateSuccess(relayed_attr->GetAddress());
+  port_->OnAllocateSuccess(relayed_attr->GetAddress(),
+                           mapped_attr->GetAddress());
   port_->ScheduleRefresh(lifetime_attr->value());
 }
 
@@ -714,6 +875,14 @@ void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
     case STUN_ERROR_UNAUTHORIZED:       // Unauthrorized.
       OnAuthChallenge(response, error_code->code());
       break;
+    case STUN_ERROR_TRY_ALTERNATE:
+      OnTryAlternate(response, error_code->code());
+      break;
+    case STUN_ERROR_ALLOCATION_MISMATCH:
+      // We must handle this error async because trying to delete the socket in
+      // OnErrorResponse will cause a deadlock on the socket.
+      port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH);
+      break;
     default:
       LOG_J(LS_WARNING, port_) << "Allocate response error, code="
                                << error_code->code();
@@ -758,6 +927,57 @@ void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
   port_->SendRequest(new TurnAllocateRequest(port_), 0);
 }
 
+void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
+  // TODO(guoweis): Currently, we only support UDP redirect
+  if (port_->server_address().proto != PROTO_UDP) {
+    LOG_J(LS_WARNING, port_) << "Receiving 300 Alternate Server on non-UDP "
+                         << "allocating request from ["
+                         << port_->server_address().address.ToSensitiveString()
+                         << "], failed as currently not supported";
+    port_->OnAllocateError();
+    return;
+  }
+
+  // According to RFC 5389 section 11, there are use cases where
+  // authentication of response is not possible, we're not validating
+  // message integrity.
+
+  // Get the alternate server address attribute value.
+  const StunAddressAttribute* alternate_server_attr =
+      response->GetAddress(STUN_ATTR_ALTERNATE_SERVER);
+  if (!alternate_server_attr) {
+    LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER "
+                             << "attribute in try alternate error response";
+    port_->OnAllocateError();
+    return;
+  }
+  if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) {
+    port_->OnAllocateError();
+    return;
+  }
+
+  // Check the attributes.
+  const StunByteStringAttribute* realm_attr =
+      response->GetByteString(STUN_ATTR_REALM);
+  if (realm_attr) {
+    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in "
+                          << "try alternate error response.";
+    port_->set_realm(realm_attr->GetString());
+  }
+
+  const StunByteStringAttribute* nonce_attr =
+      response->GetByteString(STUN_ATTR_NONCE);
+  if (nonce_attr) {
+    LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in "
+                          << "try alternate error response.";
+    port_->set_nonce(nonce_attr->GetString());
+  }
+
+  // Send another allocate request to alternate server,
+  // with the received realm and nonce values.
+  port_->SendRequest(new TurnAllocateRequest(port_), 0);
+}
+
 TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
     : StunRequest(new TurnMessage()),
       port_(port) {
@@ -785,7 +1005,6 @@ void TurnRefreshRequest::OnResponse(StunMessage* response) {
 }
 
 void TurnRefreshRequest::OnErrorResponse(StunMessage* response) {
-  // TODO(juberti): Handle 437 error response as a success.
   const StunErrorCodeAttribute* error_code = response->GetErrorCode();
   LOG_J(LS_WARNING, port_) << "Refresh response error, code="
                            << error_code->code();
@@ -803,7 +1022,7 @@ void TurnRefreshRequest::OnTimeout() {
 
 TurnCreatePermissionRequest::TurnCreatePermissionRequest(
     TurnPort* port, TurnEntry* entry,
-    const talk_base::SocketAddress& ext_addr)
+    const rtc::SocketAddress& ext_addr)
     : StunRequest(new TurnMessage()),
       port_(port),
       entry_(entry),
@@ -844,7 +1063,7 @@ void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) {
 
 TurnChannelBindRequest::TurnChannelBindRequest(
     TurnPort* port, TurnEntry* entry,
-    int channel_id, const talk_base::SocketAddress& ext_addr)
+    int channel_id, const rtc::SocketAddress& ext_addr)
     : StunRequest(new TurnMessage()),
       port_(port),
       entry_(entry),
@@ -892,7 +1111,7 @@ void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) {
 }
 
 TurnEntry::TurnEntry(TurnPort* port, int channel_id,
-                     const talk_base::SocketAddress& ext_addr)
+                     const rtc::SocketAddress& ext_addr)
     : port_(port),
       channel_id_(channel_id),
       ext_addr_(ext_addr),
@@ -912,14 +1131,14 @@ void TurnEntry::SendChannelBindRequest(int delay) {
 }
 
 int TurnEntry::Send(const void* data, size_t size, bool payload,
-                    const talk_base::PacketOptions& options) {
-  talk_base::ByteBuffer buf;
+                    const rtc::PacketOptions& options) {
+  rtc::ByteBuffer buf;
   if (state_ != STATE_BOUND) {
     // If we haven't bound the channel yet, we have to use a Send Indication.
     TurnMessage msg;
     msg.SetType(TURN_SEND_INDICATION);
     msg.SetTransactionID(
-        talk_base::CreateRandomString(kStunTransactionIdLength));
+        rtc::CreateRandomString(kStunTransactionIdLength));
     VERIFY(msg.AddAttribute(new StunXorAddressAttribute(
         STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)));
     VERIFY(msg.AddAttribute(new StunByteStringAttribute(