summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip.withnall@collabora.co.uk>2014-10-30 09:10:51 +0000
committerPhilip Withnall <philip.withnall@collabora.co.uk>2014-10-30 09:10:51 +0000
commit88cd37a4ffbe4bc623eda2c0ac01565d467976f3 (patch)
tree2bc739c4149be4dcf29d2a3817d1b1a7cace5c6e
parent3bc28d43a5189e561087f9340467ef2bd314c7fb (diff)
agent: Close pseudo-TCP socket earlier in component_close()
This tries to mitigate the race condition between finishing the TCP FIN handshake and closing the underlying sockets, but it’s impossible to mitigate properly without API changes. See the comment.
-rw-r--r--agent/component.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/agent/component.c b/agent/component.c
index c6a5601..8a1d064 100644
--- a/agent/component.c
+++ b/agent/component.c
@@ -228,6 +228,20 @@ component_close (Component *cmp)
IOCallbackData *data;
GOutputVector *vec;
+ /* Start closing the pseudo-TCP socket first. FIXME: There is a very big and
+ * reliably triggerable race here. pseudo_tcp_socket_close() does not block
+ * on the socket closing — it only sends the first packet of the FIN
+ * handshake. component_close() will immediately afterwards close the
+ * underlying component sockets, aborting the handshake.
+ *
+ * On the principle that starting the FIN handshake is better than not
+ * starting it, even if it’s later truncated, call pseudo_tcp_socket_close().
+ * A long-term fix is needed in the form of making component_close() (and all
+ * its callers) async, so we can properly block on closure. */
+ if (cmp->tcp) {
+ pseudo_tcp_socket_close (cmp->tcp, TRUE);
+ }
+
if (cmp->restart_candidate)
nice_candidate_free (cmp->restart_candidate),
cmp->restart_candidate = NULL;
@@ -262,9 +276,6 @@ component_close (Component *cmp)
g_cancellable_cancel (cmp->tcp_writable_cancellable);
g_clear_object (&cmp->tcp_writable_cancellable);
}
- if (cmp->tcp) {
- pseudo_tcp_socket_close (cmp->tcp, TRUE);
- }
while ((data = g_queue_pop_head (&cmp->pending_io_messages)) != NULL)
io_callback_data_free (data);