#ifndef _HAPROXY_MUX_QUIC_T_H #define _HAPROXY_MUX_QUIC_T_H #ifdef USE_QUIC #ifndef USE_OPENSSL #error "Must define USE_OPENSSL" #endif #include #include #include #include #include #include #include #include #include #include /* Stream types */ enum qcs_type { QCS_CLT_BIDI, QCS_SRV_BIDI, QCS_CLT_UNI, QCS_SRV_UNI, /* Must be the last one */ QCS_MAX_TYPES }; #define QC_CF_ERRL 0x00000001 /* fatal error detected locally, connection should be closed soon */ #define QC_CF_ERRL_DONE 0x00000002 /* local error properly handled, connection can be released */ /* unused 0x00000004 */ #define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */ #define QC_CF_APP_SHUT 0x00000010 /* Application layer shutdown done. */ #define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */ struct qcc { struct connection *conn; uint64_t nb_sc; /* number of attached stream connectors */ uint64_t nb_hreq; /* number of in-progress http requests */ uint32_t flags; /* QC_CF_* */ int glitches; /* total number of glitches on this connection */ /* flow-control fields set by us enforced on our side. */ struct { struct list frms; /* prepared frames related to flow-control */ uint64_t ms_bidi_init; /* max initial sub-ID of bidi stream allowed for the peer */ uint64_t ms_bidi; /* max sub-ID of bidi stream allowed for the peer */ uint64_t cl_bidi_r; /* total count of closed remote bidi stream since last MAX_STREAMS emission */ uint64_t ms_uni; /* max sub-ID of uni stream allowed for the peer */ uint64_t msd_bidi_l; /* initial max-stream-data on local bidi streams */ uint64_t msd_bidi_r; /* initial max-stream-data on remote bidi streams */ uint64_t msd_uni_r; /* initial max-stream-data on remote uni streams */ uint64_t md; /* current max-data allowed for the peer */ uint64_t md_init; /* initial max-data */ uint64_t offsets_recv; /* sum of offsets received */ uint64_t offsets_consume; /* sum of offsets consumed */ } lfctl; /* flow-control fields set by the peer which we must respect. */ struct { uint64_t md; /* connection flow control limit updated on MAX_DATA frames reception */ uint64_t msd_bidi_l; /* initial max-stream-data from peer on local bidi streams */ uint64_t msd_bidi_r; /* initial max-stream-data from peer on remote bidi streams */ uint64_t msd_uni_l; /* initial max-stream-data from peer on local uni streams */ } rfctl; struct { struct quic_fctl fc; /* stream flow control applied on sending */ } tx; uint64_t largest_bidi_r; /* largest remote bidi stream ID opened. */ uint64_t largest_uni_r; /* largest remote uni stream ID opened. */ uint64_t next_bidi_l; /* next stream ID to use for local bidi stream */ uint64_t next_uni_l; /* next stream ID to use for local uni stream */ struct eb_root streams_by_id; /* all active streams by their ID */ struct list send_retry_list; /* list of qcs eligible to send retry */ struct list send_list; /* list of qcs ready to send (STREAM, STOP_SENDING or RESET_STREAM emission) */ struct list fctl_list; /* list of sending qcs blocked on conn flow control */ struct list buf_wait_list; /* list of qcs blocked on stream desc buf */ struct wait_event wait_event; /* To be used if we're waiting for I/Os */ struct proxy *proxy; /* haproxy timeout management */ struct task *task; struct list opening_list; /* list of not already attached streams (http-request timeout) */ int timeout; int shut_timeout; int idle_start; /* base time for http-keep-alive timeout */ struct quic_err err; /* code for locally detected error */ const struct qcc_app_ops *app_ops; void *ctx; /* Application layer context */ }; #define QC_SF_NONE 0x00000000 #define QC_SF_SIZE_KNOWN 0x00000001 /* last frame received for this stream */ #define QC_SF_FIN_STREAM 0x00000002 /* FIN bit must be set for last frame of the stream */ #define QC_SF_BLK_MROOM 0x00000004 /* app layer is blocked waiting for room in the qcs.tx.buf */ #define QC_SF_DETACH 0x00000008 /* sc is detached but there is remaining data to send */ /* unused 0x00000010 */ #define QC_SF_DEM_FULL 0x00000020 /* demux blocked on request channel buffer full */ #define QC_SF_READ_ABORTED 0x00000040 /* Rx closed using STOP_SENDING*/ #define QC_SF_TO_RESET 0x00000080 /* a RESET_STREAM must be sent */ #define QC_SF_HREQ_RECV 0x00000100 /* a full HTTP request has been received */ #define QC_SF_TO_STOP_SENDING 0x00000200 /* a STOP_SENDING must be sent */ #define QC_SF_UNKNOWN_PL_LENGTH 0x00000400 /* HTX EOM may be missing from the stream layer */ #define QC_SF_RECV_RESET 0x00000800 /* a RESET_STREAM was received */ /* Maximum size of stream Rx buffer. */ #define QC_S_RX_BUF_SZ (global.tune.bufsize - NCB_RESERVED_SZ) /* QUIC stream states * * On initialization a stream is put on idle state. It is opened as soon as * data has been successfully sent or received on it. * * A bidirectional stream has two channels which can be closed separately. The * local channel is closed when the STREAM frame with FIN or a RESET_STREAM has * been emitted. The remote channel is closed as soon as all data from the peer * has been received. The stream goes instantely to the close state once both * channels are closed. * * A unidirectional stream has only one channel of communication. Thus, it does * not use half closed states and transition directly from open to close state. */ enum qcs_state { QC_SS_IDLE = 0, /* initial state */ QC_SS_OPEN, /* opened */ QC_SS_HLOC, /* half-closed local */ QC_SS_HREM, /* half-closed remote */ QC_SS_CLO, /* closed */ } __attribute__((packed)); struct qcs { struct qcc *qcc; struct sedesc *sd; uint32_t flags; /* QC_SF_* */ enum qcs_state st; /* QC_SS_* state */ void *ctx; /* app-ops context */ struct { uint64_t offset; /* absolute current base offset of ncbuf */ uint64_t offset_max; /* maximum absolute offset received */ struct ncbuf ncbuf; /* receive buffer - can handle out-of-order offset frames */ struct buffer app_buf; /* receive buffer used by stconn layer */ uint64_t msd; /* current max-stream-data limit to enforce */ uint64_t msd_init; /* initial max-stream-data */ } rx; struct { struct quic_fctl fc; /* stream flow control applied on sending */ } tx; struct eb64_node by_id; uint64_t id; struct qc_stream_desc *stream; struct list el; /* element of qcc.send_retry_list */ struct list el_send; /* element of qcc.send_list */ struct list el_opening; /* element of qcc.opening_list */ struct list el_fctl; /* element of qcc.fctl_list */ struct list el_buf; /* element of qcc.buf_wait_list */ struct wait_event wait_event; struct wait_event *subs; uint64_t err; /* error code to transmit via RESET_STREAM */ int start; /* base timestamp for http-request timeout */ }; /* Used as qcc_app_ops.close callback argument. */ enum qcc_app_ops_close_side { QCC_APP_OPS_CLOSE_SIDE_RD, /* Read channel closed (RESET_STREAM received). */ QCC_APP_OPS_CLOSE_SIDE_WR /* Write channel closed (STOP_SENDING received). */ }; /* QUIC application layer operations */ struct qcc_app_ops { /* Initialize connection app context. */ int (*init)(struct qcc *qcc); /* Finish connection initialization if prelude required. */ int (*finalize)(void *ctx); /* Initialize stream app context or leave it to NULL if rejected. */ int (*attach)(struct qcs *qcs, void *conn_ctx); /* Convert received HTTP payload to HTX. */ ssize_t (*rcv_buf)(struct qcs *qcs, struct buffer *b, int fin); /* Convert HTX to HTTP payload for sending. */ size_t (*snd_buf)(struct qcs *qcs, struct buffer *b, size_t count); /* Negotiate and commit fast-forward data from opposite MUX. */ size_t (*nego_ff)(struct qcs *qcs, size_t count); size_t (*done_ff)(struct qcs *qcs); /* Notify about stream closure. */ int (*close)(struct qcs *qcs, enum qcc_app_ops_close_side side); /* Free stream app context. */ void (*detach)(struct qcs *qcs); /* Perform graceful shutdown. */ void (*shutdown)(void *ctx); /* Free connection app context. */ void (*release)(void *ctx); /* Increment app counters on CONNECTION_CLOSE_APP reception. */ void (*inc_err_cnt)(void *ctx, int err_code); /* Set QCC error code as suspicious activity has been detected. */ void (*report_susp)(void *ctx); }; #endif /* USE_QUIC */ #endif /* _HAPROXY_MUX_QUIC_T_H */