grahpics: Move VNC server to drivers/video

and remove the empty VNC client

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao
2021-12-31 16:22:11 +08:00
committed by Xiang Xiao
parent 902d2197b0
commit 3e85d81686
24 changed files with 25 additions and 92 deletions

View File

@@ -523,6 +523,5 @@ config NXSTART_DEVNO
---help---
LCD device number (in case there are more than one LCDs connected).
Default: 0
source "graphics/vnc/Kconfig"
endif # NX

View File

@@ -24,7 +24,6 @@ include nxglib/Make.defs
include nxbe/Make.defs
include nxmu/Make.defs
include nxterm/Make.defs
include vnc/Make.defs
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)graphics}

View File

@@ -98,10 +98,6 @@ apps/grahpics/nxwidgets
The NxWidgets code is provided as a separate package located outside of the
NuttX source tree (probably at this location).
graphics/vnc
The future home of the VNC Remote Frame Buffer (RFB) server and client
implementations.
Installing New Fonts
^^^^^^^^^^^^^^^^^^^^

View File

@@ -1,7 +0,0 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
source "graphics/vnc/server/Kconfig"
source "graphics/vnc/client/Kconfig"

View File

@@ -1,22 +0,0 @@
############################################################################
# graphics/vnc/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include vnc/server/Make.defs
include vnc/client/Make.defs

View File

@@ -1,15 +0,0 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig VNCCLIENT
bool "VNC client"
default n
depends on NET_TCP && !VNC_SERVER && EXPERIMENTAL
---help---
Enable support for a VNC Remote Frame Buffer (RFB) client
if VNCCLIENT
endif # VNCCLIENT

View File

@@ -1,27 +0,0 @@
############################################################################
# graphics/vnc/client/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifeq ($(CONFIG_VNCCLIENT),y)
DEPPATH += --dep-path vnc/client
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)/graphics/vnc/client}
VPATH += :vnc/client
endif

View File

@@ -1,162 +0,0 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig VNCSERVER
bool "VNC server"
default n
depends on NET_TCP
select FB_UPDATE
---help---
Enable support for a VNC Remote Frame Buffer (RFB) server.
if VNCSERVER
choice
prompt "VNC server protocol"
default VNCSERVER_PROTO3p8
config VNCSERVER_PROTO3p3
bool "Version 3.3"
depends on EXPERIMENTAL
config VNCSERVER_PROTO3p8
bool "Version 3.8"
endchoice # VNC server protocol
config VNCSERVER_NDISPLAYS
int "Number of displays"
default 1
range 1 99
---help---
Specifies the number of RFB displays supported by the server.
Normally this should be one.
config VNCSERVER_NAME
string "VNC display name"
default "NuttX"
config VNCSERVER_PRIO
int "VNC server task priority"
default 100
config VNCSERVER_STACKSIZE
int "VNC server stack size"
default DEFAULT_TASK_STACKSIZE
config VNCSERVER_UPDATER_PRIO
int "VNC updater thread priority"
default 100
config VNCSERVER_UPDATER_STACKSIZE
int "VNC updater thread stack size"
default DEFAULT_TASK_STACKSIZE
choice
prompt "VNC color format"
default VNCSERVER_COLORFMT_RGB16
config VNCSERVER_COLORFMT_RGB8
bool "RGB8 3:3:2"
config VNCSERVER_COLORFMT_RGB16
bool "RGB16 5:6:5"
config VNCSERVER_COLORFMT_RGB32
bool "RGB32 8:8:8"
endchoice # VNC color format
config VNCSERVER_SCREENWIDTH
int "Framebuffer width (pixels)"
default 320
---help---
This setting defines the width in pixels of the local framebuffer.
Memory usage: PixelWidth * ScreenWidth * ScreenHeight
So, for example, a 320x240 screen with RGB16 pixels would require
2x320x240 = 150 KB of RAM.
config VNCSERVER_SCREENHEIGHT
int "Framebuffer height (rows)"
default 240
---help---
This setting defines the height in rows of the local framebuffer.
Memory usage: PixelWidth * ScreenWidth * ScreenHeight
So, for example, a 320x240 screen with RGB16 pixels would require
2x320x240 = 150 KB of RAM.
config VNCSERVER_NUPDATES
int "Number of pre-allocate update structures"
default 48
---help---
This setting provides the number of pre-allocated update structures
that will be used. Dynamic memory allocations are never made. In
the likely event that we run out of update structures, the graphics
subsystem will pause and wait for the next structures to be released.
Overhead is 12-bytes per update structure.
config VNCSERVER_UPDATE_BUFSIZE
int "Max update buffer size (bytes)"
default 1024
---help---
A single buffer is pre-allocated for rendering updates. This
setting specifies the maximum in bytes of that update buffer. For
example, an update buffers of 32 pixels at 8-bits per pixel and
32-rows would yield a buffer size of 1024!
There is a very strong interaction with this setting and the network MTU.
Ideally, this buffer should fit in one network packet to avoid accessive
re-assembly of partial TCP packets.
REVISIT: In fact, if the buffer does not fit in one network packet,
then there appears to be reliability issues in the connection. I am
not sure why that is; TCP is a stream so it should not matter how
many packets are in a transfer.
Example: Negotiated pixel depth = 8 BPP, window width = 800 pixels.
CONFIG_VNCSERVER_UPDATE_BUFSIZE needs to be the payload size (MSS)
of the transfer or 800 bytes. The MTU is then:
MSS = MTU - sizeof(IP Header) - sizeof(VNC FramebufferUpdate Header)
For IPv4, the IP Header is 20 bytes; 40 bytes for IPv6. The
FramebufferUpdate header is 16 bytes so. The desired MSS is 800 bytes
so MTU = 836 or 856. For Ethernet, this is a total packet size of 870
bytes.
config VNCSERVER_KBDENCODE
bool "Encode keyboard input"
default n
depends on LIBC_KBDCODEC
---help---
Use a special encoding of keyboard characters as defined in
include/nuttx/input/kbd_coded.h.
config VNCSERVER_INBUFFER_SIZE
int "Input buffer size"
default 80
config VNCSERVER_DEBUG
bool "VNC Server debug"
default n
depends on DEBUG_FEATURES && !DEBUG_GRAPHICS
---help---
Normally VNC debug output is selected with DEBUG_GRAPHICS. The
VNC server support this special option to enable GRAPHICS debug
output for the VNC server while GRAPHICS debug is disabled. This
provides an cleaner, less cluttered output when you only wish to
debug the VNC server versus enabling DEBUG_GRAPHICS globally.
config VNCSERVER_UPDATE_DEBUG
bool "Detailed updater debug"
default n
depends on DEBUG_GRAPHICS || VNCSERVER_DEBUG
endif # VNCSERVER

View File

@@ -1,30 +0,0 @@
############################################################################
# graphics/vnc/server/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifeq ($(CONFIG_VNCSERVER),y)
CSRCS += vnc_server.c vnc_negotiate.c vnc_updater.c vnc_receiver.c
CSRCS += vnc_raw.c vnc_rre.c vnc_color.c vnc_fbdev.c vnc_keymap.c
DEPPATH += --dep-path vnc/server
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)/graphics/vnc/server}
VPATH += :vnc/server
endif

View File

@@ -1,411 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_color.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include "vnc_server.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_convert_rgbNN
*
* Description:
* Convert the native framebuffer color format (either RGB8 3:3:2,
* RGB16 5:6:5, or RGB32 8:8:8) to the remote framebuffer color format
* (either RGB8 2:2:2, RGB8 3:3:2, RGB16 5:5:5, RGB16 5:6:5, or RGB32
* 8:8:8)
*
* Input Parameters:
* pixel - The src color in local framebuffer format.
*
* Returned Value:
* The pixel in the remote framebuffer color format.
*
****************************************************************************/
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
{
/* 76543210
* --------
* RRRGGGBB
* ..RRGGBB
*/
return (uint8_t)(((rgb >> 2) & 0x30) |
((rgb >> 1) & 0x0c) |
(rgb & 0x03));
}
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
{
/* Identity mapping */
return (uint8_t)rgb;
}
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
{
/* 111111
* 54321098 76543210
* -----------------
* RRRGGGBB
* .RRR..GG G..BB...
*/
return (uint8_t)((((uint16_t)rgb << 8) & 0x7000) |
(((uint16_t)rgb << 5) & 0x0380) |
(((uint16_t)rgb << 3) & 0x0018));
}
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
{
/* 111111
* 54321098 76543210
* -----------------
* RRRGGGBB
* RRR..GGG ...BB...
*/
return (uint8_t)((((uint16_t)rgb << 8) & 0xe000) |
(((uint16_t)rgb << 6) & 0x0700) |
(((uint16_t)rgb << 3) & 0x0018));
}
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* ----------------------------------
* RRRGGGBB
* RRR..... GGG..... BB......
*/
return (((uint32_t)rgb << 16) & 0x00e00000) |
(((uint32_t)rgb << 11) & 0x0000e000) |
(((uint32_t)rgb << 6) & 0x000000c0);
}
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
{
/* 111111
* 54321098 76543210
* -----------------
* RRRRRGGG GGGBBBBB
* ..RRGGBB
*/
return (uint8_t)(((rgb >> 10) & 0x0030) |
((rgb >> 7) & 0x000c) |
((rgb >> 3) & 0x0003));
}
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
{
/* 111111
* 54321098 76543210
* -----------------
* RRRRRGGG GGGBBBBB
* RRRGGGBB
*/
return (uint8_t)(((rgb >> 8) & 0x00e0) |
((rgb >> 6) & 0x001c) |
((rgb >> 3) & 0x0003));
}
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
{
/* 111111
* 54321098 76543210
* -----------------
* RRRRRGGG GGGBBBBB
* .RRRRRGG GGGBBBBB
*/
return (((rgb >> 1) & ~0x001f) | (rgb & 0x001f));
}
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
{
/* Identity mapping */
return (uint32_t)rgb;
}
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* ----------------------------------
* RRRRRGGG GGGBBBBB
* RRRRR... GGGGGG.. BBBBB...
*/
return (((uint32_t)rgb << 8) & 0x00f80000) |
(((uint32_t)rgb << 6) & 0x0000fc00) |
(((uint32_t)rgb << 3) & 0x000000f8);
}
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* -----------------------------------
* RRRRRRRR GGGGGGGG BBBBBBBB
* ..RRGGBB
*/
return (uint8_t)(((rgb >> 18) & 0x00000030) |
((rgb >> 12) & 0x0000000c) |
((rgb >> 6) & 0x00000003));
}
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* -----------------------------------
* RRRRRRRR GGGGGGGG BBBBBBBB
* RRRGGGBB
*/
return (uint8_t)(((rgb >> 16) & 0x00000070) |
((rgb >> 11) & 0x0000001c) |
((rgb >> 6) & 0x00000003));
}
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* -----------------------------------
* RRRRRRRR GGGGGGGG BBBBBBBB
* .RRRRRGG GGGBBBBB
*/
return (uint16_t)(((rgb >> 9) & 0x00007c00) |
((rgb >> 6) & 0x000003e0) |
((rgb >> 3) & 0x0000001f));
}
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb)
{
/* 33222222 22221111 111111
* 10987654 32109876 54321098 76543210
* -----------------------------------
* RRRRRRRR GGGGGGGG BBBBBBBB
* RRRRRGGG GGGBBBBB
*/
return (uint16_t)(((rgb >> 8) & 0x0000f800) |
((rgb >> 5) & 0x000007e0) |
((rgb >> 3) & 0x0000001f));
}
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb)
{
/* Identity mapping */
return rgb;
}
#else
# error Unspecified/unsupported color format
#endif
/****************************************************************************
* Name: vnc_colors
*
* Description:
* Test the update rectangle to see if it contains complex colors. If it
* contains only a few colors, then it may be a candidate for some type
* run-length encoding.
*
* REVISIT: This function is imperfect: It will fail if there are more
* than 8 colors in the region. For small colors, we can keep a local
* array for all color formats and always return the exact result, no
* matter now many colors.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - The update region in the local frame buffer.
* maxcolors - The maximum number of colors that should be returned. This
* currently cannot exceed eight.
* colors - The top 'maxcolors' most frequency colors are returned.
*
* Returned Value:
* The number of valid colors in the colors[] array are returned, the
* first entry being the most frequent. A negated errno value is returned
* if the colors cannot be determined. This would be the case if the color
* there are more than 'maxcolors' colors in the update rectangle.
*
****************************************************************************/
int vnc_colors(FAR struct vnc_session_s *session,
FAR struct fb_area_s *rect,
unsigned int maxcolors,
FAR lfb_color_t *colors)
{
FAR const lfb_color_t *rowstart;
FAR const lfb_color_t *pixptr;
lfb_color_t pixel;
fb_coord_t x;
fb_coord_t y;
int ncolors = 0;
int pixndx;
int maxndx;
int cmpndx;
unsigned int counts[8] =
{
0, 0, 0, 0, 0, 0, 0, 0
};
DEBUGASSERT(session != NULL && rect != NULL &&
maxcolors <= 8 && colors != NULL);
/* Pointer to the first pixel in the first row in the local framebuffer */
rowstart = (FAR lfb_color_t *)
(session->fb + RFB_STRIDE * rect->y +
RFB_BYTESPERPIXEL * rect->x);
/* Loop for each row in the rectangle */
for (y = 0; y < rect->h; y++)
{
/* Loop for each column in the row */
pixptr = rowstart;
for (x = 0; x < rect->w; x++)
{
/* Compare this pix to all of the others we have seen */
pixel = *pixptr++;
for (pixndx = 0; pixndx < ncolors; pixndx++)
{
if (colors[pixndx] == pixel)
{
break;
}
}
/* Have we seen this color before? */
if (pixndx < ncolors)
{
/* Yes.. just increment the count of the number of times we
* have seen it.
*/
counts[pixndx]++;
}
/* Do we have space for another color? */
else if (ncolors >= maxcolors)
{
/* No, then bail. We don't have enough memory to deal with
* large number of colors.
*/
return -E2BIG;
}
/* Add the new color to the list of colors that we have found */
else
{
colors[ncolors] = pixel;
counts[ncolors] = 1;
ncolors++;
}
}
/* Set the point to the start of the next row */
rowstart = (FAR lfb_color_t *)((uintptr_t)rowstart + RFB_STRIDE);
}
/* Now sort the colors by how often we saw them with the most frequent
* color in the first position.
*/
/* Loop for colors N={0..(ncolors-1)} */
for (pixndx = 0; pixndx < ncolors - 1; pixndx++)
{
/* Compare color N with colors M={(N_1)..ncolors} */
maxndx = pixndx;
for (cmpndx = maxndx + 1; cmpndx < ncolors; cmpndx++)
{
/* Have we seen color M more often that color N? */
if (counts[cmpndx] > counts[maxndx])
{
/* Yes.. then color M has been seen more frequently */
maxndx = cmpndx;
}
}
/* Do nothing if color N is the most often seen */
if (maxndx != pixndx)
{
/* Otherwise swap color N and color M */
/* Remember color N */
lfb_color_t tmpcolor = colors[pixndx];
int tmpcount = counts[pixndx];
/* Set color N to color M */
colors[pixndx] = colors[maxndx];
counts[pixndx] = counts[maxndx];
/* Set color M to color N */
colors[maxndx] = tmpcolor;
counts[maxndx] = tmpcount;
}
}
/* And return the number of colors that we found */
return ncolors;
}

View File

