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 433