Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

CConnection.cxx 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2017 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 <stdio.h>
  20. #include <string.h>
  21. #include <rfb/Exception.h>
  22. #include <rfb/fenceTypes.h>
  23. #include <rfb/CMsgReader.h>
  24. #include <rfb/CMsgWriter.h>
  25. #include <rfb/CSecurity.h>
  26. #include <rfb/Security.h>
  27. #include <rfb/SecurityClient.h>
  28. #include <rfb/CConnection.h>
  29. #include <rfb/util.h>
  30. #include <rfb/LogWriter.h>
  31. #include <rdr/InStream.h>
  32. #include <rdr/OutStream.h>
  33. using namespace rfb;
  34. static LogWriter vlog("CConnection");
  35. CConnection::CConnection()
  36. : csecurity(0), is(0), os(0), reader_(0), writer_(0),
  37. shared(false),
  38. state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
  39. framebuffer(NULL), decoder(this)
  40. {
  41. }
  42. CConnection::~CConnection()
  43. {
  44. setFramebuffer(NULL);
  45. if (csecurity) csecurity->destroy();
  46. delete reader_;
  47. reader_ = 0;
  48. delete writer_;
  49. writer_ = 0;
  50. }
  51. void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  52. {
  53. is = is_;
  54. os = os_;
  55. }
  56. void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
  57. {
  58. decoder.flush();
  59. if ((framebuffer != NULL) && (fb != NULL)) {
  60. Rect rect;
  61. const rdr::U8* data;
  62. int stride;
  63. const rdr::U8 black[4] = { 0, 0, 0, 0 };
  64. // Copy still valid area
  65. rect.setXYWH(0, 0,
  66. __rfbmin(fb->width(), framebuffer->width()),
  67. __rfbmin(fb->height(), framebuffer->height()));
  68. data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
  69. fb->imageRect(rect, data, stride);
  70. // Black out any new areas
  71. if (fb->width() > framebuffer->width()) {
  72. rect.setXYWH(framebuffer->width(), 0,
  73. fb->width() - framebuffer->width(),
  74. fb->height());
  75. fb->fillRect(rect, black);
  76. }
  77. if (fb->height() > framebuffer->height()) {
  78. rect.setXYWH(0, framebuffer->height(),
  79. fb->width(),
  80. fb->height() - framebuffer->height());
  81. fb->fillRect(rect, black);
  82. }
  83. }
  84. delete framebuffer;
  85. framebuffer = fb;
  86. }
  87. void CConnection::initialiseProtocol()
  88. {
  89. state_ = RFBSTATE_PROTOCOL_VERSION;
  90. }
  91. void CConnection::processMsg()
  92. {
  93. switch (state_) {
  94. case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
  95. case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
  96. case RFBSTATE_SECURITY: processSecurityMsg(); break;
  97. case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
  98. case RFBSTATE_INITIALISATION: processInitMsg(); break;
  99. case RFBSTATE_NORMAL: reader_->readMsg(); break;
  100. case RFBSTATE_UNINITIALISED:
  101. throw Exception("CConnection::processMsg: not initialised yet?");
  102. default:
  103. throw Exception("CConnection::processMsg: invalid state");
  104. }
  105. }
  106. void CConnection::processVersionMsg()
  107. {
  108. vlog.debug("reading protocol version");
  109. bool done;
  110. if (!cp.readVersion(is, &done)) {
  111. state_ = RFBSTATE_INVALID;
  112. throw Exception("reading version failed: not an RFB server?");
  113. }
  114. if (!done) return;
  115. vlog.info("Server supports RFB protocol version %d.%d",
  116. cp.majorVersion, cp.minorVersion);
  117. // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
  118. if (cp.beforeVersion(3,3)) {
  119. vlog.error("Server gave unsupported RFB protocol version %d.%d",
  120. cp.majorVersion, cp.minorVersion);
  121. state_ = RFBSTATE_INVALID;
  122. throw Exception("Server gave unsupported RFB protocol version %d.%d",
  123. cp.majorVersion, cp.minorVersion);
  124. } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
  125. cp.setVersion(3,3);
  126. } else if (cp.afterVersion(3,8)) {
  127. cp.setVersion(3,8);
  128. }
  129. cp.writeVersion(os);
  130. state_ = RFBSTATE_SECURITY_TYPES;
  131. vlog.info("Using RFB protocol version %d.%d",
  132. cp.majorVersion, cp.minorVersion);
  133. }
  134. void CConnection::processSecurityTypesMsg()
  135. {
  136. vlog.debug("processing security types message");
  137. int secType = secTypeInvalid;
  138. std::list<rdr::U8> secTypes;
  139. secTypes = security.GetEnabledSecTypes();
  140. if (cp.isVersion(3,3)) {
  141. // legacy 3.3 server may only offer "vnc authentication" or "none"
  142. secType = is->readU32();
  143. if (secType == secTypeInvalid) {
  144. throwConnFailedException();
  145. } else if (secType == secTypeNone || secType == secTypeVncAuth) {
  146. std::list<rdr::U8>::iterator i;
  147. for (i = secTypes.begin(); i != secTypes.end(); i++)
  148. if (*i == secType) {
  149. secType = *i;
  150. break;
  151. }
  152. if (i == secTypes.end())
  153. secType = secTypeInvalid;
  154. } else {
  155. vlog.error("Unknown 3.3 security type %d", secType);
  156. throw Exception("Unknown 3.3 security type");
  157. }
  158. } else {
  159. // >=3.7 server will offer us a list
  160. int nServerSecTypes = is->readU8();
  161. if (nServerSecTypes == 0)
  162. throwConnFailedException();
  163. std::list<rdr::U8>::iterator j;
  164. for (int i = 0; i < nServerSecTypes; i++) {
  165. rdr::U8 serverSecType = is->readU8();
  166. vlog.debug("Server offers security type %s(%d)",
  167. secTypeName(serverSecType), serverSecType);
  168. /*
  169. * Use the first type sent by server which matches client's type.
  170. * It means server's order specifies priority.
  171. */
  172. if (secType == secTypeInvalid) {
  173. for (j = secTypes.begin(); j != secTypes.end(); j++)
  174. if (*j == serverSecType) {
  175. secType = *j;
  176. break;
  177. }
  178. }
  179. }
  180. // Inform the server of our decision
  181. if (secType != secTypeInvalid) {
  182. os->writeU8(secType);
  183. os->flush();
  184. vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
  185. }
  186. }
  187. if (secType == secTypeInvalid) {
  188. state_ = RFBSTATE_INVALID;
  189. vlog.error("No matching security types");
  190. throw Exception("No matching security types");
  191. }
  192. state_ = RFBSTATE_SECURITY;
  193. csecurity = security.GetCSecurity(secType);
  194. processSecurityMsg();
  195. }
  196. void CConnection::processSecurityMsg()
  197. {
  198. vlog.debug("processing security message");
  199. if (csecurity->processMsg(this)) {
  200. state_ = RFBSTATE_SECURITY_RESULT;
  201. processSecurityResultMsg();
  202. }
  203. }
  204. void CConnection::processSecurityResultMsg()
  205. {
  206. vlog.debug("processing security result message");
  207. int result;
  208. if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
  209. result = secResultOK;
  210. } else {
  211. if (!is->checkNoWait(1)) return;
  212. result = is->readU32();
  213. }
  214. switch (result) {
  215. case secResultOK:
  216. securityCompleted();
  217. return;
  218. case secResultFailed:
  219. vlog.debug("auth failed");
  220. break;
  221. case secResultTooMany:
  222. vlog.debug("auth failed - too many tries");
  223. break;
  224. default:
  225. throw Exception("Unknown security result from server");
  226. }
  227. state_ = RFBSTATE_INVALID;
  228. if (cp.beforeVersion(3,8))
  229. throw AuthFailureException();
  230. CharArray reason(is->readString());
  231. throw AuthFailureException(reason.buf);
  232. }
  233. void CConnection::processInitMsg()
  234. {
  235. vlog.debug("reading server initialisation");
  236. reader_->readServerInit();
  237. }
  238. void CConnection::throwConnFailedException()
  239. {
  240. state_ = RFBSTATE_INVALID;
  241. CharArray reason;
  242. reason.buf = is->readString();
  243. throw ConnFailedException(reason.buf);
  244. }
  245. void CConnection::securityCompleted()
  246. {
  247. state_ = RFBSTATE_INITIALISATION;
  248. reader_ = new CMsgReader(this, is);
  249. writer_ = new CMsgWriter(&cp, os);
  250. vlog.debug("Authentication success!");
  251. authSuccess();
  252. writer_->writeClientInit(shared);
  253. }
  254. void CConnection::setDesktopSize(int w, int h)
  255. {
  256. decoder.flush();
  257. CMsgHandler::setDesktopSize(w,h);
  258. }
  259. void CConnection::setExtendedDesktopSize(unsigned reason,
  260. unsigned result,
  261. int w, int h,
  262. const ScreenSet& layout)
  263. {
  264. decoder.flush();
  265. CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
  266. }
  267. void CConnection::readAndDecodeRect(const Rect& r, int encoding,
  268. ModifiablePixelBuffer* pb)
  269. {
  270. decoder.decodeRect(r, encoding, pb);
  271. decoder.flush();
  272. }
  273. void CConnection::framebufferUpdateStart()
  274. {
  275. CMsgHandler::framebufferUpdateStart();
  276. }
  277. void CConnection::framebufferUpdateEnd()
  278. {
  279. decoder.flush();
  280. CMsgHandler::framebufferUpdateEnd();
  281. }
  282. void CConnection::dataRect(const Rect& r, int encoding)
  283. {
  284. decoder.decodeRect(r, encoding, framebuffer);
  285. }
  286. void CConnection::authSuccess()
  287. {
  288. }
  289. void CConnection::serverInit()
  290. {
  291. state_ = RFBSTATE_NORMAL;
  292. vlog.debug("initialisation done");
  293. }
  294. void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
  295. {
  296. CMsgHandler::fence(flags, len, data);
  297. if (!(flags & fenceFlagRequest))
  298. return;
  299. // We cannot guarantee any synchronisation at this level
  300. flags = 0;
  301. writer()->writeFence(flags, len, data);
  302. }