xref: /aosp_15_r20/external/libevent/bufferevent_ratelim.c (revision 663afb9b963571284e0f0a60f257164ab54f64bf)
1*663afb9bSAndroid Build Coastguard Worker /*
2*663afb9bSAndroid Build Coastguard Worker  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
3*663afb9bSAndroid Build Coastguard Worker  * Copyright (c) 2002-2006 Niels Provos <[email protected]>
4*663afb9bSAndroid Build Coastguard Worker  * All rights reserved.
5*663afb9bSAndroid Build Coastguard Worker  *
6*663afb9bSAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
7*663afb9bSAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
8*663afb9bSAndroid Build Coastguard Worker  * are met:
9*663afb9bSAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
10*663afb9bSAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
11*663afb9bSAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
12*663afb9bSAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
13*663afb9bSAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
14*663afb9bSAndroid Build Coastguard Worker  * 3. The name of the author may not be used to endorse or promote products
15*663afb9bSAndroid Build Coastguard Worker  *    derived from this software without specific prior written permission.
16*663afb9bSAndroid Build Coastguard Worker  *
17*663afb9bSAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*663afb9bSAndroid Build Coastguard Worker  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*663afb9bSAndroid Build Coastguard Worker  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*663afb9bSAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*663afb9bSAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*663afb9bSAndroid Build Coastguard Worker  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*663afb9bSAndroid Build Coastguard Worker  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*663afb9bSAndroid Build Coastguard Worker  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*663afb9bSAndroid Build Coastguard Worker  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*663afb9bSAndroid Build Coastguard Worker  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*663afb9bSAndroid Build Coastguard Worker  */
28*663afb9bSAndroid Build Coastguard Worker #include "evconfig-private.h"
29*663afb9bSAndroid Build Coastguard Worker 
30*663afb9bSAndroid Build Coastguard Worker #include <sys/types.h>
31*663afb9bSAndroid Build Coastguard Worker #include <limits.h>
32*663afb9bSAndroid Build Coastguard Worker #include <string.h>
33*663afb9bSAndroid Build Coastguard Worker #include <stdlib.h>
34*663afb9bSAndroid Build Coastguard Worker 
35*663afb9bSAndroid Build Coastguard Worker #include "event2/event.h"
36*663afb9bSAndroid Build Coastguard Worker #include "event2/event_struct.h"
37*663afb9bSAndroid Build Coastguard Worker #include "event2/util.h"
38*663afb9bSAndroid Build Coastguard Worker #include "event2/bufferevent.h"
39*663afb9bSAndroid Build Coastguard Worker #include "event2/bufferevent_struct.h"
40*663afb9bSAndroid Build Coastguard Worker #include "event2/buffer.h"
41*663afb9bSAndroid Build Coastguard Worker 
42*663afb9bSAndroid Build Coastguard Worker #include "ratelim-internal.h"
43*663afb9bSAndroid Build Coastguard Worker 
44*663afb9bSAndroid Build Coastguard Worker #include "bufferevent-internal.h"
45*663afb9bSAndroid Build Coastguard Worker #include "mm-internal.h"
46*663afb9bSAndroid Build Coastguard Worker #include "util-internal.h"
47*663afb9bSAndroid Build Coastguard Worker #include "event-internal.h"
48*663afb9bSAndroid Build Coastguard Worker 
49*663afb9bSAndroid Build Coastguard Worker int
ev_token_bucket_init_(struct ev_token_bucket * bucket,const struct ev_token_bucket_cfg * cfg,ev_uint32_t current_tick,int reinitialize)50*663afb9bSAndroid Build Coastguard Worker ev_token_bucket_init_(struct ev_token_bucket *bucket,
51*663afb9bSAndroid Build Coastguard Worker     const struct ev_token_bucket_cfg *cfg,
52*663afb9bSAndroid Build Coastguard Worker     ev_uint32_t current_tick,
53*663afb9bSAndroid Build Coastguard Worker     int reinitialize)
54*663afb9bSAndroid Build Coastguard Worker {
55*663afb9bSAndroid Build Coastguard Worker 	if (reinitialize) {
56*663afb9bSAndroid Build Coastguard Worker 		/* on reinitialization, we only clip downwards, since we've
57*663afb9bSAndroid Build Coastguard Worker 		   already used who-knows-how-much bandwidth this tick.  We
58*663afb9bSAndroid Build Coastguard Worker 		   leave "last_updated" as it is; the next update will add the
59*663afb9bSAndroid Build Coastguard Worker 		   appropriate amount of bandwidth to the bucket.
60*663afb9bSAndroid Build Coastguard Worker 		*/
61*663afb9bSAndroid Build Coastguard Worker 		if (bucket->read_limit > (ev_int64_t) cfg->read_maximum)
62*663afb9bSAndroid Build Coastguard Worker 			bucket->read_limit = cfg->read_maximum;
63*663afb9bSAndroid Build Coastguard Worker 		if (bucket->write_limit > (ev_int64_t) cfg->write_maximum)
64*663afb9bSAndroid Build Coastguard Worker 			bucket->write_limit = cfg->write_maximum;
65*663afb9bSAndroid Build Coastguard Worker 	} else {
66*663afb9bSAndroid Build Coastguard Worker 		bucket->read_limit = cfg->read_rate;
67*663afb9bSAndroid Build Coastguard Worker 		bucket->write_limit = cfg->write_rate;
68*663afb9bSAndroid Build Coastguard Worker 		bucket->last_updated = current_tick;
69*663afb9bSAndroid Build Coastguard Worker 	}
70*663afb9bSAndroid Build Coastguard Worker 	return 0;
71*663afb9bSAndroid Build Coastguard Worker }
72*663afb9bSAndroid Build Coastguard Worker 
73*663afb9bSAndroid Build Coastguard Worker int
ev_token_bucket_update_(struct ev_token_bucket * bucket,const struct ev_token_bucket_cfg * cfg,ev_uint32_t current_tick)74*663afb9bSAndroid Build Coastguard Worker ev_token_bucket_update_(struct ev_token_bucket *bucket,
75*663afb9bSAndroid Build Coastguard Worker     const struct ev_token_bucket_cfg *cfg,
76*663afb9bSAndroid Build Coastguard Worker     ev_uint32_t current_tick)
77*663afb9bSAndroid Build Coastguard Worker {
78*663afb9bSAndroid Build Coastguard Worker 	/* It's okay if the tick number overflows, since we'll just
79*663afb9bSAndroid Build Coastguard Worker 	 * wrap around when we do the unsigned substraction. */
80*663afb9bSAndroid Build Coastguard Worker 	unsigned n_ticks = current_tick - bucket->last_updated;
81*663afb9bSAndroid Build Coastguard Worker 
82*663afb9bSAndroid Build Coastguard Worker 	/* Make sure some ticks actually happened, and that time didn't
83*663afb9bSAndroid Build Coastguard Worker 	 * roll back. */
84*663afb9bSAndroid Build Coastguard Worker 	if (n_ticks == 0 || n_ticks > INT_MAX)
85*663afb9bSAndroid Build Coastguard Worker 		return 0;
86*663afb9bSAndroid Build Coastguard Worker 
87*663afb9bSAndroid Build Coastguard Worker 	/* Naively, we would say
88*663afb9bSAndroid Build Coastguard Worker 		bucket->limit += n_ticks * cfg->rate;
89*663afb9bSAndroid Build Coastguard Worker 
90*663afb9bSAndroid Build Coastguard Worker 		if (bucket->limit > cfg->maximum)
91*663afb9bSAndroid Build Coastguard Worker 			bucket->limit = cfg->maximum;
92*663afb9bSAndroid Build Coastguard Worker 
93*663afb9bSAndroid Build Coastguard Worker 	   But we're worried about overflow, so we do it like this:
94*663afb9bSAndroid Build Coastguard Worker 	*/
95*663afb9bSAndroid Build Coastguard Worker 
96*663afb9bSAndroid Build Coastguard Worker 	if ((cfg->read_maximum - bucket->read_limit) / n_ticks < cfg->read_rate)
97*663afb9bSAndroid Build Coastguard Worker 		bucket->read_limit = cfg->read_maximum;
98*663afb9bSAndroid Build Coastguard Worker 	else
99*663afb9bSAndroid Build Coastguard Worker 		bucket->read_limit += n_ticks * cfg->read_rate;
100*663afb9bSAndroid Build Coastguard Worker 
101*663afb9bSAndroid Build Coastguard Worker 
102*663afb9bSAndroid Build Coastguard Worker 	if ((cfg->write_maximum - bucket->write_limit) / n_ticks < cfg->write_rate)
103*663afb9bSAndroid Build Coastguard Worker 		bucket->write_limit = cfg->write_maximum;
104*663afb9bSAndroid Build Coastguard Worker 	else
105*663afb9bSAndroid Build Coastguard Worker 		bucket->write_limit += n_ticks * cfg->write_rate;
106*663afb9bSAndroid Build Coastguard Worker 
107*663afb9bSAndroid Build Coastguard Worker 
108*663afb9bSAndroid Build Coastguard Worker 	bucket->last_updated = current_tick;
109*663afb9bSAndroid Build Coastguard Worker 
110*663afb9bSAndroid Build Coastguard Worker 	return 1;
111*663afb9bSAndroid Build Coastguard Worker }
112*663afb9bSAndroid Build Coastguard Worker 
113*663afb9bSAndroid Build Coastguard Worker static inline void
bufferevent_update_buckets(struct bufferevent_private * bev)114*663afb9bSAndroid Build Coastguard Worker bufferevent_update_buckets(struct bufferevent_private *bev)
115*663afb9bSAndroid Build Coastguard Worker {
116*663afb9bSAndroid Build Coastguard Worker 	/* Must hold lock on bev. */
117*663afb9bSAndroid Build Coastguard Worker 	struct timeval now;
118*663afb9bSAndroid Build Coastguard Worker 	unsigned tick;
119*663afb9bSAndroid Build Coastguard Worker 	event_base_gettimeofday_cached(bev->bev.ev_base, &now);
120*663afb9bSAndroid Build Coastguard Worker 	tick = ev_token_bucket_get_tick_(&now, bev->rate_limiting->cfg);
121*663afb9bSAndroid Build Coastguard Worker 	if (tick != bev->rate_limiting->limit.last_updated)
122*663afb9bSAndroid Build Coastguard Worker 		ev_token_bucket_update_(&bev->rate_limiting->limit,
123*663afb9bSAndroid Build Coastguard Worker 		    bev->rate_limiting->cfg, tick);
124*663afb9bSAndroid Build Coastguard Worker }
125*663afb9bSAndroid Build Coastguard Worker 
126*663afb9bSAndroid Build Coastguard Worker ev_uint32_t
ev_token_bucket_get_tick_(const struct timeval * tv,const struct ev_token_bucket_cfg * cfg)127*663afb9bSAndroid Build Coastguard Worker ev_token_bucket_get_tick_(const struct timeval *tv,
128*663afb9bSAndroid Build Coastguard Worker     const struct ev_token_bucket_cfg *cfg)
129*663afb9bSAndroid Build Coastguard Worker {
130*663afb9bSAndroid Build Coastguard Worker 	/* This computation uses two multiplies and a divide.  We could do
131*663afb9bSAndroid Build Coastguard Worker 	 * fewer if we knew that the tick length was an integer number of
132*663afb9bSAndroid Build Coastguard Worker 	 * seconds, or if we knew it divided evenly into a second.  We should
133*663afb9bSAndroid Build Coastguard Worker 	 * investigate that more.
134*663afb9bSAndroid Build Coastguard Worker 	 */
135*663afb9bSAndroid Build Coastguard Worker 
136*663afb9bSAndroid Build Coastguard Worker 	/* We cast to an ev_uint64_t first, since we don't want to overflow
137*663afb9bSAndroid Build Coastguard Worker 	 * before we do the final divide. */
138*663afb9bSAndroid Build Coastguard Worker 	ev_uint64_t msec = (ev_uint64_t)tv->tv_sec * 1000 + tv->tv_usec / 1000;
139*663afb9bSAndroid Build Coastguard Worker 	return (unsigned)(msec / cfg->msec_per_tick);
140*663afb9bSAndroid Build Coastguard Worker }
141*663afb9bSAndroid Build Coastguard Worker 
142*663afb9bSAndroid Build Coastguard Worker struct ev_token_bucket_cfg *
ev_token_bucket_cfg_new(size_t read_rate,size_t read_burst,size_t write_rate,size_t write_burst,const struct timeval * tick_len)143*663afb9bSAndroid Build Coastguard Worker ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst,
144*663afb9bSAndroid Build Coastguard Worker     size_t write_rate, size_t write_burst,
145*663afb9bSAndroid Build Coastguard Worker     const struct timeval *tick_len)
146*663afb9bSAndroid Build Coastguard Worker {
147*663afb9bSAndroid Build Coastguard Worker 	struct ev_token_bucket_cfg *r;
148*663afb9bSAndroid Build Coastguard Worker 	struct timeval g;
149*663afb9bSAndroid Build Coastguard Worker 	if (! tick_len) {
150*663afb9bSAndroid Build Coastguard Worker 		g.tv_sec = 1;
151*663afb9bSAndroid Build Coastguard Worker 		g.tv_usec = 0;
152*663afb9bSAndroid Build Coastguard Worker 		tick_len = &g;
153*663afb9bSAndroid Build Coastguard Worker 	}
154*663afb9bSAndroid Build Coastguard Worker 	if (read_rate > read_burst || write_rate > write_burst ||
155*663afb9bSAndroid Build Coastguard Worker 	    read_rate < 1 || write_rate < 1)
156*663afb9bSAndroid Build Coastguard Worker 		return NULL;
157*663afb9bSAndroid Build Coastguard Worker 	if (read_rate > EV_RATE_LIMIT_MAX ||
158*663afb9bSAndroid Build Coastguard Worker 	    write_rate > EV_RATE_LIMIT_MAX ||
159*663afb9bSAndroid Build Coastguard Worker 	    read_burst > EV_RATE_LIMIT_MAX ||
160*663afb9bSAndroid Build Coastguard Worker 	    write_burst > EV_RATE_LIMIT_MAX)
161*663afb9bSAndroid Build Coastguard Worker 		return NULL;
162*663afb9bSAndroid Build Coastguard Worker 	r = mm_calloc(1, sizeof(struct ev_token_bucket_cfg));
163*663afb9bSAndroid Build Coastguard Worker 	if (!r)
164*663afb9bSAndroid Build Coastguard Worker 		return NULL;
165*663afb9bSAndroid Build Coastguard Worker 	r->read_rate = read_rate;
166*663afb9bSAndroid Build Coastguard Worker 	r->write_rate = write_rate;
167*663afb9bSAndroid Build Coastguard Worker 	r->read_maximum = read_burst;
168*663afb9bSAndroid Build Coastguard Worker 	r->write_maximum = write_burst;
169*663afb9bSAndroid Build Coastguard Worker 	memcpy(&r->tick_timeout, tick_len, sizeof(struct timeval));
170*663afb9bSAndroid Build Coastguard Worker 	r->msec_per_tick = (tick_len->tv_sec * 1000) +
171*663afb9bSAndroid Build Coastguard Worker 	    (tick_len->tv_usec & COMMON_TIMEOUT_MICROSECONDS_MASK)/1000;
172*663afb9bSAndroid Build Coastguard Worker 	return r;
173*663afb9bSAndroid Build Coastguard Worker }
174*663afb9bSAndroid Build Coastguard Worker 
175*663afb9bSAndroid Build Coastguard Worker void
ev_token_bucket_cfg_free(struct ev_token_bucket_cfg * cfg)176*663afb9bSAndroid Build Coastguard Worker ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg)
177*663afb9bSAndroid Build Coastguard Worker {
178*663afb9bSAndroid Build Coastguard Worker 	mm_free(cfg);
179*663afb9bSAndroid Build Coastguard Worker }
180*663afb9bSAndroid Build Coastguard Worker 
181*663afb9bSAndroid Build Coastguard Worker /* Default values for max_single_read & max_single_write variables. */
182*663afb9bSAndroid Build Coastguard Worker #define MAX_SINGLE_READ_DEFAULT 16384
183*663afb9bSAndroid Build Coastguard Worker #define MAX_SINGLE_WRITE_DEFAULT 16384
184*663afb9bSAndroid Build Coastguard Worker 
185*663afb9bSAndroid Build Coastguard Worker #define LOCK_GROUP(g) EVLOCK_LOCK((g)->lock, 0)
186*663afb9bSAndroid Build Coastguard Worker #define UNLOCK_GROUP(g) EVLOCK_UNLOCK((g)->lock, 0)
187*663afb9bSAndroid Build Coastguard Worker 
188*663afb9bSAndroid Build Coastguard Worker static int bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g);
189*663afb9bSAndroid Build Coastguard Worker static int bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g);
190*663afb9bSAndroid Build Coastguard Worker static void bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g);
191*663afb9bSAndroid Build Coastguard Worker static void bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g);
192*663afb9bSAndroid Build Coastguard Worker 
193*663afb9bSAndroid Build Coastguard Worker /** Helper: figure out the maximum amount we should write if is_write, or
194*663afb9bSAndroid Build Coastguard Worker     the maximum amount we should read if is_read.  Return that maximum, or
195*663afb9bSAndroid Build Coastguard Worker     0 if our bucket is wholly exhausted.
196*663afb9bSAndroid Build Coastguard Worker  */
197*663afb9bSAndroid Build Coastguard Worker static inline ev_ssize_t
bufferevent_get_rlim_max_(struct bufferevent_private * bev,int is_write)198*663afb9bSAndroid Build Coastguard Worker bufferevent_get_rlim_max_(struct bufferevent_private *bev, int is_write)
199*663afb9bSAndroid Build Coastguard Worker {
200*663afb9bSAndroid Build Coastguard Worker 	/* needs lock on bev. */
201*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t max_so_far = is_write?bev->max_single_write:bev->max_single_read;
202*663afb9bSAndroid Build Coastguard Worker 
203*663afb9bSAndroid Build Coastguard Worker #define LIM(x)						\
204*663afb9bSAndroid Build Coastguard Worker 	(is_write ? (x).write_limit : (x).read_limit)
205*663afb9bSAndroid Build Coastguard Worker 
206*663afb9bSAndroid Build Coastguard Worker #define GROUP_SUSPENDED(g)			\
207*663afb9bSAndroid Build Coastguard Worker 	(is_write ? (g)->write_suspended : (g)->read_suspended)
208*663afb9bSAndroid Build Coastguard Worker 
209*663afb9bSAndroid Build Coastguard Worker 	/* Sets max_so_far to MIN(x, max_so_far) */
210*663afb9bSAndroid Build Coastguard Worker #define CLAMPTO(x)				\
211*663afb9bSAndroid Build Coastguard Worker 	do {					\
212*663afb9bSAndroid Build Coastguard Worker 		if (max_so_far > (x))		\
213*663afb9bSAndroid Build Coastguard Worker 			max_so_far = (x);	\
214*663afb9bSAndroid Build Coastguard Worker 	} while (0);
215*663afb9bSAndroid Build Coastguard Worker 
216*663afb9bSAndroid Build Coastguard Worker 	if (!bev->rate_limiting)
217*663afb9bSAndroid Build Coastguard Worker 		return max_so_far;
218*663afb9bSAndroid Build Coastguard Worker 
219*663afb9bSAndroid Build Coastguard Worker 	/* If rate-limiting is enabled at all, update the appropriate
220*663afb9bSAndroid Build Coastguard Worker 	   bucket, and take the smaller of our rate limit and the group
221*663afb9bSAndroid Build Coastguard Worker 	   rate limit.
222*663afb9bSAndroid Build Coastguard Worker 	 */
223*663afb9bSAndroid Build Coastguard Worker 
224*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->cfg) {
225*663afb9bSAndroid Build Coastguard Worker 		bufferevent_update_buckets(bev);
226*663afb9bSAndroid Build Coastguard Worker 		max_so_far = LIM(bev->rate_limiting->limit);
227*663afb9bSAndroid Build Coastguard Worker 	}
228*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->group) {
229*663afb9bSAndroid Build Coastguard Worker 		struct bufferevent_rate_limit_group *g =
230*663afb9bSAndroid Build Coastguard Worker 		    bev->rate_limiting->group;
231*663afb9bSAndroid Build Coastguard Worker 		ev_ssize_t share;
232*663afb9bSAndroid Build Coastguard Worker 		LOCK_GROUP(g);
233*663afb9bSAndroid Build Coastguard Worker 		if (GROUP_SUSPENDED(g)) {
234*663afb9bSAndroid Build Coastguard Worker 			/* We can get here if we failed to lock this
235*663afb9bSAndroid Build Coastguard Worker 			 * particular bufferevent while suspending the whole
236*663afb9bSAndroid Build Coastguard Worker 			 * group. */
237*663afb9bSAndroid Build Coastguard Worker 			if (is_write)
238*663afb9bSAndroid Build Coastguard Worker 				bufferevent_suspend_write_(&bev->bev,
239*663afb9bSAndroid Build Coastguard Worker 				    BEV_SUSPEND_BW_GROUP);
240*663afb9bSAndroid Build Coastguard Worker 			else
241*663afb9bSAndroid Build Coastguard Worker 				bufferevent_suspend_read_(&bev->bev,
242*663afb9bSAndroid Build Coastguard Worker 				    BEV_SUSPEND_BW_GROUP);
243*663afb9bSAndroid Build Coastguard Worker 			share = 0;
244*663afb9bSAndroid Build Coastguard Worker 		} else {
245*663afb9bSAndroid Build Coastguard Worker 			/* XXXX probably we should divide among the active
246*663afb9bSAndroid Build Coastguard Worker 			 * members, not the total members. */
247*663afb9bSAndroid Build Coastguard Worker 			share = LIM(g->rate_limit) / g->n_members;
248*663afb9bSAndroid Build Coastguard Worker 			if (share < g->min_share)
249*663afb9bSAndroid Build Coastguard Worker 				share = g->min_share;
250*663afb9bSAndroid Build Coastguard Worker 		}
251*663afb9bSAndroid Build Coastguard Worker 		UNLOCK_GROUP(g);
252*663afb9bSAndroid Build Coastguard Worker 		CLAMPTO(share);
253*663afb9bSAndroid Build Coastguard Worker 	}
254*663afb9bSAndroid Build Coastguard Worker 
255*663afb9bSAndroid Build Coastguard Worker 	if (max_so_far < 0)
256*663afb9bSAndroid Build Coastguard Worker 		max_so_far = 0;
257*663afb9bSAndroid Build Coastguard Worker 	return max_so_far;
258*663afb9bSAndroid Build Coastguard Worker }
259*663afb9bSAndroid Build Coastguard Worker 
260*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_read_max_(struct bufferevent_private * bev)261*663afb9bSAndroid Build Coastguard Worker bufferevent_get_read_max_(struct bufferevent_private *bev)
262*663afb9bSAndroid Build Coastguard Worker {
263*663afb9bSAndroid Build Coastguard Worker 	return bufferevent_get_rlim_max_(bev, 0);
264*663afb9bSAndroid Build Coastguard Worker }
265*663afb9bSAndroid Build Coastguard Worker 
266*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_write_max_(struct bufferevent_private * bev)267*663afb9bSAndroid Build Coastguard Worker bufferevent_get_write_max_(struct bufferevent_private *bev)
268*663afb9bSAndroid Build Coastguard Worker {
269*663afb9bSAndroid Build Coastguard Worker 	return bufferevent_get_rlim_max_(bev, 1);
270*663afb9bSAndroid Build Coastguard Worker }
271*663afb9bSAndroid Build Coastguard Worker 
272*663afb9bSAndroid Build Coastguard Worker int
bufferevent_decrement_read_buckets_(struct bufferevent_private * bev,ev_ssize_t bytes)273*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_read_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
274*663afb9bSAndroid Build Coastguard Worker {
275*663afb9bSAndroid Build Coastguard Worker 	/* XXXXX Make sure all users of this function check its return value */
276*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
277*663afb9bSAndroid Build Coastguard Worker 	/* need to hold lock on bev */
278*663afb9bSAndroid Build Coastguard Worker 	if (!bev->rate_limiting)
279*663afb9bSAndroid Build Coastguard Worker 		return 0;
280*663afb9bSAndroid Build Coastguard Worker 
281*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->cfg) {
282*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->limit.read_limit -= bytes;
283*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->limit.read_limit <= 0) {
284*663afb9bSAndroid Build Coastguard Worker 			bufferevent_suspend_read_(&bev->bev, BEV_SUSPEND_BW);
285*663afb9bSAndroid Build Coastguard Worker 			if (event_add(&bev->rate_limiting->refill_bucket_event,
286*663afb9bSAndroid Build Coastguard Worker 				&bev->rate_limiting->cfg->tick_timeout) < 0)
287*663afb9bSAndroid Build Coastguard Worker 				r = -1;
288*663afb9bSAndroid Build Coastguard Worker 		} else if (bev->read_suspended & BEV_SUSPEND_BW) {
289*663afb9bSAndroid Build Coastguard Worker 			if (!(bev->write_suspended & BEV_SUSPEND_BW))
290*663afb9bSAndroid Build Coastguard Worker 				event_del(&bev->rate_limiting->refill_bucket_event);
291*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
292*663afb9bSAndroid Build Coastguard Worker 		}
293*663afb9bSAndroid Build Coastguard Worker 	}
294*663afb9bSAndroid Build Coastguard Worker 
295*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->group) {
296*663afb9bSAndroid Build Coastguard Worker 		LOCK_GROUP(bev->rate_limiting->group);
297*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->group->rate_limit.read_limit -= bytes;
298*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->group->total_read += bytes;
299*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->group->rate_limit.read_limit <= 0) {
300*663afb9bSAndroid Build Coastguard Worker 			bev_group_suspend_reading_(bev->rate_limiting->group);
301*663afb9bSAndroid Build Coastguard Worker 		} else if (bev->rate_limiting->group->read_suspended) {
302*663afb9bSAndroid Build Coastguard Worker 			bev_group_unsuspend_reading_(bev->rate_limiting->group);
303*663afb9bSAndroid Build Coastguard Worker 		}
304*663afb9bSAndroid Build Coastguard Worker 		UNLOCK_GROUP(bev->rate_limiting->group);
305*663afb9bSAndroid Build Coastguard Worker 	}
306*663afb9bSAndroid Build Coastguard Worker 
307*663afb9bSAndroid Build Coastguard Worker 	return r;
308*663afb9bSAndroid Build Coastguard Worker }
309*663afb9bSAndroid Build Coastguard Worker 
310*663afb9bSAndroid Build Coastguard Worker int
bufferevent_decrement_write_buckets_(struct bufferevent_private * bev,ev_ssize_t bytes)311*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_write_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
312*663afb9bSAndroid Build Coastguard Worker {
313*663afb9bSAndroid Build Coastguard Worker 	/* XXXXX Make sure all users of this function check its return value */
314*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
315*663afb9bSAndroid Build Coastguard Worker 	/* need to hold lock */
316*663afb9bSAndroid Build Coastguard Worker 	if (!bev->rate_limiting)
317*663afb9bSAndroid Build Coastguard Worker 		return 0;
318*663afb9bSAndroid Build Coastguard Worker 
319*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->cfg) {
320*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->limit.write_limit -= bytes;
321*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->limit.write_limit <= 0) {
322*663afb9bSAndroid Build Coastguard Worker 			bufferevent_suspend_write_(&bev->bev, BEV_SUSPEND_BW);
323*663afb9bSAndroid Build Coastguard Worker 			if (event_add(&bev->rate_limiting->refill_bucket_event,
324*663afb9bSAndroid Build Coastguard Worker 				&bev->rate_limiting->cfg->tick_timeout) < 0)
325*663afb9bSAndroid Build Coastguard Worker 				r = -1;
326*663afb9bSAndroid Build Coastguard Worker 		} else if (bev->write_suspended & BEV_SUSPEND_BW) {
327*663afb9bSAndroid Build Coastguard Worker 			if (!(bev->read_suspended & BEV_SUSPEND_BW))
328*663afb9bSAndroid Build Coastguard Worker 				event_del(&bev->rate_limiting->refill_bucket_event);
329*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
330*663afb9bSAndroid Build Coastguard Worker 		}
331*663afb9bSAndroid Build Coastguard Worker 	}
332*663afb9bSAndroid Build Coastguard Worker 
333*663afb9bSAndroid Build Coastguard Worker 	if (bev->rate_limiting->group) {
334*663afb9bSAndroid Build Coastguard Worker 		LOCK_GROUP(bev->rate_limiting->group);
335*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->group->rate_limit.write_limit -= bytes;
336*663afb9bSAndroid Build Coastguard Worker 		bev->rate_limiting->group->total_written += bytes;
337*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->group->rate_limit.write_limit <= 0) {
338*663afb9bSAndroid Build Coastguard Worker 			bev_group_suspend_writing_(bev->rate_limiting->group);
339*663afb9bSAndroid Build Coastguard Worker 		} else if (bev->rate_limiting->group->write_suspended) {
340*663afb9bSAndroid Build Coastguard Worker 			bev_group_unsuspend_writing_(bev->rate_limiting->group);
341*663afb9bSAndroid Build Coastguard Worker 		}
342*663afb9bSAndroid Build Coastguard Worker 		UNLOCK_GROUP(bev->rate_limiting->group);
343*663afb9bSAndroid Build Coastguard Worker 	}
344*663afb9bSAndroid Build Coastguard Worker 
345*663afb9bSAndroid Build Coastguard Worker 	return r;
346*663afb9bSAndroid Build Coastguard Worker }
347*663afb9bSAndroid Build Coastguard Worker 
348*663afb9bSAndroid Build Coastguard Worker /** Stop reading on every bufferevent in <b>g</b> */
349*663afb9bSAndroid Build Coastguard Worker static int
bev_group_suspend_reading_(struct bufferevent_rate_limit_group * g)350*663afb9bSAndroid Build Coastguard Worker bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g)
351*663afb9bSAndroid Build Coastguard Worker {
352*663afb9bSAndroid Build Coastguard Worker 	/* Needs group lock */
353*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev;
354*663afb9bSAndroid Build Coastguard Worker 	g->read_suspended = 1;
355*663afb9bSAndroid Build Coastguard Worker 	g->pending_unsuspend_read = 0;
356*663afb9bSAndroid Build Coastguard Worker 
357*663afb9bSAndroid Build Coastguard Worker 	/* Note that in this loop we call EVLOCK_TRY_LOCK_ instead of BEV_LOCK,
358*663afb9bSAndroid Build Coastguard Worker 	   to prevent a deadlock.  (Ordinarily, the group lock nests inside
359*663afb9bSAndroid Build Coastguard Worker 	   the bufferevent locks.  If we are unable to lock any individual
360*663afb9bSAndroid Build Coastguard Worker 	   bufferevent, it will find out later when it looks at its limit
361*663afb9bSAndroid Build Coastguard Worker 	   and sees that its group is suspended.)
362*663afb9bSAndroid Build Coastguard Worker 	*/
363*663afb9bSAndroid Build Coastguard Worker 	LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
364*663afb9bSAndroid Build Coastguard Worker 		if (EVLOCK_TRY_LOCK_(bev->lock)) {
365*663afb9bSAndroid Build Coastguard Worker 			bufferevent_suspend_read_(&bev->bev,
366*663afb9bSAndroid Build Coastguard Worker 			    BEV_SUSPEND_BW_GROUP);
367*663afb9bSAndroid Build Coastguard Worker 			EVLOCK_UNLOCK(bev->lock, 0);
368*663afb9bSAndroid Build Coastguard Worker 		}
369*663afb9bSAndroid Build Coastguard Worker 	}
370*663afb9bSAndroid Build Coastguard Worker 	return 0;
371*663afb9bSAndroid Build Coastguard Worker }
372*663afb9bSAndroid Build Coastguard Worker 
373*663afb9bSAndroid Build Coastguard Worker /** Stop writing on every bufferevent in <b>g</b> */
374*663afb9bSAndroid Build Coastguard Worker static int
bev_group_suspend_writing_(struct bufferevent_rate_limit_group * g)375*663afb9bSAndroid Build Coastguard Worker bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g)
376*663afb9bSAndroid Build Coastguard Worker {
377*663afb9bSAndroid Build Coastguard Worker 	/* Needs group lock */
378*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev;
379*663afb9bSAndroid Build Coastguard Worker 	g->write_suspended = 1;
380*663afb9bSAndroid Build Coastguard Worker 	g->pending_unsuspend_write = 0;
381*663afb9bSAndroid Build Coastguard Worker 	LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
382*663afb9bSAndroid Build Coastguard Worker 		if (EVLOCK_TRY_LOCK_(bev->lock)) {
383*663afb9bSAndroid Build Coastguard Worker 			bufferevent_suspend_write_(&bev->bev,
384*663afb9bSAndroid Build Coastguard Worker 			    BEV_SUSPEND_BW_GROUP);
385*663afb9bSAndroid Build Coastguard Worker 			EVLOCK_UNLOCK(bev->lock, 0);
386*663afb9bSAndroid Build Coastguard Worker 		}
387*663afb9bSAndroid Build Coastguard Worker 	}
388*663afb9bSAndroid Build Coastguard Worker 	return 0;
389*663afb9bSAndroid Build Coastguard Worker }
390*663afb9bSAndroid Build Coastguard Worker 
391*663afb9bSAndroid Build Coastguard Worker /** Timer callback invoked on a single bufferevent with one or more exhausted
392*663afb9bSAndroid Build Coastguard Worker     buckets when they are ready to refill. */
393*663afb9bSAndroid Build Coastguard Worker static void
bev_refill_callback_(evutil_socket_t fd,short what,void * arg)394*663afb9bSAndroid Build Coastguard Worker bev_refill_callback_(evutil_socket_t fd, short what, void *arg)
395*663afb9bSAndroid Build Coastguard Worker {
396*663afb9bSAndroid Build Coastguard Worker 	unsigned tick;
397*663afb9bSAndroid Build Coastguard Worker 	struct timeval now;
398*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev = arg;
399*663afb9bSAndroid Build Coastguard Worker 	int again = 0;
400*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(&bev->bev);
401*663afb9bSAndroid Build Coastguard Worker 	if (!bev->rate_limiting || !bev->rate_limiting->cfg) {
402*663afb9bSAndroid Build Coastguard Worker 		BEV_UNLOCK(&bev->bev);
403*663afb9bSAndroid Build Coastguard Worker 		return;
404*663afb9bSAndroid Build Coastguard Worker 	}
405*663afb9bSAndroid Build Coastguard Worker 
406*663afb9bSAndroid Build Coastguard Worker 	/* First, update the bucket */
407*663afb9bSAndroid Build Coastguard Worker 	event_base_gettimeofday_cached(bev->bev.ev_base, &now);
408*663afb9bSAndroid Build Coastguard Worker 	tick = ev_token_bucket_get_tick_(&now,
409*663afb9bSAndroid Build Coastguard Worker 	    bev->rate_limiting->cfg);
410*663afb9bSAndroid Build Coastguard Worker 	ev_token_bucket_update_(&bev->rate_limiting->limit,
411*663afb9bSAndroid Build Coastguard Worker 	    bev->rate_limiting->cfg,
412*663afb9bSAndroid Build Coastguard Worker 	    tick);
413*663afb9bSAndroid Build Coastguard Worker 
414*663afb9bSAndroid Build Coastguard Worker 	/* Now unsuspend any read/write operations as appropriate. */
415*663afb9bSAndroid Build Coastguard Worker 	if ((bev->read_suspended & BEV_SUSPEND_BW)) {
416*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->limit.read_limit > 0)
417*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
418*663afb9bSAndroid Build Coastguard Worker 		else
419*663afb9bSAndroid Build Coastguard Worker 			again = 1;
420*663afb9bSAndroid Build Coastguard Worker 	}
421*663afb9bSAndroid Build Coastguard Worker 	if ((bev->write_suspended & BEV_SUSPEND_BW)) {
422*663afb9bSAndroid Build Coastguard Worker 		if (bev->rate_limiting->limit.write_limit > 0)
423*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
424*663afb9bSAndroid Build Coastguard Worker 		else
425*663afb9bSAndroid Build Coastguard Worker 			again = 1;
426*663afb9bSAndroid Build Coastguard Worker 	}
427*663afb9bSAndroid Build Coastguard Worker 	if (again) {
428*663afb9bSAndroid Build Coastguard Worker 		/* One or more of the buckets may need another refill if they
429*663afb9bSAndroid Build Coastguard Worker 		   started negative.
430*663afb9bSAndroid Build Coastguard Worker 
431*663afb9bSAndroid Build Coastguard Worker 		   XXXX if we need to be quiet for more ticks, we should
432*663afb9bSAndroid Build Coastguard Worker 		   maybe figure out what timeout we really want.
433*663afb9bSAndroid Build Coastguard Worker 		*/
434*663afb9bSAndroid Build Coastguard Worker 		/* XXXX Handle event_add failure somehow */
435*663afb9bSAndroid Build Coastguard Worker 		event_add(&bev->rate_limiting->refill_bucket_event,
436*663afb9bSAndroid Build Coastguard Worker 		    &bev->rate_limiting->cfg->tick_timeout);
437*663afb9bSAndroid Build Coastguard Worker 	}
438*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(&bev->bev);
439*663afb9bSAndroid Build Coastguard Worker }
440*663afb9bSAndroid Build Coastguard Worker 
441*663afb9bSAndroid Build Coastguard Worker /** Helper: grab a random element from a bufferevent group.
442*663afb9bSAndroid Build Coastguard Worker  *
443*663afb9bSAndroid Build Coastguard Worker  * Requires that we hold the lock on the group.
444*663afb9bSAndroid Build Coastguard Worker  */
445*663afb9bSAndroid Build Coastguard Worker static struct bufferevent_private *
bev_group_random_element_(struct bufferevent_rate_limit_group * group)446*663afb9bSAndroid Build Coastguard Worker bev_group_random_element_(struct bufferevent_rate_limit_group *group)
447*663afb9bSAndroid Build Coastguard Worker {
448*663afb9bSAndroid Build Coastguard Worker 	int which;
449*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev;
450*663afb9bSAndroid Build Coastguard Worker 
451*663afb9bSAndroid Build Coastguard Worker 	/* requires group lock */
452*663afb9bSAndroid Build Coastguard Worker 
453*663afb9bSAndroid Build Coastguard Worker 	if (!group->n_members)
454*663afb9bSAndroid Build Coastguard Worker 		return NULL;
455*663afb9bSAndroid Build Coastguard Worker 
456*663afb9bSAndroid Build Coastguard Worker 	EVUTIL_ASSERT(! LIST_EMPTY(&group->members));
457*663afb9bSAndroid Build Coastguard Worker 
458*663afb9bSAndroid Build Coastguard Worker 	which = evutil_weakrand_range_(&group->weakrand_seed, group->n_members);
459*663afb9bSAndroid Build Coastguard Worker 
460*663afb9bSAndroid Build Coastguard Worker 	bev = LIST_FIRST(&group->members);
461*663afb9bSAndroid Build Coastguard Worker 	while (which--)
462*663afb9bSAndroid Build Coastguard Worker 		bev = LIST_NEXT(bev, rate_limiting->next_in_group);
463*663afb9bSAndroid Build Coastguard Worker 
464*663afb9bSAndroid Build Coastguard Worker 	return bev;
465*663afb9bSAndroid Build Coastguard Worker }
466*663afb9bSAndroid Build Coastguard Worker 
467*663afb9bSAndroid Build Coastguard Worker /** Iterate over the elements of a rate-limiting group 'g' with a random
468*663afb9bSAndroid Build Coastguard Worker     starting point, assigning each to the variable 'bev', and executing the
469*663afb9bSAndroid Build Coastguard Worker     block 'block'.
470*663afb9bSAndroid Build Coastguard Worker 
471*663afb9bSAndroid Build Coastguard Worker     We do this in a half-baked effort to get fairness among group members.
472*663afb9bSAndroid Build Coastguard Worker     XXX Round-robin or some kind of priority queue would be even more fair.
473*663afb9bSAndroid Build Coastguard Worker  */
474*663afb9bSAndroid Build Coastguard Worker #define FOREACH_RANDOM_ORDER(block)			\
475*663afb9bSAndroid Build Coastguard Worker 	do {						\
476*663afb9bSAndroid Build Coastguard Worker 		first = bev_group_random_element_(g);	\
477*663afb9bSAndroid Build Coastguard Worker 		for (bev = first; bev != LIST_END(&g->members); \
478*663afb9bSAndroid Build Coastguard Worker 		    bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
479*663afb9bSAndroid Build Coastguard Worker 			block ;					 \
480*663afb9bSAndroid Build Coastguard Worker 		}						 \
481*663afb9bSAndroid Build Coastguard Worker 		for (bev = LIST_FIRST(&g->members); bev && bev != first; \
482*663afb9bSAndroid Build Coastguard Worker 		    bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
483*663afb9bSAndroid Build Coastguard Worker 			block ;						\
484*663afb9bSAndroid Build Coastguard Worker 		}							\
485*663afb9bSAndroid Build Coastguard Worker 	} while (0)
486*663afb9bSAndroid Build Coastguard Worker 
487*663afb9bSAndroid Build Coastguard Worker static void
bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group * g)488*663afb9bSAndroid Build Coastguard Worker bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g)
489*663afb9bSAndroid Build Coastguard Worker {
490*663afb9bSAndroid Build Coastguard Worker 	int again = 0;
491*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev, *first;
492*663afb9bSAndroid Build Coastguard Worker 
493*663afb9bSAndroid Build Coastguard Worker 	g->read_suspended = 0;
494*663afb9bSAndroid Build Coastguard Worker 	FOREACH_RANDOM_ORDER({
495*663afb9bSAndroid Build Coastguard Worker 		if (EVLOCK_TRY_LOCK_(bev->lock)) {
496*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_read_(&bev->bev,
497*663afb9bSAndroid Build Coastguard Worker 			    BEV_SUSPEND_BW_GROUP);
498*663afb9bSAndroid Build Coastguard Worker 			EVLOCK_UNLOCK(bev->lock, 0);
499*663afb9bSAndroid Build Coastguard Worker 		} else {
500*663afb9bSAndroid Build Coastguard Worker 			again = 1;
501*663afb9bSAndroid Build Coastguard Worker 		}
502*663afb9bSAndroid Build Coastguard Worker 	});
503*663afb9bSAndroid Build Coastguard Worker 	g->pending_unsuspend_read = again;
504*663afb9bSAndroid Build Coastguard Worker }
505*663afb9bSAndroid Build Coastguard Worker 
506*663afb9bSAndroid Build Coastguard Worker static void
bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group * g)507*663afb9bSAndroid Build Coastguard Worker bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g)
508*663afb9bSAndroid Build Coastguard Worker {
509*663afb9bSAndroid Build Coastguard Worker 	int again = 0;
510*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bev, *first;
511*663afb9bSAndroid Build Coastguard Worker 	g->write_suspended = 0;
512*663afb9bSAndroid Build Coastguard Worker 
513*663afb9bSAndroid Build Coastguard Worker 	FOREACH_RANDOM_ORDER({
514*663afb9bSAndroid Build Coastguard Worker 		if (EVLOCK_TRY_LOCK_(bev->lock)) {
515*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_write_(&bev->bev,
516*663afb9bSAndroid Build Coastguard Worker 			    BEV_SUSPEND_BW_GROUP);
517*663afb9bSAndroid Build Coastguard Worker 			EVLOCK_UNLOCK(bev->lock, 0);
518*663afb9bSAndroid Build Coastguard Worker 		} else {
519*663afb9bSAndroid Build Coastguard Worker 			again = 1;
520*663afb9bSAndroid Build Coastguard Worker 		}
521*663afb9bSAndroid Build Coastguard Worker 	});
522*663afb9bSAndroid Build Coastguard Worker 	g->pending_unsuspend_write = again;
523*663afb9bSAndroid Build Coastguard Worker }
524*663afb9bSAndroid Build Coastguard Worker 
525*663afb9bSAndroid Build Coastguard Worker /** Callback invoked every tick to add more elements to the group bucket
526*663afb9bSAndroid Build Coastguard Worker     and unsuspend group members as needed.
527*663afb9bSAndroid Build Coastguard Worker  */
528*663afb9bSAndroid Build Coastguard Worker static void
bev_group_refill_callback_(evutil_socket_t fd,short what,void * arg)529*663afb9bSAndroid Build Coastguard Worker bev_group_refill_callback_(evutil_socket_t fd, short what, void *arg)
530*663afb9bSAndroid Build Coastguard Worker {
531*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *g = arg;
532*663afb9bSAndroid Build Coastguard Worker 	unsigned tick;
533*663afb9bSAndroid Build Coastguard Worker 	struct timeval now;
534*663afb9bSAndroid Build Coastguard Worker 
535*663afb9bSAndroid Build Coastguard Worker 	event_base_gettimeofday_cached(event_get_base(&g->master_refill_event), &now);
536*663afb9bSAndroid Build Coastguard Worker 
537*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(g);
538*663afb9bSAndroid Build Coastguard Worker 
539*663afb9bSAndroid Build Coastguard Worker 	tick = ev_token_bucket_get_tick_(&now, &g->rate_limit_cfg);
540*663afb9bSAndroid Build Coastguard Worker 	ev_token_bucket_update_(&g->rate_limit, &g->rate_limit_cfg, tick);
541*663afb9bSAndroid Build Coastguard Worker 
542*663afb9bSAndroid Build Coastguard Worker 	if (g->pending_unsuspend_read ||
543*663afb9bSAndroid Build Coastguard Worker 	    (g->read_suspended && (g->rate_limit.read_limit >= g->min_share))) {
544*663afb9bSAndroid Build Coastguard Worker 		bev_group_unsuspend_reading_(g);
545*663afb9bSAndroid Build Coastguard Worker 	}
546*663afb9bSAndroid Build Coastguard Worker 	if (g->pending_unsuspend_write ||
547*663afb9bSAndroid Build Coastguard Worker 	    (g->write_suspended && (g->rate_limit.write_limit >= g->min_share))){
548*663afb9bSAndroid Build Coastguard Worker 		bev_group_unsuspend_writing_(g);
549*663afb9bSAndroid Build Coastguard Worker 	}
550*663afb9bSAndroid Build Coastguard Worker 
551*663afb9bSAndroid Build Coastguard Worker 	/* XXXX Rather than waiting to the next tick to unsuspend stuff
552*663afb9bSAndroid Build Coastguard Worker 	 * with pending_unsuspend_write/read, we should do it on the
553*663afb9bSAndroid Build Coastguard Worker 	 * next iteration of the mainloop.
554*663afb9bSAndroid Build Coastguard Worker 	 */
555*663afb9bSAndroid Build Coastguard Worker 
556*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(g);
557*663afb9bSAndroid Build Coastguard Worker }
558*663afb9bSAndroid Build Coastguard Worker 
559*663afb9bSAndroid Build Coastguard Worker int
bufferevent_set_rate_limit(struct bufferevent * bev,struct ev_token_bucket_cfg * cfg)560*663afb9bSAndroid Build Coastguard Worker bufferevent_set_rate_limit(struct bufferevent *bev,
561*663afb9bSAndroid Build Coastguard Worker     struct ev_token_bucket_cfg *cfg)
562*663afb9bSAndroid Build Coastguard Worker {
563*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp = BEV_UPCAST(bev);
564*663afb9bSAndroid Build Coastguard Worker 	int r = -1;
565*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit *rlim;
566*663afb9bSAndroid Build Coastguard Worker 	struct timeval now;
567*663afb9bSAndroid Build Coastguard Worker 	ev_uint32_t tick;
568*663afb9bSAndroid Build Coastguard Worker 	int reinit = 0, suspended = 0;
569*663afb9bSAndroid Build Coastguard Worker 	/* XXX reference-count cfg */
570*663afb9bSAndroid Build Coastguard Worker 
571*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
572*663afb9bSAndroid Build Coastguard Worker 
573*663afb9bSAndroid Build Coastguard Worker 	if (cfg == NULL) {
574*663afb9bSAndroid Build Coastguard Worker 		if (bevp->rate_limiting) {
575*663afb9bSAndroid Build Coastguard Worker 			rlim = bevp->rate_limiting;
576*663afb9bSAndroid Build Coastguard Worker 			rlim->cfg = NULL;
577*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
578*663afb9bSAndroid Build Coastguard Worker 			bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
579*663afb9bSAndroid Build Coastguard Worker 			if (event_initialized(&rlim->refill_bucket_event))
580*663afb9bSAndroid Build Coastguard Worker 				event_del(&rlim->refill_bucket_event);
581*663afb9bSAndroid Build Coastguard Worker 		}
582*663afb9bSAndroid Build Coastguard Worker 		r = 0;
583*663afb9bSAndroid Build Coastguard Worker 		goto done;
584*663afb9bSAndroid Build Coastguard Worker 	}
585*663afb9bSAndroid Build Coastguard Worker 
586*663afb9bSAndroid Build Coastguard Worker 	event_base_gettimeofday_cached(bev->ev_base, &now);
587*663afb9bSAndroid Build Coastguard Worker 	tick = ev_token_bucket_get_tick_(&now, cfg);
588*663afb9bSAndroid Build Coastguard Worker 
589*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting && bevp->rate_limiting->cfg == cfg) {
590*663afb9bSAndroid Build Coastguard Worker 		/* no-op */
591*663afb9bSAndroid Build Coastguard Worker 		r = 0;
592*663afb9bSAndroid Build Coastguard Worker 		goto done;
593*663afb9bSAndroid Build Coastguard Worker 	}
594*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting == NULL) {
595*663afb9bSAndroid Build Coastguard Worker 		rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
596*663afb9bSAndroid Build Coastguard Worker 		if (!rlim)
597*663afb9bSAndroid Build Coastguard Worker 			goto done;
598*663afb9bSAndroid Build Coastguard Worker 		bevp->rate_limiting = rlim;
599*663afb9bSAndroid Build Coastguard Worker 	} else {
600*663afb9bSAndroid Build Coastguard Worker 		rlim = bevp->rate_limiting;
601*663afb9bSAndroid Build Coastguard Worker 	}
602*663afb9bSAndroid Build Coastguard Worker 	reinit = rlim->cfg != NULL;
603*663afb9bSAndroid Build Coastguard Worker 
604*663afb9bSAndroid Build Coastguard Worker 	rlim->cfg = cfg;
605*663afb9bSAndroid Build Coastguard Worker 	ev_token_bucket_init_(&rlim->limit, cfg, tick, reinit);
606*663afb9bSAndroid Build Coastguard Worker 
607*663afb9bSAndroid Build Coastguard Worker 	if (reinit) {
608*663afb9bSAndroid Build Coastguard Worker 		EVUTIL_ASSERT(event_initialized(&rlim->refill_bucket_event));
609*663afb9bSAndroid Build Coastguard Worker 		event_del(&rlim->refill_bucket_event);
610*663afb9bSAndroid Build Coastguard Worker 	}
611*663afb9bSAndroid Build Coastguard Worker 	event_assign(&rlim->refill_bucket_event, bev->ev_base,
612*663afb9bSAndroid Build Coastguard Worker 	    -1, EV_FINALIZE, bev_refill_callback_, bevp);
613*663afb9bSAndroid Build Coastguard Worker 
614*663afb9bSAndroid Build Coastguard Worker 	if (rlim->limit.read_limit > 0) {
615*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
616*663afb9bSAndroid Build Coastguard Worker 	} else {
617*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
618*663afb9bSAndroid Build Coastguard Worker 		suspended=1;
619*663afb9bSAndroid Build Coastguard Worker 	}
620*663afb9bSAndroid Build Coastguard Worker 	if (rlim->limit.write_limit > 0) {
621*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
622*663afb9bSAndroid Build Coastguard Worker 	} else {
623*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
624*663afb9bSAndroid Build Coastguard Worker 		suspended = 1;
625*663afb9bSAndroid Build Coastguard Worker 	}
626*663afb9bSAndroid Build Coastguard Worker 
627*663afb9bSAndroid Build Coastguard Worker 	if (suspended)
628*663afb9bSAndroid Build Coastguard Worker 		event_add(&rlim->refill_bucket_event, &cfg->tick_timeout);
629*663afb9bSAndroid Build Coastguard Worker 
630*663afb9bSAndroid Build Coastguard Worker 	r = 0;
631*663afb9bSAndroid Build Coastguard Worker 
632*663afb9bSAndroid Build Coastguard Worker done:
633*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
634*663afb9bSAndroid Build Coastguard Worker 	return r;
635*663afb9bSAndroid Build Coastguard Worker }
636*663afb9bSAndroid Build Coastguard Worker 
637*663afb9bSAndroid Build Coastguard Worker struct bufferevent_rate_limit_group *
bufferevent_rate_limit_group_new(struct event_base * base,const struct ev_token_bucket_cfg * cfg)638*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_new(struct event_base *base,
639*663afb9bSAndroid Build Coastguard Worker     const struct ev_token_bucket_cfg *cfg)
640*663afb9bSAndroid Build Coastguard Worker {
641*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *g;
642*663afb9bSAndroid Build Coastguard Worker 	struct timeval now;
643*663afb9bSAndroid Build Coastguard Worker 	ev_uint32_t tick;
644*663afb9bSAndroid Build Coastguard Worker 
645*663afb9bSAndroid Build Coastguard Worker 	event_base_gettimeofday_cached(base, &now);
646*663afb9bSAndroid Build Coastguard Worker 	tick = ev_token_bucket_get_tick_(&now, cfg);
647*663afb9bSAndroid Build Coastguard Worker 
648*663afb9bSAndroid Build Coastguard Worker 	g = mm_calloc(1, sizeof(struct bufferevent_rate_limit_group));
649*663afb9bSAndroid Build Coastguard Worker 	if (!g)
650*663afb9bSAndroid Build Coastguard Worker 		return NULL;
651*663afb9bSAndroid Build Coastguard Worker 	memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
652*663afb9bSAndroid Build Coastguard Worker 	LIST_INIT(&g->members);
653*663afb9bSAndroid Build Coastguard Worker 
654*663afb9bSAndroid Build Coastguard Worker 	ev_token_bucket_init_(&g->rate_limit, cfg, tick, 0);
655*663afb9bSAndroid Build Coastguard Worker 
656*663afb9bSAndroid Build Coastguard Worker 	event_assign(&g->master_refill_event, base, -1, EV_PERSIST|EV_FINALIZE,
657*663afb9bSAndroid Build Coastguard Worker 	    bev_group_refill_callback_, g);
658*663afb9bSAndroid Build Coastguard Worker 	/*XXXX handle event_add failure */
659*663afb9bSAndroid Build Coastguard Worker 	event_add(&g->master_refill_event, &cfg->tick_timeout);
660*663afb9bSAndroid Build Coastguard Worker 
661*663afb9bSAndroid Build Coastguard Worker 	EVTHREAD_ALLOC_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
662*663afb9bSAndroid Build Coastguard Worker 
663*663afb9bSAndroid Build Coastguard Worker 	bufferevent_rate_limit_group_set_min_share(g, 64);
664*663afb9bSAndroid Build Coastguard Worker 
665*663afb9bSAndroid Build Coastguard Worker 	evutil_weakrand_seed_(&g->weakrand_seed,
666*663afb9bSAndroid Build Coastguard Worker 	    (ev_uint32_t) ((now.tv_sec + now.tv_usec) + (ev_intptr_t)g));
667*663afb9bSAndroid Build Coastguard Worker 
668*663afb9bSAndroid Build Coastguard Worker 	return g;
669*663afb9bSAndroid Build Coastguard Worker }
670*663afb9bSAndroid Build Coastguard Worker 
671*663afb9bSAndroid Build Coastguard Worker int
bufferevent_rate_limit_group_set_cfg(struct bufferevent_rate_limit_group * g,const struct ev_token_bucket_cfg * cfg)672*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_set_cfg(
673*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *g,
674*663afb9bSAndroid Build Coastguard Worker 	const struct ev_token_bucket_cfg *cfg)
675*663afb9bSAndroid Build Coastguard Worker {
676*663afb9bSAndroid Build Coastguard Worker 	int same_tick;
677*663afb9bSAndroid Build Coastguard Worker 	if (!g || !cfg)
678*663afb9bSAndroid Build Coastguard Worker 		return -1;
679*663afb9bSAndroid Build Coastguard Worker 
680*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(g);
681*663afb9bSAndroid Build Coastguard Worker 	same_tick = evutil_timercmp(
682*663afb9bSAndroid Build Coastguard Worker 		&g->rate_limit_cfg.tick_timeout, &cfg->tick_timeout, ==);
683*663afb9bSAndroid Build Coastguard Worker 	memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
684*663afb9bSAndroid Build Coastguard Worker 
685*663afb9bSAndroid Build Coastguard Worker 	if (g->rate_limit.read_limit > (ev_ssize_t)cfg->read_maximum)
686*663afb9bSAndroid Build Coastguard Worker 		g->rate_limit.read_limit = cfg->read_maximum;
687*663afb9bSAndroid Build Coastguard Worker 	if (g->rate_limit.write_limit > (ev_ssize_t)cfg->write_maximum)
688*663afb9bSAndroid Build Coastguard Worker 		g->rate_limit.write_limit = cfg->write_maximum;
689*663afb9bSAndroid Build Coastguard Worker 
690*663afb9bSAndroid Build Coastguard Worker 	if (!same_tick) {
691*663afb9bSAndroid Build Coastguard Worker 		/* This can cause a hiccup in the schedule */
692*663afb9bSAndroid Build Coastguard Worker 		event_add(&g->master_refill_event, &cfg->tick_timeout);
693*663afb9bSAndroid Build Coastguard Worker 	}
694*663afb9bSAndroid Build Coastguard Worker 
695*663afb9bSAndroid Build Coastguard Worker 	/* The new limits might force us to adjust min_share differently. */
696*663afb9bSAndroid Build Coastguard Worker 	bufferevent_rate_limit_group_set_min_share(g, g->configured_min_share);
697*663afb9bSAndroid Build Coastguard Worker 
698*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(g);
699*663afb9bSAndroid Build Coastguard Worker 	return 0;
700*663afb9bSAndroid Build Coastguard Worker }
701*663afb9bSAndroid Build Coastguard Worker 
702*663afb9bSAndroid Build Coastguard Worker int
bufferevent_rate_limit_group_set_min_share(struct bufferevent_rate_limit_group * g,size_t share)703*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_set_min_share(
704*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *g,
705*663afb9bSAndroid Build Coastguard Worker 	size_t share)
706*663afb9bSAndroid Build Coastguard Worker {
707*663afb9bSAndroid Build Coastguard Worker 	if (share > EV_SSIZE_MAX)
708*663afb9bSAndroid Build Coastguard Worker 		return -1;
709*663afb9bSAndroid Build Coastguard Worker 
710*663afb9bSAndroid Build Coastguard Worker 	g->configured_min_share = share;
711*663afb9bSAndroid Build Coastguard Worker 
712*663afb9bSAndroid Build Coastguard Worker 	/* Can't set share to less than the one-tick maximum.  IOW, at steady
713*663afb9bSAndroid Build Coastguard Worker 	 * state, at least one connection can go per tick. */
714*663afb9bSAndroid Build Coastguard Worker 	if (share > g->rate_limit_cfg.read_rate)
715*663afb9bSAndroid Build Coastguard Worker 		share = g->rate_limit_cfg.read_rate;
716*663afb9bSAndroid Build Coastguard Worker 	if (share > g->rate_limit_cfg.write_rate)
717*663afb9bSAndroid Build Coastguard Worker 		share = g->rate_limit_cfg.write_rate;
718*663afb9bSAndroid Build Coastguard Worker 
719*663afb9bSAndroid Build Coastguard Worker 	g->min_share = share;
720*663afb9bSAndroid Build Coastguard Worker 	return 0;
721*663afb9bSAndroid Build Coastguard Worker }
722*663afb9bSAndroid Build Coastguard Worker 
723*663afb9bSAndroid Build Coastguard Worker void
bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group * g)724*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *g)
725*663afb9bSAndroid Build Coastguard Worker {
726*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(g);
727*663afb9bSAndroid Build Coastguard Worker 	EVUTIL_ASSERT(0 == g->n_members);
728*663afb9bSAndroid Build Coastguard Worker 	event_del(&g->master_refill_event);
729*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(g);
730*663afb9bSAndroid Build Coastguard Worker 	EVTHREAD_FREE_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
731*663afb9bSAndroid Build Coastguard Worker 	mm_free(g);
732*663afb9bSAndroid Build Coastguard Worker }
733*663afb9bSAndroid Build Coastguard Worker 
734*663afb9bSAndroid Build Coastguard Worker int
bufferevent_add_to_rate_limit_group(struct bufferevent * bev,struct bufferevent_rate_limit_group * g)735*663afb9bSAndroid Build Coastguard Worker bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
736*663afb9bSAndroid Build Coastguard Worker     struct bufferevent_rate_limit_group *g)
737*663afb9bSAndroid Build Coastguard Worker {
738*663afb9bSAndroid Build Coastguard Worker 	int wsuspend, rsuspend;
739*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp = BEV_UPCAST(bev);
740*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
741*663afb9bSAndroid Build Coastguard Worker 
742*663afb9bSAndroid Build Coastguard Worker 	if (!bevp->rate_limiting) {
743*663afb9bSAndroid Build Coastguard Worker 		struct bufferevent_rate_limit *rlim;
744*663afb9bSAndroid Build Coastguard Worker 		rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
745*663afb9bSAndroid Build Coastguard Worker 		if (!rlim) {
746*663afb9bSAndroid Build Coastguard Worker 			BEV_UNLOCK(bev);
747*663afb9bSAndroid Build Coastguard Worker 			return -1;
748*663afb9bSAndroid Build Coastguard Worker 		}
749*663afb9bSAndroid Build Coastguard Worker 		event_assign(&rlim->refill_bucket_event, bev->ev_base,
750*663afb9bSAndroid Build Coastguard Worker 		    -1, EV_FINALIZE, bev_refill_callback_, bevp);
751*663afb9bSAndroid Build Coastguard Worker 		bevp->rate_limiting = rlim;
752*663afb9bSAndroid Build Coastguard Worker 	}
753*663afb9bSAndroid Build Coastguard Worker 
754*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting->group == g) {
755*663afb9bSAndroid Build Coastguard Worker 		BEV_UNLOCK(bev);
756*663afb9bSAndroid Build Coastguard Worker 		return 0;
757*663afb9bSAndroid Build Coastguard Worker 	}
758*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting->group)
759*663afb9bSAndroid Build Coastguard Worker 		bufferevent_remove_from_rate_limit_group(bev);
760*663afb9bSAndroid Build Coastguard Worker 
761*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(g);
762*663afb9bSAndroid Build Coastguard Worker 	bevp->rate_limiting->group = g;
763*663afb9bSAndroid Build Coastguard Worker 	++g->n_members;
764*663afb9bSAndroid Build Coastguard Worker 	LIST_INSERT_HEAD(&g->members, bevp, rate_limiting->next_in_group);
765*663afb9bSAndroid Build Coastguard Worker 
766*663afb9bSAndroid Build Coastguard Worker 	rsuspend = g->read_suspended;
767*663afb9bSAndroid Build Coastguard Worker 	wsuspend = g->write_suspended;
768*663afb9bSAndroid Build Coastguard Worker 
769*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(g);
770*663afb9bSAndroid Build Coastguard Worker 
771*663afb9bSAndroid Build Coastguard Worker 	if (rsuspend)
772*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_read_(bev, BEV_SUSPEND_BW_GROUP);
773*663afb9bSAndroid Build Coastguard Worker 	if (wsuspend)
774*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_write_(bev, BEV_SUSPEND_BW_GROUP);
775*663afb9bSAndroid Build Coastguard Worker 
776*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
777*663afb9bSAndroid Build Coastguard Worker 	return 0;
778*663afb9bSAndroid Build Coastguard Worker }
779*663afb9bSAndroid Build Coastguard Worker 
780*663afb9bSAndroid Build Coastguard Worker int
bufferevent_remove_from_rate_limit_group(struct bufferevent * bev)781*663afb9bSAndroid Build Coastguard Worker bufferevent_remove_from_rate_limit_group(struct bufferevent *bev)
782*663afb9bSAndroid Build Coastguard Worker {
783*663afb9bSAndroid Build Coastguard Worker 	return bufferevent_remove_from_rate_limit_group_internal_(bev, 1);
784*663afb9bSAndroid Build Coastguard Worker }
785*663afb9bSAndroid Build Coastguard Worker 
786*663afb9bSAndroid Build Coastguard Worker int
bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent * bev,int unsuspend)787*663afb9bSAndroid Build Coastguard Worker bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
788*663afb9bSAndroid Build Coastguard Worker     int unsuspend)
789*663afb9bSAndroid Build Coastguard Worker {
790*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp = BEV_UPCAST(bev);
791*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
792*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting && bevp->rate_limiting->group) {
793*663afb9bSAndroid Build Coastguard Worker 		struct bufferevent_rate_limit_group *g =
794*663afb9bSAndroid Build Coastguard Worker 		    bevp->rate_limiting->group;
795*663afb9bSAndroid Build Coastguard Worker 		LOCK_GROUP(g);
796*663afb9bSAndroid Build Coastguard Worker 		bevp->rate_limiting->group = NULL;
797*663afb9bSAndroid Build Coastguard Worker 		--g->n_members;
798*663afb9bSAndroid Build Coastguard Worker 		LIST_REMOVE(bevp, rate_limiting->next_in_group);
799*663afb9bSAndroid Build Coastguard Worker 		UNLOCK_GROUP(g);
800*663afb9bSAndroid Build Coastguard Worker 	}
801*663afb9bSAndroid Build Coastguard Worker 	if (unsuspend) {
802*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW_GROUP);
803*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW_GROUP);
804*663afb9bSAndroid Build Coastguard Worker 	}
805*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
806*663afb9bSAndroid Build Coastguard Worker 	return 0;
807*663afb9bSAndroid Build Coastguard Worker }
808*663afb9bSAndroid Build Coastguard Worker 
809*663afb9bSAndroid Build Coastguard Worker /* ===
810*663afb9bSAndroid Build Coastguard Worker  * API functions to expose rate limits.
811*663afb9bSAndroid Build Coastguard Worker  *
812*663afb9bSAndroid Build Coastguard Worker  * Don't use these from inside Libevent; they're meant to be for use by
813*663afb9bSAndroid Build Coastguard Worker  * the program.
814*663afb9bSAndroid Build Coastguard Worker  * === */
815*663afb9bSAndroid Build Coastguard Worker 
816*663afb9bSAndroid Build Coastguard Worker /* Mostly you don't want to use this function from inside libevent;
817*663afb9bSAndroid Build Coastguard Worker  * bufferevent_get_read_max_() is more likely what you want*/
818*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_read_limit(struct bufferevent * bev)819*663afb9bSAndroid Build Coastguard Worker bufferevent_get_read_limit(struct bufferevent *bev)
820*663afb9bSAndroid Build Coastguard Worker {
821*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
822*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
823*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
824*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
825*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
826*663afb9bSAndroid Build Coastguard Worker 		bufferevent_update_buckets(bevp);
827*663afb9bSAndroid Build Coastguard Worker 		r = bevp->rate_limiting->limit.read_limit;
828*663afb9bSAndroid Build Coastguard Worker 	} else {
829*663afb9bSAndroid Build Coastguard Worker 		r = EV_SSIZE_MAX;
830*663afb9bSAndroid Build Coastguard Worker 	}
831*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
832*663afb9bSAndroid Build Coastguard Worker 	return r;
833*663afb9bSAndroid Build Coastguard Worker }
834*663afb9bSAndroid Build Coastguard Worker 
835*663afb9bSAndroid Build Coastguard Worker /* Mostly you don't want to use this function from inside libevent;
836*663afb9bSAndroid Build Coastguard Worker  * bufferevent_get_write_max_() is more likely what you want*/
837*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_write_limit(struct bufferevent * bev)838*663afb9bSAndroid Build Coastguard Worker bufferevent_get_write_limit(struct bufferevent *bev)
839*663afb9bSAndroid Build Coastguard Worker {
840*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
841*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
842*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
843*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
844*663afb9bSAndroid Build Coastguard Worker 	if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
845*663afb9bSAndroid Build Coastguard Worker 		bufferevent_update_buckets(bevp);
846*663afb9bSAndroid Build Coastguard Worker 		r = bevp->rate_limiting->limit.write_limit;
847*663afb9bSAndroid Build Coastguard Worker 	} else {
848*663afb9bSAndroid Build Coastguard Worker 		r = EV_SSIZE_MAX;
849*663afb9bSAndroid Build Coastguard Worker 	}
850*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
851*663afb9bSAndroid Build Coastguard Worker 	return r;
852*663afb9bSAndroid Build Coastguard Worker }
853*663afb9bSAndroid Build Coastguard Worker 
854*663afb9bSAndroid Build Coastguard Worker int
bufferevent_set_max_single_read(struct bufferevent * bev,size_t size)855*663afb9bSAndroid Build Coastguard Worker bufferevent_set_max_single_read(struct bufferevent *bev, size_t size)
856*663afb9bSAndroid Build Coastguard Worker {
857*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
858*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
859*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
860*663afb9bSAndroid Build Coastguard Worker 	if (size == 0 || size > EV_SSIZE_MAX)
861*663afb9bSAndroid Build Coastguard Worker 		bevp->max_single_read = MAX_SINGLE_READ_DEFAULT;
862*663afb9bSAndroid Build Coastguard Worker 	else
863*663afb9bSAndroid Build Coastguard Worker 		bevp->max_single_read = size;
864*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
865*663afb9bSAndroid Build Coastguard Worker 	return 0;
866*663afb9bSAndroid Build Coastguard Worker }
867*663afb9bSAndroid Build Coastguard Worker 
868*663afb9bSAndroid Build Coastguard Worker int
bufferevent_set_max_single_write(struct bufferevent * bev,size_t size)869*663afb9bSAndroid Build Coastguard Worker bufferevent_set_max_single_write(struct bufferevent *bev, size_t size)
870*663afb9bSAndroid Build Coastguard Worker {
871*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
872*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
873*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
874*663afb9bSAndroid Build Coastguard Worker 	if (size == 0 || size > EV_SSIZE_MAX)
875*663afb9bSAndroid Build Coastguard Worker 		bevp->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
876*663afb9bSAndroid Build Coastguard Worker 	else
877*663afb9bSAndroid Build Coastguard Worker 		bevp->max_single_write = size;
878*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
879*663afb9bSAndroid Build Coastguard Worker 	return 0;
880*663afb9bSAndroid Build Coastguard Worker }
881*663afb9bSAndroid Build Coastguard Worker 
882*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_max_single_read(struct bufferevent * bev)883*663afb9bSAndroid Build Coastguard Worker bufferevent_get_max_single_read(struct bufferevent *bev)
884*663afb9bSAndroid Build Coastguard Worker {
885*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
886*663afb9bSAndroid Build Coastguard Worker 
887*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
888*663afb9bSAndroid Build Coastguard Worker 	r = BEV_UPCAST(bev)->max_single_read;
889*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
890*663afb9bSAndroid Build Coastguard Worker 	return r;
891*663afb9bSAndroid Build Coastguard Worker }
892*663afb9bSAndroid Build Coastguard Worker 
893*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_max_single_write(struct bufferevent * bev)894*663afb9bSAndroid Build Coastguard Worker bufferevent_get_max_single_write(struct bufferevent *bev)
895*663afb9bSAndroid Build Coastguard Worker {
896*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
897*663afb9bSAndroid Build Coastguard Worker 
898*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
899*663afb9bSAndroid Build Coastguard Worker 	r = BEV_UPCAST(bev)->max_single_write;
900*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
901*663afb9bSAndroid Build Coastguard Worker 	return r;
902*663afb9bSAndroid Build Coastguard Worker }
903*663afb9bSAndroid Build Coastguard Worker 
904*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_max_to_read(struct bufferevent * bev)905*663afb9bSAndroid Build Coastguard Worker bufferevent_get_max_to_read(struct bufferevent *bev)
906*663afb9bSAndroid Build Coastguard Worker {
907*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
908*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
909*663afb9bSAndroid Build Coastguard Worker 	r = bufferevent_get_read_max_(BEV_UPCAST(bev));
910*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
911*663afb9bSAndroid Build Coastguard Worker 	return r;
912*663afb9bSAndroid Build Coastguard Worker }
913*663afb9bSAndroid Build Coastguard Worker 
914*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_get_max_to_write(struct bufferevent * bev)915*663afb9bSAndroid Build Coastguard Worker bufferevent_get_max_to_write(struct bufferevent *bev)
916*663afb9bSAndroid Build Coastguard Worker {
917*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
918*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
919*663afb9bSAndroid Build Coastguard Worker 	r = bufferevent_get_write_max_(BEV_UPCAST(bev));
920*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
921*663afb9bSAndroid Build Coastguard Worker 	return r;
922*663afb9bSAndroid Build Coastguard Worker }
923*663afb9bSAndroid Build Coastguard Worker 
924*663afb9bSAndroid Build Coastguard Worker const struct ev_token_bucket_cfg *
bufferevent_get_token_bucket_cfg(const struct bufferevent * bev)925*663afb9bSAndroid Build Coastguard Worker bufferevent_get_token_bucket_cfg(const struct bufferevent *bev) {
926*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
927*663afb9bSAndroid Build Coastguard Worker 	struct ev_token_bucket_cfg *cfg;
928*663afb9bSAndroid Build Coastguard Worker 
929*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
930*663afb9bSAndroid Build Coastguard Worker 
931*663afb9bSAndroid Build Coastguard Worker 	if (bufev_private->rate_limiting) {
932*663afb9bSAndroid Build Coastguard Worker 		cfg = bufev_private->rate_limiting->cfg;
933*663afb9bSAndroid Build Coastguard Worker 	} else {
934*663afb9bSAndroid Build Coastguard Worker 		cfg = NULL;
935*663afb9bSAndroid Build Coastguard Worker 	}
936*663afb9bSAndroid Build Coastguard Worker 
937*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
938*663afb9bSAndroid Build Coastguard Worker 
939*663afb9bSAndroid Build Coastguard Worker 	return cfg;
940*663afb9bSAndroid Build Coastguard Worker }
941*663afb9bSAndroid Build Coastguard Worker 
942*663afb9bSAndroid Build Coastguard Worker /* Mostly you don't want to use this function from inside libevent;
943*663afb9bSAndroid Build Coastguard Worker  * bufferevent_get_read_max_() is more likely what you want*/
944*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_rate_limit_group_get_read_limit(struct bufferevent_rate_limit_group * grp)945*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_get_read_limit(
946*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *grp)
947*663afb9bSAndroid Build Coastguard Worker {
948*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
949*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(grp);
950*663afb9bSAndroid Build Coastguard Worker 	r = grp->rate_limit.read_limit;
951*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(grp);
952*663afb9bSAndroid Build Coastguard Worker 	return r;
953*663afb9bSAndroid Build Coastguard Worker }
954*663afb9bSAndroid Build Coastguard Worker 
955*663afb9bSAndroid Build Coastguard Worker /* Mostly you don't want to use this function from inside libevent;
956*663afb9bSAndroid Build Coastguard Worker  * bufferevent_get_write_max_() is more likely what you want. */
957*663afb9bSAndroid Build Coastguard Worker ev_ssize_t
bufferevent_rate_limit_group_get_write_limit(struct bufferevent_rate_limit_group * grp)958*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_get_write_limit(
959*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *grp)
960*663afb9bSAndroid Build Coastguard Worker {
961*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t r;
962*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(grp);
963*663afb9bSAndroid Build Coastguard Worker 	r = grp->rate_limit.write_limit;
964*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(grp);
965*663afb9bSAndroid Build Coastguard Worker 	return r;
966*663afb9bSAndroid Build Coastguard Worker }
967*663afb9bSAndroid Build Coastguard Worker 
968*663afb9bSAndroid Build Coastguard Worker int
bufferevent_decrement_read_limit(struct bufferevent * bev,ev_ssize_t decr)969*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr)
970*663afb9bSAndroid Build Coastguard Worker {
971*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
972*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t old_limit, new_limit;
973*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
974*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
975*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
976*663afb9bSAndroid Build Coastguard Worker 	EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
977*663afb9bSAndroid Build Coastguard Worker 	old_limit = bevp->rate_limiting->limit.read_limit;
978*663afb9bSAndroid Build Coastguard Worker 
979*663afb9bSAndroid Build Coastguard Worker 	new_limit = (bevp->rate_limiting->limit.read_limit -= decr);
980*663afb9bSAndroid Build Coastguard Worker 	if (old_limit > 0 && new_limit <= 0) {
981*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
982*663afb9bSAndroid Build Coastguard Worker 		if (event_add(&bevp->rate_limiting->refill_bucket_event,
983*663afb9bSAndroid Build Coastguard Worker 			&bevp->rate_limiting->cfg->tick_timeout) < 0)
984*663afb9bSAndroid Build Coastguard Worker 			r = -1;
985*663afb9bSAndroid Build Coastguard Worker 	} else if (old_limit <= 0 && new_limit > 0) {
986*663afb9bSAndroid Build Coastguard Worker 		if (!(bevp->write_suspended & BEV_SUSPEND_BW))
987*663afb9bSAndroid Build Coastguard Worker 			event_del(&bevp->rate_limiting->refill_bucket_event);
988*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
989*663afb9bSAndroid Build Coastguard Worker 	}
990*663afb9bSAndroid Build Coastguard Worker 
991*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
992*663afb9bSAndroid Build Coastguard Worker 	return r;
993*663afb9bSAndroid Build Coastguard Worker }
994*663afb9bSAndroid Build Coastguard Worker 
995*663afb9bSAndroid Build Coastguard Worker int
bufferevent_decrement_write_limit(struct bufferevent * bev,ev_ssize_t decr)996*663afb9bSAndroid Build Coastguard Worker bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr)
997*663afb9bSAndroid Build Coastguard Worker {
998*663afb9bSAndroid Build Coastguard Worker 	/* XXXX this is mostly copy-and-paste from
999*663afb9bSAndroid Build Coastguard Worker 	 * bufferevent_decrement_read_limit */
1000*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
1001*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t old_limit, new_limit;
1002*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_private *bevp;
1003*663afb9bSAndroid Build Coastguard Worker 	BEV_LOCK(bev);
1004*663afb9bSAndroid Build Coastguard Worker 	bevp = BEV_UPCAST(bev);
1005*663afb9bSAndroid Build Coastguard Worker 	EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
1006*663afb9bSAndroid Build Coastguard Worker 	old_limit = bevp->rate_limiting->limit.write_limit;
1007*663afb9bSAndroid Build Coastguard Worker 
1008*663afb9bSAndroid Build Coastguard Worker 	new_limit = (bevp->rate_limiting->limit.write_limit -= decr);
1009*663afb9bSAndroid Build Coastguard Worker 	if (old_limit > 0 && new_limit <= 0) {
1010*663afb9bSAndroid Build Coastguard Worker 		bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
1011*663afb9bSAndroid Build Coastguard Worker 		if (event_add(&bevp->rate_limiting->refill_bucket_event,
1012*663afb9bSAndroid Build Coastguard Worker 			&bevp->rate_limiting->cfg->tick_timeout) < 0)
1013*663afb9bSAndroid Build Coastguard Worker 			r = -1;
1014*663afb9bSAndroid Build Coastguard Worker 	} else if (old_limit <= 0 && new_limit > 0) {
1015*663afb9bSAndroid Build Coastguard Worker 		if (!(bevp->read_suspended & BEV_SUSPEND_BW))
1016*663afb9bSAndroid Build Coastguard Worker 			event_del(&bevp->rate_limiting->refill_bucket_event);
1017*663afb9bSAndroid Build Coastguard Worker 		bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
1018*663afb9bSAndroid Build Coastguard Worker 	}
1019*663afb9bSAndroid Build Coastguard Worker 
1020*663afb9bSAndroid Build Coastguard Worker 	BEV_UNLOCK(bev);
1021*663afb9bSAndroid Build Coastguard Worker 	return r;
1022*663afb9bSAndroid Build Coastguard Worker }
1023*663afb9bSAndroid Build Coastguard Worker 
1024*663afb9bSAndroid Build Coastguard Worker int
bufferevent_rate_limit_group_decrement_read(struct bufferevent_rate_limit_group * grp,ev_ssize_t decr)1025*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_decrement_read(
1026*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
1027*663afb9bSAndroid Build Coastguard Worker {
1028*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
1029*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t old_limit, new_limit;
1030*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(grp);
1031*663afb9bSAndroid Build Coastguard Worker 	old_limit = grp->rate_limit.read_limit;
1032*663afb9bSAndroid Build Coastguard Worker 	new_limit = (grp->rate_limit.read_limit -= decr);
1033*663afb9bSAndroid Build Coastguard Worker 
1034*663afb9bSAndroid Build Coastguard Worker 	if (old_limit > 0 && new_limit <= 0) {
1035*663afb9bSAndroid Build Coastguard Worker 		bev_group_suspend_reading_(grp);
1036*663afb9bSAndroid Build Coastguard Worker 	} else if (old_limit <= 0 && new_limit > 0) {
1037*663afb9bSAndroid Build Coastguard Worker 		bev_group_unsuspend_reading_(grp);
1038*663afb9bSAndroid Build Coastguard Worker 	}
1039*663afb9bSAndroid Build Coastguard Worker 
1040*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(grp);
1041*663afb9bSAndroid Build Coastguard Worker 	return r;
1042*663afb9bSAndroid Build Coastguard Worker }
1043*663afb9bSAndroid Build Coastguard Worker 
1044*663afb9bSAndroid Build Coastguard Worker int
bufferevent_rate_limit_group_decrement_write(struct bufferevent_rate_limit_group * grp,ev_ssize_t decr)1045*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_decrement_write(
1046*663afb9bSAndroid Build Coastguard Worker 	struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
1047*663afb9bSAndroid Build Coastguard Worker {
1048*663afb9bSAndroid Build Coastguard Worker 	int r = 0;
1049*663afb9bSAndroid Build Coastguard Worker 	ev_ssize_t old_limit, new_limit;
1050*663afb9bSAndroid Build Coastguard Worker 	LOCK_GROUP(grp);
1051*663afb9bSAndroid Build Coastguard Worker 	old_limit = grp->rate_limit.write_limit;
1052*663afb9bSAndroid Build Coastguard Worker 	new_limit = (grp->rate_limit.write_limit -= decr);
1053*663afb9bSAndroid Build Coastguard Worker 
1054*663afb9bSAndroid Build Coastguard Worker 	if (old_limit > 0 && new_limit <= 0) {
1055*663afb9bSAndroid Build Coastguard Worker 		bev_group_suspend_writing_(grp);
1056*663afb9bSAndroid Build Coastguard Worker 	} else if (old_limit <= 0 && new_limit > 0) {
1057*663afb9bSAndroid Build Coastguard Worker 		bev_group_unsuspend_writing_(grp);
1058*663afb9bSAndroid Build Coastguard Worker 	}
1059*663afb9bSAndroid Build Coastguard Worker 
1060*663afb9bSAndroid Build Coastguard Worker 	UNLOCK_GROUP(grp);
1061*663afb9bSAndroid Build Coastguard Worker 	return r;
1062*663afb9bSAndroid Build Coastguard Worker }
1063*663afb9bSAndroid Build Coastguard Worker 
1064*663afb9bSAndroid Build Coastguard Worker void
bufferevent_rate_limit_group_get_totals(struct bufferevent_rate_limit_group * grp,ev_uint64_t * total_read_out,ev_uint64_t * total_written_out)1065*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_get_totals(struct bufferevent_rate_limit_group *grp,
1066*663afb9bSAndroid Build Coastguard Worker     ev_uint64_t *total_read_out, ev_uint64_t *total_written_out)
1067*663afb9bSAndroid Build Coastguard Worker {
1068*663afb9bSAndroid Build Coastguard Worker 	EVUTIL_ASSERT(grp != NULL);
1069*663afb9bSAndroid Build Coastguard Worker 	if (total_read_out)
1070*663afb9bSAndroid Build Coastguard Worker 		*total_read_out = grp->total_read;
1071*663afb9bSAndroid Build Coastguard Worker 	if (total_written_out)
1072*663afb9bSAndroid Build Coastguard Worker 		*total_written_out = grp->total_written;
1073*663afb9bSAndroid Build Coastguard Worker }
1074*663afb9bSAndroid Build Coastguard Worker 
1075*663afb9bSAndroid Build Coastguard Worker void
bufferevent_rate_limit_group_reset_totals(struct bufferevent_rate_limit_group * grp)1076*663afb9bSAndroid Build Coastguard Worker bufferevent_rate_limit_group_reset_totals(struct bufferevent_rate_limit_group *grp)
1077*663afb9bSAndroid Build Coastguard Worker {
1078*663afb9bSAndroid Build Coastguard Worker 	grp->total_read = grp->total_written = 0;
1079*663afb9bSAndroid Build Coastguard Worker }
1080*663afb9bSAndroid Build Coastguard Worker 
1081*663afb9bSAndroid Build Coastguard Worker int
bufferevent_ratelim_init_(struct bufferevent_private * bev)1082*663afb9bSAndroid Build Coastguard Worker bufferevent_ratelim_init_(struct bufferevent_private *bev)
1083*663afb9bSAndroid Build Coastguard Worker {
1084*663afb9bSAndroid Build Coastguard Worker 	bev->rate_limiting = NULL;
1085*663afb9bSAndroid Build Coastguard Worker 	bev->max_single_read = MAX_SINGLE_READ_DEFAULT;
1086*663afb9bSAndroid Build Coastguard Worker 	bev->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
1087*663afb9bSAndroid Build Coastguard Worker 
1088*663afb9bSAndroid Build Coastguard Worker 	return 0;
1089*663afb9bSAndroid Build Coastguard Worker }
1090