(root)/
glib-2.79.0/
gio/
tests/
gdbus-overflow.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: David Zeuthen <davidz@redhat.com>
      21   */
      22  
      23  #include "config.h"
      24  
      25  #include <gio/gio.h>
      26  #include <unistd.h>
      27  #include <string.h>
      28  
      29  /* for open(2) */
      30  #include <sys/types.h>
      31  #include <sys/stat.h>
      32  #include <fcntl.h>
      33  #include <string.h>
      34  
      35  /* for g_unlink() */
      36  #include <glib/gstdio.h>
      37  
      38  #include <gio/gnetworking.h>
      39  #include <gio/gunixsocketaddress.h>
      40  #include <gio/gunixfdlist.h>
      41  
      42  /* used in test_overflow */
      43  #ifdef G_OS_UNIX
      44  #include <gio/gunixconnection.h>
      45  #include <errno.h>
      46  #endif
      47  
      48  #ifdef G_OS_UNIX
      49  static gboolean is_unix = TRUE;
      50  #else
      51  static gboolean is_unix = FALSE;
      52  #endif
      53  
      54  static gchar *tmp_address = NULL;
      55  static gchar *test_guid = NULL;
      56  static GMainLoop *loop = NULL;
      57  
      58  static const gchar *test_interface_introspection_xml =
      59    "<node>"
      60    "  <interface name='org.gtk.GDBus.PeerTestInterface'>"
      61    "    <method name='HelloPeer'>"
      62    "      <arg type='s' name='greeting' direction='in'/>"
      63    "      <arg type='s' name='response' direction='out'/>"
      64    "    </method>"
      65    "    <method name='EmitSignal'/>"
      66    "    <method name='EmitSignalWithNameSet'/>"
      67    "    <method name='OpenFile'>"
      68    "      <arg type='s' name='path' direction='in'/>"
      69    "    </method>"
      70    "    <signal name='PeerSignal'>"
      71    "      <arg type='s' name='a_string'/>"
      72    "    </signal>"
      73    "    <property type='s' name='PeerProperty' access='read'/>"
      74    "  </interface>"
      75    "</node>";
      76  static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
      77  
      78  
      79  #ifdef G_OS_UNIX
      80  
      81  /* Chosen to be big enough to overflow the socket buffer */
      82  #define OVERFLOW_NUM_SIGNALS 5000
      83  #define OVERFLOW_TIMEOUT_SEC 10
      84  
      85  static GDBusMessage *
      86  overflow_filter_func (GDBusConnection *connection,
      87                        GDBusMessage    *message,
      88                        gboolean         incoming,
      89                        gpointer         user_data)
      90  {
      91    gint *counter = user_data;  /* (atomic) */
      92    g_atomic_int_inc (counter);
      93    return message;
      94  }
      95  
      96  static gboolean
      97  overflow_on_500ms_later_func (gpointer user_data)
      98  {
      99    g_main_loop_quit (loop);
     100    return G_SOURCE_REMOVE;
     101  }
     102  
     103  static void
     104  test_overflow (void)
     105  {
     106    gint sv[2];
     107    gint n;
     108    GSocket *socket;
     109    GSocketConnection *socket_connection;
     110    GDBusConnection *producer, *consumer;
     111    GError *error;
     112    GTimer *timer;
     113    gint n_messages_received;  /* (atomic) */
     114    gint n_messages_sent;  /* (atomic) */
     115  
     116    g_assert_cmpint (socketpair (AF_UNIX, SOCK_STREAM, 0, sv), ==, 0);
     117  
     118    error = NULL;
     119    socket = g_socket_new_from_fd (sv[0], &error);
     120    g_assert_no_error (error);
     121    socket_connection = g_socket_connection_factory_create_connection (socket);
     122    g_assert (socket_connection != NULL);
     123    g_object_unref (socket);
     124    producer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
     125  					 NULL, /* guid */
     126  					 G_DBUS_CONNECTION_FLAGS_NONE,
     127  					 NULL, /* GDBusAuthObserver */
     128  					 NULL, /* GCancellable */
     129  
     130  					 &error);
     131    g_dbus_connection_set_exit_on_close (producer, TRUE);
     132    g_assert_no_error (error);
     133    g_object_unref (socket_connection);
     134    g_atomic_int_set (&n_messages_sent, 0);
     135    g_dbus_connection_add_filter (producer, overflow_filter_func, (gpointer) &n_messages_sent, NULL);
     136  
     137    /* send enough data that we get an EAGAIN */
     138    for (n = 0; n < OVERFLOW_NUM_SIGNALS; n++)
     139      {
     140        error = NULL;
     141        g_dbus_connection_emit_signal (producer,
     142                                       NULL, /* destination */
     143                                       "/org/foo/Object",
     144                                       "org.foo.Interface",
     145                                       "Member",
     146                                       g_variant_new ("(s)", "a string"),
     147                                       &error);
     148        g_assert_no_error (error);
     149      }
     150  
     151    /* sleep for 0.5 sec (to allow the GDBus IO thread to fill up the
     152     * kernel buffers) and verify that n_messages_sent <
     153     * OVERFLOW_NUM_SIGNALS
     154     *
     155     * This is to verify that not all the submitted messages have been
     156     * sent to the underlying transport.
     157     */
     158    g_timeout_add (500, overflow_on_500ms_later_func, NULL);
     159    g_main_loop_run (loop);
     160    g_assert_cmpint (g_atomic_int_get (&n_messages_sent), <, OVERFLOW_NUM_SIGNALS);
     161  
     162    /* now suck it all out as a client, and add it up */
     163    socket = g_socket_new_from_fd (sv[1], &error);
     164    g_assert_no_error (error);
     165    socket_connection = g_socket_connection_factory_create_connection (socket);
     166    g_assert (socket_connection != NULL);
     167    g_object_unref (socket);
     168    consumer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
     169  					 NULL, /* guid */
     170  					 G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
     171  					 NULL, /* GDBusAuthObserver */
     172  					 NULL, /* GCancellable */
     173  					 &error);
     174    g_assert_no_error (error);
     175    g_object_unref (socket_connection);
     176    g_atomic_int_set (&n_messages_received, 0);
     177    g_dbus_connection_add_filter (consumer, overflow_filter_func, (gpointer) &n_messages_received, NULL);
     178    g_dbus_connection_start_message_processing (consumer);
     179  
     180    timer = g_timer_new ();
     181    g_timer_start (timer);
     182  
     183    while (g_atomic_int_get (&n_messages_received) < OVERFLOW_NUM_SIGNALS && g_timer_elapsed (timer, NULL) < OVERFLOW_TIMEOUT_SEC)
     184        g_main_context_iteration (NULL, FALSE);
     185  
     186    g_assert_cmpint (g_atomic_int_get (&n_messages_sent), ==, OVERFLOW_NUM_SIGNALS);
     187    g_assert_cmpint (g_atomic_int_get (&n_messages_received), ==, OVERFLOW_NUM_SIGNALS);
     188  
     189    g_timer_destroy (timer);
     190    g_object_unref (consumer);
     191    g_object_unref (producer);
     192  }
     193  #else
     194  static void
     195  test_overflow (void)
     196  {
     197    /* TODO: test this with e.g. GWin32InputStream/GWin32OutputStream */
     198  }
     199  #endif
     200  
     201  /* ---------------------------------------------------------------------------------------------------- */
     202  
     203  
     204  int
     205  main (int   argc,
     206        char *argv[])
     207  {
     208    gint ret;
     209    GDBusNodeInfo *introspection_data = NULL;
     210    gchar *tmpdir = NULL;
     211  
     212    g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
     213  
     214    introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
     215    g_assert (introspection_data != NULL);
     216    test_interface_introspection_data = introspection_data->interfaces[0];
     217  
     218    test_guid = g_dbus_generate_guid ();
     219  
     220    if (is_unix)
     221      {
     222        tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
     223        tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
     224      }
     225    else
     226      tmp_address = g_strdup ("nonce-tcp:");
     227  
     228    /* all the tests rely on a shared main loop */
     229    loop = g_main_loop_new (NULL, FALSE);
     230  
     231    g_test_add_func ("/gdbus/overflow", test_overflow);
     232  
     233    ret = g_test_run();
     234  
     235    g_main_loop_unref (loop);
     236    g_free (test_guid);
     237    g_dbus_node_info_unref (introspection_data);
     238    if (is_unix)
     239      g_free (tmp_address);
     240    if (tmpdir)
     241      {
     242        g_rmdir (tmpdir);
     243        g_free (tmpdir);
     244      }
     245  
     246    return ret;
     247  }