1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/p2p/base/stunrequest.h" 29 30#include "webrtc/base/common.h" 31#include "webrtc/base/helpers.h" 32#include "webrtc/base/logging.h" 33 34namespace cricket { 35 36const uint32 MSG_STUN_SEND = 1; 37 38const int MAX_SENDS = 9; 39const int DELAY_UNIT = 100; // 100 milliseconds 40const int DELAY_MAX_FACTOR = 16; 41 42StunRequestManager::StunRequestManager(rtc::Thread* thread) 43 : thread_(thread) { 44} 45 46StunRequestManager::~StunRequestManager() { 47 while (requests_.begin() != requests_.end()) { 48 StunRequest *request = requests_.begin()->second; 49 requests_.erase(requests_.begin()); 50 delete request; 51 } 52} 53 54void StunRequestManager::Send(StunRequest* request) { 55 SendDelayed(request, 0); 56} 57 58void StunRequestManager::SendDelayed(StunRequest* request, int delay) { 59 request->set_manager(this); 60 ASSERT(requests_.find(request->id()) == requests_.end()); 61 request->Construct(); 62 requests_[request->id()] = request; 63 thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL); 64} 65 66void 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 76void 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 i = 0; i < requests.size(); ++i) { 82 // StunRequest destructor calls Remove() which deletes requests 83 // from |requests_|. 84 delete requests[i]; 85 } 86} 87 88bool StunRequestManager::CheckResponse(StunMessage* msg) { 89 RequestMap::iterator iter = requests_.find(msg->transaction_id()); 90 if (iter == requests_.end()) 91 return false; 92 93 StunRequest* request = iter->second; 94 if (msg->type() == GetStunSuccessResponseType(request->type())) { 95 request->OnResponse(msg); 96 } else if (msg->type() == GetStunErrorResponseType(request->type())) { 97 request->OnErrorResponse(msg); 98 } else { 99 LOG(LERROR) << "Received response with wrong type: " << msg->type() 100 << " (expecting " 101 << GetStunSuccessResponseType(request->type()) << ")"; 102 return false; 103 } 104 105 delete request; 106 return true; 107} 108 109bool StunRequestManager::CheckResponse(const char* data, size_t size) { 110 // Check the appropriate bytes of the stream to see if they match the 111 // transaction ID of a response we are expecting. 112 113 if (size < 20) 114 return false; 115 116 std::string id; 117 id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength); 118 119 RequestMap::iterator iter = requests_.find(id); 120 if (iter == requests_.end()) 121 return false; 122 123 // Parse the STUN message and continue processing as usual. 124 125 rtc::ByteBuffer buf(data, size); 126 rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew()); 127 if (!response->Read(&buf)) 128 return false; 129 130 return CheckResponse(response.get()); 131} 132 133StunRequest::StunRequest() 134 : count_(0), timeout_(false), manager_(0), 135 msg_(new StunMessage()), tstamp_(0) { 136 msg_->SetTransactionID( 137 rtc::CreateRandomString(kStunTransactionIdLength)); 138} 139 140StunRequest::StunRequest(StunMessage* request) 141 : count_(0), timeout_(false), manager_(0), 142 msg_(request), tstamp_(0) { 143 msg_->SetTransactionID( 144 rtc::CreateRandomString(kStunTransactionIdLength)); 145} 146 147StunRequest::~StunRequest() { 148 ASSERT(manager_ != NULL); 149 if (manager_) { 150 manager_->Remove(this); 151 manager_->thread_->Clear(this); 152 } 153 delete msg_; 154} 155 156void StunRequest::Construct() { 157 if (msg_->type() == 0) { 158 Prepare(msg_); 159 ASSERT(msg_->type() != 0); 160 } 161} 162 163int StunRequest::type() { 164 ASSERT(msg_ != NULL); 165 return msg_->type(); 166} 167 168const StunMessage* StunRequest::msg() const { 169 return msg_; 170} 171 172uint32 StunRequest::Elapsed() const { 173 return rtc::TimeSince(tstamp_); 174} 175 176 177void StunRequest::set_manager(StunRequestManager* manager) { 178 ASSERT(!manager_); 179 manager_ = manager; 180} 181 182void StunRequest::OnMessage(rtc::Message* pmsg) { 183 ASSERT(manager_ != NULL); 184 ASSERT(pmsg->message_id == MSG_STUN_SEND); 185 186 if (timeout_) { 187 OnTimeout(); 188 delete this; 189 return; 190 } 191 192 tstamp_ = rtc::Time(); 193 194 rtc::ByteBuffer buf; 195 msg_->Write(&buf); 196 manager_->SignalSendPacket(buf.Data(), buf.Length(), this); 197 198 int delay = GetNextDelay(); 199 manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL); 200} 201 202int StunRequest::GetNextDelay() { 203 int delay = DELAY_UNIT * rtc::_min(1 << count_, DELAY_MAX_FACTOR); 204 count_ += 1; 205 if (count_ == MAX_SENDS) 206 timeout_ = true; 207 return delay; 208} 209 210} // namespace cricket 211