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#include "qvnc_p.h"
40#include "qvncscreen.h"
41#include "qvncclient.h"
42#include "QtNetwork/qtcpserver.h"
43#include "QtNetwork/qtcpsocket.h"
44#include <qendian.h>
45#include <qthread.h>
46
47#include <QtGui/qguiapplication.h>
48#include <QtGui/QWindow>
49
50#ifdef Q_OS_WIN
51#include <Winsock2.h>
52#else
53#include <arpa/inet.h>
54#endif
55
56#include <QtCore/QDebug>
57
58QT_BEGIN_NAMESPACE
59
60Q_LOGGING_CATEGORY(lcVnc, "qt.qpa.vnc");
61
62QVncDirtyMap::QVncDirtyMap(QVncScreen *screen)
63 : screen(screen), bytesPerPixel(0), numDirty(0)
64{
65 bytesPerPixel = (screen->depth() + 7) / 8;
66 bufferWidth = screen->geometry().width();
67 bufferHeight = screen->geometry().height();
68 bufferStride = bufferWidth * bytesPerPixel;
69 buffer = new uchar[bufferHeight * bufferStride];
70
71 mapWidth = (bufferWidth + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
72 mapHeight = (bufferHeight + MAP_TILE_SIZE - 1) / MAP_TILE_SIZE;
73 numTiles = mapWidth * mapHeight;
74 map = new uchar[numTiles];
75}
76
77QVncDirtyMap::~QVncDirtyMap()
78{
79 delete[] map;
80 delete[] buffer;
81}
82
83void QVncDirtyMap::reset()
84{
85 memset(map, 1, numTiles);
86 memset(buffer, 0, bufferHeight * bufferStride);
87 numDirty = numTiles;
88}
89
90inline bool QVncDirtyMap::dirty(int x, int y) const
91{
92 return map[y * mapWidth + x];
93}
94
95inline void QVncDirtyMap::setClean(int x, int y)
96{
97 map[y * mapWidth + x] = 0;
98 --numDirty;
99}
100
101template <class T>
102void QVncDirtyMapOptimized<T>::setDirty(int tileX, int tileY, bool force)
103{
104 static bool alwaysForce = qEnvironmentVariableIsSet("QT_VNC_NO_COMPAREBUFFER");
105 if (alwaysForce)
106 force = true;
107
108 bool changed = false;
109
110 if (!force) {
111 const int lstep = bufferStride;
112 const int startX = tileX * MAP_TILE_SIZE;
113 const int startY = tileY * MAP_TILE_SIZE;
114 const uchar *scrn = screen->image()->constBits()
115 + startY * lstep + startX * bytesPerPixel;
116 uchar *old = buffer + startY * bufferStride + startX * sizeof(T);
117
118 const int tileHeight = (startY + MAP_TILE_SIZE > bufferHeight ?
119 bufferHeight - startY : MAP_TILE_SIZE);
120 const int tileWidth = (startX + MAP_TILE_SIZE > bufferWidth ?
121 bufferWidth - startX : MAP_TILE_SIZE);
122 const bool doInlines = (tileWidth == MAP_TILE_SIZE);
123
124 int y = tileHeight;
125
126 if (doInlines) { // hw: memcmp/memcpy is inlined when using constants
127 while (y) {
128 if (memcmp(old, scrn, sizeof(T) * MAP_TILE_SIZE)) {
129 changed = true;
130 break;
131 }
132 scrn += lstep;
133 old += bufferStride;
134 --y;
135 }
136
137 while (y) {
138 memcpy(old, scrn, sizeof(T) * MAP_TILE_SIZE);
139 scrn += lstep;
140 old += bufferStride;
141 --y;
142 }
143 } else {
144 while (y) {
145 if (memcmp(old, scrn, sizeof(T) * tileWidth)) {
146 changed = true;
147 break;
148 }
149 scrn += lstep;
150 old += bufferStride;
151 --y;
152 }
153
154 while (y) {
155 memcpy(old, scrn, sizeof(T) * tileWidth);
156 scrn += lstep;
157 old += bufferStride;
158 --y;
159 }
160 }
161 }
162
163 const int mapIndex = tileY * mapWidth + tileX;
164 if ((force || changed) && !map[mapIndex]) {
165 map[mapIndex] = 1;
166 ++numDirty;
167 }
168}
169
170template class QVncDirtyMapOptimized<unsigned char>;
171template class QVncDirtyMapOptimized<unsigned short>;
172template class QVncDirtyMapOptimized<unsigned int>;
173
174static const struct {
175 int keysym;
176 int keycode;
177} keyMap[] = {
178 { 0xff08, Qt::Key_Backspace },
179 { 0xff09, Qt::Key_Tab },
180 { 0xff0d, Qt::Key_Return },
181 { 0xff1b, Qt::Key_Escape },
182 { 0xff63, Qt::Key_Insert },
183 { 0xffff, Qt::Key_Delete },
184 { 0xff50, Qt::Key_Home },
185 { 0xff57, Qt::Key_End },
186 { 0xff55, Qt::Key_PageUp },
187 { 0xff56, Qt::Key_PageDown },
188 { 0xff51, Qt::Key_Left },
189 { 0xff52, Qt::Key_Up },
190 { 0xff53, Qt::Key_Right },
191 { 0xff54, Qt::Key_Down },
192 { 0xffbe, Qt::Key_F1 },
193 { 0xffbf, Qt::Key_F2 },
194 { 0xffc0, Qt::Key_F3 },
195 { 0xffc1, Qt::Key_F4 },
196 { 0xffc2, Qt::Key_F5 },
197 { 0xffc3, Qt::Key_F6 },
198 { 0xffc4, Qt::Key_F7 },
199 { 0xffc5, Qt::Key_F8 },
200 { 0xffc6, Qt::Key_F9 },
201 { 0xffc7, Qt::Key_F10 },
202 { 0xffc8, Qt::Key_F11 },
203 { 0xffc9, Qt::Key_F12 },
204 { 0xffe1, Qt::Key_Shift },
205 { 0xffe2, Qt::Key_Shift },
206 { 0xffe3, Qt::Key_Control },
207 { 0xffe4, Qt::Key_Control },
208 { 0xffe7, Qt::Key_Meta },
209 { 0xffe8, Qt::Key_Meta },
210 { 0xffe9, Qt::Key_Alt },
211 { 0xffea, Qt::Key_Alt },
212
213 { 0xffb0, Qt::Key_0 },
214 { 0xffb1, Qt::Key_1 },
215 { 0xffb2, Qt::Key_2 },
216 { 0xffb3, Qt::Key_3 },
217 { 0xffb4, Qt::Key_4 },
218 { 0xffb5, Qt::Key_5 },
219 { 0xffb6, Qt::Key_6 },
220 { 0xffb7, Qt::Key_7 },
221 { 0xffb8, Qt::Key_8 },
222 { 0xffb9, Qt::Key_9 },
223
224 { 0xff8d, Qt::Key_Return },
225 { 0xffaa, Qt::Key_Asterisk },
226 { 0xffab, Qt::Key_Plus },
227 { 0xffad, Qt::Key_Minus },
228 { 0xffae, Qt::Key_Period },
229 { 0xffaf, Qt::Key_Slash },
230
231 { 0xff95, Qt::Key_Home },
232 { 0xff96, Qt::Key_Left },
233 { 0xff97, Qt::Key_Up },
234 { 0xff98, Qt::Key_Right },
235 { 0xff99, Qt::Key_Down },
236 { 0xff9a, Qt::Key_PageUp },
237 { 0xff9b, Qt::Key_PageDown },
238 { 0xff9c, Qt::Key_End },
239 { 0xff9e, Qt::Key_Insert },
240 { 0xff9f, Qt::Key_Delete },
241
242 { 0, 0 }
243};
244
245void QRfbRect::read(QTcpSocket *s)
246{
247 quint16 buf[4];
248 s->read((char*)buf, 8);
249 x = ntohs(buf[0]);
250 y = ntohs(buf[1]);
251 w = ntohs(buf[2]);
252 h = ntohs(buf[3]);
253}
254
255void QRfbRect::write(QTcpSocket *s) const
256{
257 quint16 buf[4];
258 buf[0] = htons(x);
259 buf[1] = htons(y);
260 buf[2] = htons(w);
261 buf[3] = htons(h);
262 s->write((char*)buf, 8);
263}
264
265void QRfbPixelFormat::read(QTcpSocket *s)
266{
267 char buf[16];
268 s->read(buf, 16);
269 bitsPerPixel = buf[0];
270 depth = buf[1];
271 bigEndian = buf[2];
272 trueColor = buf[3];
273
274 quint16 a = ntohs(*(quint16 *)(buf + 4));
275 redBits = 0;
276 while (a) { a >>= 1; redBits++; }
277
278 a = ntohs(*(quint16 *)(buf + 6));
279 greenBits = 0;
280 while (a) { a >>= 1; greenBits++; }
281
282 a = ntohs(*(quint16 *)(buf + 8));
283 blueBits = 0;
284 while (a) { a >>= 1; blueBits++; }
285
286 redShift = buf[10];
287 greenShift = buf[11];
288 blueShift = buf[12];
289}
290
291void QRfbPixelFormat::write(QTcpSocket *s)
292{
293 char buf[16];
294 buf[0] = bitsPerPixel;
295 buf[1] = depth;
296 buf[2] = bigEndian;
297 buf[3] = trueColor;
298
299 quint16 a = 0;
300 for (int i = 0; i < redBits; i++) a = (a << 1) | 1;
301 *(quint16 *)(buf + 4) = htons(a);
302
303 a = 0;
304 for (int i = 0; i < greenBits; i++) a = (a << 1) | 1;
305 *(quint16 *)(buf + 6) = htons(a);
306
307 a = 0;
308 for (int i = 0; i < blueBits; i++) a = (a << 1) | 1;
309 *(quint16 *)(buf + 8) = htons(a);
310
311 buf[10] = redShift;
312 buf[11] = greenShift;
313 buf[12] = blueShift;
314 s->write(buf, 16);
315}
316
317
318void QRfbServerInit::setName(const char *n)
319{
320 delete[] name;
321 name = new char [strlen(n) + 1];
322 strcpy(name, n);
323}
324
325void QRfbServerInit::read(QTcpSocket *s)
326{
327 s->read((char *)&width, 2);
328 width = ntohs(width);
329 s->read((char *)&height, 2);
330 height = ntohs(height);
331 format.read(s);
332
333 quint32 len;
334 s->read((char *)&len, 4);
335 len = ntohl(len);
336
337 name = new char [len + 1];
338 s->read(name, len);
339 name[len] = '\0';
340}
341
342void QRfbServerInit::write(QTcpSocket *s)
343{
344 quint16 t = htons(width);
345 s->write((char *)&t, 2);
346 t = htons(height);
347 s->write((char *)&t, 2);
348 format.write(s);
349 quint32 len = strlen(name);
350 len = htonl(len);
351 s->write((char *)&len, 4);
352 s->write(name, strlen(name));
353}
354
355bool QRfbSetEncodings::read(QTcpSocket *s)
356{
357 if (s->bytesAvailable() < 3)
358 return false;
359
360 char tmp;
361 s->read(&tmp, 1); // padding
362 s->read((char *)&count, 2);
363 count = ntohs(count);
364
365 return true;
366}
367
368bool QRfbFrameBufferUpdateRequest::read(QTcpSocket *s)
369{
370 if (s->bytesAvailable() < 9)
371 return false;
372
373 s->read(&incremental, 1);
374 rect.read(s);
375
376 return true;
377}
378
379bool QRfbKeyEvent::read(QTcpSocket *s)
380{
381 if (s->bytesAvailable() < 7)
382 return false;
383
384 s->read(&down, 1);
385 quint16 tmp;
386 s->read((char *)&tmp, 2); // padding
387
388 quint32 key;
389 s->read((char *)&key, 4);
390 key = ntohl(key);
391
392 unicode = 0;
393 keycode = 0;
394 int i = 0;
395 while (keyMap[i].keysym && !keycode) {
396 if (keyMap[i].keysym == (int)key)
397 keycode = keyMap[i].keycode;
398 i++;
399 }
400
401 if (keycode >= ' ' && keycode <= '~')
402 unicode = keycode;
403
404 if (!keycode) {
405 if (key <= 0xff) {
406 unicode = key;
407 if (key >= 'a' && key <= 'z')
408 keycode = Qt::Key_A + key - 'a';
409 else if (key >= ' ' && key <= '~')
410 keycode = Qt::Key_Space + key - ' ';
411 }
412 }
413
414 return true;
415}
416
417bool QRfbPointerEvent::read(QTcpSocket *s)
418{
419 if (s->bytesAvailable() < 5)
420 return false;
421
422 char buttonMask;
423 s->read(&buttonMask, 1);
424 buttons = Qt::NoButton;
425 if (buttonMask & 1)
426 buttons |= Qt::LeftButton;
427 if (buttonMask & 2)
428 buttons |= Qt::MiddleButton;
429 if (buttonMask & 4)
430 buttons |= Qt::RightButton;
431
432 quint16 tmp;
433 s->read((char *)&tmp, 2);
434 x = ntohs(tmp);
435 s->read((char *)&tmp, 2);
436 y = ntohs(tmp);
437
438 return true;
439}
440
441bool QRfbClientCutText::read(QTcpSocket *s)
442{
443 if (s->bytesAvailable() < 7)
444 return false;
445
446 char tmp[3];
447 s->read(tmp, 3); // padding
448 s->read((char *)&length, 4);
449 length = ntohl(length);
450
451 return true;
452}
453
454void QRfbRawEncoder::write()
455{
456// QVncDirtyMap *map = server->dirtyMap();
457 QTcpSocket *socket = client->clientSocket();
458
459 const int bytesPerPixel = client->clientBytesPerPixel();
460
461 // create a region from the dirty rects and send the region's merged rects.
462 // ### use the tile map again
463 QRegion rgn = client->dirtyRegion();
464 qCDebug(lcVnc) << "QRfbRawEncoder::write()" << rgn;
465// if (map) {
466// for (int y = 0; y < map->mapHeight; ++y) {
467// for (int x = 0; x < map->mapWidth; ++x) {
468// if (!map->dirty(x, y))
469// continue;
470// rgn += QRect(x * MAP_TILE_SIZE, y * MAP_TILE_SIZE,
471// MAP_TILE_SIZE, MAP_TILE_SIZE);
472// map->setClean(x, y);
473// }
474// }
475
476// rgn &= QRect(0, 0, server->screen()->geometry().width(),
477// server->screen()->geometry().height());
478// }
479
480 const auto rectsInRegion = rgn.rectCount();
481
482 {
483 const char tmp[2] = { 0, 0 }; // msg type, padding
484 socket->write(tmp, sizeof(tmp));
485 }
486
487 {
488 const quint16 count = htons(rectsInRegion);
489 socket->write((char *)&count, sizeof(count));
490 }
491
492 if (rectsInRegion <= 0)
493 return;
494
495 const QImage screenImage = client->server()->screenImage();
496
497 for (const QRect &tileRect: rgn) {
498 const QRfbRect rect(tileRect.x(), tileRect.y(),
499 tileRect.width(), tileRect.height());
500 rect.write(socket);
501
502 const quint32 encoding = htonl(0); // raw encoding
503 socket->write((char *)&encoding, sizeof(encoding));
504
505 qsizetype linestep = screenImage.bytesPerLine();
506 const uchar *screendata = screenImage.scanLine(rect.y)
507 + rect.x * screenImage.depth() / 8;
508
509 if (client->doPixelConversion()) {
510 const int bufferSize = rect.w * rect.h * bytesPerPixel;
511 if (bufferSize > buffer.size())
512 buffer.resize(bufferSize);
513
514 // convert pixels
515 char *b = buffer.data();
516 const int bstep = rect.w * bytesPerPixel;
517 for (int i = 0; i < rect.h; ++i) {
518 client->convertPixels(b, (const char*)screendata, rect.w);
519 screendata += linestep;
520 b += bstep;
521 }
522 socket->write(buffer.constData(), bufferSize);
523 } else {
524 for (int i = 0; i < rect.h; ++i) {
525 socket->write((const char*)screendata, rect.w * bytesPerPixel);
526 screendata += linestep;
527 }
528 }
529 if (socket->state() == QAbstractSocket::UnconnectedState)
530 break;
531 }
532 socket->flush();
533}
534
535#if QT_CONFIG(cursor)
536QVncClientCursor::QVncClientCursor()
537{
538 QWindow *w = QGuiApplication::focusWindow();
539 QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor);
540 changeCursor(&c, nullptr);
541}
542
543QVncClientCursor::~QVncClientCursor()
544{
545}
546
547void QVncClientCursor::write(QVncClient *client) const
548{
549 QTcpSocket *socket = client->clientSocket();
550
551 // FramebufferUpdate header
552 {
553 const quint16 tmp[6] = { htons(0),
554 htons(1),
555 htons(uint16_t(hotspot.x())), htons(uint16_t(hotspot.y())),
556 htons(uint16_t(cursor.width())),
557 htons(uint16_t(cursor.height())) };
558 socket->write((char*)tmp, sizeof(tmp));
559
560 const qint32 encoding = qToBigEndian(-239);
561 socket->write((char*)(&encoding), sizeof(encoding));
562 }
563
564 if (cursor.isNull())
565 return;
566
567 // write pixels
568 Q_ASSERT(cursor.hasAlphaChannel());
569 const QImage img = cursor.convertToFormat(client->server()->screen()->format());
570 const int n = client->clientBytesPerPixel() * img.width();
571 char *buffer = new char[n];
572 for (int i = 0; i < img.height(); ++i) {
573 client->convertPixels(buffer, (const char*)img.scanLine(i), img.width());
574 socket->write(buffer, n);
575 }
576 delete[] buffer;
577
578 // write mask
579 const QImage bitmap = cursor.createAlphaMask().convertToFormat(QImage::Format_Mono);
580 Q_ASSERT(bitmap.depth() == 1);
581 Q_ASSERT(bitmap.size() == img.size());
582 const int width = (bitmap.width() + 7) / 8;
583 for (int i = 0; i < bitmap.height(); ++i)
584 socket->write((const char*)bitmap.scanLine(i), width);
585}
586
587void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
588{
589 Q_UNUSED(window);
590 const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor;
591
592 if (shape == Qt::BitmapCursor) {
593 // application supplied cursor
594 hotspot = widgetCursor->hotSpot();
595 cursor = widgetCursor->pixmap().toImage();
596 } else {
597 // system cursor
598 QPlatformCursorImage platformImage(nullptr, nullptr, 0, 0, 0, 0);
599 platformImage.set(shape);
600 cursor = *platformImage.image();
601 hotspot = platformImage.hotspot();
602 }
603 for (auto client : qAsConst(clients))
604 client->setDirtyCursor();
605}
606
607void QVncClientCursor::addClient(QVncClient *client)
608{
609 if (!clients.contains(client)) {
610 clients.append(client);
611 // Force a cursor update when the client connects.
612 client->setDirtyCursor();
613 }
614}
615
616uint QVncClientCursor::removeClient(QVncClient *client)
617{
618 clients.removeOne(client);
619 return clients.count();
620}
621#endif // QT_CONFIG(cursor)
622
623QVncServer::QVncServer(QVncScreen *screen, quint16 port)
624 : qvnc_screen(screen)
625 , m_port(port)
626{
627 QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
628}
629
630void QVncServer::init()
631{
632 serverSocket = new QTcpServer(this);
633 if (!serverSocket->listen(QHostAddress::Any, m_port))
634 qWarning() << "QVncServer could not connect:" << serverSocket->errorString();
635 else
636 qWarning("QVncServer created on port %d", m_port);
637
638 connect(serverSocket, SIGNAL(newConnection()), this, SLOT(newConnection()));
639
640}
641
642QVncServer::~QVncServer()
643{
644 qDeleteAll(clients);
645}
646
647void QVncServer::setDirty()
648{
649 for (auto client : qAsConst(clients))
650 client->setDirty(qvnc_screen->dirtyRegion);
651
652 qvnc_screen->clearDirty();
653}
654
655
656void QVncServer::newConnection()
657{
658 auto clientSocket = serverSocket->nextPendingConnection();
659 clients.append(new QVncClient(clientSocket, this));
660
661 dirtyMap()->reset();
662
663 qCDebug(lcVnc) << "new Connection from: " << clientSocket->localAddress();
664
665 qvnc_screen->setPowerState(QPlatformScreen::PowerStateOn);
666}
667
668void QVncServer::discardClient(QVncClient *client)
669{
670 clients.removeOne(client);
671 client->deleteLater();
672 if (clients.isEmpty()) {
673 qvnc_screen->disableClientCursor(client);
674 qvnc_screen->setPowerState(QPlatformScreen::PowerStateOff);
675 }
676}
677
678inline QImage QVncServer::screenImage() const
679{
680 return *qvnc_screen->image();
681}
682
683QT_END_NAMESPACE
684