| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 "webrtc/p2p/base/constants.h" |  | 
| 30 #include "webrtc/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 |  | 
| OLD | NEW | 
|---|