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