99
1010#include "internal/uint_set.h"
1111#include "internal/common.h"
12+ #include "internal/quic_stream.h"
1213#include "internal/quic_strm_reas.h"
1314#include "internal/list.h"
1415
2122
2223#define DIRECT_STORAGE_SZ (2 * sizeof(void *))
2324
25+ /*
26+ * Maximal allocation overhead in packet buffers is ~64kB for
27+ * connection. If ~64kB limit is exceeded, then the newly received
28+ * chunks are moved from the packet to the stream buffer.
29+ */
30+ #define PKT_BUFFER_OVERHEAD_TRESHOLD (65535)
31+
2432/*
2533 * storage type indicates where stream data bytes
2634 * are stored.
@@ -50,6 +58,11 @@ struct stream_chunk_t {
5058 } sc_storage_u ;
5159};
5260
61+ struct quic_rstream_qparm_st {
62+ size_t rsqp_pkt_overhead_treshold ;
63+ size_t rsqp_pkt_overhead_sz ;
64+ };
65+
5366#define sc_data sc_data_u.u_data
5467#define sc_data_w sc_data_u.u_data_w
5568
@@ -61,6 +74,7 @@ DEFINE_LIST_OF(sc, struct stream_chunk_t);
6174
6275#define SCHUNK_SIZE (_sc ) ((_sc)->sc_range.end - (_sc)->sc_range.start)
6376#define SRANGE_SIZE (_sr ) ((_sr)->sr_range.end - (_sr)->sr_range.start)
77+ #define SCHUNK_OVERHEAD (_pkt , _sc ) ((_pkt)->datagram_len - SCHUNK_SIZE(_sc))
6478
6579/*
6680 * Stream range keeps list of continuous stream chunks. The range
@@ -88,6 +102,18 @@ OSSL_RBT_GENERATE(srange, stream_range_t, sr_rbe, srange_cmp);
88102
89103#define UINT64_TO_SIZE_T (_x ) ((size_t)(((_x) > SIZE_MAX) ? SIZE_MAX : (_x)))
90104
105+ static void rsqp_add_overhead (QUIC_RSTREAM_QPARM * rsqp , size_t sc_overhead )
106+ {
107+ if (rsqp != NULL )
108+ rsqp -> rsqp_pkt_overhead_sz += sc_overhead ;
109+ }
110+
111+ static void rsqp_sub_overhead (QUIC_RSTREAM_QPARM * rsqp , size_t sc_overhead )
112+ {
113+ if (rsqp != NULL )
114+ rsqp -> rsqp_pkt_overhead_sz -= sc_overhead ;
115+ }
116+
91117/*
92118 * Cleansing (SSL_OP_CLEANSE_PLAINTEXT) must write through the const
93119 * data pointers received from ossl_sframe_set_insert(), which may
@@ -192,27 +218,9 @@ static int srange_cmp(const struct stream_range_t *a_sr,
192218static int keep_schunk_data_on_packet (SFRAME_SET * fs , OSSL_QRX_PKT * pkt ,
193219 UINT_RANGE * r )
194220{
195- /*
196- * the function decides whether stream data should be moved
197- * from packet buffer to stream buffer or if data can stay
198- * at packet buffer.
199- *
200- * Keeping the data at packet saves yet another buffer
201- * allocation at heap (+ data transfer). On the other hand
202- * it opens door to malicious peer to force stack to use more
203- * memory than necessary.
204- *
205- * The function here should asses a current stream quality:
206- * how many stream chunks are there
207- * the time elapsed since the arrival of earlier chunk
208- * the time elapsed since the application consumed the data
209- * the size of the chunk compared with the whole packet size
210- * the size of chunk with respect to DIRECT_STORAGE_SZ
211- * ...
212- * the code to collect those parameters is still missing, once
213- * this gap will be filled this function will be able to
214- * make the decision.
215- */
221+ if (fs -> rsqp != NULL
222+ && fs -> rsqp -> rsqp_pkt_overhead_sz >= fs -> rsqp -> rsqp_pkt_overhead_treshold )
223+ return 0 ;
216224
217225 return 1 ;
218226}
@@ -222,6 +230,7 @@ static struct stream_chunk_t *new_schunk(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
222230{
223231 struct stream_chunk_t * sc ;
224232 uint64_t rsize ;
233+ size_t overhead ;
225234
226235 if (pkt == NULL )
227236 return NULL ;
@@ -230,14 +239,29 @@ static struct stream_chunk_t *new_schunk(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
230239 if (sc == NULL )
231240 return NULL ;
232241
242+ rsize = r -> end - r -> start ;
243+ assert (rsize <= pkt -> datagram_len );
244+ overhead = UINT64_TO_SIZE_T (pkt -> datagram_len - rsize );
245+ rsqp_add_overhead (fs -> rsqp , overhead );
246+
233247 if (keep_schunk_data_on_packet (fs , pkt , r ) == 1 ) {
234248 sc -> sc_st = ST_TYPE_PKT ;
235249 sc -> sc_pkt = pkt ;
236250 ossl_qrx_pkt_up_ref (pkt );
237251 sc -> sc_data = data ;
238252 sc -> sc_range = * r ;
253+ if (fs -> rsqp != NULL )
254+ DEBUG_PRINT (stderr ,
255+ "%s sc: %p sc overhead: %d pkt_buf_overhead_sz: %zu -> %zu\n" ,
256+ OPENSSL_FUNC , (void * )sc , SCHUNK_OVERHEAD (pkt , sc ),
257+ fs -> rsqp -> rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD (pkt , sc ),
258+ fs -> rsqp -> rsqp_pkt_overhead_sz );
239259 } else {
240- rsize = r -> end - r -> start ;
260+ /*
261+ * Only data which stay on packet must be accounted as overhead.
262+ */
263+ rsqp_sub_overhead (fs -> rsqp , overhead );
264+
241265 if (rsize <= DIRECT_STORAGE_SZ ) {
242266 DEBUG_PRINT (stderr , "%s ST_TYPE_DIRECT sc: %p %llu\n" , OPENSSL_FUNC ,
243267 (void * )sc , rsize );
@@ -277,6 +301,16 @@ static void destroy_schunk(SFRAME_SET *fs, struct stream_chunk_t *sc)
277301
278302 switch (sc -> sc_st ) {
279303 case ST_TYPE_PKT :
304+ assert (fs -> rsqp == NULL
305+ || fs -> rsqp -> rsqp_pkt_overhead_sz >= SCHUNK_OVERHEAD (sc -> sc_pkt , sc ));
306+ if (fs -> rsqp != NULL )
307+ DEBUG_PRINT (stderr ,
308+ "%s sc: %p sc overhead: %d pkt_buf_overhead_sz: %zu -> %zu\n" ,
309+ OPENSSL_FUNC , (void * )sc , SCHUNK_OVERHEAD (sc -> sc_pkt , sc ),
310+ fs -> rsqp -> rsqp_pkt_overhead_sz ,
311+ fs -> rsqp -> rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD (sc -> sc_pkt , sc ));
312+ rsqp_sub_overhead (fs -> rsqp ,
313+ UINT64_TO_SIZE_T (SCHUNK_OVERHEAD (sc -> sc_pkt , sc )));
280314 ossl_qrx_pkt_release (sc -> sc_pkt );
281315 break ;
282316 case ST_TYPE_HEAP :
@@ -338,10 +372,11 @@ static struct stream_range_t *create_range(SFRAME_SET *fs,
338372 return sr ;
339373}
340374
341- void ossl_sframe_set_init (SFRAME_SET * fs )
375+ void ossl_sframe_set_init (SFRAME_SET * fs , QUIC_RSTREAM_QPARM * rsqp )
342376{
343377 memset (fs , 0 , sizeof (* fs ));
344378 OSSL_RBT_INIT (srange , & fs -> ranges );
379+ fs -> rsqp = rsqp ;
345380}
346381
347382static uint64_t get_sc_dstorage_sz (struct stream_chunk_t * sc )
@@ -715,6 +750,7 @@ static int chop_range(SFRAME_SET *fs, struct stream_range_t *sr,
715750 uint64_t new_end )
716751{
717752 struct stream_chunk_t * sc ;
753+ size_t unused_sz ;
718754
719755 assert (sr -> sr_range .end >= new_end );
720756
@@ -744,6 +780,15 @@ static int chop_range(SFRAME_SET *fs, struct stream_range_t *sr,
744780 sc -> sc_range .end = new_end ;
745781 sr -> sr_range .end = new_end ;
746782
783+ if (sc -> sc_st == ST_TYPE_PKT ) {
784+ rsqp_add_overhead (fs -> rsqp , unused_sz );
785+ if (fs -> rsqp != NULL )
786+ DEBUG_PRINT (stderr , "%s sc: %p unused_sz: %zu %zu -> %zu\n" ,
787+ OPENSSL_FUNC , (void * )sc , unused_sz ,
788+ fs -> rsqp -> rsqp_pkt_overhead_sz - unused_sz ,
789+ fs -> rsqp -> rsqp_pkt_overhead_sz );
790+ }
791+
747792 return 1 ;
748793}
749794
@@ -764,7 +809,8 @@ static struct stream_range_t *merge_ranges(SFRAME_SET *fs,
764809 * sub_sr and super_sr are equal ranges (sets) super_sr
765810 * sub_sr is subset of super_sr (super_sr includes sub_sr).
766811 */
767- assert (super_sr -> sr_range .start <= sub_sr -> sr_range .start && super_sr -> sr_range .end >= sub_sr -> sr_range .end );
812+ assert (super_sr -> sr_range .start <= sub_sr -> sr_range .start
813+ && super_sr -> sr_range .end >= sub_sr -> sr_range .end );
768814
769815 DEBUG_PRINT (stderr , "%s super: %p [ %llu, %llu ], sub: %p [ %llu, %llu]\n" ,
770816 OPENSSL_FUNC , (void * )super_sr , super_sr -> sr_range .start ,
@@ -953,7 +999,7 @@ int ossl_sframe_set_insert(SFRAME_SET *fs, UINT_RANGE *r, OSSL_QRX_PKT *pkt,
953999 (void * )sr , sr -> sr_range .start , sr -> sr_range .end );
9541000
9551001 /*
956- * sandwich, append, prepend can still be improved to handle
1002+ * Following calls can still be improved to handle
9571003 * chunks with direct storage better, but I don't think it's
9581004 * worth the effort. out of order short data chunks (less
9591005 * than DIRECT_STORAGE_SZ) should be considered exceptional.
@@ -1006,23 +1052,27 @@ int ossl_sframe_set_insert(SFRAME_SET *fs, UINT_RANGE *r, OSSL_QRX_PKT *pkt,
10061052 adjacent_sr -> sr_range .end );
10071053 fs -> stream_ranges -- ;
10081054
1009- if (sr -> sr_range .start <= adjacent_sr -> sr_range .start && sr -> sr_range .end >= adjacent_sr -> sr_range .end ) {
1055+ if (sr -> sr_range .start <= adjacent_sr -> sr_range .start
1056+ && sr -> sr_range .end >= adjacent_sr -> sr_range .end ) {
10101057 /*
10111058 * adjacent_sr subset of sr
10121059 */
10131060 joined_sr = merge_ranges (fs , sr , adjacent_sr );
1014- } else if (sr -> sr_range .start >= adjacent_sr -> sr_range .start && sr -> sr_range .end <= adjacent_sr -> sr_range .end ) {
1061+ } else if (sr -> sr_range .start >= adjacent_sr -> sr_range .start
1062+ && sr -> sr_range .end <= adjacent_sr -> sr_range .end ) {
10151063 /*
10161064 * sr subset of adjacent_sr
10171065 */
10181066 joined_sr = merge_ranges (fs , adjacent_sr , sr );
1019- } else if (sr -> sr_range .start < adjacent_sr -> sr_range .start && sr -> sr_range .end >= adjacent_sr -> sr_range .start ) {
1067+ } else if (sr -> sr_range .start < adjacent_sr -> sr_range .start
1068+ && sr -> sr_range .end >= adjacent_sr -> sr_range .start ) {
10201069 /*
10211070 * adjacent_sr follows sr
10221071 */
10231072 assert (sr -> sr_range .end < adjacent_sr -> sr_range .end );
10241073 joined_sr = append_range (fs , sr , adjacent_sr );
1025- } else if (sr -> sr_range .start <= adjacent_sr -> sr_range .end && sr -> sr_range .end > adjacent_sr -> sr_range .end ) {
1074+ } else if (sr -> sr_range .start <= adjacent_sr -> sr_range .end
1075+ && sr -> sr_range .end > adjacent_sr -> sr_range .end ) {
10261076 /*
10271077 * sr follows adjacent_sr
10281078 */
@@ -1185,6 +1235,7 @@ int ossl_sframe_set_move_offset(SFRAME_SET *fs, uint64_t new_offset)
11851235{
11861236 struct stream_range_t * sr = OSSL_RBT_MIN (srange , & fs -> ranges );
11871237 struct stream_chunk_t * sc , * save_sc ;
1238+ size_t unused_sz ;
11881239
11891240 if (new_offset == fs -> offset )
11901241 return 1 ;
@@ -1231,6 +1282,15 @@ int ossl_sframe_set_move_offset(SFRAME_SET *fs, uint64_t new_offset)
12311282 sr -> sr_range .start = new_offset ;
12321283 DEBUG_PRINT (stderr , "[ %lli, %llu ]\n" ,
12331284 sr -> sr_range .start , sr -> sr_range .end );
1285+
1286+ if (sc -> sc_st == ST_TYPE_PKT ) {
1287+ rsqp_add_overhead (fs -> rsqp , unused_sz );
1288+ if (fs -> rsqp != NULL )
1289+ DEBUG_PRINT (stderr , "%s sc: %p unused_sz: %zu %zu -> %zu\n" ,
1290+ OPENSSL_FUNC , (void * )sc , unused_sz ,
1291+ fs -> rsqp -> rsqp_pkt_overhead_sz - unused_sz ,
1292+ fs -> rsqp -> rsqp_pkt_overhead_sz );
1293+ }
12341294 }
12351295
12361296 return 1 ;
@@ -1249,3 +1309,24 @@ int ossl_sframe_set_avail(SFRAME_SET *fs, uint64_t *avail, int *fin)
12491309 * fin = (fs -> fin && fs -> offset + * avail == fs -> fin_off ) ? 1 : 0 ;
12501310 return 1 ;
12511311}
1312+
1313+ QUIC_RSTREAM_QPARM * ossl_quic_rstream_qparm_new (void )
1314+ {
1315+ QUIC_RSTREAM_QPARM * rsqp ;
1316+
1317+ rsqp = OPENSSL_malloc (sizeof (QUIC_RSTREAM_QPARM ));
1318+ if (rsqp != NULL ) {
1319+ rsqp -> rsqp_pkt_overhead_treshold = PKT_BUFFER_OVERHEAD_TRESHOLD ;
1320+ rsqp -> rsqp_pkt_overhead_sz = 0 ;
1321+ }
1322+
1323+ return rsqp ;
1324+ }
1325+
1326+ void ossl_quic_rstream_qparm_destroy (QUIC_RSTREAM_QPARM * rsqp )
1327+ {
1328+ if (rsqp != NULL ) {
1329+ assert (rsqp -> rsqp_pkt_overhead_sz == 0 );
1330+ OPENSSL_free (rsqp );
1331+ }
1332+ }
0 commit comments