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.

CMsgWriter.cxx 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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/OutStream.h>
  21. #include <rdr/MemOutStream.h>
  22. #include <rdr/ZlibOutStream.h>
  23. #include <rfb/msgTypes.h>
  24. #include <rfb/fenceTypes.h>
  25. #include <rfb/qemuTypes.h>
  26. #include <rfb/clipboardTypes.h>
  27. #include <rfb/Exception.h>
  28. #include <rfb/PixelFormat.h>
  29. #include <rfb/Rect.h>
  30. #include <rfb/ServerParams.h>
  31. #include <rfb/CMsgWriter.h>
  32. using namespace rfb;
  33. CMsgWriter::CMsgWriter(ServerParams* server_, rdr::OutStream* os_)
  34. : server(server_), os(os_)
  35. {
  36. }
  37. CMsgWriter::~CMsgWriter()
  38. {
  39. }
  40. void CMsgWriter::writeClientInit(bool shared)
  41. {
  42. os->writeU8(shared);
  43. endMsg();
  44. }
  45. void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
  46. {
  47. startMsg(msgTypeSetPixelFormat);
  48. os->pad(3);
  49. pf.write(os);
  50. endMsg();
  51. }
  52. void CMsgWriter::writeSetEncodings(const std::list<rdr::U32> encodings)
  53. {
  54. std::list<rdr::U32>::const_iterator iter;
  55. startMsg(msgTypeSetEncodings);
  56. os->skip(1);
  57. os->writeU16(encodings.size());
  58. for (iter = encodings.begin(); iter != encodings.end(); ++iter)
  59. os->writeU32(*iter);
  60. endMsg();
  61. }
  62. void CMsgWriter::writeSetDesktopSize(int width, int height,
  63. const ScreenSet& layout)
  64. {
  65. if (!server->supportsSetDesktopSize)
  66. throw Exception("Server does not support SetDesktopSize");
  67. startMsg(msgTypeSetDesktopSize);
  68. os->pad(1);
  69. os->writeU16(width);
  70. os->writeU16(height);
  71. os->writeU8(layout.num_screens());
  72. os->pad(1);
  73. ScreenSet::const_iterator iter;
  74. for (iter = layout.begin();iter != layout.end();++iter) {
  75. os->writeU32(iter->id);
  76. os->writeU16(iter->dimensions.tl.x);
  77. os->writeU16(iter->dimensions.tl.y);
  78. os->writeU16(iter->dimensions.width());
  79. os->writeU16(iter->dimensions.height());
  80. os->writeU32(iter->flags);
  81. }
  82. endMsg();
  83. }
  84. void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
  85. {
  86. startMsg(msgTypeFramebufferUpdateRequest);
  87. os->writeU8(incremental);
  88. os->writeU16(r.tl.x);
  89. os->writeU16(r.tl.y);
  90. os->writeU16(r.width());
  91. os->writeU16(r.height());
  92. endMsg();
  93. }
  94. void CMsgWriter::writeEnableContinuousUpdates(bool enable,
  95. int x, int y, int w, int h)
  96. {
  97. if (!server->supportsContinuousUpdates)
  98. throw Exception("Server does not support continuous updates");
  99. startMsg(msgTypeEnableContinuousUpdates);
  100. os->writeU8(!!enable);
  101. os->writeU16(x);
  102. os->writeU16(y);
  103. os->writeU16(w);
  104. os->writeU16(h);
  105. endMsg();
  106. }
  107. void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
  108. {
  109. if (!server->supportsFence)
  110. throw Exception("Server does not support fences");
  111. if (len > 64)
  112. throw Exception("Too large fence payload");
  113. if ((flags & ~fenceFlagsSupported) != 0)
  114. throw Exception("Unknown fence flags");
  115. startMsg(msgTypeClientFence);
  116. os->pad(3);
  117. os->writeU32(flags);
  118. os->writeU8(len);
  119. os->writeBytes(data, len);
  120. endMsg();
  121. }
  122. void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
  123. {
  124. if (!server->supportsQEMUKeyEvent || !keycode) {
  125. /* This event isn't meaningful without a valid keysym */
  126. if (!keysym)
  127. return;
  128. startMsg(msgTypeKeyEvent);
  129. os->writeU8(down);
  130. os->pad(2);
  131. os->writeU32(keysym);
  132. endMsg();
  133. } else {
  134. startMsg(msgTypeQEMUClientMessage);
  135. os->writeU8(qemuExtendedKeyEvent);
  136. os->writeU16(down);
  137. os->writeU32(keysym);
  138. os->writeU32(keycode);
  139. endMsg();
  140. }
  141. }
  142. void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
  143. {
  144. Point p(pos);
  145. if (p.x < 0) p.x = 0;
  146. if (p.y < 0) p.y = 0;
  147. if (p.x >= server->width()) p.x = server->width() - 1;
  148. if (p.y >= server->height()) p.y = server->height() - 1;
  149. startMsg(msgTypePointerEvent);
  150. os->writeU8(buttonMask);
  151. os->writeU16(p.x);
  152. os->writeU16(p.y);
  153. endMsg();
  154. }
  155. void CMsgWriter::writeClientCutText(const char* str)
  156. {
  157. size_t len;
  158. if (strchr(str, '\r') != NULL)
  159. throw Exception("Invalid carriage return in clipboard data");
  160. len = strlen(str);
  161. startMsg(msgTypeClientCutText);
  162. os->pad(3);
  163. os->writeU32(len);
  164. os->writeBytes(str, len);
  165. endMsg();
  166. }
  167. void CMsgWriter::writeClipboardCaps(rdr::U32 caps,
  168. const rdr::U32* lengths)
  169. {
  170. size_t i, count;
  171. if (!(server->clipboardFlags() & clipboardCaps))
  172. throw Exception("Server does not support clipboard \"caps\" action");
  173. count = 0;
  174. for (i = 0;i < 16;i++) {
  175. if (caps & (1 << i))
  176. count++;
  177. }
  178. startMsg(msgTypeClientCutText);
  179. os->pad(3);
  180. os->writeS32(-(4 + 4 * count));
  181. os->writeU32(caps | clipboardCaps);
  182. count = 0;
  183. for (i = 0;i < 16;i++) {
  184. if (caps & (1 << i))
  185. os->writeU32(lengths[count++]);
  186. }
  187. endMsg();
  188. }
  189. void CMsgWriter::writeClipboardRequest(rdr::U32 flags)
  190. {
  191. if (!(server->clipboardFlags() & clipboardRequest))
  192. throw Exception("Server does not support clipboard \"request\" action");
  193. startMsg(msgTypeClientCutText);
  194. os->pad(3);
  195. os->writeS32(-4);
  196. os->writeU32(flags | clipboardRequest);
  197. endMsg();
  198. }
  199. void CMsgWriter::writeClipboardPeek(rdr::U32 flags)
  200. {
  201. if (!(server->clipboardFlags() & clipboardPeek))
  202. throw Exception("Server does not support clipboard \"peek\" action");
  203. startMsg(msgTypeClientCutText);
  204. os->pad(3);
  205. os->writeS32(-4);
  206. os->writeU32(flags | clipboardPeek);
  207. endMsg();
  208. }
  209. void CMsgWriter::writeClipboardNotify(rdr::U32 flags)
  210. {
  211. if (!(server->clipboardFlags() & clipboardNotify))
  212. throw Exception("Server does not support clipboard \"notify\" action");
  213. startMsg(msgTypeClientCutText);
  214. os->pad(3);
  215. os->writeS32(-4);
  216. os->writeU32(flags | clipboardNotify);
  217. endMsg();
  218. }
  219. void CMsgWriter::writeClipboardProvide(rdr::U32 flags,
  220. const size_t* lengths,
  221. const rdr::U8* const* data)
  222. {
  223. rdr::MemOutStream mos;
  224. rdr::ZlibOutStream zos;
  225. int i, count;
  226. if (!(server->clipboardFlags() & clipboardProvide))
  227. throw Exception("Server does not support clipboard \"provide\" action");
  228. zos.setUnderlying(&mos);
  229. count = 0;
  230. for (i = 0;i < 16;i++) {
  231. if (!(flags & (1 << i)))
  232. continue;
  233. zos.writeU32(lengths[count]);
  234. zos.writeBytes(data[count], lengths[count]);
  235. count++;
  236. }
  237. zos.flush();
  238. startMsg(msgTypeClientCutText);
  239. os->pad(3);
  240. os->writeS32(-(4 + mos.length()));
  241. os->writeU32(flags | clipboardProvide);
  242. os->writeBytes(mos.data(), mos.length());
  243. endMsg();
  244. }
  245. void CMsgWriter::startMsg(int type)
  246. {
  247. os->writeU8(type);
  248. }
  249. void CMsgWriter::endMsg()
  250. {
  251. os->flush();
  252. }