3
* Copyright 2004--2008, Google Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
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.
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.
28
#include "talk/base/basicdefs.h"
29
#include "talk/base/basictypes.h"
30
#include "talk/base/common.h"
31
#include "talk/base/helpers.h"
32
#include "talk/base/logging.h"
33
#include "talk/base/stringutils.h"
34
#include "talk/p2p/base/constants.h"
35
#include "talk/p2p/base/transportchannel.h"
36
#include "talk/xmllite/xmlelement.h"
37
#include "pseudotcpchannel.h"
38
#include "tunnelsessionclient.h"
42
const char NS_TUNNEL[] = "http://www.google.com/talk/tunnel";
43
const buzz::StaticQName QN_TUNNEL_DESCRIPTION = { NS_TUNNEL, "description" };
44
const buzz::StaticQName QN_TUNNEL_TYPE = { NS_TUNNEL, "type" };
45
const char CN_TUNNEL[] = "tunnel";
55
struct EventData : public talk_base::MessageData {
57
EventData(int ev, int err = 0) : event(ev), error(err) { }
60
struct CreateTunnelData : public talk_base::MessageData {
62
std::string description;
63
talk_base::Thread* thread;
64
talk_base::StreamInterface* stream;
67
extern const talk_base::ConstantLabel SESSION_STATES[];
69
const talk_base::ConstantLabel SESSION_STATES[] = {
70
KLABEL(Session::STATE_INIT),
71
KLABEL(Session::STATE_SENTINITIATE),
72
KLABEL(Session::STATE_RECEIVEDINITIATE),
73
KLABEL(Session::STATE_SENTACCEPT),
74
KLABEL(Session::STATE_RECEIVEDACCEPT),
75
KLABEL(Session::STATE_SENTMODIFY),
76
KLABEL(Session::STATE_RECEIVEDMODIFY),
77
KLABEL(Session::STATE_SENTREJECT),
78
KLABEL(Session::STATE_RECEIVEDREJECT),
79
KLABEL(Session::STATE_SENTREDIRECT),
80
KLABEL(Session::STATE_SENTTERMINATE),
81
KLABEL(Session::STATE_RECEIVEDTERMINATE),
82
KLABEL(Session::STATE_INPROGRESS),
83
KLABEL(Session::STATE_DEINIT),
87
///////////////////////////////////////////////////////////////////////////////
88
// TunnelContentDescription
89
///////////////////////////////////////////////////////////////////////////////
91
struct TunnelContentDescription : public ContentDescription {
92
std::string description;
94
TunnelContentDescription(const std::string& desc) : description(desc) { }
95
virtual ContentDescription* Copy() const {
96
return new TunnelContentDescription(*this);
100
///////////////////////////////////////////////////////////////////////////////
101
// TunnelSessionClientBase
102
///////////////////////////////////////////////////////////////////////////////
104
TunnelSessionClientBase::TunnelSessionClientBase(const buzz::Jid& jid,
105
SessionManager* manager, const std::string &ns)
106
: jid_(jid), session_manager_(manager), namespace_(ns), shutdown_(false) {
107
session_manager_->AddClient(namespace_, this);
110
TunnelSessionClientBase::~TunnelSessionClientBase() {
112
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
113
it != sessions_.end();
115
Session* session = (*it)->ReleaseSession(true);
116
session_manager_->DestroySession(session);
118
session_manager_->RemoveClient(namespace_);
121
void TunnelSessionClientBase::OnSessionCreate(Session* session, bool received) {
122
LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionCreate: received="
124
ASSERT(session_manager_->signaling_thread()->IsCurrent());
127
MakeTunnelSession(session, talk_base::Thread::Current(), RESPONDER));
130
void TunnelSessionClientBase::OnSessionDestroy(Session* session) {
131
LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionDestroy";
132
ASSERT(session_manager_->signaling_thread()->IsCurrent());
135
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
136
it != sessions_.end();
138
if ((*it)->HasSession(session)) {
139
VERIFY((*it)->ReleaseSession(false) == session);
146
talk_base::StreamInterface* TunnelSessionClientBase::CreateTunnel(
147
const buzz::Jid& to, const std::string& description) {
148
// Valid from any thread
149
CreateTunnelData data;
151
data.description = description;
152
data.thread = talk_base::Thread::Current();
153
session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data);
157
talk_base::StreamInterface* TunnelSessionClientBase::AcceptTunnel(
159
ASSERT(session_manager_->signaling_thread()->IsCurrent());
160
TunnelSession* tunnel = NULL;
161
for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
162
it != sessions_.end();
164
if ((*it)->HasSession(session)) {
169
ASSERT(tunnel != NULL);
171
SessionDescription* answer = CreateAnswer(session->remote_description());
175
session->Accept(answer);
176
return tunnel->GetStream();
179
void TunnelSessionClientBase::DeclineTunnel(Session* session) {
180
ASSERT(session_manager_->signaling_thread()->IsCurrent());
181
session->Reject(STR_TERMINATE_DECLINE);
184
void TunnelSessionClientBase::OnMessage(talk_base::Message* pmsg) {
185
if (pmsg->message_id == MSG_CREATE_TUNNEL) {
186
ASSERT(session_manager_->signaling_thread()->IsCurrent());
187
CreateTunnelData* data = static_cast<CreateTunnelData*>(pmsg->pdata);
188
Session* session = session_manager_->CreateSession(jid_.Str(), namespace_);
189
TunnelSession* tunnel = MakeTunnelSession(session, data->thread,
191
sessions_.push_back(tunnel);
192
SessionDescription* offer = CreateOffer(data->jid, data->description);
193
session->Initiate(data->jid.Str(), offer);
194
data->stream = tunnel->GetStream();
198
TunnelSession* TunnelSessionClientBase::MakeTunnelSession(
199
Session* session, talk_base::Thread* stream_thread,
200
TunnelSessionRole /*role*/) {
201
return new TunnelSession(this, session, stream_thread);
204
///////////////////////////////////////////////////////////////////////////////
205
// TunnelSessionClient
206
///////////////////////////////////////////////////////////////////////////////
208
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
209
SessionManager* manager,
210
const std::string &ns)
211
: TunnelSessionClientBase(jid, manager, ns) {
214
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
215
SessionManager* manager)
216
: TunnelSessionClientBase(jid, manager, NS_TUNNEL) {
219
TunnelSessionClient::~TunnelSessionClient() {
223
bool TunnelSessionClient::ParseContent(SignalingProtocol protocol,
224
const buzz::XmlElement* elem,
225
const ContentDescription** content,
227
if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) {
228
*content = new TunnelContentDescription(type_elem->BodyText());
234
bool TunnelSessionClient::WriteContent(
235
SignalingProtocol protocol,
236
const ContentDescription* untyped_content,
237
buzz::XmlElement** elem, WriteError* error) {
238
const TunnelContentDescription* content =
239
static_cast<const TunnelContentDescription*>(untyped_content);
241
buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true);
242
buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE);
243
type_elem->SetBodyText(content->description);
244
root->AddElement(type_elem);
249
SessionDescription* NewTunnelSessionDescription(
250
const std::string& content_name, const ContentDescription* content) {
251
SessionDescription* sdesc = new SessionDescription();
252
sdesc->AddContent(content_name, NS_TUNNEL, content);
256
bool FindTunnelContent(const cricket::SessionDescription* sdesc,
258
const TunnelContentDescription** content) {
259
const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL);
264
*content = static_cast<const TunnelContentDescription*>(
269
void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
271
std::string content_name;
272
const TunnelContentDescription* content = NULL;
273
if (!FindTunnelContent(session->remote_description(),
274
&content_name, &content)) {
275
session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
279
SignalIncomingTunnel(this, jid, content->description, session);
282
SessionDescription* TunnelSessionClient::CreateOffer(
283
const buzz::Jid &jid, const std::string &description) {
284
return NewTunnelSessionDescription(
285
CN_TUNNEL, new TunnelContentDescription(description));
288
SessionDescription* TunnelSessionClient::CreateAnswer(
289
const SessionDescription* offer) {
290
std::string content_name;
291
const TunnelContentDescription* offer_tunnel = NULL;
292
if (!FindTunnelContent(offer, &content_name, &offer_tunnel))
295
return NewTunnelSessionDescription(
296
content_name, new TunnelContentDescription(offer_tunnel->description));
298
///////////////////////////////////////////////////////////////////////////////
300
///////////////////////////////////////////////////////////////////////////////
303
// Signalling thread methods
306
TunnelSession::TunnelSession(TunnelSessionClientBase* client, Session* session,
307
talk_base::Thread* stream_thread)
308
: client_(client), session_(session), channel_(NULL) {
309
ASSERT(client_ != NULL);
310
ASSERT(session_ != NULL);
311
session_->SignalState.connect(this, &TunnelSession::OnSessionState);
312
channel_ = new PseudoTcpChannel(stream_thread, session_);
313
channel_->SignalChannelClosed.connect(this, &TunnelSession::OnChannelClosed);
316
TunnelSession::~TunnelSession() {
317
ASSERT(client_ != NULL);
318
ASSERT(session_ == NULL);
319
ASSERT(channel_ == NULL);
322
talk_base::StreamInterface* TunnelSession::GetStream() {
323
ASSERT(channel_ != NULL);
324
return channel_->GetStream();
327
bool TunnelSession::HasSession(Session* session) {
328
ASSERT(NULL != session_);
329
return (session_ == session);
332
Session* TunnelSession::ReleaseSession(bool channel_exists) {
333
ASSERT(NULL != session_);
334
ASSERT(NULL != channel_);
335
Session* session = session_;
336
session_->SignalState.disconnect(this);
339
channel_->SignalChannelClosed.disconnect(this);
345
void TunnelSession::OnSessionState(BaseSession* session,
346
BaseSession::State state) {
347
LOG(LS_INFO) << "TunnelSession::OnSessionState("
348
<< talk_base::nonnull(
349
talk_base::FindLabel(state, SESSION_STATES), "Unknown")
351
ASSERT(session == session_);
354
case Session::STATE_RECEIVEDINITIATE:
357
case Session::STATE_SENTACCEPT:
358
case Session::STATE_RECEIVEDACCEPT:
361
case Session::STATE_SENTTERMINATE:
362
case Session::STATE_RECEIVEDTERMINATE:
365
case Session::STATE_DEINIT:
366
// ReleaseSession should have been called before this.
374
void TunnelSession::OnInitiate() {
375
ASSERT(client_ != NULL);
376
ASSERT(session_ != NULL);
377
client_->OnIncomingTunnel(buzz::Jid(session_->remote_name()), session_);
380
void TunnelSession::OnAccept() {
381
ASSERT(channel_ != NULL);
382
const ContentInfo* content =
383
session_->remote_description()->FirstContentByType(NS_TUNNEL);
384
ASSERT(content != NULL);
385
VERIFY(channel_->Connect(content->name, "tcp"));
388
void TunnelSession::OnTerminate() {
389
ASSERT(channel_ != NULL);
390
channel_->OnSessionTerminate(session_);
393
void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) {
394
ASSERT(channel_ == channel);
395
ASSERT(session_ != NULL);
396
session_->Terminate();
399
///////////////////////////////////////////////////////////////////////////////
401
} // namespace cricket