From 1bcaf0b93cfed5e23b0a4d73b07b6ab195d289d7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 1 Jan 1970 00:00:00 +0000 Subject: [PATCH] Added Dan's fd/socket fix. --- gtk-vnc/gtk-vnc-dan-fd-fix.patch | 136 +++++++++++++++++++++++++++++++++++++++ gtk-vnc/mingw32-gtk-vnc.spec | 7 +- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 gtk-vnc/gtk-vnc-dan-fd-fix.patch diff --git a/gtk-vnc/gtk-vnc-dan-fd-fix.patch b/gtk-vnc/gtk-vnc-dan-fd-fix.patch new file mode 100644 index 0000000..86b2b1a --- /dev/null +++ b/gtk-vnc/gtk-vnc-dan-fd-fix.patch @@ -0,0 +1,136 @@ +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 :| diff --git a/gtk-vnc/mingw32-gtk-vnc.spec b/gtk-vnc/mingw32-gtk-vnc.spec index 187a6da..809109c 100644 --- a/gtk-vnc/mingw32-gtk-vnc.spec +++ b/gtk-vnc/mingw32-gtk-vnc.spec @@ -8,7 +8,7 @@ Name: mingw32-gtk-vnc Version: 0.3.8 -Release: 0.1.20081030hg%{?dist} +Release: 0.2.20081030hg%{?dist} Summary: MinGW Windows port of VNC client GTK widget License: LGPLv2+ @@ -24,6 +24,7 @@ Patch102: gtk-vnc-02-ioctl.patch Patch103: gtk-vnc-03-wsastartup.patch #Patch104: gtk-vnc-hgignore.patch Patch105: gtk-vnc-ldflags-confusion.patch +Patch106: gtk-vnc-dan-fd-fix.patch BuildArch: noarch @@ -52,6 +53,7 @@ allowing it to be completely asynchronous while remaining single threaded. %patch103 -p1 #%patch104 -p1 %patch105 -p1 +%patch106 -p1 autoreconf @@ -88,6 +90,9 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Thu Oct 30 2008 Richard W.M. Jones - 0.3.8-0.2.20081030hg +- Add Dan's fd/socket fix for Windows. + * Thu Oct 30 2008 Richard W.M. Jones - 0.3.8-0.1.20081030hg - Upgrade to current version in Mercurial (pre-release of 0.3.8). - More MinGW patches. -- 1.8.3.1