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:
Dmitri Tikhonov 2017-10-31 09:35:58 -04:00
parent 0ae3fccd17
commit c51ce3387f
94 changed files with 4769 additions and 3321 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;">&#160;</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;">&#160;</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;">&#160;</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;">&#160;</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;">&#160;</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;">&#160;</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 -->

View File

@ -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">&#160;&#160;l&#160;&#160;</div></td></tr></table>
</td><td valign="top"><a class="el" href="structlsquic__engine__settings.html">lsquic_engine_settings</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__http__headers.html">lsquic_http_headers</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__out__spec.html">lsquic_out_spec</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__stream__if.html">lsquic_stream_if</a>&#160;&#160;&#160;</td></tr>
<tr><td valign="top"><a class="el" href="structlsquic__http__header.html">lsquic_http_header</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__logger__if.html">lsquic_logger_if</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__packout__mem__if.html">lsquic_packout_mem_if</a>&#160;&#160;&#160;</td><td></td></tr>
<tr><td valign="top"><a class="el" href="structlsquic__engine__api.html">lsquic_engine_api</a>&#160;&#160;&#160;</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>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__logger__if.html">lsquic_logger_if</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__reader.html">lsquic_reader</a>&#160;&#160;&#160;</td></tr>
<tr><td valign="top"><a class="el" href="structlsquic__http__header.html">lsquic_http_header</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__out__spec.html">lsquic_out_spec</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__stream__if.html">lsquic_stream_if</a>&#160;&#160;&#160;</td></tr>
<tr><td valign="top"><a class="el" href="structlsquic__engine__api.html">lsquic_engine_api</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__http__headers.html">lsquic_http_headers</a>&#160;&#160;&#160;</td><td valign="top"><a class="el" href="structlsquic__packout__mem__if.html">lsquic_packout_mem_if</a>&#160;&#160;&#160;</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 -->

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 -->

View File

@ -123,6 +123,8 @@ Data Structures</h2></td></tr>
<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</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">&#160;</td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</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">&#160;</td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</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">&#160;</td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</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&#160;</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&#160;</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">&#160;</td></tr>
<tr class="memitem:a97229544d7aaf6c5dcd5e071613f9c8f"><td class="memItemLeft" align="right" valign="top">size_t&#160;</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">&#160;</td></tr>
<tr class="memitem:a1071b7be4f2f28c5fedf957aa6309f9a"><td class="memItemLeft" align="right" valign="top">ssize_t&#160;</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">&#160;</td></tr>
<tr class="memitem:af5b85bb360eb8316fd663d7c5bc149c9"><td class="memItemLeft" align="right" valign="top">int&#160;</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">&#160;</td></tr>
<tr class="memitem:a715b914c55b5e534cf75713353eb1589"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a715b914c55b5e534cf75713353eb1589"></a>
ssize_t&#160;</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">&#160;</td></tr>
<tr class="memitem:a1700c950ace4e560d225b474a5e44d58"><td class="memItemLeft" align="right" valign="top">int&#160;</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">&#160;</td></tr>
<tr class="memitem:abcf25d8301c4a2796ea13e6e306a33a9"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="abcf25d8301c4a2796ea13e6e306a33a9"></a>
int&#160;</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&#160;</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">&#160;</td></tr>
<tr class="memitem:abcf25d8301c4a2796ea13e6e306a33a9"><td class="memItemLeft" align="right" valign="top">int&#160;</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">&#160;</td></tr>
<tr class="memitem:ae523cf75e48b86f5c4510b429b332acb"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="ae523cf75e48b86f5c4510b429b332acb"></a>
int&#160;</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&#160;</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> *&#160;</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&#160;</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> *&#160;</td>
<td class="paramname"><em>s</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">int&#160;</td>
<td class="paramname"><em>fdSrc</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">off_t&#160;</td>
<td class="paramname"><em>off</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">size_t&#160;</td>
<td class="paramname"><em>size</em>&#160;</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&#160;</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> *&#160;</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> *&#160;</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 *&#160;</td>
<td class="paramname"><em>filename</em>&#160;</td>
<td class="paramtype">struct <a class="el" href="structlsquic__reader.html">lsquic_reader</a> *&#160;</td>
<td class="paramname">&#160;</td>
</tr>
<tr>
<td></td>
@ -1715,7 +1680,13 @@ int&#160;</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 &ndash; <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

