(root)/
glib-2.79.0/
gio/
tests/
socket-service.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright 2014 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 Public
      18   * License along with this library; if not, see
      19   * <http://www.gnu.org/licenses/>.
      20   */
      21  
      22  #include <gio/gio.h>
      23  
      24  static void
      25  active_notify_cb (GSocketService *service,
      26                    GParamSpec     *pspec,
      27                    gpointer        data)
      28  {
      29    gboolean *success = (gboolean *)data;
      30  
      31    if (g_socket_service_is_active (service))
      32      *success = TRUE;
      33  }
      34  
      35  static void
      36  connected_cb (GObject      *client,
      37                GAsyncResult *result,
      38                gpointer      user_data)
      39  {
      40    GSocketService *service = G_SOCKET_SERVICE (user_data);
      41    GSocketConnection *conn;
      42    GError *error = NULL;
      43  
      44    g_assert_true (g_socket_service_is_active (service));
      45  
      46    conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
      47    g_assert_no_error (error);
      48    g_object_unref (conn);
      49  
      50    g_socket_service_stop (service);
      51    g_assert_false (g_socket_service_is_active (service));
      52  }
      53  
      54  static void
      55  test_start_stop (void)
      56  {
      57    gboolean success = FALSE;
      58    GInetAddress *iaddr;
      59    GSocketAddress *saddr, *listening_addr;
      60    GSocketService *service;
      61    GError *error = NULL;
      62    GSocketClient *client;
      63  
      64    iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
      65    saddr = g_inet_socket_address_new (iaddr, 0);
      66    g_object_unref (iaddr);
      67  
      68    /* instantiate with g_object_new so we can pass active = false */
      69    service = g_object_new (G_TYPE_SOCKET_SERVICE, "active", FALSE, NULL);
      70    g_assert_false (g_socket_service_is_active (service));
      71  
      72    g_signal_connect (service, "notify::active", G_CALLBACK (active_notify_cb), &success);
      73  
      74    g_socket_listener_add_address (G_SOCKET_LISTENER (service),
      75                                   saddr,
      76                                   G_SOCKET_TYPE_STREAM,
      77                                   G_SOCKET_PROTOCOL_TCP,
      78                                   NULL,
      79                                   &listening_addr,
      80                                   &error);
      81    g_assert_no_error (error);
      82    g_object_unref (saddr);
      83  
      84    client = g_socket_client_new ();
      85    g_socket_client_connect_async (client,
      86                                   G_SOCKET_CONNECTABLE (listening_addr),
      87                                   NULL,
      88                                   connected_cb, service);
      89    g_object_unref (client);
      90    g_object_unref (listening_addr);
      91  
      92    g_socket_service_start (service);
      93    g_assert_true (g_socket_service_is_active (service));
      94  
      95    do
      96      g_main_context_iteration (NULL, TRUE);
      97    while (!success);
      98  
      99    g_object_unref (service);
     100  }
     101  
     102  GMutex mutex_712570;
     103  GCond cond_712570;
     104  gboolean finalized;  /* (atomic) */
     105  
     106  GType test_threaded_socket_service_get_type (void);
     107  typedef GThreadedSocketService TestThreadedSocketService;
     108  typedef GThreadedSocketServiceClass TestThreadedSocketServiceClass;
     109  
     110  G_DEFINE_TYPE (TestThreadedSocketService, test_threaded_socket_service, G_TYPE_THREADED_SOCKET_SERVICE)
     111  
     112  static void
     113  test_threaded_socket_service_init (TestThreadedSocketService *service)
     114  {
     115  }
     116  
     117  static void
     118  test_threaded_socket_service_finalize (GObject *object)
     119  {
     120    G_OBJECT_CLASS (test_threaded_socket_service_parent_class)->finalize (object);
     121  
     122    /* Signal the main thread that finalization completed successfully
     123     * rather than hanging.
     124     */
     125    g_atomic_int_set (&finalized, TRUE);
     126    g_cond_signal (&cond_712570);
     127    g_mutex_unlock (&mutex_712570);
     128  }
     129  
     130  static void
     131  test_threaded_socket_service_class_init (TestThreadedSocketServiceClass *klass)
     132  {
     133    GObjectClass *object_class = G_OBJECT_CLASS (klass);
     134  
     135    object_class->finalize = test_threaded_socket_service_finalize;
     136  }
     137  
     138  static gboolean
     139  connection_cb (GThreadedSocketService *service,
     140                 GSocketConnection      *connection,
     141                 GObject                *source_object,
     142                 gpointer                user_data)
     143  {
     144    GMainLoop *loop = user_data;
     145  
     146    /* Since the connection attempt has come through to be handled, stop the main
     147     * thread waiting for it; this causes the #GSocketService to be stopped. */
     148    g_main_loop_quit (loop);
     149  
     150    /* Block until the main thread has dropped its ref to @service, so that we
     151     * will drop the final ref from this thread.
     152     */
     153    g_mutex_lock (&mutex_712570);
     154  
     155    /* The service should now have 1 ref owned by the current "run"
     156     * signal emission, and another added by GThreadedSocketService for
     157     * this thread. Both will be dropped after we return.
     158     */
     159    g_assert_cmpint (G_OBJECT (service)->ref_count, ==, 2);
     160  
     161    return FALSE;
     162  }
     163  
     164  static void
     165  client_connected_cb (GObject      *client,
     166                       GAsyncResult *result,
     167                       gpointer      user_data)
     168  {
     169    GSocketConnection *conn;
     170    GError *error = NULL;
     171  
     172    conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
     173    g_assert_no_error (error);
     174  
     175    g_object_unref (conn);
     176  }
     177  
     178  static void
     179  test_threaded_712570 (void)
     180  {
     181    GSocketService *service;
     182    GSocketAddress *addr, *listening_addr;
     183    GMainLoop *loop;
     184    GSocketClient *client;
     185    GError *error = NULL;
     186  
     187    g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=712570");
     188  
     189    g_mutex_lock (&mutex_712570);
     190  
     191    service = g_object_new (test_threaded_socket_service_get_type (), NULL);
     192  
     193    addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
     194    g_socket_listener_add_address (G_SOCKET_LISTENER (service),
     195                                   addr,
     196                                   G_SOCKET_TYPE_STREAM,
     197                                   G_SOCKET_PROTOCOL_TCP,
     198                                   NULL,
     199                                   &listening_addr,
     200                                   &error);
     201    g_assert_no_error (error);
     202    g_object_unref (addr);
     203  
     204    loop = g_main_loop_new (NULL, FALSE);
     205    g_signal_connect (service, "run", G_CALLBACK (connection_cb), loop);
     206  
     207    client = g_socket_client_new ();
     208    g_socket_client_connect_async (client,
     209                                   G_SOCKET_CONNECTABLE (listening_addr),
     210                                   NULL,
     211                                   client_connected_cb, loop);
     212    g_object_unref (client);
     213    g_object_unref (listening_addr);
     214  
     215    g_main_loop_run (loop);
     216    g_main_loop_unref (loop);
     217  
     218    /* Stop the service and then wait for it to asynchronously cancel
     219     * its outstanding accept() call (and drop the associated ref).
     220     * At least one main context iteration is required in some circumstances
     221     * to ensure that the cancellation actually happens.
     222     */
     223    g_socket_service_stop (G_SOCKET_SERVICE (service));
     224    g_assert_false (g_socket_service_is_active (G_SOCKET_SERVICE (service)));
     225  
     226    do
     227      g_main_context_iteration (NULL, TRUE);
     228    while (G_OBJECT (service)->ref_count > 3);
     229  
     230    /* Wait some more iterations, as #GTask results are deferred to the next
     231     * #GMainContext iteration, and propagation of a #GTask result takes an
     232     * additional ref on the source object. */
     233    g_main_context_iteration (NULL, FALSE);
     234  
     235    /* Drop our ref, then unlock the mutex and wait for the service to be
     236     * finalized. (Without the fix for 712570 it would hang forever here.)
     237     */
     238    g_object_unref (service);
     239  
     240    while (!g_atomic_int_get (&finalized))
     241      g_cond_wait (&cond_712570, &mutex_712570);
     242    g_mutex_unlock (&mutex_712570);
     243  }
     244  
     245  static void
     246  closed_read_write_async_cb (GSocketConnection *conn,
     247                              GAsyncResult      *result,
     248                              gpointer           user_data)
     249  {
     250    GError *error = NULL;
     251    gboolean res;
     252  
     253    res = g_io_stream_close_finish (G_IO_STREAM (conn), result, &error);
     254    g_assert_no_error (error);
     255    g_assert_true (res);
     256  }
     257  
     258  typedef struct {
     259    GSocketConnection *conn;
     260    guint8 *data;
     261  } WriteAsyncData;
     262  
     263  static void
     264  written_read_write_async_cb (GOutputStream *ostream,
     265                               GAsyncResult  *result,
     266                               gpointer       user_data)
     267  {
     268    WriteAsyncData *data = user_data;
     269    GError *error = NULL;
     270    gboolean res;
     271    gsize bytes_written;
     272    GSocketConnection *conn;
     273  
     274    conn = data->conn;
     275  
     276    g_free (data->data);
     277    g_free (data);
     278  
     279    res = g_output_stream_write_all_finish (ostream, result, &bytes_written, &error);
     280    g_assert_no_error (error);
     281    g_assert_true (res);
     282    g_assert_cmpuint (bytes_written, ==, 20);
     283  
     284    g_io_stream_close_async (G_IO_STREAM (conn),
     285                             G_PRIORITY_DEFAULT,
     286                             NULL,
     287                             (GAsyncReadyCallback) closed_read_write_async_cb,
     288                             NULL);
     289    g_object_unref (conn);
     290  }
     291  
     292  static void
     293  connected_read_write_async_cb (GObject      *client,
     294                                 GAsyncResult *result,
     295                                 gpointer      user_data)
     296  {
     297    GSocketConnection *conn;
     298    GOutputStream *ostream;
     299    GError *error = NULL;
     300    WriteAsyncData *data;
     301    gsize i;
     302    GSocketConnection **sconn = user_data;
     303  
     304    conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
     305    g_assert_no_error (error);
     306    g_assert_nonnull (conn);
     307  
     308    ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
     309  
     310    data = g_new0 (WriteAsyncData, 1);
     311    data->conn = conn;
     312    data->data = g_new0 (guint8, 20);
     313    for (i = 0; i < 20; i++)
     314      data->data[i] = i;
     315  
     316    g_output_stream_write_all_async (ostream,
     317                                     data->data,
     318                                     20,
     319                                     G_PRIORITY_DEFAULT,
     320                                     NULL,
     321                                     (GAsyncReadyCallback) written_read_write_async_cb,
     322                                     data /* stolen */);
     323  
     324    *sconn = g_object_ref (conn);
     325  }
     326  
     327  typedef struct {
     328    GSocketConnection *conn;
     329    GOutputVector *vectors;
     330    guint n_vectors;
     331    guint8 *data;
     332  } WritevAsyncData;
     333  
     334  static void
     335  writtenv_read_write_async_cb (GOutputStream *ostream,
     336                                GAsyncResult  *result,
     337                                gpointer       user_data)
     338  {
     339    WritevAsyncData *data = user_data;
     340    GError *error = NULL;
     341    gboolean res;
     342    gsize bytes_written;
     343    GSocketConnection *conn;
     344  
     345    conn = data->conn;
     346    g_free (data->data);
     347    g_free (data->vectors);
     348    g_free (data);
     349  
     350    res = g_output_stream_writev_all_finish (ostream, result, &bytes_written, &error);
     351    g_assert_no_error (error);
     352    g_assert_true (res);
     353    g_assert_cmpuint (bytes_written, ==, 20);
     354  
     355    g_io_stream_close_async (G_IO_STREAM (conn),
     356                             G_PRIORITY_DEFAULT,
     357                             NULL,
     358                             (GAsyncReadyCallback) closed_read_write_async_cb,
     359                             NULL);
     360    g_object_unref (conn);
     361  }
     362  
     363  static void
     364  connected_read_writev_async_cb (GObject      *client,
     365                                 GAsyncResult *result,
     366                                 gpointer      user_data)
     367  {
     368    GSocketConnection *conn;
     369    GOutputStream *ostream;
     370    GError *error = NULL;
     371    WritevAsyncData *data;
     372    gsize i;
     373    GSocketConnection **sconn = user_data;
     374  
     375    conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
     376    g_assert_no_error (error);
     377    g_assert_nonnull (conn);
     378  
     379    ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
     380  
     381    data = g_new0 (WritevAsyncData, 1);
     382    data->conn = conn;
     383    data->vectors = g_new0 (GOutputVector, 3);
     384    data->n_vectors = 3;
     385    data->data = g_new0 (guint8, 20);
     386    for (i = 0; i < 20; i++)
     387      data->data[i] = i;
     388  
     389    data->vectors[0].buffer = data->data;
     390    data->vectors[0].size = 5;
     391    data->vectors[1].buffer = data->data + 5;
     392    data->vectors[1].size = 10;
     393    data->vectors[2].buffer = data->data + 15;
     394    data->vectors[2].size = 5;
     395  
     396    g_output_stream_writev_all_async (ostream,
     397                                      data->vectors,
     398                                      data->n_vectors,
     399                                      G_PRIORITY_DEFAULT,
     400                                      NULL,
     401                                      (GAsyncReadyCallback) writtenv_read_write_async_cb,
     402                                      data /* stolen */);
     403  
     404    *sconn = g_object_ref (conn);
     405  }
     406  
     407  typedef struct {
     408    GSocketConnection *conn;
     409    guint8 *data;
     410  } ReadAsyncData;
     411  
     412  static void
     413  read_read_write_async_cb (GInputStream *istream,
     414                            GAsyncResult *result,
     415                            gpointer      user_data)
     416  {
     417    ReadAsyncData *data = user_data;
     418    GError *error = NULL;
     419    gboolean res;
     420    gsize bytes_read;
     421    GSocketConnection *conn;
     422    const guint8 expected_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };
     423  
     424    res = g_input_stream_read_all_finish (istream, result, &bytes_read, &error);
     425    g_assert_no_error (error);
     426    g_assert_true (res);
     427  
     428    g_assert_cmpmem (expected_data, sizeof expected_data, data->data, bytes_read);
     429  
     430    conn = data->conn;
     431    g_object_set_data (G_OBJECT (conn), "test-data-read", GINT_TO_POINTER (TRUE));
     432  
     433    g_free (data->data);
     434    g_free (data);
     435  
     436    g_io_stream_close_async (G_IO_STREAM (conn),
     437                             G_PRIORITY_DEFAULT,
     438                             NULL,
     439                             (GAsyncReadyCallback) closed_read_write_async_cb,
     440                             NULL);
     441    g_object_unref (conn);
     442  }
     443  
     444  static void
     445  incoming_read_write_async_cb (GSocketService    *service,
     446                                GSocketConnection *conn,
     447                                GObject           *source_object,
     448                                gpointer           user_data)
     449  {
     450    ReadAsyncData *data;
     451    GSocketConnection **cconn = user_data;
     452    GInputStream *istream;
     453  
     454    istream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
     455  
     456    data = g_new0 (ReadAsyncData, 1);
     457    data->conn = g_object_ref (conn);
     458    data->data = g_new0 (guint8, 20);
     459  
     460    g_input_stream_read_all_async (istream,
     461                                   data->data,
     462                                   20,
     463                                   G_PRIORITY_DEFAULT,
     464                                   NULL,
     465                                   (GAsyncReadyCallback) read_read_write_async_cb,
     466                                   data /* stolen */);
     467  
     468    *cconn = g_object_ref (conn);
     469  }
     470  
     471  static void
     472  test_read_write_async_internal (gboolean writev)
     473  {
     474    GInetAddress *iaddr;
     475    GSocketAddress *saddr, *listening_addr;
     476    GSocketService *service;
     477    GError *error = NULL;
     478    GSocketClient *client;
     479    GSocketConnection *sconn = NULL, *cconn = NULL;
     480  
     481    iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
     482    saddr = g_inet_socket_address_new (iaddr, 0);
     483    g_object_unref (iaddr);
     484  
     485    service = g_socket_service_new ();
     486  
     487    g_socket_listener_add_address (G_SOCKET_LISTENER (service),
     488                                   saddr,
     489                                   G_SOCKET_TYPE_STREAM,
     490                                   G_SOCKET_PROTOCOL_TCP,
     491                                   NULL,
     492                                   &listening_addr,
     493                                   &error);
     494    g_assert_no_error (error);
     495    g_object_unref (saddr);
     496  
     497    g_signal_connect (service, "incoming", G_CALLBACK (incoming_read_write_async_cb), &sconn);
     498  
     499    client = g_socket_client_new ();
     500  
     501    if (writev)
     502      g_socket_client_connect_async (client,
     503                                     G_SOCKET_CONNECTABLE (listening_addr),
     504                                     NULL,
     505                                     connected_read_writev_async_cb,
     506                                     &cconn);
     507    else
     508      g_socket_client_connect_async (client,
     509                                     G_SOCKET_CONNECTABLE (listening_addr),
     510                                     NULL,
     511                                     connected_read_write_async_cb,
     512                                     &cconn);
     513  
     514    g_object_unref (client);
     515    g_object_unref (listening_addr);
     516  
     517    g_socket_service_start (service);
     518    g_assert_true (g_socket_service_is_active (service));
     519  
     520    do
     521      {
     522        g_main_context_iteration (NULL, TRUE);
     523      }
     524    while (!sconn || !cconn ||
     525           !g_io_stream_is_closed (G_IO_STREAM (sconn)) ||
     526           !g_io_stream_is_closed (G_IO_STREAM (cconn)));
     527  
     528    g_assert_true (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (sconn), "test-data-read")));
     529  
     530    g_object_unref (sconn);
     531    g_object_unref (cconn);
     532    g_object_unref (service);
     533  }
     534  
     535  /* Test if connecting to a socket service and asynchronously writing data on
     536   * one side followed by reading the same data on the other side of the
     537   * connection works correctly
     538   */
     539  static void
     540  test_read_write_async (void)
     541  {
     542    test_read_write_async_internal (FALSE);
     543  }
     544  
     545  /* Test if connecting to a socket service and asynchronously writing data on
     546   * one side followed by reading the same data on the other side of the
     547   * connection works correctly. This uses writev() instead of normal write().
     548   */
     549  static void
     550  test_read_writev_async (void)
     551  {
     552    test_read_write_async_internal (TRUE);
     553  }
     554  
     555  
     556  int
     557  main (int   argc,
     558        char *argv[])
     559  {
     560    g_test_init (&argc, &argv, NULL);
     561  
     562    g_test_add_func ("/socket-service/start-stop", test_start_stop);
     563    g_test_add_func ("/socket-service/threaded/712570", test_threaded_712570);
     564    g_test_add_func ("/socket-service/read_write_async", test_read_write_async);
     565    g_test_add_func ("/socket-service/read_writev_async", test_read_writev_async);
     566  
     567    return g_test_run();
     568  }