From 09eabd65c680e41cb3565e13d8d3488f5065db4b Mon Sep 17 00:00:00 2001 From: "jamiewalch@chromium.org" <jamiewalch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> Date: Tue, 13 Aug 2013 00:13:48 +0000 Subject: [PATCH] Added JsonMessage to the control channel. This adds the client plumbing needed to get an arbitrary JSON message from client to host, or vice versa. This will allow us to extend the protocol at short notice, without needing to wait for client plugin changes to be promoted to Stable. BUG= Review URL: https://chromiumcodereview.appspot.com/22477006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217127 0039d316-1c4b-4281-b951-d872f2087c98 --- remoting/client/chromoting_client.cc | 7 +++++ remoting/client/chromoting_client.h | 2 ++ remoting/client/client_user_interface.h | 4 +++ .../client/jni/chromoting_jni_instance.cc | 5 ++++ remoting/client/jni/chromoting_jni_instance.h | 2 ++ remoting/client/plugin/chromoting_instance.cc | 28 ++++++++++++++++++- remoting/client/plugin/chromoting_instance.h | 3 ++ remoting/host/client_session.cc | 7 +++++ remoting/host/client_session.h | 2 ++ remoting/proto/control.proto | 11 ++++++++ remoting/proto/internal.proto | 1 + .../protocol/client_control_dispatcher.cc | 9 ++++++ remoting/protocol/client_control_dispatcher.h | 1 + remoting/protocol/client_stub.h | 4 +++ remoting/protocol/host_control_dispatcher.cc | 9 ++++++ remoting/protocol/host_control_dispatcher.h | 2 ++ remoting/protocol/host_stub.h | 4 +++ remoting/protocol/protocol_mock_objects.h | 2 ++ remoting/webapp/client_plugin.js | 3 +- remoting/webapp/client_plugin_async.js | 21 ++++++++++++++ 20 files changed, 125 insertions(+), 2 deletions(-) diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 2d308c92c47a8..f87d9e8dccd74 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc @@ -119,6 +119,13 @@ void ChromotingClient::SetPairingResponse( user_interface_->SetPairingResponse(pairing_response); } +void ChromotingClient::DeliverHostMessage( + const protocol::ExtensionMessage& message) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + user_interface_->DeliverHostMessage(message); +} + void ChromotingClient::InjectClipboardEvent( const protocol::ClipboardEvent& event) { DCHECK(task_runner_->BelongsToCurrentThread()); diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h index 625a4d8fd2e2e..58c8050d2771f 100644 --- a/remoting/client/chromoting_client.h +++ b/remoting/client/chromoting_client.h @@ -67,6 +67,8 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback, const protocol::Capabilities& capabilities) OVERRIDE; virtual void SetPairingResponse( const protocol::PairingResponse& pairing_response) OVERRIDE; + virtual void DeliverHostMessage( + const protocol::ExtensionMessage& message) OVERRIDE; // ClipboardStub implementation for receiving clipboard data from host. virtual void InjectClipboardEvent( diff --git a/remoting/client/client_user_interface.h b/remoting/client/client_user_interface.h index 9779835cc9715..88d3e79699158 100644 --- a/remoting/client/client_user_interface.h +++ b/remoting/client/client_user_interface.h @@ -42,6 +42,10 @@ class ClientUserInterface { virtual void SetPairingResponse( const protocol::PairingResponse& pairing_response) = 0; + // Deliver an extension message from the host to the client. + virtual void DeliverHostMessage( + const protocol::ExtensionMessage& message) = 0; + // Get the view's ClipboardStub implementation. virtual protocol::ClipboardStub* GetClipboardStub() = 0; diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc index b68aab9f2c62b..067e954bca05e 100644 --- a/remoting/client/jni/chromoting_jni_instance.cc +++ b/remoting/client/jni/chromoting_jni_instance.cc @@ -176,6 +176,11 @@ void ChromotingJniInstance::SetPairingResponse( response.shared_secret())); } +void ChromotingJniInstance::DeliverHostMessage( + const protocol::ExtensionMessage& message) { + NOTIMPLEMENTED(); +} + protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() { return this; } diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h index a8684bf4b8220..d066d6fe7dbbe 100644 --- a/remoting/client/jni/chromoting_jni_instance.h +++ b/remoting/client/jni/chromoting_jni_instance.h @@ -78,6 +78,8 @@ class ChromotingJniInstance virtual void SetCapabilities(const std::string& capabilities) OVERRIDE; virtual void SetPairingResponse( const protocol::PairingResponse& response) OVERRIDE; + virtual void DeliverHostMessage( + const protocol::ExtensionMessage& message) OVERRIDE; virtual protocol::ClipboardStub* GetClipboardStub() OVERRIDE; virtual protocol::CursorShapeStub* GetCursorShapeStub() OVERRIDE; virtual scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 8be169c9d2278..e22452a42168a 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -144,7 +144,7 @@ logging::LogMessageHandlerFunction g_logging_old_handler = NULL; const char ChromotingInstance::kApiFeatures[] = "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " "notifyClientDimensions notifyClientResolution pauseVideo pauseAudio " - "asyncPin thirdPartyAuth pinlessAuth"; + "asyncPin thirdPartyAuth pinlessAuth extensionMessage"; const char ChromotingInstance::kRequestedCapabilities[] = ""; const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape"; @@ -433,6 +433,13 @@ void ChromotingInstance::HandleMessage(const pp::Var& message) { return; } RequestPairing(client_name); + } else if (method == "extensionMessage") { + std::string type, message; + if (!data->GetString("type", &type) || !data->GetString("data", &message)) { + LOG(ERROR) << "Invalid extensionMessage."; + return; + } + SendClientMessage(type, message); } } @@ -537,6 +544,14 @@ void ChromotingInstance::SetPairingResponse( PostChromotingMessage("pairingResponse", data.Pass()); } +void ChromotingInstance::DeliverHostMessage( + const protocol::ExtensionMessage& message) { + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); + data->SetString("type", message.type()); + data->SetString("data", message.data()); + PostChromotingMessage("extensionMessage", data.Pass()); +} + void ChromotingInstance::FetchSecretFromDialog( bool pairing_supported, const protocol::SecretFetchedCallback& secret_fetched_callback) { @@ -839,6 +854,17 @@ void ChromotingInstance::RequestPairing(const std::string& client_name) { host_connection_->host_stub()->RequestPairing(pairing_request); } +void ChromotingInstance::SendClientMessage(const std::string& type, + const std::string& data) { + if (!IsConnected()) { + return; + } + protocol::ExtensionMessage message; + message.set_type(type); + message.set_data(data); + host_connection_->host_stub()->DeliverClientMessage(message); +} + ChromotingStats* ChromotingInstance::GetStats() { if (!client_.get()) return NULL; diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index d7fd4481f3422..23c4c4996c9dc 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -120,6 +120,8 @@ class ChromotingInstance : virtual void SetCapabilities(const std::string& capabilities) OVERRIDE; virtual void SetPairingResponse( const protocol::PairingResponse& pairing_response) OVERRIDE; + virtual void DeliverHostMessage( + const protocol::ExtensionMessage& message) OVERRIDE; virtual protocol::ClipboardStub* GetClipboardStub() OVERRIDE; virtual protocol::CursorShapeStub* GetCursorShapeStub() OVERRIDE; virtual scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> @@ -198,6 +200,7 @@ class ChromotingInstance : void OnThirdPartyTokenFetched(const std::string& token, const std::string& shared_secret); void RequestPairing(const std::string& client_name); + void SendClientMessage(const std::string& type, const std::string& data); // Helper method to post messages to the webapp. void PostChromotingMessage(const std::string& method, diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 86bbe7ffa1280..933ded3e4748c 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -187,6 +187,13 @@ void ClientSession::RequestPairing( } } +void ClientSession::DeliverClientMessage( + const protocol::ExtensionMessage& message) { + // No messages are currently supported. + LOG(INFO) << "Unexpected message received: " + << message.type() << ": " << message.data(); +} + void ClientSession::OnConnectionAuthenticated( protocol::ConnectionToClient* connection) { DCHECK(CalledOnValidThread()); diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h index f023abd8ddd72..474e13b38a022 100644 --- a/remoting/host/client_session.h +++ b/remoting/host/client_session.h @@ -111,6 +111,8 @@ class ClientSession const protocol::Capabilities& capabilities) OVERRIDE; virtual void RequestPairing( const remoting::protocol::PairingRequest& pairing_request) OVERRIDE; + virtual void DeliverClientMessage( + const protocol::ExtensionMessage& message) OVERRIDE; // protocol::ConnectionToClient::EventHandler interface. virtual void OnConnectionAuthenticated( diff --git a/remoting/proto/control.proto b/remoting/proto/control.proto index 888c0b01b9010..2d2baf620b9b0 100644 --- a/remoting/proto/control.proto +++ b/remoting/proto/control.proto @@ -66,3 +66,14 @@ message PairingResponse { // Shared secret for this client. optional string shared_secret = 2; } + +message ExtensionMessage { + // The message type. This is used to dispatch the message to the correct + // recipient. + optional string type = 1; + + // String-encoded message data. The client and host must agree on the encoding + // for each message type; different message types need not shared the same + // encoding. + optional string data = 2; +} \ No newline at end of file diff --git a/remoting/proto/internal.proto b/remoting/proto/internal.proto index 219e3ef799c14..6ae35f4e3c279 100644 --- a/remoting/proto/internal.proto +++ b/remoting/proto/internal.proto @@ -24,6 +24,7 @@ message ControlMessage { optional Capabilities capabilities = 6; optional PairingRequest pairing_request = 7; optional PairingResponse pairing_response = 8; + optional ExtensionMessage extension_message = 9; } // Defines an event message on the event channel. diff --git a/remoting/protocol/client_control_dispatcher.cc b/remoting/protocol/client_control_dispatcher.cc index 8bb918efcb58f..a42c3f628d8b0 100644 --- a/remoting/protocol/client_control_dispatcher.cc +++ b/remoting/protocol/client_control_dispatcher.cc @@ -74,6 +74,13 @@ void ClientControlDispatcher::RequestPairing( writer_.Write(SerializeAndFrameMessage(message), base::Closure()); } +void ClientControlDispatcher::DeliverClientMessage( + const ExtensionMessage& message) { + ControlMessage control_message; + control_message.mutable_extension_message()->CopyFrom(message); + writer_.Write(SerializeAndFrameMessage(control_message), base::Closure()); +} + void ClientControlDispatcher::OnMessageReceived( scoped_ptr<ControlMessage> message, const base::Closure& done_task) { DCHECK(client_stub_); @@ -88,6 +95,8 @@ void ClientControlDispatcher::OnMessageReceived( client_stub_->SetCursorShape(message->cursor_shape()); } else if (message->has_pairing_response()) { client_stub_->SetPairingResponse(message->pairing_response()); + } else if (message->has_extension_message()) { + client_stub_->DeliverHostMessage(message->extension_message()); } else { LOG(WARNING) << "Unknown control message received."; } diff --git a/remoting/protocol/client_control_dispatcher.h b/remoting/protocol/client_control_dispatcher.h index b2a0bfa5a9af2..556ce72190d24 100644 --- a/remoting/protocol/client_control_dispatcher.h +++ b/remoting/protocol/client_control_dispatcher.h @@ -40,6 +40,7 @@ class ClientControlDispatcher : public ChannelDispatcherBase, virtual void ControlAudio(const AudioControl& audio_control) OVERRIDE; virtual void SetCapabilities(const Capabilities& capabilities) OVERRIDE; virtual void RequestPairing(const PairingRequest& pairing_request) OVERRIDE; + virtual void DeliverClientMessage(const ExtensionMessage& message) OVERRIDE; // Sets the ClientStub that will be called for each incoming control // message. |client_stub| must outlive this object. diff --git a/remoting/protocol/client_stub.h b/remoting/protocol/client_stub.h index 4507ba7f821ad..d57f948d35ea3 100644 --- a/remoting/protocol/client_stub.h +++ b/remoting/protocol/client_stub.h @@ -18,6 +18,7 @@ namespace remoting { namespace protocol { class Capabilities; +class ExtensionMessage; class PairingResponse; class ClientStub : public ClipboardStub, @@ -32,6 +33,9 @@ class ClientStub : public ClipboardStub, // Passes a pairing response message to the client. virtual void SetPairingResponse(const PairingResponse& pairing_response) = 0; + // Deliver an extension message from the host to the client. + virtual void DeliverHostMessage(const ExtensionMessage& message) = 0; + private: DISALLOW_COPY_AND_ASSIGN(ClientStub); }; diff --git a/remoting/protocol/host_control_dispatcher.cc b/remoting/protocol/host_control_dispatcher.cc index b979e36060d89..26f09fc3e55e7 100644 --- a/remoting/protocol/host_control_dispatcher.cc +++ b/remoting/protocol/host_control_dispatcher.cc @@ -46,6 +46,13 @@ void HostControlDispatcher::SetPairingResponse( writer_.Write(SerializeAndFrameMessage(message), base::Closure()); } +void HostControlDispatcher::DeliverHostMessage( + const ExtensionMessage& message) { + ControlMessage control_message; + control_message.mutable_extension_message()->CopyFrom(message); + writer_.Write(SerializeAndFrameMessage(control_message), base::Closure()); +} + void HostControlDispatcher::InjectClipboardEvent(const ClipboardEvent& event) { ControlMessage message; message.mutable_clipboard_event()->CopyFrom(event); @@ -78,6 +85,8 @@ void HostControlDispatcher::OnMessageReceived( host_stub_->SetCapabilities(message->capabilities()); } else if (message->has_pairing_request()) { host_stub_->RequestPairing(message->pairing_request()); + } else if (message->has_extension_message()) { + host_stub_->DeliverClientMessage(message->extension_message()); } else { LOG(WARNING) << "Unknown control message received."; } diff --git a/remoting/protocol/host_control_dispatcher.h b/remoting/protocol/host_control_dispatcher.h index 4620be10b877f..82aa7938f5e8a 100644 --- a/remoting/protocol/host_control_dispatcher.h +++ b/remoting/protocol/host_control_dispatcher.h @@ -37,6 +37,8 @@ class HostControlDispatcher : public ChannelDispatcherBase, virtual void SetCapabilities(const Capabilities& capabilities) OVERRIDE; virtual void SetPairingResponse( const PairingResponse& pairing_response) OVERRIDE; + virtual void DeliverHostMessage( + const ExtensionMessage& message) OVERRIDE; // ClipboardStub implementation for sending clipboard data to client. virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; diff --git a/remoting/protocol/host_stub.h b/remoting/protocol/host_stub.h index 46d75346bd62d..cf9fa0b95c3fb 100644 --- a/remoting/protocol/host_stub.h +++ b/remoting/protocol/host_stub.h @@ -17,6 +17,7 @@ namespace protocol { class AudioControl; class Capabilities; class ClientResolution; +class ExtensionMessage; class PairingResponse; class PairingRequest; class VideoControl; @@ -43,6 +44,9 @@ class HostStub { // Requests pairing between the host and client for PIN-less authentication. virtual void RequestPairing(const PairingRequest& pairing_request) = 0; + // Deliver an extension message from the client to the host. + virtual void DeliverClientMessage(const ExtensionMessage& message) = 0; + protected: virtual ~HostStub() {} diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h index 74435dbb486a5..16bb8663d7fdf 100644 --- a/remoting/protocol/protocol_mock_objects.h +++ b/remoting/protocol/protocol_mock_objects.h @@ -114,6 +114,7 @@ class MockHostStub : public HostStub { MOCK_METHOD1(SetCapabilities, void(const Capabilities& capabilities)); MOCK_METHOD1(RequestPairing, void(const PairingRequest& pairing_request)); + MOCK_METHOD1(DeliverClientMessage, void(const ExtensionMessage& message)); private: DISALLOW_COPY_AND_ASSIGN(MockHostStub); @@ -128,6 +129,7 @@ class MockClientStub : public ClientStub { MOCK_METHOD1(SetCapabilities, void(const Capabilities& capabilities)); MOCK_METHOD1(SetPairingResponse, void(const PairingResponse& pairing_response)); + MOCK_METHOD1(DeliverHostMessage, void(const ExtensionMessage& message)); // ClipboardStub mock implementation. MOCK_METHOD1(InjectClipboardEvent, void(const ClipboardEvent& event)); diff --git a/remoting/webapp/client_plugin.js b/remoting/webapp/client_plugin.js index e98b345825da2..247d06821576d 100644 --- a/remoting/webapp/client_plugin.js +++ b/remoting/webapp/client_plugin.js @@ -67,7 +67,8 @@ remoting.ClientPlugin.Feature = { SEND_CLIPBOARD_ITEM: 'sendClipboardItem', THIRD_PARTY_AUTH: 'thirdPartyAuth', TRAP_KEY: 'trapKey', - PINLESS_AUTH: 'pinlessAuth' + PINLESS_AUTH: 'pinlessAuth', + EXTENSION_MESSAGE: 'extensionMessage' }; /** diff --git a/remoting/webapp/client_plugin_async.js b/remoting/webapp/client_plugin_async.js index f457d159fe466..ac82c9f914177 100644 --- a/remoting/webapp/client_plugin_async.js +++ b/remoting/webapp/client_plugin_async.js @@ -313,6 +313,10 @@ remoting.ClientPluginAsync.prototype.handleMessage_ = function(messageStr) { return; } this.onPairingComplete_(clientId, sharedSecret); + } else if (message.method == 'extensionMessage') { + // No messages currently supported. + console.log('Unexpected message received: ' + + message.data.type + ': ' + message.data.data); } }; @@ -606,6 +610,23 @@ remoting.ClientPluginAsync.prototype.requestPairing = { method: 'requestPairing', data: { clientName: clientName } })); }; +/** + * Send an extension message to the host. + * + * @param {string} type The message type. + * @param {Object} message The message payload. + */ +remoting.ClientPluginAsync.prototype.sendClientMessage = + function(type, message) { + if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) { + return; + } + this.plugin.postMessage(JSON.stringify( + { method: 'extensionMessage', + data: { type: type, data: JSON.stringify(message) } })); + +}; + /** * If we haven't yet received a "hello" message from the plugin, change its * size so that the user can confirm it if click-to-play is enabled, or can