[gtk-vnc-devel] [RFC] VNC tunnels
- From: Anthony Liguori <anthony codemonkey ws>
- To: gtk-vnc-devel List <gtk-vnc-devel lists sourceforge net>, "Daniel P. Berrange" <berrange redhat com>
- Subject: [gtk-vnc-devel] [RFC] VNC tunnels
- Date: Tue, 11 Dec 2007 20:55:56 -0600
Hi,
I'm looking for some feedback before submitting to QEMU that I've got
the protocol extensions reasonably nailed down. Attached is the
preliminary gtk-vnc and QEMU patch to enable VNC channels.
There's something of a fundamental architecture shift here that I'd also
like to discuss. Originally, I had planned that gvnc would only depend
on glib. Since then, I've come under the opinion that it should
actually have been a proper GObject. This patch introduces a GObject
called "VncTunnel" which represents an active tunnel. These tunnels
really aren't dependent at all on VncDisplay so they are actually
created and managed by gvnc. This effectively adds a GObject dependency
on gvnc.
I've also #if 0'd out a lot of the SharedMemory extension. I'll
properly remove that though until I can figure out the least racy way to
do it.
Right now, I've modified the gvncviewer.py example a little bit so that
if you launch QEMU with -monitor vnc:org.qemu.monitor you can see some
monitor output.
The protocol extensions are as follows:
I'm using a psuedo-encoding (-258) to identify support for VNC tunnels.
I'm introducing three server and three client messages based on the idea
of "extended messages". This is really just a way to multiplex messages
over one message type (which is all I have allocated).
The three client messages are:
TunnelOpenRequest
u8 id 255
u8 xid 0
u16 size
u8[size] name
TunnelClientShutdown
u8 id 255
u8 xid 1
u16 tid
TunnelClientSend
u8 id 255
u8 xid 2
u16 tid
u32 size
u8[size] data
And the three server messages are:
TunnelOpenResponse
u8 id 255
u8 xid 0
u16 tid
TunnelServerShutdown
u8 id 255
u8 xid 1
u16 tid
TunnelServerSend
u8 id 255
u8 xid 2
u16 tid
u32 size
u8[size] data
Semantically, a client open's a VNC channel and is assigned an ID. The
client can then close the channel or the server can close the
connection. When the client closes the channel, the server will also
close the channel. Finally, either the client or server is capable of
sending a message in either direction.
I thought about enumerating supported channels but I think that it
becomes less useful if channel names can be created during execution.
For instance, if you sent a monitor command of "change cdrom
vnc:org.qemu.cdrom" that would create a new channel on the server. So,
does that mean we would need another server message to tell the client
that a new channel is available? It seems to me that it's better to
just ignore the enumeration problem entirely.
Any thoughts?
Regards,
Anthony Liguori
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h 2007-12-10 12:29:40.000000000 -0600
+++ qemu/sysemu.h 2007-12-10 12:30:09.000000000 -0600
@@ -179,4 +179,6 @@
void do_usb_del(const char *devname);
void usb_info(void);
+CharDriverState *qemu_chr_open_vnc(const char *name);
+
#endif
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c 2007-12-10 12:28:43.000000000 -0600
+++ qemu/vl.c 2007-12-10 12:29:49.000000000 -0600
@@ -3373,6 +3373,9 @@
printf("Unable to open driver: %s\n", p);
return 0;
} else
+ if (strstart(filename, "vnc:", &p)) {
+ return qemu_chr_open_vnc(p);
+ } else
#ifndef _WIN32
if (strstart(filename, "unix:", &p)) {
return qemu_chr_open_tcp(p, 0, 1);
Index: qemu/vnc.c
===================================================================
--- qemu.orig/vnc.c 2007-12-10 12:21:02.000000000 -0600
+++ qemu/vnc.c 2007-12-11 15:49:21.000000000 -0600
@@ -40,7 +40,7 @@
#include <gnutls/x509.h>
#endif /* CONFIG_VNC_TLS */
-// #define _VNC_DEBUG 1
+#define _VNC_DEBUG 1
#if _VNC_DEBUG
#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
@@ -65,7 +65,7 @@
typedef struct VncState VncState;
-typedef int VncReadEvent(VncState *vs, char *data, size_t len);
+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
typedef void VncWritePixels(VncState *vs, void *data, int size);
@@ -118,6 +118,18 @@
#endif /* CONFIG_VNC_TLS */
+typedef struct VNCTunnelState VNCTunnelState;
+
+struct VNCTunnelState
+{
+ CharDriverState chr;
+ VncState *vs;
+ char *name;
+ int16_t id;
+ int connected;
+ VNCTunnelState *next;
+};
+
struct VncState
{
QEMUTimer *timer;
@@ -133,6 +145,7 @@
int has_resize;
int has_hextile;
int has_pointer_type_change;
+ int has_tunnels;
int absolute;
int last_x;
int last_y;
@@ -174,10 +187,24 @@
size_t read_handler_expect;
/* input */
uint8_t modifiers_state[256];
+
+ VNCTunnelState *tunnel_list;
};
static VncState *vnc_state; /* needed for info vnc */
+static void vnc_write(VncState *vs, const void *data, size_t len);
+static void vnc_write_u32(VncState *vs, uint32_t value);
+static void vnc_write_s32(VncState *vs, int32_t value);
+static void vnc_write_u16(VncState *vs, uint16_t value);
+static void vnc_write_u8(VncState *vs, uint8_t value);
+static void vnc_flush(VncState *vs);
+static void vnc_update_client(void *opaque);
+static void vnc_client_read(void *opaque);
+
+static void tunnel_find_rsp(VncState *vs, int16_t id);
+static void tunnel_write(VncState *vs, int16_t id, const void *data, size_t size);
+
void do_info_vnc(void)
{
if (vnc_state == NULL)
@@ -194,6 +221,112 @@
}
}
+/* VNC Tunnel functions */
+
+static int vnc_tunnel_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ VNCTunnelState *s = chr->opaque;
+
+ if (s->vs->csock != -1 && s->vs->has_tunnels) {
+ tunnel_write(s->vs, s->id, buf, len);
+ return len;
+ }
+
+ return 0;
+}
+
+CharDriverState *qemu_chr_open_vnc(const char *name)
+{
+ VNCTunnelState *s;
+ static int16_t max_tunnel_id;
+
+ s = qemu_mallocz(sizeof(VNCTunnelState));
+ if (!s)
+ return NULL;
+
+ s->name = strdup(name);
+ if (s->name == NULL) {
+ qemu_free(s);
+ return NULL;
+ }
+
+ s->vs = vnc_state;
+ s->id = max_tunnel_id++;
+ s->chr.opaque = s;
+ s->chr.chr_write = vnc_tunnel_write;
+ qemu_chr_reset(&s->chr);
+
+ s->next = s->vs->tunnel_list;
+ s->vs->tunnel_list = s;
+
+ return &s->chr;
+}
+
+static VNCTunnelState *find_tunnel_by_tid(VncState *vs, uint16_t tid)
+{
+ VNCTunnelState *s;
+
+ for (s = vs->tunnel_list; s; s = s->next) {
+ if (s->id == tid)
+ return s;
+ }
+
+ return NULL;
+}
+
+static void vnc_tunnel_open_request(VncState *vs,
+ const char *name, size_t size)
+{
+ VNCTunnelState *s;
+
+ for (s = vs->tunnel_list; s; s = s->next) {
+ if (strlen(s->name) == size && memcmp(s->name, name, size) == 0)
+ break;
+ }
+
+ if (s == NULL || s->connected)
+ tunnel_find_rsp(vs, -1);
+ else
+ tunnel_find_rsp(vs, s->id);
+
+ qemu_chr_reset(&s->chr);
+}
+
+static void vnc_server_tunnel_shutdown(VncState *vs, VNCTunnelState *s)
+{
+ s->connected = 0;
+ vnc_write_u8(vs, 255);
+ vnc_write_u8(vs, 1);
+ vnc_write_u16(vs, s->id);
+ vnc_flush(vs);
+}
+
+static void vnc_tunnel_client_shutdown(VncState *vs, uint16_t tid)
+{
+ VNCTunnelState *s;
+
+ s = find_tunnel_by_tid(vs, tid);
+ if (s)
+ vnc_server_tunnel_shutdown(vs, s);
+}
+
+static void vnc_tunnel_client_send(VncState *vs, int16_t tid,
+ const void *data, size_t size)
+{
+ VNCTunnelState *s;
+ CharDriverState *chr;
+
+ s = find_tunnel_by_tid(vs, tid);
+ if (s == NULL || !s->connected)
+ return;
+
+ /* FIXME signal disconnection */
+ chr = (CharDriverState *)s;
+
+ if (qemu_chr_can_read(chr))
+ qemu_chr_read(chr, (char *)data, size);
+}
+
/* TODO
1) Get the queue working for IO.
2) there is some weirdness when using the -S option (the screen is grey
@@ -201,15 +334,6 @@
3) resolutions > 1024
*/
-static void vnc_write(VncState *vs, const void *data, size_t len);
-static void vnc_write_u32(VncState *vs, uint32_t value);
-static void vnc_write_s32(VncState *vs, int32_t value);
-static void vnc_write_u16(VncState *vs, uint16_t value);
-static void vnc_write_u8(VncState *vs, uint8_t value);
-static void vnc_flush(VncState *vs);
-static void vnc_update_client(void *opaque);
-static void vnc_client_read(void *opaque);
-
static inline void vnc_set_bit(uint32_t *d, int k)
{
d[k >> 5] |= 1 << (k & 0x1f);
@@ -1064,6 +1188,37 @@
}
}
+static void advertise_tunnel_support(VncState *vs)
+{
+ printf("%d\n", __LINE__);
+ vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1);
+ vnc_framebuffer_update(vs, 0, 0, vs->ds->width, vs->ds->height, -258);
+ vnc_flush(vs);
+}
+
+static void tunnel_find_rsp(VncState *vs, int16_t id)
+{
+ printf("%d\n", id);
+ printf("%d\n", __LINE__);
+ vnc_write_u8(vs, 255);
+ vnc_write_u8(vs, 0); /* find response */
+ vnc_write_u16(vs, id);
+ vnc_flush(vs);
+}
+
+static void tunnel_write(VncState *vs, int16_t id, const void *data, size_t size)
+{
+ printf("%d\n", __LINE__);
+ vnc_write_u8(vs, 255);
+ vnc_write_u8(vs, 2); /* tunnel server send */
+ vnc_write_u16(vs, id);
+ vnc_write_u32(vs, size);
+ vnc_write(vs, data, size);
+ vnc_flush(vs);
+}
+
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
{
int i;
@@ -1071,6 +1226,7 @@
vs->has_hextile = 0;
vs->has_resize = 0;
vs->has_pointer_type_change = 0;
+ vs->has_tunnels = 0;
vs->absolute = -1;
vs->ds->dpy_copy = NULL;
@@ -1091,6 +1247,10 @@
case -257:
vs->has_pointer_type_change = 1;
break;
+ case -258:
+ vs->has_tunnels = 1;
+ advertise_tunnel_support(vs);
+ break;
default:
break;
}
@@ -1181,7 +1341,7 @@
vga_hw_update();
}
-static int protocol_client_msg(VncState *vs, char *data, size_t len)
+static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
{
int i;
uint16_t limit;
@@ -1244,6 +1404,38 @@
client_cut_text(vs, read_u32(data, 4), data + 8);
break;
+ case 255:
+ if (len == 1)
+ return 2;
+
+ switch (read_u8(data, 1)) {
+ case 0:
+ if (len < 4)
+ return 4;
+
+ if (len == 4)
+ return 4 + read_u16(data, 2);
+
+ vnc_tunnel_open_request(vs, data + 4, read_u16(data, 2));
+ break;
+ case 1:
+ if (len < 4)
+ return 4;
+
+ vnc_tunnel_client_shutdown(vs, read_u16(data, 2));
+ break;
+ case 2:
+ if (len < 8)
+ return 8;
+
+ if (len == 8)
+ return 8 + read_u32(data, 4);
+
+ vnc_tunnel_client_send(vs, read_u16(data, 2),
+ data + 8, read_u32(data, 4));
+ break;
+ }
+ break;
default:
printf("Msg: %d\n", data[0]);
vnc_client_error(vs);
@@ -1254,7 +1446,7 @@
return 0;
}
-static int protocol_client_init(VncState *vs, char *data, size_t len)
+static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
{
char pad[3] = { 0, 0, 0 };
char buf[1024];
@@ -1327,7 +1519,7 @@
vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
}
-static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len)
+static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
{
char response[VNC_AUTH_CHALLENGE_SIZE];
int i, j, pwlen;
@@ -1738,7 +1930,7 @@
return vnc_continue_handshake(vs);
}
-static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len)
+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
{
int auth = read_u32(data, 0);
@@ -1768,7 +1960,7 @@
return 0;
}
-static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len)
+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
{
if (data[0] != 0 ||
data[1] != 2) {
@@ -1798,7 +1990,7 @@
}
#endif /* CONFIG_VNC_TLS */
-static int protocol_client_auth(VncState *vs, char *data, size_t len)
+static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
{
/* We only advertise 1 auth scheme at a time, so client
* must pick the one we sent. Verify this */
@@ -1847,7 +2039,7 @@
return 0;
}
-static int protocol_version(VncState *vs, char *version, size_t len)
+static int protocol_version(VncState *vs, uint8_t *version, size_t len)
{
char local[13];
diff -r d6f1a50dbb0b examples/gvncviewer.py
--- a/examples/gvncviewer.py Sun Oct 21 17:11:07 2007 -0300
+++ b/examples/gvncviewer.py Tue Dec 11 20:44:49 2007 -0600
@@ -34,10 +34,19 @@ def vnc_connected(src):
def vnc_connected(src):
print "Connected to server"
+def tun_io_watch(tun):
+ sys.stdout.write(tun.recv())
+ sys.stdout.flush()
+
def vnc_initialized(src, window):
print "Connection initialized"
set_title(src, window, False)
window.show_all()
+
+def vnc_tunnel_init(src):
+ print "Server supports tunnels"
+ tunnel = vnc.tunnel_open("org.qemu.monitor")
+ tunnel.connect('vnc-tunnel-io-watch', tun_io_watch)
def vnc_disconnected(src):
print "Disconnected from server"
@@ -170,6 +179,7 @@ vnc.connect("vnc-pointer-ungrab", vnc_un
vnc.connect("vnc-connected", vnc_connected)
vnc.connect("vnc-initialized", vnc_initialized, window)
+vnc.connect("vnc-tunnel-init", vnc_tunnel_init)
vnc.connect("vnc-disconnected", vnc_disconnected)
vnc.connect("vnc-auth-credential", vnc_auth_cred)
diff -r d6f1a50dbb0b src/Makefile.am
--- a/src/Makefile.am Sun Oct 21 17:11:07 2007 -0300
+++ b/src/Makefile.am Tue Dec 11 20:44:49 2007 -0600
@@ -20,6 +20,7 @@ libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h
gvnc.h gvnc.c \
vncdisplay.h vncdisplay.c \
vncshmimage.h vncshmimage.c \
+ vnctunnel.h vnctunnel.c \
vncmarshal.h vncmarshal.c \
utils.h
@@ -46,8 +47,8 @@ CODEGENDIR = $(shell pkg-config --variab
CODEGENDIR = $(shell pkg-config --variable=codegendir pygtk-2.0)
DEFSDIR = $(shell pkg-config --variable=defsdir pygtk-2.0)
-vnc.defs: vncdisplay.h
- $(PYTHON) $(CODEGENDIR)/h2def.py $< > $@
+vnc.defs: vncdisplay.h vnctunnel.h
+ $(PYTHON) $(CODEGENDIR)/h2def.py $^ > $@
vncmodule.defs.c: vnc.override vnc.defs
pygtk-codegen-2.0 --prefix gtkvnc \
diff -r d6f1a50dbb0b src/gvnc.c
--- a/src/gvnc.c Sun Oct 21 17:11:07 2007 -0300
+++ b/src/gvnc.c Tue Dec 11 20:44:49 2007 -0600
@@ -9,6 +9,8 @@
*/
#include "gvnc.h"
+
+#include <glib.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -31,6 +33,8 @@
#include "coroutine.h"
#include "d3des.h"
+#include "vnctunnel.h"
+
#include "utils.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
@@ -124,6 +128,10 @@ struct gvnc
char *xmit_buffer;
int xmit_buffer_capacity;
int xmit_buffer_size;
+
+ gboolean has_extmsg;
+ GList *pending_tunnels;
+ GList *open_tunnels;
};
#define nibhi(a) (((a) >> 4) & 0x0F)
@@ -710,6 +718,7 @@ gboolean gvnc_set_pixel_format(struct gv
return !gvnc_has_error(gvnc);
}
+#if 0
gboolean gvnc_set_shared_buffer(struct gvnc *gvnc, int line_size, int shmid)
{
gvnc_write_u8(gvnc, 255);
@@ -720,6 +729,7 @@ gboolean gvnc_set_shared_buffer(struct g
return !gvnc_has_error(gvnc);
}
+#endif
gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, int32_t *encoding)
{
@@ -818,11 +828,71 @@ gboolean gvnc_client_cut_text(struct gvn
{
uint8_t pad[3] = {0};
- gvnc_write_u8(gvnc, 6);
- gvnc_write(gvnc, pad, 3);
- gvnc_write_u32(gvnc, length);
- gvnc_write(gvnc, data, length);
- gvnc_flush(gvnc);
+ gvnc_buffered_write_u8(gvnc, 6);
+ gvnc_buffered_write(gvnc, pad, 3);
+ gvnc_buffered_write_u32(gvnc, length);
+ gvnc_buffered_write(gvnc, data, length);
+ gvnc_buffered_flush(gvnc);
+ return !gvnc_has_error(gvnc);
+}
+
+VncTunnel *gvnc_tunnel_open(struct gvnc *gvnc, const char *name)
+{
+ VncTunnel *tunnel;
+
+ if (!gvnc_tunnel_open_request(gvnc, name))
+ return NULL;
+
+ tunnel = vnc_tunnel_new(gvnc);
+ gvnc->pending_tunnels = g_list_append(gvnc->pending_tunnels, tunnel);
+
+ return tunnel;
+}
+
+gboolean gvnc_tunnel_open_request(struct gvnc *gvnc, const char *name)
+{
+ size_t size = strlen(name);
+
+ if (!gvnc->has_extmsg) {
+ gvnc->has_error = TRUE;
+ return FALSE;
+ }
+
+ gvnc_buffered_write_u8(gvnc, 255);
+ gvnc_buffered_write_u8(gvnc, 0);
+ gvnc_buffered_write_u16(gvnc, size);
+ gvnc_buffered_write(gvnc, name, size);
+ gvnc_buffered_flush(gvnc);
+ return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_tunnel_client_shutdown(struct gvnc *gvnc, uint16_t id)
+{
+ if (!gvnc->has_extmsg) {
+ gvnc->has_error = TRUE;
+ return FALSE;
+ }
+
+ gvnc_buffered_write_u8(gvnc, 255);
+ gvnc_buffered_write_u8(gvnc, 1);
+ gvnc_buffered_write_u16(gvnc, id);
+ return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_tunnel_client_send(struct gvnc *gvnc, uint16_t id,
+ const void *data, size_t length)
+{
+ if (!gvnc->has_extmsg) {
+ gvnc->has_error = TRUE;
+ return FALSE;
+ }
+
+ gvnc_buffered_write_u8(gvnc, 255);
+ gvnc_buffered_write_u8(gvnc, 2);
+ gvnc_buffered_write_u16(gvnc, id);
+ gvnc_buffered_write_u32(gvnc, length);
+ gvnc_buffered_write(gvnc, data, length);
+ gvnc_buffered_flush(gvnc);
return !gvnc_has_error(gvnc);
}
@@ -1010,6 +1080,86 @@ static void gvnc_server_cut_text(struct
gvnc->has_error = TRUE;
}
+static gint tunnel_cmp(gconstpointer a, gconstpointer b)
+{
+ VncTunnel *lhs = VNC_TUNNEL(a);
+ uint16_t *ptid = (void *)b;
+ return vnc_tunnel_get_tid(lhs) - *ptid;
+}
+
+static VncTunnel *find_tunnel_by_tid(struct gvnc *gvnc, uint16_t tid)
+{
+ GList *obj;
+ obj = g_list_find_custom(gvnc->open_tunnels, &tid, tunnel_cmp);
+ if (obj)
+ return VNC_TUNNEL(obj->data);
+ return NULL;
+}
+
+static void gvnc_tunnel_open_response(struct gvnc *gvnc, uint16_t id)
+{
+ VncTunnel *tunnel;
+
+ if (gvnc->has_error)
+ return;
+
+ GVNC_DEBUG("Tunnel open response\n");
+
+ if (!gvnc->pending_tunnels) {
+ gvnc->has_error = TRUE;
+ return;
+ }
+
+ tunnel = gvnc->pending_tunnels->data;
+ gvnc->pending_tunnels = g_list_remove(gvnc->pending_tunnels, tunnel);
+ if ((int16_t)id == -1)
+ vnc_tunnel_feed_shutdown(tunnel);
+ else {
+ vnc_tunnel_set_tid(tunnel, id);
+ gvnc->open_tunnels = g_list_prepend(gvnc->open_tunnels,
+ tunnel);
+ }
+}
+
+static void gvnc_tunnel_server_shutdown(struct gvnc *gvnc, uint16_t id)
+{
+ VncTunnel *tunnel;
+
+ if (gvnc->has_error)
+ return;
+
+ GVNC_DEBUG("Tunnel server shutdown\n");
+
+ tunnel = find_tunnel_by_tid(gvnc, id);
+ if (!tunnel) {
+ gvnc->has_error = TRUE;
+ return;
+ }
+
+ vnc_tunnel_feed_shutdown(tunnel);
+ gvnc->open_tunnels = g_list_remove(gvnc->open_tunnels, tunnel);
+}
+
+static void gvnc_tunnel_server_send(struct gvnc *gvnc, uint16_t id,
+ const void *data, size_t len)
+{
+ VncTunnel *tunnel;
+
+ if (gvnc->has_error)
+ return;
+
+ GVNC_DEBUG("Tunnel server send\n");
+
+ tunnel = find_tunnel_by_tid(gvnc, id);
+ if (!tunnel) {
+ GVNC_DEBUG("Unable to find tunnel %d\n", id);
+ gvnc->has_error = TRUE;
+ return;
+ }
+
+ vnc_tunnel_feed_recv(tunnel, data, len);
+}
+
static void gvnc_resize(struct gvnc *gvnc, int width, int height)
{
if (gvnc->has_error || !gvnc->ops.resize)
@@ -1026,6 +1176,7 @@ static void gvnc_pointer_type_change(str
gvnc->has_error = TRUE;
}
+#if 0
static void gvnc_shared_memory_rmid(struct gvnc *gvnc, int shmid)
{
if (gvnc->has_error || !gvnc->ops.shared_memory_rmid)
@@ -1033,6 +1184,7 @@ static void gvnc_shared_memory_rmid(stru
if (!gvnc->ops.shared_memory_rmid(gvnc->ops_data, shmid))
gvnc->has_error = TRUE;
}
+#endif
#define RICH_CURSOR_BLIT(gvnc, pixbuf, image, mask, pitch, width, height, src_pixel_t) \
do { \
@@ -1185,6 +1337,7 @@ static void gvnc_framebuffer_update(stru
case GVNC_ENCODING_POINTER_CHANGE:
gvnc_pointer_type_change(gvnc, x);
break;
+#if 0
case GVNC_ENCODING_SHARED_MEMORY:
switch (gvnc_read_u32(gvnc)) {
case 0:
@@ -1200,6 +1353,12 @@ static void gvnc_framebuffer_update(stru
break;
}
break;
+#endif
+ case GVNC_ENCODING_TUNNEL_IO:
+ gvnc->has_extmsg = TRUE;
+ if (gvnc->ops.tunnels_available)
+ gvnc->ops.tunnels_available(gvnc->ops_data);
+ break;
case GVNC_ENCODING_RICH_CURSOR:
gvnc_rich_cursor(gvnc, x, y, width, height);
break;
@@ -1305,6 +1464,42 @@ gboolean gvnc_server_message(struct gvnc
gvnc_server_cut_text(gvnc, data, n_text);
free(data);
} break;
+ case 255: /* ExtClientMessage */
+ switch (gvnc_read_u8(gvnc)) {
+ case 0: /* TunnelOpenResponse */
+ gvnc_tunnel_open_response(gvnc, gvnc_read_u16(gvnc));
+ break;
+ case 1: /* TunnelServerShutdown */
+ gvnc_tunnel_server_shutdown(gvnc, gvnc_read_u16(gvnc));
+ break;
+ case 2: { /* TunnelServerSend */
+ uint8_t *data;
+ uint16_t id;
+ size_t size;
+
+ id = gvnc_read_u16(gvnc);
+ size = gvnc_read_u32(gvnc);
+ if ((size + 1) < size || (size + 1) < 1) {
+ gvnc->has_error = TRUE;
+ break;
+ }
+
+ data = malloc(size + 1);
+ if (data == NULL) {
+ gvnc->has_error = TRUE;
+ break;
+ }
+ gvnc_read(gvnc, data, size);
+ data[size] = 0;
+
+ gvnc_tunnel_server_send(gvnc, id, data, size);
+ free(data);
+ } break;
+ default:
+ gvnc->has_error = TRUE;
+ break;
+ }
+ break;
default:
gvnc->has_error = TRUE;
break;
@@ -1842,7 +2037,6 @@ struct gvnc *gvnc_new(const struct gvnc_
gvnc->ops_data = ops_data;
gvnc->auth_type = GVNC_AUTH_INVALID;
gvnc->auth_subtype = GVNC_AUTH_INVALID;
-
return gvnc;
}
@@ -2305,11 +2499,12 @@ gboolean gvnc_set_local(struct gvnc *gvn
return !gvnc_has_error(gvnc);
}
+#if 0
gboolean gvnc_shared_memory_enabled(struct gvnc *gvnc)
{
return gvnc->shared_memory_enabled;
}
-
+#endif
const char *gvnc_get_name(struct gvnc *gvnc)
{
diff -r d6f1a50dbb0b src/gvnc.h
--- a/src/gvnc.h Sun Oct 21 17:11:07 2007 -0300
+++ b/src/gvnc.h Tue Dec 11 20:44:49 2007 -0600
@@ -3,6 +3,8 @@
#include <glib.h>
#include <stdint.h>
+
+#include "vnctunnel.h"
struct gvnc;
@@ -18,9 +20,12 @@ struct gvnc_ops
gboolean (*server_cut_text)(void *, const void *, size_t);
gboolean (*resize)(void *, int, int);
gboolean (*pointer_type_change)(void *, int);
+#if 0
gboolean (*shared_memory_rmid)(void *, int);
+#endif
gboolean (*local_cursor)(void *, int, int, int, int, uint8_t *);
gboolean (*auth_unsupported)(void *, unsigned int);
+ gboolean (*tunnels_available)(void *);
};
struct gvnc_pixel_format
@@ -74,7 +79,10 @@ typedef enum {
GVNC_ENCODING_XCURSOR = -240,
GVNC_ENCODING_POINTER_CHANGE = -257,
+#if 0
GVNC_ENCODING_SHARED_MEMORY = -258,
+#endif
+ GVNC_ENCODING_TUNNEL_IO = -258,
} gvnc_encoding;
typedef enum {
@@ -129,6 +137,13 @@ gboolean gvnc_is_initialized(struct gvnc
gboolean gvnc_server_message(struct gvnc *gvnc);
+gboolean gvnc_tunnel_open_request(struct gvnc *gvnc, const char *name);
+
+gboolean gvnc_tunnel_client_shutdown(struct gvnc *gvnc, uint16_t id);
+
+gboolean gvnc_tunnel_client_send(struct gvnc *gvnc, uint16_t id,
+ const void *data, size_t length);
+
gboolean gvnc_client_cut_text(struct gvnc *gvnc,
const void *data, size_t length);
@@ -147,17 +162,23 @@ gboolean gvnc_set_pixel_format(struct gv
gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
const struct gvnc_pixel_format *fmt);
+#if 0
gboolean gvnc_set_shared_buffer(struct gvnc *gvnc, int line_size, int shmid);
+#endif
gboolean gvnc_has_error(struct gvnc *gvnc);
gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb);
+#if 0
gboolean gvnc_shared_memory_enabled(struct gvnc *gvnc);
+#endif
const char *gvnc_get_name(struct gvnc *gvnc);
int gvnc_get_width(struct gvnc *gvnc);
int gvnc_get_height(struct gvnc *gvnc);
+
+VncTunnel *gvnc_tunnel_open(struct gvnc *gvnc, const char *name);
#endif
/*
diff -r d6f1a50dbb0b src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version Sun Oct 21 17:11:07 2007 -0300
+++ b/src/libgtk-vnc_sym.version Tue Dec 11 20:44:49 2007 -0600
@@ -25,6 +25,13 @@
vnc_display_get_name;
vnc_display_client_cut_text;
+
+ vnc_display_tunnel_open;
+
+ vnc_tunnel_get_type;
+ vnc_tunnel_recv;
+ vnc_tunnel_send;
+ vnc_tunnel_new;
gvnc_new;
gvnc_free;
diff -r d6f1a50dbb0b src/vnc.override
--- a/src/vnc.override Sun Oct 21 17:11:07 2007 -0300
+++ b/src/vnc.override Tue Dec 11 20:44:49 2007 -0600
@@ -3,13 +3,19 @@ headers
#include <Python.h>
#include "pygobject.h"
#include "vncdisplay.h"
+#include "vnctunnel.h"
%%
modulename gtkvnc
%%
import gtk.DrawingArea as PyGtkDrawingArea_Type
+import gobject.GObject as PyGObject_Type
%%
ignore-glob
*_get_type
+ vnc_tunnel_get_tid
+ vnc_tunnel_set_tid
+ vnc_tunnel_feed_recv
+ vnc_tunnel_feed_shutdown
%%
override vnc_display_send_keys kwargs
static PyObject*
@@ -46,3 +52,45 @@ _wrap_vnc_display_send_keys(PyGObject *s
vnc_display_send_keys(VNC_DISPLAY(self->obj), keys, len);
free(keys);
}
+
+%%
+override vnc_tunnel_recv noargs
+static PyObject *
+_wrap_vnc_tunnel_recv(PyGObject *self)
+{
+ gchar *str;
+ guint size;
+ PyObject *ret;
+
+ str = vnc_tunnel_recv(VNC_TUNNEL(self->obj), &size);
+ if (str == NULL) {
+ Py_INCREF(Py_None);
+ ret = Py_None;
+ } else {
+ ret = PyString_FromStringAndSize(str, size);
+ g_free(str);
+ }
+
+ return ret;
+}
+
+%%
+override vnc_tunnel_send onearg
+static PyObject *
+_wrap_vnc_tunnel_send(PyGObject *self, PyObject *arg)
+{
+ GString *str;
+ char *data;
+ Py_ssize_t length;
+ PyObject *ret;
+ int err;
+
+ err = PyString_AsStringAndSize(arg, &data, &length);
+ if (err == -1)
+ return NULL;
+
+ vnc_tunnel_send(VNC_TUNNEL(self->obj), data, length);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
diff -r d6f1a50dbb0b src/vncdisplay.c
--- a/src/vncdisplay.c Sun Oct 21 17:11:07 2007 -0300
+++ b/src/vncdisplay.c Tue Dec 11 20:44:49 2007 -0600
@@ -80,6 +80,8 @@ typedef enum
VNC_SERVER_CUT_TEXT,
VNC_BELL,
+
+ VNC_TUNNEL_INIT,
LAST_SIGNAL
} vnc_display_signals;
@@ -482,9 +484,11 @@ static gboolean on_resize(void *opaque,
priv->fb.linesize = priv->shm_image->bytes_per_line;
priv->fb.data = (uint8_t *)priv->shm_image->pixels;
+#if 0
if (gvnc_shared_memory_enabled(priv->gvnc) && priv->fb.shm_id != -1)
gvnc_set_shared_buffer(priv->gvnc,
priv->fb.linesize, priv->fb.shm_id);
+#endif
gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
@@ -510,6 +514,7 @@ static gboolean on_pointer_type_change(v
return TRUE;
}
+#if 0
static gboolean on_shared_memory_rmid(void *opaque, int shmid)
{
VncDisplay *obj = VNC_DISPLAY(opaque);
@@ -525,6 +530,7 @@ static gboolean on_shared_memory_rmid(vo
priv->fb.shm_id = -1;
return TRUE;
}
+#endif
static gboolean on_auth_cred(void *opaque)
@@ -674,6 +680,17 @@ static gboolean on_local_cursor(void *op
return TRUE;
}
+static gboolean on_tunnels_available(void *opaque)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+
+ g_signal_emit (G_OBJECT (obj),
+ signals[VNC_TUNNEL_INIT],
+ 0);
+
+ return TRUE;
+}
+
static const struct gvnc_ops vnc_display_ops = {
.auth_cred = on_auth_cred,
.auth_type = on_auth_type,
@@ -682,7 +699,7 @@ static const struct gvnc_ops vnc_display
.update = on_update,
.resize = on_resize,
.pointer_type_change = on_pointer_type_change,
- .shared_memory_rmid = on_shared_memory_rmid,
+ .tunnels_available = on_tunnels_available,
.local_cursor = on_local_cursor,
.auth_unsupported = on_auth_unsupported,
.server_cut_text = on_server_cut_text,
@@ -696,7 +713,7 @@ static void *vnc_coroutine(void *opaque)
int32_t encodings[] = { GVNC_ENCODING_DESKTOP_RESIZE,
GVNC_ENCODING_RICH_CURSOR,
GVNC_ENCODING_XCURSOR,
- GVNC_ENCODING_SHARED_MEMORY,
+ GVNC_ENCODING_TUNNEL_IO,
GVNC_ENCODING_POINTER_CHANGE,
GVNC_ENCODING_HEXTILE,
GVNC_ENCODING_COPY_RECT,
@@ -730,7 +747,7 @@ static void *vnc_coroutine(void *opaque)
signals[VNC_INITIALIZED],
0);
- if (!gvnc_set_encodings(priv->gvnc, 6, encodings))
+ if (!gvnc_set_encodings(priv->gvnc, 8, encodings))
goto cleanup;
if (!gvnc_framebuffer_update_request(priv->gvnc, 0, 0, 0, priv->fb.width, priv->fb.height))
@@ -855,7 +872,7 @@ static void vnc_display_destroy (GtkObje
}
-static void vnc_display_finalize (GObject *obj)
+static void vnc_display_finalize(GObject *obj)
{
VncDisplay *display = VNC_DISPLAY (obj);
GVNC_DEBUG("Releasing VNC widget\n");
@@ -923,6 +940,16 @@ static void vnc_display_class_init(VncDi
1,
G_TYPE_VALUE_ARRAY);
+
+ signals[VNC_TUNNEL_INIT] =
+ g_signal_new ("vnc-tunnel-init",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (VncDisplayClass, vnc_tunnel_init),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
signals[VNC_POINTER_GRAB] =
g_signal_new("vnc-pointer-grab",
@@ -1245,6 +1272,13 @@ void vnc_display_client_cut_text(VncDisp
gvnc_client_cut_text(obj->priv->gvnc, text, strlen (text));
}
+VncTunnel *vnc_display_tunnel_open(VncDisplay *obj, const gchar *name)
+{
+ g_return_val_if_fail(VNC_IS_DISPLAY(obj), NULL);
+
+ return gvnc_tunnel_open(obj->priv->gvnc, name);
+}
+
/*
* Local variables:
* c-indent-level: 8
diff -r d6f1a50dbb0b src/vncdisplay.h
--- a/src/vncdisplay.h Sun Oct 21 17:11:07 2007 -0300
+++ b/src/vncdisplay.h Tue Dec 11 20:44:49 2007 -0600
@@ -17,6 +17,8 @@ typedef struct _VncDisplayPrivate VncDis
#include <gtk/gtkdrawingarea.h>
#include <glib.h>
+
+#include "vnctunnel.h"
#define VNC_TYPE_DISPLAY (vnc_display_get_type())
#define VNC_TYPE_DISPLAY_CREDENTIAL (vnc_display_credential_get_type())
@@ -52,6 +54,7 @@ struct _VncDisplayClass
void (* vnc_initialized) (VncDisplay *display);
void (* vnc_disconnected) (VncDisplay *display);
void (* vnc_auth_credential) (VncDisplay *display, GValueArray *credList);
+ void (* vnc_tunnel_init) (VncDisplay *display);
};
typedef enum
@@ -89,6 +92,8 @@ const char * vnc_display_get_name(VncDis
void vnc_display_client_cut_text(VncDisplay *obj, const gchar *text);
+VncTunnel * vnc_display_tunnel_open(VncDisplay *obj, const gchar *name);
+
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]