xref: /aosp_15_r20/external/webrtc/p2p/base/stun_request.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/stun_request.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker #include <vector>
17*d9f75844SAndroid Build Coastguard Worker 
18*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
19*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/pending_task_safety_flag.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/helpers.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/string_encode.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"  // For TimeMillis
25*d9f75844SAndroid Build Coastguard Worker 
26*d9f75844SAndroid Build Coastguard Worker namespace cricket {
27*d9f75844SAndroid Build Coastguard Worker using ::webrtc::SafeTask;
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker // RFC 5389 says SHOULD be 500ms.
30*d9f75844SAndroid Build Coastguard Worker // For years, this was 100ms, but for networks that
31*d9f75844SAndroid Build Coastguard Worker // experience moments of high RTT (such as 2G networks), this doesn't
32*d9f75844SAndroid Build Coastguard Worker // work well.
33*d9f75844SAndroid Build Coastguard Worker const int STUN_INITIAL_RTO = 250;  // milliseconds
34*d9f75844SAndroid Build Coastguard Worker 
35*d9f75844SAndroid Build Coastguard Worker // The timeout doubles each retransmission, up to this many times
36*d9f75844SAndroid Build Coastguard Worker // RFC 5389 says SHOULD retransmit 7 times.
37*d9f75844SAndroid Build Coastguard Worker // This has been 8 for years (not sure why).
38*d9f75844SAndroid Build Coastguard Worker const int STUN_MAX_RETRANSMISSIONS = 8;           // Total sends: 9
39*d9f75844SAndroid Build Coastguard Worker 
40*d9f75844SAndroid Build Coastguard Worker // We also cap the doubling, even though the standard doesn't say to.
41*d9f75844SAndroid Build Coastguard Worker // This has been 1.6 seconds for years, but for networks that
42*d9f75844SAndroid Build Coastguard Worker // experience moments of high RTT (such as 2G networks), this doesn't
43*d9f75844SAndroid Build Coastguard Worker // work well.
44*d9f75844SAndroid Build Coastguard Worker const int STUN_MAX_RTO = 8000;  // milliseconds, or 5 doublings
45*d9f75844SAndroid Build Coastguard Worker 
StunRequestManager(webrtc::TaskQueueBase * thread,std::function<void (const void *,size_t,StunRequest *)> send_packet)46*d9f75844SAndroid Build Coastguard Worker StunRequestManager::StunRequestManager(
47*d9f75844SAndroid Build Coastguard Worker     webrtc::TaskQueueBase* thread,
48*d9f75844SAndroid Build Coastguard Worker     std::function<void(const void*, size_t, StunRequest*)> send_packet)
49*d9f75844SAndroid Build Coastguard Worker     : thread_(thread), send_packet_(std::move(send_packet)) {}
50*d9f75844SAndroid Build Coastguard Worker 
51*d9f75844SAndroid Build Coastguard Worker StunRequestManager::~StunRequestManager() = default;
52*d9f75844SAndroid Build Coastguard Worker 
Send(StunRequest * request)53*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::Send(StunRequest* request) {
54*d9f75844SAndroid Build Coastguard Worker   SendDelayed(request, 0);
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker 
SendDelayed(StunRequest * request,int delay)57*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
58*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
59*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(this, request->manager());
60*d9f75844SAndroid Build Coastguard Worker   auto [iter, was_inserted] =
61*d9f75844SAndroid Build Coastguard Worker       requests_.emplace(request->id(), absl::WrapUnique(request));
62*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(was_inserted);
63*d9f75844SAndroid Build Coastguard Worker   request->Send(webrtc::TimeDelta::Millis(delay));
64*d9f75844SAndroid Build Coastguard Worker }
65*d9f75844SAndroid Build Coastguard Worker 
FlushForTest(int msg_type)66*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::FlushForTest(int msg_type) {
67*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
68*d9f75844SAndroid Build Coastguard Worker   for (const auto& [unused, request] : requests_) {
69*d9f75844SAndroid Build Coastguard Worker     if (msg_type == kAllRequestsForTest || msg_type == request->type()) {
70*d9f75844SAndroid Build Coastguard Worker       // Calling `Send` implies starting the send operation which may be posted
71*d9f75844SAndroid Build Coastguard Worker       // on a timer and be repeated on a timer until timeout. To make sure that
72*d9f75844SAndroid Build Coastguard Worker       // a call to `Send` doesn't conflict with a previously started `Send`
73*d9f75844SAndroid Build Coastguard Worker       // operation, we reset the `task_safety_` flag here, which has the effect
74*d9f75844SAndroid Build Coastguard Worker       // of canceling any outstanding tasks and prepare a new flag for
75*d9f75844SAndroid Build Coastguard Worker       // operations related to this call to `Send`.
76*d9f75844SAndroid Build Coastguard Worker       request->ResetTasksForTest();
77*d9f75844SAndroid Build Coastguard Worker       request->Send(webrtc::TimeDelta::Zero());
78*d9f75844SAndroid Build Coastguard Worker     }
79*d9f75844SAndroid Build Coastguard Worker   }
80*d9f75844SAndroid Build Coastguard Worker }
81*d9f75844SAndroid Build Coastguard Worker 
HasRequestForTest(int msg_type)82*d9f75844SAndroid Build Coastguard Worker bool StunRequestManager::HasRequestForTest(int msg_type) {
83*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
84*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_NE(msg_type, kAllRequestsForTest);
85*d9f75844SAndroid Build Coastguard Worker   for (const auto& [unused, request] : requests_) {
86*d9f75844SAndroid Build Coastguard Worker     if (msg_type == request->type()) {
87*d9f75844SAndroid Build Coastguard Worker       return true;
88*d9f75844SAndroid Build Coastguard Worker     }
89*d9f75844SAndroid Build Coastguard Worker   }
90*d9f75844SAndroid Build Coastguard Worker   return false;
91*d9f75844SAndroid Build Coastguard Worker }
92*d9f75844SAndroid Build Coastguard Worker 
Clear()93*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::Clear() {
94*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
95*d9f75844SAndroid Build Coastguard Worker   requests_.clear();
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker 
CheckResponse(StunMessage * msg)98*d9f75844SAndroid Build Coastguard Worker bool StunRequestManager::CheckResponse(StunMessage* msg) {
99*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
100*d9f75844SAndroid Build Coastguard Worker   RequestMap::iterator iter = requests_.find(msg->transaction_id());
101*d9f75844SAndroid Build Coastguard Worker   if (iter == requests_.end())
102*d9f75844SAndroid Build Coastguard Worker     return false;
103*d9f75844SAndroid Build Coastguard Worker 
104*d9f75844SAndroid Build Coastguard Worker   StunRequest* request = iter->second.get();
105*d9f75844SAndroid Build Coastguard Worker 
106*d9f75844SAndroid Build Coastguard Worker   // Now that we know the request, we can see if the response is
107*d9f75844SAndroid Build Coastguard Worker   // integrity-protected or not.
108*d9f75844SAndroid Build Coastguard Worker   // For some tests, the message integrity is not set in the request.
109*d9f75844SAndroid Build Coastguard Worker   // Complain, and then don't check.
110*d9f75844SAndroid Build Coastguard Worker   bool skip_integrity_checking =
111*d9f75844SAndroid Build Coastguard Worker       (request->msg()->integrity() == StunMessage::IntegrityStatus::kNotSet);
112*d9f75844SAndroid Build Coastguard Worker   if (skip_integrity_checking) {
113*d9f75844SAndroid Build Coastguard Worker     // This indicates lazy test writing (not adding integrity attribute).
114*d9f75844SAndroid Build Coastguard Worker     // Complain, but only in debug mode (while developing).
115*d9f75844SAndroid Build Coastguard Worker     RTC_DLOG(LS_ERROR)
116*d9f75844SAndroid Build Coastguard Worker         << "CheckResponse called on a passwordless request. Fix test!";
117*d9f75844SAndroid Build Coastguard Worker   } else {
118*d9f75844SAndroid Build Coastguard Worker     if (msg->integrity() == StunMessage::IntegrityStatus::kNotSet) {
119*d9f75844SAndroid Build Coastguard Worker       // Checking status for the first time. Normal.
120*d9f75844SAndroid Build Coastguard Worker       msg->ValidateMessageIntegrity(request->msg()->password());
121*d9f75844SAndroid Build Coastguard Worker     } else if (msg->integrity() == StunMessage::IntegrityStatus::kIntegrityOk &&
122*d9f75844SAndroid Build Coastguard Worker                msg->password() == request->msg()->password()) {
123*d9f75844SAndroid Build Coastguard Worker       // Status is already checked, with the same password. This is the case
124*d9f75844SAndroid Build Coastguard Worker       // we would want to see happen.
125*d9f75844SAndroid Build Coastguard Worker     } else if (msg->integrity() ==
126*d9f75844SAndroid Build Coastguard Worker                StunMessage::IntegrityStatus::kIntegrityBad) {
127*d9f75844SAndroid Build Coastguard Worker       // This indicates that the original check had the wrong password.
128*d9f75844SAndroid Build Coastguard Worker       // Bad design, needs revisiting.
129*d9f75844SAndroid Build Coastguard Worker       // TODO(crbug.com/1177125): Fix this.
130*d9f75844SAndroid Build Coastguard Worker       msg->RevalidateMessageIntegrity(request->msg()->password());
131*d9f75844SAndroid Build Coastguard Worker     } else {
132*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK_NOTREACHED();
133*d9f75844SAndroid Build Coastguard Worker     }
134*d9f75844SAndroid Build Coastguard Worker   }
135*d9f75844SAndroid Build Coastguard Worker 
136*d9f75844SAndroid Build Coastguard Worker   bool success = true;
137*d9f75844SAndroid Build Coastguard Worker 
138*d9f75844SAndroid Build Coastguard Worker   if (!msg->GetNonComprehendedAttributes().empty()) {
139*d9f75844SAndroid Build Coastguard Worker     // If a response contains unknown comprehension-required attributes, it's
140*d9f75844SAndroid Build Coastguard Worker     // simply discarded and the transaction is considered failed. See RFC5389
141*d9f75844SAndroid Build Coastguard Worker     // sections 7.3.3 and 7.3.4.
142*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << ": Discarding response due to unknown "
143*d9f75844SAndroid Build Coastguard Worker                          "comprehension-required attribute.";
144*d9f75844SAndroid Build Coastguard Worker     success = false;
145*d9f75844SAndroid Build Coastguard Worker   } else if (msg->type() == GetStunSuccessResponseType(request->type())) {
146*d9f75844SAndroid Build Coastguard Worker     if (!msg->IntegrityOk() && !skip_integrity_checking) {
147*d9f75844SAndroid Build Coastguard Worker       return false;
148*d9f75844SAndroid Build Coastguard Worker     }
149*d9f75844SAndroid Build Coastguard Worker     request->OnResponse(msg);
150*d9f75844SAndroid Build Coastguard Worker   } else if (msg->type() == GetStunErrorResponseType(request->type())) {
151*d9f75844SAndroid Build Coastguard Worker     request->OnErrorResponse(msg);
152*d9f75844SAndroid Build Coastguard Worker   } else {
153*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Received response with wrong type: " << msg->type()
154*d9f75844SAndroid Build Coastguard Worker                       << " (expecting "
155*d9f75844SAndroid Build Coastguard Worker                       << GetStunSuccessResponseType(request->type()) << ")";
156*d9f75844SAndroid Build Coastguard Worker     return false;
157*d9f75844SAndroid Build Coastguard Worker   }
158*d9f75844SAndroid Build Coastguard Worker 
159*d9f75844SAndroid Build Coastguard Worker   requests_.erase(iter);
160*d9f75844SAndroid Build Coastguard Worker   return success;
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker 
empty() const163*d9f75844SAndroid Build Coastguard Worker bool StunRequestManager::empty() const {
164*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
165*d9f75844SAndroid Build Coastguard Worker   return requests_.empty();
166*d9f75844SAndroid Build Coastguard Worker }
167*d9f75844SAndroid Build Coastguard Worker 
CheckResponse(const char * data,size_t size)168*d9f75844SAndroid Build Coastguard Worker bool StunRequestManager::CheckResponse(const char* data, size_t size) {
169*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
170*d9f75844SAndroid Build Coastguard Worker   // Check the appropriate bytes of the stream to see if they match the
171*d9f75844SAndroid Build Coastguard Worker   // transaction ID of a response we are expecting.
172*d9f75844SAndroid Build Coastguard Worker 
173*d9f75844SAndroid Build Coastguard Worker   if (size < 20)
174*d9f75844SAndroid Build Coastguard Worker     return false;
175*d9f75844SAndroid Build Coastguard Worker 
176*d9f75844SAndroid Build Coastguard Worker   std::string id;
177*d9f75844SAndroid Build Coastguard Worker   id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
178*d9f75844SAndroid Build Coastguard Worker 
179*d9f75844SAndroid Build Coastguard Worker   RequestMap::iterator iter = requests_.find(id);
180*d9f75844SAndroid Build Coastguard Worker   if (iter == requests_.end())
181*d9f75844SAndroid Build Coastguard Worker     return false;
182*d9f75844SAndroid Build Coastguard Worker 
183*d9f75844SAndroid Build Coastguard Worker   // Parse the STUN message and continue processing as usual.
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferReader buf(data, size);
186*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<StunMessage> response(iter->second->msg_->CreateNew());
187*d9f75844SAndroid Build Coastguard Worker   if (!response->Read(&buf)) {
188*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to read STUN response "
189*d9f75844SAndroid Build Coastguard Worker                         << rtc::hex_encode(id);
190*d9f75844SAndroid Build Coastguard Worker     return false;
191*d9f75844SAndroid Build Coastguard Worker   }
192*d9f75844SAndroid Build Coastguard Worker 
193*d9f75844SAndroid Build Coastguard Worker   return CheckResponse(response.get());
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker 
OnRequestTimedOut(StunRequest * request)196*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::OnRequestTimedOut(StunRequest* request) {
197*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(thread_);
198*d9f75844SAndroid Build Coastguard Worker   requests_.erase(request->id());
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker 
SendPacket(const void * data,size_t size,StunRequest * request)201*d9f75844SAndroid Build Coastguard Worker void StunRequestManager::SendPacket(const void* data,
202*d9f75844SAndroid Build Coastguard Worker                                     size_t size,
203*d9f75844SAndroid Build Coastguard Worker                                     StunRequest* request) {
204*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(this, request->manager());
205*d9f75844SAndroid Build Coastguard Worker   send_packet_(data, size, request);
206*d9f75844SAndroid Build Coastguard Worker }
207*d9f75844SAndroid Build Coastguard Worker 
StunRequest(StunRequestManager & manager)208*d9f75844SAndroid Build Coastguard Worker StunRequest::StunRequest(StunRequestManager& manager)
209*d9f75844SAndroid Build Coastguard Worker     : manager_(manager),
210*d9f75844SAndroid Build Coastguard Worker       msg_(new StunMessage(STUN_INVALID_MESSAGE_TYPE)),
211*d9f75844SAndroid Build Coastguard Worker       tstamp_(0),
212*d9f75844SAndroid Build Coastguard Worker       count_(0),
213*d9f75844SAndroid Build Coastguard Worker       timeout_(false) {
214*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
215*d9f75844SAndroid Build Coastguard Worker }
216*d9f75844SAndroid Build Coastguard Worker 
StunRequest(StunRequestManager & manager,std::unique_ptr<StunMessage> message)217*d9f75844SAndroid Build Coastguard Worker StunRequest::StunRequest(StunRequestManager& manager,
218*d9f75844SAndroid Build Coastguard Worker                          std::unique_ptr<StunMessage> message)
219*d9f75844SAndroid Build Coastguard Worker     : manager_(manager),
220*d9f75844SAndroid Build Coastguard Worker       msg_(std::move(message)),
221*d9f75844SAndroid Build Coastguard Worker       tstamp_(0),
222*d9f75844SAndroid Build Coastguard Worker       count_(0),
223*d9f75844SAndroid Build Coastguard Worker       timeout_(false) {
224*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
225*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!msg_->transaction_id().empty());
226*d9f75844SAndroid Build Coastguard Worker }
227*d9f75844SAndroid Build Coastguard Worker 
~StunRequest()228*d9f75844SAndroid Build Coastguard Worker StunRequest::~StunRequest() {}
229*d9f75844SAndroid Build Coastguard Worker 
type()230*d9f75844SAndroid Build Coastguard Worker int StunRequest::type() {
231*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(msg_ != NULL);
232*d9f75844SAndroid Build Coastguard Worker   return msg_->type();
233*d9f75844SAndroid Build Coastguard Worker }
234*d9f75844SAndroid Build Coastguard Worker 
msg() const235*d9f75844SAndroid Build Coastguard Worker const StunMessage* StunRequest::msg() const {
236*d9f75844SAndroid Build Coastguard Worker   return msg_.get();
237*d9f75844SAndroid Build Coastguard Worker }
238*d9f75844SAndroid Build Coastguard Worker 
Elapsed() const239*d9f75844SAndroid Build Coastguard Worker int StunRequest::Elapsed() const {
240*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
241*d9f75844SAndroid Build Coastguard Worker   return static_cast<int>(rtc::TimeMillis() - tstamp_);
242*d9f75844SAndroid Build Coastguard Worker }
243*d9f75844SAndroid Build Coastguard Worker 
SendInternal()244*d9f75844SAndroid Build Coastguard Worker void StunRequest::SendInternal() {
245*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
246*d9f75844SAndroid Build Coastguard Worker   if (timeout_) {
247*d9f75844SAndroid Build Coastguard Worker     OnTimeout();
248*d9f75844SAndroid Build Coastguard Worker     manager_.OnRequestTimedOut(this);
249*d9f75844SAndroid Build Coastguard Worker     return;
250*d9f75844SAndroid Build Coastguard Worker   }
251*d9f75844SAndroid Build Coastguard Worker 
252*d9f75844SAndroid Build Coastguard Worker   tstamp_ = rtc::TimeMillis();
253*d9f75844SAndroid Build Coastguard Worker 
254*d9f75844SAndroid Build Coastguard Worker   rtc::ByteBufferWriter buf;
255*d9f75844SAndroid Build Coastguard Worker   msg_->Write(&buf);
256*d9f75844SAndroid Build Coastguard Worker   manager_.SendPacket(buf.Data(), buf.Length(), this);
257*d9f75844SAndroid Build Coastguard Worker 
258*d9f75844SAndroid Build Coastguard Worker   OnSent();
259*d9f75844SAndroid Build Coastguard Worker   SendDelayed(webrtc::TimeDelta::Millis(resend_delay()));
260*d9f75844SAndroid Build Coastguard Worker }
261*d9f75844SAndroid Build Coastguard Worker 
SendDelayed(webrtc::TimeDelta delay)262*d9f75844SAndroid Build Coastguard Worker void StunRequest::SendDelayed(webrtc::TimeDelta delay) {
263*d9f75844SAndroid Build Coastguard Worker   network_thread()->PostDelayedTask(
264*d9f75844SAndroid Build Coastguard Worker       SafeTask(task_safety_.flag(), [this]() { SendInternal(); }), delay);
265*d9f75844SAndroid Build Coastguard Worker }
266*d9f75844SAndroid Build Coastguard Worker 
Send(webrtc::TimeDelta delay)267*d9f75844SAndroid Build Coastguard Worker void StunRequest::Send(webrtc::TimeDelta delay) {
268*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
269*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(delay.ms(), 0);
270*d9f75844SAndroid Build Coastguard Worker 
271*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!task_safety_.flag()->alive()) << "Send already called?";
272*d9f75844SAndroid Build Coastguard Worker   task_safety_.flag()->SetAlive();
273*d9f75844SAndroid Build Coastguard Worker 
274*d9f75844SAndroid Build Coastguard Worker   delay.IsZero() ? SendInternal() : SendDelayed(delay);
275*d9f75844SAndroid Build Coastguard Worker }
276*d9f75844SAndroid Build Coastguard Worker 
ResetTasksForTest()277*d9f75844SAndroid Build Coastguard Worker void StunRequest::ResetTasksForTest() {
278*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
279*d9f75844SAndroid Build Coastguard Worker   task_safety_.reset(webrtc::PendingTaskSafetyFlag::CreateDetachedInactive());
280*d9f75844SAndroid Build Coastguard Worker   count_ = 0;
281*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!timeout_);
282*d9f75844SAndroid Build Coastguard Worker }
283*d9f75844SAndroid Build Coastguard Worker 
OnSent()284*d9f75844SAndroid Build Coastguard Worker void StunRequest::OnSent() {
285*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
286*d9f75844SAndroid Build Coastguard Worker   count_ += 1;
287*d9f75844SAndroid Build Coastguard Worker   int retransmissions = (count_ - 1);
288*d9f75844SAndroid Build Coastguard Worker   if (retransmissions >= STUN_MAX_RETRANSMISSIONS) {
289*d9f75844SAndroid Build Coastguard Worker     timeout_ = true;
290*d9f75844SAndroid Build Coastguard Worker   }
291*d9f75844SAndroid Build Coastguard Worker   RTC_DLOG(LS_VERBOSE) << "Sent STUN request " << count_
292*d9f75844SAndroid Build Coastguard Worker                        << "; resend delay = " << resend_delay();
293*d9f75844SAndroid Build Coastguard Worker }
294*d9f75844SAndroid Build Coastguard Worker 
resend_delay()295*d9f75844SAndroid Build Coastguard Worker int StunRequest::resend_delay() {
296*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
297*d9f75844SAndroid Build Coastguard Worker   if (count_ == 0) {
298*d9f75844SAndroid Build Coastguard Worker     return 0;
299*d9f75844SAndroid Build Coastguard Worker   }
300*d9f75844SAndroid Build Coastguard Worker   int retransmissions = (count_ - 1);
301*d9f75844SAndroid Build Coastguard Worker   int rto = STUN_INITIAL_RTO << retransmissions;
302*d9f75844SAndroid Build Coastguard Worker   return std::min(rto, STUN_MAX_RTO);
303*d9f75844SAndroid Build Coastguard Worker }
304*d9f75844SAndroid Build Coastguard Worker 
set_timed_out()305*d9f75844SAndroid Build Coastguard Worker void StunRequest::set_timed_out() {
306*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread());
307*d9f75844SAndroid Build Coastguard Worker   timeout_ = true;
308*d9f75844SAndroid Build Coastguard Worker }
309*d9f75844SAndroid Build Coastguard Worker 
310*d9f75844SAndroid Build Coastguard Worker }  // namespace cricket
311