summaryrefslogtreecommitdiffstats
path: root/remoting/protocol
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-27 20:10:51 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-27 20:10:51 +0000
commite3f03d06435a6bb335f0170ec708c5527eb58b8f (patch)
tree4c3d3b2b9815c432f62fb4225ba7bdcdb62021a0 /remoting/protocol
parent047470cd5b1f4b24ba923b2f533ef9109d0c2664 (diff)
downloadchromium_src-e3f03d06435a6bb335f0170ec708c5527eb58b8f.zip
chromium_src-e3f03d06435a6bb335f0170ec708c5527eb58b8f.tar.gz
chromium_src-e3f03d06435a6bb335f0170ec708c5527eb58b8f.tar.bz2
Parse termination reason and propagate the error to the Session interface.
BUG=91402 TEST=None Review URL: http://codereview.chromium.org/8046018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102999 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/protocol')
-rw-r--r--remoting/protocol/fake_session.cc8
-rw-r--r--remoting/protocol/fake_session.h6
-rw-r--r--remoting/protocol/jingle_messages.cc108
-rw-r--r--remoting/protocol/jingle_messages.h14
-rw-r--r--remoting/protocol/jingle_session.cc6
-rw-r--r--remoting/protocol/jingle_session.h3
-rw-r--r--remoting/protocol/jingle_session_manager.cc11
-rw-r--r--remoting/protocol/pepper_session.cc31
-rw-r--r--remoting/protocol/pepper_session.h13
-rw-r--r--remoting/protocol/protocol_mock_objects.h1
-rw-r--r--remoting/protocol/session.h11
11 files changed, 142 insertions, 70 deletions
diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc
index 2445d0c..a6ed4fd 100644
--- a/remoting/protocol/fake_session.cc
+++ b/remoting/protocol/fake_session.cc
@@ -205,7 +205,9 @@ FakeSession::FakeSession()
: candidate_config_(CandidateSessionConfig::CreateDefault()),
config_(SessionConfig::GetDefault()),
message_loop_(NULL),
- jid_(kTestJid) {
+ jid_(kTestJid),
+ error_(OK),
+ closed_(false) {
}
FakeSession::~FakeSession() { }
@@ -222,6 +224,10 @@ void FakeSession::SetStateChangeCallback(StateChangeCallback* callback) {
callback_.reset(callback);
}
+Session::Error FakeSession::error() {
+ return error_;
+}
+
void FakeSession::CreateStreamChannel(
const std::string& name, const StreamChannelCallback& callback) {
FakeSocket* channel = new FakeSocket();
diff --git a/remoting/protocol/fake_session.h b/remoting/protocol/fake_session.h
index d223774..d415ab1 100644
--- a/remoting/protocol/fake_session.h
+++ b/remoting/protocol/fake_session.h
@@ -130,6 +130,8 @@ class FakeSession : public Session {
message_loop_ = message_loop;
}
+ void set_error(Session::Error error) { error_ = error; }
+
bool is_closed() const { return closed_; }
FakeSocket* GetStreamChannel(const std::string& name);
@@ -138,6 +140,8 @@ class FakeSession : public Session {
// Session interface.
virtual void SetStateChangeCallback(StateChangeCallback* callback);
+ virtual Session::Error error();
+
virtual void CreateStreamChannel(
const std::string& name, const StreamChannelCallback& callback);
virtual void CreateDatagramChannel(
@@ -179,6 +183,8 @@ class FakeSession : public Session {
std::string shared_secret_;
std::string jid_;
+
+ Session::Error error_;
bool closed_;
DISALLOW_COPY_AND_ASSIGN(FakeSession);
diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc
index a7c71c3..de8e137 100644
--- a/remoting/protocol/jingle_messages.cc
+++ b/remoting/protocol/jingle_messages.cc
@@ -26,14 +26,48 @@ namespace {
const char kEmptyNamespace[] = "";
const char kXmlNamespace[] = "http://www.w3.org/XML/1998/namespace";
-const char kSessionInitiateAction[] = "session-initiate";
-const char kSessionAcceptAction[] = "session-accept";
-const char kSessionTerminateAction[] = "session-terminate";
-const char kTransportInfoAction[] = "transport-info";
-
const int kPortMin = 1000;
const int kPortMax = 65535;
+template <typename T>
+struct NameMapElement {
+ const T value;
+ const char* const name;
+};
+
+template <typename T>
+const char* ValueToName(const NameMapElement<T> map[], size_t map_size,
+ T value) {
+ for (size_t i = 0; i < map_size; ++i) {
+ if (map[i].value == value)
+ return map[i].name;
+ }
+ return NULL;
+}
+
+template <typename T>
+T NameToValue(const NameMapElement<T> map[], size_t map_size,
+ const std::string& name, T default_value) {
+ for (size_t i = 0; i < map_size; ++i) {
+ if (map[i].name == name)
+ return map[i].value;
+ }
+ return default_value;
+}
+
+static const NameMapElement<JingleMessage::ActionType> kActionTypes[] = {
+ { JingleMessage::SESSION_INITIATE, "session-initiate" },
+ { JingleMessage::SESSION_ACCEPT, "session-accept" },
+ { JingleMessage::SESSION_TERMINATE, "session-terminate" },
+ { JingleMessage::TRANSPORT_INFO, "transport-info" },
+};
+
+static const NameMapElement<JingleMessage::Reason> kReasons[] = {
+ { JingleMessage::SUCCESS, "success" },
+ { JingleMessage::DECLINE, "decline" },
+ { JingleMessage::INCOMPATIBLE_PARAMETERS, "incompatible-parameters" },
+};
+
bool ParseCandidate(const buzz::XmlElement* element,
cricket::Candidate* candidate) {
DCHECK(element->Name() == QName(kP2PTransportNamespace, "candidate"));
@@ -104,7 +138,7 @@ bool JingleMessage::IsJingleMessage(const buzz::XmlElement* stanza) {
JingleMessage::JingleMessage()
: action(UNKNOWN_ACTION),
- termination_reason(kJingleNamespace, "success") {
+ reason(UNKNOWN_REASON) {
}
JingleMessage::JingleMessage(
@@ -135,15 +169,10 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza,
if (action_str.empty()) {
*error = "action attribute is missing";
return false;
- } else if (action_str == kSessionInitiateAction) {
- action = SESSION_INITIATE;
- } else if (action_str == kSessionAcceptAction) {
- action = SESSION_ACCEPT;
- } else if (action_str == kSessionTerminateAction) {
- action = SESSION_TERMINATE;
- } else if (action_str == kTransportInfoAction) {
- action = TRANSPORT_INFO;
- } else {
+ }
+ action = NameToValue(
+ kActionTypes, arraysize(kActionTypes), action_str, UNKNOWN_ACTION);
+ if (action == UNKNOWN_ACTION) {
*error = "Unknown action " + action_str;
return false;
}
@@ -154,14 +183,17 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza,
return false;
}
- if (action == SESSION_TERMINATE) {
- const XmlElement* reason_tag =
- jingle_tag->FirstNamed(QName(kJingleNamespace, "reason"));
- if (reason_tag && reason_tag->FirstElement())
- termination_reason = reason_tag->FirstElement()->Name();
- return true;
+ const XmlElement* reason_tag =
+ jingle_tag->FirstNamed(QName(kJingleNamespace, "reason"));
+ if (reason_tag && reason_tag->FirstElement()) {
+ reason = NameToValue(
+ kReasons, arraysize(kReasons),
+ reason_tag->FirstElement()->Name().LocalPart(), UNKNOWN_REASON);
}
+ if (action == SESSION_TERMINATE)
+ return true;
+
const XmlElement* content_tag =
jingle_tag->FirstNamed(QName(kJingleNamespace, "content"));
if (!content_tag) {
@@ -227,35 +259,27 @@ buzz::XmlElement* JingleMessage::ToXml() {
root->AddElement(jingle_tag);
jingle_tag->AddAttr(QName(kEmptyNamespace, "sid"), sid);
- std::string action_attr;
- switch (action) {
- case SESSION_INITIATE:
- action_attr = kSessionInitiateAction;
- break;
- case SESSION_ACCEPT:
- action_attr = kSessionAcceptAction;
- break;
- case SESSION_TERMINATE:
- action_attr = kSessionTerminateAction;
- break;
- case TRANSPORT_INFO:
- action_attr = kTransportInfoAction;
- break;
- default:
- NOTREACHED();
- break;
- }
+ const char* action_attr = ValueToName(
+ kActionTypes, arraysize(kActionTypes), action);
+ if (!action_attr)
+ LOG(FATAL) << "Invalid action value " << action;
jingle_tag->AddAttr(QName(kEmptyNamespace, "action"), action_attr);
if (action == SESSION_INITIATE)
jingle_tag->AddAttr(QName(kEmptyNamespace, "initiator"), from);
- if (action == SESSION_TERMINATE) {
+ if (reason != UNKNOWN_REASON) {
XmlElement* reason_tag = new XmlElement(QName(kJingleNamespace, "reason"));
jingle_tag->AddElement(reason_tag);
+ const char* reason_string =
+ ValueToName(kReasons, arraysize(kReasons), reason);
+ if (reason_string == NULL)
+ LOG(FATAL) << "Invalid reason: " << reason;
+ reason_tag->AddElement(new XmlElement(
+ QName(kJingleNamespace, reason_string)));
+ }
- reason_tag->AddElement(new XmlElement(termination_reason));
- } else {
+ if (action != SESSION_TERMINATE) {
XmlElement* content_tag =
new XmlElement(QName(kJingleNamespace, "content"));
jingle_tag->AddElement(content_tag);
diff --git a/remoting/protocol/jingle_messages.h b/remoting/protocol/jingle_messages.h
index f997de8..eb1ec5c 100644
--- a/remoting/protocol/jingle_messages.h
+++ b/remoting/protocol/jingle_messages.h
@@ -33,6 +33,15 @@ struct JingleMessage {
TRANSPORT_INFO,
};
+ enum Reason {
+ // Currently only termination reasons that can be sent by the host
+ // are understood. All others are converted to UNKNOWN_REASON.
+ UNKNOWN_REASON,
+ SUCCESS,
+ DECLINE,
+ INCOMPATIBLE_PARAMETERS,
+ };
+
JingleMessage();
JingleMessage(const std::string& to_value,
ActionType action_value,
@@ -56,7 +65,10 @@ struct JingleMessage {
scoped_ptr<ContentDescription> description;
std::list<cricket::Candidate> candidates;
- buzz::QName termination_reason;
+ // Value from the <reason> tag if it is present in the
+ // message. Useful mainly for session-terminate messages, but Jingle
+ // spec allows it in any message.
+ Reason reason;
};
struct JingleMessageReply {
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index 01ea806..611f97c 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -49,6 +49,7 @@ JingleSession::JingleSession(
: jingle_session_manager_(jingle_session_manager),
local_cert_(local_cert),
state_(INITIALIZING),
+ error_(OK),
closing_(false),
cricket_session_(NULL),
config_set_(false),
@@ -132,6 +133,11 @@ void JingleSession::SetStateChangeCallback(StateChangeCallback* callback) {
state_change_callback_.reset(callback);
}
+Session::Error JingleSession::error() {
+ DCHECK(CalledOnValidThread());
+ return error_;
+}
+
void JingleSession::CreateStreamChannel(
const std::string& name, const StreamChannelCallback& callback) {
DCHECK(CalledOnValidThread());
diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h
index 505944fc..cd467a1 100644
--- a/remoting/protocol/jingle_session.h
+++ b/remoting/protocol/jingle_session.h
@@ -28,6 +28,7 @@ class JingleSession : public protocol::Session,
public:
// Session interface.
virtual void SetStateChangeCallback(StateChangeCallback* callback) OVERRIDE;
+ virtual Error error() OVERRIDE;
virtual void CreateStreamChannel(
const std::string& name,
const StreamChannelCallback& callback) OVERRIDE;
@@ -150,6 +151,8 @@ class JingleSession : public protocol::Session,
State state_;
scoped_ptr<StateChangeCallback> state_change_callback_;
+ Error error_;
+
bool closing_;
// JID of the other side. Set when the connection is initialized,
diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc
index 9400afc..4105e6f 100644
--- a/remoting/protocol/jingle_session_manager.cc
+++ b/remoting/protocol/jingle_session_manager.cc
@@ -216,7 +216,7 @@ bool JingleSessionManager::AcceptConnection(
listener_->OnIncomingSession(jingle_session, &response);
switch (response) {
- case protocol::SessionManager::ACCEPT: {
+ case SessionManager::ACCEPT: {
// Connection must be configured by the callback.
CandidateSessionConfig* candidate_config =
CandidateSessionConfig::CreateFrom(jingle_session->config());
@@ -226,13 +226,14 @@ bool JingleSessionManager::AcceptConnection(
break;
}
- case protocol::SessionManager::INCOMPATIBLE: {
- cricket_session->Reject(cricket::STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
+ case SessionManager::INCOMPATIBLE: {
+ cricket_session->TerminateWithReason(
+ cricket::STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
return false;
}
- case protocol::SessionManager::DECLINE: {
- cricket_session->Reject(cricket::STR_TERMINATE_DECLINE);
+ case SessionManager::DECLINE: {
+ cricket_session->TerminateWithReason(cricket::STR_TERMINATE_DECLINE);
return false;
}
diff --git a/remoting/protocol/pepper_session.cc b/remoting/protocol/pepper_session.cc
index e7cdf15..509440e 100644
--- a/remoting/protocol/pepper_session.cc
+++ b/remoting/protocol/pepper_session.cc
@@ -34,7 +34,7 @@ const int kTransportInfoSendDelayMs = 2;
PepperSession::PepperSession(PepperSessionManager* session_manager)
: session_manager_(session_manager),
state_(INITIALIZING),
- error_(ERROR_NO_ERROR) {
+ error_(OK) {
}
PepperSession::~PepperSession() {
@@ -44,14 +44,14 @@ PepperSession::~PepperSession() {
session_manager_->SessionDestroyed(this);
}
-PepperSession::Error PepperSession::error() {
+void PepperSession::SetStateChangeCallback(StateChangeCallback* callback) {
DCHECK(CalledOnValidThread());
- return error_;
+ state_change_callback_.reset(callback);
}
-void PepperSession::SetStateChangeCallback(StateChangeCallback* callback) {
+Session::Error PepperSession::error() {
DCHECK(CalledOnValidThread());
- state_change_callback_.reset(callback);
+ return error_;
}
void PepperSession::StartConnection(
@@ -98,7 +98,7 @@ void PepperSession::OnSessionInitiateResponse(
// TODO(sergeyu): There may be different reasons for error
// here. Parse the response stanza to find failure reason.
- OnError(ERROR_PEER_IS_OFFLINE);
+ OnError(PEER_IS_OFFLINE);
}
}
@@ -239,7 +239,7 @@ void PepperSession::OnAccept(const JingleMessage& message,
}
if (!InitializeConfigFromDescription(message.description.get())) {
- OnError(ERROR_INCOMPATIBLE_PROTOCOL);
+ OnError(INCOMPATIBLE_PROTOCOL);
return;
}
@@ -266,7 +266,20 @@ void PepperSession::ProcessTransportInfo(const JingleMessage& message) {
void PepperSession::OnTerminate(const JingleMessage& message,
JingleMessageReply* reply) {
if (state_ == CONNECTING) {
- OnError(ERROR_SESSION_REJECTED);
+ switch (message.reason) {
+ case JingleMessage::DECLINE:
+ OnError(SESSION_REJECTED);
+ break;
+
+ case JingleMessage::INCOMPATIBLE_PARAMETERS:
+ OnError(INCOMPATIBLE_PROTOCOL);
+ break;
+
+ default:
+ LOG(WARNING) << "Received session-terminate message "
+ "with an unexpected reason.";
+ OnError(SESSION_REJECTED);
+ }
return;
}
@@ -337,7 +350,7 @@ void PepperSession::OnChannelConnected(
if (!socket) {
LOG(ERROR) << "Failed to connect control or events channel. "
<< "Terminating connection";
- OnError(ERROR_CHANNEL_CONNECTION_FAILURE);
+ OnError(CHANNEL_CONNECTION_ERROR);
return;
}
diff --git a/remoting/protocol/pepper_session.h b/remoting/protocol/pepper_session.h
index 93bb6ef..ab0a26d9 100644
--- a/remoting/protocol/pepper_session.h
+++ b/remoting/protocol/pepper_session.h
@@ -43,22 +43,11 @@ class SocketWrapper;
// outgoing connections.
class PepperSession : public Session {
public:
- // TODO(sergeyu): Move this type and error() method to the Session
- // interface.
- enum Error {
- ERROR_NO_ERROR = 0,
- ERROR_PEER_IS_OFFLINE,
- ERROR_SESSION_REJECTED,
- ERROR_INCOMPATIBLE_PROTOCOL,
- ERROR_CHANNEL_CONNECTION_FAILURE,
- };
-
virtual ~PepperSession();
- Error error();
-
// Session interface.
virtual void SetStateChangeCallback(StateChangeCallback* callback) OVERRIDE;
+ virtual Error error() OVERRIDE;
virtual void CreateStreamChannel(
const std::string& name,
const StreamChannelCallback& callback) OVERRIDE;
diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h
index 4af7584..814e61b 100644
--- a/remoting/protocol/protocol_mock_objects.h
+++ b/remoting/protocol/protocol_mock_objects.h
@@ -109,6 +109,7 @@ class MockSession : public Session {
virtual ~MockSession();
MOCK_METHOD1(SetStateChangeCallback, void(StateChangeCallback* callback));
+ MOCK_METHOD0(error, Session::Error());
MOCK_METHOD2(CreateStreamChannel, void(
const std::string& name, const StreamChannelCallback& callback));
MOCK_METHOD2(CreateDatagramChannel, void(
diff --git a/remoting/protocol/session.h b/remoting/protocol/session.h
index 920a681..0697b16 100644
--- a/remoting/protocol/session.h
+++ b/remoting/protocol/session.h
@@ -49,6 +49,14 @@ class Session : public base::NonThreadSafe {
FAILED,
};
+ enum Error {
+ OK = 0,
+ PEER_IS_OFFLINE,
+ SESSION_REJECTED,
+ INCOMPATIBLE_PROTOCOL,
+ CHANNEL_CONNECTION_ERROR,
+ };
+
typedef Callback1<State>::Type StateChangeCallback;
typedef base::Callback<void(net::StreamSocket*)> StreamChannelCallback;
typedef base::Callback<void(net::Socket*)> DatagramChannelCallback;
@@ -60,6 +68,9 @@ class Session : public base::NonThreadSafe {
// Must be called on the jingle thread only.
virtual void SetStateChangeCallback(StateChangeCallback* callback) = 0;
+ // Returns error code for a failed session.
+ virtual Error error() = 0;
+
// Creates new channels for this connection. The specified callback
// is called when then new channel is created and connected. The
// callback is called with NULL if connection failed for any reason.