nx_net_governor.nx source
↩ module page · 70 lines · 2847 B
1// nx_net_governor.nx -- general network traffic-shaping governor (ISP-safe).
2//
3// module: nishi-core.net.governor
4// depends: nx_syscalls.nx
5// capability: CORE_COMPUTE
6// wired_status: FULLY_WIRED
7//
8// A REUSABLE bits-up primitive for ANY network client that must not look like
9// abuse to an ISP/IDS (which penalize BitTorrent-like / scan-like behavior:
10// many rapid connections to many IPs, sustained high bandwidth, DNS floods).
11// It shapes aggregate activity to a slow, ordinary profile:
12// * GLOBAL min-interval between ANY two requests/connections (low steady rate)
13// * total request/connection cap + total byte budget per run (low volume)
14// * per-transfer size cap (no huge transfers)
15// Pair with: standard ports, GET-only / no-seed, sequential concurrency, DNS
16// caching. Used by the crawler today; the SAME governor will pace the future
17// torrent client (per-peer connection rate + upload/download byte budgets) and
18// any other network worker. Deterministic; the caller passes the clock.
19
20import "nx_syscalls.nx"
21
22struct NxNetGov {
23 min_interval_ms: i64, // floor between ANY two requests/connections
24 max_requests: i64, // hard cap on requests/connections this run
25 byte_budget: i64, // hard cap on bytes transferred this run
26 max_resp_bytes: i64, // per-transfer size cap
27 n_requests: i64,
28 bytes_used: i64,
29 last_ms: i64,
30}
31const NX_NETGOV_BYTES: i64 = 56 // 7 * 8
32
33func nx_gov_init(g: *NxNetGov, min_interval_ms: i64, max_requests: i64,
34 byte_budget: i64, max_resp_bytes: i64) -> i64 {
35 g.min_interval_ms = min_interval_ms
36 g.max_requests = max_requests
37 g.byte_budget = byte_budget
38 g.max_resp_bytes = max_resp_bytes
39 g.n_requests = 0
40 g.bytes_used = 0
41 g.last_ms = 0 - min_interval_ms // allow the very first request immediately
42 return 0
43}
44
45// Still under the run's request + byte budgets? (0 => stop.)
46func nx_gov_can_fetch(g: *NxNetGov) -> i64 {
47 if g.n_requests >= g.max_requests { return 0 }
48 if g.bytes_used >= g.byte_budget { return 0 }
49 return 1
50}
51
52// ms to sleep before the next request to honor the GLOBAL min-interval (keeps
53// the connection rate low + steady, not bursty/scan-like).
54func nx_gov_wait_ms(g: *NxNetGov, now_ms: i64) -> i64 {
55 let elapsed: i64 = now_ms - g.last_ms
56 if elapsed >= g.min_interval_ms { return 0 }
57 return g.min_interval_ms - elapsed
58}
59
60// Record a completed request/transfer (updates rate clock + budgets).
61func nx_gov_record(g: *NxNetGov, now_ms: i64, bytes: i64) -> i64 {
62 g.n_requests = g.n_requests + 1
63 g.bytes_used = g.bytes_used + bytes
64 g.last_ms = now_ms
65 return 0
66}
67
68// Per-transfer size cap (truncate large transfers so one doesn't blow the
69// bandwidth profile).
70func nx_gov_resp_cap(g: *NxNetGov) -> i64 { return g.max_resp_bytes }