gsocket: add a testcase that shows a hang on win32

Add a unit test that checks g_socket_new_from_fd by creating
a gsocket, obtaining its fd, duplicating the fd and then creating
a gsocket from the new fd. This shows a hang on win32 since the
gsocket created from the fd never receives the FD_WRITE event
because we wait for the condition without first trying to write
and windows signals the condition only after a EWOULDBLOCK error.

https://bugzilla.gnome.org/show_bug.cgi?id=741707
This commit is contained in:
Paolo Borelli 2015-01-10 15:23:07 +01:00
parent 2c5076cd58
commit 4f4714285d

View File

@ -929,6 +929,99 @@ test_timed_wait (void)
g_slice_free (IPTestData, data);
}
static int
duplicate_fd(int fd)
{
#ifdef G_OS_WIN32
HANDLE newfd;
if (!DuplicateHandle (GetCurrentProcess (),
(HANDLE)fd,
GetCurrentProcess (),
&newfd,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
return -1;
}
return (int)newfd;
#else
return dup(fd);
#endif
}
static void
test_fd_roundtrip (void)
{
IPTestData *data;
GError *error = NULL;
GSocket *client;
GSocket *client2;
GSocketAddress *addr;
int fd;
gssize len;
gchar buf[128];
data = create_server (G_SOCKET_FAMILY_IPV4, echo_server_thread, FALSE);
addr = g_socket_get_local_address (data->server, &error);
g_assert_no_error (error);
client = g_socket_new (G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
&error);
g_assert_no_error (error);
g_socket_set_blocking (client, TRUE);
g_socket_set_timeout (client, 1);
g_socket_connect (client, addr, NULL, &error);
g_assert_no_error (error);
g_assert (g_socket_is_connected (client));
g_object_unref (addr);
/* we have to dup otherwise the fd gets closed twice on unref */
fd = duplicate_fd (g_socket_get_fd (client));
client2 = g_socket_new_from_fd (fd, &error);
g_assert_no_error (error);
g_assert_cmpint (g_socket_get_family (client2), ==, g_socket_get_family (client));
g_assert_cmpint (g_socket_get_socket_type (client2), ==, g_socket_get_socket_type (client));
g_assert_cmpint (g_socket_get_protocol (client2), ==, G_SOCKET_PROTOCOL_TCP);
len = g_socket_send (client2, testbuf, strlen (testbuf) + 1, NULL, &error);
g_assert_no_error (error);
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
len = g_socket_receive (client2, buf, sizeof (buf), NULL, &error);
g_assert_no_error (error);
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
g_assert_cmpstr (testbuf, ==, buf);
g_socket_shutdown (client, FALSE, TRUE, &error);
g_assert_no_error (error);
g_socket_shutdown (client2, FALSE, TRUE, &error);
g_assert_no_error (error);
g_thread_join (data->thread);
g_socket_close (client, &error);
g_assert_no_error (error);
g_socket_close (client2, &error);
g_assert_no_error (error);
g_socket_close (data->server, &error);
g_assert_no_error (error);
g_object_unref (data->server);
g_object_unref (client);
g_object_unref (client2);
g_slice_free (IPTestData, data);
}
static void
test_sockaddr (void)
{
@ -1355,6 +1448,7 @@ main (int argc,
#endif
g_test_add_func ("/socket/close_graceful", test_close_graceful);
g_test_add_func ("/socket/timed_wait", test_timed_wait);
g_test_add_func ("/socket/fd_roundtrip", test_fd_roundtrip);
g_test_add_func ("/socket/address", test_sockaddr);
#ifdef G_OS_UNIX
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);