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.4KB

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