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.
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
#include <collections/linked_list.h>
|
||||||
|
|
||||||
#include "whitelist_msg.h"
|
#include "whitelist_msg.h"
|
||||||
|
|
||||||
@@ -49,13 +50,53 @@ struct private_whitelist_control_t {
|
|||||||
stream_service_t *service;
|
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
|
* Dispatch a received message
|
||||||
*/
|
*/
|
||||||
static bool on_accept(private_whitelist_control_t *this, stream_t *stream)
|
static bool on_accept(private_whitelist_control_t *this, stream_t *stream)
|
||||||
{
|
{
|
||||||
identification_t *id, *current;
|
identification_t *id;
|
||||||
enumerator_t *enumerator;
|
|
||||||
whitelist_msg_t msg;
|
whitelist_msg_t msg;
|
||||||
|
|
||||||
if (!stream->read_all(stream, &msg, sizeof(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);
|
this->listener->remove(this->listener, id);
|
||||||
break;
|
break;
|
||||||
case WHITELIST_LIST:
|
case WHITELIST_LIST:
|
||||||
enumerator = this->listener->create_enumerator(this->listener);
|
list(this, stream, id);
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
case WHITELIST_FLUSH:
|
case WHITELIST_FLUSH:
|
||||||
this->listener->flush(this->listener, id);
|
this->listener->flush(this->listener, id);
|
||||||
|
|||||||
Reference in New Issue
Block a user