blob: 851bd70b89018f4d91e039cb3187dd020c7856cb [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "p2p/base/stunrequest.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000012
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000013#include <algorithm>
kwiberg3ec46792016-04-27 07:22:53 -070014#include <memory>
Steve Anton6c38cc72017-11-29 10:25:58 -080015#include <vector>
kwiberg3ec46792016-04-27 07:22:53 -070016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
18#include "rtc_base/helpers.h"
19#include "rtc_base/logging.h"
20#include "rtc_base/ptr_util.h"
21#include "rtc_base/stringencode.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000022
23namespace cricket {
24
Peter Boström0c4e06b2015-10-07 12:23:21 +020025const uint32_t MSG_STUN_SEND = 1;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000026
pthatcher94a2f212017-02-08 14:42:22 -080027// RFC 5389 says SHOULD be 500ms.
28// For years, this was 100ms, but for networks that
29// experience moments of high RTT (such as 2G networks), this doesn't
30// work well.
31const int STUN_INITIAL_RTO = 250; // milliseconds
32
33// The timeout doubles each retransmission, up to this many times
34// RFC 5389 says SHOULD retransmit 7 times.
35// This has been 8 for years (not sure why).
36const int STUN_MAX_RETRANSMISSIONS = 8; // Total sends: 9
37
38// We also cap the doubling, even though the standard doesn't say to.
39// This has been 1.6 seconds for years, but for networks that
40// experience moments of high RTT (such as 2G networks), this doesn't
41// work well.
42const int STUN_MAX_RTO = 8000; // milliseconds, or 5 doublings
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000043
44StunRequestManager::StunRequestManager(rtc::Thread* thread)
45 : thread_(thread) {
46}
47
48StunRequestManager::~StunRequestManager() {
49 while (requests_.begin() != requests_.end()) {
50 StunRequest *request = requests_.begin()->second;
51 requests_.erase(requests_.begin());
52 delete request;
53 }
54}
55
56void StunRequestManager::Send(StunRequest* request) {
57 SendDelayed(request, 0);
58}
59
60void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
61 request->set_manager(this);
nisseede5da42017-01-12 05:15:36 -080062 RTC_DCHECK(requests_.find(request->id()) == requests_.end());
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +000063 request->set_origin(origin_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064 request->Construct();
65 requests_[request->id()] = request;
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000066 if (delay > 0) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070067 thread_->PostDelayed(RTC_FROM_HERE, delay, request, MSG_STUN_SEND, NULL);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000068 } else {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070069 thread_->Send(RTC_FROM_HERE, request, MSG_STUN_SEND, NULL);
pthatcher@webrtc.orgfe672e32015-01-17 00:58:15 +000070 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000071}
72
honghaiz6b9ab922016-01-05 09:06:12 -080073void StunRequestManager::Flush(int msg_type) {
Honghai Zhang85975432015-11-12 11:07:12 -080074 for (const auto kv : requests_) {
75 StunRequest* request = kv.second;
honghaiz6b9ab922016-01-05 09:06:12 -080076 if (msg_type == kAllRequests || msg_type == request->type()) {
77 thread_->Clear(request, MSG_STUN_SEND);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070078 thread_->Send(RTC_FROM_HERE, request, MSG_STUN_SEND, NULL);
honghaiz6b9ab922016-01-05 09:06:12 -080079 }
Honghai Zhang85975432015-11-12 11:07:12 -080080 }
81}
82
honghaize2af9ef2016-03-03 08:27:47 -080083bool StunRequestManager::HasRequest(int msg_type) {
84 for (const auto kv : requests_) {
85 StunRequest* request = kv.second;
86 if (msg_type == kAllRequests || msg_type == request->type()) {
87 return true;
88 }
89 }
90 return false;
91}
92
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000093void StunRequestManager::Remove(StunRequest* request) {
nisseede5da42017-01-12 05:15:36 -080094 RTC_DCHECK(request->manager() == this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000095 RequestMap::iterator iter = requests_.find(request->id());
96 if (iter != requests_.end()) {
nisseede5da42017-01-12 05:15:36 -080097 RTC_DCHECK(iter->second == request);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000098 requests_.erase(iter);
99 thread_->Clear(request);
100 }
101}
102
103void StunRequestManager::Clear() {
104 std::vector<StunRequest*> requests;
105 for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
106 requests.push_back(i->second);
107
Peter Boström0c4e06b2015-10-07 12:23:21 +0200108 for (uint32_t i = 0; i < requests.size(); ++i) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000109 // StunRequest destructor calls Remove() which deletes requests
110 // from |requests_|.
111 delete requests[i];
112 }
113}
114
115bool StunRequestManager::CheckResponse(StunMessage* msg) {
116 RequestMap::iterator iter = requests_.find(msg->transaction_id());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700117 if (iter == requests_.end()) {
Peter Thatcher3e95d3e2015-05-18 15:55:18 -0700118 // TODO(pthatcher): Log unknown responses without being too spammy
119 // in the logs.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000120 return false;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700121 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000122
123 StunRequest* request = iter->second;
124 if (msg->type() == GetStunSuccessResponseType(request->type())) {
125 request->OnResponse(msg);
126 } else if (msg->type() == GetStunErrorResponseType(request->type())) {
127 request->OnErrorResponse(msg);
128 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100129 RTC_LOG(LERROR) << "Received response with wrong type: " << msg->type()
130 << " (expecting "
131 << GetStunSuccessResponseType(request->type()) << ")";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000132 return false;
133 }
134
135 delete request;
136 return true;
137}
138
139bool StunRequestManager::CheckResponse(const char* data, size_t size) {
140 // Check the appropriate bytes of the stream to see if they match the
141 // transaction ID of a response we are expecting.
142
143 if (size < 20)
144 return false;
145
146 std::string id;
147 id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
148
149 RequestMap::iterator iter = requests_.find(id);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700150 if (iter == requests_.end()) {
Peter Thatcher3e95d3e2015-05-18 15:55:18 -0700151 // TODO(pthatcher): Log unknown responses without being too spammy
152 // in the logs.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000153 return false;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700154 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000155
156 // Parse the STUN message and continue processing as usual.
157
jbauchf1f87202016-03-30 06:43:37 -0700158 rtc::ByteBufferReader buf(data, size);
kwiberg3ec46792016-04-27 07:22:53 -0700159 std::unique_ptr<StunMessage> response(iter->second->msg_->CreateNew());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700160 if (!response->Read(&buf)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100161 RTC_LOG(LS_WARNING) << "Failed to read STUN response "
162 << rtc::hex_encode(id);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000163 return false;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700164 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000165
166 return CheckResponse(response.get());
167}
168
169StunRequest::StunRequest()
170 : count_(0), timeout_(false), manager_(0),
171 msg_(new StunMessage()), tstamp_(0) {
172 msg_->SetTransactionID(
173 rtc::CreateRandomString(kStunTransactionIdLength));
174}
175
176StunRequest::StunRequest(StunMessage* request)
177 : count_(0), timeout_(false), manager_(0),
178 msg_(request), tstamp_(0) {
179 msg_->SetTransactionID(
180 rtc::CreateRandomString(kStunTransactionIdLength));
181}
182
183StunRequest::~StunRequest() {
nisseede5da42017-01-12 05:15:36 -0800184 RTC_DCHECK(manager_ != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000185 if (manager_) {
186 manager_->Remove(this);
187 manager_->thread_->Clear(this);
188 }
189 delete msg_;
190}
191
192void StunRequest::Construct() {
193 if (msg_->type() == 0) {
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000194 if (!origin_.empty()) {
zsteinf42cc9d2017-03-27 16:17:19 -0700195 msg_->AddAttribute(
196 rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_ORIGIN, origin_));
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000197 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000198 Prepare(msg_);
nisseede5da42017-01-12 05:15:36 -0800199 RTC_DCHECK(msg_->type() != 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 }
201}
202
203int StunRequest::type() {
nisseede5da42017-01-12 05:15:36 -0800204 RTC_DCHECK(msg_ != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000205 return msg_->type();
206}
207
208const StunMessage* StunRequest::msg() const {
209 return msg_;
210}
211
Jonas Orelandbdcee282017-10-10 14:01:40 +0200212StunMessage* StunRequest::mutable_msg() {
213 return msg_;
214}
215
honghaiz34b11eb2016-03-16 08:55:44 -0700216int StunRequest::Elapsed() const {
nisse1bffc1d2016-05-02 08:18:55 -0700217 return static_cast<int>(rtc::TimeMillis() - tstamp_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218}
219
220
221void StunRequest::set_manager(StunRequestManager* manager) {
nisseede5da42017-01-12 05:15:36 -0800222 RTC_DCHECK(!manager_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000223 manager_ = manager;
224}
225
226void StunRequest::OnMessage(rtc::Message* pmsg) {
nisseede5da42017-01-12 05:15:36 -0800227 RTC_DCHECK(manager_ != NULL);
228 RTC_DCHECK(pmsg->message_id == MSG_STUN_SEND);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000229
230 if (timeout_) {
231 OnTimeout();
232 delete this;
233 return;
234 }
235
nisse1bffc1d2016-05-02 08:18:55 -0700236 tstamp_ = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000237
jbauchf1f87202016-03-30 06:43:37 -0700238 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000239 msg_->Write(&buf);
240 manager_->SignalSendPacket(buf.Data(), buf.Length(), this);
241
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700242 OnSent();
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700243 manager_->thread_->PostDelayed(RTC_FROM_HERE, resend_delay(), this,
244 MSG_STUN_SEND, NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245}
246
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700247void StunRequest::OnSent() {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000248 count_ += 1;
pthatcher94a2f212017-02-08 14:42:22 -0800249 int retransmissions = (count_ - 1);
250 if (retransmissions >= STUN_MAX_RETRANSMISSIONS) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 timeout_ = true;
Taylor Brandstetter5ef034a2016-05-25 17:20:35 -0700252 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100253 RTC_LOG(LS_VERBOSE) << "Sent STUN request " << count_
254 << "; resend delay = " << resend_delay();
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700255}
256
257int StunRequest::resend_delay() {
258 if (count_ == 0) {
259 return 0;
260 }
pthatcher94a2f212017-02-08 14:42:22 -0800261 int retransmissions = (count_ - 1);
262 int rto = STUN_INITIAL_RTO << retransmissions;
263 return std::min(rto, STUN_MAX_RTO);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264}
265
266} // namespace cricket