diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-27 20:10:51 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-27 20:10:51 +0000 |
commit | e3f03d06435a6bb335f0170ec708c5527eb58b8f (patch) | |
tree | 4c3d3b2b9815c432f62fb4225ba7bdcdb62021a0 /remoting/protocol | |
parent | 047470cd5b1f4b24ba923b2f533ef9109d0c2664 (diff) | |
download | chromium_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.cc | 8 | ||||
-rw-r--r-- | remoting/protocol/fake_session.h | 6 | ||||
-rw-r--r-- | remoting/protocol/jingle_messages.cc | 108 | ||||
-rw-r--r-- | remoting/protocol/jingle_messages.h | 14 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.cc | 6 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.h | 3 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_manager.cc | 11 | ||||
-rw-r--r-- | remoting/protocol/pepper_session.cc | 31 | ||||
-rw-r--r-- | remoting/protocol/pepper_session.h | 13 | ||||
-rw-r--r-- | remoting/protocol/protocol_mock_objects.h | 1 | ||||
-rw-r--r-- | remoting/protocol/session.h | 11 |
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. |