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 
58 QT_BEGIN_NAMESPACE
59 
60 Q_LOGGING_CATEGORY(lcVnc, "qt.qpa.vnc");
61 
QVncDirtyMap(QVncScreen * screen)62 QVncDirtyMap::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 
~QVncDirtyMap()77 QVncDirtyMap::~QVncDirtyMap()
78 {
79     delete[] map;
80     delete[] buffer;
81 }
82 
reset()83 void QVncDirtyMap::reset()
84 {
85     memset(map, 1, numTiles);
86     memset(buffer, 0, bufferHeight * bufferStride);
87     numDirty = numTiles;
88 }
89 
dirty(int x,int y) const90 inline bool QVncDirtyMap::dirty(int x, int y) const
91 {
92     return map[y * mapWidth + x];
93 }
94 
setClean(int x,int y)95 inline void QVncDirtyMap::setClean(int x, int y)
96 {
97     map[y * mapWidth + x] = 0;
98     --numDirty;
99 }
100 
101 template <class T>
setDirty(int tileX,int tileY,bool force)102 void 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 
170 template class QVncDirtyMapOptimized<unsigned char>;
171 template class QVncDirtyMapOptimized<unsigned short>;
172 template class QVncDirtyMapOptimized<unsigned int>;
173 
174 static 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 
read(QTcpSocket * s)245 void 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 
write(QTcpSocket * s) const255 void 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 
read(QTcpSocket * s)265 void 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 
write(QTcpSocket * s)291 void 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 
setName(const char * n)318 void QRfbServerInit::setName(const char *n)
319 {
320     delete[] name;
321     name = new char [strlen(n) + 1];
322     strcpy(name, n);
323 }
324 
read(QTcpSocket * s)325 void 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 
write(QTcpSocket * s)342 void 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 
read(QTcpSocket * s)355 bool 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 
read(QTcpSocket * s)368 bool 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 
read(QTcpSocket * s)379 bool 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 
read(QTcpSocket * s)417 bool 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 
read(QTcpSocket * s)441 bool 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 
write()454 void 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         int 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)
QVncClientCursor()536 QVncClientCursor::QVncClientCursor()
537 {
538     QWindow *w = QGuiApplication::focusWindow();
539     QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor);
540     changeCursor(&c, nullptr);
541 }
542 
~QVncClientCursor()543 QVncClientCursor::~QVncClientCursor()
544 {
545 }
546 
write(QVncClient * client) const547 void 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 
changeCursor(QCursor * widgetCursor,QWindow * window)587 void 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 
addClient(QVncClient * client)607 void 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 
removeClient(QVncClient * client)616 uint QVncClientCursor::removeClient(QVncClient *client)
617 {
618     clients.removeOne(client);
619     return clients.count();
620 }
621 #endif // QT_CONFIG(cursor)
622 
QVncServer(QVncScreen * screen,quint16 port)623 QVncServer::QVncServer(QVncScreen *screen, quint16 port)
624     : qvnc_screen(screen)
625     , m_port(port)
626 {
627     QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
628 }
629 
init()630 void 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 
~QVncServer()642 QVncServer::~QVncServer()
643 {
644     qDeleteAll(clients);
645 }
646 
setDirty()647 void QVncServer::setDirty()
648 {
649     for (auto client : qAsConst(clients))
650         client->setDirty(qvnc_screen->dirtyRegion);
651 
652     qvnc_screen->clearDirty();
653 }
654 
655 
newConnection()656 void 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 
discardClient(QVncClient * client)668 void 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 
screenImage() const678 inline QImage QVncServer::screenImage() const
679 {
680     return *qvnc_screen->image();
681 }
682 
683 QT_END_NAMESPACE
684