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 "webrtc/p2p/base/stunrequest.h"
12 
13 #include <algorithm>
14 #include "webrtc/base/common.h"
15 #include "webrtc/base/helpers.h"
16 #include "webrtc/base/logging.h"
17 #include "webrtc/base/stringencode.h"
18 
19 namespace cricket {
20 
21 const uint32_t MSG_STUN_SEND = 1;
22 
23 const int MAX_SENDS = 9;
24 const int DELAY_UNIT = 100;  // 100 milliseconds
25 const int DELAY_MAX_FACTOR = 16;
26 
StunRequestManager(rtc::Thread * thread)27 StunRequestManager::StunRequestManager(rtc::Thread* thread)
28     : thread_(thread) {
29 }
30 
~StunRequestManager()31 StunRequestManager::~StunRequestManager() {
32   while (requests_.begin() != requests_.end()) {
33     StunRequest *request = requests_.begin()->second;
34     requests_.erase(requests_.begin());
35     delete request;
36   }
37 }
38 
Send(StunRequest * request)39 void StunRequestManager::Send(StunRequest* request) {
40   SendDelayed(request, 0);
41 }
42 
SendDelayed(StunRequest * request,int delay)43 void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
44   request->set_manager(this);
45   ASSERT(requests_.find(request->id()) == requests_.end());
46   request->set_origin(origin_);
47   request->Construct();
48   requests_[request->id()] = request;
49   if (delay > 0) {
50     thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
51   } else {
52     thread_->Send(request, MSG_STUN_SEND, NULL);
53   }
54 }
55 
Flush(int msg_type)56 void StunRequestManager::Flush(int msg_type) {
57   for (const auto kv : requests_) {
58     StunRequest* request = kv.second;
59     if (msg_type == kAllRequests || msg_type == request->type()) {
60       thread_->Clear(request, MSG_STUN_SEND);
61       thread_->Send(request, MSG_STUN_SEND, NULL);
62     }
63   }
64 }
65 
Remove(StunRequest * request)66 void StunRequestManager::Remove(StunRequest* request) {
67   ASSERT(request->manager() == this);
68   RequestMap::iterator iter = requests_.find(request->id());
69   if (iter != requests_.end()) {
70     ASSERT(iter->second == request);
71     requests_.erase(iter);
72     thread_->Clear(request);
73   }
74 }
75 
Clear()76 void StunRequestManager::Clear() {
77   std::vector<StunRequest*> requests;
78   for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
79     requests.push_back(i->second);
80 
81   for (uint32_t i = 0; i < requests.size(); ++i) {
82     // StunRequest destructor calls Remove() which deletes requests
83     // from |requests_|.
84     delete requests[i];
85   }
86 }
87 
CheckResponse(StunMessage * msg)88 bool StunRequestManager::CheckResponse(StunMessage* msg) {
89   RequestMap::iterator iter = requests_.find(msg->transaction_id());
90   if (iter == requests_.end()) {
91     // TODO(pthatcher): Log unknown responses without being too spammy
92     // in the logs.
93     return false;
94   }
95 
96   StunRequest* request = iter->second;
97   if (msg->type() == GetStunSuccessResponseType(request->type())) {
98     request->OnResponse(msg);
99   } else if (msg->type() == GetStunErrorResponseType(request->type())) {
100     request->OnErrorResponse(msg);
101   } else {
102     LOG(LERROR) << "Received response with wrong type: " << msg->type()
103                 << " (expecting "
104                 << GetStunSuccessResponseType(request->type()) << ")";
105     return false;
106   }
107 
108   delete request;
109   return true;
110 }
111 
CheckResponse(const char * data,size_t size)112 bool StunRequestManager::CheckResponse(const char* data, size_t size) {
113   // Check the appropriate bytes of the stream to see if they match the
114   // transaction ID of a response we are expecting.
115 
116   if (size < 20)
117     return false;
118 
119   std::string id;
120   id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
121 
122   RequestMap::iterator iter = requests_.find(id);
123   if (iter == requests_.end()) {
124     // TODO(pthatcher): Log unknown responses without being too spammy
125     // in the logs.
126     return false;
127   }
128 
129   // Parse the STUN message and continue processing as usual.
130 
131   rtc::ByteBuffer buf(data, size);
132   rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew());
133   if (!response->Read(&buf)) {
134     LOG(LS_WARNING) << "Failed to read STUN response " << rtc::hex_encode(id);
135     return false;
136   }
137 
138   return CheckResponse(response.get());
139 }
140 
StunRequest()141 StunRequest::StunRequest()
142     : count_(0), timeout_(false), manager_(0),
143       msg_(new StunMessage()), tstamp_(0) {
144   msg_->SetTransactionID(
145       rtc::CreateRandomString(kStunTransactionIdLength));
146 }
147 
StunRequest(StunMessage * request)148 StunRequest::StunRequest(StunMessage* request)
149     : count_(0), timeout_(false), manager_(0),
150       msg_(request), tstamp_(0) {
151   msg_->SetTransactionID(
152       rtc::CreateRandomString(kStunTransactionIdLength));
153 }
154 
~StunRequest()155 StunRequest::~StunRequest() {
156   ASSERT(manager_ != NULL);
157   if (manager_) {
158     manager_->Remove(this);
159     manager_->thread_->Clear(this);
160   }
161   delete msg_;
162 }
163 
Construct()164 void StunRequest::Construct() {
165   if (msg_->type() == 0) {
166     if (!origin_.empty()) {
167       msg_->AddAttribute(new StunByteStringAttribute(STUN_ATTR_ORIGIN,
168           origin_));
169     }
170     Prepare(msg_);
171     ASSERT(msg_->type() != 0);
172   }
173 }
174 
type()175 int StunRequest::type() {
176   ASSERT(msg_ != NULL);
177   return msg_->type();
178 }
179 
msg() const180 const StunMessage* StunRequest::msg() const {
181   return msg_;
182 }
183 
Elapsed() const184 uint32_t StunRequest::Elapsed() const {
185   return rtc::TimeSince(tstamp_);
186 }
187 
188 
set_manager(StunRequestManager * manager)189 void StunRequest::set_manager(StunRequestManager* manager) {
190   ASSERT(!manager_);
191   manager_ = manager;
192 }
193 
OnMessage(rtc::Message * pmsg)194 void StunRequest::OnMessage(rtc::Message* pmsg) {
195   ASSERT(manager_ != NULL);
196   ASSERT(pmsg->message_id == MSG_STUN_SEND);
197 
198   if (timeout_) {
199     OnTimeout();
200     delete this;
201     return;
202   }
203 
204   tstamp_ = rtc::Time();
205 
206   rtc::ByteBuffer buf;
207   msg_->Write(&buf);
208   manager_->SignalSendPacket(buf.Data(), buf.Length(), this);
209 
210   OnSent();
211   manager_->thread_->PostDelayed(resend_delay(), this, MSG_STUN_SEND, NULL);
212 }
213 
OnSent()214 void StunRequest::OnSent() {
215   count_ += 1;
216   if (count_ == MAX_SENDS)
217     timeout_ = true;
218 }
219 
resend_delay()220 int StunRequest::resend_delay() {
221   if (count_ == 0) {
222     return 0;
223   }
224   return DELAY_UNIT * std::min(1 << (count_-1), DELAY_MAX_FACTOR);
225 }
226 
227 }  // namespace cricket
228