(root)/
glib-2.79.0/
gio/
tests/
gsocketclient-slow.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright (C) 2018 Igalia S.L.
       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  
      21  #include <gio/gio.h>
      22  
      23  static void
      24  on_connected (GObject      *source_object,
      25                GAsyncResult *result,
      26                gpointer      user_data)
      27  {
      28    GSocketConnection *conn;
      29    GError *error = NULL;
      30  
      31    conn = g_socket_client_connect_to_uri_finish (G_SOCKET_CLIENT (source_object), result, &error);
      32    g_assert_no_error (error);
      33  
      34    g_object_unref (conn);
      35    g_main_loop_quit (user_data);
      36  }
      37  
      38  static void
      39  test_happy_eyeballs (void)
      40  {
      41    GSocketClient *client;
      42    GSocketService *service;
      43    GError *error = NULL;
      44    guint16 port;
      45    GMainLoop *loop;
      46  
      47    loop = g_main_loop_new (NULL, FALSE);
      48  
      49    service = g_socket_service_new ();
      50    port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
      51    g_assert_no_error (error);
      52    g_socket_service_start (service);
      53  
      54    /* All of the magic here actually happens in slow-connect-preload.c
      55     * which as you would guess is preloaded. So this is just making a
      56     * normal connection that happens to take 600ms each time. This will
      57     * trigger the logic to make multiple parallel connections.
      58     */
      59    client = g_socket_client_new ();
      60    g_socket_client_connect_to_host_async (client, "localhost", port, NULL, on_connected, loop);
      61    g_main_loop_run (loop);
      62  
      63    g_main_loop_unref (loop);
      64    g_object_unref (service);
      65    g_object_unref (client);
      66  }
      67  
      68  static void
      69  on_connected_cancelled (GObject      *source_object,
      70                          GAsyncResult *result,
      71                          gpointer      user_data)
      72  {
      73    GSocketConnection *conn;
      74    GError *error = NULL;
      75  
      76    conn = g_socket_client_connect_to_uri_finish (G_SOCKET_CLIENT (source_object), result, &error);
      77    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
      78    g_assert_null (conn);
      79  
      80    g_error_free (error);
      81    g_main_loop_quit (user_data);
      82  }
      83  
      84  typedef struct
      85  {
      86    GCancellable *cancellable;
      87    gboolean completed;
      88  } EventCallbackData;
      89  
      90  static void
      91  on_event (GSocketClient      *client,
      92            GSocketClientEvent  event,
      93            GSocketConnectable *connectable,
      94            GIOStream          *connection,
      95            EventCallbackData  *data)
      96  {
      97    if (data->cancellable && event == G_SOCKET_CLIENT_CONNECTED)
      98      {
      99        g_cancellable_cancel (data->cancellable);
     100      }
     101    else if (event == G_SOCKET_CLIENT_COMPLETE)
     102      {
     103        data->completed = TRUE;
     104        g_assert_null (connection);
     105      }
     106  }
     107  
     108  static void
     109  test_happy_eyeballs_cancel_delayed (void)
     110  {
     111    GSocketClient *client;
     112    GSocketService *service;
     113    GError *error = NULL;
     114    guint16 port;
     115    GMainLoop *loop;
     116    EventCallbackData data = { NULL, FALSE };
     117  
     118    /* This just tests that cancellation works as expected, still emits the completed signal,
     119     * and never returns a connection */
     120  
     121    loop = g_main_loop_new (NULL, FALSE);
     122  
     123    service = g_socket_service_new ();
     124    port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
     125    g_assert_no_error (error);
     126    g_socket_service_start (service);
     127  
     128    client = g_socket_client_new ();
     129    data.cancellable = g_cancellable_new ();
     130    g_socket_client_connect_to_host_async (client, "localhost", port, data.cancellable, on_connected_cancelled, loop);
     131    g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
     132    g_main_loop_run (loop);
     133  
     134    g_assert_true (data.completed);
     135    g_main_loop_unref (loop);
     136    g_object_unref (service);
     137    g_object_unref (client);
     138    g_object_unref (data.cancellable);
     139  }
     140  
     141  static void
     142  test_happy_eyeballs_cancel_instant (void)
     143  {
     144    GSocketClient *client;
     145    GSocketService *service;
     146    GError *error = NULL;
     147    guint16 port;
     148    GMainLoop *loop;
     149    GCancellable *cancel;
     150    EventCallbackData data = { NULL, FALSE };
     151  
     152    /* This tests the same things as above, test_happy_eyeballs_cancel_delayed(), but
     153     * with different timing since it sends an already cancelled cancellable */
     154  
     155    loop = g_main_loop_new (NULL, FALSE);
     156  
     157    service = g_socket_service_new ();
     158    port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
     159    g_assert_no_error (error);
     160    g_socket_service_start (service);
     161  
     162    client = g_socket_client_new ();
     163    cancel = g_cancellable_new ();
     164    g_cancellable_cancel (cancel);
     165    g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop);
     166    g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
     167    g_main_loop_run (loop);
     168  
     169    g_assert_true (data.completed);
     170    g_main_loop_unref (loop);
     171    g_object_unref (service);
     172    g_object_unref (client);
     173    g_object_unref (cancel);
     174  }
     175  
     176  int
     177  main (int argc, char *argv[])
     178  {
     179    g_test_init (&argc, &argv, NULL);
     180  
     181    g_test_add_func ("/socket-client/happy-eyeballs/slow", test_happy_eyeballs);
     182    g_test_add_func ("/socket-client/happy-eyeballs/cancellation/instant", test_happy_eyeballs_cancel_instant);
     183    g_test_add_func ("/socket-client/happy-eyeballs/cancellation/delayed", test_happy_eyeballs_cancel_delayed);
     184  
     185  
     186    return g_test_run ();
     187  }