1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qvncclient.h"
41#include "qvnc_p.h"
42
43#include <QtNetwork/QTcpSocket>
44#include <QtCore/QCoreApplication>
45
46#include <qpa/qwindowsysteminterface.h>
47#include <QtGui/qguiapplication.h>
48
49#ifdef Q_OS_WIN
50#include <Winsock2.h>
51#else
52#include <arpa/inet.h>
53#endif
54
55QT_BEGIN_NAMESPACE
56
57QVncClient::QVncClient(QTcpSocket *clientSocket, QVncServer *server)
58 : QObject(server)
59 , m_server(server)
60 , m_clientSocket(clientSocket)
61 , m_encoder(nullptr)
62 , m_msgType(0)
63 , m_handleMsg(false)
64 , m_encodingsPending(0)
65 , m_cutTextPending(0)
66 , m_supportHextile(false)
67 , m_wantUpdate(false)
68 , m_dirtyCursor(false)
69 , m_updatePending(false)
70 , m_protocolVersion(V3_3)
71{
72 connect(sender: m_clientSocket,SIGNAL(readyRead()),receiver: this,SLOT(readClient()));
73 connect(sender: m_clientSocket,SIGNAL(disconnected()),receiver: this,SLOT(discardClient()));
74
75 // send protocol version
76 const char *proto = "RFB 003.003\n";
77 m_clientSocket->write(data: proto, len: 12);
78 m_state = Protocol;
79}
80
81QVncClient::~QVncClient()
82{
83 delete m_encoder;
84}
85
86QTcpSocket *QVncClient::clientSocket() const
87{
88 return m_clientSocket;
89}
90
91void QVncClient::setDirty(const QRegion &region)
92{
93 m_dirtyRegion += region;
94 if (m_state == Connected &&
95 ((m_server->dirtyMap()->numDirty > 0) || m_dirtyCursor)) {
96 scheduleUpdate();
97 }
98}
99
100void QVncClient::convertPixels(char *dst, const char *src, int count, int screendepth) const
101{
102 // cutoffs
103#if Q_BYTE_ORDER == Q_BIG_ENDIAN
104 if (!m_swapBytes)
105#endif
106 if (m_sameEndian) {
107 if (screendepth == m_pixelFormat.bitsPerPixel) { // memcpy cutoffs
108
109 switch (screendepth) {
110 case 32:
111 memcpy(dest: dst, src: src, n: count * sizeof(quint32));
112 return;
113 case 16:
114 if (m_pixelFormat.redBits == 5
115 && m_pixelFormat.greenBits == 6
116 && m_pixelFormat.blueBits == 5)
117 {
118 memcpy(dest: dst, src: src, n: count * sizeof(quint16));
119 return;
120 }
121 }
122 }
123 }
124
125 const int bytesPerPixel = (m_pixelFormat.bitsPerPixel + 7) / 8;
126
127 for (int i = 0; i < count; ++i) {
128 int r, g, b;
129
130 switch (screendepth) {
131 case 8: {
132 QRgb rgb = m_server->screen()->image()->colorTable()[int(*src)];
133 r = qRed(rgb);
134 g = qGreen(rgb);
135 b = qBlue(rgb);
136 src++;
137 break;
138 }
139 case 16: {
140 quint16 p = *reinterpret_cast<const quint16*>(src);
141#if Q_BYTE_ORDER == Q_BIG_ENDIAN
142 if (m_swapBytes)
143 p = ((p & 0xff) << 8) | ((p & 0xff00) >> 8);
144#endif
145 r = (p >> 11) & 0x1f;
146 g = (p >> 5) & 0x3f;
147 b = p & 0x1f;
148 r <<= 3;
149 g <<= 2;
150 b <<= 3;
151 src += sizeof(quint16);
152 break;
153 }
154 case 32: {
155 quint32 p = *reinterpret_cast<const quint32*>(src);
156 r = (p >> 16) & 0xff;
157 g = (p >> 8) & 0xff;
158 b = p & 0xff;
159 src += sizeof(quint32);
160 break;
161 }
162 default: {
163 r = g = b = 0;
164 qWarning(msg: "QVNCServer: don't support %dbpp display", screendepth);
165 return;
166 }
167 }
168
169#if Q_BYTE_ORDER == Q_BIG_ENDIAN
170 if (m_swapBytes)
171 qSwap(r, b);
172#endif
173
174 r >>= (8 - m_pixelFormat.redBits);
175 g >>= (8 - m_pixelFormat.greenBits);
176 b >>= (8 - m_pixelFormat.blueBits);
177
178 int pixel = (r << m_pixelFormat.redShift) |
179 (g << m_pixelFormat.greenShift) |
180 (b << m_pixelFormat.blueShift);
181
182 if (m_sameEndian || m_pixelFormat.bitsPerPixel == 8) {
183 memcpy(dest: dst, src: &pixel, n: bytesPerPixel);
184 dst += bytesPerPixel;
185 continue;
186 }
187
188
189 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
190 switch (m_pixelFormat.bitsPerPixel) {
191 case 16:
192 pixel = (((pixel & 0x0000ff00) << 8) |
193 ((pixel & 0x000000ff) << 24));
194 break;
195 case 32:
196 pixel = (((pixel & 0xff000000) >> 24) |
197 ((pixel & 0x00ff0000) >> 8) |
198 ((pixel & 0x0000ff00) << 8) |
199 ((pixel & 0x000000ff) << 24));
200 break;
201 default:
202 qWarning(msg: "Cannot handle %d bpp client", m_pixelFormat.bitsPerPixel);
203 }
204 } else { // QSysInfo::ByteOrder == QSysInfo::LittleEndian
205 switch (m_pixelFormat.bitsPerPixel) {
206 case 16:
207 pixel = (((pixel & 0xff000000) >> 8) |
208 ((pixel & 0x00ff0000) << 8));
209 break;
210 case 32:
211 pixel = (((pixel & 0xff000000) >> 24) |
212 ((pixel & 0x00ff0000) >> 8) |
213 ((pixel & 0x0000ff00) << 8) |
214 ((pixel & 0x000000ff) << 24));
215 break;
216 default:
217 qWarning(msg: "Cannot handle %d bpp client",
218 m_pixelFormat.bitsPerPixel);
219 break;
220 }
221 }
222 memcpy(dest: dst, src: &pixel, n: bytesPerPixel);
223 dst += bytesPerPixel;
224 }
225}
226
227void QVncClient::readClient()
228{
229 qCDebug(lcVnc) << "readClient" << m_state;
230 switch (m_state) {
231 case Disconnected:
232
233 break;
234 case Protocol:
235 if (m_clientSocket->bytesAvailable() >= 12) {
236 char proto[13];
237 m_clientSocket->read(data: proto, maxlen: 12);
238 proto[12] = '\0';
239 qCDebug(lcVnc, "Client protocol version %s", proto);
240 if (!strcmp(s1: proto, s2: "RFB 003.008\n")) {
241 m_protocolVersion = V3_8;
242 } else if (!strcmp(s1: proto, s2: "RFB 003.007\n")) {
243 m_protocolVersion = V3_7;
244 } else {
245 m_protocolVersion = V3_3;
246 }
247
248 if (m_protocolVersion == V3_3) {
249 // No authentication
250 quint32 auth = htonl(hostlong: 1);
251 m_clientSocket->write(data: (char *) &auth, len: sizeof(auth));
252 m_state = Init;
253 }
254 }
255 break;
256 case Authentication:
257
258 break;
259 case Init:
260 if (m_clientSocket->bytesAvailable() >= 1) {
261 quint8 shared;
262 m_clientSocket->read(data: (char *) &shared, maxlen: 1);
263
264 // Server Init msg
265 QRfbServerInit sim;
266 QRfbPixelFormat &format = sim.format;
267 switch (m_server->screen()->depth()) {
268 case 32:
269 format.bitsPerPixel = 32;
270 format.depth = 32;
271 format.bigEndian = 0;
272 format.trueColor = true;
273 format.redBits = 8;
274 format.greenBits = 8;
275 format.blueBits = 8;
276 format.redShift = 16;
277 format.greenShift = 8;
278 format.blueShift = 0;
279 break;
280
281 case 24:
282 format.bitsPerPixel = 24;
283 format.depth = 24;
284 format.bigEndian = 0;
285 format.trueColor = true;
286 format.redBits = 8;
287 format.greenBits = 8;
288 format.blueBits = 8;
289 format.redShift = 16;
290 format.greenShift = 8;
291 format.blueShift = 0;
292 break;
293
294 case 18:
295 format.bitsPerPixel = 24;
296 format.depth = 18;
297 format.bigEndian = 0;
298 format.trueColor = true;
299 format.redBits = 6;
300 format.greenBits = 6;
301 format.blueBits = 6;
302 format.redShift = 12;
303 format.greenShift = 6;
304 format.blueShift = 0;
305 break;
306
307 case 16:
308 format.bitsPerPixel = 16;
309 format.depth = 16;
310 format.bigEndian = 0;
311 format.trueColor = true;
312 format.redBits = 5;
313 format.greenBits = 6;
314 format.blueBits = 5;
315 format.redShift = 11;
316 format.greenShift = 5;
317 format.blueShift = 0;
318 break;
319
320 case 15:
321 format.bitsPerPixel = 16;
322 format.depth = 15;
323 format.bigEndian = 0;
324 format.trueColor = true;
325 format.redBits = 5;
326 format.greenBits = 5;
327 format.blueBits = 5;
328 format.redShift = 10;
329 format.greenShift = 5;
330 format.blueShift = 0;
331 break;
332
333 case 12:
334 format.bitsPerPixel = 16;
335 format.depth = 12;
336 format.bigEndian = 0;
337 format.trueColor = true;
338 format.redBits = 4;
339 format.greenBits = 4;
340 format.blueBits = 4;
341 format.redShift = 8;
342 format.greenShift = 4;
343 format.blueShift = 0;
344 break;
345
346 case 8:
347 case 4:
348 format.bitsPerPixel = 8;
349 format.depth = 8;
350 format.bigEndian = 0;
351 format.trueColor = false;
352 format.redBits = 0;
353 format.greenBits = 0;
354 format.blueBits = 0;
355 format.redShift = 0;
356 format.greenShift = 0;
357 format.blueShift = 0;
358 break;
359
360 default:
361 qWarning(msg: "QVNC cannot drive depth %d", m_server->screen()->depth());
362 discardClient();
363 return;
364 }
365 sim.width = m_server->screen()->geometry().width();
366 sim.height = m_server->screen()->geometry().height();
367 sim.setName("Qt for Embedded Linux VNC Server");
368 sim.write(s: m_clientSocket);
369 m_state = Connected;
370 }
371 break;
372
373 case Connected:
374 do {
375 if (!m_handleMsg) {
376 m_clientSocket->read(data: (char *)&m_msgType, maxlen: 1);
377 m_handleMsg = true;
378 }
379 if (m_handleMsg) {
380 switch (m_msgType ) {
381 case SetPixelFormat:
382 setPixelFormat();
383 break;
384 case FixColourMapEntries:
385 qWarning(msg: "Not supported: FixColourMapEntries");
386 m_handleMsg = false;
387 break;
388 case SetEncodings:
389 setEncodings();
390 break;
391 case FramebufferUpdateRequest:
392 frameBufferUpdateRequest();
393 break;
394 case KeyEvent:
395 keyEvent();
396 break;
397 case PointerEvent:
398 pointerEvent();
399 break;
400 case ClientCutText:
401 clientCutText();
402 break;
403 default:
404 qWarning(msg: "Unknown message type: %d", (int)m_msgType);
405 m_handleMsg = false;
406 }
407 }
408 } while (!m_handleMsg && m_clientSocket->bytesAvailable());
409 break;
410 default:
411 break;
412 }
413}
414
415void QVncClient::discardClient()
416{
417 m_state = Disconnected;
418 m_server->discardClient(client: this);
419}
420
421void QVncClient::checkUpdate()
422{
423 if (!m_wantUpdate)
424 return;
425#if QT_CONFIG(cursor)
426 if (m_dirtyCursor) {
427 m_server->screen()->clientCursor->write(client: this);
428 m_dirtyCursor = false;
429 m_wantUpdate = false;
430 return;
431 }
432#endif
433 if (!m_dirtyRegion.isEmpty()) {
434 if (m_encoder)
435 m_encoder->write();
436 m_wantUpdate = false;
437 m_dirtyRegion = QRegion();
438 }
439}
440
441void QVncClient::scheduleUpdate()
442{
443 if (!m_updatePending) {
444 m_updatePending = true;
445 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::UpdateRequest));
446 }
447}
448
449bool QVncClient::event(QEvent *event)
450{
451 if (event->type() == QEvent::UpdateRequest) {
452 m_updatePending = false;
453 checkUpdate();
454 return true;
455 }
456 return QObject::event(event);
457}
458
459void QVncClient::setPixelFormat()
460{
461 if (m_clientSocket->bytesAvailable() >= 19) {
462 char buf[3];
463 m_clientSocket->read(data: buf, maxlen: 3); // just padding
464 m_pixelFormat.read(s: m_clientSocket);
465 qCDebug(lcVnc, "Want format: %d %d %d %d %d %d %d %d %d %d",
466 int(m_pixelFormat.bitsPerPixel),
467 int(m_pixelFormat.depth),
468 int(m_pixelFormat.bigEndian),
469 int(m_pixelFormat.trueColor),
470 int(m_pixelFormat.redBits),
471 int(m_pixelFormat.greenBits),
472 int(m_pixelFormat.blueBits),
473 int(m_pixelFormat.redShift),
474 int(m_pixelFormat.greenShift),
475 int(m_pixelFormat.blueShift));
476 if (!m_pixelFormat.trueColor) {
477 qWarning(msg: "Can only handle true color clients");
478 discardClient();
479 }
480 m_handleMsg = false;
481 m_sameEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) == !!m_pixelFormat.bigEndian;
482 m_needConversion = pixelConversionNeeded();
483#if Q_BYTE_ORDER == Q_BIG_ENDIAN
484 m_swapBytes = server()->screen()->swapBytes();
485#endif
486 }
487}
488
489void QVncClient::setEncodings()
490{
491 QRfbSetEncodings enc;
492
493 if (!m_encodingsPending && enc.read(s: m_clientSocket)) {
494 m_encodingsPending = enc.count;
495 if (!m_encodingsPending)
496 m_handleMsg = false;
497 }
498
499 if (m_encoder) {
500 delete m_encoder;
501 m_encoder = nullptr;
502 }
503
504 enum Encodings {
505 Raw = 0,
506 CopyRect = 1,
507 RRE = 2,
508 CoRRE = 4,
509 Hextile = 5,
510 ZRLE = 16,
511 Cursor = -239,
512 DesktopSize = -223
513 };
514
515 if (m_encodingsPending && (unsigned)m_clientSocket->bytesAvailable() >=
516 m_encodingsPending * sizeof(quint32)) {
517 for (int i = 0; i < m_encodingsPending; ++i) {
518 qint32 enc;
519 m_clientSocket->read(data: (char *)&enc, maxlen: sizeof(qint32));
520 enc = ntohl(netlong: enc);
521 qCDebug(lcVnc, "QVncServer::setEncodings: %d", enc);
522 switch (enc) {
523 case Raw:
524 if (!m_encoder) {
525 m_encoder = new QRfbRawEncoder(this);
526 qCDebug(lcVnc, "QVncServer::setEncodings: using raw");
527 }
528 break;
529 case CopyRect:
530 m_supportCopyRect = true;
531 break;
532 case RRE:
533 m_supportRRE = true;
534 break;
535 case CoRRE:
536 m_supportCoRRE = true;
537 break;
538 case Hextile:
539 m_supportHextile = true;
540 if (m_encoder)
541 break;
542 break;
543 case ZRLE:
544 m_supportZRLE = true;
545 break;
546 case Cursor:
547 m_supportCursor = true;
548 m_server->screen()->enableClientCursor(client: this);
549 break;
550 case DesktopSize:
551 m_supportDesktopSize = true;
552 break;
553 default:
554 break;
555 }
556 }
557 m_handleMsg = false;
558 m_encodingsPending = 0;
559 }
560
561 if (!m_encoder) {
562 m_encoder = new QRfbRawEncoder(this);
563 qCDebug(lcVnc, "QVncServer::setEncodings: fallback using raw");
564 }
565}
566
567void QVncClient::frameBufferUpdateRequest()
568{
569 qCDebug(lcVnc) << "FramebufferUpdateRequest";
570 QRfbFrameBufferUpdateRequest ev;
571
572 if (ev.read(s: m_clientSocket)) {
573 if (!ev.incremental) {
574 QRect r(ev.rect.x, ev.rect.y, ev.rect.w, ev.rect.h);
575 r.translate(p: m_server->screen()->geometry().topLeft());
576 setDirty(r);
577 }
578 m_wantUpdate = true;
579 checkUpdate();
580 m_handleMsg = false;
581 }
582}
583
584void QVncClient::pointerEvent()
585{
586 QRfbPointerEvent ev;
587 static int buttonState = Qt::NoButton;
588 if (ev.read(s: m_clientSocket)) {
589 const QPointF pos = m_server->screen()->geometry().topLeft() + QPoint(ev.x, ev.y);
590 int buttonStateChange = buttonState ^ int(ev.buttons);
591 QEvent::Type type = QEvent::MouseMove;
592 if (int(ev.buttons) > buttonState)
593 type = QEvent::MouseButtonPress;
594 else if (int(ev.buttons) < buttonState)
595 type = QEvent::MouseButtonRelease;
596 QWindowSystemInterface::handleMouseEvent(window: nullptr, local: pos, global: pos, state: ev.buttons, button: Qt::MouseButton(buttonStateChange),
597 type, mods: QGuiApplication::keyboardModifiers());
598 buttonState = int(ev.buttons);
599 m_handleMsg = false;
600 }
601}
602
603void QVncClient::keyEvent()
604{
605 QRfbKeyEvent ev;
606
607 if (ev.read(s: m_clientSocket)) {
608 if (ev.keycode == Qt::Key_Shift)
609 m_keymod = ev.down ? m_keymod | Qt::ShiftModifier :
610 m_keymod & ~Qt::ShiftModifier;
611 else if (ev.keycode == Qt::Key_Control)
612 m_keymod = ev.down ? m_keymod | Qt::ControlModifier :
613 m_keymod & ~Qt::ControlModifier;
614 else if (ev.keycode == Qt::Key_Alt)
615 m_keymod = ev.down ? m_keymod | Qt::AltModifier :
616 m_keymod & ~Qt::AltModifier;
617 if (ev.unicode || ev.keycode)
618 QWindowSystemInterface::handleKeyEvent(window: nullptr, t: ev.down ? QEvent::KeyPress : QEvent::KeyRelease, k: ev.keycode, mods: m_keymod, text: QString(ev.unicode));
619 m_handleMsg = false;
620 }
621}
622
623void QVncClient::clientCutText()
624{
625 QRfbClientCutText ev;
626
627 if (m_cutTextPending == 0 && ev.read(s: m_clientSocket)) {
628 m_cutTextPending = ev.length;
629 if (!m_cutTextPending)
630 m_handleMsg = false;
631 }
632
633 if (m_cutTextPending && m_clientSocket->bytesAvailable() >= m_cutTextPending) {
634 char *text = new char [m_cutTextPending+1];
635 m_clientSocket->read(data: text, maxlen: m_cutTextPending);
636 delete [] text;
637 m_cutTextPending = 0;
638 m_handleMsg = false;
639 }
640}
641
642bool QVncClient::pixelConversionNeeded() const
643{
644 if (!m_sameEndian)
645 return true;
646
647#if Q_BYTE_ORDER == Q_BIG_ENDIAN
648 if (server()->screen()->swapBytes())
649 return true;
650#endif
651
652 const int screendepth = m_server->screen()->depth();
653 if (screendepth != m_pixelFormat.bitsPerPixel)
654 return true;
655
656 switch (screendepth) {
657 case 32:
658 case 24:
659 return false;
660 case 16:
661 return (m_pixelFormat.redBits == 5
662 && m_pixelFormat.greenBits == 6
663 && m_pixelFormat.blueBits == 5);
664 }
665 return true;
666}
667
668QT_END_NAMESPACE
669

source code of qtbase/src/plugins/platforms/vnc/qvncclient.cpp