1269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org/*
2269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *
4269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
5269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
6269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
7269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
8269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org */
10269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
11269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/stunport.h"
12269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
13269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/common.h"
14269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/portallocator.h"
15269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/p2p/base/stun.h"
169af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh#include "webrtc/base/checks.h"
17269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/common.h"
18269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/helpers.h"
19fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh#include "webrtc/base/ipaddress.h"
20269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/logging.h"
21269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/nethelpers.h"
22269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
23269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgnamespace cricket {
24269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
25269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// TODO: Move these to a common place (used in relayport too)
26269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgconst int KEEPALIVE_DELAY = 10 * 1000;  // 10 seconds - sort timeouts
27269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgconst int RETRY_TIMEOUT = 50 * 1000;    // ICE says 50 secs
2845b0efd378abef87676e6ec55516b10ce583ddachonghaiz// Stop sending STUN binding requests after this amount of time
2945b0efd378abef87676e6ec55516b10ce583ddachonghaiz// (in milliseconds) because the connection binding requests should keep
3045b0efd378abef87676e6ec55516b10ce583ddachonghaiz// the NAT binding alive.
3145b0efd378abef87676e6ec55516b10ce583ddachonghaizconst int KEEP_ALIVE_TIMEOUT = 2 * 60 * 1000;  // 2 minutes
32269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
33269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// Handles a binding request sent to the STUN server.
34269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgclass StunBindingRequest : public StunRequest {
35269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org public:
3645b0efd378abef87676e6ec55516b10ce583ddachonghaiz  StunBindingRequest(UDPPort* port,
3745b0efd378abef87676e6ec55516b10ce583ddachonghaiz                     const rtc::SocketAddress& addr,
3845b0efd378abef87676e6ec55516b10ce583ddachonghaiz                     uint32_t deadline)
3945b0efd378abef87676e6ec55516b10ce583ddachonghaiz      : port_(port), server_addr_(addr), deadline_(deadline) {
40269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    start_time_ = rtc::Time();
41269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
42269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
43269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  virtual ~StunBindingRequest() {
44269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
45269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
46269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const rtc::SocketAddress& server_addr() const { return server_addr_; }
47269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
481cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  virtual void Prepare(StunMessage* request) override {
49269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    request->SetType(STUN_BINDING_REQUEST);
50269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
51269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
521cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  virtual void OnResponse(StunMessage* response) override {
53269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const StunAddressAttribute* addr_attr =
54269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
55269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!addr_attr) {
56269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG(LS_ERROR) << "Binding response missing mapped address.";
57269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
58269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org               addr_attr->family() != STUN_ADDRESS_IPV6) {
59269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG(LS_ERROR) << "Binding address has bad family";
60269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    } else {
61269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
62269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->OnStunBindingRequestSucceeded(server_addr_, addr);
63269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
64269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
65269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // We will do a keep-alive regardless of whether this request succeeds.
6645b0efd378abef87676e6ec55516b10ce583ddachonghaiz    // It will be stopped after |deadline_| mostly to conserve the battery life.
6745b0efd378abef87676e6ec55516b10ce583ddachonghaiz    if (rtc::Time() <= deadline_) {
68269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->requests_.SendDelayed(
6945b0efd378abef87676e6ec55516b10ce583ddachonghaiz          new StunBindingRequest(port_, server_addr_, deadline_),
70269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          port_->stun_keepalive_delay());
71269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
72269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
73269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
741cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  virtual void OnErrorResponse(StunMessage* response) override {
75269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const StunErrorCodeAttribute* attr = response->GetErrorCode();
76269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!attr) {
77269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG(LS_ERROR) << "Bad allocate response error code";
78269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    } else {
79269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG(LS_ERROR) << "Binding error response:"
80269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 << " class=" << attr->eclass()
81269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 << " number=" << attr->number()
82269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 << " reason='" << attr->reason() << "'";
83269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
84269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
85269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->OnStunBindingOrResolveRequestFailed(server_addr_);
86269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
8745b0efd378abef87676e6ec55516b10ce583ddachonghaiz    uint32_t now = rtc::Time();
8845b0efd378abef87676e6ec55516b10ce583ddachonghaiz    if (now <= deadline_ && rtc::TimeDiff(now, start_time_) <= RETRY_TIMEOUT) {
89269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      port_->requests_.SendDelayed(
9045b0efd378abef87676e6ec55516b10ce583ddachonghaiz          new StunBindingRequest(port_, server_addr_, deadline_),
91269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          port_->stun_keepalive_delay());
92269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
93269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
94269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
951cf6f8101ae9db517332783e99c98e14ff4c47e1Peter Thatcher  virtual void OnTimeout() override {
96269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_ERROR) << "Binding request timed out from "
97269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      << port_->GetLocalAddress().ToSensitiveString()
98269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      << " (" << port_->Network()->name() << ")";
99269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
100269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    port_->OnStunBindingOrResolveRequestFailed(server_addr_);
101269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
102269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
103269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org private:
104269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  UDPPort* port_;
105269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const rtc::SocketAddress server_addr_;
1060c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström  uint32_t start_time_;
10745b0efd378abef87676e6ec55516b10ce583ddachonghaiz  uint32_t deadline_;
108269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
109269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
110269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgUDPPort::AddressResolver::AddressResolver(
111269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    rtc::PacketSocketFactory* factory)
112269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    : socket_factory_(factory) {}
113269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
114269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgUDPPort::AddressResolver::~AddressResolver() {
115269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (ResolverMap::iterator it = resolvers_.begin();
116269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org       it != resolvers_.end(); ++it) {
1178a4f547dadecb1ec4e1647e0ca1ad74be3048801Guo-wei Shieh    // TODO(guoweis): Change to asynchronous DNS resolution to prevent the hang
1188a4f547dadecb1ec4e1647e0ca1ad74be3048801Guo-wei Shieh    // when passing true to the Destroy() which is a safer way to avoid the code
1198a4f547dadecb1ec4e1647e0ca1ad74be3048801Guo-wei Shieh    // unloaded before the thread exits. Please see webrtc bug 5139.
1208a4f547dadecb1ec4e1647e0ca1ad74be3048801Guo-wei Shieh    it->second->Destroy(false);
121269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
122269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
123269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
124269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::AddressResolver::Resolve(
125269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& address) {
126269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (resolvers_.find(address) != resolvers_.end())
127269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
128269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
129269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::AsyncResolverInterface* resolver =
130269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      socket_factory_->CreateAsyncResolver();
131269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolvers_.insert(
132269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>(
133269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          address, resolver));
134269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
135269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver->SignalDone.connect(this,
136269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                               &UDPPort::AddressResolver::OnResolveResult);
137269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
138269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver->Start(address);
139269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
140269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
141269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool UDPPort::AddressResolver::GetResolvedAddress(
142269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& input,
143269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    int family,
144269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    rtc::SocketAddress* output) const {
145269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ResolverMap::const_iterator it = resolvers_.find(input);
146269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (it == resolvers_.end())
147269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
148269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
149269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return it->second->GetResolvedAddress(family, output);
150269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
151269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
152269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::AddressResolver::OnResolveResult(
153269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    rtc::AsyncResolverInterface* resolver) {
154269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (ResolverMap::iterator it = resolvers_.begin();
155269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org       it != resolvers_.end(); ++it) {
156269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (it->second == resolver) {
157269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      SignalDone(it->first, resolver->GetError());
158269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return;
159269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
160269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
161269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
162269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
163269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgUDPPort::UDPPort(rtc::Thread* thread,
164269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 rtc::PacketSocketFactory* factory,
165269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 rtc::Network* network,
166269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 rtc::AsyncPacketSocket* socket,
167332331fb01f8a316ac6d61cf4572478610fb3472pkasting@chromium.org                 const std::string& username,
1680ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                 const std::string& password,
169fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh                 const std::string& origin,
1709af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh                 bool emit_local_for_anyaddress)
1719af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh    : Port(thread,
1729af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh           factory,
1739af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh           network,
1749af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh           socket->GetLocalAddress().ipaddr(),
1759af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh           username,
1769af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh           password),
177269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      requests_(thread),
178269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      socket_(socket),
179269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      error_(0),
180269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ready_(false),
181fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh      stun_keepalive_delay_(KEEPALIVE_DELAY),
1829af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh      emit_local_for_anyaddress_(emit_local_for_anyaddress) {
1830ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org  requests_.set_origin(origin);
184269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
185269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
186269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgUDPPort::UDPPort(rtc::Thread* thread,
187269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 rtc::PacketSocketFactory* factory,
188269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                 rtc::Network* network,
189332331fb01f8a316ac6d61cf4572478610fb3472pkasting@chromium.org                 const rtc::IPAddress& ip,
1900c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström                 uint16_t min_port,
1910c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström                 uint16_t max_port,
192332331fb01f8a316ac6d61cf4572478610fb3472pkasting@chromium.org                 const std::string& username,
1930ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org                 const std::string& password,
194fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh                 const std::string& origin,
1959af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh                 bool emit_local_for_anyaddress)
1960c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström    : Port(thread,
1970c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           LOCAL_PORT_TYPE,
1980c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           factory,
1990c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           network,
2000c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           ip,
2010c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           min_port,
2020c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           max_port,
2030c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           username,
2040c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström           password),
205269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      requests_(thread),
206269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      socket_(NULL),
207269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      error_(0),
208269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      ready_(false),
209fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh      stun_keepalive_delay_(KEEPALIVE_DELAY),
2109af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh      emit_local_for_anyaddress_(emit_local_for_anyaddress) {
2110ba1533fdbe4a098723da8262f1374d71c3a1806pthatcher@webrtc.org  requests_.set_origin(origin);
212269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
213269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
214269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool UDPPort::Init() {
215269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!SharedSocket()) {
216269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ASSERT(socket_ == NULL);
217269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_ = socket_factory()->CreateUdpSocket(
218269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        rtc::SocketAddress(ip(), 0), min_port(), max_port());
219269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (!socket_) {
220269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG_J(LS_WARNING, this) << "UDP socket creation failed";
221269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return false;
222269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
223269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
224269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
225c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefan  socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket);
226269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
227269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
228269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
229269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
230269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
231269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
232269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgUDPPort::~UDPPort() {
233269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!SharedSocket())
234269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    delete socket_;
235269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
236269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
237269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::PrepareAddress() {
238269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(requests_.empty());
239269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
240269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    OnLocalAddressReady(socket_, socket_->GetLocalAddress());
241269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
242269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
243269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
244269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::MaybePrepareStunCandidate() {
245269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Sending binding request to the STUN server if address is available to
246269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // prepare STUN candidate.
247269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!server_addresses_.empty()) {
248269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SendStunBindingRequests();
249269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
250269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Port is done allocating candidates.
251269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    MaybeSetPortCompleteOrError();
252269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
253269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
254269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
255269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgConnection* UDPPort::CreateConnection(const Candidate& address,
256f9945b2d1aa2d78b19987219ea872605167d7b5fHonghai Zhang                                      CandidateOrigin origin) {
257f9945b2d1aa2d78b19987219ea872605167d7b5fHonghai Zhang  if (!SupportsProtocol(address.protocol())) {
258269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return NULL;
259f9945b2d1aa2d78b19987219ea872605167d7b5fHonghai Zhang  }
260269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
261269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!IsCompatibleAddress(address.address())) {
262269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return NULL;
263269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
264269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
265269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
266269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ASSERT(false);
267269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return NULL;
268269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
269269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
270269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  Connection* conn = new ProxyConnection(this, 0, address);
271269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  AddConnection(conn);
272269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return conn;
273269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
274269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
275269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint UDPPort::SendTo(const void* data, size_t size,
276269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                    const rtc::SocketAddress& addr,
277269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                    const rtc::PacketOptions& options,
278269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                    bool payload) {
279269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  int sent = socket_->SendTo(data, size, addr, options);
280269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (sent < 0) {
281269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    error_ = socket_->GetError();
282269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_ERROR, this) << "UDP send of " << size
283269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                          << " bytes failed with error " << error_;
284269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
285269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return sent;
286269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
287269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
288269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint UDPPort::SetOption(rtc::Socket::Option opt, int value) {
289269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return socket_->SetOption(opt, value);
290269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
291269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
292269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint UDPPort::GetOption(rtc::Socket::Option opt, int* value) {
293269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return socket_->GetOption(opt, value);
294269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
295269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
296269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgint UDPPort::GetError() {
297269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return error_;
298269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
299269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
300269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
301269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                                  const rtc::SocketAddress& address) {
302fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh  // When adapter enumeration is disabled and binding to the any address, the
3039af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  // default local address will be issued as a candidate instead if
3049af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  // |emit_local_for_anyaddress| is true. This is to allow connectivity for
3059af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  // applications which absolutely requires a HOST candidate.
306fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh  rtc::SocketAddress addr = address;
307e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh
308e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh  // If MaybeSetDefaultLocalAddress fails, we keep the "any" IP so that at
309e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh  // least the port is listening.
3109af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  MaybeSetDefaultLocalAddress(&addr);
311fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh
312fe3bc9d5aeffed8bbfb34c330d8b991abd1a1abaGuo-wei Shieh  AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "",
3133d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh             LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false);
314269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  MaybePrepareStunCandidate();
315269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
316269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
31720a34619080005c3b0e49d85b307113ea2b180c3tfarinavoid UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
31820a34619080005c3b0e49d85b307113ea2b180c3tfarina                           const char* data,
31920a34619080005c3b0e49d85b307113ea2b180c3tfarina                           size_t size,
32020a34619080005c3b0e49d85b307113ea2b180c3tfarina                           const rtc::SocketAddress& remote_addr,
32120a34619080005c3b0e49d85b307113ea2b180c3tfarina                           const rtc::PacketTime& packet_time) {
322269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(socket == socket_);
32320a34619080005c3b0e49d85b307113ea2b180c3tfarina  ASSERT(!remote_addr.IsUnresolvedIP());
324269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
325269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Look for a response from the STUN server.
326269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Even if the response doesn't match one of our outstanding requests, we
327269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // will eat it because it might be a response to a retransmitted packet, and
328269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // we already cleared the request when we got the first response.
329269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
330269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    requests_.CheckResponse(data, size);
331269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
332269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
333269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
334269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (Connection* conn = GetConnection(remote_addr)) {
335269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    conn->OnReadPacket(data, size, packet_time);
336269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
337269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
338269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
339269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
340269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
341c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefanvoid UDPPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
342c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefan                           const rtc::SentPacket& sent_packet) {
34355674ffb32307c6f3efaab442340d3c5c075073bStefan Holmer  PortInterface::SignalSentPacket(sent_packet);
344c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefan}
345c1aeaf0dc37d96f31c92f893f4e30e7a5f7cc2b7stefan
346269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
347269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  Port::OnReadyToSend();
348269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
349269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
350269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::SendStunBindingRequests() {
351269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // We will keep pinging the stun server to make sure our NAT pin-hole stays
35245b0efd378abef87676e6ec55516b10ce583ddachonghaiz  // open until the deadline (specified in SendStunBindingRequest).
353269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(requests_.empty());
354269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
355269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (ServerAddresses::const_iterator it = server_addresses_.begin();
356269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org       it != server_addresses_.end(); ++it) {
357269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SendStunBindingRequest(*it);
358269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
359269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
360269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
361269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
362269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!resolver_) {
363269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    resolver_.reset(new AddressResolver(socket_factory()));
364269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
365269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
366269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
3670f490a5b8609c1f10dba37d7a7b0b2fc055543ebHonghai Zhang  LOG_J(LS_INFO, this) << "Starting STUN host lookup for "
3680f490a5b8609c1f10dba37d7a7b0b2fc055543ebHonghai Zhang                       << stun_addr.ToSensitiveString();
369269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  resolver_->Resolve(stun_addr);
370269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
371269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
372269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnResolveResult(const rtc::SocketAddress& input,
373269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                              int error) {
374269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ASSERT(resolver_.get() != NULL);
375269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
376269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::SocketAddress resolved;
377269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (error != 0 ||
378269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      !resolver_->GetResolvedAddress(input, ip().family(), &resolved))  {
379269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
380269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org                            << error;
381269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    OnStunBindingOrResolveRequestFailed(input);
382269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
383269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
384269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
385269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  server_addresses_.erase(input);
386269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
387269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_addresses_.find(resolved) == server_addresses_.end()) {
388269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    server_addresses_.insert(resolved);
389269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SendStunBindingRequest(resolved);
390269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
391269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
392269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
39320a34619080005c3b0e49d85b307113ea2b180c3tfarinavoid UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) {
39420a34619080005c3b0e49d85b307113ea2b180c3tfarina  if (stun_addr.IsUnresolvedIP()) {
395269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    ResolveStunAddress(stun_addr);
396269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
397269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
398269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    // Check if |server_addr_| is compatible with the port's ip.
399269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (IsCompatibleAddress(stun_addr)) {
40045b0efd378abef87676e6ec55516b10ce583ddachonghaiz      requests_.Send(new StunBindingRequest(this, stun_addr,
40145b0efd378abef87676e6ec55516b10ce583ddachonghaiz                                            rtc::Time() + KEEP_ALIVE_TIMEOUT));
402269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    } else {
403269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // Since we can't send stun messages to the server, we should mark this
404269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // port ready.
405269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      LOG(LS_WARNING) << "STUN server address is incompatible.";
406269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      OnStunBindingOrResolveRequestFailed(stun_addr);
407269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
408269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
409269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
410269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
411e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shiehbool UDPPort::MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const {
4129af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  if (!addr->IsAnyIP() || !emit_local_for_anyaddress_ ||
4139af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh      !Network()->default_local_address_provider()) {
414e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh    return true;
4159af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  }
4169af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  rtc::IPAddress default_address;
4179af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  bool result =
4189af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh      Network()->default_local_address_provider()->GetDefaultLocalAddress(
4199af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh          addr->family(), &default_address);
420953eabc0273ba0566f2889904dd4ffb6ee50bfa9Guo-wei Shieh  if (!result || default_address.IsNil()) {
421e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh    return false;
422e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh  }
423e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh
4249af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh  addr->SetIP(default_address);
425e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh  return true;
4269af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh}
4279af97f89103d8f1f77b52a6ae77b8b7bcdc23f71Guo-wei Shieh
428269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnStunBindingRequestSucceeded(
429269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& stun_server_addr,
430269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& stun_reflected_addr) {
431269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (bind_request_succeeded_servers_.find(stun_server_addr) !=
432269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          bind_request_succeeded_servers_.end()) {
433269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
434269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
435269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  bind_request_succeeded_servers_.insert(stun_server_addr);
436269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
437269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // If socket is shared and |stun_reflected_addr| is equal to local socket
438269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // address, or if the same address has been added by another STUN server,
439269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // then discarding the stun address.
440269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // For STUN, related address is the local socket address.
441269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) &&
442269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      !HasCandidateWithAddress(stun_reflected_addr)) {
443269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
444269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    rtc::SocketAddress related_address = socket_->GetLocalAddress();
445e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh    // If we can't stamp the related address correctly, empty it to avoid leak.
446e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh    if (!MaybeSetDefaultLocalAddress(&related_address) ||
447e03cab94c1bac43f4d6c4775023a957f98ee8132Guo-wei Shieh        !(candidate_filter() & CF_HOST)) {
448269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // If candidate filter doesn't have CF_HOST specified, empty raddr to
449269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      // avoid local address leakage.
450269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      related_address = rtc::EmptySocketAddressWithFamily(
451269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          related_address.family());
452269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
453269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
4543d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh    AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address,
4553d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh               UDP_PROTOCOL_NAME, "", "", STUN_PORT_TYPE,
4563d564c10157d7de1d2d4236f4e2a13ff1363d52bGuo-wei Shieh               ICE_TYPE_PREFERENCE_SRFLX, 0, false);
457269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
458269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  MaybeSetPortCompleteOrError();
459269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
460269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
461269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnStunBindingOrResolveRequestFailed(
462269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const rtc::SocketAddress& stun_server_addr) {
463269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (bind_request_failed_servers_.find(stun_server_addr) !=
464269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          bind_request_failed_servers_.end()) {
465269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
466269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
467269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  bind_request_failed_servers_.insert(stun_server_addr);
468269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  MaybeSetPortCompleteOrError();
469269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
470269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
471269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::MaybeSetPortCompleteOrError() {
472269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (ready_)
473269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
474269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
475269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Do not set port ready if we are still waiting for bind responses.
476269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const size_t servers_done_bind_request = bind_request_failed_servers_.size() +
477269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      bind_request_succeeded_servers_.size();
478269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_addresses_.size() != servers_done_bind_request) {
479269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return;
480269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
481269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
482269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // Setting ready status.
483269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  ready_ = true;
484269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
485269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // The port is "completed" if there is no stun server provided, or the bind
486269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  // request succeeded for any stun server, or the socket is shared.
487269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (server_addresses_.empty() ||
488269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      bind_request_succeeded_servers_.size() > 0 ||
489269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      SharedSocket()) {
490269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SignalPortComplete(this);
491269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  } else {
492269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    SignalPortError(this);
493269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
494269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
495269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
496269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org// TODO: merge this with SendTo above.
497269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
498269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
499269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  rtc::PacketOptions options(DefaultDscpValue());
500269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0)
501269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    PLOG(LERROR, socket_->GetError()) << "sendto";
502269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
503269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
504269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
505269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const std::vector<Candidate>& existing_candidates = Candidates();
506269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  std::vector<Candidate>::const_iterator it = existing_candidates.begin();
507269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (; it != existing_candidates.end(); ++it) {
508269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    if (it->address() == addr)
509269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      return true;
510269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
511269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return false;
512269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
513269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
514269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}  // namespace cricket
515