1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/p2p/base/stunport.h" 29 30#include "talk/p2p/base/common.h" 31#include "talk/p2p/base/stun.h" 32#include "webrtc/base/common.h" 33#include "webrtc/base/helpers.h" 34#include "webrtc/base/logging.h" 35#include "webrtc/base/nethelpers.h" 36 37namespace cricket { 38 39// TODO: Move these to a common place (used in relayport too) 40const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts 41const int RETRY_DELAY = 50; // 50ms, from ICE spec 42const int RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs 43 44// Handles a binding request sent to the STUN server. 45class StunBindingRequest : public StunRequest { 46 public: 47 StunBindingRequest(UDPPort* port, bool keep_alive, 48 const rtc::SocketAddress& addr) 49 : port_(port), keep_alive_(keep_alive), server_addr_(addr) { 50 start_time_ = rtc::Time(); 51 } 52 53 virtual ~StunBindingRequest() { 54 } 55 56 const rtc::SocketAddress& server_addr() const { return server_addr_; } 57 58 virtual void Prepare(StunMessage* request) { 59 request->SetType(STUN_BINDING_REQUEST); 60 } 61 62 virtual void OnResponse(StunMessage* response) { 63 const StunAddressAttribute* addr_attr = 64 response->GetAddress(STUN_ATTR_MAPPED_ADDRESS); 65 if (!addr_attr) { 66 LOG(LS_ERROR) << "Binding response missing mapped address."; 67 } else if (addr_attr->family() != STUN_ADDRESS_IPV4 && 68 addr_attr->family() != STUN_ADDRESS_IPV6) { 69 LOG(LS_ERROR) << "Binding address has bad family"; 70 } else { 71 rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port()); 72 port_->OnStunBindingRequestSucceeded(server_addr_, addr); 73 } 74 75 // We will do a keep-alive regardless of whether this request succeeds. 76 // This should have almost no impact on network usage. 77 if (keep_alive_) { 78 port_->requests_.SendDelayed( 79 new StunBindingRequest(port_, true, server_addr_), 80 port_->stun_keepalive_delay()); 81 } 82 } 83 84 virtual void OnErrorResponse(StunMessage* response) { 85 const StunErrorCodeAttribute* attr = response->GetErrorCode(); 86 if (!attr) { 87 LOG(LS_ERROR) << "Bad allocate response error code"; 88 } else { 89 LOG(LS_ERROR) << "Binding error response:" 90 << " class=" << attr->eclass() 91 << " number=" << attr->number() 92 << " reason='" << attr->reason() << "'"; 93 } 94 95 port_->OnStunBindingOrResolveRequestFailed(server_addr_); 96 97 if (keep_alive_ 98 && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { 99 port_->requests_.SendDelayed( 100 new StunBindingRequest(port_, true, server_addr_), 101 port_->stun_keepalive_delay()); 102 } 103 } 104 105 virtual void OnTimeout() { 106 LOG(LS_ERROR) << "Binding request timed out from " 107 << port_->GetLocalAddress().ToSensitiveString() 108 << " (" << port_->Network()->name() << ")"; 109 110 port_->OnStunBindingOrResolveRequestFailed(server_addr_); 111 112 if (keep_alive_ 113 && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { 114 port_->requests_.SendDelayed( 115 new StunBindingRequest(port_, true, server_addr_), 116 RETRY_DELAY); 117 } 118 } 119 120 private: 121 UDPPort* port_; 122 bool keep_alive_; 123 const rtc::SocketAddress server_addr_; 124 uint32 start_time_; 125}; 126 127UDPPort::AddressResolver::AddressResolver( 128 rtc::PacketSocketFactory* factory) 129 : socket_factory_(factory) {} 130 131UDPPort::AddressResolver::~AddressResolver() { 132 for (ResolverMap::iterator it = resolvers_.begin(); 133 it != resolvers_.end(); ++it) { 134 it->second->Destroy(true); 135 } 136} 137 138void UDPPort::AddressResolver::Resolve( 139 const rtc::SocketAddress& address) { 140 if (resolvers_.find(address) != resolvers_.end()) 141 return; 142 143 rtc::AsyncResolverInterface* resolver = 144 socket_factory_->CreateAsyncResolver(); 145 resolvers_.insert( 146 std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>( 147 address, resolver)); 148 149 resolver->SignalDone.connect(this, 150 &UDPPort::AddressResolver::OnResolveResult); 151 152 resolver->Start(address); 153} 154 155bool UDPPort::AddressResolver::GetResolvedAddress( 156 const rtc::SocketAddress& input, 157 int family, 158 rtc::SocketAddress* output) const { 159 ResolverMap::const_iterator it = resolvers_.find(input); 160 if (it == resolvers_.end()) 161 return false; 162 163 return it->second->GetResolvedAddress(family, output); 164} 165 166void UDPPort::AddressResolver::OnResolveResult( 167 rtc::AsyncResolverInterface* resolver) { 168 for (ResolverMap::iterator it = resolvers_.begin(); 169 it != resolvers_.end(); ++it) { 170 if (it->second == resolver) { 171 SignalDone(it->first, resolver->GetError()); 172 return; 173 } 174 } 175} 176 177UDPPort::UDPPort(rtc::Thread* thread, 178 rtc::PacketSocketFactory* factory, 179 rtc::Network* network, 180 rtc::AsyncPacketSocket* socket, 181 const std::string& username, const std::string& password) 182 : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), 183 username, password), 184 requests_(thread), 185 socket_(socket), 186 error_(0), 187 ready_(false), 188 stun_keepalive_delay_(KEEPALIVE_DELAY) { 189} 190 191UDPPort::UDPPort(rtc::Thread* thread, 192 rtc::PacketSocketFactory* factory, 193 rtc::Network* network, 194 const rtc::IPAddress& ip, int min_port, int max_port, 195 const std::string& username, const std::string& password) 196 : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port, 197 username, password), 198 requests_(thread), 199 socket_(NULL), 200 error_(0), 201 ready_(false), 202 stun_keepalive_delay_(KEEPALIVE_DELAY) { 203} 204 205bool UDPPort::Init() { 206 if (!SharedSocket()) { 207 ASSERT(socket_ == NULL); 208 socket_ = socket_factory()->CreateUdpSocket( 209 rtc::SocketAddress(ip(), 0), min_port(), max_port()); 210 if (!socket_) { 211 LOG_J(LS_WARNING, this) << "UDP socket creation failed"; 212 return false; 213 } 214 socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket); 215 } 216 socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend); 217 socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady); 218 requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket); 219 return true; 220} 221 222UDPPort::~UDPPort() { 223 if (!SharedSocket()) 224 delete socket_; 225} 226 227void UDPPort::PrepareAddress() { 228 ASSERT(requests_.empty()); 229 if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { 230 OnLocalAddressReady(socket_, socket_->GetLocalAddress()); 231 } 232} 233 234void UDPPort::MaybePrepareStunCandidate() { 235 // Sending binding request to the STUN server if address is available to 236 // prepare STUN candidate. 237 if (!server_addresses_.empty()) { 238 SendStunBindingRequests(); 239 } else { 240 // Port is done allocating candidates. 241 MaybeSetPortCompleteOrError(); 242 } 243} 244 245Connection* UDPPort::CreateConnection(const Candidate& address, 246 CandidateOrigin origin) { 247 if (address.protocol() != "udp") 248 return NULL; 249 250 if (!IsCompatibleAddress(address.address())) { 251 return NULL; 252 } 253 254 if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) { 255 ASSERT(false); 256 return NULL; 257 } 258 259 Connection* conn = new ProxyConnection(this, 0, address); 260 AddConnection(conn); 261 return conn; 262} 263 264int UDPPort::SendTo(const void* data, size_t size, 265 const rtc::SocketAddress& addr, 266 const rtc::PacketOptions& options, 267 bool payload) { 268 int sent = socket_->SendTo(data, size, addr, options); 269 if (sent < 0) { 270 error_ = socket_->GetError(); 271 LOG_J(LS_ERROR, this) << "UDP send of " << size 272 << " bytes failed with error " << error_; 273 } 274 return sent; 275} 276 277int UDPPort::SetOption(rtc::Socket::Option opt, int value) { 278 return socket_->SetOption(opt, value); 279} 280 281int UDPPort::GetOption(rtc::Socket::Option opt, int* value) { 282 return socket_->GetOption(opt, value); 283} 284 285int UDPPort::GetError() { 286 return error_; 287} 288 289void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, 290 const rtc::SocketAddress& address) { 291 AddAddress(address, address, rtc::SocketAddress(), 292 UDP_PROTOCOL_NAME, "", LOCAL_PORT_TYPE, 293 ICE_TYPE_PREFERENCE_HOST, 0, false); 294 MaybePrepareStunCandidate(); 295} 296 297void UDPPort::OnReadPacket( 298 rtc::AsyncPacketSocket* socket, const char* data, size_t size, 299 const rtc::SocketAddress& remote_addr, 300 const rtc::PacketTime& packet_time) { 301 ASSERT(socket == socket_); 302 ASSERT(!remote_addr.IsUnresolved()); 303 304 // Look for a response from the STUN server. 305 // Even if the response doesn't match one of our outstanding requests, we 306 // will eat it because it might be a response to a retransmitted packet, and 307 // we already cleared the request when we got the first response. 308 if (server_addresses_.find(remote_addr) != server_addresses_.end()) { 309 requests_.CheckResponse(data, size); 310 return; 311 } 312 313 if (Connection* conn = GetConnection(remote_addr)) { 314 conn->OnReadPacket(data, size, packet_time); 315 } else { 316 Port::OnReadPacket(data, size, remote_addr, PROTO_UDP); 317 } 318} 319 320void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { 321 Port::OnReadyToSend(); 322} 323 324void UDPPort::SendStunBindingRequests() { 325 // We will keep pinging the stun server to make sure our NAT pin-hole stays 326 // open during the call. 327 ASSERT(requests_.empty()); 328 329 for (ServerAddresses::const_iterator it = server_addresses_.begin(); 330 it != server_addresses_.end(); ++it) { 331 SendStunBindingRequest(*it); 332 } 333} 334 335void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) { 336 if (!resolver_) { 337 resolver_.reset(new AddressResolver(socket_factory())); 338 resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult); 339 } 340 341 resolver_->Resolve(stun_addr); 342} 343 344void UDPPort::OnResolveResult(const rtc::SocketAddress& input, 345 int error) { 346 ASSERT(resolver_.get() != NULL); 347 348 rtc::SocketAddress resolved; 349 if (error != 0 || 350 !resolver_->GetResolvedAddress(input, ip().family(), &resolved)) { 351 LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error " 352 << error; 353 OnStunBindingOrResolveRequestFailed(input); 354 return; 355 } 356 357 server_addresses_.erase(input); 358 359 if (server_addresses_.find(resolved) == server_addresses_.end()) { 360 server_addresses_.insert(resolved); 361 SendStunBindingRequest(resolved); 362 } 363} 364 365void UDPPort::SendStunBindingRequest( 366 const rtc::SocketAddress& stun_addr) { 367 if (stun_addr.IsUnresolved()) { 368 ResolveStunAddress(stun_addr); 369 370 } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { 371 // Check if |server_addr_| is compatible with the port's ip. 372 if (IsCompatibleAddress(stun_addr)) { 373 requests_.Send(new StunBindingRequest(this, true, stun_addr)); 374 } else { 375 // Since we can't send stun messages to the server, we should mark this 376 // port ready. 377 LOG(LS_WARNING) << "STUN server address is incompatible."; 378 OnStunBindingOrResolveRequestFailed(stun_addr); 379 } 380 } 381} 382 383void UDPPort::OnStunBindingRequestSucceeded( 384 const rtc::SocketAddress& stun_server_addr, 385 const rtc::SocketAddress& stun_reflected_addr) { 386 if (bind_request_succeeded_servers_.find(stun_server_addr) != 387 bind_request_succeeded_servers_.end()) { 388 return; 389 } 390 bind_request_succeeded_servers_.insert(stun_server_addr); 391 392 if (!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) { 393 // If socket is shared and |stun_reflected_addr| is equal to local socket 394 // address then discarding the stun address. 395 // For STUN related address is local socket address. 396 AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), 397 socket_->GetLocalAddress(), UDP_PROTOCOL_NAME, "", 398 STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, false); 399 } 400 MaybeSetPortCompleteOrError(); 401} 402 403void UDPPort::OnStunBindingOrResolveRequestFailed( 404 const rtc::SocketAddress& stun_server_addr) { 405 if (bind_request_failed_servers_.find(stun_server_addr) != 406 bind_request_failed_servers_.end()) { 407 return; 408 } 409 bind_request_failed_servers_.insert(stun_server_addr); 410 MaybeSetPortCompleteOrError(); 411} 412 413void UDPPort::MaybeSetPortCompleteOrError() { 414 if (ready_) 415 return; 416 417 // Do not set port ready if we are still waiting for bind responses. 418 const size_t servers_done_bind_request = bind_request_failed_servers_.size() + 419 bind_request_succeeded_servers_.size(); 420 if (server_addresses_.size() != servers_done_bind_request) { 421 return; 422 } 423 424 // Setting ready status. 425 ready_ = true; 426 427 // The port is "completed" if there is no stun server provided, or the bind 428 // request succeeded for any stun server, or the socket is shared. 429 if (server_addresses_.empty() || 430 bind_request_succeeded_servers_.size() > 0 || 431 SharedSocket()) { 432 SignalPortComplete(this); 433 } else { 434 SignalPortError(this); 435 } 436} 437 438// TODO: merge this with SendTo above. 439void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) { 440 StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req); 441 rtc::PacketOptions options(DefaultDscpValue()); 442 if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) 443 PLOG(LERROR, socket_->GetError()) << "sendto"; 444} 445 446} // namespace cricket 447