X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Ftests%2Fsocket.c;h=f4c23f8f43a3c3ba42e0c60ce5aa56244f1b288e;hb=4f734873006729d18551c215d9dcf22392dbeaf3;hp=d2919b86ca268d9feebb5f7695bcb4bca14a51ae;hpb=d85b722734a6fcfe94032f6113de9e5c190fd7c3;p=platform%2Fupstream%2Fglib.git diff --git a/gio/tests/socket.c b/gio/tests/socket.c index d2919b8..f4c23f8 100644 --- a/gio/tests/socket.c +++ b/gio/tests/socket.c @@ -13,25 +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; @@ -101,11 +100,13 @@ create_server (GSocketFamily family, #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)); + 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 @@ -274,6 +275,7 @@ test_ip_async (GSocketFamily 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, @@ -339,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); } @@ -354,6 +362,7 @@ test_ip_sync (GSocketFamily 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, @@ -421,9 +430,100 @@ 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) @@ -463,8 +563,20 @@ test_ipv6_v4mapped (void) 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, @@ -475,6 +587,7 @@ test_ipv6_v4mapped (void) 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); @@ -499,6 +612,96 @@ test_ipv6_v4mapped (void) } #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) @@ -640,13 +843,241 @@ 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); @@ -654,11 +1085,20 @@ main (int argc, #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(); }