Blame gio/tests/socket-service.c

Packit ae235b
/* GLib testing framework examples and tests
Packit ae235b
 *
Packit ae235b
 * Copyright 2014 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, see
Packit ae235b
 * <http://www.gnu.org/licenses/>.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include <gio/gio.h>
Packit ae235b
Packit ae235b
static void
Packit ae235b
active_notify_cb (GSocketService *service,
Packit ae235b
                  GParamSpec     *pspec,
Packit ae235b
                  gpointer        data)
Packit ae235b
{
Packit ae235b
  gboolean *success = (gboolean *)data;
Packit ae235b
Packit ae235b
  if (g_socket_service_is_active (service))
Packit ae235b
    *success = TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
connected_cb (GObject      *client,
Packit ae235b
              GAsyncResult *result,
Packit ae235b
              gpointer      user_data)
Packit ae235b
{
Packit ae235b
  GSocketService *service = G_SOCKET_SERVICE (user_data);
Packit ae235b
  GSocketConnection *conn;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  g_assert_true (g_socket_service_is_active (service));
Packit ae235b
Packit ae235b
  conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_object_unref (conn);
Packit ae235b
Packit ae235b
  g_socket_service_stop (service);
Packit ae235b
  g_assert_false (g_socket_service_is_active (service));
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_start_stop (void)
Packit ae235b
{
Packit ae235b
  gboolean success = FALSE;
Packit ae235b
  GInetAddress *iaddr;
Packit ae235b
  GSocketAddress *saddr, *listening_addr;
Packit ae235b
  GSocketService *service;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GSocketClient *client;
Packit ae235b
Packit ae235b
  iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
Packit ae235b
  saddr = g_inet_socket_address_new (iaddr, 0);
Packit ae235b
  g_object_unref (iaddr);
Packit ae235b
Packit ae235b
  /* instanciate with g_object_new so we can pass active = false */
Packit ae235b
  service = g_object_new (G_TYPE_SOCKET_SERVICE, "active", FALSE, NULL);
Packit ae235b
  g_assert_false (g_socket_service_is_active (service));
Packit ae235b
Packit ae235b
  g_signal_connect (service, "notify::active", G_CALLBACK (active_notify_cb), &success);
Packit ae235b
Packit ae235b
  g_socket_listener_add_address (G_SOCKET_LISTENER (service),
Packit ae235b
                                 saddr,
Packit ae235b
                                 G_SOCKET_TYPE_STREAM,
Packit ae235b
                                 G_SOCKET_PROTOCOL_TCP,
Packit ae235b
                                 NULL,
Packit ae235b
                                 &listening_addr,
Packit ae235b
                                 &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_object_unref (saddr);
Packit ae235b
Packit ae235b
  client = g_socket_client_new ();
Packit ae235b
  g_socket_client_connect_async (client,
Packit ae235b
                                 G_SOCKET_CONNECTABLE (listening_addr),
Packit ae235b
                                 NULL,
Packit ae235b
                                 connected_cb, service);
Packit ae235b
  g_object_unref (client);
Packit ae235b
  g_object_unref (listening_addr);
Packit ae235b
Packit ae235b
  g_socket_service_start (service);
Packit ae235b
  g_assert_true (g_socket_service_is_active (service));
Packit ae235b
Packit ae235b
  do
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
  while (!success);
Packit ae235b
Packit ae235b
  g_object_unref (service);
Packit ae235b
}
Packit ae235b
Packit ae235b
GMutex mutex_712570;
Packit ae235b
GCond cond_712570;
Packit ae235b
volatile gboolean finalized;
Packit ae235b
Packit ae235b
GType test_threaded_socket_service_get_type (void);
Packit ae235b
typedef GThreadedSocketService TestThreadedSocketService;
Packit ae235b
typedef GThreadedSocketServiceClass TestThreadedSocketServiceClass;
Packit ae235b
Packit ae235b
G_DEFINE_TYPE (TestThreadedSocketService, test_threaded_socket_service, G_TYPE_THREADED_SOCKET_SERVICE)
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_threaded_socket_service_init (TestThreadedSocketService *service)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_threaded_socket_service_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  G_OBJECT_CLASS (test_threaded_socket_service_parent_class)->finalize (object);
Packit ae235b
Packit ae235b
  /* Signal the main thread that finalization completed successfully
Packit ae235b
   * rather than hanging.
Packit ae235b
   */
Packit ae235b
  finalized = TRUE;
Packit ae235b
  g_cond_signal (&cond_712570);
Packit ae235b
  g_mutex_unlock (&mutex_712570);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_threaded_socket_service_class_init (TestThreadedSocketServiceClass *klass)
