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.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2011-2019 Brian P. Hinz
  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  17. * USA.
  18. */
  19. package com.tigervnc.rfb;
  20. import java.awt.color.*;
  21. import java.awt.image.*;
  22. import java.nio.*;
  23. import java.util.*;
  24. import java.util.concurrent.atomic.AtomicBoolean;
  25. import com.tigervnc.network.*;
  26. import com.tigervnc.rdr.*;
  27. abstract public class CConnection extends CMsgHandler {
  28. static LogWriter vlog = new LogWriter("CConnection");
  29. private static final String osName =
  30. System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
  31. public CConnection()
  32. {
  33. super();
  34. csecurity = null;
  35. supportsLocalCursor = false; supportsDesktopResize = false;
  36. is = null; os = null; reader_ = null; writer_ = null;
  37. shared = false;
  38. state_ = stateEnum.RFBSTATE_UNINITIALISED;
  39. pendingPFChange = false; preferredEncoding = Encodings.encodingTight;
  40. compressLevel = 2; qualityLevel = -1;
  41. formatChange = false; encodingChange = false;
  42. firstUpdate = true; pendingUpdate = false; continuousUpdates = false;
  43. forceNonincremental = true;
  44. framebuffer = null; decoder = new DecodeManager(this);
  45. security = new SecurityClient();
  46. }
  47. // Methods to initialise the connection
  48. // setServerName() is used to provide a unique(ish) name for the server to
  49. // which we are connected. This might be the result of getPeerEndpoint on
  50. // a TcpSocket, for example, or a host specified by DNS name & port.
  51. // The serverName is used when verifying the Identity of a host (see RA2).
  52. public void setServerName(String name_) { serverName = name_; }
  53. public void setServerPort(int port_) { serverPort = port_; }
  54. // setStreams() sets the streams to be used for the connection. These must
  55. // be set before initialiseProtocol() and processMsg() are called. The
  56. // CSecurity object may call setStreams() again to provide alternative
  57. // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
  58. // streams). Ownership of the streams remains with the caller
  59. // (i.e. SConnection will not delete them).
  60. public final void setStreams(InStream is_, OutStream os_)
  61. {
  62. is = is_;
  63. os = os_;
  64. }
  65. // setShared sets the value of the shared flag which will be sent to the
  66. // server upon initialisation.
  67. public final void setShared(boolean s) { shared = s; }
  68. // setFramebuffer configures the PixelBuffer that the CConnection
  69. // should render all pixel data in to. Note that the CConnection
  70. // takes ownership of the PixelBuffer and it must not be deleted by
  71. // anyone else. Call setFramebuffer again with NULL or a different
  72. // PixelBuffer to delete the previous one.
  73. public void setFramebuffer(ModifiablePixelBuffer fb)
  74. {
  75. decoder.flush();
  76. if (fb != null) {
  77. assert(fb.width() == server.width());
  78. assert(fb.height() == server.height());
  79. }
  80. if ((framebuffer != null) && (fb != null)) {
  81. Rect rect = new Rect();
  82. Raster data;
  83. byte[] black = new byte[4];
  84. // Copy still valid area
  85. rect.setXYWH(0, 0,
  86. Math.min(fb.width(), framebuffer.width()),
  87. Math.min(fb.height(), framebuffer.height()));
  88. data = framebuffer.getBuffer(rect);
  89. fb.imageRect(framebuffer.getPF(), rect, data);
  90. // Black out any new areas
  91. if (fb.width() > framebuffer.width()) {
  92. rect.setXYWH(framebuffer.width(), 0,
  93. fb.width() - framebuffer.width(),
  94. fb.height());
  95. fb.fillRect(rect, black);
  96. }
  97. if (fb.height() > framebuffer.height()) {
  98. rect.setXYWH(0, framebuffer.height(),
  99. fb.width(),
  100. fb.height() - framebuffer.height());
  101. fb.fillRect(rect, black);
  102. }
  103. }
  104. framebuffer = fb;
  105. }
  106. // initialiseProtocol() should be called once the streams and security
  107. // types are set. Subsequently, processMsg() should be called whenever
  108. // there is data to read on the InStream.
  109. public final void initialiseProtocol()
  110. {
  111. state_ = stateEnum.RFBSTATE_PROTOCOL_VERSION;
  112. }
  113. // processMsg() should be called whenever there is data to read on the
  114. // InStream. You must have called initialiseProtocol() first.
  115. public void processMsg()
  116. {
  117. switch (state_) {
  118. case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
  119. case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
  120. case RFBSTATE_SECURITY: processSecurityMsg(); break;
  121. case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
  122. case RFBSTATE_INITIALISATION: processInitMsg(); break;
  123. case RFBSTATE_NORMAL: reader_.readMsg(); break;
  124. case RFBSTATE_UNINITIALISED:
  125. throw new Exception("CConnection.processMsg: not initialised yet?");
  126. default:
  127. throw new Exception("CConnection.processMsg: invalid state");
  128. }
  129. }
  130. private void processVersionMsg()
  131. {
  132. ByteBuffer verStr = ByteBuffer.allocate(12);
  133. int majorVersion;
  134. int minorVersion;
  135. vlog.debug("reading protocol version");
  136. if (!is.checkNoWait(12))
  137. return;
  138. is.readBytes(verStr, 12);
  139. if ((new String(verStr.array())).matches("RFB \\d{3}\\.\\d{3}\\n")) {
  140. majorVersion =
  141. Integer.parseInt((new String(verStr.array())).substring(4,7));
  142. minorVersion =
  143. Integer.parseInt((new String(verStr.array())).substring(8,11));
  144. } else {
  145. state_ = stateEnum.RFBSTATE_INVALID;
  146. throw new Exception("reading version failed: not an RFB server?");
  147. }
  148. server.setVersion(majorVersion, minorVersion);
  149. vlog.info("Server supports RFB protocol version "
  150. +server.majorVersion+"."+ server.minorVersion);
  151. // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
  152. if (server.beforeVersion(3,3)) {
  153. String msg = ("Server gave unsupported RFB protocol version "+
  154. server.majorVersion+"."+server.minorVersion);
  155. vlog.error(msg);
  156. state_ = stateEnum.RFBSTATE_INVALID;
  157. throw new Exception(msg);
  158. } else if (server.beforeVersion(3,7)) {
  159. server.setVersion(3,3);
  160. } else if (server.afterVersion(3,8)) {
  161. server.setVersion(3,8);
  162. }
  163. verStr.clear();
  164. verStr.put(String.format("RFB %03d.%03d\n",
  165. majorVersion, minorVersion).getBytes()).flip();
  166. os.writeBytes(verStr.array(), 0, 12);
  167. os.flush();
  168. state_ = stateEnum.RFBSTATE_SECURITY_TYPES;
  169. vlog.info("Using RFB protocol version "+
  170. server.majorVersion+"."+server.minorVersion);
  171. }
  172. private void processSecurityTypesMsg()
  173. {
  174. vlog.debug("processing security types message");
  175. int secType = Security.secTypeInvalid;
  176. List<Integer> secTypes = new ArrayList<Integer>();
  177. secTypes = security.GetEnabledSecTypes();
  178. if (server.isVersion(3,3)) {
  179. // legacy 3.3 server may only offer "vnc authentication" or "none"
  180. secType = is.readU32();
  181. if (secType == Security.secTypeInvalid) {
  182. throwConnFailedException();
  183. } else if (secType == Security.secTypeNone || secType == Security.secTypeVncAuth) {
  184. Iterator<Integer> i;
  185. for (i = secTypes.iterator(); i.hasNext(); ) {
  186. int refType = (Integer)i.next();
  187. if (refType == secType) {
  188. secType = refType;
  189. break;
  190. }
  191. }
  192. if (!secTypes.contains(secType))
  193. secType = Security.secTypeInvalid;
  194. } else {
  195. vlog.error("Unknown 3.3 security type "+secType);
  196. throw new Exception("Unknown 3.3 security type");
  197. }
  198. } else {
  199. // 3.7 server will offer us a list
  200. int nServerSecTypes = is.readU8();
  201. if (nServerSecTypes == 0)
  202. throwConnFailedException();
  203. Iterator<Integer> j;
  204. for (int i = 0; i < nServerSecTypes; i++) {
  205. int serverSecType = is.readU8();
  206. vlog.debug("Server offers security type "+
  207. Security.secTypeName(serverSecType)+"("+serverSecType+")");
  208. /*
  209. * Use the first type sent by server which matches client's type.
  210. * It means server's order specifies priority.
  211. */
  212. if (secType == Security.secTypeInvalid) {
  213. for (j = secTypes.iterator(); j.hasNext(); ) {
  214. int refType = (Integer)j.next();
  215. if (refType == serverSecType) {
  216. secType = refType;
  217. break;
  218. }
  219. }
  220. }
  221. }
  222. // Inform the server of our decision
  223. if (secType != Security.secTypeInvalid) {
  224. os.writeU8(secType);
  225. os.flush();
  226. vlog.debug("Choosing security type "+Security.secTypeName(secType)+
  227. "("+secType+")");
  228. }
  229. }
  230. if (secType == Security.secTypeInvalid) {
  231. state_ = stateEnum.RFBSTATE_INVALID;
  232. vlog.error("No matching security types");
  233. throw new Exception("No matching security types");
  234. }
  235. state_ = stateEnum.RFBSTATE_SECURITY;
  236. csecurity = security.GetCSecurity(secType);
  237. processSecurityMsg();
  238. }
  239. private void processSecurityMsg() {
  240. vlog.debug("processing security message");
  241. if (csecurity.processMsg(this)) {
  242. state_ = stateEnum.RFBSTATE_SECURITY_RESULT;
  243. processSecurityResultMsg();
  244. }
  245. }
  246. private void processSecurityResultMsg() {
  247. vlog.debug("processing security result message");
  248. int result;
  249. if (server.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) {
  250. result = Security.secResultOK;
  251. } else {
  252. if (!is.checkNoWait(1)) return;
  253. result = is.readU32();
  254. }
  255. switch (result) {
  256. case Security.secResultOK:
  257. securityCompleted();
  258. return;
  259. case Security.secResultFailed:
  260. vlog.debug("auth failed");
  261. break;
  262. case Security.secResultTooMany:
  263. vlog.debug("auth failed - too many tries");
  264. break;
  265. default:
  266. throw new Exception("Unknown security result from server");
  267. }
  268. state_ = stateEnum.RFBSTATE_INVALID;
  269. if (server.beforeVersion(3,8))
  270. throw new AuthFailureException();
  271. String reason = is.readString();
  272. throw new AuthFailureException(reason);
  273. }
  274. private void processInitMsg() {
  275. vlog.debug("reading server initialisation");
  276. reader_.readServerInit();
  277. }
  278. private void throwConnFailedException() {
  279. state_ = stateEnum.RFBSTATE_INVALID;
  280. String reason;
  281. reason = is.readString();
  282. throw new ConnFailedException(reason);
  283. }
  284. private void securityCompleted() {
  285. state_ = stateEnum.RFBSTATE_INITIALISATION;
  286. reader_ = new CMsgReader(this, is);
  287. writer_ = new CMsgWriter(server, os);
  288. vlog.debug("Authentication success!");
  289. authSuccess();
  290. writer_.writeClientInit(shared);
  291. }
  292. // Methods overridden from CMsgHandler
  293. // Note: These must be called by any deriving classes
  294. public void setDesktopSize(int w, int h) {
  295. decoder.flush();
  296. super.setDesktopSize(w,h);
  297. if (continuousUpdates)
  298. writer().writeEnableContinuousUpdates(true, 0, 0,
  299. server.width(),
  300. server.height());
  301. resizeFramebuffer();
  302. assert(framebuffer != null);
  303. assert(framebuffer.width() == server.width());
  304. assert(framebuffer.height() == server.height());
  305. }
  306. public void setExtendedDesktopSize(int reason,
  307. int result,
  308. int w, int h,
  309. ScreenSet layout) {
  310. decoder.flush();
  311. super.setExtendedDesktopSize(reason, result, w, h, layout);
  312. if (continuousUpdates)
  313. writer().writeEnableContinuousUpdates(true, 0, 0,
  314. server.width(),
  315. server.height());
  316. resizeFramebuffer();
  317. assert(framebuffer != null);
  318. assert(framebuffer.width() == server.width());
  319. assert(framebuffer.height() == server.height());
  320. }
  321. public void endOfContinuousUpdates()
  322. {
  323. super.endOfContinuousUpdates();
  324. // We've gotten the marker for a format change, so make the pending
  325. // one active
  326. if (pendingPFChange) {
  327. server.setPF(pendingPF);
  328. pendingPFChange = false;
  329. // We might have another change pending
  330. if (formatChange)
  331. requestNewUpdate();
  332. }
  333. }
  334. // serverInit() is called when the ServerInit message is received. The
  335. // derived class must call on to CConnection::serverInit().
  336. public void serverInit(int width, int height,
  337. PixelFormat pf, String name)
  338. {
  339. super.serverInit(width, height, pf, name);
  340. state_ = stateEnum.RFBSTATE_NORMAL;
  341. vlog.debug("initialisation done");
  342. initDone();
  343. assert(framebuffer != null);
  344. // FIXME: even if the client is scaling?
  345. assert(framebuffer.width() == server.width());
  346. assert(framebuffer.height() == server.height());
  347. // We want to make sure we call SetEncodings at least once
  348. encodingChange = true;
  349. requestNewUpdate();
  350. // This initial update request is a bit of a corner case, so we need
  351. // to help out setting the correct format here.
  352. if (pendingPFChange) {
  353. server.setPF(pendingPF);
  354. pendingPFChange = false;
  355. }
  356. }
  357. public void readAndDecodeRect(Rect r, int encoding,
  358. ModifiablePixelBuffer pb)
  359. {
  360. decoder.decodeRect(r, encoding, pb);
  361. decoder.flush();
  362. }
  363. public void framebufferUpdateStart()
  364. {
  365. super.framebufferUpdateStart();
  366. assert(framebuffer != null);
  367. // Note: This might not be true if continuous updates are supported
  368. pendingUpdate = false;
  369. requestNewUpdate();
  370. }
  371. public void framebufferUpdateEnd()
  372. {
  373. decoder.flush();
  374. super.framebufferUpdateEnd();
  375. // A format change has been scheduled and we are now past the update
  376. // with the old format. Time to active the new one.
  377. if (pendingPFChange && !continuousUpdates) {
  378. server.setPF(pendingPF);
  379. pendingPFChange = false;
  380. }
  381. if (firstUpdate) {
  382. if (server.supportsContinuousUpdates) {
  383. vlog.info("Enabling continuous updates");
  384. continuousUpdates = true;
  385. writer().writeEnableContinuousUpdates(true, 0, 0,
  386. server.width(),
  387. server.height());
  388. }
  389. firstUpdate = false;
  390. }
  391. }
  392. public void dataRect(Rect r, int encoding)
  393. {
  394. decoder.decodeRect(r, encoding, framebuffer);
  395. }
  396. // Methods to be overridden in a derived class
  397. // authSuccess() is called when authentication has succeeded.
  398. public void authSuccess() { }
  399. // initDone() is called when the connection is fully established
  400. // and standard messages can be sent. This is called before the
  401. // initial FramebufferUpdateRequest giving a derived class the
  402. // chance to modify pixel format and settings. The derived class
  403. // must also make sure it has provided a valid framebuffer before
  404. // returning.
  405. public void initDone() { }
  406. // resizeFramebuffer() is called whenever the framebuffer
  407. // dimensions or the screen layout changes. A subclass must make
  408. // sure the pixel buffer has been updated once this call returns.
  409. public void resizeFramebuffer()
  410. {
  411. assert(false);
  412. }
  413. // refreshFramebuffer() forces a complete refresh of the entire
  414. // framebuffer
  415. public void refreshFramebuffer()
  416. {
  417. forceNonincremental = true;
  418. // Without fences, we cannot safely trigger an update request directly
  419. // but must wait for the next update to arrive.
  420. if (continuousUpdates)
  421. requestNewUpdate();
  422. }
  423. // setPreferredEncoding()/getPreferredEncoding() adjusts which
  424. // encoding is listed first as a hint to the server that it is the
  425. // preferred one
  426. public void setPreferredEncoding(int encoding)
  427. {
  428. if (preferredEncoding == encoding)
  429. return;
  430. preferredEncoding = encoding;
  431. encodingChange = true;
  432. }
  433. public int getPreferredEncoding()
  434. {
  435. return preferredEncoding;
  436. }
  437. // setCompressLevel()/setQualityLevel() controls the encoding hints
  438. // sent to the server
  439. public void setCompressLevel(int level)
  440. {
  441. if (compressLevel == level)
  442. return;
  443. compressLevel = level;
  444. encodingChange = true;
  445. }
  446. public void setQualityLevel(int level)
  447. {
  448. if (qualityLevel == level)
  449. return;
  450. qualityLevel = level;
  451. encodingChange = true;
  452. }
  453. // setPF() controls the pixel format requested from the server.
  454. // server.pf() will automatically be adjusted once the new format
  455. // is active.
  456. public void setPF(PixelFormat pf)
  457. {
  458. if (server.pf().equal(pf) && !formatChange)
  459. return;
  460. nextPF = pf;
  461. formatChange = true;
  462. }
  463. public CMsgReader reader() { return reader_; }
  464. public CMsgWriter writer() { return writer_; }
  465. public InStream getInStream() { return is; }
  466. public OutStream getOutStream() { return os; }
  467. // Access method used by SSecurity implementations that can verify servers'
  468. // Identities, to determine the unique(ish) name of the server.
  469. public String getServerName() { return serverName; }
  470. public int getServerPort() { return serverPort; }
  471. boolean isSecure() { return csecurity != null ? csecurity.isSecure() : false; }
  472. public enum stateEnum {
  473. RFBSTATE_UNINITIALISED,
  474. RFBSTATE_PROTOCOL_VERSION,
  475. RFBSTATE_SECURITY_TYPES,
  476. RFBSTATE_SECURITY,
  477. RFBSTATE_SECURITY_RESULT,
  478. RFBSTATE_INITIALISATION,
  479. RFBSTATE_NORMAL,
  480. RFBSTATE_INVALID
  481. };
  482. public stateEnum state() { return state_; }
  483. protected void setState(stateEnum s) { state_ = s; }
  484. protected void setReader(CMsgReader r) { reader_ = r; }
  485. protected void setWriter(CMsgWriter w) { writer_ = w; }
  486. protected ModifiablePixelBuffer getFramebuffer() { return framebuffer; }
  487. public void fence(int flags, int len, byte[] data)
  488. {
  489. super.fence(flags, len, data);
  490. if ((flags & fenceTypes.fenceFlagRequest) != 0)
  491. return;
  492. // We cannot guarantee any synchronisation at this level
  493. flags = 0;
  494. writer().writeFence(flags, len, data);
  495. }
  496. // requestNewUpdate() requests an update from the server, having set the
  497. // format and encoding appropriately.
  498. private void requestNewUpdate()
  499. {
  500. if (formatChange && !pendingPFChange) {
  501. /* Catch incorrect requestNewUpdate calls */
  502. assert(!pendingUpdate || continuousUpdates);
  503. // We have to make sure we switch the internal format at a safe
  504. // time. For continuous updates we temporarily disable updates and
  505. // look for a EndOfContinuousUpdates message to see when to switch.
  506. // For classical updates we just got a new update right before this
  507. // function was called, so we need to make sure we finish that
  508. // update before we can switch.
  509. pendingPFChange = true;
  510. pendingPF = nextPF;
  511. if (continuousUpdates)
  512. writer().writeEnableContinuousUpdates(false, 0, 0, 0, 0);
  513. writer().writeSetPixelFormat(pendingPF);
  514. if (continuousUpdates)
  515. writer().writeEnableContinuousUpdates(true, 0, 0,
  516. server.width(),
  517. server.height());
  518. formatChange = false;
  519. }
  520. if (encodingChange) {
  521. updateEncodings();
  522. encodingChange = false;
  523. }
  524. if (forceNonincremental || !continuousUpdates) {
  525. pendingUpdate = true;
  526. writer().writeFramebufferUpdateRequest(new Rect(0, 0,
  527. server.width(),
  528. server.height()),
  529. !forceNonincremental);
  530. }
  531. forceNonincremental = false;
  532. }
  533. // Ask for encodings based on which decoders are supported. Assumes higher
  534. // encoding numbers are more desirable.
  535. private void updateEncodings()
  536. {
  537. List<Integer> encodings = new ArrayList<Integer>();
  538. if (server.supportsLocalCursor) {
  539. // JRE on Windows does not support cursors with alpha
  540. if (!osName.contains("windows")) {
  541. encodings.add(Encodings.pseudoEncodingCursorWithAlpha);
  542. encodings.add(Encodings.pseudoEncodingVMwareCursor);
  543. }
  544. encodings.add(Encodings.pseudoEncodingCursor);
  545. encodings.add(Encodings.pseudoEncodingXCursor);
  546. }
  547. if (server.supportsDesktopResize) {
  548. encodings.add(Encodings.pseudoEncodingDesktopSize);
  549. encodings.add(Encodings.pseudoEncodingExtendedDesktopSize);
  550. }
  551. if (server.supportsClientRedirect)
  552. encodings.add(Encodings.pseudoEncodingClientRedirect);
  553. encodings.add(Encodings.pseudoEncodingDesktopName);
  554. encodings.add(Encodings.pseudoEncodingLastRect);
  555. encodings.add(Encodings.pseudoEncodingContinuousUpdates);
  556. encodings.add(Encodings.pseudoEncodingFence);
  557. if (Decoder.supported(preferredEncoding)) {
  558. encodings.add(preferredEncoding);
  559. }
  560. encodings.add(Encodings.encodingCopyRect);
  561. for (int i = Encodings.encodingMax; i >= 0; i--) {
  562. if ((i != preferredEncoding) && Decoder.supported(i))
  563. encodings.add(i);
  564. }
  565. if (compressLevel >= 0 && compressLevel <= 9)
  566. encodings.add(Encodings.pseudoEncodingCompressLevel0 + compressLevel);
  567. if (qualityLevel >= 0 && qualityLevel <= 9)
  568. encodings.add(Encodings.pseudoEncodingQualityLevel0 + qualityLevel);
  569. writer().writeSetEncodings(encodings);
  570. }
  571. private void throwAuthFailureException() {
  572. String reason;
  573. vlog.debug("state="+state()+", ver="+server.majorVersion+"."+server.minorVersion);
  574. if (state() == stateEnum.RFBSTATE_SECURITY_RESULT && !server.beforeVersion(3,8)) {
  575. reason = is.readString();
  576. } else {
  577. reason = "Authentication failure";
  578. }
  579. state_ = stateEnum.RFBSTATE_INVALID;
  580. vlog.error(reason);
  581. throw new AuthFailureException(reason);
  582. }
  583. public CSecurity csecurity;
  584. public SecurityClient security;
  585. protected boolean supportsLocalCursor;
  586. protected boolean supportsDesktopResize;
  587. private InStream is;
  588. private OutStream os;
  589. private CMsgReader reader_;
  590. private CMsgWriter writer_;
  591. private boolean deleteStreamsWhenDone;
  592. private boolean shared;
  593. private stateEnum state_;
  594. private String serverName;
  595. private int serverPort;
  596. private boolean pendingPFChange;
  597. private PixelFormat pendingPF;
  598. private int preferredEncoding;
  599. private int compressLevel;
  600. private int qualityLevel;
  601. private boolean formatChange;
  602. private PixelFormat nextPF;
  603. private boolean encodingChange;
  604. private boolean firstUpdate;
  605. private boolean pendingUpdate;
  606. private boolean continuousUpdates;
  607. private boolean forceNonincremental;
  608. protected ModifiablePixelBuffer framebuffer;
  609. private DecodeManager decoder;
  610. }