Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / session / tunnel / tunnelsessionclient.cc
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 "pseudotcpchannel.h"
29 #include "talk/p2p/base/constants.h"
30 #include "talk/p2p/base/transportchannel.h"
31 #include "webrtc/libjingle/xmllite/xmlelement.h"
32 #include "tunnelsessionclient.h"
33 #include "webrtc/base/basicdefs.h"
34 #include "webrtc/base/basictypes.h"
35 #include "webrtc/base/common.h"
36 #include "webrtc/base/helpers.h"
37 #include "webrtc/base/logging.h"
38 #include "webrtc/base/stringutils.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 rtc::MessageData {
56   int event, error;
57   EventData(int ev, int err = 0) : event(ev), error(err) { }
58 };
59
60 struct CreateTunnelData : public rtc::MessageData {
61   buzz::Jid jid;
62   std::string description;
63   rtc::Thread* thread;
64   rtc::StreamInterface* stream;
65 };
66
67 extern const rtc::ConstantLabel SESSION_STATES[];
68
69 const rtc::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, rtc::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 rtc::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 = rtc::Thread::Current();
153   data.stream = NULL;
154   session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data);
155   return data.stream;
156 }
157
158 rtc::StreamInterface* TunnelSessionClientBase::AcceptTunnel(
159     Session* session) {
160   ASSERT(session_manager_->signaling_thread()->IsCurrent());
161   TunnelSession* tunnel = NULL;
162   for (std::vector<TunnelSession*>::iterator it = sessions_.begin();
163        it != sessions_.end();
164        ++it) {
165     if ((*it)->HasSession(session)) {
166       tunnel = *it;
167       break;
168     }
169   }
170   ASSERT(tunnel != NULL);
171
172   SessionDescription* answer = CreateAnswer(session->remote_description());
173   if (answer == NULL)
174     return NULL;
175
176   session->Accept(answer);
177   return tunnel->GetStream();
178 }
179
180 void TunnelSessionClientBase::DeclineTunnel(Session* session) {
181   ASSERT(session_manager_->signaling_thread()->IsCurrent());
182   session->Reject(STR_TERMINATE_DECLINE);
183 }
184
185 void TunnelSessionClientBase::OnMessage(rtc::Message* pmsg) {
186   if (pmsg->message_id == MSG_CREATE_TUNNEL) {
187     ASSERT(session_manager_->signaling_thread()->IsCurrent());
188     CreateTunnelData* data = static_cast<CreateTunnelData*>(pmsg->pdata);
189     SessionDescription* offer = CreateOffer(data->jid, data->description);
190     if (offer == NULL) {
191       return;
192     }
193
194     Session* session = session_manager_->CreateSession(jid_.Str(), namespace_);
195     TunnelSession* tunnel = MakeTunnelSession(session, data->thread,
196                                               INITIATOR);
197     sessions_.push_back(tunnel);
198     session->Initiate(data->jid.Str(), offer);
199     data->stream = tunnel->GetStream();
200   }
201 }
202
203 TunnelSession* TunnelSessionClientBase::MakeTunnelSession(
204     Session* session, rtc::Thread* stream_thread,
205     TunnelSessionRole /*role*/) {
206   return new TunnelSession(this, session, stream_thread);
207 }
208
209 ///////////////////////////////////////////////////////////////////////////////
210 // TunnelSessionClient
211 ///////////////////////////////////////////////////////////////////////////////
212
213 TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
214                                          SessionManager* manager,
215                                          const std::string &ns)
216     : TunnelSessionClientBase(jid, manager, ns) {
217 }
218
219 TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
220                                          SessionManager* manager)
221     : TunnelSessionClientBase(jid, manager, NS_TUNNEL) {
222 }
223
224 TunnelSessionClient::~TunnelSessionClient() {
225 }
226
227
228 bool TunnelSessionClient::ParseContent(SignalingProtocol protocol,
229                                        const buzz::XmlElement* elem,
230                                        ContentDescription** content,
231                                        ParseError* error) {
232   if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) {
233     *content = new TunnelContentDescription(type_elem->BodyText());
234     return true;
235   }
236   return false;
237 }
238
239 bool TunnelSessionClient::WriteContent(
240     SignalingProtocol protocol,
241     const ContentDescription* untyped_content,
242     buzz::XmlElement** elem, WriteError* error) {
243   const TunnelContentDescription* content =
244       static_cast<const TunnelContentDescription*>(untyped_content);
245
246   buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true);
247   buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE);
248   type_elem->SetBodyText(content->description);
249   root->AddElement(type_elem);
250   *elem = root;
251   return true;
252 }
253
254 SessionDescription* NewTunnelSessionDescription(
255     const std::string& content_name, ContentDescription* content) {
256   SessionDescription* sdesc = new SessionDescription();
257   sdesc->AddContent(content_name, NS_TUNNEL, content);
258   return sdesc;
259 }
260
261 bool FindTunnelContent(const cricket::SessionDescription* sdesc,
262                        std::string* name,
263                        const TunnelContentDescription** content) {
264   const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL);
265   if (cinfo == NULL)
266     return false;
267
268   *name = cinfo->name;
269   *content = static_cast<const TunnelContentDescription*>(
270       cinfo->description);
271   return true;
272 }
273
274 void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
275                                            Session *session) {
276   std::string content_name;
277   const TunnelContentDescription* content = NULL;
278   if (!FindTunnelContent(session->remote_description(),
279                          &content_name, &content)) {
280     session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
281     return;
282   }
283
284   SignalIncomingTunnel(this, jid, content->description, session);
285 }
286
287 SessionDescription* TunnelSessionClient::CreateOffer(
288     const buzz::Jid &jid, const std::string &description) {
289   SessionDescription* offer = NewTunnelSessionDescription(
290       CN_TUNNEL, new TunnelContentDescription(description));
291   rtc::scoped_ptr<TransportDescription> tdesc(
292       session_manager_->transport_desc_factory()->CreateOffer(
293           TransportOptions(), NULL));
294   if (tdesc.get()) {
295     offer->AddTransportInfo(TransportInfo(CN_TUNNEL, *tdesc));
296   } else {
297     delete offer;
298     offer = NULL;
299   }
300   return offer;
301 }
302
303 SessionDescription* TunnelSessionClient::CreateAnswer(
304     const SessionDescription* offer) {
305   std::string content_name;
306   const TunnelContentDescription* offer_tunnel = NULL;
307   if (!FindTunnelContent(offer, &content_name, &offer_tunnel))
308     return NULL;
309
310   SessionDescription* answer = NewTunnelSessionDescription(
311       content_name, new TunnelContentDescription(offer_tunnel->description));
312   const TransportInfo* tinfo = offer->GetTransportInfoByName(content_name);
313   if (tinfo) {
314     const TransportDescription* offer_tdesc = &tinfo->description;
315     ASSERT(offer_tdesc != NULL);
316     rtc::scoped_ptr<TransportDescription> tdesc(
317       session_manager_->transport_desc_factory()->CreateAnswer(
318           offer_tdesc, TransportOptions(),  NULL));
319     if (tdesc.get()) {
320       answer->AddTransportInfo(TransportInfo(content_name, *tdesc));
321     } else {
322       delete answer;
323       answer = NULL;
324     }
325   }
326   return answer;
327 }
328 ///////////////////////////////////////////////////////////////////////////////
329 // TunnelSession
330 ///////////////////////////////////////////////////////////////////////////////
331
332 //
333 // Signalling thread methods
334 //
335
336 TunnelSession::TunnelSession(TunnelSessionClientBase* client, Session* session,
337                              rtc::Thread* stream_thread)
338     : client_(client), session_(session), channel_(NULL) {
339   ASSERT(client_ != NULL);
340   ASSERT(session_ != NULL);
341   session_->SignalState.connect(this, &TunnelSession::OnSessionState);
342   channel_ = new PseudoTcpChannel(stream_thread, session_);
343   channel_->SignalChannelClosed.connect(this, &TunnelSession::OnChannelClosed);
344 }
345
346 TunnelSession::~TunnelSession() {
347   ASSERT(client_ != NULL);
348   ASSERT(session_ == NULL);
349   ASSERT(channel_ == NULL);
350 }
351
352 rtc::StreamInterface* TunnelSession::GetStream() {
353   ASSERT(channel_ != NULL);
354   return channel_->GetStream();
355 }
356
357 bool TunnelSession::HasSession(Session* session) {
358   ASSERT(NULL != session_);
359   return (session_ == session);
360 }
361
362 Session* TunnelSession::ReleaseSession(bool channel_exists) {
363   ASSERT(NULL != session_);
364   ASSERT(NULL != channel_);
365   Session* session = session_;
366   session_->SignalState.disconnect(this);
367   session_ = NULL;
368   if (channel_exists)
369     channel_->SignalChannelClosed.disconnect(this);
370   channel_ = NULL;
371   delete this;
372   return session;
373 }
374
375 void TunnelSession::OnSessionState(BaseSession* session,
376                                    BaseSession::State state) {
377   LOG(LS_INFO) << "TunnelSession::OnSessionState("
378                << rtc::nonnull(
379                     rtc::FindLabel(state, SESSION_STATES), "Unknown")
380                << ")";
381   ASSERT(session == session_);
382
383   switch (state) {
384   case Session::STATE_RECEIVEDINITIATE:
385     OnInitiate();
386     break;
387   case Session::STATE_SENTACCEPT:
388   case Session::STATE_RECEIVEDACCEPT:
389     OnAccept();
390     break;
391   case Session::STATE_SENTTERMINATE:
392   case Session::STATE_RECEIVEDTERMINATE:
393     OnTerminate();
394     break;
395   case Session::STATE_DEINIT:
396     // ReleaseSession should have been called before this.
397     ASSERT(false);
398     break;
399   default:
400     break;
401   }
402 }
403
404 void TunnelSession::OnInitiate() {
405   ASSERT(client_ != NULL);
406   ASSERT(session_ != NULL);
407   client_->OnIncomingTunnel(buzz::Jid(session_->remote_name()), session_);
408 }
409
410 void TunnelSession::OnAccept() {
411   ASSERT(channel_ != NULL);
412   const ContentInfo* content =
413       session_->remote_description()->FirstContentByType(NS_TUNNEL);
414   ASSERT(content != NULL);
415   VERIFY(channel_->Connect(
416       content->name, "tcp", ICE_CANDIDATE_COMPONENT_DEFAULT));
417 }
418
419 void TunnelSession::OnTerminate() {
420   ASSERT(channel_ != NULL);
421   channel_->OnSessionTerminate(session_);
422 }
423
424 void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) {
425   ASSERT(channel_ == channel);
426   ASSERT(session_ != NULL);
427   session_->Terminate();
428 }
429
430 ///////////////////////////////////////////////////////////////////////////////
431
432 } // namespace cricket