libevent/ratelim-internal.h
Nick Mathewson 0bffe43a15 Fix a nasty dangling-event bug when using rate-limiting groups
When we freed a bufferevent that was in a rate-limiting group and
blocked on IO, the process of freeing it caused it to get removed
from the group.  But removing the bufferevent from the group made
its limits get removed, which could make it get un-suspended and in
turn cause its events to get re-added.  Since we would then
immediately _free_ the events, this would result in dangling
pointers.

Fixes bug 3041007.
2010-08-09 12:08:40 -04:00

106 lines
4.0 KiB
C

/*
* Copyright (c) 2009-2010 Niels Provos and Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _RATELIM_INTERNAL_H_
#define _RATELIM_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/util.h>
/** A token bucket is an internal structure that tracks how many bytes we are
* currently willing to read or write on a given bufferevent or group of
* bufferevents */
struct ev_token_bucket {
/** How many bytes are we willing to read or write right now? These
* values are signed so that we can do "defecit spending" */
ev_int32_t read_limit, write_limit;
/** When was this bucket last updated? Measured in abstract 'ticks'
* relative to the token bucket configuration. */
ev_uint32_t last_updated;
};
/** Configuration info for a token bucket or set of token buckets. */
struct ev_token_bucket_cfg {
/** How many bytes are we willing to read on average per tick? */
ev_uint32_t read_rate;
/** How many bytes are we willing to read at most in any one tick? */
ev_uint32_t read_maximum;
/** How many bytes are we willing to write on average per tick? */
ev_uint32_t write_rate;
/** How many bytes are we willing to write at most in any one tick? */
ev_uint32_t write_maximum;
/* How long is a tick? Note that fractions of a millisecond are
* ignored. */
struct timeval tick_timeout;
/* How long is a tick, in milliseconds? Derived from tick_timeout. */
unsigned msec_per_tick;
};
/** The current tick is 'current_tick': add bytes to 'bucket' as specified in
* 'cfg'. */
int ev_token_bucket_update(struct ev_token_bucket *bucket,
const struct ev_token_bucket_cfg *cfg,
ev_uint32_t current_tick);
/** In which tick does 'tv' fall according to 'cfg'? Note that ticks can
* overflow easily; your code needs to handle this. */
ev_uint32_t ev_token_bucket_get_tick(const struct timeval *tv,
const struct ev_token_bucket_cfg *cfg);
/** Adjust 'bucket' to respect 'cfg', and note that it was last updated in
* 'current_tick'. If 'reinitialize' is true, we are changing the
* configuration of 'bucket'; otherwise, we are setting it up for the first
* time.
*/
int ev_token_bucket_init(struct ev_token_bucket *bucket,
const struct ev_token_bucket_cfg *cfg,
ev_uint32_t current_tick,
int reinitialize);
int bufferevent_remove_from_rate_limit_group_internal(struct bufferevent *bev,
int unsuspend);
/** Decrease the read limit of 'b' by 'n' bytes */
#define ev_token_bucket_decrement_read(b,n) \
do { \
(b)->read_limit -= (n); \
} while (0)
/** Decrease the write limit of 'b' by 'n' bytes */
#define ev_token_bucket_decrement_write(b,n) \
do { \
(b)->write_limit -= (n); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif