PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/gio/tests/socket-service.c

https://gitlab.com/ImageMagick/glib
C | 247 lines | 163 code | 47 blank | 37 comment | 4 complexity | 360b75ed7dccc51419c0e5267ca934c5 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0
  1. /* GLib testing framework examples and tests
  2. *
  3. * Copyright 2014 Red Hat, Inc.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, see
  17. * <http://www.gnu.org/licenses/>.
  18. */
  19. #include <gio/gio.h>
  20. static void
  21. active_notify_cb (GSocketService *service,
  22. GParamSpec *pspec,
  23. gpointer data)
  24. {
  25. gboolean *success = (gboolean *)data;
  26. if (g_socket_service_is_active (service))
  27. *success = TRUE;
  28. }
  29. static void
  30. connected_cb (GObject *client,
  31. GAsyncResult *result,
  32. gpointer user_data)
  33. {
  34. GSocketService *service = G_SOCKET_SERVICE (user_data);
  35. GSocketConnection *conn;
  36. GError *error = NULL;
  37. g_assert_true (g_socket_service_is_active (service));
  38. conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
  39. g_assert_no_error (error);
  40. g_object_unref (conn);
  41. g_socket_service_stop (service);
  42. g_assert_false (g_socket_service_is_active (service));
  43. }
  44. static void
  45. test_start_stop (void)
  46. {
  47. gboolean success = FALSE;
  48. GInetAddress *iaddr;
  49. GSocketAddress *saddr, *listening_addr;
  50. GSocketService *service;
  51. GError *error = NULL;
  52. GSocketClient *client;
  53. iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
  54. saddr = g_inet_socket_address_new (iaddr, 0);
  55. g_object_unref (iaddr);
  56. /* instanciate with g_object_new so we can pass active = false */
  57. service = g_object_new (G_TYPE_SOCKET_SERVICE, "active", FALSE, NULL);
  58. g_assert_false (g_socket_service_is_active (service));
  59. g_signal_connect (service, "notify::active", G_CALLBACK (active_notify_cb), &success);
  60. g_socket_listener_add_address (G_SOCKET_LISTENER (service),
  61. saddr,
  62. G_SOCKET_TYPE_STREAM,
  63. G_SOCKET_PROTOCOL_TCP,
  64. NULL,
  65. &listening_addr,
  66. &error);
  67. g_assert_no_error (error);
  68. g_object_unref (saddr);
  69. client = g_socket_client_new ();
  70. g_socket_client_connect_async (client,
  71. G_SOCKET_CONNECTABLE (listening_addr),
  72. NULL,
  73. connected_cb, service);
  74. g_object_unref (client);
  75. g_object_unref (listening_addr);
  76. g_socket_service_start (service);
  77. g_assert_true (g_socket_service_is_active (service));
  78. do
  79. g_main_context_iteration (NULL, TRUE);
  80. while (!success);
  81. g_object_unref (service);
  82. }
  83. GMutex mutex_712570;
  84. GCond cond_712570;
  85. volatile gboolean finalized;
  86. GType test_threaded_socket_service_get_type (void);
  87. typedef GThreadedSocketService TestThreadedSocketService;
  88. typedef GThreadedSocketServiceClass TestThreadedSocketServiceClass;
  89. G_DEFINE_TYPE (TestThreadedSocketService, test_threaded_socket_service, G_TYPE_THREADED_SOCKET_SERVICE)
  90. static void
  91. test_threaded_socket_service_init (TestThreadedSocketService *service)
  92. {
  93. }
  94. static void
  95. test_threaded_socket_service_finalize (GObject *object)
  96. {
  97. G_OBJECT_CLASS (test_threaded_socket_service_parent_class)->finalize (object);
  98. /* Signal the main thread that finalization completed successfully
  99. * rather than hanging.
  100. */
  101. finalized = TRUE;
  102. g_cond_signal (&cond_712570);
  103. g_mutex_unlock (&mutex_712570);
  104. }
  105. static void
  106. test_threaded_socket_service_class_init (TestThreadedSocketServiceClass *klass)
  107. {
  108. GObjectClass *object_class = G_OBJECT_CLASS (klass);
  109. object_class->finalize = test_threaded_socket_service_finalize;
  110. }
  111. static gboolean
  112. connection_cb (GThreadedSocketService *service,
  113. GSocketConnection *connection,
  114. GObject *source_object,
  115. gpointer user_data)
  116. {
  117. /* Block until the main thread has dropped its ref to @service, so that we
  118. * will drop the final ref from this thread.
  119. */
  120. g_mutex_lock (&mutex_712570);
  121. /* The service should now have 1 ref owned by the current "run"
  122. * signal emission, and another added by GThreadedSocketService for
  123. * this thread. Both will be dropped after we return.
  124. */
  125. g_assert_cmpint (G_OBJECT (service)->ref_count, ==, 2);
  126. return FALSE;
  127. }
  128. static void
  129. client_connected_cb (GObject *client,
  130. GAsyncResult *result,
  131. gpointer user_data)
  132. {
  133. GMainLoop *loop = user_data;
  134. GSocketConnection *conn;
  135. GError *error = NULL;
  136. conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
  137. g_assert_no_error (error);
  138. g_object_unref (conn);
  139. g_main_loop_quit (loop);
  140. }
  141. static void
  142. test_threaded_712570 (void)
  143. {
  144. GSocketService *service;
  145. GSocketAddress *addr, *listening_addr;
  146. GMainLoop *loop;
  147. GSocketClient *client;
  148. GError *error = NULL;
  149. g_test_bug ("712570");
  150. g_mutex_lock (&mutex_712570);
  151. service = g_object_new (test_threaded_socket_service_get_type (), NULL);
  152. addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
  153. g_socket_listener_add_address (G_SOCKET_LISTENER (service),
  154. addr,
  155. G_SOCKET_TYPE_STREAM,
  156. G_SOCKET_PROTOCOL_TCP,
  157. NULL,
  158. &listening_addr,
  159. &error);
  160. g_assert_no_error (error);
  161. g_object_unref (addr);
  162. g_signal_connect (service, "run", G_CALLBACK (connection_cb), NULL);
  163. loop = g_main_loop_new (NULL, FALSE);
  164. client = g_socket_client_new ();
  165. g_socket_client_connect_async (client,
  166. G_SOCKET_CONNECTABLE (listening_addr),
  167. NULL,
  168. client_connected_cb, loop);
  169. g_object_unref (client);
  170. g_object_unref (listening_addr);
  171. g_main_loop_run (loop);
  172. g_main_loop_unref (loop);
  173. /* Stop the service and then wait for it to asynchronously cancel
  174. * its outstanding accept() call (and drop the associated ref).
  175. * At least one main context iteration is required in some circumstances
  176. * to ensure that the cancellation actually happens.
  177. */
  178. g_socket_service_stop (G_SOCKET_SERVICE (service));
  179. g_assert_false (g_socket_service_is_active (G_SOCKET_SERVICE (service)));
  180. do
  181. g_main_context_iteration (NULL, TRUE);
  182. while (G_OBJECT (service)->ref_count > 3);
  183. /* Drop our ref, then unlock the mutex and wait for the service to be
  184. * finalized. (Without the fix for 712570 it would hang forever here.)
  185. */
  186. g_object_unref (service);
  187. while (!finalized)
  188. g_cond_wait (&cond_712570, &mutex_712570);
  189. g_mutex_unlock (&mutex_712570);
  190. }
  191. int
  192. main (int argc,
  193. char *argv[])
  194. {
  195. g_test_init (&argc, &argv, NULL);
  196. g_test_bug_base ("http://bugzilla.gnome.org/");
  197. g_test_add_func ("/socket-service/start-stop", test_start_stop);
  198. g_test_add_func ("/socket-service/threaded/712570", test_threaded_712570);
  199. return g_test_run();
  200. }