blob: 65eb027f489e80bc1ac7c32c8df71bf3b0290f33 [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());
44 request->Construct();
45 requests_[request->id()] = request;
46 thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
47}
48
49void StunRequestManager::Remove(StunRequest* request) {
50 ASSERT(request->manager() == this);
51 RequestMap::iterator iter = requests_.find(request->id());
52 if (iter != requests_.end()) {
53 ASSERT(iter->second == request);
54 requests_.erase(iter);
55 thread_->Clear(request);
56 }
57}
58
59void StunRequestManager::Clear() {
60 std::vector<StunRequest*> requests;
61 for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i)
62 requests.push_back(i->second);
63
64 for (uint32 i = 0; i < requests.size(); ++i) {
65 // StunRequest destructor calls Remove() which deletes requests
66 // from |requests_|.
67 delete requests[i];
68 }
69}
70
71bool StunRequestManager::CheckResponse(StunMessage* msg) {
72 RequestMap::iterator iter = requests_.find(msg->transaction_id());
73 if (iter == requests_.end())
74 return false;
75
76 StunRequest* request = iter->second;
77 if (msg->type() == GetStunSuccessResponseType(request->type())) {
78 request->OnResponse(msg);
79 } else if (msg->type() == GetStunErrorResponseType(request->type())) {
80 request->OnErrorResponse(msg);
81 } else {
82 LOG(LERROR) << "Received response with wrong type: " << msg->type()
83 << " (expecting "
84 << GetStunSuccessResponseType(request->type()) << ")";
85 return false;
86 }
87
88 delete request;
89 return true;
90}
91
92bool StunRequestManager::CheckResponse(const char* data, size_t size) {
93 // Check the appropriate bytes of the stream to see if they match the
94 // transaction ID of a response we are expecting.
95
96 if (size < 20)
97 return false;
98
99 std::string id;
100 id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
101
102 RequestMap::iterator iter = requests_.find(id);
103 if (iter == requests_.end())
104 return false;
105
106 // Parse the STUN message and continue processing as usual.
107
108 rtc::ByteBuffer buf(data, size);
109 rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew());
110 if (!response->Read(&buf))
111 return false;
112
113 return CheckResponse(response.get());
114}
115
116StunRequest::StunRequest()
117 : count_(0), timeout_(false), manager_(0),
118 msg_(new StunMessage()), tstamp_(0) {
119 msg_->SetTransactionID(
120 rtc::CreateRandomString(kStunTransactionIdLength));
121}
122
123StunRequest::StunRequest(StunMessage* request)
124 : count_(0), timeout_(false), manager_(0),
125 msg_(request), tstamp_(0) {
126 msg_->SetTransactionID(
127 rtc::CreateRandomString(kStunTransactionIdLength));
128}
129
130StunRequest::~StunRequest() {
131 ASSERT(manager_ != NULL);
132 if (manager_) {
133 manager_->Remove(this);
134 manager_->thread_->Clear(this);
135 }
136 delete msg_;
137}
138
139void StunRequest::Construct() {
140 if (msg_->type() == 0) {
141 Prepare(msg_);
142 ASSERT(msg_->type() != 0);
143 }
144}
145
146int StunRequest::type() {
147 ASSERT(msg_ != NULL);
148 return msg_->type();
149}
150
151const StunMessage* StunRequest::msg() const {
152 return msg_;
153}
154
155uint32 StunRequest::Elapsed() const {
156 return rtc::TimeSince(tstamp_);
157}
158
159
160void StunRequest::set_manager(StunRequestManager* manager) {
161 ASSERT(!manager_);
162 manager_ = manager;
163}
164
165void StunRequest::OnMessage(rtc::Message* pmsg) {
166 ASSERT(manager_ != NULL);
167 ASSERT(pmsg->message_id == MSG_STUN_SEND);
168
169 if (timeout_) {
170 OnTimeout();
171 delete this;
172 return;
173 }
174
175 tstamp_ = rtc::Time();
176
177 rtc::ByteBuffer buf;
178 msg_->Write(&buf);
179 manager_->SignalSendPacket(buf.Data(), buf.Length(), this);
180
181 int delay = GetNextDelay();
182 manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL);
183}
184
185int StunRequest::GetNextDelay() {
186 int delay = DELAY_UNIT * rtc::_min(1 << count_, DELAY_MAX_FACTOR);
187 count_ += 1;
188 if (count_ == MAX_SENDS)
189 timeout_ = true;
190 return delay;
191}
192
193} // namespace cricket