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