vnc_receiver.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /****************************************************************************
  2. * graphics/vnc/vnc_receiver.c
  3. *
  4. * Copyright (C) 2016 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <assert.h>
  40. #include <errno.h>
  41. #if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
  42. # undef CONFIG_DEBUG_ERROR
  43. # undef CONFIG_DEBUG_WARN
  44. # undef CONFIG_DEBUG_INFO
  45. # undef CONFIG_DEBUG_GRAPHICS_ERROR
  46. # undef CONFIG_DEBUG_GRAPHICS_WARN
  47. # undef CONFIG_DEBUG_GRAPHICS_INFO
  48. # define CONFIG_DEBUG_ERROR 1
  49. # define CONFIG_DEBUG_WARN 1
  50. # define CONFIG_DEBUG_INFO 1
  51. # define CONFIG_DEBUG_GRAPHICS 1
  52. # define CONFIG_DEBUG_GRAPHICS_ERROR 1
  53. # define CONFIG_DEBUG_GRAPHICS_WARN 1
  54. # define CONFIG_DEBUG_GRAPHICS_INFO 1
  55. #endif
  56. #include <debug.h>
  57. #ifdef CONFIG_NET_SOCKOPTS
  58. # include <sys/time.h>
  59. #endif
  60. #include <nuttx/net/net.h>
  61. #include <nuttx/video/rfb.h>
  62. #include <nuttx/video/vnc.h>
  63. #include <nuttx/nx/nx.h>
  64. #include <nuttx/nx/nxglib.h>
  65. #include "vnc_server.h"
  66. /****************************************************************************
  67. * Private Functions
  68. ****************************************************************************/
  69. /****************************************************************************
  70. * Name: vnc_read_remainder
  71. *
  72. * Description:
  73. * After receiving the first byte of a client-to-server message, this
  74. * reads in the remainder of the message.
  75. *
  76. * Input Parameters:
  77. * session - An instance of the session structure.
  78. * msglen - The full length of the message
  79. *
  80. * Returned Value:
  81. * At present, always returns OK
  82. *
  83. ****************************************************************************/
  84. int vnc_read_remainder(FAR struct vnc_session_s *session, size_t msglen,
  85. size_t offset)
  86. {
  87. ssize_t nrecvd;
  88. size_t ntotal;
  89. /* Loop until the rest of the message is received. */
  90. for (ntotal = 0; ntotal < msglen; offset += nrecvd, ntotal += nrecvd)
  91. {
  92. /* Receive more of the message */
  93. nrecvd = psock_recv(&session->connect, &session->inbuf[offset],
  94. msglen - ntotal, 0);
  95. if (nrecvd < 0)
  96. {
  97. gerr("ERROR: Receive message failed: %d\n", (int)nrecvd);
  98. return (int)nrecvd;
  99. }
  100. }
  101. return OK;
  102. }
  103. /****************************************************************************
  104. * Public Functions
  105. ****************************************************************************/
  106. /****************************************************************************
  107. * Name: vnc_receiver
  108. *
  109. * Description:
  110. * This function handles all Client-to-Server messages.
  111. *
  112. * Input Parameters:
  113. * session - An instance of the session structure.
  114. *
  115. * Returned Value:
  116. * At present, always returns OK
  117. *
  118. ****************************************************************************/
  119. int vnc_receiver(FAR struct vnc_session_s *session)
  120. {
  121. #ifdef CONFIG_NET_SOCKOPTS
  122. struct timeval tv;
  123. #endif
  124. ssize_t nrecvd;
  125. int ret;
  126. DEBUGASSERT(session);
  127. ginfo("Receiver running for Display %d\n", session->display);
  128. #ifdef CONFIG_NET_SOCKOPTS
  129. /* Disable the receive timeout so that we will wait indefinitely for the
  130. * next Client-to-Server message.
  131. */
  132. tv.tv_sec = 0;
  133. tv.tv_usec = 0;
  134. ret = psock_setsockopt(&session->connect, SOL_SOCKET, SO_RCVTIMEO,
  135. &tv, sizeof(struct timeval));
  136. if (ret < 0)
  137. {
  138. gerr("ERROR: Failed to disable receive timeout: %d\n", ret);
  139. return ret;
  140. }
  141. #endif
  142. /* Loop until the client disconnects or an unhandled error occurs */
  143. for (; ; )
  144. {
  145. /* Set up to read one byte which should be the message type of the
  146. * next Client-to-Server message. We will block here until the message
  147. * is received.
  148. */
  149. nrecvd = psock_recv(&session->connect, session->inbuf, 1, 0);
  150. if (nrecvd < 0)
  151. {
  152. gerr("ERROR: Receive byte failed: %d\n", (int)nrecvd);
  153. return (int)nrecvd;
  154. }
  155. /* A return value of zero means that the connection was gracefully
  156. * closed by the VNC client.
  157. */
  158. else if (nrecvd == 0)
  159. {
  160. gwarn("WARNING: Connection closed\n");
  161. return OK;
  162. }
  163. DEBUGASSERT(nrecvd == 1);
  164. /* The single byte received should be the message type. Handle the
  165. * message according to this message type.
  166. */
  167. switch (session->inbuf[0])
  168. {
  169. case RFB_SETPIXELFMT_MSG: /* SetPixelFormat */
  170. {
  171. ginfo("Received SetPixelFormat\n");
  172. /* Read the rest of the SetPixelFormat message */
  173. ret = vnc_read_remainder(session,
  174. sizeof(struct rfb_setpixelformat_s) - 1,
  175. 1);
  176. if (ret < 0)
  177. {
  178. gerr("ERROR: Failed to read SetPixelFormat message: %d\n",
  179. ret);
  180. }
  181. else
  182. {
  183. FAR struct rfb_setpixelformat_s *setformat =
  184. (FAR struct rfb_setpixelformat_s *)session->inbuf;
  185. ret = vnc_client_pixelformat(session, &setformat->format);
  186. if (ret < 0)
  187. {
  188. /* We do not support this pixel format */
  189. /* REVISIT: We are going to be putting garbage on the RFB */
  190. gerr("ERROR: PixelFormat not supported\n");
  191. }
  192. }
  193. }
  194. break;
  195. case RFB_SETENCODINGS_MSG: /* SetEncodings */
  196. {
  197. FAR struct rfb_setencodings_s *encodings;
  198. unsigned int nencodings;
  199. ginfo("Received SetEncodings\n");
  200. /* Read the SetEncodings message without the following
  201. * encodings.
  202. */
  203. ret = vnc_read_remainder(session,
  204. SIZEOF_RFB_SERVERINIT_S(0) - 1,
  205. 1);
  206. if (ret < 0)
  207. {
  208. gerr("ERROR: Failed to read SetEncodings message: %d\n",
  209. ret);
  210. }
  211. else
  212. {
  213. /* Read the following encodings */
  214. encodings = (FAR struct rfb_setencodings_s *)session->inbuf;
  215. nencodings = rfb_getbe16(encodings->nencodings);
  216. ret = vnc_read_remainder(session,
  217. nencodings * sizeof(uint32_t),
  218. SIZEOF_RFB_SERVERINIT_S(0));
  219. if (ret < 0)
  220. {
  221. gerr("ERROR: Failed to read encodings: %d\n",
  222. ret);
  223. }
  224. else
  225. {
  226. /* Pick out any mutually supported encodings */
  227. ret = vnc_client_encodings(session, encodings);
  228. if (ret < 0)
  229. {
  230. gerr("ERROR: vnc_set_encodings failed: %d\n", ret);
  231. }
  232. }
  233. }
  234. }
  235. break;
  236. case RFB_FBUPDATEREQ_MSG: /* FramebufferUpdateRequest */
  237. {
  238. FAR struct rfb_fbupdatereq_s *update;
  239. struct nxgl_rect_s rect;
  240. ginfo("Received FramebufferUpdateRequest\n");
  241. /* Read the rest of the FramebufferUpdateRequest message */
  242. ret = vnc_read_remainder(session,
  243. sizeof(struct rfb_fbupdatereq_s) - 1,
  244. 1);
  245. if (ret < 0)
  246. {
  247. gerr("ERROR: Failed to read FramebufferUpdateRequest message: %d\n",
  248. ret);
  249. }
  250. else
  251. {
  252. /* Enqueue the update */
  253. update = (FAR struct rfb_fbupdatereq_s *)session->inbuf;
  254. rect.pt1.x = rfb_getbe16(update->xpos);
  255. rect.pt1.y = rfb_getbe16(update->ypos);
  256. rect.pt2.x = rect.pt1.x + rfb_getbe16(update->width);
  257. rect.pt2.y = rect.pt1.y + rfb_getbe16(update->height);
  258. ret = vnc_update_rectangle(session, &rect, false);
  259. if (ret < 0)
  260. {
  261. gerr("ERROR: Failed to queue update: %d\n", ret);
  262. }
  263. }
  264. }
  265. break;
  266. case RFB_KEYEVENT_MSG: /* KeyEvent */
  267. {
  268. FAR struct rfb_keyevent_s *keyevent;
  269. ginfo("Received KeyEvent\n");
  270. /* Read the rest of the KeyEvent message */
  271. ret = vnc_read_remainder(session,
  272. sizeof(struct rfb_keyevent_s) - 1,
  273. 1);
  274. if (ret < 0)
  275. {
  276. gerr("ERROR: Failed to read KeyEvent message: %d\n",
  277. ret);
  278. }
  279. else
  280. {
  281. /* Inject the key press/release event into NX */
  282. keyevent = (FAR struct rfb_keyevent_s *)session->inbuf;
  283. vnc_key_map(session, rfb_getbe16(keyevent->key),
  284. (bool)keyevent->down);
  285. }
  286. }
  287. break;
  288. case RFB_POINTEREVENT_MSG: /* PointerEvent */
  289. {
  290. #ifdef CONFIG_NX_XYINPUT
  291. FAR struct rfb_pointerevent_s *event;
  292. uint8_t buttons;
  293. #endif
  294. ginfo("Received PointerEvent\n");
  295. /* Read the rest of the PointerEvent message */
  296. ret = vnc_read_remainder(session,
  297. sizeof(struct rfb_pointerevent_s) - 1,
  298. 1);
  299. if (ret < 0)
  300. {
  301. gerr("ERROR: Failed to read PointerEvent message: %d\n",
  302. ret);
  303. }
  304. #ifdef CONFIG_NX_XYINPUT
  305. /* REVISIT: How will be get the NX handle? */
  306. else if (session->mouseout != NULL)
  307. {
  308. event = (FAR struct rfb_pointerevent_s *)session->inbuf;
  309. /* Map buttons bitmap. Bits 0-7 are buttons 1-8, 0=up,
  310. * 1=down. By convention Bit 0 = left button, Bit 1 =
  311. * middle button, and Bit 2 = right button.
  312. */
  313. buttons = 0;
  314. if ((event->buttons & (1 << 0)) != 0)
  315. {
  316. buttons |= NX_MOUSE_LEFTBUTTON;
  317. }
  318. if ((event->buttons & (1 << 1)) != 0)
  319. {
  320. buttons |= NX_MOUSE_CENTERBUTTON;
  321. }
  322. if ((event->buttons & (1 << 2)) != 0)
  323. {
  324. buttons |= NX_MOUSE_RIGHTBUTTON;
  325. }
  326. session->mouseout(session->arg,
  327. (nxgl_coord_t)rfb_getbe16(event->xpos),
  328. (nxgl_coord_t)rfb_getbe16(event->ypos),
  329. buttons);
  330. }
  331. #endif
  332. }
  333. break;
  334. case RFB_CLIENTCUTTEXT_MSG: /* ClientCutText */
  335. {
  336. FAR struct rfb_clientcuttext_s *cuttext;
  337. uint32_t length;
  338. ginfo("Received ClientCutText\n");
  339. /* Read the ClientCutText message without the following
  340. * text.
  341. */
  342. ret = vnc_read_remainder(session,
  343. SIZEOF_RFB_CLIENTCUTTEXT_S(0) - 1,
  344. 1);
  345. if (ret < 0)
  346. {
  347. gerr("ERROR: Failed to read ClientCutText message: %d\n",
  348. ret);
  349. }
  350. else
  351. {
  352. /* Read the following text */
  353. cuttext = (FAR struct rfb_clientcuttext_s *)session->inbuf;
  354. length = rfb_getbe32(cuttext->length);
  355. ret = vnc_read_remainder(session, length,
  356. SIZEOF_RFB_CLIENTCUTTEXT_S(0));
  357. if (ret < 0)
  358. {
  359. gerr("ERROR: Failed to read text: %d\n",
  360. ret);
  361. }
  362. else
  363. {
  364. /* REVISIT: ClientCutText is currently ignored */
  365. }
  366. }
  367. }
  368. break;
  369. default:
  370. gerr("ERROR: Unsynchronized, msgtype=%d\n", session->inbuf[0]);
  371. return -EPROTO;
  372. }
  373. }
  374. return -ENOSYS;
  375. }
  376. /****************************************************************************
  377. * Name: vnc_client_encodings
  378. *
  379. * Description:
  380. * Pick out any mutually supported encodings from the Client-to-Server
  381. * SetEncodings message
  382. *
  383. * Input Parameters:
  384. * session - An instance of the session structure.
  385. * encodings - The received SetEncodings message
  386. *
  387. * Returned Value:
  388. * At present, always returns OK
  389. *
  390. ****************************************************************************/
  391. int vnc_client_encodings(FAR struct vnc_session_s *session,
  392. FAR struct rfb_setencodings_s *encodings)
  393. {
  394. uint32_t encoding;
  395. unsigned int nencodings;
  396. unsigned int i;
  397. DEBUGASSERT(session != NULL && encodings != NULL);
  398. /* Assume that there are no common encodings (other than RAW) */
  399. session->rre = false;
  400. /* Loop for each client supported encoding */
  401. nencodings = rfb_getbe16(encodings->nencodings);
  402. for (i = 0; i < nencodings; i++)
  403. {
  404. /* Get the next encoding */
  405. encoding = rfb_getbe32(&encodings->encodings[i << 2]);
  406. /* Only a limited support for of RRE is vailable now. */
  407. if (encoding == RFB_ENCODING_RRE)
  408. {
  409. session->rre = true;
  410. }
  411. }
  412. session->change = true;
  413. return OK;
  414. }
  415. /****************************************************************************
  416. * Name: vnc_mouse
  417. *
  418. * Description:
  419. * This is the default keyboard/mouse callout function. This is simply a
  420. * wrapper around nx_mousein(). When
  421. * configured using vnc_fbinitialize(), the 'arg' must be the correct
  422. * NXHANDLE value.
  423. *
  424. * Input Parameters:
  425. * See vnc_mouseout_t and vnc_kbdout_t typde definitions above. These
  426. * callouts have arguments that match the inputs to nx_kbdin() and
  427. * nx_mousein() (if arg is really of type NXHANDLE).
  428. *
  429. * Returned Value:
  430. * None
  431. *
  432. ****************************************************************************/
  433. #ifdef CONFIG_NX_XYINPUT
  434. void vnc_mouseout(FAR void *arg, nxgl_coord_t x, nxgl_coord_t y,
  435. uint8_t buttons)
  436. {
  437. DEBUGASSERT(arg != NULL);
  438. (void)nx_mousein((NXHANDLE)arg, x, y, buttons);
  439. }
  440. #endif