Line data Source code
1 : #ifndef HEADER_fd_src_waltz_quic_fd_quic_conn_h
2 : #define HEADER_fd_src_waltz_quic_fd_quic_conn_h
3 :
4 : #include "fd_quic.h"
5 : #include "fd_quic_common.h"
6 : #include "fd_quic_ack_tx.h"
7 : #include "fd_quic_stream.h"
8 : #include "fd_quic_conn_id.h"
9 : #include "crypto/fd_quic_crypto_suites.h"
10 : #include "fd_quic_pkt_meta.h"
11 : #include "fd_quic_svc_q.h"
12 : #include "../fd_rtt_est.h"
13 :
14 0 : #define FD_QUIC_CONN_STATE_INVALID 0 /* dead object / freed */
15 0 : #define FD_QUIC_CONN_STATE_HANDSHAKE 1 /* currently doing handshaking with peer */
16 0 : #define FD_QUIC_CONN_STATE_HANDSHAKE_COMPLETE 2 /* handshake complete, confirming with peer */
17 0 : #define FD_QUIC_CONN_STATE_ACTIVE 3 /* connection established - data may be transferred */
18 0 : #define FD_QUIC_CONN_STATE_PEER_CLOSE 4 /* peer requested close */
19 0 : #define FD_QUIC_CONN_STATE_ABORT 5 /* connection terminating due to error */
20 0 : #define FD_QUIC_CONN_STATE_CLOSE_PENDING 6 /* connection is closing */
21 0 : #define FD_QUIC_CONN_STATE_DEAD 7 /* connection about to be freed */
22 : #define FD_QUIC_CONN_STATE_CNT 8
23 :
24 : FD_STATIC_ASSERT( FD_QUIC_CONN_STATE_CNT == sizeof(((fd_quic_metrics_t*)0)->conn_state_cnt)/sizeof(((fd_quic_metrics_t*)0)->conn_state_cnt[0]),
25 : "metrics conn_state_cnt is the wrong size" );
26 :
27 : #define FD_QUIC_REASON_CODES(X,SEP) \
28 0 : X(NO_ERROR , 0x00 , "No error" ) SEP \
29 0 : X(INTERNAL_ERROR , 0x01 , "Implementation error" ) SEP \
30 0 : X(CONNECTION_REFUSED , 0x02 , "Server refuses a connection" ) SEP \
31 0 : X(FLOW_CONTROL_ERROR , 0x03 , "Flow control error" ) SEP \
32 0 : X(STREAM_LIMIT_ERROR , 0x04 , "Too many streams opened" ) SEP \
33 0 : X(STREAM_STATE_ERROR , 0x05 , "Frame received in invalid stream state" ) SEP \
34 0 : X(FINAL_SIZE_ERROR , 0x06 , "Change to final size" ) SEP \
35 0 : X(FRAME_ENCODING_ERROR , 0x07 , "Frame encoding error" ) SEP \
36 0 : X(TRANSPORT_PARAMETER_ERROR , 0x08 , "Error in transport parameters" ) SEP \
37 0 : X(CONNECTION_ID_LIMIT_ERROR , 0x09 , "Too many connection IDs received" ) SEP \
38 0 : X(PROTOCOL_VIOLATION , 0x0a , "Generic protocol violation" ) SEP \
39 0 : X(INVALID_TOKEN , 0x0b , "Invalid Token received" ) SEP \
40 0 : X(APPLICATION_ERROR , 0x0c , "Application error" ) SEP \
41 0 : X(CRYPTO_BUFFER_EXCEEDED , 0x0d , "CRYPTO data buffer overflowed" ) SEP \
42 0 : X(KEY_UPDATE_ERROR , 0x0e , "Invalid packet protection update" ) SEP \
43 0 : X(AEAD_LIMIT_REACHED , 0x0f , "Excessive use of packet protection keys" ) SEP \
44 0 : X(NO_VIABLE_PATH , 0x10 , "No viable network path exists" ) SEP \
45 0 : X(CRYPTO_BASE , 0x100 , "0x0100-0x01ff CRYPTO_ERROR TLS alert code" ) SEP \
46 0 : X(HANDSHAKE_FAILURE , 0x128 , "Handshake failed" )
47 :
48 : enum {
49 : # define COMMA ,
50 : # define _(NAME,CODE,DESC) \
51 : FD_QUIC_CONN_REASON_##NAME = CODE
52 : FD_QUIC_REASON_CODES(_,COMMA)
53 : # undef _
54 : # undef COMMA
55 : };
56 :
57 : char const *
58 : fd_quic_conn_reason_name( uint reason );
59 :
60 :
61 : struct fd_quic_conn_stream_rx {
62 : ulong rx_hi_stream_id; /* highest RX stream ID sent by peer + 4 */
63 : ulong rx_sup_stream_id; /* highest allowed RX stream ID + 4 */
64 :
65 : ulong rx_max_data; /* the limit on the number of bytes the peer is allowed to send to us */
66 : ulong rx_tot_data; /* total of all bytes received across all streams and including implied bytes */
67 : ulong rx_max_data_ackd; /* max max_data acked by peer */
68 :
69 : ulong rx_max_streams_unidir_ackd; /* value of MAX_STREAMS acked for UNIDIR */
70 :
71 : long rx_streams_active; /* FIXME: This is a user scratch field, not in use by fd_quic */
72 :
73 : /* FIXME add a TLB */
74 : };
75 :
76 : typedef struct fd_quic_conn_stream_rx fd_quic_conn_stream_rx_t;
77 :
78 : struct fd_quic_conn {
79 : /* 'PERSISTENT' means field should survive a conn_clear */
80 : uint conn_idx; /* connection index - PERSISTENT */
81 : /* connections are sized at runtime */
82 : /* storing the index avoids a division */
83 : uint conn_gen; /* generation of this connection slot - PERSISTENT */
84 :
85 : fd_quic_t * quic; /* PERSISTENT */
86 : void * context; /* user context */
87 :
88 : uint server : 1; /* role from self POV: 0=client, 1=server */
89 : uint established : 1; /* used by clients to determine whether to
90 : switch the destination conn id used */
91 : uint transport_params_set : 1;
92 : uint called_conn_new : 1; /* whether we need to call conn_final on teardown */
93 : uint visited : 1; /* scratch bit, no strict definition */
94 : uint key_phase : 1;
95 : uint key_update : 1;
96 :
97 : /* metadata used by service queue */
98 : fd_quic_svc_timers_conn_meta_t svc_meta;
99 :
100 : /* Dlist membership */
101 : uint free_conn_next;
102 :
103 : ulong our_conn_id;
104 :
105 : /* Save original retry_source_connection_id
106 : * This is used by clients to compare against the retry_source_connection_id
107 : * in the transport parameters as specified in rfc 9000 7.3 */
108 : fd_quic_conn_id_t retry_src_conn_id;
109 :
110 : /* Host network endpoint. Used to determine src address and port */
111 : fd_quic_net_endpoint_t host;
112 :
113 : /* Peer network endpoints – have multiple connection ids and ip:port */
114 : /* TODO: footprint allows specifying conn_id_cnt but hardcoded limit used here */
115 : fd_quic_net_endpoint_t peer[1];
116 : fd_quic_conn_id_t peer_cids[1]; /* FIXME support new/retire conn ID */
117 :
118 : /* initial source connection id */
119 : ulong initial_source_conn_id;
120 :
121 : uint tx_max_datagram_sz; /* max UDP datagram sz allowed by peer */
122 : ulong tx_max_datagram_frame_sz; /* max RFC 9221 QUIC datagram sz allowed by peer */
123 :
124 : /* handshake members */
125 : uint handshake_complete : 1; /* have we completed a successful handshake? */
126 : uint handshake_done_send : 1; /* do we need to send handshake-done to peer? */
127 : uint handshake_done_ackd : 1; /* was handshake_done ack'ed? */
128 : fd_quic_tls_hs_t * tls_hs;
129 :
130 : /* amount of handshake data already sent from head of queue */
131 : ulong hs_sent_bytes[4];
132 :
133 : /* amount of handshake data ack'ed by peer counted from head of queue */
134 : ulong hs_ackd_bytes[4];
135 :
136 : /* Keys for header and packet protection
137 : secrets: Contains 'master' secrets used to derive other keys
138 : keys[e][d]: Current pair of keys for each encryption level (e)
139 : and direction (d==0 is incoming, d==1 is outgoing)
140 : new_keys[e]: App keys to use for the next key update. Once app
141 : keys are available these are always kept up-to-date
142 : keys_avail: Bit set of available keys, LSB indexed by enc level */
143 : fd_quic_crypto_secrets_t secrets;
144 : fd_quic_crypto_keys_t keys[FD_QUIC_NUM_ENC_LEVELS][2];
145 : fd_quic_crypto_keys_t new_keys[2];
146 : uint keys_avail;
147 :
148 : fd_quic_stream_t send_streams[1]; /* sentinel of list of streams needing action */
149 : fd_quic_stream_t used_streams[1]; /* sentinel of list of used streams */
150 : /* invariant: an allocated stream must be in exactly one of the following lists:
151 : send_streams
152 : used_streams */
153 :
154 : /* stream id members */
155 : ulong tx_next_stream_id; /* stream ID to be used for new stream */
156 : ulong tx_sup_stream_id; /* highest allowed TX stream ID + 4 */
157 :
158 : fd_quic_stream_map_t * stream_map; /* map stream_id -> stream - PERSISTENT */
159 :
160 : /* packet number info
161 : each encryption level maps to a packet number space
162 : 0-RTT and 1-RTT both map to APPLICATION
163 : exp_pkt_number[j] is one past the highest packet number received */
164 : ulong exp_pkt_number[3]; /* different packet number spaces:
165 : INITIAL, HANDSHAKE and APPLICATION */
166 : ulong pkt_number[3]; /* tx packet number by pn space */
167 : ulong rx_pn_mask[3]; /* bit i set if exp_pkt_number-1-i was received */
168 : ulong highest_acked[3]; /* highest packet number acked (meaningless if 0) */
169 :
170 : ushort ipv4_id; /* ipv4 id field */
171 :
172 : /* buffer to send next */
173 : /* must be at least FD_QUIC_MAX_UDP_PAYLOAD_SZ */
174 : uchar tx_buf_conn[2048];
175 : uchar * tx_ptr; /* ptr to free space in tx_buf_conn */
176 :
177 : uint state; /* PERSISTENT to keep state counters correct */
178 : uint reason; /* quic reason for closing. see FD_QUIC_CONN_REASON_* */
179 : uint app_reason; /* application reason for closing */
180 :
181 : fd_quic_ack_gen_t ack_gen[1];
182 : ulong unacked_sz; /* Number of received stream frame payload bytes pending ACK */
183 : /* Resets to zero when conn is rescheduled or ACKs are sent */
184 :
185 : fd_quic_pkt_meta_tracker_t pkt_meta_tracker;
186 :
187 : /* flow control */
188 : ulong tx_max_data; /* the limit on the number of bytes we are allowed
189 : to send to the peer across all streams */
190 : /* even if a bytes on a stream are not received,
191 : higher offsets received imply the usage of those bytes,
192 : and they count against the max */
193 : ulong tx_tot_data; /* total of all bytes received across all streams
194 : and including implied bytes */
195 :
196 : uint flags;
197 0 : # define FD_QUIC_CONN_FLAGS_MAX_DATA (1u<<0u)
198 0 : # define FD_QUIC_CONN_FLAGS_CLOSE_SENT (1u<<1u)
199 0 : # define FD_QUIC_CONN_FLAGS_MAX_STREAMS_UNIDIR (1u<<2u)
200 0 : # define FD_QUIC_CONN_FLAGS_PING (1u<<4u)
201 0 : # define FD_QUIC_CONN_FLAGS_PING_SENT (1u<<5u)
202 :
203 : /* max stream data per stream type */
204 : ulong tx_initial_max_stream_data_uni;
205 :
206 : /* last tx packet num with max_data frame referring to this stream
207 : set to next_pkt_number to indicate a new max_data frame should be sent
208 : if we time out this packet (or possibly a later packet) we resend the frame
209 : and update this value */
210 : ulong upd_pkt_number;
211 :
212 : /* idle timeout arguments */
213 : long idle_timeout_ns;
214 : long last_activity;
215 : long last_ack;
216 : long let_die_time_ns; /* stop keep-alive after this time */
217 :
218 : /* round trip time related members */
219 : fd_rtt_estimate_t rtt[1];
220 : float rtt_period_ns; /* bound on time between RTT measurements */
221 : float peer_ack_delay_scale; /* convert ACK delay units to nanoseconds */
222 : float peer_max_ack_delay_ns; /* peer max ack delay in nanoseconds */
223 :
224 : ulong token_len;
225 : uchar token[ FD_QUIC_RETRY_MAX_TOKEN_SZ ];
226 :
227 : fd_quic_conn_stream_rx_t srx[1];
228 :
229 : ulong used_pkt_meta;
230 : };
231 :
232 : FD_PROTOTYPES_BEGIN
233 :
234 : FD_FN_CONST static inline ulong
235 0 : fd_quic_conn_uid( fd_quic_conn_t const * conn ) {
236 0 : return ( (ulong)conn->conn_idx << 32UL ) | ( (ulong)conn->conn_gen );
237 0 : }
238 :
239 : FD_FN_CONST static inline uint
240 0 : fd_quic_conn_uid_idx( ulong conn_uid ) {
241 0 : return (uint)( conn_uid >> 32UL );
242 0 : }
243 :
244 : FD_FN_CONST static inline uint
245 0 : fd_quic_conn_uid_gen( ulong conn_uid ) {
246 0 : return (uint)( conn_uid & 0xffffffffUL );
247 0 : }
248 :
249 : /* returns the alignment requirement of fd_quic_conn_t */
250 : FD_FN_CONST ulong
251 : fd_quic_conn_align( void );
252 :
253 : /* returns the footprint of the connection object for given limits */
254 : ulong
255 : fd_quic_conn_footprint( fd_quic_limits_t const * );
256 :
257 : /* called by fd_quic_new to initialize the connection objects
258 : used by fd_quic */
259 : fd_quic_conn_t *
260 : fd_quic_conn_new( void * mem,
261 : fd_quic_t * quic,
262 : fd_quic_limits_t const * limits );
263 :
264 : /* clears all non-persistent members of the connection object */
265 : static inline void
266 0 : fd_quic_conn_clear( fd_quic_conn_t * conn ) {
267 0 : fd_quic_t * quic = conn->quic;
268 0 : uint conn_idx = conn->conn_idx;
269 0 : uint conn_gen = conn->conn_gen;
270 0 : uint conn_state = conn->state;
271 0 : fd_quic_stream_map_t * stream_map = conn->stream_map;
272 :
273 0 : fd_memset( conn, 0, sizeof( fd_quic_conn_t ) );
274 :
275 0 : conn->quic = quic;
276 0 : conn->conn_idx = conn_idx;
277 0 : conn->conn_gen = conn_gen;
278 0 : conn->state = conn_state;
279 0 : conn->stream_map = stream_map;
280 0 : }
281 :
282 : /* set the user-defined context value on the connection */
283 : void
284 : fd_quic_conn_set_context( fd_quic_conn_t * conn, void * context );
285 :
286 : /* get the user-defined context value from a connection */
287 : void *
288 : fd_quic_conn_get_context( fd_quic_conn_t * conn );
289 :
290 :
291 : /* set all conns to not visited, used for validation */
292 : void
293 : fd_quic_conn_validate_init( fd_quic_t * quic );
294 :
295 : FD_PROTOTYPES_END
296 :
297 : #endif /* HEADER_fd_src_waltz_quic_fd_quic_conn_h */
|