(root)/
glib-2.79.0/
gio/
gtcpconnection.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright © 2008, 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  
      15  /**
      16   * GTcpConnection:
      17   *
      18   * This is the subclass of [class@Gio.SocketConnection] that is created
      19   * for TCP/IP sockets.
      20   *
      21   * Since: 2.22
      22   */
      23  
      24  #include "config.h"
      25  #include "gtcpconnection.h"
      26  #include "gasyncresult.h"
      27  #include "gtask.h"
      28  #include "giostream.h"
      29  #include "glibintl.h"
      30  
      31  struct _GTcpConnectionPrivate
      32  {
      33    guint graceful_disconnect : 1;
      34  };
      35  
      36  G_DEFINE_TYPE_WITH_CODE (GTcpConnection, g_tcp_connection,
      37  			 G_TYPE_SOCKET_CONNECTION,
      38                           G_ADD_PRIVATE (GTcpConnection)
      39    g_socket_connection_factory_register_type (g_define_type_id,
      40  					     G_SOCKET_FAMILY_IPV4,
      41  					     G_SOCKET_TYPE_STREAM,
      42  					     G_SOCKET_PROTOCOL_DEFAULT);
      43    g_socket_connection_factory_register_type (g_define_type_id,
      44  					     G_SOCKET_FAMILY_IPV6,
      45  					     G_SOCKET_TYPE_STREAM,
      46  					     G_SOCKET_PROTOCOL_DEFAULT);
      47    g_socket_connection_factory_register_type (g_define_type_id,
      48  					     G_SOCKET_FAMILY_IPV4,
      49  					     G_SOCKET_TYPE_STREAM,
      50  					     G_SOCKET_PROTOCOL_TCP);
      51    g_socket_connection_factory_register_type (g_define_type_id,
      52  					     G_SOCKET_FAMILY_IPV6,
      53  					     G_SOCKET_TYPE_STREAM,
      54  					     G_SOCKET_PROTOCOL_TCP);
      55  			 );
      56  
      57  static gboolean g_tcp_connection_close       (GIOStream            *stream,
      58  					      GCancellable         *cancellable,
      59  					      GError              **error);
      60  static void     g_tcp_connection_close_async (GIOStream            *stream,
      61  					      int                   io_priority,
      62  					      GCancellable         *cancellable,
      63  					      GAsyncReadyCallback   callback,
      64  					      gpointer              user_data);
      65  
      66  
      67  enum
      68  {
      69    PROP_0,
      70    PROP_GRACEFUL_DISCONNECT
      71  };
      72  
      73  static void
      74  g_tcp_connection_init (GTcpConnection *connection)
      75  {
      76    connection->priv = g_tcp_connection_get_instance_private (connection);
      77    connection->priv->graceful_disconnect = FALSE;
      78  }
      79  
      80  static void
      81  g_tcp_connection_get_property (GObject    *object,
      82  			       guint       prop_id,
      83  			       GValue     *value,
      84  			       GParamSpec *pspec)
      85  {
      86    GTcpConnection *connection = G_TCP_CONNECTION (object);
      87  
      88    switch (prop_id)
      89      {
      90        case PROP_GRACEFUL_DISCONNECT:
      91  	g_value_set_boolean (value, connection->priv->graceful_disconnect);
      92  	break;
      93  
      94        default:
      95  	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      96      }
      97  }
      98  
      99  static void
     100  g_tcp_connection_set_property (GObject      *object,
     101  			       guint         prop_id,
     102  			       const GValue *value,
     103  			       GParamSpec   *pspec)
     104  {
     105    GTcpConnection *connection = G_TCP_CONNECTION (object);
     106  
     107    switch (prop_id)
     108      {
     109        case PROP_GRACEFUL_DISCONNECT:
     110  	g_tcp_connection_set_graceful_disconnect (connection,
     111  						  g_value_get_boolean (value));
     112  	break;
     113  
     114        default:
     115  	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     116      }
     117  }
     118  
     119  static void
     120  g_tcp_connection_class_init (GTcpConnectionClass *class)
     121  {
     122    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
     123    GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class);
     124  
     125    gobject_class->set_property = g_tcp_connection_set_property;
     126    gobject_class->get_property = g_tcp_connection_get_property;
     127  
     128    stream_class->close_fn = g_tcp_connection_close;
     129    stream_class->close_async = g_tcp_connection_close_async;
     130  
     131    /**
     132     * GTcpConnection:graceful-disconnect:
     133     *
     134     * Whether [method@Gio.IOStream.close] does a graceful disconnect.
     135     *
     136     * Since: 2.22
     137     */
     138    g_object_class_install_property (gobject_class, PROP_GRACEFUL_DISCONNECT,
     139  				   g_param_spec_boolean ("graceful-disconnect", NULL, NULL,
     140  							 FALSE,
     141  							 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     142  
     143  }
     144  
     145  static gboolean
     146  g_tcp_connection_close (GIOStream     *stream,
     147  			GCancellable  *cancellable,
     148  			GError       **error)
     149  {
     150    GTcpConnection *connection = G_TCP_CONNECTION (stream);
     151    GSocket *socket;
     152    char buffer[1024];
     153    gssize ret;
     154    gboolean had_error;
     155  
     156    socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
     157    had_error = FALSE;
     158  
     159    if (connection->priv->graceful_disconnect &&
     160        !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
     161      {
     162        if (!g_socket_shutdown (socket, FALSE, TRUE, error))
     163  	{
     164  	  error = NULL; /* Ignore further errors */
     165  	  had_error = TRUE;
     166  	}
     167        else
     168  	{
     169  	  while (TRUE)
     170  	    {
     171  	      ret = g_socket_receive_with_blocking (socket,  buffer, sizeof (buffer),
     172  						    TRUE, cancellable, error);
     173  	      if (ret < 0)
     174  		{
     175  		  had_error = TRUE;
     176  		  error = NULL;
     177  		  break;
     178  		}
     179  	      if (ret == 0)
     180  		break;
     181  	    }
     182  	}
     183      }
     184  
     185    return G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
     186      ->close_fn (stream, cancellable, error) && !had_error;
     187  }
     188  
     189  /* consumes @error */
     190  static void
     191  async_close_finish (GTask    *task,
     192                      GError   *error)
     193  {
     194    GIOStreamClass *parent = G_IO_STREAM_CLASS (g_tcp_connection_parent_class);
     195    GIOStream *stream = g_task_get_source_object (task);
     196    GCancellable *cancellable = g_task_get_cancellable (task);
     197  
     198    /* Close underlying stream, ignoring further errors if we already
     199     * have one.
     200     */
     201    if (error)
     202      parent->close_fn (stream, cancellable, NULL);
     203    else
     204      parent->close_fn (stream, cancellable, &error);
     205  
     206    if (error)
     207      g_task_return_error (task, error);
     208    else
     209      g_task_return_boolean (task, TRUE);
     210  
     211    g_object_unref (task);
     212  }
     213  
     214  
     215  static gboolean
     216  close_read_ready (GSocket        *socket,
     217  		  GIOCondition    condition,
     218  		  GTask          *task)
     219  {
     220    GError *error = NULL;
     221    char buffer[1024];
     222    gssize ret;
     223  
     224    ret = g_socket_receive_with_blocking (socket,  buffer, sizeof (buffer),
     225                                          FALSE, g_task_get_cancellable (task),
     226                                          &error);
     227    if (ret < 0)
     228      {
     229        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
     230  	{
     231  	  g_error_free (error);
     232  	  return TRUE;
     233  	}
     234        else
     235  	{
     236  	  async_close_finish (task, error);
     237  	  return FALSE;
     238  	}
     239      }
     240  
     241    if (ret == 0)
     242      {
     243        async_close_finish (task, NULL);
     244        return FALSE;
     245      }
     246  
     247    return TRUE;
     248  }
     249  
     250  
     251  static void
     252  g_tcp_connection_close_async (GIOStream           *stream,
     253  			      int                  io_priority,
     254  			      GCancellable        *cancellable,
     255  			      GAsyncReadyCallback  callback,
     256  			      gpointer             user_data)
     257  {
     258    GTcpConnection *connection = G_TCP_CONNECTION (stream);
     259    GSocket *socket;
     260    GSource *source;
     261    GError *error;
     262    GTask *task;
     263  
     264    if (connection->priv->graceful_disconnect &&
     265        !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
     266      {
     267        task = g_task_new (stream, cancellable, callback, user_data);
     268        g_task_set_source_tag (task, g_tcp_connection_close_async);
     269        g_task_set_priority (task, io_priority);
     270  
     271        socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
     272  
     273        error = NULL;
     274        if (!g_socket_shutdown (socket, FALSE, TRUE, &error))
     275  	{
     276  	  g_task_return_error (task, error);
     277  	  g_object_unref (task);
     278  	  return;
     279  	}
     280  
     281        source = g_socket_create_source (socket, G_IO_IN, cancellable);
     282        g_task_attach_source (task, source, (GSourceFunc) close_read_ready);
     283        g_source_unref (source);
     284  
     285        return;
     286      }
     287  
     288    G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
     289      ->close_async (stream, io_priority, cancellable, callback, user_data);
     290  }
     291  
     292  /**
     293   * g_tcp_connection_set_graceful_disconnect:
     294   * @connection: a #GTcpConnection
     295   * @graceful_disconnect: Whether to do graceful disconnects or not
     296   *
     297   * This enables graceful disconnects on close. A graceful disconnect
     298   * means that we signal the receiving end that the connection is terminated
     299   * and wait for it to close the connection before closing the connection.
     300   *
     301   * A graceful disconnect means that we can be sure that we successfully sent
     302   * all the outstanding data to the other end, or get an error reported.
     303   * However, it also means we have to wait for all the data to reach the
     304   * other side and for it to acknowledge this by closing the socket, which may
     305   * take a while. For this reason it is disabled by default.
     306   *
     307   * Since: 2.22
     308   */
     309  void
     310  g_tcp_connection_set_graceful_disconnect (GTcpConnection *connection,
     311  					  gboolean        graceful_disconnect)
     312  {
     313    graceful_disconnect = !!graceful_disconnect;
     314    if (graceful_disconnect != connection->priv->graceful_disconnect)
     315      {
     316        connection->priv->graceful_disconnect = graceful_disconnect;
     317        g_object_notify (G_OBJECT (connection), "graceful-disconnect");
     318      }
     319  }
     320  
     321  /**
     322   * g_tcp_connection_get_graceful_disconnect:
     323   * @connection: a #GTcpConnection
     324   *
     325   * Checks if graceful disconnects are used. See
     326   * g_tcp_connection_set_graceful_disconnect().
     327   *
     328   * Returns: %TRUE if graceful disconnect is used on close, %FALSE otherwise
     329   *
     330   * Since: 2.22
     331   */
     332  gboolean
     333  g_tcp_connection_get_graceful_disconnect (GTcpConnection *connection)
     334  {
     335    return connection->priv->graceful_disconnect;
     336  }