Line data Source code
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 32 : rate_limit_is_ready(ratelim_t *lim, time_t now) 23 : { 24 32 : if (lim->rate + lim->last_allowed <= now) { 25 18 : int res = lim->n_calls_since_last_time + 1; 26 18 : lim->last_allowed = now; 27 18 : lim->n_calls_since_last_time = 0; 28 18 : return res; 29 : } else { 30 14 : if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { 31 14 : ++lim->n_calls_since_last_time; 32 : } 33 : 34 14 : 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 32 : rate_limit_log(ratelim_t *lim, time_t now) 43 : { 44 32 : int n; 45 32 : if ((n = rate_limit_is_ready(lim, now))) { 46 18 : time_t started_limiting = lim->started_limiting; 47 18 : lim->started_limiting = 0; 48 18 : if (n == 1) { 49 15 : return tor_strdup(""); 50 : } else { 51 3 : char *cp=NULL; 52 3 : const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; 53 3 : unsigned difference = (unsigned)(now - started_limiting); 54 3 : difference = round_to_next_multiple_of(difference, 60); 55 3 : tor_asprintf(&cp, 56 : " [%s%d similar message(s) suppressed in last %d seconds]", 57 : opt_over, n-1, (int)difference); 58 3 : return cp; 59 : } 60 : } else { 61 14 : if (lim->started_limiting == 0) { 62 5 : lim->started_limiting = now; 63 : } 64 14 : return NULL; 65 : } 66 : }