From 964fa628272ee0f2576763db33b9707b6e5177f8 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Sat, 17 Jun 2006 23:08:35 +0000 Subject: [PATCH] VNC viewer --- apps/vnc/Makefile.vnc | 2 + apps/vnc/vnc-draw.h | 61 ++++ apps/vnc/vnc-dsc.c | 74 +++++ apps/vnc/vnc-dsc.h | 42 +++ apps/vnc/vnc-viewer.c | 755 ++++++++++++++++++++++++++++++++++++++++++ apps/vnc/vnc-viewer.h | 327 ++++++++++++++++++ apps/vnc/vnc.c | 236 +++++++++++++ apps/vnc/vnc.h | 40 +++ 8 files changed, 1537 insertions(+) create mode 100644 apps/vnc/Makefile.vnc create mode 100644 apps/vnc/vnc-draw.h create mode 100644 apps/vnc/vnc-dsc.c create mode 100644 apps/vnc/vnc-dsc.h create mode 100644 apps/vnc/vnc-viewer.c create mode 100644 apps/vnc/vnc-viewer.h create mode 100644 apps/vnc/vnc.c create mode 100644 apps/vnc/vnc.h diff --git a/apps/vnc/Makefile.vnc b/apps/vnc/Makefile.vnc new file mode 100644 index 000000000..15441e9d2 --- /dev/null +++ b/apps/vnc/Makefile.vnc @@ -0,0 +1,2 @@ +APP_SOURCES += vnc.c vnc-viewer.c vnc-draw.c +DSC_SOURCES += vnc-dsc.c \ No newline at end of file diff --git a/apps/vnc/vnc-draw.h b/apps/vnc/vnc-draw.h new file mode 100644 index 000000000..e6bc3947e --- /dev/null +++ b/apps/vnc/vnc-draw.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki VNC client. + * + * $Id: vnc-draw.h,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ + +#ifndef __VNC_DRAW_H__ +#define __VNC_DRAW_H__ + +#include "net/uip_arch.h" + +/* Pointer to the bitmap area in memory. */ +extern u8_t vnc_draw_bitmap[]; + +/* Initialize the vnc-draw module. */ +void vnc_draw_init(void); + +/* Draw one line of pixels starting at point (x, y). The pixel data is + given by the "data" argument and the length of data is given by the + "datalen" argument. The data format is one pixel per byte in bgr233 + format (bbgggrrr). */ +void vnc_draw_pixelline(u16_t x, u16_t y, + u8_t *data, u16_t datalen); + +/* The following functions should return the x and y coordinates and + the width and height of the viewport. */ +u16_t vnc_draw_viewport_x(void); +u16_t vnc_draw_viewport_y(void); +u16_t vnc_draw_viewport_w(void); +u16_t vnc_draw_viewport_h(void); + +#endif /* __VNC_DRAW_H__ */ diff --git a/apps/vnc/vnc-dsc.c b/apps/vnc/vnc-dsc.c new file mode 100644 index 000000000..b2d2564b4 --- /dev/null +++ b/apps/vnc/vnc-dsc.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki desktop environment + * + * $Id: vnc-dsc.c,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ + +#include "sys/dsc.h" + +extern struct ctk_icon vnc_icon; +/*-----------------------------------------------------------------------------------*/ +DSC(vnc_dsc, + "Remote control your PC using Contiki", + "vnc.prg", + vnc_process, + &vnc_icon); +/*-----------------------------------------------------------------------------------*/ +#if CTK_CONF_ICON_BITMAPS +static unsigned char vncicon_bitmap[3*3*8] = { + 0x00, 0x7e, 0x40, 0x73, 0x46, 0x4c, 0x18, 0x13, + 0x00, 0x00, 0xff, 0x81, 0x34, 0xc9, 0x00, 0xb6, + 0x00, 0x7e, 0x02, 0xce, 0x72, 0x32, 0x18, 0x48, + + 0x30, 0x27, 0x24, 0x20, 0x37, 0x24, 0x20, 0x33, + 0x00, 0x7b, 0x42, 0x00, 0x7b, 0x42, 0x00, 0x3b, + 0x0c, 0x24, 0x24, 0x04, 0xa4, 0x24, 0x04, 0x4c, + + 0x12, 0x19, 0x4c, 0x46, 0x63, 0x40, 0x7c, 0x00, + 0x22, 0x91, 0x00, 0xc4, 0x81, 0xff, 0x00, 0x00, + 0x08, 0x18, 0x32, 0x62, 0xc6, 0x02, 0x3e, 0x00 +}; +#endif /* CTK_CONF_ICON_BITMAPS */ + +#if CTK_CONF_ICON_TEXTMAPS +static char vncicon_textmap[9] = { + 'V', 'N', 'C', + 'c', 'l', 'i', + 'e', 'n', 't' +}; +#endif /* CTK_CONF_ICON_TEXTMAPS */ + +#if CTK_CONF_ICONS +static struct ctk_icon vnc_icon = + {CTK_ICON("VNC viewer", vncicon_bitmap, vncicon_textmap)}; +#endif /* CTK_CONF_ICONS */ +/*-----------------------------------------------------------------------------------*/ diff --git a/apps/vnc/vnc-dsc.h b/apps/vnc/vnc-dsc.h new file mode 100644 index 000000000..2eff72c15 --- /dev/null +++ b/apps/vnc/vnc-dsc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki desktop environment + * + * $Id: vnc-dsc.h,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ +#ifndef __VNC_DSC_H__ +#define __VNC_DSC_H__ + +#include "sys/dsc.h" + +DSC_HEADER(vnc_dsc); + +#endif /* __VNC_DSC_H__ */ diff --git a/apps/vnc/vnc-viewer.c b/apps/vnc/vnc-viewer.c new file mode 100644 index 000000000..fd2322aee --- /dev/null +++ b/apps/vnc/vnc-viewer.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: vnc-viewer.c,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ + +/* A micro implementation of a VNC client. VNC is a protocol for + remote network displays. See http://www.uk.research.att.com/vnc/ + for information about VNC. +*/ + +#include "vnc-draw.h" +#include "net/uip.h" +#include "vnc-viewer.h" + +#include /* XXX for memcpy */ +#include /* XXX for printf */ + +/* RFB server initial handshaking string. */ +#define RFB_SERVER_VERSION_STRING rfb_server_version_string + +/* "RFB 003.003" */ +static u8_t rfb_server_version_string[12] = + {82,70,66,32,48,48,51,46,48,48,51,10}; + +#if 0 +#define PRINTF(x) +#else +#define PRINTF(x) printf x +#endif + +#ifndef NULL +#define NULL (void *)0 +#endif + +static struct vnc_viewer_state vnc_viewer_state; +#define vs (&vnc_viewer_state) + +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_init(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_close(void) +{ + vs->close = 1; +} +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_connect(u16_t *server, u8_t display) +{ + struct uip_conn *conn; + + vnc_draw_init(); + + memset(vs, 0, sizeof(struct vnc_viewer_state)); + conn = uip_connect(server, htons(5900 + display)); + if(conn == NULL) { + return; + } + tcp_markconn(conn, NULL); + + vs->close = 0; +} +/*-----------------------------------------------------------------------------------*/ +static void +senddata(void) +{ + register u8_t *dataptr; + u16_t dataleft; + + dataptr = (u8_t *)uip_appdata; + + switch(vs->sendmsg) { + case VNC_SEND_VERSION: + PRINTF(("Sending VERSION_STRING\n")); + uip_send(RFB_SERVER_VERSION_STRING, sizeof(RFB_SERVER_VERSION_STRING)); + break; + case VNC_SEND_AUTH: + /* Send 16 bytes of encrypted challange response. */ + /* XXX: not implemented. */ + PRINTF(("Sending AUTH\n")); + uip_send(uip_appdata, 16); + break; + case VNC_SEND_CINIT: + PRINTF(("Sending CINIT\n")); + /* Send one byte of client init. */ + *(u8_t *)dataptr = 1; + uip_send(uip_appdata, 1); + break; + case VNC_SEND_PFMT: + PRINTF(("Sending PFMT\n")); + ((struct rfb_set_pixel_format *)dataptr)->type = RFB_SET_PIXEL_FORMAT; + + /* Set to BGR233 pixel format. */ + ((struct rfb_set_pixel_format *)dataptr)->format.bps = 8; + ((struct rfb_set_pixel_format *)dataptr)->format.depth = 8; + ((struct rfb_set_pixel_format *)dataptr)->format.endian = 1; + ((struct rfb_set_pixel_format *)dataptr)->format.truecolor = 1; + ((struct rfb_set_pixel_format *)dataptr)->format.red_max = htons(7); + ((struct rfb_set_pixel_format *)dataptr)->format.green_max = htons(7); + ((struct rfb_set_pixel_format *)dataptr)->format.blue_max = htons(3); + ((struct rfb_set_pixel_format *)dataptr)->format.red_shift = 0; + ((struct rfb_set_pixel_format *)dataptr)->format.green_shift = 3; + ((struct rfb_set_pixel_format *)dataptr)->format.blue_shift = 6; + + uip_send(uip_appdata, sizeof(struct rfb_set_pixel_format)); + + break; + case VNC_SEND_ENCODINGS: + PRINTF(("Sending ENCODINGS\n")); + ((struct rfb_set_encodings *)dataptr)->type = RFB_SET_ENCODINGS; + ((struct rfb_set_encodings *)dataptr)->encodings = htons(1); + dataptr += sizeof(struct rfb_set_encodings); + dataptr[0] = dataptr[1] = dataptr[2] = 0; + dataptr[3] = RFB_ENC_RAW; + /* ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[4] = + ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[5] = + ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[6] = 0; + ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[7] = RFB_ENC_RRE;*/ + uip_send(uip_appdata, sizeof(struct rfb_set_encodings) + 4); + break; + case VNC_SEND_UPDATERQ: + ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; + ((struct rfb_fb_update_request *)dataptr)->incremental = 0; + ((struct rfb_fb_update_request *)dataptr)->x = htons(vnc_draw_viewport_x()); + ((struct rfb_fb_update_request *)dataptr)->y = htons(vnc_draw_viewport_y()); + ((struct rfb_fb_update_request *)dataptr)->w = htons(vnc_draw_viewport_w()); + ((struct rfb_fb_update_request *)dataptr)->h = htons(vnc_draw_viewport_h()); + uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); + break; + case VNC_SEND_UPDATERQ_INC: + ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; + ((struct rfb_fb_update_request *)dataptr)->incremental = 1; + ((struct rfb_fb_update_request *)dataptr)->x = htons(vnc_draw_viewport_x()); + ((struct rfb_fb_update_request *)dataptr)->y = htons(vnc_draw_viewport_y()); + ((struct rfb_fb_update_request *)dataptr)->w = htons(vnc_draw_viewport_w()); + ((struct rfb_fb_update_request *)dataptr)->h = htons(vnc_draw_viewport_h()); + uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); + break; + + case VNC_SEND_EVENTS: + + dataleft = uip_mss(); + + vs->eventptr_unacked = vs->eventptr_acked; + while(vs->eventptr_unacked != vs->eventptr_next && + dataleft > sizeof(struct rfb_key_event)) { + switch(vs->event_queue[vs->eventptr_unacked].type) { + case VNC_POINTER_EVENT: + ((struct rfb_pointer_event *)dataptr)->type = RFB_POINTER_EVENT; + ((struct rfb_pointer_event *)dataptr)->buttonmask = + vs->event_queue[vs->eventptr_unacked].ev.ptr.buttonmask; + ((struct rfb_pointer_event *)dataptr)->x = + htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.x); + ((struct rfb_pointer_event *)dataptr)->y = + htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.y); + /* uip_send(uip_appdata, sizeof(struct rfb_pointer_event));*/ + dataptr += sizeof(struct rfb_pointer_event); + dataleft -= sizeof(struct rfb_pointer_event); + break; + case VNC_KEY_EVENT: + PRINTF(("Send key event.\n")); + ((struct rfb_key_event *)dataptr)->type = RFB_KEY_EVENT; + ((struct rfb_key_event *)dataptr)->down = + vs->event_queue[vs->eventptr_unacked].ev.key.down; + ((struct rfb_key_event *)dataptr)->key[0] = + ((struct rfb_key_event *)dataptr)->key[1]; + ((struct rfb_key_event *)dataptr)->key[2] = + vs->event_queue[vs->eventptr_unacked].ev.key.key >> 8; + + ((struct rfb_key_event *)dataptr)->key[3] = + vs->event_queue[vs->eventptr_unacked].ev.key.key & 0xff; + /* uip_send(uip_appdata, sizeof(struct rfb_key_event));*/ + dataptr += sizeof(struct rfb_key_event); + dataleft -= sizeof(struct rfb_key_event); + break; + case VNC_UPDATERQ_EVENT: + ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; + ((struct rfb_fb_update_request *)dataptr)->incremental = 0; + ((struct rfb_fb_update_request *)dataptr)->x = + htons(vs->event_queue[vs->eventptr_unacked].ev.urq.x); + ((struct rfb_fb_update_request *)dataptr)->y = + htons(vs->event_queue[vs->eventptr_unacked].ev.urq.y); + ((struct rfb_fb_update_request *)dataptr)->w = + htons(vs->event_queue[vs->eventptr_unacked].ev.urq.w); + ((struct rfb_fb_update_request *)dataptr)->h = + htons(vs->event_queue[vs->eventptr_unacked].ev.urq.h); + /* uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); */ + dataptr += sizeof(struct rfb_fb_update_request); + dataleft -= sizeof(struct rfb_fb_update_request); + break; + } + vs->eventptr_unacked = (vs->eventptr_unacked + 1) % VNC_EVENTQUEUE_SIZE; + } + + uip_send(uip_appdata, uip_mss() - dataleft); + break; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +buffer_data(u8_t *data, u16_t datalen) +{ + PRINTF(("Buffering %d bytes of data\n", datalen)); + + if(vs->buffersize + datalen > VNC_BUFFERSIZE) { + PRINTF(("Out of buffer space!\n")); + vs->buffersize = 0; + return; + } + + memcpy(&(vs->buffer[vs->buffersize]), data, datalen); + + vs->buffersize += datalen; + vs->bufferleft -= datalen; +} +/*-----------------------------------------------------------------------------------*/ +static void +clearbuffer(void) +{ + PRINTF(("Clearing buffer\n")); + vs->buffersize = 0; +} +/*-----------------------------------------------------------------------------------*/ +/* Returns: the amount of bytes actually read. */ +static u16_t +recv_rectstate(u8_t *dataptr, u16_t datalen) +{ + u16_t pixels; + u16_t pixelsleft; + + switch(vs->rectstate) { + case VNC_RECTSTATE_RAW: + + if(vs->rectstateleft > datalen) { + pixels = datalen; + vs->rectstateleft -= datalen; + } else { + pixels = vs->rectstateleft; + datalen = datalen - vs->rectstateleft; + vs->rectstateleft = 0; + vs->rectstate = VNC_RECTSTATE_NONE; + vs->sendmsg = VNC_SEND_NONE; + vs->waitmsg = VNC_WAIT_NONE; + vnc_viewer_refresh(); + } + + + pixelsleft = pixels; + while(pixelsleft > 0) { + if(pixelsleft >= vs->rectstatex2 - vs->rectstatex) { + vnc_draw_pixelline(vs->rectstatex, vs->rectstatey, + dataptr, + vs->rectstatex2 - vs->rectstatex); + dataptr += vs->rectstatex2 - vs->rectstatex; + pixelsleft -= vs->rectstatex2 - vs->rectstatex; + vs->rectstatex = vs->rectstatex0; + ++vs->rectstatey; + vnc_viewer_refresh(); + } else { + vnc_draw_pixelline(vs->rectstatex, vs->rectstatey, + dataptr, + pixelsleft); + vs->rectstatex += pixelsleft; + pixelsleft = 0; + } + + } + + break; + case VNC_RECTSTATE_RRE: + break; + } + return pixels; +} +/*-----------------------------------------------------------------------------------*/ +/* Returns: the amount of bytes that needs to be buffered before the + rect can be drawn. */ +static unsigned short +recv_update_rect(register struct rfb_fb_update_rect_hdr *rhdr, + u16_t dataleft) +{ + struct rfb_rre_hdr *rrehdr; + + + if((rhdr->encoding[0] | + rhdr->encoding[1] | + rhdr->encoding[2]) == 0) { + switch(rhdr->encoding[3]) { + case RFB_ENC_RAW: + vs->rectstateleft = (u32_t)htons(rhdr->rect.w) * (u32_t)htons(rhdr->rect.h); + vs->rectstate = VNC_RECTSTATE_RAW; + vs->rectstatex0 = vs->rectstatex = htons(rhdr->rect.x); + vs->rectstatey0 = vs->rectstatey = htons(rhdr->rect.y); + vs->rectstatew = htons(rhdr->rect.w); + vs->rectstateh = htons(rhdr->rect.h); + vs->rectstatex2 = vs->rectstatex0 + vs->rectstatew; + vs->rectstatey2 = vs->rectstatey0 + vs->rectstateh; + break; + + case RFB_ENC_RRE: + rrehdr = (struct rfb_rre_hdr *)((u8_t *)rhdr + + sizeof(struct rfb_fb_update_rect_hdr)); + PRINTF(("Received RRE subrects %d (%d)\n", + (htons(rrehdr->subrects[1]) << 16) + + htons(rrehdr->subrects[0]), + rrehdr->bgpixel)); + vs->rectstateleft = ((u32_t)(htons(rrehdr->subrects[1]) << 16) + + (u32_t)htons(rrehdr->subrects[0])); + vs->rectstate = VNC_RECTSTATE_RRE; + + break; + + default: + PRINTF(("Bad encoding %02x%02x%02x%02x\n", rhdr->encoding[0], + rhdr->encoding[1],rhdr->encoding[2],rhdr->encoding[3])); + break; + } + + } + + return 0; + + PRINTF(("recv_update_rect: returning%d\n", vs->rectstateleft)); + return sizeof(struct rfb_fb_update_rect_hdr) + vs->rectstateleft; +} +/*-----------------------------------------------------------------------------------*/ +/* identify_data(): + * + * This function looks at the state of the connection (i.e., if it is + * handshaking or in steady-state) as well as on the contents of the + * incoming message and returns the number of bytes of data that is to + * be expected. + */ +static u16_t +identify_data(register u8_t *data, u16_t datalen) +{ + switch(vs->waitmsg) { + case VNC_WAIT_VERSION: + /* Expecting version string (12 bytes). */ + return 12; + break; + case VNC_WAIT_AUTH: + return 4; + break; + case VNC_WAIT_AUTH_RESPONSE: + return 1; + break; + case VNC_WAIT_SINIT: + /* XXX: We should check that the entire message header is + received, otherwise we should buffer it. */ + return sizeof(struct rfb_server_init) + + ((struct rfb_server_init *)uip_appdata)->namelength[3] + + ((struct rfb_server_init *)uip_appdata)->namelength[2]; + + case VNC_WAIT_UPDATE: + case VNC_WAIT_NONE: + switch(*data) { + case RFB_FB_UPDATE: + PRINTF(("RFB FB UPDATE received\n")); + return sizeof(struct rfb_fb_update); + + case RFB_BELL: + return 1; + + case RFB_SERVER_CUT_TEXT: + PRINTF(("Cut text received, unhandled\n")); + return 8 + (data[6] << 8) + data[7]; + + case RFB_SET_COLORMAP_ENTRIES: + uip_abort(); + PRINTF(("Set colormap entries received, unhandled\n")); + return 0; + + default: + uip_abort(); + PRINTF(("Weird message type received (%d)\n", *(u8_t *)uip_appdata)); + return 0; + } + break; + + case VNC_WAIT_UPDATE_RECT: + return sizeof(struct rfb_fb_update_rect_hdr); + + default: + PRINTF(("identify: bad waitmsg %d\n", vs->waitmsg)); + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +/* handle_data(): + * + * Handles the data. + */ +static unsigned short +handle_data(register u8_t *data, u16_t datalen) +{ + + switch(vs->waitmsg) { + case VNC_WAIT_VERSION: + /* Make sure we get the right version string from the server. */ + /* XXX: not implemented. */ + PRINTF(("Got version, waiting for auth, sending version\n")); + vs->waitmsg = VNC_WAIT_AUTH; + vs->sendmsg = VNC_SEND_VERSION; + break; + case VNC_WAIT_AUTH: + switch(data[3]) { + case RFB_AUTH_FAILED: + PRINTF(("Connection failed.\n")); + uip_abort(); + return 0; + + case RFB_AUTH_NONE: + vs->sendmsg = VNC_SEND_CINIT; + vs->waitmsg = VNC_WAIT_SINIT; + PRINTF(("No authentication needed.\n")); + break; + case RFB_AUTH_VNC: + vs->sendmsg = VNC_SEND_AUTH; + vs->waitmsg = VNC_WAIT_AUTH_RESPONSE; + PRINTF(("VNC authentication needed.\n")); + break; + } + break; + case VNC_WAIT_SINIT: + /* PRINTF(("Server init: w %d h %d, bps %d, d %d, name '%s'\n", + htons(((struct rfb_server_init *)data)->width), + htons(((struct rfb_server_init *)data)->height), + ((struct rfb_server_init *)data)->format.bps, + ((struct rfb_server_init *)data)->format.depth, + ((u8_t *)data + sizeof(struct rfb_server_init))));*/ + vs->w = htons(((struct rfb_server_init *)data)->width); + vs->h = htons(((struct rfb_server_init *)data)->height); + vs->sendmsg = VNC_SEND_PFMT; + vs->waitmsg = VNC_WAIT_NONE; + break; + + case VNC_WAIT_UPDATE: + case VNC_WAIT_NONE: + switch(*data) { + case RFB_FB_UPDATE: + vs->waitmsg = VNC_WAIT_UPDATE_RECT; + vs->rectsleft = htons(((struct rfb_fb_update *)data)->rects); + PRINTF(("Handling RFB FB UPDATE for %d rects\n", vs->rectsleft)); + break; + + case RFB_BELL: + PRINTF(("BELL\n")); + break; + + case RFB_SERVER_CUT_TEXT: + PRINTF(("Cut text received, unhandled\n")); + break; + + case RFB_SET_COLORMAP_ENTRIES: + PRINTF(("Set colormap entries received, unhandled\n")); + break; + + default: + PRINTF(("Weird message type received (%d)\n", *(u8_t *)data)); + break; + } + break; + + case VNC_WAIT_UPDATE_RECT: + PRINTF(("Handling data in WAIT_UPDATE_RECT, %d rects left (%d bytes)\n", vs->rectsleft, datalen)); + --vs->rectsleft; + if(vs->rectsleft > 0) { + vs->waitmsg = VNC_WAIT_UPDATE_RECT; + } else { + vs->waitmsg = VNC_WAIT_NONE; + vs->sendmsg = VNC_SEND_NONE; + vs->rectstate = VNC_RECTSTATE_NONE; + } + return recv_update_rect((struct rfb_fb_update_rect_hdr *)data, datalen); + break; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +/* newdata(): + * + * Called whenever new data arrives. + * + * First, checks if data needs to be buffered before a previously + * identified request can be fulfilled. If so, the incoming data is + * buffered and the data handler is called. If no data needs to be + * buffered, the code proceeds to identify the incoming request. If + * the incoming request can be processed immediately (i.e., all data + * is contained in this message) the data handler is invoked. If data + * has to be buffered to fulfill the request, this is noted and taken + * care of the next time this function is invoked (i.e., for the next + * incoming data chunk). + */ +static u8_t +newdata(void) +{ + u16_t datalen; + u16_t readlen; + u8_t *dataptr; + + datalen = uip_datalen(); + dataptr = (u8_t *)uip_appdata; + + PRINTF(("newdata: %d bytes\n", datalen)); + + /* If we are in a "rectstate", meaning that the incoming data is + part of a rectangle that is being incrementaly drawn on the + screen, we handle that first. */ + if(vs->rectstate != VNC_RECTSTATE_NONE) { + readlen = recv_rectstate(dataptr, datalen); + PRINTF(("newdata: vs->rectstate %d, datalen %d, readlen %d\n", + vs->rectstate, datalen, readlen)); + datalen -= readlen; + dataptr += readlen; + } + + /* Next, check if we are supposed to buffer data from the incoming + segment. */ + while(vs->bufferleft > 0 && datalen > 0) { + if(datalen >= vs->bufferleft) { + /* There is more data in the incoming chunk than we need to + buffer, so we buffer as much as we can and handle the + buffered data, and repeat the (identify->buffer->handle) + sequence for the data that is left in the incoming chunk. */ + datalen -= vs->bufferleft; + dataptr += vs->bufferleft; + buffer_data((u8_t *)uip_appdata, vs->bufferleft); + handle_data(vs->buffer, vs->buffersize); + clearbuffer(); + } else { /* datalen < vs->bufferleft */ + /* We need to buffer more data than was received with this + chunk, so we buffer the avaliable data and return. */ + buffer_data(dataptr, datalen); + return 0; + } + } + + /* Finally, if there is data left in the segment, we handle it. */ + while(datalen > 0) { + + if(vs->rectstate != VNC_RECTSTATE_NONE) { + readlen = recv_rectstate(dataptr, datalen); + PRINTF(("newdata (2): vs->rectstate %d, datalen %d, readlen %d\n", + vs->rectstate, datalen, readlen)); + datalen -= readlen; + dataptr += readlen; + } else { + + /* We get here if there is data to be identified in the incoming + chunk. */ + readlen = identify_data(dataptr, datalen); + + if(readlen == 0) { + PRINTF(("Identify returned 0\n")); + return 0; + } + + PRINTF(("Reading %d bytes more\n", readlen)); + /* The data has been identified and the amount of data that + needs to be read to be able to process the data is in the + "readlen" variable. If the incoming chunk contains enough + data, we handle it directly, otherwise we buffer the incoming + data and set the state so that we know that there is more + data to be buffered. */ + if(readlen > datalen) { + clearbuffer(); /* Should not be needed, but just in case... */ + vs->bufferleft = readlen; + buffer_data(dataptr, datalen); + return 0; + } + if(readlen <= datalen) { + PRINTF(("Before handle_data %d\n", readlen)); + readlen += handle_data(dataptr, readlen); + PRINTF(("After handle_data %d\n", readlen)); + datalen -= readlen; + dataptr += readlen; + } + + } + if(datalen > 0) { + PRINTF(("newdata: there is more data left after first iteration... %d\n", datalen)); + } + + } + + return 0; +} +/*-----------------------------------------------------------------------------------*/ +/* Called when there is nothing else to do - checks for any pending + events (mouse movements or keypresses). If no events are found, it + makes sure that we send out an incremental update request. */ +static void +check_events(void) +{ + if(vs->sendmsg == VNC_SEND_NONE && + vs->eventptr_next != vs->eventptr_acked && + vs->eventptr_acked == vs->eventptr_unacked) { + vs->sendmsg = VNC_SEND_EVENTS; + } +} +/*-----------------------------------------------------------------------------------*/ +static void +request_update(void) +{ + if(vs->sendmsg == VNC_SEND_NONE) { + vs->sendmsg = VNC_SEND_UPDATERQ_INC; + vs->waitmsg = VNC_WAIT_UPDATE; + PRINTF(("request_update: requesting\n")); + } else { + PRINTF(("request_update: not requesting\n")); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +acked(void) +{ + switch(vs->sendmsg) { + case VNC_SEND_PFMT: + vs->sendmsg = VNC_SEND_ENCODINGS; + break; + case VNC_SEND_ENCODINGS: + vs->sendmsg = VNC_SEND_UPDATERQ; + vs->waitmsg = VNC_WAIT_UPDATE; + clearbuffer(); + break; + case VNC_SEND_EVENTS: + vs->eventptr_acked = vs->eventptr_unacked; + vs->sendmsg = VNC_SEND_NONE; + check_events(); + break; + default: + vs->sendmsg = VNC_SEND_NONE; + break; + } +} +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_appcall(void * nullptr) +{ + if(vs->close == 1) { + uip_close(); + return; + } + + if(uip_connected()) { + vs->sendmsg = VNC_SEND_NONE; + vs->waitmsg = VNC_WAIT_VERSION; + return; + } + + if(uip_acked()) { + acked(); + } + + if(uip_newdata()) { + newdata(); + } + + if(vs->sendmsg == VNC_SEND_NONE && + vs->waitmsg == VNC_WAIT_NONE && + vs->rectstate == VNC_RECTSTATE_NONE) { + check_events(); + request_update(); + } + PRINTF(("vs->sendmsg %d, vs->waitmsg %d, vs->rectstate %d\n", + vs->sendmsg, vs->waitmsg, vs->rectstate)); + + if(uip_rexmit() || + uip_newdata() || + uip_acked()) { + senddata(); + } else if(uip_poll()) { + check_events(); + senddata(); + } +} +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_post_event(u8_t type, + u16_t data1, u16_t data2, + u16_t data3, u16_t data4) +{ + register struct vnc_event *ev; + struct vnc_event *ev0; + + ev0 = &(vs->event_queue[(vs->eventptr_next - 1) % VNC_EVENTQUEUE_SIZE]); + + ev = &(vs->event_queue[vs->eventptr_next]); + switch(type) { + case VNC_POINTER_EVENT: + if(0 && vs->eventptr_next != vs->eventptr_acked && + ev0->type == VNC_POINTER_EVENT && + data1 == ev0->ev.ptr.buttonmask) { + ev0->ev.ptr.x = data2; + ev0->ev.ptr.y = data3; + return; + } else { + ev->type = type; + ev->ev.ptr.buttonmask = data1; + ev->ev.ptr.x = data2; + ev->ev.ptr.y = data3; + } + break; + case VNC_KEY_EVENT: + PRINTF(("Key event posted\n")); + ev->type = type; + ev->ev.key.down = data1; + ev->ev.key.key = data2; + break; + case VNC_UPDATERQ_EVENT: + PRINTF(("Update request event posted\n")); + ev->type = type; + ev->ev.urq.x = data1; + ev->ev.urq.y = data2; + ev->ev.urq.w = data3; + ev->ev.urq.h = data4; + break; + } + vs->eventptr_next = (vs->eventptr_next + 1) % VNC_EVENTQUEUE_SIZE; +} +/*-----------------------------------------------------------------------------------*/ diff --git a/apps/vnc/vnc-viewer.h b/apps/vnc/vnc-viewer.h new file mode 100644 index 000000000..c5defced4 --- /dev/null +++ b/apps/vnc/vnc-viewer.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki VNC client. + * + * $Id: vnc-viewer.h,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ + +#ifndef __VNC_VIEWER_H__ +#define __VNC_VIEWER_H__ + + +struct vnc_viewer_state; + +/*typedef unsigned long u32_t;*/ + +void vnc_viewer_init(void); +void vnc_viewer_appcall(void *nullptr); + +void vnc_viewer_connect(u16_t *server, u8_t display); +void vnc_viewer_close(void); + +/* Callback: redraws the VNC viewer bitmap area. */ +void vnc_viewer_refresh(void); + +#define VNC_POINTER_EVENT RFB_POINTER_EVENT +#define VNC_KEY_EVENT RFB_KEY_EVENT +#define VNC_UPDATERQ_EVENT 7 + +#define VNC_VIEWER_POST_POINTER_EVENT(x, y, button) \ + vnc_viewer_post_event(VNC_POINTER_EVENT, button, x, y, 0) + +#define VNC_VIEWER_POST_KEY_EVENT(key) \ + vnc_viewer_post_event(VNC_KEY_EVENT, key, 0, 0, 0) + +#define VNC_VIEWER_POST_UPDATERQ_EVENT(x1,y1,x2,y2) \ + vnc_viewer_post_event(VNC_UPDATERQ_EVENT, x1, y1, x2, y2) + +void vnc_viewer_post_event(u8_t event, + u16_t data1, u16_t data2, + u16_t data3, u16_t data4); + +/* UIP_APPCALL: the name of the application function. This function + must return void and take no arguments (i.e., C type "void + appfunc(void)"). */ +#ifndef UIP_APPCALL +#define UIP_APPCALL vnc_viewer_app +#endif + +struct vnc_key_event { + u8_t down; + u16_t key; +}; + +struct vnc_pointer_event { + u8_t buttonmask; + u16_t x, y; +}; + +struct vnc_updaterq_event { + u16_t x, y; + u16_t w, h; +}; + +struct vnc_event { + u8_t type; + union { + struct vnc_key_event key; + struct vnc_pointer_event ptr; + struct vnc_updaterq_event urq; + } ev; +}; + +enum vnc_sendmsg { + VNC_SEND_NONE, + + VNC_SEND_VERSION, + VNC_SEND_AUTH, + VNC_SEND_CINIT, + VNC_SEND_PFMT, + VNC_SEND_ENCODINGS, + + VNC_SEND_UPDATERQ, + VNC_SEND_UPDATERQ_INC, + VNC_SEND_EVENTS, +}; + +enum vnc_waitmsg { + VNC_WAIT_NONE, + + VNC_WAIT_VERSION, + VNC_WAIT_AUTH, + VNC_WAIT_AUTH_RESPONSE, + VNC_WAIT_SINIT, + + VNC_WAIT_UPDATE, + VNC_WAIT_UPDATE_RECT, + +}; + + +enum vnc_rectstate { + VNC_RECTSTATE_NONE, + VNC_RECTSTATE_RAW, + VNC_RECTSTATE_RRE, +}; + +struct vnc_viewer_state { + u8_t close; + u16_t w, h; + + u8_t sendmsg; + + u8_t waitmsg; + + u16_t rectsleft; + + u8_t rectstate; + u32_t rectstateleft; + u16_t rectstatex, rectstatey; + u16_t rectstateh, rectstatew; + u16_t rectstatex0, rectstatey0; + u16_t rectstatex2, rectstatey2; + + + u16_t eventptr_acked; + u16_t eventptr_unacked; + u16_t eventptr_next; +#define VNC_EVENTQUEUE_SIZE 32 + struct vnc_event event_queue[VNC_EVENTQUEUE_SIZE]; + + + u16_t bufferleft; + u16_t buffersize; +#define VNC_BUFFERSIZE 64 + u8_t buffer[VNC_BUFFERSIZE]; +}; + +extern struct vnc_viewer_state vnc_viewer_state; + +/* Definitions of the RFB (Remote Frame Buffer) protocol + structures and constants. */ + +#include "net/uipopt.h" + + +/* Generic rectangle - x, y coordinates, width and height. */ +struct rfb_rect { + u16_t x; + u16_t y; + u16_t w; + u16_t h; +}; + +/* Pixel format definition. */ +struct rfb_pixel_format { + u8_t bps; /* Bits per pixel: 8, 16 or 32. */ + u8_t depth; /* Color depth: 8-32 */ + u8_t endian; /* 1 - big endian (motorola), 0 - little endian + (x86) */ + u8_t truecolor; /* 1 - true color is used, 0 - true color is not used. */ + + /* The following fields are only used if true color is used. */ + u16_t red_max, green_max, blue_max; + u8_t red_shift, green_shift, blue_shift; + u8_t pad1; + u16_t pad2; +}; + + +/* RFB authentication constants. */ + +#define RFB_AUTH_FAILED 0 +#define RFB_AUTH_NONE 1 +#define RFB_AUTH_VNC 2 + +#define RFB_VNC_AUTH_OK 0 +#define RFB_VNC_AUTH_FAILED 1 +#define RFB_VNC_AUTH_TOOMANY 2 + +/* RFB message types. */ + +/* From server to client: */ +#define RFB_FB_UPDATE 0 +#define RFB_SET_COLORMAP_ENTRIES 1 +#define RFB_BELL 2 +#define RFB_SERVER_CUT_TEXT 3 + +/* From client to server. */ +#define RFB_SET_PIXEL_FORMAT 0 +#define RFB_FIX_COLORMAP_ENTRIES 1 +#define RFB_SET_ENCODINGS 2 +#define RFB_FB_UPDATE_REQ 3 +#define RFB_KEY_EVENT 4 +#define RFB_POINTER_EVENT 5 +#define RFB_CLIENT_CUT_TEXT 6 + +/* Encoding types. */ +#define RFB_ENC_RAW 0 +#define RFB_ENC_COPYRECT 1 +#define RFB_ENC_RRE 2 +#define RFB_ENC_CORRE 3 +#define RFB_ENC_HEXTILE 4 + +/* Message definitions. */ + +/* Server to client messages. */ + +struct rfb_server_init { + u16_t width; + u16_t height; + struct rfb_pixel_format format; + u8_t namelength[4]; + /* Followed by name. */ +}; + +struct rfb_fb_update { + u8_t type; + u8_t pad; + u16_t rects; /* Number of rectanges (struct rfb_fb_update_rect_hdr + + data) that follows. */ +}; + +struct rfb_fb_update_rect_hdr { + struct rfb_rect rect; + u8_t encoding[4]; +}; + +struct rfb_copy_rect { + u16_t srcx; + u16_t srcy; +}; + +struct rfb_rre_hdr { + u16_t subrects[2]; /* Number of subrectangles (struct + rfb_rre_subrect) to follow. */ + u8_t bgpixel; +}; + +struct rfb_rre_subrect { + u8_t pixel; + struct rfb_rect rect; +}; + +struct rfb_corre_rect { + u8_t x; + u8_t y; + u8_t w; + u8_t h; +}; + +/* Client to server messages. */ + +struct rfb_set_pixel_format { + u8_t type; + u8_t pad; + u16_t pad2; + struct rfb_pixel_format format; +}; + +struct rfb_fix_colormap_entries { + u8_t type; + u8_t pad; + u16_t firstcolor; + u16_t colors; +}; + +struct rfb_set_encodings { + u8_t type; + u8_t pad; + u16_t encodings; +}; + +struct rfb_fb_update_request { + u8_t type; + u8_t incremental; + u16_t x; + u16_t y; + u16_t w; + u16_t h; +}; + +struct rfb_key_event { + u8_t type; + u8_t down; + u16_t pad; + u8_t key[4]; +}; + +#define RFB_BUTTON_MASK1 1 +#define RFB_BUTTON_MASK2 2 +#define RFB_BUTTON_MASK3 4 +struct rfb_pointer_event { + u8_t type; + u8_t buttonmask; + u16_t x; + u16_t y; +}; + +#endif /* __VNC_VIEWER_H__ */ diff --git a/apps/vnc/vnc.c b/apps/vnc/vnc.c new file mode 100644 index 000000000..d532175d5 --- /dev/null +++ b/apps/vnc/vnc.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki VNC client + * + * $Id: vnc.c,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ + +#include + +#include "contiki.h" + +/*#include "petsciiconv.h"*/ +#include "net/uiplib.h" +#include "net/uip.h" +#include "ctk/ctk.h" +#include "ctk/ctk-mouse.h" +#include "net/resolv.h" +/*#include "telnet.h"*/ +#include "vnc.h" +#include "vnc-draw.h" +#include "vnc-viewer.h" +#include "contiki-conf.h" + +#include "sys/loader.h" + +#if 1 +#define PRINTF(x) +#else +#include +#define PRINTF(x) printf x +#endif + + +#ifdef VNC_CONF_VIEWPORT_WIDTH +#define VNC_VIEWPORT_WIDTH VNC_CONF_VIEWPORT_WIDTH +#else +#define VNC_VIEWPORT_WIDTH 10 +#endif + +#ifdef VNC_CONF_VIEWPORT_HEIGHT +#define VNC_VIEWPORT_HEIGHT VNC_CONF_VIEWPORT_HEIGHT +#else +#define VNC_VIEWPORT_HEIGHT 10 +#endif + +#define HEIGHT (4 + VNC_VIEWPORT_HEIGHT/8) + +/* Main window */ +static struct ctk_window mainwindow; + +static char host[20]; +static struct ctk_textentry hosttextentry = + {CTK_TEXTENTRY(0, 0, 18, 1, host, 18)}; + +static char portentry[4]; +static struct ctk_textentry porttextentry = + {CTK_TEXTENTRY(21, 0, 3, 1, portentry, 3)}; + +static struct ctk_button connectbutton = + {CTK_BUTTON(27, 0, 7, "Connect")}; +/*static struct ctk_button disconnectbutton = + {CTK_BUTTON(25, 3, 10, "Disconnect")};*/ + +static struct ctk_separator sep1 = + {CTK_SEPARATOR(0, 1, 36)}; + +static struct ctk_bitmap vncbitmap = + {CTK_BITMAP(2, 2, + VNC_VIEWPORT_WIDTH / 8, + VNC_VIEWPORT_HEIGHT / 8, + vnc_draw_bitmap, + VNC_VIEWPORT_WIDTH, + VNC_VIEWPORT_HEIGHT)}; + +static struct ctk_button leftbutton = + {CTK_BUTTON(6, HEIGHT - 1, 4, "Left")}; + +static struct ctk_button upbutton = + {CTK_BUTTON(13, HEIGHT - 1, 2, "Up")}; + +static struct ctk_button downbutton = + {CTK_BUTTON(18, HEIGHT - 1, 4, "Down")}; + +static struct ctk_button rightbutton = + {CTK_BUTTON(25, HEIGHT - 1, 5, "Right")}; + +PROCESS(vnc_process, "VNC viewer"); + +/*-----------------------------------------------------------------------------------*/ +static void +show(char *text) +{ + +} +/*-----------------------------------------------------------------------------------*/ +static void +connect(void) +{ + u16_t addr[2], *addrptr; + u16_t port; + char *cptr; + + /* Find the first space character in host and put a zero there + to end the string. */ + for(cptr = host; *cptr != ' ' && *cptr != 0; ++cptr); + *cptr = 0; + + addrptr = &addr[0]; + if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) { + addrptr = resolv_lookup(host); + if(addrptr == NULL) { + resolv_query(host); + show("Resolving host..."); + return; + } + } + + port = 0; + for(cptr = portentry; *cptr != ' ' && *cptr != 0; ++cptr) { + if(*cptr < '0' || *cptr > '9') { + show("Port number error"); + return; + } + port = 10 * port + *cptr - '0'; + } + + + vnc_viewer_connect(addrptr, port); + + show("Connecting..."); + +} +/*-----------------------------------------------------------------------------------*/ +PROCESS_THREAD(vnc_process, ev, data) +{ + unsigned short x, y; + unsigned char xc, yc; + + PROCESS_BEGIN(); + + ctk_window_new(&mainwindow, 36, HEIGHT, "VNC client"); + ctk_window_move(&mainwindow, 0, 0); + + CTK_WIDGET_ADD(&mainwindow, &hosttextentry); + CTK_WIDGET_FOCUS(&mainwindow, &hosttextentry); + CTK_WIDGET_ADD(&mainwindow, &porttextentry); + CTK_WIDGET_ADD(&mainwindow, &connectbutton); + + CTK_WIDGET_ADD(&mainwindow, &sep1); + + CTK_WIDGET_ADD(&mainwindow, &vncbitmap); + + CTK_WIDGET_ADD(&mainwindow, &leftbutton); + CTK_WIDGET_ADD(&mainwindow, &upbutton); + CTK_WIDGET_ADD(&mainwindow, &downbutton); + CTK_WIDGET_ADD(&mainwindow, &rightbutton); + + vnc_draw_init(); + + ctk_window_open(&mainwindow); + + while(1) { + PROCESS_WAIT_EVENT(); + + if(ev == ctk_signal_button_activate) { + if(data == (process_data_t)&connectbutton) { + connect(); + } + } else if(ev == ctk_signal_window_close) { + process_exit(&vnc_process); + LOADER_UNLOAD(); + } else if(ev == resolv_event_found) { + if(strcmp(data, host) == 0) { + if(resolv_lookup(host) != NULL) { + connect(); + } else { + show("Host not found"); + } + } + } else if(ev == ctk_signal_pointer_move) { + /* Check if pointer is within the VNC viewer area */ + x = ctk_mouse_x(); + y = ctk_mouse_y(); + + xc = ctk_mouse_xtoc(x); + yc = ctk_mouse_ytoc(y); + + if(xc >= 2 && yc >= 2 && + xc < 2 + VNC_VIEWPORT_WIDTH / 8 && + yc < 2 + VNC_VIEWPORT_HEIGHT / 8) { + + VNC_VIEWER_POST_POINTER_EVENT(x, y, 0); + } + + } else if(ev == tcpip_event) { + vnc_viewer_appcall(data); + } + } + + PROCESS_END(); +} +/*-----------------------------------------------------------------------------------*/ +void +vnc_viewer_refresh(void) +{ + CTK_WIDGET_REDRAW(&vncbitmap); +} +/*-----------------------------------------------------------------------------------*/ diff --git a/apps/vnc/vnc.h b/apps/vnc/vnc.h new file mode 100644 index 000000000..5015ba623 --- /dev/null +++ b/apps/vnc/vnc.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki VNC client. + * + * $Id: vnc.h,v 1.1 2006/06/17 23:08:35 adamdunkels Exp $ + * + */ +#ifndef __VNC_H__ +#define __VNC_H__ + +void vnc_init(char *arg); + +#endif /* __VNC_H__ */