1*00b67f09SDavid van Moolenbroek /* $NetBSD: ratelimiter.c,v 1.6 2015/07/08 17:28:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007, 2012, 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2002 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: ratelimiter.c,v 1.25 2007/06/19 23:47:17 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek
26*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
27*00b67f09SDavid van Moolenbroek #include <isc/ratelimiter.h>
28*00b67f09SDavid van Moolenbroek #include <isc/task.h>
29*00b67f09SDavid van Moolenbroek #include <isc/time.h>
30*00b67f09SDavid van Moolenbroek #include <isc/timer.h>
31*00b67f09SDavid van Moolenbroek #include <isc/util.h>
32*00b67f09SDavid van Moolenbroek
33*00b67f09SDavid van Moolenbroek typedef enum {
34*00b67f09SDavid van Moolenbroek isc_ratelimiter_stalled = 0,
35*00b67f09SDavid van Moolenbroek isc_ratelimiter_ratelimited = 1,
36*00b67f09SDavid van Moolenbroek isc_ratelimiter_idle = 2,
37*00b67f09SDavid van Moolenbroek isc_ratelimiter_shuttingdown = 3
38*00b67f09SDavid van Moolenbroek } isc_ratelimiter_state_t;
39*00b67f09SDavid van Moolenbroek
40*00b67f09SDavid van Moolenbroek struct isc_ratelimiter {
41*00b67f09SDavid van Moolenbroek isc_mem_t * mctx;
42*00b67f09SDavid van Moolenbroek isc_mutex_t lock;
43*00b67f09SDavid van Moolenbroek int refs;
44*00b67f09SDavid van Moolenbroek isc_task_t * task;
45*00b67f09SDavid van Moolenbroek isc_timer_t * timer;
46*00b67f09SDavid van Moolenbroek isc_interval_t interval;
47*00b67f09SDavid van Moolenbroek isc_uint32_t pertic;
48*00b67f09SDavid van Moolenbroek isc_ratelimiter_state_t state;
49*00b67f09SDavid van Moolenbroek isc_event_t shutdownevent;
50*00b67f09SDavid van Moolenbroek ISC_LIST(isc_event_t) pending;
51*00b67f09SDavid van Moolenbroek };
52*00b67f09SDavid van Moolenbroek
53*00b67f09SDavid van Moolenbroek #define ISC_RATELIMITEREVENT_SHUTDOWN (ISC_EVENTCLASS_RATELIMITER + 1)
54*00b67f09SDavid van Moolenbroek
55*00b67f09SDavid van Moolenbroek static void
56*00b67f09SDavid van Moolenbroek ratelimiter_tick(isc_task_t *task, isc_event_t *event);
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek static void
59*00b67f09SDavid van Moolenbroek ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event);
60*00b67f09SDavid van Moolenbroek
61*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_create(isc_mem_t * mctx,isc_timermgr_t * timermgr,isc_task_t * task,isc_ratelimiter_t ** ratelimiterp)62*00b67f09SDavid van Moolenbroek isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
63*00b67f09SDavid van Moolenbroek isc_task_t *task, isc_ratelimiter_t **ratelimiterp)
64*00b67f09SDavid van Moolenbroek {
65*00b67f09SDavid van Moolenbroek isc_result_t result;
66*00b67f09SDavid van Moolenbroek isc_ratelimiter_t *rl;
67*00b67f09SDavid van Moolenbroek INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
68*00b67f09SDavid van Moolenbroek
69*00b67f09SDavid van Moolenbroek rl = isc_mem_get(mctx, sizeof(*rl));
70*00b67f09SDavid van Moolenbroek if (rl == NULL)
71*00b67f09SDavid van Moolenbroek return ISC_R_NOMEMORY;
72*00b67f09SDavid van Moolenbroek rl->mctx = mctx;
73*00b67f09SDavid van Moolenbroek rl->refs = 1;
74*00b67f09SDavid van Moolenbroek rl->task = task;
75*00b67f09SDavid van Moolenbroek isc_interval_set(&rl->interval, 0, 0);
76*00b67f09SDavid van Moolenbroek rl->timer = NULL;
77*00b67f09SDavid van Moolenbroek rl->pertic = 1;
78*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_idle;
79*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(rl->pending);
80*00b67f09SDavid van Moolenbroek
81*00b67f09SDavid van Moolenbroek result = isc_mutex_init(&rl->lock);
82*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
83*00b67f09SDavid van Moolenbroek goto free_mem;
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek result = isc_timer_create(timermgr, isc_timertype_inactive,
86*00b67f09SDavid van Moolenbroek NULL, NULL, rl->task, ratelimiter_tick,
87*00b67f09SDavid van Moolenbroek rl, &rl->timer);
88*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
89*00b67f09SDavid van Moolenbroek goto free_mutex;
90*00b67f09SDavid van Moolenbroek
91*00b67f09SDavid van Moolenbroek /*
92*00b67f09SDavid van Moolenbroek * Increment the reference count to indicate that we may
93*00b67f09SDavid van Moolenbroek * (soon) have events outstanding.
94*00b67f09SDavid van Moolenbroek */
95*00b67f09SDavid van Moolenbroek rl->refs++;
96*00b67f09SDavid van Moolenbroek
97*00b67f09SDavid van Moolenbroek ISC_EVENT_INIT(&rl->shutdownevent,
98*00b67f09SDavid van Moolenbroek sizeof(isc_event_t),
99*00b67f09SDavid van Moolenbroek 0, NULL, ISC_RATELIMITEREVENT_SHUTDOWN,
100*00b67f09SDavid van Moolenbroek ratelimiter_shutdowncomplete, rl, rl, NULL, NULL);
101*00b67f09SDavid van Moolenbroek
102*00b67f09SDavid van Moolenbroek *ratelimiterp = rl;
103*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
104*00b67f09SDavid van Moolenbroek
105*00b67f09SDavid van Moolenbroek free_mutex:
106*00b67f09SDavid van Moolenbroek DESTROYLOCK(&rl->lock);
107*00b67f09SDavid van Moolenbroek free_mem:
108*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, rl, sizeof(*rl));
109*00b67f09SDavid van Moolenbroek return (result);
110*00b67f09SDavid van Moolenbroek }
111*00b67f09SDavid van Moolenbroek
112*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_setinterval(isc_ratelimiter_t * rl,isc_interval_t * interval)113*00b67f09SDavid van Moolenbroek isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
114*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
115*00b67f09SDavid van Moolenbroek
116*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
117*00b67f09SDavid van Moolenbroek REQUIRE(interval != NULL);
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
120*00b67f09SDavid van Moolenbroek rl->interval = *interval;
121*00b67f09SDavid van Moolenbroek /*
122*00b67f09SDavid van Moolenbroek * If the timer is currently running, change its rate.
123*00b67f09SDavid van Moolenbroek */
124*00b67f09SDavid van Moolenbroek if (rl->state == isc_ratelimiter_ratelimited) {
125*00b67f09SDavid van Moolenbroek result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
126*00b67f09SDavid van Moolenbroek &rl->interval, ISC_FALSE);
127*00b67f09SDavid van Moolenbroek }
128*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
129*00b67f09SDavid van Moolenbroek return (result);
130*00b67f09SDavid van Moolenbroek }
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek void
isc_ratelimiter_setpertic(isc_ratelimiter_t * rl,isc_uint32_t pertic)133*00b67f09SDavid van Moolenbroek isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) {
134*00b67f09SDavid van Moolenbroek
135*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
136*00b67f09SDavid van Moolenbroek
137*00b67f09SDavid van Moolenbroek if (pertic == 0)
138*00b67f09SDavid van Moolenbroek pertic = 1;
139*00b67f09SDavid van Moolenbroek rl->pertic = pertic;
140*00b67f09SDavid van Moolenbroek }
141*00b67f09SDavid van Moolenbroek
142*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_enqueue(isc_ratelimiter_t * rl,isc_task_t * task,isc_event_t ** eventp)143*00b67f09SDavid van Moolenbroek isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
144*00b67f09SDavid van Moolenbroek isc_event_t **eventp)
145*00b67f09SDavid van Moolenbroek {
146*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
147*00b67f09SDavid van Moolenbroek isc_event_t *ev;
148*00b67f09SDavid van Moolenbroek
149*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
150*00b67f09SDavid van Moolenbroek REQUIRE(task != NULL);
151*00b67f09SDavid van Moolenbroek REQUIRE(eventp != NULL && *eventp != NULL);
152*00b67f09SDavid van Moolenbroek ev = *eventp;
153*00b67f09SDavid van Moolenbroek REQUIRE(ev->ev_sender == NULL);
154*00b67f09SDavid van Moolenbroek
155*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
156*00b67f09SDavid van Moolenbroek if (rl->state == isc_ratelimiter_ratelimited ||
157*00b67f09SDavid van Moolenbroek rl->state == isc_ratelimiter_stalled) {
158*00b67f09SDavid van Moolenbroek ev->ev_sender = task;
159*00b67f09SDavid van Moolenbroek *eventp = NULL;
160*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(rl->pending, ev, ev_link);
161*00b67f09SDavid van Moolenbroek } else if (rl->state == isc_ratelimiter_idle) {
162*00b67f09SDavid van Moolenbroek result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
163*00b67f09SDavid van Moolenbroek &rl->interval, ISC_FALSE);
164*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS) {
165*00b67f09SDavid van Moolenbroek ev->ev_sender = task;
166*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_ratelimited;
167*00b67f09SDavid van Moolenbroek }
168*00b67f09SDavid van Moolenbroek } else {
169*00b67f09SDavid van Moolenbroek INSIST(rl->state == isc_ratelimiter_shuttingdown);
170*00b67f09SDavid van Moolenbroek result = ISC_R_SHUTTINGDOWN;
171*00b67f09SDavid van Moolenbroek }
172*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
173*00b67f09SDavid van Moolenbroek if (*eventp != NULL && result == ISC_R_SUCCESS)
174*00b67f09SDavid van Moolenbroek isc_task_send(task, eventp);
175*00b67f09SDavid van Moolenbroek return (result);
176*00b67f09SDavid van Moolenbroek }
177*00b67f09SDavid van Moolenbroek
178*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_dequeue(isc_ratelimiter_t * rl,isc_event_t * event)179*00b67f09SDavid van Moolenbroek isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event) {
180*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
183*00b67f09SDavid van Moolenbroek REQUIRE(event != NULL);
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
186*00b67f09SDavid van Moolenbroek if (ISC_LINK_LINKED(event, ev_link)) {
187*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(rl->pending, event, ev_link);
188*00b67f09SDavid van Moolenbroek event->ev_sender = NULL;
189*00b67f09SDavid van Moolenbroek } else
190*00b67f09SDavid van Moolenbroek result = ISC_R_NOTFOUND;
191*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
192*00b67f09SDavid van Moolenbroek return (result);
193*00b67f09SDavid van Moolenbroek }
194*00b67f09SDavid van Moolenbroek
195*00b67f09SDavid van Moolenbroek static void
ratelimiter_tick(isc_task_t * task,isc_event_t * event)196*00b67f09SDavid van Moolenbroek ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
197*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
198*00b67f09SDavid van Moolenbroek isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
199*00b67f09SDavid van Moolenbroek isc_event_t *p;
200*00b67f09SDavid van Moolenbroek isc_uint32_t pertic;
201*00b67f09SDavid van Moolenbroek
202*00b67f09SDavid van Moolenbroek UNUSED(task);
203*00b67f09SDavid van Moolenbroek
204*00b67f09SDavid van Moolenbroek isc_event_free(&event);
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek pertic = rl->pertic;
207*00b67f09SDavid van Moolenbroek while (pertic != 0) {
208*00b67f09SDavid van Moolenbroek pertic--;
209*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
210*00b67f09SDavid van Moolenbroek p = ISC_LIST_HEAD(rl->pending);
211*00b67f09SDavid van Moolenbroek if (p != NULL) {
212*00b67f09SDavid van Moolenbroek /*
213*00b67f09SDavid van Moolenbroek * There is work to do. Let's do it after unlocking.
214*00b67f09SDavid van Moolenbroek */
215*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(rl->pending, p, ev_link);
216*00b67f09SDavid van Moolenbroek } else {
217*00b67f09SDavid van Moolenbroek /*
218*00b67f09SDavid van Moolenbroek * No work left to do. Stop the timer so that we don't
219*00b67f09SDavid van Moolenbroek * waste resources by having it fire periodically.
220*00b67f09SDavid van Moolenbroek */
221*00b67f09SDavid van Moolenbroek result = isc_timer_reset(rl->timer,
222*00b67f09SDavid van Moolenbroek isc_timertype_inactive,
223*00b67f09SDavid van Moolenbroek NULL, NULL, ISC_FALSE);
224*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
225*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_idle;
226*00b67f09SDavid van Moolenbroek pertic = 0; /* Force the loop to exit. */
227*00b67f09SDavid van Moolenbroek }
228*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
229*00b67f09SDavid van Moolenbroek if (p != NULL) {
230*00b67f09SDavid van Moolenbroek isc_task_t *evtask = p->ev_sender;
231*00b67f09SDavid van Moolenbroek isc_task_send(evtask, &p);
232*00b67f09SDavid van Moolenbroek }
233*00b67f09SDavid van Moolenbroek INSIST(p == NULL);
234*00b67f09SDavid van Moolenbroek }
235*00b67f09SDavid van Moolenbroek }
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek void
isc_ratelimiter_shutdown(isc_ratelimiter_t * rl)238*00b67f09SDavid van Moolenbroek isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
239*00b67f09SDavid van Moolenbroek isc_event_t *ev;
240*00b67f09SDavid van Moolenbroek isc_task_t *task;
241*00b67f09SDavid van Moolenbroek
242*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
243*00b67f09SDavid van Moolenbroek
244*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
245*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_shuttingdown;
246*00b67f09SDavid van Moolenbroek (void)isc_timer_reset(rl->timer, isc_timertype_inactive,
247*00b67f09SDavid van Moolenbroek NULL, NULL, ISC_FALSE);
248*00b67f09SDavid van Moolenbroek while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) {
249*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(rl->pending, ev, ev_link);
250*00b67f09SDavid van Moolenbroek ev->ev_attributes |= ISC_EVENTATTR_CANCELED;
251*00b67f09SDavid van Moolenbroek task = ev->ev_sender;
252*00b67f09SDavid van Moolenbroek isc_task_send(task, &ev);
253*00b67f09SDavid van Moolenbroek }
254*00b67f09SDavid van Moolenbroek isc_timer_detach(&rl->timer);
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek /*
257*00b67f09SDavid van Moolenbroek * Send an event to our task. The delivery of this event
258*00b67f09SDavid van Moolenbroek * indicates that no more timer events will be delivered.
259*00b67f09SDavid van Moolenbroek */
260*00b67f09SDavid van Moolenbroek ev = &rl->shutdownevent;
261*00b67f09SDavid van Moolenbroek isc_task_send(rl->task, &ev);
262*00b67f09SDavid van Moolenbroek
263*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
264*00b67f09SDavid van Moolenbroek }
265*00b67f09SDavid van Moolenbroek
266*00b67f09SDavid van Moolenbroek static void
ratelimiter_shutdowncomplete(isc_task_t * task,isc_event_t * event)267*00b67f09SDavid van Moolenbroek ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event) {
268*00b67f09SDavid van Moolenbroek isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
269*00b67f09SDavid van Moolenbroek
270*00b67f09SDavid van Moolenbroek UNUSED(task);
271*00b67f09SDavid van Moolenbroek
272*00b67f09SDavid van Moolenbroek isc_ratelimiter_detach(&rl);
273*00b67f09SDavid van Moolenbroek }
274*00b67f09SDavid van Moolenbroek
275*00b67f09SDavid van Moolenbroek static void
ratelimiter_free(isc_ratelimiter_t * rl)276*00b67f09SDavid van Moolenbroek ratelimiter_free(isc_ratelimiter_t *rl) {
277*00b67f09SDavid van Moolenbroek DESTROYLOCK(&rl->lock);
278*00b67f09SDavid van Moolenbroek isc_mem_put(rl->mctx, rl, sizeof(*rl));
279*00b67f09SDavid van Moolenbroek }
280*00b67f09SDavid van Moolenbroek
281*00b67f09SDavid van Moolenbroek void
isc_ratelimiter_attach(isc_ratelimiter_t * source,isc_ratelimiter_t ** target)282*00b67f09SDavid van Moolenbroek isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
283*00b67f09SDavid van Moolenbroek
284*00b67f09SDavid van Moolenbroek REQUIRE(source != NULL);
285*00b67f09SDavid van Moolenbroek REQUIRE(target != NULL && *target == NULL);
286*00b67f09SDavid van Moolenbroek
287*00b67f09SDavid van Moolenbroek LOCK(&source->lock);
288*00b67f09SDavid van Moolenbroek REQUIRE(source->refs > 0);
289*00b67f09SDavid van Moolenbroek source->refs++;
290*00b67f09SDavid van Moolenbroek INSIST(source->refs > 0);
291*00b67f09SDavid van Moolenbroek UNLOCK(&source->lock);
292*00b67f09SDavid van Moolenbroek *target = source;
293*00b67f09SDavid van Moolenbroek }
294*00b67f09SDavid van Moolenbroek
295*00b67f09SDavid van Moolenbroek void
isc_ratelimiter_detach(isc_ratelimiter_t ** rlp)296*00b67f09SDavid van Moolenbroek isc_ratelimiter_detach(isc_ratelimiter_t **rlp) {
297*00b67f09SDavid van Moolenbroek isc_ratelimiter_t *rl;
298*00b67f09SDavid van Moolenbroek isc_boolean_t free_now = ISC_FALSE;
299*00b67f09SDavid van Moolenbroek
300*00b67f09SDavid van Moolenbroek REQUIRE(rlp != NULL && *rlp != NULL);
301*00b67f09SDavid van Moolenbroek
302*00b67f09SDavid van Moolenbroek rl = *rlp;
303*00b67f09SDavid van Moolenbroek
304*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
305*00b67f09SDavid van Moolenbroek REQUIRE(rl->refs > 0);
306*00b67f09SDavid van Moolenbroek rl->refs--;
307*00b67f09SDavid van Moolenbroek if (rl->refs == 0)
308*00b67f09SDavid van Moolenbroek free_now = ISC_TRUE;
309*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
310*00b67f09SDavid van Moolenbroek
311*00b67f09SDavid van Moolenbroek if (free_now)
312*00b67f09SDavid van Moolenbroek ratelimiter_free(rl);
313*00b67f09SDavid van Moolenbroek
314*00b67f09SDavid van Moolenbroek *rlp = NULL;
315*00b67f09SDavid van Moolenbroek }
316*00b67f09SDavid van Moolenbroek
317*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_stall(isc_ratelimiter_t * rl)318*00b67f09SDavid van Moolenbroek isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
319*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
320*00b67f09SDavid van Moolenbroek
321*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
322*00b67f09SDavid van Moolenbroek
323*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
324*00b67f09SDavid van Moolenbroek switch (rl->state) {
325*00b67f09SDavid van Moolenbroek case isc_ratelimiter_shuttingdown:
326*00b67f09SDavid van Moolenbroek result = ISC_R_SHUTTINGDOWN;
327*00b67f09SDavid van Moolenbroek break;
328*00b67f09SDavid van Moolenbroek case isc_ratelimiter_ratelimited:
329*00b67f09SDavid van Moolenbroek result = isc_timer_reset(rl->timer, isc_timertype_inactive,
330*00b67f09SDavid van Moolenbroek NULL, NULL, ISC_FALSE);
331*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
332*00b67f09SDavid van Moolenbroek /* FALLTHROUGH */
333*00b67f09SDavid van Moolenbroek case isc_ratelimiter_idle:
334*00b67f09SDavid van Moolenbroek case isc_ratelimiter_stalled:
335*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_stalled;
336*00b67f09SDavid van Moolenbroek break;
337*00b67f09SDavid van Moolenbroek }
338*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
339*00b67f09SDavid van Moolenbroek return (result);
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek
342*00b67f09SDavid van Moolenbroek isc_result_t
isc_ratelimiter_release(isc_ratelimiter_t * rl)343*00b67f09SDavid van Moolenbroek isc_ratelimiter_release(isc_ratelimiter_t *rl) {
344*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
345*00b67f09SDavid van Moolenbroek
346*00b67f09SDavid van Moolenbroek REQUIRE(rl != NULL);
347*00b67f09SDavid van Moolenbroek
348*00b67f09SDavid van Moolenbroek LOCK(&rl->lock);
349*00b67f09SDavid van Moolenbroek switch (rl->state) {
350*00b67f09SDavid van Moolenbroek case isc_ratelimiter_shuttingdown:
351*00b67f09SDavid van Moolenbroek result = ISC_R_SHUTTINGDOWN;
352*00b67f09SDavid van Moolenbroek break;
353*00b67f09SDavid van Moolenbroek case isc_ratelimiter_stalled:
354*00b67f09SDavid van Moolenbroek if (!ISC_LIST_EMPTY(rl->pending)) {
355*00b67f09SDavid van Moolenbroek result = isc_timer_reset(rl->timer,
356*00b67f09SDavid van Moolenbroek isc_timertype_ticker, NULL,
357*00b67f09SDavid van Moolenbroek &rl->interval, ISC_FALSE);
358*00b67f09SDavid van Moolenbroek if (result == ISC_R_SUCCESS)
359*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_ratelimited;
360*00b67f09SDavid van Moolenbroek } else
361*00b67f09SDavid van Moolenbroek rl->state = isc_ratelimiter_idle;
362*00b67f09SDavid van Moolenbroek break;
363*00b67f09SDavid van Moolenbroek case isc_ratelimiter_ratelimited:
364*00b67f09SDavid van Moolenbroek case isc_ratelimiter_idle:
365*00b67f09SDavid van Moolenbroek break;
366*00b67f09SDavid van Moolenbroek }
367*00b67f09SDavid van Moolenbroek UNLOCK(&rl->lock);
368*00b67f09SDavid van Moolenbroek return (result);
369*00b67f09SDavid van Moolenbroek }
370