View File

@ -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>&#160;<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>&#160;<span class="preprocessor">#ifndef __LSQUIC_TYPES_H__</span></div><div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160;<span class="preprocessor">#define __LSQUIC_TYPES_H__</span></div><div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160;</div><div class="line"><a name="l00010"></a><span class="lineno"> 10</span>&#160;<span class="preprocessor">#include &lt;stdint.h&gt;</span></div><div class="line"><a name="l00011"></a><span class="lineno"> 11</span>&#160;</div><div class="line"><a name="l00015"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#acf675534bad01d31b48d9113feff1bbb"> 15</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00018"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a41d83b8270d6f12d2812203a7614b55f"> 18</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00021"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a7e5d9c467ebef6810d3c5100e4684036"> 21</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00024"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a21c289bcbb4643effba8bb75eeffd8cd"> 24</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00027"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#ad286bcdd799bb3733f1d6568e25c57c6"> 27</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00030"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a4012fdeb11382d691dfe5f025206b8f3"> 30</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00033"></a><span class="lineno"><a class="line" href="lsquic__types_8h.html#a91f399fbcccaf01b47ca209c5c170ba2"> 33</a></span>&#160;<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>&#160;</div><div class="line"><a name="l00035"></a><span class="lineno"> 35</span>&#160;<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>

View File

@ -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']]],

View File

@ -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,'']]]
];

View File

@ -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']]]
];

View File

@ -4,7 +4,7 @@ var indexSectionsWithContent =
1: "l",
2: "l",
3: "l",
4: "eo",
4: "elo",
5: "l",
6: "l",
7: "l",

View File

@ -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']]]
];

View 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>

View 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']]]
];

View 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&#160;Page</span></a></li>
<li class="current"><a href="annotated.html"><span>Data&#160;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&#160;Structures</span></a></li>
<li><a href="classes.html"><span>Data&#160;Structure&#160;Index</span></a></li>
<li><a href="functions.html"><span>Data&#160;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 &lt;<a class="el" href="lsquic_8h_source.html">lsquic.h</a>&gt;</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(*&#160;</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">&#160;</td></tr>
<tr class="memitem:aaf6c91ecaf35ca6faa39dde9ea401f17"><td class="memItemLeft" align="right" valign="top">size_t(*&#160;</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">&#160;</td></tr>
<tr class="memitem:a8720320475c026e839eb86b535b213ff"><td class="memItemLeft" align="right" valign="top"><a class="anchor" id="a8720320475c026e839eb86b535b213ff"></a>
void *&#160;</td><td class="memItemRight" valign="bottom"><b>lsqr_ctx</b></td></tr>
<tr class="separator:a8720320475c026e839eb86b535b213ff"><td class="memSeparator" colspan="2">&#160;</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 &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.11
</small></address>
</body>
</html>

View File

@ -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

View File

@ -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]);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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 *);
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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,
};

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -21,55 +21,95 @@
#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];
static struct stream_rec *
srec_one_posi_first (struct packet_out_srec_iter *posi,
struct lsquic_packet_out *packet_out)
{
if (packet_out->po_srecs.one.sr_frame_types)
return &packet_out->po_srecs.one;
else
return NULL;
}
struct stream_rec *
srec_one_posi_next (struct packet_out_srec_iter *posi)
{
return NULL;
}
struct stream_rec *
srec_arr_posi_next (struct packet_out_srec_iter *posi)
{
while (posi->cur_srec_arr)
{
for (; posi->srec_idx < sizeof(posi->cur_srec_arr->srecs) / sizeof(posi->cur_srec_arr->srecs[0]);
++posi->srec_idx)
{
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 = TAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr);
posi->srec_idx = 0;
}
return NULL;
}
static struct stream_rec *
srec_arr_posi_first (struct packet_out_srec_iter *posi,
struct lsquic_packet_out *packet_out)
{
posi->packet_out = packet_out;
posi->cur_srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr);
posi->srec_idx = 0;
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->packet_out = packet_out;
posi->past_srec = 0;
return posi_next(posi);
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)
{
if (posi->past_srec)
{
while (posi->cur_srec_arr)
{
for (; posi->srec_idx < sizeof(posi->cur_srec_arr->srecs) / sizeof(posi->cur_srec_arr->srecs[0]);
++posi->srec_idx)
{
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->srec_idx = 0;
}
return NULL;
}
else
{
++posi->past_srec;
posi->cur_srec_arr = STAILQ_FIRST(&posi->packet_out->po_srec_arrs);
posi->srec_idx = 0;
if (posi->packet_out->po_srec.sr_frame_types)
return &posi->packet_out->po_srec;
return posi_next(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,25 +152,45 @@ 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;
return 0; /* Insert in first slot */
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)
/* 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]))
last_taken = i;
i = last_taken + 1;
if (i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]))
{
unsigned i;
for (i = 0; i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]); ++i)
if (!srec_taken(&srec_arr->srecs[i]))
{
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;
return 0; /* Insert in existing srec */
}
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);
@ -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,11 +261,15 @@ 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);
lsquic_malo_put(srec_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,
@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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)
{

View File

@ -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,
};

