+/*** Type sets ***/
+
+static uns
+log_type_mask(clist *l)
+{
+ if (clist_empty(l))
+ return ~0U;
+
+ uns types = 0;
+ CLIST_FOR_EACH(simp_node *, s, *l)
+ if (!strcmp(s->s, "all"))
+ return ~0U;
+ else
+ {
+ /*
+ * We intentionally ignore unknown types as not all types are known
+ * to all programs sharing a common configuration file. This is also
+ * the reason why Types is a list and not a bitmap.
+ */
+ int type = log_find_type(s->s);
+ if (type >= 0)
+ types |= 1 << LS_GET_TYPE(type);
+ }
+ return types;
+}
+
+/*** Generating limiters ***/
+
+/*
+ * When limiting is enabled, we let log_stream->filter point to this function
+ * and log_stream->user_data point to an array of pointers to token bucket
+ * filters for individual message types.
+ */
+static int
+log_limiter(struct log_stream *ls, struct log_msg *m)
+{
+ struct token_bucket_filter **limits = ls->user_data;
+ if (!limits)
+ return 0;
+ struct token_bucket_filter *tbf = limits[LS_GET_TYPE(m->flags)];
+ if (!tbf)
+ return 0;
+
+ ASSERT(!(m->flags & L_SIGHANDLER));
+ if (m->flags & L_LOGGER_ERR)
+ return 0;
+
+ timestamp_t now = ((timestamp_t) m->tv->tv_sec * 1000) + (m->tv->tv_usec / 1000);
+ ucwlib_lock();
+ int res = tbf_limit(tbf, now);
+ ucwlib_unlock();
+
+ if (res < 0)
+ {
+ if (res == -1)
+ {
+ struct log_msg mm = *m;
+ mm.flags |= L_LOGGER_ERR;
+ mm.raw_msg = "(maximum logging rate exceeded, some messages will be suppressed)";
+ log_pass_msg(0, ls, &mm);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static void
+log_apply_limits(struct log_stream *ls, struct limit_config *lim)
+{
+ uns mask = log_type_mask(&lim->types);
+ if (!mask)
+ return;
+
+ if (!ls->user_data)
+ {
+ ls->user_data = cf_malloc_zero(LS_NUM_TYPES * sizeof(struct token_bucket_filter *));
+ ls->filter = log_limiter;
+ }
+ struct token_bucket_filter **limits = ls->user_data;
+ struct token_bucket_filter *tbf = cf_malloc_zero(sizeof(*lim));
+ tbf->rate = lim->rate;
+ tbf->burst = lim->burst;
+ tbf_init(tbf);
+
+ for (uns i=0; i < LS_NUM_TYPES; i++)
+ if (mask & (1 << i))
+ limits[i] = tbf;
+}
+
+/*** Generating streams ***/
+