Revert "Split up (Jingle)Session from BaseSession. This is part of an ongoing effort to move Jingle-specific code out of WebRTC and into its own repository."
This reverts r7992. It broke the Chromium build because the Chroumium build relies on the logic in webtc/libjingle/session.cc, but Chromium doesn't compile that file. R=henrike@webrtc.org Review URL: https://webrtc-codereview.appspot.com/38389004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7923 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
4afb59903c
commit
f050791ba0
@ -37,12 +37,12 @@
|
|||||||
#include "talk/media/base/screencastid.h"
|
#include "talk/media/base/screencastid.h"
|
||||||
#include "talk/media/base/streamparams.h"
|
#include "talk/media/base/streamparams.h"
|
||||||
#include "talk/media/base/videocommon.h"
|
#include "talk/media/base/videocommon.h"
|
||||||
|
#include "webrtc/p2p/base/session.h"
|
||||||
#include "webrtc/p2p/client/socketmonitor.h"
|
#include "webrtc/p2p/client/socketmonitor.h"
|
||||||
#include "talk/session/media/audiomonitor.h"
|
#include "talk/session/media/audiomonitor.h"
|
||||||
#include "talk/session/media/currentspeakermonitor.h"
|
#include "talk/session/media/currentspeakermonitor.h"
|
||||||
#include "talk/session/media/mediamessages.h"
|
#include "talk/session/media/mediamessages.h"
|
||||||
#include "talk/session/media/mediasession.h"
|
#include "talk/session/media/mediasession.h"
|
||||||
#include "webrtc/libjingle/session/session.h"
|
|
||||||
#include "webrtc/libjingle/xmpp/jid.h"
|
#include "webrtc/libjingle/xmpp/jid.h"
|
||||||
#include "webrtc/base/messagequeue.h"
|
#include "webrtc/base/messagequeue.h"
|
||||||
|
|
||||||
@ -160,9 +160,9 @@ class Call : public rtc::MessageHandler, public sigslot::has_slots<> {
|
|||||||
sigslot::signal0<> SignalSetupToCallVoicemail;
|
sigslot::signal0<> SignalSetupToCallVoicemail;
|
||||||
sigslot::signal2<Call*, Session*> SignalAddSession;
|
sigslot::signal2<Call*, Session*> SignalAddSession;
|
||||||
sigslot::signal2<Call*, Session*> SignalRemoveSession;
|
sigslot::signal2<Call*, Session*> SignalRemoveSession;
|
||||||
sigslot::signal3<Call*, Session*, BaseSession::State>
|
sigslot::signal3<Call*, Session*, Session::State>
|
||||||
SignalSessionState;
|
SignalSessionState;
|
||||||
sigslot::signal3<Call*, Session*, BaseSession::Error>
|
sigslot::signal3<Call*, Session*, Session::Error>
|
||||||
SignalSessionError;
|
SignalSessionError;
|
||||||
sigslot::signal3<Call*, Session*, const std::string &>
|
sigslot::signal3<Call*, Session*, const std::string &>
|
||||||
SignalReceivedTerminateReason;
|
SignalReceivedTerminateReason;
|
||||||
@ -192,7 +192,7 @@ class Call : public rtc::MessageHandler, public sigslot::has_slots<> {
|
|||||||
private:
|
private:
|
||||||
void OnMessage(rtc::Message* message);
|
void OnMessage(rtc::Message* message);
|
||||||
void OnSessionState(BaseSession* base_session, BaseSession::State state);
|
void OnSessionState(BaseSession* base_session, BaseSession::State state);
|
||||||
void OnSessionError(BaseSession* base_session, BaseSession::Error error);
|
void OnSessionError(BaseSession* base_session, Session::Error error);
|
||||||
void OnSessionInfoMessage(
|
void OnSessionInfoMessage(
|
||||||
Session* session, const buzz::XmlElement* action_elem);
|
Session* session, const buzz::XmlElement* action_elem);
|
||||||
void OnViewRequest(
|
void OnViewRequest(
|
||||||
|
@ -1555,21 +1555,21 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
// Test failures in SetLocalContent.
|
// Test failures in SetLocalContent.
|
||||||
media_channel1_->set_fail_set_recv_codecs(true);
|
media_channel1_->set_fail_set_recv_codecs(true);
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTINITIATE);
|
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
||||||
media_channel1_->set_fail_set_recv_codecs(true);
|
media_channel1_->set_fail_set_recv_codecs(true);
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTACCEPT);
|
session1_.SetState(cricket::Session::STATE_SENTACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
||||||
|
|
||||||
// Test failures in SetRemoteContent.
|
// Test failures in SetRemoteContent.
|
||||||
media_channel1_->set_fail_set_send_codecs(true);
|
media_channel1_->set_fail_set_send_codecs(true);
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDINITIATE);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
||||||
media_channel1_->set_fail_set_send_codecs(true);
|
media_channel1_->set_fail_set_send_codecs(true);
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDACCEPT);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_CONTENT, session1_.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1581,7 +1581,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
session1_.set_local_description(sdesc);
|
session1_.set_local_description(sdesc);
|
||||||
|
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTINITIATE);
|
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
||||||
|
|
||||||
@ -1589,7 +1589,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
sdesc = CreateSessionDescriptionWithStream(2);
|
sdesc = CreateSessionDescriptionWithStream(2);
|
||||||
session1_.set_local_description(sdesc);
|
session1_.set_local_description(sdesc);
|
||||||
|
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTINITIATE);
|
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_FALSE(media_channel1_->HasSendStream(1));
|
EXPECT_FALSE(media_channel1_->HasSendStream(1));
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(2));
|
EXPECT_TRUE(media_channel1_->HasSendStream(2));
|
||||||
@ -1603,13 +1603,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
session1_.set_remote_description(sdesc);
|
session1_.set_remote_description(sdesc);
|
||||||
|
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDINITIATE);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
||||||
|
|
||||||
sdesc = CreateSessionDescriptionWithStream(2);
|
sdesc = CreateSessionDescriptionWithStream(2);
|
||||||
session1_.set_remote_description(sdesc);
|
session1_.set_remote_description(sdesc);
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDINITIATE);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_FALSE(media_channel1_->HasRecvStream(1));
|
EXPECT_FALSE(media_channel1_->HasRecvStream(1));
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(2));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(2));
|
||||||
@ -1623,7 +1623,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
session1_.set_remote_description(sdesc);
|
session1_.set_remote_description(sdesc);
|
||||||
|
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDINITIATE);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
||||||
|
|
||||||
@ -1631,7 +1631,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
sdesc = CreateSessionDescriptionWithStream(2);
|
sdesc = CreateSessionDescriptionWithStream(2);
|
||||||
session1_.set_local_description(sdesc);
|
session1_.set_local_description(sdesc);
|
||||||
|
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTPRACCEPT);
|
session1_.SetState(cricket::Session::STATE_SENTPRACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(2));
|
EXPECT_TRUE(media_channel1_->HasSendStream(2));
|
||||||
@ -1640,7 +1640,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
sdesc = CreateSessionDescriptionWithStream(3);
|
sdesc = CreateSessionDescriptionWithStream(3);
|
||||||
session1_.set_local_description(sdesc);
|
session1_.set_local_description(sdesc);
|
||||||
|
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTACCEPT);
|
session1_.SetState(cricket::Session::STATE_SENTACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(1));
|
||||||
EXPECT_FALSE(media_channel1_->HasSendStream(2));
|
EXPECT_FALSE(media_channel1_->HasSendStream(2));
|
||||||
@ -1655,7 +1655,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
session1_.set_local_description(sdesc);
|
session1_.set_local_description(sdesc);
|
||||||
|
|
||||||
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
session1_.SetError(cricket::BaseSession::ERROR_NONE, "");
|
||||||
session1_.SetState(cricket::BaseSession::STATE_SENTINITIATE);
|
session1_.SetState(cricket::Session::STATE_SENTINITIATE);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
||||||
|
|
||||||
@ -1663,7 +1663,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
sdesc = CreateSessionDescriptionWithStream(2);
|
sdesc = CreateSessionDescriptionWithStream(2);
|
||||||
session1_.set_remote_description(sdesc);
|
session1_.set_remote_description(sdesc);
|
||||||
|
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDPRACCEPT);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDPRACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
||||||
EXPECT_TRUE(media_channel1_->HasRecvStream(2));
|
EXPECT_TRUE(media_channel1_->HasRecvStream(2));
|
||||||
@ -1672,7 +1672,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
|
|||||||
sdesc = CreateSessionDescriptionWithStream(3);
|
sdesc = CreateSessionDescriptionWithStream(3);
|
||||||
session1_.set_remote_description(sdesc);
|
session1_.set_remote_description(sdesc);
|
||||||
|
|
||||||
session1_.SetState(cricket::BaseSession::STATE_RECEIVEDACCEPT);
|
session1_.SetState(cricket::Session::STATE_RECEIVEDACCEPT);
|
||||||
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
EXPECT_EQ(cricket::BaseSession::ERROR_NONE, session1_.error());
|
||||||
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
EXPECT_TRUE(media_channel1_->HasSendStream(1));
|
||||||
EXPECT_FALSE(media_channel1_->HasRecvStream(2));
|
EXPECT_FALSE(media_channel1_->HasRecvStream(2));
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
namespace cricket {
|
namespace cricket {
|
||||||
|
|
||||||
class BaseSession;
|
class BaseSession;
|
||||||
|
class Session;
|
||||||
struct AudioInfo;
|
struct AudioInfo;
|
||||||
struct MediaStreams;
|
struct MediaStreams;
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@
|
|||||||
#define TALK_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_
|
#define TALK_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_
|
||||||
|
|
||||||
#include "webrtc/p2p/base/pseudotcp.h"
|
#include "webrtc/p2p/base/pseudotcp.h"
|
||||||
|
#include "webrtc/p2p/base/session.h"
|
||||||
#include "webrtc/base/criticalsection.h"
|
#include "webrtc/base/criticalsection.h"
|
||||||
#include "webrtc/base/messagequeue.h"
|
#include "webrtc/base/messagequeue.h"
|
||||||
#include "webrtc/base/stream.h"
|
#include "webrtc/base/stream.h"
|
||||||
#include "webrtc/libjingle/session/session.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
class Thread;
|
class Thread;
|
||||||
|
@ -1,859 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "webrtc/libjingle/session/session.h"
|
|
||||||
|
|
||||||
#include "webrtc/libjingle/xmpp/constants.h"
|
|
||||||
#include "webrtc/libjingle/xmpp/jid.h"
|
|
||||||
#include "webrtc/p2p/base/p2ptransport.h"
|
|
||||||
|
|
||||||
namespace cricket {
|
|
||||||
|
|
||||||
bool BadMessage(const buzz::QName type,
|
|
||||||
const std::string& text,
|
|
||||||
MessageError* err) {
|
|
||||||
err->SetType(type);
|
|
||||||
err->SetText(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Session::Session(SessionManager* session_manager,
|
|
||||||
const std::string& local_name,
|
|
||||||
const std::string& initiator_name,
|
|
||||||
const std::string& sid,
|
|
||||||
const std::string& content_type,
|
|
||||||
SessionClient* client)
|
|
||||||
: BaseSession(session_manager->signaling_thread(),
|
|
||||||
session_manager->worker_thread(),
|
|
||||||
session_manager->port_allocator(),
|
|
||||||
sid, content_type, initiator_name == local_name) {
|
|
||||||
ASSERT(client != NULL);
|
|
||||||
session_manager_ = session_manager;
|
|
||||||
local_name_ = local_name;
|
|
||||||
initiator_name_ = initiator_name;
|
|
||||||
transport_parser_ = new P2PTransportParser();
|
|
||||||
client_ = client;
|
|
||||||
initiate_acked_ = false;
|
|
||||||
current_protocol_ = PROTOCOL_HYBRID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Session::~Session() {
|
|
||||||
delete transport_parser_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::Initiate(const std::string& to,
|
|
||||||
const SessionDescription* sdesc) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
SessionError error;
|
|
||||||
|
|
||||||
// Only from STATE_INIT
|
|
||||||
if (state() != STATE_INIT)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Setup for signaling.
|
|
||||||
set_remote_name(to);
|
|
||||||
set_local_description(sdesc);
|
|
||||||
if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
|
|
||||||
&error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not create transports: " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SendInitiateMessage(sdesc, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to connect transport proxy and impl here so that we can process
|
|
||||||
// the TransportDescriptions.
|
|
||||||
SpeculativelyConnectAllTransportChannels();
|
|
||||||
|
|
||||||
PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
|
|
||||||
SetState(Session::STATE_SENTINITIATE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::Accept(const SessionDescription* sdesc) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
|
|
||||||
// Only if just received initiate
|
|
||||||
if (state() != STATE_RECEIVEDINITIATE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Setup for signaling.
|
|
||||||
set_local_description(sdesc);
|
|
||||||
|
|
||||||
SessionError error;
|
|
||||||
if (!SendAcceptMessage(sdesc, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send accept message: " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// TODO(juberti): Add BUNDLE support to transport-info messages.
|
|
||||||
PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
|
|
||||||
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
|
|
||||||
SetState(Session::STATE_SENTACCEPT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::Reject(const std::string& reason) {
|
|
||||||
ASSERT(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;
|
|
||||||
|
|
||||||
SessionError error;
|
|
||||||
if (!SendRejectMessage(reason, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send reject message: " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetState(STATE_SENTREJECT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::TerminateWithReason(const std::string& reason) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
|
|
||||||
// Either side can terminate, at any time.
|
|
||||||
switch (state()) {
|
|
||||||
case STATE_SENTTERMINATE:
|
|
||||||
case STATE_RECEIVEDTERMINATE:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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:
|
|
||||||
SessionError error;
|
|
||||||
if (!SendTerminateMessage(reason, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetState(STATE_SENTTERMINATE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendInfoMessage(const XmlElements& elems,
|
|
||||||
const std::string& remote_name) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
SessionError error;
|
|
||||||
if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send info message " << error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) {
|
|
||||||
XmlElements elems;
|
|
||||||
WriteError write_error;
|
|
||||||
if (!WriteDescriptionInfo(current_protocol_,
|
|
||||||
contents,
|
|
||||||
GetContentParsers(),
|
|
||||||
&elems, &write_error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not write description info message: "
|
|
||||||
<< write_error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
SessionError error;
|
|
||||||
if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send description info message: "
|
|
||||||
<< error.text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TransportInfos Session::GetEmptyTransportInfos(
|
|
||||||
const ContentInfos& contents) const {
|
|
||||||
TransportInfos tinfos;
|
|
||||||
for (ContentInfos::const_iterator content = contents.begin();
|
|
||||||
content != contents.end(); ++content) {
|
|
||||||
tinfos.push_back(TransportInfo(content->name,
|
|
||||||
TransportDescription(transport_type(),
|
|
||||||
std::string(),
|
|
||||||
std::string())));
|
|
||||||
}
|
|
||||||
return tinfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnRemoteCandidates(
|
|
||||||
const TransportInfos& tinfos, ParseError* error) {
|
|
||||||
for (TransportInfos::const_iterator tinfo = tinfos.begin();
|
|
||||||
tinfo != tinfos.end(); ++tinfo) {
|
|
||||||
std::string str_error;
|
|
||||||
if (!BaseSession::OnRemoteCandidates(
|
|
||||||
tinfo->content_name, tinfo->description.candidates, &str_error)) {
|
|
||||||
return BadParse(str_error, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::CreateTransportProxies(const TransportInfos& tinfos,
|
|
||||||
SessionError* error) {
|
|
||||||
for (TransportInfos::const_iterator tinfo = tinfos.begin();
|
|
||||||
tinfo != tinfos.end(); ++tinfo) {
|
|
||||||
if (tinfo->description.transport_type != transport_type()) {
|
|
||||||
error->SetText("No supported transport in offer.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetOrCreateTransportProxy(tinfo->content_name);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TransportParserMap Session::GetTransportParsers() {
|
|
||||||
TransportParserMap parsers;
|
|
||||||
parsers[transport_type()] = transport_parser_;
|
|
||||||
return parsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
CandidateTranslatorMap Session::GetCandidateTranslators() {
|
|
||||||
CandidateTranslatorMap translators;
|
|
||||||
// NOTE: This technique makes it impossible to parse G-ICE
|
|
||||||
// candidates in session-initiate messages because the channels
|
|
||||||
// aren't yet created at that point. Since we don't use candidates
|
|
||||||
// in session-initiate messages, we should be OK. Once we switch to
|
|
||||||
// ICE, this translation shouldn't be necessary.
|
|
||||||
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
|
||||||
iter != transport_proxies().end(); ++iter) {
|
|
||||||
translators[iter->first] = iter->second;
|
|
||||||
}
|
|
||||||
return translators;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentParserMap Session::GetContentParsers() {
|
|
||||||
ContentParserMap parsers;
|
|
||||||
parsers[content_type()] = client_;
|
|
||||||
// We need to be able parse both RTP-based and SCTP-based Jingle
|
|
||||||
// with the same client.
|
|
||||||
if (content_type() == NS_JINGLE_RTP) {
|
|
||||||
parsers[NS_JINGLE_DRAFT_SCTP] = client_;
|
|
||||||
}
|
|
||||||
return parsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnTransportRequestSignaling(Transport* transport) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
TransportProxy* transproxy = GetTransportProxy(transport);
|
|
||||||
ASSERT(transproxy != NULL);
|
|
||||||
if (transproxy) {
|
|
||||||
// Reset candidate allocation status for the transport proxy.
|
|
||||||
transproxy->set_candidates_allocated(false);
|
|
||||||
}
|
|
||||||
SignalRequestSignaling(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnTransportConnecting(Transport* transport) {
|
|
||||||
// This is an indication that we should begin watching the writability
|
|
||||||
// state of the transport.
|
|
||||||
OnTransportWritable(transport);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnTransportWritable(Transport* transport) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
|
|
||||||
// If the transport is not writable, start a timer to make sure that it
|
|
||||||
// becomes writable within a reasonable amount of time. If it does not, we
|
|
||||||
// terminate since we can't actually send data. If the transport is writable,
|
|
||||||
// cancel the timer. Note that writability transitions may occur repeatedly
|
|
||||||
// during the lifetime of the session.
|
|
||||||
signaling_thread()->Clear(this, MSG_TIMEOUT);
|
|
||||||
if (transport->HasChannels() && !transport->writable()) {
|
|
||||||
signaling_thread()->PostDelayed(
|
|
||||||
session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy,
|
|
||||||
const Candidates& candidates) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
if (transproxy != NULL) {
|
|
||||||
if (initiator() && !initiate_acked_) {
|
|
||||||
// TODO: This is to work around server re-ordering
|
|
||||||
// messages. We send the candidates once the session-initiate
|
|
||||||
// is acked. Once we have fixed the server to guarantee message
|
|
||||||
// order, we can remove this case.
|
|
||||||
transproxy->AddUnsentCandidates(candidates);
|
|
||||||
} else {
|
|
||||||
if (!transproxy->negotiated()) {
|
|
||||||
transproxy->AddSentCandidates(candidates);
|
|
||||||
}
|
|
||||||
SessionError error;
|
|
||||||
if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send transport info message: "
|
|
||||||
<< error.text;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnIncomingMessage(const SessionMessage& msg) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
ASSERT(state() == STATE_INIT || msg.from == remote_name());
|
|
||||||
|
|
||||||
if (current_protocol_== PROTOCOL_HYBRID) {
|
|
||||||
if (msg.protocol == PROTOCOL_GINGLE) {
|
|
||||||
current_protocol_ = PROTOCOL_GINGLE;
|
|
||||||
} else {
|
|
||||||
current_protocol_ = PROTOCOL_JINGLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid = false;
|
|
||||||
MessageError error;
|
|
||||||
switch (msg.type) {
|
|
||||||
case ACTION_SESSION_INITIATE:
|
|
||||||
valid = OnInitiateMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_SESSION_INFO:
|
|
||||||
valid = OnInfoMessage(msg);
|
|
||||||
break;
|
|
||||||
case ACTION_SESSION_ACCEPT:
|
|
||||||
valid = OnAcceptMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_SESSION_REJECT:
|
|
||||||
valid = OnRejectMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_SESSION_TERMINATE:
|
|
||||||
valid = OnTerminateMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_TRANSPORT_INFO:
|
|
||||||
valid = OnTransportInfoMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_TRANSPORT_ACCEPT:
|
|
||||||
valid = OnTransportAcceptMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
case ACTION_DESCRIPTION_INFO:
|
|
||||||
valid = OnDescriptionInfoMessage(msg, &error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
|
|
||||||
"unknown session message type",
|
|
||||||
&error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valid) {
|
|
||||||
SendAcknowledgementMessage(msg.stanza);
|
|
||||||
} else {
|
|
||||||
SignalErrorMessage(this, msg.stanza, error.type,
|
|
||||||
"modify", error.text, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
|
|
||||||
const buzz::XmlElement* response_stanza,
|
|
||||||
const SessionMessage& msg) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
|
|
||||||
if (msg.type == ACTION_SESSION_INITIATE) {
|
|
||||||
OnInitiateAcked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnInitiateAcked() {
|
|
||||||
// TODO: This is to work around server re-ordering
|
|
||||||
// messages. We send the candidates once the session-initiate
|
|
||||||
// is acked. Once we have fixed the server to guarantee message
|
|
||||||
// order, we can remove this case.
|
|
||||||
if (!initiate_acked_) {
|
|
||||||
initiate_acked_ = true;
|
|
||||||
SessionError error;
|
|
||||||
SendAllUnsentTransportInfoMessages(&error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
|
|
||||||
const buzz::XmlElement* error_stanza) {
|
|
||||||
ASSERT(signaling_thread()->IsCurrent());
|
|
||||||
|
|
||||||
SessionMessage msg;
|
|
||||||
ParseError parse_error;
|
|
||||||
if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
|
|
||||||
LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
|
|
||||||
<< ":" << orig_stanza;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the error is a session redirect, call OnRedirectError, which will
|
|
||||||
// continue the session with a new remote JID.
|
|
||||||
SessionRedirect redirect;
|
|
||||||
if (FindSessionRedirect(error_stanza, &redirect)) {
|
|
||||||
SessionError error;
|
|
||||||
if (!OnRedirectError(redirect, &error)) {
|
|
||||||
// TODO: Should we send a message back? The standard
|
|
||||||
// says nothing about it.
|
|
||||||
std::ostringstream desc;
|
|
||||||
desc << "Failed to redirect: " << error.text;
|
|
||||||
LOG(LS_ERROR) << desc.str();
|
|
||||||
SetError(ERROR_RESPONSE, desc.str());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string error_type = "cancel";
|
|
||||||
|
|
||||||
const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
|
|
||||||
if (error) {
|
|
||||||
error_type = error->Attr(buzz::QN_TYPE);
|
|
||||||
|
|
||||||
LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
|
|
||||||
<< "in response to:\n" << orig_stanza->Str();
|
|
||||||
} else {
|
|
||||||
// don't crash if <error> is missing
|
|
||||||
LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.type == ACTION_TRANSPORT_INFO) {
|
|
||||||
// Transport messages frequently generate errors because they are sent right
|
|
||||||
// when we detect a network failure. For that reason, we ignore such
|
|
||||||
// errors, because if we do not establish writability again, we will
|
|
||||||
// terminate anyway. The exceptions are transport-specific error tags,
|
|
||||||
// which we pass on to the respective transport.
|
|
||||||
} else if ((error_type != "continue") && (error_type != "wait")) {
|
|
||||||
// We do not set an error if the other side said it is okay to continue
|
|
||||||
// (possibly after waiting). These errors can be ignored.
|
|
||||||
SetError(ERROR_RESPONSE, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnInitiateMessage(const SessionMessage& msg,
|
|
||||||
MessageError* error) {
|
|
||||||
if (!CheckState(STATE_INIT, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SessionInitiate init;
|
|
||||||
if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
|
|
||||||
GetContentParsers(), GetTransportParsers(),
|
|
||||||
GetCandidateTranslators(),
|
|
||||||
&init, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SessionError session_error;
|
|
||||||
if (!CreateTransportProxies(init.transports, &session_error)) {
|
|
||||||
return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
|
|
||||||
session_error.text, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_remote_name(msg.from);
|
|
||||||
set_initiator_name(msg.initiator);
|
|
||||||
set_remote_description(new SessionDescription(init.ClearContents(),
|
|
||||||
init.transports,
|
|
||||||
init.groups));
|
|
||||||
// Updating transport with TransportDescription.
|
|
||||||
PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
|
|
||||||
SetState(STATE_RECEIVEDINITIATE);
|
|
||||||
|
|
||||||
// Users of Session may listen to state change and call Reject().
|
|
||||||
if (state() != STATE_SENTREJECT) {
|
|
||||||
if (!OnRemoteCandidates(init.transports, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO(juberti): Auto-generate and push down the local transport answer.
|
|
||||||
// This is necessary for trickling to work with RFC 5245 ICE.
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
|
|
||||||
if (!CheckState(STATE_SENTINITIATE, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SessionAccept accept;
|
|
||||||
if (!ParseSessionAccept(msg.protocol, msg.action_elem,
|
|
||||||
GetContentParsers(), GetTransportParsers(),
|
|
||||||
GetCandidateTranslators(),
|
|
||||||
&accept, error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get an accept, we can assume the initiate has been
|
|
||||||
// received, even if we haven't gotten an IQ response.
|
|
||||||
OnInitiateAcked();
|
|
||||||
|
|
||||||
set_remote_description(new SessionDescription(accept.ClearContents(),
|
|
||||||
accept.transports,
|
|
||||||
accept.groups));
|
|
||||||
// Updating transport with TransportDescription.
|
|
||||||
PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
|
|
||||||
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
|
|
||||||
SetState(STATE_RECEIVEDACCEPT);
|
|
||||||
|
|
||||||
if (!OnRemoteCandidates(accept.transports, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
|
|
||||||
if (!CheckState(STATE_SENTINITIATE, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SetState(STATE_RECEIVEDREJECT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnInfoMessage(const SessionMessage& msg) {
|
|
||||||
SignalInfoMessage(this, msg.action_elem);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnTerminateMessage(const SessionMessage& msg,
|
|
||||||
MessageError* error) {
|
|
||||||
SessionTerminate term;
|
|
||||||
if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SignalReceivedTerminateReason(this, term.reason);
|
|
||||||
if (term.debug_reason != buzz::STR_EMPTY) {
|
|
||||||
LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetState(STATE_RECEIVEDTERMINATE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnTransportInfoMessage(const SessionMessage& msg,
|
|
||||||
MessageError* error) {
|
|
||||||
TransportInfos tinfos;
|
|
||||||
if (!ParseTransportInfos(msg.protocol, msg.action_elem,
|
|
||||||
initiator_description()->contents(),
|
|
||||||
GetTransportParsers(), GetCandidateTranslators(),
|
|
||||||
&tinfos, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!OnRemoteCandidates(tinfos, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
|
|
||||||
MessageError* error) {
|
|
||||||
// TODO: Currently here only for compatibility with
|
|
||||||
// Gingle 1.1 clients (notably, Google Voice).
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
|
|
||||||
MessageError* error) {
|
|
||||||
if (!CheckState(STATE_INPROGRESS, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
DescriptionInfo description_info;
|
|
||||||
if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
|
|
||||||
GetContentParsers(), GetTransportParsers(),
|
|
||||||
GetCandidateTranslators(),
|
|
||||||
&description_info, error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentInfos& updated_contents = description_info.contents;
|
|
||||||
|
|
||||||
// TODO: Currently, reflector sends back
|
|
||||||
// video stream updates even for an audio-only call, which causes
|
|
||||||
// this to fail. Put this back once reflector is fixed.
|
|
||||||
//
|
|
||||||
// ContentInfos::iterator it;
|
|
||||||
// First, ensure all updates are valid before modifying remote_description_.
|
|
||||||
// for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
|
|
||||||
// if (remote_description()->GetContentByName(it->name) == NULL) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: We used to replace contents from an update, but
|
|
||||||
// that no longer works with partial updates. We need to figure out
|
|
||||||
// a way to merge patial updates into contents. For now, users of
|
|
||||||
// Session should listen to SignalRemoteDescriptionUpdate and handle
|
|
||||||
// updates. They should not expect remote_description to be the
|
|
||||||
// latest value.
|
|
||||||
//
|
|
||||||
// for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
|
|
||||||
// remote_description()->RemoveContentByName(it->name);
|
|
||||||
// remote_description()->AddContent(it->name, it->type, it->description);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
SignalRemoteDescriptionUpdate(this, updated_contents);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BareJidsEqual(const std::string& name1,
|
|
||||||
const std::string& name2) {
|
|
||||||
buzz::Jid jid1(name1);
|
|
||||||
buzz::Jid jid2(name2);
|
|
||||||
|
|
||||||
return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::OnRedirectError(const SessionRedirect& redirect,
|
|
||||||
SessionError* error) {
|
|
||||||
MessageError message_error;
|
|
||||||
if (!CheckState(STATE_SENTINITIATE, &message_error)) {
|
|
||||||
return BadWrite(message_error.text, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BareJidsEqual(remote_name(), redirect.target))
|
|
||||||
return BadWrite("Redirection not allowed: must be the same bare jid.",
|
|
||||||
error);
|
|
||||||
|
|
||||||
// When we receive a redirect, we point the session at the new JID
|
|
||||||
// and resend the candidates.
|
|
||||||
set_remote_name(redirect.target);
|
|
||||||
return (SendInitiateMessage(local_description(), error) &&
|
|
||||||
ResendAllTransportInfoMessages(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::CheckState(State expected, MessageError* error) {
|
|
||||||
if (state() != expected) {
|
|
||||||
// The server can deliver messages out of order/repeated for various
|
|
||||||
// reasons. For example, if the server does not recive our iq response,
|
|
||||||
// it could assume that the iq it sent was lost, and will then send
|
|
||||||
// it again. Ideally, we should implement reliable messaging with
|
|
||||||
// duplicate elimination.
|
|
||||||
return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
|
|
||||||
"message not allowed in current state",
|
|
||||||
error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::SetError(Error error, const std::string& error_desc) {
|
|
||||||
BaseSession::SetError(error, error_desc);
|
|
||||||
if (error != ERROR_NONE)
|
|
||||||
signaling_thread()->Post(this, MSG_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::OnMessage(rtc::Message* pmsg) {
|
|
||||||
// preserve this because BaseSession::OnMessage may modify it
|
|
||||||
State orig_state = state();
|
|
||||||
|
|
||||||
BaseSession::OnMessage(pmsg);
|
|
||||||
|
|
||||||
switch (pmsg->message_id) {
|
|
||||||
case MSG_ERROR:
|
|
||||||
TerminateWithReason(STR_TERMINATE_ERROR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MSG_STATE:
|
|
||||||
switch (orig_state) {
|
|
||||||
case STATE_SENTREJECT:
|
|
||||||
case STATE_RECEIVEDREJECT:
|
|
||||||
// Assume clean termination.
|
|
||||||
Terminate();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_SENTTERMINATE:
|
|
||||||
case STATE_RECEIVEDTERMINATE:
|
|
||||||
session_manager_->DestroySession(this);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Explicitly ignoring some states here.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendInitiateMessage(const SessionDescription* sdesc,
|
|
||||||
SessionError* error) {
|
|
||||||
SessionInitiate init;
|
|
||||||
init.contents = sdesc->contents();
|
|
||||||
init.transports = GetEmptyTransportInfos(init.contents);
|
|
||||||
init.groups = sdesc->groups();
|
|
||||||
return SendMessage(ACTION_SESSION_INITIATE, init, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::WriteSessionAction(
|
|
||||||
SignalingProtocol protocol, const SessionInitiate& init,
|
|
||||||
XmlElements* elems, WriteError* error) {
|
|
||||||
return WriteSessionInitiate(protocol, init.contents, init.transports,
|
|
||||||
GetContentParsers(), GetTransportParsers(),
|
|
||||||
GetCandidateTranslators(), init.groups,
|
|
||||||
elems, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendAcceptMessage(const SessionDescription* sdesc,
|
|
||||||
SessionError* error) {
|
|
||||||
XmlElements elems;
|
|
||||||
if (!WriteSessionAccept(current_protocol_,
|
|
||||||
sdesc->contents(),
|
|
||||||
GetEmptyTransportInfos(sdesc->contents()),
|
|
||||||
GetContentParsers(), GetTransportParsers(),
|
|
||||||
GetCandidateTranslators(), sdesc->groups(),
|
|
||||||
&elems, error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendRejectMessage(const std::string& reason,
|
|
||||||
SessionError* error) {
|
|
||||||
SessionTerminate term(reason);
|
|
||||||
return SendMessage(ACTION_SESSION_REJECT, term, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendTerminateMessage(const std::string& reason,
|
|
||||||
SessionError* error) {
|
|
||||||
SessionTerminate term(reason);
|
|
||||||
return SendMessage(ACTION_SESSION_TERMINATE, term, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::WriteSessionAction(SignalingProtocol protocol,
|
|
||||||
const SessionTerminate& term,
|
|
||||||
XmlElements* elems, WriteError* error) {
|
|
||||||
WriteSessionTerminate(protocol, term, elems);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
|
|
||||||
SessionError* error) {
|
|
||||||
return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
|
|
||||||
const Candidates& candidates,
|
|
||||||
SessionError* error) {
|
|
||||||
return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
|
|
||||||
TransportDescription(transproxy->type(), std::vector<std::string>(),
|
|
||||||
std::string(), std::string(), ICEMODE_FULL,
|
|
||||||
CONNECTIONROLE_NONE, NULL, candidates)), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::WriteSessionAction(SignalingProtocol protocol,
|
|
||||||
const TransportInfo& tinfo,
|
|
||||||
XmlElements* elems, WriteError* error) {
|
|
||||||
TransportInfos tinfos;
|
|
||||||
tinfos.push_back(tinfo);
|
|
||||||
return WriteTransportInfos(protocol, tinfos,
|
|
||||||
GetTransportParsers(), GetCandidateTranslators(),
|
|
||||||
elems, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::ResendAllTransportInfoMessages(SessionError* error) {
|
|
||||||
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
|
||||||
iter != transport_proxies().end(); ++iter) {
|
|
||||||
TransportProxy* transproxy = iter->second;
|
|
||||||
if (transproxy->sent_candidates().size() > 0) {
|
|
||||||
if (!SendTransportInfoMessage(
|
|
||||||
transproxy, transproxy->sent_candidates(), error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not resend transport info messages: "
|
|
||||||
<< error->text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
transproxy->ClearSentCandidates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
|
|
||||||
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
|
||||||
iter != transport_proxies().end(); ++iter) {
|
|
||||||
TransportProxy* transproxy = iter->second;
|
|
||||||
if (transproxy->unsent_candidates().size() > 0) {
|
|
||||||
if (!SendTransportInfoMessage(
|
|
||||||
transproxy, transproxy->unsent_candidates(), error)) {
|
|
||||||
LOG(LS_ERROR) << "Could not send unsent transport info messages: "
|
|
||||||
<< error->text;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
transproxy->ClearUnsentCandidates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
|
||||||
SessionError* error) {
|
|
||||||
return SendMessage(type, action_elems, remote_name(), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
|
||||||
const std::string& remote_name, SessionError* error) {
|
|
||||||
rtc::scoped_ptr<buzz::XmlElement> stanza(
|
|
||||||
new buzz::XmlElement(buzz::QN_IQ));
|
|
||||||
|
|
||||||
SessionMessage msg(current_protocol_, type, id(), initiator_name());
|
|
||||||
msg.to = remote_name;
|
|
||||||
WriteSessionMessage(msg, action_elems, stanza.get());
|
|
||||||
|
|
||||||
SignalOutgoingMessage(this, stanza.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Action>
|
|
||||||
bool Session::SendMessage(ActionType type, const Action& action,
|
|
||||||
SessionError* error) {
|
|
||||||
rtc::scoped_ptr<buzz::XmlElement> stanza(
|
|
||||||
new buzz::XmlElement(buzz::QN_IQ));
|
|
||||||
if (!WriteActionMessage(type, action, stanza.get(), error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SignalOutgoingMessage(this, stanza.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Action>
|
|
||||||
bool Session::WriteActionMessage(ActionType type, const Action& action,
|
|
||||||
buzz::XmlElement* stanza,
|
|
||||||
WriteError* error) {
|
|
||||||
if (current_protocol_ == PROTOCOL_HYBRID) {
|
|
||||||
if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
|
|
||||||
return false;
|
|
||||||
if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Action>
|
|
||||||
bool Session::WriteActionMessage(SignalingProtocol protocol,
|
|
||||||
ActionType type, const Action& action,
|
|
||||||
buzz::XmlElement* stanza, WriteError* error) {
|
|
||||||
XmlElements action_elems;
|
|
||||||
if (!WriteSessionAction(protocol, action, &action_elems, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SessionMessage msg(protocol, type, id(), initiator_name());
|
|
||||||
msg.to = remote_name();
|
|
||||||
|
|
||||||
WriteSessionMessage(msg, action_elems, stanza);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
|
|
||||||
rtc::scoped_ptr<buzz::XmlElement> ack(
|
|
||||||
new buzz::XmlElement(buzz::QN_IQ));
|
|
||||||
ack->SetAttr(buzz::QN_TO, remote_name());
|
|
||||||
ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
|
|
||||||
ack->SetAttr(buzz::QN_TYPE, "result");
|
|
||||||
|
|
||||||
SignalOutgoingMessage(this, ack.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cricket
|
|
@ -1,265 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_LIBJINGLE_SESSION_SESSION_H_
|
|
||||||
#define WEBRTC_LIBJINGLE_SESSION_SESSION_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/libjingle/xmllite/xmlelement.h"
|
|
||||||
#include "webrtc/libjingle/xmpp/constants.h"
|
|
||||||
#include "webrtc/p2p/base/parsing.h"
|
|
||||||
#include "webrtc/p2p/base/session.h"
|
|
||||||
#include "webrtc/p2p/base/sessionclient.h"
|
|
||||||
#include "webrtc/p2p/base/sessionmanager.h"
|
|
||||||
#include "webrtc/p2p/base/sessionmessages.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace cricket {
|
|
||||||
|
|
||||||
// Used for errors that will send back a specific error message to the
|
|
||||||
// remote peer. We add "type" to the errors because it's needed for
|
|
||||||
// SignalErrorMessage.
|
|
||||||
struct MessageError : ParseError {
|
|
||||||
buzz::QName type;
|
|
||||||
|
|
||||||
// if unset, assume type is a parse error
|
|
||||||
MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {}
|
|
||||||
|
|
||||||
void SetType(const buzz::QName type) {
|
|
||||||
this->type = type;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Used for errors that may be returned by public session methods that
|
|
||||||
// can fail.
|
|
||||||
// TODO: Use this error in Session::Initiate and
|
|
||||||
// Session::Accept.
|
|
||||||
struct SessionError : WriteError {
|
|
||||||
};
|
|
||||||
|
|
||||||
// A specific Session created by the SessionManager, using XMPP for protocol.
|
|
||||||
class Session : public BaseSession {
|
|
||||||
public:
|
|
||||||
// Returns the manager that created and owns this session.
|
|
||||||
SessionManager* session_manager() const { return session_manager_; }
|
|
||||||
|
|
||||||
// Returns the client that is handling the application data of this session.
|
|
||||||
SessionClient* client() const { return client_; }
|
|
||||||
|
|
||||||
// Returns the JID of this client.
|
|
||||||
const std::string& local_name() const { return local_name_; }
|
|
||||||
|
|
||||||
// Returns the JID of the other peer in this session.
|
|
||||||
const std::string& remote_name() const { return remote_name_; }
|
|
||||||
|
|
||||||
// Set the JID of the other peer in this session.
|
|
||||||
// Typically the remote_name_ is set when the session is initiated.
|
|
||||||
// However, sometimes (e.g when a proxy is used) the peer name is
|
|
||||||
// known after the BaseSession has been initiated and it must be updated
|
|
||||||
// explicitly.
|
|
||||||
void set_remote_name(const std::string& name) { remote_name_ = name; }
|
|
||||||
|
|
||||||
// Set the JID of the initiator of this session. Allows for the overriding
|
|
||||||
// of the initiator to be a third-party, eg. the MUC JID when creating p2p
|
|
||||||
// sessions.
|
|
||||||
void set_initiator_name(const std::string& name) { initiator_name_ = name; }
|
|
||||||
|
|
||||||
// Indicates the JID of the entity who initiated this session.
|
|
||||||
// In special cases, may be different than both local_name and remote_name.
|
|
||||||
const std::string& initiator_name() const { return initiator_name_; }
|
|
||||||
|
|
||||||
SignalingProtocol current_protocol() const { return current_protocol_; }
|
|
||||||
|
|
||||||
void set_current_protocol(SignalingProtocol protocol) {
|
|
||||||
current_protocol_ = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates the error state, signaling if necessary.
|
|
||||||
virtual void SetError(Error error, const std::string& error_desc);
|
|
||||||
|
|
||||||
// When the session needs to send signaling messages, it beings by requesting
|
|
||||||
// signaling. The client should handle this by calling OnSignalingReady once
|
|
||||||
// it is ready to send the messages.
|
|
||||||
// (These are called only by SessionManager.)
|
|
||||||
sigslot::signal1<Session*> SignalRequestSignaling;
|
|
||||||
void OnSignalingReady() { BaseSession::OnSignalingReady(); }
|
|
||||||
|
|
||||||
// Takes ownership of session description.
|
|
||||||
// TODO: Add an error argument to pass back to the caller.
|
|
||||||
bool Initiate(const std::string& to,
|
|
||||||
const SessionDescription* sdesc);
|
|
||||||
|
|
||||||
// When we receive an initiate, we create a session in the
|
|
||||||
// RECEIVEDINITIATE state and respond by accepting or rejecting.
|
|
||||||
// Takes ownership of session description.
|
|
||||||
// TODO: Add an error argument to pass back to the caller.
|
|
||||||
bool Accept(const SessionDescription* sdesc);
|
|
||||||
bool Reject(const std::string& reason);
|
|
||||||
bool Terminate() {
|
|
||||||
return TerminateWithReason(STR_TERMINATE_SUCCESS);
|
|
||||||
}
|
|
||||||
bool TerminateWithReason(const std::string& reason);
|
|
||||||
// Fired whenever we receive a terminate message along with a reason
|
|
||||||
sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
|
|
||||||
|
|
||||||
// The two clients in the session may also send one another
|
|
||||||
// arbitrary XML messages, which are called "info" messages. Sending
|
|
||||||
// takes ownership of the given elements. The signal does not; the
|
|
||||||
// parent element will be deleted after the signal.
|
|
||||||
bool SendInfoMessage(const XmlElements& elems,
|
|
||||||
const std::string& remote_name);
|
|
||||||
bool SendDescriptionInfoMessage(const ContentInfos& contents);
|
|
||||||
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Creates or destroys a session. (These are called only SessionManager.)
|
|
||||||
Session(SessionManager *session_manager,
|
|
||||||
const std::string& local_name, const std::string& initiator_name,
|
|
||||||
const std::string& sid, const std::string& content_type,
|
|
||||||
SessionClient* client);
|
|
||||||
~Session();
|
|
||||||
// For each transport info, create a transport proxy. Can fail for
|
|
||||||
// incompatible transport types.
|
|
||||||
bool CreateTransportProxies(const TransportInfos& tinfos,
|
|
||||||
SessionError* error);
|
|
||||||
bool OnRemoteCandidates(const TransportInfos& tinfos,
|
|
||||||
ParseError* error);
|
|
||||||
// Returns a TransportInfo without candidates for each content name.
|
|
||||||
// Uses the transport_type_ of the session.
|
|
||||||
TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
|
|
||||||
|
|
||||||
// Maps passed to serialization functions.
|
|
||||||
TransportParserMap GetTransportParsers();
|
|
||||||
ContentParserMap GetContentParsers();
|
|
||||||
CandidateTranslatorMap GetCandidateTranslators();
|
|
||||||
|
|
||||||
virtual void OnTransportRequestSignaling(Transport* transport);
|
|
||||||
virtual void OnTransportConnecting(Transport* transport);
|
|
||||||
virtual void OnTransportWritable(Transport* transport);
|
|
||||||
virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
|
|
||||||
const Candidates& candidates);
|
|
||||||
virtual void OnMessage(rtc::Message *pmsg);
|
|
||||||
|
|
||||||
// Send various kinds of session messages.
|
|
||||||
bool SendInitiateMessage(const SessionDescription* sdesc,
|
|
||||||
SessionError* error);
|
|
||||||
bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error);
|
|
||||||
bool SendRejectMessage(const std::string& reason, SessionError* error);
|
|
||||||
bool SendTerminateMessage(const std::string& reason, SessionError* error);
|
|
||||||
bool SendTransportInfoMessage(const TransportInfo& tinfo,
|
|
||||||
SessionError* error);
|
|
||||||
bool SendTransportInfoMessage(const TransportProxy* transproxy,
|
|
||||||
const Candidates& candidates,
|
|
||||||
SessionError* error);
|
|
||||||
|
|
||||||
bool ResendAllTransportInfoMessages(SessionError* error);
|
|
||||||
bool SendAllUnsentTransportInfoMessages(SessionError* error);
|
|
||||||
|
|
||||||
// All versions of SendMessage send a message of the given type to
|
|
||||||
// the other client. Can pass either a set of elements or an
|
|
||||||
// "action", which must have a WriteSessionAction method to go along
|
|
||||||
// with it. Sending with an action supports sending a "hybrid"
|
|
||||||
// message. Sending with elements must be sent as Jingle or Gingle.
|
|
||||||
|
|
||||||
// When passing elems, must be either Jingle or Gingle protocol.
|
|
||||||
// Takes ownership of action_elems.
|
|
||||||
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
|
||||||
SessionError* error);
|
|
||||||
// Sends a messge, but overrides the remote name.
|
|
||||||
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
|
||||||
const std::string& remote_name,
|
|
||||||
SessionError* error);
|
|
||||||
// When passing an action, may be Hybrid protocol.
|
|
||||||
template <typename Action>
|
|
||||||
bool SendMessage(ActionType type, const Action& action,
|
|
||||||
SessionError* error);
|
|
||||||
|
|
||||||
// Helper methods to write the session message stanza.
|
|
||||||
template <typename Action>
|
|
||||||
bool WriteActionMessage(ActionType type, const Action& action,
|
|
||||||
buzz::XmlElement* stanza, WriteError* error);
|
|
||||||
template <typename Action>
|
|
||||||
bool WriteActionMessage(SignalingProtocol protocol,
|
|
||||||
ActionType type, const Action& action,
|
|
||||||
buzz::XmlElement* stanza, WriteError* error);
|
|
||||||
|
|
||||||
// Sending messages in hybrid form requires being able to write them
|
|
||||||
// on a per-protocol basis with a common method signature, which all
|
|
||||||
// of these have.
|
|
||||||
bool WriteSessionAction(SignalingProtocol protocol,
|
|
||||||
const SessionInitiate& init,
|
|
||||||
XmlElements* elems, WriteError* error);
|
|
||||||
bool WriteSessionAction(SignalingProtocol protocol,
|
|
||||||
const TransportInfo& tinfo,
|
|
||||||
XmlElements* elems, WriteError* error);
|
|
||||||
bool WriteSessionAction(SignalingProtocol protocol,
|
|
||||||
const SessionTerminate& term,
|
|
||||||
XmlElements* elems, WriteError* error);
|
|
||||||
|
|
||||||
// Sends a message back to the other client indicating that we have received
|
|
||||||
// and accepted their message.
|
|
||||||
void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
|
|
||||||
|
|
||||||
// Once signaling is ready, the session will use this signal to request the
|
|
||||||
// sending of each message. When messages are received by the other client,
|
|
||||||
// they should be handed to OnIncomingMessage.
|
|
||||||
// (These are called only by SessionManager.)
|
|
||||||
sigslot::signal2<Session* , const buzz::XmlElement*> SignalOutgoingMessage;
|
|
||||||
void OnIncomingMessage(const SessionMessage& msg);
|
|
||||||
|
|
||||||
void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
|
|
||||||
const buzz::XmlElement* response_stanza,
|
|
||||||
const SessionMessage& msg);
|
|
||||||
void OnInitiateAcked();
|
|
||||||
void OnFailedSend(const buzz::XmlElement* orig_stanza,
|
|
||||||
const buzz::XmlElement* error_stanza);
|
|
||||||
|
|
||||||
// Invoked when an error is found in an incoming message. This is translated
|
|
||||||
// into the appropriate XMPP response by SessionManager.
|
|
||||||
sigslot::signal6<BaseSession*,
|
|
||||||
const buzz::XmlElement*,
|
|
||||||
const buzz::QName&,
|
|
||||||
const std::string&,
|
|
||||||
const std::string&,
|
|
||||||
const buzz::XmlElement*> SignalErrorMessage;
|
|
||||||
|
|
||||||
// Handlers for the various types of messages. These functions may take
|
|
||||||
// pointers to the whole stanza or to just the session element.
|
|
||||||
bool OnInitiateMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnAcceptMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnRejectMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnInfoMessage(const SessionMessage& msg);
|
|
||||||
bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error);
|
|
||||||
bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
|
|
||||||
|
|
||||||
// Verifies that we are in the appropriate state to receive this message.
|
|
||||||
bool CheckState(State state, MessageError* error);
|
|
||||||
|
|
||||||
SessionManager* session_manager_;
|
|
||||||
bool initiate_acked_;
|
|
||||||
std::string local_name_;
|
|
||||||
std::string initiator_name_;
|
|
||||||
std::string remote_name_;
|
|
||||||
SessionClient* client_;
|
|
||||||
TransportParser* transport_parser_;
|
|
||||||
// Keeps track of what protocol we are speaking.
|
|
||||||
SignalingProtocol current_protocol_;
|
|
||||||
|
|
||||||
friend class SessionManager; // For access to constructor, destructor,
|
|
||||||
// and signaling related methods.
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cricket
|
|
||||||
|
|
||||||
#endif // WEBRTC_LIBJINGLE_SESSION_SESSION_H_
|
|
@ -207,18 +207,6 @@ class Candidate {
|
|||||||
std::string tcptype_;
|
std::string tcptype_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used during parsing and writing to map component to channel name
|
|
||||||
// and back. This is primarily for converting old G-ICE candidate
|
|
||||||
// signalling to new ICE candidate classes.
|
|
||||||
class CandidateTranslator {
|
|
||||||
public:
|
|
||||||
virtual ~CandidateTranslator() {}
|
|
||||||
virtual bool GetChannelNameFromComponent(
|
|
||||||
int component, std::string* channel_name) const = 0;
|
|
||||||
virtual bool GetComponentFromChannelName(
|
|
||||||
const std::string& channel_name, int* component) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|
||||||
#endif // WEBRTC_P2P_BASE_CANDIDATE_H_
|
#endif // WEBRTC_P2P_BASE_CANDIDATE_H_
|
||||||
|
@ -12,15 +12,17 @@
|
|||||||
|
|
||||||
#include "webrtc/p2p/base/dtlstransport.h"
|
#include "webrtc/p2p/base/dtlstransport.h"
|
||||||
#include "webrtc/p2p/base/p2ptransport.h"
|
#include "webrtc/p2p/base/p2ptransport.h"
|
||||||
|
#include "webrtc/p2p/base/sessionclient.h"
|
||||||
#include "webrtc/p2p/base/transport.h"
|
#include "webrtc/p2p/base/transport.h"
|
||||||
#include "webrtc/p2p/base/transportchannelproxy.h"
|
#include "webrtc/p2p/base/transportchannelproxy.h"
|
||||||
#include "webrtc/p2p/base/transportinfo.h"
|
#include "webrtc/p2p/base/transportinfo.h"
|
||||||
|
#include "webrtc/libjingle/xmpp/constants.h"
|
||||||
|
#include "webrtc/libjingle/xmpp/jid.h"
|
||||||
#include "webrtc/base/bind.h"
|
#include "webrtc/base/bind.h"
|
||||||
#include "webrtc/base/common.h"
|
#include "webrtc/base/common.h"
|
||||||
#include "webrtc/base/helpers.h"
|
#include "webrtc/base/helpers.h"
|
||||||
#include "webrtc/base/logging.h"
|
#include "webrtc/base/logging.h"
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
#include "webrtc/base/scoped_ptr.h"
|
||||||
#include "webrtc/base/stringencode.h"
|
|
||||||
#include "webrtc/base/sslstreamadapter.h"
|
#include "webrtc/base/sslstreamadapter.h"
|
||||||
|
|
||||||
#include "webrtc/p2p/base/constants.h"
|
#include "webrtc/p2p/base/constants.h"
|
||||||
@ -29,6 +31,14 @@ namespace cricket {
|
|||||||
|
|
||||||
using rtc::Bind;
|
using rtc::Bind;
|
||||||
|
|
||||||
|
bool BadMessage(const buzz::QName type,
|
||||||
|
const std::string& text,
|
||||||
|
MessageError* err) {
|
||||||
|
err->SetType(type);
|
||||||
|
err->SetText(text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TransportProxy::~TransportProxy() {
|
TransportProxy::~TransportProxy() {
|
||||||
for (ChannelMap::iterator iter = channels_.begin();
|
for (ChannelMap::iterator iter = channels_.begin();
|
||||||
iter != channels_.end(); ++iter) {
|
iter != channels_.end(); ++iter) {
|
||||||
@ -315,37 +325,37 @@ void TransportProxy::SetIdentity(
|
|||||||
|
|
||||||
std::string BaseSession::StateToString(State state) {
|
std::string BaseSession::StateToString(State state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BaseSession::STATE_INIT:
|
case Session::STATE_INIT:
|
||||||
return "STATE_INIT";
|
return "STATE_INIT";
|
||||||
case BaseSession::STATE_SENTINITIATE:
|
case Session::STATE_SENTINITIATE:
|
||||||
return "STATE_SENTINITIATE";
|
return "STATE_SENTINITIATE";
|
||||||
case BaseSession::STATE_RECEIVEDINITIATE:
|
case Session::STATE_RECEIVEDINITIATE:
|
||||||
return "STATE_RECEIVEDINITIATE";
|
return "STATE_RECEIVEDINITIATE";
|
||||||
case BaseSession::STATE_SENTPRACCEPT:
|
case Session::STATE_SENTPRACCEPT:
|
||||||
return "STATE_SENTPRACCEPT";
|
return "STATE_SENTPRACCEPT";
|
||||||
case BaseSession::STATE_SENTACCEPT:
|
case Session::STATE_SENTACCEPT:
|
||||||
return "STATE_SENTACCEPT";
|
return "STATE_SENTACCEPT";
|
||||||
case BaseSession::STATE_RECEIVEDPRACCEPT:
|
case Session::STATE_RECEIVEDPRACCEPT:
|
||||||
return "STATE_RECEIVEDPRACCEPT";
|
return "STATE_RECEIVEDPRACCEPT";
|
||||||
case BaseSession::STATE_RECEIVEDACCEPT:
|
case Session::STATE_RECEIVEDACCEPT:
|
||||||
return "STATE_RECEIVEDACCEPT";
|
return "STATE_RECEIVEDACCEPT";
|
||||||
case BaseSession::STATE_SENTMODIFY:
|
case Session::STATE_SENTMODIFY:
|
||||||
return "STATE_SENTMODIFY";
|
return "STATE_SENTMODIFY";
|
||||||
case BaseSession::STATE_RECEIVEDMODIFY:
|
case Session::STATE_RECEIVEDMODIFY:
|
||||||
return "STATE_RECEIVEDMODIFY";
|
return "STATE_RECEIVEDMODIFY";
|
||||||
case BaseSession::STATE_SENTREJECT:
|
case Session::STATE_SENTREJECT:
|
||||||
return "STATE_SENTREJECT";
|
return "STATE_SENTREJECT";
|
||||||
case BaseSession::STATE_RECEIVEDREJECT:
|
case Session::STATE_RECEIVEDREJECT:
|
||||||
return "STATE_RECEIVEDREJECT";
|
return "STATE_RECEIVEDREJECT";
|
||||||
case BaseSession::STATE_SENTREDIRECT:
|
case Session::STATE_SENTREDIRECT:
|
||||||
return "STATE_SENTREDIRECT";
|
return "STATE_SENTREDIRECT";
|
||||||
case BaseSession::STATE_SENTTERMINATE:
|
case Session::STATE_SENTTERMINATE:
|
||||||
return "STATE_SENTTERMINATE";
|
return "STATE_SENTTERMINATE";
|
||||||
case BaseSession::STATE_RECEIVEDTERMINATE:
|
case Session::STATE_RECEIVEDTERMINATE:
|
||||||
return "STATE_RECEIVEDTERMINATE";
|
return "STATE_RECEIVEDTERMINATE";
|
||||||
case BaseSession::STATE_INPROGRESS:
|
case Session::STATE_INPROGRESS:
|
||||||
return "STATE_INPROGRESS";
|
return "STATE_INPROGRESS";
|
||||||
case BaseSession::STATE_DEINIT:
|
case Session::STATE_DEINIT:
|
||||||
return "STATE_DEINIT";
|
return "STATE_DEINIT";
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -537,6 +547,8 @@ TransportProxy* BaseSession::GetOrCreateTransportProxy(
|
|||||||
this, &BaseSession::OnTransportWritable);
|
this, &BaseSession::OnTransportWritable);
|
||||||
transport->SignalRequestSignaling.connect(
|
transport->SignalRequestSignaling.connect(
|
||||||
this, &BaseSession::OnTransportRequestSignaling);
|
this, &BaseSession::OnTransportRequestSignaling);
|
||||||
|
transport->SignalTransportError.connect(
|
||||||
|
this, &BaseSession::OnTransportSendError);
|
||||||
transport->SignalRouteChange.connect(
|
transport->SignalRouteChange.connect(
|
||||||
this, &BaseSession::OnTransportRouteChange);
|
this, &BaseSession::OnTransportRouteChange);
|
||||||
transport->SignalCandidatesAllocationDone.connect(
|
transport->SignalCandidatesAllocationDone.connect(
|
||||||
@ -903,4 +915,846 @@ void BaseSession::OnMessage(rtc::Message *pmsg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Session::Session(SessionManager* session_manager,
|
||||||
|
const std::string& local_name,
|
||||||
|
const std::string& initiator_name,
|
||||||
|
const std::string& sid,
|
||||||
|
const std::string& content_type,
|
||||||
|
SessionClient* client)
|
||||||
|
: BaseSession(session_manager->signaling_thread(),
|
||||||
|
session_manager->worker_thread(),
|
||||||
|
session_manager->port_allocator(),
|
||||||
|
sid, content_type, initiator_name == local_name) {
|
||||||
|
ASSERT(client != NULL);
|
||||||
|
session_manager_ = session_manager;
|
||||||
|
local_name_ = local_name;
|
||||||
|
initiator_name_ = initiator_name;
|
||||||
|
transport_parser_ = new P2PTransportParser();
|
||||||
|
client_ = client;
|
||||||
|
initiate_acked_ = false;
|
||||||
|
current_protocol_ = PROTOCOL_HYBRID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::~Session() {
|
||||||
|
delete transport_parser_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::Initiate(const std::string& to,
|
||||||
|
const SessionDescription* sdesc) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
SessionError error;
|
||||||
|
|
||||||
|
// Only from STATE_INIT
|
||||||
|
if (state() != STATE_INIT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup for signaling.
|
||||||
|
set_remote_name(to);
|
||||||
|
set_local_description(sdesc);
|
||||||
|
if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
|
||||||
|
&error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not create transports: " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SendInitiateMessage(sdesc, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to connect transport proxy and impl here so that we can process
|
||||||
|
// the TransportDescriptions.
|
||||||
|
SpeculativelyConnectAllTransportChannels();
|
||||||
|
|
||||||
|
PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
|
||||||
|
SetState(Session::STATE_SENTINITIATE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::Accept(const SessionDescription* sdesc) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
|
||||||
|
// Only if just received initiate
|
||||||
|
if (state() != STATE_RECEIVEDINITIATE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup for signaling.
|
||||||
|
set_local_description(sdesc);
|
||||||
|
|
||||||
|
SessionError error;
|
||||||
|
if (!SendAcceptMessage(sdesc, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send accept message: " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO(juberti): Add BUNDLE support to transport-info messages.
|
||||||
|
PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
|
||||||
|
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
|
||||||
|
SetState(Session::STATE_SENTACCEPT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::Reject(const std::string& reason) {
|
||||||
|
ASSERT(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;
|
||||||
|
|
||||||
|
SessionError error;
|
||||||
|
if (!SendRejectMessage(reason, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send reject message: " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetState(STATE_SENTREJECT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::TerminateWithReason(const std::string& reason) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
|
||||||
|
// Either side can terminate, at any time.
|
||||||
|
switch (state()) {
|
||||||
|
case STATE_SENTTERMINATE:
|
||||||
|
case STATE_RECEIVEDTERMINATE:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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:
|
||||||
|
SessionError error;
|
||||||
|
if (!SendTerminateMessage(reason, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetState(STATE_SENTTERMINATE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendInfoMessage(const XmlElements& elems,
|
||||||
|
const std::string& remote_name) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
SessionError error;
|
||||||
|
if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send info message " << error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) {
|
||||||
|
XmlElements elems;
|
||||||
|
WriteError write_error;
|
||||||
|
if (!WriteDescriptionInfo(current_protocol_,
|
||||||
|
contents,
|
||||||
|
GetContentParsers(),
|
||||||
|
&elems, &write_error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not write description info message: "
|
||||||
|
<< write_error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SessionError error;
|
||||||
|
if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send description info message: "
|
||||||
|
<< error.text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportInfos Session::GetEmptyTransportInfos(
|
||||||
|
const ContentInfos& contents) const {
|
||||||
|
TransportInfos tinfos;
|
||||||
|
for (ContentInfos::const_iterator content = contents.begin();
|
||||||
|
content != contents.end(); ++content) {
|
||||||
|
tinfos.push_back(TransportInfo(content->name,
|
||||||
|
TransportDescription(transport_type(),
|
||||||
|
std::string(),
|
||||||
|
std::string())));
|
||||||
|
}
|
||||||
|
return tinfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnRemoteCandidates(
|
||||||
|
const TransportInfos& tinfos, ParseError* error) {
|
||||||
|
for (TransportInfos::const_iterator tinfo = tinfos.begin();
|
||||||
|
tinfo != tinfos.end(); ++tinfo) {
|
||||||
|
std::string str_error;
|
||||||
|
if (!BaseSession::OnRemoteCandidates(
|
||||||
|
tinfo->content_name, tinfo->description.candidates, &str_error)) {
|
||||||
|
return BadParse(str_error, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::CreateTransportProxies(const TransportInfos& tinfos,
|
||||||
|
SessionError* error) {
|
||||||
|
for (TransportInfos::const_iterator tinfo = tinfos.begin();
|
||||||
|
tinfo != tinfos.end(); ++tinfo) {
|
||||||
|
if (tinfo->description.transport_type != transport_type()) {
|
||||||
|
error->SetText("No supported transport in offer.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetOrCreateTransportProxy(tinfo->content_name);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportParserMap Session::GetTransportParsers() {
|
||||||
|
TransportParserMap parsers;
|
||||||
|
parsers[transport_type()] = transport_parser_;
|
||||||
|
return parsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
CandidateTranslatorMap Session::GetCandidateTranslators() {
|
||||||
|
CandidateTranslatorMap translators;
|
||||||
|
// NOTE: This technique makes it impossible to parse G-ICE
|
||||||
|
// candidates in session-initiate messages because the channels
|
||||||
|
// aren't yet created at that point. Since we don't use candidates
|
||||||
|
// in session-initiate messages, we should be OK. Once we switch to
|
||||||
|
// ICE, this translation shouldn't be necessary.
|
||||||
|
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
||||||
|
iter != transport_proxies().end(); ++iter) {
|
||||||
|
translators[iter->first] = iter->second;
|
||||||
|
}
|
||||||
|
return translators;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentParserMap Session::GetContentParsers() {
|
||||||
|
ContentParserMap parsers;
|
||||||
|
parsers[content_type()] = client_;
|
||||||
|
// We need to be able parse both RTP-based and SCTP-based Jingle
|
||||||
|
// with the same client.
|
||||||
|
if (content_type() == NS_JINGLE_RTP) {
|
||||||
|
parsers[NS_JINGLE_DRAFT_SCTP] = client_;
|
||||||
|
}
|
||||||
|
return parsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnTransportRequestSignaling(Transport* transport) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
TransportProxy* transproxy = GetTransportProxy(transport);
|
||||||
|
ASSERT(transproxy != NULL);
|
||||||
|
if (transproxy) {
|
||||||
|
// Reset candidate allocation status for the transport proxy.
|
||||||
|
transproxy->set_candidates_allocated(false);
|
||||||
|
}
|
||||||
|
SignalRequestSignaling(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnTransportConnecting(Transport* transport) {
|
||||||
|
// This is an indication that we should begin watching the writability
|
||||||
|
// state of the transport.
|
||||||
|
OnTransportWritable(transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnTransportWritable(Transport* transport) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
|
||||||
|
// If the transport is not writable, start a timer to make sure that it
|
||||||
|
// becomes writable within a reasonable amount of time. If it does not, we
|
||||||
|
// terminate since we can't actually send data. If the transport is writable,
|
||||||
|
// cancel the timer. Note that writability transitions may occur repeatedly
|
||||||
|
// during the lifetime of the session.
|
||||||
|
signaling_thread()->Clear(this, MSG_TIMEOUT);
|
||||||
|
if (transport->HasChannels() && !transport->writable()) {
|
||||||
|
signaling_thread()->PostDelayed(
|
||||||
|
session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy,
|
||||||
|
const Candidates& candidates) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
if (transproxy != NULL) {
|
||||||
|
if (initiator() && !initiate_acked_) {
|
||||||
|
// TODO: This is to work around server re-ordering
|
||||||
|
// messages. We send the candidates once the session-initiate
|
||||||
|
// is acked. Once we have fixed the server to guarantee message
|
||||||
|
// order, we can remove this case.
|
||||||
|
transproxy->AddUnsentCandidates(candidates);
|
||||||
|
} else {
|
||||||
|
if (!transproxy->negotiated()) {
|
||||||
|
transproxy->AddSentCandidates(candidates);
|
||||||
|
}
|
||||||
|
SessionError error;
|
||||||
|
if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send transport info message: "
|
||||||
|
<< error.text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnTransportSendError(Transport* transport,
|
||||||
|
const buzz::XmlElement* stanza,
|
||||||
|
const buzz::QName& name,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& text,
|
||||||
|
const buzz::XmlElement* extra_info) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
SignalErrorMessage(this, stanza, name, type, text, extra_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnIncomingMessage(const SessionMessage& msg) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
ASSERT(state() == STATE_INIT || msg.from == remote_name());
|
||||||
|
|
||||||
|
if (current_protocol_== PROTOCOL_HYBRID) {
|
||||||
|
if (msg.protocol == PROTOCOL_GINGLE) {
|
||||||
|
current_protocol_ = PROTOCOL_GINGLE;
|
||||||
|
} else {
|
||||||
|
current_protocol_ = PROTOCOL_JINGLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
MessageError error;
|
||||||
|
switch (msg.type) {
|
||||||
|
case ACTION_SESSION_INITIATE:
|
||||||
|
valid = OnInitiateMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_SESSION_INFO:
|
||||||
|
valid = OnInfoMessage(msg);
|
||||||
|
break;
|
||||||
|
case ACTION_SESSION_ACCEPT:
|
||||||
|
valid = OnAcceptMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_SESSION_REJECT:
|
||||||
|
valid = OnRejectMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_SESSION_TERMINATE:
|
||||||
|
valid = OnTerminateMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_TRANSPORT_INFO:
|
||||||
|
valid = OnTransportInfoMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_TRANSPORT_ACCEPT:
|
||||||
|
valid = OnTransportAcceptMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
case ACTION_DESCRIPTION_INFO:
|
||||||
|
valid = OnDescriptionInfoMessage(msg, &error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
|
||||||
|
"unknown session message type",
|
||||||
|
&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
SendAcknowledgementMessage(msg.stanza);
|
||||||
|
} else {
|
||||||
|
SignalErrorMessage(this, msg.stanza, error.type,
|
||||||
|
"modify", error.text, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
|
||||||
|
const buzz::XmlElement* response_stanza,
|
||||||
|
const SessionMessage& msg) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
|
||||||
|
if (msg.type == ACTION_SESSION_INITIATE) {
|
||||||
|
OnInitiateAcked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnInitiateAcked() {
|
||||||
|
// TODO: This is to work around server re-ordering
|
||||||
|
// messages. We send the candidates once the session-initiate
|
||||||
|
// is acked. Once we have fixed the server to guarantee message
|
||||||
|
// order, we can remove this case.
|
||||||
|
if (!initiate_acked_) {
|
||||||
|
initiate_acked_ = true;
|
||||||
|
SessionError error;
|
||||||
|
SendAllUnsentTransportInfoMessages(&error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
|
||||||
|
const buzz::XmlElement* error_stanza) {
|
||||||
|
ASSERT(signaling_thread()->IsCurrent());
|
||||||
|
|
||||||
|
SessionMessage msg;
|
||||||
|
ParseError parse_error;
|
||||||
|
if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
|
||||||
|
LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
|
||||||
|
<< ":" << orig_stanza;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the error is a session redirect, call OnRedirectError, which will
|
||||||
|
// continue the session with a new remote JID.
|
||||||
|
SessionRedirect redirect;
|
||||||
|
if (FindSessionRedirect(error_stanza, &redirect)) {
|
||||||
|
SessionError error;
|
||||||
|
if (!OnRedirectError(redirect, &error)) {
|
||||||
|
// TODO: Should we send a message back? The standard
|
||||||
|
// says nothing about it.
|
||||||
|
std::ostringstream desc;
|
||||||
|
desc << "Failed to redirect: " << error.text;
|
||||||
|
LOG(LS_ERROR) << desc.str();
|
||||||
|
SetError(ERROR_RESPONSE, desc.str());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string error_type = "cancel";
|
||||||
|
|
||||||
|
const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
|
||||||
|
if (error) {
|
||||||
|
error_type = error->Attr(buzz::QN_TYPE);
|
||||||
|
|
||||||
|
LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
|
||||||
|
<< "in response to:\n" << orig_stanza->Str();
|
||||||
|
} else {
|
||||||
|
// don't crash if <error> is missing
|
||||||
|
LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.type == ACTION_TRANSPORT_INFO) {
|
||||||
|
// Transport messages frequently generate errors because they are sent right
|
||||||
|
// when we detect a network failure. For that reason, we ignore such
|
||||||
|
// errors, because if we do not establish writability again, we will
|
||||||
|
// terminate anyway. The exceptions are transport-specific error tags,
|
||||||
|
// which we pass on to the respective transport.
|
||||||
|
} else if ((error_type != "continue") && (error_type != "wait")) {
|
||||||
|
// We do not set an error if the other side said it is okay to continue
|
||||||
|
// (possibly after waiting). These errors can be ignored.
|
||||||
|
SetError(ERROR_RESPONSE, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnInitiateMessage(const SessionMessage& msg,
|
||||||
|
MessageError* error) {
|
||||||
|
if (!CheckState(STATE_INIT, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SessionInitiate init;
|
||||||
|
if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
|
||||||
|
GetContentParsers(), GetTransportParsers(),
|
||||||
|
GetCandidateTranslators(),
|
||||||
|
&init, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SessionError session_error;
|
||||||
|
if (!CreateTransportProxies(init.transports, &session_error)) {
|
||||||
|
return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
|
||||||
|
session_error.text, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_remote_name(msg.from);
|
||||||
|
set_initiator_name(msg.initiator);
|
||||||
|
set_remote_description(new SessionDescription(init.ClearContents(),
|
||||||
|
init.transports,
|
||||||
|
init.groups));
|
||||||
|
// Updating transport with TransportDescription.
|
||||||
|
PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
|
||||||
|
SetState(STATE_RECEIVEDINITIATE);
|
||||||
|
|
||||||
|
// Users of Session may listen to state change and call Reject().
|
||||||
|
if (state() != STATE_SENTREJECT) {
|
||||||
|
if (!OnRemoteCandidates(init.transports, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO(juberti): Auto-generate and push down the local transport answer.
|
||||||
|
// This is necessary for trickling to work with RFC 5245 ICE.
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
|
||||||
|
if (!CheckState(STATE_SENTINITIATE, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SessionAccept accept;
|
||||||
|
if (!ParseSessionAccept(msg.protocol, msg.action_elem,
|
||||||
|
GetContentParsers(), GetTransportParsers(),
|
||||||
|
GetCandidateTranslators(),
|
||||||
|
&accept, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get an accept, we can assume the initiate has been
|
||||||
|
// received, even if we haven't gotten an IQ response.
|
||||||
|
OnInitiateAcked();
|
||||||
|
|
||||||
|
set_remote_description(new SessionDescription(accept.ClearContents(),
|
||||||
|
accept.transports,
|
||||||
|
accept.groups));
|
||||||
|
// Updating transport with TransportDescription.
|
||||||
|
PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
|
||||||
|
MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
|
||||||
|
SetState(STATE_RECEIVEDACCEPT);
|
||||||
|
|
||||||
|
if (!OnRemoteCandidates(accept.transports, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
|
||||||
|
if (!CheckState(STATE_SENTINITIATE, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SetState(STATE_RECEIVEDREJECT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnInfoMessage(const SessionMessage& msg) {
|
||||||
|
SignalInfoMessage(this, msg.action_elem);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnTerminateMessage(const SessionMessage& msg,
|
||||||
|
MessageError* error) {
|
||||||
|
SessionTerminate term;
|
||||||
|
if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SignalReceivedTerminateReason(this, term.reason);
|
||||||
|
if (term.debug_reason != buzz::STR_EMPTY) {
|
||||||
|
LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetState(STATE_RECEIVEDTERMINATE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnTransportInfoMessage(const SessionMessage& msg,
|
||||||
|
MessageError* error) {
|
||||||
|
TransportInfos tinfos;
|
||||||
|
if (!ParseTransportInfos(msg.protocol, msg.action_elem,
|
||||||
|
initiator_description()->contents(),
|
||||||
|
GetTransportParsers(), GetCandidateTranslators(),
|
||||||
|
&tinfos, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!OnRemoteCandidates(tinfos, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
|
||||||
|
MessageError* error) {
|
||||||
|
// TODO: Currently here only for compatibility with
|
||||||
|
// Gingle 1.1 clients (notably, Google Voice).
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
|
||||||
|
MessageError* error) {
|
||||||
|
if (!CheckState(STATE_INPROGRESS, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DescriptionInfo description_info;
|
||||||
|
if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
|
||||||
|
GetContentParsers(), GetTransportParsers(),
|
||||||
|
GetCandidateTranslators(),
|
||||||
|
&description_info, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentInfos& updated_contents = description_info.contents;
|
||||||
|
|
||||||
|
// TODO: Currently, reflector sends back
|
||||||
|
// video stream updates even for an audio-only call, which causes
|
||||||
|
// this to fail. Put this back once reflector is fixed.
|
||||||
|
//
|
||||||
|
// ContentInfos::iterator it;
|
||||||
|
// First, ensure all updates are valid before modifying remote_description_.
|
||||||
|
// for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
|
||||||
|
// if (remote_description()->GetContentByName(it->name) == NULL) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: We used to replace contents from an update, but
|
||||||
|
// that no longer works with partial updates. We need to figure out
|
||||||
|
// a way to merge patial updates into contents. For now, users of
|
||||||
|
// Session should listen to SignalRemoteDescriptionUpdate and handle
|
||||||
|
// updates. They should not expect remote_description to be the
|
||||||
|
// latest value.
|
||||||
|
//
|
||||||
|
// for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
|
||||||
|
// remote_description()->RemoveContentByName(it->name);
|
||||||
|
// remote_description()->AddContent(it->name, it->type, it->description);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
SignalRemoteDescriptionUpdate(this, updated_contents);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BareJidsEqual(const std::string& name1,
|
||||||
|
const std::string& name2) {
|
||||||
|
buzz::Jid jid1(name1);
|
||||||
|
buzz::Jid jid2(name2);
|
||||||
|
|
||||||
|
return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::OnRedirectError(const SessionRedirect& redirect,
|
||||||
|
SessionError* error) {
|
||||||
|
MessageError message_error;
|
||||||
|
if (!CheckState(STATE_SENTINITIATE, &message_error)) {
|
||||||
|
return BadWrite(message_error.text, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BareJidsEqual(remote_name(), redirect.target))
|
||||||
|
return BadWrite("Redirection not allowed: must be the same bare jid.",
|
||||||
|
error);
|
||||||
|
|
||||||
|
// When we receive a redirect, we point the session at the new JID
|
||||||
|
// and resend the candidates.
|
||||||
|
set_remote_name(redirect.target);
|
||||||
|
return (SendInitiateMessage(local_description(), error) &&
|
||||||
|
ResendAllTransportInfoMessages(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::CheckState(State expected, MessageError* error) {
|
||||||
|
if (state() != expected) {
|
||||||
|
// The server can deliver messages out of order/repeated for various
|
||||||
|
// reasons. For example, if the server does not recive our iq response,
|
||||||
|
// it could assume that the iq it sent was lost, and will then send
|
||||||
|
// it again. Ideally, we should implement reliable messaging with
|
||||||
|
// duplicate elimination.
|
||||||
|
return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
|
||||||
|
"message not allowed in current state",
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::SetError(Error error, const std::string& error_desc) {
|
||||||
|
BaseSession::SetError(error, error_desc);
|
||||||
|
if (error != ERROR_NONE)
|
||||||
|
signaling_thread()->Post(this, MSG_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnMessage(rtc::Message* pmsg) {
|
||||||
|
// preserve this because BaseSession::OnMessage may modify it
|
||||||
|
State orig_state = state();
|
||||||
|
|
||||||
|
BaseSession::OnMessage(pmsg);
|
||||||
|
|
||||||
|
switch (pmsg->message_id) {
|
||||||
|
case MSG_ERROR:
|
||||||
|
TerminateWithReason(STR_TERMINATE_ERROR);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_STATE:
|
||||||
|
switch (orig_state) {
|
||||||
|
case STATE_SENTREJECT:
|
||||||
|
case STATE_RECEIVEDREJECT:
|
||||||
|
// Assume clean termination.
|
||||||
|
Terminate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_SENTTERMINATE:
|
||||||
|
case STATE_RECEIVEDTERMINATE:
|
||||||
|
session_manager_->DestroySession(this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Explicitly ignoring some states here.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendInitiateMessage(const SessionDescription* sdesc,
|
||||||
|
SessionError* error) {
|
||||||
|
SessionInitiate init;
|
||||||
|
init.contents = sdesc->contents();
|
||||||
|
init.transports = GetEmptyTransportInfos(init.contents);
|
||||||
|
init.groups = sdesc->groups();
|
||||||
|
return SendMessage(ACTION_SESSION_INITIATE, init, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::WriteSessionAction(
|
||||||
|
SignalingProtocol protocol, const SessionInitiate& init,
|
||||||
|
XmlElements* elems, WriteError* error) {
|
||||||
|
return WriteSessionInitiate(protocol, init.contents, init.transports,
|
||||||
|
GetContentParsers(), GetTransportParsers(),
|
||||||
|
GetCandidateTranslators(), init.groups,
|
||||||
|
elems, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendAcceptMessage(const SessionDescription* sdesc,
|
||||||
|
SessionError* error) {
|
||||||
|
XmlElements elems;
|
||||||
|
if (!WriteSessionAccept(current_protocol_,
|
||||||
|
sdesc->contents(),
|
||||||
|
GetEmptyTransportInfos(sdesc->contents()),
|
||||||
|
GetContentParsers(), GetTransportParsers(),
|
||||||
|
GetCandidateTranslators(), sdesc->groups(),
|
||||||
|
&elems, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendRejectMessage(const std::string& reason,
|
||||||
|
SessionError* error) {
|
||||||
|
SessionTerminate term(reason);
|
||||||
|
return SendMessage(ACTION_SESSION_REJECT, term, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendTerminateMessage(const std::string& reason,
|
||||||
|
SessionError* error) {
|
||||||
|
SessionTerminate term(reason);
|
||||||
|
return SendMessage(ACTION_SESSION_TERMINATE, term, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::WriteSessionAction(SignalingProtocol protocol,
|
||||||
|
const SessionTerminate& term,
|
||||||
|
XmlElements* elems, WriteError* error) {
|
||||||
|
WriteSessionTerminate(protocol, term, elems);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
|
||||||
|
SessionError* error) {
|
||||||
|
return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
|
||||||
|
const Candidates& candidates,
|
||||||
|
SessionError* error) {
|
||||||
|
return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
|
||||||
|
TransportDescription(transproxy->type(), std::vector<std::string>(),
|
||||||
|
std::string(), std::string(), ICEMODE_FULL,
|
||||||
|
CONNECTIONROLE_NONE, NULL, candidates)), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::WriteSessionAction(SignalingProtocol protocol,
|
||||||
|
const TransportInfo& tinfo,
|
||||||
|
XmlElements* elems, WriteError* error) {
|
||||||
|
TransportInfos tinfos;
|
||||||
|
tinfos.push_back(tinfo);
|
||||||
|
return WriteTransportInfos(protocol, tinfos,
|
||||||
|
GetTransportParsers(), GetCandidateTranslators(),
|
||||||
|
elems, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::ResendAllTransportInfoMessages(SessionError* error) {
|
||||||
|
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
||||||
|
iter != transport_proxies().end(); ++iter) {
|
||||||
|
TransportProxy* transproxy = iter->second;
|
||||||
|
if (transproxy->sent_candidates().size() > 0) {
|
||||||
|
if (!SendTransportInfoMessage(
|
||||||
|
transproxy, transproxy->sent_candidates(), error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not resend transport info messages: "
|
||||||
|
<< error->text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
transproxy->ClearSentCandidates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
|
||||||
|
for (TransportMap::const_iterator iter = transport_proxies().begin();
|
||||||
|
iter != transport_proxies().end(); ++iter) {
|
||||||
|
TransportProxy* transproxy = iter->second;
|
||||||
|
if (transproxy->unsent_candidates().size() > 0) {
|
||||||
|
if (!SendTransportInfoMessage(
|
||||||
|
transproxy, transproxy->unsent_candidates(), error)) {
|
||||||
|
LOG(LS_ERROR) << "Could not send unsent transport info messages: "
|
||||||
|
<< error->text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
transproxy->ClearUnsentCandidates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
||||||
|
SessionError* error) {
|
||||||
|
return SendMessage(type, action_elems, remote_name(), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
|
||||||
|
const std::string& remote_name, SessionError* error) {
|
||||||
|
rtc::scoped_ptr<buzz::XmlElement> stanza(
|
||||||
|
new buzz::XmlElement(buzz::QN_IQ));
|
||||||
|
|
||||||
|
SessionMessage msg(current_protocol_, type, id(), initiator_name());
|
||||||
|
msg.to = remote_name;
|
||||||
|
WriteSessionMessage(msg, action_elems, stanza.get());
|
||||||
|
|
||||||
|
SignalOutgoingMessage(this, stanza.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Action>
|
||||||
|
bool Session::SendMessage(ActionType type, const Action& action,
|
||||||
|
SessionError* error) {
|
||||||
|
rtc::scoped_ptr<buzz::XmlElement> stanza(
|
||||||
|
new buzz::XmlElement(buzz::QN_IQ));
|
||||||
|
if (!WriteActionMessage(type, action, stanza.get(), error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SignalOutgoingMessage(this, stanza.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Action>
|
||||||
|
bool Session::WriteActionMessage(ActionType type, const Action& action,
|
||||||
|
buzz::XmlElement* stanza,
|
||||||
|
WriteError* error) {
|
||||||
|
if (current_protocol_ == PROTOCOL_HYBRID) {
|
||||||
|
if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
|
||||||
|
return false;
|
||||||
|
if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Action>
|
||||||
|
bool Session::WriteActionMessage(SignalingProtocol protocol,
|
||||||
|
ActionType type, const Action& action,
|
||||||
|
buzz::XmlElement* stanza, WriteError* error) {
|
||||||
|
XmlElements action_elems;
|
||||||
|
if (!WriteSessionAction(protocol, action, &action_elems, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SessionMessage msg(protocol, type, id(), initiator_name());
|
||||||
|
msg.to = remote_name();
|
||||||
|
|
||||||
|
WriteSessionMessage(msg, action_elems, stanza);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
|
||||||
|
rtc::scoped_ptr<buzz::XmlElement> ack(
|
||||||
|
new buzz::XmlElement(buzz::QN_IQ));
|
||||||
|
ack->SetAttr(buzz::QN_TO, remote_name());
|
||||||
|
ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
|
||||||
|
ack->SetAttr(buzz::QN_TYPE, "result");
|
||||||
|
|
||||||
|
SignalOutgoingMessage(this, ack.get());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
@ -16,9 +16,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "webrtc/p2p/base/candidate.h"
|
#include "webrtc/p2p/base/parsing.h"
|
||||||
#include "webrtc/p2p/base/port.h"
|
#include "webrtc/p2p/base/port.h"
|
||||||
|
#include "webrtc/p2p/base/sessionclient.h"
|
||||||
|
#include "webrtc/p2p/base/sessionmanager.h"
|
||||||
|
#include "webrtc/p2p/base/sessionmessages.h"
|
||||||
#include "webrtc/p2p/base/transport.h"
|
#include "webrtc/p2p/base/transport.h"
|
||||||
|
#include "webrtc/libjingle/xmllite/xmlelement.h"
|
||||||
|
#include "webrtc/libjingle/xmpp/constants.h"
|
||||||
#include "webrtc/base/refcount.h"
|
#include "webrtc/base/refcount.h"
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
#include "webrtc/base/scoped_ptr.h"
|
||||||
#include "webrtc/base/scoped_ref_ptr.h"
|
#include "webrtc/base/scoped_ref_ptr.h"
|
||||||
@ -36,6 +41,27 @@ class TransportChannelImpl;
|
|||||||
typedef rtc::RefCountedObject<rtc::scoped_ptr<Transport> >
|
typedef rtc::RefCountedObject<rtc::scoped_ptr<Transport> >
|
||||||
TransportWrapper;
|
TransportWrapper;
|
||||||
|
|
||||||
|
// Used for errors that will send back a specific error message to the
|
||||||
|
// remote peer. We add "type" to the errors because it's needed for
|
||||||
|
// SignalErrorMessage.
|
||||||
|
struct MessageError : ParseError {
|
||||||
|
buzz::QName type;
|
||||||
|
|
||||||
|
// if unset, assume type is a parse error
|
||||||
|
MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {}
|
||||||
|
|
||||||
|
void SetType(const buzz::QName type) {
|
||||||
|
this->type = type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used for errors that may be returned by public session methods that
|
||||||
|
// can fail.
|
||||||
|
// TODO: Use this error in Session::Initiate and
|
||||||
|
// Session::Accept.
|
||||||
|
struct SessionError : WriteError {
|
||||||
|
};
|
||||||
|
|
||||||
// Bundles a Transport and ChannelMap together. ChannelMap is used to
|
// Bundles a Transport and ChannelMap together. ChannelMap is used to
|
||||||
// create transport channels before receiving or sending a session
|
// create transport channels before receiving or sending a session
|
||||||
// initiate, and for speculatively connecting channels. Previously, a
|
// initiate, and for speculatively connecting channels. Previously, a
|
||||||
@ -392,6 +418,16 @@ class BaseSession : public sigslot::has_slots<>,
|
|||||||
const Candidates& candidates) {
|
const Candidates& candidates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called when a transport signals that it found an error in an incoming
|
||||||
|
// message.
|
||||||
|
virtual void OnTransportSendError(Transport* transport,
|
||||||
|
const buzz::XmlElement* stanza,
|
||||||
|
const buzz::QName& name,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& text,
|
||||||
|
const buzz::XmlElement* extra_info) {
|
||||||
|
}
|
||||||
|
|
||||||
virtual void OnTransportRouteChange(
|
virtual void OnTransportRouteChange(
|
||||||
Transport* transport,
|
Transport* transport,
|
||||||
int component,
|
int component,
|
||||||
@ -468,6 +504,227 @@ class BaseSession : public sigslot::has_slots<>,
|
|||||||
TransportMap transports_;
|
TransportMap transports_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A specific Session created by the SessionManager, using XMPP for protocol.
|
||||||
|
class Session : public BaseSession {
|
||||||
|
public:
|
||||||
|
// Returns the manager that created and owns this session.
|
||||||
|
SessionManager* session_manager() const { return session_manager_; }
|
||||||
|
|
||||||
|
// Returns the client that is handling the application data of this session.
|
||||||
|
SessionClient* client() const { return client_; }
|
||||||
|
|
||||||
|
// Returns the JID of this client.
|
||||||
|
const std::string& local_name() const { return local_name_; }
|
||||||
|
|
||||||
|
// Returns the JID of the other peer in this session.
|
||||||
|
const std::string& remote_name() const { return remote_name_; }
|
||||||
|
|
||||||
|
// Set the JID of the other peer in this session.
|
||||||
|
// Typically the remote_name_ is set when the session is initiated.
|
||||||
|
// However, sometimes (e.g when a proxy is used) the peer name is
|
||||||
|
// known after the BaseSession has been initiated and it must be updated
|
||||||
|
// explicitly.
|
||||||
|
void set_remote_name(const std::string& name) { remote_name_ = name; }
|
||||||
|
|
||||||
|
// Set the JID of the initiator of this session. Allows for the overriding
|
||||||
|
// of the initiator to be a third-party, eg. the MUC JID when creating p2p
|
||||||
|
// sessions.
|
||||||
|
void set_initiator_name(const std::string& name) { initiator_name_ = name; }
|
||||||
|
|
||||||
|
// Indicates the JID of the entity who initiated this session.
|
||||||
|
// In special cases, may be different than both local_name and remote_name.
|
||||||
|
const std::string& initiator_name() const { return initiator_name_; }
|
||||||
|
|
||||||
|
SignalingProtocol current_protocol() const { return current_protocol_; }
|
||||||
|
|
||||||
|
void set_current_protocol(SignalingProtocol protocol) {
|
||||||
|
current_protocol_ = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the error state, signaling if necessary.
|
||||||
|
virtual void SetError(Error error, const std::string& error_desc);
|
||||||
|
|
||||||
|
// When the session needs to send signaling messages, it beings by requesting
|
||||||
|
// signaling. The client should handle this by calling OnSignalingReady once
|
||||||
|
// it is ready to send the messages.
|
||||||
|
// (These are called only by SessionManager.)
|
||||||
|
sigslot::signal1<Session*> SignalRequestSignaling;
|
||||||
|
void OnSignalingReady() { BaseSession::OnSignalingReady(); }
|
||||||
|
|
||||||
|
// Takes ownership of session description.
|
||||||
|
// TODO: Add an error argument to pass back to the caller.
|
||||||
|
bool Initiate(const std::string& to,
|
||||||
|
const SessionDescription* sdesc);
|
||||||
|
|
||||||
|
// When we receive an initiate, we create a session in the
|
||||||
|
// RECEIVEDINITIATE state and respond by accepting or rejecting.
|
||||||
|
// Takes ownership of session description.
|
||||||
|
// TODO: Add an error argument to pass back to the caller.
|
||||||
|
bool Accept(const SessionDescription* sdesc);
|
||||||
|
bool Reject(const std::string& reason);
|
||||||
|
bool Terminate() {
|
||||||
|
return TerminateWithReason(STR_TERMINATE_SUCCESS);
|
||||||
|
}
|
||||||
|
bool TerminateWithReason(const std::string& reason);
|
||||||
|
// Fired whenever we receive a terminate message along with a reason
|
||||||
|
sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
|
||||||
|
|
||||||
|
// The two clients in the session may also send one another
|
||||||
|
// arbitrary XML messages, which are called "info" messages. Sending
|
||||||
|
// takes ownership of the given elements. The signal does not; the
|
||||||
|
// parent element will be deleted after the signal.
|
||||||
|
bool SendInfoMessage(const XmlElements& elems,
|
||||||
|
const std::string& remote_name);
|
||||||
|
bool SendDescriptionInfoMessage(const ContentInfos& contents);
|
||||||
|
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Creates or destroys a session. (These are called only SessionManager.)
|
||||||
|
Session(SessionManager *session_manager,
|
||||||
|
const std::string& local_name, const std::string& initiator_name,
|
||||||
|
const std::string& sid, const std::string& content_type,
|
||||||
|
SessionClient* client);
|
||||||
|
~Session();
|
||||||
|
// For each transport info, create a transport proxy. Can fail for
|
||||||
|
// incompatible transport types.
|
||||||
|
bool CreateTransportProxies(const TransportInfos& tinfos,
|
||||||
|
SessionError* error);
|
||||||
|
bool OnRemoteCandidates(const TransportInfos& tinfos,
|
||||||
|
ParseError* error);
|
||||||
|
// Returns a TransportInfo without candidates for each content name.
|
||||||
|
// Uses the transport_type_ of the session.
|
||||||
|
TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
|
||||||
|
|
||||||
|
// Maps passed to serialization functions.
|
||||||
|
TransportParserMap GetTransportParsers();
|
||||||
|
ContentParserMap GetContentParsers();
|
||||||
|
CandidateTranslatorMap GetCandidateTranslators();
|
||||||
|
|
||||||
|
virtual void OnTransportRequestSignaling(Transport* transport);
|
||||||
|
virtual void OnTransportConnecting(Transport* transport);
|
||||||
|
virtual void OnTransportWritable(Transport* transport);
|
||||||
|
virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
|
||||||
|
const Candidates& candidates);
|
||||||
|
virtual void OnTransportSendError(Transport* transport,
|
||||||
|
const buzz::XmlElement* stanza,
|
||||||
|
const buzz::QName& name,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& text,
|
||||||
|
const buzz::XmlElement* extra_info);
|
||||||
|
virtual void OnMessage(rtc::Message *pmsg);
|
||||||
|
|
||||||
|
// Send various kinds of session messages.
|
||||||
|
bool SendInitiateMessage(const SessionDescription* sdesc,
|
||||||
|
SessionError* error);
|
||||||
|
bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error);
|
||||||
|
bool SendRejectMessage(const std::string& reason, SessionError* error);
|
||||||
|
bool SendTerminateMessage(const std::string& reason, SessionError* error);
|
||||||
|
bool SendTransportInfoMessage(const TransportInfo& tinfo,
|
||||||
|
SessionError* error);
|
||||||
|
bool SendTransportInfoMessage(const TransportProxy* transproxy,
|
||||||
|
const Candidates& candidates,
|
||||||
|
SessionError* error);
|
||||||
|
|
||||||
|
bool ResendAllTransportInfoMessages(SessionError* error);
|
||||||
|
bool SendAllUnsentTransportInfoMessages(SessionError* error);
|
||||||
|
|
||||||
|
// All versions of SendMessage send a message of the given type to
|
||||||
|
// the other client. Can pass either a set of elements or an
|
||||||
|
// "action", which must have a WriteSessionAction method to go along
|
||||||
|
// with it. Sending with an action supports sending a "hybrid"
|
||||||
|
// message. Sending with elements must be sent as Jingle or Gingle.
|
||||||
|
|
||||||
|
// When passing elems, must be either Jingle or Gingle protocol.
|
||||||
|
// Takes ownership of action_elems.
|
||||||
|
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
||||||
|
SessionError* error);
|
||||||
|
// Sends a messge, but overrides the remote name.
|
||||||
|
bool SendMessage(ActionType type, const XmlElements& action_elems,
|
||||||
|
const std::string& remote_name,
|
||||||
|
SessionError* error);
|
||||||
|
// When passing an action, may be Hybrid protocol.
|
||||||
|
template <typename Action>
|
||||||
|
bool SendMessage(ActionType type, const Action& action,
|
||||||
|
SessionError* error);
|
||||||
|
|
||||||
|
// Helper methods to write the session message stanza.
|
||||||
|
template <typename Action>
|
||||||
|
bool WriteActionMessage(ActionType type, const Action& action,
|
||||||
|
buzz::XmlElement* stanza, WriteError* error);
|
||||||
|
template <typename Action>
|
||||||
|
bool WriteActionMessage(SignalingProtocol protocol,
|
||||||
|
ActionType type, const Action& action,
|
||||||
|
buzz::XmlElement* stanza, WriteError* error);
|
||||||
|
|
||||||
|
// Sending messages in hybrid form requires being able to write them
|
||||||
|
// on a per-protocol basis with a common method signature, which all
|
||||||
|
// of these have.
|
||||||
|
bool WriteSessionAction(SignalingProtocol protocol,
|
||||||
|
const SessionInitiate& init,
|
||||||
|
XmlElements* elems, WriteError* error);
|
||||||
|
bool WriteSessionAction(SignalingProtocol protocol,
|
||||||
|
const TransportInfo& tinfo,
|
||||||
|
XmlElements* elems, WriteError* error);
|
||||||
|
bool WriteSessionAction(SignalingProtocol protocol,
|
||||||
|
const SessionTerminate& term,
|
||||||
|
XmlElements* elems, WriteError* error);
|
||||||
|
|
||||||
|
// Sends a message back to the other client indicating that we have received
|
||||||
|
// and accepted their message.
|
||||||
|
void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
|
||||||
|
|
||||||
|
// Once signaling is ready, the session will use this signal to request the
|
||||||
|
// sending of each message. When messages are received by the other client,
|
||||||
|
// they should be handed to OnIncomingMessage.
|
||||||
|
// (These are called only by SessionManager.)
|
||||||
|
sigslot::signal2<Session* , const buzz::XmlElement*> SignalOutgoingMessage;
|
||||||
|
void OnIncomingMessage(const SessionMessage& msg);
|
||||||
|
|
||||||
|
void OnIncomingResponse(const buzz::XmlElement* orig_stanza,
|
||||||
|
const buzz::XmlElement* response_stanza,
|
||||||
|
const SessionMessage& msg);
|
||||||
|
void OnInitiateAcked();
|
||||||
|
void OnFailedSend(const buzz::XmlElement* orig_stanza,
|
||||||
|
const buzz::XmlElement* error_stanza);
|
||||||
|
|
||||||
|
// Invoked when an error is found in an incoming message. This is translated
|
||||||
|
// into the appropriate XMPP response by SessionManager.
|
||||||
|
sigslot::signal6<BaseSession*,
|
||||||
|
const buzz::XmlElement*,
|
||||||
|
const buzz::QName&,
|
||||||
|
const std::string&,
|
||||||
|
const std::string&,
|
||||||
|
const buzz::XmlElement*> SignalErrorMessage;
|
||||||
|
|
||||||
|
// Handlers for the various types of messages. These functions may take
|
||||||
|
// pointers to the whole stanza or to just the session element.
|
||||||
|
bool OnInitiateMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnAcceptMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnRejectMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnInfoMessage(const SessionMessage& msg);
|
||||||
|
bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error);
|
||||||
|
bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
|
||||||
|
|
||||||
|
// Verifies that we are in the appropriate state to receive this message.
|
||||||
|
bool CheckState(State state, MessageError* error);
|
||||||
|
|
||||||
|
SessionManager* session_manager_;
|
||||||
|
bool initiate_acked_;
|
||||||
|
std::string local_name_;
|
||||||
|
std::string initiator_name_;
|
||||||
|
std::string remote_name_;
|
||||||
|
SessionClient* client_;
|
||||||
|
TransportParser* transport_parser_;
|
||||||
|
// Keeps track of what protocol we are speaking.
|
||||||
|
SignalingProtocol current_protocol_;
|
||||||
|
|
||||||
|
friend class SessionManager; // For access to constructor, destructor,
|
||||||
|
// and signaling related methods.
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|
||||||
#endif // WEBRTC_P2P_BASE_SESSION_H_
|
#endif // WEBRTC_P2P_BASE_SESSION_H_
|
||||||
|
@ -14,6 +14,22 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
|
||||||
|
#include "webrtc/p2p/base/constants.h"
|
||||||
|
#include "webrtc/p2p/base/p2ptransport.h"
|
||||||
|
#include "webrtc/p2p/base/parsing.h"
|
||||||
|
#include "webrtc/p2p/base/portallocator.h"
|
||||||
|
#include "webrtc/p2p/base/relayport.h"
|
||||||
|
#include "webrtc/p2p/base/relayserver.h"
|
||||||
|
#include "webrtc/p2p/base/session.h"
|
||||||
|
#include "webrtc/p2p/base/sessionclient.h"
|
||||||
|
#include "webrtc/p2p/base/sessionmanager.h"
|
||||||
|
#include "webrtc/p2p/base/stunport.h"
|
||||||
|
#include "webrtc/p2p/base/stunserver.h"
|
||||||
|
#include "webrtc/p2p/base/transportchannel.h"
|
||||||
|
#include "webrtc/p2p/base/transportchannelproxy.h"
|
||||||
|
#include "webrtc/p2p/base/udpport.h"
|
||||||
|
#include "webrtc/libjingle/xmpp/constants.h"
|
||||||
#include "webrtc/base/base64.h"
|
#include "webrtc/base/base64.h"
|
||||||
#include "webrtc/base/common.h"
|
#include "webrtc/base/common.h"
|
||||||
#include "webrtc/base/gunit.h"
|
#include "webrtc/base/gunit.h"
|
||||||
@ -22,22 +38,6 @@
|
|||||||
#include "webrtc/base/natserver.h"
|
#include "webrtc/base/natserver.h"
|
||||||
#include "webrtc/base/natsocketfactory.h"
|
#include "webrtc/base/natsocketfactory.h"
|
||||||
#include "webrtc/base/stringencode.h"
|
#include "webrtc/base/stringencode.h"
|
||||||
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
|
|
||||||
#include "webrtc/p2p/base/constants.h"
|
|
||||||
#include "webrtc/p2p/base/p2ptransport.h"
|
|
||||||
#include "webrtc/p2p/base/parsing.h"
|
|
||||||
#include "webrtc/p2p/base/portallocator.h"
|
|
||||||
#include "webrtc/p2p/base/relayport.h"
|
|
||||||
#include "webrtc/p2p/base/relayserver.h"
|
|
||||||
#include "webrtc/p2p/base/sessionclient.h"
|
|
||||||
#include "webrtc/p2p/base/sessionmanager.h"
|
|
||||||
#include "webrtc/p2p/base/stunport.h"
|
|
||||||
#include "webrtc/p2p/base/stunserver.h"
|
|
||||||
#include "webrtc/p2p/base/transportchannel.h"
|
|
||||||
#include "webrtc/p2p/base/transportchannelproxy.h"
|
|
||||||
#include "webrtc/p2p/base/udpport.h"
|
|
||||||
#include "webrtc/libjingle/session/session.h"
|
|
||||||
#include "webrtc/libjingle/xmpp/constants.h"
|
|
||||||
|
|
||||||
using cricket::SignalingProtocol;
|
using cricket::SignalingProtocol;
|
||||||
using cricket::PROTOCOL_HYBRID;
|
using cricket::PROTOCOL_HYBRID;
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
#include "webrtc/p2p/base/sessionmanager.h"
|
#include "webrtc/p2p/base/sessionmanager.h"
|
||||||
|
|
||||||
#include "webrtc/p2p/base/constants.h"
|
#include "webrtc/p2p/base/constants.h"
|
||||||
|
#include "webrtc/p2p/base/session.h"
|
||||||
#include "webrtc/p2p/base/sessionmessages.h"
|
#include "webrtc/p2p/base/sessionmessages.h"
|
||||||
#include "webrtc/libjingle/session/session.h"
|
|
||||||
#include "webrtc/libjingle/xmpp/constants.h"
|
#include "webrtc/libjingle/xmpp/constants.h"
|
||||||
#include "webrtc/libjingle/xmpp/jid.h"
|
#include "webrtc/libjingle/xmpp/jid.h"
|
||||||
#include "webrtc/base/common.h"
|
#include "webrtc/base/common.h"
|
||||||
|
@ -15,11 +15,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "webrtc/p2p/base/candidate.h"
|
|
||||||
#include "webrtc/p2p/base/constants.h"
|
#include "webrtc/p2p/base/constants.h"
|
||||||
#include "webrtc/p2p/base/parsing.h"
|
#include "webrtc/p2p/base/parsing.h"
|
||||||
#include "webrtc/p2p/base/sessiondescription.h" // Needed to delete contents.
|
#include "webrtc/p2p/base/sessiondescription.h" // Needed to delete contents.
|
||||||
#include "webrtc/p2p/base/transport.h"
|
|
||||||
#include "webrtc/p2p/base/transportinfo.h"
|
#include "webrtc/p2p/base/transportinfo.h"
|
||||||
#include "webrtc/libjingle/xmllite/xmlelement.h"
|
#include "webrtc/libjingle/xmllite/xmlelement.h"
|
||||||
#include "webrtc/base/basictypes.h"
|
#include "webrtc/base/basictypes.h"
|
||||||
@ -127,6 +125,17 @@ struct SessionRedirect {
|
|||||||
std::string target;
|
std::string target;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Used during parsing and writing to map component to channel name
|
||||||
|
// and back. This is primarily for converting old G-ICE candidate
|
||||||
|
// signalling to new ICE candidate classes.
|
||||||
|
class CandidateTranslator {
|
||||||
|
public:
|
||||||
|
virtual bool GetChannelNameFromComponent(
|
||||||
|
int component, std::string* channel_name) const = 0;
|
||||||
|
virtual bool GetComponentFromChannelName(
|
||||||
|
const std::string& channel_name, int* component) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Content name => translator
|
// Content name => translator
|
||||||
typedef std::map<std::string, CandidateTranslator*> CandidateTranslatorMap;
|
typedef std::map<std::string, CandidateTranslator*> CandidateTranslatorMap;
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ struct ParseError;
|
|||||||
struct WriteError;
|
struct WriteError;
|
||||||
class CandidateTranslator;
|
class CandidateTranslator;
|
||||||
class PortAllocator;
|
class PortAllocator;
|
||||||
|
class SessionManager;
|
||||||
|
class Session;
|
||||||
class TransportChannel;
|
class TransportChannel;
|
||||||
class TransportChannelImpl;
|
class TransportChannelImpl;
|
||||||
|
|
||||||
|
@ -108,8 +108,6 @@
|
|||||||
'client/sessionsendtask.h',
|
'client/sessionsendtask.h',
|
||||||
'client/socketmonitor.cc',
|
'client/socketmonitor.cc',
|
||||||
'client/socketmonitor.h',
|
'client/socketmonitor.h',
|
||||||
'<(webrtc_root)/libjingle/session/session.cc',
|
|
||||||
'<(webrtc_root)/libjingle/session/session.h',
|
|
||||||
],
|
],
|
||||||
'direct_dependent_settings': {
|
'direct_dependent_settings': {
|
||||||
'cflags_cc!': [
|
'cflags_cc!': [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user