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