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