From 09eabd65c680e41cb3565e13d8d3488f5065db4b Mon Sep 17 00:00:00 2001 From: "jamiewalch@chromium.org" 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 2d308c92c47a87..f87d9e8dccd745 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 625a4d8fd2e2e6..58c8050d2771fd 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 9779835cc97154..88d3e796991581 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 b68aab9f2c62be..067e954bca05ef 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 a8684bf4b82204..d066d6fe7dbbe5 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 diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 8be169c9d22787..e22452a42168a4 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 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 d7fd4481f34222..23c4c4996c9dca 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 @@ -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 86bbe7ffa12800..933ded3e4748c5 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 f023abd8ddd72e..474e13b38a0221 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 888c0b01b90108..2d2baf620b9b08 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 219e3ef799c149..6ae35f4e3c2795 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 8bb918efcb58f6..a42c3f628d8b08 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 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 b2a0bfa5a9af29..556ce72190d244 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 4507ba7f821ad4..d57f948d35ea36 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 b979e36060d899..26f09fc3e55e78 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 4620be10b877f8..82aa7938f5e8a0 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 46d75346bd62d1..cf9fa0b95c3fba 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 74435dbb486a5c..16bb8663d7fdf6 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 e98b345825da24..247d06821576d4 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 f457d159fe466b..ac82c9f914177d 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