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

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