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.
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
26 #include "gtcpconnection.h"
27 #include "gasyncresult.h"
28 #include "gsimpleasyncresult.h"
29 #include "giostream.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
,
38 G_SOCKET_PROTOCOL_DEFAULT
);
39 g_socket_connection_factory_register_type (g_define_type_id
,
42 G_SOCKET_PROTOCOL_DEFAULT
);
43 g_socket_connection_factory_register_type (g_define_type_id
,
46 G_SOCKET_PROTOCOL_TCP
);
47 g_socket_connection_factory_register_type (g_define_type_id
,
50 G_SOCKET_PROTOCOL_TCP
);
53 static gboolean
g_tcp_connection_close (GIOStream
*stream
,
54 GCancellable
*cancellable
,
56 static void g_tcp_connection_close_async (GIOStream
*stream
,
58 GCancellable
*cancellable
,
59 GAsyncReadyCallback callback
,
62 struct _GTcpConnectionPrivate
64 guint graceful_disconnect
: 1;
71 PROP_GRACEFUL_DISCONNECT
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
;
84 g_tcp_connection_get_property (GObject
*object
,
89 GTcpConnection
*connection
= G_TCP_CONNECTION (object
);
93 case PROP_GRACEFUL_DISCONNECT
:
94 g_value_set_boolean (value
, connection
->priv
->graceful_disconnect
);
98 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
103 g_tcp_connection_set_property (GObject
*object
,
108 GTcpConnection
*connection
= G_TCP_CONNECTION (object
);
112 case PROP_GRACEFUL_DISCONNECT
:
113 g_tcp_connection_set_graceful_disconnect (connection
,
114 g_value_get_boolean (value
));
118 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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"),
141 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
146 g_tcp_connection_close (GIOStream
*stream
,
147 GCancellable
*cancellable
,
150 GTcpConnection
*connection
= G_TCP_CONNECTION (stream
);
157 socket
= g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream
));
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 */
173 ret
= g_socket_receive (socket
, buffer
, sizeof (buffer
),
174 cancellable
, &my_error
);
177 if (g_error_matches (my_error
, G_IO_ERROR
, G_IO_ERROR_WOULD_BLOCK
))
178 g_error_free (my_error
);
182 g_propagate_error (error
, my_error
);
193 return G_IO_STREAM_CLASS (g_tcp_connection_parent_class
)
194 ->close_fn (stream
, cancellable
, error
) && !had_error
;
198 GSimpleAsyncResult
*res
;
199 GCancellable
*cancellable
;
203 close_async_data_free (CloseAsyncData
*data
)
205 g_object_unref (data
->res
);
206 if (data
->cancellable
)
207 g_object_unref (data
->cancellable
);
212 async_close_finish (CloseAsyncData
*data
,
214 gboolean in_mainloop
)
216 GIOStreamClass
*parent
= G_IO_STREAM_CLASS (g_tcp_connection_parent_class
);
220 stream
= G_IO_STREAM (g_async_result_get_source_object (G_ASYNC_RESULT (data
->res
)));
222 /* Doesn't block, ignore error */
225 parent
->close_fn (stream
, data
->cancellable
, NULL
);
226 g_simple_async_result_set_from_error (data
->res
, error
);
231 parent
->close_fn (stream
, data
->cancellable
, &my_error
);
234 g_simple_async_result_set_from_error (data
->res
, my_error
);
235 g_error_free (my_error
);
240 g_simple_async_result_complete (data
->res
);
242 g_simple_async_result_complete_in_idle (data
->res
);
246 close_read_ready (GSocket
*socket
,
247 GIOCondition condition
,
248 CloseAsyncData
*data
)
250 GError
*error
= NULL
;
254 ret
= g_socket_receive (socket
, buffer
, sizeof (buffer
),
255 data
->cancellable
, &error
);
258 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_WOULD_BLOCK
))
259 g_error_free (error
);
262 async_close_finish (data
, error
, TRUE
);
263 g_error_free (error
);
270 async_close_finish (data
, NULL
, TRUE
);
279 g_tcp_connection_close_async (GIOStream
*stream
,
281 GCancellable
*cancellable
,
282 GAsyncReadyCallback callback
,
285 GTcpConnection
*connection
= G_TCP_CONNECTION (stream
);
286 CloseAsyncData
*data
;
291 if (connection
->priv
->graceful_disconnect
&&
292 !g_cancellable_is_cancelled (cancellable
) /* Cancelled -> close fast */)
294 data
= g_new (CloseAsyncData
, 1);
296 g_simple_async_result_new (G_OBJECT (stream
), callback
, user_data
,
297 g_tcp_connection_close_async
);
299 data
->cancellable
= g_object_ref (cancellable
);
301 data
->cancellable
= NULL
;
303 socket
= g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream
));
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
);
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
);
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.
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
369 g_tcp_connection_get_graceful_disconnect (GTcpConnection
*connection
)
371 return connection
->priv
->graceful_disconnect
;