From 77d56fd5def6f0138ca18a1b309bb59a18f6ccd6 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan.bosch@open-xchange.com> Date: Thu, 3 Dec 2020 03:36:06 +0100 Subject: [PATCH] lib-sieve: sieve - Add API for resource usage manipulation and evaluation. --- src/lib-sieve/sieve-common.h | 3 +-- src/lib-sieve/sieve-limits.h | 1 + src/lib-sieve/sieve-settings.c | 4 ++-- src/lib-sieve/sieve-types.h | 10 ++++++++ src/lib-sieve/sieve.c | 42 ++++++++++++++++++++++++++++++++++ src/lib-sieve/sieve.h | 27 ++++++++++++++++++++++ 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index ea1f420f7..b2a218328 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -3,8 +3,7 @@ #include "lib.h" -#include "sieve-config.h" -#include "sieve-types.h" +#include "sieve.h" #include <sys/types.h> diff --git a/src/lib-sieve/sieve-limits.h b/src/lib-sieve/sieve-limits.h index 8e60b448e..1a767b295 100644 --- a/src/lib-sieve/sieve-limits.h +++ b/src/lib-sieve/sieve-limits.h @@ -31,6 +31,7 @@ */ #define SIEVE_MAX_MATCH_VALUES 32 +#define SIEVE_HIGH_CPU_TIME_MSECS 1500 #define SIEVE_DEFAULT_MAX_CPU_TIME_SECS 30 /* diff --git a/src/lib-sieve/sieve-settings.c b/src/lib-sieve/sieve-settings.c index b9b60f5d4..ead6029fb 100644 --- a/src/lib-sieve/sieve-settings.c +++ b/src/lib-sieve/sieve-settings.c @@ -219,8 +219,8 @@ void sieve_settings_load(struct sieve_instance *svinst) svinst->max_cpu_time_secs = SIEVE_DEFAULT_MAX_CPU_TIME_SECS; if (sieve_setting_get_duration_value(svinst, "sieve_max_cpu_time", &period)) { - if (period > UINT_MAX) - svinst->max_cpu_time_secs = UINT_MAX; + if (period > (UINT_MAX / 1000)) + svinst->max_cpu_time_secs = (UINT_MAX / 1000); else svinst->max_cpu_time_secs = (unsigned int)period; } diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index df8928c9a..e90f6da6e 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -256,6 +256,16 @@ struct sieve_script_env { #define SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) \ (senv->default_mailbox == NULL ? "INBOX" : senv->default_mailbox ) +/* + * Resource usage + */ + +struct sieve_resource_usage { + /* The total amount of system + user CPU time consumed while executing + the Sieve script. */ + unsigned int cpu_time_msecs; +}; + /* * Script execution status */ diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index db1c246ab..b93ad560e 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -33,6 +33,7 @@ #include "sieve.h" #include "sieve-common.h" +#include "sieve-limits.h" #include "sieve-error-private.h" #include <sys/types.h> @@ -1181,3 +1182,44 @@ const char *sieve_get_postmaster_address(const struct sieve_script_env *senv) message_address_write(addr, postmaster); return str_c(addr); } + +/* + * Resource usage + */ + +void sieve_resource_usage_init(struct sieve_resource_usage *rusage_r) +{ + i_zero(rusage_r); +} + +void sieve_resource_usage_add(struct sieve_resource_usage *dst, + const struct sieve_resource_usage *src) +{ + if ((UINT_MAX - dst->cpu_time_msecs) < src->cpu_time_msecs) + dst->cpu_time_msecs = UINT_MAX; + else + dst->cpu_time_msecs += src->cpu_time_msecs; +} + +bool sieve_resource_usage_is_high(struct sieve_instance *svinst ATTR_UNUSED, + const struct sieve_resource_usage *rusage) +{ + return (rusage->cpu_time_msecs > SIEVE_HIGH_CPU_TIME_MSECS); +} + +bool sieve_resource_usage_is_excessive( + struct sieve_instance *svinst, + const struct sieve_resource_usage *rusage) +{ + i_assert(svinst->max_cpu_time_secs <= (UINT_MAX / 1000)); + return (rusage->cpu_time_msecs > (svinst->max_cpu_time_secs * 1000)); +} + +const char * +sieve_resource_usage_get_summary(const struct sieve_resource_usage *rusage) +{ + if (rusage->cpu_time_msecs == 0) + return "no usage recorded"; + + return t_strdup_printf("cpu time = %u ms", rusage->cpu_time_msecs); +} diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index 3cbf2771e..16bbffc54 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -212,4 +212,31 @@ void sieve_trace_log_free(struct sieve_trace_log **_trace_log); int sieve_trace_config_get(struct sieve_instance *svinst, struct sieve_trace_config *tr_config); +/* + * Resource usage + */ + +/* Initialize the resource usage struct, clearing all usage statistics. */ +void sieve_resource_usage_init(struct sieve_resource_usage *rusage_r); + +/* Calculate the sum of the provided resource usage statistics, writing the + result to the first. */ +void sieve_resource_usage_add(struct sieve_resource_usage *dst, + const struct sieve_resource_usage *src); + +/* Returns TRUE if the resource usage is sufficiently high to warrant recording + for checking cumulative resource limits (across several different script + executions). */ +bool sieve_resource_usage_is_high(struct sieve_instance *svinst, + const struct sieve_resource_usage *rusage); +/* Returns TRUE when the provided resource usage statistics exceed a configured + policy limit. */ +bool sieve_resource_usage_is_excessive( + struct sieve_instance *svinst, + const struct sieve_resource_usage *rusage); +/* Returns a string containing a description of the resource usage (to be used + log messages). */ +const char * +sieve_resource_usage_get_summary(const struct sieve_resource_usage *rusage); + #endif -- GitLab