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

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