mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Latest changes
- [API Change] Sendfile-like functionality is gone. The stream no longer opens files and deals with file descriptors. (Among other things, this makes the code more portable.) Three writing functions are provided: lsquic_stream_write lsquic_stream_writev lsquic_stream_writef (NEW) lsquic_stream_writef() is given an abstract reader that has function pointers for size() and read() functions which the user can implement. This is the most flexible way. lsquic_stream_write() and lsquic_stream_writev() are now both implemented as wrappers around lsquic_stream_writef(). - [OPTIMIZATION] When writing to stream, be it within or without the on_write() callback, place data directly into packet buffer, bypassing auxiliary data structures. This reduces amount of memory required, for the amount of data that can be written is limited by the congestion window. To support writes outside the on_write() callback, we keep N outgoing packet buffers per connection which can be written to by any stream. One half of these are reserved for the highest priority stream(s), the other half for all other streams. This way, low-priority streams cannot write instead of high-priority streams and, on the other hand, low-priority streams get a chance to send their packets out. The algorithm is as follows: - When user writes to stream outside of the callback: - If this is the highest priority stream, place it onto the reserved N/2 queue or fail. (The actual size of this queue is dynamic -- MAX(N/2, CWND) -- rather than N/2, allowing high-priority streams to write as much as can be sent.) - If the stream is not the highest priority, try to place the data onto the reserved N/2 queue or fail. - When tick occurs *and* more packets can be scheduled: - Transfer packets from the high N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for highest-priority streams, placing resulting packets directly onto the scheduled queue. - If more scheduling is allowed: - Transfer packets from the low N/2 queue to the scheduled queue. - If more scheduling is allowed: - Call on_write callbacks for non-highest-priority streams, placing resulting packets directly onto the scheduled queue The number N is currently 20, but it could be varied based on resource usage. - If stream is created due to incoming headers, make headers readable from on_new. - Outgoing packets are no longer marked non-writeable to prevent placing more than one STREAM frame from the same stream into a single packet. This property is maintained via code flow and an explicit check. Packets for stream data are allocated using a special function. - STREAM frame elision is cheaper, as we only perform it if a reset stream has outgoing packets referencing it. - lsquic_packet_out_t is smaller, as stream_rec elements are now inside a union.
This commit is contained in:
parent
0ae3fccd17
commit
c51ce3387f
94 changed files with 4769 additions and 3321 deletions
71
CHANGELOG
71
CHANGELOG
|
@ -1,3 +1,74 @@
|
|||
2017-10-31
|
||||
|
||||
- [API Change] Sendfile-like functionality is gone. The stream no
|
||||
longer opens files and deals with file descriptors. (Among other
|
||||
things, this makes the code more portable.) Three writing functions
|
||||
are provided:
|
||||
|
||||
lsquic_stream_write
|
||||
lsquic_stream_writev
|
||||
lsquic_stream_writef (NEW)
|
||||
|
||||
lsquic_stream_writef() is given an abstract reader that has function
|
||||
pointers for size() and read() functions which the user can implement.
|
||||
This is the most flexible way. lsquic_stream_write() and
|
||||
lsquic_stream_writev() are now both implemented as wrappers around
|
||||
lsquic_stream_writef().
|
||||
|
||||
- [OPTIMIZATION] When writing to stream, be it within or without the
|
||||
on_write() callback, place data directly into packet buffer,
|
||||
bypassing auxiliary data structures. This reduces amount of memory
|
||||
required, for the amount of data that can be written is limited
|
||||
by the congestion window.
|
||||
|
||||
To support writes outside the on_write() callback, we keep N
|
||||
outgoing packet buffers per connection which can be written to
|
||||
by any stream. One half of these are reserved for the highest
|
||||
priority stream(s), the other half for all other streams. This way,
|
||||
low-priority streams cannot write instead of high-priority streams
|
||||
and, on the other hand, low-priority streams get a chance to send
|
||||
their packets out.
|
||||
|
||||
The algorithm is as follows:
|
||||
|
||||
- When user writes to stream outside of the callback:
|
||||
- If this is the highest priority stream, place it onto the
|
||||
reserved N/2 queue or fail.
|
||||
(The actual size of this queue is dynamic -- MAX(N/2, CWND) --
|
||||
rather than N/2, allowing high-priority streams to write as
|
||||
much as can be sent.)
|
||||
- If the stream is not the highest priority, try to place the
|
||||
data onto the reserved N/2 queue or fail.
|
||||
- When tick occurs *and* more packets can be scheduled:
|
||||
- Transfer packets from the high N/2 queue to the scheduled
|
||||
queue.
|
||||
- If more scheduling is allowed:
|
||||
- Call on_write callbacks for highest-priority streams,
|
||||
placing resulting packets directly onto the scheduled queue.
|
||||
- If more scheduling is allowed:
|
||||
- Transfer packets from the low N/2 queue to the scheduled
|
||||
queue.
|
||||
- If more scheduling is allowed:
|
||||
- Call on_write callbacks for non-highest-priority streams,
|
||||
placing resulting packets directly onto the scheduled queue
|
||||
|
||||
The number N is currently 20, but it could be varied based on
|
||||
resource usage.
|
||||
|
||||
- If stream is created due to incoming headers, make headers readable
|
||||
from on_new.
|
||||
|
||||
- Outgoing packets are no longer marked non-writeable to prevent placing
|
||||
more than one STREAM frame from the same stream into a single packet.
|
||||
This property is maintained via code flow and an explicit check.
|
||||
Packets for stream data are allocated using a special function.
|
||||
|
||||
- STREAM frame elision is cheaper, as we only perform it if a reset
|
||||
stream has outgoing packets referencing it.
|
||||
|
||||
- lsquic_packet_out_t is smaller, as stream_rec elements are now
|
||||
inside a union.
|
||||
|
||||
2017-10-12
|
||||
|
||||
- Do not send RST_STREAM when stream is closed for reading
|
||||
|
|
|
@ -81,7 +81,11 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
|||
link_directories( /usr/local/lib )
|
||||
ENDIF()
|
||||
|
||||
add_executable(http_client test/http_client.c test/prog.c test/test_common.c test/test_cert.c)
|
||||
add_executable(http_client
|
||||
test/http_client.c
|
||||
test/prog.c
|
||||
test/test_common.c
|
||||
)
|
||||
|
||||
target_link_libraries(http_client lsquic event pthread libssl.a libcrypto.a ${FIULIB} z m)
|
||||
|
||||
|
|
|
@ -94,7 +94,8 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<tr id="row_4_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__logger__if.html" target="_self">lsquic_logger_if</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_5_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__out__spec.html" target="_self">lsquic_out_spec</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__packout__mem__if.html" target="_self">lsquic_packout_mem_if</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__stream__if.html" target="_self">lsquic_stream_if</a></td><td class="desc">The definition of callback functions call by lsquic_stream to process events </td></tr>
|
||||
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__reader.html" target="_self">lsquic_reader</a></td><td class="desc"></td></tr>
|
||||
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="structlsquic__stream__if.html" target="_self">lsquic_stream_if</a></td><td class="desc">The definition of callback functions call by lsquic_stream to process events </td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
|
|
|
@ -88,10 +88,10 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<div class="qindex"><a class="qindex" href="#letter_L">L</a></div>
|
||||
<table class="classindex">
|
||||
<tr><td rowspan="2" valign="bottom"><a name="letter_l"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">  l  </div></td></tr></table>
|
||||
</td><td valign="top"><a class="el" href="structlsquic__engine__settings.html">lsquic_engine_settings</a>   </td><td valign="top"><a class="el" href="structlsquic__http__headers.html">lsquic_http_headers</a>   </td><td valign="top"><a class="el" href="structlsquic__out__spec.html">lsquic_out_spec</a>   </td><td valign="top"><a class="el" href="structlsquic__stream__if.html">lsquic_stream_if</a>   </td></tr>
|
||||
<tr><td valign="top"><a class="el" href="structlsquic__http__header.html">lsquic_http_header</a>   </td><td valign="top"><a class="el" href="structlsquic__logger__if.html">lsquic_logger_if</a>   </td><td valign="top"><a class="el" href="structlsquic__packout__mem__if.html">lsquic_packout_mem_if</a>   </td><td></td></tr>
|
||||
<tr><td valign="top"><a class="el" href="structlsquic__engine__api.html">lsquic_engine_api</a>   </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
</td><td valign="top"><a class="el" href="structlsquic__engine__settings.html">lsquic_engine_settings</a>   </td><td valign="top"><a class="el" href="structlsquic__logger__if.html">lsquic_logger_if</a>   </td><td valign="top"><a class="el" href="structlsquic__reader.html">lsquic_reader</a>   </td></tr>
|
||||
<tr><td valign="top"><a class="el" href="structlsquic__http__header.html">lsquic_http_header</a>   </td><td valign="top"><a class="el" href="structlsquic__out__spec.html">lsquic_out_spec</a>   </td><td valign="top"><a class="el" href="structlsquic__stream__if.html">lsquic_stream_if</a>   </td></tr>
|
||||
<tr><td valign="top"><a class="el" href="structlsquic__engine__api.html">lsquic_engine_api</a>   </td><td valign="top"><a class="el" href="structlsquic__http__headers.html">lsquic_http_headers</a>   </td><td valign="top"><a class="el" href="structlsquic__packout__mem__if.html">lsquic_packout_mem_if</a>   </td><td></td></tr>
|
||||
<tr><td></td><td></td><td></td><td></td></tr>
|
||||
</table>
|
||||
<div class="qindex"><a class="qindex" href="#letter_L">L</a></div>
|
||||
</div><!-- contents -->
|
||||
|
|
|
@ -151,6 +151,12 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>es_versions
|
||||
: <a class="el" href="structlsquic__engine__settings.html#a9dca1ee29ab43ca9454b6b0a8d5e2799">lsquic_engine_settings</a>
|
||||
</li>
|
||||
<li>lsqr_read
|
||||
: <a class="el" href="structlsquic__reader.html#ae6a68ebf2a1fb77160b0bac599d42790">lsquic_reader</a>
|
||||
</li>
|
||||
<li>lsqr_size
|
||||
: <a class="el" href="structlsquic__reader.html#aaf6c91ecaf35ca6faa39dde9ea401f17">lsquic_reader</a>
|
||||
</li>
|
||||
<li>on_goaway_received
|
||||
: <a class="el" href="structlsquic__stream__if.html#afdab3bce65931517452d2ddd979596d7">lsquic_stream_if</a>
|
||||
</li>
|
||||
|
|
|
@ -151,6 +151,12 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>es_versions
|
||||
: <a class="el" href="structlsquic__engine__settings.html#a9dca1ee29ab43ca9454b6b0a8d5e2799">lsquic_engine_settings</a>
|
||||
</li>
|
||||
<li>lsqr_read
|
||||
: <a class="el" href="structlsquic__reader.html#ae6a68ebf2a1fb77160b0bac599d42790">lsquic_reader</a>
|
||||
</li>
|
||||
<li>lsqr_size
|
||||
: <a class="el" href="structlsquic__reader.html#aaf6c91ecaf35ca6faa39dde9ea401f17">lsquic_reader</a>
|
||||
</li>
|
||||
<li>on_goaway_received
|
||||
: <a class="el" href="structlsquic__stream__if.html#afdab3bce65931517452d2ddd979596d7">lsquic_stream_if</a>
|
||||
</li>
|
||||
|
|
|
@ -278,6 +278,9 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_ctx_t
|
||||
: <a class="el" href="lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3">lsquic_types.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_flush()
|
||||
: <a class="el" href="lsquic_8h.html#abcf25d8301c4a2796ea13e6e306a33a9">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_get_ctx()
|
||||
: <a class="el" href="lsquic_8h.html#a26335cffe38e49a6e87d94967371150d">lsquic.h</a>
|
||||
</li>
|
||||
|
@ -296,9 +299,6 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_refuse_push()
|
||||
: <a class="el" href="lsquic_8h.html#ada61e01ced7a7db11e5c503409c565be">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_sendfile()
|
||||
: <a class="el" href="lsquic_8h.html#a1700c950ace4e560d225b474a5e44d58">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_set_priority()
|
||||
: <a class="el" href="lsquic_8h.html#aa5e0ddfd53a44561248a286caacbd114">lsquic.h</a>
|
||||
</li>
|
||||
|
@ -311,11 +311,8 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_write()
|
||||
: <a class="el" href="lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_write_avail()
|
||||
: <a class="el" href="lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_write_file()
|
||||
: <a class="el" href="lsquic_8h.html#af5b85bb360eb8316fd663d7c5bc149c9">lsquic.h</a>
|
||||
<li>lsquic_stream_writef()
|
||||
: <a class="el" href="lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af">lsquic.h</a>
|
||||
</li>
|
||||
<li>LSQUIC_SUPPORTED_VERSIONS
|
||||
: <a class="el" href="lsquic_8h.html#a0420e68d347462080cf2e583b77d61a0">lsquic.h</a>
|
||||
|
|
|
@ -188,6 +188,9 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_conn()
|
||||
: <a class="el" href="lsquic_8h.html#a177184b3d7178dda5a3e95e539230b2b">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_flush()
|
||||
: <a class="el" href="lsquic_8h.html#abcf25d8301c4a2796ea13e6e306a33a9">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_get_ctx()
|
||||
: <a class="el" href="lsquic_8h.html#a26335cffe38e49a6e87d94967371150d">lsquic.h</a>
|
||||
</li>
|
||||
|
@ -206,9 +209,6 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_refuse_push()
|
||||
: <a class="el" href="lsquic_8h.html#ada61e01ced7a7db11e5c503409c565be">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_sendfile()
|
||||
: <a class="el" href="lsquic_8h.html#a1700c950ace4e560d225b474a5e44d58">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_set_priority()
|
||||
: <a class="el" href="lsquic_8h.html#aa5e0ddfd53a44561248a286caacbd114">lsquic.h</a>
|
||||
</li>
|
||||
|
@ -218,11 +218,8 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<li>lsquic_stream_write()
|
||||
: <a class="el" href="lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_write_avail()
|
||||
: <a class="el" href="lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f">lsquic.h</a>
|
||||
</li>
|
||||
<li>lsquic_stream_write_file()
|
||||
: <a class="el" href="lsquic_8h.html#af5b85bb360eb8316fd663d7c5bc149c9">lsquic.h</a>
|
||||
<li>lsquic_stream_writef()
|
||||
: <a class="el" href="lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af">lsquic.h</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- contents -->
|
||||
|
|
|
@ -123,6 +123,8 @@ Data Structures</h2></td></tr>
|
|||
<tr class="separator:"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__engine__api.html">lsquic_engine_api</a></td></tr>
|
||||
<tr class="separator:"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__reader.html">lsquic_reader</a></td></tr>
|
||||
<tr class="separator:"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__http__header.html">lsquic_http_header</a></td></tr>
|
||||
<tr class="separator:"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__http__headers.html">lsquic_http_headers</a></td></tr>
|
||||
|
@ -302,19 +304,14 @@ ssize_t </td><td class="memItemRight" valign="bottom"><b>lsquic_stream_read
|
|||
<tr class="memitem:a96da64e3694d9b79038ec7ada318bb4f"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a96da64e3694d9b79038ec7ada318bb4f"></a>
|
||||
int </td><td class="memItemRight" valign="bottom"><b>lsquic_stream_wantwrite</b> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, int is_want)</td></tr>
|
||||
<tr class="separator:a96da64e3694d9b79038ec7ada318bb4f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:a97229544d7aaf6c5dcd5e071613f9c8f"><td class="memItemLeft" align="right" valign="top">size_t </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f">lsquic_stream_write_avail</a> (const <a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s)</td></tr>
|
||||
<tr class="separator:a97229544d7aaf6c5dcd5e071613f9c8f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:a1071b7be4f2f28c5fedf957aa6309f9a"><td class="memItemLeft" align="right" valign="top">ssize_t </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a">lsquic_stream_write</a> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, const void *buf, size_t len)</td></tr>
|
||||
<tr class="separator:a1071b7be4f2f28c5fedf957aa6309f9a"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:af5b85bb360eb8316fd663d7c5bc149c9"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#af5b85bb360eb8316fd663d7c5bc149c9">lsquic_stream_write_file</a> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, const char *filename)</td></tr>
|
||||
<tr class="separator:af5b85bb360eb8316fd663d7c5bc149c9"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:a715b914c55b5e534cf75713353eb1589"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a715b914c55b5e534cf75713353eb1589"></a>
|
||||
ssize_t </td><td class="memItemRight" valign="bottom"><b>lsquic_stream_writev</b> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, const struct iovec *vec, int count)</td></tr>
|
||||
<tr class="separator:a715b914c55b5e534cf75713353eb1589"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:a1700c950ace4e560d225b474a5e44d58"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#a1700c950ace4e560d225b474a5e44d58">lsquic_stream_sendfile</a> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, int fdSrc, off_t off, size_t size)</td></tr>
|
||||
<tr class="separator:a1700c950ace4e560d225b474a5e44d58"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:abcf25d8301c4a2796ea13e6e306a33a9"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="abcf25d8301c4a2796ea13e6e306a33a9"></a>
|
||||
int </td><td class="memItemRight" valign="bottom"><b>lsquic_stream_flush</b> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s)</td></tr>
|
||||
<tr class="memitem:a49f11caabdf3638d3a3217ebdd21c3af"><td class="memItemLeft" align="right" valign="top">ssize_t </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af">lsquic_stream_writef</a> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *, struct <a class="el" href="structlsquic__reader.html">lsquic_reader</a> *)</td></tr>
|
||||
<tr class="separator:a49f11caabdf3638d3a3217ebdd21c3af"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:abcf25d8301c4a2796ea13e6e306a33a9"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="lsquic_8h.html#abcf25d8301c4a2796ea13e6e306a33a9">lsquic_stream_flush</a> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s)</td></tr>
|
||||
<tr class="separator:abcf25d8301c4a2796ea13e6e306a33a9"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ae523cf75e48b86f5c4510b429b332acb"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ae523cf75e48b86f5c4510b429b332acb"></a>
|
||||
int </td><td class="memItemRight" valign="bottom"><b>lsquic_stream_send_headers</b> (<a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> *s, const <a class="el" href="lsquic__types_8h.html#a91f399fbcccaf01b47ca209c5c170ba2">lsquic_http_headers_t</a> *h, int eos)</td></tr>
|
||||
|
@ -1399,6 +1396,30 @@ int </td><td class="memItemRight" valign="bottom"><b>lsquic_conn_get_sockad
|
|||
</div><div class="memdoc">
|
||||
<p>Get a pointer to the connection object. Use it with lsquic_conn_* functions. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="abcf25d8301c4a2796ea13e6e306a33a9"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int lsquic_stream_flush </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> * </td>
|
||||
<td class="paramname"><em>s</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Flush any buffered data. This triggers packetizing even a single byte into a separate frame. Flushing a closed stream is an error.</p>
|
||||
<dl class="retval"><dt>Return values</dt><dd>
|
||||
<table class="retval">
|
||||
<tr><td class="paramname">0</td><td>Success </td></tr>
|
||||
<tr><td class="paramname">-1</td><td>Failure </td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="a26335cffe38e49a6e87d94967371150d"></a>
|
||||
|
@ -1540,45 +1561,6 @@ int </td><td class="memItemRight" valign="bottom"><b>lsquic_conn_get_sockad
|
|||
<p>No need to call lsquic_stream_close() after this. on_close will be called.</p>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="lsquic_8h.html#a199b551bc87bb77814ab4ce58abcdff9">lsquic_stream_is_pushed</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="a1700c950ace4e560d225b474a5e44d58"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int lsquic_stream_sendfile </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> * </td>
|
||||
<td class="paramname"><em>s</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">int </td>
|
||||
<td class="paramname"><em>fdSrc</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">off_t </td>
|
||||
<td class="paramname"><em>off</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Returns 0 if `fdSrc' was queued for writing, -1 on error. This function queues at most `size' bytes to be written. If the file shrinks, fewer bytes are written. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="aa5e0ddfd53a44561248a286caacbd114"></a>
|
||||
|
@ -1671,42 +1653,25 @@ int </td><td class="memItemRight" valign="bottom"><b>lsquic_conn_get_sockad
|
|||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Write `len' bytes to the stream. Returns number of bytes written, which may be smaller that `len'. Use <a class="el" href="lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f">lsquic_stream_write_avail()</a> to find out maximum size of `len'. </p>
|
||||
<p>Write `len' bytes to the stream. Returns number of bytes written, which may be smaller that `len'. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="a97229544d7aaf6c5dcd5e071613f9c8f"></a>
|
||||
<a class="anchor" id="a49f11caabdf3638d3a3217ebdd21c3af"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">size_t lsquic_stream_write_avail </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">const <a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> * </td>
|
||||
<td class="paramname"><em>s</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Return maximum number of bytes <a class="el" href="lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a">lsquic_stream_write()</a> will write. This call is useful if you don't want to perform your own buffering. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="af5b85bb360eb8316fd663d7c5bc149c9"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int lsquic_stream_write_file </td>
|
||||
<td class="memname">ssize_t lsquic_stream_writef </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a> * </td>
|
||||
<td class="paramname"><em>s</em>, </td>
|
||||
<td class="paramname">, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">const char * </td>
|
||||
<td class="paramname"><em>filename</em> </td>
|
||||
<td class="paramtype">struct <a class="el" href="structlsquic__reader.html">lsquic_reader</a> * </td>
|
||||
<td class="paramname"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
|
@ -1715,7 +1680,13 @@ int </td><td class="memItemRight" valign="bottom"><b>lsquic_conn_get_sockad
|
|||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Returns 0 if `filename' was queued for writing, -1 on error. This function queues the size of the file as it was when the function was called. The stream will write at most this number of bytes to the peer. If the file grows, appended data is not used. </p>
|
||||
<p>Write to stream using <a class="el" href="structlsquic__reader.html">lsquic_reader</a>. This is the most generic of the write functions – <a class="el" href="lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a">lsquic_stream_write()</a> and lsquic_stream_writev() utilize the same mechanism.</p>
|
||||
<dl class="retval"><dt>Return values</dt><dd>
|
||||
<table class="retval">
|
||||
<tr><td class="paramname">Number</td><td>of bytes written or -1 on error. </td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -91,7 +91,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|||
<a href="lsquic__types_8h.html">Go to the documentation of this file.</a><div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span> <span class="comment">/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */</span></div><div class="line"><a name="l00002"></a><span class="lineno"> 2</span> <span class="preprocessor">#ifndef __LSQUIC_TYPES_H__</span></div><div class="line"><a name="l00003"></a><span class="lineno"> 3</span> <span class="preprocessor">#define __LSQUIC_TYPES_H__</span></div><div class="line"><a name="l00004"></a><span class="lineno"> 4</span> </div><div class="line"><a name="l00010"></a><span class="lineno"> 10</span> <span class="preprocessor">#include <stdint.h></span></div><div class="line"><a name="l00011"></a><span class="lineno"> 11</span> </div><div class="line"><a name="l00015"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#acf675534bad01d31b48d9113feff1bbb"> 15</a></span> <span class="keyword">typedef</span> uint64_t <a class="code" href="lsquic__types_8h.html#acf675534bad01d31b48d9113feff1bbb">lsquic_cid_t</a>;</div><div class="line"><a name="l00016"></a><span class="lineno"> 16</span> </div><div class="line"><a name="l00018"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a41d83b8270d6f12d2812203a7614b55f"> 18</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>lsquic_engine <a class="code" href="lsquic__types_8h.html#a41d83b8270d6f12d2812203a7614b55f">lsquic_engine_t</a>;</div><div class="line"><a name="l00019"></a><span class="lineno"> 19</span> </div><div class="line"><a name="l00021"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a7e5d9c467ebef6810d3c5100e4684036"> 21</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>lsquic_conn <a class="code" href="lsquic__types_8h.html#a7e5d9c467ebef6810d3c5100e4684036">lsquic_conn_t</a>;</div><div class="line"><a name="l00022"></a><span class="lineno"> 22</span> </div><div class="line"><a name="l00024"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a21c289bcbb4643effba8bb75eeffd8cd"> 24</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>lsquic_conn_ctx <a class="code" href="lsquic__types_8h.html#a21c289bcbb4643effba8bb75eeffd8cd">lsquic_conn_ctx_t</a>;</div><div class="line"><a name="l00025"></a><span class="lineno"> 25</span> </div><div class="line"><a name="l00027"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6"> 27</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>lsquic_stream <a class="code" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a>;</div><div class="line"><a name="l00028"></a><span class="lineno"> 28</span> </div><div class="line"><a name="l00030"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3"> 30</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>lsquic_stream_ctx <a class="code" href="lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3">lsquic_stream_ctx_t</a>;</div><div class="line"><a name="l00031"></a><span class="lineno"> 31</span> </div><div class="line"><a name="l00033"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a91f399fbcccaf01b47ca209c5c170ba2"> 33</a></span> <span class="keyword">typedef</span> <span class="keyword">struct </span><a class="code" href="structlsquic__http__headers.html">lsquic_http_headers</a> <a class="code" href="structlsquic__http__headers.html">lsquic_http_headers_t</a>;</div><div class="line"><a name="l00034"></a><span class="lineno"> 34</span> </div><div class="line"><a name="l00035"></a><span class="lineno"> 35</span> <span class="preprocessor">#endif</span></div><div class="ttc" id="lsquic__types_8h_html_acf675534bad01d31b48d9113feff1bbb"><div class="ttname"><a href="lsquic__types_8h.html#acf675534bad01d31b48d9113feff1bbb">lsquic_cid_t</a></div><div class="ttdeci">uint64_t lsquic_cid_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:15</div></div>
|
||||
<div class="ttc" id="lsquic__types_8h_html_a7e5d9c467ebef6810d3c5100e4684036"><div class="ttname"><a href="lsquic__types_8h.html#a7e5d9c467ebef6810d3c5100e4684036">lsquic_conn_t</a></div><div class="ttdeci">struct lsquic_conn lsquic_conn_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:21</div></div>
|
||||
<div class="ttc" id="lsquic__types_8h_html_a41d83b8270d6f12d2812203a7614b55f"><div class="ttname"><a href="lsquic__types_8h.html#a41d83b8270d6f12d2812203a7614b55f">lsquic_engine_t</a></div><div class="ttdeci">struct lsquic_engine lsquic_engine_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:18</div></div>
|
||||
<div class="ttc" id="structlsquic__http__headers_html"><div class="ttname"><a href="structlsquic__http__headers.html">lsquic_http_headers</a></div><div class="ttdef"><b>Definition:</b> lsquic.h:641</div></div>
|
||||
<div class="ttc" id="structlsquic__http__headers_html"><div class="ttname"><a href="structlsquic__http__headers.html">lsquic_http_headers</a></div><div class="ttdef"><b>Definition:</b> lsquic.h:656</div></div>
|
||||
<div class="ttc" id="lsquic__types_8h_html_a21c289bcbb4643effba8bb75eeffd8cd"><div class="ttname"><a href="lsquic__types_8h.html#a21c289bcbb4643effba8bb75eeffd8cd">lsquic_conn_ctx_t</a></div><div class="ttdeci">struct lsquic_conn_ctx lsquic_conn_ctx_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:24</div></div>
|
||||
<div class="ttc" id="lsquic__types_8h_html_a4012fdeb11382d691dfe5f025206b8f3"><div class="ttname"><a href="lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3">lsquic_stream_ctx_t</a></div><div class="ttdeci">struct lsquic_stream_ctx lsquic_stream_ctx_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:30</div></div>
|
||||
<div class="ttc" id="lsquic__types_8h_html_ad286bcdd799bb3733f1d6568e25c57c6"><div class="ttname"><a href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6">lsquic_stream_t</a></div><div class="ttdeci">struct lsquic_stream lsquic_stream_t</div><div class="ttdef"><b>Definition:</b> lsquic_types.h:27</div></div>
|
||||
|
|
|
@ -7,6 +7,8 @@ var searchData=
|
|||
['llts_5fyyyymmdd_5fhhmmssms',['LLTS_YYYYMMDD_HHMMSSMS',['../lsquic_8h.html#ac4584806627d352797a2e0cfae2e6235a8754c3fced294cfb146625c586a55a56',1,'lsquic.h']]],
|
||||
['lseng_5fhttp',['LSENG_HTTP',['../lsquic_8h.html#a8f395ac69797c7be8d9d524d464e7ed2',1,'lsquic.h']]],
|
||||
['lseng_5fserver',['LSENG_SERVER',['../lsquic_8h.html#abaf1fe07c4f99aa36d3d5502bbfc371d',1,'lsquic.h']]],
|
||||
['lsqr_5fread',['lsqr_read',['../structlsquic__reader.html#ae6a68ebf2a1fb77160b0bac599d42790',1,'lsquic_reader']]],
|
||||
['lsqr_5fsize',['lsqr_size',['../structlsquic__reader.html#aaf6c91ecaf35ca6faa39dde9ea401f17',1,'lsquic_reader']]],
|
||||
['lsquic_2eh',['lsquic.h',['../lsquic_8h.html',1,'']]],
|
||||
['lsquic_5fcid_5ft',['lsquic_cid_t',['../lsquic__types_8h.html#acf675534bad01d31b48d9113feff1bbb',1,'lsquic_types.h']]],
|
||||
['lsquic_5fconn_5fabort',['lsquic_conn_abort',['../lsquic_8h.html#a6da1350d78db9a83810a00dcee3e4944',1,'lsquic.h']]],
|
||||
|
@ -64,10 +66,12 @@ var searchData=
|
|||
['lsquic_5fout_5fspec',['lsquic_out_spec',['../structlsquic__out__spec.html',1,'']]],
|
||||
['lsquic_5fpackets_5fout_5ff',['lsquic_packets_out_f',['../lsquic_8h.html#aade9ff8d34cbcb33cd04a41377797fcf',1,'lsquic.h']]],
|
||||
['lsquic_5fpackout_5fmem_5fif',['lsquic_packout_mem_if',['../structlsquic__packout__mem__if.html',1,'']]],
|
||||
['lsquic_5freader',['lsquic_reader',['../structlsquic__reader.html',1,'']]],
|
||||
['lsquic_5fset_5flog_5flevel',['lsquic_set_log_level',['../lsquic_8h.html#a337f6adcc4ec9328e0f293d6128ee376',1,'lsquic.h']]],
|
||||
['lsquic_5fstr2ver',['lsquic_str2ver',['../lsquic_8h.html#a8fef45d333b115d996080bb254077d8d',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fconn',['lsquic_stream_conn',['../lsquic_8h.html#a177184b3d7178dda5a3e95e539230b2b',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fctx_5ft',['lsquic_stream_ctx_t',['../lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3',1,'lsquic_types.h']]],
|
||||
['lsquic_5fstream_5fflush',['lsquic_stream_flush',['../lsquic_8h.html#abcf25d8301c4a2796ea13e6e306a33a9',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fget_5fctx',['lsquic_stream_get_ctx',['../lsquic_8h.html#a26335cffe38e49a6e87d94967371150d',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fid',['lsquic_stream_id',['../lsquic_8h.html#a534523d663336969494d6a3721a63640',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fif',['lsquic_stream_if',['../structlsquic__stream__if.html',1,'']]],
|
||||
|
@ -75,13 +79,11 @@ var searchData=
|
|||
['lsquic_5fstream_5fpriority',['lsquic_stream_priority',['../lsquic_8h.html#aa45f5d45b56f5a0d7f881dbccebc5fd8',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fpush_5finfo',['lsquic_stream_push_info',['../lsquic_8h.html#ae0b8525f7dac119f6122af564d0e17fd',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5frefuse_5fpush',['lsquic_stream_refuse_push',['../lsquic_8h.html#ada61e01ced7a7db11e5c503409c565be',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fsendfile',['lsquic_stream_sendfile',['../lsquic_8h.html#a1700c950ace4e560d225b474a5e44d58',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fset_5fpriority',['lsquic_stream_set_priority',['../lsquic_8h.html#aa5e0ddfd53a44561248a286caacbd114',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fshutdown',['lsquic_stream_shutdown',['../lsquic_8h.html#a7fee61cc609a4b274a4de2b41db6a9e4',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5ft',['lsquic_stream_t',['../lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6',1,'lsquic_types.h']]],
|
||||
['lsquic_5fstream_5fwrite',['lsquic_stream_write',['../lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwrite_5favail',['lsquic_stream_write_avail',['../lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwrite_5ffile',['lsquic_stream_write_file',['../lsquic_8h.html#af5b85bb360eb8316fd663d7c5bc149c9',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwritef',['lsquic_stream_writef',['../lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af',1,'lsquic.h']]],
|
||||
['lsquic_5fsupported_5fversions',['LSQUIC_SUPPORTED_VERSIONS',['../lsquic_8h.html#a0420e68d347462080cf2e583b77d61a0',1,'lsquic.h']]],
|
||||
['lsquic_5ftypes_2eh',['lsquic_types.h',['../lsquic__types_8h.html',1,'']]],
|
||||
['lsquic_5fversion',['lsquic_version',['../lsquic_8h.html#a2633ae9ee8d564f4c499f6eb0913d4db',1,'lsquic.h']]],
|
||||
|
|
|
@ -7,5 +7,6 @@ var searchData=
|
|||
['lsquic_5flogger_5fif',['lsquic_logger_if',['../structlsquic__logger__if.html',1,'']]],
|
||||
['lsquic_5fout_5fspec',['lsquic_out_spec',['../structlsquic__out__spec.html',1,'']]],
|
||||
['lsquic_5fpackout_5fmem_5fif',['lsquic_packout_mem_if',['../structlsquic__packout__mem__if.html',1,'']]],
|
||||
['lsquic_5freader',['lsquic_reader',['../structlsquic__reader.html',1,'']]],
|
||||
['lsquic_5fstream_5fif',['lsquic_stream_if',['../structlsquic__stream__if.html',1,'']]]
|
||||
];
|
||||
|
|
|
@ -30,16 +30,15 @@ var searchData=
|
|||
['lsquic_5fset_5flog_5flevel',['lsquic_set_log_level',['../lsquic_8h.html#a337f6adcc4ec9328e0f293d6128ee376',1,'lsquic.h']]],
|
||||
['lsquic_5fstr2ver',['lsquic_str2ver',['../lsquic_8h.html#a8fef45d333b115d996080bb254077d8d',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fconn',['lsquic_stream_conn',['../lsquic_8h.html#a177184b3d7178dda5a3e95e539230b2b',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fflush',['lsquic_stream_flush',['../lsquic_8h.html#abcf25d8301c4a2796ea13e6e306a33a9',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fget_5fctx',['lsquic_stream_get_ctx',['../lsquic_8h.html#a26335cffe38e49a6e87d94967371150d',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fid',['lsquic_stream_id',['../lsquic_8h.html#a534523d663336969494d6a3721a63640',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fis_5fpushed',['lsquic_stream_is_pushed',['../lsquic_8h.html#a199b551bc87bb77814ab4ce58abcdff9',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fpriority',['lsquic_stream_priority',['../lsquic_8h.html#aa45f5d45b56f5a0d7f881dbccebc5fd8',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fpush_5finfo',['lsquic_stream_push_info',['../lsquic_8h.html#ae0b8525f7dac119f6122af564d0e17fd',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5frefuse_5fpush',['lsquic_stream_refuse_push',['../lsquic_8h.html#ada61e01ced7a7db11e5c503409c565be',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fsendfile',['lsquic_stream_sendfile',['../lsquic_8h.html#a1700c950ace4e560d225b474a5e44d58',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fset_5fpriority',['lsquic_stream_set_priority',['../lsquic_8h.html#aa5e0ddfd53a44561248a286caacbd114',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fshutdown',['lsquic_stream_shutdown',['../lsquic_8h.html#a7fee61cc609a4b274a4de2b41db6a9e4',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwrite',['lsquic_stream_write',['../lsquic_8h.html#a1071b7be4f2f28c5fedf957aa6309f9a',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwrite_5favail',['lsquic_stream_write_avail',['../lsquic_8h.html#a97229544d7aaf6c5dcd5e071613f9c8f',1,'lsquic.h']]],
|
||||
['lsquic_5fstream_5fwrite_5ffile',['lsquic_stream_write_file',['../lsquic_8h.html#af5b85bb360eb8316fd663d7c5bc149c9',1,'lsquic.h']]]
|
||||
['lsquic_5fstream_5fwritef',['lsquic_stream_writef',['../lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af',1,'lsquic.h']]]
|
||||
];
|
||||
|
|
|
@ -4,7 +4,7 @@ var indexSectionsWithContent =
|
|||
1: "l",
|
||||
2: "l",
|
||||
3: "l",
|
||||
4: "eo",
|
||||
4: "elo",
|
||||
5: "l",
|
||||
6: "l",
|
||||
7: "l",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
var searchData=
|
||||
[
|
||||
['on_5fgoaway_5freceived',['on_goaway_received',['../structlsquic__stream__if.html#afdab3bce65931517452d2ddd979596d7',1,'lsquic_stream_if']]],
|
||||
['on_5fnew_5fconn',['on_new_conn',['../structlsquic__stream__if.html#a1eb8c7575d67c7b1c75c472288751adb',1,'lsquic_stream_if']]],
|
||||
['on_5fnew_5fstream',['on_new_stream',['../structlsquic__stream__if.html#aa9c28eae8f3bd33d028578e0aef24402',1,'lsquic_stream_if']]]
|
||||
['lsqr_5fread',['lsqr_read',['../structlsquic__reader.html#ae6a68ebf2a1fb77160b0bac599d42790',1,'lsquic_reader']]],
|
||||
['lsqr_5fsize',['lsqr_size',['../structlsquic__reader.html#aaf6c91ecaf35ca6faa39dde9ea401f17',1,'lsquic_reader']]]
|
||||
];
|
||||
|
|
26
docs/html/search/variables_2.html
Normal file
26
docs/html/search/variables_2.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.11"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="variables_2.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
6
docs/html/search/variables_2.js
Normal file
6
docs/html/search/variables_2.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
var searchData=
|
||||
[
|
||||
['on_5fgoaway_5freceived',['on_goaway_received',['../structlsquic__stream__if.html#afdab3bce65931517452d2ddd979596d7',1,'lsquic_stream_if']]],
|
||||
['on_5fnew_5fconn',['on_new_conn',['../structlsquic__stream__if.html#a1eb8c7575d67c7b1c75c472288751adb',1,'lsquic_stream_if']]],
|
||||
['on_5fnew_5fstream',['on_new_stream',['../structlsquic__stream__if.html#aa9c28eae8f3bd33d028578e0aef24402',1,'lsquic_stream_if']]]
|
||||
];
|
143
docs/html/structlsquic__reader.html
Normal file
143
docs/html/structlsquic__reader.html
Normal file
|
@ -0,0 +1,143 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.11"/>
|
||||
<title>LiteSpeed QUIC Library: lsquic_reader Struct Reference</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() { init_search(); });
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">LiteSpeed QUIC Library
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.11 -->
|
||||
<script type="text/javascript">
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
</script>
|
||||
<div id="navrow1" class="tabs">
|
||||
<ul class="tablist">
|
||||
<li><a href="index.html"><span>Main Page</span></a></li>
|
||||
<li class="current"><a href="annotated.html"><span>Data Structures</span></a></li>
|
||||
<li><a href="files.html"><span>Files</span></a></li>
|
||||
<li>
|
||||
<div id="MSearchBox" class="MSearchBoxInactive">
|
||||
<span class="left">
|
||||
<img id="MSearchSelect" src="search/mag_sel.png"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
alt=""/>
|
||||
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
||||
onfocus="searchBox.OnSearchFieldFocus(true)"
|
||||
onblur="searchBox.OnSearchFieldFocus(false)"
|
||||
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
||||
</span><span class="right">
|
||||
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="navrow2" class="tabs2">
|
||||
<ul class="tablist">
|
||||
<li><a href="annotated.html"><span>Data Structures</span></a></li>
|
||||
<li><a href="classes.html"><span>Data Structure Index</span></a></li>
|
||||
<li><a href="functions.html"><span>Data Fields</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="summary">
|
||||
<a href="#pub-attribs">Data Fields</a> </div>
|
||||
<div class="headertitle">
|
||||
<div class="title">lsquic_reader Struct Reference</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
|
||||
<p><code>#include <<a class="el" href="lsquic_8h_source.html">lsquic.h</a>></code></p>
|
||||
<table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-attribs"></a>
|
||||
Data Fields</h2></td></tr>
|
||||
<tr class="memitem:ae6a68ebf2a1fb77160b0bac599d42790"><td class="memItemLeft" align="right" valign="top">size_t(* </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__reader.html#ae6a68ebf2a1fb77160b0bac599d42790">lsqr_read</a> )(void *lsqr_ctx, void *buf, size_t count)</td></tr>
|
||||
<tr class="separator:ae6a68ebf2a1fb77160b0bac599d42790"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:aaf6c91ecaf35ca6faa39dde9ea401f17"><td class="memItemLeft" align="right" valign="top">size_t(* </td><td class="memItemRight" valign="bottom"><a class="el" href="structlsquic__reader.html#aaf6c91ecaf35ca6faa39dde9ea401f17">lsqr_size</a> )(void *lsqr_ctx)</td></tr>
|
||||
<tr class="separator:aaf6c91ecaf35ca6faa39dde9ea401f17"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:a8720320475c026e839eb86b535b213ff"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a8720320475c026e839eb86b535b213ff"></a>
|
||||
void * </td><td class="memItemRight" valign="bottom"><b>lsqr_ctx</b></td></tr>
|
||||
<tr class="separator:a8720320475c026e839eb86b535b213ff"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table>
|
||||
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
|
||||
<div class="textblock"><p>Used as argument to <a class="el" href="lsquic_8h.html#a49f11caabdf3638d3a3217ebdd21c3af">lsquic_stream_writef()</a> </p>
|
||||
</div><h2 class="groupheader">Field Documentation</h2>
|
||||
<a class="anchor" id="ae6a68ebf2a1fb77160b0bac599d42790"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">size_t(* lsquic_reader::lsqr_read) (void *lsqr_ctx, void *buf, size_t count)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Not a ssize_t because the read function is not supposed to return an error. If an error occurs in the read function (for example, when reading from a file fails), it is supposed to deal with the error itself. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="anchor" id="aaf6c91ecaf35ca6faa39dde9ea401f17"></a>
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">size_t(* lsquic_reader::lsqr_size) (void *lsqr_ctx)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<p>Return number of bytes remaining in the reader. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr/>The documentation for this struct was generated from the following file:<ul>
|
||||
<li>include/<a class="el" href="lsquic_8h_source.html">lsquic.h</a></li>
|
||||
</ul>
|
||||
</div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.11
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
|
@ -590,37 +590,52 @@ ssize_t lsquic_stream_readv(lsquic_stream_t *s, const struct iovec *,
|
|||
|
||||
int lsquic_stream_wantwrite(lsquic_stream_t *s, int is_want);
|
||||
|
||||
/**
|
||||
* Return maximum number of bytes lsquic_stream_write() will write. This
|
||||
* call is useful if you don't want to perform your own buffering.
|
||||
*/
|
||||
size_t lsquic_stream_write_avail (const lsquic_stream_t *s);
|
||||
|
||||
/**
|
||||
* Write `len' bytes to the stream. Returns number of bytes written, which
|
||||
* may be smaller that `len'. Use lsquic_stream_write_avail() to find out
|
||||
* maximum size of `len'.
|
||||
* may be smaller that `len'.
|
||||
*/
|
||||
ssize_t lsquic_stream_write(lsquic_stream_t *s, const void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Returns 0 if `filename' was queued for writing, -1 on error. This
|
||||
* function queues the size of the file as it was when the function was
|
||||
* called. The stream will write at most this number of bytes to the
|
||||
* peer. If the file grows, appended data is not used.
|
||||
*/
|
||||
int lsquic_stream_write_file(lsquic_stream_t *s, const char *filename);
|
||||
|
||||
ssize_t lsquic_stream_writev(lsquic_stream_t *s, const struct iovec *vec, int count);
|
||||
|
||||
/**
|
||||
* Returns 0 if `fdSrc' was queued for writing, -1 on error. This
|
||||
* function queues at most `size' bytes to be written. If the file shrinks,
|
||||
* fewer bytes are written.
|
||||
* Used as argument to @ref lsquic_stream_writef()
|
||||
*/
|
||||
int lsquic_stream_sendfile(lsquic_stream_t *s, int fdSrc, off_t off, size_t size);
|
||||
struct lsquic_reader
|
||||
{
|
||||
/**
|
||||
* Not a ssize_t because the read function is not supposed to return
|
||||
* an error. If an error occurs in the read function (for example, when
|
||||
* reading from a file fails), it is supposed to deal with the error
|
||||
* itself.
|
||||
*/
|
||||
size_t (*lsqr_read) (void *lsqr_ctx, void *buf, size_t count);
|
||||
/**
|
||||
* Return number of bytes remaining in the reader.
|
||||
*/
|
||||
size_t (*lsqr_size) (void *lsqr_ctx);
|
||||
void *lsqr_ctx;
|
||||
};
|
||||
|
||||
int lsquic_stream_flush(lsquic_stream_t *s);
|
||||
/**
|
||||
* Write to stream using @ref lsquic_reader. This is the most generic of
|
||||
* the write functions -- @ref lsquic_stream_write() and
|
||||
* @ref lsquic_stream_writev() utilize the same mechanism.
|
||||
*
|
||||
* @retval Number of bytes written or -1 on error.
|
||||
*/
|
||||
ssize_t
|
||||
lsquic_stream_writef (lsquic_stream_t *, struct lsquic_reader *);
|
||||
|
||||
/**
|
||||
* Flush any buffered data. This triggers packetizing even a single byte
|
||||
* into a separate frame. Flushing a closed stream is an error.
|
||||
*
|
||||
* @retval 0 Success
|
||||
* @retval -1 Failure
|
||||
*/
|
||||
int
|
||||
lsquic_stream_flush (lsquic_stream_t *s);
|
||||
|
||||
/**
|
||||
* @typedef lsquic_http_header_t
|
||||
|
|
|
@ -44,3 +44,10 @@ lsquic_arr_push (struct lsquic_arr *arr, uintptr_t val)
|
|||
++arr->nelem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_arr_mem_used (const struct lsquic_arr *arr)
|
||||
{
|
||||
return sizeof(*arr) + arr->nalloc * sizeof(arr->els[0]);
|
||||
}
|
||||
|
|
|
@ -61,4 +61,7 @@ struct lsquic_arr
|
|||
int
|
||||
lsquic_arr_push (struct lsquic_arr *, uintptr_t);
|
||||
|
||||
size_t
|
||||
lsquic_arr_mem_used (const struct lsquic_arr *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -110,6 +110,7 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
|||
lsquic_packet_in_t *packet_in)
|
||||
{
|
||||
size_t header_len, data_len;
|
||||
enum enc_level enc_level;
|
||||
size_t out_len = 0;
|
||||
unsigned char *copy = lsquic_mm_get_1370(&enpub->enp_mm);
|
||||
if (!copy)
|
||||
|
@ -120,31 +121,31 @@ lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
|||
|
||||
header_len = packet_in->pi_header_sz;
|
||||
data_len = packet_in->pi_data_sz - packet_in->pi_header_sz;
|
||||
if (0 == lconn->cn_esf->esf_decrypt(lconn->cn_enc_session,
|
||||
enc_level = lconn->cn_esf->esf_decrypt(lconn->cn_enc_session,
|
||||
lconn->cn_version, 0,
|
||||
packet_in->pi_packno, packet_in->pi_data,
|
||||
&header_len, data_len,
|
||||
lsquic_packet_in_nonce(packet_in),
|
||||
copy, 1370, &out_len))
|
||||
{
|
||||
assert(header_len + out_len <= 1370);
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
lsquic_mm_put_1370(&enpub->enp_mm, packet_in->pi_data);
|
||||
packet_in->pi_data = copy;
|
||||
packet_in->pi_flags |= PI_OWN_DATA | PI_DECRYPTED;
|
||||
packet_in->pi_header_sz = header_len;
|
||||
packet_in->pi_data_sz = out_len + header_len;
|
||||
EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64,
|
||||
packet_in->pi_packno);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
copy, 1370, &out_len);
|
||||
if ((enum enc_level) -1 == enc_level)
|
||||
{
|
||||
lsquic_mm_put_1370(&enpub->enp_mm, copy);
|
||||
EV_LOG_CONN_EVENT(lconn->cn_cid, "could not decrypt packet %"PRIu64,
|
||||
packet_in->pi_packno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(header_len + out_len <= 1370);
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
lsquic_mm_put_1370(&enpub->enp_mm, packet_in->pi_data);
|
||||
packet_in->pi_data = copy;
|
||||
packet_in->pi_flags |= PI_OWN_DATA | PI_DECRYPTED
|
||||
| (enc_level << PIBIT_ENC_LEV_SHIFT);
|
||||
packet_in->pi_header_sz = header_len;
|
||||
packet_in->pi_data_sz = out_len + header_len;
|
||||
EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64,
|
||||
packet_in->pi_packno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,27 +23,19 @@ struct lsquic_conn_cap {
|
|||
uint64_t cc_max; /* Maximum cumulative number of bytes allowed
|
||||
* to be sent on this connection.
|
||||
*/
|
||||
uint64_t cc_tosend; /* Number of bytes scheduled to be sent
|
||||
* accross all streams.
|
||||
*/
|
||||
uint64_t cc_blocked; /* Last blocked offset used */
|
||||
};
|
||||
|
||||
|
||||
#define lsquic_conn_cap_init(cc, max) do { \
|
||||
(cc)->cc_sent = 0; \
|
||||
(cc)->cc_tosend = 0; \
|
||||
(cc)->cc_max = max; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define lsquic_conn_cap_avail(cap) ( \
|
||||
((cap)->cc_sent + (cap)->cc_tosend <= (cap)->cc_max) \
|
||||
? \
|
||||
((cap)->cc_max - (cap)->cc_sent - (cap)->cc_tosend) \
|
||||
: \
|
||||
0 \
|
||||
)
|
||||
(assert((cap)->cc_max >= (cap)->cc_sent)), \
|
||||
(cap)->cc_max - (cap)->cc_sent)
|
||||
|
||||
|
||||
void
|
||||
|
|
|
@ -13,14 +13,16 @@
|
|||
struct lsquic_conn;
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_mm;
|
||||
struct lsquic_stream;
|
||||
struct lsquic_hash;
|
||||
struct headers_stream;
|
||||
struct lsquic_send_ctl;
|
||||
|
||||
struct lsquic_conn_public {
|
||||
struct lsquic_streams_tailq sending_streams,
|
||||
rw_streams,
|
||||
struct lsquic_streams_tailq sending_streams, /* Send RST_STREAM, BLOCKED, and WUF frames */
|
||||
read_streams,
|
||||
write_streams, /* Send STREAM frames */
|
||||
service_streams;
|
||||
struct lsquic_hash *all_streams;
|
||||
struct lsquic_cfcw cfcw;
|
||||
struct lsquic_conn_cap conn_cap;
|
||||
struct lsquic_rtt_stats rtt_stats;
|
||||
|
|
|
@ -47,6 +47,9 @@ struct data_in_iface
|
|||
*/
|
||||
struct data_in *
|
||||
(*di_switch_impl) (struct data_in *, uint64_t read_offset);
|
||||
|
||||
size_t
|
||||
(*di_mem_used) (struct data_in *);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -71,11 +71,19 @@ error_di_switch_impl (struct data_in *data_in, uint64_t read_offset)
|
|||
}
|
||||
|
||||
|
||||
static size_t
|
||||
error_di_mem_used (struct data_in *data_in)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct data_in_iface di_if_error = {
|
||||
.di_destroy = error_di_destroy,
|
||||
.di_empty = error_di_empty,
|
||||
.di_frame_done = error_di_frame_done,
|
||||
.di_get_frame = error_di_get_frame,
|
||||
.di_insert_frame = error_di_insert_frame,
|
||||
.di_mem_used = error_di_mem_used,
|
||||
.di_switch_impl = error_di_switch_impl,
|
||||
};
|
||||
|
|
|
@ -607,11 +607,32 @@ hash_di_switch_impl (struct data_in *data_in, uint64_t read_offset)
|
|||
}
|
||||
|
||||
|
||||
static size_t
|
||||
hash_di_mem_used (struct data_in *data_in)
|
||||
{
|
||||
struct hash_data_in *const hdi = HDI_PTR(data_in);
|
||||
const struct data_block *block;
|
||||
size_t size;
|
||||
unsigned n;
|
||||
|
||||
size = sizeof(*data_in);
|
||||
|
||||
for (n = 0; n < N_BUCKETS(hdi->hdi_nbits); ++n)
|
||||
TAILQ_FOREACH(block, &hdi->hdi_buckets[n], db_next)
|
||||
size += sizeof(*block);
|
||||
|
||||
size += N_BUCKETS(hdi->hdi_nbits) * sizeof(hdi->hdi_buckets[0]);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static const struct data_in_iface di_if_hash = {
|
||||
.di_destroy = hash_di_destroy,
|
||||
.di_empty = hash_di_empty,
|
||||
.di_frame_done = hash_di_frame_done,
|
||||
.di_get_frame = hash_di_get_frame,
|
||||
.di_insert_frame = hash_di_insert_frame,
|
||||
.di_mem_used = hash_di_mem_used,
|
||||
.di_switch_impl = hash_di_switch_impl,
|
||||
};
|
||||
|
|
|
@ -416,11 +416,30 @@ nocopy_di_switch_impl (struct data_in *data_in, uint64_t read_offset)
|
|||
}
|
||||
|
||||
|
||||
/* This function overestimates amount of memory because some packets are
|
||||
* referenced by more than one stream. In the usual case, however, I
|
||||
* expect the error not to be large.
|
||||
*/
|
||||
static size_t
|
||||
nocopy_di_mem_used (struct data_in *data_in)
|
||||
{
|
||||
struct nocopy_data_in *const ncdi = NCDI_PTR(data_in);
|
||||
const stream_frame_t *frame;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*data_in);
|
||||
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
||||
size += lsquic_packet_in_mem_used(frame->packet_in);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static const struct data_in_iface di_if_nocopy = {
|
||||
.di_destroy = nocopy_di_destroy,
|
||||
.di_empty = nocopy_di_empty,
|
||||
.di_frame_done = nocopy_di_frame_done,
|
||||
.di_get_frame = nocopy_di_get_frame,
|
||||
.di_insert_frame = nocopy_di_insert_frame,
|
||||
.di_mem_used = nocopy_di_mem_used,
|
||||
.di_switch_impl = nocopy_di_switch_impl,
|
||||
};
|
||||
|
|
|
@ -878,10 +878,12 @@ lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
|||
conn = new_full_conn_client(engine, hostname, max_packet_size);
|
||||
if (!conn)
|
||||
return -1;
|
||||
ENGINE_IN(engine);
|
||||
lsquic_conn_record_peer_sa(conn, peer_sa);
|
||||
conn->cn_peer_ctx = conn_ctx;
|
||||
engine->iter_state.one.conn = conn;
|
||||
process_connections(engine, conn_iter_next_one);
|
||||
ENGINE_OUT(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -203,16 +203,17 @@ lsquic_ev_log_http_headers_in (lsquic_cid_t cid, int is_server,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stream_frame (lsquic_cid_t cid,
|
||||
const struct parse_funcs *pf, const unsigned char *buf, size_t bufsz)
|
||||
lsquic_ev_log_action_stream_frame (lsquic_cid_t cid,
|
||||
const struct parse_funcs *pf, const unsigned char *buf, size_t bufsz,
|
||||
const char *what)
|
||||
{
|
||||
struct stream_frame frame;
|
||||
int len;
|
||||
|
||||
len = pf->pf_parse_stream_frame(buf, bufsz, &frame);
|
||||
if (len > 0)
|
||||
LCID("generated STREAM frame: stream %"PRIu32", offset: %"PRIu64
|
||||
", size: %"PRIu16", fin: %d", frame.stream_id,
|
||||
LCID("%s STREAM frame: stream %"PRIu32", offset: %"PRIu64
|
||||
", size: %"PRIu16", fin: %d", what, frame.stream_id,
|
||||
frame.data_frame.df_offset, frame.data_frame.df_size,
|
||||
frame.data_frame.df_fin);
|
||||
else
|
||||
|
|
|
@ -156,12 +156,17 @@ lsquic_ev_log_http_headers_in (lsquic_cid_t, int is_server,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stream_frame (lsquic_cid_t, const struct parse_funcs *pf,
|
||||
const unsigned char *, size_t len);
|
||||
lsquic_ev_log_action_stream_frame (lsquic_cid_t, const struct parse_funcs *pf,
|
||||
const unsigned char *, size_t len, const char *action);
|
||||
|
||||
#define EV_LOG_GENERATED_STREAM_FRAME(args...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_stream_frame(args); \
|
||||
lsquic_ev_log_action_stream_frame(args, "generated"); \
|
||||
} while (0)
|
||||
|
||||
#define EV_LOG_UPDATED_STREAM_FRAME(args...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_action_stream_frame(args, "updated"); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
|
|
|
@ -1326,3 +1326,14 @@ lsquic_frame_reader_read (struct lsquic_frame_reader *fr)
|
|||
else
|
||||
return read_payload(fr);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_frame_reader_mem_used (const struct lsquic_frame_reader *fr)
|
||||
{
|
||||
size_t size;
|
||||
size = sizeof(*fr);
|
||||
if (fr->fr_header_block)
|
||||
size += fr->fr_header_block_sz;
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -117,4 +117,7 @@ lsquic_frame_reader_read (struct lsquic_frame_reader *);
|
|||
void
|
||||
lsquic_frame_reader_destroy (struct lsquic_frame_reader *);
|
||||
|
||||
size_t
|
||||
lsquic_frame_reader_mem_used (const struct lsquic_frame_reader *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,8 +64,6 @@ struct lsquic_frame_writer
|
|||
{
|
||||
struct lsquic_stream *fw_stream;
|
||||
fw_write_f fw_write;
|
||||
fw_wavail_f fw_wavail;
|
||||
fw_flush_f fw_flush;
|
||||
struct lsquic_mm *fw_mm;
|
||||
struct lsquic_henc *fw_henc;
|
||||
struct frame_buf_head fw_frabs;
|
||||
|
@ -89,7 +87,7 @@ struct lsquic_frame_writer
|
|||
struct lsquic_frame_writer *
|
||||
lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
||||
unsigned max_frame_sz, struct lsquic_henc *henc, fw_write_f write,
|
||||
fw_wavail_f wavail, fw_flush_f flush, int is_server)
|
||||
int is_server)
|
||||
{
|
||||
struct lsquic_frame_writer *fw;
|
||||
|
||||
|
@ -120,8 +118,6 @@ lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
|||
fw->fw_henc = henc;
|
||||
fw->fw_stream = stream;
|
||||
fw->fw_write = write;
|
||||
fw->fw_wavail = wavail;
|
||||
fw->fw_flush = flush;
|
||||
fw->fw_max_frame_sz = max_frame_sz;
|
||||
fw->fw_max_header_list_sz = 0;
|
||||
if (is_server)
|
||||
|
@ -206,19 +202,15 @@ lsquic_frame_writer_have_leftovers (const struct lsquic_frame_writer *fw)
|
|||
int
|
||||
lsquic_frame_writer_flush (struct lsquic_frame_writer *fw)
|
||||
{
|
||||
size_t navail = fw->fw_wavail(fw->fw_stream);
|
||||
struct frame_buf *frab;
|
||||
|
||||
while (navail > 0 && (frab = TAILQ_FIRST(&fw->fw_frabs)))
|
||||
while ((frab = TAILQ_FIRST(&fw->fw_frabs)))
|
||||
{
|
||||
size_t ntowrite = frab_left_to_read(frab);
|
||||
if (navail < ntowrite)
|
||||
ntowrite = navail;
|
||||
ssize_t nw = fw->fw_write(fw->fw_stream,
|
||||
frab->frab_buf + frab->frab_off, ntowrite);
|
||||
if (nw > 0)
|
||||
{
|
||||
navail -= nw;
|
||||
frab->frab_off += nw;
|
||||
if (frab->frab_off == frab->frab_size)
|
||||
{
|
||||
|
@ -226,12 +218,12 @@ lsquic_frame_writer_flush (struct lsquic_frame_writer *fw)
|
|||
fw_put_frab(fw, frab);
|
||||
}
|
||||
}
|
||||
else if (nw == 0)
|
||||
break;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void) fw->fw_flush(fw->fw_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -742,3 +734,17 @@ lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw,
|
|||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_frame_writer_mem_used (const struct lsquic_frame_writer *fw)
|
||||
{
|
||||
const struct frame_buf *frab;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*fw);
|
||||
TAILQ_FOREACH(frab, &fw->fw_frabs, frab_next)
|
||||
size += sizeof(*frab);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,13 +18,11 @@ struct lsquic_http_headers;
|
|||
struct lsquic_http2_setting;
|
||||
|
||||
typedef ssize_t (*fw_write_f)(struct lsquic_stream *, const void *, size_t);
|
||||
typedef size_t (*fw_wavail_f)(const struct lsquic_stream *stream);
|
||||
typedef int (*fw_flush_f)(struct lsquic_stream *);
|
||||
|
||||
struct lsquic_frame_writer *
|
||||
lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *,
|
||||
unsigned max_frame_sz, struct lsquic_henc *,
|
||||
fw_write_f, fw_wavail_f, fw_flush_f, int is_server);
|
||||
fw_write_f, int is_server);
|
||||
|
||||
void
|
||||
lsquic_frame_writer_destroy (struct lsquic_frame_writer *);
|
||||
|
@ -60,4 +58,7 @@ void
|
|||
lsquic_frame_writer_max_header_list_size (struct lsquic_frame_writer *,
|
||||
uint32_t max_size);
|
||||
|
||||
size_t
|
||||
lsquic_frame_writer_mem_used (const struct lsquic_frame_writer *);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -165,9 +165,11 @@ static void remove_session_info_entry(struct lsquic_str *key);
|
|||
|
||||
static void free_info (lsquic_session_cache_info_t *);
|
||||
|
||||
static void c_free_cert_hash_item (cert_hash_item_t *item);
|
||||
static void c_free_cert_hash_item(cert_hash_item_t *item);
|
||||
|
||||
/* client */
|
||||
static cert_hash_item_t *make_cert_hash_item(struct lsquic_str *domain, struct lsquic_str **certs, int count);
|
||||
static int c_insert_certs(cert_hash_item_t *item);
|
||||
static void c_free_cert_hash_item (cert_hash_item_t *item);
|
||||
|
||||
static int get_tag_val_u32 (unsigned char *v, int len, uint32_t *val);
|
||||
static int init_hs_hash_tables(int flags);
|
||||
|
@ -1472,7 +1474,7 @@ verify_packet_hash (const lsquic_enc_session_t *enc_session,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
static enum enc_level
|
||||
decrypt_packet (lsquic_enc_session_t *enc_session, uint8_t path_id,
|
||||
uint64_t pack_num, unsigned char *buf, size_t *header_len,
|
||||
size_t data_len, unsigned char *buf_out, size_t max_out_len,
|
||||
|
@ -1484,22 +1486,25 @@ decrypt_packet (lsquic_enc_session_t *enc_session, uint8_t path_id,
|
|||
uint64_t path_id_packet_number;
|
||||
EVP_AEAD_CTX *key = NULL;
|
||||
int try_times = 0;
|
||||
enum enc_level enc_level;
|
||||
|
||||
path_id_packet_number = combine_path_id_pack_num(path_id, pack_num);
|
||||
memcpy(buf_out, buf, *header_len);
|
||||
while(try_times < 2)
|
||||
do
|
||||
{
|
||||
if (enc_session->have_key == 3 && try_times == 0)
|
||||
{
|
||||
key = enc_session->dec_ctx_f;
|
||||
memcpy(nonce, enc_session->dec_key_nonce_f, 4);
|
||||
LSQ_DEBUG("decrypt_packet using 'F' key...");
|
||||
enc_level = ENC_LEV_FORW;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = enc_session->dec_ctx_i;
|
||||
memcpy(nonce, enc_session->dec_key_nonce_i, 4);
|
||||
LSQ_DEBUG("decrypt_packet using 'I' key...");
|
||||
enc_level = ENC_LEV_INIT;
|
||||
}
|
||||
memcpy(nonce + 4, &path_id_packet_number,
|
||||
sizeof(path_id_packet_number));
|
||||
|
@ -1529,21 +1534,10 @@ decrypt_packet (lsquic_enc_session_t *enc_session, uint8_t path_id,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if (ret)
|
||||
// {
|
||||
// *out_len = data_len;
|
||||
// memcpy(buf_out, buf, *header_len);
|
||||
// key = "\x45\xCA\x99\x4A\x40\xBC\xE3\x3B\x32\x16\x59\x51\x98\x36\xD4\x21";
|
||||
// ret = aes_aead_dec(key,
|
||||
// buf, 0,
|
||||
// lsquic_str_cstr(enc_session->sstk), 12,
|
||||
// buf + *header_len, data_len,
|
||||
// buf_out + *header_len, out_len);
|
||||
// }
|
||||
while (try_times < 2);
|
||||
|
||||
LSQ_DEBUG("***decrypt_packet %s.", (ret == 0 ? "succeed" : "failed"));
|
||||
return ret;
|
||||
return ret == 0 ? enc_level : (enum enc_level) -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1557,8 +1551,7 @@ lsquic_enc_session_have_key_gt_one (const lsquic_enc_session_t *enc_session)
|
|||
/* The size of `buf' is *header_len plus data_len. The two parts of the
|
||||
* buffer correspond to the header and the payload of incoming QUIC packet.
|
||||
*/
|
||||
/* 0 for OK, otherwise nonezero */
|
||||
static int
|
||||
static enum enc_level
|
||||
lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
|
@ -1576,9 +1569,11 @@ lsquic_enc_session_decrypt (lsquic_enc_session_t *enc_session,
|
|||
if (lsquic_enc_session_have_key_gt_one(enc_session))
|
||||
return decrypt_packet(enc_session, path_id, pack_num, buf,
|
||||
header_len, data_len, buf_out, max_out_len, out_len);
|
||||
else if (0 == verify_packet_hash(enc_session, version, buf, header_len,
|
||||
data_len, buf_out, max_out_len, out_len))
|
||||
return ENC_LEV_CLEAR;
|
||||
else
|
||||
return verify_packet_hash(enc_session, version, buf, header_len,
|
||||
data_len, buf_out, max_out_len, out_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1765,6 +1760,41 @@ lsquic_get_enc_hist (const lsquic_enc_session_t *enc_session,
|
|||
|
||||
|
||||
|
||||
|
||||
static size_t
|
||||
lsquic_enc_session_mem_used (struct lsquic_enc_session *enc_session)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*enc_session);
|
||||
|
||||
size += lsquic_str_len(&enc_session->chlo);
|
||||
size += lsquic_str_len(&enc_session->sstk);
|
||||
size += lsquic_str_len(&enc_session->ssno);
|
||||
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.ccs);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.sni);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.ccrt);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.stk);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.sno);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.prof);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.csct);
|
||||
size += lsquic_str_len(&enc_session->hs_ctx.crt);
|
||||
|
||||
if (enc_session->info)
|
||||
{
|
||||
size += sizeof(*enc_session->info);
|
||||
size += lsquic_str_len(&enc_session->info->sstk);
|
||||
size += lsquic_str_len(&enc_session->info->scfg);
|
||||
size += lsquic_str_len(&enc_session->info->sni_key);
|
||||
}
|
||||
|
||||
/* TODO: calculate memory taken up by SSL stuff */
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
|
@ -1785,4 +1815,5 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 =
|
|||
.esf_generate_cid = lsquic_generate_cid,
|
||||
.esf_gen_chlo = lsquic_enc_session_gen_chlo,
|
||||
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
|
||||
.esf_mem_used = lsquic_enc_session_mem_used,
|
||||
};
|
||||
|
|
|
@ -25,6 +25,14 @@ enum handshake_error /* TODO: rename this enum */
|
|||
HS_2RTT = 2,
|
||||
};
|
||||
|
||||
enum enc_level
|
||||
{
|
||||
ENC_LEV_UNSET,
|
||||
ENC_LEV_CLEAR,
|
||||
ENC_LEV_INIT,
|
||||
ENC_LEV_FORW,
|
||||
};
|
||||
|
||||
/* client side need to store 0rtt info per STK */
|
||||
typedef struct lsquic_session_cache_info_st
|
||||
{
|
||||
|
@ -85,8 +93,13 @@ struct enc_session_funcs
|
|||
unsigned char *buf_out, size_t max_out_len, size_t *out_len,
|
||||
int is_hello);
|
||||
|
||||
/* Decrypt buffer */
|
||||
int (*esf_decrypt)(lsquic_enc_session_t *enc_session, enum lsquic_version,
|
||||
/** Decrypt buffer
|
||||
*
|
||||
* If decryption is successful, decryption level is returned. Otherwise,
|
||||
* the return value is -1.
|
||||
*/
|
||||
enum enc_level (*esf_decrypt)(lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
|
@ -116,6 +129,9 @@ struct enc_session_funcs
|
|||
int
|
||||
(*esf_handle_chlo_reply) (lsquic_enc_session_t *,
|
||||
const uint8_t *data, int len);
|
||||
|
||||
size_t
|
||||
(*esf_mem_used)(lsquic_enc_session_t *);
|
||||
};
|
||||
|
||||
extern
|
||||
|
|
|
@ -226,3 +226,12 @@ lsquic_hash_count (struct lsquic_hash *hash)
|
|||
{
|
||||
return hash->qh_count;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_hash_mem_used (const struct lsquic_hash *hash)
|
||||
{
|
||||
return sizeof(*hash)
|
||||
+ N_BUCKETS(hash->qh_nbits) * sizeof(hash->qh_buckets[0])
|
||||
+ lsquic_malo_mem_used(hash->qh_malo_els);
|
||||
}
|
||||
|
|
|
@ -40,4 +40,6 @@ lsquic_hash_next (struct lsquic_hash *);
|
|||
unsigned
|
||||
lsquic_hash_count (struct lsquic_hash *);
|
||||
|
||||
size_t
|
||||
lsquic_hash_mem_used (const struct lsquic_hash *);
|
||||
#endif
|
||||
|
|
|
@ -94,8 +94,8 @@ headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
|||
return NULL;
|
||||
}
|
||||
hs->hs_fw = lsquic_frame_writer_new(hs->hs_mm, stream, 0, &hs->hs_henc,
|
||||
lsquic_stream_write, lsquic_stream_write_avail,
|
||||
lsquic_stream_flush, (hs->hs_flags & HS_IS_SERVER));
|
||||
lsquic_stream_write,
|
||||
(hs->hs_flags & HS_IS_SERVER));
|
||||
if (!hs->hs_fw)
|
||||
{
|
||||
LSQ_WARN("could not create frame writer: %s", strerror(errno));
|
||||
|
@ -127,6 +127,7 @@ headers_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
|
|||
int s = lsquic_frame_writer_flush(hs->hs_fw);
|
||||
if (0 == s)
|
||||
{
|
||||
LSQ_DEBUG("flushed");
|
||||
lsquic_stream_wantwrite(stream,
|
||||
lsquic_frame_writer_have_leftovers(hs->hs_fw));
|
||||
}
|
||||
|
@ -379,6 +380,33 @@ lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
|||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_headers_stream_mem_used (const struct headers_stream *hs)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*hs);
|
||||
size += lsquic_frame_reader_mem_used(hs->hs_fr);
|
||||
size += lsquic_frame_writer_mem_used(hs->hs_fw);
|
||||
size -= sizeof(hs->hs_hdec);
|
||||
size += lsquic_hdec_mem_used(&hs->hs_hdec);
|
||||
if (hs->hs_flags & HS_HENC_INITED)
|
||||
{
|
||||
size -= sizeof(hs->hs_henc);
|
||||
size += lsquic_henc_mem_used(&hs->hs_henc);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_headers_stream_get_stream (const struct headers_stream *hs)
|
||||
{
|
||||
return hs->hs_stream;
|
||||
}
|
||||
|
||||
|
||||
static const struct frame_reader_callbacks frame_callbacks = {
|
||||
.frc_on_headers = headers_on_incoming_headers,
|
||||
.frc_on_push_promise = headers_on_push_promise,
|
||||
|
|
|
@ -66,6 +66,12 @@ int
|
|||
lsquic_headers_stream_send_settings (struct headers_stream *hs,
|
||||
const struct lsquic_http2_setting *, unsigned count);
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_headers_stream_get_stream (const struct headers_stream *);
|
||||
|
||||
size_t
|
||||
lsquic_headers_stream_mem_used (const struct headers_stream *);
|
||||
|
||||
extern const struct lsquic_stream_if *const lsquic_headers_stream_if;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -417,3 +417,24 @@ lsquic_hdec_decode (struct lsquic_hdec *dec,
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_hdec_mem_used (const struct lsquic_hdec *dec)
|
||||
{
|
||||
const struct dec_table_entry *entry;
|
||||
size_t size;
|
||||
unsigned i;
|
||||
|
||||
size = sizeof(*dec);
|
||||
for (i = 0; i < lsquic_arr_count(&dec->hpd_dyn_table); ++i)
|
||||
{
|
||||
entry = (void *) lsquic_arr_get(&dec->hpd_dyn_table, i);
|
||||
size += sizeof(*entry) + entry->dte_val_len + entry->dte_name_len;
|
||||
}
|
||||
|
||||
size -= sizeof(dec->hpd_dyn_table);
|
||||
size += lsquic_arr_mem_used(&dec->hpd_dyn_table);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ lsquic_hdec_decode (struct lsquic_hdec *dec,
|
|||
void
|
||||
lsquic_hdec_set_max_capacity (struct lsquic_hdec *, unsigned);
|
||||
|
||||
size_t
|
||||
lsquic_hdec_mem_used (const struct lsquic_hdec *);
|
||||
|
||||
#ifndef NDEBUG
|
||||
int
|
||||
lsquic_hdec_dec_int (const unsigned char **src, const unsigned char *src_end,
|
||||
|
|
|
@ -854,3 +854,20 @@ lsquic_henc_iter_next (struct lsquic_henc *enc,
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_henc_mem_used (const struct lsquic_henc *enc)
|
||||
{
|
||||
const struct enc_table_entry *entry;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*enc);
|
||||
|
||||
STAILQ_FOREACH(entry, &enc->hpe_all_entries, ete_next_all)
|
||||
size += sizeof(*entry) + entry->ete_name_len + entry->ete_val_len;
|
||||
|
||||
size += N_BUCKETS(enc->hpe_nbits) * sizeof(enc->hpe_buckets[0]);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,9 @@ lsquic_henc_encode (struct lsquic_henc *henc, unsigned char *dst,
|
|||
void
|
||||
lsquic_henc_set_max_capacity (struct lsquic_henc *, unsigned);
|
||||
|
||||
size_t
|
||||
lsquic_henc_mem_used (const struct lsquic_henc *);
|
||||
|
||||
#ifndef NDEBUG
|
||||
unsigned
|
||||
lsquic_henc_get_stx_tab_id (const char *name, hpack_strlen_t name_len,
|
||||
|
|
|
@ -287,3 +287,17 @@ find_free_slot (uint64_t slots)
|
|||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_malo_mem_used (const struct malo *malo)
|
||||
{
|
||||
const struct malo_page *page;
|
||||
size_t size;
|
||||
|
||||
size = 0;
|
||||
SLIST_FOREACH(page, &malo->all_pages, next_page)
|
||||
size += sizeof(*page);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -35,4 +35,7 @@ lsquic_malo_first (struct malo *);
|
|||
void *
|
||||
lsquic_malo_next (struct malo *);
|
||||
|
||||
size_t
|
||||
lsquic_malo_mem_used (const struct malo *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -209,7 +209,6 @@ lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
|||
}
|
||||
|
||||
memset(packet_out, 0, sizeof(*packet_out));
|
||||
STAILQ_INIT(&packet_out->po_srec_arrs);
|
||||
packet_out->po_n_alloc = size;
|
||||
packet_out->po_data = (unsigned char *) pob;
|
||||
|
||||
|
@ -291,3 +290,37 @@ lsquic_mm_put_packet_in (struct lsquic_mm *mm,
|
|||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_mm_mem_used (const struct lsquic_mm *mm)
|
||||
{
|
||||
const struct packet_out_buf *pob;
|
||||
const struct payload_buf *pb;
|
||||
const struct four_k_page *fkp;
|
||||
const struct sixteen_k_page *skp;
|
||||
unsigned i;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*mm);
|
||||
size += sizeof(*mm->acki);
|
||||
size += lsquic_malo_mem_used(mm->malo.stream_frame);
|
||||
size += lsquic_malo_mem_used(mm->malo.stream_rec_arr);
|
||||
size += lsquic_malo_mem_used(mm->malo.packet_in);
|
||||
size += lsquic_malo_mem_used(mm->malo.packet_out);
|
||||
|
||||
for (i = 0; i < MM_N_OUT_BUCKETS; ++i)
|
||||
SLIST_FOREACH(pob, &mm->packet_out_bufs[i], next_pob)
|
||||
size += packet_out_sizes[i];
|
||||
|
||||
SLIST_FOREACH(pb, &mm->payload_bufs, next_pb)
|
||||
size += 1370;
|
||||
|
||||
SLIST_FOREACH(fkp, &mm->four_k_pages, next_fkp)
|
||||
size += 0x1000;
|
||||
|
||||
SLIST_FOREACH(skp, &mm->sixteen_k_pages, next_skp)
|
||||
size += 0x4000;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -75,4 +75,7 @@ lsquic_mm_get_16k (struct lsquic_mm *);
|
|||
void
|
||||
lsquic_mm_put_16k (struct lsquic_mm *, void *);
|
||||
|
||||
size_t
|
||||
lsquic_mm_mem_used (const struct lsquic_mm *mm);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,3 +33,17 @@ packet_in_ver_next (struct ver_iter *vi, lsquic_ver_tag_t *ver_tag)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_packet_in_mem_used (const struct lsquic_packet_in *packet_in)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*packet_in);
|
||||
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
size += packet_in->pi_data_sz;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ typedef struct lsquic_packet_in
|
|||
PI_DECRYPTED = (1 << 0),
|
||||
PI_OWN_DATA = (1 << 1), /* We own pi_data */
|
||||
PI_CONN_ID = (1 << 2), /* pi_conn_id is set */
|
||||
#define PIBIT_ENC_LEV_SHIFT 5
|
||||
PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */
|
||||
PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */
|
||||
} pi_flags:8;
|
||||
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
|
||||
* packet data, which is NOT TO BE MODIFIED.
|
||||
|
@ -81,6 +84,9 @@ typedef struct lsquic_packet_in
|
|||
#define lsquic_packet_in_nonce(p) \
|
||||
((p)->pi_nonce ? (p)->pi_data + (p)->pi_nonce : NULL)
|
||||
|
||||
#define lsquic_packet_in_enc_level(p) \
|
||||
(((p)->pi_flags >> PIBIT_ENC_LEV_SHIFT) & 0x3)
|
||||
|
||||
/* The version iterator is used on a version negotiation packet only.
|
||||
* The iterator functions return 1 when next version is returned and
|
||||
* 0 when there are no more versions.
|
||||
|
@ -98,4 +104,7 @@ packet_in_ver_first (const lsquic_packet_in_t *packet_in, struct ver_iter *,
|
|||
int
|
||||
packet_in_ver_next (struct ver_iter *, lsquic_ver_tag_t *ver_tag);
|
||||
|
||||
size_t
|
||||
lsquic_packet_in_mem_used (const struct lsquic_packet_in *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,25 +21,31 @@
|
|||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_logger.h"
|
||||
#include "lsquic_ev_log.h"
|
||||
|
||||
typedef char _stream_rec_arr_is_at_most_64bytes[
|
||||
(sizeof(struct stream_rec_arr) <= 64) - 1];
|
||||
|
||||
|
||||
struct stream_rec *
|
||||
posi_first (struct packet_out_srec_iter *posi,
|
||||
lsquic_packet_out_t *packet_out)
|
||||
static struct stream_rec *
|
||||
srec_one_posi_first (struct packet_out_srec_iter *posi,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
posi->packet_out = packet_out;
|
||||
posi->past_srec = 0;
|
||||
return posi_next(posi);
|
||||
if (packet_out->po_srecs.one.sr_frame_types)
|
||||
return &packet_out->po_srecs.one;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct stream_rec *
|
||||
posi_next (struct packet_out_srec_iter *posi)
|
||||
srec_one_posi_next (struct packet_out_srec_iter *posi)
|
||||
{
|
||||
if (posi->past_srec)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct stream_rec *
|
||||
srec_arr_posi_next (struct packet_out_srec_iter *posi)
|
||||
{
|
||||
while (posi->cur_srec_arr)
|
||||
{
|
||||
|
@ -49,27 +55,61 @@ posi_next (struct packet_out_srec_iter *posi)
|
|||
if (posi->cur_srec_arr->srecs[ posi->srec_idx ].sr_frame_types)
|
||||
return &posi->cur_srec_arr->srecs[ posi->srec_idx++ ];
|
||||
}
|
||||
posi->cur_srec_arr = STAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr);
|
||||
posi->cur_srec_arr = TAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr);
|
||||
posi->srec_idx = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
static struct stream_rec *
|
||||
srec_arr_posi_first (struct packet_out_srec_iter *posi,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
++posi->past_srec;
|
||||
posi->cur_srec_arr = STAILQ_FIRST(&posi->packet_out->po_srec_arrs);
|
||||
posi->packet_out = packet_out;
|
||||
posi->cur_srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr);
|
||||
posi->srec_idx = 0;
|
||||
if (posi->packet_out->po_srec.sr_frame_types)
|
||||
return &posi->packet_out->po_srec;
|
||||
return posi_next(posi);
|
||||
return srec_arr_posi_next(posi);
|
||||
}
|
||||
|
||||
|
||||
static struct stream_rec * (* const posi_firsts[])
|
||||
(struct packet_out_srec_iter *, struct lsquic_packet_out *) =
|
||||
{
|
||||
srec_one_posi_first,
|
||||
srec_arr_posi_first,
|
||||
};
|
||||
|
||||
|
||||
static struct stream_rec * (* const posi_nexts[])
|
||||
(struct packet_out_srec_iter *posi) =
|
||||
{
|
||||
srec_one_posi_next,
|
||||
srec_arr_posi_next,
|
||||
};
|
||||
|
||||
|
||||
struct stream_rec *
|
||||
posi_first (struct packet_out_srec_iter *posi,
|
||||
lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
posi->impl_idx = !!(packet_out->po_flags & PO_SREC_ARR);
|
||||
return posi_firsts[posi->impl_idx](posi, packet_out);
|
||||
}
|
||||
|
||||
|
||||
struct stream_rec *
|
||||
posi_next (struct packet_out_srec_iter *posi)
|
||||
{
|
||||
return posi_nexts[posi->impl_idx](posi);
|
||||
}
|
||||
|
||||
|
||||
/* Assumption: there can only be one STREAM and only one RST_STREAM frame
|
||||
* for a particular stream per packet. The latter is true because a stream
|
||||
* will only send out one of them. The former is true due the way packets
|
||||
* are filled: stream will write out STREAM frame as large as it can.
|
||||
* will only send out one RST_STREAM frame. The former is true because we
|
||||
* make sure only to place one STREAM frame from a particular stream into a
|
||||
* packet.
|
||||
*
|
||||
* Assumption: frames are added to the packet_out in order of their placement
|
||||
* in packet_out->po_data. There is an assertion in this function that guards
|
||||
|
@ -80,11 +120,13 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
|||
struct lsquic_mm *mm,
|
||||
struct lsquic_stream *new_stream,
|
||||
enum QUIC_FRAME_TYPE frame_type,
|
||||
unsigned short off)
|
||||
unsigned short off, unsigned short len)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec_arr *srec_arr;
|
||||
struct stream_rec *srec;
|
||||
int last_taken;
|
||||
unsigned i;
|
||||
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
if (srec->sr_stream == new_stream)
|
||||
|
@ -95,6 +137,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
|||
assert(!(srec->sr_frame_types & (1 << QUIC_FRAME_STREAM)));
|
||||
srec->sr_frame_types |= (1 << QUIC_FRAME_STREAM);
|
||||
srec->sr_off = off;
|
||||
srec->sr_len = len;
|
||||
break;
|
||||
default:
|
||||
assert(QUIC_FRAME_RST_STREAM == frame_type);
|
||||
|
@ -109,26 +152,46 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
|||
|
||||
++new_stream->n_unacked;
|
||||
|
||||
if (!srec_taken(&packet_out->po_srec))
|
||||
if (!(packet_out->po_flags & PO_SREC_ARR))
|
||||
{
|
||||
packet_out->po_srec.sr_frame_types = (1 << frame_type);
|
||||
packet_out->po_srec.sr_stream = new_stream;
|
||||
packet_out->po_srec.sr_off = off;
|
||||
if (!srec_taken(&packet_out->po_srecs.one))
|
||||
{
|
||||
packet_out->po_srecs.one.sr_frame_types = (1 << frame_type);
|
||||
packet_out->po_srecs.one.sr_stream = new_stream;
|
||||
packet_out->po_srecs.one.sr_off = off;
|
||||
packet_out->po_srecs.one.sr_len = len;
|
||||
return 0; /* Insert in first slot */
|
||||
}
|
||||
srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
|
||||
if (!srec_arr)
|
||||
return -1;
|
||||
memset(srec_arr, 0, sizeof(*srec_arr));
|
||||
srec_arr->srecs[0] = packet_out->po_srecs.one;
|
||||
TAILQ_INIT(&packet_out->po_srecs.arr);
|
||||
TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr,
|
||||
next_stream_rec_arr);
|
||||
packet_out->po_flags |= PO_SREC_ARR;
|
||||
i = 1;
|
||||
goto set_elem;
|
||||
}
|
||||
|
||||
STAILQ_FOREACH(srec_arr, &packet_out->po_srec_arrs, next_stream_rec_arr)
|
||||
{
|
||||
unsigned i;
|
||||
/* New records go at the very end: */
|
||||
srec_arr = TAILQ_LAST(&packet_out->po_srecs.arr, stream_rec_arr_tailq);
|
||||
last_taken = -1;
|
||||
for (i = 0; i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]); ++i)
|
||||
if (!srec_taken(&srec_arr->srecs[i]))
|
||||
if (srec_taken(&srec_arr->srecs[i]))
|
||||
last_taken = i;
|
||||
|
||||
i = last_taken + 1;
|
||||
if (i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]))
|
||||
{
|
||||
set_elem:
|
||||
srec_arr->srecs[i].sr_frame_types = (1 << frame_type);
|
||||
srec_arr->srecs[i].sr_stream = new_stream;
|
||||
srec_arr->srecs[i].sr_off = off;
|
||||
srec_arr->srecs[i].sr_len = len;
|
||||
return 0; /* Insert in existing srec */
|
||||
}
|
||||
}
|
||||
|
||||
srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
|
||||
if (!srec_arr)
|
||||
|
@ -138,7 +201,8 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
|||
srec_arr->srecs[0].sr_frame_types = (1 << frame_type);
|
||||
srec_arr->srecs[0].sr_stream = new_stream;
|
||||
srec_arr->srecs[0].sr_off = off;
|
||||
STAILQ_INSERT_TAIL(&packet_out->po_srec_arrs, srec_arr, next_stream_rec_arr);
|
||||
srec_arr->srecs[0].sr_len = len;
|
||||
TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, next_stream_rec_arr);
|
||||
return 0; /* Insert in new srec */
|
||||
}
|
||||
|
||||
|
@ -172,7 +236,7 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
|
|||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
packet_out->po_flags = PO_WRITEABLE | flags;
|
||||
packet_out->po_flags = flags;
|
||||
if (ver_tag)
|
||||
packet_out->po_ver_tag = *ver_tag;
|
||||
if (nonce)
|
||||
|
@ -197,12 +261,16 @@ void
|
|||
lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out,
|
||||
struct lsquic_engine_public *enpub)
|
||||
{
|
||||
struct stream_rec_arr *srec_arr;
|
||||
while ((srec_arr = STAILQ_FIRST(&packet_out->po_srec_arrs)))
|
||||
if (packet_out->po_flags & PO_SREC_ARR)
|
||||
{
|
||||
STAILQ_REMOVE_HEAD(&packet_out->po_srec_arrs, next_stream_rec_arr);
|
||||
struct stream_rec_arr *srec_arr, *next;
|
||||
for (srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr);
|
||||
srec_arr; srec_arr = next)
|
||||
{
|
||||
next = TAILQ_NEXT(srec_arr, next_stream_rec_arr);
|
||||
lsquic_malo_put(srec_arr);
|
||||
}
|
||||
}
|
||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
enpub->enp_pmi->pmi_release(enpub->enp_pmi_ctx,
|
||||
packet_out->po_enc_data);
|
||||
|
@ -217,12 +285,10 @@ lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out,
|
|||
*/
|
||||
void
|
||||
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
||||
const struct parse_funcs *pf,
|
||||
uint32_t stream_id)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *srec;
|
||||
struct stream_frame frame;
|
||||
unsigned short adj = 0;
|
||||
int n_stream_frames = 0, n_elided = 0;
|
||||
int victim;
|
||||
|
@ -251,24 +317,12 @@ lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
|||
{
|
||||
++n_elided;
|
||||
|
||||
const int len =
|
||||
pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
|
||||
packet_out->po_data_sz - srec->sr_off, &frame);
|
||||
if (len < 0)
|
||||
{ /* This is pretty severe: we should be able to parse our own
|
||||
* frames. Should this abort the connection?
|
||||
*/
|
||||
LSQ_ERROR("can't parse our own stream frame");
|
||||
return;
|
||||
}
|
||||
assert(frame.stream_id == srec->sr_stream->id);
|
||||
|
||||
/* Move the data and adjust sizes */
|
||||
adj += len;
|
||||
adj += srec->sr_len;
|
||||
memmove(packet_out->po_data + srec->sr_off,
|
||||
packet_out->po_data + srec->sr_off + len,
|
||||
packet_out->po_data_sz - srec->sr_off - len);
|
||||
packet_out->po_data_sz -= len;
|
||||
packet_out->po_data + srec->sr_off + srec->sr_len,
|
||||
packet_out->po_data_sz - srec->sr_off - srec->sr_len);
|
||||
packet_out->po_data_sz -= srec->sr_len;
|
||||
|
||||
/* See what we can do with the stream */
|
||||
srec->sr_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
||||
|
@ -301,3 +355,419 @@ lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out)
|
|||
if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
srec->sr_off -= delta;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_packet_out_has_frame (struct lsquic_packet_out *packet_out,
|
||||
const struct lsquic_stream *stream,
|
||||
enum QUIC_FRAME_TYPE frame_type)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *srec;
|
||||
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
if (srec->sr_stream == stream &&
|
||||
srec->sr_frame_types & (1 << frame_type))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_packet_out_has_hsk_frames (struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *srec;
|
||||
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
if ((srec->sr_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
&& LSQUIC_STREAM_HANDSHAKE == srec->sr_stream->id)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_packet_out_ack_streams (lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *srec;
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
lsquic_stream_acked(srec->sr_stream);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
||||
unsigned n_srecs)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
for (n = 0; n < n_srecs; ++n)
|
||||
{
|
||||
struct stream_rec *const srec = srecs[n];
|
||||
memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||
packet_out->po_data + srec->sr_off, srec->sr_len);
|
||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||
srec->sr_stream, QUIC_FRAME_STREAM,
|
||||
new_packet_out->po_data_sz, srec->sr_len))
|
||||
return -1;
|
||||
srec->sr_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
||||
assert(srec->sr_stream->n_unacked > 1);
|
||||
--srec->sr_stream->n_unacked;
|
||||
new_packet_out->po_data_sz += srec->sr_len;
|
||||
}
|
||||
|
||||
packet_out->po_data_sz = srecs[0]->sr_off;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||
lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
|
||||
unsigned n_srecs, unsigned max_idx)
|
||||
{
|
||||
unsigned n;
|
||||
struct stream_rec *const max_srec = srecs[max_idx];
|
||||
|
||||
memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||
packet_out->po_data + max_srec->sr_off, max_srec->sr_len);
|
||||
memmove(packet_out->po_data + max_srec->sr_off,
|
||||
packet_out->po_data + max_srec->sr_off + max_srec->sr_len,
|
||||
packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len);
|
||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||
max_srec->sr_stream, QUIC_FRAME_STREAM,
|
||||
new_packet_out->po_data_sz, max_srec->sr_len))
|
||||
return -1;
|
||||
|
||||
max_srec->sr_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
||||
assert(max_srec->sr_stream->n_unacked > 1);
|
||||
--max_srec->sr_stream->n_unacked;
|
||||
new_packet_out->po_data_sz += max_srec->sr_len;
|
||||
packet_out->po_data_sz -= max_srec->sr_len;
|
||||
|
||||
for (n = max_idx + 1; n < n_srecs; ++n)
|
||||
srecs[n]->sr_off -= max_srec->sr_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct split_reader_ctx
|
||||
{
|
||||
unsigned off;
|
||||
unsigned len;
|
||||
signed char fin;
|
||||
unsigned char buf[QUIC_MAX_PAYLOAD_SZ / 2 + 1];
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
split_reader_fin (void *ctx)
|
||||
{
|
||||
struct split_reader_ctx *const reader_ctx = ctx;
|
||||
return reader_ctx->off == reader_ctx->len && reader_ctx->fin;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
split_reader_size (void *ctx)
|
||||
{
|
||||
struct split_reader_ctx *const reader_ctx = ctx;
|
||||
return reader_ctx->len - reader_ctx->off;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
split_reader_read (void *ctx, void *buf, size_t len, int *fin)
|
||||
{
|
||||
struct split_reader_ctx *const reader_ctx = ctx;
|
||||
if (len > reader_ctx->len - reader_ctx->off)
|
||||
len = reader_ctx->len - reader_ctx->off;
|
||||
memcpy(buf, reader_ctx->buf, len);
|
||||
reader_ctx->off += len;
|
||||
*fin = split_reader_fin(reader_ctx);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||
lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf,
|
||||
struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx)
|
||||
{
|
||||
struct stream_rec *const max_srec = srecs[max_idx];
|
||||
struct stream_frame frame;
|
||||
int len;
|
||||
unsigned n;
|
||||
struct split_reader_ctx reader_ctx;
|
||||
|
||||
len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off,
|
||||
max_srec->sr_len, &frame);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_ERROR("could not parse own frame");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(frame.data_frame.df_size / 2 <= sizeof(reader_ctx.buf));
|
||||
if (frame.data_frame.df_size / 2 > sizeof(reader_ctx.buf))
|
||||
return -1;
|
||||
|
||||
memcpy(reader_ctx.buf,
|
||||
frame.data_frame.df_data + frame.data_frame.df_size / 2,
|
||||
frame.data_frame.df_size - frame.data_frame.df_size / 2);
|
||||
reader_ctx.off = 0;
|
||||
reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2;
|
||||
reader_ctx.fin = frame.data_frame.df_fin;
|
||||
|
||||
len = pf->pf_gen_stream_frame(
|
||||
new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(new_packet_out), frame.stream_id,
|
||||
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
||||
split_reader_fin, split_reader_size, split_reader_read,
|
||||
&reader_ctx);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_ERROR("could not generate new frame 1");
|
||||
return -1;
|
||||
}
|
||||
if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
|
||||
max_srec->sr_stream, QUIC_FRAME_STREAM,
|
||||
new_packet_out->po_data_sz, len))
|
||||
return -1;
|
||||
new_packet_out->po_data_sz += len;
|
||||
|
||||
memcpy(reader_ctx.buf, frame.data_frame.df_data,
|
||||
frame.data_frame.df_size / 2);
|
||||
reader_ctx.off = 0;
|
||||
reader_ctx.len = frame.data_frame.df_size / 2;
|
||||
reader_ctx.fin = 0;
|
||||
len = pf->pf_gen_stream_frame(
|
||||
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
||||
frame.stream_id, frame.data_frame.df_offset,
|
||||
split_reader_fin, split_reader_size, split_reader_read,
|
||||
&reader_ctx);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_ERROR("could not generate new frame 2");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned short adj = max_srec->sr_len - (unsigned short) len;
|
||||
max_srec->sr_len = len;
|
||||
for (n = max_idx + 1; n < n_srecs; ++n)
|
||||
srecs[n]->sr_off -= adj;
|
||||
packet_out->po_data_sz -= adj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void
|
||||
verify_srecs (lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
const struct stream_rec *srec;
|
||||
unsigned off;
|
||||
|
||||
srec = posi_first(&posi, packet_out);
|
||||
assert(srec);
|
||||
|
||||
off = 0;
|
||||
for ( ; srec; srec = posi_next(&posi))
|
||||
{
|
||||
assert(srec->sr_off == off);
|
||||
assert(srec->sr_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||
off += srec->sr_len;
|
||||
}
|
||||
|
||||
assert(packet_out->po_data_sz == off);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||
lsquic_packet_out_t *packet_out, lsquic_packet_out_t *new_packet_out,
|
||||
const struct parse_funcs *pf, unsigned excess_bytes)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *local_arr[4];
|
||||
struct stream_rec **new_srecs, **srecs = local_arr;
|
||||
struct stream_rec *srec;
|
||||
unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
|
||||
unsigned n_srecs, max_idx, n, nbytes;
|
||||
#ifndef NDEBUG
|
||||
unsigned short frame_sum = 0;
|
||||
#endif
|
||||
int rv;
|
||||
|
||||
assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM));
|
||||
|
||||
n_srecs = 0;
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
{
|
||||
assert(srec->sr_frame_types == (1 << QUIC_FRAME_STREAM));
|
||||
if (n_srecs >= n_srecs_alloced)
|
||||
{
|
||||
n_srecs_alloced *= 2;
|
||||
if (srecs == local_arr)
|
||||
{
|
||||
srecs = malloc(sizeof(srecs[0]) * n_srecs_alloced);
|
||||
if (!srecs)
|
||||
goto err;
|
||||
memcpy(srecs, local_arr, sizeof(local_arr));
|
||||
}
|
||||
else
|
||||
{
|
||||
new_srecs = realloc(srecs, sizeof(srecs[0]) * n_srecs_alloced);
|
||||
if (!new_srecs)
|
||||
goto err;
|
||||
srecs = new_srecs;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
frame_sum += srec->sr_len;
|
||||
#endif
|
||||
if (n_srecs == 0 || srecs[max_idx]->sr_len < srec->sr_len)
|
||||
max_idx = n_srecs;
|
||||
|
||||
srecs[n_srecs++] = srec;
|
||||
}
|
||||
|
||||
assert(frame_sum == packet_out->po_data_sz);
|
||||
|
||||
if (n_srecs == 1)
|
||||
goto common_case;
|
||||
|
||||
if (n_srecs < 1)
|
||||
goto err;
|
||||
|
||||
/* Case 1: see if we can remove one or more trailing frames to make
|
||||
* packet smaller.
|
||||
*/
|
||||
nbytes = 0;
|
||||
for (n = n_srecs - 1; n > max_idx && nbytes < excess_bytes; --n)
|
||||
nbytes += srecs[n]->sr_len;
|
||||
if (nbytes >= excess_bytes)
|
||||
{
|
||||
rv = split_off_last_frames(mm, packet_out, new_packet_out,
|
||||
srecs + n + 1, n_srecs - n - 1);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Case 2: see if we can move the largest frame to new packet. */
|
||||
nbytes = 0;
|
||||
for (n = 0; n < n_srecs; ++n)
|
||||
if (n != max_idx)
|
||||
nbytes += srecs[n]->sr_len;
|
||||
if (nbytes >= excess_bytes)
|
||||
{
|
||||
rv = move_largest_frame(mm, packet_out, new_packet_out, srecs,
|
||||
n_srecs, max_idx);
|
||||
goto end;
|
||||
}
|
||||
|
||||
common_case:
|
||||
/* Case 3: we have to split the largest frame (which could be the
|
||||
* the only frame) in two.
|
||||
*/
|
||||
rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs,
|
||||
n_srecs, max_idx);
|
||||
|
||||
end:
|
||||
if (srecs != local_arr)
|
||||
free(srecs);
|
||||
#ifndef NDEBUG
|
||||
if (0 == rv)
|
||||
{
|
||||
verify_srecs(packet_out);
|
||||
verify_srecs(new_packet_out);
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
|
||||
err:
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_packet_out_zero_pad (lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
if (packet_out->po_n_alloc > packet_out->po_data_sz)
|
||||
{
|
||||
memset(packet_out->po_data + packet_out->po_data_sz, 0,
|
||||
packet_out->po_n_alloc - packet_out->po_data_sz);
|
||||
packet_out->po_data_sz = packet_out->po_n_alloc;
|
||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_packet_out_mem_used (const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
const struct stream_rec_arr *srec_arr;
|
||||
size_t size;
|
||||
|
||||
size = 0; /* The struct is allocated using malo */
|
||||
if (packet_out->po_enc_data)
|
||||
size += packet_out->po_enc_data_sz;
|
||||
if (packet_out->po_data)
|
||||
size += packet_out->po_n_alloc;
|
||||
if (packet_out->po_nonce)
|
||||
size += 32;
|
||||
|
||||
if (packet_out->po_flags & PO_SREC_ARR)
|
||||
TAILQ_FOREACH(srec_arr, &packet_out->po_srecs.arr, next_stream_rec_arr)
|
||||
size += sizeof(*srec_arr);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out,
|
||||
const struct parse_funcs *pf,
|
||||
const struct lsquic_stream *stream)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
const struct stream_rec *srec;
|
||||
struct stream_frame stream_frame;
|
||||
uint64_t last_offset;
|
||||
int len;
|
||||
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
if ((srec->sr_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
&& srec->sr_stream == stream)
|
||||
{
|
||||
len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
|
||||
srec->sr_len, &stream_frame);
|
||||
assert(len >= 0);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
last_offset = stream_frame.data_frame.df_offset
|
||||
+ stream_frame.data_frame.df_size;
|
||||
if (last_offset == stream->tosend_off)
|
||||
{
|
||||
pf->pf_turn_on_fin(packet_out->po_data + srec->sr_off);
|
||||
EV_LOG_UPDATED_STREAM_FRAME(lsquic_stream_cid(stream),
|
||||
pf, packet_out->po_data + srec->sr_off, srec->sr_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -18,33 +18,43 @@ struct parse_funcs;
|
|||
* zero or more stream_rec structures. stream_rec keeps a pointer to a stream
|
||||
* that has STREAM or RST_STREAM frames inside packet_out. `sr_frame_types'
|
||||
* is a bitmask that records which of these two frames are in the packet.
|
||||
* If this value is zero, `sr_stream' and `sr_off' values are not valid.
|
||||
* `sr_off' indicates where inside packet_out->po_data STREAM frame begins.
|
||||
* If this value is zero, values of the other struct members are not valid.
|
||||
* `sr_off' indicates where inside packet_out->po_data STREAM frame begins
|
||||
* and `sr_len' is its length. These values are not kept for RST_STREAM
|
||||
* frames.
|
||||
*
|
||||
* We need this information for two reasons:
|
||||
* We need this information for three reasons:
|
||||
* 1. A stream is not destroyed until all of its STREAM and RST_STREAM
|
||||
* frames are acknowledged. This is to make sure that we do not exceed
|
||||
* maximum allowed number of streams.
|
||||
* 2. When a packet is resubmitted, STREAM frames for a stream that has
|
||||
* been reset are not to be resubmitted.
|
||||
* 3. A buffered packet may have to be split before it is scheduled (this
|
||||
* occurs if we guessed incorrectly the number of bytes required to
|
||||
* encode the packet number and the actual number would make packet
|
||||
* larger than the max).
|
||||
*
|
||||
*/
|
||||
struct stream_rec {
|
||||
struct lsquic_stream *sr_stream;
|
||||
unsigned short sr_off;
|
||||
unsigned short sr_off,
|
||||
sr_len;
|
||||
short sr_frame_types;
|
||||
};
|
||||
|
||||
#define srec_taken(srec) ((srec)->sr_frame_types)
|
||||
|
||||
struct stream_rec_arr {
|
||||
STAILQ_ENTRY(stream_rec_arr) next_stream_rec_arr;
|
||||
TAILQ_ENTRY(stream_rec_arr) next_stream_rec_arr;
|
||||
struct stream_rec srecs[
|
||||
( 64 /* Efficient size for malo allocator */
|
||||
- sizeof(SLIST_ENTRY(stream_rec)) /* next_stream_rec */
|
||||
- sizeof(TAILQ_ENTRY(stream_rec)) /* next_stream_rec_arr */
|
||||
) / sizeof(struct stream_rec)
|
||||
];
|
||||
};
|
||||
|
||||
TAILQ_HEAD(stream_rec_arr_tailq, stream_rec_arr);
|
||||
|
||||
typedef struct lsquic_packet_out
|
||||
{
|
||||
/* `po_next' is used for packets_out, unacked_packets and expired_packets
|
||||
|
@ -56,13 +66,14 @@ typedef struct lsquic_packet_out
|
|||
lsquic_packno_t po_packno;
|
||||
|
||||
/* A lot of packets contain data belonging to only one stream. Thus,
|
||||
* `srec' is used first. If this is not enough, any number of
|
||||
* `one' is used first. If this is not enough, any number of
|
||||
* stream_rec_arr structures can be allocated to handle more stream
|
||||
* records.
|
||||
*/
|
||||
struct stream_rec po_srec;
|
||||
STAILQ_HEAD(, stream_rec_arr)
|
||||
po_srec_arrs;
|
||||
union {
|
||||
struct stream_rec one;
|
||||
struct stream_rec_arr_tailq arr;
|
||||
} po_srecs;
|
||||
|
||||
/* If PO_ENCRYPTED is set, this points to the buffer that holds encrypted
|
||||
* data.
|
||||
|
@ -82,7 +93,7 @@ typedef struct lsquic_packet_out
|
|||
enum packet_out_flags {
|
||||
PO_HELLO = (1 << 1), /* Packet contains SHLO or CHLO data */
|
||||
PO_ENCRYPTED= (1 << 3), /* po_enc_data has encrypted data */
|
||||
PO_WRITEABLE= (1 << 4), /* Packet is writeable */
|
||||
PO_SREC_ARR = (1 << 4),
|
||||
#define POBIT_SHIFT 5
|
||||
PO_BITS_0 = (1 << 5), /* PO_BITS_0 and PO_BITS_1 encode the */
|
||||
PO_BITS_1 = (1 << 6), /* packet number length. See macros below. */
|
||||
|
@ -127,7 +138,7 @@ struct packet_out_srec_iter {
|
|||
lsquic_packet_out_t *packet_out;
|
||||
struct stream_rec_arr *cur_srec_arr;
|
||||
unsigned srec_idx;
|
||||
int past_srec;
|
||||
int impl_idx;
|
||||
};
|
||||
|
||||
struct stream_rec *
|
||||
|
@ -150,13 +161,36 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
|||
struct lsquic_mm *mm,
|
||||
struct lsquic_stream *new_stream,
|
||||
enum QUIC_FRAME_TYPE,
|
||||
unsigned short off);
|
||||
unsigned short off, unsigned short len);
|
||||
|
||||
void
|
||||
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *,
|
||||
const struct parse_funcs *, uint32_t);
|
||||
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *, uint32_t);
|
||||
|
||||
int
|
||||
lsquic_packet_out_split_in_two (struct lsquic_mm *, lsquic_packet_out_t *,
|
||||
lsquic_packet_out_t *, const struct parse_funcs *, unsigned excess_bytes);
|
||||
|
||||
void
|
||||
lsquic_packet_out_chop_regen (lsquic_packet_out_t *);
|
||||
|
||||
int
|
||||
lsquic_packet_out_has_frame (struct lsquic_packet_out *,
|
||||
const struct lsquic_stream *, enum QUIC_FRAME_TYPE);
|
||||
|
||||
int
|
||||
lsquic_packet_out_has_hsk_frames (struct lsquic_packet_out *);
|
||||
|
||||
void
|
||||
lsquic_packet_out_ack_streams (struct lsquic_packet_out *);
|
||||
|
||||
void
|
||||
lsquic_packet_out_zero_pad (struct lsquic_packet_out *);
|
||||
|
||||
size_t
|
||||
lsquic_packet_out_mem_used (const struct lsquic_packet_out *);
|
||||
|
||||
int
|
||||
lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *,
|
||||
const struct parse_funcs *, const struct lsquic_stream *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -136,3 +136,17 @@ lsquic_packints_next (struct packints *pints)
|
|||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_packints_mem_used (const struct packints *packints)
|
||||
{
|
||||
const struct packet_interval *pi;
|
||||
unsigned count;
|
||||
|
||||
count = 0;
|
||||
TAILQ_FOREACH(pi, &packints->pk_intervals, next_pi)
|
||||
++count;
|
||||
|
||||
return count * sizeof(*pi);
|
||||
}
|
||||
|
|
|
@ -44,4 +44,7 @@ lsquic_packints_sanity_check (const struct packints *);
|
|||
# define lsquic_packints_sanity_check(pints)
|
||||
#endif
|
||||
|
||||
size_t
|
||||
lsquic_packints_mem_used (const struct packints *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,6 +153,8 @@ struct parse_funcs
|
|||
#endif
|
||||
size_t
|
||||
(*pf_calc_stream_frame_header_sz) (uint32_t stream_id, uint64_t offset);
|
||||
void
|
||||
(*pf_turn_on_fin) (unsigned char *);
|
||||
};
|
||||
|
||||
extern const struct parse_funcs lsquic_parse_funcs_gquic_le;
|
||||
|
@ -208,4 +210,7 @@ calc_stream_frame_header_sz_gquic (uint32_t stream_id, uint64_t offset);
|
|||
char *
|
||||
acki2str (const struct ack_info *acki, size_t *sz);
|
||||
|
||||
void
|
||||
lsquic_turn_on_fin_Q035_thru_Q039 (unsigned char *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,6 +79,14 @@ gquic_ietf_parse_stream_frame_header_sz (unsigned char type)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
gquic_ietf_turn_on_fin (unsigned char *stream_header)
|
||||
{
|
||||
/* 11FSSOOD */
|
||||
*stream_header |= 0x20;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gquic_ietf_parse_stream_frame (const unsigned char *buf, size_t rem_packet_sz,
|
||||
stream_frame_t *stream_frame)
|
||||
|
@ -565,4 +573,5 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q041 =
|
|||
.pf_read_float_time16 = gquic_be_read_float_time16,
|
||||
#endif
|
||||
.pf_parse_frame_type = parse_frame_type_gquic_Q041,
|
||||
.pf_turn_on_fin = gquic_ietf_turn_on_fin,
|
||||
};
|
||||
|
|
|
@ -944,4 +944,5 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
|
|||
.pf_read_float_time16 = gquic_be_read_float_time16,
|
||||
#endif
|
||||
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
|
||||
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
|
||||
};
|
||||
|
|
|
@ -674,6 +674,14 @@ parse_stream_frame_header_sz_gquic (unsigned char type)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_turn_on_fin_Q035_thru_Q039 (unsigned char *stream_header)
|
||||
{
|
||||
/* 1fdoooss */
|
||||
*stream_header |= 0x40;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
calc_stream_frame_header_sz_gquic (uint32_t stream_id, uint64_t offset)
|
||||
{
|
||||
|
|
|
@ -875,4 +875,5 @@ const struct parse_funcs lsquic_parse_funcs_gquic_le =
|
|||
.pf_read_float_time16 = gquic_le_read_float_time16,
|
||||
#endif
|
||||
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
|
||||
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
|
||||
};
|
||||
|
|
|
@ -149,3 +149,12 @@ lsquic_rechist_next (lsquic_rechist_t *rechist)
|
|||
{
|
||||
return lsquic_packints_next(&rechist->rh_pints);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_rechist_mem_used (const struct lsquic_rechist *rechist)
|
||||
{
|
||||
return sizeof(*rechist)
|
||||
- sizeof(rechist->rh_pints)
|
||||
+ lsquic_packints_mem_used(&rechist->rh_pints);
|
||||
}
|
||||
|
|
|
@ -66,4 +66,7 @@ lsquic_rechist_cutoff (const lsquic_rechist_t *);
|
|||
lsquic_time_t
|
||||
lsquic_rechist_largest_recv (const lsquic_rechist_t *);
|
||||
|
||||
size_t
|
||||
lsquic_rechist_mem_used (const struct lsquic_rechist *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "lsquic_conn.h"
|
||||
#include "lsquic_conn_flow.h"
|
||||
#include "lsquic_conn_public.h"
|
||||
#include "lsquic_hash.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_SENDCTL
|
||||
#define LSQUIC_LOG_CONN_ID ctl->sc_conn_pub->lconn->cn_cid
|
||||
|
@ -78,6 +79,30 @@ static void
|
|||
send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time);
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
static
|
||||
#elif __GNUC__
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
int
|
||||
lsquic_send_ctl_schedule_stream_packets_immediately (lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
return !(ctl->sc_flags & SC_BUFFER_STREAM);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
static
|
||||
#elif __GNUC__
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_guess_packno_bits (lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
return PACKNO_LEN_2;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_send_ctl_have_unacked_stream_frames (const lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
|
@ -204,6 +229,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
|
|||
struct lsquic_engine_public *enpub, const struct ver_neg *ver_neg,
|
||||
struct lsquic_conn_public *conn_pub, unsigned short pack_size)
|
||||
{
|
||||
unsigned i;
|
||||
memset(ctl, 0, sizeof(*ctl));
|
||||
TAILQ_INIT(&ctl->sc_scheduled_packets);
|
||||
TAILQ_INIT(&ctl->sc_unacked_packets);
|
||||
|
@ -220,6 +246,9 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
|
|||
lsquic_cubic_init(&ctl->sc_cubic, LSQUIC_LOG_CONN_ID);
|
||||
if (ctl->sc_flags & SC_PACE)
|
||||
pacer_init(&ctl->sc_pacer, LSQUIC_LOG_CONN_ID, 100000);
|
||||
for (i = 0; i < sizeof(ctl->sc_buffered_packets) /
|
||||
sizeof(ctl->sc_buffered_packets[0]); ++i)
|
||||
TAILQ_INIT(&ctl->sc_buffered_packets[i].bpq_packets);
|
||||
}
|
||||
|
||||
|
||||
|
@ -423,16 +452,6 @@ take_rtt_sample (lsquic_send_ctl_t *ctl, const lsquic_packet_out_t *packet_out,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
ack_streams (lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
struct packet_out_srec_iter posi;
|
||||
struct stream_rec *srec;
|
||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||
lsquic_stream_acked(srec->sr_stream);
|
||||
}
|
||||
|
||||
|
||||
/* Returns true if packet was rescheduled, false otherwise. In the latter
|
||||
* case, you should not dereference packet_out after the function returns.
|
||||
*/
|
||||
|
@ -459,7 +478,6 @@ send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl,
|
|||
LSQ_DEBUG("lost retransmittable packet %"PRIu64,
|
||||
packet_out->po_packno);
|
||||
TAILQ_INSERT_TAIL(&ctl->sc_lost_packets, packet_out, po_next);
|
||||
packet_out->po_flags &= ~PO_WRITEABLE;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
@ -614,7 +632,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
LSQ_DEBUG("Got ACK for packet %"PRIu64", remove from unacked queue",
|
||||
packet_out->po_packno);
|
||||
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
||||
ack_streams(packet_out);
|
||||
lsquic_packet_out_ack_streams(packet_out);
|
||||
if ((ctl->sc_flags & SC_NSTP) &&
|
||||
(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK)))
|
||||
TAILQ_INSERT_TAIL(&acked_acks, packet_out, po_next);
|
||||
|
@ -710,8 +728,7 @@ send_ctl_next_lost (lsquic_send_ctl_t *ctl)
|
|||
TAILQ_REMOVE(&ctl->sc_lost_packets, lost_packet, po_next);
|
||||
if (lost_packet->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
{
|
||||
lsquic_packet_out_elide_reset_stream_frames(lost_packet,
|
||||
ctl->sc_conn_pub->lconn->cn_pf, 0);
|
||||
lsquic_packet_out_elide_reset_stream_frames(lost_packet, 0);
|
||||
}
|
||||
return lost_packet;
|
||||
}
|
||||
|
@ -913,7 +930,6 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
|
|||
{
|
||||
TAILQ_INSERT_HEAD(&ctl->sc_scheduled_packets, packet_out, po_next);
|
||||
++ctl->sc_n_scheduled;
|
||||
packet_out->po_flags &= ~PO_WRITEABLE;
|
||||
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
|
||||
#if LSQUIC_SEND_STATS
|
||||
++ctl->sc_stats.n_delayed;
|
||||
|
@ -944,18 +960,11 @@ lsquic_send_ctl_have_outgoing_retx_frames (const lsquic_send_ctl_t *ctl)
|
|||
}
|
||||
|
||||
|
||||
lsquic_packet_out_t *
|
||||
lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *ctl, unsigned need_at_least)
|
||||
static lsquic_packet_out_t *
|
||||
send_ctl_allocate_packet (lsquic_send_ctl_t *ctl, enum lsquic_packno_bits bits,
|
||||
unsigned need_at_least)
|
||||
{
|
||||
lsquic_packet_out_t *packet_out;
|
||||
lsquic_packno_t packno, smallest_unacked;
|
||||
enum lsquic_packno_bits bits;
|
||||
unsigned n_in_flight;
|
||||
|
||||
packno = send_ctl_next_packno(ctl);
|
||||
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
|
||||
n_in_flight = lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
||||
bits = calc_packno_bits(packno, smallest_unacked, n_in_flight);
|
||||
|
||||
packet_out = lsquic_packet_out_new(&ctl->sc_enpub->enp_mm,
|
||||
ctl->sc_conn_pub->packet_out_malo,
|
||||
|
@ -975,17 +984,29 @@ lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *ctl, unsigned need_at_least)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
packet_out->po_packno = packno;
|
||||
LSQ_DEBUG("created packet (smallest_unacked: %"PRIu64"; n_in_flight "
|
||||
"estimate: %u; bits: %u) %"PRIu64"", smallest_unacked,
|
||||
n_in_flight, bits, packno);
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
|
||||
lsquic_packet_out_t *
|
||||
lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *ctl, unsigned need_at_least)
|
||||
{
|
||||
lsquic_packet_out_t *packet_out;
|
||||
enum lsquic_packno_bits bits;
|
||||
|
||||
bits = lsquic_send_ctl_packno_bits(ctl);
|
||||
packet_out = send_ctl_allocate_packet(ctl, bits, need_at_least);
|
||||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
packet_out->po_packno = send_ctl_next_packno(ctl);
|
||||
LSQ_DEBUG("created packet %"PRIu64, packet_out->po_packno);
|
||||
EV_LOG_PACKET_CREATED(LSQUIC_LOG_CONN_ID, packet_out);
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
|
||||
/* If `need_at_least' is set to zero, this means get maximum allowed payload
|
||||
* size (in other words, allocate a new packet).
|
||||
/* Do not use for STREAM frames
|
||||
*/
|
||||
lsquic_packet_out_t *
|
||||
lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *ctl,
|
||||
|
@ -994,23 +1015,14 @@ lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *ctl,
|
|||
lsquic_packet_out_t *packet_out;
|
||||
unsigned n_out;
|
||||
|
||||
if (need_at_least != 0)
|
||||
{
|
||||
assert(need_at_least > 0);
|
||||
|
||||
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
||||
if (packet_out &&
|
||||
/* Do not append to resubmitted packets to avoid writing more
|
||||
* than one STREAM or RST_STREAM frame from the same stream to
|
||||
* the packet. This logic can be optimized: we can pass what
|
||||
* we want to write to this packet and use it if it's not STREAM
|
||||
* or RST_STREAM frame. We can go further and query whether the
|
||||
* packet already contains a frame from this stream.
|
||||
*/
|
||||
(packet_out->po_flags & PO_WRITEABLE) &&
|
||||
lsquic_packet_out_avail(packet_out) >= need_at_least)
|
||||
if (packet_out
|
||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least)
|
||||
{
|
||||
return packet_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lsquic_send_ctl_can_send(ctl))
|
||||
{
|
||||
|
@ -1035,6 +1047,41 @@ lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *ctl,
|
|||
}
|
||||
|
||||
|
||||
static lsquic_packet_out_t *
|
||||
send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl,
|
||||
unsigned need_at_least, const lsquic_stream_t *stream)
|
||||
{
|
||||
lsquic_packet_out_t *packet_out;
|
||||
unsigned n_out;
|
||||
|
||||
assert(need_at_least > 0);
|
||||
|
||||
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
||||
if (packet_out
|
||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
||||
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
||||
{
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
if (!lsquic_send_ctl_can_send(ctl))
|
||||
return NULL;
|
||||
|
||||
packet_out = lsquic_send_ctl_new_packet_out(ctl, need_at_least);
|
||||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
if (ctl->sc_flags & SC_PACE)
|
||||
{
|
||||
n_out = ctl->sc_n_in_flight + ctl->sc_n_scheduled;
|
||||
pacer_packet_scheduled(&ctl->sc_pacer, n_out,
|
||||
send_ctl_in_recovery(ctl), send_ctl_transfer_time, ctl);
|
||||
}
|
||||
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
update_for_resending (lsquic_send_ctl_t *ctl, lsquic_packet_out_t *packet_out)
|
||||
{
|
||||
|
@ -1134,19 +1181,19 @@ lsquic_send_ctl_set_tcid0 (lsquic_send_ctl_t *ctl, int tcid0)
|
|||
}
|
||||
|
||||
|
||||
/* This function is called to inform the send controller that stream
|
||||
* `stream_id' has been reset. The controller elides this stream's stream
|
||||
* frames from packets that have already been scheduled. If a packet
|
||||
* becomes empty as a result, it is dropped.
|
||||
/* The controller elides this STREAM frames of stream `stream_id' from
|
||||
* scheduled and buffered packets. If a packet becomes empty as a result,
|
||||
* it is dropped.
|
||||
*
|
||||
* Packets on other queues do not need to be processed: unacked packets
|
||||
* have already been sent, and lost packets' reset stream frames will be
|
||||
* elided in due time.
|
||||
*/
|
||||
void
|
||||
lsquic_send_ctl_reset_stream (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
||||
lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
||||
{
|
||||
struct lsquic_packet_out *packet_out, *next;
|
||||
unsigned n;
|
||||
|
||||
for (packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets); packet_out;
|
||||
packet_out = next)
|
||||
|
@ -1156,8 +1203,7 @@ lsquic_send_ctl_reset_stream (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
|||
if ((packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
)
|
||||
{
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out,
|
||||
ctl->sc_conn_pub->lconn->cn_pf, stream_id);
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, stream_id);
|
||||
if (0 == packet_out->po_frame_types)
|
||||
{
|
||||
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
||||
|
@ -1169,6 +1215,29 @@ lsquic_send_ctl_reset_stream (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < sizeof(ctl->sc_buffered_packets) /
|
||||
sizeof(ctl->sc_buffered_packets[0]); ++n)
|
||||
{
|
||||
for (packet_out = TAILQ_FIRST(&ctl->sc_buffered_packets[n].bpq_packets);
|
||||
packet_out; packet_out = next)
|
||||
{
|
||||
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM)))
|
||||
continue;
|
||||
next = TAILQ_NEXT(packet_out, po_next);
|
||||
if (0 == packet_out->po_frame_types)
|
||||
{
|
||||
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
||||
"stream %"PRIu32, packet_out->po_packno, stream_id);
|
||||
TAILQ_REMOVE(&ctl->sc_buffered_packets[n].bpq_packets,
|
||||
packet_out, po_next);
|
||||
--ctl->sc_buffered_packets[n].bpq_count;
|
||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||
LSQ_DEBUG("Elide packet from buffered queue #%u; count: %u",
|
||||
n, ctl->sc_buffered_packets[n].bpq_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1256,7 +1325,6 @@ lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *ctl)
|
|||
if (packet_out->po_regen_sz < packet_out->po_data_sz
|
||||
&& !droppable_hello_packet(ctl, packet_out))
|
||||
{
|
||||
packet_out->po_flags &= ~PO_WRITEABLE;
|
||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||
{
|
||||
ctl->sc_enpub->enp_pmi->pmi_release(ctl->sc_enpub->enp_pmi_ctx,
|
||||
|
@ -1335,3 +1403,277 @@ lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *ctl)
|
|||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
static
|
||||
#elif __GNUC__
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
enum buf_packet_type
|
||||
lsquic_send_ctl_determine_bpt (lsquic_send_ctl_t *ctl,
|
||||
const lsquic_stream_t *stream)
|
||||
{
|
||||
const lsquic_stream_t *other_stream;
|
||||
struct lsquic_hash_elem *el;
|
||||
struct lsquic_hash *all_streams;
|
||||
|
||||
all_streams = ctl->sc_conn_pub->all_streams;
|
||||
for (el = lsquic_hash_first(all_streams); el;
|
||||
el = lsquic_hash_next(all_streams))
|
||||
{
|
||||
other_stream = lsquic_hashelem_getdata(el);
|
||||
if (other_stream != stream
|
||||
&& (!(other_stream->stream_flags & STREAM_U_WRITE_DONE))
|
||||
&& !lsquic_stream_is_critical(other_stream)
|
||||
&& other_stream->sm_priority < stream->sm_priority)
|
||||
return BPT_OTHER_PRIO;
|
||||
}
|
||||
return BPT_HIGHEST_PRIO;
|
||||
}
|
||||
|
||||
|
||||
static enum buf_packet_type
|
||||
send_ctl_lookup_bpt (lsquic_send_ctl_t *ctl,
|
||||
const struct lsquic_stream *stream)
|
||||
{
|
||||
if (ctl->sc_cached_bpt.stream_id != stream->id)
|
||||
{
|
||||
ctl->sc_cached_bpt.stream_id = stream->id;
|
||||
ctl->sc_cached_bpt.packet_type =
|
||||
lsquic_send_ctl_determine_bpt(ctl, stream);
|
||||
}
|
||||
return ctl->sc_cached_bpt.packet_type;
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
send_ctl_max_bpq_count (const lsquic_send_ctl_t *ctl,
|
||||
enum buf_packet_type packet_type)
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
switch (packet_type)
|
||||
{
|
||||
case BPT_OTHER_PRIO:
|
||||
return MAX_BPQ_COUNT;
|
||||
case BPT_HIGHEST_PRIO:
|
||||
default: /* clang does not complain about absence of `default'... */
|
||||
count = ctl->sc_n_scheduled + ctl->sc_n_in_flight;
|
||||
if (count < lsquic_cubic_get_cwnd(&ctl->sc_cubic))
|
||||
{
|
||||
count -= lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
||||
if (count > MAX_BPQ_COUNT)
|
||||
return count;
|
||||
}
|
||||
return MAX_BPQ_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static lsquic_packet_out_t *
|
||||
send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
|
||||
enum buf_packet_type packet_type, unsigned need_at_least,
|
||||
const struct lsquic_stream *stream)
|
||||
{
|
||||
struct buf_packet_q *const packet_q =
|
||||
&ctl->sc_buffered_packets[packet_type];
|
||||
lsquic_packet_out_t *packet_out;
|
||||
enum lsquic_packno_bits bits;
|
||||
|
||||
packet_out = TAILQ_LAST(&packet_q->bpq_packets, lsquic_packets_tailq);
|
||||
if (packet_out
|
||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
||||
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
||||
{
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
if (packet_q->bpq_count >= send_ctl_max_bpq_count(ctl, packet_type))
|
||||
return NULL;
|
||||
|
||||
bits = lsquic_send_ctl_guess_packno_bits(ctl);
|
||||
packet_out = send_ctl_allocate_packet(ctl, bits, need_at_least);
|
||||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
TAILQ_INSERT_TAIL(&packet_q->bpq_packets, packet_out, po_next);
|
||||
++packet_q->bpq_count;
|
||||
LSQ_DEBUG("Add new packet to buffered queue #%u; count: %u",
|
||||
packet_type, packet_q->bpq_count);
|
||||
return packet_out;
|
||||
}
|
||||
|
||||
|
||||
lsquic_packet_out_t *
|
||||
lsquic_send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl,
|
||||
unsigned need_at_least, const struct lsquic_stream *stream)
|
||||
{
|
||||
enum buf_packet_type packet_type;
|
||||
|
||||
if (lsquic_send_ctl_schedule_stream_packets_immediately(ctl))
|
||||
return send_ctl_get_packet_for_stream(ctl, need_at_least, stream);
|
||||
else
|
||||
{
|
||||
packet_type = send_ctl_lookup_bpt(ctl, stream);
|
||||
return send_ctl_get_buffered_packet(ctl, packet_type, need_at_least,
|
||||
stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
static
|
||||
#elif __GNUC__
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_calc_packno_bits (lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
lsquic_packno_t smallest_unacked;
|
||||
unsigned n_in_flight;
|
||||
|
||||
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
|
||||
n_in_flight = lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
||||
return calc_packno_bits(ctl->sc_cur_packno + 1, smallest_unacked,
|
||||
n_in_flight);
|
||||
}
|
||||
|
||||
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_packno_bits (lsquic_send_ctl_t *ctl)
|
||||
{
|
||||
|
||||
if (lsquic_send_ctl_schedule_stream_packets_immediately(ctl))
|
||||
return lsquic_send_ctl_calc_packno_bits(ctl);
|
||||
else
|
||||
return lsquic_send_ctl_guess_packno_bits(ctl);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
split_buffered_packet (lsquic_send_ctl_t *ctl,
|
||||
enum buf_packet_type packet_type, lsquic_packet_out_t *packet_out,
|
||||
enum lsquic_packno_bits bits, unsigned excess_bytes)
|
||||
{
|
||||
struct buf_packet_q *const packet_q =
|
||||
&ctl->sc_buffered_packets[packet_type];
|
||||
lsquic_packet_out_t *new_packet_out;
|
||||
|
||||
assert(TAILQ_FIRST(&packet_q->bpq_packets) == packet_out);
|
||||
|
||||
new_packet_out = send_ctl_allocate_packet(ctl, bits, 0);
|
||||
if (!packet_out)
|
||||
return -1;
|
||||
|
||||
if (0 == lsquic_packet_out_split_in_two(&ctl->sc_enpub->enp_mm, packet_out,
|
||||
new_packet_out, ctl->sc_conn_pub->lconn->cn_pf, excess_bytes))
|
||||
{
|
||||
TAILQ_INSERT_AFTER(&packet_q->bpq_packets, packet_out, new_packet_out,
|
||||
po_next);
|
||||
++packet_q->bpq_count;
|
||||
LSQ_DEBUG("Add split packet to buffered queue #%u; count: %u",
|
||||
packet_type, packet_q->bpq_count);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *ctl,
|
||||
enum buf_packet_type packet_type)
|
||||
{
|
||||
struct buf_packet_q *const packet_q =
|
||||
&ctl->sc_buffered_packets[packet_type];
|
||||
lsquic_packet_out_t *packet_out;
|
||||
unsigned used, excess;
|
||||
|
||||
assert(lsquic_send_ctl_schedule_stream_packets_immediately(ctl));
|
||||
const enum lsquic_packno_bits bits = lsquic_send_ctl_calc_packno_bits(ctl);
|
||||
const unsigned need = packno_bits2len(bits);
|
||||
|
||||
while ((packet_out = TAILQ_FIRST(&packet_q->bpq_packets)) &&
|
||||
lsquic_send_ctl_can_send(ctl))
|
||||
{
|
||||
if (bits != lsquic_packet_out_packno_bits(packet_out))
|
||||
{
|
||||
used = packno_bits2len(lsquic_packet_out_packno_bits(packet_out));
|
||||
if (need > used
|
||||
&& need - used > lsquic_packet_out_avail(packet_out))
|
||||
{
|
||||
excess = need - used - lsquic_packet_out_avail(packet_out);
|
||||
if (0 != split_buffered_packet(ctl, packet_type,
|
||||
packet_out, bits, excess))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
TAILQ_REMOVE(&packet_q->bpq_packets, packet_out, po_next);
|
||||
--packet_q->bpq_count;
|
||||
LSQ_DEBUG("Remove packet from buffered queue #%u; count: %u",
|
||||
packet_type, packet_q->bpq_count);
|
||||
packet_out->po_packno = send_ctl_next_packno(ctl);
|
||||
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_send_ctl_turn_on_fin (struct lsquic_send_ctl *ctl,
|
||||
const struct lsquic_stream *stream)
|
||||
{
|
||||
enum buf_packet_type packet_type;
|
||||
struct buf_packet_q *packet_q;
|
||||
lsquic_packet_out_t *packet_out;
|
||||
const struct parse_funcs *pf;
|
||||
|
||||
pf = ctl->sc_conn_pub->lconn->cn_pf;
|
||||
packet_type = send_ctl_lookup_bpt(ctl, stream);
|
||||
packet_q = &ctl->sc_buffered_packets[packet_type];
|
||||
|
||||
TAILQ_FOREACH_REVERSE(packet_out, &packet_q->bpq_packets,
|
||||
lsquic_packets_tailq, po_next)
|
||||
if (0 == lsquic_packet_out_turn_on_fin(packet_out, pf, stream))
|
||||
return 0;
|
||||
|
||||
TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next)
|
||||
if (0 == packet_out->po_sent
|
||||
&& 0 == lsquic_packet_out_turn_on_fin(packet_out, pf, stream))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_send_ctl_mem_used (const struct lsquic_send_ctl *ctl)
|
||||
{
|
||||
const lsquic_packet_out_t *packet_out;
|
||||
unsigned n;
|
||||
size_t size;
|
||||
const struct lsquic_packets_tailq queues[] = {
|
||||
ctl->sc_scheduled_packets,
|
||||
ctl->sc_unacked_packets,
|
||||
ctl->sc_lost_packets,
|
||||
ctl->sc_buffered_packets[0].bpq_packets,
|
||||
ctl->sc_buffered_packets[1].bpq_packets,
|
||||
};
|
||||
|
||||
size = sizeof(*ctl);
|
||||
|
||||
for (n = 0; n < sizeof(queues) / sizeof(queues[0]); ++n)
|
||||
TAILQ_FOREACH(packet_out, &queues[n], po_next)
|
||||
size += lsquic_packet_out_mem_used(packet_out);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,10 +19,20 @@ struct lsquic_engine_public;
|
|||
struct lsquic_conn_public;
|
||||
struct ver_neg;
|
||||
|
||||
enum buf_packet_type { BPT_HIGHEST_PRIO, BPT_OTHER_PRIO, };
|
||||
|
||||
#define MAX_BPQ_COUNT 10
|
||||
struct buf_packet_q
|
||||
{
|
||||
struct lsquic_packets_tailq bpq_packets;
|
||||
unsigned bpq_count;
|
||||
};
|
||||
|
||||
typedef struct lsquic_send_ctl {
|
||||
struct lsquic_packets_tailq sc_scheduled_packets,
|
||||
sc_unacked_packets,
|
||||
sc_lost_packets;
|
||||
struct buf_packet_q sc_buffered_packets[BPT_OTHER_PRIO + 1];
|
||||
struct lsquic_engine_public *sc_enpub;
|
||||
struct lsquic_alarmset *sc_alset;
|
||||
const struct ver_neg *sc_ver_neg;
|
||||
|
@ -44,6 +54,11 @@ typedef struct lsquic_send_ctl {
|
|||
*/
|
||||
lsquic_packno_t sc_largest_ack2ed;
|
||||
lsquic_time_t sc_loss_to;
|
||||
struct
|
||||
{
|
||||
uint32_t stream_id;
|
||||
enum buf_packet_type packet_type;
|
||||
} sc_cached_bpt;
|
||||
unsigned sc_n_consec_rtos;
|
||||
unsigned sc_next_limit;
|
||||
unsigned sc_n_in_flight; /* Number of packets in flight */
|
||||
|
@ -56,6 +71,7 @@ typedef struct lsquic_send_ctl {
|
|||
SC_NSTP = (1 << 2),
|
||||
SC_PACE = (1 << 3),
|
||||
SC_SCHED_TICK = (1 << 4),
|
||||
SC_BUFFER_STREAM= (1 << 5),
|
||||
} sc_flags:8;
|
||||
unsigned char sc_n_hsk;
|
||||
unsigned char sc_n_tlp;
|
||||
|
@ -93,12 +109,12 @@ int
|
|||
lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl);
|
||||
|
||||
void
|
||||
lsquic_send_ctl_scheduled_one (lsquic_send_ctl_t *, lsquic_packet_out_t *);
|
||||
lsquic_send_ctl_scheduled_one (lsquic_send_ctl_t *, struct lsquic_packet_out *);
|
||||
|
||||
void
|
||||
lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *, lsquic_packet_out_t *);
|
||||
lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *, struct lsquic_packet_out *);
|
||||
|
||||
lsquic_packet_out_t *
|
||||
struct lsquic_packet_out *
|
||||
lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *);
|
||||
|
||||
void
|
||||
|
@ -126,13 +142,17 @@ lsquic_send_ctl_have_outgoing_retx_frames (const lsquic_send_ctl_t *);
|
|||
#define lsquic_send_ctl_last_scheduled(ctl) \
|
||||
TAILQ_LAST(&(ctl)->sc_scheduled_packets, lsquic_packets_tailq)
|
||||
|
||||
lsquic_packet_out_t *
|
||||
struct lsquic_packet_out *
|
||||
lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *, unsigned);
|
||||
|
||||
lsquic_packet_out_t *
|
||||
struct lsquic_packet_out *
|
||||
lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *,
|
||||
unsigned need_at_least, int *is_err);
|
||||
|
||||
struct lsquic_packet_out *
|
||||
lsquic_send_ctl_get_packet_for_stream (lsquic_send_ctl_t *,
|
||||
unsigned need_at_least, const struct lsquic_stream *);
|
||||
|
||||
unsigned
|
||||
lsquic_send_ctl_reschedule_packets (lsquic_send_ctl_t *);
|
||||
|
||||
|
@ -148,7 +168,7 @@ lsquic_send_ctl_set_tcid0 (lsquic_send_ctl_t *, int);
|
|||
#define lsquic_send_ctl_turn_nstp_on(ctl) ((ctl)->sc_flags |= SC_NSTP)
|
||||
|
||||
void
|
||||
lsquic_send_ctl_reset_stream (lsquic_send_ctl_t *, uint32_t);
|
||||
lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *, uint32_t);
|
||||
|
||||
int
|
||||
lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *);
|
||||
|
@ -180,4 +200,41 @@ lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *);
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_packno_bits (lsquic_send_ctl_t *);
|
||||
|
||||
int
|
||||
lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *, enum buf_packet_type);
|
||||
|
||||
#define lsquic_send_ctl_invalidate_bpt_cache(ctl) do { \
|
||||
(ctl)->sc_cached_bpt.stream_id = 0; \
|
||||
} while (0)
|
||||
|
||||
#ifndef NDEBUG
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_guess_packno_bits (struct lsquic_send_ctl *);
|
||||
|
||||
int
|
||||
lsquic_send_ctl_schedule_stream_packets_immediately (struct lsquic_send_ctl *);
|
||||
|
||||
enum buf_packet_type
|
||||
lsquic_send_ctl_determine_bpt (struct lsquic_send_ctl *,
|
||||
const struct lsquic_stream *);
|
||||
|
||||
enum lsquic_packno_bits
|
||||
lsquic_send_ctl_calc_packno_bits (struct lsquic_send_ctl *);
|
||||
#endif
|
||||
|
||||
size_t
|
||||
lsquic_send_ctl_mem_used (const struct lsquic_send_ctl *);
|
||||
|
||||
#define lsquic_send_ctl_set_buffer_stream_packets(ctl, b) do { \
|
||||
(ctl)->sc_flags &= ~SC_BUFFER_STREAM; \
|
||||
(ctl)->sc_flags |= -!!(b) & SC_BUFFER_STREAM; \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
lsquic_send_ctl_turn_on_fin (struct lsquic_send_ctl *,
|
||||
const struct lsquic_stream *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -148,3 +148,12 @@ lsquic_senhist_tostr (lsquic_senhist_t *hist, char *buf, size_t bufsz)
|
|||
if (bufsz > 0)
|
||||
buf[off] = '\0';
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_senhist_mem_used (const struct lsquic_senhist *hist)
|
||||
{
|
||||
return sizeof(*hist)
|
||||
- sizeof(hist->sh_pints)
|
||||
+ lsquic_packints_mem_used(&hist->sh_pints);
|
||||
}
|
||||
|
|
|
@ -49,4 +49,7 @@ lsquic_senhist_largest (lsquic_senhist_t *hist);
|
|||
void
|
||||
lsquic_senhist_tostr (lsquic_senhist_t *hist, char *buf, size_t bufsz);
|
||||
|
||||
size_t
|
||||
lsquic_senhist_mem_used (const struct lsquic_senhist *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -43,11 +44,9 @@ add_stream_to_spi (struct stream_prio_iter *iter, lsquic_stream_t *stream)
|
|||
|
||||
|
||||
void
|
||||
lsquic_spi_init_ext (struct stream_prio_iter *iter, struct lsquic_stream *first,
|
||||
lsquic_spi_init (struct stream_prio_iter *iter, struct lsquic_stream *first,
|
||||
struct lsquic_stream *last, uintptr_t next_ptr_offset,
|
||||
enum stream_flags onlist_mask,
|
||||
int (*filter)(void *, struct lsquic_stream *),
|
||||
void *filter_ctx, lsquic_cid_t cid, const char *name)
|
||||
enum stream_flags onlist_mask, lsquic_cid_t cid, const char *name)
|
||||
{
|
||||
struct lsquic_stream *stream;
|
||||
unsigned count;
|
||||
|
@ -59,7 +58,6 @@ lsquic_spi_init_ext (struct stream_prio_iter *iter, struct lsquic_stream *first,
|
|||
iter->spi_set[2] = 0;
|
||||
iter->spi_set[3] = 0;
|
||||
iter->spi_onlist_mask = onlist_mask;
|
||||
iter->spi_flags = 0;
|
||||
iter->spi_cur_prio = 0;
|
||||
iter->spi_prev_stream = NULL;
|
||||
iter->spi_next_stream = NULL;
|
||||
|
@ -67,19 +65,6 @@ lsquic_spi_init_ext (struct stream_prio_iter *iter, struct lsquic_stream *first,
|
|||
stream = first;
|
||||
count = 0;
|
||||
|
||||
if (filter)
|
||||
while (1)
|
||||
{
|
||||
if (filter(filter_ctx, stream))
|
||||
{
|
||||
add_stream_to_spi(iter, stream);
|
||||
++count;
|
||||
}
|
||||
if (stream == last)
|
||||
break;
|
||||
stream = NEXT_STREAM(stream, next_ptr_offset);
|
||||
}
|
||||
else
|
||||
while (1)
|
||||
{
|
||||
add_stream_to_spi(iter, stream);
|
||||
|
@ -88,6 +73,7 @@ lsquic_spi_init_ext (struct stream_prio_iter *iter, struct lsquic_stream *first,
|
|||
break;
|
||||
stream = NEXT_STREAM(stream, next_ptr_offset);
|
||||
}
|
||||
|
||||
if (count > 2)
|
||||
SPI_DEBUG("initialized; # elems: %u; sets: [ %016"PRIX64", %016"PRIX64
|
||||
", %016"PRIX64", %016"PRIX64" ]", count, iter->spi_set[0],
|
||||
|
@ -264,26 +250,6 @@ lsquic_spi_next (struct stream_prio_iter *iter)
|
|||
return stream;
|
||||
}
|
||||
|
||||
if (iter->spi_flags & SPI_EXHAUST_PRIO)
|
||||
{
|
||||
stream = TAILQ_FIRST(&iter->spi_streams[ iter->spi_cur_prio ]);
|
||||
if (stream)
|
||||
{
|
||||
iter->spi_prev_stream = stream;
|
||||
iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream);
|
||||
if (stream->id != 1 && stream->id != 3)
|
||||
SPI_DEBUG("%s: return stream %u, priority %u", __func__,
|
||||
stream->id, iter->spi_cur_prio);
|
||||
return stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI_DEBUG("%s: priority %u empty, call first again", __func__,
|
||||
iter->spi_cur_prio);
|
||||
return lsquic_spi_first(iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != find_and_set_next_priority(iter))
|
||||
{
|
||||
//SPI_DEBUG("%s: return NULL", __func__);
|
||||
|
@ -295,17 +261,64 @@ lsquic_spi_next (struct stream_prio_iter *iter)
|
|||
iter->spi_prev_stream = stream;
|
||||
iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream);
|
||||
|
||||
if (stream->id != 1 && stream->id != 3)
|
||||
if (!lsquic_stream_is_critical(stream))
|
||||
SPI_DEBUG("%s: return stream %u, priority %u", __func__, stream->id,
|
||||
iter->spi_cur_prio);
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_spi_exhaust_on (struct stream_prio_iter *iter)
|
||||
static int
|
||||
have_non_critical_streams (const struct stream_prio_iter *iter)
|
||||
{
|
||||
SPI_DEBUG("%s: exhaust %d -> 1", __func__,
|
||||
!!(iter->spi_flags & SPI_EXHAUST_PRIO));
|
||||
iter->spi_flags |= SPI_EXHAUST_PRIO;
|
||||
const struct lsquic_stream *stream;
|
||||
TAILQ_FOREACH(stream, &iter->spi_streams[ iter->spi_cur_prio ],
|
||||
next_prio_stream)
|
||||
if (!lsquic_stream_is_critical(stream))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
spi_drop_high_or_non_high (struct stream_prio_iter *iter, int drop_high)
|
||||
{
|
||||
uint64_t new_set[ sizeof(iter->spi_set) / sizeof(iter->spi_set[0]) ];
|
||||
unsigned bit, set, n;
|
||||
|
||||
memset(new_set, 0, sizeof(new_set));
|
||||
|
||||
find_and_set_lowest_priority(iter);
|
||||
set = iter->spi_cur_prio >> 6;
|
||||
bit = iter->spi_cur_prio & 0x3F;
|
||||
new_set[set] |= 1ULL << bit;
|
||||
|
||||
if (!have_non_critical_streams(iter))
|
||||
{
|
||||
++iter->spi_cur_prio;
|
||||
find_and_set_lowest_priority(iter);
|
||||
set = iter->spi_cur_prio >> 6;
|
||||
bit = iter->spi_cur_prio & 0x3F;
|
||||
new_set[set] |= 1ULL << bit;
|
||||
}
|
||||
|
||||
for (n = 0; n < sizeof(new_set) / sizeof(new_set[0]); ++n)
|
||||
if (drop_high)
|
||||
iter->spi_set[n] &= ~new_set[n];
|
||||
else
|
||||
iter->spi_set[n] = new_set[n];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_spi_drop_high (struct stream_prio_iter *iter)
|
||||
{
|
||||
spi_drop_high_or_non_high(iter, 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_spi_drop_non_high (struct stream_prio_iter *iter)
|
||||
{
|
||||
spi_drop_high_or_non_high(iter, 0);
|
||||
}
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
enum spi_flags {
|
||||
SPI_EXHAUST_PRIO = (1 << 0), /* Exhaust priority level before moving on */
|
||||
};
|
||||
|
||||
|
||||
struct stream_prio_iter
|
||||
{
|
||||
|
@ -25,7 +21,6 @@ struct stream_prio_iter
|
|||
const char *spi_name; /* Used for logging */
|
||||
uint64_t spi_set[4]; /* 256 bits */
|
||||
enum stream_flags spi_onlist_mask;
|
||||
enum spi_flags spi_flags:8;
|
||||
unsigned char spi_cur_prio;
|
||||
unsigned char spi_prev_prio;
|
||||
struct lsquic_stream *spi_prev_stream,
|
||||
|
@ -35,16 +30,9 @@ struct stream_prio_iter
|
|||
|
||||
|
||||
void
|
||||
lsquic_spi_init_ext (struct stream_prio_iter *, struct lsquic_stream *first,
|
||||
lsquic_spi_init (struct stream_prio_iter *, struct lsquic_stream *first,
|
||||
struct lsquic_stream *last, uintptr_t next_ptr_offset,
|
||||
unsigned onlist_mask, int (*filter)(void *, struct lsquic_stream *),
|
||||
void *filter_ctx, lsquic_cid_t cid, const char *name);
|
||||
|
||||
#define lsquic_spi_init(spi, first, last, off, mask, cid, name) \
|
||||
lsquic_spi_init_ext(spi, first, last, off, mask, NULL, NULL, cid, name)
|
||||
|
||||
#define lsquic_spi_init_simple(spi, first, last, off, mask) \
|
||||
lsquic_spi_init(spi, first, last, off, mask, 0, NULL)
|
||||
unsigned onlist_mask, lsquic_cid_t cid, const char *name);
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_spi_first (struct stream_prio_iter *);
|
||||
|
@ -55,4 +43,10 @@ lsquic_spi_next (struct stream_prio_iter *);
|
|||
void
|
||||
lsquic_spi_exhaust_on (struct stream_prio_iter *);
|
||||
|
||||
void
|
||||
lsquic_spi_drop_non_high (struct stream_prio_iter *);
|
||||
|
||||
void
|
||||
lsquic_spi_drop_high (struct stream_prio_iter *);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,6 @@
|
|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef __LSQUIC_STREAM_H__
|
||||
#define __LSQUIC_STREAM_H__
|
||||
|
||||
#include <lsquic_types.h>
|
||||
#ifndef LSQUIC_STREAM_H
|
||||
#define LSQUIC_STREAM_H
|
||||
|
||||
#define LSQUIC_STREAM_HANDSHAKE 1
|
||||
#define LSQUIC_STREAM_HEADERS 3
|
||||
|
@ -17,7 +15,6 @@ struct stream_frame;
|
|||
struct uncompressed_headers;
|
||||
|
||||
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
|
||||
TAILQ_HEAD(sbts_tailq, stream_buf_tosend);
|
||||
|
||||
|
||||
#ifndef LSQUIC_KEEP_STREAM_HISTORY
|
||||
|
@ -45,14 +42,14 @@ struct lsquic_stream
|
|||
STREAM_FIN_RECVD = (1 << 2), /* Received STREAM frame with FIN bit set */
|
||||
STREAM_RST_RECVD = (1 << 3), /* Received RST frame */
|
||||
STREAM_SEND_WUF = (1 << 4), /* WUF: Window Update Frame */
|
||||
STREAM_SEND_DATA = (1 << 5),
|
||||
STREAM_LAST_WRITE_OK= (1 << 5), /* Used to break out of write event dispatch loop */
|
||||
STREAM_SEND_BLOCKED = (1 << 6),
|
||||
STREAM_SEND_RST = (1 << 7), /* Error: want to send RST_STREAM */
|
||||
STREAM_U_READ_DONE = (1 << 8), /* User is done reading (shutdown was called) */
|
||||
STREAM_U_WRITE_DONE = (1 << 9), /* User is done writing (shutdown was called) */
|
||||
STREAM_FIN_SENT = (1 <<10), /* FIN was written to network */
|
||||
STREAM_RST_SENT = (1 <<11), /* RST_STREAM was written to network */
|
||||
STREAM_UNUSED12 = (1 <<12), /* Free bit, can be used */
|
||||
STREAM_WANT_FLUSH = (1 <<12), /* Flush until sm_flush_to is hit */
|
||||
STREAM_FIN_REACHED = (1 <<13), /* User read data up to FIN */
|
||||
STREAM_FINISHED = (1 <<14), /* Stream is finished */
|
||||
STREAM_ONCLOSE_DONE = (1 <<15), /* on_close has been called */
|
||||
|
@ -63,8 +60,8 @@ struct lsquic_stream
|
|||
STREAM_HAVE_UH = (1 <<20), /* Have uncompressed headers */
|
||||
STREAM_CONN_LIMITED = (1 <<21),
|
||||
STREAM_HEAD_IN_FIN = (1 <<22), /* Incoming headers has FIN bit set */
|
||||
STREAM_SAVED_WANTWR = (1 <<23),
|
||||
STREAM_CLOSE_FILE = (1 <<24),
|
||||
STREAM_ABORT_CONN = (1 <<23), /* Unrecoverable error occurred */
|
||||
STREAM_FRAMES_ELIDED= (1 <<24),
|
||||
STREAM_FORCE_FINISH = (1 <<25), /* Replaces FIN sent and received */
|
||||
STREAM_ONNEW_DONE = (1 <<26), /* on_new_stream has been called */
|
||||
STREAM_AUTOSWITCH = (1 <<27),
|
||||
|
@ -72,12 +69,13 @@ struct lsquic_stream
|
|||
} stream_flags;
|
||||
|
||||
/* There are more than one reason that a stream may be put onto
|
||||
* connections's sending_streams queue:
|
||||
* connections's sending_streams queue. Note that writing STREAM
|
||||
* frames is done separately.
|
||||
*/
|
||||
#define STREAM_SENDING_FLAGS (STREAM_SEND_WUF|STREAM_SEND_DATA| \
|
||||
#define STREAM_SENDING_FLAGS (STREAM_SEND_WUF| \
|
||||
STREAM_SEND_RST|STREAM_SEND_BLOCKED)
|
||||
|
||||
#define STREAM_RW_EVENT_FLAGS (STREAM_WANT_READ|STREAM_WANT_WRITE)
|
||||
#define STREAM_WRITE_Q_FLAGS (STREAM_WANT_FLUSH|STREAM_WANT_WRITE)
|
||||
|
||||
/* Any of these flags will cause user-facing read and write and
|
||||
* shutdown calls to return an error. They also make the stream
|
||||
|
@ -87,20 +85,17 @@ struct lsquic_stream
|
|||
#define STREAM_RST_FLAGS (STREAM_RST_RECVD|STREAM_RST_SENT|\
|
||||
STREAM_SEND_RST)
|
||||
|
||||
#define STREAM_SERVICE_FLAGS (STREAM_CALL_ONCLOSE|STREAM_FREE_STREAM)
|
||||
#define STREAM_SERVICE_FLAGS (STREAM_CALL_ONCLOSE|STREAM_FREE_STREAM|\
|
||||
STREAM_ABORT_CONN)
|
||||
|
||||
const struct lsquic_stream_if *stream_if;
|
||||
struct lsquic_stream_ctx *st_ctx;
|
||||
struct lsquic_conn_public *conn_pub;
|
||||
TAILQ_ENTRY(lsquic_stream) next_send_stream, next_rw_stream,
|
||||
next_service_stream, next_prio_stream;
|
||||
TAILQ_ENTRY(lsquic_stream) next_send_stream, next_read_stream,
|
||||
next_write_stream, next_service_stream,
|
||||
next_prio_stream;
|
||||
|
||||
/* These fields are dealing with data going from user to connection
|
||||
* (out to the network).
|
||||
*/
|
||||
struct sbts_tailq bufs_tosend;
|
||||
uint32_t error_code;
|
||||
size_t tosend_sz; /* Data size in bufs_tosend */
|
||||
uint64_t tosend_off;
|
||||
uint64_t max_send_off;
|
||||
|
||||
|
@ -111,36 +106,26 @@ struct lsquic_stream
|
|||
uint64_t read_offset;
|
||||
lsquic_sfcw_t fc;
|
||||
|
||||
/** If @ref STREAM_WANT_FLUSH is set, flush until this offset. */
|
||||
uint64_t sm_flush_to;
|
||||
|
||||
/* Last offset sent in BLOCKED frame */
|
||||
uint64_t blocked_off;
|
||||
|
||||
/* To write files, user-supplied on_write callback gets swapped out
|
||||
* temporarily.
|
||||
*/
|
||||
void (*on_write_cb)(struct lsquic_stream *,
|
||||
struct lsquic_stream_ctx *);
|
||||
|
||||
struct uncompressed_headers *uh,
|
||||
*push_req;
|
||||
|
||||
/* To let other streams write even as we schedule a large file, it is
|
||||
* written out to sbt queue in chunks. Intermediate state is stored in
|
||||
* this structure. Obviously, only one file can be scheduled at a time.
|
||||
* When the file is all written out, the file descriptor is closed and
|
||||
* user-supplied on_write callback gets installed again.
|
||||
*/
|
||||
off_t file_size;
|
||||
off_t file_off;
|
||||
int file_fd;
|
||||
unsigned char file_byte;
|
||||
unsigned char *sm_buf;
|
||||
void *sm_onnew_arg;
|
||||
|
||||
unsigned n_unacked;
|
||||
unsigned short sm_n_buffered; /* Amount of data in sm_buf */
|
||||
|
||||
unsigned char sm_priority; /* 0: high; 255: low */
|
||||
#if LSQUIC_KEEP_STREAM_HISTORY
|
||||
sm_hist_idx_t sm_hist_idx;
|
||||
#endif
|
||||
|
||||
unsigned n_unacked;
|
||||
|
||||
#if LSQUIC_KEEP_STREAM_HISTORY
|
||||
/* Stream history: see enum stream_history_event */
|
||||
unsigned char sm_hist_buf[ 1 << SM_HIST_BITS ];
|
||||
|
@ -173,7 +158,7 @@ lsquic_stream_new_ext (uint32_t id, struct lsquic_conn_public *conn_pub,
|
|||
(SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH))
|
||||
|
||||
void
|
||||
lsquic_stream_call_on_new (lsquic_stream_t *, void *stream_if_ctx);
|
||||
lsquic_stream_call_on_new (lsquic_stream_t *);
|
||||
|
||||
void
|
||||
lsquic_stream_destroy (lsquic_stream_t *);
|
||||
|
@ -230,20 +215,6 @@ lsquic_stream_window_update (lsquic_stream_t *stream, uint64_t offset);
|
|||
int
|
||||
lsquic_stream_set_max_send_off (lsquic_stream_t *stream, unsigned offset);
|
||||
|
||||
size_t
|
||||
lsquic_stream_tosend_sz (const lsquic_stream_t *);
|
||||
|
||||
/* Read data inserted by the client using lsquic_stream_write().
|
||||
*/
|
||||
size_t
|
||||
lsquic_stream_tosend_read (lsquic_stream_t *, void *, size_t, int *);
|
||||
|
||||
/* Return current offset associated with data written to network
|
||||
* stream.
|
||||
*/
|
||||
uint64_t
|
||||
lsquic_stream_tosend_offset (const lsquic_stream_t *stream);
|
||||
|
||||
/* The caller should only call this function if STREAM_SEND_WUF is set and
|
||||
* it must generate a window update frame using this value.
|
||||
*/
|
||||
|
@ -251,7 +222,10 @@ uint64_t
|
|||
lsquic_stream_fc_recv_off (lsquic_stream_t *stream);
|
||||
|
||||
void
|
||||
lsquic_stream_dispatch_rw_events (lsquic_stream_t *);
|
||||
lsquic_stream_dispatch_read_events (lsquic_stream_t *);
|
||||
|
||||
void
|
||||
lsquic_stream_dispatch_write_events (lsquic_stream_t *);
|
||||
|
||||
void
|
||||
lsquic_stream_blocked_frame_sent (lsquic_stream_t *);
|
||||
|
@ -300,13 +274,13 @@ lsquic_stream_set_priority_internal (lsquic_stream_t *, unsigned priority);
|
|||
* during Pending RW Queue processing. We only check for stream read progress,
|
||||
* as the write progress is defined as any new data packetized for sending.
|
||||
*/
|
||||
struct stream_rw_prog_status
|
||||
struct stream_read_prog_status
|
||||
{
|
||||
uint64_t srps_read_offset;
|
||||
enum stream_flags srps_flags;
|
||||
};
|
||||
|
||||
#define lsquic_stream_get_rw_prog_status(stream, stats) do { \
|
||||
#define lsquic_stream_get_read_prog_status(stream, stats) do { \
|
||||
(stats)->srps_read_offset = (stream)->read_offset; \
|
||||
(stats)->srps_flags = \
|
||||
(stream)->stream_flags & STREAM_RW_PROG_FLAGS; \
|
||||
|
@ -318,5 +292,17 @@ struct stream_rw_prog_status
|
|||
((stream)->stream_flags & STREAM_RW_PROG_FLAGS) \
|
||||
)
|
||||
|
||||
#endif //__LSQUIC_STREAM_H__
|
||||
#define lsquic_stream_is_critical(stream) ( \
|
||||
(stream)->id == LSQUIC_STREAM_HANDSHAKE || \
|
||||
((stream)->id == LSQUIC_STREAM_HEADERS && \
|
||||
(stream)->stream_flags & STREAM_USE_HEADERS))
|
||||
|
||||
size_t
|
||||
lsquic_stream_mem_used (const struct lsquic_stream *);
|
||||
|
||||
lsquic_cid_t
|
||||
lsquic_stream_cid (const struct lsquic_stream *);
|
||||
|
||||
#define lsquic_stream_has_data_to_flush(stream) ((stream)->sm_n_buffered > 0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -131,6 +131,7 @@ struct lsquic_stream_ctx {
|
|||
HEADERS_SENT = (1 << 0),
|
||||
} sh_flags;
|
||||
unsigned count;
|
||||
struct lsquic_reader reader;
|
||||
};
|
||||
|
||||
|
||||
|
@ -161,6 +162,16 @@ http_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
|||
st_h->client_ctx->hcc_cur_pe = TAILQ_FIRST(
|
||||
&st_h->client_ctx->hcc_path_elems);
|
||||
st_h->path = st_h->client_ctx->hcc_cur_pe->path;
|
||||
if (st_h->client_ctx->payload)
|
||||
{
|
||||
st_h->reader.lsqr_read = test_reader_read;
|
||||
st_h->reader.lsqr_size = test_reader_size;
|
||||
st_h->reader.lsqr_ctx = create_lsquic_reader_ctx(st_h->client_ctx->payload);
|
||||
if (!st_h->reader.lsqr_ctx)
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
st_h->reader.lsqr_ctx = NULL;
|
||||
LSQ_INFO("created new stream, path: %s", st_h->path);
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
|
||||
|
@ -232,20 +243,34 @@ send_headers (lsquic_stream_ctx_t *st_h)
|
|||
static void
|
||||
http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||
{
|
||||
ssize_t nw;
|
||||
|
||||
if (st_h->sh_flags & HEADERS_SENT)
|
||||
{
|
||||
if (st_h->client_ctx->payload)
|
||||
if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
|
||||
{
|
||||
if (0 != lsquic_stream_write_file(stream, st_h->client_ctx->payload))
|
||||
nw = lsquic_stream_writef(stream, &st_h->reader);
|
||||
if (nw < 0)
|
||||
{
|
||||
LSQ_ERROR("cannot queue file %s for writing: %s",
|
||||
st_h->client_ctx->payload, strerror(errno));
|
||||
LSQ_ERROR("write error: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (test_reader_size(st_h->reader.lsqr_ctx) > 0)
|
||||
{
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
lsquic_stream_shutdown(stream, 1);
|
||||
lsquic_stream_wantread(stream, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lsquic_stream_shutdown(stream, 1);
|
||||
lsquic_stream_wantread(stream, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
st_h->sh_flags |= HEADERS_SENT;
|
||||
|
@ -327,6 +352,8 @@ http_client_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
|||
}
|
||||
else
|
||||
lsquic_conn_make_stream(conn);
|
||||
if (st_h->reader.lsqr_ctx)
|
||||
destroy_lsquic_reader_ctx(st_h->reader.lsqr_ctx);
|
||||
free(st_h);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
|
||||
#include "test_config.h"
|
||||
#include "test_cert.h"
|
||||
#include "test_common.h"
|
||||
#include "prog.h"
|
||||
|
||||
|
|
133
test/test_cert.c
133
test/test_cert.c
|
@ -1,133 +0,0 @@
|
|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic.h"
|
||||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
#include "../src/liblsquic/lsquic_hash.h"
|
||||
|
||||
#include "test_cert.h"
|
||||
|
||||
int
|
||||
load_cert (struct lsquic_hash *certs, const char *optarg)
|
||||
{
|
||||
int rv = -1;
|
||||
char *sni, *cert_file, *key_file;
|
||||
struct server_cert *cert = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
FILE *f = NULL;
|
||||
|
||||
sni = strdup(optarg);
|
||||
cert_file = strchr(sni, ',');
|
||||
if (!cert_file)
|
||||
goto end;
|
||||
*cert_file = '\0';
|
||||
++cert_file;
|
||||
key_file = strchr(cert_file, ',');
|
||||
if (!key_file)
|
||||
goto end;
|
||||
*key_file = '\0';
|
||||
++key_file;
|
||||
|
||||
cert = malloc(sizeof(*cert));
|
||||
cert->ce_sni = strdup(sni);
|
||||
|
||||
cert->ce_ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (!cert->ce_ssl_ctx)
|
||||
{
|
||||
LSQ_ERROR("SSL_CTX_new failed");
|
||||
goto end;
|
||||
}
|
||||
if (1 != SSL_CTX_use_certificate_chain_file(cert->ce_ssl_ctx, cert_file))
|
||||
{
|
||||
LSQ_ERROR("SSL_CTX_use_certificate_chain_file failed: %s", cert_file);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strstr(key_file, ".pkcs8"))
|
||||
{
|
||||
f = fopen(key_file, "r");
|
||||
if (!f)
|
||||
{
|
||||
LSQ_ERROR("fopen(%s) failed: %s", cert_file, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
pkey = d2i_PrivateKey_fp(f, NULL);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
if (!pkey)
|
||||
{
|
||||
LSQ_ERROR("Reading private key from %s failed", key_file);
|
||||
goto end;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey(cert->ce_ssl_ctx, pkey))
|
||||
{
|
||||
LSQ_ERROR("SSL_CTX_use_PrivateKey failed");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else if (1 != SSL_CTX_use_PrivateKey_file(cert->ce_ssl_ctx, key_file,
|
||||
SSL_FILETYPE_PEM))
|
||||
{
|
||||
LSQ_ERROR("SSL_CTX_use_PrivateKey_file failed");
|
||||
goto end;
|
||||
}
|
||||
|
||||
lsquic_hash_insert(certs, cert->ce_sni, strlen(cert->ce_sni), cert);
|
||||
rv = 0;
|
||||
|
||||
end:
|
||||
free(sni);
|
||||
if (f)
|
||||
fclose(f);
|
||||
if (rv != 0)
|
||||
{ /* Error: free cert and its components */
|
||||
if (cert)
|
||||
{
|
||||
free(cert->ce_sni);
|
||||
free(cert);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct ssl_ctx_st *
|
||||
lookup_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED,
|
||||
const char *sni)
|
||||
{
|
||||
if (!cert_lu_ctx)
|
||||
return NULL;
|
||||
struct lsquic_hash_elem *el = lsquic_hash_find(cert_lu_ctx, sni, strlen(sni));
|
||||
struct server_cert *server_cert = NULL;
|
||||
if (el)
|
||||
{
|
||||
server_cert = lsquic_hashelem_getdata(el);
|
||||
if (server_cert)
|
||||
return server_cert->ce_ssl_ctx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
delete_certs (struct lsquic_hash *certs)
|
||||
{
|
||||
struct lsquic_hash_elem *el;
|
||||
struct server_cert *cert;
|
||||
|
||||
for (el = lsquic_hash_first(certs); el; el = lsquic_hash_next(certs))
|
||||
{
|
||||
cert = lsquic_hashelem_getdata(el);
|
||||
SSL_CTX_free(cert->ce_ssl_ctx);
|
||||
free(cert->ce_sni);
|
||||
free(cert);
|
||||
}
|
||||
lsquic_hash_destroy(certs);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef TEST_CERT_H
|
||||
#define TEST_CERT_H
|
||||
|
||||
struct lsquic_hash;
|
||||
struct ssl_ctx_st;
|
||||
struct sockaddr;
|
||||
|
||||
struct server_cert
|
||||
{
|
||||
char *ce_sni;
|
||||
struct ssl_ctx_st *ce_ssl_ctx;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
load_cert (struct lsquic_hash *, const char *optarg);
|
||||
|
||||
struct ssl_ctx_st *
|
||||
lookup_cert (void *cert_lu_ctx, const struct sockaddr * /*unused */,
|
||||
const char *sni);
|
||||
|
||||
void
|
||||
delete_certs (struct lsquic_hash *);
|
||||
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
@ -1087,3 +1088,78 @@ pba_cleanup (struct packout_buf_allocator *pba)
|
|||
}
|
||||
|
||||
|
||||
struct reader_ctx
|
||||
{
|
||||
size_t file_size;
|
||||
size_t nread;
|
||||
int fd;
|
||||
};
|
||||
|
||||
|
||||
size_t
|
||||
test_reader_size (void *void_ctx)
|
||||
{
|
||||
struct reader_ctx *const ctx = void_ctx;
|
||||
return ctx->file_size - ctx->nread;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
test_reader_read (void *void_ctx, void *buf, size_t count)
|
||||
{
|
||||
struct reader_ctx *const ctx = void_ctx;
|
||||
ssize_t nread;
|
||||
|
||||
if (count > test_reader_size(ctx))
|
||||
count = test_reader_size(ctx);
|
||||
|
||||
nread = read(ctx->fd, buf, count);
|
||||
if (nread >= 0)
|
||||
{
|
||||
ctx->nread += nread;
|
||||
return nread;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("%s: error reading from file: %s", __func__, strerror(errno));
|
||||
ctx->nread = ctx->file_size = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct reader_ctx *
|
||||
create_lsquic_reader_ctx (const char *filename)
|
||||
{
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
LSQ_ERROR("cannot open %s for reading: %s", filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (0 != fstat(fd, &st))
|
||||
{
|
||||
LSQ_ERROR("cannot fstat(%s) failed: %s", filename, strerror(errno));
|
||||
(void) close(fd);
|
||||
return NULL;
|
||||
}
|
||||
struct reader_ctx *ctx = malloc(sizeof(*ctx));
|
||||
ctx->file_size = st.st_size;
|
||||
ctx->nread = 0;
|
||||
ctx->fd = fd;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
destroy_lsquic_reader_ctx (struct reader_ctx *ctx)
|
||||
{
|
||||
(void) close(ctx->fd);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ struct event;
|
|||
struct packets_in;
|
||||
struct lsquic_conn;
|
||||
struct prog;
|
||||
struct reader_ctx;
|
||||
|
||||
enum sport_flags
|
||||
{
|
||||
|
@ -93,4 +94,16 @@ pba_release (void *packout_buf_allocator, void *obj);
|
|||
void
|
||||
pba_cleanup (struct packout_buf_allocator *);
|
||||
|
||||
size_t
|
||||
test_reader_size (void *void_ctx);
|
||||
|
||||
size_t
|
||||
test_reader_read (void *void_ctx, void *buf, size_t count);
|
||||
|
||||
struct reader_ctx *
|
||||
create_lsquic_reader_ctx (const char *filename);
|
||||
|
||||
void
|
||||
destroy_lsquic_reader_ctx (struct reader_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,12 +34,8 @@ add_executable(test_stream test_stream.c)
|
|||
target_link_libraries(test_stream lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
|
||||
add_test(stream test_stream)
|
||||
add_test(stream_hash test_stream -h)
|
||||
add_test(stream_write_file test_stream -w Makefile)
|
||||
add_test(stream_hash_write_file test_stream -h -w Makefile)
|
||||
add_test(stream_A test_stream -A)
|
||||
add_test(stream_hash_A test_stream -A -h)
|
||||
add_test(stream_write_file_A test_stream -A -w Makefile)
|
||||
add_test(stream_hash_write_file_A test_stream -A -h -w Makefile)
|
||||
|
||||
add_executable(test_spi test_spi.c)
|
||||
target_link_libraries(test_spi lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
|
||||
|
@ -126,7 +122,7 @@ target_link_libraries(test_ackgen_gquic_ietf lsquic pthread libssl.a libcrypto.a
|
|||
add_test(ackgen_gquic_ietf test_ackgen_gquic_ietf)
|
||||
|
||||
add_executable(test_sfcw test_sfcw.c)
|
||||
target_link_libraries(test_sfcw lsquic m ${FIULIB})
|
||||
target_link_libraries(test_sfcw lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
|
||||
add_test(sfcw test_sfcw)
|
||||
|
||||
add_executable(test_alarmset test_alarmset.c)
|
||||
|
|
|
@ -334,6 +334,7 @@ test_6byte_packnos (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
lsquic_log_to_fstream(stderr, 0);
|
||||
lsq_log_levels[LSQLM_PARSE] = LSQ_LOG_DEBUG;
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ test_8byte_packnos (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
lsquic_log_to_fstream(stderr, 0);
|
||||
lsq_log_levels[LSQLM_PARSE] = LSQ_LOG_DEBUG;
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ test_6byte_packnos (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
lsquic_log_to_fstream(stderr, 0);
|
||||
lsq_log_levels[LSQLM_PARSE] = LSQ_LOG_DEBUG;
|
||||
|
||||
|
|
|
@ -444,6 +444,7 @@ test_ack_truncation (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
|
|
|
@ -444,6 +444,7 @@ test_ack_truncation (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
|
|
|
@ -443,6 +443,7 @@ test_ack_truncation (void)
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
|
|
|
@ -105,13 +105,13 @@ elide_single_stream_frame (void)
|
|||
packet_out->po_data_sz += len;
|
||||
packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
|
||||
QUIC_FRAME_STREAM, off);
|
||||
QUIC_FRAME_STREAM, off, len);
|
||||
assert(1 == streams[0].n_unacked);
|
||||
assert(posi_first(&posi, packet_out));
|
||||
|
||||
streams[0].stream_flags |= STREAM_RST_SENT;
|
||||
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, pf, 0);
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, 0);
|
||||
assert(0 == streams[0].n_unacked);
|
||||
assert(0 == packet_out->po_frame_types);
|
||||
assert(!posi_first(&posi, packet_out));
|
||||
|
@ -205,7 +205,7 @@ elide_three_stream_frames (int chop_regen)
|
|||
(gsf_read_f) lsquic_stream_tosend_read,
|
||||
&streams[0]);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz);
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
|
||||
packet_out->po_data_sz += len;
|
||||
/* STREAM B */
|
||||
setup_stream_contents(123, "BBBBBBBBBB");
|
||||
|
@ -218,7 +218,7 @@ elide_three_stream_frames (int chop_regen)
|
|||
(gsf_read_f) lsquic_stream_tosend_read,
|
||||
&streams[1]);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz);
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
|
||||
packet_out->po_data_sz += len;
|
||||
/* STREAM C */
|
||||
setup_stream_contents(123, "CCCCCCCCCC");
|
||||
|
@ -231,13 +231,13 @@ elide_three_stream_frames (int chop_regen)
|
|||
(gsf_read_f) lsquic_stream_tosend_read,
|
||||
&streams[2]);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2],
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz);
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
|
||||
packet_out->po_data_sz += len;
|
||||
/* Reset A */
|
||||
len = pf->pf_gen_rst_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||
lsquic_packet_out_avail(packet_out), 'A', 133, 0);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
|
||||
QUIC_FRAME_RST_STREAM, 0);
|
||||
QUIC_FRAME_RST_STREAM, 0, 0);
|
||||
packet_out->po_data_sz += len;
|
||||
/* STREAM D */
|
||||
setup_stream_contents(123, "DDDDDDDDDD");
|
||||
|
@ -250,7 +250,7 @@ elide_three_stream_frames (int chop_regen)
|
|||
(gsf_read_f) lsquic_stream_tosend_read,
|
||||
&streams[3]);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3],
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz);
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
|
||||
packet_out->po_data_sz += len;
|
||||
/* STREAM E */
|
||||
setup_stream_contents(123, "EEEEEEEEEE");
|
||||
|
@ -263,7 +263,7 @@ elide_three_stream_frames (int chop_regen)
|
|||
(gsf_read_f) lsquic_stream_tosend_read,
|
||||
&streams[4]);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4],
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz);
|
||||
QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
|
||||
packet_out->po_data_sz += len;
|
||||
packet_out->po_frame_types = (1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM);
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ elide_three_stream_frames (int chop_regen)
|
|||
|
||||
if (chop_regen)
|
||||
lsquic_packet_out_chop_regen(packet_out);
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, pf, 0);
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, 0);
|
||||
|
||||
assert(ref_out->po_data_sz == packet_out->po_data_sz + (chop_regen ? 5 : 0));
|
||||
assert(ref_out->po_regen_sz == packet_out->po_regen_sz + (chop_regen ? 5 : 0));
|
||||
|
|
|
@ -82,20 +82,6 @@ stream_write (struct lsquic_stream *stream, const void *buf, size_t sz)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
stream_flush (struct lsquic_stream *stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
stream_navail (const struct lsquic_stream *stream)
|
||||
{
|
||||
return stream->sm_max_write;
|
||||
}
|
||||
|
||||
|
||||
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
|
||||
|
||||
|
||||
|
@ -112,8 +98,7 @@ test_chop (unsigned max_write_sz)
|
|||
lsquic_henc_init(&henc);
|
||||
stream = stream_new(max_write_sz);
|
||||
|
||||
fw = lsquic_frame_writer_new(&mm, stream, 0, &henc,
|
||||
stream_write, stream_navail, stream_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, stream, 0, &henc, stream_write, 0);
|
||||
|
||||
struct lsquic_http_header header_arr[] =
|
||||
{
|
||||
|
|
|
@ -98,20 +98,6 @@ stream_write (struct lsquic_stream *stream, const void *buf, size_t sz)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
stream_flush (struct lsquic_stream *stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
stream_navail (const struct lsquic_stream *stream)
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
read_from_stream (struct lsquic_stream *stream, void *buf, size_t sz)
|
||||
{
|
||||
|
@ -209,7 +195,7 @@ test_rw (unsigned max_frame_sz)
|
|||
stream->sm_max_sz = 1;
|
||||
|
||||
fw = lsquic_frame_writer_new(&mm, stream, max_frame_sz, &henc,
|
||||
stream_write, stream_navail, stream_flush, 0);
|
||||
stream_write, 0);
|
||||
|
||||
struct lsquic_http_headers headers = {
|
||||
.count = N_HEADERS,
|
||||
|
|
|
@ -46,20 +46,6 @@ output_write (struct lsquic_stream *stream, const void *buf, size_t sz)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
output_flush (struct lsquic_stream *stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
output_navail (const struct lsquic_stream *stream)
|
||||
{
|
||||
return output.max - output.sz;
|
||||
}
|
||||
|
||||
|
||||
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
|
||||
|
||||
|
||||
|
@ -77,12 +63,11 @@ test_max_frame_size (void)
|
|||
for (max_size = 1; max_size < 6 /* one settings frame */; ++max_size)
|
||||
{
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc,
|
||||
output_write, output_navail, output_flush, 0);
|
||||
output_write, 0);
|
||||
assert(!fw);
|
||||
}
|
||||
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc,
|
||||
output_write, output_navail, output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, max_size, &henc, output_write, 0);
|
||||
assert(fw);
|
||||
|
||||
lsquic_frame_writer_destroy(fw);
|
||||
|
@ -101,8 +86,7 @@ test_one_header (void)
|
|||
|
||||
lsquic_henc_init(&henc);
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
|
||||
output_navail, output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
||||
reset_output(0);
|
||||
|
||||
struct lsquic_http_header header_arr[] =
|
||||
|
@ -162,8 +146,7 @@ test_oversize_header (void)
|
|||
|
||||
lsquic_henc_init(&henc);
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
|
||||
output_navail, output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 0);
|
||||
reset_output(0);
|
||||
|
||||
value = malloc(big_len);
|
||||
|
@ -201,8 +184,7 @@ test_continuations (void)
|
|||
|
||||
lsquic_henc_init(&henc);
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write, output_navail,
|
||||
output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 6, &henc, output_write, 0);
|
||||
reset_output(0);
|
||||
|
||||
/*
|
||||
|
@ -287,8 +269,7 @@ test_settings_short (void)
|
|||
struct lsquic_mm mm;
|
||||
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 7, NULL, output_write, output_navail,
|
||||
output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 7, NULL, output_write, 0);
|
||||
|
||||
{
|
||||
reset_output(0);
|
||||
|
@ -332,8 +313,7 @@ test_settings_normal (void)
|
|||
struct lsquic_mm mm;
|
||||
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0, NULL, output_write, output_navail,
|
||||
output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0, NULL, output_write, 0);
|
||||
|
||||
{
|
||||
reset_output(0);
|
||||
|
@ -390,8 +370,7 @@ test_priority (void)
|
|||
struct lsquic_mm mm;
|
||||
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 6, NULL, output_write, output_navail,
|
||||
output_flush, 0);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 6, NULL, output_write, 0);
|
||||
|
||||
s = lsquic_frame_writer_write_priority(fw, 3, 0, 1UL << 31, 256);
|
||||
assert(s < 0); /* Invalid dependency stream ID */
|
||||
|
@ -450,8 +429,7 @@ test_errors (void)
|
|||
|
||||
lsquic_henc_init(&henc);
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
|
||||
output_navail, output_flush, 1);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
||||
reset_output(0);
|
||||
|
||||
{
|
||||
|
@ -501,8 +479,7 @@ test_push_promise (void)
|
|||
|
||||
lsquic_henc_init(&henc);
|
||||
lsquic_mm_init(&mm);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write,
|
||||
output_navail, output_flush, 1);
|
||||
fw = lsquic_frame_writer_new(&mm, NULL, 0x200, &henc, output_write, 1);
|
||||
reset_output(0);
|
||||
|
||||
/*
|
||||
|
|
|
@ -40,13 +40,13 @@ main (void)
|
|||
lsquic_mm_init(&enpub.enp_mm);
|
||||
packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, QUIC_MAX_PAYLOAD_SZ);
|
||||
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], QUIC_FRAME_STREAM, 7);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], QUIC_FRAME_STREAM, 8);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2], QUIC_FRAME_STREAM, 9);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], QUIC_FRAME_RST_STREAM, 10);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3], QUIC_FRAME_STREAM, 11);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4], QUIC_FRAME_STREAM, 12);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[5], QUIC_FRAME_STREAM, 13);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], QUIC_FRAME_STREAM, 7, 1);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], QUIC_FRAME_STREAM, 8, 1);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2], QUIC_FRAME_STREAM, 9, 1);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], QUIC_FRAME_RST_STREAM, 10, 0);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3], QUIC_FRAME_STREAM, 11, 1);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4], QUIC_FRAME_STREAM, 12, 1);
|
||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[5], QUIC_FRAME_STREAM, 13, 1);
|
||||
|
||||
srec = posi_first(&posi, packet_out);
|
||||
assert(srec->sr_stream == &streams[0]);
|
||||
|
|
|
@ -172,6 +172,8 @@ main (void)
|
|||
unsigned i;
|
||||
const struct lsquic_packno_range *range;
|
||||
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
|
||||
lsquic_log_to_fstream(stderr, 0);
|
||||
lsq_log_levels[LSQLM_PARSE] = LSQ_LOG_DEBUG;
|
||||
lsq_log_levels[LSQLM_RECHIST] = LSQ_LOG_DEBUG;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
int
|
||||
main (void)
|
||||
{
|
||||
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
|
||||
const unsigned INIT_WINDOW_SIZE = 16 * 1024;
|
||||
struct lsquic_sfcw fc;
|
||||
struct lsquic_conn lconn;
|
||||
|
|
|
@ -57,19 +57,19 @@ test_same_priority (unsigned priority)
|
|||
lsquic_stream_t *stream;
|
||||
|
||||
TAILQ_INIT(&streams);
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_rw_stream);
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_write_stream);
|
||||
stream_arr[0]->stream_flags |= flags;
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_rw_stream);
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_write_stream);
|
||||
stream_arr[1]->stream_flags |= flags;
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_rw_stream);
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_write_stream);
|
||||
stream_arr[2]->stream_flags |= flags;
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_rw_stream);
|
||||
TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_write_stream);
|
||||
stream_arr[3]->stream_flags |= flags;
|
||||
|
||||
lsquic_spi_init_simple(&spi, TAILQ_FIRST(&streams),
|
||||
lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
|
||||
TAILQ_LAST(&streams, lsquic_streams_tailq),
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_rw_stream),
|
||||
flags);
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
|
||||
flags, 0, __func__);
|
||||
|
||||
stream = lsquic_spi_first(&spi);
|
||||
assert(stream == stream_arr[0]);
|
||||
|
@ -83,9 +83,9 @@ test_same_priority (unsigned priority)
|
|||
assert(stream == NULL);
|
||||
|
||||
/* Test reinitialization: */
|
||||
lsquic_spi_init_simple(&spi, stream_arr[0], stream_arr[1],
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_rw_stream),
|
||||
flags);
|
||||
lsquic_spi_init(&spi, stream_arr[0], stream_arr[1],
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
|
||||
flags, 0, __func__);
|
||||
stream = lsquic_spi_first(&spi);
|
||||
assert(stream == stream_arr[0]);
|
||||
stream = lsquic_spi_next(&spi);
|
||||
|
@ -116,10 +116,10 @@ test_different_priorities (int *priority)
|
|||
++n_streams;
|
||||
}
|
||||
|
||||
lsquic_spi_init_simple(&spi, TAILQ_FIRST(&streams),
|
||||
lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
|
||||
TAILQ_LAST(&streams, lsquic_streams_tailq),
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
|
||||
flags);
|
||||
flags, 0, __func__);
|
||||
|
||||
for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
|
||||
stream = lsquic_spi_next(&spi), ++count)
|
||||
|
@ -140,191 +140,92 @@ test_different_priorities (int *priority)
|
|||
}
|
||||
|
||||
|
||||
#define MAGIC 0x12312312U
|
||||
|
||||
struct my_filter_ctx
|
||||
struct stream_info
|
||||
{
|
||||
unsigned magic;
|
||||
uint32_t stream_id;
|
||||
unsigned char prio;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
filter_out_odd_priorities (void *ctx, lsquic_stream_t *stream)
|
||||
const struct stream_info infos1[] = {
|
||||
{ LSQUIC_STREAM_HANDSHAKE, 0, },
|
||||
{ LSQUIC_STREAM_HEADERS, 0, },
|
||||
{ 5, 0, },
|
||||
{ 7, 1, },
|
||||
{ 127, 200, },
|
||||
};
|
||||
|
||||
|
||||
const struct stream_info infos2[] = {
|
||||
{ LSQUIC_STREAM_HANDSHAKE, 0, },
|
||||
{ LSQUIC_STREAM_HEADERS, 0, },
|
||||
{ 5, 4, },
|
||||
{ 7, 1, },
|
||||
{ 127, 200, },
|
||||
};
|
||||
|
||||
|
||||
struct drop_test
|
||||
{
|
||||
struct my_filter_ctx *fctx = ctx;
|
||||
assert(fctx->magic == MAGIC);
|
||||
return 0 == (stream->sm_priority & 1);
|
||||
}
|
||||
const struct stream_info *infos;
|
||||
unsigned n_infos;
|
||||
unsigned high_streams;
|
||||
};
|
||||
|
||||
|
||||
static const struct drop_test drop_tests[] = {
|
||||
{ infos1, 5, 0x7, },
|
||||
{ infos2, 5, 0x3, },
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
test_different_priorities_filter_odd (int *priority)
|
||||
test_drop (const struct drop_test *test)
|
||||
{
|
||||
|
||||
struct lsquic_stream stream_arr[20];
|
||||
unsigned seen_mask, n;
|
||||
struct lsquic_streams_tailq streams;
|
||||
unsigned flags = 0xC000; /* Arbitrary value */
|
||||
lsquic_stream_t *stream;
|
||||
int prio, prev_prio, count, n_streams = 0;
|
||||
int drop_high;
|
||||
|
||||
TAILQ_INIT(&streams);
|
||||
|
||||
for ( ; *priority >= 0; ++priority)
|
||||
for (n = 0; n < test->n_infos; ++n)
|
||||
{
|
||||
assert(*priority < 256);
|
||||
stream = new_stream(*priority);
|
||||
TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
|
||||
stream->stream_flags |= flags;
|
||||
++n_streams;
|
||||
stream_arr[n].sm_priority = test->infos[n].prio;
|
||||
stream_arr[n].id = test->infos[n].stream_id;
|
||||
stream_arr[n].stream_flags = STREAM_USE_HEADERS;
|
||||
}
|
||||
|
||||
struct my_filter_ctx my_filter_ctx = { MAGIC };
|
||||
|
||||
lsquic_spi_init_ext(&spi, TAILQ_FIRST(&streams),
|
||||
TAILQ_LAST(&streams, lsquic_streams_tailq),
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
|
||||
flags, filter_out_odd_priorities, &my_filter_ctx, 0, NULL);
|
||||
|
||||
for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
|
||||
stream = lsquic_spi_next(&spi), ++count)
|
||||
for (drop_high = 0; drop_high < 2; ++drop_high)
|
||||
{
|
||||
prio = stream->sm_priority;
|
||||
assert(0 == (prio & 1));
|
||||
assert(prio >= prev_prio);
|
||||
if (prio > prev_prio)
|
||||
prev_prio = prio;
|
||||
}
|
||||
|
||||
assert(count < n_streams);
|
||||
|
||||
while ((stream = TAILQ_FIRST(&streams)))
|
||||
{
|
||||
TAILQ_REMOVE(&streams, stream, next_send_stream);
|
||||
free(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* First part of this test is the same as test_different_priorities().
|
||||
* After that, we turn on exhaust option and begin to take streams off
|
||||
* the list.
|
||||
*/
|
||||
static void
|
||||
test_exhaust (void)
|
||||
{
|
||||
const int priorities[] = {
|
||||
10, /* stream_arr[0] */
|
||||
101, /* stream_arr[1] */
|
||||
1, /* stream_arr[2] */
|
||||
3, /* stream_arr[3] */
|
||||
1, /* stream_arr[4] */
|
||||
0, /* stream_arr[5] */
|
||||
-1
|
||||
};
|
||||
const int *priority = priorities;
|
||||
struct lsquic_stream *stream_arr[sizeof(priorities) / sizeof(priorities[0])];
|
||||
struct lsquic_streams_tailq streams;
|
||||
const unsigned flags = 0x0300; /* Arbitrary value */
|
||||
lsquic_stream_t *stream, *prev_stream;
|
||||
int prio, prev_prio, count, n_streams = 0;
|
||||
|
||||
TAILQ_INIT(&streams);
|
||||
for (n = 0; n < test->n_infos; ++n)
|
||||
TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream);
|
||||
|
||||
for ( ; *priority >= 0; ++priority)
|
||||
{
|
||||
assert(*priority < 256);
|
||||
stream = new_stream(*priority);
|
||||
stream_arr[n_streams] = stream;
|
||||
TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
|
||||
stream->stream_flags |= flags;
|
||||
++n_streams;
|
||||
}
|
||||
|
||||
lsquic_spi_init_simple(&spi, TAILQ_FIRST(&streams),
|
||||
lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
|
||||
TAILQ_LAST(&streams, lsquic_streams_tailq),
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
|
||||
flags);
|
||||
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
|
||||
STREAM_WRITE_Q_FLAGS, 0, __func__);
|
||||
|
||||
for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
|
||||
stream = lsquic_spi_next(&spi), ++count)
|
||||
{
|
||||
prio = stream->sm_priority;
|
||||
assert(prio >= prev_prio);
|
||||
if (prio > prev_prio)
|
||||
prev_prio = prio;
|
||||
}
|
||||
if (drop_high)
|
||||
lsquic_spi_drop_high(&spi);
|
||||
else
|
||||
lsquic_spi_drop_non_high(&spi);
|
||||
|
||||
assert(count == n_streams);
|
||||
seen_mask = 0;
|
||||
for (stream = lsquic_spi_first(&spi); stream;
|
||||
stream = lsquic_spi_next(&spi))
|
||||
seen_mask |= 1 << (stream - stream_arr);
|
||||
|
||||
lsquic_spi_exhaust_on(&spi);
|
||||
|
||||
for (count = 0, stream = lsquic_spi_first(&spi); stream && count < 3;
|
||||
stream = lsquic_spi_next(&spi), ++count)
|
||||
{
|
||||
assert(stream == stream_arr[5]);
|
||||
assert(stream->sm_priority == 0);
|
||||
}
|
||||
assert(count == 3);
|
||||
|
||||
/* Unsetting of flags should take this stream off for next iteration */
|
||||
stream->stream_flags &= ~flags;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == stream_arr[2]);
|
||||
assert(stream->sm_priority == 1);
|
||||
|
||||
/* Now it should alternate between two streams with priority 1: */
|
||||
for (count = 0, prev_stream = stream;
|
||||
(stream = lsquic_spi_next(&spi)) && count < 10;
|
||||
++count, prev_stream = stream)
|
||||
{
|
||||
assert(stream != prev_stream);
|
||||
assert(stream->sm_priority == 1);
|
||||
assert(stream == stream_arr[2] || stream == stream_arr[4]);
|
||||
}
|
||||
assert(count == 10);
|
||||
|
||||
/* Unset one of them: */
|
||||
stream->stream_flags &= ~flags;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == prev_stream);
|
||||
assert(stream->sm_priority == 1);
|
||||
|
||||
/* Only one left, we should get it back again: */
|
||||
prev_stream = stream;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == prev_stream);
|
||||
assert(stream->sm_priority == 1);
|
||||
|
||||
/* Unset this one, too: */
|
||||
stream->stream_flags &= ~flags;
|
||||
|
||||
/* Next one should have priority 3: */
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == stream_arr[3]);
|
||||
assert(stream->sm_priority == 3);
|
||||
|
||||
/* Run them out: */
|
||||
stream->stream_flags &= ~flags;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == stream_arr[0]);
|
||||
assert(stream->sm_priority == 10);
|
||||
|
||||
stream->stream_flags &= ~flags;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == stream_arr[1]);
|
||||
assert(stream->sm_priority == 101);
|
||||
|
||||
stream->stream_flags &= ~flags;
|
||||
stream = lsquic_spi_next(&spi);
|
||||
assert(stream == NULL); /* The End. */
|
||||
|
||||
while ((stream = TAILQ_FIRST(&streams)))
|
||||
{
|
||||
TAILQ_REMOVE(&streams, stream, next_send_stream);
|
||||
free(stream);
|
||||
if (drop_high)
|
||||
assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask);
|
||||
else
|
||||
assert(test->high_streams == seen_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
@ -355,12 +256,9 @@ main (int argc, char **argv)
|
|||
test_different_priorities(prio);
|
||||
}
|
||||
|
||||
{
|
||||
int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
|
||||
test_different_priorities_filter_odd(prio);
|
||||
}
|
||||
|
||||
test_exhaust();
|
||||
unsigned n;
|
||||
for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n)
|
||||
test_drop(&drop_tests[n]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue