lookip: Disconnect asynchronously to avoid dead-locking watcher unregistration
authorMartin Willi <martin@revosec.ch>
Mon, 17 Feb 2014 08:44:14 +0000 (09:44 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 17 Feb 2014 08:48:55 +0000 (09:48 +0100)
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
src/libstrongswan/networking/streams/stream.h

index a39eb88..f19c7c1 100644 (file)
@@ -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)
@@ -114,6 +125,22 @@ static void disconnect(private_lookip_socket_t *this, stream_t *stream)
 }
 
 /**
+ * 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
  */
 static bool event_cb(entry_t *entry, bool up, host_t *vip, host_t *other,
index 810514d..3516d91 100644 (file)
@@ -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