View File

@ -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);
}

View File

@ -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

View File

@ -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,22 +1015,13 @@ 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
&& lsquic_packet_out_avail(packet_out) >= need_at_least)
{
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)
{
return packet_out;
}
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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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,
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)
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, 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,27 +65,15 @@ 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);
++count;
if (stream == last)
break;
stream = NEXT_STREAM(stream, next_ptr_offset);
}
while (1)
{
add_stream_to_spi(iter, stream);
++count;
if (stream == last)
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);
}

View File

@ -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

View File

@ -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

View File

@ -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,19 +243,33 @@ 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);
}
lsquic_stream_shutdown(stream, 1);
lsquic_stream_wantread(stream, 1);
}
else
{
@ -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);
}

View File

@ -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"

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -444,6 +444,7 @@ test_ack_truncation (void)
int
main (void)
{
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
test1();
test2();
test3();

View File

@ -444,6 +444,7 @@ test_ack_truncation (void)
int
main (void)
{
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
test1();
test2();
test3();

View File

@ -443,6 +443,7 @@ test_ack_truncation (void)
int
main (void)
{
lsquic_global_init(LSQUIC_GLOBAL_SERVER);
test1();
test2();
test3();

View File

@ -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));

View File

@ -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[] =
{

View File

@ -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,

View File

@ -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);
/*

View File

@ -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]);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
TAILQ_INIT(&streams);
for (n = 0; n < test->n_infos; ++n)
TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream);
assert(count < n_streams);
lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
STREAM_WRITE_Q_FLAGS, 0, __func__);
while ((stream = TAILQ_FIRST(&streams)))
{
TAILQ_REMOVE(&streams, stream, next_send_stream);
free(stream);
if (drop_high)
lsquic_spi_drop_high(&spi);
else
lsquic_spi_drop_non_high(&spi);
seen_mask = 0;
for (stream = lsquic_spi_first(&spi); stream;
stream = lsquic_spi_next(&spi))
seen_mask |= 1 << (stream - stream_arr);
if (drop_high)
assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask);
else
assert(test->high_streams == seen_mask);
}
}
/* 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 ( ; *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),
TAILQ_LAST(&streams, lsquic_streams_tailq),
(uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
flags);
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;
}
assert(count == n_streams);
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);
}
}
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