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.

SMsgReader.cxx 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-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 <stdio.h>
  23. #include <rdr/InStream.h>
  24. #include <rdr/ZlibInStream.h>
  25. #include <rfb/msgTypes.h>
  26. #include <rfb/qemuTypes.h>
  27. #include <rfb/clipboardTypes.h>
  28. #include <rfb/Exception.h>
  29. #include <rfb/util.h>
  30. #include <rfb/SMsgHandler.h>
  31. #include <rfb/SMsgReader.h>
  32. #include <rfb/Configuration.h>
  33. #include <rfb/LogWriter.h>
  34. using namespace rfb;
  35. static LogWriter vlog("SMsgReader");
  36. static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
  37. SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
  38. : handler(handler_), is(is_), state(MSGSTATE_IDLE)
  39. {
  40. }
  41. SMsgReader::~SMsgReader()
  42. {
  43. }
  44. bool SMsgReader::readClientInit()
  45. {
  46. if (!is->hasData(1))
  47. return false;
  48. bool shared = is->readU8();
  49. handler->clientInit(shared);
  50. return true;
  51. }
  52. bool SMsgReader::readMsg()
  53. {
  54. bool ret;
  55. if (state == MSGSTATE_IDLE) {
  56. if (!is->hasData(1))
  57. return false;
  58. currentMsgType = is->readU8();
  59. state = MSGSTATE_MESSAGE;
  60. }
  61. switch (currentMsgType) {
  62. case msgTypeSetPixelFormat:
  63. ret = readSetPixelFormat();
  64. break;
  65. case msgTypeSetEncodings:
  66. ret = readSetEncodings();
  67. break;
  68. case msgTypeSetDesktopSize:
  69. ret = readSetDesktopSize();
  70. break;
  71. case msgTypeFramebufferUpdateRequest:
  72. ret = readFramebufferUpdateRequest();
  73. break;
  74. case msgTypeEnableContinuousUpdates:
  75. ret = readEnableContinuousUpdates();
  76. break;
  77. case msgTypeClientFence:
  78. ret = readFence();
  79. break;
  80. case msgTypeKeyEvent:
  81. ret = readKeyEvent();
  82. break;
  83. case msgTypePointerEvent:
  84. ret = readPointerEvent();
  85. break;
  86. case msgTypeClientCutText:
  87. ret = readClientCutText();
  88. break;
  89. case msgTypeQEMUClientMessage:
  90. ret = readQEMUMessage();
  91. break;
  92. default:
  93. vlog.error("unknown message type %d", currentMsgType);
  94. throw Exception("unknown message type");
  95. }
  96. if (ret)
  97. state = MSGSTATE_IDLE;
  98. return ret;
  99. }
  100. bool SMsgReader::readSetPixelFormat()
  101. {
  102. if (!is->hasData(3 + 16))
  103. return false;
  104. is->skip(3);
  105. PixelFormat pf;
  106. pf.read(is);
  107. handler->setPixelFormat(pf);
  108. return true;
  109. }
  110. bool SMsgReader::readSetEncodings()
  111. {
  112. if (!is->hasData(1 + 2))
  113. return false;
  114. is->setRestorePoint();
  115. is->skip(1);
  116. int nEncodings = is->readU16();
  117. if (!is->hasDataOrRestore(nEncodings * 4))
  118. return false;
  119. is->clearRestorePoint();
  120. rdr::S32Array encodings(nEncodings);
  121. for (int i = 0; i < nEncodings; i++)
  122. encodings.buf[i] = is->readU32();
  123. handler->setEncodings(nEncodings, encodings.buf);
  124. return true;
  125. }
  126. bool SMsgReader::readSetDesktopSize()
  127. {
  128. int width, height;
  129. int screens, i;
  130. rdr::U32 id, flags;
  131. int sx, sy, sw, sh;
  132. ScreenSet layout;
  133. if (!is->hasData(1 + 2 + 2 + 1 + 1))
  134. return true;
  135. is->setRestorePoint();
  136. is->skip(1);
  137. width = is->readU16();
  138. height = is->readU16();
  139. screens = is->readU8();
  140. is->skip(1);
  141. if (!is->hasDataOrRestore(screens * (4 + 2 + 2 + 2 + 2 + 4)))
  142. return false;
  143. is->clearRestorePoint();
  144. for (i = 0;i < screens;i++) {
  145. id = is->readU32();
  146. sx = is->readU16();
  147. sy = is->readU16();
  148. sw = is->readU16();
  149. sh = is->readU16();
  150. flags = is->readU32();
  151. layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
  152. }
  153. handler->setDesktopSize(width, height, layout);
  154. return true;
  155. }
  156. bool SMsgReader::readFramebufferUpdateRequest()
  157. {
  158. if (!is->hasData(1 + 2 + 2 + 2 + 2))
  159. return false;
  160. bool inc = is->readU8();
  161. int x = is->readU16();
  162. int y = is->readU16();
  163. int w = is->readU16();
  164. int h = is->readU16();
  165. handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
  166. return true;
  167. }
  168. bool SMsgReader::readEnableContinuousUpdates()
  169. {
  170. bool enable;
  171. int x, y, w, h;
  172. if (!is->hasData(1 + 2 + 2 + 2 + 2))
  173. return false;
  174. enable = is->readU8();
  175. x = is->readU16();
  176. y = is->readU16();
  177. w = is->readU16();
  178. h = is->readU16();
  179. handler->enableContinuousUpdates(enable, x, y, w, h);
  180. return true;
  181. }
  182. bool SMsgReader::readFence()
  183. {
  184. rdr::U32 flags;
  185. rdr::U8 len;
  186. char data[64];
  187. if (!is->hasData(3 + 4 + 1))
  188. return false;
  189. is->setRestorePoint();
  190. is->skip(3);
  191. flags = is->readU32();
  192. len = is->readU8();
  193. if (!is->hasDataOrRestore(len))
  194. return false;
  195. is->clearRestorePoint();
  196. if (len > sizeof(data)) {
  197. vlog.error("Ignoring fence with too large payload");
  198. is->skip(len);
  199. return true;
  200. }
  201. is->readBytes(data, len);
  202. handler->fence(flags, len, data);
  203. return true;
  204. }
  205. bool SMsgReader::readKeyEvent()
  206. {
  207. if (!is->hasData(1 + 2 + 4))
  208. return false;
  209. bool down = is->readU8();
  210. is->skip(2);
  211. rdr::U32 key = is->readU32();
  212. handler->keyEvent(key, 0, down);
  213. return true;
  214. }
  215. bool SMsgReader::readPointerEvent()
  216. {
  217. if (!is->hasData(1 + 2 + 2))
  218. return false;
  219. int mask = is->readU8();
  220. int x = is->readU16();
  221. int y = is->readU16();
  222. handler->pointerEvent(Point(x, y), mask);
  223. return true;
  224. }
  225. bool SMsgReader::readClientCutText()
  226. {
  227. if (!is->hasData(3 + 4))
  228. return false;
  229. is->setRestorePoint();
  230. is->skip(3);
  231. rdr::U32 len = is->readU32();
  232. if (len & 0x80000000) {
  233. rdr::S32 slen = len;
  234. slen = -slen;
  235. if (readExtendedClipboard(slen)) {
  236. is->clearRestorePoint();
  237. return true;
  238. } else {
  239. is->gotoRestorePoint();
  240. return false;
  241. }
  242. }
  243. if (!is->hasDataOrRestore(len))
  244. return false;
  245. is->clearRestorePoint();
  246. if (len > (size_t)maxCutText) {
  247. is->skip(len);
  248. vlog.error("Cut text too long (%d bytes) - ignoring", len);
  249. return true;
  250. }
  251. CharArray ca(len);
  252. is->readBytes(ca.buf, len);
  253. CharArray filtered(convertLF(ca.buf, len));
  254. handler->clientCutText(filtered.buf);
  255. return true;
  256. }
  257. bool SMsgReader::readExtendedClipboard(rdr::S32 len)
  258. {
  259. rdr::U32 flags;
  260. rdr::U32 action;
  261. if (!is->hasData(len))
  262. return false;
  263. if (len < 4)
  264. throw Exception("Invalid extended clipboard message");
  265. if (len > maxCutText) {
  266. vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
  267. is->skip(len);
  268. return true;
  269. }
  270. flags = is->readU32();
  271. action = flags & clipboardActionMask;
  272. if (action & clipboardCaps) {
  273. int i;
  274. size_t num;
  275. rdr::U32 lengths[16];
  276. num = 0;
  277. for (i = 0;i < 16;i++) {
  278. if (flags & (1 << i))
  279. num++;
  280. }
  281. if (len < (rdr::S32)(4 + 4*num))
  282. throw Exception("Invalid extended clipboard message");
  283. num = 0;
  284. for (i = 0;i < 16;i++) {
  285. if (flags & (1 << i))
  286. lengths[num++] = is->readU32();
  287. }
  288. handler->handleClipboardCaps(flags, lengths);
  289. } else if (action == clipboardProvide) {
  290. rdr::ZlibInStream zis;
  291. int i;
  292. size_t num;
  293. size_t lengths[16];
  294. rdr::U8* buffers[16];
  295. zis.setUnderlying(is, len - 4);
  296. num = 0;
  297. for (i = 0;i < 16;i++) {
  298. if (!(flags & 1 << i))
  299. continue;
  300. if (!zis.hasData(4))
  301. throw Exception("Extended clipboard decode error");
  302. lengths[num] = zis.readU32();
  303. if (lengths[num] > (size_t)maxCutText) {
  304. vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
  305. (unsigned)lengths[num]);
  306. // Slowly (safely) drain away the data
  307. while (lengths[num] > 0) {
  308. size_t chunk;
  309. if (!zis.hasData(1))
  310. throw Exception("Extended clipboard decode error");
  311. chunk = zis.avail();
  312. if (chunk > lengths[num])
  313. chunk = lengths[num];
  314. zis.skip(chunk);
  315. lengths[num] -= chunk;
  316. }
  317. flags &= ~(1 << i);
  318. continue;
  319. }
  320. if (!zis.hasData(lengths[num]))
  321. throw Exception("Extended clipboard decode error");
  322. buffers[num] = new rdr::U8[lengths[num]];
  323. zis.readBytes(buffers[num], lengths[num]);
  324. num++;
  325. }
  326. zis.flushUnderlying();
  327. zis.setUnderlying(NULL, 0);
  328. handler->handleClipboardProvide(flags, lengths, buffers);
  329. num = 0;
  330. for (i = 0;i < 16;i++) {
  331. if (!(flags & 1 << i))
  332. continue;
  333. delete [] buffers[num++];
  334. }
  335. } else {
  336. switch (action) {
  337. case clipboardRequest:
  338. handler->handleClipboardRequest(flags);
  339. break;
  340. case clipboardPeek:
  341. handler->handleClipboardPeek(flags);
  342. break;
  343. case clipboardNotify:
  344. handler->handleClipboardNotify(flags);
  345. break;
  346. default:
  347. throw Exception("Invalid extended clipboard action");
  348. }
  349. }
  350. return true;
  351. }
  352. bool SMsgReader::readQEMUMessage()
  353. {
  354. int subType;
  355. bool ret;
  356. if (!is->hasData(1))
  357. return false;
  358. is->setRestorePoint();
  359. subType = is->readU8();
  360. switch (subType) {
  361. case qemuExtendedKeyEvent:
  362. ret = readQEMUKeyEvent();
  363. break;
  364. default:
  365. throw Exception("unknown QEMU submessage type %d", subType);
  366. }
  367. if (!ret) {
  368. is->gotoRestorePoint();
  369. return false;
  370. } else {
  371. is->clearRestorePoint();
  372. return true;
  373. }
  374. }
  375. bool SMsgReader::readQEMUKeyEvent()
  376. {
  377. if (!is->hasData(2 + 4 + 4))
  378. return false;
  379. bool down = is->readU16();
  380. rdr::U32 keysym = is->readU32();
  381. rdr::U32 keycode = is->readU32();
  382. if (!keycode) {
  383. vlog.error("Key event without keycode - ignoring");
  384. return true;
  385. }
  386. handler->keyEvent(keysym, keycode, down);
  387. return true;
  388. }