mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 23:46:15 +01:00
a60014f1b6
The flowinfo and scope_id fields of struct sockaddr_in6 are in host byte order, but the code previously assumed they were in network byte order. Fix that. This is an ABI-breaking change (since before you would have had to use g_ntohl() and g_htonl() with them to get the correct values, and now that would give the wrong values), but the previous behavior was clearly wrong, and no one ever reported it, so it is likely that no one was actually using it. https://bugzilla.gnome.org/show_bug.cgi?id=684404
852 lines
22 KiB
C
852 lines
22 KiB
C
/* GLib testing framework examples and tests
|
|
*
|
|
* Copyright (C) 2008-2011 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#ifdef G_OS_UNIX
|
|
#include <errno.h>
|
|
#include <sys/wait.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <gio/gnetworking.h>
|
|
#include <gio/gunixconnection.h>
|
|
#endif
|
|
|
|
#include "gnetworkingprivate.h"
|
|
|
|
typedef struct {
|
|
GSocket *server;
|
|
GSocket *client;
|
|
GSocketFamily family;
|
|
GThread *thread;
|
|
GMainLoop *loop;
|
|
} IPTestData;
|
|
|
|
static gpointer
|
|
echo_server_thread (gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GSocket *sock;
|
|
GError *error = NULL;
|
|
gssize nread, nwrote;
|
|
gchar buf[128];
|
|
|
|
sock = g_socket_accept (data->server, NULL, &error);
|
|
g_assert_no_error (error);
|
|
|
|
while (TRUE)
|
|
{
|
|
nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (nread, >=, 0);
|
|
|
|
if (nread == 0)
|
|
break;
|
|
|
|
nwrote = g_socket_send (sock, buf, nread, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (nwrote, ==, nread);
|
|
}
|
|
|
|
g_socket_close (sock, &error);
|
|
g_assert_no_error (error);
|
|
g_object_unref (sock);
|
|
return NULL;
|
|
}
|
|
|
|
static IPTestData *
|
|
create_server (GSocketFamily family,
|
|
GThreadFunc server_thread,
|
|
gboolean v4mapped)
|
|
{
|
|
IPTestData *data;
|
|
GSocket *server;
|
|
GError *error = NULL;
|
|
GSocketAddress *addr;
|
|
GInetAddress *iaddr;
|
|
|
|
data = g_slice_new (IPTestData);
|
|
data->family = family;
|
|
|
|
data->server = server = g_socket_new (family,
|
|
G_SOCKET_TYPE_STREAM,
|
|
G_SOCKET_PROTOCOL_DEFAULT,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_cmpint (g_socket_get_family (server), ==, family);
|
|
g_assert_cmpint (g_socket_get_socket_type (server), ==, G_SOCKET_TYPE_STREAM);
|
|
g_assert_cmpint (g_socket_get_protocol (server), ==, G_SOCKET_PROTOCOL_DEFAULT);
|
|
|
|
g_socket_set_blocking (server, TRUE);
|
|
|
|
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
|
|
if (v4mapped)
|
|
{
|
|
int fd, v6_only;
|
|
|
|
fd = g_socket_get_fd (server);
|
|
v6_only = 0;
|
|
setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only, sizeof (v6_only));
|
|
if (! g_socket_speaks_ipv4 (data->server))
|
|
{
|
|
g_object_unref (data->server);
|
|
g_slice_free (IPTestData, data);
|
|
return NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (v4mapped)
|
|
iaddr = g_inet_address_new_any (family);
|
|
else
|
|
iaddr = g_inet_address_new_loopback (family);
|
|
addr = g_inet_socket_address_new (iaddr, 0);
|
|
g_object_unref (iaddr);
|
|
|
|
g_assert_cmpint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)), ==, 0);
|
|
g_socket_bind (server, addr, TRUE, &error);
|
|
g_assert_no_error (error);
|
|
g_object_unref (addr);
|
|
|
|
addr = g_socket_get_local_address (server, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)), !=, 0);
|
|
g_object_unref (addr);
|
|
|
|
g_socket_listen (server, &error);
|
|
g_assert_no_error (error);
|
|
|
|
data->thread = g_thread_new ("server", server_thread, data);
|
|
|
|
return data;
|
|
}
|
|
|
|
static const gchar *testbuf = "0123456789abcdef";
|
|
|
|
static gboolean
|
|
test_ip_async_read_ready (GSocket *client,
|
|
GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GError *error = NULL;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
g_assert_cmpint (cond, ==, G_IO_IN);
|
|
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
|
|
|
|
g_assert_cmpstr (testbuf, ==, buf);
|
|
|
|
g_main_loop_quit (data->loop);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
test_ip_async_write_ready (GSocket *client,
|
|
GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GError *error = NULL;
|
|
GSource *source;
|
|
gssize len;
|
|
|
|
g_assert_cmpint (cond, ==, G_IO_OUT);
|
|
|
|
len = g_socket_send (client, testbuf, strlen (testbuf) + 1, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
|
|
|
|
source = g_socket_create_source (client, G_IO_IN, NULL);
|
|
g_source_set_callback (source, (GSourceFunc)test_ip_async_read_ready,
|
|
data, NULL);
|
|
g_source_attach (source, NULL);
|
|
g_source_unref (source);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
test_ip_async_timed_out (GSocket *client,
|
|
GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GError *error = NULL;
|
|
GSource *source;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
if (data->family == G_SOCKET_FAMILY_IPV4)
|
|
{
|
|
g_assert_cmpint (cond, ==, G_IO_IN);
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_cmpint (len, ==, -1);
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
source = g_socket_create_source (client, G_IO_OUT, NULL);
|
|
g_source_set_callback (source, (GSourceFunc)test_ip_async_write_ready,
|
|
data, NULL);
|
|
g_source_attach (source, NULL);
|
|
g_source_unref (source);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
test_ip_async_connected (GSocket *client,
|
|
GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GError *error = NULL;
|
|
GSource *source;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
g_socket_check_connect_result (client, &error);
|
|
g_assert_no_error (error);
|
|
/* We do this after the check_connect_result, since that will give a
|
|
* more useful assertion in case of error.
|
|
*/
|
|
g_assert_cmpint (cond, ==, G_IO_OUT);
|
|
|
|
g_assert (g_socket_is_connected (client));
|
|
|
|
/* This adds 1 second to "make check", so let's just only do it once. */
|
|
if (data->family == G_SOCKET_FAMILY_IPV4)
|
|
{
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_cmpint (len, ==, -1);
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
|
|
g_clear_error (&error);
|
|
|
|
source = g_socket_create_source (client, G_IO_IN, NULL);
|
|
g_source_set_callback (source, (GSourceFunc)test_ip_async_timed_out,
|
|
data, NULL);
|
|
g_source_attach (source, NULL);
|
|
g_source_unref (source);
|
|
}
|
|
else
|
|
test_ip_async_timed_out (client, 0, data);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
idle_test_ip_async_connected (gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
|
|
return test_ip_async_connected (data->client, G_IO_OUT, data);
|
|
}
|
|
|
|
static void
|
|
test_ip_async (GSocketFamily family)
|
|
{
|
|
IPTestData *data;
|
|
GError *error = NULL;
|
|
GSocket *client;
|
|
GSocketAddress *addr;
|
|
GSource *source;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
data = create_server (family, echo_server_thread, FALSE);
|
|
addr = g_socket_get_local_address (data->server, &error);
|
|
|
|
client = g_socket_new (family,
|
|
G_SOCKET_TYPE_STREAM,
|
|
G_SOCKET_PROTOCOL_DEFAULT,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
data->client = client;
|
|
|
|
g_assert_cmpint (g_socket_get_family (client), ==, family);
|
|
g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM);
|
|
g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT);
|
|
|
|
g_socket_set_blocking (client, FALSE);
|
|
g_socket_set_timeout (client, 1);
|
|
|
|
if (g_socket_connect (client, addr, NULL, &error))
|
|
{
|
|
g_assert_no_error (error);
|
|
g_idle_add (idle_test_ip_async_connected, data);
|
|
}
|
|
else
|
|
{
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
|
|
g_clear_error (&error);
|
|
source = g_socket_create_source (client, G_IO_OUT, NULL);
|
|
g_source_set_callback (source, (GSourceFunc)test_ip_async_connected,
|
|
data, NULL);
|
|
g_source_attach (source, NULL);
|
|
g_source_unref (source);
|
|
}
|
|
g_object_unref (addr);
|
|
|
|
data->loop = g_main_loop_new (NULL, TRUE);
|
|
g_main_loop_run (data->loop);
|
|
g_main_loop_unref (data->loop);
|
|
|
|
g_socket_shutdown (client, FALSE, TRUE, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_thread_join (data->thread);
|
|
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, 0);
|
|
|
|
g_socket_close (client, &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_slice_free (IPTestData, data);
|
|
}
|
|
|
|
static void
|
|
test_ipv4_async (void)
|
|
{
|
|
test_ip_async (G_SOCKET_FAMILY_IPV4);
|
|
}
|
|
|
|
static void
|
|
test_ipv6_async (void)
|
|
{
|
|
test_ip_async (G_SOCKET_FAMILY_IPV6);
|
|
}
|
|
|
|
static void
|
|
test_ip_sync (GSocketFamily family)
|
|
{
|
|
IPTestData *data;
|
|
GError *error = NULL;
|
|
GSocket *client;
|
|
GSocketAddress *addr;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
data = create_server (family, echo_server_thread, FALSE);
|
|
addr = g_socket_get_local_address (data->server, &error);
|
|
|
|
client = g_socket_new (family,
|
|
G_SOCKET_TYPE_STREAM,
|
|
G_SOCKET_PROTOCOL_DEFAULT,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_cmpint (g_socket_get_family (client), ==, family);
|
|
g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM);
|
|
g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT);
|
|
|
|
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);
|
|
|
|
/* This adds 1 second to "make check", so let's just only do it once. */
|
|
if (family == G_SOCKET_FAMILY_IPV4)
|
|
{
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_cmpint (len, ==, -1);
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
len = g_socket_send (client, testbuf, strlen (testbuf) + 1, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
|
|
|
|
len = g_socket_receive (client, 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_thread_join (data->thread);
|
|
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, 0);
|
|
|
|
g_socket_close (client, &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_slice_free (IPTestData, data);
|
|
}
|
|
|
|
static void
|
|
test_ipv4_sync (void)
|
|
{
|
|
test_ip_sync (G_SOCKET_FAMILY_IPV4);
|
|
}
|
|
|
|
static void
|
|
test_ipv6_sync (void)
|
|
{
|
|
test_ip_sync (G_SOCKET_FAMILY_IPV6);
|
|
}
|
|
|
|
static gpointer
|
|
graceful_server_thread (gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GSocket *sock;
|
|
GError *error = NULL;
|
|
gssize len;
|
|
|
|
sock = g_socket_accept (data->server, NULL, &error);
|
|
g_assert_no_error (error);
|
|
|
|
len = g_socket_send (sock, testbuf, strlen (testbuf) + 1, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
|
|
|
|
return sock;
|
|
}
|
|
|
|
static void
|
|
test_close_graceful (void)
|
|
{
|
|
GSocketFamily family = G_SOCKET_FAMILY_IPV4;
|
|
IPTestData *data;
|
|
GError *error = NULL;
|
|
GSocket *client, *server;
|
|
GSocketAddress *addr;
|
|
gssize len;
|
|
gchar buf[128];
|
|
|
|
data = create_server (family, graceful_server_thread, FALSE);
|
|
addr = g_socket_get_local_address (data->server, &error);
|
|
|
|
client = g_socket_new (family,
|
|
G_SOCKET_TYPE_STREAM,
|
|
G_SOCKET_PROTOCOL_DEFAULT,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_cmpint (g_socket_get_family (client), ==, family);
|
|
g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM);
|
|
g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT);
|
|
|
|
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);
|
|
|
|
server = g_thread_join (data->thread);
|
|
|
|
/* similar to g_tcp_connection_set_graceful_disconnect(), but explicit */
|
|
g_socket_shutdown (server, FALSE, TRUE, &error);
|
|
g_assert_no_error (error);
|
|
|
|
/* we must timeout */
|
|
g_socket_condition_wait (client, G_IO_HUP, NULL, &error);
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
|
g_clear_error (&error);
|
|
|
|
/* check that the remaining data is received */
|
|
len = g_socket_receive (client, buf, strlen (testbuf) + 1, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, strlen (testbuf) + 1);
|
|
|
|
/* and only then the connection is closed */
|
|
len = g_socket_receive (client, buf, sizeof (buf), NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (len, ==, 0);
|
|
|
|
g_socket_close (server, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_socket_close (client, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_object_unref (server);
|
|
g_object_unref (data->server);
|
|
g_object_unref (client);
|
|
|
|
g_slice_free (IPTestData, data);
|
|
}
|
|
|
|
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
|
|
static gpointer
|
|
v4mapped_server_thread (gpointer user_data)
|
|
{
|
|
IPTestData *data = user_data;
|
|
GSocket *sock;
|
|
GError *error = NULL;
|
|
GSocketAddress *addr;
|
|
|
|
sock = g_socket_accept (data->server, NULL, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_cmpint (g_socket_get_family (sock), ==, G_SOCKET_FAMILY_IPV6);
|
|
|
|
addr = g_socket_get_local_address (sock, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (g_socket_address_get_family (addr), ==, G_SOCKET_FAMILY_IPV4);
|
|
g_object_unref (addr);
|
|
|
|
addr = g_socket_get_remote_address (sock, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (g_socket_address_get_family (addr), ==, G_SOCKET_FAMILY_IPV4);
|
|
g_object_unref (addr);
|
|
|
|
g_socket_close (sock, &error);
|
|
g_assert_no_error (error);
|
|
g_object_unref (sock);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
test_ipv6_v4mapped (void)
|
|
{
|
|
IPTestData *data;
|
|
GError *error = NULL;
|
|
GSocket *client;
|
|
GSocketAddress *addr, *v4addr;
|
|
GInetAddress *iaddr;
|
|
|
|
data = create_server (G_SOCKET_FAMILY_IPV6, v4mapped_server_thread, TRUE);
|
|
|
|
if (data == NULL)
|
|
{
|
|
g_test_message ("Test not run: not supported by the OS");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
addr = g_socket_get_local_address (data->server, &error);
|
|
iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
|
|
v4addr = g_inet_socket_address_new (iaddr, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
|
|
g_object_unref (iaddr);
|
|
g_object_unref (addr);
|
|
|
|
g_socket_connect (client, v4addr, NULL, &error);
|
|
g_assert_no_error (error);
|
|
g_assert (g_socket_is_connected (client));
|
|
|
|
g_thread_join (data->thread);
|
|
|
|
g_socket_close (client, &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 (v4addr);
|
|
|
|
g_slice_free (IPTestData, data);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
test_timed_wait (void)
|
|
{
|
|
IPTestData *data;
|
|
GError *error = NULL;
|
|
GSocket *client;
|
|
GSocketAddress *addr;
|
|
gint64 start_time;
|
|
gint poll_duration;
|
|
|
|
data = create_server (G_SOCKET_FAMILY_IPV4, echo_server_thread, FALSE);
|
|
addr = g_socket_get_local_address (data->server, &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_object_unref (addr);
|
|
|
|
start_time = g_get_monotonic_time ();
|
|
g_socket_condition_timed_wait (client, G_IO_IN, 100000 /* 100 ms */,
|
|
NULL, &error);
|
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
|
|
g_clear_error (&error);
|
|
poll_duration = g_get_monotonic_time () - start_time;
|
|
|
|
g_assert_cmpint (poll_duration, >=, 98000);
|
|
g_assert_cmpint (poll_duration, <, 112000);
|
|
|
|
g_socket_close (client, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_thread_join (data->thread);
|
|
|
|
g_socket_close (data->server, &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_object_unref (data->server);
|
|
g_object_unref (client);
|
|
|
|
g_slice_free (IPTestData, data);
|
|
}
|
|
|
|
static void
|
|
test_sockaddr (void)
|
|
{
|
|
struct sockaddr_in6 sin6, gsin6;
|
|
GSocketAddress *saddr;
|
|
GInetSocketAddress *isaddr;
|
|
GInetAddress *iaddr;
|
|
GError *error = NULL;
|
|
|
|
memset (&sin6, 0, sizeof (sin6));
|
|
sin6.sin6_family = AF_INET6;
|
|
sin6.sin6_addr = in6addr_loopback;
|
|
sin6.sin6_port = g_htons (42);
|
|
sin6.sin6_scope_id = 17;
|
|
sin6.sin6_flowinfo = 1729;
|
|
|
|
saddr = g_socket_address_new_from_native (&sin6, sizeof (sin6));
|
|
g_assert (G_IS_INET_SOCKET_ADDRESS (saddr));
|
|
|
|
isaddr = G_INET_SOCKET_ADDRESS (saddr);
|
|
iaddr = g_inet_socket_address_get_address (isaddr);
|
|
g_assert_cmpint (g_inet_address_get_family (iaddr), ==, G_SOCKET_FAMILY_IPV6);
|
|
g_assert (g_inet_address_get_is_loopback (iaddr));
|
|
|
|
g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, 42);
|
|
g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, 17);
|
|
g_assert_cmpint (g_inet_socket_address_get_flowinfo (isaddr), ==, 1729);
|
|
|
|
g_socket_address_to_native (saddr, &gsin6, sizeof (gsin6), &error);
|
|
g_assert_no_error (error);
|
|
|
|
g_assert (memcmp (&sin6.sin6_addr, &gsin6.sin6_addr, sizeof (struct in6_addr)) == 0);
|
|
g_assert_cmpint (sin6.sin6_port, ==, gsin6.sin6_port);
|
|
g_assert_cmpint (sin6.sin6_scope_id, ==, gsin6.sin6_scope_id);
|
|
g_assert_cmpint (sin6.sin6_flowinfo, ==, gsin6.sin6_flowinfo);
|
|
|
|
g_object_unref (saddr);
|
|
}
|
|
|
|
#ifdef G_OS_UNIX
|
|
static void
|
|
test_unix_from_fd (void)
|
|
{
|
|
gint fd;
|
|
GError *error;
|
|
GSocket *s;
|
|
|
|
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
|
g_assert_cmpint (fd, !=, -1);
|
|
|
|
error = NULL;
|
|
s = g_socket_new_from_fd (fd, &error);
|
|
g_assert_no_error (error);
|
|
g_assert_cmpint (g_socket_get_family (s), ==, G_SOCKET_FAMILY_UNIX);
|
|
g_assert_cmpint (g_socket_get_socket_type (s), ==, G_SOCKET_TYPE_STREAM);
|
|
g_assert_cmpint (g_socket_get_protocol (s), ==, G_SOCKET_PROTOCOL_DEFAULT);
|
|
g_object_unref (s);
|
|
}
|
|
|
|
static void
|
|
test_unix_connection (void)
|
|
{
|
|
gint fd;
|
|
GError *error;
|
|
GSocket *s;
|
|
GSocketConnection *c;
|
|
|
|
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
|
g_assert_cmpint (fd, !=, -1);
|
|
|
|
error = NULL;
|
|
s = g_socket_new_from_fd (fd, &error);
|
|
g_assert_no_error (error);
|
|
c = g_socket_connection_factory_create_connection (s);
|
|
g_assert (G_IS_UNIX_CONNECTION (c));
|
|
g_object_unref (c);
|
|
g_object_unref (s);
|
|
}
|
|
|
|
static GSocketConnection *
|
|
create_connection_for_fd (int fd)
|
|
{
|
|
GError *err = NULL;
|
|
GSocket *socket;
|
|
GSocketConnection *connection;
|
|
|
|
socket = g_socket_new_from_fd (fd, &err);
|
|
g_assert_no_error (err);
|
|
g_assert (G_IS_SOCKET (socket));
|
|
connection = g_socket_connection_factory_create_connection (socket);
|
|
g_assert (G_IS_UNIX_CONNECTION (connection));
|
|
g_object_unref (socket);
|
|
return connection;
|
|
}
|
|
|
|
#define TEST_DATA "failure to say failure to say 'i love gnome-panel!'."
|
|
|
|
static void
|
|
test_unix_connection_ancillary_data (void)
|
|
{
|
|
GError *err = NULL;
|
|
gint pv[2], sv[3];
|
|
gint status, fd, len;
|
|
char buffer[1024];
|
|
pid_t pid;
|
|
|
|
status = pipe (pv);
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
status = socketpair (PF_UNIX, SOCK_STREAM, 0, sv);
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
pid = fork ();
|
|
g_assert_cmpint (pid, >=, 0);
|
|
|
|
/* Child: close its copy of the write end of the pipe, receive it
|
|
* again from the parent over the socket, and write some text to it.
|
|
*
|
|
* Parent: send the write end of the pipe (still open for the
|
|
* parent) over the socket, close it, and read some text from the
|
|
* read end of the pipe.
|
|
*/
|
|
if (pid == 0)
|
|
{
|
|
GSocketConnection *connection;
|
|
|
|
close (sv[1]);
|
|
connection = create_connection_for_fd (sv[0]);
|
|
|
|
status = close (pv[1]);
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
err = NULL;
|
|
fd = g_unix_connection_receive_fd (G_UNIX_CONNECTION (connection), NULL,
|
|
&err);
|
|
g_assert_no_error (err);
|
|
g_assert_cmpint (fd, >, -1);
|
|
g_object_unref (connection);
|
|
|
|
do
|
|
len = write (fd, TEST_DATA, sizeof (TEST_DATA));
|
|
while (len == -1 && errno == EINTR);
|
|
g_assert_cmpint (len, ==, sizeof (TEST_DATA));
|
|
exit (0);
|
|
}
|
|
else
|
|
{
|
|
GSocketConnection *connection;
|
|
|
|
close (sv[0]);
|
|
connection = create_connection_for_fd (sv[1]);
|
|
|
|
err = NULL;
|
|
g_unix_connection_send_fd (G_UNIX_CONNECTION (connection), pv[1], NULL,
|
|
&err);
|
|
g_assert_no_error (err);
|
|
g_object_unref (connection);
|
|
|
|
status = close (pv[1]);
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
memset (buffer, 0xff, sizeof buffer);
|
|
do
|
|
len = read (pv[0], buffer, sizeof buffer);
|
|
while (len == -1 && errno == EINTR);
|
|
|
|
g_assert_cmpint (len, ==, sizeof (TEST_DATA));
|
|
g_assert_cmpstr (buffer, ==, TEST_DATA);
|
|
|
|
waitpid (pid, &status, 0);
|
|
g_assert (WIFEXITED (status));
|
|
g_assert_cmpint (WEXITSTATUS (status), ==, 0);
|
|
}
|
|
|
|
/* TODO: add test for g_unix_connection_send_credentials() and
|
|
* g_unix_connection_receive_credentials().
|
|
*/
|
|
}
|
|
#endif /* G_OS_UNIX */
|
|
|
|
int
|
|
main (int argc,
|
|
char *argv[])
|
|
{
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
g_test_add_func ("/socket/ipv4_sync", test_ipv4_sync);
|
|
g_test_add_func ("/socket/ipv4_async", test_ipv4_async);
|
|
g_test_add_func ("/socket/ipv6_sync", test_ipv6_sync);
|
|
g_test_add_func ("/socket/ipv6_async", test_ipv6_async);
|
|
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
|
|
g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped);
|
|
#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/address", test_sockaddr);
|
|
#ifdef G_OS_UNIX
|
|
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
|
|
g_test_add_func ("/socket/unix-connection", test_unix_connection);
|
|
g_test_add_func ("/socket/unix-connection-ancillary-data", test_unix_connection_ancillary_data);
|
|
#endif
|
|
|
|
return g_test_run();
|
|
}
|
|
|