(root)/
glib-2.79.0/
gio/
gunixinputstream.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   * 
       3   * Copyright (C) 2006-2007 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: Alexander Larsson <alexl@redhat.com>
      21   */
      22  
      23  #include "config.h"
      24  
      25  #include <unistd.h>
      26  #include <errno.h>
      27  #include <stdio.h>
      28  
      29  #include <glib.h>
      30  #include <glib/gstdio.h>
      31  #include <glib/glib-unix.h>
      32  #include "gioerror.h"
      33  #include "gunixinputstream.h"
      34  #include "gcancellable.h"
      35  #include "gasynchelper.h"
      36  #include "gfiledescriptorbased.h"
      37  #include "glibintl.h"
      38  #include "giounix-private.h"
      39  
      40  
      41  /**
      42   * GUnixInputStream:
      43   *
      44   * `GUnixInputStream` implements [class@Gio.InputStream] for reading from a UNIX
      45   * file descriptor, including asynchronous operations. (If the file
      46   * descriptor refers to a socket or pipe, this will use `poll()` to do
      47   * asynchronous I/O. If it refers to a regular file, it will fall back
      48   * to doing asynchronous I/O in another thread.)
      49   *
      50   * Note that `<gio/gunixinputstream.h>` belongs to the UNIX-specific GIO
      51   * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
      52   * file when using it.
      53   */
      54  
      55  enum {
      56    PROP_0,
      57    PROP_FD,
      58    PROP_CLOSE_FD
      59  };
      60  
      61  struct _GUnixInputStreamPrivate {
      62    int fd;
      63    guint close_fd : 1;
      64    guint can_poll : 1;
      65  };
      66  
      67  static void g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
      68  static void g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
      69  
      70  G_DEFINE_TYPE_WITH_CODE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM,
      71                           G_ADD_PRIVATE (GUnixInputStream)
      72  			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
      73  						g_unix_input_stream_pollable_iface_init)
      74  			 G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
      75  						g_unix_input_stream_file_descriptor_based_iface_init)
      76  			 )
      77  
      78  static void     g_unix_input_stream_set_property (GObject              *object,
      79  						  guint                 prop_id,
      80  						  const GValue         *value,
      81  						  GParamSpec           *pspec);
      82  static void     g_unix_input_stream_get_property (GObject              *object,
      83  						  guint                 prop_id,
      84  						  GValue               *value,
      85  						  GParamSpec           *pspec);
      86  static gssize   g_unix_input_stream_read         (GInputStream         *stream,
      87  						  void                 *buffer,
      88  						  gsize                 count,
      89  						  GCancellable         *cancellable,
      90  						  GError              **error);
      91  static gboolean g_unix_input_stream_close        (GInputStream         *stream,
      92  						  GCancellable         *cancellable,
      93  						  GError              **error);
      94  static void     g_unix_input_stream_skip_async   (GInputStream         *stream,
      95  						  gsize                 count,
      96  						  int                   io_priority,
      97  						  GCancellable         *cancellable,
      98  						  GAsyncReadyCallback   callback,
      99  						  gpointer              data);
     100  static gssize   g_unix_input_stream_skip_finish  (GInputStream         *stream,
     101  						  GAsyncResult         *result,
     102  						  GError              **error);
     103  
     104  static gboolean g_unix_input_stream_pollable_can_poll      (GPollableInputStream *stream);
     105  static gboolean g_unix_input_stream_pollable_is_readable   (GPollableInputStream *stream);
     106  static GSource *g_unix_input_stream_pollable_create_source (GPollableInputStream *stream,
     107  							    GCancellable         *cancellable);
     108  
     109  static void
     110  g_unix_input_stream_class_init (GUnixInputStreamClass *klass)
     111  {
     112    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     113    GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
     114  
     115    gobject_class->get_property = g_unix_input_stream_get_property;
     116    gobject_class->set_property = g_unix_input_stream_set_property;
     117  
     118    stream_class->read_fn = g_unix_input_stream_read;
     119    stream_class->close_fn = g_unix_input_stream_close;
     120    if (0)
     121      {
     122        /* TODO: Implement instead of using fallbacks */
     123        stream_class->skip_async = g_unix_input_stream_skip_async;
     124        stream_class->skip_finish = g_unix_input_stream_skip_finish;
     125      }
     126  
     127    /**
     128     * GUnixInputStream:fd:
     129     *
     130     * The file descriptor that the stream reads from.
     131     *
     132     * Since: 2.20
     133     */
     134    g_object_class_install_property (gobject_class,
     135  				   PROP_FD,
     136  				   g_param_spec_int ("fd", NULL, NULL,
     137  						     G_MININT, G_MAXINT, -1,
     138  						     G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
     139  
     140    /**
     141     * GUnixInputStream:close-fd:
     142     *
     143     * Whether to close the file descriptor when the stream is closed.
     144     *
     145     * Since: 2.20
     146     */
     147    g_object_class_install_property (gobject_class,
     148  				   PROP_CLOSE_FD,
     149  				   g_param_spec_boolean ("close-fd", NULL, NULL,
     150  							 TRUE,
     151  							 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
     152  }
     153  
     154  static void
     155  g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
     156  {
     157    iface->can_poll = g_unix_input_stream_pollable_can_poll;
     158    iface->is_readable = g_unix_input_stream_pollable_is_readable;
     159    iface->create_source = g_unix_input_stream_pollable_create_source;
     160  }
     161  
     162  static void
     163  g_unix_input_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
     164  {
     165    iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_input_stream_get_fd;
     166  }
     167  
     168  static void
     169  g_unix_input_stream_set_property (GObject         *object,
     170  				  guint            prop_id,
     171  				  const GValue    *value,
     172  				  GParamSpec      *pspec)
     173  {
     174    GUnixInputStream *unix_stream;
     175    
     176    unix_stream = G_UNIX_INPUT_STREAM (object);
     177  
     178    switch (prop_id)
     179      {
     180      case PROP_FD:
     181        unix_stream->priv->fd = g_value_get_int (value);
     182        unix_stream->priv->can_poll = _g_fd_is_pollable (unix_stream->priv->fd);
     183        break;
     184      case PROP_CLOSE_FD:
     185        unix_stream->priv->close_fd = g_value_get_boolean (value);
     186        break;
     187      default:
     188        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     189        break;
     190      }
     191  }
     192  
     193  static void
     194  g_unix_input_stream_get_property (GObject    *object,
     195  				  guint       prop_id,
     196  				  GValue     *value,
     197  				  GParamSpec *pspec)
     198  {
     199    GUnixInputStream *unix_stream;
     200  
     201    unix_stream = G_UNIX_INPUT_STREAM (object);
     202  
     203    switch (prop_id)
     204      {
     205      case PROP_FD:
     206        g_value_set_int (value, unix_stream->priv->fd);
     207        break;
     208      case PROP_CLOSE_FD:
     209        g_value_set_boolean (value, unix_stream->priv->close_fd);
     210        break;
     211      default:
     212        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     213      }
     214  }
     215  
     216  static void
     217  g_unix_input_stream_init (GUnixInputStream *unix_stream)
     218  {
     219    unix_stream->priv = g_unix_input_stream_get_instance_private (unix_stream);
     220    unix_stream->priv->fd = -1;
     221    unix_stream->priv->close_fd = TRUE;
     222  }
     223  
     224  /**
     225   * g_unix_input_stream_new:
     226   * @fd: a UNIX file descriptor
     227   * @close_fd: %TRUE to close the file descriptor when done
     228   * 
     229   * Creates a new #GUnixInputStream for the given @fd. 
     230   *
     231   * If @close_fd is %TRUE, the file descriptor will be closed 
     232   * when the stream is closed.
     233   * 
     234   * Returns: a new #GUnixInputStream
     235   **/
     236  GInputStream *
     237  g_unix_input_stream_new (gint     fd,
     238  			 gboolean close_fd)
     239  {
     240    GUnixInputStream *stream;
     241  
     242    g_return_val_if_fail (fd != -1, NULL);
     243  
     244    stream = g_object_new (G_TYPE_UNIX_INPUT_STREAM,
     245  			 "fd", fd,
     246  			 "close-fd", close_fd,
     247  			 NULL);
     248  
     249    return G_INPUT_STREAM (stream);
     250  }
     251  
     252  /**
     253   * g_unix_input_stream_set_close_fd:
     254   * @stream: a #GUnixInputStream
     255   * @close_fd: %TRUE to close the file descriptor when done
     256   *
     257   * Sets whether the file descriptor of @stream shall be closed
     258   * when the stream is closed.
     259   *
     260   * Since: 2.20
     261   */
     262  void
     263  g_unix_input_stream_set_close_fd (GUnixInputStream *stream,
     264  				  gboolean          close_fd)
     265  {
     266    g_return_if_fail (G_IS_UNIX_INPUT_STREAM (stream));
     267  
     268    close_fd = close_fd != FALSE;
     269    if (stream->priv->close_fd != close_fd)
     270      {
     271        stream->priv->close_fd = close_fd;
     272        g_object_notify (G_OBJECT (stream), "close-fd");
     273      }
     274  }
     275  
     276  /**
     277   * g_unix_input_stream_get_close_fd:
     278   * @stream: a #GUnixInputStream
     279   *
     280   * Returns whether the file descriptor of @stream will be
     281   * closed when the stream is closed.
     282   *
     283   * Returns: %TRUE if the file descriptor is closed when done
     284   *
     285   * Since: 2.20
     286   */
     287  gboolean
     288  g_unix_input_stream_get_close_fd (GUnixInputStream *stream)
     289  {
     290    g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), FALSE);
     291  
     292    return stream->priv->close_fd;
     293  }
     294  
     295  /**
     296   * g_unix_input_stream_get_fd:
     297   * @stream: a #GUnixInputStream
     298   *
     299   * Return the UNIX file descriptor that the stream reads from.
     300   *
     301   * Returns: The file descriptor of @stream
     302   *
     303   * Since: 2.20
     304   */
     305  gint
     306  g_unix_input_stream_get_fd (GUnixInputStream *stream)
     307  {
     308    g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), -1);
     309    
     310    return stream->priv->fd;
     311  }
     312  
     313  static gssize
     314  g_unix_input_stream_read (GInputStream  *stream,
     315  			  void          *buffer,
     316  			  gsize          count,
     317  			  GCancellable  *cancellable,
     318  			  GError       **error)
     319  {
     320    GUnixInputStream *unix_stream;
     321    gssize res = -1;
     322    GPollFD poll_fds[2];
     323    int nfds;
     324    int poll_ret;
     325  
     326    unix_stream = G_UNIX_INPUT_STREAM (stream);
     327  
     328    poll_fds[0].fd = unix_stream->priv->fd;
     329    poll_fds[0].events = G_IO_IN;
     330    if (unix_stream->priv->can_poll &&
     331        g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
     332      nfds = 2;
     333    else
     334      nfds = 1;
     335  
     336    while (1)
     337      {
     338        int errsv;
     339  
     340        poll_fds[0].revents = poll_fds[1].revents = 0;
     341        do
     342          {
     343            poll_ret = g_poll (poll_fds, nfds, -1);
     344            errsv = errno;
     345          }
     346        while (poll_ret == -1 && errsv == EINTR);
     347  
     348        if (poll_ret == -1)
     349  	{
     350  	  g_set_error (error, G_IO_ERROR,
     351  		       g_io_error_from_errno (errsv),
     352  		       _("Error reading from file descriptor: %s"),
     353  		       g_strerror (errsv));
     354  	  break;
     355  	}
     356  
     357        if (g_cancellable_set_error_if_cancelled (cancellable, error))
     358  	break;
     359  
     360        if (!poll_fds[0].revents)
     361  	continue;
     362  
     363        res = read (unix_stream->priv->fd, buffer, count);
     364        if (res == -1)
     365  	{
     366            int errsv = errno;
     367  
     368  	  if (errsv == EINTR || errsv == EAGAIN)
     369  	    continue;
     370  
     371  	  g_set_error (error, G_IO_ERROR,
     372  		       g_io_error_from_errno (errsv),
     373  		       _("Error reading from file descriptor: %s"),
     374  		       g_strerror (errsv));
     375  	}
     376  
     377        break;
     378      }
     379  
     380    if (nfds == 2)
     381      g_cancellable_release_fd (cancellable);
     382    return res;
     383  }
     384  
     385  static gboolean
     386  g_unix_input_stream_close (GInputStream  *stream,
     387  			   GCancellable  *cancellable,
     388  			   GError       **error)
     389  {
     390    GUnixInputStream *unix_stream;
     391    int res;
     392  
     393    unix_stream = G_UNIX_INPUT_STREAM (stream);
     394  
     395    if (!unix_stream->priv->close_fd)
     396      return TRUE;
     397    
     398    /* This might block during the close. Doesn't seem to be a way to avoid it though. */
     399    res = close (unix_stream->priv->fd);
     400    if (res == -1)
     401      {
     402        int errsv = errno;
     403  
     404        g_set_error (error, G_IO_ERROR,
     405  		   g_io_error_from_errno (errsv),
     406  		   _("Error closing file descriptor: %s"),
     407  		   g_strerror (errsv));
     408      }
     409    
     410    return res != -1;
     411  }
     412  
     413  static void
     414  g_unix_input_stream_skip_async (GInputStream        *stream,
     415  				gsize                count,
     416  				int                  io_priority,
     417  				GCancellable        *cancellable,
     418  				GAsyncReadyCallback  callback,
     419  				gpointer             data)
     420  {
     421    g_warn_if_reached ();
     422    /* TODO: Not implemented */
     423  }
     424  
     425  static gssize
     426  g_unix_input_stream_skip_finish  (GInputStream  *stream,
     427  				  GAsyncResult  *result,
     428  				  GError       **error)
     429  {
     430    g_warn_if_reached ();
     431    return 0;
     432    /* TODO: Not implemented */
     433  }
     434  
     435  static gboolean
     436  g_unix_input_stream_pollable_can_poll (GPollableInputStream *stream)
     437  {
     438    return G_UNIX_INPUT_STREAM (stream)->priv->can_poll;
     439  }
     440  
     441  static gboolean
     442  g_unix_input_stream_pollable_is_readable (GPollableInputStream *stream)
     443  {
     444    GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream);
     445    GPollFD poll_fd;
     446    gint result;
     447  
     448    poll_fd.fd = unix_stream->priv->fd;
     449    poll_fd.events = G_IO_IN;
     450    poll_fd.revents = 0;
     451  
     452    do
     453      result = g_poll (&poll_fd, 1, 0);
     454    while (result == -1 && errno == EINTR);
     455  
     456    return poll_fd.revents != 0;
     457  }
     458  
     459  static GSource *
     460  g_unix_input_stream_pollable_create_source (GPollableInputStream *stream,
     461  					    GCancellable         *cancellable)
     462  {
     463    GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream);
     464    GSource *inner_source, *cancellable_source, *pollable_source;
     465  
     466    pollable_source = g_pollable_source_new (G_OBJECT (stream));
     467  
     468    inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_IN);
     469    g_source_set_dummy_callback (inner_source);
     470    g_source_add_child_source (pollable_source, inner_source);
     471    g_source_unref (inner_source);
     472  
     473    if (cancellable)
     474      {
     475        cancellable_source = g_cancellable_source_new (cancellable);
     476        g_source_set_dummy_callback (cancellable_source);
     477        g_source_add_child_source (pollable_source, cancellable_source);
     478        g_source_unref (cancellable_source);
     479      }
     480  
     481    return pollable_source;
     482  }