Skip to content

4.8.2 Network Configuration

Import :std/ensemble/network/config for NetworkConfig, NetworkLimits, ConnectionLimits, and StreamLimits. Each is a final typed class with keyword construction, generated predicates, accessors, and setters. For example, (NetworkConfig connection-ttl: 7200) overrides one default.

Treat these objects, their nested limits, and their IOTimeout values as immutable while in use. Supplied nested objects are retained, not defensively copied. Default nested limits are freshly constructed; no-timeout defaults use the shared preconstructed !NoTimeout object. Do not mutate that sentinel. No transport or network constructor is implemented by this module.

4.8.2.1 Defaults

NetworkConfig separates authorization lifetimes, operation budgets, and I/O:

Keyword Default Contract
connection-ttl: 3600 Positive exact integer seconds
stream-ttl: 3600 Positive exact integer seconds
handshake-timeout: 10 Positive exact integer seconds
stream-open-timeout: 10 Positive exact integer seconds
renewal-timeout: 10 Positive exact integer seconds
connection-input-timeout: !NoTimeout IOTimeout
connection-output-timeout: !NoTimeout IOTimeout
stream-input-timeout: !NoTimeout IOTimeout
stream-output-timeout: !NoTimeout IOTimeout

Import :std/time/timeout to construct I/O overrides, such as (IOTimeout 30). The wrapper uses the existing timeout semantics; bare numbers and #f are not accepted in these fields. Operation budgets instead take durations, not wrappers or absolute times. Fractional and inexact operation durations are rejected; the separate IOTimeout representation retains its existing precision and semantics. TTLs are defaults, not lifetime ceilings. Operation code, not configuration construction, validates resolved expirations/deadlines against the wire range before encoding.

4.8.2.2 Resource Limits

Class Keyword Default Contract
NetworkLimits pending-connections: 32 Nonnegative fixnum
NetworkLimits election-history: 256 Nonnegative fixnum
NetworkLimits connection-limits: (ConnectionLimits) ConnectionLimits
ConnectionLimits total-streams: 128 Nonnegative fixnum
ConnectionLimits pending-streams: 16 Nonnegative fixnum
ConnectionLimits renewing-streams: 16 Positive fixnum
ConnectionLimits hello-payload: 4096 Positive u32 bytes
ConnectionLimits data-payload: 16384 Positive u32 bytes
ConnectionLimits control-payload: 65536 Positive u32 bytes
ConnectionLimits pending-control-frames: 256 Positive fixnum
ConnectionLimits pending-control-bytes: 262144 Positive fixnum bytes
ConnectionLimits control-burst: 8 Positive fixnum
ConnectionLimits stream-limits: (StreamLimits) StreamLimits
StreamLimits recv-window: 262144 Positive power-of-two u32 bytes
StreamLimits outbound-buffer: 262144 Positive power-of-two fixnum bytes

Positive u32 means an exact integer from 1 through 4294967295, inclusive. Local stream capacities must additionally be powers of two, including 1; values such as 3 and 5 are rejected, never rounded. The largest configured receive window is 2147483648; constructing stream state also requires native fixnum indexes. The peer’s advertised receive window remains any positive u32 that fits a native fixnum, with no power-of-two requirement. Payload and control limits are unchanged. Zero admission caps disable admission. Total streams counts pending and open streams in both directions together. Payload limits exclude the 13-byte frame header; pending-control bytes include headers. The control burst bounds control scheduling before ready DATA gets a turn.

renewing-streams bounds local-initiated and peer-initiated stream renewal worker ownership separately. At most twice this limit of stream renewal scopes, plus one independent connection renewal scope, may own workers. Each charged slot owns at most one worker; retired-but-running workers retain their charge until actual release. A live stream owns at most one admitted round; a deferred next OFFER has no worker. This is neither an OPEN admission cap nor a caller/waiter limit, and zero is not accepted. The field adds generated ConnectionLimits-renewing-streams and ConnectionLimits-renewing-streams-set! exports. Construction and checked setters enforce the positive-fixnum contract.

The connection runtime enforces these worker bounds and schedules renewal. Connection-round capacity is independent of stream-round worker quotas; all renewal output uses the existing aggregate control budgets. Renewable/linked policy and connection renewal require four protected control-frame slots and control-payload + 13 + 3 * 38 bytes within those budgets. The 38-byte bound is the version-1 RENEW-REQUEST including its header. This is protected capacity, not extra capacity or preallocated buffers. Insufficient configured or currently available capacity is an operation-admission failure before policy changes, not a new cross-field constructor constraint.

Pending renewable joins check configured capacity before accepting interest; the elected connection installs actual protection before activation. Later attachments check that parent’s available capacity. Once enabled, protection lasts until connection close. Ordinary and stream-renewal staging, queued frames, and in-flight work use only the unprotected remainder. Capacity waiting does not consume an automatic attempt or start credential encoding. See renewal-plan.md for the preserved design handoff.

pending-connections bounds physical setup/handshake reservations. election-history independently bounds retained commit records, including active committed entries and completed peers still protected against delayed unidentified reservations. Zero disables new history reservations, not physical reservations. History exhaustion raises IOError without evicting existing protection; resolving or retiring the old cohort releases history capacity. Neither limit constrains the other’s configured value. See network.md for transition timing.

Limits are independent: pending streams need not be less than total streams, a window need not hold a full DATA frame, and a control queue need not hold the largest allowed control payload. Each bound applies independently; small limits can make some operations impossible rather than invalidate the configuration.

Stream rings borrow exact-capacity vectors lazily from :std/io/bio/cache on first nonempty input and return them when ownership ends; see stream.md. Buffer ceilings do not eagerly allocate memory. The default 128-stream cap allows 32 MiB of receive DATA and 32 MiB of outbound DATA buffering per connection, not including metadata, control work, or transport buffers.

Invalid constructor fields raise contract exceptions. Checked generated setters also enforce field contracts, but mutation while in use is unsupported. There is no separate validation framework or live reconfiguration API.