1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/frontend/vnc_server/vnc_client_connection.h"
18 
19 #include <netinet/in.h>
20 #include <sys/time.h>
21 
22 #include <algorithm>
23 #include <cmath>
24 #include <cstdint>
25 #include <cstring>
26 #include <memory>
27 #include <mutex>
28 #include <string>
29 #include <thread>
30 #include <utility>
31 #include <vector>
32 
33 #include <gflags/gflags.h>
34 #include <android-base/logging.h>
35 #include "common/libs/tcp_socket/tcp_socket.h"
36 #include "host/frontend/vnc_server/keysyms.h"
37 #include "host/frontend/vnc_server/mocks.h"
38 #include "host/frontend/vnc_server/vnc_utils.h"
39 #include "host/libs/config/cuttlefish_config.h"
40 #include "host/libs/screen_connector/screen_connector.h"
41 
42 using cuttlefish::Message;
43 using cuttlefish::vnc::Stripe;
44 using cuttlefish::vnc::StripePtrVec;
45 using cuttlefish::vnc::VncClientConnection;
46 
47 struct ScreenRegionView {
48   using Pixel = uint32_t;
49   static constexpr int kSwiftShaderPadding = 4;
50   static constexpr int kRedShift = 0;
51   static constexpr int kGreenShift = 8;
52   static constexpr int kBlueShift = 16;
53   static constexpr int kRedBits = 8;
54   static constexpr int kGreenBits = 8;
55   static constexpr int kBlueBits = 8;
56 };
57 
58 DEFINE_bool(debug_client, false, "Turn on detailed logging for the client");
59 
60 #define DLOG(LEVEL) \
61   if (FLAGS_debug_client) LOG(LEVEL)
62 
63 namespace {
64 class BigEndianChecker {
65  public:
BigEndianChecker()66   BigEndianChecker() {
67     uint32_t u = 1;
68     is_big_endian_ = *reinterpret_cast<const char*>(&u) == 0;
69   }
operator ()() const70   bool operator()() const { return is_big_endian_; }
71 
72  private:
73   bool is_big_endian_{};
74 };
75 
76 const BigEndianChecker ImBigEndian;
77 
78 constexpr int32_t kDesktopSizeEncoding = -223;
79 constexpr int32_t kTightEncoding = 7;
80 
81 // These are the lengths not counting the first byte. The first byte
82 // indicates the message type.
83 constexpr size_t kSetPixelFormatLength = 19;
84 constexpr size_t kFramebufferUpdateRequestLength = 9;
85 constexpr size_t kSetEncodingsLength = 3;  // more bytes follow
86 constexpr size_t kKeyEventLength = 7;
87 constexpr size_t kPointerEventLength = 5;
88 constexpr size_t kClientCutTextLength = 7;  // more bytes follow
89 
HostName()90 std::string HostName() {
91   auto config = cuttlefish::CuttlefishConfig::Get();
92   auto instance = config->ForDefaultInstance();
93   return !config || instance.device_title().empty() ? std::string{"localhost"}
94                                                     : instance.device_title();
95 }
96 
uint16_tAt(const void * p)97 std::uint16_t uint16_tAt(const void* p) {
98   std::uint16_t u{};
99   std::memcpy(&u, p, sizeof u);
100   return ntohs(u);
101 }
102 
uint32_tAt(const void * p)103 std::uint32_t uint32_tAt(const void* p) {
104   std::uint32_t u{};
105   std::memcpy(&u, p, sizeof u);
106   return ntohl(u);
107 }
108 
int32_tAt(const void * p)109 std::int32_t int32_tAt(const void* p) {
110   std::uint32_t u{};
111   std::memcpy(&u, p, sizeof u);
112   u = ntohl(u);
113   std::int32_t s{};
114   std::memcpy(&s, &u, sizeof s);
115   return s;
116 }
117 
RedVal(std::uint32_t pixel)118 std::uint32_t RedVal(std::uint32_t pixel) {
119   return (pixel >> ScreenRegionView::kRedShift) &
120          ((0x1 << ScreenRegionView::kRedBits) - 1);
121 }
122 
BlueVal(std::uint32_t pixel)123 std::uint32_t BlueVal(std::uint32_t pixel) {
124   return (pixel >> ScreenRegionView::kBlueShift) &
125          ((0x1 << ScreenRegionView::kBlueBits) - 1);
126 }
127 
GreenVal(std::uint32_t pixel)128 std::uint32_t GreenVal(std::uint32_t pixel) {
129   return (pixel >> ScreenRegionView::kGreenShift) &
130          ((0x1 << ScreenRegionView::kGreenBits) - 1);
131 }
132 }  // namespace
133 namespace cuttlefish {
134 namespace vnc {
operator ==(const VncClientConnection::FrameBufferUpdateRequest & lhs,const VncClientConnection::FrameBufferUpdateRequest & rhs)135 bool operator==(const VncClientConnection::FrameBufferUpdateRequest& lhs,
136                 const VncClientConnection::FrameBufferUpdateRequest& rhs) {
137   return lhs.x_pos == rhs.x_pos && lhs.y_pos == rhs.y_pos &&
138          lhs.width == rhs.width && lhs.height == rhs.height;
139 }
140 
operator !=(const VncClientConnection::FrameBufferUpdateRequest & lhs,const VncClientConnection::FrameBufferUpdateRequest & rhs)141 bool operator!=(const VncClientConnection::FrameBufferUpdateRequest& lhs,
142                 const VncClientConnection::FrameBufferUpdateRequest& rhs) {
143   return !(lhs == rhs);
144 }
145 }  // namespace vnc
146 }  // namespace cuttlefish
147 
VncClientConnection(ClientSocket client,std::shared_ptr<VirtualInputs> virtual_inputs,BlackBoard * bb,bool aggressive)148 VncClientConnection::VncClientConnection(
149     ClientSocket client, std::shared_ptr<VirtualInputs> virtual_inputs,
150     BlackBoard* bb, bool aggressive)
151     : client_{std::move(client)}, virtual_inputs_{virtual_inputs}, bb_{bb} {
152   frame_buffer_request_handler_tid_ = std::thread(
153       &VncClientConnection::FrameBufferUpdateRequestHandler, this, aggressive);
154 }
155 
~VncClientConnection()156 VncClientConnection::~VncClientConnection() {
157   {
158     std::lock_guard<std::mutex> guard(m_);
159     closed_ = true;
160   }
161   bb_->StopWaiting(this);
162   frame_buffer_request_handler_tid_.join();
163 }
164 
StartSession()165 void VncClientConnection::StartSession() {
166   LOG(INFO) << "Starting session";
167   SetupProtocol();
168   LOG(INFO) << "Protocol set up";
169   if (client_.closed()) {
170     return;
171   }
172   SetupSecurityType();
173   LOG(INFO) << "Security type set";
174   if (client_.closed()) {
175     return;
176   }
177   GetClientInit();
178   LOG(INFO) << "Gotten client init";
179   if (client_.closed()) {
180     return;
181   }
182   SendServerInit();
183   LOG(INFO) << "Sent server init";
184   if (client_.closed()) {
185     return;
186   }
187   NormalSession();
188   LOG(INFO) << "vnc session terminated";
189 }
190 
closed()191 bool VncClientConnection::closed() {
192   std::lock_guard<std::mutex> guard(m_);
193   return closed_;
194 }
195 
SetupProtocol()196 void VncClientConnection::SetupProtocol() {
197   static constexpr char kRFBVersion[] = "RFB 003.008\n";
198   static constexpr char kRFBVersionOld[] = "RFB 003.003\n";
199   static constexpr auto kVersionLen = (sizeof kRFBVersion) - 1;
200   client_.SendNoSignal(reinterpret_cast<const std::uint8_t*>(kRFBVersion),
201                        kVersionLen);
202   auto client_protocol = client_.Recv(kVersionLen);
203   if (std::memcmp(&client_protocol[0], kRFBVersion,
204                   std::min(kVersionLen, client_protocol.size())) != 0) {
205     if (!std::memcmp(
206                 &client_protocol[0],
207                 kRFBVersionOld,
208                 std::min(kVersionLen, client_protocol.size()))) {
209         // We'll deal with V3.3 as well.
210         client_is_old_ = true;
211         return;
212     }
213 
214     client_protocol.push_back('\0');
215     LOG(ERROR) << "vnc client wants a different protocol: "
216                << reinterpret_cast<const char*>(&client_protocol[0]);
217   }
218 }
219 
SetupSecurityType()220 void VncClientConnection::SetupSecurityType() {
221   if (client_is_old_) {
222     static constexpr std::uint8_t kVNCSecurity[4] = { 0x00, 0x00, 0x00, 0x02 };
223     client_.SendNoSignal(kVNCSecurity);
224 
225     static constexpr std::uint8_t kChallenge[16] =
226         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
227 
228     client_.SendNoSignal(kChallenge);
229 
230     auto clientResponse = client_.Recv(16);
231     (void)clientResponse;  // Accept any response, we're not interested in actual security.
232 
233     static constexpr std::uint8_t kSuccess[4] = { 0x00, 0x00, 0x00, 0x00 };
234     client_.SendNoSignal(kSuccess);
235     return;
236   }
237 
238   static constexpr std::uint8_t kNoneSecurity = 0x1;
239   // The first '0x1' indicates the number of items that follow
240   static constexpr std::uint8_t kOnlyNoneSecurity[] = {0x01, kNoneSecurity};
241   client_.SendNoSignal(kOnlyNoneSecurity);
242   auto client_security = client_.Recv(1);
243   if (client_.closed()) {
244     return;
245   }
246   if (client_security.front() != kNoneSecurity) {
247     LOG(ERROR) << "vnc client is asking for security type "
248                << static_cast<int>(client_security.front());
249   }
250   static constexpr std::uint8_t kZero[4] = {};
251   client_.SendNoSignal(kZero);
252 }
253 
GetClientInit()254 void VncClientConnection::GetClientInit() {
255   auto client_shared = client_.Recv(1);
256 }
257 
SendServerInit()258 void VncClientConnection::SendServerInit() {
259   const std::string server_name = HostName();
260   std::lock_guard<std::mutex> guard(m_);
261   auto server_init = cuttlefish::CreateMessage(
262       static_cast<std::uint16_t>(ScreenWidth()),
263       static_cast<std::uint16_t>(ScreenHeight()), pixel_format_.bits_per_pixel,
264       pixel_format_.depth, pixel_format_.big_endian, pixel_format_.true_color,
265       pixel_format_.red_max, pixel_format_.green_max, pixel_format_.blue_max,
266       pixel_format_.red_shift, pixel_format_.green_shift,
267       pixel_format_.blue_shift, std::uint16_t{},  // padding
268       std::uint8_t{},                             // padding
269       static_cast<std::uint32_t>(server_name.size()), server_name);
270   client_.SendNoSignal(server_init);
271 }
272 
MakeFrameBufferUpdateHeader(std::uint16_t num_stripes)273 Message VncClientConnection::MakeFrameBufferUpdateHeader(
274     std::uint16_t num_stripes) {
275   return cuttlefish::CreateMessage(std::uint8_t{0},  // message-type
276                             std::uint8_t{},   // padding
277                             std::uint16_t{num_stripes});
278 }
279 
AppendRawStripeHeader(Message * frame_buffer_update,const Stripe & stripe)280 void VncClientConnection::AppendRawStripeHeader(Message* frame_buffer_update,
281                                                 const Stripe& stripe) {
282   static constexpr int32_t kRawEncoding = 0;
283   cuttlefish::AppendToMessage(frame_buffer_update, std::uint16_t{stripe.x},
284                        std::uint16_t{stripe.y}, std::uint16_t{stripe.width},
285                        std::uint16_t{stripe.height}, kRawEncoding);
286 }
287 
AppendJpegSize(Message * frame_buffer_update,size_t jpeg_size)288 void VncClientConnection::AppendJpegSize(Message* frame_buffer_update,
289                                          size_t jpeg_size) {
290   constexpr size_t kJpegSizeOneByteMax = 127;
291   constexpr size_t kJpegSizeTwoByteMax = 16383;
292   constexpr size_t kJpegSizeThreeByteMax = 4194303;
293 
294   if (jpeg_size <= kJpegSizeOneByteMax) {
295     cuttlefish::AppendToMessage(frame_buffer_update,
296                          static_cast<std::uint8_t>(jpeg_size));
297   } else if (jpeg_size <= kJpegSizeTwoByteMax) {
298     auto sz = static_cast<std::uint32_t>(jpeg_size);
299     cuttlefish::AppendToMessage(frame_buffer_update,
300                          static_cast<std::uint8_t>((sz & 0x7F) | 0x80),
301                          static_cast<std::uint8_t>((sz >> 7) & 0xFF));
302   } else {
303     if (jpeg_size > kJpegSizeThreeByteMax) {
304       LOG(FATAL) << "jpeg size is too big: " << jpeg_size << " must be under "
305                  << kJpegSizeThreeByteMax;
306     }
307     const auto sz = static_cast<std::uint32_t>(jpeg_size);
308     cuttlefish::AppendToMessage(frame_buffer_update,
309                          static_cast<std::uint8_t>((sz & 0x7F) | 0x80),
310                          static_cast<std::uint8_t>(((sz >> 7) & 0x7F) | 0x80),
311                          static_cast<std::uint8_t>((sz >> 14) & 0xFF));
312   }
313 }
314 
AppendRawStripe(Message * frame_buffer_update,const Stripe & stripe) const315 void VncClientConnection::AppendRawStripe(Message* frame_buffer_update,
316                                           const Stripe& stripe) const {
317   using Pixel = ScreenRegionView::Pixel;
318   auto& fbu = *frame_buffer_update;
319   AppendRawStripeHeader(&fbu, stripe);
320   auto init_size = fbu.size();
321   fbu.insert(fbu.end(), stripe.raw_data.begin(), stripe.raw_data.end());
322   for (size_t i = init_size; i < fbu.size(); i += sizeof(Pixel)) {
323     CHECK_LE(i + sizeof(Pixel), fbu.size());
324     Pixel raw_pixel{};
325     std::memcpy(&raw_pixel, &fbu[i], sizeof raw_pixel);
326     auto red = RedVal(raw_pixel);
327     auto green = GreenVal(raw_pixel);
328     auto blue = BlueVal(raw_pixel);
329     Pixel pixel = Pixel{red} << pixel_format_.red_shift |
330                   Pixel{blue} << pixel_format_.blue_shift |
331                   Pixel{green} << pixel_format_.green_shift;
332 
333     if (bool(pixel_format_.big_endian) != ImBigEndian()) {
334       // flip them bits (refactor into function)
335       auto p = reinterpret_cast<char*>(&pixel);
336       std::swap(p[0], p[3]);
337       std::swap(p[1], p[2]);
338     }
339     std::memcpy(&fbu[i], &pixel, sizeof pixel);
340   }
341 }
342 
MakeRawFrameBufferUpdate(const StripePtrVec & stripes) const343 Message VncClientConnection::MakeRawFrameBufferUpdate(
344     const StripePtrVec& stripes) const {
345   auto fbu =
346       MakeFrameBufferUpdateHeader(static_cast<std::uint16_t>(stripes.size()));
347   for (auto& stripe : stripes) {
348     AppendRawStripe(&fbu, *stripe);
349   }
350   return fbu;
351 }
352 
AppendJpegStripeHeader(Message * frame_buffer_update,const Stripe & stripe)353 void VncClientConnection::AppendJpegStripeHeader(Message* frame_buffer_update,
354                                                  const Stripe& stripe) {
355   static constexpr std::uint8_t kJpegEncoding = 0x90;
356   cuttlefish::AppendToMessage(frame_buffer_update, stripe.x, stripe.y, stripe.width,
357                        stripe.height, kTightEncoding, kJpegEncoding);
358   AppendJpegSize(frame_buffer_update, stripe.jpeg_data.size());
359 }
360 
AppendJpegStripe(Message * frame_buffer_update,const Stripe & stripe)361 void VncClientConnection::AppendJpegStripe(Message* frame_buffer_update,
362                                            const Stripe& stripe) {
363   AppendJpegStripeHeader(frame_buffer_update, stripe);
364   frame_buffer_update->insert(frame_buffer_update->end(),
365                               stripe.jpeg_data.begin(), stripe.jpeg_data.end());
366 }
367 
MakeJpegFrameBufferUpdate(const StripePtrVec & stripes)368 Message VncClientConnection::MakeJpegFrameBufferUpdate(
369     const StripePtrVec& stripes) {
370   auto fbu =
371       MakeFrameBufferUpdateHeader(static_cast<std::uint16_t>(stripes.size()));
372   for (auto& stripe : stripes) {
373     AppendJpegStripe(&fbu, *stripe);
374   }
375   return fbu;
376 }
377 
MakeFrameBufferUpdate(const StripePtrVec & stripes)378 Message VncClientConnection::MakeFrameBufferUpdate(
379     const StripePtrVec& stripes) {
380   return use_jpeg_compression_ ? MakeJpegFrameBufferUpdate(stripes)
381                                : MakeRawFrameBufferUpdate(stripes);
382 }
383 
FrameBufferUpdateRequestHandler(bool aggressive)384 void VncClientConnection::FrameBufferUpdateRequestHandler(bool aggressive) {
385   BlackBoard::Registerer reg(bb_, this);
386 
387   while (!closed()) {
388     auto stripes = bb_->WaitForSenderWork(this);
389     if (closed()) {
390       break;
391     }
392     if (stripes.empty()) {
393       LOG(FATAL) << "Got 0 stripes";
394     }
395     {
396       // lock here so a portrait frame can't be sent after a landscape
397       // DesktopSize update, or vice versa.
398       std::lock_guard<std::mutex> guard(m_);
399       DLOG(INFO) << "Sending update in "
400                  << (current_orientation_ == ScreenOrientation::Portrait
401                          ? "portrait"
402                          : "landscape")
403                  << " mode";
404       client_.SendNoSignal(MakeFrameBufferUpdate(stripes));
405     }
406     if (aggressive) {
407       bb_->FrameBufferUpdateRequestReceived(this);
408     }
409   }
410 }
411 
SendDesktopSizeUpdate()412 void VncClientConnection::SendDesktopSizeUpdate() {
413   static constexpr int32_t kDesktopSizeEncoding = -223;
414   client_.SendNoSignal(cuttlefish::CreateMessage(
415       std::uint8_t{0},   // message-type,
416       std::uint8_t{},    // padding
417       std::uint16_t{1},  // one pseudo rectangle
418       std::uint16_t{0}, std::uint16_t{0},
419       static_cast<std::uint16_t>(ScreenWidth()),
420       static_cast<std::uint16_t>(ScreenHeight()), kDesktopSizeEncoding));
421 }
422 
IsUrgent(const FrameBufferUpdateRequest & update_request) const423 bool VncClientConnection::IsUrgent(
424     const FrameBufferUpdateRequest& update_request) const {
425   return !update_request.incremental ||
426          update_request != previous_update_request_;
427 }
428 
HandleFramebufferUpdateRequest()429 void VncClientConnection::HandleFramebufferUpdateRequest() {
430   auto msg = client_.Recv(kFramebufferUpdateRequestLength);
431   if (msg.size() != kFramebufferUpdateRequestLength) {
432     return;
433   }
434   FrameBufferUpdateRequest fbur{msg[1] == 0, uint16_tAt(&msg[1]),
435                                 uint16_tAt(&msg[3]), uint16_tAt(&msg[5]),
436                                 uint16_tAt(&msg[7])};
437   if (IsUrgent(fbur)) {
438     bb_->SignalClientNeedsEntireScreen(this);
439   }
440   bb_->FrameBufferUpdateRequestReceived(this);
441   previous_update_request_ = fbur;
442 }
443 
HandleSetEncodings()444 void VncClientConnection::HandleSetEncodings() {
445   auto msg = client_.Recv(kSetEncodingsLength);
446   if (msg.size() != kSetEncodingsLength) {
447     return;
448   }
449   auto count = uint16_tAt(&msg[1]);
450   auto encodings = client_.Recv(count * sizeof(int32_t));
451   if (encodings.size() % sizeof(int32_t) != 0) {
452     return;
453   }
454   {
455     std::lock_guard<std::mutex> guard(m_);
456     use_jpeg_compression_ = false;
457   }
458   for (size_t i = 0; i < encodings.size(); i += sizeof(int32_t)) {
459     auto enc = int32_tAt(&encodings[i]);
460     DLOG(INFO) << "client requesting encoding: " << enc;
461     if (enc == kTightEncoding) {
462       // This is a deviation from the spec which says that if a jpeg quality
463       // level is not specified, tight encoding won't use jpeg.
464       std::lock_guard<std::mutex> guard(m_);
465       use_jpeg_compression_ = true;
466     }
467     if (kJpegMinQualityEncoding <= enc && enc <= kJpegMaxQualityEncoding) {
468       DLOG(INFO) << "jpeg compression level: " << enc;
469       bb_->set_jpeg_quality_level(enc);
470     }
471     if (enc == kDesktopSizeEncoding) {
472       supports_desktop_size_encoding_ = true;
473     }
474   }
475 }
476 
HandleSetPixelFormat()477 void VncClientConnection::HandleSetPixelFormat() {
478   std::lock_guard<std::mutex> guard(m_);
479   auto msg = client_.Recv(kSetPixelFormatLength);
480   if (msg.size() != kSetPixelFormatLength) {
481     return;
482   }
483   pixel_format_.bits_per_pixel = msg[3];
484   pixel_format_.depth = msg[4];
485   pixel_format_.big_endian = msg[5];
486   pixel_format_.true_color = msg[7];
487   pixel_format_.red_max = uint16_tAt(&msg[8]);
488   pixel_format_.green_max = uint16_tAt(&msg[10]);
489   pixel_format_.blue_max = uint16_tAt(&msg[12]);
490   pixel_format_.red_shift = msg[13];
491   pixel_format_.green_shift = msg[14];
492   pixel_format_.blue_shift = msg[15];
493 }
494 
HandlePointerEvent()495 void VncClientConnection::HandlePointerEvent() {
496   auto msg = client_.Recv(kPointerEventLength);
497   if (msg.size() != kPointerEventLength) {
498     return;
499   }
500   std::uint8_t button_mask = msg[0];
501   auto x_pos = uint16_tAt(&msg[1]);
502   auto y_pos = uint16_tAt(&msg[3]);
503   {
504     std::lock_guard<std::mutex> guard(m_);
505     if (current_orientation_ == ScreenOrientation::Landscape) {
506       std::tie(x_pos, y_pos) =
507           std::make_pair(ScreenConnector::ScreenWidth() - y_pos, x_pos);
508     }
509   }
510   virtual_inputs_->HandlePointerEvent(button_mask, x_pos, y_pos);
511 }
512 
UpdateAccelerometer(float,float,float)513 void VncClientConnection::UpdateAccelerometer(float /*x*/, float /*y*/,
514                                               float /*z*/) {
515   // TODO(jemoreira): Implement when vsoc sensor hal is updated
516 }
517 
CoordinatesForOrientation(ScreenOrientation orientation) const518 VncClientConnection::Coordinates VncClientConnection::CoordinatesForOrientation(
519     ScreenOrientation orientation) const {
520   // Compute the acceleration vector that we need to send to mimic
521   // this change.
522   constexpr float g = 9.81;
523   constexpr float angle = 20.0;
524   const float cos_angle = std::cos(angle / M_PI);
525   const float sin_angle = std::sin(angle / M_PI);
526   const float z = g * sin_angle;
527   switch (orientation) {
528     case ScreenOrientation::Portrait:
529       return {0, g * cos_angle, z};
530     case ScreenOrientation::Landscape:
531       return {g * cos_angle, 0, z};
532   }
533 }
534 
ScreenWidth() const535 int VncClientConnection::ScreenWidth() const {
536   return current_orientation_ == ScreenOrientation::Portrait
537              ? ScreenConnector::ScreenWidth()
538              : ScreenConnector::ScreenHeight();
539 }
540 
ScreenHeight() const541 int VncClientConnection::ScreenHeight() const {
542   return current_orientation_ == ScreenOrientation::Portrait
543              ? ScreenConnector::ScreenHeight()
544              : ScreenConnector::ScreenWidth();
545 }
546 
SetScreenOrientation(ScreenOrientation orientation)547 void VncClientConnection::SetScreenOrientation(ScreenOrientation orientation) {
548   std::lock_guard<std::mutex> guard(m_);
549   auto coords = CoordinatesForOrientation(orientation);
550   UpdateAccelerometer(coords.x, coords.y, coords.z);
551   if (supports_desktop_size_encoding_) {
552     auto previous_orientation = current_orientation_;
553     current_orientation_ = orientation;
554     if (current_orientation_ != previous_orientation &&
555         supports_desktop_size_encoding_) {
556       SendDesktopSizeUpdate();
557       bb_->SetOrientation(this, current_orientation_);
558       // TODO not sure if I should be sending a frame update along with this,
559       // or just letting the next FBUR handle it. This seems to me like it's
560       // sending one more frame buffer update than was requested, which is
561       // maybe a violation of the spec?
562     }
563   }
564 }
565 
RotateIfIsRotationCommand(std::uint32_t key)566 bool VncClientConnection::RotateIfIsRotationCommand(std::uint32_t key) {
567   // Due to different configurations on different platforms we're supporting
568   // a set of options for rotating the screen. These are similar to what
569   // the emulator supports and has supported.
570   // ctrl+left and ctrl+right work on windows and linux
571   // command+left and command+right work on Mac
572   // ctrl+fn+F11 and ctrl+fn+F12 work when chromoting to ubuntu from a Mac
573   if (!control_key_down_ && !meta_key_down_) {
574     return false;
575   }
576   switch (key) {
577     case cuttlefish::xk::Right:
578     case cuttlefish::xk::F12:
579       DLOG(INFO) << "switching to portrait";
580       SetScreenOrientation(ScreenOrientation::Portrait);
581       break;
582     case cuttlefish::xk::Left:
583     case cuttlefish::xk::F11:
584       DLOG(INFO) << "switching to landscape";
585       SetScreenOrientation(ScreenOrientation::Landscape);
586       break;
587     default:
588       return false;
589   }
590   return true;
591 }
592 
HandleKeyEvent()593 void VncClientConnection::HandleKeyEvent() {
594   auto msg = client_.Recv(kKeyEventLength);
595   if (msg.size() != kKeyEventLength) {
596     return;
597   }
598 
599   auto key = uint32_tAt(&msg[3]);
600   bool key_down = msg[0];
601   switch (key) {
602     case cuttlefish::xk::ControlLeft:
603     case cuttlefish::xk::ControlRight:
604       control_key_down_ = key_down;
605       break;
606     case cuttlefish::xk::MetaLeft:
607     case cuttlefish::xk::MetaRight:
608       meta_key_down_ = key_down;
609       break;
610     case cuttlefish::xk::F5:
611       key = cuttlefish::xk::Menu;
612       break;
613     case cuttlefish::xk::F7:
614       virtual_inputs_->PressPowerButton(key_down);
615       return;
616     default:
617       break;
618   }
619 
620   if (RotateIfIsRotationCommand(key)) {
621     return;
622   }
623 
624   virtual_inputs_->GenerateKeyPressEvent(key, key_down);
625 }
626 
HandleClientCutText()627 void VncClientConnection::HandleClientCutText() {
628   auto msg = client_.Recv(kClientCutTextLength);
629   if (msg.size() != kClientCutTextLength) {
630     return;
631   }
632   auto len = uint32_tAt(&msg[3]);
633   client_.Recv(len);
634 }
635 
NormalSession()636 void VncClientConnection::NormalSession() {
637   static constexpr std::uint8_t kSetPixelFormatMessage{0};
638   static constexpr std::uint8_t kSetEncodingsMessage{2};
639   static constexpr std::uint8_t kFramebufferUpdateRequestMessage{3};
640   static constexpr std::uint8_t kKeyEventMessage{4};
641   static constexpr std::uint8_t kPointerEventMessage{5};
642   static constexpr std::uint8_t kClientCutTextMessage{6};
643   while (true) {
644     if (client_.closed()) {
645       return;
646     }
647     auto msg = client_.Recv(1);
648     if (client_.closed()) {
649       return;
650     }
651     auto msg_type = msg.front();
652     DLOG(INFO) << "Received message type " << msg_type;
653 
654     switch (msg_type) {
655       case kSetPixelFormatMessage:
656         HandleSetPixelFormat();
657         break;
658 
659       case kSetEncodingsMessage:
660         HandleSetEncodings();
661         break;
662 
663       case kFramebufferUpdateRequestMessage:
664         HandleFramebufferUpdateRequest();
665         break;
666 
667       case kKeyEventMessage:
668         HandleKeyEvent();
669         break;
670 
671       case kPointerEventMessage:
672         HandlePointerEvent();
673         break;
674 
675       case kClientCutTextMessage:
676         HandleClientCutText();
677         break;
678 
679       default:
680         LOG(WARNING) << "message type not handled: "
681                      << static_cast<int>(msg_type);
682         break;
683     }
684   }
685 }
686