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