--- a/mod_limits/README.markdown Mon Nov 22 21:01:53 2021 +0100
+++ b/mod_limits/README.markdown Fri Jul 09 20:54:40 2021 +0200
@@ -1,68 +1,8 @@
---
labels:
-- 'Stage-Beta'
+- 'Stage-Obsolete'
summary: 'Connection-level rate limiting'
+superseded_by: mod_limits
...
-Introduction
-============
-
-On some servers, especially public ones, it is desired to make sure that
-everyone gets their fair share of system resources (and no more).
-
-mod\_limits allows you to specify traffic bandwidth limits, preventing
-any single connection hogging the server's CPU, RAM and bandwidth.
-
-Details
-=======
-
-mod\_limits detects when a connection has exceeded its traffic allowance
-and temporarily ignores a connection. Due to the way TCP and the OS's
-network API works no data is lost, only slowed.
-
-Configuration
-=============
-
-Currently mod\_limits is configured per connection type. The possible
-connection types are:
-
-- c2s
-- s2sin
-- s2sout
-- component
-
-The limits are specified like so in the **global** section of your
-config (they cannot be per-host):
-
-``` {.lua}
-limits = {
- c2s = {
- rate = "3kb/s";
- burst = "2s";
- };
- s2sin = {
- rate = "10kb/s";
- burst = "5s";
- };
-}
-```
-
-All units are in terms of *bytes*, not *bits*, so that "kb/s" is
-interpreted as "kilobytes per second", where a kilobyte is 1000 bytes.
-
-Compatibility
-=============
-
- ----- -------------------
- 0.9 Works
- 0.8 Doesn't work(\*)
- ----- -------------------
-
-(\*) This module can be made to work in 0.8 if you do two things:
-
-1. Install
- [util.throttle](http://hg.prosody.im/0.9/raw-file/d46948d3018a/util/throttle.lua)
- into your Prosody source's util/ directory.
-2. If you use libevent apply [this
- patch](http://prosody.im/patches/prosody08-mod-limits-fix.patch) to
- net/server\_event.lua.
+Since Prosody 0.10, this module is [included in Prosody](https://prosody.im/doc/modules/mod_limits), you will be redirected there shortly.
--- a/mod_limits/mod_limits.lua Mon Nov 22 21:01:53 2021 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
--- mod_limits: Rate-limiting for Prosody
--- Version: Alpha
--- Author: Matthew Wild <mwild1@gmail.com>
-
--- Because we deal we pre-authed sessions and streams we can't be host-specific
-module:set_global();
-
-local filters = require "util.filters";
-local throttle = require "util.throttle";
-local timer = require "util.timer";
-local ceil = math.ceil;
-
-local limits_cfg = module:get_option("limits", {});
-local limits_resolution = module:get_option_number("limits_resolution", 1);
-
-local default_bytes_per_second = 3000;
-local default_burst = 2;
-
-local rate_units = { b = 1, k = 3, m = 6, g = 9, t = 12 } -- Plan for the future.
-local function parse_rate(rate, sess_type)
- local quantity, unit, exp;
- if rate then
- quantity, unit = rate:match("^(%d+) ?([^/]+)/s$");
- exp = quantity and rate_units[unit:sub(1,1):lower()];
- end
- if not exp then
- module:log("error", "Error parsing rate for %s: %q, using default rate (%d bytes/s)", sess_type, rate, default_bytes_per_second);
- return default_bytes_per_second;
- end
- return quantity*(10^exp);
-end
-
-local function parse_burst(burst, sess_type)
- if type(burst) == "string" then
- burst = burst:match("^(%d+) ?s$");
- end
- local n_burst = tonumber(burst);
- if not n_burst then
- module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, tostring(burst), default_burst);
- end
- return n_burst or default_burst;
-end
-
--- Process config option into limits table:
--- limits = { c2s = { bytes_per_second = X, burst_seconds = Y } }
-local limits = {};
-
-for sess_type, sess_limits in pairs(limits_cfg) do
- limits[sess_type] = {
- bytes_per_second = parse_rate(sess_limits.rate, sess_type);
- burst_seconds = parse_burst(sess_limits.burst, sess_type);
- };
-end
-
-local default_filter_set = {};
-
-function default_filter_set.bytes_in(bytes, session)
- local throttle = session.throttle;
- if throttle then
- local ok, balance, outstanding = throttle:poll(#bytes, true);
- if not ok then
- session.log("debug", "Session %q over rate limit (%d) with %d (by %d), pausing", session.full_jid or session.from_host or session.to_host, throttle.max, #bytes, outstanding);
- outstanding = ceil(outstanding);
- session.conn:pause(); -- Read no more data from the connection until there is no outstanding data
- local outstanding_data = bytes:sub(-outstanding);
- bytes = bytes:sub(1, #bytes-outstanding);
- timer.add_task(limits_resolution, function ()
- if not session.conn then return; end
- if throttle:peek(#outstanding_data) then
- session.log("debug", "Resuming paused session");
- session.conn:resume();
- end
- session.log("debug", "mod_limits feeding %d bytes of delayed data into stream", #outstanding_data);
- -- Handle what we can of the outstanding data
- session.data(outstanding_data);
- end);
- end
- end
- return bytes;
-end
-
-local type_filters = {
- c2s = default_filter_set;
- s2sin = default_filter_set;
- s2sout = default_filter_set;
-};
-
-local function filter_hook(session)
- local session_type = session.type:match("^[^_]+");
- local filter_set, opts = type_filters[session_type], limits[session_type];
- if opts then
- session.throttle = throttle.create(opts.bytes_per_second * opts.burst_seconds, opts.burst_seconds);
- filters.add_filter(session, "bytes/in", filter_set.bytes_in, 1000);
- end
-end
-
-function module.load()
- filters.add_filter_hook(filter_hook);
-end
-
-function module.unload()
- filters.remove_filter_hook(filter_hook);
-end