diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index ea1f420f7216a1b344c484ddf67f8874dd34d689..b2a218328212e2778d74a32cd765fec7e777e9d5 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 8e60b448ec912121a5bd734cfc86844cfb41724d..1a767b29525fb3d9619cd83b9e9ae564fad059aa 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 b9b60f5d4b90dafe5b6268e6faba91e61b3d0eec..ead6029fbcebc4867e9527cf7ce5169f44a0e4f5 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 df8928c9a4b1fecba3e787f88979a417853e30a6..e90f6da6eb7827f5027949d8b62ba4badc3c18af 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 db1c246ab36e379704388ab7f3e165c5c2647105..b93ad560e4f78a61607095801b7bbd3b5f2a0dac 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 3cbf2771e4d723953be0cd316bc9fb01b0b47375..16bbffc54d5c3c99dd38baa0ec8e88fbe4d3bfbb 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