--- /dev/null
+I managed to reproduce the problem you saw with gtk-vnc and windows
+hanging. With the glib IO debug turned up high I can see it is treating
+the FD as a file handle, rather than a socket - which is to be expected
+because gnulib is wrapping winsock to give back real FDs.
+
+Unfortunately glib is on crack, and for file handles it implements
+IO waits by having a background thread for each file handle that sits
+in a read/write call forever, and sets flags. To quote the docs
+
+ "If you have created a GIOChannel for a file descriptor and started
+ watching (polling) it, you shouldn't call read() on the file descriptor.
+ This is because adding polling for a file descriptor is implemented in
+ GLib on Windows by starting a thread that sits blocked in a read() from
+ the file descriptor most of the time. All reads from the file descriptor
+ should be done by this internal GLib thread. Your code should call only
+ g_io_channel_read(). "
+
+This is just epic fail when combined with what we want todo. Making gtk-vnc
+use g_io_channel_read() instead didn't work either. I think the glib thread
+concept simply doesn't work for FDs which are aliases for sockets.
+
+So I've tried a atch which creates an IO channel using
+
+ g_io_channel_win32_new_socket(_get_osfhandle(fd))
+
+to explicitly make glib treat it as a socket, and avoid the thread insanity.
+Slightly nasty because we're reversing gnulibs magic by translating the
+FD back into a socket, but empirically it seems to work better for me. I've
+not yet got it to hang with this patch.
+
+I also needed to make our read/write functions use the 'fd' in the gvnc
+struct, instead of fetching it from the IOChannel object.
+
+Let me know if this patch works for you too....
+
+Daniel
+
+diff --git a/src/gvnc.c b/src/gvnc.c
+--- a/src/gvnc.c
++++ b/src/gvnc.c
+@@ -347,7 +347,6 @@ static int gvnc_zread(struct gvnc *gvnc,
+
+ static int gvnc_read(struct gvnc *gvnc, void *data, size_t len)
+ {
+- int fd = g_io_channel_unix_get_fd(gvnc->channel);
+ char *ptr = data;
+ size_t offset = 0;
+
+@@ -380,7 +379,7 @@ static int gvnc_read(struct gvnc *gvnc,
+ ret = -1;
+ }
+ } else
+- ret = recv (fd, gvnc->read_buffer, 4096, 0);
++ ret = recv (gvnc->fd, gvnc->read_buffer, 4096, 0);
+
+ if (ret == -1) {
+ switch (errno) {
+@@ -422,7 +421,6 @@ static int gvnc_read(struct gvnc *gvnc,
+
+ static void gvnc_flush(struct gvnc *gvnc)
+ {
+- int fd = g_io_channel_unix_get_fd(gvnc->channel);
+ size_t offset = 0;
+ while (offset < gvnc->write_offset) {
+ int ret;
+@@ -439,7 +437,7 @@ static void gvnc_flush(struct gvnc *gvnc
+ ret = -1;
+ }
+ } else
+- ret = send (fd,
++ ret = send (gvnc->fd,
+ gvnc->write_buffer+offset,
+ gvnc->write_offset-offset, 0);
+ if (ret == -1) {
+@@ -490,11 +488,10 @@ static ssize_t gvnc_tls_push(gnutls_tran
+ const void *data,
+ size_t len) {
+ struct gvnc *gvnc = (struct gvnc *)transport;
+- int fd = g_io_channel_unix_get_fd(gvnc->channel);
+ int ret;
+
+ retry:
+- ret = write(fd, data, len);
++ ret = write(gvnc->fd, data, len);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto retry;
+@@ -508,11 +505,10 @@ static ssize_t gvnc_tls_pull(gnutls_tran
+ void *data,
+ size_t len) {
+ struct gvnc *gvnc = (struct gvnc *)transport;
+- int fd = g_io_channel_unix_get_fd(gvnc->channel);
+ int ret;
+
+ retry:
+- ret = read(fd, data, len);
++ ret = read(gvnc->fd, data, len);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto retry;
+@@ -2872,7 +2868,13 @@ gboolean gvnc_open_fd(struct gvnc *gvnc,
+ if (!gvnc_set_nonblock(fd))
+ return FALSE;
+
+- if (!(gvnc->channel = g_io_channel_unix_new(fd))) {
++ if (!(gvnc->channel =
++#ifdef WIN32
++ g_io_channel_win32_new_socket(_get_osfhandle(fd))
++#else
++ g_io_channel_unix_new(fd)
++#endif
++ )) {
+ GVNC_DEBUG ("Failed to g_io_channel_unix_new()\n");
+ return FALSE;
+ }
+@@ -2917,7 +2919,13 @@ gboolean gvnc_open_host(struct gvnc *gvn
+ if (!gvnc_set_nonblock(fd))
+ break;
+
+- if (!(chan = g_io_channel_unix_new(fd))) {
++ if (!(chan =
++#ifdef WIN32
++ g_io_channel_win32_new_socket(_get_osfhandle(fd))
++#else
++ g_io_channel_unix_new(fd)
++#endif
++ )) {
+ close(fd);
+ GVNC_DEBUG ("Failed to g_io_channel_unix_new()\n");
+ break;
+
+--
+|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
+|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
+|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
+|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|