xref: /aosp_15_r20/external/webrtc/p2p/base/stun_port.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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