1package quic
2
3import (
4	"context"
5	"io"
6	"net"
7	"time"
8
9	"github.com/lucas-clemente/quic-go/internal/handshake"
10	"github.com/lucas-clemente/quic-go/internal/protocol"
11	"github.com/lucas-clemente/quic-go/logging"
12	"github.com/lucas-clemente/quic-go/quictrace"
13)
14
15// RetireBugBackwardsCompatibilityMode controls a backwards compatibility mode, necessary due to a bug in
16// quic-go v0.17.2 (and earlier), where under certain circumstances, an endpoint would retire the connection
17// ID it is currently using. See https://github.com/lucas-clemente/quic-go/issues/2658.
18// The bug has now been fixed, and new deployments have nothing to worry about.
19// Deployments that already have quic-go <= v0.17.2 deployed should active RetireBugBackwardsCompatibilityMode.
20// If activated, quic-go will take steps to avoid the bug from triggering when connected to endpoints that are still
21// running quic-go <= v0.17.2.
22// This flag will be removed in a future version of quic-go.
23var RetireBugBackwardsCompatibilityMode bool
24
25// The StreamID is the ID of a QUIC stream.
26type StreamID = protocol.StreamID
27
28// A VersionNumber is a QUIC version number.
29type VersionNumber = protocol.VersionNumber
30
31const (
32	// VersionDraft29 is IETF QUIC draft-29
33	VersionDraft29 = protocol.VersionDraft29
34	// VersionDraft32 is IETF QUIC draft-32
35	VersionDraft32 = protocol.VersionDraft32
36)
37
38// A Token can be used to verify the ownership of the client address.
39type Token struct {
40	// IsRetryToken encodes how the client received the token. There are two ways:
41	// * In a Retry packet sent when trying to establish a new connection.
42	// * In a NEW_TOKEN frame on a previous connection.
43	IsRetryToken bool
44	RemoteAddr   string
45	SentTime     time.Time
46}
47
48// A ClientToken is a token received by the client.
49// It can be used to skip address validation on future connection attempts.
50type ClientToken struct {
51	data []byte
52}
53
54type TokenStore interface {
55	// Pop searches for a ClientToken associated with the given key.
56	// Since tokens are not supposed to be reused, it must remove the token from the cache.
57	// It returns nil when no token is found.
58	Pop(key string) (token *ClientToken)
59
60	// Put adds a token to the cache with the given key. It might get called
61	// multiple times in a connection.
62	Put(key string, token *ClientToken)
63}
64
65// An ErrorCode is an application-defined error code.
66// Valid values range between 0 and MAX_UINT62.
67type ErrorCode = protocol.ApplicationErrorCode
68
69// Stream is the interface implemented by QUIC streams
70type Stream interface {
71	ReceiveStream
72	SendStream
73	// SetDeadline sets the read and write deadlines associated
74	// with the connection. It is equivalent to calling both
75	// SetReadDeadline and SetWriteDeadline.
76	SetDeadline(t time.Time) error
77}
78
79// A ReceiveStream is a unidirectional Receive Stream.
80type ReceiveStream interface {
81	// StreamID returns the stream ID.
82	StreamID() StreamID
83	// Read reads data from the stream.
84	// Read can be made to time out and return a net.Error with Timeout() == true
85	// after a fixed time limit; see SetDeadline and SetReadDeadline.
86	// If the stream was canceled by the peer, the error implements the StreamError
87	// interface, and Canceled() == true.
88	// If the session was closed due to a timeout, the error satisfies
89	// the net.Error interface, and Timeout() will be true.
90	io.Reader
91	// CancelRead aborts receiving on this stream.
92	// It will ask the peer to stop transmitting stream data.
93	// Read will unblock immediately, and future Read calls will fail.
94	// When called multiple times or after reading the io.EOF it is a no-op.
95	CancelRead(ErrorCode)
96	// SetReadDeadline sets the deadline for future Read calls and
97	// any currently-blocked Read call.
98	// A zero value for t means Read will not time out.
99
100	SetReadDeadline(t time.Time) error
101}
102
103// A SendStream is a unidirectional Send Stream.
104type SendStream interface {
105	// StreamID returns the stream ID.
106	StreamID() StreamID
107	// Write writes data to the stream.
108	// Write can be made to time out and return a net.Error with Timeout() == true
109	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
110	// If the stream was canceled by the peer, the error implements the StreamError
111	// interface, and Canceled() == true.
112	// If the session was closed due to a timeout, the error satisfies
113	// the net.Error interface, and Timeout() will be true.
114	io.Writer
115	// Close closes the write-direction of the stream.
116	// Future calls to Write are not permitted after calling Close.
117	// It must not be called concurrently with Write.
118	// It must not be called after calling CancelWrite.
119	io.Closer
120	// CancelWrite aborts sending on this stream.
121	// Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably.
122	// Write will unblock immediately, and future calls to Write will fail.
123	// When called multiple times or after closing the stream it is a no-op.
124	CancelWrite(ErrorCode)
125	// The context is canceled as soon as the write-side of the stream is closed.
126	// This happens when Close() or CancelWrite() is called, or when the peer
127	// cancels the read-side of their stream.
128	// Warning: This API should not be considered stable and might change soon.
129	Context() context.Context
130	// SetWriteDeadline sets the deadline for future Write calls
131	// and any currently-blocked Write call.
132	// Even if write times out, it may return n > 0, indicating that
133	// some of the data was successfully written.
134	// A zero value for t means Write will not time out.
135	SetWriteDeadline(t time.Time) error
136}
137
138// StreamError is returned by Read and Write when the peer cancels the stream.
139type StreamError interface {
140	error
141	Canceled() bool
142	ErrorCode() ErrorCode
143}
144
145type ConnectionState = handshake.ConnectionState
146
147// A Session is a QUIC connection between two peers.
148type Session interface {
149	// AcceptStream returns the next stream opened by the peer, blocking until one is available.
150	// If the session was closed due to a timeout, the error satisfies
151	// the net.Error interface, and Timeout() will be true.
152	AcceptStream(context.Context) (Stream, error)
153	// AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available.
154	// If the session was closed due to a timeout, the error satisfies
155	// the net.Error interface, and Timeout() will be true.
156	AcceptUniStream(context.Context) (ReceiveStream, error)
157	// OpenStream opens a new bidirectional QUIC stream.
158	// There is no signaling to the peer about new streams:
159	// The peer can only accept the stream after data has been sent on the stream.
160	// If the error is non-nil, it satisfies the net.Error interface.
161	// When reaching the peer's stream limit, err.Temporary() will be true.
162	// If the session was closed due to a timeout, Timeout() will be true.
163	OpenStream() (Stream, error)
164	// OpenStreamSync opens a new bidirectional QUIC stream.
165	// It blocks until a new stream can be opened.
166	// If the error is non-nil, it satisfies the net.Error interface.
167	// If the session was closed due to a timeout, Timeout() will be true.
168	OpenStreamSync(context.Context) (Stream, error)
169	// OpenUniStream opens a new outgoing unidirectional QUIC stream.
170	// If the error is non-nil, it satisfies the net.Error interface.
171	// When reaching the peer's stream limit, Temporary() will be true.
172	// If the session was closed due to a timeout, Timeout() will be true.
173	OpenUniStream() (SendStream, error)
174	// OpenUniStreamSync opens a new outgoing unidirectional QUIC stream.
175	// It blocks until a new stream can be opened.
176	// If the error is non-nil, it satisfies the net.Error interface.
177	// If the session was closed due to a timeout, Timeout() will be true.
178	OpenUniStreamSync(context.Context) (SendStream, error)
179	// LocalAddr returns the local address.
180	LocalAddr() net.Addr
181	// RemoteAddr returns the address of the peer.
182	RemoteAddr() net.Addr
183	// Close the connection with an error.
184	// The error string will be sent to the peer.
185	CloseWithError(ErrorCode, string) error
186	// The context is cancelled when the session is closed.
187	// Warning: This API should not be considered stable and might change soon.
188	Context() context.Context
189	// ConnectionState returns basic details about the QUIC connection.
190	// It blocks until the handshake completes.
191	// Warning: This API should not be considered stable and might change soon.
192	ConnectionState() ConnectionState
193}
194
195// An EarlySession is a session that is handshaking.
196// Data sent during the handshake is encrypted using the forward secure keys.
197// When using client certificates, the client's identity is only verified
198// after completion of the handshake.
199type EarlySession interface {
200	Session
201
202	// Blocks until the handshake completes (or fails).
203	// Data sent before completion of the handshake is encrypted with 1-RTT keys.
204	// Note that the client's identity hasn't been verified yet.
205	HandshakeComplete() context.Context
206}
207
208// Config contains all configuration data needed for a QUIC server or client.
209type Config struct {
210	// The QUIC versions that can be negotiated.
211	// If not set, it uses all versions available.
212	// Warning: This API should not be considered stable and will change soon.
213	Versions []VersionNumber
214	// The length of the connection ID in bytes.
215	// It can be 0, or any value between 4 and 18.
216	// If not set, the interpretation depends on where the Config is used:
217	// If used for dialing an address, a 0 byte connection ID will be used.
218	// If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used.
219	// When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call.
220	ConnectionIDLength int
221	// HandshakeTimeout is the maximum duration that the cryptographic handshake may take.
222	// If the timeout is exceeded, the connection is closed.
223	// If this value is zero, the timeout is set to 10 seconds.
224	HandshakeTimeout time.Duration
225	// MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
226	// The actual value for the idle timeout is the minimum of this value and the peer's.
227	// This value only applies after the handshake has completed.
228	// If the timeout is exceeded, the connection is closed.
229	// If this value is zero, the timeout is set to 30 seconds.
230	MaxIdleTimeout time.Duration
231	// AcceptToken determines if a Token is accepted.
232	// It is called with token = nil if the client didn't send a token.
233	// If not set, a default verification function is used:
234	// * it verifies that the address matches, and
235	//   * if the token is a retry token, that it was issued within the last 5 seconds
236	//   * else, that it was issued within the last 24 hours.
237	// This option is only valid for the server.
238	AcceptToken func(clientAddr net.Addr, token *Token) bool
239	// The TokenStore stores tokens received from the server.
240	// Tokens are used to skip address validation on future connection attempts.
241	// The key used to store tokens is the ServerName from the tls.Config, if set
242	// otherwise the token is associated with the server's IP address.
243	TokenStore TokenStore
244	// MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data.
245	// If this value is zero, it will default to 1 MB for the server and 6 MB for the client.
246	MaxReceiveStreamFlowControlWindow uint64
247	// MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data.
248	// If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client.
249	MaxReceiveConnectionFlowControlWindow uint64
250	// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
251	// Values above 2^60 are invalid.
252	// If not set, it will default to 100.
253	// If set to a negative value, it doesn't allow any bidirectional streams.
254	MaxIncomingStreams int64
255	// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
256	// Values above 2^60 are invalid.
257	// If not set, it will default to 100.
258	// If set to a negative value, it doesn't allow any unidirectional streams.
259	MaxIncomingUniStreams int64
260	// The StatelessResetKey is used to generate stateless reset tokens.
261	// If no key is configured, sending of stateless resets is disabled.
262	StatelessResetKey []byte
263	// KeepAlive defines whether this peer will periodically send a packet to keep the connection alive.
264	KeepAlive bool
265	// QUIC Event Tracer (see https://github.com/google/quic-trace).
266	// Warning: Support for quic-trace will soon be dropped in favor of qlog.
267	// It is disabled by default. Use the "quictrace" build tag to enable (e.g. go build -tags quictrace).
268	QuicTracer quictrace.Tracer
269	Tracer     logging.Tracer
270}
271
272// A Listener for incoming QUIC connections
273type Listener interface {
274	// Close the server. All active sessions will be closed.
275	Close() error
276	// Addr returns the local network addr that the server is listening on.
277	Addr() net.Addr
278	// Accept returns new sessions. It should be called in a loop.
279	Accept(context.Context) (Session, error)
280}
281
282// An EarlyListener listens for incoming QUIC connections,
283// and returns them before the handshake completes.
284type EarlyListener interface {
285	// Close the server. All active sessions will be closed.
286	Close() error
287	// Addr returns the local network addr that the server is listening on.
288	Addr() net.Addr
289	// Accept returns new early sessions. It should be called in a loop.
290	Accept(context.Context) (EarlySession, error)
291}
292