diff options
Diffstat (limited to 'webrtc/p2p/base/stunport.cc')
-rw-r--r-- | webrtc/p2p/base/stunport.cc | 119 |
1 files changed, 74 insertions, 45 deletions
diff --git a/webrtc/p2p/base/stunport.cc b/webrtc/p2p/base/stunport.cc index 1598fe43ce..8f37dd5218 100644 --- a/webrtc/p2p/base/stunport.cc +++ b/webrtc/p2p/base/stunport.cc @@ -13,6 +13,7 @@ #include "webrtc/p2p/base/common.h" #include "webrtc/p2p/base/portallocator.h" #include "webrtc/p2p/base/stun.h" +#include "webrtc/base/checks.h" #include "webrtc/base/common.h" #include "webrtc/base/helpers.h" #include "webrtc/base/ipaddress.h" @@ -23,15 +24,19 @@ namespace cricket { // TODO: Move these to a common place (used in relayport too) const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts -const int RETRY_DELAY = 50; // 50ms, from ICE spec const int RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs +// Stop sending STUN binding requests after this amount of time +// (in milliseconds) because the connection binding requests should keep +// the NAT binding alive. +const int KEEP_ALIVE_TIMEOUT = 2 * 60 * 1000; // 2 minutes // Handles a binding request sent to the STUN server. class StunBindingRequest : public StunRequest { public: - StunBindingRequest(UDPPort* port, bool keep_alive, - const rtc::SocketAddress& addr) - : port_(port), keep_alive_(keep_alive), server_addr_(addr) { + StunBindingRequest(UDPPort* port, + const rtc::SocketAddress& addr, + uint32_t deadline) + : port_(port), server_addr_(addr), deadline_(deadline) { start_time_ = rtc::Time(); } @@ -58,10 +63,10 @@ class StunBindingRequest : public StunRequest { } // We will do a keep-alive regardless of whether this request succeeds. - // This should have almost no impact on network usage. - if (keep_alive_) { + // It will be stopped after |deadline_| mostly to conserve the battery life. + if (rtc::Time() <= deadline_) { port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), + new StunBindingRequest(port_, server_addr_, deadline_), port_->stun_keepalive_delay()); } } @@ -79,10 +84,10 @@ class StunBindingRequest : public StunRequest { port_->OnStunBindingOrResolveRequestFailed(server_addr_); - if (keep_alive_ - && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { + uint32_t now = rtc::Time(); + if (now <= deadline_ && rtc::TimeDiff(now, start_time_) <= RETRY_TIMEOUT) { port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), + new StunBindingRequest(port_, server_addr_, deadline_), port_->stun_keepalive_delay()); } } @@ -93,20 +98,13 @@ class StunBindingRequest : public StunRequest { << " (" << port_->Network()->name() << ")"; port_->OnStunBindingOrResolveRequestFailed(server_addr_); - - if (keep_alive_ - && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { - port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), - RETRY_DELAY); - } } private: UDPPort* port_; - bool keep_alive_; const rtc::SocketAddress server_addr_; uint32_t start_time_; + uint32_t deadline_; }; UDPPort::AddressResolver::AddressResolver( @@ -116,7 +114,10 @@ UDPPort::AddressResolver::AddressResolver( UDPPort::AddressResolver::~AddressResolver() { for (ResolverMap::iterator it = resolvers_.begin(); it != resolvers_.end(); ++it) { - it->second->Destroy(true); + // TODO(guoweis): Change to asynchronous DNS resolution to prevent the hang + // when passing true to the Destroy() which is a safer way to avoid the code + // unloaded before the thread exits. Please see webrtc bug 5139. + it->second->Destroy(false); } } @@ -166,15 +167,19 @@ UDPPort::UDPPort(rtc::Thread* thread, const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) - : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), - username, password), + bool emit_local_for_anyaddress) + : Port(thread, + factory, + network, + socket->GetLocalAddress().ipaddr(), + username, + password), requests_(thread), socket_(socket), error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY), - emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) { + emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -187,7 +192,7 @@ UDPPort::UDPPort(rtc::Thread* thread, const std::string& username, const std::string& password, const std::string& origin, - bool emit_localhost_for_anyaddress) + bool emit_local_for_anyaddress) : Port(thread, LOCAL_PORT_TYPE, factory, @@ -202,7 +207,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY), - emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) { + emit_local_for_anyaddress_(emit_local_for_anyaddress) { requests_.set_origin(origin); } @@ -248,9 +253,10 @@ void UDPPort::MaybePrepareStunCandidate() { } Connection* UDPPort::CreateConnection(const Candidate& address, - CandidateOrigin origin) { - if (address.protocol() != "udp") + CandidateOrigin origin) { + if (!SupportsProtocol(address.protocol())) { return NULL; + } if (!IsCompatibleAddress(address.address())) { return NULL; @@ -294,25 +300,27 @@ int UDPPort::GetError() { void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& address) { // When adapter enumeration is disabled and binding to the any address, the - // loopback address will be issued as a candidate instead if - // |emit_localhost_for_anyaddress| is true. This is to allow connectivity on - // demo pages without STUN/TURN to work. + // default local address will be issued as a candidate instead if + // |emit_local_for_anyaddress| is true. This is to allow connectivity for + // applications which absolutely requires a HOST candidate. rtc::SocketAddress addr = address; - if (addr.IsAnyIP() && emit_localhost_for_anyaddress_) { - addr.SetIP(rtc::GetLoopbackIP(addr.family())); - } + + // If MaybeSetDefaultLocalAddress fails, we keep the "any" IP so that at + // least the port is listening. + MaybeSetDefaultLocalAddress(&addr); AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "", LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false); MaybePrepareStunCandidate(); } -void UDPPort::OnReadPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { +void UDPPort::OnReadPacket(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.IsUnresolved()); + ASSERT(!remote_addr.IsUnresolvedIP()); // Look for a response from the STUN server. // Even if the response doesn't match one of our outstanding requests, we @@ -332,7 +340,7 @@ void UDPPort::OnReadPacket( void UDPPort::OnSentPacket(rtc::AsyncPacketSocket* socket, const rtc::SentPacket& sent_packet) { - Port::OnSentPacket(sent_packet); + PortInterface::SignalSentPacket(sent_packet); } void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { @@ -341,7 +349,7 @@ void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { void UDPPort::SendStunBindingRequests() { // We will keep pinging the stun server to make sure our NAT pin-hole stays - // open during the call. + // open until the deadline (specified in SendStunBindingRequest). ASSERT(requests_.empty()); for (ServerAddresses::const_iterator it = server_addresses_.begin(); @@ -356,6 +364,8 @@ void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) { resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult); } + LOG_J(LS_INFO, this) << "Starting STUN host lookup for " + << stun_addr.ToSensitiveString(); resolver_->Resolve(stun_addr); } @@ -380,15 +390,15 @@ void UDPPort::OnResolveResult(const rtc::SocketAddress& input, } } -void UDPPort::SendStunBindingRequest( - const rtc::SocketAddress& stun_addr) { - if (stun_addr.IsUnresolved()) { +void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) { + if (stun_addr.IsUnresolvedIP()) { ResolveStunAddress(stun_addr); } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { // Check if |server_addr_| is compatible with the port's ip. if (IsCompatibleAddress(stun_addr)) { - requests_.Send(new StunBindingRequest(this, true, stun_addr)); + requests_.Send(new StunBindingRequest(this, stun_addr, + rtc::Time() + KEEP_ALIVE_TIMEOUT)); } else { // Since we can't send stun messages to the server, we should mark this // port ready. @@ -398,6 +408,23 @@ void UDPPort::SendStunBindingRequest( } } +bool UDPPort::MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const { + if (!addr->IsAnyIP() || !emit_local_for_anyaddress_ || + !Network()->default_local_address_provider()) { + return true; + } + rtc::IPAddress default_address; + bool result = + Network()->default_local_address_provider()->GetDefaultLocalAddress( + addr->family(), &default_address); + if (!result || default_address.IsNil()) { + return false; + } + + addr->SetIP(default_address); + return true; +} + void UDPPort::OnStunBindingRequestSucceeded( const rtc::SocketAddress& stun_server_addr, const rtc::SocketAddress& stun_reflected_addr) { @@ -415,7 +442,9 @@ void UDPPort::OnStunBindingRequestSucceeded( !HasCandidateWithAddress(stun_reflected_addr)) { rtc::SocketAddress related_address = socket_->GetLocalAddress(); - if (!(candidate_filter() & CF_HOST)) { + // If we can't stamp the related address correctly, empty it to avoid leak. + if (!MaybeSetDefaultLocalAddress(&related_address) || + !(candidate_filter() & CF_HOST)) { // If candidate filter doesn't have CF_HOST specified, empty raddr to // avoid local address leakage. related_address = rtc::EmptySocketAddressWithFamily( |