~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/googletalk/libjingle/talk/session/tunnel/tunnelsessionclient.cc

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * libjingle
3
 
 * Copyright 2004--2008, 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/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"
39
 
 
40
 
namespace cricket {
41
 
 
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";
46
 
 
47
 
enum {
48
 
  MSG_CLOCK = 1,
49
 
  MSG_DESTROY,
50
 
  MSG_TERMINATE,
51
 
  MSG_EVENT,
52
 
  MSG_CREATE_TUNNEL,
53
 
};
54
 
 
55
 
struct EventData : public talk_base::MessageData {
56
 
  int event, error;
57
 
  EventData(int ev, int err = 0) : event(ev), error(err) { }
58
 
};
59
 
 
60
 
struct CreateTunnelData : public talk_base::MessageData {
61
 
  buzz::Jid jid;
62
 
  std::string description;
63
 
  talk_base::Thread* thread;
64
 
  talk_base::StreamInterface* stream;
65
 
};
66
 
 
67
 
extern const talk_base::ConstantLabel SESSION_STATES[];
68
 
 
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),
84
 
  LASTLABEL
85
 
};
86
 
 
87
 
///////////////////////////////////////////////////////////////////////////////
88
 
// TunnelContentDescription
89
 
///////////////////////////////////////////////////////////////////////////////
90
 
 
91
 
struct TunnelContentDescription : public ContentDescription {
92
 
  std::string description;
93
 
 
94
 
  TunnelContentDescription(const std::string& desc) : description(desc) { }
95
 
  virtual ContentDescription* Copy() const {
96
 
    return new TunnelContentDescription(*this);
97
 
  }
98
 
};
99
 
 
100
 
///////////////////////////////////////////////////////////////////////////////
101
 
// TunnelSessionClientBase
102
 
///////////////////////////////////////////////////////////////////////////////
103
 
 
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);
108
 
}
109
 
 
110
 
TunnelSessionClientBase::~TunnelSessionClientBase() {
111
 
  shutdown_ = true;
112
 
  for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
113
 
       it != sessions_.end();
114
 
       ++it) {
115
 
     Session* session = (*it)->ReleaseSession(true);
116
 
     session_manager_->DestroySession(session);
117
 
  }
118
 
  session_manager_->RemoveClient(namespace_);
119
 
}
120
 
 
121
 
void TunnelSessionClientBase::OnSessionCreate(Session* session, bool received) {
122
 
  LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionCreate: received=" 
123
 
               << received;
124
 
  ASSERT(session_manager_->signaling_thread()->IsCurrent());
125
 
  if (received)
126
 
    sessions_.push_back(
127
 
        MakeTunnelSession(session, talk_base::Thread::Current(), RESPONDER));
128
 
}
129
 
 
130
 
void TunnelSessionClientBase::OnSessionDestroy(Session* session) {
131
 
  LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionDestroy";
132
 
  ASSERT(session_manager_->signaling_thread()->IsCurrent());
133
 
  if (shutdown_)
134
 
    return;
135
 
  for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
136
 
       it != sessions_.end();
137
 
       ++it) {
138
 
    if ((*it)->HasSession(session)) {
139
 
      VERIFY((*it)->ReleaseSession(false) == session);
140
 
      sessions_.erase(it);
141
 
      return;
142
 
    }
143
 
  }
144
 
}
145
 
 
146
 
talk_base::StreamInterface* TunnelSessionClientBase::CreateTunnel(
147
 
    const buzz::Jid& to, const std::string& description) {
148
 
  // Valid from any thread
149
 
  CreateTunnelData data;
150
 
  data.jid = to;
151
 
  data.description = description;
152
 
  data.thread = talk_base::Thread::Current();
153
 
  session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data);
154
 
  return data.stream;
155
 
}
156
 
 
157
 
talk_base::StreamInterface* TunnelSessionClientBase::AcceptTunnel(
158
 
    Session* session) {
159
 
  ASSERT(session_manager_->signaling_thread()->IsCurrent());
160
 
  TunnelSession* tunnel = NULL;
161
 
  for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
162
 
       it != sessions_.end();
163
 
       ++it) {
164
 
    if ((*it)->HasSession(session)) {
165
 
      tunnel = *it;
166
 
      break;
167
 
    }
168
 
  }
169
 
  ASSERT(tunnel != NULL);
170
 
 
171
 
  SessionDescription* answer = CreateAnswer(session->remote_description());
172
 
  if (answer == NULL)
173
 
    return NULL;
174
 
 
175
 
  session->Accept(answer);
176
 
  return tunnel->GetStream();
177
 
}
178
 
 
179
 
void TunnelSessionClientBase::DeclineTunnel(Session* session) {
180
 
  ASSERT(session_manager_->signaling_thread()->IsCurrent());
181
 
  session->Reject(STR_TERMINATE_DECLINE);
182
 
}
183
 
 
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,
190
 
                                              INITIATOR);
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();
195
 
  }
196
 
}
197
 
 
198
 
TunnelSession* TunnelSessionClientBase::MakeTunnelSession(
199
 
    Session* session, talk_base::Thread* stream_thread,
200
 
    TunnelSessionRole /*role*/) {
201
 
  return new TunnelSession(this, session, stream_thread);
202
 
}
203
 
 
204
 
///////////////////////////////////////////////////////////////////////////////
205
 
// TunnelSessionClient
206
 
