networking · intermediate · ~15 min

Token-bucket rate limiter (single slot)

Token-bucket rate limiting, a defensive shield against brute force.

Challenge

Implement a single-slot token-bucket rate limiter — the smoothing technique behind rate-limited APIs and brute-force defenses.

Task

Given the bucket struct (defined by the harness):

typedef struct { double tokens; double rate; double max; double last_refill; } bucket_t;

implement int rl_allow(bucket_t *b, double now) that decides whether one request is allowed at time now. It must:

  1. Refill: add rate * (now - last_refill) tokens, capped at max.
  2. Update last_refill = now.
  3. If tokens >= 1.0, consume one token and return 1; otherwise return 0.

Input

  • b: the bucket (carries current tokens, refill rate per unit time, max capacity, and last_refill timestamp).
  • now: the current time, in the same units as rate and last_refill.

Output

Return 1 if a token was available and consumed (request allowed), else 0 (request denied). The bucket is updated in place.

Example

b = {tokens:0, rate:1, max:3, last_refill:0}
rl_allow(&b, 0.0)  ->  0   (no tokens yet)
rl_allow(&b, 1.0)  ->  1   (1s elapsed -> 1 token, consumed)
rl_allow(&b, 1.0)  ->  0   (no time passed, bucket empty)
rl_allow(&b, 5.0)  ->  1   (refill capped at max=3, one consumed)

Edge cases

  • Refilled tokens never exceed max.
  • Calling twice at the same now adds no tokens the second time.

Input format

b: the bucket struct (tokens, rate, max, last_refill); now: current time.

Output format

1 if a token was available and consumed (allowed), else 0; b is updated in place.

Constraints

Refill by rate*(now-last_refill), cap at max, set last_refill=now, then consume one token if >= 1.

Starter code

#include <stdio.h>
int rl_allow(bucket_t *b, double now) { /* TODO */ return 0; }

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.