blob: e61c2e72cda21b2b2e2037ea3e75c4cc64502831 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossmana4c0aac2017-02-19 15:50:29 +01002 * Copyright 2011-2017 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
Pierre Ossmandd45b442018-10-31 17:08:59 +010019#include <assert.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000020#include <stdio.h>
21#include <string.h>
Pierre Ossman0068a4f2015-11-09 15:48:19 +010022
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rfb/Exception.h>
Pierre Ossmanc754cce2011-11-14 15:44:11 +000024#include <rfb/fenceTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010025#include <rfb/CMsgReader.h>
26#include <rfb/CMsgWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#include <rfb/CSecurity.h>
Pierre Ossman96728352018-06-20 11:35:05 +020028#include <rfb/Decoder.h>
Adam Tkac5a0caed2010-04-23 13:58:10 +000029#include <rfb/Security.h>
Pierre Ossman0068a4f2015-11-09 15:48:19 +010030#include <rfb/SecurityClient.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000031#include <rfb/CConnection.h>
32#include <rfb/util.h>
33
34#include <rfb/LogWriter.h>
35
Pierre Ossman0068a4f2015-11-09 15:48:19 +010036#include <rdr/InStream.h>
37#include <rdr/OutStream.h>
38
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000039using namespace rfb;
40
41static LogWriter vlog("CConnection");
42
43CConnection::CConnection()
Adam Tkacf324dc42010-04-23 14:10:17 +000044 : csecurity(0), is(0), os(0), reader_(0), writer_(0),
Adam Tkac05a0cd62010-07-20 15:07:44 +000045 shared(false),
Pierre Ossman9f273e92015-11-09 16:34:54 +010046 state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
Pierre Ossmanef6881b2018-06-20 11:26:18 +020047 pendingPFChange(false), preferredEncoding(encodingTight),
48 formatChange(false), encodingChange(false),
49 firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
50 forceNonincremental(true),
Pierre Ossman9f273e92015-11-09 16:34:54 +010051 framebuffer(NULL), decoder(this)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052{
53}
54
55CConnection::~CConnection()
56{
Pierre Ossman9f273e92015-11-09 16:34:54 +010057 setFramebuffer(NULL);
Pierre Ossman82d22e62018-09-21 15:26:37 +020058 if (csecurity)
59 delete csecurity;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000060 delete reader_;
61 reader_ = 0;
62 delete writer_;
63 writer_ = 0;
64}
65
66void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
67{
68 is = is_;
69 os = os_;
70}
71
Pierre Ossman9f273e92015-11-09 16:34:54 +010072void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
73{
Pierre Ossman504afa22015-11-12 12:21:58 +010074 decoder.flush();
75
Pierre Ossman9f273e92015-11-09 16:34:54 +010076 if ((framebuffer != NULL) && (fb != NULL)) {
77 Rect rect;
78
79 const rdr::U8* data;
80 int stride;
81
82 const rdr::U8 black[4] = { 0, 0, 0, 0 };
83
84 // Copy still valid area
85
86 rect.setXYWH(0, 0,
87 __rfbmin(fb->width(), framebuffer->width()),
88 __rfbmin(fb->height(), framebuffer->height()));
89 data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
90 fb->imageRect(rect, data, stride);
91
92 // Black out any new areas
93
94 if (fb->width() > framebuffer->width()) {
95 rect.setXYWH(framebuffer->width(), 0,
Brian P. Hinz5d663052016-09-05 09:15:50 -040096 fb->width() - framebuffer->width(),
Pierre Ossman9f273e92015-11-09 16:34:54 +010097 fb->height());
98 fb->fillRect(rect, black);
99 }
100
101 if (fb->height() > framebuffer->height()) {
102 rect.setXYWH(0, framebuffer->height(),
103 fb->width(),
104 fb->height() - framebuffer->height());
105 fb->fillRect(rect, black);
106 }
107 }
108
109 delete framebuffer;
110 framebuffer = fb;
111}
112
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000113void CConnection::initialiseProtocol()
114{
115 state_ = RFBSTATE_PROTOCOL_VERSION;
116}
117
118void CConnection::processMsg()
119{
120 switch (state_) {
121
122 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
123 case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
124 case RFBSTATE_SECURITY: processSecurityMsg(); break;
125 case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
126 case RFBSTATE_INITIALISATION: processInitMsg(); break;
127 case RFBSTATE_NORMAL: reader_->readMsg(); break;
128 case RFBSTATE_UNINITIALISED:
129 throw Exception("CConnection::processMsg: not initialised yet?");
130 default:
131 throw Exception("CConnection::processMsg: invalid state");
132 }
133}
134
135void CConnection::processVersionMsg()
136{
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200137 char verStr[13];
138 int majorVersion;
139 int minorVersion;
140
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000141 vlog.debug("reading protocol version");
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200142
143 if (!is->checkNoWait(12))
144 return;
145
146 is->readBytes(verStr, 12);
147 verStr[12] = '\0';
148
149 if (sscanf(verStr, "RFB %03d.%03d\n",
150 &majorVersion, &minorVersion) != 2) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000151 state_ = RFBSTATE_INVALID;
152 throw Exception("reading version failed: not an RFB server?");
153 }
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200154
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200155 server.setVersion(majorVersion, minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000156
157 vlog.info("Server supports RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200158 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000159
160 // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200161 if (server.beforeVersion(3,3)) {
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100162 vlog.error("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200163 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000164 state_ = RFBSTATE_INVALID;
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100165 throw Exception("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200166 server.majorVersion, server.minorVersion);
167 } else if (useProtocol3_3 || server.beforeVersion(3,7)) {
168 server.setVersion(3,3);
169 } else if (server.afterVersion(3,8)) {
170 server.setVersion(3,8);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000171 }
172
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200173 sprintf(verStr, "RFB %03d.%03d\n",
174 server.majorVersion, server.minorVersion);
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200175 os->writeBytes(verStr, 12);
176 os->flush();
177
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000178 state_ = RFBSTATE_SECURITY_TYPES;
179
180 vlog.info("Using RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200181 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000182}
183
184
185void CConnection::processSecurityTypesMsg()
186{
187 vlog.debug("processing security types message");
188
189 int secType = secTypeInvalid;
190
Adam Tkac05a0cd62010-07-20 15:07:44 +0000191 std::list<rdr::U8> secTypes;
Michal Srbdccb5f72017-03-27 13:55:46 +0300192 secTypes = security.GetEnabledSecTypes();
Adam Tkac05a0cd62010-07-20 15:07:44 +0000193
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200194 if (server.isVersion(3,3)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000195
196 // legacy 3.3 server may only offer "vnc authentication" or "none"
197
198 secType = is->readU32();
199 if (secType == secTypeInvalid) {
200 throwConnFailedException();
201
202 } else if (secType == secTypeNone || secType == secTypeVncAuth) {
Adam Tkac05a0cd62010-07-20 15:07:44 +0000203 std::list<rdr::U8>::iterator i;
204 for (i = secTypes.begin(); i != secTypes.end(); i++)
205 if (*i == secType) {
206 secType = *i;
207 break;
208 }
209
210 if (i == secTypes.end())
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000211 secType = secTypeInvalid;
212 } else {
213 vlog.error("Unknown 3.3 security type %d", secType);
214 throw Exception("Unknown 3.3 security type");
215 }
216
217 } else {
218
219 // >=3.7 server will offer us a list
220
221 int nServerSecTypes = is->readU8();
222 if (nServerSecTypes == 0)
223 throwConnFailedException();
224
Adam Tkac05a0cd62010-07-20 15:07:44 +0000225 std::list<rdr::U8>::iterator j;
Adam Tkac05a0cd62010-07-20 15:07:44 +0000226
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000227 for (int i = 0; i < nServerSecTypes; i++) {
228 rdr::U8 serverSecType = is->readU8();
229 vlog.debug("Server offers security type %s(%d)",
Adam Tkac7cb47d62011-02-21 12:55:24 +0000230 secTypeName(serverSecType), serverSecType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000231
Adam Tkac7cb47d62011-02-21 12:55:24 +0000232 /*
233 * Use the first type sent by server which matches client's type.
234 * It means server's order specifies priority.
235 */
236 if (secType == secTypeInvalid) {
237 for (j = secTypes.begin(); j != secTypes.end(); j++)
238 if (*j == serverSecType) {
239 secType = *j;
240 break;
241 }
242 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000243 }
244
245 // Inform the server of our decision
246 if (secType != secTypeInvalid) {
247 os->writeU8(secType);
248 os->flush();
Pierre Ossman71d66662014-11-11 13:42:51 +0100249 vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000250 }
251 }
252
253 if (secType == secTypeInvalid) {
254 state_ = RFBSTATE_INVALID;
255 vlog.error("No matching security types");
256 throw Exception("No matching security types");
257 }
258
259 state_ = RFBSTATE_SECURITY;
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200260 csecurity = security.GetCSecurity(this, secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000261 processSecurityMsg();
262}
263
264void CConnection::processSecurityMsg()
265{
266 vlog.debug("processing security message");
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200267 if (csecurity->processMsg()) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000268 state_ = RFBSTATE_SECURITY_RESULT;
269 processSecurityResultMsg();
270 }
271}
272
273void CConnection::processSecurityResultMsg()
274{
275 vlog.debug("processing security result message");
276 int result;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200277 if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000278 result = secResultOK;
279 } else {
280 if (!is->checkNoWait(1)) return;
281 result = is->readU32();
282 }
283 switch (result) {
284 case secResultOK:
285 securityCompleted();
286 return;
287 case secResultFailed:
288 vlog.debug("auth failed");
289 break;
290 case secResultTooMany:
291 vlog.debug("auth failed - too many tries");
292 break;
293 default:
294 throw Exception("Unknown security result from server");
295 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000296 state_ = RFBSTATE_INVALID;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200297 if (server.beforeVersion(3,8))
Pierre Ossman19225502017-10-12 15:05:07 +0200298 throw AuthFailureException();
299 CharArray reason(is->readString());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000300 throw AuthFailureException(reason.buf);
301}
302
303void CConnection::processInitMsg()
304{
305 vlog.debug("reading server initialisation");
306 reader_->readServerInit();
307}
308
309void CConnection::throwConnFailedException()
310{
311 state_ = RFBSTATE_INVALID;
312 CharArray reason;
313 reason.buf = is->readString();
314 throw ConnFailedException(reason.buf);
315}
316
317void CConnection::securityCompleted()
318{
319 state_ = RFBSTATE_INITIALISATION;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100320 reader_ = new CMsgReader(this, is);
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200321 writer_ = new CMsgWriter(&server, os);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000322 vlog.debug("Authentication success!");
323 authSuccess();
324 writer_->writeClientInit(shared);
325}
326
Pierre Ossman3da238d2015-11-12 12:20:05 +0100327void CConnection::setDesktopSize(int w, int h)
328{
Pierre Ossman504afa22015-11-12 12:21:58 +0100329 decoder.flush();
330
Pierre Ossman3da238d2015-11-12 12:20:05 +0100331 CMsgHandler::setDesktopSize(w,h);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200332
333 if (continuousUpdates)
334 writer()->writeEnableContinuousUpdates(true, 0, 0,
335 server.width(),
336 server.height());
Pierre Ossman3da238d2015-11-12 12:20:05 +0100337}
338
339void CConnection::setExtendedDesktopSize(unsigned reason,
340 unsigned result,
341 int w, int h,
342 const ScreenSet& layout)
343{
Pierre Ossman504afa22015-11-12 12:21:58 +0100344 decoder.flush();
345
Pierre Ossman3da238d2015-11-12 12:20:05 +0100346 CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200347
348 if (continuousUpdates)
349 writer()->writeEnableContinuousUpdates(true, 0, 0,
350 server.width(),
351 server.height());
352}
353
354void CConnection::endOfContinuousUpdates()
355{
356 CMsgHandler::endOfContinuousUpdates();
357
358 // We've gotten the marker for a format change, so make the pending
359 // one active
360 if (pendingPFChange) {
361 server.setPF(pendingPF);
362 pendingPFChange = false;
363
364 // We might have another change pending
365 if (formatChange)
366 requestNewUpdate();
367 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100368}
369
Pierre Ossmandd45b442018-10-31 17:08:59 +0100370void CConnection::serverInit(int width, int height,
371 const PixelFormat& pf,
372 const char* name)
Pierre Ossman2affd772018-06-20 07:03:10 +0200373{
Pierre Ossmandd45b442018-10-31 17:08:59 +0100374 CMsgHandler::serverInit(width, height, pf, name);
375
Pierre Ossman2affd772018-06-20 07:03:10 +0200376 state_ = RFBSTATE_NORMAL;
377 vlog.debug("initialisation done");
378
379 initDone();
Pierre Ossmandd45b442018-10-31 17:08:59 +0100380 assert(framebuffer != NULL);
381 assert(framebuffer->width() == server.width());
382 assert(framebuffer->height() == server.height());
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200383
384 // We want to make sure we call SetEncodings at least once
385 encodingChange = true;
386
387 requestNewUpdate();
388
389 // This initial update request is a bit of a corner case, so we need
390 // to help out setting the correct format here.
391 if (pendingPFChange) {
392 server.setPF(pendingPF);
393 pendingPFChange = false;
394 }
Pierre Ossman2affd772018-06-20 07:03:10 +0200395}
396
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100397void CConnection::readAndDecodeRect(const Rect& r, int encoding,
398 ModifiablePixelBuffer* pb)
399{
400 decoder.decodeRect(r, encoding, pb);
401 decoder.flush();
402}
403
Pierre Ossman3da238d2015-11-12 12:20:05 +0100404void CConnection::framebufferUpdateStart()
405{
406 CMsgHandler::framebufferUpdateStart();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200407
408 assert(framebuffer != NULL);
409
410 // Note: This might not be true if continuous updates are supported
411 pendingUpdate = false;
412
413 requestNewUpdate();
Pierre Ossman3da238d2015-11-12 12:20:05 +0100414}
415
416void CConnection::framebufferUpdateEnd()
417{
Pierre Ossman504afa22015-11-12 12:21:58 +0100418 decoder.flush();
419
Pierre Ossman3da238d2015-11-12 12:20:05 +0100420 CMsgHandler::framebufferUpdateEnd();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200421
422 // A format change has been scheduled and we are now past the update
423 // with the old format. Time to active the new one.
424 if (pendingPFChange && !continuousUpdates) {
425 server.setPF(pendingPF);
426 pendingPFChange = false;
427 }
428
429 if (firstUpdate) {
430 if (server.supportsContinuousUpdates) {
431 vlog.info("Enabling continuous updates");
432 continuousUpdates = true;
433 writer()->writeEnableContinuousUpdates(true, 0, 0,
434 server.width(),
435 server.height());
436 }
437
438 firstUpdate = false;
439 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100440}
441
Pierre Ossman9f273e92015-11-09 16:34:54 +0100442void CConnection::dataRect(const Rect& r, int encoding)
443{
444 decoder.decodeRect(r, encoding, framebuffer);
445}
446
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000447void CConnection::authSuccess()
448{
449}
450
Pierre Ossman2affd772018-06-20 07:03:10 +0200451void CConnection::initDone()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000452{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000453}
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000454
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200455void CConnection::refreshFramebuffer()
456{
457 forceNonincremental = true;
458
459 // Without continuous updates we have to make sure we only have a
460 // single update in flight, so we'll have to wait to do the refresh
461 if (continuousUpdates)
462 requestNewUpdate();
463}
464
465void CConnection::setPreferredEncoding(int encoding)
466{
467 if (preferredEncoding == encoding)
468 return;
469
470 preferredEncoding = encoding;
471 encodingChange = true;
472}
473
474int CConnection::getPreferredEncoding()
475{
476 return preferredEncoding;
477}
478
479void CConnection::setCompressLevel(int level)
480{
481 if (server.compressLevel == level)
482 return;
483
484 server.compressLevel = level;
485 encodingChange = true;
486}
487
488void CConnection::setQualityLevel(int level)
489{
490 if (server.qualityLevel == level)
491 return;
492
493 server.qualityLevel = level;
494 encodingChange = true;
495}
496
497void CConnection::setPF(const PixelFormat& pf)
498{
499 if (server.pf().equal(pf) && !formatChange)
500 return;
501
502 nextPF = pf;
503 formatChange = true;
504}
505
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000506void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
507{
508 CMsgHandler::fence(flags, len, data);
509
510 if (!(flags & fenceFlagRequest))
511 return;
512
513 // We cannot guarantee any synchronisation at this level
514 flags = 0;
515
516 writer()->writeFence(flags, len, data);
517}
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200518
519// requestNewUpdate() requests an update from the server, having set the
520// format and encoding appropriately.
521void CConnection::requestNewUpdate()
522{
523 if (formatChange && !pendingPFChange) {
524 /* Catch incorrect requestNewUpdate calls */
525 assert(!pendingUpdate || continuousUpdates);
526
527 // We have to make sure we switch the internal format at a safe
528 // time. For continuous updates we temporarily disable updates and
529 // look for a EndOfContinuousUpdates message to see when to switch.
530 // For classical updates we just got a new update right before this
531 // function was called, so we need to make sure we finish that
532 // update before we can switch.
533
534 pendingPFChange = true;
535 pendingPF = nextPF;
536
537 if (continuousUpdates)
538 writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
539
540 writer()->writeSetPixelFormat(pendingPF);
541
542 if (continuousUpdates)
543 writer()->writeEnableContinuousUpdates(true, 0, 0,
544 server.width(),
545 server.height());
546
547 formatChange = false;
548 }
549
550 if (encodingChange) {
Pierre Ossman96728352018-06-20 11:35:05 +0200551 updateEncodings();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200552 encodingChange = false;
553 }
554
555 if (forceNonincremental || !continuousUpdates) {
556 pendingUpdate = true;
557 writer()->writeFramebufferUpdateRequest(Rect(0, 0,
558 server.width(),
559 server.height()),
560 !forceNonincremental);
561 }
562
563 forceNonincremental = false;
564}
Pierre Ossman96728352018-06-20 11:35:05 +0200565
566// Ask for encodings based on which decoders are supported. Assumes higher
567// encoding numbers are more desirable.
568
569void CConnection::updateEncodings()
570{
Pierre Ossman1143ee62018-06-20 11:40:37 +0200571 std::list<rdr::U32> encodings;
Pierre Ossman96728352018-06-20 11:35:05 +0200572
573 if (server.supportsLocalCursor) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200574 encodings.push_back(pseudoEncodingCursorWithAlpha);
575 encodings.push_back(pseudoEncodingCursor);
576 encodings.push_back(pseudoEncodingXCursor);
Pierre Ossman96728352018-06-20 11:35:05 +0200577 }
578 if (server.supportsDesktopResize)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200579 encodings.push_back(pseudoEncodingDesktopSize);
Pierre Ossman96728352018-06-20 11:35:05 +0200580 if (server.supportsExtendedDesktopSize)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200581 encodings.push_back(pseudoEncodingExtendedDesktopSize);
Pierre Ossman96728352018-06-20 11:35:05 +0200582 if (server.supportsLEDState)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200583 encodings.push_back(pseudoEncodingLEDState);
Pierre Ossman96728352018-06-20 11:35:05 +0200584
Pierre Ossman5588f4f2018-06-20 11:48:17 +0200585 encodings.push_back(pseudoEncodingDesktopName);
Pierre Ossman1143ee62018-06-20 11:40:37 +0200586 encodings.push_back(pseudoEncodingLastRect);
587 encodings.push_back(pseudoEncodingContinuousUpdates);
588 encodings.push_back(pseudoEncodingFence);
589 encodings.push_back(pseudoEncodingQEMUKeyEvent);
Pierre Ossman96728352018-06-20 11:35:05 +0200590
591 if (Decoder::supported(preferredEncoding)) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200592 encodings.push_back(preferredEncoding);
Pierre Ossman96728352018-06-20 11:35:05 +0200593 }
594
Pierre Ossman1143ee62018-06-20 11:40:37 +0200595 encodings.push_back(encodingCopyRect);
Pierre Ossman96728352018-06-20 11:35:05 +0200596
Pierre Ossman96728352018-06-20 11:35:05 +0200597 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman3bbe8d72018-06-20 11:42:36 +0200598 if ((i != preferredEncoding) && Decoder::supported(i))
599 encodings.push_back(i);
Pierre Ossman96728352018-06-20 11:35:05 +0200600 }
601
602 if (server.compressLevel >= 0 && server.compressLevel <= 9)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200603 encodings.push_back(pseudoEncodingCompressLevel0 + server.compressLevel);
Pierre Ossman96728352018-06-20 11:35:05 +0200604 if (server.qualityLevel >= 0 && server.qualityLevel <= 9)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200605 encodings.push_back(pseudoEncodingQualityLevel0 + server.qualityLevel);
Pierre Ossman96728352018-06-20 11:35:05 +0200606
Pierre Ossman1143ee62018-06-20 11:40:37 +0200607 writer()->writeSetEncodings(encodings);
Pierre Ossman96728352018-06-20 11:35:05 +0200608}