LCOV - code coverage report
Current view: top level - waltz/quic/tests - fd_quic_sandbox.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 186 234 79.5 %
Date: 2024-11-13 11:58:15 Functions: 12 14 85.7 %

          Line data    Source code
       1             : #include "fd_quic_sandbox.h"
       2             : #include "../fd_quic_private.h"
       3             : 
       4             : /* fd_quic_sandbox_capture_pkt captures a single outgoing packet sent by
       5             :    fd_quic. */
       6             : 
       7             : static void
       8             : fd_quic_sandbox_capture_pkt( fd_quic_sandbox_t *       sandbox,
       9     1206805 :                              fd_aio_pkt_info_t const * pkt ) {
      10             : 
      11     1206805 :   ulong            seq    = sandbox->pkt_seq_w;
      12     1206805 :   fd_frag_meta_t * mcache = sandbox->pkt_mcache;
      13     1206805 :   void *           dcache = sandbox->pkt_dcache;
      14     1206805 :   ulong            mtu    = sandbox->pkt_mtu;
      15     1206805 :   ulong            chunk  = sandbox->pkt_chunk;
      16     1206805 :   ulong            chunk0 = fd_dcache_compact_chunk0( sandbox, dcache );
      17     1206805 :   ulong            wmark  = fd_dcache_compact_wmark ( sandbox, dcache, mtu );
      18     1206805 :   ulong            depth  = fd_mcache_depth( mcache );
      19     1206805 :   ulong            sz     = pkt->buf_sz;
      20     1206805 :   uchar *          data   = fd_chunk_to_laddr( sandbox, chunk );
      21     1206805 :   ulong            ctl    = fd_frag_meta_ctl( /* orig */ 0, /* som */ 1, /* eom */ 1, /* err */ 0 );
      22     1206805 :   ulong            ts     = sandbox->wallclock;
      23             : 
      24     1206805 :   fd_memcpy( data, pkt->buf, sz );
      25     1206805 :   fd_mcache_publish( mcache, depth, seq, 0UL, chunk, sz, ctl, ts, ts );
      26             : 
      27     1206805 :   sandbox->pkt_seq_w = fd_seq_inc( seq, 1UL );
      28     1206805 :   sandbox->pkt_chunk = fd_dcache_compact_next( chunk, pkt->buf_sz, chunk0, wmark );
      29     1206805 : }
      30             : 
      31             : /* fd_quic_sandbox_aio_send implements fd_aio_send_func_t.  Called by
      32             :    the sandbox fd_quic to capture response packets into the sandbox
      33             :    capture ring. */
      34             : 
      35             : static int
      36             : fd_quic_sandbox_aio_send( void *                    ctx,
      37             :                           fd_aio_pkt_info_t const * batch,
      38             :                           ulong                     batch_cnt,
      39             :                           ulong *                   opt_batch_idx,
      40     2413610 :                           int                       flush ) {
      41             : 
      42     2413610 :   fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)ctx;
      43             : 
      44     3620415 :   for( ulong j=0UL; j<batch_cnt; j++ ) {
      45     1206805 :     fd_quic_sandbox_capture_pkt( sandbox, batch + j );
      46     1206805 :   }
      47             : 
      48     2413610 :   ulong _batch_idx[1];
      49     2413610 :   opt_batch_idx = opt_batch_idx ? opt_batch_idx : _batch_idx;
      50     2413610 :   *opt_batch_idx = batch_cnt;
      51             : 
      52     2413610 :   (void)flush;
      53     2413610 :   return FD_AIO_SUCCESS;
      54     2413610 : }
      55             : 
      56             : fd_frag_meta_t const *
      57           0 : fd_quic_sandbox_next_packet( fd_quic_sandbox_t * sandbox ) {
      58           0 :   fd_frag_meta_t * mcache = sandbox->pkt_mcache;
      59             : 
      60           0 :   ulong depth = fd_mcache_depth( mcache );
      61           0 :   ulong seq   = sandbox->pkt_seq_r;
      62           0 :   ulong mline = fd_mcache_line_idx( seq, depth );
      63             : 
      64           0 :   fd_frag_meta_t * frag = mcache + mline;
      65           0 :   if( FD_UNLIKELY( fd_seq_lt( frag->seq, seq ) ) ) return NULL;
      66           0 :   if( FD_UNLIKELY( fd_seq_gt( frag->seq, seq ) ) ) {
      67             :     /* Occurs if the fd_quic published 'depth' packets in succession
      68             :        without any reads via this function. */
      69           0 :     FD_LOG_WARNING(( "overrun detected, some captured packets were lost" ));
      70           0 :     seq = frag->seq;
      71           0 :   }
      72             : 
      73           0 :   sandbox->pkt_seq_r = fd_seq_inc( seq, 1UL );
      74             : 
      75           0 :   return frag;
      76           0 : }
      77             : 
      78             : uchar const fd_quic_sandbox_self_ed25519_keypair[64] =
      79             :   { /* private key */
      80             :     0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
      81             :     0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
      82             :     0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
      83             :     0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
      84             :     /* public key */
      85             :     0xdb, 0x99, 0x5f, 0xe2, 0x51, 0x69, 0xd1, 0x41,
      86             :     0xca, 0xb9, 0xbb, 0xba, 0x92, 0xba, 0xa0, 0x1f,
      87             :     0x9f, 0x2e, 0x1e, 0xce, 0x7d, 0xf4, 0xcb, 0x2a,
      88             :     0xc0, 0x51, 0x90, 0xf3, 0x7f, 0xcc, 0x1f, 0x9d };
      89             : 
      90             : 
      91             : uchar const fd_quic_sandbox_peer_ed25519_keypair[64] =
      92             :   { /* private key */
      93             :     0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
      94             :     0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
      95             :     0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
      96             :     0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
      97             :     /* public key */
      98             :     0x21, 0x52, 0xf8, 0xd1, 0x9b, 0x79, 0x1d, 0x24,
      99             :     0x45, 0x32, 0x42, 0xe1, 0x5f, 0x2e, 0xab, 0x6c,
     100             :     0xb7, 0xcf, 0xfa, 0x7b, 0x6a, 0x5e, 0xd3, 0x00,
     101             :     0x97, 0x96, 0x0e, 0x06, 0x98, 0x81, 0xdb, 0x12 };
     102             : 
     103             : uchar const fd_quic_sandbox_aes128_key[16] =
     104             :   { 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
     105             :     0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43 };
     106             : 
     107             : uchar const fd_quic_sandbox_aes128_iv[12] =
     108             :   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     109             :     0x00, 0x00, 0x00, 0x00 };
     110             : 
     111             : static ulong
     112           0 : fd_quic_sandbox_now_cb( void * context ) {
     113           0 :   fd_quic_sandbox_t * sandbox = context;
     114           0 :   return sandbox->wallclock;
     115           0 : }
     116             : 
     117             : ulong
     118          15 : fd_quic_sandbox_align( void ) {
     119          15 :   return fd_ulong_max( fd_ulong_max( fd_ulong_max( fd_ulong_max(
     120          15 :       alignof(fd_quic_sandbox_t),
     121          15 :       fd_quic_align() ),
     122          15 :       fd_mcache_align() ),
     123          15 :       fd_dcache_align() ),
     124          15 :       FD_CHUNK_ALIGN );
     125          15 : }
     126             : 
     127             : ulong
     128             : fd_quic_sandbox_footprint( fd_quic_limits_t const * quic_limits,
     129             :                            ulong                    pkt_cnt,
     130           6 :                            ulong                    mtu ) {
     131             : 
     132           6 :   ulong root_align = fd_quic_sandbox_align();
     133           6 :   ulong quic_fp    = fd_quic_footprint( quic_limits );
     134           6 :   ulong mcache_fp  = fd_mcache_footprint( pkt_cnt, 0UL );
     135           6 :   ulong dcache_fp  = fd_dcache_footprint( fd_dcache_req_data_sz( mtu, pkt_cnt, 1UL, 1 ), 0UL );
     136             : 
     137           6 :   if( FD_UNLIKELY( !quic_fp   ) ) return 0UL;
     138           6 :   if( FD_UNLIKELY( !mcache_fp ) ) return 0UL;
     139           6 :   if( FD_UNLIKELY( !dcache_fp ) ) return 0UL;
     140             : 
     141           6 :   ulong l = FD_LAYOUT_INIT;
     142           6 :   l = FD_LAYOUT_APPEND( l, root_align,        sizeof(fd_quic_sandbox_t) );
     143           6 :   l = FD_LAYOUT_APPEND( l, fd_quic_align(),   quic_fp                   );
     144           6 :   l = FD_LAYOUT_APPEND( l, fd_mcache_align(), mcache_fp                 );
     145           6 :   l = FD_LAYOUT_APPEND( l, fd_dcache_align(), dcache_fp                 );
     146           6 :   return FD_LAYOUT_FINI( l, root_align );
     147           6 : }
     148             : 
     149             : void *
     150             : fd_quic_sandbox_new( void *                   mem,
     151             :                      fd_quic_limits_t const * quic_limits,
     152             :                      ulong                    pkt_cnt,
     153           3 :                      ulong                    mtu ) {
     154             : 
     155           3 :   if( FD_UNLIKELY( !mem ) ) {
     156           0 :     FD_LOG_WARNING(( "NULL mem" ));
     157           0 :     return NULL;
     158           0 :   }
     159             : 
     160           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_quic_sandbox_align() ) ) ) {
     161           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     162           0 :     return NULL;
     163           0 :   }
     164             : 
     165           3 :   ulong fp = fd_quic_sandbox_footprint( quic_limits, pkt_cnt, mtu );
     166           3 :   if( FD_UNLIKELY( !fp ) ) {
     167           0 :     FD_LOG_WARNING(( "invalid params" ));
     168           0 :     return NULL;
     169           0 :   }
     170             : 
     171           3 :   ulong root_align     = fd_quic_sandbox_align();
     172           3 :   ulong quic_fp        = fd_quic_footprint( quic_limits );
     173           3 :   ulong mcache_fp      = fd_mcache_footprint( pkt_cnt, 0UL );
     174           3 :   ulong dcache_data_sz = fd_dcache_req_data_sz( mtu, pkt_cnt, 1UL, 1 );
     175           3 :   ulong dcache_fp      = fd_dcache_footprint( dcache_data_sz, 0UL );
     176             : 
     177           3 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     178           3 :   fd_quic_sandbox_t * sandbox    = FD_SCRATCH_ALLOC_APPEND( l, root_align,        sizeof(fd_quic_sandbox_t) );
     179           3 :   void *              quic_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_quic_align(),   quic_fp                   );
     180           3 :   void *              mcache_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_mcache_align(), mcache_fp                 );
     181           3 :   void *              dcache_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_dcache_align(), dcache_fp                 );
     182           3 :   FD_SCRATCH_ALLOC_FINI( l, root_align );
     183             : 
     184           3 :   ulong seq0 = 0UL;  /* the first packet in the capture always has sequence number 0 */
     185             : 
     186           3 :   *sandbox = (fd_quic_sandbox_t) {
     187           3 :     .quic       = fd_quic_join  ( fd_quic_new( quic_mem, quic_limits ) ),
     188           3 :     .pkt_mcache = fd_mcache_join( fd_mcache_new( mcache_mem, pkt_cnt, 0UL, seq0 ) ),
     189           3 :     .pkt_dcache = fd_dcache_join( fd_dcache_new( dcache_mem, dcache_data_sz, 0UL ) ),
     190           3 :     .pkt_seq_r  = seq0,
     191           3 :     .pkt_mtu    = mtu
     192           3 :   };
     193             : 
     194           3 :   FD_COMPILER_MFENCE();
     195           3 :   sandbox->magic = FD_QUIC_SANDBOX_MAGIC;
     196           3 :   FD_COMPILER_MFENCE();
     197             : 
     198           3 :   return sandbox;
     199           3 : }
     200             : 
     201             : fd_quic_sandbox_t *
     202           3 : fd_quic_sandbox_join( void * mem ) {
     203             : 
     204           3 :   if( FD_UNLIKELY( !mem ) ) {
     205           0 :     FD_LOG_WARNING(( "NULL mem" ));
     206           0 :     return NULL;
     207           0 :   }
     208             : 
     209           3 :   fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)mem;
     210           3 :   if( FD_UNLIKELY( sandbox->magic != FD_QUIC_SANDBOX_MAGIC ) ) {
     211           0 :     FD_LOG_WARNING(( "invalid magic" ));
     212           0 :     return NULL;
     213           0 :   }
     214             : 
     215           3 :   return sandbox;
     216           3 : }
     217             : 
     218             : fd_quic_sandbox_t *
     219             : fd_quic_sandbox_init( fd_quic_sandbox_t * sandbox,
     220           3 :                       int                 role ) {
     221             : 
     222           3 :   fd_quic_t *        quic     = sandbox->quic;
     223           3 :   fd_quic_config_t * quic_cfg = &quic->config;
     224             : 
     225           3 :   quic_cfg->role                  = role;
     226           3 :   quic_cfg->idle_timeout          = FD_QUIC_SANDBOX_IDLE_TIMEOUT;
     227           3 :   quic_cfg->net.ip_addr           = FD_QUIC_SANDBOX_SELF_IP4;
     228           3 :   quic_cfg->net.listen_udp_port   = FD_QUIC_SANDBOX_SELF_PORT;
     229           3 :   quic_cfg->net.ephem_udp_port.lo = FD_QUIC_SANDBOX_SELF_PORT;
     230           3 :   quic_cfg->net.ephem_udp_port.hi = FD_QUIC_SANDBOX_SELF_PORT + 1;
     231           3 :   quic_cfg->initial_rx_max_stream_data = 512UL; /* arbitrary */
     232           3 :   memcpy( quic_cfg->identity_public_key, fd_quic_sandbox_self_ed25519_keypair + 32, 32 );
     233           3 :   memset( &quic->metrics, 0, sizeof(fd_quic_metrics_t) );
     234             : 
     235           3 :   fd_aio_t aio_tx = {
     236           3 :     .send_func = fd_quic_sandbox_aio_send,
     237           3 :     .ctx       = sandbox
     238           3 :   };
     239           3 :   fd_quic_set_aio_net_tx( quic, &aio_tx );
     240             : 
     241           3 :   quic->cb.now_ctx = sandbox;
     242           3 :   quic->cb.now     = fd_quic_sandbox_now_cb;
     243             : 
     244           3 :   if( FD_UNLIKELY( !fd_quic_init( quic ) ) ) {
     245           0 :     FD_LOG_WARNING(( "fd_quic_init failed" ));
     246           0 :     return NULL;
     247           0 :   }
     248             : 
     249           3 :   sandbox->wallclock = 0UL;
     250           3 :   sandbox->pkt_seq_r = 0UL;
     251           3 :   sandbox->pkt_seq_w = 0UL;
     252           3 :   sandbox->pkt_mcache[0].seq = ULONG_MAX;  /* mark first entry as unpublished */
     253           3 :   sandbox->pkt_chunk = fd_dcache_compact_chunk0( sandbox, sandbox->pkt_dcache );
     254             : 
     255           3 :   return sandbox;
     256           3 : }
     257             : 
     258             : void *
     259           3 : fd_quic_sandbox_leave( fd_quic_sandbox_t * sandbox ) {
     260           3 :   return (void *)sandbox;
     261           3 : }
     262             : 
     263             : void *
     264           3 : fd_quic_sandbox_delete( void * mem ) {
     265             : 
     266           3 :   if( FD_UNLIKELY( !mem ) ) {
     267           0 :     FD_LOG_WARNING(( "NULL mem" ));
     268           0 :     return NULL;
     269           0 :   }
     270             : 
     271           3 :   fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)mem;
     272           3 :   if( FD_UNLIKELY( sandbox->magic != FD_QUIC_SANDBOX_MAGIC ) ) {
     273           0 :     FD_LOG_WARNING(( "invalid magic" ));
     274           0 :     return NULL;
     275           0 :   }
     276             : 
     277           3 :   FD_COMPILER_MFENCE();
     278           3 :   sandbox->magic = 0UL;
     279           3 :   FD_COMPILER_MFENCE();
     280             : 
     281           3 :   fd_quic_delete  ( fd_quic_leave  ( sandbox->quic       ) );
     282           3 :   fd_mcache_delete( fd_mcache_leave( sandbox->pkt_mcache ) );
     283           3 :   fd_dcache_delete( fd_dcache_leave( sandbox->pkt_dcache ) );
     284             : 
     285           3 :   return mem;
     286           3 : }
     287             : 
     288             : fd_quic_conn_t *
     289             : fd_quic_sandbox_new_conn_established( fd_quic_sandbox_t * sandbox,
     290      300000 :                                       fd_rng_t *          rng ) {
     291             : 
     292      300000 :   fd_quic_t * quic = sandbox->quic;
     293             : 
     294             :   /* fd_quic_t conn IDs are always 8 bytes */
     295      300000 :   ulong             our_conn_id_u64 = fd_rng_ulong( rng );
     296             : 
     297             :   /* the peer may choose a conn ID size 1 to 16 bytes
     298             :      For now, pick 8 bytes too */
     299      300000 :   ulong             peer_conn_id_u64 = fd_rng_ulong( rng );
     300      300000 :   fd_quic_conn_id_t peer_conn_id     = fd_quic_conn_id_new( &peer_conn_id_u64, 8UL );
     301             : 
     302      300000 :   fd_quic_conn_t * conn = fd_quic_conn_create(
     303      300000 :       /* quic         */ quic,
     304      300000 :       /* our_conn_id  */ our_conn_id_u64,
     305      300000 :       /* peer_conn_id */ &peer_conn_id,
     306             :       /* dst_ip_addr  */ FD_QUIC_SANDBOX_PEER_IP4,
     307             :       /* dst_udp_addr */ FD_QUIC_SANDBOX_PEER_PORT,
     308      300000 :       /* server       */ quic->config.role == FD_QUIC_ROLE_SERVER );
     309      300000 :   if( FD_UNLIKELY( !conn ) ) {
     310           0 :     FD_LOG_WARNING(( "fd_quic_conn_create failed" ));
     311           0 :     return NULL;
     312           0 :   }
     313             : 
     314      300000 :   conn->state       = FD_QUIC_CONN_STATE_ACTIVE;
     315      300000 :   conn->established = 1;
     316             : 
     317             :   /* Mock a completed handshake */
     318      300000 :   conn->handshake_complete = 1;
     319      300000 :   conn->hs_data_empty      = 1;
     320      300000 :   conn->peer_enc_level     = fd_quic_enc_level_appdata_id;
     321             : 
     322      300000 :   conn->idle_timeout  = FD_QUIC_SANDBOX_IDLE_TIMEOUT;
     323      300000 :   conn->last_activity = sandbox->wallclock;
     324             : 
     325             :   /* Reset flow control limits */
     326      300000 :   conn->tx_max_data      = 0UL;
     327      300000 :   conn->tx_tot_data      = 0UL;
     328      300000 :   conn->rx_max_data      = 0UL;
     329      300000 :   conn->rx_tot_data      = 0UL;
     330      300000 :   conn->rx_max_data_ackd = 0UL;
     331      300000 :   conn->tx_initial_max_stream_data_uni = 0UL;
     332             : 
     333             :   /* TODO set a realistic packet number */
     334             : 
     335      300000 :   return conn;
     336      300000 : }
     337             : 
     338             : void
     339             : fd_quic_sandbox_send_frame( fd_quic_sandbox_t * sandbox,
     340             :                             fd_quic_conn_t *    conn,
     341             :                             fd_quic_pkt_t *     pkt_meta,
     342             :                             uchar const *       frame_ptr,
     343    25161723 :                             ulong               frame_sz ) {
     344             : 
     345             :   /* TODO consider crafting a real app packet instead of bypassing
     346             :           packet processing checks */
     347             : 
     348    25161723 :   fd_quic_t * quic = sandbox->quic;
     349             : 
     350             :   /* set pkt_type to FD_QUIC_PKT_TYPE_ONE_RTT as it allows all
     351             :    * frame types */
     352    25161723 :   uint pkt_type = FD_QUIC_PKT_TYPE_ONE_RTT;
     353             : 
     354    25161723 :   ulong rc = fd_quic_handle_v1_frame( quic, conn, pkt_meta, pkt_type, frame_ptr, frame_sz );
     355    25161723 :   if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return;
     356    25161723 :   if( FD_UNLIKELY( rc==0UL || rc>frame_sz ) ) {
     357           0 :     fd_quic_conn_error( conn, FD_QUIC_CONN_REASON_PROTOCOL_VIOLATION, __LINE__ );
     358           0 :     return;
     359           0 :   }
     360             : 
     361    25161723 : }
     362             : 
     363             : void
     364             : fd_quic_sandbox_send_lone_frame( fd_quic_sandbox_t * sandbox,
     365             :                                  fd_quic_conn_t *    conn,
     366             :                                  uchar const *       frame,
     367    25161723 :                                  ulong               frame_sz ) {
     368             : 
     369    25161723 :   FD_TEST( frame_sz <= sandbox->pkt_mtu );
     370             : 
     371    25161723 :   ulong pkt_num = conn->exp_pkt_number[2]++;
     372             : 
     373    25161723 :   ulong quic_pkt_sz = frame_sz;  /* TODO mock some QUIC packetization overhead */
     374             : 
     375    25161723 :   fd_quic_pkt_t pkt_meta = {
     376    25161723 :     .ip4 = {{
     377    25161723 :       .verihl       = FD_IP4_VERIHL(4,5),
     378    25161723 :       .net_tot_len  = (ushort)( 20 + 8 + quic_pkt_sz ),
     379    25161723 :       .net_frag_off = 0x4000u, /* don't fragment */
     380    25161723 :       .ttl          = 64,
     381    25161723 :       .protocol     = FD_IP4_HDR_PROTOCOL_UDP,
     382    25161723 :     }},
     383    25161723 :     .udp = {{
     384    25161723 :       .net_sport = FD_QUIC_SANDBOX_PEER_PORT,
     385    25161723 :       .net_dport = FD_QUIC_SANDBOX_SELF_PORT,
     386    25161723 :       .net_len   = (ushort)( 8 + quic_pkt_sz ),
     387    25161723 :     }},
     388    25161723 :     .pkt_number = pkt_num,
     389    25161723 :     .rcv_time   = sandbox->wallclock,
     390    25161723 :     .enc_level  = fd_quic_enc_level_appdata_id,
     391    25161723 :   };
     392             : 
     393    25161723 :   fd_quic_sandbox_send_frame( sandbox, conn, &pkt_meta, frame, frame_sz );
     394             : 
     395    25161723 :   fd_quic_lazy_ack_pkt( sandbox->quic, conn, &pkt_meta );
     396             : 
     397    25161723 : }

Generated by: LCOV version 1.14