GSettings: deprecate 'schema' property
[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 "gsimpleasyncresult.h"
29 #include "giostream.h"
30 #include "glibintl.h"
31
32
33 G_DEFINE_TYPE_WITH_CODE (GTcpConnection, g_tcp_connection,
34                          G_TYPE_SOCKET_CONNECTION,
35   g_socket_connection_factory_register_type (g_define_type_id,
36                                              G_SOCKET_FAMILY_IPV4,
37                                              G_SOCKET_TYPE_STREAM,
38                                              G_SOCKET_PROTOCOL_DEFAULT);
39   g_socket_connection_factory_register_type (g_define_type_id,
40                                              G_SOCKET_FAMILY_IPV6,
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_IPV4,
45                                              G_SOCKET_TYPE_STREAM,
46                                              G_SOCKET_PROTOCOL_TCP);
47   g_socket_connection_factory_register_type (g_define_type_id,
48                                              G_SOCKET_FAMILY_IPV6,
49                                              G_SOCKET_TYPE_STREAM,
50                                              G_SOCKET_PROTOCOL_TCP);
51                          );
52
53 static gboolean g_tcp_connection_close       (GIOStream            *stream,
54                                               GCancellable         *cancellable,
55                                               GError              **error);
56 static void     g_tcp_connection_close_async (GIOStream            *stream,
57                                               int                   io_priority,
58                                               GCancellable         *cancellable,
59                                               GAsyncReadyCallback   callback,
60                                               gpointer              user_data);
61
62 struct _GTcpConnectionPrivate
63 {
64   guint graceful_disconnect : 1;
65 };
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_TYPE_INSTANCE_GET_PRIVATE (connection,
78                                                   G_TYPE_TCP_CONNECTION,
79                                                   GTcpConnectionPrivate);
80   connection->priv->graceful_disconnect = FALSE;
81 }
82
83 static void
84 g_tcp_connection_get_property (GObject    *object,
85                                guint       prop_id,
86                                GValue     *value,
87                                GParamSpec *pspec)
88 {
89   GTcpConnection *connection = G_TCP_CONNECTION (object);
90
91   switch (prop_id)
92     {
93       case PROP_GRACEFUL_DISCONNECT:
94         g_value_set_boolean (value, connection->priv->graceful_disconnect);
95         break;
96
97       default:
98         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99     }
100 }
101
102 static void
103 g_tcp_connection_set_property (GObject      *object,
104                                guint         prop_id,
105                                const GValue *value,
106                                GParamSpec   *pspec)
107 {
108   GTcpConnection *connection = G_TCP_CONNECTION (object);
109
110   switch (prop_id)
111     {
112       case PROP_GRACEFUL_DISCONNECT:
113         g_tcp_connection_set_graceful_disconnect (connection,
114                                                   g_value_get_boolean (value));
115         break;
116
117       default:
118         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
119     }
120 }
121
122 static void
123 g_tcp_connection_class_init (GTcpConnectionClass *class)
124 {
125   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
126   GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class);
127
128   g_type_class_add_private (class, sizeof (GTcpConnectionPrivate));
129
130   gobject_class->set_property = g_tcp_connection_set_property;
131   gobject_class->get_property = g_tcp_connection_get_property;
132
133   stream_class->close_fn = g_tcp_connection_close;
134   stream_class->close_async = g_tcp_connection_close_async;
135
136   g_object_class_install_property (gobject_class, PROP_GRACEFUL_DISCONNECT,
137                                    g_param_spec_boolean ("graceful-disconnect",
138                                                          P_("Graceful Disconnect"),
139                                                          P_("Whether or not close does a graceful disconnect"),
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   GError *my_error;
155   gboolean had_error;
156
157   socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
158   had_error = FALSE;
159
160   if (connection->priv->graceful_disconnect &&
161       !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
162     {
163       if (!g_socket_shutdown (socket, FALSE, TRUE, error))
164         {
165           error = NULL; /* Ignore further errors */
166           had_error = TRUE;
167         }
168       else
169         {
170           while (TRUE)
171             {
172               my_error = NULL;
173               ret = g_socket_receive (socket,  buffer, sizeof (buffer),
174                                       cancellable, &my_error);
175               if (ret < 0)
176                 {
177                   if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
178                     g_error_free (my_error);
179                   else
180                     {
181                       had_error = TRUE;
182                       g_propagate_error (error, my_error);
183                       error = NULL;
184                       break;
185                     }
186                 }
187               if (ret == 0)
188                 break;
189             }
190         }
191     }
192
193   return G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
194     ->close_fn (stream, cancellable, error) && !had_error;
195 }
196
197 typedef struct {
198   GSimpleAsyncResult *res;
199   GCancellable *cancellable;
200 } CloseAsyncData;
201
202 static void
203 close_async_data_free (CloseAsyncData *data)
204 {
205   g_object_unref (data->res);
206   if (data->cancellable)
207     g_object_unref (data->cancellable);
208   g_free (data);
209 }
210
211 static void
212 async_close_finish (CloseAsyncData *data,
213                     GError         *error /* consumed */,
214                     gboolean        in_mainloop)
215 {
216   GIOStreamClass *parent = G_IO_STREAM_CLASS (g_tcp_connection_parent_class);
217   GIOStream *stream;
218   GError *my_error;
219
220   stream = G_IO_STREAM (g_async_result_get_source_object (G_ASYNC_RESULT (data->res)));
221
222   /* Doesn't block, ignore error */
223   if (error)
224     {
225       parent->close_fn (stream, data->cancellable, NULL);
226       g_simple_async_result_take_error (data->res, error);
227     }
228   else
229     {
230       my_error = NULL;
231       parent->close_fn (stream, data->cancellable, &my_error);
232       if (my_error)
233         g_simple_async_result_take_error (data->res, my_error);
234     }
235
236   if (in_mainloop)
237     g_simple_async_result_complete (data->res);
238   else
239     g_simple_async_result_complete_in_idle (data->res);
240 }
241
242 static gboolean
243 close_read_ready (GSocket        *socket,
244                   GIOCondition    condition,
245                   CloseAsyncData *data)
246 {
247   GError *error = NULL;
248   char buffer[1024];
249   gssize ret;
250
251   ret = g_socket_receive (socket,  buffer, sizeof (buffer),
252                           data->cancellable, &error);
253   if (ret < 0)
254     {
255       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
256         g_error_free (error);
257       else
258         {
259           async_close_finish (data, error, TRUE);
260           return FALSE;
261         }
262     }
263
264   if (ret == 0)
265     {
266       async_close_finish (data, NULL, TRUE);
267       return FALSE;
268     }
269
270   return TRUE;
271 }
272
273
274 static void
275 g_tcp_connection_close_async (GIOStream           *stream,
276                               int                  io_priority,
277                               GCancellable        *cancellable,
278                               GAsyncReadyCallback  callback,
279                               gpointer             user_data)
280 {
281   GTcpConnection *connection = G_TCP_CONNECTION (stream);
282   CloseAsyncData *data;
283   GSocket *socket;
284   GSource *source;
285   GError *error;
286
287   if (connection->priv->graceful_disconnect &&
288       !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
289     {
290       data = g_new (CloseAsyncData, 1);
291       data->res =
292         g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
293                                    g_tcp_connection_close_async);
294       if (cancellable)
295         data->cancellable = g_object_ref (cancellable);
296       else
297         data->cancellable = NULL;
298
299       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
300
301       error = NULL;
302       if (!g_socket_shutdown (socket, FALSE, TRUE, &error))
303         {
304           async_close_finish (data, error, FALSE);
305           close_async_data_free (data);
306           return;
307         }
308
309       source = g_socket_create_source (socket, G_IO_IN, cancellable);
310       g_source_set_callback (source,
311                              (GSourceFunc) close_read_ready,
312                              data, (GDestroyNotify)close_async_data_free);
313       g_source_attach (source, g_main_context_get_thread_default ());
314       g_source_unref (source);
315
316       return;
317     }
318
319   G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
320     ->close_async (stream, io_priority, cancellable, callback, user_data);
321 }
322
323 /**
324  * g_tcp_connection_set_graceful_disconnect:
325  * @connection: a #GTcpConnection
326  * @graceful_disconnect: Whether to do graceful disconnects or not
327  *
328  * This enabled graceful disconnects on close. A graceful disconnect
329  * means that we signal the receiving end that the connection is terminated
330  * and wait for it to close the connection before closing the connection.
331  *
332  * A graceful disconnect means that we can be sure that we successfully sent
333  * all the outstanding data to the other end, or get an error reported.
334  * However, it also means we have to wait for all the data to reach the
335  * other side and for it to acknowledge this by closing the socket, which may
336  * take a while. For this reason it is disabled by default.
337  *
338  * Since: 2.22
339  */
340 void
341 g_tcp_connection_set_graceful_disconnect (GTcpConnection *connection,
342                                           gboolean        graceful_disconnect)
343 {
344   graceful_disconnect = !!graceful_disconnect;
345   if (graceful_disconnect != connection->priv->graceful_disconnect)
346     {
347       connection->priv->graceful_disconnect = graceful_disconnect;
348       g_object_notify (G_OBJECT (connection), "graceful-disconnect");
349     }
350 }
351
352 /**
353  * g_tcp_connection_get_graceful_disconnect:
354  * @connection: a #GTcpConnection
355  *
356  * Checks if graceful disconnects are used. See
357  * g_tcp_connection_set_graceful_disconnect().
358  *
359  * Returns: %TRUE if graceful disconnect is used on close, %FALSE otherwise
360  *
361  * Since: 2.22
362  */
363 gboolean
364 g_tcp_connection_get_graceful_disconnect (GTcpConnection *connection)
365 {
366   return connection->priv->graceful_disconnect;
367 }