blob: 3ea217fa1bfe59052e44ceaf86483bff7363b209 [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()
Pierre Ossmanb03512c2018-06-20 16:03:23 +020044 : csecurity(0),
45 supportsLocalCursor(false), supportsDesktopResize(false),
46 supportsLEDState(false),
47 is(0), os(0), reader_(0), writer_(0),
Adam Tkac05a0cd62010-07-20 15:07:44 +000048 shared(false),
Pierre Ossman9f273e92015-11-09 16:34:54 +010049 state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
Pierre Ossmanef6881b2018-06-20 11:26:18 +020050 pendingPFChange(false), preferredEncoding(encodingTight),
Pierre Ossmanb03512c2018-06-20 16:03:23 +020051 compressLevel(2), qualityLevel(-1),
Pierre Ossmanef6881b2018-06-20 11:26:18 +020052 formatChange(false), encodingChange(false),
53 firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
54 forceNonincremental(true),
Pierre Ossman9f273e92015-11-09 16:34:54 +010055 framebuffer(NULL), decoder(this)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000056{
57}
58
59CConnection::~CConnection()
60{
Pierre Ossman9f273e92015-11-09 16:34:54 +010061 setFramebuffer(NULL);
Pierre Ossman82d22e62018-09-21 15:26:37 +020062 if (csecurity)
63 delete csecurity;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000064 delete reader_;
65 reader_ = 0;
66 delete writer_;
67 writer_ = 0;
68}
69
70void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
71{
72 is = is_;
73 os = os_;
74}
75
Pierre Ossman9f273e92015-11-09 16:34:54 +010076void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
77{
Pierre Ossman504afa22015-11-12 12:21:58 +010078 decoder.flush();
79
Pierre Ossman6ea58ba2018-06-20 15:47:49 +020080 if (fb) {
81 assert(fb->width() == server.width());
82 assert(fb->height() == server.height());
83 }
84
Pierre Ossman9f273e92015-11-09 16:34:54 +010085 if ((framebuffer != NULL) && (fb != NULL)) {
86 Rect rect;
87
88 const rdr::U8* data;
89 int stride;
90
91 const rdr::U8 black[4] = { 0, 0, 0, 0 };
92
93 // Copy still valid area
94
95 rect.setXYWH(0, 0,
96 __rfbmin(fb->width(), framebuffer->width()),
97 __rfbmin(fb->height(), framebuffer->height()));
98 data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
99 fb->imageRect(rect, data, stride);
100
101 // Black out any new areas
102
103 if (fb->width() > framebuffer->width()) {
104 rect.setXYWH(framebuffer->width(), 0,
Brian P. Hinz5d663052016-09-05 09:15:50 -0400105 fb->width() - framebuffer->width(),
Pierre Ossman9f273e92015-11-09 16:34:54 +0100106 fb->height());
107 fb->fillRect(rect, black);
108 }
109
110 if (fb->height() > framebuffer->height()) {
111 rect.setXYWH(0, framebuffer->height(),
112 fb->width(),
113 fb->height() - framebuffer->height());
114 fb->fillRect(rect, black);
115 }
116 }
117
118 delete framebuffer;
119 framebuffer = fb;
120}
121
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000122void CConnection::initialiseProtocol()
123{
124 state_ = RFBSTATE_PROTOCOL_VERSION;
125}
126
127void CConnection::processMsg()
128{
129 switch (state_) {
130
131 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
132 case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
133 case RFBSTATE_SECURITY: processSecurityMsg(); break;
134 case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
135 case RFBSTATE_INITIALISATION: processInitMsg(); break;
136 case RFBSTATE_NORMAL: reader_->readMsg(); break;
137 case RFBSTATE_UNINITIALISED:
138 throw Exception("CConnection::processMsg: not initialised yet?");
139 default:
140 throw Exception("CConnection::processMsg: invalid state");
141 }
142}
143
144void CConnection::processVersionMsg()
145{
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200146 char verStr[13];
147 int majorVersion;
148 int minorVersion;
149
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000150 vlog.debug("reading protocol version");
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200151
152 if (!is->checkNoWait(12))
153 return;
154
155 is->readBytes(verStr, 12);
156 verStr[12] = '\0';
157
158 if (sscanf(verStr, "RFB %03d.%03d\n",
159 &majorVersion, &minorVersion) != 2) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000160 state_ = RFBSTATE_INVALID;
161 throw Exception("reading version failed: not an RFB server?");
162 }
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200163
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200164 server.setVersion(majorVersion, minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000165
166 vlog.info("Server supports RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200167 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000168
169 // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200170 if (server.beforeVersion(3,3)) {
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100171 vlog.error("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200172 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000173 state_ = RFBSTATE_INVALID;
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100174 throw Exception("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200175 server.majorVersion, server.minorVersion);
176 } else if (useProtocol3_3 || server.beforeVersion(3,7)) {
177 server.setVersion(3,3);
178 } else if (server.afterVersion(3,8)) {
179 server.setVersion(3,8);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000180 }
181
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200182 sprintf(verStr, "RFB %03d.%03d\n",
183 server.majorVersion, server.minorVersion);
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200184 os->writeBytes(verStr, 12);
185 os->flush();
186
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000187 state_ = RFBSTATE_SECURITY_TYPES;
188
189 vlog.info("Using RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200190 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000191}
192
193
194void CConnection::processSecurityTypesMsg()
195{
196 vlog.debug("processing security types message");
197
198 int secType = secTypeInvalid;
199
Adam Tkac05a0cd62010-07-20 15:07:44 +0000200 std::list<rdr::U8> secTypes;
Michal Srbdccb5f72017-03-27 13:55:46 +0300201 secTypes = security.GetEnabledSecTypes();
Adam Tkac05a0cd62010-07-20 15:07:44 +0000202
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200203 if (server.isVersion(3,3)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000204
205 // legacy 3.3 server may only offer "vnc authentication" or "none"
206
207 secType = is->readU32();
208 if (secType == secTypeInvalid) {
209 throwConnFailedException();
210
211 } else if (secType == secTypeNone || secType == secTypeVncAuth) {
Adam Tkac05a0cd62010-07-20 15:07:44 +0000212 std::list<rdr::U8>::iterator i;
213 for (i = secTypes.begin(); i != secTypes.end(); i++)
214 if (*i == secType) {
215 secType = *i;
216 break;
217 }
218
219 if (i == secTypes.end())
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000220 secType = secTypeInvalid;
221 } else {
222 vlog.error("Unknown 3.3 security type %d", secType);
223 throw Exception("Unknown 3.3 security type");
224 }
225
226 } else {
227
228 // >=3.7 server will offer us a list
229
230 int nServerSecTypes = is->readU8();
231 if (nServerSecTypes == 0)
232 throwConnFailedException();
233
Adam Tkac05a0cd62010-07-20 15:07:44 +0000234 std::list<rdr::U8>::iterator j;
Adam Tkac05a0cd62010-07-20 15:07:44 +0000235
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000236 for (int i = 0; i < nServerSecTypes; i++) {
237 rdr::U8 serverSecType = is->readU8();
238 vlog.debug("Server offers security type %s(%d)",
Adam Tkac7cb47d62011-02-21 12:55:24 +0000239 secTypeName(serverSecType), serverSecType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000240
Adam Tkac7cb47d62011-02-21 12:55:24 +0000241 /*
242 * Use the first type sent by server which matches client's type.
243 * It means server's order specifies priority.
244 */
245 if (secType == secTypeInvalid) {
246 for (j = secTypes.begin(); j != secTypes.end(); j++)
247 if (*j == serverSecType) {
248 secType = *j;
249 break;
250 }
251 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000252 }
253
254 // Inform the server of our decision
255 if (secType != secTypeInvalid) {
256 os->writeU8(secType);
257 os->flush();
Pierre Ossman71d66662014-11-11 13:42:51 +0100258 vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000259 }
260 }
261
262 if (secType == secTypeInvalid) {
263 state_ = RFBSTATE_INVALID;
264 vlog.error("No matching security types");
265 throw Exception("No matching security types");
266 }
267
268 state_ = RFBSTATE_SECURITY;
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200269 csecurity = security.GetCSecurity(this, secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000270 processSecurityMsg();
271}
272
273void CConnection::processSecurityMsg()
274{
275 vlog.debug("processing security message");
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200276 if (csecurity->processMsg()) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000277 state_ = RFBSTATE_SECURITY_RESULT;
278 processSecurityResultMsg();
279 }
280}
281
282void CConnection::processSecurityResultMsg()
283{
284 vlog.debug("processing security result message");
285 int result;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200286 if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000287 result = secResultOK;
288 } else {
289 if (!is->checkNoWait(1)) return;
290 result = is->readU32();
291 }
292 switch (result) {
293 case secResultOK:
294 securityCompleted();
295 return;
296 case secResultFailed:
297 vlog.debug("auth failed");
298 break;
299 case secResultTooMany:
300 vlog.debug("auth failed - too many tries");
301 break;
302 default:
303 throw Exception("Unknown security result from server");
304 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000305 state_ = RFBSTATE_INVALID;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200306 if (server.beforeVersion(3,8))
Pierre Ossman19225502017-10-12 15:05:07 +0200307 throw AuthFailureException();
308 CharArray reason(is->readString());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000309 throw AuthFailureException(reason.buf);
310}
311
312void CConnection::processInitMsg()
313{
314 vlog.debug("reading server initialisation");
315 reader_->readServerInit();
316}
317
318void CConnection::throwConnFailedException()
319{
320 state_ = RFBSTATE_INVALID;
321 CharArray reason;
322 reason.buf = is->readString();
323 throw ConnFailedException(reason.buf);
324}
325
326void CConnection::securityCompleted()
327{
328 state_ = RFBSTATE_INITIALISATION;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100329 reader_ = new CMsgReader(this, is);
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200330 writer_ = new CMsgWriter(&server, os);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000331 vlog.debug("Authentication success!");
332 authSuccess();
333 writer_->writeClientInit(shared);
334}
335
Pierre Ossman3da238d2015-11-12 12:20:05 +0100336void CConnection::setDesktopSize(int w, int h)
337{
Pierre Ossman504afa22015-11-12 12:21:58 +0100338 decoder.flush();
339
Pierre Ossman3da238d2015-11-12 12:20:05 +0100340 CMsgHandler::setDesktopSize(w,h);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200341
342 if (continuousUpdates)
343 writer()->writeEnableContinuousUpdates(true, 0, 0,
344 server.width(),
345 server.height());
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200346
347 resizeFramebuffer();
348 assert(framebuffer != NULL);
349 assert(framebuffer->width() == server.width());
350 assert(framebuffer->height() == server.height());
Pierre Ossman3da238d2015-11-12 12:20:05 +0100351}
352
353void CConnection::setExtendedDesktopSize(unsigned reason,
354 unsigned result,
355 int w, int h,
356 const ScreenSet& layout)
357{
Pierre Ossman504afa22015-11-12 12:21:58 +0100358 decoder.flush();
359
Pierre Ossman3da238d2015-11-12 12:20:05 +0100360 CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200361
362 if (continuousUpdates)
363 writer()->writeEnableContinuousUpdates(true, 0, 0,
364 server.width(),
365 server.height());
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200366
367 resizeFramebuffer();
368 assert(framebuffer != NULL);
369 assert(framebuffer->width() == server.width());
370 assert(framebuffer->height() == server.height());
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200371}
372
373void CConnection::endOfContinuousUpdates()
374{
375 CMsgHandler::endOfContinuousUpdates();
376
377 // We've gotten the marker for a format change, so make the pending
378 // one active
379 if (pendingPFChange) {
380 server.setPF(pendingPF);
381 pendingPFChange = false;
382
383 // We might have another change pending
384 if (formatChange)
385 requestNewUpdate();
386 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100387}
388
Pierre Ossmandd45b442018-10-31 17:08:59 +0100389void CConnection::serverInit(int width, int height,
390 const PixelFormat& pf,
391 const char* name)
Pierre Ossman2affd772018-06-20 07:03:10 +0200392{
Pierre Ossmandd45b442018-10-31 17:08:59 +0100393 CMsgHandler::serverInit(width, height, pf, name);
394
Pierre Ossman2affd772018-06-20 07:03:10 +0200395 state_ = RFBSTATE_NORMAL;
396 vlog.debug("initialisation done");
397
398 initDone();
Pierre Ossmandd45b442018-10-31 17:08:59 +0100399 assert(framebuffer != NULL);
400 assert(framebuffer->width() == server.width());
401 assert(framebuffer->height() == server.height());
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200402
403 // We want to make sure we call SetEncodings at least once
404 encodingChange = true;
405
406 requestNewUpdate();
407
408 // This initial update request is a bit of a corner case, so we need
409 // to help out setting the correct format here.
410 if (pendingPFChange) {
411 server.setPF(pendingPF);
412 pendingPFChange = false;
413 }
Pierre Ossman2affd772018-06-20 07:03:10 +0200414}
415
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100416void CConnection::readAndDecodeRect(const Rect& r, int encoding,
417 ModifiablePixelBuffer* pb)
418{
419 decoder.decodeRect(r, encoding, pb);
420 decoder.flush();
421}
422
Pierre Ossman3da238d2015-11-12 12:20:05 +0100423void CConnection::framebufferUpdateStart()
424{
425 CMsgHandler::framebufferUpdateStart();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200426
427 assert(framebuffer != NULL);
428
429 // Note: This might not be true if continuous updates are supported
430 pendingUpdate = false;
431
432 requestNewUpdate();
Pierre Ossman3da238d2015-11-12 12:20:05 +0100433}
434
435void CConnection::framebufferUpdateEnd()
436{
Pierre Ossman504afa22015-11-12 12:21:58 +0100437 decoder.flush();
438
Pierre Ossman3da238d2015-11-12 12:20:05 +0100439 CMsgHandler::framebufferUpdateEnd();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200440
441 // A format change has been scheduled and we are now past the update
442 // with the old format. Time to active the new one.
443 if (pendingPFChange && !continuousUpdates) {
444 server.setPF(pendingPF);
445 pendingPFChange = false;
446 }
447
448 if (firstUpdate) {
449 if (server.supportsContinuousUpdates) {
450 vlog.info("Enabling continuous updates");
451 continuousUpdates = true;
452 writer()->writeEnableContinuousUpdates(true, 0, 0,
453 server.width(),
454 server.height());
455 }
456
457 firstUpdate = false;
458 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100459}
460
Pierre Ossman9f273e92015-11-09 16:34:54 +0100461void CConnection::dataRect(const Rect& r, int encoding)
462{
463 decoder.decodeRect(r, encoding, framebuffer);
464}
465
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000466void CConnection::authSuccess()
467{
468}
469
Pierre Ossman2affd772018-06-20 07:03:10 +0200470void CConnection::initDone()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000471{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000472}
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000473
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200474void CConnection::resizeFramebuffer()
475{
476 assert(false);
477}
478
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200479void CConnection::refreshFramebuffer()
480{
481 forceNonincremental = true;
482
483 // Without continuous updates we have to make sure we only have a
484 // single update in flight, so we'll have to wait to do the refresh
485 if (continuousUpdates)
486 requestNewUpdate();
487}
488
489void CConnection::setPreferredEncoding(int encoding)
490{
491 if (preferredEncoding == encoding)
492 return;
493
494 preferredEncoding = encoding;
495 encodingChange = true;
496}
497
498int CConnection::getPreferredEncoding()
499{
500 return preferredEncoding;
501}
502
503void CConnection::setCompressLevel(int level)
504{
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200505 if (compressLevel == level)
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200506 return;
507
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200508 compressLevel = level;
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200509 encodingChange = true;
510}
511
512void CConnection::setQualityLevel(int level)
513{
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200514 if (qualityLevel == level)
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200515 return;
516
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200517 qualityLevel = level;
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200518 encodingChange = true;
519}
520
521void CConnection::setPF(const PixelFormat& pf)
522{
523 if (server.pf().equal(pf) && !formatChange)
524 return;
525
526 nextPF = pf;
527 formatChange = true;
528}
529
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000530void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
531{
532 CMsgHandler::fence(flags, len, data);
533
534 if (!(flags & fenceFlagRequest))
535 return;
536
537 // We cannot guarantee any synchronisation at this level
538 flags = 0;
539
540 writer()->writeFence(flags, len, data);
541}
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200542
543// requestNewUpdate() requests an update from the server, having set the
544// format and encoding appropriately.
545void CConnection::requestNewUpdate()
546{
547 if (formatChange && !pendingPFChange) {
548 /* Catch incorrect requestNewUpdate calls */
549 assert(!pendingUpdate || continuousUpdates);
550
551 // We have to make sure we switch the internal format at a safe
552 // time. For continuous updates we temporarily disable updates and
553 // look for a EndOfContinuousUpdates message to see when to switch.
554 // For classical updates we just got a new update right before this
555 // function was called, so we need to make sure we finish that
556 // update before we can switch.
557
558 pendingPFChange = true;
559 pendingPF = nextPF;
560
561 if (continuousUpdates)
562 writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
563
564 writer()->writeSetPixelFormat(pendingPF);
565
566 if (continuousUpdates)
567 writer()->writeEnableContinuousUpdates(true, 0, 0,
568 server.width(),
569 server.height());
570
571 formatChange = false;
572 }
573
574 if (encodingChange) {
Pierre Ossman96728352018-06-20 11:35:05 +0200575 updateEncodings();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200576 encodingChange = false;
577 }
578
579 if (forceNonincremental || !continuousUpdates) {
580 pendingUpdate = true;
581 writer()->writeFramebufferUpdateRequest(Rect(0, 0,
582 server.width(),
583 server.height()),
584 !forceNonincremental);
585 }
586
587 forceNonincremental = false;
588}
Pierre Ossman96728352018-06-20 11:35:05 +0200589
590// Ask for encodings based on which decoders are supported. Assumes higher
591// encoding numbers are more desirable.
592
593void CConnection::updateEncodings()
594{
Pierre Ossman1143ee62018-06-20 11:40:37 +0200595 std::list<rdr::U32> encodings;
Pierre Ossman96728352018-06-20 11:35:05 +0200596
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200597 if (supportsLocalCursor) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200598 encodings.push_back(pseudoEncodingCursorWithAlpha);
599 encodings.push_back(pseudoEncodingCursor);
600 encodings.push_back(pseudoEncodingXCursor);
Pierre Ossman96728352018-06-20 11:35:05 +0200601 }
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200602 if (supportsDesktopResize) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200603 encodings.push_back(pseudoEncodingDesktopSize);
Pierre Ossman1143ee62018-06-20 11:40:37 +0200604 encodings.push_back(pseudoEncodingExtendedDesktopSize);
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200605 }
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200606 if (supportsLEDState)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200607 encodings.push_back(pseudoEncodingLEDState);
Pierre Ossman96728352018-06-20 11:35:05 +0200608
Pierre Ossman5588f4f2018-06-20 11:48:17 +0200609 encodings.push_back(pseudoEncodingDesktopName);
Pierre Ossman1143ee62018-06-20 11:40:37 +0200610 encodings.push_back(pseudoEncodingLastRect);
611 encodings.push_back(pseudoEncodingContinuousUpdates);
612 encodings.push_back(pseudoEncodingFence);
613 encodings.push_back(pseudoEncodingQEMUKeyEvent);
Pierre Ossman96728352018-06-20 11:35:05 +0200614
615 if (Decoder::supported(preferredEncoding)) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200616 encodings.push_back(preferredEncoding);
Pierre Ossman96728352018-06-20 11:35:05 +0200617 }
618
Pierre Ossman1143ee62018-06-20 11:40:37 +0200619 encodings.push_back(encodingCopyRect);
Pierre Ossman96728352018-06-20 11:35:05 +0200620
Pierre Ossman96728352018-06-20 11:35:05 +0200621 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman3bbe8d72018-06-20 11:42:36 +0200622 if ((i != preferredEncoding) && Decoder::supported(i))
623 encodings.push_back(i);
Pierre Ossman96728352018-06-20 11:35:05 +0200624 }
625
Pierre Ossmanb03512c2018-06-20 16:03:23 +0200626 if (compressLevel >= 0 && compressLevel <= 9)
627 encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel);
628 if (qualityLevel >= 0 && qualityLevel <= 9)
629 encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel);
Pierre Ossman96728352018-06-20 11:35:05 +0200630
Pierre Ossman1143ee62018-06-20 11:40:37 +0200631 writer()->writeSetEncodings(encodings);
Pierre Ossman96728352018-06-20 11:35:05 +0200632}