@@ -1641,5 +1641,239 @@ int crypto_hs_offset_test()
1641
1641
ret = crypto_hs_offset_test_one (pc [i ]);
1642
1642
}
1643
1643
1644
+ return ret ;
1645
+ }
1646
+
1647
+ /*
1648
+ * Test what happens if there is data sent after reset,
1649
+ * and possibly other shenanigans.
1650
+ *
1651
+ */
1652
+
1653
+ static test_api_stream_desc_t test_scenario_reset_case [] = {
1654
+ { 4 , 0 , 128 , 1000000 },
1655
+ { 8 , 0 , 128 , 1000000 }
1656
+ };
1657
+
1658
+ typedef struct st_reset_loop_callback_t {
1659
+ uint64_t data_sent [4 ];
1660
+ uint64_t data_received [4 ];
1661
+ int fin_received [4 ];
1662
+ int reset_received [4 ];
1663
+ } reset_loop_callback_t ;
1664
+
1665
+
1666
+ int reset_loop_prepare_to_send (reset_loop_callback_t * cb , int stream_rank , void * context , size_t space )
1667
+ {
1668
+ int ret = 0 ;
1669
+ uint8_t * buffer ;
1670
+
1671
+ if (stream_rank >= 4 ) {
1672
+ ret = -1 ;
1673
+ }
1674
+ else {
1675
+ int is_fin = (cb -> data_sent [stream_rank ] + space > 1000000 );
1676
+ buffer = (uint8_t * )picoquic_provide_stream_data_buffer (context , space , is_fin , !is_fin );
1677
+
1678
+ if (buffer == NULL ) {
1679
+ ret = -1 ;
1680
+ }
1681
+ else {
1682
+ memset (buffer , (uint8_t )('a' + stream_rank ), space );
1683
+ cb -> data_sent [stream_rank ] += space ;
1684
+ }
1685
+ }
1686
+ return ret ;
1687
+ }
1688
+
1689
+ int reset_loop_callback (picoquic_cnx_t * cnx ,
1690
+ uint64_t stream_id , uint8_t * bytes , size_t length ,
1691
+ picoquic_call_back_event_t fin_or_event , void * callback_ctx , void * v_stream_ctx )
1692
+ {
1693
+
1694
+ int ret = 0 ;
1695
+ int stream_rank = (int )((stream_id / 2 ) - 2 ) + cnx -> client_mode ;
1696
+ reset_loop_callback_t * cb = (reset_loop_callback_t * )callback_ctx ;
1697
+
1698
+ if (ret == 0 ) {
1699
+ switch (fin_or_event ) {
1700
+ case picoquic_callback_stream_data :
1701
+ case picoquic_callback_stream_fin :
1702
+ cb -> data_received [stream_rank ] += length ;
1703
+ if (fin_or_event == picoquic_callback_stream_fin ) {
1704
+ cb -> fin_received [stream_rank ] += 1 ;
1705
+ }
1706
+ if (!cnx -> client_mode && cb -> data_sent [stream_rank ] == 0 ) {
1707
+ picoquic_mark_active_stream (cnx , stream_id , 1 , cb );
1708
+ }
1709
+ break ;
1710
+ case picoquic_callback_prepare_to_send :
1711
+ ret = reset_loop_prepare_to_send (cb , stream_rank , bytes , length );
1712
+ break ;
1713
+ case picoquic_callback_datagram :
1714
+ /* Receive data in a datagram */
1715
+ break ;
1716
+ case picoquic_callback_prepare_datagram :
1717
+ ret = -1 ;
1718
+ break ;
1719
+ case picoquic_callback_stream_reset : /* Client reset stream #x */
1720
+ cb -> reset_received [stream_rank ] += 1 ;
1721
+ break ;
1722
+ case picoquic_callback_stop_sending : /* Client asks server to reset stream #x */
1723
+ ret = picoquic_reset_stream (cnx , stream_id , 0 );
1724
+ break ;
1725
+ case picoquic_callback_stateless_reset : /* Received an error message */
1726
+ case picoquic_callback_close : /* Received connection close */
1727
+ case picoquic_callback_application_close : /* Received application close */
1728
+ /* Remove the connection from the context, and then delete it */
1729
+ picoquic_set_callback (cnx , NULL , NULL );
1730
+ break ;
1731
+ case picoquic_callback_version_negotiation :
1732
+ /* The server should never receive a version negotiation response */
1733
+ break ;
1734
+ case picoquic_callback_stream_gap :
1735
+ /* This callback is never used. */
1736
+ break ;
1737
+ case picoquic_callback_almost_ready :
1738
+ case picoquic_callback_ready :
1739
+ break ;
1740
+ case picoquic_callback_datagram_acked :
1741
+ /* Ack for packet carrying datagram-object received from peer */
1742
+ case picoquic_callback_datagram_lost :
1743
+ /* Packet carrying datagram-object probably lost */
1744
+ case picoquic_callback_datagram_spurious :
1745
+ /* Packet carrying datagram-object was not really lost */
1746
+ break ;
1747
+ case picoquic_callback_pacing_changed :
1748
+ /* Notification of rate change from congestion controller */
1749
+ break ;
1750
+ default :
1751
+ /* unexpected */
1752
+ break ;
1753
+ }
1754
+ }
1755
+
1756
+ if (ret != 0 ) {
1757
+ DBG_PRINTF ("Reset loop callback returns %d, event %d" , ret , fin_or_event );
1758
+ }
1759
+
1760
+ return ret ;
1761
+ }
1762
+
1763
+ int reset_loop_test ()
1764
+ {
1765
+ uint64_t simulated_time = 0 ;
1766
+ uint64_t loss_mask = 0 ;
1767
+ uint64_t timeout ;
1768
+ uint64_t test_stream = 8 ;
1769
+ reset_loop_callback_t cb = { 0 };
1770
+ picoquic_stream_head_t * stream = NULL ;
1771
+ picoquic_test_tls_api_ctx_t * test_ctx = NULL ;
1772
+ int ret = tls_api_init_ctx (& test_ctx , PICOQUIC_INTERNAL_TEST_VERSION_1 ,
1773
+ PICOQUIC_TEST_SNI , PICOQUIC_TEST_ALPN , & simulated_time , NULL , NULL , 0 , 0 , 0 );
1774
+
1775
+ if (ret == 0 ) {
1776
+ uint8_t bogus_data [4 ] = { 0 };
1777
+ picoquic_set_default_callback (test_ctx -> qserver , reset_loop_callback , & cb );
1778
+ picoquic_set_callback (test_ctx -> cnx_client , reset_loop_callback , & cb );
1779
+ picoquic_start_client_cnx (test_ctx -> cnx_client );
1780
+ picoquic_add_to_stream (test_ctx -> cnx_client , 4 , bogus_data , 4 , 0 );
1781
+ picoquic_add_to_stream (test_ctx -> cnx_client , 8 , bogus_data , 4 , 0 );
1782
+ }
1783
+
1784
+ if (ret == 0 ) {
1785
+ ret = tls_api_connection_loop (test_ctx , & loss_mask , 0 , & simulated_time );
1786
+ }
1787
+
1788
+ /* Prepare to send data */
1789
+ if (ret == 0 ) {
1790
+ picoquic_mark_active_stream (test_ctx -> cnx_client , 4 , 1 , & cb );
1791
+ picoquic_mark_active_stream (test_ctx -> cnx_client , 8 , 1 , & cb );
1792
+ /* set priorities */
1793
+ if (ret == 0 ) {
1794
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_client , 4 , 8 );
1795
+ }
1796
+ if (ret == 0 ) {
1797
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_client , 8 , 8 );
1798
+ }
1799
+ }
1800
+
1801
+ /* Perform a few rounds of sending loop, but not enough to send all the data */
1802
+ if (ret == 0 ) {
1803
+ timeout = simulated_time + 100000 ;
1804
+ ret = tls_api_wait_for_timeout (test_ctx , & simulated_time , timeout );
1805
+ }
1806
+
1807
+ /* trigger a reset of tst stream */
1808
+ if (ret == 0 ) {
1809
+ ret = picoquic_reset_stream (test_ctx -> cnx_server , test_stream , 0 );
1810
+ }
1811
+
1812
+ /* set priorities */
1813
+ if (ret == 0 ) {
1814
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_client , 4 , 9 );
1815
+ }
1816
+ if (ret == 0 ) {
1817
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_client , 8 , 7 );
1818
+ }
1819
+ if (ret == 0 ) {
1820
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_server , 4 , 9 );
1821
+ }
1822
+ if (ret == 0 ) {
1823
+ ret = picoquic_set_stream_priority (test_ctx -> cnx_server , 8 , 7 );
1824
+ }
1825
+
1826
+ /* make sure that reset is sent */
1827
+ if (ret == 0 ) {
1828
+ timeout = simulated_time + 100000 ;
1829
+ for (int i = 0 ; ret == 0 && i < 16 ; i ++ ) {
1830
+ int was_active = 0 ;
1831
+ ret = tls_api_one_sim_round (test_ctx , & simulated_time , timeout , & was_active );
1832
+ if (ret == 0 ) {
1833
+ stream = picoquic_find_stream (test_ctx -> cnx_server , test_stream );
1834
+ if (stream == NULL ) {
1835
+ ret = -1 ;
1836
+ break ;
1837
+ }
1838
+ else if (stream -> reset_sent ) {
1839
+ break ;
1840
+ }
1841
+ }
1842
+ }
1843
+ }
1844
+ if (ret == 0 && (stream == NULL || !stream -> reset_sent )) {
1845
+ DBG_PRINTF ("Could not reset stream %" PRIu64 , test_stream );
1846
+ ret = -1 ;
1847
+ }
1848
+
1849
+ if (ret == 0 ) {
1850
+ /* add data to the stream to elicit some bad behavior */
1851
+ uint8_t bogus_data [4 ] = { 1 , 2 , 3 , 4 };
1852
+ if (picoquic_add_to_stream (test_ctx -> cnx_server , test_stream , bogus_data , 4 , 1 ) == 0 ) {
1853
+ DBG_PRINTF ("Adding on stream %" PRIu64 " after reset should be forbidden" , test_stream );
1854
+ ret = -1 ;
1855
+ }
1856
+ }
1857
+
1858
+ if (ret == 0 ) {
1859
+ /* add data to the stream to elicit some bad behavior */
1860
+ uint8_t bogus_context [4 ] = { 0 , 0 , 0 , 0 };
1861
+ if (picoquic_mark_active_stream (test_ctx -> cnx_server , test_stream , 1 , bogus_context ) == 0 ) {
1862
+ DBG_PRINTF ("Marking stream %" PRIu64 " active after reset should be forbidden" , test_stream );
1863
+ ret = -1 ;
1864
+ }
1865
+ }
1866
+
1867
+ /* Do a loop to check the behavior */
1868
+ if (ret == 0 ) {
1869
+ timeout = simulated_time + 2000000 ;
1870
+ ret = tls_api_wait_for_timeout (test_ctx , & simulated_time , timeout );
1871
+ }
1872
+
1873
+ if (test_ctx != NULL ) {
1874
+ tls_api_delete_ctx (test_ctx );
1875
+ test_ctx = NULL ;
1876
+ }
1877
+
1644
1878
return ret ;
1645
1879
}
0 commit comments