Layer: L4 Transport ยท Build flags: PC_ENABLE_PER_IP_THROTTLE
What this example teaches
The global accept throttle caps total accepts but cannot tell one noisy client from many legitimate ones. This per-IP throttle closes that gap: the accept callback rejects a new connection once a single source IPv4 has opened more than PC_PER_IP_THROTTLE_MAX connections within PC_PER_IP_THROTTLE_WINDOW_MS, so one abusive host is throttled without affecting everyone else.
Bounded memory, no heap. A fixed BSS table of PC_PER_IP_THROTTLE_SLOTS buckets tracks the busiest recent addresses (an LRU-ish set, not one slot per possible IP), so the defense itself stays deterministic.
Build-time only. Like the global throttle, there is no runtime API - the handler is plain; enabling the flag activates the defense in the accept path:
server.begin(80);
@ HTTP_GET
Safe, idempotent read.
Fully-parsed HTTP/1.1 request.
Tuning + pairing. Set the knobs as build flags (cap, window, table size), and pair it with the global accept throttle for layered defense:
build_flags = -DPC_ENABLE_PER_IP_THROTTLE=1 -DPC_PER_IP_THROTTLE_MAX=10 \
-DPC_PER_IP_THROTTLE_WINDOW_MS=10000 -DPC_PER_IP_THROTTLE_SLOTS=16
Build and run
pio ci --board=esp32dev --project-option="framework=arduino" \
--project-option="build_flags=-DPC_ENABLE_PER_IP_THROTTLE=1" \
--lib="." examples/L4-Transport/PerIpThrottle/PerIpThrottle.ino
From one host, open many rapid connections and watch that host get refused while another host still connects.
Annotated source
The complete sketch (PerIpThrottle.ino), reproduced verbatim with added explanatory comments:
#define PC_ENABLE_PER_IP_THROTTLE 1
static const char *SSID = "YOUR_SSID";
static const char *PASSWORD = "YOUR_PASSWORD";
void setup()
{
Serial.print("Connecting to WiFi");
{
delay(250);
Serial.print('.');
}
Serial.printf("IP: %u.%u.%u.%u\n", (unsigned)(ip & 0xFF), (unsigned)((ip >> 8) & 0xFF),
(unsigned)((ip >> 16) & 0xFF), (unsigned)((ip >> 24) & 0xFF));
}
void loop()
{
}
Single-port HTTP server with deterministic, zero-allocation execution.
void send(uint8_t slot_id, int code, const char *content_type, const char *payload)
Send an HTTP response with a body and close the connection.
int32_t begin(const WebServerConfig *cfg=nullptr)
Initialize all connection slots and open all registered listeners.
void on(const char *path, HttpMethod method, Handler callback)
Register a route handler.
void handle()
Drive the server - call every Arduino loop() iteration.
bool init_wifi_physical(const char *, const char *)
Connect to a WiFi access point.
uint32_t pc_net_egress_ip(void)
IPv4 (network byte order) of the current egress interface, or 0 if none.
bool wifi_ready()
True if the WiFi station link is up (associated + an IP is assigned).
Layer 1 (Physical) - link bring-up and live egress-interface reporting.
Layer 7 (Application) - public HTTP routing API.