From 961409b66858facdad00e4bf38f534ced3c1255e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 17 Feb 2014 09:44:14 +0100 Subject: [PATCH] lookip: Disconnect asynchronously to avoid dead-locking watcher unregistration While it really would be desirable to allow stream destruction during on_read() callbacks, this does not work anymore since e49b2998. Until we have a proper solution for this issue, use asynchronous disconnects for the only user doing so. Fixes #518. --- src/libcharon/plugins/lookip/lookip_socket.c | 33 +++++++++++++++++-- src/libstrongswan/networking/streams/stream.h | 5 ++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/libcharon/plugins/lookip/lookip_socket.c b/src/libcharon/plugins/lookip/lookip_socket.c index a39eb884a..f19c7c1a9 100644 --- a/src/libcharon/plugins/lookip/lookip_socket.c +++ b/src/libcharon/plugins/lookip/lookip_socket.c @@ -87,10 +87,21 @@ static void entry_destroy(entry_t *entry) } /** - * Disconnect a stream, remove connection entry + * Data for async disconnect job */ -static void disconnect(private_lookip_socket_t *this, stream_t *stream) +typedef struct { + /** socket ref */ + private_lookip_socket_t *this; + /** stream to disconnect */ + stream_t *stream; +} disconnect_data_t; + +/** + * Disconnect a stream asynchronously, remove connection entry + */ +static job_requeue_t disconnect_async(disconnect_data_t *data) { + private_lookip_socket_t *this = data->this; enumerator_t *enumerator; entry_t *entry; @@ -98,7 +109,7 @@ static void disconnect(private_lookip_socket_t *this, stream_t *stream) enumerator = this->connected->create_enumerator(this->connected); while (enumerator->enumerate(enumerator, &entry)) { - if (entry->stream == stream) + if (entry->stream == data->stream) { this->connected->remove_at(this->connected, enumerator); if (entry->up || entry->down) @@ -113,6 +124,22 @@ static void disconnect(private_lookip_socket_t *this, stream_t *stream) this->mutex->unlock(this->mutex); } +/** + * Queue async disconnect job + */ +static void disconnect(private_lookip_socket_t *this, stream_t *stream) +{ + disconnect_data_t *data; + + INIT(data, + .this = this, + .stream = stream, + ); + + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create(disconnect_async, data, free, NULL)); +} + /** * Callback function for listener up/down events */ diff --git a/src/libstrongswan/networking/streams/stream.h b/src/libstrongswan/networking/streams/stream.h index 810514da9..3516d9186 100644 --- a/src/libstrongswan/networking/streams/stream.h +++ b/src/libstrongswan/networking/streams/stream.h @@ -39,9 +39,8 @@ typedef stream_t*(*stream_constructor_t)(char *uri); /** * Callback function prototype, called when stream is ready. * - * It is allowed to destroy the stream during the callback, but only if it has - * no other active on_read()/on_write() callback and returns FALSE. It is not - * allowed to to call on_read()/on_write/() during the callback. + * It is not allowed to destroy the stream nor to call on_read()/on_write/() + * during the callback. * * As select() may return even if a read()/write() would actually block, it is * recommended to use the non-blocking calls and handle return values