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