@@ -1,892 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_fbdev.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#include <nuttx/kthread.h>
#include <nuttx/video/fb.h>
#include <nuttx/video/vnc.h>
#include "vnc_server.h"
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure provides the frame buffer interface and also incapulates
* information about the frame buffer instances for each display.
*/
struct vnc_fbinfo_s
{
/* The publicly visible frame buffer interface. This must appear first
* so that struct vnc_fbinfo_s is cast compatible with struct fb_vtable_s.
*/
struct fb_vtable_s vtable;
/* Our private per-display information */
bool initialized; /* True: This instance has been initialized */
uint8_t display; /* Display number */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Get information about the video controller configuration and the
* configuration of each color plane.
*/
static int up_getvideoinfo(FAR struct fb_vtable_s *vtable,
FAR struct fb_videoinfo_s *vinfo);
static int up_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
FAR struct fb_planeinfo_s *pinfo);
/* The following are provided only if the video hardware supports RGB color
* mapping.
*/
#ifdef CONFIG_FB_CMAP
static int up_getcmap(FAR struct fb_vtable_s *vtable,
FAR struct fb_cmap_s *cmap);
static int up_putcmap(FAR struct fb_vtable_s *vtable,
FAR const struct fb_cmap_s *cmap);
#endif
/* The following are provided only if the video hardware supports a hardware
* cursor.
*/
#ifdef CONFIG_FB_HWCURSOR
static int up_getcursor(FAR struct fb_vtable_s *vtable,
FAR struct fb_cursorattrib_s *attrib);
static int up_setcursor(FAR struct fb_vtable_s *vtable,
FAR struct fb_setcursor_s *settings);
#endif
/* Update the host window when there is a change to the framebuffer */
static int up_updateearea(FAR struct fb_vtable_s *vtable,
FAR const struct fb_area_s *area);
/****************************************************************************
* Private Data
****************************************************************************/
/* Current cursor position */
#ifdef CONFIG_FB_HWCURSOR
static struct fb_cursorpos_s g_cpos;
/* Current cursor size */
#ifdef CONFIG_FB_HWCURSORSIZE
static struct fb_cursorsize_s g_csize;
#endif
#endif
/* The framebuffer objects, one for each configured display. */
static struct vnc_fbinfo_s g_fbinfo[RFB_MAX_DISPLAYS];
/****************************************************************************
* Public Data
****************************************************************************/
/* Used to synchronize the server thread with the framebuffer driver.
* NOTE: This depends on the fact that all zero is correct initial state
* for the semaphores.
*/
struct fb_startup_s g_fbstartup[RFB_MAX_DISPLAYS];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: up_getvideoinfo
****************************************************************************/
static int up_getvideoinfo(FAR struct fb_vtable_s *vtable,
FAR struct fb_videoinfo_s *vinfo)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
ginfo("vtable=%p vinfo=%p\n", vtable, vinfo);
DEBUGASSERT(fbinfo != NULL && vinfo != NULL);
if (fbinfo != NULL && vinfo != NULL)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
/* Return the requested video info. We are committed to using the
* configured color format in the framebuffer, but performing color
* conversions on the fly for the remote framebuffer as necessary.
*/
vinfo->fmt = RFB_COLORFMT;
vinfo->xres = CONFIG_VNCSERVER_SCREENWIDTH;
vinfo->yres = CONFIG_VNCSERVER_SCREENHEIGHT;
vinfo->nplanes = 1;
return OK;
}
gerr("ERROR: Invalid arguments\n");
return -EINVAL;
}
/****************************************************************************
* Name: up_getplaneinfo
****************************************************************************/
static int up_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
FAR struct fb_planeinfo_s *pinfo)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
ginfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
DEBUGASSERT(fbinfo != NULL && pinfo != NULL && planeno == 0);
if (fbinfo != NULL && pinfo != NULL && planeno == 0)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
DEBUGASSERT(session->fb != NULL);
/* Return the requested plane info. We are committed to using the
* configured bits-per-pixels in the framebuffer, but performing color
* conversions on the fly for the remote framebuffer as necessary.
*/
pinfo->fbmem = (FAR void *)session->fb;
pinfo->fblen = RFB_SIZE;
pinfo->stride = RFB_STRIDE;
pinfo->display = fbinfo->display;
pinfo->bpp = RFB_BITSPERPIXEL;
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
/****************************************************************************
* Name: up_getcmap
****************************************************************************/
#ifdef CONFIG_FB_CMAP
static int up_getcmap(FAR struct fb_vtable_s *vtable,
FAR struct fb_cmap_s *cmap)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
int i;
ginfo("vtable=%p cmap=%p\n", vtable, cmap);
DEBUGASSERT(fbinfo != NULL && cmap != NULL);
if (fbinfo != NULL && cmap != NULL)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
ginfo("first=%d len=%d\n", vcmap->first, cmap->len);
#warning Missing logic
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
#endif
/****************************************************************************
* Name: up_putcmap
****************************************************************************/
#ifdef CONFIG_FB_CMAP
static int up_putcmap(FAR struct fb_vtable_s *vtable,
FAR const struct fb_cmap_s *cmap)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
int i;
ginfo("vtable=%p cmap=%p\n", vtable, cmap);
DEBUGASSERT(fbinfo != NULL && cmap != NULL);
if (fbinfo != NULL && cmap != NULL)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
ginfo("first=%d len=%d\n", vcmap->first, cmap->len);
#warning Missing logic
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
#endif
/****************************************************************************
* Name: up_getcursor
****************************************************************************/
#ifdef CONFIG_FB_HWCURSOR
static int up_getcursor(FAR struct fb_vtable_s *vtable,
FAR struct fb_cursorattrib_s *attrib)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
int i;
ginfo("vtable=%p attrib=%p\n", vtable, attrib);
DEBUGASSERT(fbinfo != NULL && attrib != NULL);
if (fbinfo != NULL && attrib != NULL)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
#warning Missing logic
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
#endif
/****************************************************************************
* Name: up_setcursor
****************************************************************************/
#ifdef CONFIG_FB_HWCURSOR
static int up_setcursor(FAR struct fb_vtable_s *vtable,
FAR struct fb_setcursor_s *settings)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
int i;
ginfo("vtable=%p settings=%p\n", vtable, settings);
DEBUGASSERT(fbinfo != NULL && settings != NULL);
if (fbinfo != NULL && settings != NULL)
{
DEBUGASSERT(fbinfo->display >= 0 &&
fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
gerr("ERROR: session is not connected\n");
return -ENOTCONN;
}
ginfo("flags: %02x\n", settings->flags);
if ((settings->flags & FB_CUR_SETPOSITION) != 0)
{
#warning Missing logic
}
#ifdef CONFIG_FB_HWCURSORSIZE
if ((settings->flags & FB_CUR_SETSIZE) != 0)
{
#warning Missing logic
}
#endif
#ifdef CONFIG_FB_HWCURSORIMAGE
if ((settings->flags & FB_CUR_SETIMAGE) != 0)
{
#warning Missing logic
}
#endif
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
#endif
/****************************************************************************
* Name: up_updateearea
****************************************************************************/
static int up_updateearea(FAR struct fb_vtable_s *vtable,
FAR const struct fb_area_s *area)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
int ret = OK;
DEBUGASSERT(fbinfo != NULL && area != NULL);
/* Recover the session information from the display number in the planeinfo
* structure.
*/
DEBUGASSERT(fbinfo->display >= 0 && fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
/* Verify that the session is still valid */
if (session != NULL && session->state == VNCSERVER_RUNNING)
{
/* Queue the rectangular update */
ret = vnc_update_rectangle(session, area, true);
if (ret < 0)
{
gerr("ERROR: vnc_update_rectangle failed: %d\n", ret);
}
}
return ret;
}
#ifdef CONFIG_FB_SYNC
/****************************************************************************
* Name: up_waitforsync
****************************************************************************/
static int up_waitforsync(FAR struct fb_vtable_s *vtable)
{
FAR struct vnc_fbinfo_s *fbinfo = (FAR struct vnc_fbinfo_s *)vtable;
FAR struct vnc_session_s *session;
DEBUGASSERT(fbinfo);
DEBUGASSERT(fbinfo->display >= 0 && fbinfo->display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[fbinfo->display];
if (session && session->state == VNCSERVER_RUNNING)
{
return nxsem_wait(&session->vsyncsem);
}
return ERROR;
}
#endif
/****************************************************************************
* Name: vnc_start_server
*
* Description:
* Start the VNC server.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
static int vnc_start_server(int display)
{
FAR char *argv[2];
char str[8];
pid_t pid;
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
/* Check if the server is already running */
if (g_vnc_sessions[display] != NULL)
{
DEBUGASSERT(g_vnc_sessions[display]->state >= VNCSERVER_INITIALIZED);
return OK;
}
/* Start the VNC server kernel thread. */
ginfo("Starting the VNC server for display %d\n", display);
g_fbstartup[display].result = -EBUSY;
nxsem_reset(&g_fbstartup[display].fbinit, 0);
nxsem_reset(&g_fbstartup[display].fbconnect, 0);
/* Format the kernel thread arguments (ASCII.. yech) */
itoa(display, str, 10);
argv[0] = str;
argv[1] = NULL;
pid = kthread_create("vnc_server", CONFIG_VNCSERVER_PRIO,
CONFIG_VNCSERVER_STACKSIZE,
(main_t)vnc_server, argv);
if (pid < 0)
{
gerr("ERROR: Failed to start the VNC server: %d\n", (int)pid);
return (int)pid;
}
return OK;
}
/****************************************************************************
* Name: vnc_wait_start
*
* Description:
* Wait for the server to be started.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
static inline int vnc_wait_start(int display)
{
int ret;
/* Check if there has been a session allocated yet. This is one of the
* first things that the VNC server will do with the kernel thread is
* started. But we might be here before the thread has gotten that far.
*
* If it has been allocated, then wait until it is in the INIITIALIZED
* state. The INITIAILIZED states indicates that the session structure
* has been allocated and fully initialized.
*/
while (g_vnc_sessions[display] == NULL ||
g_vnc_sessions[display]->state == VNCSERVER_UNINITIALIZED)
{
/* The server is not yet running. Wait for the server to post the FB
* semaphore. In certain error situations, the server may post the
* semaphore, then reset it to zero. There are are certainly race
* conditions here, but I think none that are fatal.
*/
ret = nxsem_wait_uninterruptible(&g_fbstartup[display].fbinit);
if (ret < 0)
{
return ret;
}
}
return OK;
}
/****************************************************************************
* Name: vnc_wait_connect
*
* Description:
* Wait for the server to be connected to the VNC client. We can do
* nothing until that connection is established.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
static inline int vnc_wait_connect(int display)
{
int ret;
/* Check if there has been a session allocated yet. This is one of the
* first things that the VNC server will do with the kernel thread is
* started. But we might be here before the thread has gotten that far.
*
* If it has been allocated, then wait until it is in the RUNNING state.
* The RUNNING state indicates that the server has started, it has
* established a connection with the VNC client, it is negotiated
* encodings and framebuffer characteristics, and it has started the
* updater thread. The server is now ready to receive Client-to-Server
* messages and to perform remote framebuffer updates.
*/
while (g_vnc_sessions[display] == NULL ||
g_vnc_sessions[display]->state != VNCSERVER_RUNNING)
{
/* The server is not yet running. Wait for the server to post the FB
* semaphore. In certain error situations, the server may post the
* semaphore, then reset it to zero. There are are certainly race
* conditions here, but I think none that are fatal.
*/
ret = nxsem_wait_uninterruptible(&g_fbstartup[display].fbconnect);
if (ret < 0)
{
return ret;
}
/* We were awakened. A result of -EBUSY means that the negotiation
* is not complete. Why would we be awakened in that case? Some
* counting semaphore screw-up?
*/
ret = g_fbstartup[display].result;
if (ret != -EBUSY)
{
#ifdef CONFIG_DEBUG_FEATURES
if (ret < 0)
{
DEBUGASSERT(g_vnc_sessions[display] == NULL);
gerr("ERROR: VNC server startup failed: %d\n", ret);
}
else
{
DEBUGASSERT(g_vnc_sessions[display] != NULL &&
g_vnc_sessions[display]->state ==
VNCSERVER_RUNNING);
}
#endif
return ret;
}
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_fbinitialize
*
* Description:
* Initialize the framebuffer video hardware associated with the display.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
*
* Returned Value:
* Zero is returned on success; a negated errno value is returned on any
* failure.
*
****************************************************************************/
int up_fbinitialize(int display)
{
int ret;
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
/* Start the VNC server kernel thread. */
ret = vnc_start_server(display);
if (ret < 0)
{
gerr("ERROR: vnc_start_server() failed: %d\n", ret);
return ret;
}
/* Wait for the VNC client to connect and for the RFB to be ready */
ret = vnc_wait_connect(display);
if (ret < 0)
{
gerr("ERROR: vnc_wait_connect() failed: %d\n", ret);
}
return ret;
}
/****************************************************************************
* Name: vnc_fbinitialize
*
* Description:
* Initialize the VNC frame buffer driver. The VNC frame buffer driver
* supports two initialization interfaces: The standard up_fbinitialize()
* that will be called from the graphics layer and this special
* initialization function that can be used only by VNC aware OS logic.
*
* The two initialization functions may be called separated or together in
* either order. The difference is that standard up_fbinitialize(), if
* used by itself, will not have any remote mouse or keyboard inputs that
* are reported to the VNC framebuffer driver from the remote VNC client.
*
* In the standard graphics architecture, the keyboard/mouse inputs are
* received by some application/board specific logic at the highest level
* in the architecture via input drivers. The received keyboard/mouse
* input data must then be "injected" into NX where it can they can be
* assigned to the window that has focus. They will eventually be
* received by the Window instances via NX callback methods.
*
* NX is a middleware layer in the architecture, below the
* application/board specific logic but above the driver level logic. The
* frame buffer driver, on the other hand lies at the very lowest level in
* the graphics architecture. It cannot call upward into the application
* nor can it call upward into NX. So, some other logic.
*
* vnc_fbinitialize() provides an optional, alternative initialization
* function. It is optional because it need not be called. If it is not
* called, however, keyboard/mouse inputs from the remote VNC client will
* be lost. By calling vnc_fbinitialize(), you can provide callout
* functions that can be received by logic higher in the architecture.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
* kbdout - If non-NULL, then the pointed-to function will be called to
* handle all keyboard input as it is received. This may be either raw,
* ASCII keypress input or encoded keyboard input as determined by
* CONFIG_VNCSERVER_KBDENCODE. See include/nuttx/input/kbd_codec.h.
* mouseout - If non-NULL, then the pointed-to function will be called to
* handle all mouse input as it is received.
* arg - An opaque user provided argument that will be provided when the
* callouts are performed.
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise, a negated errno value is
* returned to indicate the nature of the failure.
*
****************************************************************************/
int vnc_fbinitialize(int display, vnc_kbdout_t kbdout,
vnc_mouseout_t mouseout, FAR void *arg)
{
FAR struct vnc_session_s *session;
int ret;
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
/* Start the VNC server kernel thread. */
ret = vnc_start_server(display);
if (ret < 0)
{
gerr("ERROR: vnc_start_server() failed: %d\n", ret);
return ret;
}
/* Wait for the VNC server to start and complete initialization. */
ret = vnc_wait_start(display);
if (ret < 0)
{
gerr("ERROR: vnc_wait_start() failed: %d\n", ret);
return ret;
}
/* Save the input callout function information in the session structure. */
session = g_vnc_sessions[display];
DEBUGASSERT(session != NULL);
session->kbdout = kbdout;
session->mouseout = mouseout;
session->arg = arg;
return OK;
}
/****************************************************************************
* Name: up_fbgetvplane
*
* Description:
* Return a a reference to the framebuffer object for the specified video
* plane of the specified plane. Many OSDs support multiple planes of
* video.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
* vplane - Identifies the plane being queried.
*
* Returned Value:
* A non-NULL pointer to the frame buffer access structure is returned on
* success; NULL is returned on any failure.
*
****************************************************************************/
FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
{
FAR struct vnc_session_s *session;
FAR struct vnc_fbinfo_s *fbinfo;
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[display];
/* Verify that the session is still valid */
if (session == NULL || session->state != VNCSERVER_RUNNING)
{
return NULL;
}
if (vplane == 0)
{
/* Has the framebuffer information been initialized for this display? */
fbinfo = &g_fbinfo[display];
if (!fbinfo->initialized)
{
fbinfo->vtable.getvideoinfo = up_getvideoinfo,
fbinfo->vtable.getplaneinfo = up_getplaneinfo,
#ifdef CONFIG_FB_CMAP
fbinfo->vtable.getcmap = up_getcmap,
fbinfo->vtable.putcmap = up_putcmap,
#endif
#ifdef CONFIG_FB_HWCURSOR
fbinfo->vtable.getcursor = up_getcursor,
fbinfo->vtable.setcursor = up_setcursor,
#endif
#ifdef CONFIG_FB_SYNC
fbinfo->vtable.waitforvsync = up_waitforsync;
#endif
fbinfo->vtable.updatearea = up_updateearea,
fbinfo->display = display;
fbinfo->initialized = true;
}
return &fbinfo->vtable;
}
else
{
return NULL;
}
}
/****************************************************************************
* Name: up_fbuninitialize
*
* Description:
* Uninitialize the framebuffer support for the specified display.
*
* Input Parameters:
* display - In the case of hardware with multiple displays, this
* specifies the display. Normally this is zero.
*
* Returned Value:
* None
*
****************************************************************************/
void up_fbuninitialize(int display)
{
#if 0 /* Do nothing */
FAR struct vnc_session_s *session;
FAR struct vnc_fbinfo_s *fbinfo;
DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS);
session = g_vnc_sessions[display];
/* Verify that the session is still valid */
if (session != NULL)
{
fbinfo = &g_fbinfo[display];
#warning Missing logic
UNUSED(session);
UNUSED(fbinfo);
}
#endif
}

