LCOV - code coverage report
Current view: top level - waltz/quic - fd_quic_private.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 88 91 96.7 %
Date: 2025-03-20 12:08:36 Functions: 16 144 11.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_quic_fd_quic_private_h
       2             : #define HEADER_fd_src_waltz_quic_fd_quic_private_h
       3             : 
       4             : #include "fd_quic.h"
       5             : #include "templ/fd_quic_transport_params.h"
       6             : #include "fd_quic_conn_map.h"
       7             : #include "fd_quic_stream.h"
       8             : #include "log/fd_quic_log_tx.h"
       9             : #include "fd_quic_pkt_meta.h"
      10             : #include "tls/fd_quic_tls.h"
      11             : #include "fd_quic_stream_pool.h"
      12             : #include "fd_quic_pretty_print.h"
      13             : 
      14             : #include "../../util/log/fd_dtrace.h"
      15             : #include "../../util/net/fd_ip4.h"
      16             : #include "../../util/net/fd_udp.h"
      17             : 
      18             : /* Handshake allocator pool */
      19             : #define POOL_NAME fd_quic_tls_hs_pool
      20        9972 : #define POOL_T    fd_quic_tls_hs_t
      21             : #include "../../util/tmpl/fd_pool.c"
      22             : 
      23             : /* FD_QUIC_DISABLE_CRYPTO: set to 1 to disable packet protection and
      24             :    encryption.  Only intended for testing. */
      25             : #ifndef FD_QUIC_DISABLE_CRYPTO
      26             : #define FD_QUIC_DISABLE_CRYPTO 0
      27             : #endif
      28             : 
      29   106502370 : #define FD_QUIC_PKT_NUM_UNUSED  (~0ul)
      30    40681146 : #define FD_QUIC_PKT_NUM_PENDING (~1ul)
      31             : 
      32             : /* FD_QUIC_MAGIC is used to signal the layout of shared memory region
      33             :    of an fd_quic_t. */
      34             : 
      35        2130 : #define FD_QUIC_MAGIC (0xdadf8cfa01cc5460UL)
      36             : 
      37             : /* FD_QUIC_SVC_{...} specify connection timer types. */
      38             : 
      39   120033084 : #define FD_QUIC_SVC_INSTANT (0U)  /* as soon as possible */
      40   198541619 : #define FD_QUIC_SVC_ACK_TX  (1U)  /* within local max_ack_delay (ACK TX coalesce) */
      41   133903739 : #define FD_QUIC_SVC_WAIT    (2U)  /* within min(idle_timeout, peer max_ack_delay) */
      42   134003071 : #define FD_QUIC_SVC_CNT     (3U)  /* number of FD_QUIC_SVC_{...} levels */
      43             : 
      44             : /* fd_quic_svc_queue_t is a simple doubly linked list. */
      45             : 
      46             : struct fd_quic_svc_queue {
      47             :   /* FIXME track count */ // uint cnt;
      48             :   uint head;
      49             :   uint tail;
      50             : };
      51             : 
      52             : typedef struct fd_quic_svc_queue fd_quic_svc_queue_t;
      53             : 
      54             : 
      55             : /* fd_quic_state_t is the internal state of an fd_quic_t.  Valid for
      56             :    lifetime of join. */
      57             : 
      58             : struct __attribute__((aligned(16UL))) fd_quic_state_private {
      59             :   /* Flags */
      60             :   ulong flags;
      61             : 
      62             :   ulong now; /* the time we entered into fd_quic_service, or fd_quic_aio_cb_receive */
      63             : 
      64             :   /* transport_params: Template for QUIC-TLS transport params extension.
      65             :      Contains a mix of mutable and immutable fields.  Immutable fields
      66             :      are set on join.  Mutable fields may be modified during packet
      67             :      processing.  Any code using this struct must ensure that the
      68             :      mutable fields are cleared before using (otherwise would leak a
      69             :      side channel).
      70             : 
      71             :      Mutable fields include:
      72             :      - original_destination_connection_id
      73             :      - initial_source_conn_id */
      74             : 
      75             :   fd_quic_transport_params_t transport_params;
      76             : 
      77             :   /* Various internal state */
      78             : 
      79             :   fd_quic_log_tx_t        log_tx[1];
      80             :   uint                    free_conn_list; /* free list of unused connections */
      81             :   fd_quic_conn_map_t *    conn_map;       /* map connection ids -> connection */
      82             :   fd_quic_tls_t           tls[1];
      83             :   fd_quic_tls_hs_t *      hs_pool;
      84             :   fd_quic_stream_pool_t * stream_pool;    /* stream pool, nullable */
      85             :   fd_rng_t                _rng[1];        /* random number generator */
      86             :   fd_quic_svc_queue_t     svc_queue[ FD_QUIC_SVC_CNT ]; /* dlists */
      87             :   ulong                   svc_delay[ FD_QUIC_SVC_CNT ]; /* target service delay */
      88             : 
      89             :   /* need to be able to access connections by index */
      90             :   ulong                   conn_base;      /* address of array of all connections */
      91             :                                           /* not using fd_quic_conn_t* to avoid confusion */
      92             :                                           /* use fd_quic_conn_at_idx instead */
      93             :   ulong                   conn_sz;        /* size of one connection element */
      94             : 
      95             :   /* flow control - configured initial limits */
      96             :   ulong initial_max_data;           /* directly from transport params */
      97             :   ulong initial_max_stream_data[4]; /* from 4 transport params indexed by stream type */
      98             : 
      99             :   /* last arp/routing tables update */
     100             :   ulong ip_table_upd;
     101             : 
     102             :   /* state for QUIC sampling */
     103             :   fd_quic_pretty_print_t quic_pretty_print;
     104             : 
     105             :   /* secret for generating RETRY tokens */
     106             :   uchar retry_secret[FD_QUIC_RETRY_SECRET_SZ];
     107             :   uchar retry_iv    [FD_QUIC_RETRY_IV_SZ];
     108             : 
     109             :   /* Scratch space for packet protection */
     110             :   uchar                   crypt_scratch[FD_QUIC_MTU];
     111             : };
     112             : 
     113             : /* FD_QUIC_STATE_OFF is the offset of fd_quic_state_t within fd_quic_t. */
     114   733794461 : #define FD_QUIC_STATE_OFF (fd_ulong_align_up( sizeof(fd_quic_t), alignof(fd_quic_state_t) ))
     115             : 
     116             : struct fd_quic_pkt {
     117             :   fd_ip4_hdr_t       ip4[1];
     118             :   fd_udp_hdr_t       udp[1];
     119             : 
     120             :   /* the following are the "current" values only. There may be more QUIC packets
     121             :      in a UDP datagram */
     122             :   ulong              pkt_number;  /* quic packet number currently being decoded/parsed */
     123             :   ulong              rcv_time;    /* time packet was received */
     124             :   uint               enc_level;   /* encryption level */
     125             :   uint               datagram_sz; /* length of the original datagram */
     126             :   uint               ack_flag;    /* ORed together: 0-don't ack  1-ack  2-cancel ack */
     127   277972926 : # define ACK_FLAG_RQD     1
     128   185011328 : # define ACK_FLAG_CANCEL  2
     129             : 
     130             :   ulong              rtt_pkt_number; /* packet number used for rtt */
     131             :   ulong              rtt_ack_time;
     132             :   ulong              rtt_ack_delay;
     133             : };
     134             : 
     135             : struct fd_quic_frame_ctx {
     136             :   fd_quic_t *      quic;
     137             :   fd_quic_conn_t * conn;
     138             :   fd_quic_pkt_t *  pkt;
     139             : };
     140             : 
     141             : typedef struct fd_quic_frame_ctx fd_quic_frame_ctx_t;
     142             : 
     143             : FD_PROTOTYPES_BEGIN
     144             : 
     145             : /* fd_quic_get_state returns a pointer to private state area given a
     146             :    pointer to fd_quic_t.  Const func, guaranteed to not access memory. */
     147             : 
     148             : FD_FN_CONST static inline fd_quic_state_t *
     149   733794461 : fd_quic_get_state( fd_quic_t * quic ) {
     150   733794461 :   return (fd_quic_state_t *)( (ulong)quic + FD_QUIC_STATE_OFF );
     151   733794461 : }
     152             : 
     153             : FD_FN_CONST static inline fd_quic_state_t const *
     154           0 : fd_quic_get_state_const( fd_quic_t const * quic ) {
     155           0 :   return (fd_quic_state_t const *)( (ulong)quic + FD_QUIC_STATE_OFF );
     156           0 : }
     157             : 
     158             : /* fd_quic_conn_service is called periodically to perform pending
     159             :    operations and time based operations.
     160             : 
     161             :    args
     162             :      quic        managing quic
     163             :      conn        connection to service
     164             :      now         the current timestamp */
     165             : void
     166             : fd_quic_conn_service( fd_quic_t *      quic,
     167             :                       fd_quic_conn_t * conn,
     168             :                       ulong            now );
     169             : 
     170             : /* fd_quic_svc_schedule installs a connection timer.  svc_type is in
     171             :    [0,FD_QUIC_SVC_CNT) and specifies the timer delay.  Lower timers
     172             :    override higher ones. */
     173             : 
     174             : void
     175             : fd_quic_svc_schedule( fd_quic_state_t * state,
     176             :                       fd_quic_conn_t *  conn,
     177             :                       uint              svc_type );
     178             : 
     179             : static inline void
     180             : fd_quic_svc_schedule1( fd_quic_conn_t * conn,
     181    13596236 :                        uint             svc_type ) {
     182    13596236 :   fd_quic_svc_schedule( fd_quic_get_state( conn->quic ), conn, svc_type );
     183    13596236 : }
     184             : 
     185             : /* Memory management **************************************************/
     186             : 
     187             : fd_quic_conn_t *
     188             : fd_quic_conn_create( fd_quic_t *               quic,
     189             :                      ulong                     our_conn_id,
     190             :                      fd_quic_conn_id_t const * peer_conn_id,
     191             :                      uint                      peer_ip_addr,
     192             :                      ushort                    peer_udp_port,
     193             :                      uint                      self_ip_addr,
     194             :                      ushort                    self_udp_port,
     195             :                      int                       server );
     196             : 
     197             : /* fd_quic_conn_free frees up resources related to the connection and
     198             :    returns it to the connection free list. */
     199             : void
     200             : fd_quic_conn_free( fd_quic_t *      quic,
     201             :                    fd_quic_conn_t * conn );
     202             : 
     203             : void
     204             : fd_quic_tx_stream_free( fd_quic_t *        quic,
     205             :                         fd_quic_conn_t *   conn,
     206             :                         fd_quic_stream_t * stream,
     207             :                         int                code );
     208             : 
     209             : /* Callbacks provided by fd_quic **************************************/
     210             : 
     211             : /* used by quic to receive data from network */
     212             : int
     213             : fd_quic_aio_cb_receive( void *                    context,
     214             :                         fd_aio_pkt_info_t const * batch,
     215             :                         ulong                     batch_sz,
     216             :                         ulong *                   opt_batch_idx,
     217             :                         int                       flush );
     218             : 
     219             : /* declare callbacks from quic-tls into quic */
     220             : int
     221             : fd_quic_tls_cb_client_hello( fd_quic_tls_hs_t * hs,
     222             :                              void *             context );
     223             : 
     224             : int
     225             : fd_quic_tls_cb_handshake_data( fd_quic_tls_hs_t * hs,
     226             :                                void *             context,
     227             :                                uint               enc_level,
     228             :                                uchar const *      data,
     229             :                                ulong              data_sz );
     230             : 
     231             : void
     232             : fd_quic_tls_cb_alert( fd_quic_tls_hs_t * hs,
     233             :                       void *             context,
     234             :                       int                alert );
     235             : 
     236             : void
     237             : fd_quic_tls_cb_secret( fd_quic_tls_hs_t *           hs,
     238             :                        void *                       context,
     239             :                        fd_quic_tls_secret_t const * secret );
     240             : 
     241             : void
     242             : fd_quic_tls_cb_handshake_complete( fd_quic_tls_hs_t * hs,
     243             :                                    void *             context  );
     244             : 
     245             : void
     246             : fd_quic_tls_cb_peer_params( void *        context,
     247             :                             uchar const * peer_tp_enc,
     248             :                             ulong         peer_tp_enc_sz );
     249             : 
     250             : /* Helpers for calling callbacks **************************************/
     251             : 
     252             : static inline ulong
     253   119867157 : fd_quic_now( fd_quic_t * quic ) {
     254   119867157 :   return quic->cb.now( quic->cb.now_ctx );
     255   119867157 : }
     256             : 
     257             : static inline void
     258             : fd_quic_cb_conn_new( fd_quic_t *      quic,
     259        6015 :                      fd_quic_conn_t * conn ) {
     260        6015 :   if( conn->called_conn_new ) return;
     261        6015 :   conn->called_conn_new = 1;
     262        6015 :   if( !quic->cb.conn_new ) return;
     263             : 
     264        6015 :   quic->cb.conn_new( conn, quic->cb.quic_ctx );
     265        6015 : }
     266             : 
     267             : static inline void
     268             : fd_quic_cb_conn_hs_complete( fd_quic_t *      quic,
     269        6015 :                              fd_quic_conn_t * conn ) {
     270        6015 :   if( !quic->cb.conn_hs_complete ) return;
     271        6015 :   quic->cb.conn_hs_complete( conn, quic->cb.quic_ctx );
     272        6015 : }
     273             : 
     274             : static inline void
     275             : fd_quic_cb_conn_final( fd_quic_t *      quic,
     276       14370 :                        fd_quic_conn_t * conn ) {
     277       14370 :   if( !quic->cb.conn_final || !conn->called_conn_new ) return;
     278       12024 :   quic->cb.conn_final( conn, quic->cb.quic_ctx );
     279       12024 : }
     280             : 
     281             : static inline int
     282             : fd_quic_cb_stream_rx( fd_quic_t *        quic,
     283             :                       fd_quic_conn_t *   conn,
     284             :                       ulong              stream_id,
     285             :                       ulong              offset,
     286             :                       uchar const *      data,
     287             :                       ulong              data_sz,
     288    92365731 :                       int                fin ) {
     289    92365731 :   quic->metrics.stream_rx_event_cnt++;
     290    92365731 :   quic->metrics.stream_rx_byte_cnt += data_sz;
     291             : 
     292    92365731 :   if( !quic->cb.stream_rx ) return FD_QUIC_SUCCESS;
     293    13560005 :   return quic->cb.stream_rx( conn, stream_id, offset, data, data_sz, fin );
     294    92365731 : }
     295             : 
     296             : static inline void
     297             : fd_quic_cb_stream_notify( fd_quic_t *        quic,
     298             :                           fd_quic_stream_t * stream,
     299             :                           void *             stream_ctx,
     300    13549151 :                           int                event ) {
     301    13549151 :   quic->metrics.stream_closed_cnt[ event ]++;
     302    13549151 :   quic->metrics.stream_active_cnt--;
     303             : 
     304    13549151 :   if( !quic->cb.stream_notify ) return;
     305    13549151 :   quic->cb.stream_notify( stream, stream_ctx, event );
     306    13549151 : }
     307             : 
     308             : 
     309             : FD_FN_CONST ulong
     310             : fd_quic_reconstruct_pkt_num( ulong pktnum_comp,
     311             :                              ulong pktnum_sz,
     312             :                              ulong exp_pkt_number );
     313             : 
     314             : void
     315             : fd_quic_pkt_meta_retry( fd_quic_t *          quic,
     316             :                         fd_quic_conn_t *     conn,
     317             :                         int                  force,
     318             :                         uint                 arg_enc_level );
     319             : 
     320             : /* reclaim resources associated with packet metadata
     321             :    this is called in response to received acks */
     322             : void
     323             : fd_quic_reclaim_pkt_meta( fd_quic_conn_t *     conn,
     324             :                           fd_quic_pkt_meta_t * pkt_meta,
     325             :                           uint                 enc_level );
     326             : 
     327             : ulong
     328             : fd_quic_process_quic_packet_v1( fd_quic_t *     quic,
     329             :                                 fd_quic_pkt_t * pkt,
     330             :                                 uchar *         cur_ptr,
     331             :                                 ulong           cur_sz );
     332             : 
     333             : ulong
     334             : fd_quic_handle_v1_initial( fd_quic_t *               quic,
     335             :                            fd_quic_conn_t **         p_conn,
     336             :                            fd_quic_pkt_t *           pkt,
     337             :                            fd_quic_conn_id_t const * dcid,
     338             :                            fd_quic_conn_id_t const * scid,
     339             :                            uchar *                   cur_ptr,
     340             :                            ulong                     cur_sz );
     341             : 
     342             : ulong
     343             : fd_quic_handle_v1_one_rtt( fd_quic_t *      quic,
     344             :                            fd_quic_conn_t * conn,
     345             :                            fd_quic_pkt_t *  pkt,
     346             :                            uchar *          cur_ptr,
     347             :                            ulong            cur_sz );
     348             : 
     349             : /* fd_quic_handle_v1_frame is the primary entrypoint for handling of
     350             :    incoming QUIC frames.  {quic,conn,pkt} identify the frame context.
     351             :    Memory region [frame_ptr,frame_ptr+frame_sz) contains the serialized
     352             :    QUIC frame (may contain arbitrary zero padding at the beginning).
     353             : 
     354             :    Returns value in (0,buf_sz) if the frame was successfully processed.
     355             :    Returns FD_QUIC_PARSE_FAIL if the frame was inherently malformed.
     356             :    Returns 0 or value in [buf_sz,ULONG_MAX) in case of a protocol
     357             :    violation. */
     358             : 
     359             : ulong
     360             : fd_quic_handle_v1_frame( fd_quic_t *       quic,
     361             :                          fd_quic_conn_t *  conn,
     362             :                          fd_quic_pkt_t *   pkt,
     363             :                          uint              pkt_type,
     364             :                          uchar const *     frame_ptr,
     365             :                          ulong             frame_sz );
     366             : 
     367             : /* fd_quic_lazy_ack_pkt enqueues future acknowledgement for the given
     368             :    packet.  The ACK will be sent out at a fd_quic_service call.  The
     369             :    delay is determined by the fd_quic_config_t ack_threshold and
     370             :    ack_delay settings.   Respects pkt->ack_flag (ACK_FLAG_RQD schedules
     371             :    an ACK instantly, ACK_FLAG_CANCEL suppresses the ACK by making this
     372             :    function behave like a no-op)  */
     373             : 
     374             : int
     375             : fd_quic_lazy_ack_pkt( fd_quic_t *           quic,
     376             :                       fd_quic_conn_t *      conn,
     377             :                       fd_quic_pkt_t const * pkt );
     378             : 
     379             : static inline fd_quic_conn_t *
     380   250839638 : fd_quic_conn_at_idx( fd_quic_state_t * quic_state, ulong idx ) {
     381   250839638 :   ulong addr = quic_state->conn_base;
     382   250839638 :   ulong sz   = quic_state->conn_sz;
     383   250839638 :   return (fd_quic_conn_t*)( addr + idx * sz );
     384   250839638 : }
     385             : 
     386             : /* called with round-trip-time (rtt) and the ack delay (from the spec)
     387             :  * to sample the round trip times.
     388             :  * Arguments:
     389             :  *   conn            The connection to be updated
     390             :  *   rtt_ticks       The round trip time in ticks
     391             :  *   ack_delay       The ack_delay field supplied by the peer in peer units
     392             :  *
     393             :  * Updates:
     394             :  *   smoothed_rtt    EMA over adjusted rtt
     395             :  *   min_rtt         minimum unadjusted rtt over all samples
     396             :  *   latest_rtt      the most recent rtt sample */
     397             : static inline void
     398      248444 : fd_quic_sample_rtt( fd_quic_conn_t * conn, long rtt_ticks, long ack_delay ) {
     399             :   /* for convenience */
     400      248444 :   fd_quic_conn_rtt_t * rtt = conn->rtt;
     401             : 
     402             :   /* ack_delay is in peer units, so scale to put in ticks */
     403      248444 :   float ack_delay_ticks = (float)ack_delay * rtt->peer_ack_delay_scale;
     404             : 
     405             :   /* bound ack_delay by peer_max_ack_delay */
     406      248444 :   ack_delay_ticks = fminf( ack_delay_ticks, rtt->peer_max_ack_delay_ticks );
     407             : 
     408             :   /* minrtt is estimated from rtt_ticks without adjusting for ack_delay */
     409      248444 :   rtt->min_rtt = fminf( rtt->min_rtt, (float)rtt_ticks );
     410             : 
     411             :   /* smoothed_rtt is calculated from adjusted rtt_ticks
     412             :        except: ack_delay must not be subtracted if the result would be less than minrtt */
     413      248444 :   float adj_rtt = fmaxf( rtt->min_rtt, (float)rtt_ticks - (float)ack_delay_ticks );
     414             : 
     415      248444 :   rtt->latest_rtt = adj_rtt;
     416             : 
     417             :   /* according to rfc 9002 */
     418      248444 :   if( !rtt->is_rtt_valid ) {
     419          15 :     rtt->smoothed_rtt = adj_rtt;
     420          15 :     rtt->var_rtt      = adj_rtt * 0.5f;
     421          15 :     rtt->is_rtt_valid = 1;
     422      248429 :   } else {
     423      248429 :     rtt->smoothed_rtt = (7.f/8.f) * rtt->smoothed_rtt + (1.f/8.f) * adj_rtt;
     424      248429 :     float var_rtt_sample = fabsf( rtt->smoothed_rtt - adj_rtt );
     425      248429 :     rtt->var_rtt = (3.f/4.f) * rtt->var_rtt + (1.f/4.f) * var_rtt_sample;
     426             : 
     427      248429 :     FD_DEBUG({
     428      248429 :       double us_per_tick = 1.0 / (double)conn->quic->config.tick_per_us;
     429      248429 :       FD_LOG_NOTICE(( "conn_idx: %u  min_rtt: %f  smoothed_rtt: %f  var_rtt: %f  adj_rtt: %f  rtt_ticks: %f  ack_delay_ticks: %f  diff: %f",
     430      248429 :                        (uint)conn->conn_idx,
     431      248429 :                        us_per_tick * (double)rtt->min_rtt,
     432      248429 :                        us_per_tick * (double)rtt->smoothed_rtt,
     433      248429 :                        us_per_tick * (double)rtt->var_rtt,
     434      248429 :                        us_per_tick * (double)adj_rtt,
     435      248429 :                        us_per_tick * (double)rtt_ticks,
     436      248429 :                        us_per_tick * (double)ack_delay_ticks,
     437      248429 :                        us_per_tick * ( (double)rtt_ticks - (double)ack_delay_ticks ) ));
     438      248429 :     })
     439      248429 :   }
     440             : 
     441      248444 : }
     442             : 
     443             : /* fd_quic_calc_expiry returns the timestamp of the next expiry event. */
     444             : 
     445             : static inline ulong
     446    13602188 : fd_quic_calc_expiry( fd_quic_conn_t * conn, ulong now ) {
     447             :   /* Instead of a full implementation of PTO, we're setting an expiry
     448             :      time per sent QUIC packet
     449             :      This calculates the expiry time according to the PTO spec
     450             :      6.2.1. Computing PTO
     451             :      When an ack-eliciting packet is transmitted, the sender schedules
     452             :      a timer for the PTO period as follows:
     453             :      PTO = smoothed_rtt + max(4*rttvar, kGranularity) + max_ack_delay  */
     454             : 
     455    13602188 :   fd_quic_conn_rtt_t * rtt = conn->rtt;
     456             : 
     457    13602188 :   ulong duration = (ulong)( rtt->smoothed_rtt
     458    13602188 :                         + fmaxf( 4.0f * rtt->var_rtt, rtt->sched_granularity_ticks )
     459    13602188 :                         + rtt->peer_max_ack_delay_ticks );
     460             : 
     461    13602188 :   FD_DTRACE_PROBE_2( quic_calc_expiry, conn->our_conn_id, duration );
     462             : 
     463    13602188 :   return now + (ulong)500e6; /* 500ms */
     464    13602188 : }
     465             : 
     466             : uchar *
     467             : fd_quic_gen_stream_frames( fd_quic_conn_t *     conn,
     468             :                            uchar *              payload_ptr,
     469             :                            uchar *              payload_end,
     470             :                            fd_quic_pkt_meta_t * pkt_meta,
     471             :                            ulong                pkt_number,
     472             :                            ulong                now );
     473             : 
     474             : FD_PROTOTYPES_END
     475             : 
     476             : #endif /* HEADER_fd_src_waltz_quic_fd_quic_private_h */

Generated by: LCOV version 1.14