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