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