///////////////////////////////////////////////////////////////////////////////
207
 
 
208
 
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
209
 
                                         SessionManager* manager,
210
 
                                         const std::string &ns)
211
 
    : TunnelSessionClientBase(jid, manager, ns) {
212
 
}
213
 
 
214
 
TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
215
 
                                         SessionManager* manager)
216
 
    : TunnelSessionClientBase(jid, manager, NS_TUNNEL) {
217
 
}
218
 
 
219
 
TunnelSessionClient::~TunnelSessionClient() {
220
 
}
221
 
 
222
 
 
223
 
bool TunnelSessionClient::ParseContent(SignalingProtocol protocol,
224
 
                                       const buzz::XmlElement* elem,
225
 
                                       const ContentDescription** content,
226
 
                                       ParseError* error) {
227
 
  if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) {
228
 
    *content = new TunnelContentDescription(type_elem->BodyText());
229
 
    return true;
230
 
  }
231
 
  return false;
232
 
}
233
 
 
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);
240
 
 
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);
245
 
  *elem = root;
246
 
  return true;
247
 
}
248
 
 
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);
253
 
  return sdesc;
254
 
}
255
 
 
256
 
bool FindTunnelContent(const cricket::SessionDescription* sdesc,
257
 
                       std::string* name,
258
 
                       const TunnelContentDescription** content) {
259
 
  const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL);
260
 
  if (cinfo == NULL)
261
 
    return false;
262
 
 
263
 
  *name = cinfo->name;
264
 
  *content = static_cast<const TunnelContentDescription*>(
265
 
      cinfo->description);
266
 
  return true;
267
 
}
268
 
 
269
 
void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
270
 
                                           Session *session) {
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);
276
 
    return;
277
 
  }
278
 
 
279
 
  SignalIncomingTunnel(this, jid, content->description, session);
280
 
}
281
 
 
282
 
SessionDescription* TunnelSessionClient::CreateOffer(
283
 
    const buzz::Jid &jid, const std::string &description) {
284
 
  return NewTunnelSessionDescription(
285
 
      CN_TUNNEL, new TunnelContentDescription(description));
286
 
}
287
 
 
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))
293
 
    return NULL;
294
 
 
295
 
  return NewTunnelSessionDescription(
296
 
      content_name, new TunnelContentDescription(offer_tunnel->description));
297
 
}
298
 
///////////////////////////////////////////////////////////////////////////////
299
 
// TunnelSession
300
 
///////////////////////////////////////////////////////////////////////////////
301
 
 
302
 
//
303
 
// Signalling thread methods
304
 
//
305
 
 
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);
314
 
}
315
 
 
316
 
TunnelSession::~TunnelSession() {
317
 
  ASSERT(client_ != NULL);
318
 
  ASSERT(session_ == NULL);
319
 
  ASSERT(channel_ == NULL);
320
 
}
321
 
 
322
 
talk_base::StreamInterface* TunnelSession::GetStream() {
323
 
  ASSERT(channel_ != NULL);
324
 
  return channel_->GetStream();
325
 
}
326
 
 
327
 
bool TunnelSession::HasSession(Session* session) {
328
 
  ASSERT(NULL != session_);
329
 
  return (session_ == session);
330
 
}
331
 
 
332
 
Session* TunnelSession::ReleaseSession(bool channel_exists) {
333
 
  ASSERT(NULL != session_);
334
 
  ASSERT(NULL != channel_);
335
 
  Session* session = session_;
336
 
  session_->SignalState.disconnect(this);
337
 
  session_ = NULL;
338
 
  if (channel_exists)
339
 
    channel_->SignalChannelClosed.disconnect(this);
340
 
  channel_ = NULL;
341
 
  delete this;
342
 
  return session;
343
 
}
344
 
 
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")
350
 
               << ")";
351
 
  ASSERT(session == session_);
352
 
 
353
 
  switch (state) {
354
 
  case Session::STATE_RECEIVEDINITIATE:
355
 
    OnInitiate();
356
 
    break;
357
 
  case Session::STATE_SENTACCEPT:
358
 
  case Session::STATE_RECEIVEDACCEPT:
359
 
    OnAccept();
360
 
    break;
361
 
  case Session::STATE_SENTTERMINATE:
362
 
  case Session::STATE_RECEIVEDTERMINATE:
363
 
    OnTerminate();
364
 
    break;
365
 
  case Session::STATE_DEINIT:
366
 
    // ReleaseSession should have been called before this.
367
 
    ASSERT(false);
368
 
    break;
369
 
  default:
370
 
    break;
371
 
  }
372
 
}
373
 
 
374
 
void TunnelSession::OnInitiate() {
375
 
  ASSERT(client_ != NULL);
376
 
  ASSERT(session_ != NULL);
377
 
  client_->OnIncomingTunnel(buzz::Jid(session_->remote_name()), session_);
378
 
}
379
 
 
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"));
386
 
}
387
 
 
388
 
void TunnelSession::OnTerminate() {
389
 
  ASSERT(channel_ != NULL);
390
 
  channel_->OnSessionTerminate(session_);
391
 
}
392
 
 
393
 
void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) {
394
 
  ASSERT(channel_ == channel);
395
 
  ASSERT(session_ != NULL);
396
 
  session_->Terminate();
397
 
}
398
 
 
399
 
///////////////////////////////////////////////////////////////////////////////
400
 
 
401
 
} // namespace cricket