Work around deadlock in unix-streams test
[glib.git] / gio / gtcpconnection.c
blob89aeabaad7b99090786f2b8c8e96079d40eed1ac
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright © 2008, 2009 Codethink Limited
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.
10 * See the included COPYING file for more information.
13 /**
14 * SECTION: gtcpconnection
15 * @title: GTcpConnection
16 * @short_description: a TCP GSocketConnection
17 * @see_also: #GSocketConnection.
19 * This is the subclass of #GSocketConnection that is created
20 * for TCP/IP sockets.
22 * Since: 2.22
25 #include "config.h"
26 #include "gtcpconnection.h"
27 #include "gasyncresult.h"
28 #include "gsimpleasyncresult.h"
29 #include "giostream.h"
30 #include "glibintl.h"
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);
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);
62 struct _GTcpConnectionPrivate
64 guint graceful_disconnect : 1;
68 enum
70 PROP_0,
71 PROP_GRACEFUL_DISCONNECT
74 static void
75 g_tcp_connection_init (GTcpConnection *connection)
77 connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
78 G_TYPE_TCP_CONNECTION,
79 GTcpConnectionPrivate);
80 connection->priv->graceful_disconnect = FALSE;
83 static void
84 g_tcp_connection_get_property (GObject *object,
85 guint prop_id,
86 GValue *value,
87 GParamSpec *pspec)
89 GTcpConnection *connection = G_TCP_CONNECTION (object);
91 switch (prop_id)
93 case PROP_GRACEFUL_DISCONNECT:
94 g_value_set_boolean (value, connection->priv->graceful_disconnect);
95 break;
97 default:
98 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102 static void
103 g_tcp_connection_set_property (GObject *object,
104 guint prop_id,
105 const GValue *value,
106 GParamSpec *pspec)
108 GTcpConnection *connection = G_TCP_CONNECTION (object);
110 switch (prop_id)
112 case PROP_GRACEFUL_DISCONNECT:
113 g_tcp_connection_set_graceful_disconnect (connection,
114 g_value_get_boolean (value));
115 break;
117 default:
118 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122 static void
123 g_tcp_connection_class_init (GTcpConnectionClass *class)
125 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
126 GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class);
128 g_type_class_add_private (class, sizeof (GTcpConnectionPrivate));
130 gobject_class->set_property = g_tcp_connection_set_property;
131 gobject_class->get_property = g_tcp_connection_get_property;
133 stream_class->close_fn = g_tcp_connection_close;
134 stream_class->close_async = g_tcp_connection_close_async;
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));
145 static gboolean
146 g_tcp_connection_close (GIOStream *stream,
147 GCancellable *cancellable,
148 GError **error)
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;
157 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
158 had_error = FALSE;
160 if (connection->priv->graceful_disconnect &&
161 !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
163 if (!g_socket_shutdown (socket, FALSE, TRUE, error))
165 error = NULL; /* Ignore further errors */
166 had_error = TRUE;
168 else
170 while (TRUE)
172 my_error = NULL;
173 ret = g_socket_receive (socket, buffer, sizeof (buffer),
174 cancellable, &my_error);
175 if (ret < 0)
177 if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
178 g_error_free (my_error);
179 else
181 had_error = TRUE;
182 g_propagate_error (error, my_error);
183 error = NULL;
184 break;
187 if (ret == 0)
188 break;
193 return G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
194 ->close_fn (stream, cancellable, error) && !had_error;
197 typedef struct {
198 GSimpleAsyncResult *res;
199 GCancellable *cancellable;
200 } CloseAsyncData;
202 static void
203 close_async_data_free (CloseAsyncData *data)
205 g_object_unref (data->res);
206 if (data->cancellable)
207 g_object_unref (data->cancellable);
208 g_free (data);
211 static void
212 async_close_finish (CloseAsyncData *data,
213 GError *error,
214 gboolean in_mainloop)
216 GIOStreamClass *parent = G_IO_STREAM_CLASS (g_tcp_connection_parent_class);
217 GIOStream *stream;
218 GError *my_error;
220 stream = G_IO_STREAM (g_async_result_get_source_object (G_ASYNC_RESULT (data->res)));
222 /* Doesn't block, ignore error */
223 if (error)
225 parent->close_fn (stream, data->cancellable, NULL);
226 g_simple_async_result_set_from_error (data->res, error);
228 else
230 my_error = NULL;
231 parent->close_fn (stream, data->cancellable, &my_error);
232 if (my_error)
234 g_simple_async_result_set_from_error (data->res, my_error);
235 g_error_free (my_error);
239 if (in_mainloop)
240 g_simple_async_result_complete (data->res);
241 else
242 g_simple_async_result_complete_in_idle (data->res);
245 static gboolean
246 close_read_ready (GSocket *socket,
247 GIOCondition condition,
248 CloseAsyncData *data)
250 GError *error = NULL;
251 char buffer[1024];
252 gssize ret;
254 ret = g_socket_receive (socket, buffer, sizeof (buffer),
255 data->cancellable, &error);
256 if (ret < 0)
258 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
259 g_error_free (error);
260 else
262 async_close_finish (data, error, TRUE);
263 g_error_free (error);
264 return FALSE;
268 if (ret == 0)
270 async_close_finish (data, NULL, TRUE);
271 return FALSE;
274 return TRUE;
278 static void
279 g_tcp_connection_close_async (GIOStream *stream,
280 int io_priority,
281 GCancellable *cancellable,
282 GAsyncReadyCallback callback,
283 gpointer user_data)
285 GTcpConnection *connection = G_TCP_CONNECTION (stream);
286 CloseAsyncData *data;
287 GSocket *socket;
288 GSource *source;
289 GError *error;
291 if (connection->priv->graceful_disconnect &&
292 !g_cancellable_is_cancelled (cancellable) /* Cancelled -> close fast */)
294 data = g_new (CloseAsyncData, 1);
295 data->res =
296 g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
297 g_tcp_connection_close_async);
298 if (cancellable)
299 data->cancellable = g_object_ref (cancellable);
300 else
301 data->cancellable = NULL;
303 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
305 error = NULL;
306 if (!g_socket_shutdown (socket, FALSE, TRUE, &error))
308 async_close_finish (data, error, FALSE);
309 g_error_free (error);
310 close_async_data_free (data);
311 return;
314 source = g_socket_create_source (socket, G_IO_IN, cancellable);
315 g_source_set_callback (source,
316 (GSourceFunc) close_read_ready,
317 data, (GDestroyNotify)close_async_data_free);
318 g_source_attach (source, g_main_context_get_thread_default ());
319 g_source_unref (source);
321 return;
324 G_IO_STREAM_CLASS (g_tcp_connection_parent_class)
325 ->close_async (stream, io_priority, cancellable, callback, user_data);
329 * g_tcp_connection_set_graceful_disconnect:
330 * @connection: a #GTcpConnection
331 * @graceful_disconnect: Whether to do graceful disconnects or not
333 * This enabled graceful disconnects on close. A graceful disconnect
334 * means that we signal the recieving end that the connection is terminated
335 * and wait for it to close the connection before closing the connection.
337 * A graceful disconnect means that we can be sure that we successfully sent
338 * all the outstanding data to the other end, or get an error reported.
339 * However, it also means we have to wait for all the data to reach the
340 * other side and for it to acknowledge this by closing the socket, which may
341 * take a while. For this reason it is disabled by default.
343 * Since: 2.22
345 void
346 g_tcp_connection_set_graceful_disconnect (GTcpConnection *connection,
347 gboolean graceful_disconnect)
349 graceful_disconnect = !!graceful_disconnect;
350 if (graceful_disconnect != connection->priv->graceful_disconnect)
352 connection->priv->graceful_disconnect = graceful_disconnect;
353 g_object_notify (G_OBJECT (connection), "graceful-disconnect");
358 * g_tcp_connection_get_graceful_disconnect:
359 * @connection: a #GTcpConnection
361 * Checks if graceful disconnects are used. See
362 * g_tcp_connection_set_graceful_disconnect().
364 * Returns: %TRUE if graceful disconnect is used on close, %FALSE otherwise
366 * Since: 2.22
368 gboolean
369 g_tcp_connection_get_graceful_disconnect (GTcpConnection *connection)
371 return connection->priv->graceful_disconnect;