]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
whitelist: use a read-copy when listing entries
authorMartin Willi <martin@revosec.ch>
Mon, 8 Jul 2013 09:44:52 +0000 (11:44 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 17 Jul 2013 14:55:51 +0000 (16:55 +0200)
While this requires a little more overhead, we can free the lock should the
stream block, allowing other threads to add/remove entries.

src/libcharon/plugins/whitelist/whitelist_control.c

index c3f7ac40eb1aa506c9db289d61e5ff1f643c3b87..e97885c8f36fcb3be7fd64875bd3205af7e47e34 100644 (file)
@@ -23,6 +23,7 @@
 #include <errno.h>
 
 #include <daemon.h>
+#include <collections/linked_list.h>
 
 #include "whitelist_msg.h"
 
@@ -49,13 +50,53 @@ struct private_whitelist_control_t {
        stream_service_t *service;
 };
 
+/*
+ * List whitelist entries using a read-copy
+ */
+static void list(private_whitelist_control_t *this,
+                                stream_t *stream, identification_t *id)
+{
+       identification_t *current;
+       enumerator_t *enumerator;
+       linked_list_t *list;
+       whitelist_msg_t msg = {
+               .type = htonl(WHITELIST_LIST),
+       };
+
+       list = linked_list_create();
+       enumerator = this->listener->create_enumerator(this->listener);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (current->matches(current, id))
+               {
+                       list->insert_last(list, current->clone(current));
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       while (list->remove_first(list, (void**)&current) == SUCCESS)
+       {
+               snprintf(msg.id, sizeof(msg.id), "%Y", current);
+               current->destroy(current);
+               if (!stream->write_all(stream, &msg, sizeof(msg)))
+               {
+                       DBG1(DBG_CFG, "listing whitelist failed: %s", strerror(errno));
+                       break;
+               }
+       }
+       list->destroy_offset(list, offsetof(identification_t, destroy));
+
+       msg.type = htonl(WHITELIST_END);
+       memset(msg.id, 0, sizeof(msg.id));
+       stream->write_all(stream, &msg, sizeof(msg));
+}
+
 /**
  * Dispatch a received message
  */
 static bool on_accept(private_whitelist_control_t *this, stream_t *stream)
 {
-       identification_t *id, *current;
-       enumerator_t *enumerator;
+       identification_t *id;
        whitelist_msg_t msg;
 
        if (!stream->read_all(stream, &msg, sizeof(msg)))
@@ -74,23 +115,7 @@ static bool on_accept(private_whitelist_control_t *this, stream_t *stream)
                        this->listener->remove(this->listener, id);
                        break;
                case WHITELIST_LIST:
-                       enumerator = this->listener->create_enumerator(this->listener);
-                       while (enumerator->enumerate(enumerator, &current))
-                       {
-                               if (current->matches(current, id))
-                               {
-                                       snprintf(msg.id, sizeof(msg.id), "%Y", current);
-                                       if (!stream->write_all(stream, &msg, sizeof(msg)))
-                                       {
-                                               DBG1(DBG_CFG, "listing whitelist failed");
-                                               break;
-                                       }
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-                       msg.type = htonl(WHITELIST_END);
-                       memset(msg.id, 0, sizeof(msg.id));
-                       stream->write_all(stream, &msg, sizeof(msg));
+                       list(this, stream, id);
                        break;
                case WHITELIST_FLUSH:
                        this->listener->flush(this->listener, id);