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

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