(root)/
glib-2.79.0/
gio/
gunixfdmessage.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright © 2009 Codethink Limited
       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   * See the included COPYING file for more information.
      13   *
      14   * Authors: Ryan Lortie <desrt@desrt.ca>
      15   */
      16  
      17  /**
      18   * GUnixFDMessage:
      19   *
      20   * This [class@Gio.SocketControlMessage] contains a [class@Gio.UnixFDList].
      21   * It may be sent using [method@Gio.Socket.send_message] and received using
      22   * [method@Gio.Socket.receive_message] over UNIX sockets (ie: sockets in the
      23   * `G_SOCKET_FAMILY_UNIX` family). The file descriptors are copied
      24   * between processes by the kernel.
      25   *
      26   * For an easier way to send and receive file descriptors over
      27   * stream-oriented UNIX sockets, see [method@Gio.UnixConnection.send_fd] and
      28   * [method@Gio.UnixConnection.receive_fd].
      29   *
      30   * Note that `<gio/gunixfdmessage.h>` belongs to the UNIX-specific GIO
      31   * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
      32   * file when using it.
      33   */
      34  
      35  #include "config.h"
      36  
      37  #include <unistd.h>
      38  #include <string.h>
      39  #include <fcntl.h>
      40  #include <errno.h>
      41  
      42  #include "gunixfdmessage.h"
      43  #include "gunixfdlist.h"
      44  #include "gnetworking.h"
      45  #include "gioerror.h"
      46  
      47  struct _GUnixFDMessagePrivate
      48  {
      49    GUnixFDList *list;
      50  };
      51  
      52  G_DEFINE_TYPE_WITH_PRIVATE (GUnixFDMessage, g_unix_fd_message, G_TYPE_SOCKET_CONTROL_MESSAGE)
      53  
      54  static gsize
      55  g_unix_fd_message_get_size (GSocketControlMessage *message)
      56  {
      57    GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
      58  
      59    return g_unix_fd_list_get_length (fd_message->priv->list) * sizeof (gint);
      60  }
      61  
      62  static int
      63  g_unix_fd_message_get_level (GSocketControlMessage *message)
      64  {
      65    return SOL_SOCKET;
      66  }
      67  
      68  static int
      69  g_unix_fd_message_get_msg_type (GSocketControlMessage *message)
      70  {
      71    return SCM_RIGHTS;
      72  }
      73  
      74  static GSocketControlMessage *
      75  g_unix_fd_message_deserialize (int      level,
      76  			       int      type,
      77  			       gsize    size,
      78  			       gpointer data)
      79  {
      80    GSocketControlMessage *message;
      81    GUnixFDList *list;
      82    gint n, s, i;
      83    gint *fds;
      84  
      85    if (level != SOL_SOCKET ||
      86        type != SCM_RIGHTS)
      87      return NULL;
      88    
      89    if (size % 4 > 0)
      90      {
      91        g_warning ("Kernel returned non-integral number of fds");
      92        return NULL;
      93      }
      94  
      95    fds = data;
      96    n = size / sizeof (gint);
      97  
      98    /* Note we probably handled this in gsocket.c already if we're on
      99     * Linux and have MSG_CMSG_CLOEXEC, but this code remains as a fallback
     100     * in case the kernel is too old for MSG_CMSG_CLOEXEC.
     101     */
     102    for (i = 0; i < n; i++)
     103      {
     104        int errsv;
     105  
     106        do
     107          {
     108            s = fcntl (fds[i], F_SETFD, FD_CLOEXEC);
     109            errsv = errno;
     110          }
     111        while (s < 0 && errsv == EINTR);
     112  
     113        if (s < 0)
     114          {
     115            g_warning ("Error setting close-on-exec flag on incoming fd: %s",
     116                       g_strerror (errsv));
     117            return NULL;
     118          }
     119      }
     120  
     121    list = g_unix_fd_list_new_from_array (fds, n);
     122    message = g_unix_fd_message_new_with_fd_list (list);
     123    g_object_unref (list);
     124  
     125    return message;
     126  }
     127  
     128  static void
     129  g_unix_fd_message_serialize (GSocketControlMessage *message,
     130  			     gpointer               data)
     131  {
     132    GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
     133    const gint *fds;
     134    gint n_fds;
     135  
     136    fds = g_unix_fd_list_peek_fds (fd_message->priv->list, &n_fds);
     137    memcpy (data, fds, sizeof (gint) * n_fds);
     138  }
     139  
     140  static void
     141  g_unix_fd_message_set_property (GObject *object, guint prop_id,
     142                                  const GValue *value, GParamSpec *pspec)
     143  {
     144    GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
     145  
     146    g_assert (message->priv->list == NULL);
     147    g_assert_cmpint (prop_id, ==, 1);
     148  
     149    message->priv->list = g_value_dup_object (value);
     150  
     151    if (message->priv->list == NULL)
     152      message->priv->list = g_unix_fd_list_new ();
     153  }
     154  
     155  /**
     156   * g_unix_fd_message_get_fd_list:
     157   * @message: a #GUnixFDMessage
     158   *
     159   * Gets the #GUnixFDList contained in @message.  This function does not
     160   * return a reference to the caller, but the returned list is valid for
     161   * the lifetime of @message.
     162   *
     163   * Returns: (transfer none): the #GUnixFDList from @message
     164   *
     165   * Since: 2.24
     166   **/
     167  GUnixFDList *
     168  g_unix_fd_message_get_fd_list (GUnixFDMessage *message)
     169  {
     170    return message->priv->list;
     171  }
     172  
     173  static void
     174  g_unix_fd_message_get_property (GObject *object, guint prop_id,
     175                                  GValue *value, GParamSpec *pspec)
     176  {
     177    GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
     178  
     179    g_assert_cmpint (prop_id, ==, 1);
     180  
     181    g_value_set_object (value, g_unix_fd_message_get_fd_list (message));
     182  }
     183  
     184  static void
     185  g_unix_fd_message_init (GUnixFDMessage *message)
     186  {
     187    message->priv = g_unix_fd_message_get_instance_private (message);
     188  }
     189  
     190  static void
     191  g_unix_fd_message_finalize (GObject *object)
     192  {
     193    GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
     194  
     195    g_object_unref (message->priv->list);
     196  
     197    G_OBJECT_CLASS (g_unix_fd_message_parent_class)
     198      ->finalize (object);
     199  }
     200  
     201  static void
     202  g_unix_fd_message_class_init (GUnixFDMessageClass *class)
     203  {
     204    GSocketControlMessageClass *scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
     205    GObjectClass *object_class = G_OBJECT_CLASS (class);
     206  
     207    scm_class->get_size = g_unix_fd_message_get_size;
     208    scm_class->get_level = g_unix_fd_message_get_level;
     209    scm_class->get_type = g_unix_fd_message_get_msg_type;
     210    scm_class->serialize = g_unix_fd_message_serialize;
     211    scm_class->deserialize = g_unix_fd_message_deserialize;
     212    object_class->finalize = g_unix_fd_message_finalize;
     213    object_class->set_property = g_unix_fd_message_set_property;
     214    object_class->get_property = g_unix_fd_message_get_property;
     215  
     216    /**
     217     * GUnixFDMessage:fd-list:
     218     *
     219     * The [class@Gio.UnixFDList] object to send with the message.
     220     *
     221     * Since: 2.22
     222     */
     223    g_object_class_install_property (object_class, 1,
     224      g_param_spec_object ("fd-list", NULL, NULL,
     225                           G_TYPE_UNIX_FD_LIST, G_PARAM_STATIC_STRINGS |
     226                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     227  }
     228  
     229  /**
     230   * g_unix_fd_message_new:
     231   *
     232   * Creates a new #GUnixFDMessage containing an empty file descriptor
     233   * list.
     234   *
     235   * Returns: a new #GUnixFDMessage
     236   *
     237   * Since: 2.22
     238   **/
     239  GSocketControlMessage *
     240  g_unix_fd_message_new (void)
     241  {
     242    return g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
     243  }
     244  
     245  /**
     246   * g_unix_fd_message_new_with_fd_list:
     247   * @fd_list: a #GUnixFDList
     248   *
     249   * Creates a new #GUnixFDMessage containing @list.
     250   *
     251   * Returns: a new #GUnixFDMessage
     252   *
     253   * Since: 2.24
     254   **/
     255  GSocketControlMessage *
     256  g_unix_fd_message_new_with_fd_list (GUnixFDList *fd_list)
     257  {
     258    return g_object_new (G_TYPE_UNIX_FD_MESSAGE,
     259                         "fd-list", fd_list,
     260                         NULL);
     261  }
     262  
     263  /**
     264   * g_unix_fd_message_steal_fds:
     265   * @message: a #GUnixFDMessage
     266   * @length: (out) (optional): pointer to the length of the returned
     267   *     array, or %NULL
     268   *
     269   * Returns the array of file descriptors that is contained in this
     270   * object.
     271   *
     272   * After this call, the descriptors are no longer contained in
     273   * @message. Further calls will return an empty list (unless more
     274   * descriptors have been added).
     275   *
     276   * The return result of this function must be freed with g_free().
     277   * The caller is also responsible for closing all of the file
     278   * descriptors.
     279   *
     280   * If @length is non-%NULL then it is set to the number of file
     281   * descriptors in the returned array. The returned array is also
     282   * terminated with -1.
     283   *
     284   * This function never returns %NULL. In case there are no file
     285   * descriptors contained in @message, an empty array is returned.
     286   *
     287   * Returns: (array length=length) (transfer full): an array of file
     288   *     descriptors
     289   *
     290   * Since: 2.22
     291   **/
     292  gint *
     293  g_unix_fd_message_steal_fds (GUnixFDMessage *message,
     294                               gint           *length)
     295  {
     296    g_return_val_if_fail (G_UNIX_FD_MESSAGE (message), NULL);
     297  
     298    return g_unix_fd_list_steal_fds (message->priv->list, length);
     299  }
     300  
     301  /**
     302   * g_unix_fd_message_append_fd:
     303   * @message: a #GUnixFDMessage
     304   * @fd: a valid open file descriptor
     305   * @error: a #GError pointer
     306   *
     307   * Adds a file descriptor to @message.
     308   *
     309   * The file descriptor is duplicated using dup(). You keep your copy
     310   * of the descriptor and the copy contained in @message will be closed
     311   * when @message is finalized.
     312   *
     313   * A possible cause of failure is exceeding the per-process or
     314   * system-wide file descriptor limit.
     315   *
     316   * Returns: %TRUE in case of success, else %FALSE (and @error is set)
     317   *
     318   * Since: 2.22
     319   **/
     320  gboolean
     321  g_unix_fd_message_append_fd (GUnixFDMessage  *message,
     322                               gint             fd,
     323                               GError         **error)
     324  {
     325    g_return_val_if_fail (G_UNIX_FD_MESSAGE (message), FALSE);
     326  
     327    return g_unix_fd_list_append (message->priv->list, fd, error) >= 0;
     328  }