(root)/
glib-2.79.0/
gio/
tests/
pollable.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright (C) 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  
      21  #include "config.h"
      22  
      23  #include <gio/gio.h>
      24  #include <glib/gstdio.h>
      25  
      26  #ifdef G_OS_UNIX
      27  #include <fcntl.h>
      28  #ifdef HAVE_OPENPTY
      29  #include <pty.h>
      30  #endif
      31  #include <gio/gunixinputstream.h>
      32  #include <gio/gunixoutputstream.h>
      33  #endif
      34  
      35  /* openpty() is non-standard and might not be available on all kernels
      36   * and libc implementations, but glibc on Linux definitely has it */
      37  #if defined(__linux__) && defined(__GNUC__) && !defined(HAVE_OPENPTY)
      38  #error Should have been able to find openpty on GNU/Linux
      39  #endif
      40  
      41  static gboolean
      42  poll_source_callback (GPollableInputStream *input,
      43  		      gpointer              user_data)
      44  {
      45    GError *error = NULL;
      46    char buf[2];
      47    gssize nread;
      48    gboolean *success = user_data;
      49  
      50    g_assert_true (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (input)));
      51  
      52    nread = g_pollable_input_stream_read_nonblocking (input, buf, 2, NULL, &error);
      53    g_assert_no_error (error);
      54    g_assert_cmpint (nread, ==, 2);
      55    g_assert_cmpstr (buf, ==, "x");
      56    g_assert_false (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (input)));
      57  
      58    *success = TRUE;
      59    return G_SOURCE_REMOVE;
      60  }
      61  
      62  static gboolean
      63  check_source_not_readable_callback (gpointer user_data)
      64  {
      65    GPollableInputStream *in = G_POLLABLE_INPUT_STREAM (user_data);
      66  
      67    g_assert_false (g_pollable_input_stream_is_readable (in));
      68  
      69    return G_SOURCE_REMOVE;
      70  }
      71  
      72  typedef struct
      73  {
      74    GPollableInputStream *in;  /* (unowned) */
      75    GOutputStream *out;  /* (unowned) */
      76  } Streams;
      77  
      78  static gboolean
      79  write_callback (gpointer user_data)
      80  {
      81    Streams *streams = user_data;
      82    const char *buf = "x";
      83    gssize nwrote;
      84    GError *error = NULL;
      85  
      86    g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (streams->out)));
      87  
      88    nwrote = g_output_stream_write (streams->out, buf, 2, NULL, &error);
      89    g_assert_no_error (error);
      90    g_assert_cmpint (nwrote, ==, 2);
      91    g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (streams->out)));
      92  
      93    /* Wait for the pipe to propagate the write for sockets. */
      94    while (!g_pollable_input_stream_is_readable (streams->in));
      95    g_assert_true (g_pollable_input_stream_is_readable (streams->in));
      96  
      97    return G_SOURCE_REMOVE;
      98  }
      99  
     100  static gboolean
     101  quit_callback (gpointer user_data)
     102  {
     103    GMainLoop *loop = user_data;
     104  
     105    g_main_loop_quit (loop);
     106  
     107    return G_SOURCE_REMOVE;
     108  }
     109  
     110  static void
     111  test_streams (GPollableInputStream *in,
     112                GOutputStream        *out)
     113  {
     114    gboolean readable;
     115    GError *error = NULL;
     116    char buf[1];
     117    gssize nread;
     118    GSource *poll_source;
     119    gboolean success = FALSE;
     120    Streams streams;
     121    GMainLoop *loop = NULL;
     122  
     123    g_assert_true (g_pollable_input_stream_can_poll (in));
     124    g_assert_true (g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (out)));
     125  
     126    readable = g_pollable_input_stream_is_readable (in);
     127    g_assert_false (readable);
     128  
     129    nread = g_pollable_input_stream_read_nonblocking (in, buf, 1, NULL, &error);
     130    g_assert_cmpint (nread, ==, -1);
     131    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
     132    g_clear_error (&error);
     133  
     134    /* Create 4 sources, in decreasing order of priority:
     135     *   1. poll source on @in
     136     *   2. idle source that checks if @in is readable once
     137     *      (it won't be) and then removes itself
     138     *   3. idle source that writes a byte to @out, checks that
     139     *      @in is now readable, and removes itself
     140     *   4. idle source that checks if @in is readable once
     141     *      (it won't be, since the poll source will fire before
     142     *      this one does) and then quits the loop.
     143     *
     144     * If the poll source triggers before it should, then it will get a
     145     * %G_IO_ERROR_WOULD_BLOCK, and if check() fails in either
     146     * direction, we will catch it at some point.
     147     */
     148  
     149    poll_source = g_pollable_input_stream_create_source (in, NULL);
     150    g_source_set_priority (poll_source, 1);
     151    g_source_set_callback (poll_source, (GSourceFunc) poll_source_callback, &success, NULL);
     152    g_source_attach (poll_source, NULL);
     153    g_source_unref (poll_source);
     154  
     155    streams.in = in;
     156    streams.out = out;
     157    loop = g_main_loop_new (NULL, FALSE);
     158  
     159    g_idle_add_full (2, check_source_not_readable_callback, in, NULL);
     160    g_idle_add_full (3, write_callback, &streams, NULL);
     161    g_idle_add_full (4, check_source_not_readable_callback, in, NULL);
     162    g_idle_add_full (5, quit_callback, loop, NULL);
     163  
     164    g_main_loop_run (loop);
     165    g_main_loop_unref (loop);
     166  
     167    g_assert_cmpint (success, ==, TRUE);
     168  }
     169  
     170  #ifdef G_OS_UNIX
     171  
     172  #define g_assert_not_pollable(fd) \
     173    G_STMT_START {                                                        \
     174      GPollableInputStream *in = NULL;                                    \
     175      GOutputStream *out = NULL;                                          \
     176                                                                          \
     177      in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (fd, FALSE)); \
     178      out = g_unix_output_stream_new (fd, FALSE);                         \
     179                                                                          \
     180      g_assert_false (g_pollable_input_stream_can_poll (in));             \
     181      g_assert_false (g_pollable_output_stream_can_poll (                 \
     182          G_POLLABLE_OUTPUT_STREAM (out)));                               \
     183                                                                          \
     184      g_clear_object (&in);                                               \
     185      g_clear_object (&out);                                              \
     186    } G_STMT_END
     187  
     188  static void
     189  test_pollable_unix_pipe (void)
     190  {
     191    int pipefds[2], status;
     192    GPollableInputStream *in = NULL;
     193    GOutputStream *out = NULL;
     194  
     195    g_test_summary ("Test that pipes are considered pollable, just like sockets");
     196  
     197    status = pipe (pipefds);
     198    g_assert_cmpint (status, ==, 0);
     199  
     200    in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (pipefds[0], TRUE));
     201    out = g_unix_output_stream_new (pipefds[1], TRUE);
     202  
     203    test_streams (in, out);
     204  
     205    g_object_unref (in);
     206    g_object_unref (out);
     207  }
     208  
     209  static void
     210  test_pollable_unix_pty (void)
     211  {
     212  #ifdef HAVE_OPENPTY
     213    GPollableInputStream *in = NULL;
     214    GOutputStream *out = NULL;
     215    int a, b, status;
     216  #endif
     217  
     218    g_test_summary ("Test that PTYs are considered pollable");
     219  
     220  #ifdef HAVE_OPENPTY
     221    status = openpty (&a, &b, NULL, NULL, NULL);
     222  
     223    if (status == -1)
     224      {
     225        g_test_skip ("Unable to open PTY");
     226        return;
     227      }
     228  
     229    in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (a, TRUE));
     230    out = g_unix_output_stream_new (b, TRUE);
     231  
     232    test_streams (in, out);
     233  
     234    g_object_unref (in);
     235    g_object_unref (out);
     236  
     237    close (a);
     238    close (b);
     239  #else
     240    g_test_skip ("openpty not found");
     241  #endif
     242  }
     243  
     244  static void
     245  test_pollable_unix_file (void)
     246  {
     247    int fd;
     248  
     249    g_test_summary ("Test that regular files are not considered pollable");
     250  
     251    fd = g_open ("/etc/hosts", O_RDONLY, 0);
     252    if (fd == -1)
     253      {
     254        g_test_skip ("Unable to open /etc/hosts");
     255        return;
     256      }
     257  
     258    g_assert_not_pollable (fd);
     259  
     260    close (fd);
     261  }
     262  
     263  static void
     264  test_pollable_unix_nulldev (void)
     265  {
     266    g_test_summary ("Test that /dev/null is not considered pollable, but only if "
     267                    "on a system where we are able to tell it apart from devices "
     268                    "that actually implement poll");
     269  
     270  #if defined (HAVE_EPOLL_CREATE) || defined (HAVE_KQUEUE)
     271    int fd = g_open ("/dev/null", O_RDWR, 0);
     272    g_assert_cmpint (fd, !=, -1);
     273  
     274    g_assert_not_pollable (fd);
     275  
     276    close (fd);
     277  #else
     278    g_test_skip ("Cannot detect /dev/null as non-pollable on this system");
     279  #endif
     280  }
     281  
     282  static void
     283  test_pollable_converter (void)
     284  {
     285    GConverter *converter;
     286    GError *error = NULL;
     287    GInputStream *ibase;
     288    int pipefds[2], status;
     289    GPollableInputStream *in = NULL;
     290    GOutputStream *out = NULL;
     291  
     292    status = pipe (pipefds);
     293    g_assert_cmpint (status, ==, 0);
     294  
     295    ibase = G_INPUT_STREAM (g_unix_input_stream_new (pipefds[0], TRUE));
     296    converter = G_CONVERTER (g_charset_converter_new ("UTF-8", "UTF-8", &error));
     297    g_assert_no_error (error);
     298  
     299    in = G_POLLABLE_INPUT_STREAM (g_converter_input_stream_new (ibase, converter));
     300    g_object_unref (converter);
     301    g_object_unref (ibase);
     302  
     303    out = g_unix_output_stream_new (pipefds[1], TRUE);
     304  
     305    test_streams (in, out);
     306  
     307    g_object_unref (in);
     308    g_object_unref (out);
     309  }
     310  
     311  #endif
     312  
     313  static void
     314  client_connected (GObject      *source,
     315  		  GAsyncResult *result,
     316  		  gpointer      user_data)
     317  {
     318    GSocketClient *client = G_SOCKET_CLIENT (source);
     319    GSocketConnection **conn = user_data;
     320    GError *error = NULL;
     321  
     322    *conn = g_socket_client_connect_finish (client, result, &error);
     323    g_assert_no_error (error);
     324  }
     325  
     326  static void
     327  server_connected (GObject      *source,
     328  		  GAsyncResult *result,
     329  		  gpointer      user_data)
     330  {
     331    GSocketListener *listener = G_SOCKET_LISTENER (source);
     332    GSocketConnection **conn = user_data;
     333    GError *error = NULL;
     334  
     335    *conn = g_socket_listener_accept_finish (listener, result, NULL, &error);
     336    g_assert_no_error (error);
     337  }
     338  
     339  static void
     340  test_pollable_socket (void)
     341  {
     342    GInetAddress *iaddr;
     343    GSocketAddress *saddr, *effective_address;
     344    GSocketListener *listener;
     345    GSocketClient *client;
     346    GError *error = NULL;
     347    GSocketConnection *client_conn = NULL, *server_conn = NULL;
     348    GPollableInputStream *in = NULL;
     349    GOutputStream *out = NULL;
     350  
     351    iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
     352    saddr = g_inet_socket_address_new (iaddr, 0);
     353    g_object_unref (iaddr);
     354  
     355    listener = g_socket_listener_new ();
     356    g_socket_listener_add_address (listener, saddr,
     357  				 G_SOCKET_TYPE_STREAM,
     358  				 G_SOCKET_PROTOCOL_TCP,
     359  				 NULL,
     360  				 &effective_address,
     361  				 &error);
     362    g_assert_no_error (error);
     363    g_object_unref (saddr);
     364  
     365    client = g_socket_client_new ();
     366  
     367    g_socket_client_connect_async (client,
     368  				 G_SOCKET_CONNECTABLE (effective_address),
     369  				 NULL, client_connected, &client_conn);
     370    g_socket_listener_accept_async (listener, NULL,
     371  				  server_connected, &server_conn);
     372  
     373    while (!client_conn || !server_conn)
     374      g_main_context_iteration (NULL, TRUE);
     375  
     376    in = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (client_conn)));
     377    out = g_io_stream_get_output_stream (G_IO_STREAM (server_conn));
     378  
     379    test_streams (in, out);
     380  
     381    g_object_unref (client_conn);
     382    g_object_unref (server_conn);
     383    g_object_unref (client);
     384    g_object_unref (listener);
     385    g_object_unref (effective_address);
     386  }
     387  
     388  int
     389  main (int   argc,
     390        char *argv[])
     391  {
     392    g_test_init (&argc, &argv, NULL);
     393  
     394  #ifdef G_OS_UNIX
     395    g_test_add_func ("/pollable/unix/pipe", test_pollable_unix_pipe);
     396    g_test_add_func ("/pollable/unix/pty", test_pollable_unix_pty);
     397    g_test_add_func ("/pollable/unix/file", test_pollable_unix_file);
     398    g_test_add_func ("/pollable/unix/nulldev", test_pollable_unix_nulldev);
     399    g_test_add_func ("/pollable/converter", test_pollable_converter);
     400  #endif
     401    g_test_add_func ("/pollable/socket", test_pollable_socket);
     402  
     403    return g_test_run();
     404  }