limits.go RawHistoryFolder
1package brokerwire
2
3// Stateless bound refusals.
4//
5// The broker preamble negotiates one immutable pair of ceilings per
6// connection: MaxReceiveEnvelopeBytes bounds every envelope this side
7// accepts, and StreamChunkLimit bounds one opaque ClientStreamData or
8// ServerStreamData frame. Envelope ceilings are fixed: ordinary envelopes
9// never exceed the advertised floor, and the preamble advertisement itself
10// rides inside BrokerPreambleLimit.
11//
12// The broker has no Output/image/picker bulk category: every application
13// envelope is control-class and shares one ceiling. Stream chunk payloads
14// are bounded separately so hostile lengths never allocate.
15
16import (
17 "github.com/bnema/vev/internal/protocol/wire"
18)
19
20const (
21 // BrokerRoleClient is the broker preamble client role. It is disjoint
22 // from the session preamble roles 1/2.
23 BrokerRoleClient uint32 = 3
24 // BrokerRoleServer is the broker preamble server role.
25 BrokerRoleServer uint32 = 4
26
27 // BrokerPreambleLimit bounds the serialized broker preamble envelope.
28 BrokerPreambleLimit = 4 << 10
29
30 // MinBrokerEnvelopeBytes is the advertised-envelope floor: a broker
31 // peer must accept at least 1 MiB per envelope.
32 MinBrokerEnvelopeBytes uint64 = 1 << 20
33 // MaxBrokerEnvelopeBytes is the advertised-envelope ceiling: a broker
34 // peer must never advertise above 16 MiB (wire.AbsoluteEnvelopeLimit).
35 MaxBrokerEnvelopeBytes uint64 = wire.AbsoluteEnvelopeLimit
36
37 // MinStreamChunkBytes is the smallest legal stream chunk ceiling.
38 MinStreamChunkBytes uint64 = 1
39 // MaxStreamChunkBytes is the largest legal stream chunk ceiling:
40 // 64 KiB per opaque stream frame.
41 MaxStreamChunkBytes uint64 = 64 << 10
42
43 // StreamWindowBytes is the stream-data credit each side of one logical
44 // stream grants its peer per direction. A sender spends StreamChunkCredit
45 // per data frame and waits when it has too little, so the receiver never
46 // queues more than this per stream; StreamWindowUpdate returns the credit
47 // of consumed frames.
48 StreamWindowBytes uint64 = 4 << 20
49 // StreamChunkCreditOverhead is the fixed credit one data frame costs on top
50 // of its payload, so a burst of tiny frames is bounded in count as well.
51 StreamChunkCreditOverhead uint64 = 64
52)
53
54// StreamChunkCredit is the flow-control cost of one stream data frame of n
55// payload bytes.
56func StreamChunkCredit(n int) uint64 { return uint64(n) + StreamChunkCreditOverhead }
57
58// Ceilings are the immutable per-connection ceilings negotiated once by the
59// broker preamble. MaxReceiveEnvelopeBytes bounds every envelope this side
60// accepts; StreamChunkLimit bounds one opaque stream data frame in either
61// direction.
62//
63// The preamble helpers and the connection dispatcher share this value: a
64// caller that completed the preamble reads the negotiated limits from
65// BrokerPreambleRequest or BrokerPreambleResponse and passes them to
66// EncodeClient/DecodeClient and EncodeServer/DecodeServer.
67type Ceilings struct {
68 MaxReceiveEnvelopeBytes uint64
69 StreamChunkLimit uint64
70}
71
72// brokerCeilings is the in-package alias for Ceilings. It exists only so
73// The codec tests keep their short spelling; production code uses Ceilings.
74type brokerCeilings = Ceilings
75
76// defaultBrokerCeilings advertises the local broker receive policy: the
77// full absolute envelope ceiling and the maximum stream chunk.
78func defaultBrokerCeilings() Ceilings {
79 return Ceilings{
80 MaxReceiveEnvelopeBytes: wire.AbsoluteEnvelopeLimit,
81 StreamChunkLimit: MaxStreamChunkBytes,
82 }
83}
84
85// DefaultCeilings returns the local broker receive policy: the full absolute
86// envelope ceiling and the maximum stream chunk. It is the offer a broker IPC
87// client or server advertises before negotiation.
88func DefaultCeilings() Ceilings { return defaultBrokerCeilings() }
89
90// effectiveBrokerCeilings takes the minima of both sides' advertisements.
91func effectiveBrokerCeilings(local, remote Ceilings) Ceilings {
92 return Ceilings{
93 MaxReceiveEnvelopeBytes: min(local.MaxReceiveEnvelopeBytes, remote.MaxReceiveEnvelopeBytes),
94 StreamChunkLimit: min(local.StreamChunkLimit, remote.StreamChunkLimit),
95 }
96}
97
98// EffectiveCeilings returns the element-wise minima of the two advertised
99// ceilings: one byte stream carries exactly the limits both peers accepted.
100func EffectiveCeilings(local, remote Ceilings) Ceilings {
101 return effectiveBrokerCeilings(local, remote)
102}
103
104// checkBrokerCeilings refuses a zero, below-floor, or above-ceiling
105// advertisement. Envelope bounds are the 1 MiB..16 MiB advertised window;
106// chunk bounds are 1..64 KiB.
107func checkBrokerCeilings(remote Ceilings) error {
108 if remote.MaxReceiveEnvelopeBytes < MinBrokerEnvelopeBytes ||
109 remote.MaxReceiveEnvelopeBytes > MaxBrokerEnvelopeBytes {
110 return ErrPreambleRejected
111 }
112 if remote.StreamChunkLimit < MinStreamChunkBytes ||
113 remote.StreamChunkLimit > MaxStreamChunkBytes {
114 return ErrPreambleRejected
115 }
116 return nil
117}
118
119// Validate reports whether one advertised ceiling is negotiable: an envelope
120// window inside 1 MiB..16 MiB and a stream chunk inside 1..64 KiB.
121func (c Ceilings) Validate() error { return checkBrokerCeilings(c) }
122
123// checkBrokerEnvelopeCeiling rejects one serialized broker envelope above
124// the negotiated ceiling. All broker envelopes are control-class: the
125// negotiated ceiling always applies in full.
126func checkBrokerEnvelopeCeiling(payload []byte, ceiling uint64) error {
127 if uint64(len(payload)) > ceiling {
128 return wire.ErrScanLength
129 }
130 return nil
131}
132
133// CheckPreambleSize refuses one serialized broker preamble above the 4 KiB
134// bound before scanning or allocation. Callers apply it to an encoded
135// preamble before sending and to a received payload before decode; the
136// session contract applies the identical wire.PreambleLimit.
137func CheckPreambleSize(payload []byte) error {
138 if len(payload) > BrokerPreambleLimit {
139 return ErrPreambleRejected
140 }
141 return nil
142}