📄 session.cc
字号:
/* * libjingle * Copyright 2004--2005, 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/p2p/base/session.h"#include "talk/base/common.h"#include "talk/base/logging.h"#include "talk/base/helpers.h"#include "talk/xmpp/constants.h"#include "talk/xmpp/jid.h"#include "talk/p2p/base/sessionclient.h"#include "talk/p2p/base/transport.h"#include "talk/p2p/base/transportchannelproxy.h"#include "talk/p2p/base/p2ptransport.h"#include "talk/p2p/base/constants.h"namespace {const uint32 MSG_TIMEOUT = 1;const uint32 MSG_ERROR = 2;const uint32 MSG_STATE = 3;// This will be initialized at run time to hold the list of default transports.std::string* gDefaultTransports = NULL;size_t gNumDefaultTransports = 0;} // namespacenamespace cricket {Session::Session(SessionManager *session_manager, const std::string& name, const SessionID& id, const std::string& session_type, SessionClient* client) { ASSERT(session_manager->signaling_thread()->IsCurrent()); ASSERT(client != NULL); session_manager_ = session_manager; name_ = name; id_ = id; session_type_ = session_type; client_ = client; error_ = ERROR_NONE; state_ = STATE_INIT; initiator_ = false; description_ = NULL; remote_description_ = NULL; transport_ = NULL; compatibility_mode_ = false;}Session::~Session() { ASSERT(session_manager_->signaling_thread()->IsCurrent()); ASSERT(state_ != STATE_DEINIT); state_ = STATE_DEINIT; SignalState(this, state_); delete description_; delete remote_description_; for (ChannelMap::iterator iter = channels_.begin(); iter != channels_.end(); ++iter) { iter->second->SignalDestroyed(iter->second); delete iter->second; } for (TransportList::iterator iter = potential_transports_.begin(); iter != potential_transports_.end(); ++iter) { delete *iter; } delete transport_;}bool Session::Initiate(const std::string &to, std::vector<buzz::XmlElement*>* extra_xml, const SessionDescription *description) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); // Only from STATE_INIT if (state_ != STATE_INIT) return false; // Setup for signaling. remote_name_ = to; initiator_ = true; description_ = description; // Make sure we have transports to negotiate. CreateTransports(); // Send the initiate message, including the application and transport offers. XmlElements elems; elems.push_back(client_->TranslateSessionDescription(description)); for (TransportList::iterator iter = potential_transports_.begin(); iter != potential_transports_.end(); ++iter) { buzz::XmlElement* elem = (*iter)->CreateTransportOffer(); elems.push_back(elem); } if (extra_xml != NULL) { std::vector<buzz::XmlElement*>::iterator iter = extra_xml->begin(); for (std::vector<buzz::XmlElement*>::iterator iter = extra_xml->begin(); iter != extra_xml->end(); ++iter) { elems.push_back(new buzz::XmlElement(**iter)); } } SendSessionMessage("initiate", elems); SetState(Session::STATE_SENTINITIATE); // We speculatively start attempting connection of the P2P transports. ConnectDefaultTransportChannels(true); return true;}void Session::ConnectDefaultTransportChannels(bool create) { Transport* transport = GetTransport(kNsP2pTransport); if (transport) { for (ChannelMap::iterator iter = channels_.begin(); iter != channels_.end(); ++iter) { ASSERT(create != transport->HasChannel(iter->first)); if (create) { transport->CreateChannel(iter->first, session_type()); } } transport->ConnectChannels(); }}void Session::CreateDefaultTransportChannel(const std::string& name) { // This method is only relevant when we have created the default transport // but not received a transport-accept. ASSERT(transport_ == NULL); ASSERT(state_ == STATE_SENTINITIATE); Transport* p2p_transport = GetTransport(kNsP2pTransport); if (p2p_transport) { ASSERT(!p2p_transport->HasChannel(name)); p2p_transport->CreateChannel(name, session_type()); }}bool Session::Accept(const SessionDescription *description) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); // Only if just received initiate if (state_ != STATE_RECEIVEDINITIATE) return false; // Setup for signaling. initiator_ = false; description_ = description; // If we haven't selected a transport, wait for ChooseTransport to complete if (transport_ == NULL) return true; // Send the accept message. XmlElements elems; elems.push_back(client_->TranslateSessionDescription(description_)); SendSessionMessage("accept", elems); SetState(Session::STATE_SENTACCEPT); return true;}bool Session::Reject() { ASSERT(session_manager_->signaling_thread()->IsCurrent()); // Reject is sent in response to an initiate or modify, to reject the // request if (state_ != STATE_RECEIVEDINITIATE && state_ != STATE_RECEIVEDMODIFY) return false; // Setup for signaling. initiator_ = false; // Send the reject message. SendSessionMessage("reject", XmlElements()); SetState(STATE_SENTREJECT); return true;}bool Session::Redirect(const std::string & target) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); // Redirect is sent in response to an initiate or modify, to redirect the // request if (state_ != STATE_RECEIVEDINITIATE) return false; // Setup for signaling. initiator_ = false; // Send a redirect message to the given target. We include an element that // names the redirector (us), which may be useful to the other side. buzz::XmlElement* target_elem = new buzz::XmlElement(QN_REDIRECT_TARGET); target_elem->AddAttr(buzz::QN_NAME, target); buzz::XmlElement* cookie = new buzz::XmlElement(QN_REDIRECT_COOKIE); buzz::XmlElement* regarding = new buzz::XmlElement(QN_REDIRECT_REGARDING); regarding->AddAttr(buzz::QN_NAME, name_); cookie->AddElement(regarding); XmlElements elems; elems.push_back(target_elem); elems.push_back(cookie); SendSessionMessage("redirect", elems); // A redirect puts us in the same state as reject. It just sends a different // kind of reject message, if you like. SetState(STATE_SENTREDIRECT); return true;}bool Session::Terminate() { ASSERT(session_manager_->signaling_thread()->IsCurrent()); // Either side can terminate, at any time. switch (state_) { case STATE_SENTTERMINATE: case STATE_RECEIVEDTERMINATE: return false; case STATE_SENTREDIRECT: // We must not send terminate if we redirect. break; case STATE_SENTREJECT: case STATE_RECEIVEDREJECT: // We don't need to send terminate if we sent or received a reject... // it's implicit. break; default: SendSessionMessage("terminate", XmlElements()); break; } SetState(STATE_SENTTERMINATE); return true;}void Session::SendInfoMessage(const XmlElements& elems) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); SendSessionMessage("info", elems);}void Session::SetPotentialTransports(const std::string names[], size_t length) { ASSERT(session_manager_->signaling_thread()->IsCurrent()); for (size_t i = 0; i < length; ++i) { Transport* transport = NULL; if (names[i] == kNsP2pTransport) { transport = new P2PTransport(session_manager_); } else { ASSERT(false); } if (transport) { ASSERT(transport->name() == names[i]); potential_transports_.push_back(transport); transport->SignalConnecting.connect( this, &Session::OnTransportConnecting); transport->SignalWritableState.connect( this, &Session::OnTransportWritable); transport->SignalRequestSignaling.connect( this, &Session::OnTransportRequestSignaling); transport->SignalTransportMessage.connect( this, &Session::OnTransportSendMessage); transport->SignalTransportError.connect( this, &Session::OnTransportSendError); transport->SignalChannelGone.connect( this, &Session::OnTransportChannelGone); } }}Transport* Session::GetTransport(const std::string& name) { if (transport_ != NULL) { if (name == transport_->name()) return transport_; } else { for (TransportList::iterator iter = potential_transports_.begin(); iter != potential_transports_.end(); ++iter) { if (name == (*iter)->name()) return *iter; } } return NULL;}TransportChannel* Session::CreateChannel(const std::string& name) { //ASSERT(session_manager_->signaling_thread()->IsCurrent()); ASSERT(channels_.find(name) == channels_.end()); TransportChannelProxy* channel = new TransportChannelProxy(name, session_type_); channels_[name] = channel; if (transport_) { ASSERT(!transport_->HasChannel(name)); channel->SetImplementation(transport_->CreateChannel(name, session_type_)); } else if (state_ == STATE_SENTINITIATE) { // In this case, we have already speculatively created the default // transport. We should create this channel as well so that it may begin // early connection. CreateDefaultTransportChannel(name); } return channel;}TransportChannel* Session::GetChannel(const std::string& name) { ChannelMap::iterator iter = channels_.find(name); return (iter != channels_.end()) ? iter->second : NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -