ratelim.c (2099B)
1 /* Copyright (c) 2003-2004, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * \file ratelim.c 8 * \brief Summarize similar messages that would otherwise flood the logs. 9 **/ 10 11 #include "lib/log/ratelim.h" 12 #include "lib/malloc/malloc.h" 13 #include "lib/string/printf.h" 14 #include "lib/intmath/muldiv.h" 15 16 /** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number 17 * of calls to rate_limit_is_ready (including this one!) since the last time 18 * rate_limit_is_ready returned nonzero. Otherwise return 0. 19 * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning 20 * about this event and stop counting. */ 21 static int 22 rate_limit_is_ready(ratelim_t *lim, time_t now) 23 { 24 if (lim->rate + lim->last_allowed <= now) { 25 int res = lim->n_calls_since_last_time + 1; 26 lim->last_allowed = now; 27 lim->n_calls_since_last_time = 0; 28 return res; 29 } else { 30 if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { 31 ++lim->n_calls_since_last_time; 32 } 33 34 return 0; 35 } 36 } 37 38 /** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly 39 * allocated string indicating how many messages were suppressed, suitable to 40 * append to a log message. Otherwise return NULL. */ 41 char * 42 rate_limit_log(ratelim_t *lim, time_t now) 43 { 44 int n; 45 if ((n = rate_limit_is_ready(lim, now))) { 46 time_t started_limiting = lim->started_limiting; 47 lim->started_limiting = 0; 48 if (n == 1) { 49 return tor_strdup(""); 50 } else { 51 char *cp=NULL; 52 const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; 53 unsigned difference = (unsigned)(now - started_limiting); 54 difference = round_to_next_multiple_of(difference, 60); 55 tor_asprintf(&cp, 56 " [%s%d similar message(s) suppressed in last %d seconds]", 57 opt_over, n-1, (int)difference); 58 return cp; 59 } 60 } else { 61 if (lim->started_limiting == 0) { 62 lim->started_limiting = now; 63 } 64 return NULL; 65 } 66 }