From b7e4c63cd9490018d7f8db138de98168ae4e4050 Mon Sep 17 00:00:00 2001 From: Jonny Lamb Date: Fri, 11 Mar 2011 09:54:19 +0000 Subject: porter: don't close twice if we close in a send callback We need to decide before we complete the "send stanza" asynchronous operation whether we have a close result pending. If we don't, we can get into a pickle if the callback to send_async calls close_async. The problem is that close_async doesn't use the same stanza queue as send_async so needs special-casing. For example: Previously, we send a stanza using send_async. The simple async result would be completed with g_simple_async_result_complete() and the callback to send_async would be called. However, if in the callback close_async is called, the stream close is sent directly with wocky_xmpp_connection_send_close_async and priv->close_result is assigned. Once the callback returns, send_stanza_cb continues BUT at the end there is a test for whether there is a close result pending. This is for when you send a whole bunch of stanzas followed by a close request, so the porter waits until all the stanzas are sent before sending the stream close, which is cool. However, priv->close_result is now != NULL so the porter thinks we're in exactly that case -- that we're waiting until all the stanzas are sent and will try and send a stream close afterwards. As we've already done that the xmpp connection will say "hey another send operation pending" and everything will fall apart. Signed-off-by: Jonny Lamb --- wocky/wocky-porter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wocky/wocky-porter.c b/wocky/wocky-porter.c index d83c035..b167b96 100644 --- a/wocky/wocky-porter.c +++ b/wocky/wocky-porter.c @@ -90,6 +90,7 @@ struct _WockyPorterPrivate GCancellable *receive_cancellable; GSimpleAsyncResult *close_result; + gboolean waiting_to_close; gboolean remote_closed; gboolean local_closed; GCancellable *close_cancellable; @@ -750,12 +751,13 @@ send_stanza_cb (GObject *source, } } - if (priv->close_result != NULL && + if (priv->waiting_to_close && g_queue_get_length (priv->sending_queue) == 0) { /* Queue is empty and we are waiting to close the connection. */ DEBUG ("Queue has been flushed. Closing the connection."); send_close (self); + priv->waiting_to_close = FALSE; } g_object_unref (self); @@ -1429,6 +1431,7 @@ wocky_porter_close_async (WockyPorter *self, { DEBUG ("Sending queue is not empty. Flushing it before " "closing the connection."); + priv->waiting_to_close = TRUE; return; } -- cgit v1.2.3