+static void
+test_reuse_tcp (void)
+{
+ GSocket *sock1, *sock2;
+ GError *error = NULL;
+ GInetAddress *iaddr;
+ GSocketAddress *addr;
+
+ sock1 = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
+ addr = g_inet_socket_address_new (iaddr, 0);
+ g_object_unref (iaddr);
+ g_socket_bind (sock1, addr, TRUE, &error);
+ g_object_unref (addr);
+ g_assert_no_error (error);
+
+ g_socket_listen (sock1, &error);
+ g_assert_no_error (error);
+
+ sock2 = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ addr = g_socket_get_local_address (sock1, &error);
+ g_assert_no_error (error);
+ g_socket_bind (sock2, addr, TRUE, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE);
+ g_clear_error (&error);
+ g_object_unref (addr);
+
+ g_object_unref (sock1);
+ g_object_unref (sock2);
+}
+
+static void
+test_reuse_udp (void)
+{
+ GSocket *sock1, *sock2;
+ GError *error = NULL;
+ GInetAddress *iaddr;
+ GSocketAddress *addr;
+
+ sock1 = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_DATAGRAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
+ addr = g_inet_socket_address_new (iaddr, 0);
+ g_object_unref (iaddr);
+ g_socket_bind (sock1, addr, TRUE, &error);
+ g_object_unref (addr);
+ g_assert_no_error (error);
+
+ sock2 = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_DATAGRAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ addr = g_socket_get_local_address (sock1, &error);
+ g_assert_no_error (error);
+ g_socket_bind (sock2, addr, TRUE, &error);
+ g_object_unref (addr);
+ g_assert_no_error (error);
+
+ g_object_unref (sock1);
+ g_object_unref (sock2);
+}
+
+static void
+test_get_available (gconstpointer user_data)
+{
+ GSocketType socket_type = GPOINTER_TO_UINT (user_data);
+ GError *err = NULL;
+ GSocket *listener, *server, *client;
+ GInetAddress *addr;
+ GSocketAddress *saddr;
+ gchar data[] = "0123456789abcdef";
+ gchar buf[34];
+ gssize nread;
+
+ listener = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ socket_type,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &err);
+ g_assert_no_error (err);
+ g_assert (G_IS_SOCKET (listener));
+
+ client = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ socket_type,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &err);
+ g_assert_no_error (err);
+ g_assert (G_IS_SOCKET (client));
+
+ if (socket_type == G_SOCKET_TYPE_STREAM)
+ {
+ g_socket_set_option (client, IPPROTO_TCP, TCP_NODELAY, TRUE, &err);
+ g_assert_no_error (err);
+ }
+
+ addr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
+ saddr = g_inet_socket_address_new (addr, 0);
+
+ g_socket_bind (listener, saddr, TRUE, &err);
+ g_assert_no_error (err);
+ g_object_unref (saddr);
+ g_object_unref (addr);
+
+ saddr = g_socket_get_local_address (listener, &err);
+ g_assert_no_error (err);
+
+ if (socket_type == G_SOCKET_TYPE_STREAM)
+ {
+ g_socket_listen (listener, &err);
+ g_assert_no_error (err);
+ g_socket_connect (client, saddr, NULL, &err);
+ g_assert_no_error (err);
+
+ server = g_socket_accept (listener, NULL, &err);
+ g_assert_no_error (err);
+ g_socket_set_blocking (server, FALSE);
+ g_object_unref (listener);
+ }
+ else
+ server = listener;
+
+ g_socket_send_to (client, saddr, data, sizeof (data), NULL, &err);
+ g_assert_no_error (err);
+
+ while (!g_socket_condition_wait (server, G_IO_IN, NULL, NULL))
+ ;
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, sizeof (data));
+
+ g_socket_send_to (client, saddr, data, sizeof (data), NULL, &err);
+ g_assert_no_error (err);
+
+ /* We need to wait until the data has actually been copied into the
+ * server socket's buffers, but g_socket_condition_wait() won't help
+ * here since the socket is definitely already readable. So there's
+ * a race condition in checking its available bytes. In the TCP
+ * case, we poll for a bit until the new data shows up. In the UDP
+ * case, there's not much we can do, but at least the failure mode
+ * is passes-when-it-shouldn't, not fails-when-it-shouldn't.
+ */
+ if (socket_type == G_SOCKET_TYPE_STREAM)
+ {
+ int tries;
+
+ for (tries = 0; tries < 100; tries++)
+ {
+ if (g_socket_get_available_bytes (server) > sizeof (data))
+ break;
+ g_usleep (100000);
+ }
+
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, 2 * sizeof (data));
+ }
+ else
+ {
+ g_usleep (100000);
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, sizeof (data));
+ }
+
+ g_assert_cmpint (sizeof (buf), >=, 2 * sizeof (data));
+ nread = g_socket_receive (server, buf, sizeof (buf), NULL, &err);
+ g_assert_no_error (err);
+
+ if (socket_type == G_SOCKET_TYPE_STREAM)
+ {
+ g_assert_cmpint (nread, ==, 2 * sizeof (data));
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, 0);
+ }
+ else
+ {
+ g_assert_cmpint (nread, ==, sizeof (data));
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, sizeof (data));
+ }
+
+ nread = g_socket_receive (server, buf, sizeof (buf), NULL, &err);
+ if (socket_type == G_SOCKET_TYPE_STREAM)
+ {
+ g_assert_cmpint (nread, ==, -1);
+ g_assert_error (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
+ g_clear_error (&err);
+ }
+ else
+ {
+ g_assert_cmpint (nread, ==, sizeof (data));
+ g_assert_no_error (err);
+ }
+
+ g_assert_cmpint (g_socket_get_available_bytes (server), ==, 0);
+
+ g_socket_close (server, &err);
+ g_assert_no_error (err);
+
+ g_object_unref (saddr);
+ g_object_unref (server);
+ g_object_unref (client);
+}
+