Packit ae235b
{
Packit ae235b
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit ae235b
Packit ae235b
  object_class->finalize = test_threaded_socket_service_finalize;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
connection_cb (GThreadedSocketService *service,
Packit ae235b
               GSocketConnection      *connection,
Packit ae235b
               GObject                *source_object,
Packit ae235b
               gpointer                user_data)
Packit ae235b
{
Packit ae235b
  /* Block until the main thread has dropped its ref to @service, so that we
Packit ae235b
   * will drop the final ref from this thread.
Packit ae235b
   */
Packit ae235b
  g_mutex_lock (&mutex_712570);
Packit ae235b
Packit ae235b
  /* The service should now have 1 ref owned by the current "run"
Packit ae235b
   * signal emission, and another added by GThreadedSocketService for
Packit ae235b
   * this thread. Both will be dropped after we return.
Packit ae235b
   */
Packit ae235b
  g_assert_cmpint (G_OBJECT (service)->ref_count, ==, 2);
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
client_connected_cb (GObject      *client,
Packit ae235b
                     GAsyncResult *result,
Packit ae235b
                     gpointer      user_data)
Packit ae235b
{
Packit ae235b
  GMainLoop *loop = user_data;
Packit ae235b
  GSocketConnection *conn;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
Packit ae235b
  g_object_unref (conn);
Packit ae235b
  g_main_loop_quit (loop);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
test_threaded_712570 (void)
Packit ae235b
{
Packit ae235b
  GSocketService *service;
Packit ae235b
  GSocketAddress *addr, *listening_addr;
Packit ae235b
  GMainLoop *loop;
Packit ae235b
  GSocketClient *client;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  g_test_bug ("712570");
Packit ae235b
Packit ae235b
  g_mutex_lock (&mutex_712570);
Packit ae235b
Packit ae235b
  service = g_object_new (test_threaded_socket_service_get_type (), NULL);
Packit ae235b
Packit ae235b
  addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
Packit ae235b
  g_socket_listener_add_address (G_SOCKET_LISTENER (service),
Packit ae235b
                                 addr,
Packit ae235b
                                 G_SOCKET_TYPE_STREAM,
Packit ae235b
                                 G_SOCKET_PROTOCOL_TCP,
Packit ae235b
                                 NULL,
Packit ae235b
                                 &listening_addr,
Packit ae235b
                                 &error);
Packit ae235b
  g_assert_no_error (error);
Packit ae235b
  g_object_unref (addr);
Packit ae235b
Packit ae235b
  g_signal_connect (service, "run", G_CALLBACK (connection_cb), NULL);
Packit ae235b
Packit ae235b
  loop = g_main_loop_new (NULL, FALSE);
Packit ae235b
Packit ae235b
  client = g_socket_client_new ();
Packit ae235b
  g_socket_client_connect_async (client,
Packit ae235b
                                 G_SOCKET_CONNECTABLE (listening_addr),
Packit ae235b
                                 NULL,
Packit ae235b
                                 client_connected_cb, loop);
Packit ae235b
  g_object_unref (client);
Packit ae235b
  g_object_unref (listening_addr);
Packit ae235b
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_main_loop_unref (loop);
Packit ae235b
Packit ae235b
  /* Stop the service and then wait for it to asynchronously cancel
Packit ae235b
   * its outstanding accept() call (and drop the associated ref).
Packit ae235b
   * At least one main context iteration is required in some circumstances
Packit ae235b
   * to ensure that the cancellation actually happens.
Packit ae235b
   */
Packit ae235b
  g_socket_service_stop (G_SOCKET_SERVICE (service));
Packit ae235b
  g_assert_false (g_socket_service_is_active (G_SOCKET_SERVICE (service)));
Packit ae235b
Packit ae235b
  do
Packit ae235b
    g_main_context_iteration (NULL, TRUE);
Packit ae235b
  while (G_OBJECT (service)->ref_count > 3);
Packit ae235b
Packit ae235b
  /* Drop our ref, then unlock the mutex and wait for the service to be
Packit ae235b
   * finalized. (Without the fix for 712570 it would hang forever here.)
Packit ae235b
   */
Packit ae235b
  g_object_unref (service);
Packit ae235b
Packit ae235b
  while (!finalized)
Packit ae235b
    g_cond_wait (&cond_712570, &mutex_712570);
Packit ae235b
  g_mutex_unlock (&mutex_712570);
Packit ae235b
}
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int   argc,
Packit ae235b
      char *argv[])
Packit ae235b
{
Packit ae235b
  g_test_init (&argc, &argv, NULL);
Packit ae235b
Packit ae235b
  g_test_bug_base ("http://bugzilla.gnome.org/");
Packit ae235b
Packit ae235b
  g_test_add_func ("/socket-service/start-stop", test_start_stop);
Packit ae235b
  g_test_add_func ("/socket-service/threaded/712570", test_threaded_712570);
Packit ae235b
Packit ae235b
  return g_test_run();
Packit ae235b
}