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