1 /*
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
11 #include "p2p/base/stun_port.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "absl/memory/memory.h"
17 #include "absl/strings/string_view.h"
18 #include "api/transport/stun.h"
19 #include "p2p/base/connection.h"
20 #include "p2p/base/p2p_constants.h"
21 #include "p2p/base/port_allocator.h"
22 #include "rtc_base/async_resolver_interface.h"
23 #include "rtc_base/checks.h"
24 #include "rtc_base/experiments/field_trial_parser.h"
25 #include "rtc_base/helpers.h"
26 #include "rtc_base/ip_address.h"
27 #include "rtc_base/logging.h"
28 #include "rtc_base/strings/string_builder.h"
29
30 namespace cricket {
31
32 namespace {
33
ResolveStunHostnameForFamily(const webrtc::FieldTrialsView & field_trials)34 bool ResolveStunHostnameForFamily(const webrtc::FieldTrialsView& field_trials) {
35 // Bug fix for STUN hostname resolution on IPv6.
36 // Field trial key reserved in bugs.webrtc.org/14334
37 static constexpr char field_trial_name[] =
38 "WebRTC-IPv6NetworkResolutionFixes";
39 if (!field_trials.IsEnabled(field_trial_name)) {
40 return false;
41 }
42
43 webrtc::FieldTrialParameter<bool> resolve_stun_hostname_for_family(
44 "ResolveStunHostnameForFamily", /*default_value=*/false);
45 webrtc::ParseFieldTrial({&resolve_stun_hostname_for_family},
46 field_trials.Lookup(field_trial_name));
47 return resolve_stun_hostname_for_family;
48 }
49
50 } // namespace
51
52 // TODO(?): Move these to a common place (used in relayport too)
53 const int RETRY_TIMEOUT = 50 * 1000; // 50 seconds
54
55 // Stop logging errors in UDPPort::SendTo after we have logged
56 // `kSendErrorLogLimit` messages. Start again after a successful send.
57 const int kSendErrorLogLimit = 5;
58
59 // Handles a binding request sent to the STUN server.
60 class StunBindingRequest : public StunRequest {
61 public:
StunBindingRequest(UDPPort * port,const rtc::SocketAddress & addr,int64_t start_time)62 StunBindingRequest(UDPPort* port,
63 const rtc::SocketAddress& addr,
64 int64_t start_time)
65 : StunRequest(port->request_manager(),
66 std::make_unique<StunMessage>(STUN_BINDING_REQUEST)),
67 port_(port),
68 server_addr_(addr),
69 start_time_(start_time) {}
70
server_addr() const71 const rtc::SocketAddress& server_addr() const { return server_addr_; }
72
OnResponse(StunMessage * response)73 void OnResponse(StunMessage* response) override {
74 const StunAddressAttribute* addr_attr =
75 response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
76 if (!addr_attr) {
77 RTC_LOG(LS_ERROR) << "Binding response missing mapped address.";
78 } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
79 addr_attr->family() != STUN_ADDRESS_IPV6) {
80 RTC_LOG(LS_ERROR) << "Binding address has bad family";
81 } else {
82 rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
83 port_->OnStunBindingRequestSucceeded(this->Elapsed(), server_addr_, addr);
84 }
85
86 // The keep-alive requests will be stopped after its lifetime has passed.
87 if (WithinLifetime(rtc::TimeMillis())) {
88 port_->request_manager_.SendDelayed(
89 new StunBindingRequest(port_, server_addr_, start_time_),
90 port_->stun_keepalive_delay());
91 }
92 }
93
OnErrorResponse(StunMessage * response)94 void OnErrorResponse(StunMessage* response) override {
95 const StunErrorCodeAttribute* attr = response->GetErrorCode();
96 if (!attr) {
97 RTC_LOG(LS_ERROR) << "Missing binding response error code.";
98 } else {
99 RTC_LOG(LS_ERROR) << "Binding error response:"
100 " class="
101 << attr->eclass() << " number=" << attr->number()
102 << " reason=" << attr->reason();
103 }
104
105 port_->OnStunBindingOrResolveRequestFailed(
106 server_addr_, attr ? attr->number() : STUN_ERROR_GLOBAL_FAILURE,
107 attr ? attr->reason()
108 : "STUN binding response with no error code attribute.");
109
110 int64_t now = rtc::TimeMillis();
111 if (WithinLifetime(now) &&
112 rtc::TimeDiff(now, start_time_) < RETRY_TIMEOUT) {
113 port_->request_manager_.SendDelayed(
114 new StunBindingRequest(port_, server_addr_, start_time_),
115 port_->stun_keepalive_delay());
116 }
117 }
OnTimeout()118 void OnTimeout() override {
119 RTC_LOG(LS_ERROR) << "Binding request timed out from "
120 << port_->GetLocalAddress().ToSensitiveString() << " ("
121 << port_->Network()->name() << ")";
122 port_->OnStunBindingOrResolveRequestFailed(
123 server_addr_, SERVER_NOT_REACHABLE_ERROR,
124 "STUN binding request timed out.");
125 }
126
127 private:
128 // Returns true if `now` is within the lifetime of the request (a negative
129 // lifetime means infinite).
WithinLifetime(int64_t now) const130 bool WithinLifetime(int64_t now) const {
131 int lifetime = port_->stun_keepalive_lifetime();
132 return lifetime < 0 || rtc::TimeDiff(now, start_time_) <= lifetime;
133 }
134
135 UDPPort* port_;
136 const rtc::SocketAddress server_addr_;
137
138 int64_t start_time_;
139 };
140
AddressResolver(rtc::PacketSocketFactory * factory,std::function<void (const rtc::SocketAddress &,int)> done_callback)141 UDPPort::AddressResolver::AddressResolver(
142 rtc::PacketSocketFactory* factory,
143 std::function<void(const rtc::SocketAddress&, int)> done_callback)
144 : socket_factory_(factory), done_(std::move(done_callback)) {}
145
Resolve(const rtc::SocketAddress & address,int family,const webrtc::FieldTrialsView & field_trials)146 void UDPPort::AddressResolver::Resolve(
147 const rtc::SocketAddress& address,
148 int family,
149 const webrtc::FieldTrialsView& field_trials) {
150 if (resolvers_.find(address) != resolvers_.end())
151 return;
152
153 auto resolver = socket_factory_->CreateAsyncDnsResolver();
154 auto resolver_ptr = resolver.get();
155 std::pair<rtc::SocketAddress,
156 std::unique_ptr<webrtc::AsyncDnsResolverInterface>>
157 pair = std::make_pair(address, std::move(resolver));
158
159 resolvers_.insert(std::move(pair));
160 auto callback = [this, address] {
161 ResolverMap::const_iterator it = resolvers_.find(address);
162 if (it != resolvers_.end()) {
163 done_(it->first, it->second->result().GetError());
164 }
165 };
166 if (ResolveStunHostnameForFamily(field_trials)) {
167 resolver_ptr->Start(address, family, std::move(callback));
168 } else {
169 resolver_ptr->Start(address, std::move(callback));
170 }
171 }
172
GetResolvedAddress(const rtc::SocketAddress & input,int family,rtc::SocketAddress * output) const173 bool UDPPort::AddressResolver::GetResolvedAddress(
174 const rtc::SocketAddress& input,
175 int family,
176 rtc::SocketAddress* output) const {
177 ResolverMap::const_iterator it = resolvers_.find(input);
178 if (it == resolvers_.end())
179 return false;
180
181 return it->second->result().GetResolvedAddress(family, output);
182 }
183
UDPPort(rtc::Thread * thread,rtc::PacketSocketFactory * factory,const rtc::Network * network,rtc::AsyncPacketSocket * socket,absl::string_view username,absl::string_view password,bool emit_local_for_anyaddress,const webrtc::FieldTrialsView * field_trials)184 UDPPort::UDPPort(rtc::Thread* thread,
185 rtc::PacketSocketFactory* factory,
186 const rtc::Network* network,
187 rtc::AsyncPacketSocket* socket,
188 absl::string_view username,
189 absl::string_view password,
190 bool emit_local_for_anyaddress,
191 const webrtc::FieldTrialsView* field_trials)
192 : Port(thread,
193 LOCAL_PORT_TYPE,
194 factory,
195 network,
196 username,
197 password,
198 field_trials),
199 request_manager_(
200 thread,
201 [this](const void* data, size_t size, StunRequest* request) {
202 OnSendPacket(data, size, request);
203 }),
204 socket_(socket),
205 error_(0),
206 ready_(false),
207 stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
208 dscp_(rtc::DSCP_NO_CHANGE),
209 emit_local_for_anyaddress_(emit_local_for_anyaddress) {}
210
UDPPort(rtc::Thread * thread,rtc::PacketSocketFactory * factory,const rtc::Network * network,uint16_t min_port,uint16_t max_port,absl::string_view username,absl::string_view password,bool emit_local_for_anyaddress,const webrtc::FieldTrialsView * field_trials)211 UDPPort::UDPPort(rtc::Thread* thread,
212 rtc::PacketSocketFactory* factory,
213 const rtc::Network* network,
214 uint16_t min_port,
215 uint16_t max_port,
216 absl::string_view username,
217 absl::string_view password,
218 bool emit_local_for_anyaddress,
219 const webrtc::FieldTrialsView* field_trials)
220 : Port(thread,
221 LOCAL_PORT_TYPE,
222 factory,
223 network,
224 min_port,
225 max_port,
226 username,
227 password,
228 field_trials),
229 request_manager_(
230 thread,
231 [this](const void* data, size_t size, StunRequest* request) {
232 OnSendPacket(data, size, request);
233 }),
234 socket_(nullptr),
235 error_(0),
236 ready_(false),
237 stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
238 dscp_(rtc::DSCP_NO_CHANGE),
239 emit_local_for_anyaddress_(emit_local_for_anyaddress) {}
240
Init()241 bool UDPPort::Init() {
242 stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
243 if (!SharedSocket()) {
244 RTC_DCHECK(socket_ == nullptr);
245 socket_ = socket_factory()->CreateUdpSocket(
246 rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
247 if (!socket_) {
248 RTC_LOG(LS_WARNING) << ToString() << ": UDP socket creation failed";
249 return false;
250 }
251 socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
252 }
253 socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket);
254 socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
255 socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
256 return true;
257 }
258
~UDPPort()259 UDPPort::~UDPPort() {
260 if (!SharedSocket())
261 delete socket_;
262 }
263
PrepareAddress()264 void UDPPort::PrepareAddress() {
265 RTC_DCHECK(request_manager_.empty());
266 if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
267 OnLocalAddressReady(socket_, socket_->GetLocalAddress());
268 }
269 }
270
MaybePrepareStunCandidate()271 void UDPPort::MaybePrepareStunCandidate() {
272 // Sending binding request to the STUN server if address is available to
273 // prepare STUN candidate.
274 if (!server_addresses_.empty()) {
275 SendStunBindingRequests();
276 } else {
277 // Port is done allocating candidates.
278 MaybeSetPortCompleteOrError();
279 }
280 }
281
CreateConnection(const Candidate & address,CandidateOrigin origin)282 Connection* UDPPort::CreateConnection(const Candidate& address,
283 CandidateOrigin origin) {
284 if (!SupportsProtocol(address.protocol())) {
285 return nullptr;
286 }
287
288 if (!IsCompatibleAddress(address.address())) {
289 return nullptr;
290 }
291
292 // In addition to DCHECK-ing the non-emptiness of local candidates, we also
293 // skip this Port with null if there are latent bugs to violate it; otherwise
294 // it would lead to a crash when accessing the local candidate of the
295 // connection that would be created below.
296 if (Candidates().empty()) {
297 RTC_DCHECK_NOTREACHED();
298 return nullptr;
299 }
300 // When the socket is shared, the srflx candidate is gathered by the UDPPort.
301 // The assumption here is that
302 // 1) if the IP concealment with mDNS is not enabled, the gathering of the
303 // host candidate of this port (which is synchronous),
304 // 2) or otherwise if enabled, the start of name registration of the host
305 // candidate (as the start of asynchronous gathering)
306 // is always before the gathering of a srflx candidate (and any prflx
307 // candidate).
308 //
309 // See also the definition of MdnsNameRegistrationStatus::kNotStarted in
310 // port.h.
311 RTC_DCHECK(!SharedSocket() || Candidates()[0].type() == LOCAL_PORT_TYPE ||
312 mdns_name_registration_status() !=
313 MdnsNameRegistrationStatus::kNotStarted);
314
315 Connection* conn = new ProxyConnection(NewWeakPtr(), 0, address);
316 AddOrReplaceConnection(conn);
317 return conn;
318 }
319
SendTo(const void * data,size_t size,const rtc::SocketAddress & addr,const rtc::PacketOptions & options,bool payload)320 int UDPPort::SendTo(const void* data,
321 size_t size,
322 const rtc::SocketAddress& addr,
323 const rtc::PacketOptions& options,
324 bool payload) {
325 rtc::PacketOptions modified_options(options);
326 CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
327 int sent = socket_->SendTo(data, size, addr, modified_options);
328 if (sent < 0) {
329 error_ = socket_->GetError();
330 // Rate limiting added for crbug.com/856088.
331 // TODO(webrtc:9622): Use general rate limiting mechanism once it exists.
332 if (send_error_count_ < kSendErrorLogLimit) {
333 ++send_error_count_;
334 RTC_LOG(LS_ERROR) << ToString() << ": UDP send of " << size
335 << " bytes to host " << addr.ToSensitiveString() << " ("
336 << addr.ToResolvedSensitiveString()
337 << ") failed with error " << error_;
338 }
339 } else {
340 send_error_count_ = 0;
341 }
342 return sent;
343 }
344
UpdateNetworkCost()345 void UDPPort::UpdateNetworkCost() {
346 Port::UpdateNetworkCost();
347 stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
348 }
349
StunDscpValue() const350 rtc::DiffServCodePoint UDPPort::StunDscpValue() const {
351 return dscp_;
352 }
353
SetOption(rtc::Socket::Option opt,int value)354 int UDPPort::SetOption(rtc::Socket::Option opt, int value) {
355 if (opt == rtc::Socket::OPT_DSCP) {
356 // Save value for future packets we instantiate.
357 dscp_ = static_cast<rtc::DiffServCodePoint>(value);
358 }
359 return socket_->SetOption(opt, value);
360 }
361
GetOption(rtc::Socket::Option opt,int * value)362 int UDPPort::GetOption(rtc::Socket::Option opt, int* value) {
363 return socket_->GetOption(opt, value);
364 }
365
GetError()366 int UDPPort::GetError() {
367 return error_;
368 }
369
HandleIncomingPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & remote_addr,int64_t packet_time_us)370 bool UDPPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
371 const char* data,
372 size_t size,
373 const rtc::SocketAddress& remote_addr,
374 int64_t packet_time_us) {
375 // All packets given to UDP port will be consumed.
376 OnReadPacket(socket, data, size, remote_addr, packet_time_us);
377 return true;
378 }
379
SupportsProtocol(absl::string_view protocol) const380 bool UDPPort::SupportsProtocol(absl::string_view protocol) const {
381 return protocol == UDP_PROTOCOL_NAME;
382 }
383
GetProtocol() const384 ProtocolType UDPPort::GetProtocol() const {
385 return PROTO_UDP;
386 }
387
GetStunStats(absl::optional<StunStats> * stats)388 void UDPPort::GetStunStats(absl::optional<StunStats>* stats) {
389 *stats = stats_;
390 }
391
set_stun_keepalive_delay(const absl::optional<int> & delay)392 void UDPPort::set_stun_keepalive_delay(const absl::optional<int>& delay) {
393 stun_keepalive_delay_ = delay.value_or(STUN_KEEPALIVE_INTERVAL);
394 }
395
OnLocalAddressReady(rtc::AsyncPacketSocket * socket,const rtc::SocketAddress & address)396 void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
397 const rtc::SocketAddress& address) {
398 // When adapter enumeration is disabled and binding to the any address, the
399 // default local address will be issued as a candidate instead if
400 // `emit_local_for_anyaddress` is true. This is to allow connectivity for
401 // applications which absolutely requires a HOST candidate.
402 rtc::SocketAddress addr = address;
403
404 // If MaybeSetDefaultLocalAddress fails, we keep the "any" IP so that at
405 // least the port is listening.
406 MaybeSetDefaultLocalAddress(&addr);
407
408 AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "",
409 LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, "", false);
410 MaybePrepareStunCandidate();
411 }
412
PostAddAddress(bool is_final)413 void UDPPort::PostAddAddress(bool is_final) {
414 MaybeSetPortCompleteOrError();
415 }
416
OnReadPacket(rtc::AsyncPacketSocket * socket,const char * data,size_t size,const rtc::SocketAddress & remote_addr,const int64_t & packet_time_us)417 void UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
418 const char* data,
419 size_t size,
420 const rtc::SocketAddress& remote_addr,
421 const int64_t& packet_time_us) {
422 RTC_DCHECK(socket == socket_);
423 RTC_DCHECK(!remote_addr.IsUnresolvedIP());
424
425 // Look for a response from the STUN server.
426 // Even if the response doesn't match one of our outstanding requests, we
427 // will eat it because it might be a response to a retransmitted packet, and
428 // we already cleared the request when we got the first response.
429 if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
430 request_manager_.CheckResponse(data, size);
431 return;
432 }
433
434 if (Connection* conn = GetConnection(remote_addr)) {
435 conn->OnReadPacket(data, size, packet_time_us);
436 } else {
437 Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
438 }
439 }
440
OnSentPacket(rtc::AsyncPacketSocket * socket,const rtc::SentPacket & sent_packet)441 void UDPPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
442 const rtc::SentPacket& sent_packet) {
443 PortInterface::SignalSentPacket(sent_packet);
444 }
445
OnReadyToSend(rtc::AsyncPacketSocket * socket)446 void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
447 Port::OnReadyToSend();
448 }
449
SendStunBindingRequests()450 void UDPPort::SendStunBindingRequests() {
451 // We will keep pinging the stun server to make sure our NAT pin-hole stays
452 // open until the deadline (specified in SendStunBindingRequest).
453 RTC_DCHECK(request_manager_.empty());
454
455 for (ServerAddresses::const_iterator it = server_addresses_.begin();
456 it != server_addresses_.end();) {
457 // sending a STUN binding request may cause the current SocketAddress to be
458 // erased from the set, invalidating the loop iterator before it is
459 // incremented (even if the SocketAddress itself still exists). So make a
460 // copy of the loop iterator, which may be safely invalidated.
461 ServerAddresses::const_iterator addr = it++;
462 SendStunBindingRequest(*addr);
463 }
464 }
465
ResolveStunAddress(const rtc::SocketAddress & stun_addr)466 void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
467 if (!resolver_) {
468 resolver_.reset(new AddressResolver(
469 socket_factory(), [&](const rtc::SocketAddress& input, int error) {
470 OnResolveResult(input, error);
471 }));
472 }
473
474 RTC_LOG(LS_INFO) << ToString() << ": Starting STUN host lookup for "
475 << stun_addr.ToSensitiveString();
476 resolver_->Resolve(stun_addr, Network()->family(), field_trials());
477 }
478
OnResolveResult(const rtc::SocketAddress & input,int error)479 void UDPPort::OnResolveResult(const rtc::SocketAddress& input, int error) {
480 RTC_DCHECK(resolver_.get() != nullptr);
481
482 rtc::SocketAddress resolved;
483 if (error != 0 || !resolver_->GetResolvedAddress(
484 input, Network()->GetBestIP().family(), &resolved)) {
485 RTC_LOG(LS_WARNING) << ToString()
486 << ": StunPort: stun host lookup received error "
487 << error;
488 OnStunBindingOrResolveRequestFailed(input, SERVER_NOT_REACHABLE_ERROR,
489 "STUN host lookup received error.");
490 return;
491 }
492
493 server_addresses_.erase(input);
494
495 if (server_addresses_.find(resolved) == server_addresses_.end()) {
496 server_addresses_.insert(resolved);
497 SendStunBindingRequest(resolved);
498 }
499 }
500
SendStunBindingRequest(const rtc::SocketAddress & stun_addr)501 void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr) {
502 if (stun_addr.IsUnresolvedIP()) {
503 ResolveStunAddress(stun_addr);
504
505 } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
506 // Check if `server_addr_` is compatible with the port's ip.
507 if (IsCompatibleAddress(stun_addr)) {
508 request_manager_.Send(
509 new StunBindingRequest(this, stun_addr, rtc::TimeMillis()));
510 } else {
511 // Since we can't send stun messages to the server, we should mark this
512 // port ready.
513 const char* reason = "STUN server address is incompatible.";
514 RTC_LOG(LS_WARNING) << reason;
515 OnStunBindingOrResolveRequestFailed(stun_addr, SERVER_NOT_REACHABLE_ERROR,
516 reason);
517 }
518 }
519 }
520
MaybeSetDefaultLocalAddress(rtc::SocketAddress * addr) const521 bool UDPPort::MaybeSetDefaultLocalAddress(rtc::SocketAddress* addr) const {
522 if (!addr->IsAnyIP() || !emit_local_for_anyaddress_ ||
523 !Network()->default_local_address_provider()) {
524 return true;
525 }
526 rtc::IPAddress default_address;
527 bool result =
528 Network()->default_local_address_provider()->GetDefaultLocalAddress(
529 addr->family(), &default_address);
530 if (!result || default_address.IsNil()) {
531 return false;
532 }
533
534 addr->SetIP(default_address);
535 return true;
536 }
537
OnStunBindingRequestSucceeded(int rtt_ms,const rtc::SocketAddress & stun_server_addr,const rtc::SocketAddress & stun_reflected_addr)538 void UDPPort::OnStunBindingRequestSucceeded(
539 int rtt_ms,
540 const rtc::SocketAddress& stun_server_addr,
541 const rtc::SocketAddress& stun_reflected_addr) {
542 RTC_DCHECK(stats_.stun_binding_responses_received <
543 stats_.stun_binding_requests_sent);
544 stats_.stun_binding_responses_received++;
545 stats_.stun_binding_rtt_ms_total += rtt_ms;
546 stats_.stun_binding_rtt_ms_squared_total += rtt_ms * rtt_ms;
547 if (bind_request_succeeded_servers_.find(stun_server_addr) !=
548 bind_request_succeeded_servers_.end()) {
549 return;
550 }
551 bind_request_succeeded_servers_.insert(stun_server_addr);
552 // If socket is shared and `stun_reflected_addr` is equal to local socket
553 // address and mDNS obfuscation is not enabled, or if the same address has
554 // been added by another STUN server, then discarding the stun address.
555 // For STUN, related address is the local socket address.
556 if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress() ||
557 Network()->GetMdnsResponder() != nullptr) &&
558 !HasStunCandidateWithAddress(stun_reflected_addr)) {
559 rtc::SocketAddress related_address = socket_->GetLocalAddress();
560 // If we can't stamp the related address correctly, empty it to avoid leak.
561 if (!MaybeSetDefaultLocalAddress(&related_address)) {
562 related_address =
563 rtc::EmptySocketAddressWithFamily(related_address.family());
564 }
565
566 rtc::StringBuilder url;
567 url << "stun:" << stun_server_addr.hostname() << ":"
568 << stun_server_addr.port();
569 AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address,
570 UDP_PROTOCOL_NAME, "", "", STUN_PORT_TYPE,
571 ICE_TYPE_PREFERENCE_SRFLX, 0, url.str(), false);
572 }
573 MaybeSetPortCompleteOrError();
574 }
575
OnStunBindingOrResolveRequestFailed(const rtc::SocketAddress & stun_server_addr,int error_code,absl::string_view reason)576 void UDPPort::OnStunBindingOrResolveRequestFailed(
577 const rtc::SocketAddress& stun_server_addr,
578 int error_code,
579 absl::string_view reason) {
580 rtc::StringBuilder url;
581 url << "stun:" << stun_server_addr.ToString();
582 SignalCandidateError(
583 this, IceCandidateErrorEvent(GetLocalAddress().HostAsSensitiveURIString(),
584 GetLocalAddress().port(), url.str(),
585 error_code, reason));
586 if (bind_request_failed_servers_.find(stun_server_addr) !=
587 bind_request_failed_servers_.end()) {
588 return;
589 }
590 bind_request_failed_servers_.insert(stun_server_addr);
591 MaybeSetPortCompleteOrError();
592 }
593
MaybeSetPortCompleteOrError()594 void UDPPort::MaybeSetPortCompleteOrError() {
595 if (mdns_name_registration_status() ==
596 MdnsNameRegistrationStatus::kInProgress) {
597 return;
598 }
599
600 if (ready_) {
601 return;
602 }
603
604 // Do not set port ready if we are still waiting for bind responses.
605 const size_t servers_done_bind_request =
606 bind_request_failed_servers_.size() +
607 bind_request_succeeded_servers_.size();
608 if (server_addresses_.size() != servers_done_bind_request) {
609 return;
610 }
611
612 // Setting ready status.
613 ready_ = true;
614
615 // The port is "completed" if there is no stun server provided, or the bind
616 // request succeeded for any stun server, or the socket is shared.
617 if (server_addresses_.empty() || bind_request_succeeded_servers_.size() > 0 ||
618 SharedSocket()) {
619 SignalPortComplete(this);
620 } else {
621 SignalPortError(this);
622 }
623 }
624
625 // TODO(?): merge this with SendTo above.
OnSendPacket(const void * data,size_t size,StunRequest * req)626 void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
627 StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
628 rtc::PacketOptions options(StunDscpValue());
629 options.info_signaled_after_sent.packet_type = rtc::PacketType::kStunMessage;
630 CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
631 if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) {
632 RTC_LOG_ERR_EX(LS_ERROR, socket_->GetError())
633 << "UDP send of " << size << " bytes to host "
634 << sreq->server_addr().ToSensitiveString() << " ("
635 << sreq->server_addr().ToResolvedSensitiveString()
636 << ") failed with error " << error_;
637 }
638 stats_.stun_binding_requests_sent++;
639 }
640
HasStunCandidateWithAddress(const rtc::SocketAddress & addr) const641 bool UDPPort::HasStunCandidateWithAddress(
642 const rtc::SocketAddress& addr) const {
643 const std::vector<Candidate>& existing_candidates = Candidates();
644 std::vector<Candidate>::const_iterator it = existing_candidates.begin();
645 for (; it != existing_candidates.end(); ++it) {
646 if (it->type() == STUN_PORT_TYPE && it->address() == addr)
647 return true;
648 }
649 return false;
650 }
651
Create(rtc::Thread * thread,rtc::PacketSocketFactory * factory,const rtc::Network * network,uint16_t min_port,uint16_t max_port,absl::string_view username,absl::string_view password,const ServerAddresses & servers,absl::optional<int> stun_keepalive_interval,const webrtc::FieldTrialsView * field_trials)652 std::unique_ptr<StunPort> StunPort::Create(
653 rtc::Thread* thread,
654 rtc::PacketSocketFactory* factory,
655 const rtc::Network* network,
656 uint16_t min_port,
657 uint16_t max_port,
658 absl::string_view username,
659 absl::string_view password,
660 const ServerAddresses& servers,
661 absl::optional<int> stun_keepalive_interval,
662 const webrtc::FieldTrialsView* field_trials) {
663 // Using `new` to access a non-public constructor.
664 auto port = absl::WrapUnique(new StunPort(thread, factory, network, min_port,
665 max_port, username, password,
666 servers, field_trials));
667 port->set_stun_keepalive_delay(stun_keepalive_interval);
668 if (!port->Init()) {
669 return nullptr;
670 }
671 return port;
672 }
673
StunPort(rtc::Thread * thread,rtc::PacketSocketFactory * factory,const rtc::Network * network,uint16_t min_port,uint16_t max_port,absl::string_view username,absl::string_view password,const ServerAddresses & servers,const webrtc::FieldTrialsView * field_trials)674 StunPort::StunPort(rtc::Thread* thread,
675 rtc::PacketSocketFactory* factory,
676 const rtc::Network* network,
677 uint16_t min_port,
678 uint16_t max_port,
679 absl::string_view username,
680 absl::string_view password,
681 const ServerAddresses& servers,
682 const webrtc::FieldTrialsView* field_trials)
683 : UDPPort(thread,
684 factory,
685 network,
686 min_port,
687 max_port,
688 username,
689 password,
690 false,
691 field_trials) {
692 // UDPPort will set these to local udp, updating these to STUN.
693 set_type(STUN_PORT_TYPE);
694 set_server_addresses(servers);
695 }
696
PrepareAddress()697 void StunPort::PrepareAddress() {
698 SendStunBindingRequests();
699 }
700
701 } // namespace cricket
702