Home | History | Annotate | Download | only in base
      1 /*
      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 <algorithm>
     14 #include "webrtc/base/common.h"
     15 #include "webrtc/base/helpers.h"
     16 #include "webrtc/base/logging.h"
     17 #include "webrtc/base/stringencode.h"
     18 
     19 namespace cricket {
     20 
     21 const uint32_t MSG_STUN_SEND = 1;
     22 
     23 const int MAX_SENDS = 9;
     24 const int DELAY_UNIT = 100;  // 100 milliseconds
     25 const int DELAY_MAX_FACTOR = 16;
     26 
     27 StunRequestManager::StunRequestManager(rtc::Thread* thread)
     28     : thread_(thread) {
     29 }
     30 
     31 StunRequestManager::~StunRequestManager() {
     32   while (requests_.begin() != requests_.end()) {
     33     StunRequest *request = requests_.begin()->second;
     34     requests_.erase(requests_.begin());
     35     delete request;
     36   }
     37 }
     38 
     39 void StunRequestManager::Send(StunRequest* request) {
     40   SendDelayed(request, 0);
     41 }
     42 
     43 void StunRequestManager::SendDelayed(StunRequest* request, int delay) {
     44   request->set_manager(this);
     45   ASSERT(requests_.find(request->id()) == requests_.end());
     46   request->set_origin(origin_);
     47   request->Construct();
     48   requests_[request->id()] = request;
     49   if (delay > 0) {
     50     thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL);
     51   } else {
     52     thread_->Send(request, MSG_STUN_SEND, NULL);
     53   }
     54 }
     55 
     56 void StunRequestManager::Flush(int msg_type) {
     57   for (const auto kv : requests_) {
     58     StunRequest* request = kv.second;
     59     if (msg_type == kAllRequests || msg_type == request->type()) {
     60       thread_->Clear(request, MSG_STUN_SEND);
     61       thread_->Send(request, MSG_STUN_SEND, NULL);
     62     }
     63   }
     64 }
     65 
     66 void 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 
     76 void 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_t i = 0; i < requests.size(); ++i) {
     82     // StunRequest destructor calls Remove() which deletes requests
     83     // from |requests_|.
     84     delete requests[i];
     85   }
     86 }
     87 
     88 bool StunRequestManager::CheckResponse(StunMessage* msg) {
     89   RequestMap::iterator iter = requests_.find(msg->transaction_id());
     90   if (iter == requests_.end()) {
     91     // TODO(pthatcher): Log unknown responses without being too spammy
     92     // in the logs.
     93     return false;
     94   }
     95 
     96   StunRequest* request = iter->second;
     97   if (msg->type() == GetStunSuccessResponseType(request->type())) {
     98     request->OnResponse(msg);
     99   } else if (msg->type() == GetStunErrorResponseType(request->type())) {
    100     request->OnErrorResponse(msg);
    101   } else {
    102     LOG(LERROR) << "Received response with wrong type: " << msg->type()
    103                 << " (expecting "
    104                 << GetStunSuccessResponseType(request->type()) << ")";
    105     return false;
    106   }
    107 
    108   delete request;
    109   return true;
    110 }
    111 
    112 bool StunRequestManager::CheckResponse(const char* data, size_t size) {
    113   // Check the appropriate bytes of the stream to see if they match the
    114   // transaction ID of a response we are expecting.
    115 
    116   if (size < 20)
    117     return false;
    118 
    119   std::string id;
    120   id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
    121 
    122   RequestMap::iterator iter = requests_.find(id);
    123   if (iter == requests_.end()) {
    124     // TODO(pthatcher): Log unknown responses without being too spammy
    125     // in the logs.
    126     return false;
    127   }
    128 
    129   // Parse the STUN message and continue processing as usual.
    130 
    131   rtc::ByteBuffer buf(data, size);
    132   rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew());
    133   if (!response->Read(&buf)) {
    134     LOG(LS_WARNING) << "Failed to read STUN response " << rtc::hex_encode(id);
    135     return false;
    136   }
    137 
    138   return CheckResponse(response.get());
    139 }
    140 
    141 StunRequest::StunRequest()
    142     : count_(0), timeout_(false), manager_(0),
    143       msg_(new StunMessage()), tstamp_(0) {
    144   msg_->SetTransactionID(
    145       rtc::CreateRandomString(kStunTransactionIdLength));
    146 }
    147 
    148 StunRequest::StunRequest(StunMessage* request)
    149     : count_(0), timeout_(false), manager_(0),
    150       msg_(request), tstamp_(0) {
    151   msg_->SetTransactionID(
    152       rtc::CreateRandomString(kStunTransactionIdLength));
    153 }
    154 
    155 StunRequest::~StunRequest() {
    156   ASSERT(manager_ != NULL);
    157   if (manager_) {
    158     manager_->Remove(this);
    159     manager_->thread_->Clear(this);
    160   }
    161   delete msg_;
    162 }
    163 
    164 void StunRequest::Construct() {
    165   if (msg_->type() == 0) {
    166     if (!origin_.empty()) {
    167       msg_->AddAttribute(new StunByteStringAttribute(STUN_ATTR_ORIGIN,
    168           origin_));
    169     }
    170     Prepare(msg_);
    171     ASSERT(msg_->type() != 0);
    172   }
    173 }
    174 
    175 int StunRequest::type() {
    176   ASSERT(msg_ != NULL);
    177   return msg_->type();
    178 }
    179 
    180 const StunMessage* StunRequest::msg() const {
    181   return msg_;
    182 }
    183 
    184 uint32_t StunRequest::Elapsed() const {
    185   return rtc::TimeSince(tstamp_);
    186 }
    187 
    188 
    189 void StunRequest::set_manager(StunRequestManager* manager) {
    190   ASSERT(!manager_);
    191   manager_ = manager;
    192 }
    193 
    194 void StunRequest::OnMessage(rtc::Message* pmsg) {
    195   ASSERT(manager_ != NULL);
    196   ASSERT(pmsg->message_id == MSG_STUN_SEND);
    197 
    198   if (timeout_) {
    199     OnTimeout();
    200     delete this;
    201     return;
    202   }
    203 
    204   tstamp_ = rtc::Time();
    205 
    206   rtc::ByteBuffer buf;
    207   msg_->Write(&buf);
    208   manager_->SignalSendPacket(buf.Data(), buf.Length(), this);
    209 
    210   OnSent();
    211   manager_->thread_->PostDelayed(resend_delay(), this, MSG_STUN_SEND, NULL);
    212 }
    213 
    214 void StunRequest::OnSent() {
    215   count_ += 1;
    216   if (count_ == MAX_SENDS)
    217     timeout_ = true;
    218 }
    219 
    220 int StunRequest::resend_delay() {
    221   if (count_ == 0) {
    222     return 0;
    223   }
    224   return DELAY_UNIT * std::min(1 << (count_-1), DELAY_MAX_FACTOR);
    225 }
    226 
    227 }  // namespace cricket
    228