From 0a35ae781d49740c2b5df7057a439f8045e600c4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 8 Jul 2013 11:44:52 +0200 Subject: [PATCH] whitelist: use a read-copy when listing entries While this requires a little more overhead, we can free the lock should the stream block, allowing other threads to add/remove entries. --- .../plugins/whitelist/whitelist_control.c | 63 +++++++++++++------ 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c index c3f7ac40eb..e97885c8f3 100644 --- a/src/libcharon/plugins/whitelist/whitelist_control.c +++ b/src/libcharon/plugins/whitelist/whitelist_control.c @@ -23,6 +23,7 @@ #include #include +#include #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, ¤t)) + { + if (current->matches(current, id)) + { + list->insert_last(list, current->clone(current)); + } + } + enumerator->destroy(enumerator); + + while (list->remove_first(list, (void**)¤t) == 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, ¤t)) - { - 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); -- 2.47.2