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