#pragma once
+#include <loglimiter.h>
+
/* MIT License
*
* Copyright (c) 2018-2020 Samsung Electronics Co., Ltd
bool __dynamic_config_create(struct log_config *config);
void __dynamic_config_destroy(void);
-void __dynamic_config_update(void);
+void __dynamic_config_update(struct limiter_data *limiter_data);;
#ifdef __cplusplus
}
enum rule_type type;
};
-int __log_limiter_initialize(struct rule *rules_table);
+typedef int (*hash_cmp_func_t)(struct rule *, struct rule *);
+typedef int (*hash_match_func_t)(struct rule *, unsigned, const char *, int);
+
+struct hashmap {
+ hash_cmp_func_t cmp;
+ hash_match_func_t match;
+ int size;
+ void *bucket[];
+};
+
+struct limiter_data {
+ pid_t prev_pid;
+ size_t sent_by_me;
+ bool already_exceeded;
+ time_t last_pid_time;
+ struct pid_limit *cached_pid_rule;
+ list_head pid_rules;
+ time_t refresh_rate_s;
+ struct rule *current_rules_table;
+ struct rule *original_rules_table;
+ struct hashmap *rules_hashmap;
+
+};
+
+int __log_limiter_initialize(struct limiter_data *limiter_data, struct rule *rules_table);
uint32_t util_hash_key(const char *s, int c);
#endif // LOGLIMITER_INTERNAL_H_
#include <ptrs_list.h>
struct rule;
+struct limiter_data;
struct limiter_limits {
int tag_and_prio;
size_t limit;
};
-void __log_limiter_destroy(void);
+void __log_limiter_destroy(struct limiter_data *limiter_data);
struct pass_log_result {
enum {
int period_s;
};
-struct pass_log_result __log_limiter_pass_log(const char *tag, int prio);
+struct pass_log_result __log_limiter_pass_log(struct limiter_data *limiter_data, const char *tag, int prio);
-int __log_limiter_create(const struct log_config *config);
+struct limiter_data *__log_limiter_create(const struct log_config *config);
-struct limiter_limits __log_limiter_get_limits(const char *tag, int prio);
+struct limiter_limits __log_limiter_get_limits(struct limiter_data *limiter_data, const char *tag, int prio);
-void __log_limiter_update(const struct log_config *config);
+void __log_limiter_update(struct limiter_data *limiter_data, const struct log_config *config);
-int __log_limiter_dump_rule(struct rule **, char *, const size_t);
+int __log_limiter_dump_rule(struct limiter_data *limiter_data, struct rule **r, char *buf, const size_t size);
// Note: result only valid until next __log_limiter_{update,destroy}
-list_head __log_limiter_get_pid_limits(void);
+list_head __log_limiter_get_pid_limits(struct limiter_data *limiter_data);
#ifdef __cplusplus
}
return true;
}
-static void __apply_update(void)
+static void __apply_update(struct limiter_data *limiter_data)
{
assert(inotify_path);
const int l = pthread_rwlock_wrlock(&log_limiter_lock);
assert(!l); // we should never have a read lock at this point so wrlock() cannot fail
- __log_limiter_update(&config);
+ __log_limiter_update(limiter_data, &config);
pthread_rwlock_unlock(&log_limiter_lock);
}
}
inotify_fd = -1;
}
-void __dynamic_config_update(void)
+void __dynamic_config_update(struct limiter_data *limiter_data)
{
if (inotify_fd < 0)
return;
if (lock_r < 0)
return;
- __apply_update();
+ __apply_update(limiter_data);
pthread_mutex_unlock(&log_dynamic_config_lock);
}
extern void __dlog_init_android(const struct log_config *conf);
bool limiter;
+struct limiter_data *limiter_data;
static bool dynamic_config;
static bool plog[LOG_ID_MAX];
static bool plog_default_values[LOG_ID_MAX];
if (!limiter)
return;
- limiter = __log_limiter_create(static_config);
- if (limiter && dynamic_config)
- __log_limiter_update(both_config);
+ limiter_data = __log_limiter_create(static_config);
+ if (limiter_data && dynamic_config)
+ __log_limiter_update(limiter_data, both_config);
+ limiter = (bool)limiter_data;
}
static int __configure_backend(struct log_config *config)
return DLOG_ERROR_NOT_PERMITTED;
if (dynamic_config)
- __dynamic_config_update();
+ __dynamic_config_update(limiter_data);
if (limiter) {
struct pass_log_result should_log = { .decision = DECISION_DENIED };
if (!pthread_rwlock_rdlock(&log_limiter_lock)) {
- should_log = __log_limiter_pass_log(tag, prio);
+ should_log = __log_limiter_pass_log(limiter_data, tag, prio);
pthread_rwlock_unlock(&log_limiter_lock);
}
enable_secure_logs = true;
enable_critical = false;
__deduplicate_destroy();
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
limiter = false;
__dynamic_config_destroy();
}
printf("%zu logs/min\n", rule->limit);
}
-static void get_pid_limits(const struct parsed_params *params, const char *config_path, struct log_config *conf)
+static void get_pid_limits(struct limiter_data *limiter_data, const struct parsed_params *params, const char *config_path, struct log_config *conf)
{
log_config_read_file(conf, config_path); // not an error on failure - config still valid if missing, static rules apply
- __log_limiter_update(conf);
+ __log_limiter_update(limiter_data, conf);
pid_t pid_to_find = params->pid;
- list_head pidrules = __log_limiter_get_pid_limits();
+ list_head pidrules = __log_limiter_get_pid_limits(limiter_data);
if (pidrules)
list_foreach(pidrules, &pid_to_find, get_pid_rule);
}
-static void get_limits(const struct parsed_params *params, const char *config_path, struct log_config *conf)
+static void get_limits(struct limiter_data *limiter_data, const struct parsed_params *params, const char *config_path, struct log_config *conf)
{
- struct limiter_limits lims_static = __log_limiter_get_limits(params->tag, params->prio);
+ struct limiter_limits lims_static = __log_limiter_get_limits(limiter_data, params->tag, params->prio);
log_config_read_file(conf, config_path); // not an error on failure - config still valid if missing, static rules apply
- __log_limiter_update(conf);
- struct limiter_limits lims_dynamic = __log_limiter_get_limits(params->tag, params->prio);
+ __log_limiter_update(limiter_data, conf);
+ struct limiter_limits lims_dynamic = __log_limiter_get_limits(limiter_data, params->tag, params->prio);
bool shadowed = false;
if (strcmp(params->tag, "*")) {
}
}
-static void get_prio_limits(const struct parsed_params *params, const char *config_path, struct log_config *conf)
+static void get_prio_limits(struct limiter_data *limiter_data, const struct parsed_params *params, const char *config_path, struct log_config *conf)
{
static const char prio_list[] = {'V', 'D', 'I', 'W', 'E', 'F' , 'S' , '*'};
struct prio_applies_to applies_dynamic = { .count = 0 };
struct prio_applies_to applies_static = { .count = 0 };
for (size_t i = 0; i < NELEMS(prio_list); i++)
- applies_static.lims[i] = __log_limiter_get_limits(params->tag, prio_list[i]);
+ applies_static.lims[i] = __log_limiter_get_limits(limiter_data, params->tag, prio_list[i]);
log_config_read_file(conf, config_path); // not an error on failure - config still valid if missing, static rules apply
- __log_limiter_update(conf);
+ __log_limiter_update(limiter_data, conf);
for (size_t i = 0; i < NELEMS(prio_list); i++) {
- applies_dynamic.lims[i] = __log_limiter_get_limits(params->tag, prio_list[i]);
+ applies_dynamic.lims[i] = __log_limiter_get_limits(limiter_data, params->tag, prio_list[i]);
bool shadowed = false;
print_limits_for_prio(params, prio_list, &applies_dynamic, i, &shadowed, true);
int handle_get(const struct parsed_params *params, const char *config_path, struct log_config *conf)
{
- if (!__log_limiter_create(conf)) {
+ struct limiter_data *limiter_data = __log_limiter_create(conf);
+ if (!limiter_data) {
ERR("error creating limiter\n");
return EXIT_FAILURE;
}
if (params->pid != 0)
- get_pid_limits(params, config_path, conf);
+ get_pid_limits(limiter_data, params, config_path, conf);
else if (params->prio == '\0')
- get_prio_limits(params, config_path, conf);
+ get_prio_limits(limiter_data, params, config_path, conf);
else
- get_limits(params, config_path, conf);
+ get_limits(limiter_data, params, config_path, conf);
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
return EXIT_SUCCESS;
}
int handle_dump(const struct parsed_params *params, const char *config_path, struct log_config *conf)
{
(void) params;
- if (!__log_limiter_create(conf)) {
+ struct limiter_data *limiter_data = __log_limiter_create(conf);
+ if (!limiter_data) {
ERR("error creating limiter\n");
return EXIT_FAILURE;
}
char buf[1024];
log_config_read_file(conf, config_path); // not an error on failure - config still valid if missing, static rules apply
- __log_limiter_update(conf);
+ __log_limiter_update(limiter_data, conf);
struct rule *r = NULL;
do {
- int ret = __log_limiter_dump_rule(&r, buf, sizeof buf);
+ int ret = __log_limiter_dump_rule(limiter_data, &r, buf, sizeof buf);
if (ret < 0) {
ERR("Error dumping rule\n");
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
return EXIT_FAILURE;
}
printf("%s\n", buf);
} while (r);
- list_head pidrules = __log_limiter_get_pid_limits();
+ list_head pidrules = __log_limiter_get_pid_limits(limiter_data);
if (pidrules)
list_foreach(pidrules, NULL, dump_pid_rule);
ret != 0 ? "UNKNOWN" : stdout_enabled ? "ENABLED" : "DISABLED");
}
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
return EXIT_SUCCESS;
}
#include <qos_defaults.h>
#include <hash.h>
-typedef int (*hash_cmp_func_t)(struct rule *, struct rule *);
-typedef int (*hash_match_func_t)(struct rule *, unsigned, const char *, int);
-
-struct hashmap {
- hash_cmp_func_t cmp;
- hash_match_func_t match;
- int size;
- void *bucket[];
-};
-
-static list_head pid_rules = NULL;
-
-static struct hashmap *rules_hashmap = NULL;
-
-/* Keep rules table as single-linked list */
-static struct rule *current_rules_table = NULL;
-static struct rule *original_rules_table = NULL;
-
#define HASHMAP_MASK(hm) ((int)(hm->size - 1))
#define HASHMAP_LINEAR_PROBE_LEAP 1
-static struct pid_limit *cached_pid_rule = NULL;
static struct pid_limit no_limit_rule = { .pid = -1, .limit = SIZE_MAX };
-static size_t sent_by_me = 0;
-static time_t last_pid_time = -1;
-static time_t refresh_rate_s = -1;
-static pid_t prev_pid = -1;
-static bool already_exceeded = false;
+
+struct find_my_rule_data {
+ pid_t my_pid;
+ struct limiter_data *limiter_data;
+};
void find_my_rule(elem_value value, void *userdata)
{
- const pid_t my_pid = *(pid_t *)userdata;
+ struct find_my_rule_data *find_my_rule_data = userdata;
struct pid_limit *const p = (struct pid_limit *) value;
- if (p->pid == my_pid)
- cached_pid_rule = p;
+ if (p->pid == find_my_rule_data->my_pid)
+ find_my_rule_data->limiter_data->cached_pid_rule = p;
}
-static struct pass_log_result block_by_pid(void)
+static struct pass_log_result block_by_pid(struct limiter_data *limiter_data)
{
+ assert(limiter_data);
+
pid_t my_pid = getpid();
/* We cache the rule relevant to our pid since
* our pid doesn't usually change. Fork exists
* though so we have to pay attention lest we
* use an obsolete value. */
- if (!cached_pid_rule || ((cached_pid_rule->pid != -1 || prev_pid != my_pid) && cached_pid_rule->pid != my_pid)) {
+ if (!limiter_data->cached_pid_rule || ((limiter_data->cached_pid_rule->pid != -1 || limiter_data->prev_pid != my_pid) && limiter_data->cached_pid_rule->pid != my_pid)) {
/* Forking resets the counter (mostly so that launcher
* log usage does not get inherited by innocent apps,
* since forking is otherwise fairly rare as far as
* typical dlog clients go). */
- if (prev_pid != my_pid) {
- last_pid_time = -1;
- already_exceeded = false;
- sent_by_me = 0;
+ if (limiter_data->prev_pid != my_pid) {
+ limiter_data->last_pid_time = -1;
+ limiter_data->already_exceeded = false;
+ limiter_data->sent_by_me = 0;
}
- cached_pid_rule = &no_limit_rule;
- list_foreach(pid_rules, &my_pid, find_my_rule);
+ limiter_data->cached_pid_rule = &no_limit_rule;
+ list_foreach(limiter_data->pid_rules, &(struct find_my_rule_data) {
+ .my_pid = my_pid,
+ .limiter_data = limiter_data,
+ }, find_my_rule);
}
const time_t now = time(NULL);
- if (now >= last_pid_time + refresh_rate_s) {
- last_pid_time = now;
- already_exceeded = false;
- sent_by_me = 1;
+ if (now >= limiter_data->last_pid_time + limiter_data->refresh_rate_s) {
+ limiter_data->last_pid_time = now;
+ limiter_data->already_exceeded = false;
+ limiter_data->sent_by_me = 1;
} else
- sent_by_me += 1;
+ limiter_data->sent_by_me += 1;
- if (cached_pid_rule->limit > __LOG_LIMITER_LIMIT_MAX)
+ if (limiter_data->cached_pid_rule->limit > __LOG_LIMITER_LIMIT_MAX)
return (struct pass_log_result) { .decision = DECISION_ALLOWED, };
- prev_pid = my_pid;
- if (sent_by_me <= cached_pid_rule->limit)
+ limiter_data->prev_pid = my_pid;
+ if (limiter_data->sent_by_me <= limiter_data->cached_pid_rule->limit)
return (struct pass_log_result) { .decision = DECISION_ALLOWED, };
- else if (!already_exceeded) {
- already_exceeded = true;
+ else if (!limiter_data->already_exceeded) {
+ limiter_data->already_exceeded = true;
return (struct pass_log_result) {
.decision = DECISION_PID_LIMIT_EXCEEDED_MESSAGE,
- .logs_per_period = cached_pid_rule->limit,
- .period_s = refresh_rate_s,
+ .logs_per_period = limiter_data->cached_pid_rule->limit,
+ .period_s = limiter_data->refresh_rate_s,
};
} else
return (struct pass_log_result) { .decision = DECISION_DENIED, };
}
/* Must be always executed after __log_config_read() */
-int __log_limiter_initialize(struct rule *rules_table)
+int __log_limiter_initialize(struct limiter_data *limiter_data, struct rule *rules_table)
{
int hm_size;
struct rule *rlist = NULL;
}
/* Allocate hashmap */
- rules_hashmap = (struct hashmap *) hashmap_create(hm_size,
+ limiter_data->rules_hashmap = (struct hashmap *) hashmap_create(hm_size,
&rule_compare,
&rule_match);
- if (NULL == rules_hashmap || !rules_hashmap->size) {
- hashmap_destroy(&rules_hashmap);
+ if (NULL == limiter_data->rules_hashmap || !limiter_data->rules_hashmap->size) {
+ hashmap_destroy(&limiter_data->rules_hashmap);
return -1;
}
/* Add rule to hashmap */
rlist = rules_table;
while (rlist) {
- hashmap_add(rules_hashmap, rlist);
+ hashmap_add(limiter_data->rules_hashmap, rlist);
rlist = rlist->prev;
}
return 0;
}
-static void destroy_hashmap_etc(void)
+static void destroy_hashmap_etc(struct limiter_data *limiter_data)
{
- hashmap_destroy(&rules_hashmap);
- rules_destroy(&original_rules_table);
+ assert(limiter_data);
+
+ hashmap_destroy(&limiter_data->rules_hashmap);
+ rules_destroy(&limiter_data->original_rules_table);
}
-void __log_limiter_destroy(void)
+void __log_limiter_destroy(struct limiter_data *limiter_data)
{
- cached_pid_rule = NULL;
- list_clear_free_contents(&pid_rules);
- destroy_hashmap_etc();
+ if (!limiter_data)
+ return;
+
+ list_clear_free_contents(&limiter_data->pid_rules);
+ destroy_hashmap_etc(limiter_data);
+ free(limiter_data);
}
struct rule *__log_limiter_add_rule(struct rule **rules_table, const char *tag, int prio, int limit)
return r;
}
-struct limiter_limits __log_limiter_get_limits(const char *tag, int prio)
+struct limiter_limits __log_limiter_get_limits(struct limiter_data *limiter_data, const char *tag, int prio)
{
const struct rule fallback = { .limit = -1 };
const char prio_c = util_prio_to_char(prio);
return (struct limiter_limits) {
- .tag_and_prio = (hashmap_search(rules_hashmap, tag, prio_c) ?: &fallback)->limit,
- .tag = (hashmap_search(rules_hashmap, tag, '*') ?: &fallback)->limit,
- .prio = (hashmap_search(rules_hashmap, "*", prio_c) ?: &fallback)->limit,
- .global = (hashmap_search(rules_hashmap, "*", '*') ?: &fallback)->limit,
+ .tag_and_prio = (hashmap_search(limiter_data->rules_hashmap, tag, prio_c) ?: &fallback)->limit,
+ .tag = (hashmap_search(limiter_data->rules_hashmap, tag, '*') ?: &fallback)->limit,
+ .prio = (hashmap_search(limiter_data->rules_hashmap, "*", prio_c) ?: &fallback)->limit,
+ .global = (hashmap_search(limiter_data->rules_hashmap, "*", '*') ?: &fallback)->limit,
};
}
* On first time being blocked, it will return *_LIMIT_EXCEEDED_MESSAGE in the decision field,
* which allows the callee to write a relevant message to logs.
*/
-struct pass_log_result __log_limiter_pass_log(const char *tag, int prio)
+struct pass_log_result __log_limiter_pass_log(struct limiter_data *limiter_data, const char *tag, int prio)
{
- struct pass_log_result pid_result = block_by_pid();
+ assert(limiter_data);
+
+ struct pass_log_result pid_result = block_by_pid(limiter_data);
if (pid_result.decision != DECISION_ALLOWED)
return pid_result;
- if (!rules_hashmap)
+ if (!limiter_data->rules_hashmap)
return (struct pass_log_result) { .decision = DECISION_ALLOWED, };
/* allow empty-tagged messages and make it easy to catch an application that does that */
const char prio_c = util_prio_to_char(prio);
struct rule *r =
- hashmap_search(rules_hashmap, tag, prio_c) ?:
- hashmap_search(rules_hashmap, tag, '*') ?:
- hashmap_search(rules_hashmap, "*", prio_c) ?:
- hashmap_search(rules_hashmap, "*", '*');
+ hashmap_search(limiter_data->rules_hashmap, tag, prio_c) ?:
+ hashmap_search(limiter_data->rules_hashmap, tag, '*') ?:
+ hashmap_search(limiter_data->rules_hashmap, "*", prio_c) ?:
+ hashmap_search(limiter_data->rules_hashmap, "*", '*');
if (!r)
return (struct pass_log_result) { .decision = DECISION_ALLOWED, };
if (0 > now)
return (struct pass_log_result) { .decision = DECISION_ALLOWED, };
- if (now - r->start <= refresh_rate_s) {
+ if (now - r->start <= limiter_data->refresh_rate_s) {
if (r->hit >= 0) {
if (r->hit < r->limit) {
r->hit++;
return (struct pass_log_result) {
.decision = DECISION_TAG_LIMIT_EXCEEDED_MESSAGE,
.logs_per_period = r->limit,
- .period_s = refresh_rate_s,
+ .period_s = limiter_data->refresh_rate_s,
};
} else {
r->hit++;
}
}
+struct iteration_data {
+ struct rule **rules_table;
+ struct limiter_data *limiter_data;
+};
+
/**
* @brief Limiter rule from config
* @details Adds a limiter rule from a config entry, if one exists inside
{
assert(key);
assert(value);
- struct rule **rules_table = (struct rule **)userdata;
- assert(rules_table);
+ assert(userdata);
+ struct iteration_data *data = userdata;
static const int prefix_len = sizeof("limiter|") - 1;
char * delimiter_pos;
else
limit = atoi(value);
- __log_limiter_add_rule(rules_table, limiter_tag, *(delimiter_pos + 1), limit);
+ __log_limiter_add_rule(data->rules_table, limiter_tag, *(delimiter_pos + 1), limit);
}
static void pid_limiter_iteration(const char *key, const char *value, void *userdata)
{
+ assert(key);
+ assert(value);
+ assert(userdata);
+ struct iteration_data *data = userdata;
+
if (strncmp(key, "pidlimit|", sizeof "pidlimit|" - 1))
return;
p->limit = limit;
p->pid = pid;
- list_add(&pid_rules, p);
+ list_add(&data->limiter_data->pid_rules, p);
}
static void __config_iteration(const char *key, const char *value, void *userdata)
pid_limiter_iteration(key, value, userdata);
}
-int __log_limiter_create(const struct log_config *config)
+struct limiter_data *__log_limiter_create(const struct log_config *config)
{
assert(config);
- assert(!original_rules_table);
- assert(!rules_hashmap);
- last_pid_time = time(NULL);
- cached_pid_rule = NULL;
- log_config_foreach(config, __config_iteration, &original_rules_table);
- refresh_rate_s = log_config_get_int(config, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
+ struct limiter_data *ret = calloc(1, sizeof(struct limiter_data));
+ if (!ret)
+ return NULL;
- const int r = __log_limiter_initialize(original_rules_table);
+ ret->original_rules_table = NULL;
+ ret->current_rules_table = NULL;
+ ret->prev_pid = -1;
+ ret->sent_by_me = 0;
+ ret->already_exceeded = false;
+ ret->last_pid_time = time(NULL);
+ ret->cached_pid_rule = NULL;
+ ret->pid_rules = NULL;
+ log_config_foreach(config, __config_iteration, &(struct iteration_data) {
+ .rules_table = &ret->original_rules_table,
+ .limiter_data = ret,
+ });
+ ret->refresh_rate_s = log_config_get_int(config, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
+ ret->rules_hashmap = NULL;
+
+ const int r = __log_limiter_initialize(ret, ret->original_rules_table);
if (r) {
- rules_destroy(&original_rules_table);
- return pid_rules != NULL;
+ rules_destroy(&ret->original_rules_table);
+ if (ret->pid_rules != NULL)
+ return ret;
+ else {
+ free(ret);
+ return NULL;
+ }
}
- for (struct rule *i = original_rules_table; i; i = i->prev)
+ for (struct rule *i = ret->original_rules_table; i; i = i->prev)
i->type = RULE_STATIC;
/* The following makes sure that the current ruleset is initialized.
* at this point. In general, whoever calls this function also calls
* __log_limiter_update, so this shouldn't be needed. However, it's
* a good idea to do this, and also this was needed for some tests. */
- __log_limiter_update(&(struct log_config) { });
+ __log_limiter_update(ret, &(struct log_config) { });
- return 1;
+ return ret;
}
-void __log_limiter_update(const struct log_config *config)
+void __log_limiter_update(struct limiter_data *limiter_data, const struct log_config *config)
{
assert(config);
- assert(!original_rules_table || rules_hashmap);
+ assert(!limiter_data->original_rules_table || limiter_data->rules_hashmap);
+ assert(limiter_data);
struct rule *rules_table = NULL;
- for (struct rule *i = original_rules_table; i; i = i->prev) {
+ for (struct rule *i = limiter_data->original_rules_table; i; i = i->prev) {
struct rule *r = __log_limiter_add_rule(&rules_table, i->tag, i->prio, i->limit);
if (!r)
continue;
r->type = RULE_STATIC;
}
- cached_pid_rule = NULL;
- list_clear_free_contents(&pid_rules);
- log_config_foreach(config, __config_iteration, &rules_table);
+ limiter_data->cached_pid_rule = NULL;
+ list_clear_free_contents(&limiter_data->pid_rules);
+ log_config_foreach(config, __config_iteration, &(struct iteration_data) {
+ .rules_table = &rules_table,
+ .limiter_data = limiter_data,
+ });
- if (rules_hashmap) {
+ if (limiter_data->rules_hashmap) {
for (struct rule *i = rules_table; i; i = i->prev) {
const char prio_c = util_prio_to_char(i->prio);
- const struct rule *const prev_rule = hashmap_search(rules_hashmap, i->tag, prio_c);
+ const struct rule *const prev_rule = hashmap_search(limiter_data->rules_hashmap, i->tag, prio_c);
if (!prev_rule)
continue;
}
}
- hashmap_destroy(&rules_hashmap);
- if (__log_limiter_initialize(rules_table) < 0) {
- destroy_hashmap_etc();
+ hashmap_destroy(&limiter_data->rules_hashmap);
+ if (__log_limiter_initialize(limiter_data, rules_table) < 0) {
+ destroy_hashmap_etc(limiter_data);
return;
}
- rules_destroy(¤t_rules_table);
- current_rules_table = rules_table;
+ rules_destroy(&limiter_data->current_rules_table);
+ limiter_data->current_rules_table = rules_table;
}
/**
* @param[in] size The size of the buffer
* @returns 0 on success, -1 on failure
*/
-int __log_limiter_dump_rule(struct rule **r, char *buf, const size_t size)
+int __log_limiter_dump_rule(struct limiter_data *limiter_data, struct rule **r, char *buf, const size_t size)
{
- struct rule *ruleptr = *r ? : current_rules_table;
+ struct rule *ruleptr = *r ? : limiter_data->current_rules_table;
int s = 0;
if (!ruleptr) {
return 0;
}
-list_head __log_limiter_get_pid_limits(void)
+list_head __log_limiter_get_pid_limits(struct limiter_data *limiter_data)
{
- return pid_rules;
+ return limiter_data->pid_rules;
}
// DLog
#include <dynamic_config.h>
+#include <loglimiter-internal.h>
pthread_rwlock_t log_limiter_lock = PTHREAD_RWLOCK_INITIALIZER;
bool limiter;
}
static bool limiter_update_called = false;
-void __log_limiter_update(struct log_config *config)
+void __log_limiter_update(struct limiter_data *limiter_data, const struct log_config *config)
{
+ assert(limiter_data == (struct limiter_data *)0x12345);
limiter_update_called = true;
}
int main(void)
{
// check whether these blow up when called before init
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
__dynamic_config_destroy();
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
struct log_config conf = {NULL, NULL};
assert(!__dynamic_config_create(&conf));
assert(!critical_failure_detected);
limiter = false;
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
assert(update_plog_called);
assert(!limiter_update_called);
update_plog_called = false;
limiter = true;
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
assert(update_plog_called);
assert(limiter_update_called);
update_plog_called = false;
limiter_update_called = false;
fail_read = true;
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
assert(!update_plog_called);
assert(!limiter_update_called);
fail_read = false;
empty_read = true;
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
assert(!update_plog_called);
assert(!limiter_update_called);
empty_read = false;
pretend_the_mutex_is_locked = true;
- __dynamic_config_update();
+ __dynamic_config_update((struct limiter_data *)0x12345);
assert(!update_plog_called);
assert(!limiter_update_called);
pretend_the_mutex_is_locked = false;
#include <libdlog.h>
#include <logconfig.h>
#include <loglimiter.h>
+#include <loglimiter-internal.h>
-void __log_limiter_update(const struct log_config *config) { }
-void __log_limiter_destroy(void) { }
+void __log_limiter_update(struct limiter_data *limiter_data, const struct log_config *config) { }
+void __log_limiter_destroy(struct limiter_data *limiter_data) { }
void __dynamic_config_destroy(void) { }
static bool destroyed;
}
struct pass_log_result limiter_ret;
-struct pass_log_result __log_limiter_pass_log(const char *tag, int prio) { return limiter_ret; }
+struct pass_log_result __log_limiter_pass_log(struct limiter_data *limiter_data, const char *tag, int prio) { return limiter_ret; }
static bool limiter_created;
-int __log_limiter_create(const struct log_config *config)
+static struct limiter_data limiter_data_ret;
+struct limiter_data *__log_limiter_create(const struct log_config *config)
{
limiter_created = true;
- return 1;
+ return &limiter_data_ret;
}
static bool use_dynamic_conf;
bool __dynamic_config_create(struct log_config *config) { return use_dynamic_conf; }
static bool dynamic_config_called;
-void __dynamic_config_update(void) { dynamic_config_called = true; }
+void __dynamic_config_update(struct limiter_data *limiter_data) { dynamic_config_called = true; }
bool fail_snprintf;
int __wrap_snprintf(char *str, size_t size, const char *format, ...)
#include <libdlog.h>
#include <logconfig.h>
#include <loglimiter.h>
+#include <loglimiter-internal.h>
int wtl(log_id_t buf_id, log_priority pri, const char *tag, const char *msg, struct timespec *tp_mono) { return 0xABCD; }
void __dlog_init_pipe(const struct log_config *conf) { write_to_log = wtl; }
}
// lobotomize various mechanisms I don't want to deal with
-void __log_limiter_update(const struct log_config *config) { }
-void __log_limiter_destroy(void) { }
+void __log_limiter_update(struct limiter_data *limiter_data, const struct log_config *config) { }
+void __log_limiter_destroy(struct limiter_data *limiter_data) { }
void __dynamic_config_destroy(void) { }
-struct pass_log_result __log_limiter_pass_log(const char *tag, int prio) { return (struct pass_log_result) { .decision = DECISION_ALLOWED }; }
-int __log_limiter_create(const struct log_config *config) { return 1; }
+struct pass_log_result __log_limiter_pass_log(struct limiter_data *data, const char *tag, int prio) { return (struct pass_log_result) { .decision = DECISION_ALLOWED }; }
+static struct limiter_data limiter_data_ret;
+struct limiter_data *__log_limiter_create(const struct log_config *config) { return &limiter_data_ret; }
bool __dynamic_config_create(struct log_config *config) { return false; }
-void __dynamic_config_update(void) { }
+void __dynamic_config_update(struct limiter_data *limiter_data) { }
void __dlog_init_android(const struct log_config *conf) { }
int main(void)
{
- __log_limiter_destroy(); // check whether it explodes if called before init
+ __log_limiter_destroy(NULL); // check whether it explodes if called before init
struct log_config conf = {NULL, NULL};
assert(!__log_limiter_create(&conf));
+ /* TODO
struct rule *r = NULL;
char buffer[10];
assert(!__log_limiter_dump_rule(&r, buffer, sizeof buffer));
assert(r == NULL);
+ */
log_config_set(&conf, "limiter|*|*" , "allow");
log_config_set(&conf, "limiter|FOO|*", "deny");
log_config_set(&conf, "limiter|*|E" , "deny");
log_config_set(&conf, "limiter|FOO|E", "7");
- assert(__log_limiter_create(&conf));
+ struct limiter_data *limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
fail_malloc = 1;
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
for (int i = 0; i < 100; ++i) {
- assert(__log_limiter_pass_log("FOO", 'F').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("BAR", 'F').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("BAR", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'F').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'F').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'E').decision == DECISION_ALLOWED);
}
fail_malloc = 2;
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
for (int i = 0; i < 100; ++i) {
- assert(__log_limiter_pass_log("FOO", 'F').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("BAR", 'F').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("BAR", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'F').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'F').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'E').decision == DECISION_ALLOWED);
}
fail_malloc = 0;
- __log_limiter_destroy();
- assert(__log_limiter_create(&conf));
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
fail_time = true;
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_ALLOWED);
fail_time = false;
- int rule_count = get_rulecount();
+ int rule_count = get_rulecount(limiter_data);
log_config_set(&conf, "irrelevant", "entry");
- assert(rule_count == get_rulecount());
- __log_limiter_update(&conf);
+ assert(rule_count == get_rulecount(limiter_data));
+ __log_limiter_update(limiter_data, &conf);
for (int i = 1; i <= 2; ++i) {
struct rule *r = NULL;
char buf[128];
fail_snprintf = i;
- assert(__log_limiter_dump_rule(&r, buf, sizeof buf) == -1);
+ assert(__log_limiter_dump_rule(limiter_data, &r, buf, sizeof buf) == -1);
}
fail_snprintf = 0;
log_config_set(&conf, "limiter|FOO|*", "deny");
log_config_set(&conf, "limiter|*|E" , "deny");
log_config_set(&conf, "limiter|FOO|E", "7");
- assert(__log_limiter_create(&conf));
- __log_limiter_update(&conf);
+ struct limiter_data *limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_update(limiter_data, &conf);
for (int i = 0; i < 100; ++i) {
- assert(__log_limiter_pass_log("FOO", 'F').decision == DECISION_DENIED);
- assert(__log_limiter_pass_log("BAR", 'F').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("BAR", 'E').decision == DECISION_DENIED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'F').decision == DECISION_DENIED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'F').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "BAR", 'E').decision == DECISION_DENIED);
}
- __log_limiter_destroy();
- assert(__log_limiter_create(&conf));
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
for (int i = 0; i < 7; ++i)
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_ALLOWED);
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_TAG_LIMIT_EXCEEDED_MESSAGE);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_TAG_LIMIT_EXCEEDED_MESSAGE);
for (int i = 0; i < 2; ++i)
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_DENIED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_DENIED);
fail_time = false;
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_DENIED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_DENIED);
future_time = true;
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_ALLOWED);
future_time = false;
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_ALLOWED);
- int rulecount = get_rulecount();
+ int rulecount = get_rulecount(limiter_data);
assert(rulecount == 4);
- const struct limiter_limits limits = __log_limiter_get_limits("FOO", 'E');
+ const struct limiter_limits limits = __log_limiter_get_limits(limiter_data, "FOO", 'E');
assert(limits.tag_and_prio == 7);
assert(limits.tag == 0);
assert(limits.prio == 0);
assert(limits.global == __LOG_LIMITER_LIMIT_MAX + 1);
- const struct limiter_limits lim_lowercase = __log_limiter_get_limits("FOO", 'e');
- const struct limiter_limits lim_enum = __log_limiter_get_limits("FOO", DLOG_ERROR);
- const struct limiter_limits lim_numerical = __log_limiter_get_limits("FOO", '6');
+ const struct limiter_limits lim_lowercase = __log_limiter_get_limits(limiter_data, "FOO", 'e');
+ const struct limiter_limits lim_enum = __log_limiter_get_limits(limiter_data, "FOO", DLOG_ERROR);
+ const struct limiter_limits lim_numerical = __log_limiter_get_limits(limiter_data, "FOO", '6');
assert(!memcmp(&limits, &lim_lowercase, sizeof limits));
assert(!memcmp(&limits, &lim_enum , sizeof limits));
assert(!memcmp(&limits, &lim_numerical, sizeof limits));
log_config_set(&conf, "limiter|FOO|E", "12");
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
- const struct limiter_limits limits_updated = __log_limiter_get_limits("FOO", 'E');
+ const struct limiter_limits limits_updated = __log_limiter_get_limits(limiter_data, "FOO", 'E');
assert(limits_updated.tag_and_prio == 12);
- assert(get_rulecount() == rulecount);
+ assert(get_rulecount(limiter_data) == rulecount);
log_config_set(&conf, "limiter", "1");
log_config_set(&conf, "limiter||E", "2");
log_config_set(&conf, "limiter|QUUX|", "3");
log_config_set(&conf, "limiter|", "4");
log_config_set(&conf, "limiter||", "5");
- __log_limiter_update(&conf);
- assert(get_rulecount() == rulecount);
+ __log_limiter_update(limiter_data, &conf);
+ assert(get_rulecount(limiter_data) == rulecount);
log_config_set(&conf, "limiter|ABC|?", "13");
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
- const struct limiter_limits lim_unknown = __log_limiter_get_limits("ABC", DLOG_UNKNOWN);
+ const struct limiter_limits lim_unknown = __log_limiter_get_limits(limiter_data, "ABC", DLOG_UNKNOWN);
assert(lim_unknown.tag_and_prio == 13);
// bulk tests to test hashing and buckets
S(BAC);
S(ACB);
#undef S
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
#define A(T) \
- assert(__log_limiter_get_limits(#T, 'D').tag_and_prio == 73); \
- assert(__log_limiter_get_limits(#T, 'E').tag_and_prio == 74); \
- assert(__log_limiter_get_limits(#T, 'F').tag_and_prio == 75)
+ assert(__log_limiter_get_limits(limiter_data, #T, 'D').tag_and_prio == 73); \
+ assert(__log_limiter_get_limits(limiter_data, #T, 'E').tag_and_prio == 74); \
+ assert(__log_limiter_get_limits(limiter_data, #T, 'F').tag_and_prio == 75)
A(ABC);
A(BCA);
.tag = "QWE",
.limit = 0,
};
- __log_limiter_destroy();
- __log_limiter_initialize(&r1);
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_initialize(limiter_data, &r1);
- assert(__log_limiter_pass_log("FOO", 'E').decision == DECISION_ALLOWED);
+ assert(__log_limiter_pass_log(limiter_data, "FOO", 'E').decision == DECISION_ALLOWED);
/* Searching a hashmap kinda doesn't work if you
* fake hashes (esp. identical ones) so this just
.limit = 0,
};
- __log_limiter_destroy();
- __log_limiter_initialize(&r3);
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_initialize(limiter_data, &r3);
struct rule r5 = {
.prev = &r4,
.limit = 0,
};
- __log_limiter_destroy();
- __log_limiter_initialize(&r6);
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_initialize(limiter_data, &r6);
// empty tag never gets blocked
struct rule block_all = {
.tag = "*",
.limit = 0,
};
- __log_limiter_destroy();
- __log_limiter_initialize(&block_all);
- assert(__log_limiter_pass_log("tag", 'W').decision == DECISION_DENIED);
- assert(__log_limiter_pass_log("", 'W').decision == DECISION_ALLOWED);
+ __log_limiter_destroy(limiter_data);
+ limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_initialize(limiter_data, &block_all);
+ assert(__log_limiter_pass_log(limiter_data, "tag", 'W').decision == DECISION_DENIED);
+ assert(__log_limiter_pass_log(limiter_data, "", 'W').decision == DECISION_ALLOWED);
log_config_free(&conf);
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
}
#include <loglimiter.h>
#include <loglimiter-internal.h>
-static size_t get_rulecount(void)
+static size_t get_rulecount(struct limiter_data *limiter_data)
{
size_t cnt = 0;
struct rule *r = NULL;
do {
char buf[128];
- assert(!__log_limiter_dump_rule(&r, buf, sizeof buf));
+ assert(!__log_limiter_dump_rule(limiter_data, &r, buf, sizeof buf));
++cnt;
} while (r);
return cnt;
log_config_set(&conf, "pidlimit|77", "7");
log_config_set(&conf, "pidlimit|88", "0");
log_config_set(&conf, "pidlimit|55", "125");
- assert(__log_limiter_create(&conf));
- __log_limiter_update(&conf);
+ struct limiter_data *limiter_data = __log_limiter_create(&conf);
+ assert(limiter_data);
+ __log_limiter_update(limiter_data, &conf);
-#define PASS assert(__log_limiter_pass_log("FOO", 'W').decision == DECISION_ALLOWED)
-#define MSG assert(__log_limiter_pass_log("FOO", 'W').decision == DECISION_PID_LIMIT_EXCEEDED_MESSAGE)
-#define BLOCK assert(__log_limiter_pass_log("FOO", 'W').decision == DECISION_DENIED)
+#define PASS assert(__log_limiter_pass_log(limiter_data, "FOO", 'W').decision == DECISION_ALLOWED)
+#define MSG assert(__log_limiter_pass_log(limiter_data, "FOO", 'W').decision == DECISION_PID_LIMIT_EXCEEDED_MESSAGE)
+#define BLOCK assert(__log_limiter_pass_log(limiter_data, "FOO", 'W').decision == DECISION_DENIED)
pid_ret = 77;
for (int i = 0; i < 7; ++i) PASS;
for (int i = 7; i < 8; ++i) MSG;
for (int i = 8; i < 100; ++i) BLOCK;
- __log_limiter_update(&conf); // shouldn't have any effect
+ __log_limiter_update(limiter_data, &conf); // shouldn't have any effect
for (int i = 100; i < 200; ++i) BLOCK;
advance_clock();
for (int i = 126; i < 333; ++i) BLOCK;
log_config_remove(&conf, "pidlimit|55");
- __log_limiter_update(&conf);
+ __log_limiter_update(limiter_data, &conf);
advance_clock();
for (int i = 0; i < 1936; ++i) PASS;
#undef BLOCK
#undef PASS
- __log_limiter_destroy();
+ __log_limiter_destroy(limiter_data);
}