g_io_add_watch and non-blocking io on windows

2007-07-05 Thread Alexander Semyonov
Hello! I am trying to discover how to use non-blocking io with glib on
windows. I am trying such program:

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */

#include glib.h

#ifdef G_OS_WIN32
#include winsock2.h
#include ws2tcpip.h
#endif

gboolean
connect_cb (GIOChannel *io_channel, GIOCondition condition, gpointer data)
{
switch (condition) {
case G_IO_OUT:
g_debug (Connected.);
break;
case G_IO_ERR:
g_debug (Error!);
break;
}

return FALSE;
}

int
main (int argc, char *argv[])
{
#ifdef G_OS_WIN32
int ret;
WSADATA wsaData;
SOCKET  sd;
struct sockaddr_in target;
struct hostent*hptr;
u_long mode = 1;
GMainLoop *loop;
GIOChannel*io_channel;
GSource   *source;

ret = WSAStartup (0x0202, wsaData);
if (ret) {
g_error (WSAStaroup failed with error %d, ret);
}

sd = socket (AF_INET, SOCK_STREAM, 0);
if (sd == INVALID_SOCKET) {
g_error (socket failed with error %d, WSAGetLastError ());
}

target.sin_family = AF_INET;
target.sin_port   = htons (80);
if ( (hptr = gethostbyname (somehost.com)) == NULL) {
g_error (gethostbyname () failed with error %d\n, WSAGetLastError
());
}
memcpy ((target.sin_addr.s_addr), hptr-h_addr_list[0],
sizeof (target.sin_addr.s_addr));

if (ioctlsocket(sd, FIONBIO, mode) == SOCKET_ERROR) {
g_error(ioctlsocket() failed \n);
}

loop = g_main_loop_new (NULL, FALSE);
io_channel = g_io_channel_win32_new_socket (sd);
g_io_channel_set_encoding (io_channel, NULL, NULL);
g_io_channel_set_buffered (io_channel, FALSE);
g_io_add_watch (io_channel, G_IO_ERR | G_IO_OUT, connect_cb, NULL);

g_debug (Executing connect async...);
ret = connect (sd, (const struct sockaddr *) target, sizeof (target));
if (ret == SOCKET_ERROR) {
if (WSAGetLastError () != WSAEWOULDBLOCK)
g_error (connect () failed with error %d\n, WSAGetLastError
());
}

g_debug (Starting GMainLoop...);
g_main_loop_run (loop);

#endif

return 0;
}

/* END */

My problem is that condition parameter in callback is always G_IO_OUT even
if target host:port is unreachable. How can I discover that connect was
unsuccessfull? Thanx.

// wbr Alexander
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: g_io_add_watch and non-blocking io on windows

2007-07-05 Thread Tor Lillqvist
Alexander Semyonov writes:
  My problem is that condition parameter in callback is always G_IO_OUT even
  if target host:port is unreachable. How can I discover that connect was
  unsuccessfull?

Yeah. The code in giowin32.c is known to be rather fragile and indeed
buggy.

This might be fixed by a patch attached to bug #357674. The bug
description seems partly similar. Unfortunately the patch is not
attached to the bug, but just as a pointer to a zip file on the web
that doesn't exist any longer, sigh.

(Yeah, I said in December last year in that bug that I would look into
it soon... Please consider half a year later soon...)

Daniel, you commented on that bug and apparently did manage to
download the zip file with the patch when it still was available, do
you still have it?

--tml
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: g_io_add_watch and non-blocking io on windows

2007-07-05 Thread Tor Lillqvist
Tor Lillqvist writes:
  Daniel, you commented on that bug and apparently did manage to
  download the zip file with the patch when it still was available, do
  you still have it?

(I got it, thanks. And of course, right after that, I did find it on
my disk after all... Will have a close look at it and see if it helps
Alexander's problem, for instance.)

--tml
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: g_io_add_watch and non-blocking io on windows

2007-07-05 Thread Tor Lillqvist
Alexander Semyonov writes:
  My problem is that condition parameter in callback is always G_IO_OUT even
  if target host:port is unreachable. How can I discover that connect was
  unsuccessfull? Thanx.

The root cause for this apparently is that the giowin32.c code doesn't
check whether the connection actually succeeded or not when
WSAEnumNetworkEvents() returns with the FD_CONNECT bit set in the
WSANETWORKEVENTS.

Reading the fine documentation for connect() on MSDN, it clearly says
that when using the WSAEventSelect() mechanism (which giowin32.c
does), the event will fire and WSAEnumNetworkEvents() will return with
the FD_CONNECT bit set in WSANETWORKEVENTS.lNetworkEvents when the
connection attempt has finished, successfuly or not.

Whether it succeeded or not should be checked from the error code
corresponding to FD_CONNECT in the WSANETWORKEVENTS.iErrorCode. This
is what giowin32.c should do, if it needs to differentiate. (Which is
not 100% clear, read on...)

What do you expect to happen if the connection fails? Presumably that
your callback function is called with G_IO_ERR? Is that what happens
on Unix? (Your test program only contains Win32 code to set up the
socket.) Or is that G_IO_ERR just your guess?

Could it be G_IO_HUP that one should look for instead? (That wouldn't
be entirely logical, if there hasn't been any connection in the first
place, how can it be hung up...?)

Or could it really be that G_IO_OUT is actually the right event to get
even when the connection didn't succeed, and it's then up to notice
that the socket is not connected only when actually attempting to send
that? That would be rather silly, I think.

--tml
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: g_io_add_watch and non-blocking io on windows

2007-07-05 Thread Tor Lillqvist
The patch attached to bug #357674 didn't help for this problem after
all. Will have to read through that bug description and the patch
closely and commit if I am reasonably convinced it doesn't cause any
regressions...

Anyway, it turns out that at least on Linux poll() sets
POLLERR|POLLHUP when it returns after polling a socket that is being
asynchronously connected and the connection finally has failed. So
g_io_win32_check() in giowin32.c should also set G_IO_ERR and G_IO_HUP
in this case.

I read in
http://www.opengroup.org/onlinepubs/95399/functions/poll.html that
POLLOUT and POLLHUP are mutually exclusive. I guess this means GLib
should also guarantee that G_IO_OUT and G_IO_HUP are mutually
exclusive. But on the other hand, if I understand the documentaion
correctly, Win32 signals FD_CLOSE only once, so do we need to make
that sticky once received once? Sigh...

Anyway, I committed a patch to giowin32.c that makes your test
program's callback function receive G_IO_ERR when the connect()
fails. (After that the program goes into a tight loop and keeps doing
g_main_poll() even if there is nothing to poll...)

2007-07-06  Tor Lillqvist  [EMAIL PROTECTED]

* glib/giowin32.c (g_io_win32_check): When WSAEnumNetworkEvents()
signals FD_CONNECT that means that the connection attempt
finished, either successfully or failed. Test explicitly whether
the connnection succeeded and set either G_IO_OUT if it did,
G_IO_ERR|G_IO_HUP if it failed.

Make sure we never set both G_IO_OUT and G_IO_HUP simultaneously
because in Unix poll(2) POLLOUT and POLLHUP are mutually
exclusive.

Ignore whether the caller wants to watch G_IO_HUP or not. Always
select for FD_CLOSE because Unix poll(2) also ignores whether
POLLHUP in set the requested events bitmask or not.

--tml
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list