📄 tunnelsessionclient.cc
字号:
/* * libjingle * Copyright 2004--2006, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "talk/base/basicdefs.h"#include "talk/base/basictypes.h"#include "talk/base/common.h"#include "talk/base/helpers.h"#include "talk/base/logging.h"#include "talk/base/stringutils.h"#include "talk/p2p/base/transportchannel.h"#include "talk/xmllite/xmlelement.h"#include "pseudotcpchannel.h"#include "tunnelsessionclient.h"namespace cricket {const std::string NS_TUNNEL("http://www.google.com/talk/tunnel");const buzz::QName QN_TUNNEL_DESCRIPTION(NS_TUNNEL, "description");const buzz::QName QN_TUNNEL_TYPE(NS_TUNNEL, "type");enum { MSG_CLOCK = 1, MSG_DESTROY, MSG_TERMINATE, MSG_EVENT, MSG_CREATE_TUNNEL,};struct EventData : public talk_base::MessageData { int event, error; EventData(int ev, int err = 0) : event(ev), error(err) { }};struct CreateTunnelData : public talk_base::MessageData { buzz::Jid jid; std::string description; talk_base::Thread* thread; talk_base::StreamInterface* stream;};extern const talk_base::ConstantLabel SESSION_STATES[];const talk_base::ConstantLabel SESSION_STATES[] = { KLABEL(Session::STATE_INIT), KLABEL(Session::STATE_SENTINITIATE), KLABEL(Session::STATE_RECEIVEDINITIATE), KLABEL(Session::STATE_SENTACCEPT), KLABEL(Session::STATE_RECEIVEDACCEPT), KLABEL(Session::STATE_SENTMODIFY), KLABEL(Session::STATE_RECEIVEDMODIFY), KLABEL(Session::STATE_SENTREJECT), KLABEL(Session::STATE_RECEIVEDREJECT), KLABEL(Session::STATE_SENTREDIRECT), KLABEL(Session::STATE_SENTTERMINATE), KLABEL(Session::STATE_RECEIVEDTERMINATE), KLABEL(Session::STATE_INPROGRESS), KLABEL(Session::STATE_DEINIT), LASTLABEL};///////////////////////////////////////////////////////////////////////////////// TunnelSessionDescription///////////////////////////////////////////////////////////////////////////////struct TunnelSessionDescription : public SessionDescription { std::string description; TunnelSessionDescription(const std::string& desc) : description(desc) { }};///////////////////////////////////////////////////////////////////////////////// TunnelSessionClient///////////////////////////////////////////////////////////////////////////////TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager) : jid_(jid), session_manager_(manager), shutdown_(false) { // Register ourselves as the handler of tunnel sessions. session_manager_->AddClient(NS_TUNNEL, this);}TunnelSessionClient::~TunnelSessionClient() { shutdown_ = true; for (std::vector<TunnelSession*>::iterator it = sessions_.begin(); it != sessions_.end(); ++it) { Session* session = (*it)->ReleaseSession(true); session_manager_->DestroySession(session); } session_manager_->RemoveClient(NS_TUNNEL);}const SessionDescription* TunnelSessionClient::CreateSessionDescription( const buzz::XmlElement* element) { if (const buzz::XmlElement* type_elem = element->FirstNamed(QN_TUNNEL_TYPE)) { return new TunnelSessionDescription(type_elem->BodyText()); } ASSERT(false); return 0;}buzz::XmlElement* TunnelSessionClient::TranslateSessionDescription( const SessionDescription* description) { const TunnelSessionDescription* desc = static_cast<const TunnelSessionDescription*>(description); buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true); buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE); type_elem->SetBodyText(desc->description); root->AddElement(type_elem); return root;}void TunnelSessionClient::OnSessionCreate(Session* session, bool received) { LOG(LS_INFO) << "TunnelSessionClient::OnSessionCreate: received=" << received; ASSERT(session_manager_->signaling_thread()->IsCurrent()); if (received) sessions_.push_back( new TunnelSession(this, session, talk_base::Thread::Current()));}void TunnelSessionClient::OnSessionDestroy(Session* session) { LOG(LS_INFO) << "TunnelSessionClient::OnSessionDestroy"; ASSERT(session_manager_->signaling_thread()->IsCurrent()); if (shutdown_) return; for (std::vector<TunnelSession*>::iterator it = sessions_.begin(); it != sessions_.end(); ++it) { if ((*it)->HasSession(session)) { VERIFY((*it)->ReleaseSession(false) == session); sessions_.erase(it); return; } }}talk_base::StreamInterface* TunnelSessionClient::CreateTunnel( const buzz::Jid& to, const std::string& description) { // Valid from any thread CreateTunnelData data; data.jid = to; data.description = description; data.thread = talk_base::Thread::Current(); session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data); return data.stream;}talk_base::StreamInterface* TunnelSessionClient::AcceptTunnel( Session* session) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); TunnelSession* tunnel = NULL; for (std::vector<TunnelSession*>::iterator it = sessions_.begin(); it != sessions_.end(); ++it) { if ((*it)->HasSession(session)) { tunnel = *it; break; } } ASSERT(tunnel != NULL); const TunnelSessionDescription* in_desc = static_cast<const TunnelSessionDescription*>( session->remote_description()); TunnelSessionDescription* out_desc = new TunnelSessionDescription( in_desc->description); session->Accept(out_desc); return tunnel->GetStream();}void TunnelSessionClient::DeclineTunnel(Session* session) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); session->Reject();}void TunnelSessionClient::OnMessage(talk_base::Message* pmsg) { if (pmsg->message_id == MSG_CREATE_TUNNEL) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); CreateTunnelData* data = static_cast<CreateTunnelData*>(pmsg->pdata); Session* session = session_manager_->CreateSession(jid_.Str(), NS_TUNNEL); TunnelSession* tunnel = new TunnelSession(this, session, data->thread); sessions_.push_back(tunnel); TunnelSessionDescription* desc = new TunnelSessionDescription(data->description); session->Initiate(data->jid.Str(), NULL, desc); data->stream = tunnel->GetStream(); }}///////////////////////////////////////////////////////////////////////////////// TunnelSession/////////////////////////////////////////////////////////////////////////////////// Signalling thread methods//TunnelSession::TunnelSession(TunnelSessionClient* client, Session* session, talk_base::Thread* stream_thread) : client_(client), session_(session), channel_(NULL) { ASSERT(client_ != NULL); ASSERT(session_ != NULL); session_->SignalState.connect(this, &TunnelSession::OnSessionState); channel_ = new PseudoTcpChannel(stream_thread, session_); channel_->SignalChannelClosed.connect(this, &TunnelSession::OnChannelClosed);}TunnelSession::~TunnelSession() { ASSERT(client_ != NULL); ASSERT(session_ == NULL); ASSERT(channel_ == NULL);}talk_base::StreamInterface* TunnelSession::GetStream() { ASSERT(channel_ != NULL); return channel_->GetStream();}bool TunnelSession::HasSession(Session* session) { ASSERT(NULL != session_); return (session_ == session);}Session* TunnelSession::ReleaseSession(bool channel_exists) { ASSERT(NULL != session_); ASSERT(NULL != channel_); Session* session = session_; session_->SignalState.disconnect(this); session_ = NULL; if (channel_exists) channel_->SignalChannelClosed.disconnect(this); channel_ = NULL; delete this; return session;}void TunnelSession::OnSessionState(Session* session, Session::State state) { LOG(LS_INFO) << "TunnelSession::OnSessionState(" << talk_base::nonnull( talk_base::FindLabel(state, SESSION_STATES), "Unknown") << ")"; ASSERT(session == session_); switch (state) { case Session::STATE_RECEIVEDINITIATE: OnInitiate(); break; case Session::STATE_SENTACCEPT: case Session::STATE_RECEIVEDACCEPT: OnAccept(); break; case Session::STATE_SENTTERMINATE: case Session::STATE_RECEIVEDTERMINATE: OnTerminate(); break; case Session::STATE_DEINIT: // ReleaseSession should have been called before this. ASSERT(false); break; }}void TunnelSession::OnInitiate() { const TunnelSessionDescription* in_desc = static_cast<const TunnelSessionDescription*>( session_->remote_description()); ASSERT(client_ != NULL); ASSERT(session_ != NULL); client_->SignalIncomingTunnel(client_, buzz::Jid(session_->remote_name()), in_desc->description, session_);}void TunnelSession::OnAccept() { ASSERT(channel_ != NULL); VERIFY(channel_->Connect("tcp"));}void TunnelSession::OnTerminate() {}void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) { ASSERT(channel_ == channel); ASSERT(session_ != NULL); session_->Terminate();}///////////////////////////////////////////////////////////////////////////////} // namespace cricket
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -