PageRenderTime 78ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/gio/tests/gdbus-non-socket.c

https://gitlab.com/ImageMagick/glib
C | 302 lines | 196 code | 49 blank | 57 comment | 2 complexity | e63842298b3bbf11fd8ca1f20c755ac7 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0
  1. /* GLib testing framework examples and tests
  2. *
  3. * Copyright (C) 2008-2010 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
  16. * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * Author: David Zeuthen <davidz@redhat.com>
  19. */
  20. #include <gio/gio.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #ifdef G_OS_UNIX
  25. #include <gio/gunixinputstream.h>
  26. #include <gio/gunixoutputstream.h>
  27. #include <gio/gunixconnection.h>
  28. #endif
  29. #include "gdbus-tests.h"
  30. static GMainLoop *loop = NULL;
  31. /* ---------------------------------------------------------------------------------------------------- */
  32. #ifdef G_OS_UNIX
  33. #include "test-pipe-unix.h"
  34. #include "test-io-stream.h"
  35. /* ---------------------------------------------------------------------------------------------------- */
  36. static const GDBusArgInfo pokee_method_poke_out_arg0 = {
  37. -1, /* ref_count */
  38. "result",
  39. "s",
  40. NULL /* annotations */
  41. };
  42. static const GDBusArgInfo *pokee_method_poke_out_args[2] = {
  43. &pokee_method_poke_out_arg0,
  44. NULL,
  45. };
  46. static const GDBusArgInfo pokee_method_poke_in_arg0 = {
  47. -1, /* ref_count */
  48. "value",
  49. "s",
  50. NULL /* annotations */
  51. };
  52. static const GDBusArgInfo *pokee_method_poke_in_args[2] = {
  53. &pokee_method_poke_in_arg0,
  54. NULL,
  55. };
  56. static const GDBusMethodInfo pokee_method_poke = {
  57. -1, /* ref_count */
  58. "Poke",
  59. (GDBusArgInfo**) pokee_method_poke_in_args,
  60. (GDBusArgInfo**) pokee_method_poke_out_args,
  61. NULL /* annotations */
  62. };
  63. static const GDBusMethodInfo *pokee_methods[2] = {
  64. &pokee_method_poke,
  65. NULL
  66. };
  67. static const GDBusInterfaceInfo pokee_object_info = {
  68. -1, /* ref_count */
  69. "org.gtk.GDBus.Pokee",
  70. (GDBusMethodInfo**) pokee_methods,
  71. NULL, /* signals */
  72. NULL, /* properties */
  73. NULL /* annotations */
  74. };
  75. static void
  76. pokee_method_call (GDBusConnection *connection,
  77. const gchar *sender,
  78. const gchar *object_path,
  79. const gchar *interface_name,
  80. const gchar *method_name,
  81. GVariant *parameters,
  82. GDBusMethodInvocation *invocation,
  83. gpointer user_data)
  84. {
  85. const gchar *str;
  86. gchar *ret;
  87. g_assert_cmpstr (method_name, ==, "Poke");
  88. g_variant_get (parameters, "(&s)", &str);
  89. ret = g_strdup_printf ("You poked me with: '%s'", str);
  90. g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", ret));
  91. g_free (ret);
  92. }
  93. static const GDBusInterfaceVTable pokee_vtable = {
  94. pokee_method_call,
  95. NULL, /* get_property */
  96. NULL /* set_property */
  97. };
  98. /* Processes:
  99. *
  100. * parent
  101. * \- first child (via fork()) is the pokee
  102. * \- second child (via g_test_trap_fork()) is the poker
  103. *
  104. * The second child only exists to avoid sharing a main context between several
  105. * second-children if we run a test resembling this one multiple times.
  106. * See https://bugzilla.gnome.org/show_bug.cgi?id=658999 for why that's bad.
  107. */
  108. static void
  109. test_non_socket (void)
  110. {
  111. GIOStream *streams[2];
  112. GDBusConnection *connection;
  113. GError *error;
  114. gchar *guid;
  115. pid_t first_child;
  116. GVariant *ret;
  117. const gchar *str;
  118. gboolean ok;
  119. error = NULL;
  120. ok = test_bidi_pipe (&streams[0], &streams[1], &error);
  121. g_assert_no_error (error);
  122. g_assert (ok);
  123. g_assert (G_IS_IO_STREAM (streams[0]));
  124. g_assert (G_IS_INPUT_STREAM (g_io_stream_get_input_stream (streams[0])));
  125. g_assert (G_IS_OUTPUT_STREAM (g_io_stream_get_output_stream (streams[0])));
  126. g_assert (G_IS_IO_STREAM (streams[1]));
  127. g_assert (G_IS_INPUT_STREAM (g_io_stream_get_input_stream (streams[1])));
  128. g_assert (G_IS_OUTPUT_STREAM (g_io_stream_get_output_stream (streams[1])));
  129. switch ((first_child = fork ()))
  130. {
  131. case -1:
  132. g_assert_not_reached ();
  133. break;
  134. case 0:
  135. /* first child */
  136. /* we shouldn't do this in the parent, because we shouldn't use a
  137. * GMainContext both before and after fork
  138. */
  139. loop = g_main_loop_new (NULL, FALSE);
  140. ok = g_io_stream_close (streams[1], NULL, &error);
  141. g_assert_no_error (error);
  142. g_assert (ok);
  143. g_object_unref (streams[1]);
  144. guid = g_dbus_generate_guid ();
  145. error = NULL;
  146. /* We need to delay message processing to avoid the race
  147. * described in
  148. *
  149. * https://bugzilla.gnome.org/show_bug.cgi?id=627188
  150. *
  151. * This is because (early) dispatching is done on the IO thread
  152. * (method_call() isn't called until we're in the right thread
  153. * though) so in rare cases the parent sends the message before
  154. * we (the first child) register the object
  155. */
  156. connection = g_dbus_connection_new_sync (streams[0],
  157. guid,
  158. G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
  159. G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
  160. NULL, /* GDBusAuthObserver */
  161. NULL,
  162. &error);
  163. g_free (guid);
  164. g_assert_no_error (error);
  165. g_object_unref (streams[0]);
  166. /* make sure we exit along with the parent */
  167. g_dbus_connection_set_exit_on_close (connection, TRUE);
  168. error = NULL;
  169. g_dbus_connection_register_object (connection,
  170. "/pokee",
  171. (GDBusInterfaceInfo *) &pokee_object_info,
  172. &pokee_vtable,
  173. NULL, /* user_data */
  174. NULL, /* user_data_free_func */
  175. &error);
  176. g_assert_no_error (error);
  177. /* and now start message processing */
  178. g_dbus_connection_start_message_processing (connection);
  179. g_main_loop_run (loop);
  180. g_assert_not_reached ();
  181. break;
  182. default:
  183. /* parent continues below */
  184. break;
  185. }
  186. /* This is #ifdef G_OS_UNIX anyway, so just use g_test_trap_fork() */
  187. G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
  188. if (!g_test_trap_fork (0, 0))
  189. {
  190. /* parent */
  191. g_object_unref (streams[0]);
  192. g_object_unref (streams[1]);
  193. g_test_trap_assert_passed ();
  194. g_assert_cmpint (kill (first_child, SIGTERM), ==, 0);
  195. return;
  196. }
  197. G_GNUC_END_IGNORE_DEPRECATIONS;
  198. /* second child */
  199. /* we shouldn't do this in the parent, because we shouldn't use a
  200. * GMainContext both before and after fork
  201. */
  202. loop = g_main_loop_new (NULL, FALSE);
  203. ok = g_io_stream_close (streams[0], NULL, &error);
  204. g_assert_no_error (error);
  205. g_assert (ok);
  206. g_object_unref (streams[0]);
  207. connection = g_dbus_connection_new_sync (streams[1],
  208. NULL, /* guid */
  209. G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
  210. NULL, /* GDBusAuthObserver */
  211. NULL,
  212. &error);
  213. g_assert_no_error (error);
  214. g_object_unref (streams[1]);
  215. /* poke the first child */
  216. error = NULL;
  217. ret = g_dbus_connection_call_sync (connection,
  218. NULL, /* name */
  219. "/pokee",
  220. "org.gtk.GDBus.Pokee",
  221. "Poke",
  222. g_variant_new ("(s)", "I am the POKER!"),
  223. G_VARIANT_TYPE ("(s)"), /* return type */
  224. G_DBUS_CALL_FLAGS_NONE,
  225. -1,
  226. NULL, /* cancellable */
  227. &error);
  228. g_assert_no_error (error);
  229. g_variant_get (ret, "(&s)", &str);
  230. g_assert_cmpstr (str, ==, "You poked me with: 'I am the POKER!'");
  231. g_variant_unref (ret);
  232. g_object_unref (connection);
  233. g_main_loop_unref (loop);
  234. exit (0);
  235. }
  236. #else /* G_OS_UNIX */
  237. static void
  238. test_non_socket (void)
  239. {
  240. /* TODO: test this with e.g. GWin32InputStream/GWin32OutputStream */
  241. }
  242. #endif
  243. /* ---------------------------------------------------------------------------------------------------- */
  244. int
  245. main (int argc,
  246. char *argv[])
  247. {
  248. gint ret;
  249. g_test_init (&argc, &argv, NULL);
  250. g_test_add_func ("/gdbus/non-socket", test_non_socket);
  251. ret = g_test_run();
  252. return ret;
  253. }