1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use ;
use crate::;
/// Produces the parameters the server returns in an open reply and will enforce
/// for the session.
///
/// **Protocol version is rewritten to [`PROTOCOL_VERSION`].** A server must
/// return version 1 so that version-1 clients accept the session; any requested
/// value, including an absent, zero, negative or future one, is accepted and
/// answered with 1. Detecting a version mismatch is therefore client-side only.
///
/// **A positive Length above the configured maximum is reduced to it.** That
/// bounds the echo datagram — and so the buffer — a remote peer can make this
/// server negotiate, which is why it happens here rather than at send time: the
/// value returned in the open reply has to be the one the server will actually
/// honor. A negative Length is left exactly as requested and a zero stays zero;
/// neither asks for space beyond the mandatory field block, which `irtt-proto`
/// floors echo sizing at, so there is nothing to reduce and rewriting them would
/// answer with a session the client did not ask for.
///
/// **Duration is reduced to the configured maximum test duration**, when one is
/// configured. A *continuous* request — Duration absent, which is the wire
/// default of zero — is answered with the maximum as well, because restricting
/// continuous mode to a finite test is exactly what configuring a maximum asks
/// for; the client models that as an ordinary duration reduction. An explicit
/// zero or negative Duration never reaches here, being refused during request
/// admission, and a configured maximum is never zero, so a finite request can
/// never be rewritten into a continuous session.
///
/// **Interval is raised to the configured minimum and then capped at a quarter
/// of the idle timeout.** The floor bounds how fast a session may ask to be
/// answered; the cap keeps a well-behaved client from idling itself out by
/// sending at the very interval it was given. An absent Interval takes the floor
/// like any other value below it, since absence means the wire default of zero
/// rather than a refusal — an explicit zero is refused during request admission.
///
/// The two can disagree: a configured minimum above a quarter of the idle
/// timeout ends with the cap winning, and the returned interval below the
/// configured minimum. That is deliberate, and `rate` is where the consequence
/// is settled — the session's allowance then replenishes at the *negotiated*
/// interval, so this server never enforces a cadence slower than the one it just
/// handed the client.
///
/// **ServerFill is settled separately**, by
/// [`negotiate_server_fill`](crate::fill::negotiate_server_fill), because it
/// produces a second result this function has nowhere to put: the effective
/// fill the session will use, which is not always what the descriptor in
/// `Params` says. The two run back to back on the same open.
///
/// **StampAt is reduced to the configured timestamp allowance**, by
/// [`restrict_stamp_at`]. The Clock is deliberately untouched: the allowance is
/// a policy about which timestamps this server provides, and the echo layout
/// carries no timestamp field once the placement is [`StampAt::None`], so there
/// is no clock to restrict as well. Rewriting it would answer with a session the
/// client did not ask for.
///
/// **DSCP is forced to zero when the server disallows it**, and otherwise
/// returned exactly as requested — including a value outside `0..=255`, which
/// stays in the negotiated parameters and is transported unmarked. Zero is a
/// negotiated value like any other and `Params::encode` simply omits it, so a
/// restricted reply carries no DSCP tag and the session's stored parameters
/// carry zero. That one value is what the runtime derives an unmarked reply
/// from; no session or transport state records the policy separately.
///
/// Both restrictions run here, before the core validates the effective session,
/// which is what makes a timestamp-disallowing server accept an open that
/// selected timestamps without sending a Clock.
///
/// Negotiation is not by itself an acknowledgement: the core validates what this
/// function returns and silently discards an open whose effective parameters it
/// could not execute. That is a separate step on purpose — this function decides
/// what the session *would* be, and the core decides whether that session can
/// exist. Capping Length here is not enough on its own, because the mandatory
/// echo field block can exceed the configured maximum by itself.
pub
/// The timestamp placement a server offering `allowance` provides for a session
/// that requested `requested`.
///
/// The mapping is the observed one, from the clean specification's Section 11.4.
/// Only one row substitutes rather than removes: under [`Single`], a request for
/// both instants is answered with [`StampAt::Midpoint`] — one instant that still
/// describes both — and not with whichever of Send or Receive an implementation
/// happened to prefer. Every already-single placement passes through, and
/// [`None`] removes all of them.
///
/// The allowance bounds reported *instants*, not fields: the clock is untouched,
/// so a negotiated midpoint on `Clock::Both` still reports one field per domain.
///
/// [`Single`]: TimestampAllowance::Single
/// [`None`]: TimestampAllowance::None