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

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