X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Ftests%2Fsocket.c;h=f4c23f8f43a3c3ba42e0c60ce5aa56244f1b288e;hb=4f734873006729d18551c215d9dcf22392dbeaf3;hp=87b426ef75f65569b1f46f33df5de24804fe914b;hpb=eac8d47e373bd57e3cb117508c0812b53963a732;p=platform%2Fupstream%2Fglib.git diff --git a/gio/tests/socket.c b/gio/tests/socket.c index 87b426e..f4c23f8 100644 --- a/gio/tests/socket.c +++ b/gio/tests/socket.c @@ -13,23 +13,24 @@ * 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. + * Public License along with this library; if not, see . */ #include #ifdef G_OS_UNIX #include -#include -#include #include #include #include +#include #include #endif +#include "gnetworkingprivate.h" + +static gboolean ipv6_supported; + typedef struct { GSocket *server; GSocket *client; @@ -66,11 +67,14 @@ echo_server_thread (gpointer user_data) g_socket_close (sock, &error); g_assert_no_error (error); + g_object_unref (sock); return NULL; } static IPTestData * -create_server (GSocketFamily family) +create_server (GSocketFamily family, + GThreadFunc server_thread, + gboolean v4mapped) { IPTestData *data; GSocket *server; @@ -93,7 +97,23 @@ create_server (GSocketFamily family) g_socket_set_blocking (server, TRUE); - iaddr = g_inet_address_new_loopback (family); +#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY) + if (v4mapped) + { + g_socket_set_option (data->server, IPPROTO_IPV6, IPV6_V6ONLY, FALSE, NULL); + 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); @@ -105,12 +125,12 @@ create_server (GSocketFamily family) 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_create (echo_server_thread, data, TRUE, &error); - g_assert_no_error (error); + data->thread = g_thread_new ("server", server_thread, data); return data; } @@ -178,7 +198,7 @@ test_ip_async_timed_out (GSocket *client, if (data->family == G_SOCKET_FAMILY_IPV4) { - g_assert_cmpint (cond, ==, 0); + 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); @@ -253,8 +273,9 @@ test_ip_async (GSocketFamily family) gssize len; gchar buf[128]; - data = create_server (family); + data = create_server (family, echo_server_thread, FALSE); addr = g_socket_get_local_address (data->server, &error); + g_assert_no_error (error); client = g_socket_new (family, G_SOCKET_TYPE_STREAM, @@ -285,6 +306,7 @@ test_ip_async (GSocketFamily family) 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); @@ -319,6 +341,12 @@ test_ipv4_async (void) static void test_ipv6_async (void) { + if (!ipv6_supported) + { + g_test_skip ("No support for IPv6"); + return; + } + test_ip_async (G_SOCKET_FAMILY_IPV6); } @@ -332,8 +360,9 @@ test_ip_sync (GSocketFamily family) gssize len; gchar buf[128]; - data = create_server (family); + data = create_server (family, echo_server_thread, FALSE); addr = g_socket_get_local_address (data->server, &error); + g_assert_no_error (error); client = g_socket_new (family, G_SOCKET_TYPE_STREAM, @@ -351,6 +380,7 @@ test_ip_sync (GSocketFamily family) 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) @@ -400,9 +430,278 @@ test_ipv4_sync (void) static void test_ipv6_sync (void) { + if (!ipv6_supported) + { + g_test_skip ("No support for IPv6"); + return; + } + 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); + g_assert_no_error (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; + + if (!ipv6_supported) + { + g_test_skip ("No support for IPv6"); + return; + } + + 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); + g_assert_no_error (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); + 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_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) @@ -544,22 +843,262 @@ test_unix_connection_ancillary_data (void) } #endif /* G_OS_UNIX */ +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); +} + int main (int argc, char *argv[]) { - g_type_init (); + GSocket *sock; + GError *error = NULL; + g_test_init (&argc, &argv, NULL); + sock = g_socket_new (G_SOCKET_FAMILY_IPV6, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + &error); + if (sock != NULL) + { + ipv6_supported = TRUE; + g_object_unref (sock); + } + else + { + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_clear_error (&error); + } + 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_sync", test_ipv6_async); + 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 + g_test_add_func ("/socket/reuse/tcp", test_reuse_tcp); + g_test_add_func ("/socket/reuse/udp", test_reuse_udp); + g_test_add_data_func ("/socket/get_available/datagram", GUINT_TO_POINTER (G_SOCKET_TYPE_DATAGRAM), + test_get_available); + g_test_add_data_func ("/socket/get_available/stream", GUINT_TO_POINTER (G_SOCKET_TYPE_STREAM), + test_get_available); return g_test_run(); }