15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004--2005, Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/stunport.h"
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h"
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h"
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/helpers.h"
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/nethelpers.h"
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/common.h"
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/stun.h"
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket {
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO: Move these to a common place (used in relayport too)
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst int KEEPALIVE_DELAY = 10 * 1000;  // 10 seconds - sort timeouts
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst int RETRY_DELAY = 50;             // 50ms, from ICE spec
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst int RETRY_TIMEOUT = 50 * 1000;    // ICE says 50 secs
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Handles a binding request sent to the STUN server.
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass StunBindingRequest : public StunRequest {
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  StunBindingRequest(UDPPort* port, bool keep_alive,
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                     const talk_base::SocketAddress& addr)
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : port_(port), keep_alive_(keep_alive), server_addr_(addr) {
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    start_time_ = talk_base::Time();
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~StunBindingRequest() {
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const talk_base::SocketAddress& server_addr() const { return server_addr_; }
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void Prepare(StunMessage* request) {
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    request->SetType(STUN_BINDING_REQUEST);
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnResponse(StunMessage* response) {
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const StunAddressAttribute* addr_attr =
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!addr_attr) {
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Binding response missing mapped address.";
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               addr_attr->family() != STUN_ADDRESS_IPV6) {
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Binding address has bad family";
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      talk_base::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      port_->OnStunBindingRequestSucceeded(addr);
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We will do a keep-alive regardless of whether this request suceeds.
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // This should have almost no impact on network usage.
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (keep_alive_) {
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      port_->requests_.SendDelayed(
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          new StunBindingRequest(port_, true, server_addr_),
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          port_->stun_keepalive_delay());
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnErrorResponse(StunMessage* response) {
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const StunErrorCodeAttribute* attr = response->GetErrorCode();
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!attr) {
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Bad allocate response error code";
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Binding error response:"
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << " class=" << attr->eclass()
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << " number=" << attr->number()
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << " reason='" << attr->reason() << "'";
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    port_->OnStunBindingOrResolveRequestFailed();
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (keep_alive_
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        && (talk_base::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      port_->requests_.SendDelayed(
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          new StunBindingRequest(port_, true, server_addr_),
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          port_->stun_keepalive_delay());
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnTimeout() {
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "Binding request timed out from "
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      << port_->GetLocalAddress().ToSensitiveString()
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      << " (" << port_->Network()->name() << ")";
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    port_->OnStunBindingOrResolveRequestFailed();
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (keep_alive_
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        && (talk_base::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      port_->requests_.SendDelayed(
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          new StunBindingRequest(port_, true, server_addr_),
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          RETRY_DELAY);
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  UDPPort* port_;
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool keep_alive_;
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::SocketAddress server_addr_;
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 start_time_;
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgUDPPort::UDPPort(talk_base::Thread* thread,
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 talk_base::Network* network,
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 talk_base::AsyncPacketSocket* socket,
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 const std::string& username, const std::string& password)
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : Port(thread, network, socket->GetLocalAddress().ipaddr(),
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           username, password),
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      requests_(thread),
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      socket_(socket),
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_(0),
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_(NULL),
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ready_(false),
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stun_keepalive_delay_(KEEPALIVE_DELAY) {
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgUDPPort::UDPPort(talk_base::Thread* thread,
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   talk_base::PacketSocketFactory* factory,
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   talk_base::Network* network,
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   const talk_base::IPAddress& ip, int min_port, int max_port,
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   const std::string& username, const std::string& password)
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           username, password),
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      requests_(thread),
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      socket_(NULL),
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_(0),
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_(NULL),
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ready_(false),
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stun_keepalive_delay_(KEEPALIVE_DELAY) {
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool UDPPort::Init() {
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!SharedSocket()) {
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(socket_ == NULL);
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socket_ = socket_factory()->CreateUdpSocket(
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        talk_base::SocketAddress(ip(), 0), min_port(), max_port());
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!socket_) {
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_J(LS_WARNING, this) << "UDP socket creation failed";
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgUDPPort::~UDPPort() {
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (resolver_) {
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    resolver_->Destroy(false);
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!SharedSocket())
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete socket_;
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::PrepareAddress() {
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(requests_.empty());
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND) {
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    OnLocalAddressReady(socket_, socket_->GetLocalAddress());
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::MaybePrepareStunCandidate() {
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Sending binding request to the STUN server if address is available to
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // prepare STUN candidate.
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!server_addr_.IsNil()) {
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SendStunBindingRequest();
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Processing host candidate address.
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetResult(true);
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgConnection* UDPPort::CreateConnection(const Candidate& address,
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       CandidateOrigin origin) {
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (address.protocol() != "udp")
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return NULL;
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!IsCompatibleAddress(address.address())) {
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return NULL;
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(false);
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return NULL;
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Connection* conn = new ProxyConnection(this, 0, address);
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AddConnection(conn);
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return conn;
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint UDPPort::SendTo(const void* data, size_t size,
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                     const talk_base::SocketAddress& addr, bool payload) {
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int sent = socket_->SendTo(data, size, addr);
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (sent < 0) {
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    error_ = socket_->GetError();
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_J(LS_ERROR, this) << "UDP send of " << size
2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                          << " bytes failed with error " << error_;
2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return sent;
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint UDPPort::SetOption(talk_base::Socket::Option opt, int value) {
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return socket_->SetOption(opt, value);
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint UDPPort::GetOption(talk_base::Socket::Option opt, int* value) {
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return socket_->GetOption(opt, value);
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint UDPPort::GetError() {
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return error_;
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnLocalAddressReady(talk_base::AsyncPacketSocket* socket,
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                  const talk_base::SocketAddress& address) {
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AddAddress(address, address, UDP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             ICE_TYPE_PREFERENCE_HOST, false);
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  MaybePrepareStunCandidate();
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnReadPacket(talk_base::AsyncPacketSocket* socket,
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                           const char* data, size_t size,
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                           const talk_base::SocketAddress& remote_addr) {
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(socket == socket_);
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Look for a response from the STUN server.
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Even if the response doesn't match one of our outstanding requests, we
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // will eat it because it might be a response to a retransmitted packet, and
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // we already cleared the request when we got the first response.
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(!server_addr_.IsUnresolved());
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (remote_addr == server_addr_) {
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    requests_.CheckResponse(data, size);
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (Connection* conn = GetConnection(remote_addr)) {
2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    conn->OnReadPacket(data, size);
2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Port::OnReadyToSend();
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::SendStunBindingRequest() {
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // We will keep pinging the stun server to make sure our NAT pin-hole stays
2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // open during the call.
2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO: Support multiple stun servers, or make ResolveStunAddress find a
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // server with the correct family, or something similar.
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(requests_.empty());
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (server_addr_.IsUnresolved()) {
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ResolveStunAddress();
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND) {
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (server_addr_.family() == ip().family()) {
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      requests_.Send(new StunBindingRequest(this, true, server_addr_));
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::ResolveStunAddress() {
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (resolver_)
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  resolver_ = new talk_base::AsyncResolver();
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  resolver_->SignalWorkDone.connect(this, &UDPPort::OnResolveResult);
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  resolver_->set_address(server_addr_);
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  resolver_->Start();
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnResolveResult(talk_base::SignalThread* t) {
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(t == resolver_);
3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (resolver_->error() != 0) {
3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                            << resolver_->error();
3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    OnStunBindingOrResolveRequestFailed();
3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  server_addr_ = resolver_->address();
3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SendStunBindingRequest();
3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnStunBindingRequestSucceeded(
3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const talk_base::SocketAddress& stun_addr) {
3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ready_)  // Discarding the binding response if port is already enabled.
3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!SharedSocket() || stun_addr != socket_->GetLocalAddress()) {
3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If socket is shared and |stun_addr| is equal to local socket
3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // address then discarding the stun address.
3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Setting related address before STUN candidate is added. For STUN
3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // related address is local socket address.
3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    set_related_address(socket_->GetLocalAddress());
3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_PRFLX, false);
3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetResult(true);
3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnStunBindingOrResolveRequestFailed() {
3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ready_)  // Discarding failure response if port is already enabled.
3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If socket is shared, we should process local udp candidate.
3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetResult(SharedSocket());
3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::SetResult(bool success) {
3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Setting ready status.
3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ready_ = true;
3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (success) {
3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SignalPortComplete(this);
3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SignalPortError(this);
3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO: merge this with SendTo above.
3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (socket_->SendTo(data, size, sreq->server_addr()) < 0)
3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    PLOG(LERROR, socket_->GetError()) << "sendto";
3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace cricket
354