blob: 2f6bf614c69eedcb176524e407828d8eed703aac [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stunport.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
Steve Anton6c38cc72017-11-29 10:25:58 -080013#include <utility>
14#include <vector>
15
Qingsi Wang866e08d2018-03-22 17:54:23 -070016#include "p2p/base/p2pconstants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "p2p/base/portallocator.h"
18#include "p2p/base/stun.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/helpers.h"
21#include "rtc_base/ipaddress.h"
22#include "rtc_base/logging.h"
23#include "rtc_base/nethelpers.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024
25namespace cricket {
26
Steve Anton6c38cc72017-11-29 10:25:58 -080027// TODO(?): Move these to a common place (used in relayport too)
honghaize2af9ef2016-03-03 08:27:47 -080028const int RETRY_TIMEOUT = 50 * 1000; // 50 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000029
30// Handles a binding request sent to the STUN server.
31class StunBindingRequest : public StunRequest {
32 public:
honghaiz45b0efd2015-12-04 08:57:26 -080033 StunBindingRequest(UDPPort* port,
34 const rtc::SocketAddress& addr,
Honghai Zhang351d77b2016-05-20 15:08:29 -070035 int64_t start_time)
36 : port_(port), server_addr_(addr), start_time_(start_time) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000037
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000038 const rtc::SocketAddress& server_addr() const { return server_addr_; }
39
Steve Anton1cf1b7d2017-10-30 10:00:15 -070040 void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000041 request->SetType(STUN_BINDING_REQUEST);
42 }
43
Steve Anton1cf1b7d2017-10-30 10:00:15 -070044 void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045 const StunAddressAttribute* addr_attr =
46 response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
47 if (!addr_attr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010048 RTC_LOG(LS_ERROR) << "Binding response missing mapped address.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000049 } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
50 addr_attr->family() != STUN_ADDRESS_IPV6) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010051 RTC_LOG(LS_ERROR) << "Binding address has bad family";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052 } else {
53 rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
Qingsi Wang72a43a12018-02-20 16:03:18 -080054 port_->OnStunBindingRequestSucceeded(this->Elapsed(), server_addr_, addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000055 }
56
honghaize2af9ef2016-03-03 08:27:47 -080057 // The keep-alive requests will be stopped after its lifetime has passed.
nisse1bffc1d2016-05-02 08:18:55 -070058 if (WithinLifetime(rtc::TimeMillis())) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059 port_->requests_.SendDelayed(
Honghai Zhang351d77b2016-05-20 15:08:29 -070060 new StunBindingRequest(port_, server_addr_, start_time_),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000061 port_->stun_keepalive_delay());
62 }
63 }
64
Steve Anton1cf1b7d2017-10-30 10:00:15 -070065 void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000066 const StunErrorCodeAttribute* attr = response->GetErrorCode();
67 if (!attr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010068 RTC_LOG(LS_ERROR) << "Missing binding response error code.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000069 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +010070 RTC_LOG(LS_ERROR) << "Binding error response:"
Jonas Olssond7d762d2018-03-28 09:47:51 +020071 " class=" << attr->eclass()
72 << " number=" << attr->number() << " reason="
73 << attr->reason();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000074 }
75
76 port_->OnStunBindingOrResolveRequestFailed(server_addr_);
77
nisse1bffc1d2016-05-02 08:18:55 -070078 int64_t now = rtc::TimeMillis();
honghaize2af9ef2016-03-03 08:27:47 -080079 if (WithinLifetime(now) &&
Honghai Zhang82d78622016-05-06 11:29:15 -070080 rtc::TimeDiff(now, start_time_) < RETRY_TIMEOUT) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000081 port_->requests_.SendDelayed(
Honghai Zhang351d77b2016-05-20 15:08:29 -070082 new StunBindingRequest(port_, server_addr_, start_time_),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000083 port_->stun_keepalive_delay());
84 }
85 }
Steve Anton1cf1b7d2017-10-30 10:00:15 -070086 void OnTimeout() override {
Mirko Bonadei675513b2017-11-09 11:09:25 +010087 RTC_LOG(LS_ERROR) << "Binding request timed out from "
88 << port_->GetLocalAddress().ToSensitiveString() << " ("
89 << port_->Network()->name() << ")";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000090
91 port_->OnStunBindingOrResolveRequestFailed(server_addr_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000092 }
93
94 private:
honghaize2af9ef2016-03-03 08:27:47 -080095 // Returns true if |now| is within the lifetime of the request (a negative
96 // lifetime means infinite).
honghaiz34b11eb2016-03-16 08:55:44 -070097 bool WithinLifetime(int64_t now) const {
Honghai Zhang351d77b2016-05-20 15:08:29 -070098 int lifetime = port_->stun_keepalive_lifetime();
99 return lifetime < 0 || rtc::TimeDiff(now, start_time_) <= lifetime;
honghaize2af9ef2016-03-03 08:27:47 -0800100 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000101 UDPPort* port_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000102 const rtc::SocketAddress server_addr_;
honghaize2af9ef2016-03-03 08:27:47 -0800103
honghaiz34b11eb2016-03-16 08:55:44 -0700104 int64_t start_time_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000105};
106
107UDPPort::AddressResolver::AddressResolver(
108 rtc::PacketSocketFactory* factory)
109 : socket_factory_(factory) {}
110
111UDPPort::AddressResolver::~AddressResolver() {
112 for (ResolverMap::iterator it = resolvers_.begin();
113 it != resolvers_.end(); ++it) {
Guo-wei Shieh8a4f5472015-10-30 09:12:34 -0700114 // TODO(guoweis): Change to asynchronous DNS resolution to prevent the hang
115 // when passing true to the Destroy() which is a safer way to avoid the code
116 // unloaded before the thread exits. Please see webrtc bug 5139.
117 it->second->Destroy(false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000118 }
119}
120
121void UDPPort::AddressResolver::Resolve(
122 const rtc::SocketAddress& address) {
123 if (resolvers_.find(address) != resolvers_.end())
124 return;
125
126 rtc::AsyncResolverInterface* resolver =
127 socket_factory_->CreateAsyncResolver();
128 resolvers_.insert(
129 std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>(
130 address, resolver));
131
132 resolver->SignalDone.connect(this,
133 &UDPPort::AddressResolver::OnResolveResult);
134
135 resolver->Start(address);
136}
137
138bool UDPPort::AddressResolver::GetResolvedAddress(
139 const rtc::SocketAddress& input,
140 int family,
141 rtc::SocketAddress* output) const {
142 ResolverMap::const_iterator it = resolvers_.find(input);
143 if (it == resolvers_.end())
144 return false;
145
146 return it->second->GetResolvedAddress(family, output);
147}
148
149void UDPPort::AddressResolver::OnResolveResult(
150 rtc::AsyncResolverInterface* resolver) {
151 for (ResolverMap::iterator it = resolvers_.begin();
152 it != resolvers_.end(); ++it) {
153 if (it->second == resolver) {
154 SignalDone(it->first, resolver->GetError());
155 return;
156 }
157 }
158}
159
160UDPPort::UDPPort(rtc::Thread* thread,
161 rtc::PacketSocketFactory* factory,
162 rtc::Network* network,
163 rtc::AsyncPacketSocket* socket,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000164 const std::string& username,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000165 const std::string& password,
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700166 const std::string& origin,
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800167 bool emit_local_for_anyaddress)
Qingsi Wang866e08d2018-03-22 17:54:23 -0700168 : Port(thread, LOCAL_PORT_TYPE, factory, network, username, password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000169 requests_(thread),
170 socket_(socket),
171 error_(0),
172 ready_(false),
Qingsi Wang866e08d2018-03-22 17:54:23 -0700173 stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800174 emit_local_for_anyaddress_(emit_local_for_anyaddress) {
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000175 requests_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000176}
177
178UDPPort::UDPPort(rtc::Thread* thread,
179 rtc::PacketSocketFactory* factory,
180 rtc::Network* network,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200181 uint16_t min_port,
182 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000183 const std::string& username,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000184 const std::string& password,
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700185 const std::string& origin,
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800186 bool emit_local_for_anyaddress)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200187 : Port(thread,
188 LOCAL_PORT_TYPE,
189 factory,
190 network,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200191 min_port,
192 max_port,
193 username,
194 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000195 requests_(thread),
196 socket_(NULL),
197 error_(0),
198 ready_(false),
Qingsi Wang866e08d2018-03-22 17:54:23 -0700199 stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800200 emit_local_for_anyaddress_(emit_local_for_anyaddress) {
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000201 requests_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000202}
203
204bool UDPPort::Init() {
Honghai Zhang351d77b2016-05-20 15:08:29 -0700205 stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000206 if (!SharedSocket()) {
nisseede5da42017-01-12 05:15:36 -0800207 RTC_DCHECK(socket_ == NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000208 socket_ = socket_factory()->CreateUdpSocket(
deadbeef5c3c1042017-08-04 15:01:57 -0700209 rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000210 if (!socket_) {
Jonas Olssond7d762d2018-03-28 09:47:51 +0200211 RTC_LOG(LS_WARNING) << ToString()
212 << ": UDP socket creation failed";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000213 return false;
214 }
215 socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
216 }
stefanc1aeaf02015-10-15 07:26:07 -0700217 socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
219 socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
220 requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
221 return true;
222}
223
224UDPPort::~UDPPort() {
225 if (!SharedSocket())
226 delete socket_;
227}
228
229void UDPPort::PrepareAddress() {
nisseede5da42017-01-12 05:15:36 -0800230 RTC_DCHECK(requests_.empty());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000231 if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
232 OnLocalAddressReady(socket_, socket_->GetLocalAddress());
233 }
234}
235
236void UDPPort::MaybePrepareStunCandidate() {
237 // Sending binding request to the STUN server if address is available to
238 // prepare STUN candidate.
239 if (!server_addresses_.empty()) {
240 SendStunBindingRequests();
241 } else {
242 // Port is done allocating candidates.
243 MaybeSetPortCompleteOrError();
244 }
245}
246
247Connection* UDPPort::CreateConnection(const Candidate& address,
Honghai Zhangf9945b22015-12-15 12:20:13 -0800248 CandidateOrigin origin) {
249 if (!SupportsProtocol(address.protocol())) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000250 return NULL;
Honghai Zhangf9945b22015-12-15 12:20:13 -0800251 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000252
253 if (!IsCompatibleAddress(address.address())) {
254 return NULL;
255 }
256
257 if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
nissec80e7412017-01-11 05:56:46 -0800258 RTC_NOTREACHED();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000259 return NULL;
260 }
261
262 Connection* conn = new ProxyConnection(this, 0, address);
honghaiz36f50e82016-06-01 15:57:03 -0700263 AddOrReplaceConnection(conn);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264 return conn;
265}
266
267int UDPPort::SendTo(const void* data, size_t size,
268 const rtc::SocketAddress& addr,
269 const rtc::PacketOptions& options,
270 bool payload) {
Qingsi Wang6e641e62018-04-11 20:14:17 -0700271 rtc::PacketOptions modified_options(options);
272 CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
273 int sent = socket_->SendTo(data, size, addr, modified_options);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000274 if (sent < 0) {
275 error_ = socket_->GetError();
Jonas Olssond7d762d2018-03-28 09:47:51 +0200276 RTC_LOG(LS_ERROR) << ToString() << ": UDP send of "
277 << size << " bytes failed with error " << error_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000278 }
279 return sent;
280}
281
Honghai Zhang351d77b2016-05-20 15:08:29 -0700282void UDPPort::UpdateNetworkCost() {
283 Port::UpdateNetworkCost();
284 stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
285}
286
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000287int UDPPort::SetOption(rtc::Socket::Option opt, int value) {
288 return socket_->SetOption(opt, value);
289}
290
291int UDPPort::GetOption(rtc::Socket::Option opt, int* value) {
292 return socket_->GetOption(opt, value);
293}
294
295int UDPPort::GetError() {
296 return error_;
297}
298
Steve Anton1cf1b7d2017-10-30 10:00:15 -0700299bool UDPPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
300 const char* data,
301 size_t size,
302 const rtc::SocketAddress& remote_addr,
303 const rtc::PacketTime& packet_time) {
304 // All packets given to UDP port will be consumed.
305 OnReadPacket(socket, data, size, remote_addr, packet_time);
306 return true;
307}
308
309bool UDPPort::SupportsProtocol(const std::string& protocol) const {
310 return protocol == UDP_PROTOCOL_NAME;
311}
312
313ProtocolType UDPPort::GetProtocol() const {
314 return PROTO_UDP;
315}
316
Qingsi Wang72a43a12018-02-20 16:03:18 -0800317void UDPPort::GetStunStats(rtc::Optional<StunStats>* stats) {
318 *stats = stats_;
319}
320
Qingsi Wangdb53f8e2018-02-20 14:45:49 -0800321void UDPPort::set_stun_keepalive_delay(const rtc::Optional<int>& delay) {
Qingsi Wang866e08d2018-03-22 17:54:23 -0700322 stun_keepalive_delay_ = delay.value_or(STUN_KEEPALIVE_INTERVAL);
Qingsi Wangdb53f8e2018-02-20 14:45:49 -0800323}
324
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000325void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
326 const rtc::SocketAddress& address) {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700327 // When adapter enumeration is disabled and binding to the any address, the
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800328 // default local address will be issued as a candidate instead if
329 // |emit_local_for_anyaddress| is true. This is to allow connectivity for
330 // applications which absolutely requires a HOST candidate.
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700331 rtc::SocketAddress addr = address;
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800332
333 // If MaybeSetDefaultLocalAddress fails, we keep the "any" IP so that at
334 // least the port is listening.
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800335 MaybeSetDefaultLocalAddress(&addr);
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700336
337 AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "",
zhihuang26d99c22017-02-13 12:47:27 -0800338 LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, "", false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000339 MaybePrepareStunCandidate();
340}
341
tfarina20a34612015-11-02 16:20:22 -0800342void UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
343 const char* data,
344 size_t size,
345 const rtc::SocketAddress& remote_addr,
346 const rtc::PacketTime& packet_time) {
nisseede5da42017-01-12 05:15:36 -0800347 RTC_DCHECK(socket == socket_);
348 RTC_DCHECK(!remote_addr.IsUnresolvedIP());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000349
350 // Look for a response from the STUN server.
351 // Even if the response doesn't match one of our outstanding requests, we
352 // will eat it because it might be a response to a retransmitted packet, and
353 // we already cleared the request when we got the first response.
354 if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
355 requests_.CheckResponse(data, size);
356 return;
357 }
358
359 if (Connection* conn = GetConnection(remote_addr)) {
360 conn->OnReadPacket(data, size, packet_time);
361 } else {
362 Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
363 }
364}
365
stefanc1aeaf02015-10-15 07:26:07 -0700366void UDPPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
367 const rtc::SentPacket& sent_packet) {
Stefan Holmer55674ff2016-01-14 15:49:16 +0100368 PortInterface::SignalSentPacket(sent_packet);
stefanc1aeaf02015-10-15 07:26:07 -0700369}
370
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000371void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
372 Port::OnReadyToSend();
373}
374
375void UDPPort::SendStunBindingRequests() {
376 // We will keep pinging the stun server to make sure our NAT pin-hole stays
honghaiz45b0efd2015-12-04 08:57:26 -0800377 // open until the deadline (specified in SendStunBindingRequest).
nisseede5da42017-01-12 05:15:36 -0800378 RTC_DCHECK(requests_.empty());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379
380 for (ServerAddresses::const_iterator it = server_addresses_.begin();
381 it != server_addresses_.end(); ++it) {
382 SendStunBindingRequest(*it);
383 }
384}
385
386void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
387 if (!resolver_) {
388 resolver_.reset(new AddressResolver(socket_factory()));
389 resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
390 }
391
Jonas Olssond7d762d2018-03-28 09:47:51 +0200392 RTC_LOG(LS_INFO) << ToString()
393 << ": Starting STUN host lookup for "
394 << stun_addr.ToSensitiveString();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000395 resolver_->Resolve(stun_addr);
396}
397
398void UDPPort::OnResolveResult(const rtc::SocketAddress& input,
399 int error) {
nisseede5da42017-01-12 05:15:36 -0800400 RTC_DCHECK(resolver_.get() != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000401
402 rtc::SocketAddress resolved;
deadbeef5c3c1042017-08-04 15:01:57 -0700403 if (error != 0 || !resolver_->GetResolvedAddress(
404 input, Network()->GetBestIP().family(), &resolved)) {
Jonas Olssond7d762d2018-03-28 09:47:51 +0200405 RTC_LOG(LS_WARNING) << ToString()
406 << ": StunPort: stun host lookup received error "
407 << error;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000408 OnStunBindingOrResolveRequestFailed(input);
409 return;
410 }
411
412 server_addresses_.erase(input);
413
414 if (server_addresses_.find(resolved) == server_addresses_.end()) {
415 server_addresses_.insert(resolved);
416 SendStunBindingRequest(resolved);
417 }
418}
419
tfarina20a34612015-11-02 16:20:22 -0800420void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) {
421 if (stun_addr.IsUnresolvedIP()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000422 ResolveStunAddress(stun_addr);
423
424 } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
425 // Check if |server_addr_| is compatible with the port's ip.
426 if (IsCompatibleAddress(stun_addr)) {
Honghai Zhang351d77b2016-05-20 15:08:29 -0700427 requests_.Send(
428 new StunBindingRequest(this, stun_addr, rtc::TimeMillis()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000429 } else {
430 // Since we can't send stun messages to the server, we should mark this
431 // port ready.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100432 RTC_LOG(LS_WARNING) << "STUN server address is incompatible.";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000433 OnStunBindingOrResolveRequestFailed(stun_addr);
434 }
435 }
436}
437
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800438bool UDPPort::MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const {
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800439 if (!addr->IsAnyIP() || !emit_local_for_anyaddress_ ||
440 !Network()->default_local_address_provider()) {
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800441 return true;
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800442 }
443 rtc::IPAddress default_address;
444 bool result =
445 Network()->default_local_address_provider()->GetDefaultLocalAddress(
446 addr->family(), &default_address);
Guo-wei Shieh953eabc2015-11-24 12:00:33 -0800447 if (!result || default_address.IsNil()) {
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800448 return false;
449 }
450
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800451 addr->SetIP(default_address);
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800452 return true;
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800453}
454
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000455void UDPPort::OnStunBindingRequestSucceeded(
Qingsi Wang72a43a12018-02-20 16:03:18 -0800456 int rtt_ms,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000457 const rtc::SocketAddress& stun_server_addr,
458 const rtc::SocketAddress& stun_reflected_addr) {
Qingsi Wang72a43a12018-02-20 16:03:18 -0800459 RTC_DCHECK(stats_.stun_binding_responses_received <
460 stats_.stun_binding_requests_sent);
461 stats_.stun_binding_responses_received++;
462 stats_.stun_binding_rtt_ms_total += rtt_ms;
463 stats_.stun_binding_rtt_ms_squared_total += rtt_ms * rtt_ms;
Qingsi Wang4ff54432018-03-01 18:25:20 -0800464 if (bind_request_succeeded_servers_.find(stun_server_addr) !=
465 bind_request_succeeded_servers_.end()) {
466 return;
467 }
468 bind_request_succeeded_servers_.insert(stun_server_addr);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000469 // If socket is shared and |stun_reflected_addr| is equal to local socket
470 // address, or if the same address has been added by another STUN server,
471 // then discarding the stun address.
472 // For STUN, related address is the local socket address.
473 if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) &&
474 !HasCandidateWithAddress(stun_reflected_addr)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000475 rtc::SocketAddress related_address = socket_->GetLocalAddress();
Guo-wei Shiehe03cab92015-11-11 11:11:19 -0800476 // If we can't stamp the related address correctly, empty it to avoid leak.
Taylor Brandstetter417eebe2016-05-23 16:02:19 -0700477 if (!MaybeSetDefaultLocalAddress(&related_address)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000478 related_address = rtc::EmptySocketAddressWithFamily(
479 related_address.family());
480 }
481
zhihuang26d99c22017-02-13 12:47:27 -0800482 std::ostringstream url;
483 url << "stun:" << stun_server_addr.ipaddr().ToString() << ":"
484 << stun_server_addr.port();
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700485 AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address,
486 UDP_PROTOCOL_NAME, "", "", STUN_PORT_TYPE,
zhihuang26d99c22017-02-13 12:47:27 -0800487 ICE_TYPE_PREFERENCE_SRFLX, 0, url.str(), false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000488 }
489 MaybeSetPortCompleteOrError();
490}
491
492void UDPPort::OnStunBindingOrResolveRequestFailed(
493 const rtc::SocketAddress& stun_server_addr) {
494 if (bind_request_failed_servers_.find(stun_server_addr) !=
495 bind_request_failed_servers_.end()) {
496 return;
497 }
498 bind_request_failed_servers_.insert(stun_server_addr);
499 MaybeSetPortCompleteOrError();
500}
501
502void UDPPort::MaybeSetPortCompleteOrError() {
503 if (ready_)
504 return;
505
506 // Do not set port ready if we are still waiting for bind responses.
507 const size_t servers_done_bind_request = bind_request_failed_servers_.size() +
508 bind_request_succeeded_servers_.size();
509 if (server_addresses_.size() != servers_done_bind_request) {
510 return;
511 }
512
513 // Setting ready status.
514 ready_ = true;
515
516 // The port is "completed" if there is no stun server provided, or the bind
517 // request succeeded for any stun server, or the socket is shared.
518 if (server_addresses_.empty() ||
519 bind_request_succeeded_servers_.size() > 0 ||
520 SharedSocket()) {
521 SignalPortComplete(this);
522 } else {
523 SignalPortError(this);
524 }
525}
526
Steve Anton6c38cc72017-11-29 10:25:58 -0800527// TODO(?): merge this with SendTo above.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000528void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
529 StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
530 rtc::PacketOptions options(DefaultDscpValue());
Qingsi Wang6e641e62018-04-11 20:14:17 -0700531 options.info_signaled_after_sent.packet_type = rtc::PacketType::kStunMessage;
532 CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
Qingsi Wang72a43a12018-02-20 16:03:18 -0800533 if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100534 RTC_LOG_ERR_EX(LERROR, socket_->GetError()) << "sendto";
Qingsi Wang72a43a12018-02-20 16:03:18 -0800535 }
536 stats_.stun_binding_requests_sent++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000537}
538
539bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
540 const std::vector<Candidate>& existing_candidates = Candidates();
541 std::vector<Candidate>::const_iterator it = existing_candidates.begin();
542 for (; it != existing_candidates.end(); ++it) {
543 if (it->address() == addr)
544 return true;
545 }
546 return false;
547}
548
Steve Anton1cf1b7d2017-10-30 10:00:15 -0700549StunPort* StunPort::Create(rtc::Thread* thread,
550 rtc::PacketSocketFactory* factory,
551 rtc::Network* network,
552 uint16_t min_port,
553 uint16_t max_port,
554 const std::string& username,
555 const std::string& password,
556 const ServerAddresses& servers,
Qingsi Wang4ff54432018-03-01 18:25:20 -0800557 const std::string& origin,
558 rtc::Optional<int> stun_keepalive_interval) {
Steve Anton1cf1b7d2017-10-30 10:00:15 -0700559 StunPort* port = new StunPort(thread, factory, network, min_port, max_port,
560 username, password, servers, origin);
Qingsi Wang4ff54432018-03-01 18:25:20 -0800561 port->set_stun_keepalive_delay(stun_keepalive_interval);
Steve Anton1cf1b7d2017-10-30 10:00:15 -0700562 if (!port->Init()) {
563 delete port;
564 port = NULL;
565 }
566 return port;
567}
568
569StunPort::StunPort(rtc::Thread* thread,
570 rtc::PacketSocketFactory* factory,
571 rtc::Network* network,
572 uint16_t min_port,
573 uint16_t max_port,
574 const std::string& username,
575 const std::string& password,
576 const ServerAddresses& servers,
577 const std::string& origin)
578 : UDPPort(thread,
579 factory,
580 network,
581 min_port,
582 max_port,
583 username,
584 password,
585 origin,
586 false) {
587 // UDPPort will set these to local udp, updating these to STUN.
588 set_type(STUN_PORT_TYPE);
589 set_server_addresses(servers);
590}
591
592void StunPort::PrepareAddress() {
593 SendStunBindingRequests();
594}
595
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596} // namespace cricket