LCOV - code coverage report
Current view: top level - gio - gtcpconnection.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 25.5 % 102 26
Test Date: 2024-11-26 05:23:01 Functions: 57.1 % 14 8
Branches: - 0 0

             Branch data     Line data    Source code
       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                 :        2245 : 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                 :         120 : g_tcp_connection_init (GTcpConnection *connection)
      75                 :             : {
      76                 :         120 :   connection->priv = g_tcp_connection_get_instance_private (connection);
      77                 :         120 :   connection->priv->graceful_disconnect = FALSE;
      78                 :         120 : }
      79                 :             : 
      80                 :             : static void
      81                 :           0 : g_tcp_connection_get_property (GObject    *object,
      82                 :             :                                guint       prop_id,
      83                 :             :                                GValue     *value,
      84                 :             :                                GParamSpec *pspec)
      85                 :             : {
      86                 :           0 :   GTcpConnection *connection = G_TCP_CONNECTION (object);
      87                 :             : 
      88                 :           0 :   switch (prop_id)
      89                 :             :     {
      90                 :           0 :       case PROP_GRACEFUL_DISCONNECT:
      91                 :           0 :         g_value_set_boolean (value, connection->priv->graceful_disconnect);
      92                 :           0 :         break;
      93                 :             : 
      94                 :           0 :       default:
      95                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      96                 :             :     }
      97                 :           0 : }
      98                 :             : 
      99                 :             : static void
     100                 :           0 : g_tcp_connection_set_property (GObject      *object,
     101                 :             :                                guint         prop_id,
     102                 :             :                                const GValue *value,
     103                 :             :                                GParamSpec   *pspec)
     104                 :             : {
     105                 :           0 :   GTcpConnection *connection = G_TCP_CONNECTION (object);
     106                 :             : 
     107                 :           0 :   switch (prop_id)
     108                 :             :     {
     109                 :           0 :       case PROP_GRACEFUL_DISCONNECT:
     110                 :           0 :         g_tcp_connection_set_graceful_disconnect (connection,
     111                 :             :                                                   g_value_get_boolean (value));
     112                 :           0 :         break;
     113                 :             : 
     114                 :           0 :       default:
     115                 :           0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     116                 :             :     }
     117                 :           0 : }
     118                 :             : 
     119                 :             : static void
     120                 :           9 : g_tcp_connection_class_init (GTcpConnectionClass *class)
     121                 :             : {
     122                 :           9 :   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
     123                 :           9 :   GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class);
     124                 :             : 
     125                 :           9 :   gobject_class->set_property = g_tcp_connection_set_property;
     126                 :           9 :   gobject_class->get_property = g_tcp_connection_get_property;
     127                 :             : 
     128                 :           9 :   stream_class->close_fn = g_tcp_connection_close;
     129                 :           9 :   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                 :           9 :   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                 :           9 : }
     144                 :             : 
     145                 :             : static gboolean
     146                 :          57 : g_tcp_connection_close (GIOStream     *stream,
     147                 :             :                         GCancellable  *cancellable,
     148                 :             :                         GError       **error)
     149                 :             : {
     150                 :          57 :   GTcpConnection *connection = G_TCP_CONNECTION (stream);
     151                 :             :   GSocket *socket;
     152                 :             :   char buffer[1024];
     153                 :             :   gssize ret;
     154                 :             :   gboolean had_error;
     155                 :             : 
     156                 :          57 :   socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
     157                 :          57 :   had_error = FALSE;
     158                 :             : 
     159                 :          57 :   if (connection->priv->graceful_disconnect &&
     160                 :           0 :       !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
     161                 :             :     {
     162                 :           0 :       if (!g_socket_shutdown (socket, FALSE, TRUE, error))
     163                 :             :         {
     164                 :           0 :           error = NULL; /* Ignore further errors */
     165                 :           0 :           had_error = TRUE;
     166                 :             :         }
     167                 :             :       else
     168                 :             :         {
     169                 :             :           while (TRUE)
     170                 :             :             {
     171                 :           0 :               ret = g_socket_receive_with_blocking (socket,  buffer, sizeof (buffer),
     172                 :             :                                                     TRUE, cancellable, error);
     173                 :           0 :               if (ret < 0)
     174                 :             :                 {
     175                 :           0 :                   had_error = TRUE;
     176                 :           0 :                   error = NULL;
     177                 :           0 :                   break;
     178                 :             :                 }
     179                 :           0 :               if (ret == 0)
     180                 :           0 :                 break;
     181                 :             :             }
     182                 :             :         }
     183                 :             :     }
     184                 :             : 
     185                 :          57 :   return G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
     186                 :          57 :     ->close_fn (stream, cancellable, error) && !had_error;
     187                 :             : }
     188                 :             : 
     189                 :             : /* consumes @error */
     190                 :             : static void
     191                 :           0 : async_close_finish (GTask    *task,
     192                 :             :                     GError   *error)
     193                 :             : {
     194                 :           0 :   GIOStreamClass *parent = G_IO_STREAM_CLASS (g_tcp_connection_parent_class);
     195                 :           0 :   GIOStream *stream = g_task_get_source_object (task);
     196                 :           0 :   GCancellable *cancellable = g_task_get_cancellable (task);
     197                 :             : 
     198                 :             :   /* Close underlying stream, ignoring further errors if we already
     199                 :             :    * have one.
     200                 :             :    */
     201                 :           0 :   if (error)
     202                 :           0 :     parent->close_fn (stream, cancellable, NULL);
     203                 :             :   else
     204                 :           0 :     parent->close_fn (stream, cancellable, &error);
     205                 :             : 
     206                 :           0 :   if (error)
     207                 :           0 :     g_task_return_error (task, error);
     208                 :             :   else
     209                 :           0 :     g_task_return_boolean (task, TRUE);
     210                 :             : 
     211                 :           0 :   g_object_unref (task);
     212                 :           0 : }
     213                 :             : 
     214                 :             : 
     215                 :             : static gboolean
     216                 :           0 : close_read_ready (GSocket        *socket,
     217                 :             :                   GIOCondition    condition,
     218                 :             :                   GTask          *task)
     219                 :             : {
     220                 :           0 :   GError *error = NULL;
     221                 :             :   char buffer[1024];
     222                 :             :   gssize ret;
     223                 :             : 
     224                 :           0 :   ret = g_socket_receive_with_blocking (socket,  buffer, sizeof (buffer),
     225                 :             :                                         FALSE, g_task_get_cancellable (task),
     226                 :             :                                         &error);
     227                 :           0 :   if (ret < 0)
     228                 :             :     {
     229                 :           0 :       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
     230                 :             :         {
     231                 :           0 :           g_error_free (error);
     232                 :           0 :           return TRUE;
     233                 :             :         }
     234                 :             :       else
     235                 :             :         {
     236                 :           0 :           async_close_finish (task, error);
     237                 :           0 :           return FALSE;
     238                 :             :         }
     239                 :             :     }
     240                 :             : 
     241                 :           0 :   if (ret == 0)
     242                 :             :     {
     243                 :           0 :       async_close_finish (task, NULL);
     244                 :           0 :       return FALSE;
     245                 :             :     }
     246                 :             : 
     247                 :           0 :   return TRUE;
     248                 :             : }
     249                 :             : 
     250                 :             : 
     251                 :             : static void
     252                 :          11 : g_tcp_connection_close_async (GIOStream           *stream,
     253                 :             :                               int                  io_priority,
     254                 :             :                               GCancellable        *cancellable,
     255                 :             :                               GAsyncReadyCallback  callback,
     256                 :             :                               gpointer             user_data)
     257                 :             : {
     258                 :          11 :   GTcpConnection *connection = G_TCP_CONNECTION (stream);
     259                 :             :   GSocket *socket;
     260                 :             :   GSource *source;
     261                 :             :   GError *error;
     262                 :             :   GTask *task;
     263                 :             : 
     264                 :          11 :   if (connection->priv->graceful_disconnect &&
     265                 :           0 :       !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
     266                 :             :     {
     267                 :           0 :       task = g_task_new (stream, cancellable, callback, user_data);
     268                 :           0 :       g_task_set_source_tag (task, g_tcp_connection_close_async);
     269                 :           0 :       g_task_set_priority (task, io_priority);
     270                 :             : 
     271                 :           0 :       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
     272                 :             : 
     273                 :           0 :       error = NULL;
     274                 :           0 :       if (!g_socket_shutdown (socket, FALSE, TRUE, &error))
     275                 :             :         {
     276                 :           0 :           g_task_return_error (task, error);
     277                 :           0 :           g_object_unref (task);
     278                 :           0 :           return;
     279                 :             :         }
     280                 :             : 
     281                 :           0 :       source = g_socket_create_source (socket, G_IO_IN, cancellable);
     282                 :           0 :       g_task_attach_source (task, source, (GSourceFunc) close_read_ready);
     283                 :           0 :       g_source_unref (source);
     284                 :             : 
     285                 :           0 :       return;
     286                 :             :     }
     287                 :             : 
     288                 :          11 :   G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
     289                 :          11 :     ->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                 :           0 : g_tcp_connection_set_graceful_disconnect (GTcpConnection *connection,
     311                 :             :                                           gboolean        graceful_disconnect)
     312                 :             : {
     313                 :           0 :   graceful_disconnect = !!graceful_disconnect;
     314                 :           0 :   if (graceful_disconnect != connection->priv->graceful_disconnect)
     315                 :             :     {
     316                 :           0 :       connection->priv->graceful_disconnect = graceful_disconnect;
     317                 :           0 :       g_object_notify (G_OBJECT (connection), "graceful-disconnect");
     318                 :             :     }
     319                 :           0 : }
     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                 :           0 : g_tcp_connection_get_graceful_disconnect (GTcpConnection *connection)
     334                 :             : {
     335                 :           0 :   return connection->priv->graceful_disconnect;
     336                 :             : }
        

Generated by: LCOV version 2.0-1