1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "remoting/protocol/client_control_dispatcher.h"
6 
7 #include <stdint.h>
8 
9 #include "base/callback.h"
10 #include "base/callback_helpers.h"
11 #include "net/socket/stream_socket.h"
12 #include "remoting/base/compound_buffer.h"
13 #include "remoting/base/constants.h"
14 #include "remoting/proto/control.pb.h"
15 #include "remoting/proto/internal.pb.h"
16 #include "remoting/protocol/client_stub.h"
17 #include "remoting/protocol/message_pipe.h"
18 #include "remoting/protocol/message_serialization.h"
19 
20 namespace remoting {
21 namespace protocol {
22 
23 namespace {
24 
25 // 32-bit BGRA is 4 bytes per pixel.
26 const int kBytesPerPixel = 4;
27 
CursorShapeIsValid(const CursorShapeInfo & cursor_shape)28 bool CursorShapeIsValid(const CursorShapeInfo& cursor_shape) {
29   if (!cursor_shape.has_data() ||
30       !cursor_shape.has_width() ||
31       !cursor_shape.has_height() ||
32       !cursor_shape.has_hotspot_x() ||
33       !cursor_shape.has_hotspot_y()) {
34     LOG(ERROR) << "Cursor shape is missing required fields.";
35     return false;
36   }
37 
38   int width = cursor_shape.width();
39   int height = cursor_shape.height();
40 
41   // Verify that |width| and |height| are within sane limits. Otherwise integer
42   // overflow can occur while calculating |cursor_total_bytes| below.
43   if (width < 0 || width > (SHRT_MAX / 2) ||
44       height < 0 || height > (SHRT_MAX / 2)) {
45     LOG(ERROR) << "Cursor dimensions are out of bounds for SetCursor: "
46                << width << "x" << height;
47     return false;
48   }
49 
50   uint32_t cursor_total_bytes = width * height * kBytesPerPixel;
51   if (cursor_shape.data().size() < cursor_total_bytes) {
52     LOG(ERROR) << "Expected " << cursor_total_bytes << " bytes for a "
53                << width << "x" << height << " cursor. Only received "
54                << cursor_shape.data().size() << " bytes";
55     return false;
56   }
57 
58   return true;
59 }
60 
61 }  // namespace
62 
ClientControlDispatcher()63 ClientControlDispatcher::ClientControlDispatcher()
64     : ChannelDispatcherBase(kControlChannelName) {}
65 ClientControlDispatcher::~ClientControlDispatcher() = default;
66 
InjectClipboardEvent(const ClipboardEvent & event)67 void ClientControlDispatcher::InjectClipboardEvent(
68     const ClipboardEvent& event) {
69   ControlMessage message;
70   message.mutable_clipboard_event()->CopyFrom(event);
71   message_pipe()->Send(&message, {});
72 }
73 
NotifyClientResolution(const ClientResolution & resolution)74 void ClientControlDispatcher::NotifyClientResolution(
75     const ClientResolution& resolution) {
76   ControlMessage message;
77   message.mutable_client_resolution()->CopyFrom(resolution);
78   message_pipe()->Send(&message, {});
79 }
80 
ControlVideo(const VideoControl & video_control)81 void ClientControlDispatcher::ControlVideo(const VideoControl& video_control) {
82   ControlMessage message;
83   message.mutable_video_control()->CopyFrom(video_control);
84   message_pipe()->Send(&message, {});
85 }
86 
ControlAudio(const AudioControl & audio_control)87 void ClientControlDispatcher::ControlAudio(const AudioControl& audio_control) {
88   ControlMessage message;
89   message.mutable_audio_control()->CopyFrom(audio_control);
90   message_pipe()->Send(&message, {});
91 }
92 
SetCapabilities(const Capabilities & capabilities)93 void ClientControlDispatcher::SetCapabilities(
94     const Capabilities& capabilities) {
95   ControlMessage message;
96   message.mutable_capabilities()->CopyFrom(capabilities);
97   message_pipe()->Send(&message, {});
98 }
99 
RequestPairing(const PairingRequest & pairing_request)100 void ClientControlDispatcher::RequestPairing(
101     const PairingRequest& pairing_request) {
102   ControlMessage message;
103   message.mutable_pairing_request()->CopyFrom(pairing_request);
104   message_pipe()->Send(&message, {});
105 }
106 
DeliverClientMessage(const ExtensionMessage & message)107 void ClientControlDispatcher::DeliverClientMessage(
108     const ExtensionMessage& message) {
109   ControlMessage control_message;
110   control_message.mutable_extension_message()->CopyFrom(message);
111   message_pipe()->Send(&control_message, {});
112 }
113 
SelectDesktopDisplay(const SelectDesktopDisplayRequest & select_display)114 void ClientControlDispatcher::SelectDesktopDisplay(
115     const SelectDesktopDisplayRequest& select_display) {
116   ControlMessage message;
117   message.mutable_select_display()->CopyFrom(select_display);
118   message_pipe()->Send(&message, {});
119 }
120 
ControlPeerConnection(const protocol::PeerConnectionParameters & parameters)121 void ClientControlDispatcher::ControlPeerConnection(
122     const protocol::PeerConnectionParameters& parameters) {
123   ControlMessage message;
124   message.mutable_peer_connection_parameters()->CopyFrom(parameters);
125   message_pipe()->Send(&message, {});
126 }
127 
OnIncomingMessage(std::unique_ptr<CompoundBuffer> buffer)128 void ClientControlDispatcher::OnIncomingMessage(
129     std::unique_ptr<CompoundBuffer> buffer) {
130   DCHECK(client_stub_);
131   DCHECK(clipboard_stub_);
132 
133   std::unique_ptr<ControlMessage> message =
134       ParseMessage<ControlMessage>(buffer.get());
135   if (!message)
136     return;
137 
138   if (message->has_clipboard_event()) {
139     clipboard_stub_->InjectClipboardEvent(message->clipboard_event());
140   } else if (message->has_capabilities()) {
141     client_stub_->SetCapabilities(message->capabilities());
142   } else if (message->has_cursor_shape()) {
143     if (CursorShapeIsValid(message->cursor_shape()))
144       client_stub_->SetCursorShape(message->cursor_shape());
145   } else if (message->has_pairing_response()) {
146     client_stub_->SetPairingResponse(message->pairing_response());
147   } else if (message->has_extension_message()) {
148     client_stub_->DeliverHostMessage(message->extension_message());
149   } else if (message->has_video_layout()) {
150     client_stub_->SetVideoLayout(message->video_layout());
151   } else {
152     LOG(WARNING) << "Unknown control message received.";
153   }
154 }
155 
156 }  // namespace protocol
157 }  // namespace remoting
158