~ubuntu-branches/ubuntu/edgy/kopete/edgy-updates

« back to all changes in this revision

Viewing changes to kopete/protocols/jabber/jingle/libjingle/talk/p2p/base/stunrequest.cc

  • Committer: Bazaar Package Importer
  • Author(s): Harald Sitter
  • Date: 2006-06-12 21:32:28 UTC
  • Revision ID: james.westby@ubuntu.com-20060612213228-d823h1niurgb7pfg
Tags: upstream-3.5.3+kopete0.12.0
ImportĀ upstreamĀ versionĀ 3.5.3+kopete0.12.0

Show diffs side-by-side

added added

removed removed

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