You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CConnection.cxx 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2019 Pierre Ossman for Cendio AB
  3. *
  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. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <rfb/Exception.h>
  26. #include <rfb/clipboardTypes.h>
  27. #include <rfb/fenceTypes.h>
  28. #include <rfb/CMsgReader.h>
  29. #include <rfb/CMsgWriter.h>
  30. #include <rfb/CSecurity.h>
  31. #include <rfb/Decoder.h>
  32. #include <rfb/KeysymStr.h>
  33. #include <rfb/Security.h>
  34. #include <rfb/SecurityClient.h>
  35. #include <rfb/CConnection.h>
  36. #include <rfb/util.h>
  37. #include <rfb/LogWriter.h>
  38. #include <rdr/InStream.h>
  39. #include <rdr/OutStream.h>
  40. using namespace rfb;
  41. static LogWriter vlog("CConnection");
  42. CConnection::CConnection()
  43. : csecurity(0),
  44. supportsLocalCursor(false), supportsCursorPosition(false),
  45. supportsDesktopResize(false), supportsLEDState(false),
  46. is(0), os(0), reader_(0), writer_(0),
  47. shared(false),
  48. state_(RFBSTATE_UNINITIALISED),
  49. pendingPFChange(false), preferredEncoding(encodingTight),
  50. compressLevel(2), qualityLevel(-1),
  51. formatChange(false), encodingChange(false),
  52. firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
  53. forceNonincremental(true),
  54. framebuffer(NULL), decoder(this),
  55. hasRemoteClipboard(false), hasLocalClipboard(false)
  56. {
  57. }
  58. CConnection::~CConnection()
  59. {
  60. close();
  61. }
  62. void CConnection::setServerName(const char* name_)
  63. {
  64. if (name_ == NULL)
  65. name_ = "";
  66. serverName = name_;
  67. }
  68. void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  69. {
  70. is = is_;
  71. os = os_;
  72. }
  73. void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
  74. {
  75. decoder.flush();
  76. if (fb) {
  77. assert(fb->width() == server.width());
  78. assert(fb->height() == server.height());
  79. }
  80. if ((framebuffer != NULL) && (fb != NULL)) {
  81. Rect rect;
  82. const uint8_t* data;
  83. int stride;
  84. const uint8_t black[4] = { 0, 0, 0, 0 };
  85. // Copy still valid area
  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. // Black out any new areas
  92. if (fb->width() > framebuffer->width()) {
  93. rect.setXYWH(framebuffer->width(), 0,
  94. fb->width() - framebuffer->width(),
  95. fb->height());
  96. fb->fillRect(rect, black);
  97. }
  98. if (fb->height() > framebuffer->height()) {
  99. rect.setXYWH(0, framebuffer->height(),
  100. fb->width(),
  101. fb->height() - framebuffer->height());
  102. fb->fillRect(rect, black);
  103. }
  104. }
  105. delete framebuffer;
  106. framebuffer = fb;
  107. }
  108. void CConnection::initialiseProtocol()
  109. {
  110. state_ = RFBSTATE_PROTOCOL_VERSION;
  111. }
  112. bool CConnection::processMsg()
  113. {
  114. switch (state_) {
  115. case RFBSTATE_PROTOCOL_VERSION: return processVersionMsg(); break;
  116. case RFBSTATE_SECURITY_TYPES: return processSecurityTypesMsg(); break;
  117. case RFBSTATE_SECURITY: return processSecurityMsg(); break;
  118. case RFBSTATE_SECURITY_RESULT: return processSecurityResultMsg(); break;
  119. case RFBSTATE_SECURITY_REASON: return processSecurityReasonMsg(); break;
  120. case RFBSTATE_INITIALISATION: return processInitMsg(); break;
  121. case RFBSTATE_NORMAL: return reader_->readMsg(); break;
  122. case RFBSTATE_CLOSING:
  123. throw Exception("CConnection::processMsg: called while closing");
  124. case RFBSTATE_UNINITIALISED:
  125. throw Exception("CConnection::processMsg: not initialised yet?");
  126. default:
  127. throw Exception("CConnection::processMsg: invalid state");
  128. }
  129. }
  130. bool CConnection::processVersionMsg()
  131. {
  132. char verStr[27]; // FIXME: gcc has some bug in format-overflow
  133. int majorVersion;
  134. int minorVersion;
  135. vlog.debug("reading protocol version");
  136. if (!is->hasData(12))
  137. return false;
  138. is->readBytes((uint8_t*)verStr, 12);
  139. verStr[12] = '\0';
  140. if (sscanf(verStr, "RFB %03d.%03d\n",
  141. &majorVersion, &minorVersion) != 2) {
  142. state_ = RFBSTATE_INVALID;
  143. throw Exception("reading version failed: not an RFB server?");
  144. }
  145. server.setVersion(majorVersion, minorVersion);
  146. vlog.info("Server supports RFB protocol version %d.%d",
  147. server.majorVersion, server.minorVersion);
  148. // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
  149. if (server.beforeVersion(3,3)) {
  150. vlog.error("Server gave unsupported RFB protocol version %d.%d",
  151. server.majorVersion, server.minorVersion);
  152. state_ = RFBSTATE_INVALID;
  153. throw Exception("Server gave unsupported RFB protocol version %d.%d",
  154. server.majorVersion, server.minorVersion);
  155. } else if (server.beforeVersion(3,7)) {
  156. server.setVersion(3,3);
  157. } else if (server.afterVersion(3,8)) {
  158. server.setVersion(3,8);
  159. }
  160. sprintf(verStr, "RFB %03d.%03d\n",
  161. server.majorVersion, server.minorVersion);
  162. os->writeBytes((const uint8_t*)verStr, 12);
  163. os->flush();
  164. state_ = RFBSTATE_SECURITY_TYPES;
  165. vlog.info("Using RFB protocol version %d.%d",
  166. server.majorVersion, server.minorVersion);
  167. return true;
  168. }
  169. bool CConnection::processSecurityTypesMsg()
  170. {
  171. vlog.debug("processing security types message");
  172. int secType = secTypeInvalid;
  173. std::list<uint8_t> secTypes;
  174. secTypes = security.GetEnabledSecTypes();
  175. if (server.isVersion(3,3)) {
  176. // legacy 3.3 server may only offer "vnc authentication" or "none"
  177. if (!is->hasData(4))
  178. return false;
  179. secType = is->readU32();
  180. if (secType == secTypeInvalid) {
  181. state_ = RFBSTATE_SECURITY_REASON;
  182. return true;
  183. } else if (secType == secTypeNone || secType == secTypeVncAuth) {
  184. std::list<uint8_t>::iterator i;
  185. for (i = secTypes.begin(); i != secTypes.end(); i++)
  186. if (*i == secType) {
  187. secType = *i;
  188. break;
  189. }
  190. if (i == secTypes.end())
  191. secType = secTypeInvalid;
  192. } else {
  193. vlog.error("Unknown 3.3 security type %d", secType);
  194. throw Exception("Unknown 3.3 security type");
  195. }
  196. } else {
  197. // >=3.7 server will offer us a list
  198. if (!is->hasData(1))
  199. return false;
  200. is->setRestorePoint();
  201. int nServerSecTypes = is->readU8();
  202. if (!is->hasDataOrRestore(nServerSecTypes))
  203. return false;
  204. is->clearRestorePoint();
  205. if (nServerSecTypes == 0) {
  206. state_ = RFBSTATE_SECURITY_REASON;
  207. return true;
  208. }
  209. std::list<uint8_t>::iterator j;
  210. for (int i = 0; i < nServerSecTypes; i++) {
  211. uint8_t serverSecType = is->readU8();
  212. vlog.debug("Server offers security type %s(%d)",
  213. secTypeName(serverSecType), serverSecType);
  214. /*
  215. * Use the first type sent by server which matches client's type.
  216. * It means server's order specifies priority.
  217. */
  218. if (secType == secTypeInvalid) {
  219. for (j = secTypes.begin(); j != secTypes.end(); j++)
  220. if (*j == serverSecType) {
  221. secType = *j;
  222. break;
  223. }
  224. }
  225. }
  226. // Inform the server of our decision
  227. if (secType != secTypeInvalid) {
  228. os->writeU8(secType);
  229. os->flush();
  230. vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
  231. }
  232. }
  233. if (secType == secTypeInvalid) {
  234. state_ = RFBSTATE_INVALID;
  235. vlog.error("No matching security types");
  236. throw Exception("No matching security types");
  237. }
  238. state_ = RFBSTATE_SECURITY;
  239. csecurity = security.GetCSecurity(this, secType);
  240. return true;
  241. }
  242. bool CConnection::processSecurityMsg()
  243. {
  244. vlog.debug("processing security message");
  245. if (!csecurity->processMsg())
  246. return false;
  247. state_ = RFBSTATE_SECURITY_RESULT;
  248. return true;
  249. }
  250. bool CConnection::processSecurityResultMsg()
  251. {
  252. vlog.debug("processing security result message");
  253. int result;
  254. if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
  255. result = secResultOK;
  256. } else {
  257. if (!is->hasData(4))
  258. return false;
  259. result = is->readU32();
  260. }
  261. switch (result) {
  262. case secResultOK:
  263. securityCompleted();
  264. return true;
  265. case secResultFailed:
  266. vlog.debug("auth failed");
  267. break;
  268. case secResultTooMany:
  269. vlog.debug("auth failed - too many tries");
  270. break;
  271. default:
  272. throw Exception("Unknown security result from server");
  273. }
  274. if (server.beforeVersion(3,8)) {
  275. state_ = RFBSTATE_INVALID;
  276. throw AuthFailureException();
  277. }
  278. state_ = RFBSTATE_SECURITY_REASON;
  279. return true;
  280. }
  281. bool CConnection::processSecurityReasonMsg()
  282. {
  283. vlog.debug("processing security reason message");
  284. if (!is->hasData(4))
  285. return false;
  286. is->setRestorePoint();
  287. uint32_t len = is->readU32();
  288. if (!is->hasDataOrRestore(len))
  289. return false;
  290. is->clearRestorePoint();
  291. std::vector<char> reason(len + 1);
  292. is->readBytes((uint8_t*)reason.data(), len);
  293. reason[len] = '\0';
  294. state_ = RFBSTATE_INVALID;
  295. throw AuthFailureException(reason.data());
  296. }
  297. bool CConnection::processInitMsg()
  298. {
  299. vlog.debug("reading server initialisation");
  300. return reader_->readServerInit();
  301. }
  302. void CConnection::securityCompleted()
  303. {
  304. state_ = RFBSTATE_INITIALISATION;
  305. reader_ = new CMsgReader(this, is);
  306. writer_ = new CMsgWriter(&server, os);
  307. vlog.debug("Authentication success!");
  308. authSuccess();
  309. writer_->writeClientInit(shared);
  310. }
  311. void CConnection::close()
  312. {
  313. state_ = RFBSTATE_CLOSING;
  314. /*
  315. * We're already shutting down, so just log any pending decoder
  316. * problems
  317. */
  318. try {
  319. decoder.flush();
  320. } catch (rdr::Exception& e) {
  321. vlog.error("%s", e.str());
  322. }
  323. setFramebuffer(NULL);
  324. delete csecurity;
  325. csecurity = NULL;
  326. delete reader_;
  327. reader_ = NULL;
  328. delete writer_;
  329. writer_ = NULL;
  330. }
  331. void CConnection::setDesktopSize(int w, int h)
  332. {
  333. decoder.flush();
  334. CMsgHandler::setDesktopSize(w,h);
  335. if (continuousUpdates)
  336. writer()->writeEnableContinuousUpdates(true, 0, 0,
  337. server.width(),
  338. server.height());
  339. resizeFramebuffer();
  340. assert(framebuffer != NULL);
  341. assert(framebuffer->width() == server.width());
  342. assert(framebuffer->height() == server.height());
  343. }
  344. void CConnection::setExtendedDesktopSize(unsigned reason,
  345. unsigned result,
  346. int w, int h,
  347. const ScreenSet& layout)
  348. {
  349. decoder.flush();
  350. CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
  351. if (continuousUpdates)
  352. writer()->writeEnableContinuousUpdates(true, 0, 0,
  353. server.width(),
  354. server.height());
  355. resizeFramebuffer();
  356. assert(framebuffer != NULL);
  357. assert(framebuffer->width() == server.width());
  358. assert(framebuffer->height() == server.height());
  359. }
  360. void CConnection::endOfContinuousUpdates()
  361. {
  362. CMsgHandler::endOfContinuousUpdates();
  363. // We've gotten the marker for a format change, so make the pending
  364. // one active
  365. if (pendingPFChange) {
  366. server.setPF(pendingPF);
  367. pendingPFChange = false;
  368. // We might have another change pending
  369. if (formatChange)
  370. requestNewUpdate();
  371. }
  372. }
  373. void CConnection::serverInit(int width, int height,
  374. const PixelFormat& pf,
  375. const char* name)
  376. {
  377. CMsgHandler::serverInit(width, height, pf, name);
  378. state_ = RFBSTATE_NORMAL;
  379. vlog.debug("initialisation done");
  380. initDone();
  381. assert(framebuffer != NULL);
  382. assert(framebuffer->width() == server.width());
  383. assert(framebuffer->height() == server.height());
  384. // We want to make sure we call SetEncodings at least once
  385. encodingChange = true;
  386. requestNewUpdate();
  387. // This initial update request is a bit of a corner case, so we need
  388. // to help out setting the correct format here.
  389. if (pendingPFChange) {
  390. server.setPF(pendingPF);
  391. pendingPFChange = false;
  392. }
  393. }
  394. bool CConnection::readAndDecodeRect(const Rect& r, int encoding,
  395. ModifiablePixelBuffer* pb)
  396. {
  397. if (!decoder.decodeRect(r, encoding, pb))
  398. return false;
  399. decoder.flush();
  400. return true;
  401. }
  402. void CConnection::framebufferUpdateStart()
  403. {
  404. CMsgHandler::framebufferUpdateStart();
  405. assert(framebuffer != NULL);
  406. // Note: This might not be true if continuous updates are supported
  407. pendingUpdate = false;
  408. requestNewUpdate();
  409. }
  410. void CConnection::framebufferUpdateEnd()
  411. {
  412. decoder.flush();
  413. CMsgHandler::framebufferUpdateEnd();
  414. // A format change has been scheduled and we are now past the update
  415. // with the old format. Time to active the new one.
  416. if (pendingPFChange && !continuousUpdates) {
  417. server.setPF(pendingPF);
  418. pendingPFChange = false;
  419. }
  420. if (firstUpdate) {
  421. if (server.supportsContinuousUpdates) {
  422. vlog.info("Enabling continuous updates");
  423. continuousUpdates = true;
  424. writer()->writeEnableContinuousUpdates(true, 0, 0,
  425. server.width(),
  426. server.height());
  427. }
  428. firstUpdate = false;
  429. }
  430. }
  431. bool CConnection::dataRect(const Rect& r, int encoding)
  432. {
  433. return decoder.decodeRect(r, encoding, framebuffer);
  434. }
  435. void CConnection::serverCutText(const char* str)
  436. {
  437. hasLocalClipboard = false;
  438. serverClipboard = str;
  439. hasRemoteClipboard = true;
  440. handleClipboardAnnounce(true);
  441. }
  442. void CConnection::handleClipboardCaps(uint32_t flags,
  443. const uint32_t* lengths)
  444. {
  445. uint32_t sizes[] = { 0 };
  446. CMsgHandler::handleClipboardCaps(flags, lengths);
  447. writer()->writeClipboardCaps(rfb::clipboardUTF8 |
  448. rfb::clipboardRequest |
  449. rfb::clipboardPeek |
  450. rfb::clipboardNotify |
  451. rfb::clipboardProvide,
  452. sizes);
  453. }
  454. void CConnection::handleClipboardRequest(uint32_t flags)
  455. {
  456. if (!(flags & rfb::clipboardUTF8)) {
  457. vlog.debug("Ignoring clipboard request for unsupported formats 0x%x", flags);
  458. return;
  459. }
  460. if (!hasLocalClipboard) {
  461. vlog.debug("Ignoring unexpected clipboard request");
  462. return;
  463. }
  464. handleClipboardRequest();
  465. }
  466. void CConnection::handleClipboardPeek()
  467. {
  468. if (server.clipboardFlags() & rfb::clipboardNotify)
  469. writer()->writeClipboardNotify(hasLocalClipboard ? rfb::clipboardUTF8 : 0);
  470. }
  471. void CConnection::handleClipboardNotify(uint32_t flags)
  472. {
  473. hasRemoteClipboard = false;
  474. if (flags & rfb::clipboardUTF8) {
  475. hasLocalClipboard = false;
  476. handleClipboardAnnounce(true);
  477. } else {
  478. handleClipboardAnnounce(false);
  479. }
  480. }
  481. void CConnection::handleClipboardProvide(uint32_t flags,
  482. const size_t* lengths,
  483. const uint8_t* const* data)
  484. {
  485. if (!(flags & rfb::clipboardUTF8)) {
  486. vlog.debug("Ignoring clipboard provide with unsupported formats 0x%x", flags);
  487. return;
  488. }
  489. // FIXME: This conversion magic should be in CMsgReader
  490. if (!isValidUTF8((const char*)data[0], lengths[0])) {
  491. vlog.error("Invalid UTF-8 sequence in clipboard - ignoring");
  492. return;
  493. }
  494. serverClipboard = convertLF((const char*)data[0], lengths[0]);
  495. hasRemoteClipboard = true;
  496. // FIXME: Should probably verify that this data was actually requested
  497. handleClipboardData(serverClipboard.c_str());
  498. }
  499. void CConnection::authSuccess()
  500. {
  501. }
  502. void CConnection::initDone()
  503. {
  504. }
  505. void CConnection::resizeFramebuffer()
  506. {
  507. assert(false);
  508. }
  509. void CConnection::handleClipboardRequest()
  510. {
  511. }
  512. void CConnection::handleClipboardAnnounce(bool /*available*/)
  513. {
  514. }
  515. void CConnection::handleClipboardData(const char* /*data*/)
  516. {
  517. }
  518. void CConnection::requestClipboard()
  519. {
  520. if (hasRemoteClipboard) {
  521. handleClipboardData(serverClipboard.c_str());
  522. return;
  523. }
  524. if (server.clipboardFlags() & rfb::clipboardRequest)
  525. writer()->writeClipboardRequest(rfb::clipboardUTF8);
  526. }
  527. void CConnection::announceClipboard(bool available)
  528. {
  529. hasLocalClipboard = available;
  530. unsolicitedClipboardAttempt = false;
  531. // Attempt an unsolicited transfer?
  532. if (available &&
  533. (server.clipboardSize(rfb::clipboardUTF8) > 0) &&
  534. (server.clipboardFlags() & rfb::clipboardProvide)) {
  535. vlog.debug("Attempting unsolicited clipboard transfer...");
  536. unsolicitedClipboardAttempt = true;
  537. handleClipboardRequest();
  538. return;
  539. }
  540. if (server.clipboardFlags() & rfb::clipboardNotify) {
  541. writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
  542. return;
  543. }
  544. if (available)
  545. handleClipboardRequest();
  546. }
  547. void CConnection::sendClipboardData(const char* data)
  548. {
  549. if (server.clipboardFlags() & rfb::clipboardProvide) {
  550. // FIXME: This conversion magic should be in CMsgWriter
  551. std::string filtered(convertCRLF(data));
  552. size_t sizes[1] = { filtered.size() + 1 };
  553. const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() };
  554. if (unsolicitedClipboardAttempt) {
  555. unsolicitedClipboardAttempt = false;
  556. if (sizes[0] > server.clipboardSize(rfb::clipboardUTF8)) {
  557. vlog.debug("Clipboard was too large for unsolicited clipboard transfer");
  558. if (server.clipboardFlags() & rfb::clipboardNotify)
  559. writer()->writeClipboardNotify(rfb::clipboardUTF8);
  560. return;
  561. }
  562. }
  563. writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
  564. } else {
  565. writer()->writeClientCutText(data);
  566. }
  567. }
  568. void CConnection::refreshFramebuffer()
  569. {
  570. forceNonincremental = true;
  571. // Without continuous updates we have to make sure we only have a
  572. // single update in flight, so we'll have to wait to do the refresh
  573. if (continuousUpdates)
  574. requestNewUpdate();
  575. }
  576. void CConnection::setPreferredEncoding(int encoding)
  577. {
  578. if (preferredEncoding == encoding)
  579. return;
  580. preferredEncoding = encoding;
  581. encodingChange = true;
  582. }
  583. int CConnection::getPreferredEncoding()
  584. {
  585. return preferredEncoding;
  586. }
  587. void CConnection::setCompressLevel(int level)
  588. {
  589. if (compressLevel == level)
  590. return;
  591. compressLevel = level;
  592. encodingChange = true;
  593. }
  594. void CConnection::setQualityLevel(int level)
  595. {
  596. if (qualityLevel == level)
  597. return;
  598. qualityLevel = level;
  599. encodingChange = true;
  600. }
  601. void CConnection::setPF(const PixelFormat& pf)
  602. {
  603. if (server.pf() == pf && !formatChange)
  604. return;
  605. nextPF = pf;
  606. formatChange = true;
  607. }
  608. void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[])
  609. {
  610. CMsgHandler::fence(flags, len, data);
  611. if (!(flags & fenceFlagRequest))
  612. return;
  613. // We cannot guarantee any synchronisation at this level
  614. flags = 0;
  615. writer()->writeFence(flags, len, data);
  616. }
  617. // requestNewUpdate() requests an update from the server, having set the
  618. // format and encoding appropriately.
  619. void CConnection::requestNewUpdate()
  620. {
  621. if (formatChange && !pendingPFChange) {
  622. /* Catch incorrect requestNewUpdate calls */
  623. assert(!pendingUpdate || continuousUpdates);
  624. // We have to make sure we switch the internal format at a safe
  625. // time. For continuous updates we temporarily disable updates and
  626. // look for a EndOfContinuousUpdates message to see when to switch.
  627. // For classical updates we just got a new update right before this
  628. // function was called, so we need to make sure we finish that
  629. // update before we can switch.
  630. pendingPFChange = true;
  631. pendingPF = nextPF;
  632. if (continuousUpdates)
  633. writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
  634. writer()->writeSetPixelFormat(pendingPF);
  635. if (continuousUpdates)
  636. writer()->writeEnableContinuousUpdates(true, 0, 0,
  637. server.width(),
  638. server.height());
  639. formatChange = false;
  640. }
  641. if (encodingChange) {
  642. updateEncodings();
  643. encodingChange = false;
  644. }
  645. if (forceNonincremental || !continuousUpdates) {
  646. pendingUpdate = true;
  647. writer()->writeFramebufferUpdateRequest(Rect(0, 0,
  648. server.width(),
  649. server.height()),
  650. !forceNonincremental);
  651. }
  652. forceNonincremental = false;
  653. }
  654. // Ask for encodings based on which decoders are supported. Assumes higher
  655. // encoding numbers are more desirable.
  656. void CConnection::updateEncodings()
  657. {
  658. std::list<uint32_t> encodings;
  659. if (supportsLocalCursor) {
  660. encodings.push_back(pseudoEncodingCursorWithAlpha);
  661. encodings.push_back(pseudoEncodingVMwareCursor);
  662. encodings.push_back(pseudoEncodingCursor);
  663. encodings.push_back(pseudoEncodingXCursor);
  664. }
  665. if (supportsCursorPosition) {
  666. encodings.push_back(pseudoEncodingVMwareCursorPosition);
  667. }
  668. if (supportsDesktopResize) {
  669. encodings.push_back(pseudoEncodingDesktopSize);
  670. encodings.push_back(pseudoEncodingExtendedDesktopSize);
  671. }
  672. if (supportsLEDState) {
  673. encodings.push_back(pseudoEncodingLEDState);
  674. encodings.push_back(pseudoEncodingVMwareLEDState);
  675. }
  676. encodings.push_back(pseudoEncodingDesktopName);
  677. encodings.push_back(pseudoEncodingLastRect);
  678. encodings.push_back(pseudoEncodingExtendedClipboard);
  679. encodings.push_back(pseudoEncodingContinuousUpdates);
  680. encodings.push_back(pseudoEncodingFence);
  681. encodings.push_back(pseudoEncodingQEMUKeyEvent);
  682. if (Decoder::supported(preferredEncoding)) {
  683. encodings.push_back(preferredEncoding);
  684. }
  685. encodings.push_back(encodingCopyRect);
  686. for (int i = encodingMax; i >= 0; i--) {
  687. if ((i != preferredEncoding) && Decoder::supported(i))
  688. encodings.push_back(i);
  689. }
  690. if (compressLevel >= 0 && compressLevel <= 9)
  691. encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel);
  692. if (qualityLevel >= 0 && qualityLevel <= 9)
  693. encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel);
  694. writer()->writeSetEncodings(encodings);
  695. }