View File

@@ -1,610 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_keymap.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/ascii.h>
#define XK_MISCELLANY 1 /* Select X11 character set */
#define XK_LATIN1 1
#define XK_XKB_KEYS 1
#include <nuttx/video/vnc.h>
#include <nuttx/input/x11_keysymdef.h>
#include <nuttx/input/kbd_codec.h>
#include "vnc_server.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define FIRST_PRTCHAR ASCII_SPACE
#define LAST_PRTCHAR ASCII_TILDE
#define NPRTCHARS (ASCII_TILDE + ASCII_SPACE - 1)
#define ISPRINTABLE(c) ((c) >= FIRST_PRTCHAR && (c) <= LAST_PRTCHAR)
#define ISLOWERCASE(c) ((c) >= ASCII_a && (c) <= ASCII_z)
#define ISUPPERCASE(c) ((c) >= ASCII_A && (c) <= ASCII_Z)
#define ISALPHABETIC(c) (ISLOWERCASE(c) || ISUPPERCASE(c))
/****************************************************************************
* Private types
****************************************************************************/
enum vnc_modifier_e
{
MOD_SHIFT = 0, /* Left or right shift key */
MOD_CONTROL, /* Left or right control key */
MOD_ALT, /* Alt key */
MOD_CAPSLOCK, /* Caps lock */
MOD_SHIFTLOCK, /* Shift lock */
#ifdef CONFIG_VNCSERVER_KBDENCODE
MOD_SCROLLLOCK, /* Scroll lock */
MOD_NUMLOCK, /* Num lock */
#endif
NMODIFIERS
};
struct vnc_keymap_s
{
uint16_t nxcode;
uint16_t x11code;
};
/****************************************************************************
* Private Data
****************************************************************************/
/* Special key modifiers */
static const struct vnc_keymap_s g_modifiers[] =
{
{MOD_SHIFT, XK_Shift_L},
{MOD_SHIFT, XK_Shift_R},
{MOD_CONTROL, XK_Control_L},
{MOD_CONTROL, XK_Control_R},
{MOD_ALT, XK_Alt_L},
{MOD_ALT, XK_Alt_R},
{MOD_CAPSLOCK, XK_Caps_Lock},
{MOD_SHIFTLOCK, XK_Shift_Lock},
#ifdef CONFIG_VNCSERVER_KBDENCODE
{MOD_SCROLLLOCK, XK_Scroll_Lock},
{MOD_NUMLOCK, XK_Num_Lock},
#endif
};
#define G_MODIFIERS_NELEM (sizeof(g_modifiers) / sizeof(struct vnc_keymap_s))
/* Map special mappings for X11 codes to ASCII characters */
static const struct vnc_keymap_s g_asciimap[] =
{
/* Control characters */
#ifdef CONFIG_VNCSERVER_KBDENCODE
{ASCII_BS, XK_BackSpace},
#endif
{ASCII_TAB, XK_Tab},
{ASCII_LF, XK_Linefeed},
{ASCII_CR, XK_Return},
{ASCII_ESC, XK_Escape},
#ifdef CONFIG_VNCSERVER_KBDENCODE
{ASCII_DEL, XK_Delete},
#endif
/* Alternative encodings */
{'`', XK_dead_grave},
{'<EFBFBD>', XK_dead_acute},
{ASCII_TILDE, XK_dead_tilde},
{ASCII_CARET, XK_dead_circumflex},
/* Keypad aliases */
{ASCII_0, XK_KP_0},
{ASCII_1, XK_KP_1},
{ASCII_2, XK_KP_2},
{ASCII_3, XK_KP_3},
{ASCII_4, XK_KP_4},
{ASCII_5, XK_KP_5},
{ASCII_6, XK_KP_6},
{ASCII_7, XK_KP_7},
{ASCII_8, XK_KP_8},
{ASCII_9, XK_KP_9},
{ASCII_ASTERISK, XK_KP_Multiply},
{ASCII_PLUS, XK_KP_Add},
{ASCII_COMMA, XK_KP_Separator},
{ASCII_HYPHEN, XK_KP_Subtract},
{ASCII_PERIOD, XK_KP_Decimal},
{ASCII_DIVIDE, XK_KP_Divide},
{ASCII_SPACE, XK_KP_Space},
{ASCII_TAB, XK_KP_Tab},
{ASCII_CR, XK_KP_Enter},
#ifdef CONFIG_VNCSERVER_KBDENCODE
{ASCII_DEL, XK_KP_Delete},
#endif
};
#define G_ASCIIMAP_NELEM (sizeof(g_asciimap) / sizeof(struct vnc_keymap_s))
#ifdef CONFIG_VNCSERVER_KBDENCODE
static const struct vnc_keymap_s g_cursor[] =
{
{KEYCODE_BACKDEL, XK_BackSpace},
{KEYCODE_FWDDEL, XK_Delete},
{KEYCODE_FWDDEL, XK_KP_Delete},
{KEYCODE_HOME, XK_Home},
{KEYCODE_HOME, XK_KP_Home},
{KEYCODE_END, XK_End},
{KEYCODE_END, XK_KP_End},
{KEYCODE_LEFT, XK_Left},
{KEYCODE_LEFT, XK_KP_Left},
{KEYCODE_RIGHT, XK_Right},
{KEYCODE_RIGHT, XK_KP_Right},
{KEYCODE_UP, XK_Up},
{KEYCODE_UP, XK_KP_Up},
{KEYCODE_DOWN, XK_Down},
{KEYCODE_DOWN, XK_KP_Down},
{KEYCODE_PAGEUP, XK_Page_Up},
{KEYCODE_PAGEUP, XK_KP_Prior},
{KEYCODE_PAGEUP, XK_KP_Page_Up},
{KEYCODE_PAGEDOWN, XK_Page_Down},
{KEYCODE_PAGEDOWN, XK_KP_Next},
{KEYCODE_PAGEDOWN, XK_KP_Page_Down},
{KEYCODE_INSERT, XK_Insert},
{KEYCODE_INSERT, XK_KP_Insert},
{KEYCODE_SELECT, XK_Select},
{KEYCODE_EXECUTE, XK_Execute},
{KEYCODE_HELP, XK_Help},
{KEYCODE_MENU, XK_Alt_L},
{KEYCODE_MENU, XK_Alt_R},
{KEYCODE_PAUSE, XK_Pause},
{KEYCODE_PRTSCRN, XK_Print},
{KEYCODE_CLEAR, XK_Clear},
{MOD_SCROLLLOCK, XK_Scroll_Lock},
{MOD_NUMLOCK, XK_Num_Lock},
{KEYCODE_F1, XK_KP_F1},
{KEYCODE_F1, XK_F1},
{KEYCODE_F2, XK_KP_F2},
{KEYCODE_F2, XK_F2},
{KEYCODE_F3, XK_KP_F3},
{KEYCODE_F3, XK_F3},
{KEYCODE_F4, XK_KP_F4},
{KEYCODE_F4, XK_F4},
{KEYCODE_F5, XK_F5},
{KEYCODE_F6, XK_F6},
{KEYCODE_F7, XK_F7},
{KEYCODE_F8, XK_F8},
{KEYCODE_F9, XK_F9},
{KEYCODE_F10, XK_F10},
{KEYCODE_F11, XK_F11},
{KEYCODE_F12, XK_F12},
{KEYCODE_F13, XK_F13},
{KEYCODE_F14, XK_F14},
{KEYCODE_F15, XK_F15},
{KEYCODE_F16, XK_F16},
{KEYCODE_F17, XK_F17},
{KEYCODE_F18, XK_F18},
{KEYCODE_F19, XK_F19},
{KEYCODE_F20, XK_F20},
{KEYCODE_F21, XK_F21},
{KEYCODE_F22, XK_F22},
{KEYCODE_F23, XK_F23},
{KEYCODE_F24, XK_F24},
};
#endif
/* Changes the case of a character. Based on US keyboard layout */
static const uint8_t g_caseswap[NPRTCHARS] =
{
ASCII_SPACE, ASCII_1, ASCII_RSQUOTE, ASCII_3, /* ! " # */
ASCII_4, ASCII_5, ASCII_7, ASCII_QUOTE, /* $ % & ' */
ASCII_9, ASCII_0, ASCII_8, ASCII_EQUAL, /* ( ) * + */
ASCII_LT, ASCII_UNDERSCORE, ASCII_GT, ASCII_QUESTION, /* , - . / */
ASCII_RPAREN, ASCII_EXCLAM, ASCII_AT, ASCII_NUMBER, /* 0 1 2 3 */
ASCII_DOLLAR, ASCII_PERCENT, ASCII_CIRCUMFLEX, ASCII_AMPERSAND, /* 4 5 6 7 */
ASCII_ASTERISK, ASCII_LPAREN, ASCII_SEMICOLON, ASCII_COLON, /* 8 9 : ; */
ASCII_COMMA, ASCII_PLUS, ASCII_PERIOD, ASCII_SLASH, /* < = > ? */
ASCII_2, ASCII_a, ASCII_b, ASCII_c, /* @ A B C */
ASCII_d, ASCII_e, ASCII_f, ASCII_g, /* D E F G */
ASCII_h, ASCII_i, ASCII_j, ASCII_k, /* H I J K */
ASCII_l, ASCII_m, ASCII_n, ASCII_o, /* L M N O */
ASCII_p, ASCII_q, ASCII_r, ASCII_s, /* P Q R S */
ASCII_t, ASCII_u, ASCII_v, ASCII_v, /* T U V W */
ASCII_x, ASCII_y, ASCII_z, ASCII_LBRACE, /* X Y Z [ */
ASCII_VERTBAR, ASCII_RBRACE, ASCII_6, ASCII_HYPHEN, /* \ ] ^ _ */
ASCII_TILDE, ASCII_A, ASCII_B, ASCII_C, /* ' a b c */
ASCII_D, ASCII_E, ASCII_F, ASCII_G, /* c e f g */
ASCII_H, ASCII_I, ASCII_J, ASCII_K, /* h i j k */
ASCII_L, ASCII_M, ASCII_N, ASCII_O, /* l m n o */
ASCII_P, ASCII_Q, ASCII_R, ASCII_S, /* p q r s */
ASCII_T, ASCII_U, ASCII_V, ASCII_W, /* t u v w */
ASCII_X, ASCII_Y, ASCII_Z, ASCII_LBRACKET, /* x y z { */
ASCII_BACKSLASH, ASCII_RBRACKET, ASCII_RSQUOTE, /* | } ~ */
};
/* State of each modifier */
static bool g_modstate[NMODIFIERS];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_kbd_encode
*
* Description:
* Encode one escape sequence command into the proivded buffer.
*
* Input Parameters:
* buffer - The location to write the sequence
* keycode - The command to be added to the output stream.
* terminator - Escape sequence terminating character.
*
* Returned Value:
* Number of bytes written
*
****************************************************************************/
#ifdef CONFIG_VNCSERVER_KBDENCODE
static inline int vnc_kbd_encode(FAR uint8_t *buffer, uint8_t keycode,
uint8_t terminator)
{
*buffer++ = ASCII_ESC;
*buffer++ = ASCII_LBRACKET;
*buffer++ = keycode;
*buffer = terminator;
return 4;
}
#endif
/****************************************************************************
* Name: vnc_kbd_press
*
* Description:
* Indicates a normal key press event. Put one byte of normal keyboard
* data into the user provided buffer.
*
* Input Parameters:
* buffer - The location to write the sequence
* ch - The character to be added to the output stream.
*
* Returned Value:
* Number of bytes written
*
****************************************************************************/
#ifdef CONFIG_VNCSERVER_KBDENCODE
static inline void vnc_kbd_press(FAR uint8_t *buffer, uint8_t ch)
{
*buffer = ch;
return 1;
}
#endif
/****************************************************************************
* Name: vnc_kbd_release
*
* Description:
* Encode the release of a normal key.
*
* Input Parameters:
* buffer - The location to write the sequence
* ch - The character associated with the key that was releared.
*
* Returned Value:
* Number of bytes written
*
****************************************************************************/
#ifdef CONFIG_VNCSERVER_KBDENCODE
static inline void vnc_kbd_release(FAR uint8_t *buffer, uint8_t ch)
{
return vnc_kbd_encode(buffer, ch, ('a' + KBD_RELEASE));
}
#endif
/****************************************************************************
* Name: vnc_kbd_specpress
*
* Description:
* Denotes a special key press event. Put one special keyboard command
* into the user provided buffer.
*
* Input Parameters:
* buffer - The location to write the sequence
* keycode - The command to be added to the output stream.
*
* Returned Value:
* Number of bytes written
*
****************************************************************************/
#ifdef CONFIG_VNCSERVER_KBDENCODE
static inline void vnc_kbd_specpress(FAR uint8_t *buffer, uint8_t keycode)
{
return vnc_kbd_encode(buffer, keycode, stream, ('a' + KBD_SPECPRESS));
}
#endif
/****************************************************************************
* Name: vnc_kbd_specrel
*
* Description:
* Denotes a special key release event. Put one special keyboard
* command into the user provided buffer.
*
* Input Parameters:
* buffer - The location to write the sequence
* keycode - The command to be added to the output stream.
*
* Returned Value:
* Number of bytes written
*
****************************************************************************/
#ifdef CONFIG_VNCSERVER_KBDENCODE
static inline void vnc_kbd_specrel(FAR uint8_t *buffer, uint8_t keycode)
{
return vnc_kbd_encode(buffer, keycode, stream, ('a' + KBD_SPECREL));
}
#endif
/****************************************************************************
* Name: vnc_kbd_lookup
*
* Description:
* Attempt to map the X11 keycode by searching in a lookup table.
*
****************************************************************************/
static int vnc_kbd_lookup(FAR const struct vnc_keymap_s *table,
unsigned int nelem, uint16_t keysym)
{
int i;
/* First just try to map the virtual keycode using our lookup-table */
for (i = 0; i < nelem; i++)
{
if (table[i].x11code == keysym)
{
/* We have a match */
return (int)table[i].nxcode;
}
}
/* No match */
return -EINVAL;
}
/****************************************************************************
* Name: vnc_kbd_ascii
*
* Description:
* Attempt to map the X11 keycode into the corresponding ASCII code.
*
****************************************************************************/
static int vnc_kbd_ascii(uint16_t keysym)
{
/* ISO/IEC 8859-1 Latin1 matches C ASCII in this range: */
#ifdef CONFIG_VNCSERVER_KBDENCODE
if (keysym >= ASCII_SPACE && keysym < ASCII_DEL)
#else
if (keysym >= ASCII_SPACE && keysym <= ASCII_DEL)
#endif
{
return (int)keysym;
}
/* Perform a lookup to handler some special cases */
return vnc_kbd_lookup(g_asciimap, G_ASCIIMAP_NELEM, keysym);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_key_map
*
* Description:
* Map the receive X11 keysym into something understood by NuttX and route
* that through NX to the appropriate window.
*
* Input Parameters:
* session - An instance of the session structure allocated by
* vnc_create_session().
* keysym - The X11 keysym value (see include/nuttx/inputx11_keysymdef)
* keydown - True: Key pressed; False: Key released
*
* Returned Value:
* None
*
****************************************************************************/
void vnc_key_map(FAR struct vnc_session_s *session, uint16_t keysym,
bool keydown)
{
#ifdef CONFIG_VNCSERVER_KBDENCODE
uint8_t buffer[4]
int nch;
#else
uint8_t buffer;
#endif
int16_t keych;
/* Check for modifier keys */
keych = vnc_kbd_lookup(g_modifiers, G_MODIFIERS_NELEM, keysym);
if (keych >= 0)
{
g_modstate[keych] = keydown;
return;
}
#ifndef CONFIG_VNCSERVER_KBDENCODE
/* If we are not encoding key presses, then we have to ignore key release
* events.
*/
if (!keydown)
{
return;
}
#endif
/* If no external keyboard input handler has been provided,
* then we have to drop the keyboard input.
*/
if (session->kbdout == NULL)
{
return;
}
/* Try to convert the keycode to an ASCII value */
keych = vnc_kbd_ascii((char)(keysym & 255));
if (keych >= 0)
{
/* It is a simple ASCII-mappable LATIN1 character. Now we need
* to apply any modifiers.
*/
if (g_modstate[MOD_CONTROL])
{
/* Make into a control character */
keych &= 0x1f;
}
/* Other modifiers apply only to printable characters */
else if (ISPRINTABLE(keych))
{
/* If Shift Lock is selected, then the case of all printable
* characters should be reversed (unless the Shift key is also
* pressed)
*/
if (g_modstate[MOD_SHIFTLOCK])
{
if (g_modstate[MOD_SHIFT])
{
/* Swap case */
keych = g_caseswap[keych];
}
}
/* If Caps Lock is selected, then the case of alphabetic
* characters should be reversed (unless the Shift key is also
* pressed)
*/
else if (g_modstate[MOD_CAPSLOCK] && ISALPHABETIC(keych))
{
if (g_modstate[MOD_SHIFT])
{
/* Swap case */
keych = g_caseswap[keych];
}
}
/* If (1) only the Shift Key is pressed or (2) the Shift key is
* pressed with Caps Lock, but the character is not alphabetic,
* then the case of all printable characters should be reversed.
*/
else if (g_modstate[MOD_SHIFT])
{
keych = g_caseswap[keych];
}
}
#ifdef CONFIG_VNCSERVER_KBDENCODE
/* Encode the normal character */
if (keydown)
{
nch = vnc_kbd_press(buffer, keych);
}
else
{
nch = vnc_kbd_release(buffer, keych);
}
/* Inject the normal character sequence into NX */
session->kbdout(session->arg, nch, buffer);
#else
/* Inject the single key press into NX */
buffer = (uint8_t)keych;
session->kbdout(session->arg, 1, &buffer);
#endif
}
/* Not mappable to an ASCII LATIN1 character */
#ifdef CONFIG_VNCSERVER_KBDENCODE
else
{
/* Lookup cursor movement/screen control keysyms */
keych = vnc_kbd_lookup(g_modifiers, G_MODIFIERS_NELEM, keysym);
if (keych >= 0)
{
/* Encode the speical character */
if (keydown)
{
nch = vnc_kbd_specpress(buffer, keych);
}
else
{
nch = vnc_kbd_specrel(buffer, keych);
}
/* Inject the special character sequence into NX */
session->kbdout(session->arg, nch, buffer);
}
}
#endif
}

View File

@@ -1,521 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_negotiate.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#ifdef CONFIG_NET_SOCKOPTS
# include <sys/time.h>
#endif
#include <nuttx/video/fb.h>
#include <nuttx/video/rfb.h>
#include "vnc_server.h"
/****************************************************************************
* Private Data
****************************************************************************/
#if defined(CONFIG_VNCSERVER_PROTO3p3)
static const char g_vncproto[] = RFB_PROTOCOL_VERSION_3p3;
#elif defined(CONFIG_VNCSERVER_PROTO3p8)
static const char g_vncproto[] = RFB_PROTOCOL_VERSION_3p8;
static const char g_nosecurity[] = "No security types are supported";
#endif
static const char g_vncname[] = CONFIG_VNCSERVER_NAME;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_negotiate
*
* Description:
* Perform the VNC initialization sequence after the client has successfully
* connected to the server. Negotiate security, framebuffer and color
* properties.
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Returns zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int vnc_negotiate(FAR struct vnc_session_s *session)
{
#ifdef CONFIG_VNCSERVER_PROTO3p3
FAR struct rfb_sectype_s *sectype;
#else /* ifdef CONFIG_VNCSERVER_PROTO3p8 */
FAR struct rfb_supported_sectypes_s *sectypes;
FAR struct rfb_selected_sectype_s *sectype;
FAR struct rfb_sectype_result_s *secresult;
FAR struct rfb_sectype_fail_s *secfail;
#endif
FAR struct rfb_serverinit_s *serverinit;
FAR struct rfb_pixelfmt_s *pixelfmt;
FAR struct rfb_setpixelformat_s *setformat;
FAR struct rfb_setencodings_s *encodings;
ssize_t nsent;
ssize_t nrecvd;
size_t len;
#ifdef CONFIG_NET_SOCKOPTS
struct timeval tv;
int ret;
/* Set a receive timeout so that we don't hang if the client does not
* respond according to RFB 3.3 protocol.
*/
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = psock_setsockopt(&session->connect, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(struct timeval));
if (ret < 0)
{
gerr("ERROR: Failed to set receive timeout: %d\n", ret);
return ret;
}
#endif
/* Inform the client of the VNC protocol version */
ginfo("Send protocol version: %s\n", g_vncproto);
len = strlen(g_vncproto);
nsent = psock_send(&session->connect, g_vncproto, len, 0);
if (nsent < 0)
{
gerr("ERROR: Send ProtocolVersion failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == len);
/* Receive the echo of the protocol string */
ginfo("Receive echo from VNC client\n");
nrecvd = psock_recv(&session->connect, session->inbuf, len, 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive protocol confirmation failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return -ECONNABORTED;
}
DEBUGASSERT(nrecvd == len);
#ifdef CONFIG_VNCSERVER_PROTO3p3
/* Version 3.3: The server decides the security type and sends a single
* word containing the security type: Tell the client that we won't use
* any stinkin' security.
*/
ginfo("Send SecurityType\n");
sectype = (FAR struct rfb_sectype_s *)session->outbuf;
rfb_putbe32(sectype->type, RFB_SECTYPE_NONE);
nsent = psock_send(&session->connect, sectype,
sizeof(struct rfb_sectype_s), 0);
if (nsent < 0)
{
gerr("ERROR: Send Security failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_s));
#else /* ifdef CONFIG_VNCSERVER_PROTO3p8 */
/* Version 3.8: Offer the client a choice of security -- where None is the
* only option offered.
*/
ginfo("Send SupportedSecurityTypes\n");
sectypes = (FAR struct rfb_supported_sectypes_s *)session->outbuf;
sectypes->ntypes = 1;
sectypes->type[0] = RFB_SECTYPE_NONE;
nsent = psock_send(&session->connect, sectypes,
SIZEOF_RFB_SUPPORTED_SECTYPES_S(1), 0);
if (nsent < 0)
{
gerr("ERROR: Send SupportedSecurityTypes failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == SIZEOF_RFB_SUPPORTED_SECTYPES_S(1));
/* If the server listed at least one valid security type supported by the
* client, the client sends back a single byte indicating which security
* type is to be used on the connection.
*/
ginfo("Receive SecurityType\n");
sectype = (FAR struct rfb_selected_sectype_s *)session->inbuf;
nrecvd = psock_recv(&session->connect, sectype,
sizeof(struct rfb_selected_sectype_s), 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive SecurityType failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return -ECONNABORTED;
}
DEBUGASSERT(nrecvd == sizeof(struct rfb_selected_sectype_s));
ginfo("Send SecurityResult\n");
secresult = (FAR struct rfb_sectype_result_s *)session->outbuf;
if (sectype->type != RFB_SECTYPE_NONE)
{
gerr("ERROR: Received unsupported SecurityType: %d\n", sectype->type);
/* REVISIT: Should send the reason string here */
rfb_putbe32(secresult->result, RFB_SECTYPE_FAIL);
nsent = psock_send(&session->connect, secresult,
sizeof(struct rfb_sectype_result_s), 0);
if (nsent < 0)
{
gerr("ERROR: Send SecurityResult failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_result_s));
ginfo("Send failure reason\n");
secfail = (FAR struct rfb_sectype_fail_s *)session->outbuf;
len = strlen(g_nosecurity);
rfb_putbe32(secfail->len, len);
memcpy(secfail->str, g_nosecurity, len);
nsent = psock_send(&session->connect, secfail,
SIZEOF_RFB_SECTYPE_FAIL_S(len), 0);
if (nsent < 0)
{
gerr("ERROR: Send failure reason failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == SIZEOF_RFB_SECTYPE_FAIL_S(len));
return -EPROTONOSUPPORT;
}
rfb_putbe32(secresult->result, RFB_SECTYPE_SUCCESS);
nsent = psock_send(&session->connect, secresult,
sizeof(struct rfb_sectype_result_s), 0);
if (nsent < 0)
{
gerr("ERROR: Send SecurityResult failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == sizeof(struct rfb_sectype_result_s));
#endif
/* Receive the ClientInit message
*
* "Once the client and server are sure that theyre happy to talk to one
* another using the agreed security type, the protocol passes to the
* initialization phase. The client sends a ClientInit message followed
* by the server sending a ServerInit message."
*
* In this implementation, the sharing flag is ignored.
*/
ginfo("Receive ClientInit\n");
nrecvd = psock_recv(&session->connect, session->inbuf,
sizeof(struct rfb_clientinit_s), 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive ClientInit failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return -ECONNABORTED;
}
DEBUGASSERT(nrecvd == sizeof(struct rfb_clientinit_s));
/* Send the ServerInit message
*
* "After receiving the ClientInit message, the server sends a ServerInit
* message. This tells the client the width and height of the servers
* framebuffer, its pixel format and the name associated with the
* desktop:"
*
* RealVNC client supports this resolutions:
* Full (all available colors) - Max resolution of the platform
* (TrueColor)
* Medium (256 colors) - 256 colors (Paletted)
* Low (64 colors) - RGB8 2:2:2 (default, TrueColor)
* Very Low (8 colors) - RGB3 1:1:1 (TrueColor)
*/
ginfo("Send ServerInit\n");
serverinit = (FAR struct rfb_serverinit_s *)session->outbuf;
rfb_putbe16(serverinit->width, CONFIG_VNCSERVER_SCREENWIDTH);
rfb_putbe16(serverinit->height, CONFIG_VNCSERVER_SCREENHEIGHT);
pixelfmt = &serverinit->format;
pixelfmt->bpp = RFB_BITSPERPIXEL;
pixelfmt->depth = RFB_PIXELDEPTH;
pixelfmt->bigendian = 0;
pixelfmt->truecolor = RFB_TRUECOLOR;
rfb_putbe16(pixelfmt->rmax, RFB_RMAX);
rfb_putbe16(pixelfmt->gmax, RFB_GMAX);
rfb_putbe16(pixelfmt->bmax, RFB_BMAX);
pixelfmt->rshift = RFB_RSHIFT;
pixelfmt->gshift = RFB_GSHIFT;
pixelfmt->bshift = RFB_BSHIFT;
len = strlen(g_vncname);
rfb_putbe32(serverinit->namelen, len);
memcpy(serverinit->name, g_vncname, len);
nsent = psock_send(&session->connect, serverinit,
SIZEOF_RFB_SERVERINIT_S(len), 0);
if (nsent < 0)
{
gerr("ERROR: Send ServerInit failed: %d\n", (int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == SIZEOF_RFB_SERVERINIT_S(len));
/* We now expect to receive the SetPixelFormat message from the client.
* This may override some of our framebuffer settings.
*/
ginfo("Receive SetPixelFormat\n");
setformat = (FAR struct rfb_setpixelformat_s *)session->inbuf;
nrecvd = psock_recv(&session->connect, setformat,
sizeof(struct rfb_setpixelformat_s), 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive SetPixelFormat failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return -ECONNABORTED;
}
else if (nrecvd != sizeof(struct rfb_setpixelformat_s))
{
/* Must not be a SetPixelFormat message? */
gerr("ERROR: SetFormat wrong size: %d\n", (int)nrecvd);
return -EPROTO;
}
else if (setformat->msgtype != RFB_SETPIXELFMT_MSG)
{
gerr("ERROR: Not a SetPixelFormat message: %d\n",
(int)setformat->msgtype);
return -EPROTO;
}
/* Instantiate the client pixel format, verifying that the client request
* format is one that we can handle.
*/
ret = vnc_client_pixelformat(session, &setformat->format);
if (ret < 0)
{
/* We do not support this pixel format */
gerr("ERROR: PixelFormat not supported\n");
return ret;
}
/* Receive supported encoding types from client. */
ginfo("Receive encoding types\n");
encodings = (FAR struct rfb_setencodings_s *)session->inbuf;
nrecvd = psock_recv(&session->connect, encodings,
CONFIG_VNCSERVER_INBUFFER_SIZE, 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive SetEncodings failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return -ECONNABORTED;
}
if (encodings->msgtype == RFB_SETENCODINGS_MSG)
{
DEBUGASSERT(nrecvd >= SIZEOF_RFB_SETENCODINGS_S(0));
/* Pick out any mutually supported encodings */
ret = vnc_client_encodings(session, encodings);
if (ret < 0)
{
gerr("ERROR: vnc_set_encodings failed: %d\n", ret);
return ret;
}
}
session->state = VNCSERVER_CONFIGURED;
return OK;
}
/****************************************************************************
* Name: vnc_client_pixelformat
*
* Description:
* A Client-to-Sever SetPixelFormat message has been received. We need to
* immediately switch the output color format that we generate.
*
* Input Parameters:
* session - An instance of the session structure.
* pixelfmt - The pixel from the received SetPixelFormat message
*
* Returned Value:
* Returns zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int vnc_client_pixelformat(FAR struct vnc_session_s *session,
FAR struct rfb_pixelfmt_s *pixelfmt)
{
if (pixelfmt->truecolor == 0)
{
/* At present, we support only TrueColor formats */
gerr("ERROR: No support for palette colors\n");
return -ENOSYS;
}
if (pixelfmt->bpp == 8 && pixelfmt->depth == 6)
{
ginfo("Client pixel format: RGB8 2:2:2\n");
session->colorfmt = FB_FMT_RGB8_222;
session->bpp = 8;
session->bigendian = false;
}
else if (pixelfmt->bpp == 8 && pixelfmt->depth == 8)
{
ginfo("Client pixel format: RGB8 3:3:2\n");
session->colorfmt = FB_FMT_RGB8_332;
session->bpp = 8;
session->bigendian = false;
}
else if (pixelfmt->bpp == 16 && pixelfmt->depth == 15)
{
ginfo("Client pixel format: RGB16 5:5:5\n");
session->colorfmt = FB_FMT_RGB16_555;
session->bpp = 16;
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
}
else if (pixelfmt->bpp == 16 && pixelfmt->depth == 16)
{
ginfo("Client pixel format: RGB16 5:6:5\n");
session->colorfmt = FB_FMT_RGB16_565;
session->bpp = 16;
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
}
else if (pixelfmt->bpp == 32 && pixelfmt->depth == 24)
{
ginfo("Client pixel format: RGB32 8:8:8\n");
session->colorfmt = FB_FMT_RGB32;
session->bpp = 32;
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
}
else if (pixelfmt->bpp == 32 && pixelfmt->depth == 32)
{
session->colorfmt = FB_FMT_RGB32;
session->bpp = 32;
session->bigendian = (pixelfmt->bigendian != 0) ? true : false;
}
else
{
/* We do not support any other conversions */
gerr("ERROR: No support for this BPP=%d and depth=%d\n",
pixelfmt->bpp, pixelfmt->depth);
return -ENOSYS;
}
session->change = true;
return OK;
}

View File

@@ -1,500 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_raw.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#include "vnc_server.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_copy8
*
* Description:
* Copy a 16/32-bit pixels from the source rectangle to a 8-bit pixel
* destination rectangle.
*
* Input Parameters:
* session - A reference to the VNC session structure.
* row,col - The upper left X/Y (pixel/row) position of the rectangle
* width,height - The width (pixels) and height (rows of the rectangle)
* convert - The function to use to convert from the local framebuffer
* color format to the remote framebuffer color format.
*
* Returned Value:
* The size of the transfer in bytes.
*
****************************************************************************/
static size_t vnc_copy8(FAR struct vnc_session_s *session,
fb_coord_t row, fb_coord_t col,
fb_coord_t height, fb_coord_t width,
vnc_convert8_t convert)
{
FAR struct rfb_framebufferupdate_s *update;
FAR const lfb_color_t *srcleft;
FAR const lfb_color_t *src;
FAR uint8_t *dest;
fb_coord_t x;
fb_coord_t y;
/* Destination rectangle start address */
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
dest = (FAR uint8_t *)update->rect[0].data;
/* Source rectangle start address (left/top) */
srcleft = (FAR lfb_color_t *)
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
/* Transfer each row from the source buffer into the update buffer */
for (y = 0; y < height; y++)
{
src = srcleft;
for (x = 0; x < width; x++)
{
*dest++ = convert(*src);
src++;
}
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
}
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
}
/****************************************************************************
* Name: vnc_copy16
*
* Description:
* Copy a 16/32-bit pixels from the source rectangle to a 16-bit pixel
* destination rectangle.
*
* Input Parameters:
* session - A reference to the VNC session structure.
* row,col - The upper left X/Y (pixel/row) position of the rectangle
* width,height - The width (pixels) and height (rows of the rectangle)
* convert - The function to use to convert from the local framebuffer
* color format to the remote framebuffer color format.
*
* Returned Value:
* The size of the transfer in bytes.
*
****************************************************************************/
static size_t vnc_copy16(FAR struct vnc_session_s *session,
fb_coord_t row, fb_coord_t col,
fb_coord_t height, fb_coord_t width,
vnc_convert16_t convert)
{
FAR struct rfb_framebufferupdate_s *update;
FAR const lfb_color_t *srcleft;
FAR const lfb_color_t *src;
FAR uint8_t *dest;
uint16_t pixel;
fb_coord_t x;
fb_coord_t y;
bool bigendian;
/* Destination rectangle start address */
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
dest = (FAR uint8_t *)update->rect[0].data;
/* Source rectangle start address (left/top) */
srcleft = (FAR lfb_color_t *)
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
/* Transfer each row from the source buffer into the update buffer */
bigendian = session->bigendian;
for (y = 0; y < height; y++)
{
src = srcleft;
for (x = 0; x < width; x++)
{
pixel = convert(*src);
if (bigendian)
{
rfb_putbe16(dest, pixel);
}
else
{
rfb_putle16(dest, pixel);
}
dest += sizeof(uint16_t);
src++;
}
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
}
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
}
/****************************************************************************
* Name: vnc_copy32
*
* Description:
* Copy a 16/32-bit pixels from the source rectangle to a 32-bit pixel
* destination rectangle.
*
* Input Parameters:
* session - A reference to the VNC session structure.
* row,col - The upper left X/Y (pixel/row) position of the rectangle
* width,height - The width (pixels) and height (rows of the rectangle)
* convert - The function to use to convert from the local framebuffer
* color format to the remote framebuffer color format.
*
* Returned Value:
* The size of the transfer in bytes.
*
****************************************************************************/
static size_t vnc_copy32(FAR struct vnc_session_s *session,
fb_coord_t row, fb_coord_t col,
fb_coord_t height, fb_coord_t width,
vnc_convert32_t convert)
{
FAR struct rfb_framebufferupdate_s *update;
FAR const lfb_color_t *srcleft;
FAR const lfb_color_t *src;
FAR uint8_t *dest;
fb_coord_t x;
fb_coord_t y;
uint32_t pixel;
bool bigendian;
/* Destination rectangle start address */
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
dest = (FAR uint8_t *)update->rect[0].data;
/* Source rectangle start address (left/top) */
srcleft = (FAR lfb_color_t *)
(session->fb + RFB_STRIDE * row + RFB_BYTESPERPIXEL * col);
/* Transfer each row from the source buffer into the update buffer */
bigendian = session->bigendian;
for (y = 0; y < height; y++)
{
src = srcleft;
for (x = 0; x < width; x++)
{
pixel = convert(*src);
if (bigendian)
{
rfb_putbe32(dest, pixel);
}
else
{
rfb_putle32(dest, pixel);
}
dest += sizeof(uint32_t);
src++;
}
srcleft = (FAR lfb_color_t *)((uintptr_t)srcleft + RFB_STRIDE);
}
return (size_t)((uintptr_t)dest - (uintptr_t)update->rect[0].data);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_raw
*
* Description:
* As a fallback, send the framebuffer update using the RAW encoding which
* must be supported by all VNC clients.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - Describes the rectangle in the local framebuffer.
*
* Returned Value:
* Zero (OK) on success; A negated errno value is returned on failure that
* indicates the nature of the failure. A failure is only returned
* in cases of a network failure and unexpected internal failures.
*
****************************************************************************/
int vnc_raw(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect)
{
FAR struct rfb_framebufferupdate_s *update;
FAR const uint8_t *src;
fb_coord_t srcwidth;
fb_coord_t srcheight;
fb_coord_t destwidth;
fb_coord_t destheight;
fb_coord_t deststride;
fb_coord_t updwidth;
fb_coord_t updheight;
fb_coord_t width;
fb_coord_t x;
fb_coord_t y;
unsigned int bytesperpixel;
unsigned int maxwidth;
size_t size;
ssize_t nsent;
uint8_t colorfmt;
union
{
vnc_convert8_t bpp8;
vnc_convert16_t bpp16;
vnc_convert32_t bpp32;
} convert;
/* Set up characteristics of the client pixel format to use on this
* update. These can change at any time if a SetPixelFormat is
* received asynchronously.
*/
bytesperpixel = (session->bpp + 7) >> 3;
maxwidth = CONFIG_VNCSERVER_UPDATE_BUFSIZE / bytesperpixel;
/* Set up the color conversion */
colorfmt = session->colorfmt;
switch (colorfmt)
{
case FB_FMT_RGB8_222:
convert.bpp8 = vnc_convert_rgb8_222;
break;
case FB_FMT_RGB8_332:
convert.bpp8 = vnc_convert_rgb8_332;
break;
case FB_FMT_RGB16_555:
convert.bpp16 = vnc_convert_rgb16_555;
break;
case FB_FMT_RGB16_565:
convert.bpp16 = vnc_convert_rgb16_565;
break;
case FB_FMT_RGB32:
convert.bpp32 = vnc_convert_rgb32_888;
break;
default:
gerr("ERROR: Unrecognized color format: %d\n", session->colorfmt);
return -EINVAL;
}
/* Get with width and height of the source and destination rectangles.
* The source rectangle many be larger than the destination rectangle.
* In that case, we will have to emit multiple rectangles.
*/
srcwidth = rect->w;
srcheight = rect->h;
deststride = srcwidth * bytesperpixel;
if (deststride > maxwidth)
{
deststride = maxwidth;
}
DEBUGASSERT(CONFIG_VNCSERVER_UPDATE_BUFSIZE >
SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0)));
destwidth = deststride / bytesperpixel;
/* Reserve some space for message header */
destheight = (CONFIG_VNCSERVER_UPDATE_BUFSIZE -
SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0))) /
deststride;
if (destheight > srcheight)
{
destheight = srcheight;
}
/* Format the rectangle header. We may have to send several update
* messages if the pre-allocated outbuf is smaller than the rectangle.
* Each update contains a small "sub-rectangle" of the origin update.
*
* Loop until all sub-rectangles have been output. Start with the
* top row and transfer rectangles horizontally across each swath.
* The height of the swath is destwidth (the last may be shorter).
*
* NOTE that the loop also terminates of the color format changes
* asynchronously.
*/
for (y = rect->y;
srcheight > 0 && colorfmt == session->colorfmt;
srcheight -= updheight, y += updheight)
{
/* updheight = Height to update on this pass through the loop.
* This will be destheight unless fewer than that number of rows
* remain.
*/
updheight = destheight;
if (updheight > srcheight)
{
updheight = srcheight;
}
/* Loop until this horizontal swath has been sent to the VNC client.
* Start with the leftmost pixel and transfer rectangles
* horizontally with width of destwidth until all srcwidth
* columns have been transferred (the last rectangle may be
* narrower).
*
* NOTE that the loop also terminates of the color format
* changes asynchronously.
*/
for (width = srcwidth, x = rect->x;
width > 0 && colorfmt == session->colorfmt;
width -= updwidth, x += updwidth)
{
/* updwidth = Width to update on this pass through the loop.
* This will be destwidth unless fewer than that number of
* columns remain.
*/
updwidth = destwidth;
if (updwidth > width)
{
updwidth = width;
}
/* Transfer the frame buffer data into the rectangle,
* performing the necessary color conversions.
*/
if (bytesperpixel == 1)
{
size = vnc_copy8(session, y, x, updheight, updwidth,
convert.bpp8);
}
else if (bytesperpixel == 2)
{
size = vnc_copy16(session, y, x, updheight, updwidth,
convert.bpp16);
}
else /* bytesperpixel == 4 */
{
size = vnc_copy32(session, y, x, updheight, updwidth,
convert.bpp32);
}
/* Format the FramebufferUpdate message */
update = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
update->msgtype = RFB_FBUPDATE_MSG;
update->padding = 0;
rfb_putbe16(update->nrect, 1);
rfb_putbe16(update->rect[0].xpos, x);
rfb_putbe16(update->rect[0].ypos, y);
rfb_putbe16(update->rect[0].width, updwidth);
rfb_putbe16(update->rect[0].height, updheight);
rfb_putbe32(update->rect[0].encoding, RFB_ENCODING_RAW);
DEBUGASSERT(size <= CONFIG_VNCSERVER_UPDATE_BUFSIZE);
/* We are ready to send the update packet to the VNC client */
size += SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0));
src = session->outbuf;
/* At the very last most, make certain that the color format
* has not changed asynchronously.
*/
if (colorfmt == session->colorfmt)
{
/* Okay send until all of the bytes are out. This may
* loop for the case where TCP write buffering is enabled
* and there are a limited number of IOBs available.
*/
do
{
nsent = psock_send(&session->connect, src, size, 0);
if (nsent < 0)
{
gerr("ERROR: Send FrameBufferUpdate failed: %d\n",
(int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent <= size);
src += nsent;
size -= nsent;
}
while (size > 0);
updinfo("Sent {(%d, %d),(%d, %d)}\n",
x, y, x + updwidth -1, y + updheight - 1);
}
}
}
return OK;
}

View File

@@ -1,478 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_receiver.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#ifdef CONFIG_NET_SOCKOPTS
# include <sys/time.h>
#endif
#include <nuttx/net/net.h>
#include <nuttx/video/rfb.h>
#include <nuttx/video/vnc.h>
#include <nuttx/input/mouse.h>
#include "vnc_server.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_read_remainder
*
* Description:
* After receiving the first byte of a client-to-server message, this
* reads in the remainder of the message.
*
* Input Parameters:
* session - An instance of the session structure.
* msglen - The full length of the message
*
* Returned Value:
* At present, always returns OK
*
****************************************************************************/
int vnc_read_remainder(FAR struct vnc_session_s *session, size_t msglen,
size_t offset)
{
ssize_t nrecvd;
size_t ntotal;
/* Loop until the rest of the message is received. */
for (ntotal = 0; ntotal < msglen; offset += nrecvd, ntotal += nrecvd)
{
/* Receive more of the message */
nrecvd = psock_recv(&session->connect, &session->inbuf[offset],
msglen - ntotal, 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive message failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_receiver
*
* Description:
* This function handles all Client-to-Server messages.
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* At present, always returns OK
*
****************************************************************************/
int vnc_receiver(FAR struct vnc_session_s *session)
{
#ifdef CONFIG_NET_SOCKOPTS
struct timeval tv;
#endif
ssize_t nrecvd;
int ret;
DEBUGASSERT(session);
ginfo("Receiver running for Display %d\n", session->display);
#ifdef CONFIG_NET_SOCKOPTS
/* Disable the receive timeout so that we will wait indefinitely for the
* next Client-to-Server message.
*/
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = psock_setsockopt(&session->connect, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(struct timeval));
if (ret < 0)
{
gerr("ERROR: Failed to disable receive timeout: %d\n", ret);
return ret;
}
#endif
/* Loop until the client disconnects or an unhandled error occurs */
for (; ; )
{
/* Set up to read one byte which should be the message type of the
* next Client-to-Server message. We will block here until the message
* is received.
*/
nrecvd = psock_recv(&session->connect, session->inbuf, 1, 0);
if (nrecvd < 0)
{
gerr("ERROR: Receive byte failed: %d\n", (int)nrecvd);
return (int)nrecvd;
}
/* A return value of zero means that the connection was gracefully
* closed by the VNC client.
*/
else if (nrecvd == 0)
{
gwarn("WARNING: Connection closed\n");
return OK;
}
DEBUGASSERT(nrecvd == 1);
/* The single byte received should be the message type. Handle the
* message according to this message type.
*/
switch (session->inbuf[0])
{
case RFB_SETPIXELFMT_MSG: /* SetPixelFormat */
{
ginfo("Received SetPixelFormat\n");
/* Read the rest of the SetPixelFormat message */
ret = vnc_read_remainder(session,
sizeof(struct rfb_setpixelformat_s) - 1,
1);
if (ret < 0)
{
gerr("ERROR: Failed to read SetPixelFormat message: %d\n",
ret);
}
else
{
FAR struct rfb_setpixelformat_s *setformat =
(FAR struct rfb_setpixelformat_s *)session->inbuf;
ret = vnc_client_pixelformat(session, &setformat->format);
if (ret < 0)
{
/* We do not support this pixel format */
/* REVISIT:
* We are going to be putting garbage on the RFB
*/
gerr("ERROR: PixelFormat not supported\n");
}
}
}
break;
case RFB_SETENCODINGS_MSG: /* SetEncodings */
{
FAR struct rfb_setencodings_s *encodings;
unsigned int nencodings;
ginfo("Received SetEncodings\n");
/* Read the SetEncodings message without the following
* encodings.
*/
ret = vnc_read_remainder(session,
SIZEOF_RFB_SERVERINIT_S(0) - 1,
1);
if (ret < 0)
{
gerr("ERROR: Failed to read SetEncodings message: %d\n",
ret);
}
else
{
/* Read the following encodings */
encodings = (FAR struct rfb_setencodings_s *)
session->inbuf;
nencodings = rfb_getbe16(encodings->nencodings);
ret = vnc_read_remainder(session,
nencodings * sizeof(uint32_t),
SIZEOF_RFB_SERVERINIT_S(0));
if (ret < 0)
{
gerr("ERROR: Failed to read encodings: %d\n",
ret);
}
else
{
/* Pick out any mutually supported encodings */
ret = vnc_client_encodings(session, encodings);
if (ret < 0)
{
gerr("ERROR: vnc_set_encodings failed: %d\n", ret);
}
}
}
}
break;
case RFB_FBUPDATEREQ_MSG: /* FramebufferUpdateRequest */
{
FAR struct rfb_fbupdatereq_s *update;
struct fb_area_s rect;
ginfo("Received FramebufferUpdateRequest\n");
/* Read the rest of the FramebufferUpdateRequest message */
ret = vnc_read_remainder(session,
sizeof(struct rfb_fbupdatereq_s) - 1,
1);
if (ret < 0)
{
gerr("ERROR: "
"Failed to read FramebufferUpdateRequest message: %d\n",
ret);
}
else
{
/* Enqueue the update */
update = (FAR struct rfb_fbupdatereq_s *)session->inbuf;
rect.x = rfb_getbe16(update->xpos);
rect.y = rfb_getbe16(update->ypos);
rect.w = rfb_getbe16(update->width);
rect.h = rfb_getbe16(update->height);
ret = vnc_update_rectangle(session, &rect, false);
if (ret < 0)
{
gerr("ERROR: Failed to queue update: %d\n", ret);
}
}
}
break;
case RFB_KEYEVENT_MSG: /* KeyEvent */
{
FAR struct rfb_keyevent_s *keyevent;
ginfo("Received KeyEvent\n");
/* Read the rest of the KeyEvent message */
ret = vnc_read_remainder(session,
sizeof(struct rfb_keyevent_s) - 1,
1);
if (ret < 0)
{
gerr("ERROR: Failed to read KeyEvent message: %d\n",
ret);
}
else
{
/* Inject the key press/release event into NX */
keyevent = (FAR struct rfb_keyevent_s *)session->inbuf;
vnc_key_map(session, rfb_getbe16(keyevent->key),
(bool)keyevent->down);
}
}
break;
case RFB_POINTEREVENT_MSG: /* PointerEvent */
{
FAR struct rfb_pointerevent_s *event;
uint8_t buttons;
ginfo("Received PointerEvent\n");
/* Read the rest of the PointerEvent message */
ret = vnc_read_remainder(session,
sizeof(struct rfb_pointerevent_s) - 1,
1);
if (ret < 0)
{
gerr("ERROR: Failed to read PointerEvent message: %d\n",
ret);
}
else if (session->mouseout != NULL)
{
event = (FAR struct rfb_pointerevent_s *)session->inbuf;
/* Map buttons bitmap. Bits 0-7 are buttons 1-8, 0=up,
* 1=down. By convention Bit 0 = left button, Bit 1 =
* middle button, and Bit 2 = right button.
*/
buttons = 0;
if ((event->buttons & (1 << 0)) != 0)
{
buttons |= MOUSE_BUTTON_1;
}
if ((event->buttons & (1 << 1)) != 0)
{
buttons |= MOUSE_BUTTON_2;
}
if ((event->buttons & (1 << 2)) != 0)
{
buttons |= MOUSE_BUTTON_3;
}
session->mouseout(session->arg,
(fb_coord_t)rfb_getbe16(event->xpos),
(fb_coord_t)rfb_getbe16(event->ypos),
buttons);
}
}
break;
case RFB_CLIENTCUTTEXT_MSG: /* ClientCutText */
{
FAR struct rfb_clientcuttext_s *cuttext;
uint32_t length;
ginfo("Received ClientCutText\n");
/* Read the ClientCutText message without the following
* text.
*/
ret = vnc_read_remainder(session,
SIZEOF_RFB_CLIENTCUTTEXT_S(0) - 1,
1);
if (ret < 0)
{
gerr("ERROR: Failed to read ClientCutText message: %d\n",
ret);
}
else
{
/* Read the following text */
cuttext = (FAR struct rfb_clientcuttext_s *)session->inbuf;
length = rfb_getbe32(cuttext->length);
ret = vnc_read_remainder(session, length,
SIZEOF_RFB_CLIENTCUTTEXT_S(0));
if (ret < 0)
{
gerr("ERROR: Failed to read text: %d\n",
ret);
}
else
{
/* REVISIT: ClientCutText is currently ignored */
}
}
}
break;
default:
gerr("ERROR: Unsynchronized, msgtype=%d\n", session->inbuf[0]);
return -EPROTO;
}
}
return -ENOSYS;
}
/****************************************************************************
* Name: vnc_client_encodings
*
* Description:
* Pick out any mutually supported encodings from the Client-to-Server
* SetEncodings message
*
* Input Parameters:
* session - An instance of the session structure.
* encodings - The received SetEncodings message
*
* Returned Value:
* At present, always returns OK
*
****************************************************************************/
int vnc_client_encodings(FAR struct vnc_session_s *session,
FAR struct rfb_setencodings_s *encodings)
{
uint32_t encoding;
unsigned int nencodings;
unsigned int i;
DEBUGASSERT(session != NULL && encodings != NULL);
/* Assume that there are no common encodings (other than RAW) */
session->rre = false;
/* Loop for each client supported encoding */
nencodings = rfb_getbe16(encodings->nencodings);
for (i = 0; i < nencodings; i++)
{
/* Get the next encoding */
encoding = rfb_getbe32(&encodings->encodings[i << 2]);
/* Only a limited support for of RRE is available now. */
if (encoding == RFB_ENCODING_RRE)
{
session->rre = true;
}
}
session->change = true;
return OK;
}

View File

@@ -1,273 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_rre.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#include "vnc_server.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct rre_encode8_s
{
struct rfb_rrehdr8_s hdr;
struct rfb_rrerect8_s rect;
};
struct rre_encode16_s
{
struct rfb_rrehdr16_s hdr;
struct rfb_rrerect16_s rect;
};
struct rre_encode32_s
{
struct rfb_rrehdr32_s hdr;
struct rfb_rrerect32_s rect;
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_rreNN
*
* Description:
* Encode a single RRE sub-rectangle, NN=bits-per-pixel
*
* Input Parameters:
* session - An instance of the session structure.
* dest - The locate to save the RRE encoded data
* rect - Describes the rectangle in the local framebuffer.
* bgcolor - The local color of the pixel data
*
* Returned Value:
* The size of the framebuffer update message is returned..
*
****************************************************************************/
ssize_t vnc_rre8(FAR struct vnc_session_s *session,
FAR struct rre_encode8_s *dest,
FAR struct fb_area_s *rect,
uint8_t bgcolor)
{
rfb_putbe32(dest->hdr.nsubrects, 1);
dest->hdr.pixel = bgcolor;
dest->rect.pixel = bgcolor;
rfb_putbe16(dest->rect.xpos, rect->x);
rfb_putbe16(dest->rect.ypos, rect->y);
rfb_putbe16(dest->rect.width, rect->w);
rfb_putbe16(dest->rect.height, rect->h);
return sizeof(struct rre_encode8_s);
}
ssize_t vnc_rre16(FAR struct vnc_session_s *session,
FAR struct rre_encode16_s *dest,
FAR struct fb_area_s *rect,
uint16_t bgcolor)
{
rfb_putbe32(dest->hdr.nsubrects, 1);
rfb_putbe16(dest->hdr.pixel, bgcolor);
rfb_putbe16(dest->rect.pixel, bgcolor);
rfb_putbe16(dest->rect.xpos, rect->x);
rfb_putbe16(dest->rect.ypos, rect->y);
rfb_putbe16(dest->rect.width, rect->w);
rfb_putbe16(dest->rect.height, rect->h);
return sizeof(struct rre_encode16_s);
}
ssize_t vnc_rre32(FAR struct vnc_session_s *session,
FAR struct rre_encode32_s *dest,
FAR struct fb_area_s *rect,
uint32_t bgcolor)
{
rfb_putbe32(dest->hdr.nsubrects, 1);
rfb_putbe32(dest->hdr.pixel, bgcolor);
rfb_putbe32(dest->rect.pixel, bgcolor);
rfb_putbe16(dest->rect.xpos, rect->x);
rfb_putbe16(dest->rect.ypos, rect->y);
rfb_putbe16(dest->rect.width, rect->w);
rfb_putbe16(dest->rect.height, rect->h);
return sizeof(struct rre_encode32_s);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_rre
*
* Description:
* This function does not really do RRE encoding. It just checks if the
* update region is one color then uses the RRE encoding format to send
* the constant color rectangle.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - Describes the rectangle in the local framebuffer.
*
* Returned Value:
* Zero is returned if RRE coding was not performed (but no error was
* encountered). Otherwise, the size of the framebuffer update message
* is returned on success or a negated errno value is returned on failure
* that indicates the nature of the failure. A failure is only
* returned in cases of a network failure and unexpected internal failures.
*
****************************************************************************/
int vnc_rre(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect)
{
FAR struct rfb_framebufferupdate_s *rre;
FAR struct rfb_rectangle_s *rrect;
lfb_color_t bgcolor;
size_t nbytes;
ssize_t nsent;
int ret;
/* Check if the client supports the RRE encoding */
if (session->rre)
{
/* Check if the update region contains only a single color */
ret = vnc_colors(session, rect, 1, &bgcolor);
if (ret == 1)
{
/* Format the FrameBuffer Update with a single RRE encoded
* rectangle.
*/
rre = (FAR struct rfb_framebufferupdate_s *)session->outbuf;
rre->msgtype = RFB_FBUPDATE_MSG;
rre->padding = 0;
rfb_putbe16(rre->nrect, 1);
rrect = (FAR struct rfb_rectangle_s *)&rre->rect;
rfb_putbe16(rrect->xpos, rect->x);
rfb_putbe16(rrect->ypos, rect->y);
rfb_putbe16(rrect->width, rect->w);
rfb_putbe16(rrect->height, rect->h);
rfb_putbe32(rrect->encoding, RFB_ENCODING_RRE);
/* The sub-rectangle encoding depends of the remote pixel width */
nbytes = SIZEOF_RFB_FRAMEBUFFERUPDATE_S(SIZEOF_RFB_RECTANGE_S(0));
switch (session->colorfmt)
{
case FB_FMT_RGB8_222:
nbytes += vnc_rre8(session,
(FAR struct rre_encode8_s *)rrect->data,
rect, vnc_convert_rgb8_222(bgcolor));
break;
case FB_FMT_RGB8_332:
nbytes += vnc_rre8(session,
(FAR struct rre_encode8_s *)rrect->data,
rect, vnc_convert_rgb8_332(bgcolor));
break;
case FB_FMT_RGB16_555:
nbytes += vnc_rre16(session,
(FAR struct rre_encode16_s *)rrect->data,
rect, vnc_convert_rgb16_555(bgcolor));
break;
case FB_FMT_RGB16_565:
nbytes += vnc_rre16(session,
(FAR struct rre_encode16_s *)rrect->data,
rect, vnc_convert_rgb16_565(bgcolor));
break;
case FB_FMT_RGB32:
nbytes += vnc_rre32(session,
(FAR struct rre_encode32_s *)rrect->data,
rect, vnc_convert_rgb32_888(bgcolor));
break;
default:
gerr("ERROR: Unrecognized color format: %d\n",
session->colorfmt);
return -EINVAL;
}
/* At the very last most, make certain that the supported encoding
* has not changed asynchronously.
*/
if (session->rre)
{
/* Okay send until all of the bytes are out. This may
* loop for the case where TCP write buffering is enabled
* and there are a limited number of IOBs available.
*/
nsent = psock_send(&session->connect, rre, nbytes, 0);
if (nsent < 0)
{
gerr("ERROR: Send RRE FrameBufferUpdate failed: %d\n",
(int)nsent);
return (int)nsent;
}
DEBUGASSERT(nsent == nbytes);
updinfo("Sent {(%d, %d),(%d, %d)}\n",
rect->x, rect->y, rect->w, rect->h);
return nbytes;
}
return -EINVAL;
}
}
return 0;
}

View File

@@ -1,373 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_server.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "nuttx/config.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <queue.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
#include "vnc_server.h"
/****************************************************************************
* Public Data
****************************************************************************/
/* Given a display number as an index, the following array can be used to
* look-up the session structure for that display.
*/
FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_reset_session
*
* Description:
* Conclude the current VNC session. This function re-initializes the
* session structure; it does not free either the session structure nor
* the framebuffer so that they may be re-used.
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void vnc_reset_session(FAR struct vnc_session_s *session,
FAR uint8_t *fb, int display)
{
int i;
/* Close any open sockets */
if (session->state >= VNCSERVER_CONNECTED)
{
psock_close(&session->connect);
psock_close(&session->listen);
}
/* [Re-]initialize the session. */
memset(&session->connect, 0, sizeof(struct socket));
memset(&session->listen, 0, sizeof(struct socket));
/* Put all of the pre-allocated update structures into the freelist */
sq_init(&session->updqueue);
sq_init(&session->updfree);
for (i = 0; i < CONFIG_VNCSERVER_NUPDATES; i++)
{
sq_addlast((FAR sq_entry_t *)&session->updpool[i], &session->updfree);
}
/* Set the INITIALIZED state */
nxsem_reset(&session->freesem, CONFIG_VNCSERVER_NUPDATES);
nxsem_reset(&session->queuesem, 0);
session->fb = fb;
session->display = display;
session->state = VNCSERVER_INITIALIZED;
session->nwhupd = 0;
session->change = true;
/* Careful not to disturb the keyboard/mouse callouts set by
* vnc_fbinitialize(). Client related data left in garbage state.
*/
}
/****************************************************************************
* Name: vnc_connect
*
* Description:
* Wait for a connection from the VNC client
*
* Input Parameters:
* session - An instance of the session structure.
* port - The listen port to use
*
* Returned Value:
* Returns zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
static int vnc_connect(FAR struct vnc_session_s *session, int port)
{
struct sockaddr_in addr;
int ret;
ginfo("Connecting display %d\n", session->display);
/* Create a listening socket */
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
ret = psock_socket(AF_INET, SOCK_STREAM, 0, &session->listen);
if (ret < 0)
{
return ret;
}
/* Bind the listening socket to a local address */
ret = psock_bind(&session->listen, (struct sockaddr *)&addr,
sizeof(struct sockaddr_in));
if (ret < 0)
{
goto errout_with_listener;
}
/* Listen for a connection */
ret = psock_listen(&session->listen, 5);
if (ret < 0)
{
goto errout_with_listener;
}
/* Connect to the client */
ginfo("Accepting connection for Display %d\n", session->display);
ret = psock_accept(&session->listen, NULL, NULL, &session->connect);
if (ret < 0)
{
goto errout_with_listener;
}
ginfo("Display %d connected\n", session->display);
session->state = VNCSERVER_CONNECTED;
return OK;
errout_with_listener:
psock_close(&session->listen);
return ret;
}
/****************************************************************************
* Pubic Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_server
*
* Description:
* The VNC server daemon. This daemon is implemented as a kernel thread.
*
* Input Parameters:
* Standard kernel thread arguments (all ignored)
*
* Returned Value:
* This function does not return.
*
****************************************************************************/
int vnc_server(int argc, FAR char *argv[])
{
FAR struct vnc_session_s *session;
FAR uint8_t *fb;
int display;
int ret;
/* A single argument is expected: A display port number in ASCII form */
if (argc != 2)
{
/* In this case the start-up logic will probably hang, waiting for the
* display-related semaphore to be set.
*/
gerr("ERROR: Unexpected number of arguments: %d\n", argc);
ret = -EINVAL;
goto errout_with_hang;
}
display = atoi(argv[1]);
if (display < 0 || display >= RFB_MAX_DISPLAYS)
{
/* In this case the start-up logic will probably hang, waiting for the
* display-related semaphore to be set.
*/
gerr("ERROR: Invalid display number: %d\n", display);
ret = -EINVAL;
goto errout_with_hang;
}
ginfo("Server started for Display %d\n", display);
/* Allocate the framebuffer memory. We rely on the fact that
* the KMM allocator will align memory to 32-bits or better.
*/
fb = (FAR uint8_t *)kmm_zalloc(RFB_SIZE);
if (fb == NULL)
{
gerr("ERROR: Failed to allocate framebuffer memory: %lu KB\n",
(unsigned long)(RFB_SIZE / 1024));
ret = -ENOMEM;
goto errout_with_post;
}
/* Allocate a session structure for this display */
session = kmm_zalloc(sizeof(struct vnc_session_s));
if (session == NULL)
{
gerr("ERROR: Failed to allocate session\n");
ret = -ENOMEM;
goto errout_with_fb;
}
g_vnc_sessions[display] = session;
nxsem_init(&session->freesem, 0, CONFIG_VNCSERVER_NUPDATES);
nxsem_init(&session->queuesem, 0, 0);
#ifdef CONFIG_FB_SYNC
nxsem_init(&session->vsyncsem, 0, 0);
nxsem_set_protocol(&session->vsyncsem, SEM_PRIO_NONE);
#endif
/* Inform any waiter that we have started */
vnc_reset_session(session, fb, display);
nxsem_post(&g_fbstartup[display].fbinit);
/* Loop... handling each each VNC client connection to this display. Only
* a single client is allowed for each display.
*/
for (; ; )
{
/* Release the last session and [Re-]initialize the session structure
* for the next connection.
*/
vnc_reset_session(session, fb, display);
g_fbstartup[display].result = -EBUSY;
nxsem_reset(&g_fbstartup[display].fbconnect, 0);
/* Establish a connection with the VNC client */
ret = vnc_connect(session, RFB_DISPLAY_PORT(display));
if (ret >= 0)
{
ginfo("New VNC connection\n");
/* Perform the VNC initialization sequence after the client has
* successfully connected to the server. Negotiate security,
* framebuffer and color properties.
*/
ret = vnc_negotiate(session);
if (ret < 0)
{
gerr("ERROR: Failed to negotiate security/framebuffer: %d\n",
ret);
continue;
}
/* Start the VNC updater thread that sends all Server-to-Client
* messages.
*/
ret = vnc_start_updater(session);
if (ret < 0)
{
gerr("ERROR: Failed to start updater thread: %d\n", ret);
continue;
}
/* Let the framebuffer driver know that we are ready to perform
* updates.
*/
g_fbstartup[display].result = OK;
nxsem_post(&g_fbstartup[display].fbconnect);
/* Run the VNC receiver on this trhead. The VNC receiver handles
* all Client-to-Server messages. The VNC receiver function does
* not return until the session has been terminated (or an error
* occurs).
*/
ret = vnc_receiver(session);
ginfo("Session terminated with %d\n", ret);
UNUSED(ret);
/* Stop the VNC updater thread. */
ret = vnc_stop_updater(session);
if (ret < 0)
{
gerr("ERROR: Failed to stop updater thread: %d\n", ret);
}
}
}
errout_with_fb:
kmm_free(fb);
errout_with_post:
g_fbstartup[display].result = ret;
nxsem_post(&g_fbstartup[display].fbconnect);
errout_with_hang:
return EXIT_FAILURE;
}

View File

@@ -1,563 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_server.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __GRAPHICS_VNC_SERVER_VNC_SERVER_H
#define __GRAPHICS_VNC_SERVER_VNC_SERVER_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <pthread.h>
#include <queue.h>
#include <nuttx/video/fb.h>
#include <nuttx/video/rfb.h>
#include <nuttx/video/vnc.h>
#include <nuttx/net/net.h>
#include <nuttx/semaphore.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration */
#if !defined(CONFIG_VNCSERVER_PROTO3p3) && !defined(CONFIG_VNCSERVER_PROTO3p8)
# error No VNC protocol selected
#endif
#if defined(CONFIG_VNCSERVER_PROTO3p3) && defined(CONFIG_VNCSERVER_PROTO3p8)
# error Too many VNC protocols selected
#endif
#ifndef CONFIG_VNCSERVER_NDISPLAYS
# define CONFIG_VNCSERVER_NDISPLAYS 1
#endif
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
# define RFB_COLORFMT FB_FMT_RGB8_332
# define RFB_BITSPERPIXEL 8
# define RFB_PIXELDEPTH 8
# define RFB_TRUECOLOR 1
# define RFB_RMAX 0x07
# define RFB_GMAX 0x07
# define RFB_BMAX 0x03
# define RFB_RSHIFT 5
# define RFB_GSHIFT 2
# define RFB_BSHIFT 0
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
# define RFB_COLORFMT FB_FMT_RGB16_565
# define RFB_BITSPERPIXEL 16
# define RFB_PIXELDEPTH 16
# define RFB_TRUECOLOR 1
# define RFB_RMAX 0x001f
# define RFB_GMAX 0x003f
# define RFB_BMAX 0x001f
# define RFB_RSHIFT 11
# define RFB_GSHIFT 5
# define RFB_BSHIFT 0
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
# define RFB_COLORFMT FB_FMT_RGB32
# define RFB_BITSPERPIXEL 32
# define RFB_PIXELDEPTH 24
# define RFB_TRUECOLOR 1
# define RFB_RMAX 0x000000ff
# define RFB_GMAX 0x000000ff
# define RFB_BMAX 0x000000ff
# define RFB_RSHIFT 16
# define RFB_GSHIFT 8
# define RFB_BSHIFT 0
#else
# error Unspecified/unsupported color format
#endif
#ifndef CONFIG_VNCSERVER_SCREENWIDTH
# define CONFIG_VNCSERVER_SCREENWIDTH 320
#endif
#ifndef CONFIG_VNCSERVER_SCREENHEIGHT
# define CONFIG_VNCSERVER_SCREENHEIGHT 240
#endif
#ifndef CONFIG_VNCSERVER_NAME
# define CONFIG_VNCSERVER_NAME "NuttX"
#endif
#ifndef CONFIG_VNCSERVER_PRIO
# define CONFIG_VNCSERVER_PRIO 100
#endif
#ifndef CONFIG_VNCSERVER_STACKSIZE
# define CONFIG_VNCSERVER_STACKSIZE 2048
#endif
#ifndef CONFIG_VNCSERVER_UPDATER_PRIO
# define CONFIG_VNCSERVER_UPDATER_PRIO 100
#endif
#ifndef CONFIG_VNCSERVER_UPDATER_STACKSIZE
# define CONFIG_VNCSERVER_UPDATER_STACKSIZE 2048
#endif
#ifndef CONFIG_VNCSERVER_INBUFFER_SIZE
# define CONFIG_VNCSERVER_INBUFFER_SIZE 80
#endif
#ifndef CONFIG_VNCSERVER_NUPDATES
# define CONFIG_VNCSERVER_NUPDATES 48
#endif
#ifndef CONFIG_VNCSERVER_UPDATE_BUFSIZE
# define CONFIG_VNCSERVER_UPDATE_BUFSIZE 4096
#endif
#define VNCSERVER_UPDATE_BUFSIZE \
(CONFIG_VNCSERVER_UPDATE_BUFSIZE + SIZEOF_RFB_FRAMEBUFFERUPDATE_S(0))
/* Local framebuffer characteristics in bytes */
#define RFB_BYTESPERPIXEL ((RFB_BITSPERPIXEL + 7) >> 3)
#define RFB_STRIDE (RFB_BYTESPERPIXEL * CONFIG_VNCSERVER_SCREENWIDTH)
#define RFB_SIZE (RFB_STRIDE * CONFIG_VNCSERVER_SCREENHEIGHT)
/* RFB Port Number */
#define RFB_PORT_BASE 5900
#define RFB_MAX_DISPLAYS CONFIG_VNCSERVER_NDISPLAYS
#define RFB_DISPLAY_PORT(d) (RFB_PORT_BASE + (d))
/* Miscellaneous */
#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
/* Debug */
#ifdef CONFIG_VNCSERVER_UPDATE_DEBUG
# define upderr _err
# define updwarn _warn
# define updinfo _info
#else
# define upderr _none
# define updwarn _none
# define updinfo _none
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/* This enumeration indicates the state of the VNC server */
enum vnc_server_e
{
VNCSERVER_UNINITIALIZED = 0, /* Initial state */
VNCSERVER_INITIALIZED, /* State structured initialized, but not connected */
VNCSERVER_CONNECTED, /* Connect to a client, but not yet configured */
VNCSERVER_CONFIGURED, /* Configured and ready to transfer graphics */
VNCSERVER_RUNNING, /* Running and actively transferring graphics */
VNCSERVER_STOPPING, /* The updater has been asked to stop */
VNCSERVER_STOPPED /* The updater has stopped */
};
/* This structure is used to queue FrameBufferUpdate event. It includes a
* pointer to support singly linked list.
*/
struct vnc_fbupdate_s
{
FAR struct vnc_fbupdate_s *flink;
bool whupd; /* True: whole screen update */
struct fb_area_s rect; /* The enqueued update rectangle */
};
struct vnc_session_s
{
/* Connection data */
struct socket listen; /* Listen socket */
struct socket connect; /* Connected socket */
volatile uint8_t state; /* See enum vnc_server_e */
volatile uint8_t nwhupd; /* Number of whole screen updates queued */
volatile bool change; /* True: Frambebuffer data change since last whole screen update */
/* Display geometry and color characteristics */
uint8_t display; /* Display number (for debug) */
volatile uint8_t colorfmt; /* Remote color format (See include/nuttx/fb.h) */
volatile uint8_t bpp; /* Remote bits per pixel */
volatile bool bigendian; /* True: Remote expect data in big-endian format */
volatile bool rre; /* True: Remote supports RRE encoding */
FAR uint8_t *fb; /* Allocated local frame buffer */
/* VNC client input support */
vnc_kbdout_t kbdout; /* Callout when keyboard input is received */
vnc_mouseout_t mouseout; /* Callout when keyboard input is received */
FAR void *arg; /* Argument that accompanies the callouts */
/* Updater information */
pthread_t updater; /* Updater thread ID */
/* Update list information */
struct vnc_fbupdate_s updpool[CONFIG_VNCSERVER_NUPDATES];
sq_queue_t updfree;
sq_queue_t updqueue;
sem_t freesem;
sem_t queuesem;
#ifdef CONFIG_FB_SYNC
sem_t vsyncsem;
#endif
/* I/O buffers for misc network send/receive */
uint8_t inbuf[CONFIG_VNCSERVER_INBUFFER_SIZE];
uint8_t outbuf[VNCSERVER_UPDATE_BUFSIZE];
};
/* This structure is used to communicate start-up status between the server
* the framebuffer driver.
*/
struct fb_startup_s
{
sem_t fbinit; /* Wait for session creation */
sem_t fbconnect; /* Wait for client connection */
int16_t result; /* OK: successfully initialized */
};
/* The size of the color type in the local framebuffer */
#if defined(CONFIG_VNCSERVER_COLORFMT_RGB8)
typedef uint8_t lfb_color_t;
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB16)
typedef uint16_t lfb_color_t;
#elif defined(CONFIG_VNCSERVER_COLORFMT_RGB32)
typedef uint32_t lfb_color_t;
#else
# error Unspecified/unsupported color format
#endif
/* Color conversion function pointer types */
typedef CODE uint8_t (*vnc_convert8_t) (lfb_color_t rgb);
typedef CODE uint16_t (*vnc_convert16_t)(lfb_color_t rgb);
typedef CODE uint32_t (*vnc_convert32_t)(lfb_color_t rgb);
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* Given a display number as an index, the following array can be used to
* look-up the session structure for that display.
*/
EXTERN FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS];
/* Used to synchronize the server thread with the framebuffer driver. */
EXTERN struct fb_startup_s g_fbstartup[RFB_MAX_DISPLAYS];
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: vnc_server
*
* Description:
* The VNC server daemon. This daemon is implemented as a kernel thread.
*
* Input Parameters:
* Standard kernel thread arguments (all ignored)
*
* Returned Value:
* This function does not return.
*
****************************************************************************/
int vnc_server(int argc, FAR char *argv[]);
/****************************************************************************
* Name: vnc_negotiate
*
* Description:
* Perform the VNC initialization sequence after the client has successfully
* connected to the server. Negotiate security, framebuffer and color
* properties.
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Returns zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int vnc_negotiate(FAR struct vnc_session_s *session);
/****************************************************************************
* Name: vnc_client_pixelformat
*
* Description:
* A Client-to-Sever SetPixelFormat message has been received. We need to
* immediately switch the output color format that we generate.
*
* Input Parameters:
* session - An instance of the session structure.
* pixelfmt - The pixel from the received SetPixelFormat message
*
* Returned Value:
* Returns zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int vnc_client_pixelformat(FAR struct vnc_session_s *session,
FAR struct rfb_pixelfmt_s *pixelfmt);
/****************************************************************************
* Name: vnc_client_encodings
*
* Description:
* Pick out any mutually supported encodings from the Client-to-Server
* SetEncodings message
*
* Input Parameters:
* session - An instance of the session structure.
* encodings - The received SetEncodings message
*
* Returned Value:
* At present, always returns OK
*
****************************************************************************/
int vnc_client_encodings(FAR struct vnc_session_s *session,
FAR struct rfb_setencodings_s *encodings);
/****************************************************************************
* Name: vnc_start_updater
*
* Description:
* Start the updater thread
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_start_updater(FAR struct vnc_session_s *session);
/****************************************************************************
* Name: vnc_stop_updater
*
* Description:
* Stop the updater thread
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_stop_updater(FAR struct vnc_session_s *session);
/****************************************************************************
* Name: vnc_update_rectangle
*
* Description:
* Queue an update of the specified rectangular region on the display.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - The rectanglular region to be updated.
* change - True: Frame buffer data has changed
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_update_rectangle(FAR struct vnc_session_s *session,
FAR const struct fb_area_s *rect,
bool change);
/****************************************************************************
* Name: vnc_receiver
*
* Description:
* This function handles all Client-to-Server messages.
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* At present, always returns OK
*
****************************************************************************/
int vnc_receiver(FAR struct vnc_session_s *session);
/****************************************************************************
* Name: vnc_rre
*
* Description:
* This function does not really do RRE encoding. It just checks if the
* update region is one color then uses the RRE encoding format to send
* the constant color rectangle.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - Describes the rectangle in the local framebuffer.
*
* Returned Value:
* Zero is returned if RRE coding was not performed (but not error was)
* encountered. Otherwise, the size of the framebuffer update message
* is returned on success or a negated errno value is returned on failure
* that indicates the nature of the failure. A failure is only
* returned in cases of a network failure and unexpected internal failures.
*
****************************************************************************/
int vnc_rre(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect);
/****************************************************************************
* Name: vnc_raw
*
* Description:
* As a fallback, send the framebuffer update using the RAW encoding which
* must be supported by all VNC clients.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - Describes the rectangle in the local framebuffer.
*
* Returned Value:
* Zero (OK) on success; A negated errno value is returned on failure that
* indicates the nature of the failure. A failure is only returned
* in cases of a network failure and unexpected internal failures.
*
****************************************************************************/
int vnc_raw(FAR struct vnc_session_s *session, FAR struct fb_area_s *rect);
/****************************************************************************
* Name: vnc_key_map
*
* Description:
* Map the receive X11 keysym into something understood by NuttX and route
* that through NX to the appropriate window.
*
* Input Parameters:
* session - An instance of the session structure.
* keysym - The X11 keysym value (see include/nuttx/inputx11_keysymdef)
* keydown - True: Key pressed; False: Key released
*
* Returned Value:
* None
*
****************************************************************************/
void vnc_key_map(FAR struct vnc_session_s *session, uint16_t keysym,
bool keydown);
/****************************************************************************
* Name: vnc_convert_rgbNN
*
* Description:
* Convert the native framebuffer color format (either RGB8 3:3:2,
* RGB16 5:6:5, or RGB32 8:8:8) to the remote framebuffer color format
* (either RGB8 2:2:2, RGB8 3:3:2, RGB16 5:5:5, RGB16 5:6:5, or RGB32
* 8:8:8)
*
* Input Parameters:
* pixel - The src color in local framebuffer format.
*
* Returned Value:
* The pixel in the remote framebuffer color format.
*
****************************************************************************/
uint8_t vnc_convert_rgb8_222(lfb_color_t rgb);
uint8_t vnc_convert_rgb8_332(lfb_color_t rgb);
uint16_t vnc_convert_rgb16_555(lfb_color_t rgb);
uint16_t vnc_convert_rgb16_565(lfb_color_t rgb);
uint32_t vnc_convert_rgb32_888(lfb_color_t rgb);
/****************************************************************************
* Name: vnc_colors
*
* Description:
* Test the update rectangle to see if it contains complex colors. If it
* contains only a few colors, then it may be a candidate for some type
* run-length encoding.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - The update region in the local frame buffer.
* maxcolors - The maximum number of colors that should be returned. This
* currently cannot exceed eight.
* colors - The top 'maxcolors' most frequency colors are returned.
*
* Returned Value:
* The number of valid colors in the colors[] array are returned, the
* first entry being the most frequent. A negated errno value is returned
* if the colors cannot be determined. This would be the case if the color
* depth is > 8 and there are more than 'maxcolors' colors in the update
* rectangle.
*
****************************************************************************/
int vnc_colors(FAR struct vnc_session_s *session,
FAR struct fb_area_s *rect,
unsigned int maxcolors, FAR lfb_color_t *colors);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __GRAPHICS_VNC_SERVER_VNC_SERVER_H */

View File

@@ -1,655 +0,0 @@
/****************************************************************************
* graphics/vnc/server/vnc_updater.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <string.h>
#include <sched.h>
#include <pthread.h>
#include <queue.h>
#include <assert.h>
#include <errno.h>
#if defined(CONFIG_VNCSERVER_DEBUG) && !defined(CONFIG_DEBUG_GRAPHICS)
# undef CONFIG_DEBUG_ERROR
# undef CONFIG_DEBUG_WARN
# undef CONFIG_DEBUG_INFO
# undef CONFIG_DEBUG_GRAPHICS_ERROR
# undef CONFIG_DEBUG_GRAPHICS_WARN
# undef CONFIG_DEBUG_GRAPHICS_INFO
# define CONFIG_DEBUG_ERROR 1
# define CONFIG_DEBUG_WARN 1
# define CONFIG_DEBUG_INFO 1
# define CONFIG_DEBUG_GRAPHICS 1
# define CONFIG_DEBUG_GRAPHICS_ERROR 1
# define CONFIG_DEBUG_GRAPHICS_WARN 1
# define CONFIG_DEBUG_GRAPHICS_INFO 1
#endif
#include <debug.h>
#include "vnc_server.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#undef VNCSERVER_SEM_DEBUG /* Define to dump queue/semaphore state */
#undef VNCSERVER_SEM_DEBUG_SILENT /* Define to dump only suspicious conditions */
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef VNCSERVER_SEM_DEBUG
static sem_t g_errsem = SEM_INITIALIZER(1);
#endif
/* A rectangle represent the entire local framebuffer */
static const struct fb_area_s g_wholescreen =
{
0, 0, CONFIG_VNCSERVER_SCREENWIDTH, CONFIG_VNCSERVER_SCREENHEIGHT
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_sem_debug
*
* Description:
* Dump information about the freesem to verify that it is sync.
*
* Input Parameters:
* session - A reference to the VNC session structure.
*
* Returned Value:
* A non-NULL structure pointer should always be returned. This function
* will wait if no structure is available.
*
****************************************************************************/
#ifdef VNCSERVER_SEM_DEBUG
static void vnc_sem_debug(FAR struct vnc_session_s *session,
FAR const char *msg, unsigned int unattached)
{
FAR struct vnc_fbupdate_s *update;
int nqueued;
int nfree;
int freesem;
int queuesem;
int freecount;
int queuecount;
int freewaiting;
int queuewaiting;
int ret;
ret = nxsem_wait_uninterruptible(&g_errsem);
if (ret < 0)
{
/* Should happen only on task cancellation */
DEBUGASSERT(ret == -ECANCELED);
return;
}
/* Count structures in the list */
nqueued = sq_count(&session->updqueue);
nfree = sq_count(&session->updfree);
freesem = session->freesem.semcount;
queuesem = session->queuesem.semcount;
freecount = freesem > 0 ? freesem : 0;
queuecount = queuesem > 0 ? queuesem : 0;
freewaiting = freesem < 0 ? -freesem : 0;
queuewaiting = queuesem < 0 ? -queuesem : 0;
#ifdef VNCSERVER_SEM_DEBUG_SILENT
/* This dumps most false alarms in the case where:
*
* - Updater was waiting on a semaphore (count is -1)
* - New update added to the queue (queue count is 1)
* - queuesem posted. Wakes up Updater and the count is 0.
*/
if ((nqueued + nfree) != (freecount + queuecount))
#endif
{
syslog(LOG_INFO, "FREESEM DEBUG: %s\n", msg);
syslog(LOG_INFO, " Free list:\n");
syslog(LOG_INFO, " semcount: %d\n", freecount);
syslog(LOG_INFO, " queued nodes: %u\n", nfree);
syslog(LOG_INFO, " waiting: %u\n", freewaiting);
syslog(LOG_INFO, " Qeued Updates:\n");
syslog(LOG_INFO, " semcount: %d\n", queuecount);
syslog(LOG_INFO, " queued nodes: %u\n", nqueued);
syslog(LOG_INFO, " waiting: %u\n", queuewaiting);
syslog(LOG_INFO, " Unqueued: %u\n", unattached);
}
nxsem_post(&g_errsem);
}
#else
# define vnc_sem_debug(s,m,u)
#endif
/****************************************************************************
* Name: vnc_alloc_update
*
* Description:
* Allocate one update structure by taking it from the freelist.
*
* Input Parameters:
* session - A reference to the VNC session structure.
*
* Returned Value:
* A non-NULL structure pointer should always be returned. This function
* will wait if no structure is available.
*
****************************************************************************/
static FAR struct vnc_fbupdate_s *
vnc_alloc_update(FAR struct vnc_session_s *session)
{
FAR struct vnc_fbupdate_s *update;
/* Reserve one element from the free list. Lock the scheduler to assure
* that the sq_remfirst() and the successful return from nxsem_wait are
* atomic. Of course, the scheduler will be unlocked while we wait.
*/
sched_lock();
vnc_sem_debug(session, "Before alloc", 0);
nxsem_wait_uninterruptible(&session->freesem);
/* It is reserved.. go get it */
update = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updfree);
vnc_sem_debug(session, "After alloc", 1);
sched_unlock();
DEBUGASSERT(update != NULL);
return update;
}
/****************************************************************************
* Name: vnc_free_update
*
* Description:
* Free one update structure by returning it from the freelist.
*
* Input Parameters:
* session - A reference to the VNC session structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void vnc_free_update(FAR struct vnc_session_s *session,
FAR struct vnc_fbupdate_s *update)
{
/* Reserve one element from the free list. Lock the scheduler to assure
* that the sq_addlast() and the nxsem_post() are atomic.
*/
sched_lock();
vnc_sem_debug(session, "Before free", 1);
/* Put the entry into the free list */
sq_addlast((FAR sq_entry_t *)update, &session->updfree);
/* Post the semaphore to indicate the availability of one more update */
nxsem_post(&session->freesem);
vnc_sem_debug(session, "After free", 0);
DEBUGASSERT(session->freesem.semcount <= CONFIG_VNCSERVER_NUPDATES);
sched_unlock();
}
/****************************************************************************
* Name: vnc_remove_queue
*
* Description:
* Remove one entry from the list of queued rectangles, waiting if
* necessary if the queue is empty.
*
* Input Parameters:
* session - A reference to the VNC session structure.
*
* Returned Value:
* A non-NULL structure pointer should always be returned. This function
* will wait if no structure is available.
*
****************************************************************************/
static FAR struct vnc_fbupdate_s *
vnc_remove_queue(FAR struct vnc_session_s *session)
{
FAR struct vnc_fbupdate_s *rect;
/* Reserve one element from the list of queued rectangle. Lock the
* scheduler to assure that the sq_remfirst() and the successful return
* from nxsem_wait are atomic. Of course, the scheduler will be unlocked
* while we wait.
*/
sched_lock();
vnc_sem_debug(session, "Before remove", 0);
nxsem_wait_uninterruptible(&session->queuesem);
/* It is reserved.. go get it */
rect = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updqueue);
vnc_sem_debug(session, "After remove", 0);
DEBUGASSERT(rect != NULL);
/* Check if we just removed the whole screen update from the queue */
if (session->nwhupd > 0 && rect->whupd)
{
session->nwhupd--;
updinfo("Whole screen update: nwhupd=%d\n", session->nwhupd);
}
sched_unlock();
return rect;
}
/****************************************************************************
* Name: vnc_add_queue
*
* Description:
* Add one rectangle entry to the list of queued rectangles to be updated.
*
* Input Parameters:
* session - A reference to the VNC session structure.
* rect - The rectangle to be added to the queue.
*
* Returned Value:
* None
*
****************************************************************************/
static void vnc_add_queue(FAR struct vnc_session_s *session,
FAR struct vnc_fbupdate_s *rect)
{
/* Lock the scheduler to assure that the sq_addlast() and the nxsem_post()
* are atomic.
*/
sched_lock();
vnc_sem_debug(session, "Before add", 1);
/* Put the entry into the list of queued rectangles. */
sq_addlast((FAR sq_entry_t *)rect, &session->updqueue);
/* Post the semaphore to indicate the availability of one more rectangle
* in the queue. This may wakeup the updater.
*/
nxsem_post(&session->queuesem);
vnc_sem_debug(session, "After add", 0);
DEBUGASSERT(session->queuesem.semcount <= CONFIG_VNCSERVER_NUPDATES);
sched_unlock();
}
/****************************************************************************
* Name: vnc_updater
*
* Description:
* This is the "updater" thread. It is the sender of all Server-to-Client
* messages
*
* Input Parameters:
* Standard pthread arguments.
*
* Returned Value:
* NULL is always returned.
*
****************************************************************************/
static FAR void *vnc_updater(FAR void *arg)
{
FAR struct vnc_session_s *session = (FAR struct vnc_session_s *)arg;
FAR struct vnc_fbupdate_s *srcrect;
int ret;
#ifdef CONFIG_FB_SYNC
int val;
#endif
DEBUGASSERT(session != NULL);
ginfo("Updater running for Display %d\n", session->display);
/* Loop, processing updates until we are asked to stop.
* REVISIT: Probably need some kind of signal mechanism to wake up
* vnc_remove_queue() in order to stop. Or perhaps a special STOP
* message in the queue?
*/
while (session->state == VNCSERVER_RUNNING)
{
/* Get the next queued rectangle update. This call will block until an
* update is available for the case where the update queue is empty.
*/
srcrect = vnc_remove_queue(session);
DEBUGASSERT(srcrect != NULL);
updinfo("Dequeued {(%d, %d),(%d, %d)}\n",
srcrect->rect.x, srcrect->rect.y,
srcrect->rect.w, srcrect->rect.h);
/* Attempt to use RRE encoding */
ret = vnc_rre(session, &srcrect->rect);
if (ret == 0)
{
/* Perform the framebuffer update using the default RAW encoding */
ret = vnc_raw(session, &srcrect->rect);
}
/* Release the update structure */
vnc_free_update(session, srcrect);
#ifdef CONFIG_FB_SYNC
ret = nxsem_get_value(&session->vsyncsem, &val);
if (ret < 0)
{
gerr("ERROR: Get vsync sem failed: %d\n", ret);
break;
}
if (sq_count(&session->updqueue) == 0 && val <= 0)
{
nxsem_post(&session->vsyncsem);
}
#endif
/* Break out and terminate the server if the encoding failed */
if (ret < 0)
{
gerr("ERROR: Encoding failed: %d\n", ret);
break;
}
}
session->state = VNCSERVER_STOPPED;
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: vnc_start_updater
*
* Description:
* Start the updater thread
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_start_updater(FAR struct vnc_session_s *session)
{
pthread_attr_t attr;
struct sched_param param;
int status;
ginfo("Starting updater for Display %d\n", session->display);
/* Create thread that is gonna send rectangles to the client */
session->state = VNCSERVER_RUNNING;
DEBUGVERIFY(pthread_attr_init(&attr));
DEBUGVERIFY(pthread_attr_setstacksize(&attr,
CONFIG_VNCSERVER_UPDATER_STACKSIZE));
param.sched_priority = CONFIG_VNCSERVER_UPDATER_PRIO;
DEBUGVERIFY(pthread_attr_setschedparam(&attr, &param));
status = pthread_create(&session->updater, &attr, vnc_updater,
(pthread_addr_t)session);
if (status != 0)
{
return -status;
}
return OK;
}
/****************************************************************************
* Name: vnc_stop_updater
*
* Description:
* Stop the updater thread
*
* Input Parameters:
* session - An instance of the session structure.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_stop_updater(FAR struct vnc_session_s *session)
{
pthread_addr_t result;
int status;
/* Is the update thread running? */
if (session->state == VNCSERVER_RUNNING)
{
/* Yes.. ask it to please stop */
session->state = VNCSERVER_STOPPING;
/* Wait for the thread to comply with our request */
status = pthread_join(session->updater, &result);
if (status != 0)
{
return -status;
}
/* Return what the thread returned */
return (int)((intptr_t)result);
}
/* Not running? Just say we stopped the thread successfully. */
return OK;
}
/****************************************************************************
* Name: vnc_update_rectangle
*
* Description:
* Queue an update of the specified rectangular region on the display.
*
* Input Parameters:
* session - An instance of the session structure.
* rect - The rectanglular region to be updated.
* change - True: Frame buffer data has changed
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
int vnc_update_rectangle(FAR struct vnc_session_s *session,
FAR const struct fb_area_s *rect, bool change)
{
FAR struct vnc_fbupdate_s *update;
struct fb_area_s intersection;
bool whupd;
intersection.x = rect->x;
intersection.y = rect->y;
/* Clip rectangle to the screen dimensions */
if (rect->w < g_wholescreen.w)
{
intersection.w = rect->w;
}
else
{
intersection.w = g_wholescreen.w;
}
if (rect->h < g_wholescreen.h)
{
intersection.h = rect->h;
}
else
{
intersection.h = g_wholescreen.h;
}
/* Make sure that the clipped rectangle has an area */
if (intersection.w && intersection.h)
{
/* Check for a whole screen update. The RealVNC client sends a lot
* of these (especially when it is confused)
*/
whupd = (memcmp(&intersection, &g_wholescreen,
sizeof(struct fb_area_s)) == 0);
/* Ignore any client update requests if there have been no changes to
* the framebuffer since the last whole screen update.
*/
sched_lock();
if (!change && !session->change)
{
/* No.. ignore the client update. We have nothing new to report. */
sched_unlock();
return OK;
}
/* Ignore all updates if there is a queued whole screen update */
if (session->nwhupd == 0)
{
/* No whole screen updates in the queue. Is this a new whole
* screen update?
*/
if (whupd)
{
/* Yes.. Discard all of the previously queued updates */
FAR struct vnc_fbupdate_s *curr;
FAR struct vnc_fbupdate_s *next;
updinfo("New whole screen update...\n");
curr = (FAR struct vnc_fbupdate_s *)session->updqueue.head;
sq_init(&session->updqueue);
nxsem_reset(&session->queuesem, 0);
for (; curr != NULL; curr = next)
{
next = curr->flink;
vnc_free_update(session, curr);
}
/* One whole screen update will be queued. There have been
* no frame buffer data changes since this update was queued.
*/
session->nwhupd = 1;
session->change = false;
}
else
{
/* We are not updating the whole screen. Remember if this
* update (OR a preceding update) was due to a data change.
*/
session->change |= change;
}
/* Allocate an update structure... waiting if necessary */
update = vnc_alloc_update(session);
DEBUGASSERT(update != NULL);
/* Copy the clipped rectangle into the update structure */
update->whupd = whupd;
memcpy(&update->rect, &intersection, sizeof(intersection));
/* Add the update to the end of the update queue. */
vnc_add_queue(session, update);
updinfo("Queued {(%d, %d),(%d, %d)}\n",
intersection.x, intersection.y,
intersection.w, intersection.h);
}
sched_unlock();
}
/* Since we ignore bad rectangles and wait for update structures, there is
* really no way a failure can occur.
*/
return OK;
}