1 I managed to reproduce the problem you saw with gtk-vnc and windows
2 hanging. With the glib IO debug turned up high I can see it is treating
3 the FD as a file handle, rather than a socket - which is to be expected
4 because gnulib is wrapping winsock to give back real FDs.
6 Unfortunately glib is on crack, and for file handles it implements
7 IO waits by having a background thread for each file handle that sits
8 in a read/write call forever, and sets flags. To quote the docs
10 "If you have created a GIOChannel for a file descriptor and started
11 watching (polling) it, you shouldn't call read() on the file descriptor.
12 This is because adding polling for a file descriptor is implemented in
13 GLib on Windows by starting a thread that sits blocked in a read() from
14 the file descriptor most of the time. All reads from the file descriptor
15 should be done by this internal GLib thread. Your code should call only
16 g_io_channel_read(). "
18 This is just epic fail when combined with what we want todo. Making gtk-vnc
19 use g_io_channel_read() instead didn't work either. I think the glib thread
20 concept simply doesn't work for FDs which are aliases for sockets.
22 So I've tried a atch which creates an IO channel using
24 g_io_channel_win32_new_socket(_get_osfhandle(fd))
26 to explicitly make glib treat it as a socket, and avoid the thread insanity.
27 Slightly nasty because we're reversing gnulibs magic by translating the
28 FD back into a socket, but empirically it seems to work better for me. I've
29 not yet got it to hang with this patch.
31 I also needed to make our read/write functions use the 'fd' in the gvnc
32 struct, instead of fetching it from the IOChannel object.
34 Let me know if this patch works for you too....
38 diff --git a/src/gvnc.c b/src/gvnc.c
41 @@ -347,7 +347,6 @@ static int gvnc_zread(struct gvnc *gvnc,
43 static int gvnc_read(struct gvnc *gvnc, void *data, size_t len)
45 - int fd = g_io_channel_unix_get_fd(gvnc->channel);
49 @@ -380,7 +379,7 @@ static int gvnc_read(struct gvnc *gvnc,
53 - ret = recv (fd, gvnc->read_buffer, 4096, 0);
54 + ret = recv (gvnc->fd, gvnc->read_buffer, 4096, 0);
58 @@ -422,7 +421,6 @@ static int gvnc_read(struct gvnc *gvnc,
60 static void gvnc_flush(struct gvnc *gvnc)
62 - int fd = g_io_channel_unix_get_fd(gvnc->channel);
64 while (offset < gvnc->write_offset) {
66 @@ -439,7 +437,7 @@ static void gvnc_flush(struct gvnc *gvnc
71 + ret = send (gvnc->fd,
72 gvnc->write_buffer+offset,
73 gvnc->write_offset-offset, 0);
75 @@ -490,11 +488,10 @@ static ssize_t gvnc_tls_push(gnutls_tran
78 struct gvnc *gvnc = (struct gvnc *)transport;
79 - int fd = g_io_channel_unix_get_fd(gvnc->channel);
83 - ret = write(fd, data, len);
84 + ret = write(gvnc->fd, data, len);
88 @@ -508,11 +505,10 @@ static ssize_t gvnc_tls_pull(gnutls_tran
91 struct gvnc *gvnc = (struct gvnc *)transport;
92 - int fd = g_io_channel_unix_get_fd(gvnc->channel);
96 - ret = read(fd, data, len);
97 + ret = read(gvnc->fd, data, len);
101 @@ -2872,7 +2868,13 @@ gboolean gvnc_open_fd(struct gvnc *gvnc,
102 if (!gvnc_set_nonblock(fd))
105 - if (!(gvnc->channel = g_io_channel_unix_new(fd))) {
106 + if (!(gvnc->channel =
108 + g_io_channel_win32_new_socket(_get_osfhandle(fd))
110 + g_io_channel_unix_new(fd)
113 GVNC_DEBUG ("Failed to g_io_channel_unix_new()\n");
116 @@ -2917,7 +2919,13 @@ gboolean gvnc_open_host(struct gvnc *gvn
117 if (!gvnc_set_nonblock(fd))
120 - if (!(chan = g_io_channel_unix_new(fd))) {
123 + g_io_channel_win32_new_socket(_get_osfhandle(fd))
125 + g_io_channel_unix_new(fd)
129 GVNC_DEBUG ("Failed to g_io_channel_unix_new()\n");
133 |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
134 |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
135 |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
136 |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|