You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2021/07/30 00:33:23 UTC
[trafficserver] branch master updated: Merge quic-latest into
master (#8010)
This is an automated email from the ASF dual-hosted git repository.
maskit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 9590447 Merge quic-latest into master (#8010)
9590447 is described below
commit 95904475eaaaa1af4b3566dd6e3fb80256d842e6
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Fri Jul 30 09:33:15 2021 +0900
Merge quic-latest into master (#8010)
Squashed commit of the following:
commit d232a12ec5ae461235f4a4d6f7c7644d05651aed
Merge: 837bd0e41 2edeae477
Author: Masakazu Kitajo <ma...@apache.org>
Date: Tue Jun 29 15:41:34 2021 +0900
Merge branch 'master' into quic-latest
* master:
reuse multiple times (#7992)
Test bad request behavior (#7884)
Fix BoringSSL build (#8001)
Update TSHttpTxnAborted API to distinguish client/server aborts (#7901)
Enforce case for well known methods (#7886)
Add null checks for http_load (#7995)
commit 837bd0e413c27b4f2132864c9a0a377a45fabaf5
Author: Masakazu Kitajo <ma...@apache.org>
Date: Mon Jun 28 15:11:03 2021 +0900
Fix unit tests for QUICStreamState
commit c5bb9e0dd41cba2198c5632f85f89f9b343eee34
Merge: 0a63fa977 202b2505c
Author: Masakazu Kitajo <ma...@apache.org>
Date: Mon Jun 28 10:02:54 2021 +0900
Merge branch 'master' into quic-latest
* master:
Implement TLSBasicSupport for QUICNetVC (#7959)
Reload server session inactivity timeout before placing a session into the pool (#7618)
Use OpeSSL EVP API if SHA1 API is unavailable (cache_promote) (#7447)
Cleanup: Get rid of HTTP2_SESSION_EVENT_RECV (#7879)
Timing and permissions update for regex_revalidate test (#7998)
limit m_current_range to max value in RangeTransform (#4843)
Allow to TLS handshake to error out on TSVConnReenable (#7994)
Cleanup: Get rid of HTTP2_SESSION_EVENT_INIT (#7878)
Add hook for loading certificate and key data from plugin (#6609)
Doc: Now's Minute invocation error (#7990)
Fix typo in configure.ac (#7993)
commit 0a63fa977f97919143f45508f1f6c5b656324d80
Merge: 312cf393c bd93f2a40
Author: Masakazu Kitajo <ma...@apache.org>
Date: Fri Jun 25 14:34:55 2021 +0900
Merge branch 'master' into quic-latest
* master:
Don't rely on SSLNetVC when HttpSM gathers info about SSL (#7961)
conf_remap: demote 'Invalid configuration' to warning (#7991)
Cleans up the code bit, including milliseconds consistency (#7989)
Pass through expect header and handle 100-continue response (#7962)
Treat TRACE with body as bad request (#7905)
Thread safe Mersenne Twister 64 using c++11 (#7859)
ESI plugin documentation updates. (#7970)
Add log name configuration and stderr/stdout support. (#7937)
Cleanup: Constify MIMEHdr (#7949)
Fixed compile error with Linux AIO unit test (#7958)
Note YAML parser library bug, and work-around, in documentation. (#7963)
Ensure that the content-length value is only digits (#7964)
String the url fragment for outgoing requests (#7966)
Fix for HTTP/2 frames (#7965)
Improve parsing error messages for strategies.yaml. (#7948)
fix the scheme of h2 0rtt tests (#7957)
Fix double test flakiness due to EOS/TXN_CLOSE race (#7956)
Use proxy.config.log.hostname for rotated log filenames (#7943)
Fixed memory leak in the QUIC stream manager (#7951)
Fixup TS_USE_LINUX_NATIVE_AIO AIO_MODE_NATIVE (#7832)
Update GitHub stale action to auto close old PRs (#7952)
Revert "Do not invalidate cached resources upon error responses to unsafe methods (#7864)" (#7954)
regex_revalidate: add stats for miss/stale counts (#7950)
Do not invalidate cached resources upon error responses to unsafe methods (#7864)
Add an HTTP/2 304 "Not Modified" AuTest. (#7882)
regex_revalidate: optionally retain rule epoch state across restarts (#7939)
Fixed memory leak in QUIC ack frame unit test (#7947)
cache_promote: Don't promote on uncacheable requests (#7942)
Fix dynamic-stack-buffer-overflow of cachekey plugin (#7945)
Compilation error fixes for QUIC unit tests (#7944)
Adds bytes counting as a trigger to the cache_promote LRU (#7765)
Add a JSON schema for strategies.yaml (#7932)
Remove second call to TRANSACT_RETURN while handling cache write lock (#7873)
Close connection after every bad request for HTTP/1.1 (#7885)
Pin Sphinx to 3.x to unblock `make html` (#7940)
Add support for Remap rule hit stats (#7936)
Remove scrap log object dead code (#7935)
Add STL forward iterators to DLL container. (#7934)
Add log SQUID code testing to redirect.test.py Au test. (#7870)
Fix race condition on server session state (#7921)
regex_reval: bug where rule type is always reported as the first (#7928)
Remove duplicate entry in overridable txn vars. (#7930)
Satisfy ci/jenkins/bin/clang-format.sh (#7929)
Add a basic Au test using strategies.yaml, with consistent hashing. (#7911)
Add a chunked negative revalidating test. (#7907)
Ensure that URL components are valid when alternate eviction is logged (#7924)
fix grammar (#7927)
AuTest: Enable h2spec generic test cases (#7926)
Adjust vc read errors (#7923)
Remove bucket search from IntrusiveHashMap::erase (#7848)
Ensure TS_VCONN_CLOSE_HOOK hook is called during TS_EVENT_VCONN_CLOSE. (#7913)
Update docs languages file to add 9.1.x for en and ja (#7917)
* Adds a new peering ring mode to next hop selection strategies. (#7897)
Add Au test for strategies.yaml, with consistent hashing, with fallover. (#7914)
Make HttpSM server reference a Transaction instead of a Session (#7849)
Set accept_options of Http1Transaction in Http1ClientSession::new_connection() (#7894)
Reset Http1Transaction before adding vc to keep_alive_queue (#7892)
Add dead server policy control and metric. Improve messages. (#7757)
Ensure the HTTP protion of the protocol string is upper case (#7904)
Fixed spelling mistakes in the docs (#7896)
add MISS capability to the regex_revalidate plugin (#7899)
docs: fix capitalization of Linux (#7898)
Redirect - Make TS to honour the number_of_redirections configuration value (#7867)
Clean up producer more regularly (#7386)
Fix crash in open_close_h2 (#7586)
Cleanup Http2ClientSession SessionHandler (#7876)
Enforce HTTP parsing restrictions on HTTP versions supported (#7875)
Do not delete the continuation twice (#7862)
Cleanup: refer Http2ClientSession::mutex (#7853)
Autest - Proxy Verifier Extension, add context template $-base string substitution in the replay file. (#7866)
Fixed some spelling mistakes in comments (#7869)
Fixed ASAN issues with MMH test (#7868)
Cleanup: Move member functions defined inside of class definitions of Http2ConnectionState & Http2ConnectionSettings (#7854)
Add URI Signing cdnistd Claim Implementation (#7822)
Adds a new --enable-all-asserts configure option (#7858)
Unifdef test code for MMH and moved it into its own test file (#7841)
Clean up lua plugin doc for overridable configurations (#7844)
Save and propagate epoll network error (#7809)
Add method to write an IpAddr value to a sockaddr. (#7821)
Add proxy.config.http.max_proxy_cycles (#7657)
Update NextHop strategies so that unavailable server retry codes (#7837)
generator: allow for POST requests (#7635)
Fixed double declaration types for log buffer tracking (#7847)
Extra braces for clang 5 / ubuntu 16.04 on array initialization (#7842)
Conflicts:
iocore/net/quic/QUICStreamFactory.cc
commit 312cf393c170bbf1ee6c945907868137197afdfa
Merge: f90e8dde9 5cdc1459f
Author: Masakazu Kitajo <ma...@apache.org>
Date: Mon May 17 10:07:42 2021 +0900
Merge branch 'master' into quic-latest
* master:
Get rid of code for OpenSSL that has old QUIC API (#7599)
Fixed warning in gcc 11 about array not being initalized (#7840)
Don't call next next dup on destroyed mime field mloc. (#7833)
build_h3_tools: use OpenSSL_1_1_1k+quic (#7836)
Address assert on captive_action (#7807)
Fix so EOS are delivered to sessions in the pool (#7828)
Fix a format specifier for size_t (#7830)
Fix stall on sending response for request with trailer header (#7831)
Simplification dir_init_done (#7817)
Remove unused member from HttpSM (#7835)
AuTest: use exteneded help output to determin curl feature support (#7834)
Apply fmt compile time argument checking to log functions (#7829)
Adds new X-Cache-Info header to the xdebug plugin (#7784)
Cleanup: Remove unused members of Http2Stream (#7813)
Cleanup: unused functions of Http2ClientSession (#7812)
Cancel cross_thread_event on clear_io_events (#7815)
Cleanup: Remove a meaningless Http2Stream::do_io_close() call (#7814)
Eliminate next dup call using stale mime field mloc is s3_auth plugin. (#7825)
NetEvent cleanup - replace #define with constexpr (#7804)
fix origin session related crashes (#7808)
Update HTTP version info in HostDB on new outbound connection (#7816)
Remove a redundant argument (#7811)
SSL Cert lookup using PP dest ip when ProxyProtocol is enabled (#7802)
Fix MLoc assert caused by s3auth (#7790)
Fix cpu utilization problem in session cache (#7719)
Fix to cookie_remap.cc tp avoid Intel compiler warning. (#7792)
TSHttpTxnCacheDiskPathGet - tighten up the code a bit. (#7806)
Doc: tcpinfo plugin table formatting (#7805)
fix DNS spike issue for TCP_RETRY mode (#7307)
Adds new TS API TSHttpTxnCacheDiskPathGet (#7783)
tests: Fixes spelling (#7789)
Traffic Dump: Add an HTTP/3 AuTest (#7758)
use sendmsg and recvmsg (#7793)
HTTP: clean up the http_hdr_describe format error (#7797)
Fixes an issue where next hop unit tests crash when run on macOS. (#7787)
Apply log throttling to HTTP/2 session error rate messages (#7772)
Cleans up uninitialized warning in LogMessage.cc (#7788)
Short circuit remap reload when a valid remap file is not specified (#7782)
DNS: Clean up argument passing to DNS queries. (#7778)
Remove extra verify-callback (#7540)
Augment test cases for tls_verify_override test (#7736)
Make when_to_revalidate setting available on HTTPS (#7753)
Add traffic_server command line option for debugging in Au test. (#7762)
Test: Update tls_partial_blind_tunnel to have a nameserver. (#7773)
Test: update tls_forward_nonhttp to have a nameserver. (#7774)
Test: add nameserver to log-filter test. (#7776)
BWF: Add support for std::error_code. (#7777)
Test: add nameserver to log-field test. (#7779)
Test: add nameserver to regex_remap test. (#7775)
Elevate privileges for traffic_manager during SSL cert reload (#7770)
Clean up HTTP version processing (#7766)
Remove proxy.config.http.down_server.abort_threshold (#7748)
Remove undocumented keepalive_internal_vc setting (#7693)
doc: header_rewrite random function not inclusive (#7760)
Experimental Cache fill plugin (#7470)
Remove references to removed options (#7756)
Propagate TLS errors (#7714)
AuTest extension: check for unrecognized configurations (#7752)
Fixes errors in the strategies.yaml documentation. (#7745)
Updates to Nexthop strategies to limit the number of simultaneous (#7744)
Fixes Issue #7739 - Next hop strategy with bad 'to' URL causes TS crash. (#7749)
header_rewrite: Various fixes for MaxMind support (#7746)
Remove unused variable is_revalidation_necessary (#7747)
Fix simple remapping in regex_remap plugin. (#7718)
Adding DNS TTL AuTests. (#7742)
Add a chunked disabled test. (#7743)
Fix monitor threads in lib records to exit on system shutdown. (#7731)
Add overload for memcpy to take a destination buffer and source string_view / TextView (#7732)
Test: Add nameserver to TLS tunnel forward test. (#7733)
AIO_NOT_IN_PROGRESS should not be 0 (#7734)
if transaction status non-success, bypass intercept plugin (#7724)
ink_utf8_to_latin1 is not defined, removing declaration (#7737)
Fix build on FreeBSD 13 (#7730)
Update VSCode CPP Standard (#7723)
Updating to use Proxy Verifier 2.2.0 (#7729)
header_rewrite: Allow for relative path to geo database files (#7727)
Override proxy.config.ssl.client.sni_policy from sni.yaml (#7703)
compress.test.py: Reference config file from Test.RunDirectory (#7725)
Ran clang-tidy over the code (#7708)
Deny unknown transfer encoding values (#7694)
Fix doc for http2.no_activity_timeout_in (#7721)
Add DynamicStats (#7704)
header_rewrite: allow for use of maxminddb as source of geo truth (#7695)
Include in parentselectdefs.h in install target (#7713)
uri_signing: fix warning which affects ubuntu:20.04 builds (#7717)
Increase the maximum slice block size from 32MB to 128MB (#7709)
commit f90e8dde99564ff4270f2ae63e8592b0948b6130
Author: Masakazu Kitajo <ma...@apache.org>
Date: Tue Jan 12 12:21:51 2021 +0900
Add QUICStreamStateListener
commit f66646cb1907f7079eaf41aa81da9705934eff18
Merge: be9837c03 9f9594fd3
Author: Masakazu Kitajo <ma...@apache.org>
Date: Sat Apr 17 13:57:50 2021 +0900
Merge branch 'master' into quic-latest
* master:
Fix ALPN support on QUIC connections (#7593)
fix mem leak in session cache (#7707)
Parent Select Plugin (#7467)
Add new TS API function TSUrlRawPortGet. (#7568)
Add NixOS support (#7697)
Remove support for --enable-remote-cov-commit (#7700)
Remove configure-time loopback interface detection (#7702)
Add sqpv log field for server protocol (#7680)
Call do_io_close instead of HTTP2_SESSION_EVENT_FINI handler (#7594)
Fix a bug in tspush that pushes corrupted content to cache (#7696)
Automatically marks PRs and issues stale (#7675)
New rate_limit plugin for simple resource limitations (#7623)
Remove undefined method HttpSM::perform_nca_cache_action (#7692)
Remove undefined method HttpSM::setup_client_header_nca (#7691)
Scalar; Move "tag" struct to be inside the "ts" namespace to avoid collisions. (#7690)
Rollback LAZY_BUF_ALLOC remove in HttpTunnel (#7583)
Add class to normalize handling of pending action (#7667)
Make HTTP/2 Curl AuTest gold files case insensitive (#7683)
Add STL compliant field iteration to MIMEHdr. - rebase. (#7476)
Fix use of -mcx16 flag - only use if it compiles cleanly. (#7684)
Refine connection failure logging and messages and eliminate suprious connection errors (#7580)
Add close header normalize openclose test (#7679)
Fix has_consumer_besides_client to deal with no clients (#7685)
create a new cache status RWW_HIT (#7670)
Updating to AuTest 1.10.0 (#7682)
sslheaders AuTest: Skip if plugin does not exist (#7678)
Add AuTest for Background Fill (#7613)
Do NOT kill tunnel if it has any consumer besides HT_HTTP_CLIENT (#7641)
AuTest: address various permissions issues (#7668)
Adding TCP Info header support to header rewrite (#7516)
Refine Inline.cc carveout for arm64 darwin builds (#7662)
Comment why log eviction isn't implemented via a log field. (#7648)
Fixing Throttler.h for older clang and gcc compilers (#7651)
Update -with-profile and add some profiling documentation (#7601)
Use correct default value for verify.server.policy (#7636)
Update server_response_body_bytes when background fill worked (#7621)
Remove erroneous manager.log mesg with remap include file reload (#7646)
Change ROUNDUP from function-like macro to function template. (#7614)
Document http.default_buffer_water_mark (#7612)
Add proxy.config.cache.log.alternate.eviction (#7629)
Fix HttpSessionManager::acquireSession from previous rebase error (#7631)
Fix tls_client_versions and tls_hooks18 tests (#7645)
Updating documentation for negative_revalidating_lifetime (#7633)
Remove reference to client.verify.server from tests and other bits (#7639)
Add pooled_server_connections metric (#7627)
Expose URL element methods through HTTPHdr (#7628)
Add default implementation for allow_half_open (#7630)
Add thread yeield to avoid busy waiting in LogObject::_checkout_write(). (#7576)
Add proxy.process.http.background_fill_total_count (#7625)
statichit: misc. fixes (#7634)
Remove unused variables (#7626)
Adding negative revalidating AuTests. (#7620)
Add failed state to hostdb to better track failing origins (#7291)
Use standard isdigit library function (#7619)
Typo in output when forcing kqueue for configure (#7617)
Implement log throttling (#7279)
Increase Proxy Verifier caching delay. (#7616)
Set pcre_malloc/free function pointers in core main() only. (#7608)
commit be9837c03219f2cb9efbd4981d13dbc78294ce51
Merge: 99ff68fa3 d4fc16f64
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Mar 17 09:38:59 2021 +0900
Merge branch 'master' into quic-latest
* master:
Fix the connection limit crash while using parents (#7604)
Remove inline for detail::cache::CacheData::idAddr (#7592)
Remove UnixNetVConnection::startEvent - not actually called. (#7596)
Use return values to fix ubuntu release build error (#7591)
Fix double destuct on Http2Stream termination (#7600)
Add pointer/reference upcast function that is checked in debug builds. (#7582)
Call constructors and destructors for H1/2 Session/Transaction via ClassAllocator (#7584)
Add gold test for remap config .include directive. (#7589)
Change the default value for verify.server.policy (#7587)
Build the test library for tls_engine consistently (#7588)
Generalize ALPN logic (#7555)
Fix the final consumer write size from unchunked to chunked tunnel (#7577)
Reactivate accept_no_activity_timeout (#7408)
Tidy up session/transaction destruction process (#7571)
Remove ProxyTransaction::set_proxy_ssn (#7567)
Introduce TLSBasicSupport interface (#7556)
Cleanup: Rename IOBufferReader of Http2ClientSession (#7569)
Add a check for compress response, if from server and 304, then check cache for headers instead of the 304 response (#7564)
Updates the STATUS file with all recent releases (#7566)
Make Allocator.h less silly (no creepy "proto" object). (#6241)
Cleanup: Remove unused member of Http2ClientSession (#7570)
enable origin server session cache by default (#7537)
Add tscontdestroy when transaction is closed and pacing rate is reset (#7572)
Remove reference to CoreUtils (#7557)
Remove unused enums from YamlSNIConfig struct. (#7565)
Removes deprecated sni.yaml option: disable_h2 (#7547)
This PR updates parent selection to limit the number of simultaneous (#7485)
Fix KA header not checking strategy (#7483)
Get rid of kruft LogObject copy constructor. (#7553)
For TSHttpHdrEffectiveUrlBufGet(), include scheme for request to server URL. (#7545)
Adding lower_ support to stats and bonding_slave data points for port status (#7560)
Change cookie_remap plugin to allow use of pre-remap URL (and components). (#7519)
check verify policy and properties (#7559)
Fix parent.config to 504 not 502 on timeout (#7558)
use SSL_CTX address as part of the lookup key (#7552)
Add ALPN support on TLS Partial Blind Tunnel (#7511)
Add server_name option to proxy.config.ssl.client.sni_policy (#7533)
Fix a crash on origin session reuse (#7543)
Removes the test plugins from the .spec file / RPM (#7551)
Convert the inactive_client_timeout test to use Proxy Verifier (#7535)
Fix ja3_fingerprint configure syntax (#7550)
Fix asserts in multiplexer plugin. (#7532)
parse expiration time and reload config at time out (#7281)
Fix origin_session_reuse test (#7542)
Fix tls_session_reuse test (#7541)
Split SSL_CTX initialization logic into small functions (#7434)
Remove dependency for SSL stuff from P_Net.h (#7531)
Unify all the connect timeouts into one (#7335)
Fix lua_states_stats Au test. (#7232)
origin session reuse (#7479)
Updating to use Proxy Verifier 2.1.0 (#7534)
update the session reuse tests (#7529)
commit 99ff68fa395a6e3f8ab2e27e98049ceb00a0a7c8
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Feb 17 11:14:40 2021 +0900
Fix link error
commit c4ad0c071d53fb888d8b2ffac34b848524f4fe68
Merge: c40d95a91 cd33010ff
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Feb 17 09:56:25 2021 +0900
Merge branch 'master' into quic-latest
* master:
Select lua context per thread (#7465)
Fix out of bounds access error in jtest (#7526)
Disable compiling Inline.cc on macOS (#7389)
Makes sure the types are correct, avoiding compiler warnings (#7523)
Move has_request_body to ProxyTransaction (#7499)
Make the H3 build script work properly on Debian platforms (#7522)
slice/handleFirstServerHeader: return sooner on requested range errors (#7486)
Add new log field for negotiated ALPN Protocol ID with the client (#7491)
Add Outbound PROXY Protocol (v1/v2) Support (#7446)
Updates the Dockerfile for debian (#7518)
Disable client inactivity timeout while server is processing POST request (#7309)
Upgrade Catch.hpp to v2.13.4 (#7464)
Move reopen_moved_log_files to log flushing thread (#7450)
replace psutil.pid() with psutil.process_iter() for safer execution (#7515)
Fix spacing in clang-analyzer.sh script (#7480)
Fix out of bounds access error in ats_base64_decode (#7490)
Updated to build lastest versions of Fedora and CentOS docker images (#7505)
Fix QUIC unit tests build issue on GNU ld (#7496)
Fix QUIC unit test failures (#7497)
Fixed build issues with Fedora 34 (#7506)
Fixing DNS local_ipv* config option (#7507)
traffic_dump: AuTests to use Proxy Verifier. (#7502)
Disable ja3 plugin when building with boringssl (#7500)
Avoid -Warray-bounds on PROXY Protocol Builder (#7488)
AuTest: Upgrade to Proxy Verifier 2.0.2 (#7493)
fix certs (#7494)
Add zlib1g-dev to Debian dependencies in README (#7495)
Unit Test - Increase openssl's key size. Place test certs into a common test folder. (#7451)
Add basic type aliases for std::chrono types to ink_time.h for future use. (#7482)
traffic_ctl - Fix lookup key for run-root option (#7484)
update thread config tests (#7370)
Perf: Replace casecmp with memcmp in HPACK static table lookup (#6521)
Add PROXY Protocol Builder (#7445)
Adjust so transfer-encoding header can be treated hop-by-hop (#7473)
Convert auxkey form 2 uint32_t to 1 uint64_t. (#7350)
Remove the queuing option from proxy.config.http.per_server.connection (#7302)
Remove unused function ink_microseconds. (#7481)
use std::unordered_map to store sessions (#7405)
drop use of BIO_f_base64 and EVP_PKEY_new_mac_key (#7106)
Do not write to the cache if the plugin decides not to write to the cache (#7461)
API to retrieve NoStore set by plugins (#7439)
Update AuTest version update directions for pipenv (#7469)
Add command line utility to help convert remap plugin usage to ATS9. (#7426)
Cleanup: Get rid of MIMEFieldWrapper from HPACK encoding (#6520)
Proxy Verifier: Making use of delay directives for caching tests. (#7468)
Cleanup: Add SNIRoutingType (#7453)
Updating to Proxy Verifier v2.0.0 (#7454)
Adjust to actually try a server address more than once (#7288)
Change atoi to atol, causing obvious issues on what needs to be int64's (#7466)
Cleans up duplicated TSOutboundConnectionMatchType definition (#7090)
Fixing compress expectation for new microserver (#7463)
Update to the new MicroServer 1.0.6 release (#7460)
CacheRead: clear dir entry if doc is found to be truncated (#7064)
Do not provide a stale negative cache (#7422)
Generalize SNI support (#6870)
Add synchronization between UDPNetProcessor::UDPBind in main Thread and initialize_thread_for_udp_net in ET_UDP Thread (#7407)
Fix heap use after free in DNSProcessor::getby() (#3871)
Fix comment in include/tscore/Filenames.h. (#7457)
Fix Makefile target for creating changelogs (#7455)
Change squid log code for self looping (#7443)
Enhancements for compress plugin (#7416)
Add incoming PROXY Protocol v2 support (#7340)
Cleanup: Remove unused members of NextHopProperty (#7436)
Small fix to regex_remap PR # 7347. (#7437)
PoolableSession (#6828)
option to disable compression for range request's response (#7287)
Make TSUrlSchemeGet() return scheme implied by URL type when there is no explicit scheme. (#7262)
commit c40d95a912166224e517b07d6dc3ffd273907fc9
Merge: 573035c60 ecd70df36
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Jan 20 09:39:34 2021 +0900
Merge branch 'master' into quic-latest
* master:
Fix a link error on traffi_quic command (#7433)
Fix stall on outbound TLS handshake (#7432)
Fix the Proxy Verifier AuTest extension to handle cert paths correctly (#7415)
Update documentation for TSSslSessionInsert (#7420)
Improve zlib detection logic (#7430)
Fix parent connect fail segfault (#7429)
commit 573035c606fa088349420de35f0cdabe38649f5e
Merge: 5704095ba 95b8d575a
Author: Masakazu Kitajo <ma...@apache.org>
Date: Fri Jan 15 23:24:29 2021 +0900
Merge branch 'master' into quic-latest
* master:
Doc: Fix typo in negative_revalidating_lifetime (#7427)
Change comment handling for long lines in url_sig plugin (#7421)
Add unit tests for PROXY Protocol v1 parser (#7332)
LGTM: Remove superfluous const qualifier in return type (#7412)
Fix issue with unavailable server retry codes (#7410)
Remove the warning statement (#7414)
default to throttling and subsequently simplify the transfer code (#7257)
Improvement to lua plugin (#7413)
Make places to bind/unbind SSL object with/from NetVC (#7399)
traffic_ctl - plugin msg now require only the tag as mandatory field data field is now optional. (#7364)
API - Add new api function TSHttpTxnServerSsnTransactionCount() to retrieve the number of transactions between TS proxy and the origin server from a single session. (#7387)
Fix clang compiler complaint about an unused parameter in SNIAction. (#7409)
Add compression support to stats_over_http (#7393)
Doc: Fix INPUT tag of Doxyfile (#7404)
Remove unneeded variables in UnixNetVConnection (#7403)
Correctly pass back errno to HttpSM (#7402)
Reverting to old negative_caching conditional behavior (#7401)
Remove unused MAYBE_ABORT state (#7400)
traffic_manager should not retry on disk failure (#7397)
Eliminate dangling pointer into stack space. (#7392)
This PR aims to address some of the lock contention found and (#7377)
Remove a special treatment for SSLNetVC in migrateToCurrentThread() (#7384)
Replace ::exit() with _exit() to avoid secondary cleanup cores (#7395)
[Doc] Fix build warnings (#7391)
Clear call_sm on tunnel reset (#7352)
Unused code: HostDBContinuation::removeEvent (#7383)
Traffic Dump: Fix stream-id printing after first transaction. (#7311)
Add comments to ink_queue.h. (#7376)
Cleanup incoming PROXY Protocol v1 (#7331)
In CI, only run autopep8 on branches that enforce autopep8 (#7270)
Fix FreeBSD 12 link issue in test_libhttp2. (#7367)
Adjust flags to ensure tunnel producer is cleaned up (#7336)
Cleanup: Remove SSL Wire Trace releated code in UnixNetVConnection (#7368)
Use EVP MAC API if available (#7363)
Use EVP API instead of MD5_Init/Update/Final (secure_link plugin) (#7355)
Use ERR_get_error_all if available (#7354)
Use OpeSSL EVP API instead of SHA256_Init/Update/Final (#7342)
Cleanup: Get rid of NetVConnection::outstanding() (#7366)
Cleanup: Remove unused functions (#7365)
Add a post case to the conn_timeout test (#7334)
Fix sni ip_allow and host_sni_policy (#7349)
AuTest for Split DNS (#7325)
Make reloading client certificate configuration more reliable (#7313)
Add negative caching tests and fixes. (#7361)
ESI: Ensure gzip header is always initialized (#7360)
Allow for regex_remap of pristine URL. (#7347)
Set thread mutex to the DNSHandler mutex of SplitDNS (#7321)
Fix lookup split dns rule with fast path (#7320)
Add note to background fetch about include/exclude (#7343)
AuTest for incoming PROXY Protocol v1 (#7326)
Fix vc close migration race condition (#7337)
TLS Session Reuse: Downgrade add_session messages to debug (#7345)
TLS Session Reuse: Downgrade noisy log to debug (#7344)
Remove the last remnants of the enable_url_expandomatic (#7276)
Remove unnecessary cast from ReverseProxy. (#7329)
Updates the Dockerfile with more packages (#7323)
fixup in HttpSM to only set [TS_MILESTONE_SERVER_CLOSE if TS_MILESTONE_SERVER_CONNECT has been set (#7259)
Add option for hybrid global and thread session pools (#6978)
Get appropriate locks on SSN_START hook delays (#7295)
s3_auth: demote noisy errors around configuration that doesn't affect plugin usability (#7306)
Follow the comments in I_Thread.h, add an independent ink_thread_key for EThread. (#6288)
Reduce the number of write operation on H2 (#7282)
commit 5704095ba63316e672d9fae67d2757fff084e03c
Merge: 882a79d87 0c88b24a0
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Oct 28 21:06:11 2020 +0900
Merge branch 'master' into quic-latest
* master:
Adds a shell script to help build the H3 toolchains (#7299)
Remove unfinished h2c support (#7286)
Allow disabling SO_MARK and IP_TOS usage (#7292)
Enable all h2spec test (#7289)
Fix bad HTTP/2 post client causing stuck HttpSM (#7237)
Sticky server does not work with H2 client (#7261)
7096: Synchronize Server Session Management and Network I/O (#7278)
HostDB: remove unused field in HostDBApplicationInfo, and update remaining types in http_data to fix broken padding. (#7264)
Add support for a new (TSMgmtDataTypeGet) mgmt API function to retrieve the record data type (#7221)
Fix example in default sni.yaml configuration. (#7277)
Fix proxy.process.http.current_client_transactions (#7258)
Add AuTest for HTTP/2 Graceful Shutdown (#7271)
Fix truncated reponse on HTTP/2 graceful shutdown (#7267)
url_sig add 'ignore_expiry = true' option for log replay testing (#7231)
Respecting default rolling_enabled in plugins. (#7275)
gracefully handle TSReleaseAsserts in statichit and generator plugins (#7269)
Removes commented out code from esi plugin (#7273)
Allow initial // in request targets. (#7266)
Document external log rotation support via SIGUSR2 (#7265)
Let Dedicated EThreads use `EThread::schedule` (#7228)
HostDB: Fix cache data version checking to use full version, not major version. (#7263)
Bugfix: set a default inactivity timeout only if a read or write I/O operation was set (#7226)
Treat objects with negative max-age CC directives as stale. (#7260)
Remove some usless defines, which just obsfucates code (#7252)
Remove useless if for port set assertion. (#7250)
Fix test_error_page_selection memory leaks and logic errors (#7248)
[multiplexer] option to skip post/put requests (#7233)
Incorporates the latest CI build changes (#7251)
Add support for server protocol stack API (#7239)
Fix for plugins ASAN suppression file (#7249)
RolledLogDeleter: do not sort on each candidate consideration. (#7243)
Make double Au test more reliable. (#7216)
Ensure that ca override does not get lost (#7219)
Stop crash on disk failure (#7218)
Do not cache Transfer-Encoding header (#7234)
clean up body factory tests (#7236)
Revert "Create an explicit runroot.yaml for AuTests (#7177)" (#7235)
New option to dead server to not retry during dead period (#7142)
Increment ssl_error_syscall only if not EOF (#7225)
Fix renamed setting in default config (#7224)
Log config reload: use new config for initialization (#7215)
Introduce proxy-verifier to AuTests (#7211)
Follow redirection responses when refreshing stale cache objects. (#7213)
Create an explicit runroot.yaml for AuTests (#7177)
Support external log rotation tools via SIGUSR2 (#6806)
Add support for TS API for Note, Status, Warning, Alert (#7208)
If the weight is 0, the SRV record should be selected from the highest priority group (#7206)
Cleanup: remove unnecessary memset() within dns_process() (#7209)
Docs cleanup (#7210)
Strip whitespaces after field-name and before the colon in headers from the origin (#7202)
Adds new plugin: statichit (#7173)
Add duplicate header field processing when creating outgoing response (#7207)
commit 882a79d87126a27482b2d1dc5a172ef042acad6b
Merge: 2a9887f4c bb5c39086
Author: Masakazu Kitajo <ma...@apache.org>
Date: Fri Sep 18 10:01:14 2020 +0900
Merge branch 'master' into quic-latest
* master:
Rename ambiguous log variable (#7199)
KWF useless member function HttpSM::kill_this_async_hook(). (#7198)
Fix the active_timeout test to work without quic enabled (#7197)
Remove obsolete cdn_ HttpTransact vars (#7182)
Remove unused HttpUpdate mechanism (#7194)
Updates the list of supported / linked Docs versions (#7152)
Make custom xdebug HTTP header name available to other plugins. (#7193)
Update sni outbound policy to allow directly setting the outbound SNI. (#7188)
commit 2a9887f4c4c5a9259cdd64bf24c76b1618d78d29
Author: Masakazu Kitajo <ma...@apache.org>
Date: Wed Sep 16 17:54:01 2020 +0900
Avoid unnecessary QUIC CID randomization
commit 42e8898aafbdb8f17fefb1da99d7ae7cdc019a19
Author: Masakazu Kitajo <ma...@apache.org>
Date: Tue Sep 15 12:41:28 2020 +0900
Simplify interface between H3 and QUIC, and remove memcopy between them
commit 112fc71a324397a590c1cad6a4b2cfed27a551c2
Merge: ac31adaa8 b09096481
Author: Masakazu Kitajo <ma...@apache.org>
Date: Tue Sep 15 09:21:25 2020 +0900
Merge branch 'master' into quic-latest
* master:
Add an autest testcase for HTTP3 (#7063)
Fix TSHttpTxnServerPacket* API's to correctly update existing server connections (#7175)
Do not lose original inactivity timeout on disable (#7134)
Emits log when OCSP fails to connect to server (#7183)
autopep8: avoid running on non-tracked files. (#7186)
TextView: Add additional constructor tests. (#7189)
Remove duplicate code (#7180)
TextView: add constructor size values to enable strlen even for null pointers. (#7185)
Add virtual destructor to QUICRTTProvider. (#7184)
AuTest: Reuse venv if it exists already (#7178)
TS_API for Note,Status,Warning,Alert,Fatal (#7181)
Traffic Dump: Record HTTP/2 priority. (#7149)
leaks in logs (#7172)
Additions to enable loading qat_engine (#7150)
Removes references to non-existent function handle_conditional_headers (#7162)
Fix #7164 Chaning Warning to Debug and creating a stat for inserting duplicates to pending dns (#7166)
Fix #7167, make autopep8 failure (#7168)
MicroDNS Extension: handle different 'default' types (#7159)
Traffic Dump documentation for post_process.py (#7161)
Fix memory leaks in multiplexer plugin (#7160)
rc: fixes systemd unit file stopping (#7157)
Fix lua plugin mem leak problem (#7158)
Don't make an error on duplicated RETIRE_CONNECTION frames (#7131)
URL::parse fixes for empty paths (#7119)
Replace ACTION_RESULT_NONE with nullptr (#7135)
Add metric tracking async job pauses (#7153)
PluginFactory - Remove unused code that was left from last PluginFactory change(TSPluginDSOReloadEnable) (#7155)
Fix stale pointer due to SSL config reload (#7148)
slice: check if vio is still valid before calling TSVIODone* on shutdown (#7147)
Deprecate cqhv field (#7143)
Don't return QUIC frame if the size exceeds maximum frame size (#7121)
Check VIO availability before acquiring a lock for it (#7145)
Fix #7116, skip the insertion of the same continuation to pending dns (#7117)
Allow override of CA certs for cert from client based on SNI server name sent by client. (#7130)
Fix typo in cache docs (#7144)
remove useless shortopt (#7138)
Protect TSActionCancel from null INKContInternal actions (#7128)
Check VIO availability before checking whether the VIO has data (#7120)
Accept NAT rebinding on a QUIC connection (#7123)
Fixes garbled logs when using %<vbn> log tag (#7140)
Removes duplicated listing of files in same Makefile target (#7137)
Updated gdb mutex script to get process file for Fedora 32 (#7133)
SSLConfig mem leak fix (#7125)
Replaces "smart" quotes with ASCII equivalents (#7126)
Comment out a wrong assertion in QUIC Loss Detection logic (#7129)
Add member initialization to the Errata class. (#7132)
Cancel active/inactive timeout on closing Http2Stream (#7111)
Add modsecurity lua script to example (#7105)
Expose remap config file callback (#7073)
Make tls_hooks tests more likely to pass (#7122)
commit ac31adaa82f9271f902de2f45c071e328f620271
Merge: 4d579f49a e904dbcef
Author: Masakazu Kitajo <ma...@apache.org>
Date: Mon Aug 17 09:14:14 2020 +0900
Merge branch 'master' into quic-latest
* master:
Backing out my update of our jenkin's autest file. (#7118)
Don't send image/webp responses from cache to broswers that don't support it (#7104)
Updating our autest suite to require Python3.6 (#7113)
Squashed commit of the following: (#7110)
Supporting out of source builds for AuTests. (#7109)
Fixes uninitialized variables found by Xcode (#7100)
Add cross references between server session sharing match and upstream connection tracking match. (#7038)
---
iocore/net/quic/Makefile.am | 3 +
iocore/net/quic/Mock.h | 90 +++-
iocore/net/quic/QUICApplication.cc | 248 +---------
iocore/net/quic/QUICApplication.h | 52 +-
iocore/net/quic/QUICBidirectionalStream.cc | 381 +++++----------
iocore/net/quic/QUICBidirectionalStream.h | 23 +-
iocore/net/quic/QUICPacket.h | 2 +-
iocore/net/quic/QUICPacketFactory.cc | 4 +-
iocore/net/quic/QUICStream.cc | 158 +-----
iocore/net/quic/QUICStream.h | 49 +-
.../net/quic/QUICStreamAdapter.cc | 16 +-
.../net/quic/QUICStreamAdapter.h | 52 +-
iocore/net/quic/QUICStreamFactory.cc | 6 +-
iocore/net/quic/QUICStreamFactory.h | 6 +-
iocore/net/quic/QUICStreamManager.cc | 89 ++--
iocore/net/quic/QUICStreamManager.h | 11 +-
iocore/net/quic/QUICStreamState.cc | 96 ++--
iocore/net/quic/QUICStreamState.h | 43 +-
iocore/net/quic/QUICStreamVCAdapter.cc | 320 +++++++++++++
iocore/net/quic/QUICStreamVCAdapter.h | 105 ++++
iocore/net/quic/QUICTransferProgressProvider.cc | 83 ++++
iocore/net/quic/QUICTransferProgressProvider.h | 44 +-
iocore/net/quic/QUICUnidirectionalStream.cc | 533 ++++-----------------
iocore/net/quic/QUICUnidirectionalStream.h | 20 +-
iocore/net/quic/test/test_QUICStream.cc | 189 +++++---
iocore/net/quic/test/test_QUICStreamState.cc | 134 +++---
proxy/http3/Http09App.cc | 53 +-
proxy/http3/Http09App.h | 4 +
proxy/http3/Http3App.cc | 157 +++---
proxy/http3/Http3App.h | 28 +-
proxy/http3/Http3DataFramer.cc | 8 +-
proxy/http3/Http3DataFramer.h | 2 +-
proxy/http3/Http3Frame.cc | 127 +++--
proxy/http3/Http3Frame.h | 12 +-
proxy/http3/Http3FrameCollector.cc | 22 +-
proxy/http3/Http3FrameCollector.h | 4 +-
proxy/http3/Http3FrameDispatcher.cc | 15 +-
proxy/http3/Http3FrameDispatcher.h | 4 +-
proxy/http3/Http3FrameGenerator.h | 4 +-
proxy/http3/Http3HeaderFramer.cc | 9 +-
proxy/http3/Http3HeaderFramer.h | 2 +-
proxy/http3/Http3HeaderVIOAdaptor.cc | 122 ++++-
proxy/http3/Http3HeaderVIOAdaptor.h | 23 +-
proxy/http3/Http3Transaction.cc | 178 ++-----
proxy/http3/Http3Transaction.h | 19 +-
proxy/http3/QPACK.cc | 159 +++---
proxy/http3/QPACK.h | 33 +-
proxy/http3/test/main.cc | 8 +
proxy/http3/test/test_Http3Frame.cc | 24 +-
proxy/http3/test/test_QPACK.cc | 22 +-
src/traffic_quic/quic_client.cc | 67 ++-
src/traffic_quic/quic_client.h | 11 +
src/traffic_quic/traffic_quic.cc | 5 +
53 files changed, 1946 insertions(+), 1933 deletions(-)
diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am
index 8a60a23..ca72382 100644
--- a/iocore/net/quic/Makefile.am
+++ b/iocore/net/quic/Makefile.am
@@ -62,6 +62,8 @@ libquic_a_SOURCES = \
QUICNewRenoCongestionController.cc \
QUICFlowController.cc \
QUICStreamState.cc \
+ QUICStreamAdapter.cc \
+ QUICStreamVCAdapter.cc \
QUICStream.cc \
QUICHandshake.cc \
QUICPacketHeaderProtector.cc \
@@ -92,6 +94,7 @@ libquic_a_SOURCES = \
QUICFrameGenerator.cc \
QUICFrameRetransmitter.cc \
QUICAddrVerifyState.cc \
+ QUICTransferProgressProvider.cc \
QUICBidirectionalStream.cc \
QUICCryptoStream.cc \
QUICUnidirectionalStream.cc \
diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h
index eda260c..3185315 100644
--- a/iocore/net/quic/Mock.h
+++ b/iocore/net/quic/Mock.h
@@ -36,6 +36,7 @@
#include "QUICPinger.h"
#include "QUICPadder.h"
#include "QUICHandshakeProtocol.h"
+#include "QUICStreamAdapter.h"
class MockQUICContext;
@@ -717,6 +718,76 @@ private:
MockQUICCongestionController _cc;
};
+class MockQUICStreamAdapter : public QUICStreamAdapter
+{
+public:
+ MockQUICStreamAdapter(QUICStream &stream) : QUICStreamAdapter(stream) {}
+
+ void
+ write_to_stream(const uint8_t *buf, size_t len)
+ {
+ this->_total_sending_data_len += len;
+ this->_sending_data_len += len;
+ }
+
+ int64_t
+ write(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) override
+ {
+ this->_total_receiving_data_len += data_length;
+ this->_receiving_data_len += data_length;
+ return data_length;
+ }
+ bool
+ is_eos() override
+ {
+ return false;
+ }
+ uint64_t
+ unread_len() override
+ {
+ return this->_sending_data_len;
+ }
+ uint64_t
+ read_len() override
+ {
+ return 0;
+ }
+ uint64_t
+ total_len() override
+ {
+ return this->_total_sending_data_len;
+ }
+ void
+ encourge_read() override
+ {
+ }
+ void
+ encourge_write() override
+ {
+ }
+ void
+ notify_eos() override
+ {
+ }
+
+protected:
+ Ptr<IOBufferBlock>
+ _read(size_t len) override
+ {
+ this->_sending_data_len -= len;
+ Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
+ block->fill(len);
+ return block;
+ }
+
+private:
+ size_t _sending_data_len = 0;
+ size_t _total_sending_data_len = 0;
+ size_t _receiving_data_len = 0;
+ size_t _total_receiving_data_len = 0;
+};
+
class MockQUICApplication : public QUICApplication
{
public:
@@ -726,20 +797,29 @@ public:
main_event_handler(int event, Event *data)
{
if (event == 12345) {
- QUICStreamIO *stream_io = static_cast<QUICStreamIO *>(data->cookie);
- stream_io->write_reenable();
}
return EVENT_CONT;
}
void
+ on_new_stream(QUICStream &stream) override
+ {
+ auto ite = this->_streams.emplace(stream.id(), stream);
+ QUICStreamAdapter &adapter = ite.first->second;
+ stream.set_io_adapter(&adapter);
+ }
+
+ void
send(const uint8_t *data, size_t size, QUICStreamId stream_id)
{
- QUICStreamIO *stream_io = this->_find_stream_io(stream_id);
- stream_io->write(data, size);
+ auto ite = this->_streams.find(stream_id);
+ auto &adapter = ite->second;
+ adapter.write_to_stream(data, size);
- eventProcessor.schedule_imm(this, ET_CALL, 12345, stream_io);
+ // eventProcessor.schedule_imm(this, ET_CALL, 12345, adapter);
}
+
+ std::unordered_map<QUICStreamId, MockQUICStreamAdapter> _streams;
};
class MockQUICPacketR : public QUICPacketR
diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc
index a5bfd26..d6dc495 100644
--- a/iocore/net/quic/QUICApplication.cc
+++ b/iocore/net/quic/QUICApplication.cc
@@ -24,172 +24,6 @@
#include "QUICApplication.h"
#include "QUICStream.h"
-static constexpr char tag_stream_io[] = "quic_stream_io";
-static constexpr char tag_app[] = "quic_app";
-
-#define QUICStreamIODebug(fmt, ...) \
- Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream_vc->connection_info()->cids().data(), this->_stream_vc->id(), \
- ##__VA_ARGS__)
-
-//
-// QUICStreamIO
-//
-QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStreamVConnection *stream_vc) : _stream_vc(stream_vc)
-{
- this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K);
- this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K);
-
- this->_read_buffer_reader = this->_read_buffer->alloc_reader();
- this->_write_buffer_reader = this->_write_buffer->alloc_reader();
-
- switch (stream_vc->direction()) {
- case QUICStreamDirection::BIDIRECTIONAL:
- this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer);
- this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader);
- break;
- case QUICStreamDirection::SEND:
- this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader);
- break;
- case QUICStreamDirection::RECEIVE:
- this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer);
- break;
- default:
- ink_assert(false);
- break;
- }
-}
-
-QUICStreamIO::~QUICStreamIO()
-{
- // All readers will be deallocated
- free_MIOBuffer(this->_read_buffer);
- free_MIOBuffer(this->_write_buffer);
-};
-
-uint32_t
-QUICStreamIO::stream_id() const
-{
- return this->_stream_vc->id();
-}
-
-bool
-QUICStreamIO::is_bidirectional() const
-{
- return this->_stream_vc->is_bidirectional();
-}
-
-int64_t
-QUICStreamIO::read(uint8_t *buf, int64_t len)
-{
- if (is_debug_tag_set(tag_stream_io)) {
- if (this->_read_vio->nbytes == INT64_MAX) {
- QUICStreamIODebug("nbytes=- ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->ndone,
- this->_read_buffer_reader->read_avail(), len);
- } else {
- QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->nbytes,
- this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len);
- }
- }
-
- int64_t nread = this->_read_buffer_reader->read(buf, len);
- if (nread > 0) {
- this->_read_vio->ndone += nread;
- }
-
- this->_stream_vc->on_read();
-
- return nread;
-}
-
-int64_t
-QUICStreamIO::peek(uint8_t *buf, int64_t len)
-{
- return this->_read_buffer_reader->memcpy(buf, len) - reinterpret_cast<char *>(buf);
-}
-
-void
-QUICStreamIO::consume(int64_t len)
-{
- this->_read_buffer_reader->consume(len);
- this->_stream_vc->on_read();
-}
-
-bool
-QUICStreamIO::is_read_done() const
-{
- return this->_read_vio->ntodo() == 0;
-}
-
-int64_t
-QUICStreamIO::write(const uint8_t *buf, int64_t len)
-{
- SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread());
-
- int64_t nwritten = this->_write_buffer->write(buf, len);
- if (nwritten > 0) {
- this->_nwritten += nwritten;
- }
-
- return len;
-}
-
-int64_t
-QUICStreamIO::write(IOBufferReader *r, int64_t len)
-{
- SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread());
-
- int64_t bytes_avail = this->_write_buffer->write_avail();
-
- if (bytes_avail > 0) {
- if (is_debug_tag_set(tag_stream_io)) {
- if (this->_write_vio->nbytes == INT64_MAX) {
- QUICStreamIODebug("nbytes=- ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->ndone,
- bytes_avail, len);
- } else {
- QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64,
- this->_write_vio->nbytes, this->_write_vio->ndone, bytes_avail, len);
- }
- }
-
- int64_t bytes_len = std::min(bytes_avail, len);
- int64_t nwritten = this->_write_buffer->write(r, bytes_len);
-
- if (nwritten > 0) {
- this->_nwritten += nwritten;
- }
-
- return nwritten;
- } else {
- return 0;
- }
-}
-
-// TODO: Similar to other "write" apis, but do not copy.
-int64_t
-QUICStreamIO::write(IOBufferBlock *b)
-{
- ink_assert(!"not implemented yet");
- return 0;
-}
-
-void
-QUICStreamIO::write_done()
-{
- this->_write_vio->nbytes = this->_nwritten;
-}
-
-void
-QUICStreamIO::read_reenable()
-{
- return this->_read_vio->reenable();
-}
-
-void
-QUICStreamIO::write_reenable()
-{
- return this->_write_vio->reenable();
-}
-
//
// QUICApplication
//
@@ -198,84 +32,4 @@ QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMut
this->_qc = qc;
}
-QUICApplication::~QUICApplication()
-{
- for (auto const &kv : this->_stream_map) {
- delete kv.second;
- }
-}
-
-// @brief Bind stream and application
-void
-QUICApplication::set_stream(QUICStreamVConnection *stream_vc, QUICStreamIO *stream_io)
-{
- if (stream_io == nullptr) {
- stream_io = new QUICStreamIO(this, stream_vc);
- }
- this->_stream_map.insert(std::make_pair(stream_vc->id(), stream_io));
-}
-
-// @brief Bind stream and application
-void
-QUICApplication::set_stream(QUICStreamIO *stream_io)
-{
- this->_stream_map.insert(std::make_pair(stream_io->stream_id(), stream_io));
-}
-
-bool
-QUICApplication::is_stream_set(QUICStreamVConnection *stream)
-{
- auto result = this->_stream_map.find(stream->id());
-
- return result != this->_stream_map.end();
-}
-
-void
-QUICApplication::reenable(QUICStreamVConnection *stream)
-{
- QUICStreamIO *stream_io = this->_find_stream_io(stream->id());
- if (stream_io) {
- stream_io->read_reenable();
- stream_io->write_reenable();
- } else {
- Debug(tag_app, "[%s] Unknown Stream id=%" PRIx64, this->_qc->cids().data(), stream->id());
- }
-
- return;
-}
-
-void
-QUICApplication::unset_stream(QUICStreamVConnection *stream)
-{
- QUICStreamIO *stream_io = this->_find_stream_io(stream->id());
- if (stream_io) {
- this->_stream_map.erase(stream->id());
- }
-}
-
-QUICStreamIO *
-QUICApplication::_find_stream_io(QUICStreamId id)
-{
- auto result = this->_stream_map.find(id);
-
- if (result == this->_stream_map.end()) {
- return nullptr;
- } else {
- return result->second;
- }
-}
-
-QUICStreamIO *
-QUICApplication::_find_stream_io(VIO *vio)
-{
- if (vio == nullptr) {
- return nullptr;
- }
-
- QUICStream *stream = dynamic_cast<QUICStream *>(vio->vc_server);
- if (stream == nullptr) {
- return nullptr;
- }
-
- return this->_find_stream_io(stream->id());
-}
+QUICApplication::~QUICApplication() {}
diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h
index c4fb16f..a697ea2 100644
--- a/iocore/net/quic/QUICApplication.h
+++ b/iocore/net/quic/QUICApplication.h
@@ -32,48 +32,6 @@
class QUICApplication;
/**
- @brief QUICStream I/O Interface for QUICApplication
- */
-class QUICStreamIO
-{
-public:
- QUICStreamIO(QUICApplication *app, QUICStreamVConnection *stream);
- virtual ~QUICStreamIO();
-
- uint32_t stream_id() const;
- bool is_bidirectional() const;
-
- int64_t read(uint8_t *buf, int64_t len);
- int64_t peek(uint8_t *buf, int64_t len);
- void consume(int64_t len);
- bool is_read_done() const;
- virtual void read_reenable();
-
- int64_t write(const uint8_t *buf, int64_t len);
- int64_t write(IOBufferReader *r, int64_t len);
- int64_t write(IOBufferBlock *b);
- void write_done();
- virtual void write_reenable();
-
-protected:
- MIOBuffer *_read_buffer = nullptr;
- MIOBuffer *_write_buffer = nullptr;
-
- IOBufferReader *_read_buffer_reader = nullptr;
- IOBufferReader *_write_buffer_reader = nullptr;
-
-private:
- QUICStreamVConnection *_stream_vc = nullptr;
-
- VIO *_read_vio = nullptr;
- VIO *_write_vio = nullptr;
-
- // Track how much data is written to _write_vio. When total size of data become clear,
- // set it to _write_vio.nbytes.
- uint64_t _nwritten = 0;
-};
-
-/**
* @brief Abstract QUIC Application Class
* @detail Every quic application must inherits this class
*/
@@ -83,18 +41,10 @@ public:
QUICApplication(QUICConnection *qc);
virtual ~QUICApplication();
- void set_stream(QUICStreamVConnection *stream_vc, QUICStreamIO *stream_io = nullptr);
- void set_stream(QUICStreamIO *stream_io);
- bool is_stream_set(QUICStreamVConnection *stream_vc);
- void reenable(QUICStreamVConnection *stream_vc);
- void unset_stream(QUICStreamVConnection *stream_vc);
+ virtual void on_new_stream(QUICStream &stream) = 0;
protected:
- QUICStreamIO *_find_stream_io(QUICStreamId id);
- QUICStreamIO *_find_stream_io(VIO *vio);
-
QUICConnection *_qc = nullptr;
private:
- std::map<QUICStreamId, QUICStreamIO *> _stream_map;
};
diff --git a/iocore/net/quic/QUICBidirectionalStream.cc b/iocore/net/quic/QUICBidirectionalStream.cc
index 4203ec0..e5653e7 100644
--- a/iocore/net/quic/QUICBidirectionalStream.cc
+++ b/iocore/net/quic/QUICBidirectionalStream.cc
@@ -22,118 +22,25 @@
*/
#include "QUICBidirectionalStream.h"
+#include "QUICStreamAdapter.h"
//
// QUICBidirectionalStream
//
QUICBidirectionalStream::QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid,
uint64_t recv_max_stream_data, uint64_t send_max_stream_data)
- : QUICStreamVConnection(cinfo, sid),
+ : QUICStream(cinfo, sid),
_remote_flow_controller(send_max_stream_data, _id),
_local_flow_controller(rtt_provider, recv_max_stream_data, _id),
_flow_control_buffer_size(recv_max_stream_data),
- _state(nullptr, &this->_progress_vio, this, nullptr)
+ _state(nullptr, &this->_progress_sa, this, nullptr)
{
- SET_HANDLER(&QUICBidirectionalStream::state_stream_open);
-
QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(),
this->_local_flow_controller.current_limit());
QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
this->_remote_flow_controller.current_limit());
}
-int
-QUICBidirectionalStream::state_stream_open(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
- QUICErrorUPtr error = nullptr;
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- int64_t len = this->_process_read_vio();
- if (len > 0) {
- this->_signal_read_event();
- }
-
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
-
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- QUICStreamDebug("unknown event");
- ink_assert(false);
- }
-
- // FIXME error is always nullptr
- if (error != nullptr) {
- if (error->cls == QUICErrorClass::TRANSPORT) {
- QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code),
- static_cast<unsigned int>(error->code));
- } else {
- QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->code));
- }
- if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
- // Stream Error
- QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast<QUICStreamError *>(error.get()));
- this->reset(std::move(serror));
- } else {
- // Connection Error
- // TODO Close connection (Does this really happen?)
- }
- }
-
- return EVENT_DONE;
-}
-
-int
-QUICBidirectionalStream::state_stream_closed(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- ink_assert(false);
- }
-
- return EVENT_DONE;
-}
-
bool
QUICBidirectionalStream::is_transfer_goal_set() const
{
@@ -168,7 +75,6 @@ QUICConnectionErrorUPtr
QUICBidirectionalStream::recv(const QUICStreamFrame &frame)
{
ink_assert(_id == frame.stream_id());
- ink_assert(this->_read_vio.op == VIO::READ);
// Check stream state - Do this first before accept the frame
if (!this->_state.is_allowed_to_receive(frame)) {
@@ -202,9 +108,11 @@ QUICBidirectionalStream::recv(const QUICStreamFrame &frame)
last_offset = stream_frame->offset();
last_length = stream_frame->data_length();
- this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast<uint8_t *>(stream_frame->data()->start()),
- stream_frame->data_length(), stream_frame->has_fin_flag());
- this->_state.update_with_receiving_frame(*new_frame);
+ this->_adapter->write(stream_frame->offset(), reinterpret_cast<uint8_t *>(stream_frame->data()->start()),
+ stream_frame->data_length(), stream_frame->has_fin_flag());
+ if (this->_state.update_with_receiving_frame(*new_frame)) {
+ this->_notify_state_change();
+ }
delete new_frame;
new_frame = this->_received_stream_frame_buffer.pop();
@@ -218,7 +126,7 @@ QUICBidirectionalStream::recv(const QUICStreamFrame &frame)
this->_local_flow_controller.current_limit());
}
- this->_signal_read_event();
+ this->_adapter->encourge_read();
return nullptr;
}
@@ -230,10 +138,7 @@ QUICBidirectionalStream::recv(const QUICMaxStreamDataFrame &frame)
QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
this->_remote_flow_controller.current_limit());
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
+ this->_adapter->encourge_write();
return nullptr;
}
@@ -249,7 +154,9 @@ QUICBidirectionalStream::recv(const QUICStreamDataBlockedFrame &frame)
QUICConnectionErrorUPtr
QUICBidirectionalStream::recv(const QUICStopSendingFrame &frame)
{
- this->_state.update_with_receiving_frame(frame);
+ if (this->_state.update_with_receiving_frame(frame)) {
+ this->_notify_state_change();
+ }
this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING));
// We received and processed STOP_SENDING frame, so return NO_ERROR here
return nullptr;
@@ -258,97 +165,11 @@ QUICBidirectionalStream::recv(const QUICStopSendingFrame &frame)
QUICConnectionErrorUPtr
QUICBidirectionalStream::recv(const QUICRstStreamFrame &frame)
{
- this->_state.update_with_receiving_frame(frame);
- this->_signal_read_eos_event();
- return nullptr;
-}
-
-// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag
-VIO *
-QUICBidirectionalStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
-{
- if (buf) {
- this->_read_vio.buffer.writer_for(buf);
- } else {
- this->_read_vio.buffer.clear();
- }
-
- this->_read_vio.mutex = c ? c->mutex : this->mutex;
- this->_read_vio.cont = c;
- this->_read_vio.nbytes = nbytes;
- this->_read_vio.ndone = 0;
- this->_read_vio.vc_server = this;
- this->_read_vio.op = VIO::READ;
-
- this->_process_read_vio();
- this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio);
-
- return &this->_read_vio;
-}
-
-VIO *
-QUICBidirectionalStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
-{
- if (buf) {
- this->_write_vio.buffer.reader_for(buf);
- } else {
- this->_write_vio.buffer.clear();
- }
-
- this->_write_vio.mutex = c ? c->mutex : this->mutex;
- this->_write_vio.cont = c;
- this->_write_vio.nbytes = nbytes;
- this->_write_vio.ndone = 0;
- this->_write_vio.vc_server = this;
- this->_write_vio.op = VIO::WRITE;
-
- this->_process_write_vio();
- this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio);
-
- return &this->_write_vio;
-}
-
-void
-QUICBidirectionalStream::do_io_close(int lerrno)
-{
- SET_HANDLER(&QUICBidirectionalStream::state_stream_closed);
-
- this->_read_vio.buffer.clear();
- this->_read_vio.nbytes = 0;
- this->_read_vio.op = VIO::NONE;
- this->_read_vio.cont = nullptr;
-
- this->_write_vio.buffer.clear();
- this->_write_vio.nbytes = 0;
- this->_write_vio.op = VIO::NONE;
- this->_write_vio.cont = nullptr;
-}
-
-void
-QUICBidirectionalStream::do_io_shutdown(ShutdownHowTo_t howto)
-{
- ink_assert(false); // unimplemented yet
- return;
-}
-
-void
-QUICBidirectionalStream::reenable(VIO *vio)
-{
- if (vio->op == VIO::READ) {
- QUICVStreamDebug("read_vio reenabled");
-
- int64_t len = this->_process_read_vio();
- if (len > 0) {
- this->_signal_read_event();
- }
- } else if (vio->op == VIO::WRITE) {
- QUICVStreamDebug("write_vio reenabled");
-
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
+ if (this->_state.update_with_receiving_frame(frame)) {
+ this->_notify_state_change();
}
+ this->_adapter->notify_eos();
+ return nullptr;
}
bool
@@ -361,9 +182,9 @@ QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, size_t c
if (!this->is_retransmited_frame_queue_empty()) {
return true;
}
- if (this->_write_vio.op != VIO::NONE && this->_write_vio.get_reader()->is_read_avail_more_than(0)) {
+ if (this->_adapter && this->_adapter->unread_len() > 0) {
return true;
- };
+ }
return false;
}
@@ -386,7 +207,9 @@ QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level,
return nullptr;
}
this->_records_rst_stream_frame(level, *static_cast<QUICRstStreamFrame *>(frame));
- this->_state.update_with_sending_frame(*frame);
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
+ }
this->_is_reset_sent = true;
return frame;
}
@@ -400,7 +223,9 @@ QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level,
return nullptr;
}
this->_records_stop_sending_frame(level, *static_cast<QUICStopSendingFrame *>(frame));
- this->_state.update_with_sending_frame(*frame);
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
+ }
this->_is_stop_sending_sent = true;
return frame;
}
@@ -412,91 +237,87 @@ QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level,
return frame;
}
- if (this->_write_vio.op != VIO::NONE && this->_state.is_allowed_to_send(QUICFrameType::STREAM)) {
- SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+ if (!this->_adapter || !this->_state.is_allowed_to_send(QUICFrameType::STREAM)) {
+ return frame;
+ }
+
+ uint64_t maximum_data_size = 0;
+ if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
+ return frame;
+ }
+ maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD;
+
+ bool pure_fin = false;
+ bool fin = false;
+ if (this->_adapter->is_eos()) {
+ // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero.
+ pure_fin = true;
+ fin = true;
+ }
- uint64_t maximum_data_size = 0;
- if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
+ uint64_t len = 0;
+ if (!pure_fin) {
+ uint64_t data_len = this->_adapter->unread_len();
+ if (data_len == 0) {
return frame;
}
- maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD;
-
- bool pure_fin = false;
- bool fin = false;
- if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) &&
- this->_write_vio.nbytes == static_cast<int64_t>(this->_send_offset)) {
- // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero.
- pure_fin = true;
- fin = true;
- }
- uint64_t len = 0;
- IOBufferReader *reader = this->_write_vio.get_reader();
- if (!pure_fin) {
- uint64_t data_len = reader->block_read_avail();
- if (data_len == 0) {
- return frame;
- }
-
- // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin
- uint64_t stream_credit = this->_remote_flow_controller.credit();
- if (stream_credit == 0) {
- // STREAM_DATA_BLOCKED
- frame =
- this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, current_packet_size, seq_num);
- return frame;
- }
-
- if (connection_credit == 0) {
- // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller
- return frame;
- }
-
- len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit)));
-
- // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0
- ink_assert(len != 0);
-
- if (this->_write_vio.nbytes == static_cast<int64_t>(this->_send_offset + len)) {
- fin = true;
- }
+ // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin
+ uint64_t stream_credit = this->_remote_flow_controller.credit();
+ if (stream_credit == 0) {
+ // STREAM_DATA_BLOCKED
+ frame =
+ this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, current_packet_size, seq_num);
+ return frame;
}
- Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(reader->get_current_block()->clone());
- block->consume(reader->start_offset);
- block->_end = std::min(block->start() + len, block->_buf_end);
- ink_assert(static_cast<uint64_t>(block->read_avail()) == len);
-
- // STREAM - Pure FIN or data length is lager than 0
- // FIXME has_length_flag and has_offset_flag should be configurable
- frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true,
- this->_issue_frame_id(), this);
- if (!this->_state.is_allowed_to_send(*frame)) {
- QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type()));
+ if (connection_credit == 0) {
+ // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller
return frame;
}
- if (!pure_fin) {
- int ret = this->_remote_flow_controller.update(this->_send_offset + len);
- // We cannot cancel sending the frame after updating the flow controller
+ len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit)));
- // Calling update always success, because len is always less than stream_credit
- ink_assert(ret == 0);
+ // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0
+ ink_assert(len != 0);
- QUICVStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
- this->_remote_flow_controller.current_limit());
- if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) {
- QUICStreamDebug("Flow Controller will block sending a STREAM frame");
- }
+ if (this->_adapter->total_len() == this->_send_offset + len) {
+ fin = true;
+ }
+ }
+
+ Ptr<IOBufferBlock> block = this->_adapter->read(len);
+ ink_assert(static_cast<uint64_t>(block->read_avail()) == len);
+
+ // STREAM - Pure FIN or data length is lager than 0
+ // FIXME has_length_flag and has_offset_flag should be configurable
+ frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(),
+ this);
+ if (!this->_state.is_allowed_to_send(*frame)) {
+ QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type()));
+ return frame;
+ }
- reader->consume(len);
- this->_send_offset += len;
- this->_write_vio.ndone += len;
+ if (!pure_fin) {
+ int ret = this->_remote_flow_controller.update(this->_send_offset + len);
+ // We cannot cancel sending the frame after updating the flow controller
+
+ // Calling update always success, because len is always less than stream_credit
+ ink_assert(ret == 0);
+
+ QUICVStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
+ this->_remote_flow_controller.current_limit());
+ if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) {
+ QUICStreamDebug("Flow Controller will block sending a STREAM frame");
}
- this->_records_stream_frame(level, *static_cast<QUICStreamFrame *>(frame));
- this->_signal_write_event();
- this->_state.update_with_sending_frame(*frame);
+ this->_send_offset += len;
+ }
+ this->_records_stream_frame(level, *static_cast<QUICStreamFrame *>(frame));
+
+ this->_adapter->encourge_write();
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
}
return frame;
@@ -522,7 +343,9 @@ QUICBidirectionalStream::_on_frame_acked(QUICFrameInformationUPtr &info)
break;
}
- this->_state.update_on_ack();
+ if (this->_state.update_on_ack()) {
+ this->_notify_state_change();
+ }
}
void
@@ -564,13 +387,17 @@ QUICBidirectionalStream::reset(QUICStreamErrorUPtr error)
void
QUICBidirectionalStream::on_read()
{
- this->_state.update_on_read();
+ if (this->_state.update_on_read()) {
+ this->_notify_state_change();
+ }
}
void
QUICBidirectionalStream::on_eos()
{
- this->_state.update_on_eos();
+ if (this->_state.update_on_eos()) {
+ this->_notify_state_change();
+ }
}
QUICOffset
@@ -584,3 +411,9 @@ QUICBidirectionalStream::largest_offset_sent() const
{
return this->_remote_flow_controller.current_offset();
}
+
+void
+QUICBidirectionalStream::_on_adapter_updated()
+{
+ this->_progress_sa.set_stream_adapter(this->_adapter);
+}
diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h
index d64f899..6f0118b 100644
--- a/iocore/net/quic/QUICBidirectionalStream.h
+++ b/iocore/net/quic/QUICBidirectionalStream.h
@@ -25,24 +25,18 @@
#include "QUICStream.h"
-class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransferProgressProvider
+class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressProvider
{
public:
QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid,
uint64_t recv_max_stream_data, uint64_t send_max_stream_data);
QUICBidirectionalStream()
- : QUICStreamVConnection(),
- _remote_flow_controller(0, 0),
- _local_flow_controller(nullptr, 0, 0),
- _state(nullptr, nullptr, nullptr, nullptr)
+ : QUICStream(), _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), _state(nullptr, nullptr, nullptr, nullptr)
{
}
~QUICBidirectionalStream() {}
- int state_stream_open(int event, void *data);
- int state_stream_closed(int event, void *data);
-
// QUICFrameGenerator
bool will_generate_frame(QUICEncryptionLevel level, size_t current_packet_size, bool ack_eliciting, uint32_t seq_num) override;
QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size,
@@ -54,13 +48,6 @@ public:
virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override;
virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override;
- // Implement VConnection Interface.
- VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override;
- VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override;
- void do_io_close(int lerrno = -1) override;
- void do_io_shutdown(ShutdownHowTo_t howto) override;
- void reenable(VIO *vio) override;
-
void stop_sending(QUICStreamErrorUPtr error) override;
void reset(QUICStreamErrorUPtr error) override;
@@ -79,6 +66,9 @@ public:
QUICOffset largest_offset_received() const override;
QUICOffset largest_offset_sent() const override;
+protected:
+ virtual void _on_adapter_updated() override;
+
private:
QUICStreamErrorUPtr _reset_reason = nullptr;
bool _is_reset_sent = false;
@@ -88,7 +78,7 @@ private:
bool _is_transfer_complete = false;
bool _is_reset_complete = false;
- QUICTransferProgressProviderVIO _progress_vio = {this->_write_vio};
+ QUICTransferProgressProviderSA _progress_sa;
QUICRemoteStreamFlowController _remote_flow_controller;
QUICLocalStreamFlowController _local_flow_controller;
@@ -98,7 +88,6 @@ private:
// TODO: Consider to replace with ts/RbTree.h or other data structure
QUICIncomingStreamFrameBuffer _received_stream_frame_buffer;
- // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState
QUICBidirectionalStreamStateMachine _state;
// QUICFrameGenerator
diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h
index e9d0212..49d0b14 100644
--- a/iocore/net/quic/QUICPacket.h
+++ b/iocore/net/quic/QUICPacket.h
@@ -275,7 +275,7 @@ private:
QUICKeyPhase _key_phase;
QUICPacketNumber _packet_number;
int _packet_number_len;
- QUICConnectionId _dcid;
+ QUICConnectionId _dcid = QUICConnectionId::ZERO();
};
class QUICStatelessResetPacket : public QUICPacket
diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc
index 2fcb1a2..279cf7d 100644
--- a/iocore/net/quic/QUICPacketFactory.cc
+++ b/iocore/net/quic/QUICPacketFactory.cc
@@ -75,8 +75,8 @@ QUICPacketFactory::create(uint8_t *packet_buf, UDPConnection *udp_con, IpEndpoin
QUICPacketType type;
QUICVersion version;
- QUICConnectionId dcid;
- QUICConnectionId scid;
+ QUICConnectionId dcid = QUICConnectionId::ZERO();
+ QUICConnectionId scid = QUICConnectionId::ZERO();
QUICPacketNumber packet_number;
QUICKeyPhase key_phase;
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 93ac8f1..932d1c1 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -62,6 +62,13 @@ QUICStream::final_offset() const
return 0;
}
+void
+QUICStream::set_io_adapter(QUICStreamAdapter *adapter)
+{
+ this->_adapter = adapter;
+ this->_on_adapter_updated();
+}
+
QUICOffset
QUICStream::reordered_bytes() const
{
@@ -154,6 +161,20 @@ QUICStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFra
}
void
+QUICStream::set_state_listener(QUICStreamStateListener *listener)
+{
+ this->_state_listener = listener;
+}
+
+void
+QUICStream::_notify_state_change()
+{
+ if (this->_state_listener) {
+ // TODO Check own state and call an appropriate callback function
+ }
+}
+
+void
QUICStream::reset(QUICStreamErrorUPtr error)
{
}
@@ -184,140 +205,3 @@ void
QUICStream::on_read()
{
}
-
-//
-// QUICStreamVConnection
-//
-QUICStreamVConnection::~QUICStreamVConnection()
-{
- if (this->_read_event) {
- this->_read_event->cancel();
- this->_read_event = nullptr;
- }
-
- if (this->_write_event) {
- this->_write_event->cancel();
- this->_write_event = nullptr;
- }
-}
-
-void
-QUICStreamVConnection::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin)
-{
- SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
-
- uint64_t bytes_added = this->_read_vio.buffer.writer()->write(data, data_length);
-
- // Until receive FIN flag, keep nbytes INT64_MAX
- if (fin && bytes_added == data_length) {
- this->_read_vio.nbytes = offset + data_length;
- }
-}
-
-/**
- * Replace existing event only if the new event is different than the inprogress event
- */
-Event *
-QUICStreamVConnection::_send_tracked_event(Event *event, int send_event, VIO *vio)
-{
- if (event != nullptr) {
- if (event->callback_event != send_event) {
- event->cancel();
- event = nullptr;
- }
- }
-
- if (event == nullptr) {
- event = this_ethread()->schedule_imm(this, send_event, vio);
- }
-
- return event;
-}
-
-/**
- * @brief Signal event to this->_read_vio.cont
- */
-void
-QUICStreamVConnection::_signal_read_event()
-{
- if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) {
- return;
- }
- MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread());
-
- int event = this->_read_vio.nbytes == INT64_MAX ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE;
-
- if (lock.is_locked()) {
- this->_read_vio.cont->handleEvent(event, &this->_read_vio);
- } else {
- this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio);
- }
-}
-
-/**
- * @brief Signal event to this->_write_vio.cont
- */
-void
-QUICStreamVConnection::_signal_write_event()
-{
- if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) {
- return;
- }
- MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread());
-
- int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE;
-
- if (lock.is_locked()) {
- this->_write_vio.cont->handleEvent(event, &this->_write_vio);
- } else {
- this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio);
- }
-}
-
-/**
- * @brief Signal event to this->_write_vio.cont
- */
-void
-QUICStreamVConnection::_signal_read_eos_event()
-{
- if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) {
- return;
- }
- MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread());
-
- int event = VC_EVENT_EOS;
-
- if (lock.is_locked()) {
- this->_write_vio.cont->handleEvent(event, &this->_write_vio);
- } else {
- this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio);
- }
-}
-
-int64_t
-QUICStreamVConnection::_process_read_vio()
-{
- if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) {
- return 0;
- }
-
- // Pass through. Read operation is done by QUICStream::recv(const std::shared_ptr<const QUICStreamFrame> frame)
- // TODO: 1. pop frame from _received_stream_frame_buffer
- // 2. write data to _read_vio
-
- return 0;
-}
-
-/**
- * @brief Send STREAM DATA from _response_buffer
- * @detail Call _signal_write_event() to indicate event upper layer
- */
-int64_t
-QUICStreamVConnection::_process_write_vio()
-{
- if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) {
- return 0;
- }
-
- return 0;
-}
diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h
index afeb03c..d6cdf06 100644
--- a/iocore/net/quic/QUICStream.h
+++ b/iocore/net/quic/QUICStream.h
@@ -37,6 +37,9 @@
#include "QUICFrameRetransmitter.h"
#include "QUICDebugNames.h"
+class QUICStreamAdapter;
+class QUICStreamStateListener;
+
/**
* @brief QUIC Stream
* TODO: This is similar to Http2Stream. Need to think some integration.
@@ -54,6 +57,14 @@ public:
bool is_bidirectional() const;
QUICOffset final_offset() const;
+ /**
+ * Set an adapter to read/write data from/to this stream
+ *
+ * This is an interface for QUICApplication. An application can set an adapter
+ * to access data in the way the applications wants.
+ */
+ void set_io_adapter(QUICStreamAdapter *adapter);
+
/*
* QUICApplication need to call one of these functions when it process VC_EVENT_*
*/
@@ -74,6 +85,8 @@ public:
virtual void stop_sending(QUICStreamErrorUPtr error);
virtual void reset(QUICStreamErrorUPtr error);
+ void set_state_listener(QUICStreamStateListener *listener);
+
LINK(QUICStream, link);
protected:
@@ -82,41 +95,23 @@ protected:
QUICOffset _send_offset = 0;
QUICOffset _reordered_bytes = 0;
+ QUICStreamAdapter *_adapter = nullptr;
+ QUICStreamStateListener *_state_listener = nullptr;
+
+ virtual void _on_adapter_updated(){};
+
+ void _notify_state_change();
+
void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame);
void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame);
void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame);
void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame);
};
-// This is VConnection class for VIO operation.
-class QUICStreamVConnection : public VConnection, public QUICStream
+class QUICStreamStateListener
{
public:
- QUICStreamVConnection(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) : VConnection(nullptr), QUICStream(cinfo, sid)
- {
- mutex = new_ProxyMutex();
- }
-
- QUICStreamVConnection() : VConnection(nullptr) {}
- virtual ~QUICStreamVConnection();
-
- LINK(QUICStreamVConnection, link);
-
-protected:
- virtual int64_t _process_read_vio();
- virtual int64_t _process_write_vio();
- void _signal_read_event();
- void _signal_write_event();
- void _signal_read_eos_event();
- Event *_send_tracked_event(Event *, int, VIO *);
-
- void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin);
-
- VIO _read_vio;
- VIO _write_vio;
-
- Event *_read_event = nullptr;
- Event *_write_event = nullptr;
+ virtual void on_stream_state_close(const QUICStream *stream) = 0;
};
#define QUICStreamDebug(fmt, ...) \
diff --git a/proxy/http3/Http3FrameGenerator.h b/iocore/net/quic/QUICStreamAdapter.cc
similarity index 78%
copy from proxy/http3/Http3FrameGenerator.h
copy to iocore/net/quic/QUICStreamAdapter.cc
index 6da188f..8534781 100644
--- a/proxy/http3/Http3FrameGenerator.h
+++ b/iocore/net/quic/QUICStreamAdapter.cc
@@ -21,14 +21,12 @@
* limitations under the License.
*/
-#pragma once
+#include "QUICStreamAdapter.h"
-#include "Http3Frame.h"
-
-class Http3FrameGenerator
+Ptr<IOBufferBlock>
+QUICStreamAdapter::read(size_t len)
{
-public:
- virtual ~Http3FrameGenerator(){};
- virtual Http3FrameUPtr generate_frame(uint16_t max_size) = 0;
- virtual bool is_done() const = 0;
-};
+ auto ret = this->_read(len);
+ this->_stream.on_read();
+ return ret;
+}
diff --git a/proxy/http3/Http09App.h b/iocore/net/quic/QUICStreamAdapter.h
similarity index 50%
copy from proxy/http3/Http09App.h
copy to iocore/net/quic/QUICStreamAdapter.h
index ab35399..3c3a0e3 100644
--- a/proxy/http3/Http09App.h
+++ b/iocore/net/quic/QUICStreamAdapter.h
@@ -23,29 +23,43 @@
#pragma once
-#include "IPAllow.h"
+#include "QUICStream.h"
-#include "HttpSessionAccept.h"
+class QUICStreamAdapter
+{
+public:
+ QUICStreamAdapter(QUICStream &stream) : _stream(stream) {}
+ virtual ~QUICStreamAdapter() = default;
-#include "QUICApplication.h"
+ QUICStream &
+ stream()
+ {
+ return _stream;
+ }
-class QUICNetVConnection;
-class Http09Session;
+ virtual int64_t write(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) = 0;
+ Ptr<IOBufferBlock> read(size_t len);
+ virtual bool is_eos() = 0;
+ virtual uint64_t unread_len() = 0;
+ virtual uint64_t read_len() = 0;
+ virtual uint64_t total_len() = 0;
-/**
- * @brief A simple multi-streamed application.
- * @detail Response to simple HTTP/0.9 GETs
- * This will be removed when HTTP/0.9 over QUIC support is dropped
- *
- */
-class Http09App : public QUICApplication
-{
-public:
- Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options);
- ~Http09App();
+ /**
+ * Tell the application that there is data to read
+ */
+ virtual void encourge_read() = 0;
+
+ /**
+ * Tell the application that there is some space to write data
+ */
+ virtual void encourge_write() = 0;
- int main_event_handler(int event, Event *data);
+ /**
+ * Tell the application that there is no more data to read
+ */
+ virtual void notify_eos() = 0;
-private:
- Http09Session *_ssn = nullptr;
+protected:
+ virtual Ptr<IOBufferBlock> _read(size_t len) = 0;
+ QUICStream &_stream;
};
diff --git a/iocore/net/quic/QUICStreamFactory.cc b/iocore/net/quic/QUICStreamFactory.cc
index 548be10..1f09c75 100644
--- a/iocore/net/quic/QUICStreamFactory.cc
+++ b/iocore/net/quic/QUICStreamFactory.cc
@@ -26,10 +26,10 @@
#include "QUICUnidirectionalStream.h"
#include "QUICStreamFactory.h"
-QUICStreamVConnection *
+QUICStream *
QUICStreamFactory::create(QUICStreamId sid, uint64_t local_max_stream_data, uint64_t remote_max_stream_data)
{
- QUICStreamVConnection *stream = nullptr;
+ QUICStream *stream = nullptr;
switch (QUICTypeUtil::detect_stream_direction(sid, this->_info->direction())) {
case QUICStreamDirection::BIDIRECTIONAL:
stream = new QUICBidirectionalStream(this->_rtt_provider, this->_info, sid, local_max_stream_data, remote_max_stream_data);
@@ -50,7 +50,7 @@ QUICStreamFactory::create(QUICStreamId sid, uint64_t local_max_stream_data, uint
}
void
-QUICStreamFactory::delete_stream(QUICStreamVConnection *stream)
+QUICStreamFactory::delete_stream(QUICStream *stream)
{
delete stream;
}
diff --git a/iocore/net/quic/QUICStreamFactory.h b/iocore/net/quic/QUICStreamFactory.h
index fd497bf..43690ed 100644
--- a/iocore/net/quic/QUICStreamFactory.h
+++ b/iocore/net/quic/QUICStreamFactory.h
@@ -25,7 +25,7 @@
#include "QUICTypes.h"
-class QUICStreamVConnection;
+class QUICStream;
// PS: this class function should not static because of THREAD_ALLOC and THREAD_FREE
class QUICStreamFactory
@@ -35,10 +35,10 @@ public:
~QUICStreamFactory() {}
// create a bidistream, send only stream or receive only stream
- QUICStreamVConnection *create(QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data);
+ QUICStream *create(QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data);
// delete stream by stream type
- void delete_stream(QUICStreamVConnection *stream);
+ void delete_stream(QUICStream *stream);
private:
QUICRTTProvider *_rtt_provider = nullptr;
diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc
index 54a6d20..2338321 100644
--- a/iocore/net/quic/QUICStreamManager.cc
+++ b/iocore/net/quic/QUICStreamManager.cc
@@ -94,17 +94,14 @@ QUICConnectionErrorUPtr
QUICStreamManager::create_stream(QUICStreamId stream_id)
{
// TODO: check stream_id
- QUICConnectionErrorUPtr error = nullptr;
- QUICStreamVConnection *stream_vc = this->_find_or_create_stream_vc(stream_id);
- if (!stream_vc) {
+ QUICConnectionErrorUPtr error = nullptr;
+ QUICStream *stream = this->_find_or_create_stream(stream_id);
+ if (!stream) {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::STREAM_LIMIT_ERROR);
}
QUICApplication *application = this->_app_map->get(stream_id);
-
- if (!application->is_stream_set(stream_vc)) {
- application->set_stream(stream_vc);
- }
+ application->on_new_stream(*stream);
return error;
}
@@ -136,7 +133,7 @@ QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id)
void
QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error)
{
- auto stream = this->_find_stream_vc(stream_id);
+ auto stream = this->_find_stream(stream_id);
stream->reset(std::move(error));
}
@@ -177,7 +174,7 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram
QUICConnectionErrorUPtr
QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame)
{
- QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id());
+ QUICStream *stream = this->_find_or_create_stream(frame.stream_id());
if (stream) {
return stream->recv(frame);
} else {
@@ -188,7 +185,7 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame)
QUICConnectionErrorUPtr
QUICStreamManager::_handle_frame(const QUICStreamDataBlockedFrame &frame)
{
- QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id());
+ QUICStream *stream = this->_find_or_create_stream(frame.stream_id());
if (stream) {
return stream->recv(frame);
} else {
@@ -199,24 +196,18 @@ QUICStreamManager::_handle_frame(const QUICStreamDataBlockedFrame &frame)
QUICConnectionErrorUPtr
QUICStreamManager::_handle_frame(const QUICStreamFrame &frame)
{
- QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id());
- if (!stream) {
+ QUICStream *stream = this->_find_or_create_stream(frame.stream_id());
+ if (stream) {
+ return stream->recv(frame);
+ } else {
return std::make_unique<QUICConnectionError>(QUICTransErrorCode::STREAM_LIMIT_ERROR);
}
-
- QUICApplication *application = this->_app_map->get(frame.stream_id());
-
- if (application && !application->is_stream_set(stream)) {
- application->set_stream(stream);
- }
-
- return stream->recv(frame);
}
QUICConnectionErrorUPtr
QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame)
{
- QUICStream *stream = this->_find_or_create_stream_vc(frame.stream_id());
+ QUICStream *stream = this->_find_or_create_stream(frame.stream_id());
if (stream) {
return stream->recv(frame);
} else {
@@ -227,7 +218,7 @@ QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame)
QUICConnectionErrorUPtr
QUICStreamManager::_handle_frame(const QUICStopSendingFrame &frame)
{
- QUICStream *stream = this->_find_or_create_stream_vc(frame.stream_id());
+ QUICStream *stream = this->_find_or_create_stream(frame.stream_id());
if (stream) {
return stream->recv(frame);
} else {
@@ -247,10 +238,10 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamsFrame &frame)
return nullptr;
}
-QUICStreamVConnection *
-QUICStreamManager::_find_stream_vc(QUICStreamId id)
+QUICStream *
+QUICStreamManager::_find_stream(QUICStreamId id)
{
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
if (s->id() == id) {
return s;
}
@@ -258,10 +249,10 @@ QUICStreamManager::_find_stream_vc(QUICStreamId id)
return nullptr;
}
-QUICStreamVConnection *
-QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
+QUICStream *
+QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id)
{
- QUICStreamVConnection *stream = this->_find_stream_vc(stream_id);
+ QUICStream *stream = this->_find_stream(stream_id);
if (!stream) {
if (!this->_local_tp) {
return nullptr;
@@ -353,7 +344,11 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id)
stream = this->_stream_factory.create(stream_id, local_max_stream_data, remote_max_stream_data);
ink_assert(stream != nullptr);
+ stream->set_state_listener(this);
this->stream_list.push(stream);
+
+ QUICApplication *application = this->_app_map->get(stream_id);
+ application->on_new_stream(*stream);
}
return stream;
@@ -365,7 +360,7 @@ QUICStreamManager::total_reordered_bytes() const
uint64_t total_bytes = 0;
// FIXME Iterating all (open + closed) streams is expensive
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
total_bytes += s->reordered_bytes();
}
return total_bytes;
@@ -377,7 +372,7 @@ QUICStreamManager::total_offset_received() const
uint64_t total_offset_received = 0;
// FIXME Iterating all (open + closed) streams is expensive
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
total_offset_received += s->largest_offset_received();
}
return total_offset_received;
@@ -400,7 +395,7 @@ uint32_t
QUICStreamManager::stream_count() const
{
uint32_t count = 0;
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
++count;
}
return count;
@@ -429,7 +424,7 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level, size_t current
return false;
}
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
if (s->will_generate_frame(level, current_packet_size, ack_eliciting, seq_num)) {
return true;
}
@@ -454,7 +449,7 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6
}
// FIXME We should pick a stream based on priority
- for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) {
+ for (QUICStream *s = this->stream_list.head; s; s = s->link.next) {
frame = s->generate_frame(buf, level, connection_credit, maximum_frame_size, current_packet_size, seq_num);
if (frame) {
break;
@@ -468,6 +463,34 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6
return frame;
}
+void
+QUICStreamManager::on_stream_state_close(const QUICStream *stream)
+{
+ auto direction = this->_context->connection_info()->direction();
+ switch (QUICTypeUtil::detect_stream_type(stream->id())) {
+ case QUICStreamType::SERVER_BIDI:
+ if (direction == NET_VCONNECTION_OUT) {
+ this->_local_max_streams_bidi += 1;
+ }
+ break;
+ case QUICStreamType::SERVER_UNI:
+ if (direction == NET_VCONNECTION_OUT) {
+ this->_local_max_streams_uni += 1;
+ }
+ break;
+ case QUICStreamType::CLIENT_BIDI:
+ if (direction == NET_VCONNECTION_IN) {
+ this->_local_max_streams_bidi += 1;
+ }
+ break;
+ case QUICStreamType::CLIENT_UNI:
+ if (direction == NET_VCONNECTION_IN) {
+ this->_local_max_streams_uni += 1;
+ }
+ break;
+ }
+}
+
bool
QUICStreamManager::_is_level_matched(QUICEncryptionLevel level)
{
diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h
index f158035..a52a375 100644
--- a/iocore/net/quic/QUICStreamManager.h
+++ b/iocore/net/quic/QUICStreamManager.h
@@ -36,7 +36,7 @@
class QUICTransportParameters;
-class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator
+class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator, public QUICStreamStateListener
{
public:
QUICStreamManager(QUICContext *context, QUICApplicationMap *app_map);
@@ -58,7 +58,7 @@ public:
void set_default_application(QUICApplication *app);
- DLL<QUICStreamVConnection> stream_list;
+ DLL<QUICStream> stream_list;
// QUICFrameHandler
virtual std::vector<QUICFrameType> interests() override;
@@ -69,12 +69,15 @@ public:
QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size,
size_t current_packet_size, uint32_t timestamp) override;
+ // QUICStreamStateListener
+ void on_stream_state_close(const QUICStream *stream) override;
+
protected:
virtual bool _is_level_matched(QUICEncryptionLevel level) override;
private:
- QUICStreamVConnection *_find_stream_vc(QUICStreamId id);
- QUICStreamVConnection *_find_or_create_stream_vc(QUICStreamId stream_id);
+ QUICStream *_find_stream(QUICStreamId id);
+ QUICStream *_find_or_create_stream(QUICStreamId stream_id);
void _add_total_offset_sent(uint32_t sent_byte);
QUICConnectionErrorUPtr _handle_frame(const QUICStreamFrame &frame);
QUICConnectionErrorUPtr _handle_frame(const QUICRstStreamFrame &frame);
diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc
index 7c5b8d1..e5ddb6c 100644
--- a/iocore/net/quic/QUICStreamState.cc
+++ b/iocore/net/quic/QUICStreamState.cc
@@ -72,14 +72,16 @@ QUICReceiveStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const
return false;
}
-void
+bool
QUICReceiveStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
+ return false;
}
-void
+bool
QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
+ bool state_changed = false;
// The receiving part of a stream initiated by a peer (types 1 and 3 for a client, or 0 and 2 for a server) is created when the
// first STREAM, STREAM_DATA_BLOCKED, or RESET_STREAM is received for that stream.
QUICReceiveStreamState state = this->get();
@@ -87,32 +89,32 @@ QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &fram
if (state == QUICReceiveStreamState::Init &&
(type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) {
- this->_set_state(QUICReceiveStreamState::Recv);
+ state_changed |= this->_set_state(QUICReceiveStreamState::Recv);
}
switch (this->get()) {
case QUICReceiveStreamState::Recv:
if (type == QUICFrameType::STREAM) {
if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
- this->_set_state(QUICReceiveStreamState::SizeKnown);
+ state_changed |= this->_set_state(QUICReceiveStreamState::SizeKnown);
if (this->_in_progress->is_transfer_complete()) {
- this->_set_state(QUICReceiveStreamState::DataRecvd);
+ state_changed |= this->_set_state(QUICReceiveStreamState::DataRecvd);
}
}
} else if (type == QUICFrameType::RESET_STREAM) {
- this->_set_state(QUICReceiveStreamState::ResetRecvd);
+ state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::SizeKnown:
if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) {
- this->_set_state(QUICReceiveStreamState::DataRecvd);
+ state_changed |= this->_set_state(QUICReceiveStreamState::DataRecvd);
} else if (type == QUICFrameType::RESET_STREAM) {
- this->_set_state(QUICReceiveStreamState::ResetRecvd);
+ state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::DataRecvd:
if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) {
- this->_set_state(QUICReceiveStreamState::ResetRecvd);
+ state_changed |= this->_set_state(QUICReceiveStreamState::ResetRecvd);
}
break;
case QUICReceiveStreamState::Init:
@@ -124,23 +126,25 @@ QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &fram
ink_assert(!"Unknown state");
break;
}
+ return state_changed;
}
-void
+bool
QUICReceiveStreamStateMachine::update_on_read()
{
if (this->_in_progress->is_transfer_complete()) {
- this->_set_state(QUICReceiveStreamState::DataRead);
+ return this->_set_state(QUICReceiveStreamState::DataRead);
}
+ return false;
}
-void
+bool
QUICReceiveStreamStateMachine::update_on_eos()
{
- this->_set_state(QUICReceiveStreamState::ResetRead);
+ return this->_set_state(QUICReceiveStreamState::ResetRead);
}
-void
+bool
QUICReceiveStreamStateMachine::update(const QUICSendStreamState state)
{
// The receiving part of a stream enters the "Recv" state when the sending part of a bidirectional stream initiated by the
@@ -148,12 +152,14 @@ QUICReceiveStreamStateMachine::update(const QUICSendStreamState state)
switch (this->get()) {
case QUICReceiveStreamState::Init:
if (state == QUICSendStreamState::Ready) {
- this->_set_state(QUICReceiveStreamState::Recv);
+ return this->_set_state(QUICReceiveStreamState::Recv);
}
break;
default:
break;
}
+
+ return false;
}
// ---------- QUICSendStreamState -------------
@@ -251,29 +257,30 @@ QUICSendStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const
return false;
}
-void
+bool
QUICSendStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
+ bool state_changed = false;
QUICSendStreamState state = this->get();
QUICFrameType type = frame.type();
if (state == QUICSendStreamState::Ready &&
(type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) {
- this->_set_state(QUICSendStreamState::Send);
+ state_changed |= this->_set_state(QUICSendStreamState::Send);
}
switch (this->get()) {
case QUICSendStreamState::Send:
if (type == QUICFrameType::STREAM) {
if (static_cast<const QUICStreamFrame &>(frame).has_fin_flag()) {
- this->_set_state(QUICSendStreamState::DataSent);
+ state_changed |= this->_set_state(QUICSendStreamState::DataSent);
}
} else if (type == QUICFrameType::RESET_STREAM) {
- this->_set_state(QUICSendStreamState::ResetSent);
+ state_changed |= this->_set_state(QUICSendStreamState::ResetSent);
}
break;
case QUICSendStreamState::DataSent:
if (type == QUICFrameType::RESET_STREAM) {
- this->_set_state(QUICSendStreamState::ResetSent);
+ state_changed |= this->_set_state(QUICSendStreamState::ResetSent);
}
break;
case QUICSendStreamState::Init:
@@ -286,37 +293,42 @@ QUICSendStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
ink_assert(!"Unknown state");
break;
}
+ return state_changed;
}
-void
+bool
QUICSendStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
+ return false;
}
-void
+bool
QUICSendStreamStateMachine::update_on_ack()
{
if (this->_out_progress->is_transfer_complete()) {
- this->_set_state(QUICSendStreamState::DataRecvd);
+ return this->_set_state(QUICSendStreamState::DataRecvd);
} else if (this->_out_progress->is_cancelled()) {
- this->_set_state(QUICSendStreamState::ResetRecvd);
+ return this->_set_state(QUICSendStreamState::ResetRecvd);
}
+ return false;
}
-void
+bool
QUICSendStreamStateMachine::update(const QUICReceiveStreamState state)
{
+ bool state_changed = false;
// The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the "Ready"
// state then immediately transitions to the "Send" state if the receiving part enters the "Recv" state (Section 3.2).
switch (this->get()) {
case QUICSendStreamState::Ready:
if (state == QUICReceiveStreamState::Recv) {
- this->_set_state(QUICSendStreamState::Send);
+ state_changed |= this->_set_state(QUICSendStreamState::Send);
}
break;
default:
break;
}
+ return state_changed;
}
// ---------QUICBidirectionalStreamState -----------
@@ -369,48 +381,56 @@ QUICBidirectionalStreamStateMachine::get() const
}
}
-void
+bool
QUICBidirectionalStreamStateMachine::update_with_sending_frame(const QUICFrame &frame)
{
+ bool state_changed = false;
+
// The receiving part of a stream enters the "Recv" state when the sending part of a bidirectional stream initiated by the
// endpoint (type 0 for a client, type 1 for a server) enters the "Ready" state.
- this->_send_stream_state.update_with_sending_frame(frame);
+ state_changed |= this->_send_stream_state.update_with_sending_frame(frame);
// PS: It should not happen because we initialize the send side and read side together. And the SendState has the default state
// "Ready". But to obey the specs, we do this as follow.
if (this->_send_stream_state.get() == QUICSendStreamState::Ready &&
this->_recv_stream_state.get() == QUICReceiveStreamState::Init) {
- this->_recv_stream_state.update(this->_send_stream_state.get());
+ state_changed |= this->_recv_stream_state.update(this->_send_stream_state.get());
}
+
+ return state_changed;
}
-void
+bool
QUICBidirectionalStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame)
{
+ bool state_changed = false;
+
// The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the "Ready"
// state then immediately transitions to the "Send" state if the receiving part enters the "Recv" state (Section 3.2).
- this->_recv_stream_state.update_with_receiving_frame(frame);
+ state_changed |= this->_recv_stream_state.update_with_receiving_frame(frame);
if (this->_send_stream_state.get() == QUICSendStreamState::Ready &&
this->_recv_stream_state.get() == QUICReceiveStreamState::Recv) {
- this->_send_stream_state.update(this->_recv_stream_state.get());
+ state_changed |= this->_send_stream_state.update(this->_recv_stream_state.get());
}
+
+ return state_changed;
}
-void
+bool
QUICBidirectionalStreamStateMachine::update_on_ack()
{
- this->_send_stream_state.update_on_ack();
+ return this->_send_stream_state.update_on_ack();
}
-void
+bool
QUICBidirectionalStreamStateMachine::update_on_read()
{
- this->_recv_stream_state.update_on_read();
+ return this->_recv_stream_state.update_on_read();
}
-void
+bool
QUICBidirectionalStreamStateMachine::update_on_eos()
{
- this->_recv_stream_state.update_on_eos();
+ return this->_recv_stream_state.update_on_eos();
}
bool
diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h
index f95bfc0..235bfa3 100644
--- a/iocore/net/quic/QUICStreamState.h
+++ b/iocore/net/quic/QUICStreamState.h
@@ -67,8 +67,8 @@ public:
return this->_state;
}
- virtual void update_with_sending_frame(const QUICFrame &frame) = 0;
- virtual void update_with_receiving_frame(const QUICFrame &frame) = 0;
+ [[nodiscard]] virtual bool update_with_sending_frame(const QUICFrame &frame) = 0;
+ [[nodiscard]] virtual bool update_with_receiving_frame(const QUICFrame &frame) = 0;
virtual bool is_allowed_to_send(QUICFrameType type) const = 0;
virtual bool is_allowed_to_send(const QUICFrame &frame) const = 0;
@@ -76,11 +76,16 @@ public:
virtual bool is_allowed_to_receive(const QUICFrame &frame) const = 0;
protected:
- void
+ bool
_set_state(T s)
{
ink_assert(s != T::Init);
- this->_state = s;
+ if (this->_state != s) {
+ this->_state = s;
+ return true;
+ } else {
+ return false;
+ }
}
private:
@@ -109,16 +114,16 @@ public:
this->_set_state(QUICSendStreamState::Ready);
}
- void update_with_sending_frame(const QUICFrame &frame) override;
- void update_with_receiving_frame(const QUICFrame &frame) override;
- void update_on_ack();
+ [[nodiscard]] bool update_with_sending_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_with_receiving_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_on_ack();
bool is_allowed_to_send(QUICFrameType type) const override;
bool is_allowed_to_send(const QUICFrame &frame) const override;
bool is_allowed_to_receive(QUICFrameType type) const override;
bool is_allowed_to_receive(const QUICFrame &frame) const override;
- void update(const QUICReceiveStreamState opposite_side);
+ [[nodiscard]] bool update(const QUICReceiveStreamState opposite_side);
};
class QUICReceiveStreamStateMachine : public QUICUnidirectionalStreamStateMachine,
@@ -130,17 +135,17 @@ public:
{
}
- void update_with_sending_frame(const QUICFrame &frame) override;
- void update_with_receiving_frame(const QUICFrame &frame) override;
- void update_on_read();
- void update_on_eos();
+ [[nodiscard]] bool update_with_sending_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_with_receiving_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_on_read();
+ [[nodiscard]] bool update_on_eos();
bool is_allowed_to_send(QUICFrameType type) const override;
bool is_allowed_to_send(const QUICFrame &frame) const override;
bool is_allowed_to_receive(QUICFrameType type) const override;
bool is_allowed_to_receive(const QUICFrame &frame) const override;
- void update(const QUICSendStreamState opposite_side);
+ [[nodiscard]] bool update(const QUICSendStreamState opposite_side);
};
class QUICBidirectionalStreamStateMachine : public QUICStreamStateMachine<QUICBidirectionalStreamState>
@@ -150,16 +155,16 @@ public:
QUICTransferProgressProvider *recv_in, QUICTransferProgressProvider *recv_out)
: _send_stream_state(send_in, send_out), _recv_stream_state(recv_in, recv_out)
{
- this->_recv_stream_state.update(this->_send_stream_state.get());
+ ink_assert(this->_recv_stream_state.update(this->_send_stream_state.get()));
};
QUICBidirectionalStreamState get() const override;
- void update_with_sending_frame(const QUICFrame &frame) override;
- void update_with_receiving_frame(const QUICFrame &frame) override;
- void update_on_ack();
- void update_on_read();
- void update_on_eos();
+ [[nodiscard]] bool update_with_sending_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_with_receiving_frame(const QUICFrame &frame) override;
+ [[nodiscard]] bool update_on_ack();
+ [[nodiscard]] bool update_on_read();
+ [[nodiscard]] bool update_on_eos();
bool is_allowed_to_send(QUICFrameType type) const override;
bool is_allowed_to_send(const QUICFrame &frame) const override;
diff --git a/iocore/net/quic/QUICStreamVCAdapter.cc b/iocore/net/quic/QUICStreamVCAdapter.cc
new file mode 100644
index 0000000..b8c4afc
--- /dev/null
+++ b/iocore/net/quic/QUICStreamVCAdapter.cc
@@ -0,0 +1,320 @@
+/** @file
+ *
+ * A brief file description
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "I_VConnection.h"
+#include "QUICStreamVCAdapter.h"
+
+QUICStreamVCAdapter::QUICStreamVCAdapter(QUICStream &stream) : QUICStreamAdapter(stream), VConnection(new_ProxyMutex())
+{
+ SET_HANDLER(&QUICStreamVCAdapter::state_stream_open);
+}
+
+QUICStreamVCAdapter::~QUICStreamVCAdapter()
+{
+ if (this->_read_event) {
+ this->_read_event->cancel();
+ this->_read_event = nullptr;
+ }
+
+ if (this->_write_event) {
+ this->_write_event->cancel();
+ this->_write_event = nullptr;
+ }
+}
+
+int64_t
+QUICStreamVCAdapter::write(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin)
+{
+ uint64_t bytes_added = -1;
+ if (this->_read_vio.op == VIO::READ) {
+ SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
+
+ bytes_added = this->_read_vio.get_writer()->write(data, data_length);
+
+ // Until receive FIN flag, keep nbytes INT64_MAX
+ if (fin && bytes_added == data_length) {
+ this->_read_vio.nbytes = offset + data_length;
+ }
+ }
+
+ return bytes_added;
+}
+
+Ptr<IOBufferBlock>
+QUICStreamVCAdapter::_read(size_t len)
+{
+ Ptr<IOBufferBlock> block;
+
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+
+ IOBufferReader *reader = this->_write_vio.get_reader();
+ block = make_ptr<IOBufferBlock>(reader->get_current_block()->clone());
+ if (block->size()) {
+ block->consume(reader->start_offset);
+ block->_end = std::min(block->start() + len, block->_buf_end);
+ this->_write_vio.ndone += len;
+ }
+ reader->consume(block->size());
+ }
+
+ return block;
+}
+
+bool
+QUICStreamVCAdapter::is_eos()
+{
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+
+ if (this->_write_vio.nbytes == INT64_MAX) {
+ return false;
+ }
+ if (this->_write_vio.ntodo() != 0) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint64_t
+QUICStreamVCAdapter::unread_len()
+{
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+ return this->_write_vio.get_reader()->block_read_avail();
+ } else {
+ return 0;
+ }
+}
+
+uint64_t
+QUICStreamVCAdapter::read_len()
+{
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+ return this->_write_vio.ndone;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t
+QUICStreamVCAdapter::total_len()
+{
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+ return this->_write_vio.nbytes;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * @brief Signal event to this->_read_vio.cont
+ */
+void
+QUICStreamVCAdapter::encourge_read()
+{
+ if (this->_read_vio.op == VIO::READ) {
+ SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
+
+ if (this->_read_vio.cont == nullptr) {
+ return;
+ }
+
+ int event = this->_read_vio.nbytes == INT64_MAX ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE;
+ this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio);
+ }
+}
+
+/**
+ * @brief Signal event to this->_write_vio.cont
+ */
+void
+QUICStreamVCAdapter::encourge_write()
+{
+ if (this->_write_vio.op == VIO::WRITE) {
+ SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+
+ if (this->_write_vio.cont == nullptr) {
+ return;
+ }
+
+ int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE;
+ this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio);
+ }
+}
+
+/**
+ * @brief Signal event to this->_read_vio.cont
+ */
+void
+QUICStreamVCAdapter::notify_eos()
+{
+ if (this->_read_vio.op == VIO::READ) {
+ if (this->_read_vio.cont == nullptr) {
+ return;
+ }
+ int event = VC_EVENT_EOS;
+
+ MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread());
+ if (lock.is_locked()) {
+ this->_read_vio.cont->handleEvent(event, &this->_read_vio);
+ } else {
+ this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio);
+ }
+ }
+}
+
+// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag
+VIO *
+QUICStreamVCAdapter::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
+{
+ if (buf) {
+ this->_read_vio.buffer.writer_for(buf);
+ } else {
+ this->_read_vio.buffer.clear();
+ }
+
+ this->_read_vio.mutex = c ? c->mutex : this->mutex;
+ this->_read_vio.cont = c;
+ this->_read_vio.nbytes = nbytes;
+ this->_read_vio.ndone = 0;
+ this->_read_vio.vc_server = this;
+ this->_read_vio.op = VIO::READ;
+
+ return &this->_read_vio;
+}
+
+VIO *
+QUICStreamVCAdapter::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
+{
+ if (buf) {
+ this->_write_vio.buffer.reader_for(buf);
+ } else {
+ this->_write_vio.buffer.clear();
+ }
+
+ this->_write_vio.mutex = c ? c->mutex : this->mutex;
+ this->_write_vio.cont = c;
+ this->_write_vio.nbytes = nbytes;
+ this->_write_vio.ndone = 0;
+ this->_write_vio.vc_server = this;
+ this->_write_vio.op = VIO::WRITE;
+
+ return &this->_write_vio;
+}
+
+void
+QUICStreamVCAdapter::do_io_close(int lerrno)
+{
+ SET_HANDLER(&QUICStreamVCAdapter::state_stream_closed);
+
+ this->_read_vio.buffer.clear();
+ this->_read_vio.nbytes = 0;
+ this->_read_vio.op = VIO::NONE;
+ this->_read_vio.cont = nullptr;
+
+ this->_write_vio.buffer.clear();
+ this->_write_vio.nbytes = 0;
+ this->_write_vio.op = VIO::NONE;
+ this->_write_vio.cont = nullptr;
+}
+
+void
+QUICStreamVCAdapter::do_io_shutdown(ShutdownHowTo_t howto)
+{
+ ink_assert(false); // unimplemented yet
+ return;
+}
+
+void
+QUICStreamVCAdapter::reenable(VIO *vio)
+{
+ // TODO We probably need to tell QUICStream that the application consumed received data
+ // to update receive window here. In other words, we should not update receive window
+ // until the application consume data.
+}
+
+int
+QUICStreamVCAdapter::state_stream_open(int event, void *data)
+{
+ QUICErrorUPtr error = nullptr;
+
+ switch (event) {
+ case VC_EVENT_READ_READY:
+ case VC_EVENT_READ_COMPLETE: {
+ this->encourge_read();
+ break;
+ }
+ case VC_EVENT_WRITE_READY:
+ case VC_EVENT_WRITE_COMPLETE: {
+ this->encourge_write();
+ break;
+ }
+ case VC_EVENT_EOS:
+ case VC_EVENT_ERROR:
+ case VC_EVENT_INACTIVITY_TIMEOUT:
+ case VC_EVENT_ACTIVE_TIMEOUT: {
+ // TODO
+ ink_assert(false);
+ break;
+ }
+ default:
+ ink_assert(false);
+ }
+
+ return EVENT_DONE;
+}
+
+int
+QUICStreamVCAdapter::state_stream_closed(int event, void *data)
+{
+ switch (event) {
+ case VC_EVENT_READ_READY:
+ case VC_EVENT_READ_COMPLETE: {
+ // ignore
+ break;
+ }
+ case VC_EVENT_WRITE_READY:
+ case VC_EVENT_WRITE_COMPLETE: {
+ // ignore
+ break;
+ }
+ case VC_EVENT_EOS:
+ case VC_EVENT_ERROR:
+ case VC_EVENT_INACTIVITY_TIMEOUT:
+ case VC_EVENT_ACTIVE_TIMEOUT: {
+ // TODO
+ ink_assert(false);
+ break;
+ }
+ default:
+ ink_assert(false);
+ }
+
+ return EVENT_DONE;
+}
diff --git a/iocore/net/quic/QUICStreamVCAdapter.h b/iocore/net/quic/QUICStreamVCAdapter.h
new file mode 100644
index 0000000..3613159
--- /dev/null
+++ b/iocore/net/quic/QUICStreamVCAdapter.h
@@ -0,0 +1,105 @@
+/** @file
+ *
+ * A brief file description
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include "QUICStreamAdapter.h"
+#include "I_IOBuffer.h"
+
+class QUICStreamVCAdapter : public QUICStreamAdapter, public VConnection
+{
+public:
+ class IOInfo;
+
+ QUICStreamVCAdapter(QUICStream &stream);
+ virtual ~QUICStreamVCAdapter();
+
+ // Implement QUICStreamAdapter Interface
+ int64_t write(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) override;
+ void encourge_read() override;
+ bool is_eos() override;
+ uint64_t unread_len() override;
+ uint64_t read_len() override;
+ uint64_t total_len() override;
+ void encourge_write() override;
+ void notify_eos() override;
+
+ // Implement VConnection Interface.
+ VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override;
+ VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override;
+ void do_io_close(int lerrno = -1) override;
+ void do_io_shutdown(ShutdownHowTo_t howto) override;
+ void reenable(VIO *vio) override;
+
+ int state_stream_open(int event, void *data);
+ int state_stream_closed(int event, void *data);
+
+protected:
+ Ptr<IOBufferBlock> _read(size_t len) override;
+
+ VIO _read_vio;
+ VIO _write_vio;
+
+ Event *_read_event = nullptr;
+ Event *_write_event = nullptr;
+};
+
+class QUICStreamVCAdapter::IOInfo
+{
+public:
+ IOInfo(QUICStream &stream)
+ : adapter(stream), read_buffer(new_MIOBuffer(BUFFER_SIZE_INDEX_8K)), write_buffer(new_MIOBuffer(BUFFER_SIZE_INDEX_8K))
+ {
+ }
+ ~IOInfo()
+ {
+ free_MIOBuffer(this->read_buffer);
+ free_MIOBuffer(this->write_buffer);
+ }
+
+ void
+ setup_read_vio(Continuation *c)
+ {
+ read_vio = adapter.do_io_read(c, INT64_MAX, read_buffer);
+
+ // This is uncommon but it has basically the same effect as
+ // read_buffer->alloc_reader, and it allows VIO user to obtain the
+ // reader by calling read_vio.get_reader()
+ // It limits a number of readers to one, but it wouldn't be a real
+ // limitation for this particular usecase in QUICStreamVCAdapter.
+ read_vio->set_reader(read_buffer->alloc_reader());
+ adapter.encourge_read();
+ }
+
+ void
+ setup_write_vio(Continuation *c)
+ {
+ write_vio = adapter.do_io_write(c, INT64_MAX, write_buffer->alloc_reader());
+ adapter.encourge_write();
+ }
+
+ QUICStreamVCAdapter adapter;
+ MIOBuffer *read_buffer;
+ MIOBuffer *write_buffer;
+ VIO *read_vio = nullptr;
+ VIO *write_vio = nullptr;
+};
diff --git a/iocore/net/quic/QUICTransferProgressProvider.cc b/iocore/net/quic/QUICTransferProgressProvider.cc
new file mode 100644
index 0000000..a01198b
--- /dev/null
+++ b/iocore/net/quic/QUICTransferProgressProvider.cc
@@ -0,0 +1,83 @@
+/** @file
+ *
+ * Interface for providing transfer progress
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "I_IOBuffer.h"
+#include "QUICStreamAdapter.h"
+
+void
+QUICTransferProgressProviderSA::set_stream_adapter(QUICStreamAdapter *adapter)
+{
+ this->_adapter = adapter;
+}
+
+bool
+QUICTransferProgressProviderSA::is_transfer_goal_set() const
+{
+ return this->transfer_goal() != INT64_MAX;
+}
+
+uint64_t
+QUICTransferProgressProviderSA::transfer_progress() const
+{
+ return this->_adapter->read_len();
+}
+
+uint64_t
+QUICTransferProgressProviderSA::transfer_goal() const
+{
+ return this->_adapter->total_len();
+}
+
+bool
+QUICTransferProgressProviderSA::is_cancelled() const
+{
+ return false;
+}
+
+//
+// QUICTransferProgressProviderVIO::
+//
+
+bool
+QUICTransferProgressProviderVIO::is_transfer_goal_set() const
+{
+ return this->_vio.nbytes != INT64_MAX;
+}
+
+uint64_t
+QUICTransferProgressProviderVIO::transfer_progress() const
+{
+ return this->_vio.ndone;
+}
+
+uint64_t
+QUICTransferProgressProviderVIO::transfer_goal() const
+{
+ return this->_vio.nbytes;
+}
+
+bool
+QUICTransferProgressProviderVIO::is_cancelled() const
+{
+ return false;
+}
diff --git a/iocore/net/quic/QUICTransferProgressProvider.h b/iocore/net/quic/QUICTransferProgressProvider.h
index ce798fe..f0bc747 100644
--- a/iocore/net/quic/QUICTransferProgressProvider.h
+++ b/iocore/net/quic/QUICTransferProgressProvider.h
@@ -21,10 +21,11 @@
* limitations under the License.
*/
-#include "I_VIO.h"
-
#pragma once
+class VIO;
+class QUICStreamAdapter;
+
class QUICTransferProgressProvider
{
public:
@@ -40,34 +41,29 @@ public:
}
};
-class QUICTransferProgressProviderVIO : public QUICTransferProgressProvider
+class QUICTransferProgressProviderSA : public QUICTransferProgressProvider
{
public:
- QUICTransferProgressProviderVIO(VIO &vio) : _vio(vio) {}
+ void set_stream_adapter(QUICStreamAdapter *adapter);
- bool
- is_transfer_goal_set() const
- {
- return this->_vio.nbytes != INT64_MAX;
- }
+ bool is_transfer_goal_set() const override;
+ uint64_t transfer_progress() const override;
+ uint64_t transfer_goal() const override;
+ bool is_cancelled() const override;
- uint64_t
- transfer_progress() const
- {
- return this->_vio.ndone;
- }
+private:
+ QUICStreamAdapter *_adapter;
+};
- uint64_t
- transfer_goal() const
- {
- return this->_vio.nbytes;
- }
+class QUICTransferProgressProviderVIO : public QUICTransferProgressProvider
+{
+public:
+ QUICTransferProgressProviderVIO(VIO &vio) : _vio(vio) {}
- bool
- is_cancelled() const
- {
- return false;
- }
+ bool is_transfer_goal_set() const override;
+ uint64_t transfer_progress() const override;
+ uint64_t transfer_goal() const override;
+ bool is_cancelled() const override;
private:
VIO &_vio;
diff --git a/iocore/net/quic/QUICUnidirectionalStream.cc b/iocore/net/quic/QUICUnidirectionalStream.cc
index c6a3d7a..599af3a 100644
--- a/iocore/net/quic/QUICUnidirectionalStream.cc
+++ b/iocore/net/quic/QUICUnidirectionalStream.cc
@@ -22,115 +22,25 @@
*/
#include "QUICUnidirectionalStream.h"
+#include "QUICStreamAdapter.h"
//
// QUICSendStream
//
QUICSendStream::QUICSendStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t send_max_stream_data)
- : QUICStreamVConnection(cinfo, sid), _remote_flow_controller(send_max_stream_data, _id), _state(nullptr, &this->_progress_vio)
+ : QUICStream(cinfo, sid), _remote_flow_controller(send_max_stream_data, _id), _state(nullptr, &this->_progress_sa)
{
- SET_HANDLER(&QUICSendStream::state_stream_open);
-
QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
this->_remote_flow_controller.current_limit());
}
-int
-QUICSendStream::state_stream_open(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
- QUICErrorUPtr error = nullptr;
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- // should not schedule read event.
- ink_assert(0);
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
-
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- QUICStreamDebug("unknown event");
- ink_assert(false);
- }
-
- // FIXME error is always nullptr
- if (error != nullptr) {
- if (error->cls == QUICErrorClass::TRANSPORT) {
- QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code),
- static_cast<unsigned int>(error->code));
- } else {
- QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->code));
- }
- if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
- // Stream Error
- QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast<QUICStreamError *>(error.get()));
- this->reset(std::move(serror));
- } else {
- // Connection Error
- // TODO Close connection (Does this really happen?)
- }
- }
-
- return EVENT_DONE;
-}
-
-int
-QUICSendStream::state_stream_closed(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- ink_assert(false);
- }
-
- return EVENT_DONE;
-}
-
bool
QUICSendStream::will_generate_frame(QUICEncryptionLevel level, size_t current_packet_size, bool ack_eliciting, uint32_t seq_num)
{
if (!this->is_retransmited_frame_queue_empty()) {
return true;
}
- if (this->_write_vio.op != VIO::NONE && this->_write_vio.get_reader()->is_read_avail_more_than(0)) {
+ if (this->_adapter && this->_adapter->unread_len() > 0) {
return true;
}
return false;
@@ -155,96 +65,94 @@ QUICSendStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t
return nullptr;
}
this->_records_rst_stream_frame(level, *static_cast<QUICRstStreamFrame *>(frame));
- this->_state.update_with_sending_frame(*frame);
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
+ }
this->_is_reset_sent = true;
return frame;
}
- if (this->_write_vio.op != VIO::NONE && this->_state.is_allowed_to_send(QUICFrameType::STREAM)) {
- SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
+ if (!this->_adapter || !this->_state.is_allowed_to_send(QUICFrameType::STREAM)) {
+ return frame;
+ }
+
+ uint64_t maximum_data_size = 0;
+ if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
+ return frame;
+ }
+ maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD;
+
+ bool pure_fin = false;
+ bool fin = false;
+ if (this->_adapter->is_eos()) {
+ // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero.
+ pure_fin = true;
+ fin = true;
+ }
- uint64_t maximum_data_size = 0;
- if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
+ uint64_t len = 0;
+ if (!pure_fin) {
+ uint64_t data_len = this->_adapter->unread_len();
+ if (data_len == 0) {
return frame;
}
- maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD;
-
- bool pure_fin = false;
- bool fin = false;
- if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) &&
- this->_write_vio.nbytes == static_cast<int64_t>(this->_send_offset)) {
- // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero.
- pure_fin = true;
- fin = true;
- }
- uint64_t len = 0;
- IOBufferReader *reader = this->_write_vio.get_reader();
- if (!pure_fin) {
- uint64_t data_len = reader->block_read_avail();
- if (data_len == 0) {
- return frame;
- }
-
- // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin
- uint64_t stream_credit = this->_remote_flow_controller.credit();
- if (stream_credit == 0) {
- // STREAM_DATA_BLOCKED
- frame =
- this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, current_packet_size, seq_num);
- return frame;
- }
-
- if (connection_credit == 0) {
- // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller
- return frame;
- }
-
- len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit)));
-
- // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0
- ink_assert(len != 0);
-
- if (this->_write_vio.nbytes == static_cast<int64_t>(this->_send_offset + len)) {
- fin = true;
- }
+ // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin
+ uint64_t stream_credit = this->_remote_flow_controller.credit();
+ if (stream_credit == 0) {
+ // STREAM_DATA_BLOCKED
+ frame =
+ this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, current_packet_size, seq_num);
+ return frame;
}
- Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(reader->get_current_block()->clone());
- block->consume(reader->start_offset);
- block->_end = std::min(block->start() + len, block->_buf_end);
- ink_assert(static_cast<uint64_t>(block->read_avail()) == len);
-
- // STREAM - Pure FIN or data length is lager than 0
- // FIXME has_length_flag and has_offset_flag should be configurable
- frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true,
- this->_issue_frame_id(), this);
- if (!this->_state.is_allowed_to_send(*frame)) {
- QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type()));
+ if (connection_credit == 0) {
+ // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller
return frame;
}
- if (!pure_fin) {
- int ret = this->_remote_flow_controller.update(this->_send_offset + len);
- // We cannot cancel sending the frame after updating the flow controller
+ len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit)));
- // Calling update always success, because len is always less than stream_credit
- ink_assert(ret == 0);
+ // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0
+ ink_assert(len != 0);
- QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
- this->_remote_flow_controller.current_limit());
- if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) {
- QUICStreamDebug("Flow Controller will block sending a STREAM frame");
- }
+ if (this->_adapter->total_len() == this->_send_offset + len) {
+ fin = true;
+ }
+ }
+
+ Ptr<IOBufferBlock> block = this->_adapter->read(len);
+ ink_assert(static_cast<uint64_t>(block->read_avail()) == len);
+
+ // STREAM - Pure FIN or data length is lager than 0
+ // FIXME has_length_flag and has_offset_flag should be configurable
+ frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(),
+ this);
+ if (!this->_state.is_allowed_to_send(*frame)) {
+ QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type()));
+ return frame;
+ }
- reader->consume(len);
- this->_send_offset += len;
- this->_write_vio.ndone += len;
+ if (!pure_fin) {
+ int ret = this->_remote_flow_controller.update(this->_send_offset + len);
+ // We cannot cancel sending the frame after updating the flow controller
+
+ // Calling update always success, because len is always less than stream_credit
+ ink_assert(ret == 0);
+
+ QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
+ this->_remote_flow_controller.current_limit());
+ if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) {
+ QUICStreamDebug("Flow Controller will block sending a STREAM frame");
}
- this->_records_stream_frame(level, *static_cast<QUICStreamFrame *>(frame));
- this->_signal_write_event();
- this->_state.update_with_sending_frame(*frame);
+ this->_send_offset += len;
+ }
+ this->_records_stream_frame(level, *static_cast<QUICStreamFrame *>(frame));
+
+ this->_adapter->encourge_write();
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
}
return frame;
@@ -253,7 +161,9 @@ QUICSendStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t
QUICConnectionErrorUPtr
QUICSendStream::recv(const QUICStopSendingFrame &frame)
{
- this->_state.update_with_receiving_frame(frame);
+ if (this->_state.update_with_receiving_frame(frame)) {
+ this->_notify_state_change();
+ }
this->reset(QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)));
// We received and processed STOP_SENDING frame, so return NO_ERROR here
return nullptr;
@@ -266,96 +176,11 @@ QUICSendStream::recv(const QUICMaxStreamDataFrame &frame)
QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(),
this->_remote_flow_controller.current_limit());
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
-
- return nullptr;
-}
+ this->_adapter->encourge_write();
-VIO *
-QUICSendStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
-{
- QUICStreamDebug("Warning wants to read from send only stream ignore");
- // FIXME: should not assert here
- ink_assert(!"read from send only stream");
return nullptr;
}
-VIO *
-QUICSendStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
-{
- if (buf) {
- this->_write_vio.buffer.reader_for(buf);
- } else {
- this->_write_vio.buffer.clear();
- }
-
- this->_write_vio.mutex = c ? c->mutex : this->mutex;
- this->_write_vio.cont = c;
- this->_write_vio.nbytes = nbytes;
- this->_write_vio.ndone = 0;
- this->_write_vio.vc_server = this;
- this->_write_vio.op = VIO::WRITE;
-
- this->_process_write_vio();
- this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio);
-
- return &this->_write_vio;
-}
-
-void
-QUICSendStream::do_io_close(int lerrno)
-{
- SET_HANDLER(&QUICSendStream::state_stream_closed);
-
- ink_assert(this->_read_vio.nbytes == 0);
- ink_assert(this->_read_vio.op == VIO::NONE);
- ink_assert(this->_read_vio.cont == nullptr);
- this->_read_vio.buffer.clear();
-
- this->_write_vio.buffer.clear();
- this->_write_vio.nbytes = 0;
- this->_write_vio.op = VIO::NONE;
- this->_write_vio.cont = nullptr;
-}
-
-void
-QUICSendStream::do_io_shutdown(ShutdownHowTo_t howto)
-{
- switch (howto) {
- case IO_SHUTDOWN_READ:
- // ignore
- break;
- case IO_SHUTDOWN_WRITE:
- case IO_SHUTDOWN_READWRITE:
- this->do_io_close();
- break;
- default:
- ink_assert(0);
- break;
- }
-}
-
-void
-QUICSendStream::reenable(VIO *vio)
-{
- ink_assert(vio == &this->_write_vio);
- ink_assert(vio->op == VIO::WRITE);
-
- int64_t len = this->_process_write_vio();
- if (len > 0) {
- this->_signal_write_event();
- }
-}
-
-void
-QUICSendStream::reset(QUICStreamErrorUPtr error)
-{
- this->_reset_reason = std::move(error);
-}
-
void
QUICSendStream::_on_frame_acked(QUICFrameInformationUPtr &info)
{
@@ -405,111 +230,26 @@ QUICSendStream::largest_offset_sent() const
return this->_remote_flow_controller.current_offset();
}
+void
+QUICSendStream::reset(QUICStreamErrorUPtr error)
+{
+ this->_reset_reason = std::move(error);
+}
+
//
// QUICReceiveStream
//
QUICReceiveStream::QUICReceiveStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid,
uint64_t recv_max_stream_data)
- : QUICStreamVConnection(cinfo, sid),
+ : QUICStream(cinfo, sid),
_local_flow_controller(rtt_provider, recv_max_stream_data, _id),
_flow_control_buffer_size(recv_max_stream_data),
_state(this, nullptr)
{
- SET_HANDLER(&QUICReceiveStream::state_stream_open);
-
QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(),
this->_local_flow_controller.current_limit());
}
-int
-QUICReceiveStream::state_stream_open(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
- QUICErrorUPtr error = nullptr;
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- int64_t len = this->_process_read_vio();
- if (len > 0) {
- this->_signal_read_event();
- }
-
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- // should not schedule write event
- ink_assert(!"should not schedule write even");
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- QUICStreamDebug("unknown event");
- ink_assert(false);
- }
-
- // FIXME error is always nullptr
- if (error != nullptr) {
- if (error->cls == QUICErrorClass::TRANSPORT) {
- QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code),
- static_cast<unsigned int>(error->code));
- } else {
- QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls),
- static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->code));
- }
- if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
- // Stream Error
- QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast<QUICStreamError *>(error.get()));
- this->reset(std::move(serror));
- } else {
- // Connection Error
- // TODO Close connection (Does this really happen?)
- }
- }
-
- return EVENT_DONE;
-}
-
-int
-QUICReceiveStream::state_stream_closed(int event, void *data)
-{
- QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event);
-
- switch (event) {
- case VC_EVENT_READ_READY:
- case VC_EVENT_READ_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_WRITE_READY:
- case VC_EVENT_WRITE_COMPLETE: {
- // ignore
- break;
- }
- case VC_EVENT_EOS:
- case VC_EVENT_ERROR:
- case VC_EVENT_INACTIVITY_TIMEOUT:
- case VC_EVENT_ACTIVE_TIMEOUT: {
- // TODO
- ink_assert(false);
- break;
- }
- default:
- ink_assert(false);
- }
-
- return EVENT_DONE;
-}
-
bool
QUICReceiveStream::is_transfer_goal_set() const
{
@@ -560,7 +300,9 @@ QUICReceiveStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6
return nullptr;
}
this->_records_stop_sending_frame(level, *static_cast<QUICStopSendingFrame *>(frame));
- this->_state.update_with_sending_frame(*frame);
+ if (this->_state.update_with_sending_frame(*frame)) {
+ this->_notify_state_change();
+ }
this->_is_stop_sending_sent = true;
return frame;
}
@@ -574,8 +316,10 @@ QUICReceiveStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6
QUICConnectionErrorUPtr
QUICReceiveStream::recv(const QUICRstStreamFrame &frame)
{
- this->_state.update_with_receiving_frame(frame);
- this->_signal_read_eos_event();
+ if (this->_state.update_with_receiving_frame(frame)) {
+ this->_notify_state_change();
+ }
+ this->_adapter->notify_eos();
return nullptr;
}
@@ -597,7 +341,6 @@ QUICConnectionErrorUPtr
QUICReceiveStream::recv(const QUICStreamFrame &frame)
{
ink_assert(_id == frame.stream_id());
- ink_assert(this->_read_vio.op == VIO::READ);
// Check stream state - Do this first before accept the frame
if (!this->_state.is_allowed_to_receive(frame)) {
@@ -631,9 +374,11 @@ QUICReceiveStream::recv(const QUICStreamFrame &frame)
last_offset = stream_frame->offset();
last_length = stream_frame->data_length();
- this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast<uint8_t *>(stream_frame->data()->start()),
- stream_frame->data_length(), stream_frame->has_fin_flag());
- this->_state.update_with_receiving_frame(*new_frame);
+ this->_adapter->write(stream_frame->offset(), reinterpret_cast<uint8_t *>(stream_frame->data()->start()),
+ stream_frame->data_length(), stream_frame->has_fin_flag());
+ if (this->_state.update_with_receiving_frame(*new_frame)) {
+ this->_notify_state_change();
+ }
delete new_frame;
new_frame = this->_received_stream_frame_buffer.pop();
@@ -647,97 +392,25 @@ QUICReceiveStream::recv(const QUICStreamFrame &frame)
this->_local_flow_controller.current_limit());
}
- this->_signal_read_event();
+ this->_adapter->encourge_read();
return nullptr;
}
-VIO *
-QUICReceiveStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf)
-{
- if (buf) {
- this->_read_vio.buffer.writer_for(buf);
- } else {
- this->_read_vio.buffer.clear();
- }
-
- this->_read_vio.mutex = c ? c->mutex : this->mutex;
- this->_read_vio.cont = c;
- this->_read_vio.nbytes = nbytes;
- this->_read_vio.ndone = 0;
- this->_read_vio.vc_server = this;
- this->_read_vio.op = VIO::READ;
-
- this->_process_read_vio();
- this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio);
-
- return &this->_read_vio;
-}
-
-VIO *
-QUICReceiveStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner)
-{
- QUICStreamDebug("Warning wants to write to send only stream ignore");
- // FIXME: should not assert here
- ink_assert(!"write to send only stream");
- return nullptr;
-}
-
-void
-QUICReceiveStream::do_io_close(int lerrno)
-{
- SET_HANDLER(&QUICReceiveStream::state_stream_closed);
-
- ink_assert(this->_write_vio.nbytes == 0);
- ink_assert(this->_write_vio.op == VIO::NONE);
- ink_assert(this->_write_vio.cont == nullptr);
- this->_write_vio.buffer.clear();
-
- this->_read_vio.buffer.clear();
- this->_read_vio.nbytes = 0;
- this->_read_vio.op = VIO::NONE;
- this->_read_vio.cont = nullptr;
-}
-
-void
-QUICReceiveStream::do_io_shutdown(ShutdownHowTo_t howto)
-{
- switch (howto) {
- case IO_SHUTDOWN_WRITE:
- // ignore
- break;
- case IO_SHUTDOWN_READ:
- case IO_SHUTDOWN_READWRITE:
- this->do_io_close();
- break;
- default:
- ink_assert(0);
- break;
- }
-}
-
-void
-QUICReceiveStream::reenable(VIO *vio)
-{
- ink_assert(vio == &this->_read_vio);
- ink_assert(vio->op == VIO::READ);
-
- int64_t len = this->_process_read_vio();
- if (len > 0) {
- this->_signal_read_event();
- }
-}
-
void
QUICReceiveStream::on_read()
{
- this->_state.update_on_read();
+ if (this->_state.update_on_read()) {
+ this->_notify_state_change();
+ }
}
void
QUICReceiveStream::on_eos()
{
- this->_state.update_on_eos();
+ if (this->_state.update_on_eos()) {
+ this->_notify_state_change();
+ }
}
QUICOffset
diff --git a/iocore/net/quic/QUICUnidirectionalStream.h b/iocore/net/quic/QUICUnidirectionalStream.h
index 5ebe552..315c24f 100644
--- a/iocore/net/quic/QUICUnidirectionalStream.h
+++ b/iocore/net/quic/QUICUnidirectionalStream.h
@@ -25,7 +25,7 @@
#include "QUICStream.h"
-class QUICSendStream : public QUICStreamVConnection
+class QUICSendStream : public QUICStream
{
public:
QUICSendStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t send_max_stream_data);
@@ -44,13 +44,6 @@ public:
virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) override;
virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override;
- // Implement VConnection Interface.
- VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override;
- VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override;
- void do_io_close(int lerrno = -1) override;
- void do_io_shutdown(ShutdownHowTo_t howto) override;
- void reenable(VIO *vio) override;
-
void reset(QUICStreamErrorUPtr error) override;
QUICOffset largest_offset_sent() const override;
@@ -62,7 +55,7 @@ private:
bool _is_transfer_complete = false;
bool _is_reset_complete = false;
- QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio};
+ QUICTransferProgressProviderSA _progress_sa;
QUICRemoteStreamFlowController _remote_flow_controller;
@@ -73,7 +66,7 @@ private:
void _on_frame_lost(QUICFrameInformationUPtr &info) override;
};
-class QUICReceiveStream : public QUICStreamVConnection, public QUICTransferProgressProvider
+class QUICReceiveStream : public QUICStream, public QUICTransferProgressProvider
{
public:
QUICReceiveStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid,
@@ -94,13 +87,6 @@ public:
virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override;
virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override;
- // Implement VConnection Interface.
- VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override;
- VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override;
- void do_io_close(int lerrno = -1) override;
- void do_io_shutdown(ShutdownHowTo_t howto) override;
- void reenable(VIO *vio) override;
-
// QUICTransferProgressProvider
bool is_transfer_goal_set() const override;
uint64_t transfer_progress() const override;
diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc
index 828049f..9261781 100644
--- a/iocore/net/quic/test/test_QUICStream.cc
+++ b/iocore/net/quic/test/test_QUICStream.cc
@@ -25,6 +25,7 @@
#include "quic/QUICBidirectionalStream.h"
#include "quic/QUICUnidirectionalStream.h"
+#include "quic/QUICStreamVCAdapter.h"
#include "quic/Mock.h"
TEST_CASE("QUICBidiStream", "[quic]")
@@ -88,7 +89,9 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_1);
stream->recv(frame_2);
@@ -116,7 +119,9 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_8);
stream->recv(frame_7);
@@ -144,7 +149,9 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_8);
stream->recv(frame_7);
@@ -175,7 +182,9 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(BUFFER_SIZE_INDEX_32K);
@@ -216,11 +225,13 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
@@ -228,28 +239,28 @@ TEST_CASE("QUICBidiStream", "[quic]")
QUICFrame *frame = nullptr;
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -257,7 +268,7 @@ TEST_CASE("QUICBidiStream", "[quic]")
// This should not send a frame because of flow control
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame);
@@ -268,7 +279,7 @@ TEST_CASE("QUICBidiStream", "[quic]")
stream->recv(*std::make_shared<QUICMaxStreamDataFrame>(stream_id, 5120));
// This should send a frame
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -279,13 +290,13 @@ TEST_CASE("QUICBidiStream", "[quic]")
// This should send a frame
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED);
@@ -293,7 +304,7 @@ TEST_CASE("QUICBidiStream", "[quic]")
// Update window
stream->recv(*std::make_shared<QUICMaxStreamDataFrame>(stream_id, 6144));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -312,10 +323,12 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
const char data1[] = "this is a test data";
@@ -327,7 +340,7 @@ TEST_CASE("QUICBidiStream", "[quic]")
// Write data1
write_buffer->write(data1, sizeof(data1));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
// Generate STREAM frame
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
frame1 = static_cast<QUICStreamFrame *>(frame);
@@ -339,7 +352,7 @@ TEST_CASE("QUICBidiStream", "[quic]")
// Write data2
write_buffer->write(data2, sizeof(data2));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
// Lost the frame
stream->on_frame_lost(frame->id());
// Regenerate a frame
@@ -361,10 +374,12 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
QUICFrame *frame = nullptr;
@@ -392,10 +407,12 @@ TEST_CASE("QUICBidiStream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICBidirectionalStream> stream(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
QUICFrame *frame = nullptr;
@@ -426,9 +443,11 @@ TEST_CASE("QUICBidiStream", "[quic]")
// STOP_SENDING
std::unique_ptr<QUICBidirectionalStream> stream1(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- MockContinuation mock_cont1(stream1->mutex);
- stream1->do_io_write(&mock_cont1, INT64_MAX, write_buffer_reader);
- SCOPED_MUTEX_LOCK(lock1, stream1->mutex, this_ethread());
+ QUICStreamVCAdapter adapter1(*stream1);
+ stream1->set_io_adapter(&adapter1);
+ MockContinuation mock_cont1(adapter1.mutex);
+ adapter1.do_io_write(&mock_cont1, INT64_MAX, write_buffer_reader);
+ SCOPED_MUTEX_LOCK(lock1, adapter1.mutex, this_ethread());
stream1->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream1.get(), QUIC_APP_ERROR_CODE_STOPPING)));
frame = stream1->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
@@ -436,9 +455,11 @@ TEST_CASE("QUICBidiStream", "[quic]")
// RESET_STREAM
std::unique_ptr<QUICBidirectionalStream> stream2(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- MockContinuation mock_cont2(stream2->mutex);
- stream2->do_io_write(&mock_cont2, INT64_MAX, write_buffer_reader);
- SCOPED_MUTEX_LOCK(lock2, stream2->mutex, this_ethread());
+ QUICStreamVCAdapter adapter2(*stream2);
+ stream2->set_io_adapter(&adapter2);
+ MockContinuation mock_cont2(adapter2.mutex);
+ adapter2.do_io_write(&mock_cont2, INT64_MAX, write_buffer_reader);
+ SCOPED_MUTEX_LOCK(lock2, adapter2.mutex, this_ethread());
stream2->reset(QUICStreamErrorUPtr(new QUICStreamError(stream2.get(), QUIC_APP_ERROR_CODE_STOPPING)));
frame = stream2->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
@@ -446,12 +467,14 @@ TEST_CASE("QUICBidiStream", "[quic]")
// STREAM
std::unique_ptr<QUICBidirectionalStream> stream3(
new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX));
- MockContinuation mock_cont3(stream3->mutex);
- stream3->do_io_write(&mock_cont3, INT64_MAX, write_buffer_reader);
- SCOPED_MUTEX_LOCK(lock3, stream3->mutex, this_ethread());
+ QUICStreamVCAdapter adapter3(*stream3);
+ stream3->set_io_adapter(&adapter3);
+ MockContinuation mock_cont3(adapter3.mutex);
+ adapter3.do_io_write(&mock_cont3, INT64_MAX, write_buffer_reader);
+ SCOPED_MUTEX_LOCK(lock3, adapter3.mutex, this_ethread());
const char data[] = "this is a test data";
write_buffer->write(data, sizeof(data));
- stream3->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter3.handleEvent(VC_EVENT_WRITE_READY, nullptr);
frame = stream3->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
}
@@ -517,7 +540,9 @@ TEST_CASE("QUIC receive only stream", "[quic]")
QUICRTTMeasure rtt_provider;
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICReceiveStream> stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 1024));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_1);
stream->recv(frame_2);
@@ -544,7 +569,9 @@ TEST_CASE("QUIC receive only stream", "[quic]")
QUICRTTMeasure rtt_provider;
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICReceiveStream> stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_8);
stream->recv(frame_7);
@@ -571,7 +598,9 @@ TEST_CASE("QUIC receive only stream", "[quic]")
QUICRTTMeasure rtt_provider;
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICReceiveStream> stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
stream->recv(frame_8);
stream->recv(frame_7);
@@ -601,7 +630,9 @@ TEST_CASE("QUIC receive only stream", "[quic]")
QUICRTTMeasure rtt_provider;
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICReceiveStream> stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 4096));
- stream->do_io_read(nullptr, INT64_MAX, read_buffer);
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ adapter.do_io_read(nullptr, INT64_MAX, read_buffer);
Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(BUFFER_SIZE_INDEX_32K);
@@ -635,7 +666,9 @@ TEST_CASE("QUIC receive only stream", "[quic]")
QUICRTTMeasure rtt_provider;
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICReceiveStream> stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
QUICFrame *frame = nullptr;
@@ -663,8 +696,10 @@ TEST_CASE("QUIC receive only stream", "[quic]")
// STOP_SENDING
std::unique_ptr<QUICReceiveStream> stream1(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX));
- MockContinuation mock_cont1(stream1->mutex);
- SCOPED_MUTEX_LOCK(lock1, stream1->mutex, this_ethread());
+ QUICStreamVCAdapter adapter1(*stream1);
+ stream1->set_io_adapter(&adapter1);
+ MockContinuation mock_cont1(adapter1.mutex);
+ SCOPED_MUTEX_LOCK(lock1, adapter1.mutex, this_ethread());
stream1->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream1.get(), QUIC_APP_ERROR_CODE_STOPPING)));
frame = stream1->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
@@ -732,10 +767,12 @@ TEST_CASE("QUIC send only stream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICSendStream> stream(new QUICSendStream(&cinfo_provider, stream_id, 4096));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
@@ -743,28 +780,28 @@ TEST_CASE("QUIC send only stream", "[quic]")
QUICFrame *frame = nullptr;
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == false);
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -772,7 +809,7 @@ TEST_CASE("QUIC send only stream", "[quic]")
// This should not send a frame because of flow control
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame);
@@ -783,7 +820,7 @@ TEST_CASE("QUIC send only stream", "[quic]")
stream->recv(*std::make_shared<QUICMaxStreamDataFrame>(stream_id, 5120));
// This should send a frame
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -794,13 +831,13 @@ TEST_CASE("QUIC send only stream", "[quic]")
// This should send a frame
write_buffer->write(data, 1024);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED);
@@ -808,7 +845,7 @@ TEST_CASE("QUIC send only stream", "[quic]")
// Update window
stream->recv(*std::make_shared<QUICMaxStreamDataFrame>(stream_id, 6144));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
CHECK(stream->will_generate_frame(level, 0, false, 0) == true);
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
CHECK(frame->type() == QUICFrameType::STREAM);
@@ -825,10 +862,12 @@ TEST_CASE("QUIC send only stream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICSendStream> stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
const char data1[] = "this is a test data";
@@ -840,7 +879,7 @@ TEST_CASE("QUIC send only stream", "[quic]")
// Write data1
write_buffer->write(data1, sizeof(data1));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
// Generate STREAM frame
frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0, 0);
frame1 = static_cast<QUICStreamFrame *>(frame);
@@ -852,7 +891,7 @@ TEST_CASE("QUIC send only stream", "[quic]")
// Write data2
write_buffer->write(data2, sizeof(data2));
- stream->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter.handleEvent(VC_EVENT_WRITE_READY, nullptr);
// Lost the frame
stream->on_frame_lost(frame->id());
// Regenerate a frame
@@ -872,10 +911,12 @@ TEST_CASE("QUIC send only stream", "[quic]")
MockQUICConnectionInfoProvider cinfo_provider;
std::unique_ptr<QUICSendStream> stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX));
- SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
+ QUICStreamVCAdapter adapter(*stream);
+ stream->set_io_adapter(&adapter);
+ SCOPED_MUTEX_LOCK(lock, adapter.mutex, this_ethread());
- MockContinuation mock_cont(stream->mutex);
- stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
+ MockContinuation mock_cont(adapter.mutex);
+ adapter.do_io_write(&mock_cont, INT64_MAX, write_buffer_reader);
QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT;
QUICFrame *frame = nullptr;
@@ -904,21 +945,25 @@ TEST_CASE("QUIC send only stream", "[quic]")
// RESET_STREAM
std::unique_ptr<QUICSendStream> stream2(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX));
- MockContinuation mock_cont2(stream2->mutex);
- stream2->do_io_write(&mock_cont2, INT64_MAX, write_buffer_reader);
- SCOPED_MUTEX_LOCK(lock2, stream2->mutex, this_ethread());
+ QUICStreamVCAdapter adapter2(*stream2);
+ stream2->set_io_adapter(&adapter2);
+ MockContinuation mock_cont2(adapter2.mutex);
+ adapter2.do_io_write(&mock_cont2, INT64_MAX, write_buffer_reader);
+ SCOPED_MUTEX_LOCK(lock2, adapter2.mutex, this_ethread());
stream2->reset(QUICStreamErrorUPtr(new QUICStreamError(stream2.get(), QUIC_APP_ERROR_CODE_STOPPING)));
frame = stream2->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
// STREAM
std::unique_ptr<QUICSendStream> stream3(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX));
- MockContinuation mock_cont3(stream3->mutex);
- stream3->do_io_write(&mock_cont3, INT64_MAX, write_buffer_reader);
- SCOPED_MUTEX_LOCK(lock3, stream3->mutex, this_ethread());
+ QUICStreamVCAdapter adapter3(*stream3);
+ stream3->set_io_adapter(&adapter3);
+ MockContinuation mock_cont3(adapter3.mutex);
+ adapter3.do_io_write(&mock_cont3, INT64_MAX, write_buffer_reader);
+ SCOPED_MUTEX_LOCK(lock3, adapter3.mutex, this_ethread());
const char data[] = "this is a test data";
write_buffer->write(data, sizeof(data));
- stream3->handleEvent(VC_EVENT_WRITE_READY, nullptr);
+ adapter3.handleEvent(VC_EVENT_WRITE_READY, nullptr);
frame = stream3->generate_frame(frame_buf, level, 4096, 0, 0, 0);
CHECK(frame == nullptr);
}
diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc
index 9eb1128..e6f9989 100644
--- a/iocore/net/quic/test/test_QUICStreamState.cc
+++ b/iocore/net/quic/test/test_QUICStreamState.cc
@@ -57,17 +57,17 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case2. Send STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
// Case3. Send STREAM_DATA_BLOCKED
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED));
- ss.update_with_sending_frame(*stream_data_blocked_frame);
+ CHECK(!ss.update_with_sending_frame(*stream_data_blocked_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
// Case3. Send FIN in a STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_sending_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICSendStreamState::DataSent);
// Case4. STREAM is not allowed to send
@@ -75,7 +75,7 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case5. Receive all ACKs
pp.set_transfer_complete(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::DataRecvd);
}
@@ -87,7 +87,7 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case2. Send STREAM_DATA_BLOCKED
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED));
- ss.update_with_sending_frame(*stream_data_blocked_frame);
+ CHECK(ss.update_with_sending_frame(*stream_data_blocked_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
}
@@ -101,7 +101,7 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case2. Send RESET_STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM));
- ss.update_with_sending_frame(*rst_stream_frame);
+ CHECK(ss.update_with_sending_frame(*rst_stream_frame));
CHECK(ss.get() == QUICSendStreamState::ResetSent);
// Case3. Receive ACK for STREAM
@@ -109,7 +109,7 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case4. Receive ACK for RESET_STREAM
pp.set_cancelled(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::ResetRecvd);
}
@@ -121,21 +121,21 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case2. Send STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
// Case3. Send RESET_STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM));
- ss.update_with_sending_frame(*rst_stream_frame);
+ CHECK(ss.update_with_sending_frame(*rst_stream_frame));
CHECK(ss.get() == QUICSendStreamState::ResetSent);
// Case4. Receive ACK for STREAM
- ss.update_on_ack();
+ CHECK(!ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::ResetSent);
// Case5. Receive ACK for RESET_STREAM
pp.set_cancelled(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::ResetRecvd);
}
@@ -147,17 +147,17 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case2. Send STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
// Case3. Send STREAM_DATA_BLOCKED
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED));
- ss.update_with_sending_frame(*stream_data_blocked_frame);
+ CHECK(!ss.update_with_sending_frame(*stream_data_blocked_frame));
CHECK(ss.get() == QUICSendStreamState::Send);
// Case3. Send FIN in a STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_sending_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICSendStreamState::DataSent);
// Case4. STREAM is not allowed to send
@@ -165,16 +165,16 @@ TEST_CASE("QUICSendStreamState", "[quic]")
// Case4. Send RESET_STREAM
CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM));
- ss.update_with_sending_frame(*rst_stream_frame);
+ CHECK(ss.update_with_sending_frame(*rst_stream_frame));
CHECK(ss.get() == QUICSendStreamState::ResetSent);
// Case5. Receive ACK for STREAM
- ss.update_on_ack();
+ CHECK(!ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::ResetSent);
// Case6. Receive ACK for RESET_STREAM
pp.set_cancelled(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICSendStreamState::ResetRecvd);
}
}
@@ -209,29 +209,29 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
CHECK(ss.is_allowed_to_send(QUICFrameType::MAX_STREAM_DATA) == false);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(1);
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv STREAM_DATA_BLOCKED
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_DATA_BLOCKED));
- ss.update_with_receiving_frame(*stream_data_blocked_frame);
+ CHECK(!ss.update_with_receiving_frame(*stream_data_blocked_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case3. Recv FIN in a STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_goal(3);
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICReceiveStreamState::SizeKnown);
// Case4. Recv ALL data
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(3);
- ss.update_with_receiving_frame(*stream_frame_delayed);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_delayed));
CHECK(ss.get() == QUICReceiveStreamState::DataRecvd);
// Case5. Read data
in_progress.set_transfer_complete(true);
- ss.update_on_read();
+ CHECK(ss.update_on_read());
CHECK(ss.get() == QUICReceiveStreamState::DataRead);
}
@@ -242,16 +242,16 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
// Case1. Recv STREAM
QUICReceiveStreamStateMachine ss(&in_progress, nullptr);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv RESET_STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd);
// Case3. Handle reset
- ss.update_on_eos();
+ CHECK(ss.update_on_eos());
CHECK(ss.get() == QUICReceiveStreamState::ResetRead);
}
@@ -262,17 +262,17 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
// Case1. Recv STREAM
QUICReceiveStreamStateMachine ss(&in_progress, nullptr);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv FIN in a STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICReceiveStreamState::SizeKnown);
// Case3. Recv RESET_STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd);
}
@@ -284,24 +284,24 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
QUICReceiveStreamStateMachine ss(&in_progress, nullptr);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(1);
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv FIN in a STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_goal(3);
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICReceiveStreamState::SizeKnown);
// Case3. Recv ALL data
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(3);
- ss.update_with_receiving_frame(*stream_frame_delayed);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_delayed));
CHECK(ss.get() == QUICReceiveStreamState::DataRecvd);
// Case4. Recv RESET_STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(!ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::DataRecvd);
}
@@ -313,24 +313,24 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
QUICReceiveStreamStateMachine ss(&in_progress, nullptr);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(1);
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv FIN in a STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_goal(3);
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICReceiveStreamState::SizeKnown);
// Case3. Recv RESET_STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd);
// Case4. Recv ALL data
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_progress(3);
- ss.update_with_receiving_frame(*stream_frame_delayed);
+ CHECK(!ss.update_with_receiving_frame(*stream_frame_delayed));
CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd);
CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false);
}
@@ -342,18 +342,18 @@ TEST_CASE("QUICReceiveStreamState", "[quic]")
// Case1. Recv STREAM
QUICReceiveStreamStateMachine ss(&in_progress, nullptr);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICReceiveStreamState::Recv);
// Case2. Recv FIN in a STREAM
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICReceiveStreamState::SizeKnown);
// // Case3. Recv ALL data
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
in_progress.set_transfer_complete(true);
- ss.update_with_receiving_frame(*stream_frame_delayed);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_delayed));
// ss.update_on_transport_recv_event();
CHECK(ss.get() == QUICReceiveStreamState::DataRecvd);
@@ -390,11 +390,11 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
in_progress.set_transfer_complete(true);
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_R);
}
@@ -407,10 +407,10 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(ss.update_with_receiving_frame(*stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_R);
}
@@ -423,17 +423,17 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
-
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
- ss.update_with_sending_frame(*stream_frame_with_fin);
+
+ CHECK(ss.update_with_sending_frame(*stream_frame_with_fin)); // internal state is changed
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
out_progress.set_transfer_complete(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
- ss.update_with_sending_frame(*stream_frame_delayed);
+ CHECK(!ss.update_with_sending_frame(*stream_frame_delayed));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
}
@@ -446,10 +446,10 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
-
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
- ss.update_with_sending_frame(*rst_stream_frame);
+
+ CHECK(ss.update_with_sending_frame(*rst_stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
}
@@ -462,19 +462,19 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame);
-
+ CHECK(ss.update_with_sending_frame(*stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
- ss.update_with_sending_frame(*rst_stream_frame);
+
+ CHECK(ss.update_with_sending_frame(*rst_stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(!ss.update_with_receiving_frame(*stream_frame));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Closed);
- ss.update_on_eos();
+ CHECK(ss.update_on_eos()); // internal state is changed
CHECK(ss.get() == QUICBidirectionalStreamState::Closed);
}
@@ -487,20 +487,20 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_sending_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
out_progress.set_transfer_complete(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame);
+ CHECK(!ss.update_with_receiving_frame(*stream_frame));
- ss.update_with_receiving_frame(*rst_stream_frame);
+ CHECK(ss.update_with_receiving_frame(*rst_stream_frame));
CHECK(ss.get() == QUICBidirectionalStreamState::Closed);
in_progress.set_transfer_complete(true);
- ss.update_on_eos();
+ CHECK(ss.update_on_eos()); // internal state is changed
CHECK(ss.get() == QUICBidirectionalStreamState::Closed);
}
@@ -513,20 +513,20 @@ TEST_CASE("QUICBidiState", "[quic]")
CHECK(ss.get() == QUICBidirectionalStreamState::Idle);
CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM));
- ss.update_with_sending_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_sending_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICBidirectionalStreamState::Open);
out_progress.set_transfer_complete(true);
- ss.update_on_ack();
+ CHECK(ss.update_on_ack());
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM));
- ss.update_with_receiving_frame(*stream_frame_delayed);
+ CHECK(!ss.update_with_receiving_frame(*stream_frame_delayed));
- ss.update_with_receiving_frame(*stream_frame_with_fin);
+ CHECK(ss.update_with_receiving_frame(*stream_frame_with_fin));
CHECK(ss.get() == QUICBidirectionalStreamState::HC_L);
in_progress.set_transfer_complete(true);
- ss.update_on_read();
+ CHECK(ss.update_on_read());
CHECK(ss.get() == QUICBidirectionalStreamState::Closed);
}
}
diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc
index cbde812..b6dc02a 100644
--- a/proxy/http3/Http09App.cc
+++ b/proxy/http3/Http09App.cc
@@ -29,6 +29,7 @@
#include "P_VConnection.h"
#include "P_QUICNetVConnection.h"
#include "QUICDebugNames.h"
+#include "QUICStreamVCAdapter.h"
#include "Http3Session.h"
#include "Http3Transaction.h"
@@ -54,40 +55,68 @@ Http09App::~Http09App()
delete this->_ssn;
}
+void
+Http09App::on_new_stream(QUICStream &stream)
+{
+ auto ret = this->_streams.emplace(stream.id(), stream);
+ auto &info = ret.first->second;
+
+ switch (stream.direction()) {
+ case QUICStreamDirection::BIDIRECTIONAL:
+ info.setup_read_vio(this);
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::SEND:
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::RECEIVE:
+ info.setup_read_vio(this);
+ break;
+ default:
+ ink_assert(false);
+ break;
+ }
+
+ stream.set_io_adapter(&info.adapter);
+}
+
int
Http09App::main_event_handler(int event, Event *data)
{
Debug(debug_tag_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event);
- VIO *vio = reinterpret_cast<VIO *>(data);
- QUICStreamIO *stream_io = this->_find_stream_io(vio);
+ VIO *vio = reinterpret_cast<VIO *>(data->cookie);
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
- if (stream_io == nullptr) {
+ if (adapter == nullptr) {
Debug(debug_tag, "[%s] Unknown Stream", this->_qc->cids().data());
return -1;
}
- QUICStreamId stream_id = stream_io->stream_id();
+ bool is_bidirectional = adapter->stream().is_bidirectional();
+
+ QUICStreamId stream_id = adapter->stream().id();
Http09Transaction *txn = static_cast<Http09Transaction *>(this->_ssn->get_transaction(stream_id));
- uint8_t dummy;
switch (event) {
case VC_EVENT_READ_READY:
case VC_EVENT_READ_COMPLETE:
- if (!stream_io->is_bidirectional()) {
+ if (!is_bidirectional) {
// FIXME Ignore unidirectional streams for now
break;
}
- if (stream_io->peek(&dummy, 1)) {
- if (txn == nullptr) {
- txn = new Http09Transaction(this->_ssn, stream_io);
- SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
+ if (txn == nullptr) {
+ if (auto ret = this->_streams.find(stream_id); ret != this->_streams.end()) {
+ txn = new Http09Transaction(this->_ssn, ret->second);
+ SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
txn->new_transaction();
} else {
- SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
- txn->handleEvent(event);
+ ink_assert(!"Stream info should exist");
}
+ } else {
+ SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
+ txn->handleEvent(event);
}
break;
case VC_EVENT_WRITE_READY:
diff --git a/proxy/http3/Http09App.h b/proxy/http3/Http09App.h
index ab35399..14ee8e6 100644
--- a/proxy/http3/Http09App.h
+++ b/proxy/http3/Http09App.h
@@ -28,6 +28,7 @@
#include "HttpSessionAccept.h"
#include "QUICApplication.h"
+#include "QUICStreamVCAdapter.h"
class QUICNetVConnection;
class Http09Session;
@@ -44,8 +45,11 @@ public:
Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options);
~Http09App();
+ void on_new_stream(QUICStream &stream) override;
+
int main_event_handler(int event, Event *data);
private:
Http09Session *_ssn = nullptr;
+ std::unordered_map<QUICStreamId, QUICStreamVCAdapter::IOInfo> _streams;
};
diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc
index e53cf14..1de466a 100644
--- a/proxy/http3/Http3App.cc
+++ b/proxy/http3/Http3App.cc
@@ -23,11 +23,14 @@
#include "Http3App.h"
+#include <utility>
+
#include "tscore/ink_resolver.h"
#include "P_Net.h"
#include "P_VConnection.h"
#include "P_QUICNetVConnection.h"
+#include "QUICStreamVCAdapter.h"
#include "Http3.h"
#include "Http3Config.h"
@@ -71,10 +74,6 @@ Http3App::start()
QUICConnectionErrorUPtr error;
error = this->create_uni_stream(stream_id, Http3StreamType::CONTROL);
- if (error == nullptr) {
- this->_local_control_stream = this->_find_stream_io(stream_id);
- this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream);
- }
// TODO: Open uni streams for QPACK when dynamic table is used
// error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER);
@@ -88,41 +87,68 @@ Http3App::start()
// }
}
+void
+Http3App::on_new_stream(QUICStream &stream)
+{
+ auto ret = this->_streams.emplace(stream.id(), stream);
+ auto &info = ret.first->second;
+
+ switch (stream.direction()) {
+ case QUICStreamDirection::BIDIRECTIONAL:
+ info.setup_read_vio(this);
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::SEND:
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::RECEIVE:
+ info.setup_read_vio(this);
+ break;
+ default:
+ ink_assert(false);
+ break;
+ }
+
+ stream.set_io_adapter(&info.adapter);
+}
+
int
Http3App::main_event_handler(int event, Event *data)
{
Debug(debug_tag_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event);
- VIO *vio = reinterpret_cast<VIO *>(data);
- QUICStreamIO *stream_io = this->_find_stream_io(vio);
+ VIO *vio = reinterpret_cast<VIO *>(data->cookie);
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
- if (stream_io == nullptr) {
+ if (adapter == nullptr) {
Debug(debug_tag, "[%s] Unknown Stream", this->_qc->cids().data());
return -1;
}
+ bool is_bidirectional = adapter->stream().is_bidirectional();
+
switch (event) {
case VC_EVENT_READ_READY:
case VC_EVENT_READ_COMPLETE:
- if (stream_io->is_bidirectional()) {
- this->_handle_bidi_stream_on_read_ready(event, stream_io);
+ if (is_bidirectional) {
+ this->_handle_bidi_stream_on_read_ready(event, vio);
} else {
- this->_handle_uni_stream_on_read_ready(event, stream_io);
+ this->_handle_uni_stream_on_read_ready(event, vio);
}
break;
case VC_EVENT_WRITE_READY:
case VC_EVENT_WRITE_COMPLETE:
- if (stream_io->is_bidirectional()) {
- this->_handle_bidi_stream_on_write_ready(event, stream_io);
+ if (is_bidirectional) {
+ this->_handle_bidi_stream_on_write_ready(event, vio);
} else {
- this->_handle_uni_stream_on_write_ready(event, stream_io);
+ this->_handle_uni_stream_on_write_ready(event, vio);
}
break;
case VC_EVENT_EOS:
- if (stream_io->is_bidirectional()) {
- this->_handle_bidi_stream_on_eos(event, stream_io);
+ if (is_bidirectional) {
+ this->_handle_bidi_stream_on_eos(event, vio);
} else {
- this->_handle_uni_stream_on_eos(event, stream_io);
+ this->_handle_uni_stream_on_eos(event, vio);
}
break;
case VC_EVENT_ERROR:
@@ -143,11 +169,6 @@ Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type)
QUICConnectionErrorUPtr error = this->_qc->stream_manager()->create_uni_stream(new_stream_id);
if (error == nullptr) {
- QUICStreamIO *stream_io = this->_find_stream_io(new_stream_id);
-
- uint8_t buf[] = {static_cast<uint8_t>(type)};
- stream_io->write(buf, sizeof(uint8_t));
-
this->_local_uni_stream_map.insert(std::make_pair(new_stream_id, type));
Debug("http3", "[%" PRIu64 "] %s stream is created", new_stream_id, Http3DebugNames::stream_type(type));
@@ -159,26 +180,24 @@ Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type)
}
void
-Http3App::_handle_uni_stream_on_read_ready(int /* event */, QUICStreamIO *stream_io)
+Http3App::_handle_uni_stream_on_read_ready(int /* event */, VIO *vio)
{
Http3StreamType type;
- auto it = this->_remote_uni_stream_map.find(stream_io->stream_id());
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
+ auto it = this->_remote_uni_stream_map.find(adapter->stream().id());
if (it == this->_remote_uni_stream_map.end()) {
// Set uni stream suitable app (HTTP/3 or QPACK) by stream type
uint8_t buf;
- stream_io->read(&buf, 1);
+ vio->get_reader()->read(&buf, 1);
type = Http3Stream::type(&buf);
- Debug("http3", "[%d] %s stream is opened", stream_io->stream_id(), Http3DebugNames::stream_type(type));
+ Debug("http3", "[%" PRIu64 "] %s stream is opened", adapter->stream().id(), Http3DebugNames::stream_type(type));
- if (type == Http3StreamType::CONTROL) {
- if (this->_remote_control_stream) {
- // TODO: make error
- }
- this->_remote_control_stream = stream_io;
+ auto ret = this->_remote_uni_stream_map.insert(std::make_pair(adapter->stream().id(), type));
+ if (!ret.second) {
+ // A stream for the type is already exisits
+ // TODO Return an error
}
-
- this->_remote_uni_stream_map.insert(std::make_pair(stream_io->stream_id(), type));
} else {
type = it->second;
}
@@ -187,13 +206,13 @@ Http3App::_handle_uni_stream_on_read_ready(int /* event */, QUICStreamIO *stream
case Http3StreamType::CONTROL:
case Http3StreamType::PUSH: {
uint64_t nread = 0;
- this->_control_stream_dispatcher.on_read_ready(*stream_io, nread);
+ this->_control_stream_dispatcher.on_read_ready(adapter->stream().id(), *vio->get_reader(), nread);
// TODO: when PUSH comes from client, send stream error with HTTP_WRONG_STREAM_DIRECTION
break;
}
case Http3StreamType::QPACK_ENCODER:
case Http3StreamType::QPACK_DECODER: {
- this->_set_qpack_stream(type, stream_io);
+ this->_set_qpack_stream(type, adapter);
}
case Http3StreamType::UNKNOWN:
default:
@@ -203,43 +222,57 @@ Http3App::_handle_uni_stream_on_read_ready(int /* event */, QUICStreamIO *stream
}
void
-Http3App::_handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io)
+Http3App::_handle_bidi_stream_on_read_ready(int event, VIO *vio)
{
- uint8_t dummy;
- if (stream_io->peek(&dummy, 1)) {
- QUICStreamId stream_id = stream_io->stream_id();
- Http3Transaction *txn = static_cast<Http3Transaction *>(this->_ssn->get_transaction(stream_id));
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
- if (txn == nullptr) {
- txn = new Http3Transaction(this->_ssn, stream_io);
- SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
+ QUICStreamId stream_id = adapter->stream().id();
+ Http3Transaction *txn = static_cast<Http3Transaction *>(this->_ssn->get_transaction(stream_id));
+ if (txn == nullptr) {
+ if (auto ret = this->_streams.find(stream_id); ret != this->_streams.end()) {
+ txn = new Http3Transaction(this->_ssn, ret->second);
+ SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
txn->new_transaction();
} else {
- SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
- txn->handleEvent(event);
+ ink_assert(!"Stream info should exist");
}
+ } else {
+ SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
+ txn->handleEvent(event);
}
}
void
-Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *stream_io)
+Http3App::_handle_uni_stream_on_write_ready(int /* event */, VIO *vio)
{
- auto it = this->_local_uni_stream_map.find(stream_io->stream_id());
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
+
+ auto it = this->_local_uni_stream_map.find(adapter->stream().id());
if (it == this->_local_uni_stream_map.end()) {
ink_abort("stream not found");
return;
}
switch (it->second) {
- case Http3StreamType::CONTROL: {
- size_t nwritten = 0;
- this->_control_stream_collector.on_write_ready(stream_io, nwritten);
+ case Http3StreamType::CONTROL:
+ if (!this->_is_control_stream_initialized) {
+ uint8_t buf[] = {static_cast<uint8_t>(it->second)};
+ vio->get_writer()->write(buf, sizeof(uint8_t));
+ this->_is_control_stream_initialized = true;
+ } else {
+ size_t nwritten = 0;
+ bool all_done = false;
+ this->_control_stream_collector.on_write_ready(adapter->stream().id(), *vio->get_writer(), nwritten, all_done);
+ vio->nbytes += nwritten;
+ if (all_done) {
+ vio->done();
+ }
+ }
break;
- }
case Http3StreamType::QPACK_ENCODER:
case Http3StreamType::QPACK_DECODER: {
- this->_set_qpack_stream(it->second, stream_io);
+ this->_set_qpack_stream(it->second, adapter);
}
case Http3StreamType::UNKNOWN:
case Http3StreamType::PUSH:
@@ -249,32 +282,32 @@ Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *strea
}
void
-Http3App::_handle_bidi_stream_on_eos(int /* event */, QUICStreamIO *stream_io)
+Http3App::_handle_bidi_stream_on_eos(int /* event */, VIO *vio)
{
// TODO: handle eos
}
void
-Http3App::_handle_uni_stream_on_eos(int /* event */, QUICStreamIO *stream_io)
+Http3App::_handle_uni_stream_on_eos(int /* event */, VIO *v)
{
// TODO: handle eos
}
void
-Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io)
+Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamVCAdapter *adapter)
{
// Change app to QPACK from Http3
if (type == Http3StreamType::QPACK_ENCODER) {
if (this->_qc->direction() == NET_VCONNECTION_IN) {
- this->_ssn->remote_qpack()->set_encoder_stream(stream_io);
+ this->_ssn->remote_qpack()->set_encoder_stream(adapter->stream().id());
} else {
- this->_ssn->local_qpack()->set_encoder_stream(stream_io);
+ this->_ssn->local_qpack()->set_encoder_stream(adapter->stream().id());
}
} else if (type == Http3StreamType::QPACK_DECODER) {
if (this->_qc->direction() == NET_VCONNECTION_IN) {
- this->_ssn->local_qpack()->set_decoder_stream(stream_io);
+ this->_ssn->local_qpack()->set_decoder_stream(adapter->stream().id());
} else {
- this->_ssn->remote_qpack()->set_decoder_stream(stream_io);
+ this->_ssn->remote_qpack()->set_decoder_stream(adapter->stream().id());
}
} else {
ink_abort("unknown stream type");
@@ -282,9 +315,11 @@ Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io)
}
void
-Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io)
+Http3App::_handle_bidi_stream_on_write_ready(int event, VIO *vio)
{
- QUICStreamId stream_id = stream_io->stream_id();
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
+
+ QUICStreamId stream_id = adapter->stream().id();
Http3Transaction *txn = static_cast<Http3Transaction *>(this->_ssn->get_transaction(stream_id));
if (txn != nullptr) {
SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
@@ -353,7 +388,7 @@ Http3SettingsHandler::handle_frame(std::shared_ptr<const Http3Frame> frame)
// SETTINGS frame framer
//
Http3FrameUPtr
-Http3SettingsFramer::generate_frame(uint16_t max_size)
+Http3SettingsFramer::generate_frame()
{
if (this->_is_sent) {
return Http3FrameFactory::create_null_frame();
diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h
index a48432a..5de5aea 100644
--- a/proxy/http3/Http3App.h
+++ b/proxy/http3/Http3App.h
@@ -23,9 +23,12 @@
#pragma once
+#include <map>
+
#include "IPAllow.h"
#include "QUICApplication.h"
+#include "QUICStreamVCAdapter.h"
#include "HttpSessionAccept.h"
@@ -48,6 +51,8 @@ public:
Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options);
virtual ~Http3App();
+ void on_new_stream(QUICStream &stream) override;
+
virtual void start();
virtual int main_event_handler(int event, Event *data);
@@ -58,15 +63,17 @@ public:
protected:
Http3Session *_ssn = nullptr;
+ std::unordered_map<QUICStreamId, QUICStreamVCAdapter::IOInfo> _streams;
+
private:
- void _handle_uni_stream_on_read_ready(int event, QUICStreamIO *stream_io);
- void _handle_uni_stream_on_write_ready(int event, QUICStreamIO *stream_io);
- void _handle_uni_stream_on_eos(int event, QUICStreamIO *stream_io);
- void _handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io);
- void _handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io);
- void _handle_bidi_stream_on_eos(int event, QUICStreamIO *stream_io);
+ void _handle_uni_stream_on_read_ready(int event, VIO *vio);
+ void _handle_uni_stream_on_write_ready(int event, VIO *vio);
+ void _handle_uni_stream_on_eos(int event, VIO *vio);
+ void _handle_bidi_stream_on_read_ready(int event, VIO *vio);
+ void _handle_bidi_stream_on_write_ready(int event, VIO *vio);
+ void _handle_bidi_stream_on_eos(int event, VIO *vio);
- void _set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io);
+ void _set_qpack_stream(Http3StreamType type, QUICStreamVCAdapter *adapter);
Http3FrameHandler *_settings_handler = nullptr;
Http3FrameGenerator *_settings_framer = nullptr;
@@ -74,11 +81,10 @@ private:
Http3FrameDispatcher _control_stream_dispatcher;
Http3FrameCollector _control_stream_collector;
- QUICStreamIO *_remote_control_stream;
- QUICStreamIO *_local_control_stream;
-
std::map<QUICStreamId, Http3StreamType> _remote_uni_stream_map;
std::map<QUICStreamId, Http3StreamType> _local_uni_stream_map;
+
+ bool _is_control_stream_initialized = false;
};
class Http3SettingsHandler : public Http3FrameHandler
@@ -101,7 +107,7 @@ public:
Http3SettingsFramer(NetVConnectionContext_t context) : _context(context){};
// Http3FrameGenerator
- Http3FrameUPtr generate_frame(uint16_t max_size) override;
+ Http3FrameUPtr generate_frame() override;
bool is_done() const override;
private:
diff --git a/proxy/http3/Http3DataFramer.cc b/proxy/http3/Http3DataFramer.cc
index eaf5862..5fbb56d 100644
--- a/proxy/http3/Http3DataFramer.cc
+++ b/proxy/http3/Http3DataFramer.cc
@@ -28,7 +28,7 @@
Http3DataFramer::Http3DataFramer(Http3Transaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {}
Http3FrameUPtr
-Http3DataFramer::generate_frame(uint16_t max_size)
+Http3DataFramer::generate_frame()
{
if (!this->_transaction->is_response_header_sent()) {
return Http3FrameFactory::create_null_frame();
@@ -37,11 +37,7 @@ Http3DataFramer::generate_frame(uint16_t max_size)
Http3FrameUPtr frame = Http3FrameFactory::create_null_frame();
IOBufferReader *reader = this->_source_vio->get_reader();
- if (max_size <= Http3Frame::MAX_FRAM_HEADER_OVERHEAD) {
- return frame;
- }
-
- size_t payload_len = max_size - Http3Frame::MAX_FRAM_HEADER_OVERHEAD;
+ size_t payload_len = 128 * 1024;
if (!reader->is_read_avail_more_than(payload_len)) {
payload_len = reader->read_avail();
}
diff --git a/proxy/http3/Http3DataFramer.h b/proxy/http3/Http3DataFramer.h
index 045e86c..0db8715 100644
--- a/proxy/http3/Http3DataFramer.h
+++ b/proxy/http3/Http3DataFramer.h
@@ -35,7 +35,7 @@ public:
Http3DataFramer(Http3Transaction *transaction, VIO *source);
// Http3FrameGenerator
- Http3FrameUPtr generate_frame(uint16_t max_size) override;
+ Http3FrameUPtr generate_frame() override;
bool is_done() const override;
private:
diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc
index db8c98b..6bb195e 100644
--- a/proxy/http3/Http3Frame.cc
+++ b/proxy/http3/Http3Frame.cc
@@ -31,6 +31,8 @@ ClassAllocator<Http3DataFrame> http3DataFrameAllocator("http3DataFrameAllocator"
ClassAllocator<Http3HeadersFrame> http3HeadersFrameAllocator("http3HeadersFrameAllocator");
ClassAllocator<Http3SettingsFrame> http3SettingsFrameAllocator("http3SettingsFrameAllocator");
+constexpr int HEADER_OVERHEAD = 10; // This should work as long as a payload length is less than 64 bits
+
//
// Static functions
//
@@ -100,11 +102,11 @@ Http3Frame::type() const
}
}
-void
-Http3Frame::store(uint8_t *buf, size_t *len) const
+Ptr<IOBufferBlock>
+Http3Frame::to_io_buffer_block() const
{
- // If you really need this, you should keep the data passed to its constructor
- ink_assert(!"Not supported");
+ Ptr<IOBufferBlock> block;
+ return block;
}
void
@@ -119,11 +121,20 @@ Http3Frame::reset(const uint8_t *buf, size_t len)
//
Http3UnknownFrame::Http3UnknownFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len), _buf(buf), _buf_len(buf_len) {}
-void
-Http3UnknownFrame::store(uint8_t *buf, size_t *len) const
+Ptr<IOBufferBlock>
+Http3UnknownFrame::to_io_buffer_block() const
{
- memcpy(buf, this->_buf, this->_buf_len);
- *len = this->_buf_len;
+ Ptr<IOBufferBlock> block;
+ size_t n = 0;
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(HEADER_OVERHEAD + this->length(), BUFFER_SIZE_INDEX_32K));
+ uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
+ memcpy(block_start, this->_buf, this->_buf_len);
+ n += this->_buf_len;
+
+ block->fill(n);
+ return block;
}
//
@@ -142,18 +153,26 @@ Http3DataFrame::Http3DataFrame(ats_unique_buf payload, size_t payload_len)
this->_payload = this->_payload_uptr.get();
}
-void
-Http3DataFrame::store(uint8_t *buf, size_t *len) const
+Ptr<IOBufferBlock>
+Http3DataFrame::to_io_buffer_block() const
{
+ Ptr<IOBufferBlock> block;
+ size_t n = 0;
size_t written = 0;
- size_t n;
- QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(HEADER_OVERHEAD + this->length(), BUFFER_SIZE_INDEX_32K));
+ uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
+
+ QUICVariableInt::encode(block_start, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
written += n;
- QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length);
+ QUICVariableInt::encode(block_start + written, UINT64_MAX, n, this->_length);
written += n;
- memcpy(buf + written, this->_payload, this->_payload_len);
+ memcpy(block_start + written, this->_payload, this->_payload_len);
written += this->_payload_len;
- *len = written;
+
+ block->fill(written);
+ return block;
}
void
@@ -191,18 +210,26 @@ Http3HeadersFrame::Http3HeadersFrame(ats_unique_buf header_block, size_t header_
this->_header_block = this->_header_block_uptr.get();
}
-void
-Http3HeadersFrame::store(uint8_t *buf, size_t *len) const
+Ptr<IOBufferBlock>
+Http3HeadersFrame::to_io_buffer_block() const
{
+ Ptr<IOBufferBlock> block;
+ size_t n = 0;
size_t written = 0;
- size_t n;
- QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
+
+ block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ block->alloc(iobuffer_size_to_index(HEADER_OVERHEAD + this->length(), BUFFER_SIZE_INDEX_32K));
+ uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
+
+ QUICVariableInt::encode(block_start, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
written += n;
- QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length);
+ QUICVariableInt::encode(block_start + written, UINT64_MAX, n, this->_length);
written += n;
- memcpy(buf + written, this->_header_block, this->_header_block_len);
+ memcpy(block_start + written, this->_header_block, this->_header_block_len);
written += this->_header_block_len;
- *len = written;
+
+ block->fill(written);
+ return block;
}
void
@@ -270,40 +297,48 @@ Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len, uint3
}
}
-void
-Http3SettingsFrame::store(uint8_t *buf, size_t *len) const
+Ptr<IOBufferBlock>
+Http3SettingsFrame::to_io_buffer_block() const
{
- uint8_t payload[Http3SettingsFrame::MAX_PAYLOAD_SIZE] = {0};
- uint8_t *p = payload;
- size_t l = 0;
+ Ptr<IOBufferBlock> header_block;
+ Ptr<IOBufferBlock> payload_block;
+ size_t n = 0;
+ size_t written = 0;
+
+ payload_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ payload_block->alloc(iobuffer_size_to_index(Http3SettingsFrame::MAX_PAYLOAD_SIZE, BUFFER_SIZE_INDEX_32K));
+ uint8_t *payload_block_start = reinterpret_cast<uint8_t *>(payload_block->start());
for (auto &it : this->_settings) {
- QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(it.first), p, &l);
- p += l;
- QUICIntUtil::write_QUICVariableInt(it.second, p, &l);
- p += l;
+ QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(it.first), payload_block_start + written, &n);
+ written += n;
+ QUICIntUtil::write_QUICVariableInt(it.second, payload_block_start + written, &n);
+ written += n;
}
// Exercise the requirement that unknown identifiers be ignored. - 4.2.5.1.
- QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(Http3SettingsId::UNKNOWN), p, &l);
- p += l;
- QUICIntUtil::write_QUICVariableInt(0, p, &l);
- p += l;
+ QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(Http3SettingsId::UNKNOWN), payload_block_start + written, &n);
+ written += n;
+ QUICIntUtil::write_QUICVariableInt(0, payload_block_start + written, &n);
+ written += n;
+ payload_block->fill(written);
- size_t written = 0;
- size_t payload_len = p - payload;
+ size_t payload_len = written;
+ written = 0;
+
+ header_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
+ header_block->alloc(iobuffer_size_to_index(HEADER_OVERHEAD, BUFFER_SIZE_INDEX_32K));
+ uint8_t *header_block_start = reinterpret_cast<uint8_t *>(header_block->start());
- size_t n;
- QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
+ QUICVariableInt::encode(header_block_start, UINT64_MAX, n, static_cast<uint64_t>(this->_type));
written += n;
- QUICVariableInt::encode(buf + written, UINT64_MAX, n, payload_len);
+ QUICVariableInt::encode(header_block_start + written, UINT64_MAX, n, payload_len);
written += n;
+ header_block->fill(written);
- // Payload
- memcpy(buf + written, payload, payload_len);
- written += payload_len;
+ header_block->next = payload_block;
- *len = written;
+ return header_block;
}
void
@@ -415,14 +450,14 @@ Http3FrameFactory::fast_create(const uint8_t *buf, size_t len)
}
std::shared_ptr<const Http3Frame>
-Http3FrameFactory::fast_create(QUICStreamIO &stream_io, size_t frame_len)
+Http3FrameFactory::fast_create(IOBufferReader &reader, size_t frame_len)
{
uint8_t buf[65536];
// FIXME DATA frames can be giga bytes
ink_assert(sizeof(buf) > frame_len);
- if (stream_io.peek(buf, frame_len) < static_cast<int64_t>(frame_len)) {
+ if (reader.read(buf, frame_len) < static_cast<int64_t>(frame_len)) {
// Return if whole frame data is not available
return nullptr;
}
diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h
index 4ae00a9..0207c2f 100644
--- a/proxy/http3/Http3Frame.h
+++ b/proxy/http3/Http3Frame.h
@@ -42,7 +42,7 @@ public:
uint64_t total_length() const;
uint64_t length() const;
Http3FrameType type() const;
- virtual void store(uint8_t *buf, size_t *len) const;
+ virtual Ptr<IOBufferBlock> to_io_buffer_block() const;
virtual void reset(const uint8_t *buf, size_t len);
static int length(const uint8_t *buf, size_t buf_len, uint64_t &length);
static Http3FrameType type(const uint8_t *buf, size_t buf_len);
@@ -59,7 +59,7 @@ public:
Http3UnknownFrame() : Http3Frame() {}
Http3UnknownFrame(const uint8_t *buf, size_t len);
- void store(uint8_t *buf, size_t *len) const override;
+ Ptr<IOBufferBlock> to_io_buffer_block() const override;
protected:
const uint8_t *_buf = nullptr;
@@ -77,7 +77,7 @@ public:
Http3DataFrame(const uint8_t *buf, size_t len);
Http3DataFrame(ats_unique_buf payload, size_t payload_len);
- void store(uint8_t *buf, size_t *len) const override;
+ Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
const uint8_t *payload() const;
@@ -100,7 +100,7 @@ public:
Http3HeadersFrame(const uint8_t *buf, size_t len);
Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len);
- void store(uint8_t *buf, size_t *len) const override;
+ Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
const uint8_t *header_block() const;
@@ -130,7 +130,7 @@ public:
Http3SettingsId::NUM_PLACEHOLDERS,
};
- void store(uint8_t *buf, size_t *len) const override;
+ Ptr<IOBufferBlock> to_io_buffer_block() const override;
void reset(const uint8_t *buf, size_t len) override;
bool is_valid() const;
@@ -223,7 +223,7 @@ public:
* This works almost the same as create() but it reuses created objects for performance.
* If you create a frame object which has the same frame type that you created before, the object will be reset by new data.
*/
- std::shared_ptr<const Http3Frame> fast_create(QUICStreamIO &stream_io, size_t frame_len);
+ std::shared_ptr<const Http3Frame> fast_create(IOBufferReader &reader, size_t frame_len);
std::shared_ptr<const Http3Frame> fast_create(const uint8_t *buf, size_t len);
/*
diff --git a/proxy/http3/Http3FrameCollector.cc b/proxy/http3/Http3FrameCollector.cc
index 213a1e3..3118bac 100644
--- a/proxy/http3/Http3FrameCollector.cc
+++ b/proxy/http3/Http3FrameCollector.cc
@@ -26,10 +26,9 @@
#include "Http3DebugNames.h"
Http3ErrorUPtr
-Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten)
+Http3FrameCollector::on_write_ready(QUICStreamId stream_id, MIOBuffer &writer, size_t &nwritten, bool &all_done)
{
- bool all_done = true;
- uint8_t tmp[32768];
+ all_done = true;
nwritten = 0;
for (auto g : this->_generators) {
@@ -37,26 +36,17 @@ Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten)
continue;
}
size_t len = 0;
- Http3FrameUPtr frame = g->generate_frame(sizeof(tmp) - nwritten);
+ Http3FrameUPtr frame = g->generate_frame();
if (frame) {
- frame->store(tmp + nwritten, &len);
+ auto b = frame->to_io_buffer_block();
+ len = writer.write(b.get(), INT64_MAX, 0);
nwritten += len;
-
- Debug("http3", "[TX] [%d] | %s size=%zu", stream_io->stream_id(), Http3DebugNames::frame_type(frame->type()), len);
+ Debug("http3", "[TX] [%" PRIu64 "] | %s size=%zu", stream_id, Http3DebugNames::frame_type(frame->type()), len);
}
all_done &= g->is_done();
}
- if (nwritten) {
- int64_t len = stream_io->write(tmp, nwritten);
- ink_assert(len > 0 && (uint64_t)len == nwritten);
- }
-
- if (all_done) {
- stream_io->write_done();
- }
-
return Http3ErrorUPtr(new Http3NoError());
}
diff --git a/proxy/http3/Http3FrameCollector.h b/proxy/http3/Http3FrameCollector.h
index 73b7c5c..3faaf5d 100644
--- a/proxy/http3/Http3FrameCollector.h
+++ b/proxy/http3/Http3FrameCollector.h
@@ -28,10 +28,12 @@
#include "Http3FrameGenerator.h"
#include <vector>
+class QUICStreamVCAdapter;
+
class Http3FrameCollector
{
public:
- Http3ErrorUPtr on_write_ready(QUICStreamIO *stream_io, size_t &nread);
+ Http3ErrorUPtr on_write_ready(QUICStreamId stream_id, MIOBuffer &writer, size_t &nread, bool &all_done);
void add_generator(Http3FrameGenerator *generator);
diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc
index 64df8d5..5a578c2 100644
--- a/proxy/http3/Http3FrameDispatcher.cc
+++ b/proxy/http3/Http3FrameDispatcher.cc
@@ -41,7 +41,7 @@ Http3FrameDispatcher::add_handler(Http3FrameHandler *handler)
}
Http3ErrorUPtr
-Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread)
+Http3FrameDispatcher::on_read_ready(QUICStreamId stream_id, IOBufferReader &reader, uint64_t &nread)
{
std::shared_ptr<const Http3Frame> frame(nullptr);
Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError());
@@ -50,7 +50,8 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread)
while (true) {
// Read a length of Type field and hopefully a length of Length field too
uint8_t head[16];
- int64_t read_len = stream_io.peek(head, 16);
+ auto p = reader.memcpy(head, 16);
+ int64_t read_len = p - reinterpret_cast<char *>(head);
Debug("v_http3", "reading H3 frame: state=%d read_len=%" PRId64, this->_reading_state, read_len);
if (this->_reading_state == READING_TYPE_LEN) {
@@ -87,19 +88,21 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread)
if (this->_reading_state == READING_PAYLOAD) {
// Create a frame
// Type field length + Length field length + Payload length
- size_t frame_len = this->_reading_frame_type_len + this->_reading_frame_length_len + this->_reading_frame_payload_len;
- frame = this->_frame_factory.fast_create(stream_io, frame_len);
+ size_t frame_len = this->_reading_frame_type_len + this->_reading_frame_length_len + this->_reading_frame_payload_len;
+ auto cloned_reader = reader.clone();
+ frame = this->_frame_factory.fast_create(*cloned_reader, frame_len);
+ cloned_reader->dealloc();
if (frame == nullptr) {
break;
}
// Consume buffer if frame is created
nread += frame_len;
- stream_io.consume(frame_len);
+ reader.consume(frame_len);
// Dispatch
Http3FrameType type = frame->type();
- Debug("http3", "[RX] [%d] | %s size=%zu", stream_io.stream_id(), Http3DebugNames::frame_type(type), frame_len);
+ Debug("http3", "[RX] [%" PRIu64 "] | %s size=%zu", stream_id, Http3DebugNames::frame_type(type), frame_len);
std::vector<Http3FrameHandler *> handlers = this->_handlers[static_cast<uint8_t>(type)];
for (auto h : handlers) {
error = h->handle_frame(frame);
diff --git a/proxy/http3/Http3FrameDispatcher.h b/proxy/http3/Http3FrameDispatcher.h
index fae5121..315a5b0 100644
--- a/proxy/http3/Http3FrameDispatcher.h
+++ b/proxy/http3/Http3FrameDispatcher.h
@@ -28,10 +28,12 @@
#include "Http3FrameHandler.h"
#include <vector>
+class QUICStreamVCAdapter;
+
class Http3FrameDispatcher
{
public:
- Http3ErrorUPtr on_read_ready(QUICStreamIO &stream_io, uint64_t &nread);
+ Http3ErrorUPtr on_read_ready(QUICStreamId stream_id, IOBufferReader &reader, uint64_t &nread);
void add_handler(Http3FrameHandler *handler);
diff --git a/proxy/http3/Http3FrameGenerator.h b/proxy/http3/Http3FrameGenerator.h
index 6da188f..de5a4a1 100644
--- a/proxy/http3/Http3FrameGenerator.h
+++ b/proxy/http3/Http3FrameGenerator.h
@@ -29,6 +29,6 @@ class Http3FrameGenerator
{
public:
virtual ~Http3FrameGenerator(){};
- virtual Http3FrameUPtr generate_frame(uint16_t max_size) = 0;
- virtual bool is_done() const = 0;
+ virtual Http3FrameUPtr generate_frame() = 0;
+ virtual bool is_done() const = 0;
};
diff --git a/proxy/http3/Http3HeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc
index b69f298..079c5d2 100644
--- a/proxy/http3/Http3HeaderFramer.cc
+++ b/proxy/http3/Http3HeaderFramer.cc
@@ -38,8 +38,12 @@ Http3HeaderFramer::Http3HeaderFramer(Http3Transaction *transaction, VIO *source,
}
Http3FrameUPtr
-Http3HeaderFramer::generate_frame(uint16_t max_size)
+Http3HeaderFramer::generate_frame()
{
+ if (!this->_source_vio->get_reader()) {
+ return Http3FrameFactory::create_null_frame();
+ }
+
ink_assert(!this->_transaction->is_response_header_sent());
if (!this->_header_block) {
@@ -48,8 +52,7 @@ Http3HeaderFramer::generate_frame(uint16_t max_size)
}
if (this->_header_block) {
- // Create frames on demand base on max_size since we don't know how much we can write now
- uint64_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast<uint64_t>(max_size));
+ uint64_t len = std::min(this->_header_block_len - this->_header_block_wrote, UINT64_C(64 * 1024));
Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(this->_header_block_reader, len);
diff --git a/proxy/http3/Http3HeaderFramer.h b/proxy/http3/Http3HeaderFramer.h
index 2e70338..9559edb 100644
--- a/proxy/http3/Http3HeaderFramer.h
+++ b/proxy/http3/Http3HeaderFramer.h
@@ -39,7 +39,7 @@ public:
Http3HeaderFramer(Http3Transaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id);
// Http3FrameGenerator
- Http3FrameUPtr generate_frame(uint16_t max_size) override;
+ Http3FrameUPtr generate_frame() override;
bool is_done() const override;
private:
diff --git a/proxy/http3/Http3HeaderVIOAdaptor.cc b/proxy/http3/Http3HeaderVIOAdaptor.cc
index 6a55ae7..0d246c5 100644
--- a/proxy/http3/Http3HeaderVIOAdaptor.cc
+++ b/proxy/http3/Http3HeaderVIOAdaptor.cc
@@ -25,10 +25,26 @@
#include "I_VIO.h"
#include "HTTP.h"
+#include "HTTP2.h"
-Http3HeaderVIOAdaptor::Http3HeaderVIOAdaptor(HTTPHdr *hdr, QPACK *qpack, Continuation *cont, uint64_t stream_id)
- : _request_header(hdr), _qpack(qpack), _cont(cont), _stream_id(stream_id)
+// Constant strings for pseudo headers
+const char *HTTP3_VALUE_SCHEME = ":scheme";
+const char *HTTP3_VALUE_AUTHORITY = ":authority";
+
+const unsigned HTTP3_LEN_SCHEME = countof(":scheme") - 1;
+const unsigned HTTP3_LEN_AUTHORITY = countof(":authority") - 1;
+
+Http3HeaderVIOAdaptor::Http3HeaderVIOAdaptor(VIO *sink, HTTPType http_type, QPACK *qpack, uint64_t stream_id)
+ : _sink_vio(sink), _qpack(qpack), _stream_id(stream_id)
+{
+ SET_HANDLER(&Http3HeaderVIOAdaptor::event_handler);
+
+ this->_header.create(http_type);
+}
+
+Http3HeaderVIOAdaptor::~Http3HeaderVIOAdaptor()
{
+ this->_header.destroy();
}
std::vector<Http3FrameType>
@@ -43,8 +59,7 @@ Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> frame)
ink_assert(frame->type() == Http3FrameType::HEADERS);
const Http3HeadersFrame *hframe = dynamic_cast<const Http3HeadersFrame *>(frame.get());
- int res = this->_qpack->decode(this->_stream_id, hframe->header_block(), hframe->header_block_length(), *this->_request_header,
- this->_cont);
+ int res = this->_qpack->decode(this->_stream_id, hframe->header_block(), hframe->header_block_length(), _header, this);
if (res == 0) {
// When decoding is not blocked, continuation should be called directly?
@@ -59,3 +74,102 @@ Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr<const Http3Frame> frame)
return Http3ErrorUPtr(new Http3NoError());
}
+
+bool
+Http3HeaderVIOAdaptor::is_complete()
+{
+ return this->_is_complete;
+}
+
+int
+Http3HeaderVIOAdaptor::event_handler(int event, Event *data)
+{
+ switch (event) {
+ case QPACK_EVENT_DECODE_COMPLETE:
+ Debug("v_http3", "%s (%d)", "QPACK_EVENT_DECODE_COMPLETE", event);
+ if (this->_on_qpack_decode_complete()) {
+ // If READ_READY event is scheduled, should it be canceled?
+ }
+ break;
+ case QPACK_EVENT_DECODE_FAILED:
+ Debug("v_http3", "%s (%d)", "QPACK_EVENT_DECODE_FAILED", event);
+ // FIXME: handle error
+ break;
+ }
+
+ return EVENT_DONE;
+}
+
+int
+Http3HeaderVIOAdaptor::_on_qpack_decode_complete()
+{
+ ParseResult res = this->_convert_header_from_3_to_1_1(&this->_header);
+ if (res == PARSE_RESULT_ERROR) {
+ Debug("http3", "PARSE_RESULT_ERROR");
+ return -1;
+ }
+
+ // FIXME: response header might be delayed from first response body because of callback from QPACK
+ // Workaround fix for mixed response header and body
+ if (http_hdr_type_get(this->_header.m_http) == HTTP_TYPE_RESPONSE) {
+ return 0;
+ }
+
+ SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread());
+ MIOBuffer *writer = this->_sink_vio->get_writer();
+
+ // TODO: Http2Stream::send_request has same logic. It originally comes from HttpSM::write_header_into_buffer.
+ // a). Make HttpSM::write_header_into_buffer static
+ // or
+ // b). Add interface to HTTPHdr to dump data
+ // or
+ // c). Add interface to HttpSM to handle HTTPHdr directly
+ int bufindex;
+ int dumpoffset = 0;
+ int done, tmp;
+ IOBufferBlock *block;
+ do {
+ bufindex = 0;
+ tmp = dumpoffset;
+ block = writer->get_current_block();
+ if (!block) {
+ writer->add_block();
+ block = writer->get_current_block();
+ }
+ done = this->_header.print(block->end(), block->write_avail(), &bufindex, &tmp);
+ dumpoffset += bufindex;
+ writer->fill(bufindex);
+ if (!done) {
+ writer->add_block();
+ }
+ } while (!done);
+
+ this->_is_complete = true;
+ return 1;
+}
+
+ParseResult
+Http3HeaderVIOAdaptor::_convert_header_from_3_to_1_1(HTTPHdr *hdrs)
+{
+ // TODO: do HTTP/3 specific convert, if there
+
+ if (http_hdr_type_get(hdrs->m_http) == HTTP_TYPE_REQUEST) {
+ // Dirty hack to bypass checks
+ MIMEField *field;
+ if ((field = hdrs->field_find(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME)) == nullptr) {
+ char value_s[] = "https";
+ MIMEField *scheme_field = hdrs->field_create(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME);
+ scheme_field->value_set(hdrs->m_heap, hdrs->m_mime, value_s, sizeof(value_s) - 1);
+ hdrs->field_attach(scheme_field);
+ }
+
+ if ((field = hdrs->field_find(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY)) == nullptr) {
+ char value_a[] = "localhost";
+ MIMEField *authority_field = hdrs->field_create(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY);
+ authority_field->value_set(hdrs->m_heap, hdrs->m_mime, value_a, sizeof(value_a) - 1);
+ hdrs->field_attach(authority_field);
+ }
+ }
+
+ return http2_convert_header_from_2_to_1_1(hdrs);
+}
diff --git a/proxy/http3/Http3HeaderVIOAdaptor.h b/proxy/http3/Http3HeaderVIOAdaptor.h
index f81456b..4f064a2 100644
--- a/proxy/http3/Http3HeaderVIOAdaptor.h
+++ b/proxy/http3/Http3HeaderVIOAdaptor.h
@@ -27,18 +27,27 @@
#include "Http3FrameHandler.h"
-// TODO: rename, this is not VIOAdaptor anymore
-class Http3HeaderVIOAdaptor : public Http3FrameHandler
+class Http3HeaderVIOAdaptor : public Http3FrameHandler, public Continuation
{
public:
- Http3HeaderVIOAdaptor(HTTPHdr *hdr, QPACK *qpack, Continuation *cont, uint64_t stream_id);
+ Http3HeaderVIOAdaptor(VIO *sink, HTTPType http_type, QPACK *qpack, uint64_t stream_id);
+ ~Http3HeaderVIOAdaptor();
+
// Http3FrameHandler
std::vector<Http3FrameType> interests() override;
Http3ErrorUPtr handle_frame(std::shared_ptr<const Http3Frame> frame) override;
+ bool is_complete();
+ int event_handler(int event, Event *data);
+
private:
- HTTPHdr *_request_header = nullptr;
- QPACK *_qpack = nullptr;
- Continuation *_cont = nullptr;
- uint64_t _stream_id = 0;
+ VIO *_sink_vio = nullptr;
+ QPACK *_qpack = nullptr;
+ uint64_t _stream_id = 0;
+ bool _is_complete = false;
+
+ HTTPHdr _header; ///< HTTP header buffer for decoding
+
+ int _on_qpack_decode_complete();
+ ParseResult _convert_header_from_3_to_1_1(HTTPHdr *hdr);
};
diff --git a/proxy/http3/Http3Transaction.cc b/proxy/http3/Http3Transaction.cc
index 2e0b743..b8ffca7 100644
--- a/proxy/http3/Http3Transaction.cc
+++ b/proxy/http3/Http3Transaction.cc
@@ -32,7 +32,6 @@
#include "Http3HeaderFramer.h"
#include "Http3DataFramer.h"
#include "HttpSM.h"
-#include "HTTP2.h"
#define Http3TransDebug(fmt, ...) \
Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \
@@ -57,27 +56,15 @@
//
// HQTransaction
//
-HQTransaction::HQTransaction(HQSession *session, QUICStreamIO *stream_io) : super(session), _stream_io(stream_io)
+HQTransaction::HQTransaction(HQSession *session, QUICStreamVCAdapter::IOInfo &info) : super(session), _info(info)
{
this->mutex = new_ProxyMutex();
this->_thread = this_ethread();
this->_reader = this->_read_vio_buf.alloc_reader();
-
- HTTPType http_type = HTTP_TYPE_UNKNOWN;
- if (this->direction() == NET_VCONNECTION_OUT) {
- http_type = HTTP_TYPE_RESPONSE;
- } else {
- http_type = HTTP_TYPE_REQUEST;
- }
-
- this->_header.create(http_type);
}
-HQTransaction::~HQTransaction()
-{
- this->_header.destroy();
-}
+HQTransaction::~HQTransaction() {}
void
HQTransaction::set_active_timeout(ink_hrtime timeout_in)
@@ -194,14 +181,14 @@ HQTransaction::reenable(VIO *vio)
{
if (vio->op == VIO::READ) {
int64_t len = this->_process_read_vio();
- this->_stream_io->read_reenable();
+ this->_info.read_vio->reenable();
if (len > 0) {
this->_signal_read_event();
}
} else if (vio->op == VIO::WRITE) {
int64_t len = this->_process_write_vio();
- this->_stream_io->write_reenable();
+ this->_info.write_vio->reenable();
if (len > 0) {
this->_signal_write_event();
@@ -220,7 +207,7 @@ HQTransaction::transaction_done()
int
HQTransaction::get_transaction_id() const
{
- return this->_stream_io->stream_id();
+ return this->_info.adapter.stream().id();
}
void
@@ -306,17 +293,24 @@ HQTransaction::_signal_write_event()
//
// Http3Transaction
//
-Http3Transaction::Http3Transaction(Http3Session *session, QUICStreamIO *stream_io) : super(session, stream_io)
+Http3Transaction::Http3Transaction(Http3Session *session, QUICStreamVCAdapter::IOInfo &info) : super(session, info)
{
static_cast<HQSession *>(this->_proxy_ssn)->add_transaction(static_cast<HQTransaction *>(this));
+ QUICStreamId stream_id = this->_info.adapter.stream().id();
- this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id());
+ this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_id);
this->_data_framer = new Http3DataFramer(this, &this->_write_vio);
this->_frame_collector.add_generator(this->_header_framer);
this->_frame_collector.add_generator(this->_data_framer);
// this->_frame_collector.add_generator(this->_push_controller);
- this->_header_handler = new Http3HeaderVIOAdaptor(&this->_header, session->remote_qpack(), this, stream_io->stream_id());
+ HTTPType http_type = HTTP_TYPE_UNKNOWN;
+ if (this->direction() == NET_VCONNECTION_OUT) {
+ http_type = HTTP_TYPE_RESPONSE;
+ } else {
+ http_type = HTTP_TYPE_REQUEST;
+ }
+ this->_header_handler = new Http3HeaderVIOAdaptor(&this->_read_vio, http_type, session->remote_qpack(), stream_id);
this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio);
this->_frame_dispatcher.add_handler(this->_header_handler);
@@ -359,15 +353,20 @@ Http3Transaction::state_stream_open(int event, void *edata)
if (this->_process_read_vio() > 0) {
this->_signal_read_event();
}
- this->_stream_io->read_reenable();
+ this->_info.read_vio->reenable();
break;
case VC_EVENT_READ_COMPLETE:
+ if (!this->_header_handler->is_complete()) {
+ // Delay processing READ_COMPLETE
+ this_ethread()->schedule_imm(this, VC_EVENT_READ_COMPLETE);
+ break;
+ }
Http3TransVDebug("%s (%d)", get_vc_event_name(event), event);
this->_process_read_vio();
this->_data_handler->finalize();
// always signal regardless of progress
this->_signal_read_event();
- this->_stream_io->read_reenable();
+ this->_info.read_vio->reenable();
break;
case VC_EVENT_WRITE_READY:
Http3TransVDebug("%s (%d)", get_vc_event_name(event), event);
@@ -375,14 +374,14 @@ Http3Transaction::state_stream_open(int event, void *edata)
if (this->_process_write_vio() > 0) {
this->_signal_write_event();
}
- this->_stream_io->write_reenable();
+ this->_info.write_vio->reenable();
break;
case VC_EVENT_WRITE_COMPLETE:
Http3TransVDebug("%s (%d)", get_vc_event_name(event), event);
this->_process_write_vio();
// always signal regardless of progress
this->_signal_write_event();
- this->_stream_io->write_reenable();
+ this->_info.write_vio->reenable();
break;
case VC_EVENT_EOS:
case VC_EVENT_ERROR:
@@ -391,20 +390,6 @@ Http3Transaction::state_stream_open(int event, void *edata)
Http3TransVDebug("%s (%d)", get_vc_event_name(event), event);
break;
}
- case QPACK_EVENT_DECODE_COMPLETE: {
- Http3TransVDebug("%s (%d)", "QPACK_EVENT_DECODE_COMPLETE", event);
- int res = this->_on_qpack_decode_complete();
- if (res) {
- // If READ_READY event is scheduled, should it be canceled?
- this->_signal_read_event();
- }
- break;
- }
- case QPACK_EVENT_DECODE_FAILED: {
- Http3TransVDebug("%s (%d)", "QPACK_EVENT_DECODE_FAILED", event);
- // FIXME: handle error
- break;
- }
default:
Http3TransDebug("Unknown event %d", event);
}
@@ -481,7 +466,7 @@ Http3Transaction::_process_read_vio()
SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
uint64_t nread = 0;
- this->_frame_dispatcher.on_read_ready(*this->_stream_io, nread);
+ this->_frame_dispatcher.on_read_ready(this->_info.adapter.stream().id(), *this->_info.read_vio->get_reader(), nread);
return nread;
}
@@ -504,89 +489,15 @@ Http3Transaction::_process_write_vio()
SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
size_t nwritten = 0;
- this->_frame_collector.on_write_ready(this->_stream_io, nwritten);
-
- return nwritten;
-}
-
-// Constant strings for pseudo headers
-const char *HTTP3_VALUE_SCHEME = ":scheme";
-const char *HTTP3_VALUE_AUTHORITY = ":authority";
-
-const unsigned HTTP3_LEN_SCHEME = countof(":scheme") - 1;
-const unsigned HTTP3_LEN_AUTHORITY = countof(":authority") - 1;
-
-ParseResult
-Http3Transaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs)
-{
- // TODO: do HTTP/3 specific convert, if there
-
- if (http_hdr_type_get(hdrs->m_http) == HTTP_TYPE_REQUEST) {
- // Dirty hack to bypass checks
- MIMEField *field;
- if ((field = hdrs->field_find(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME)) == nullptr) {
- char value_s[] = "https";
- MIMEField *scheme_field = hdrs->field_create(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME);
- scheme_field->value_set(hdrs->m_heap, hdrs->m_mime, value_s, sizeof(value_s) - 1);
- hdrs->field_attach(scheme_field);
- }
-
- if ((field = hdrs->field_find(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY)) == nullptr) {
- char value_a[] = "localhost";
- MIMEField *authority_field = hdrs->field_create(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY);
- authority_field->value_set(hdrs->m_heap, hdrs->m_mime, value_a, sizeof(value_a) - 1);
- hdrs->field_attach(authority_field);
- }
+ bool all_done = false;
+ this->_frame_collector.on_write_ready(this->_info.adapter.stream().id(), *this->_info.write_vio->get_writer(), nwritten,
+ all_done);
+ this->_info.write_vio->nbytes += nwritten;
+ if (all_done) {
+ this->_info.write_vio->done();
}
- return http2_convert_header_from_2_to_1_1(hdrs);
-}
-
-int
-Http3Transaction::_on_qpack_decode_complete()
-{
- ParseResult res = this->_convert_header_from_3_to_1_1(&this->_header);
- if (res == PARSE_RESULT_ERROR) {
- Http3TransDebug("PARSE_RESULT_ERROR");
- return -1;
- }
-
- // FIXME: response header might be delayed from first response body because of callback from QPACK
- // Workaround fix for mixed response header and body
- if (http_hdr_type_get(this->_header.m_http) == HTTP_TYPE_RESPONSE) {
- return 0;
- }
-
- SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
- MIOBuffer *writer = this->_read_vio.get_writer();
-
- // TODO: Http2Stream::send_request has same logic. It originally comes from HttpSM::write_header_into_buffer.
- // a). Make HttpSM::write_header_into_buffer static
- // or
- // b). Add interface to HTTPHdr to dump data
- // or
- // c). Add interface to HttpSM to handle HTTPHdr directly
- int bufindex;
- int dumpoffset = 0;
- int done, tmp;
- IOBufferBlock *block;
- do {
- bufindex = 0;
- tmp = dumpoffset;
- block = writer->get_current_block();
- if (!block) {
- writer->add_block();
- block = writer->get_current_block();
- }
- done = this->_header.print(block->end(), block->write_avail(), &bufindex, &tmp);
- dumpoffset += bufindex;
- writer->fill(bufindex);
- if (!done) {
- writer->add_block();
- }
- } while (!done);
-
- return 1;
+ return nwritten;
}
// TODO: Just a place holder for now
@@ -599,7 +510,7 @@ Http3Transaction::has_request_body(int64_t content_length, bool is_chunked_set)
//
// Http09Transaction
//
-Http09Transaction::Http09Transaction(Http09Session *session, QUICStreamIO *stream_io) : super(session, stream_io)
+Http09Transaction::Http09Transaction(Http09Session *session, QUICStreamVCAdapter::IOInfo &info) : super(session, info)
{
static_cast<HQSession *>(this->_proxy_ssn)->add_transaction(static_cast<HQTransaction *>(this));
@@ -637,7 +548,7 @@ Http09Transaction::state_stream_open(int event, void *edata)
if (len > 0) {
this->_signal_read_event();
}
- this->_stream_io->read_reenable();
+ this->_info.read_vio->reenable();
break;
}
@@ -647,7 +558,7 @@ Http09Transaction::state_stream_open(int event, void *edata)
if (len > 0) {
this->_signal_write_event();
}
- this->_stream_io->write_reenable();
+ this->_info.write_vio->reenable();
break;
}
@@ -720,13 +631,15 @@ Http09Transaction::_process_read_vio()
}
SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread());
+ IOBufferReader *reader = this->_info.read_vio->get_reader();
// Nuke this block when we drop 0.9 support
if (!this->_protocol_detected) {
uint8_t start[3];
- if (this->_stream_io->peek(start, 3) < 3) {
+ if (!reader->is_read_avail_more_than(3)) {
return 0;
}
+ reader->memcpy(start, 3);
// If the first two bit are 0 and 1, the 3rd byte is type field.
// Because there is no type value larger than 0x20, we can assume that the
// request is HTTP/0.9 if the value is larger than 0x20.
@@ -739,16 +652,14 @@ Http09Transaction::_process_read_vio()
if (this->_legacy_request) {
uint64_t nread = 0;
MIOBuffer *writer = this->_read_vio.get_writer();
-
// Nuke this branch when we drop 0.9 support
if (!this->_client_req_header_complete) {
uint8_t buf[4096];
- int len = this->_stream_io->peek(buf, 4096);
+ int len = reader->read(buf, 4096);
// Check client request is complete or not
if (len < 2 || buf[len - 1] != '\n') {
return 0;
}
- this->_stream_io->consume(len);
nread += len;
this->_client_req_header_complete = true;
@@ -765,7 +676,7 @@ Http09Transaction::_process_read_vio()
} else {
uint8_t buf[4096];
int len;
- while ((len = this->_stream_io->read(buf, 4096)) > 0) {
+ while ((len = reader->read(buf, 4096)) > 0) {
nread += len;
writer->write(buf, len);
}
@@ -779,7 +690,7 @@ Http09Transaction::_process_read_vio()
int len;
uint64_t nread = 0;
- while ((len = this->_stream_io->read(buf, 4096)) > 0) {
+ while ((len = reader->read(buf, 4096)) > 0) {
nread += len;
}
@@ -810,6 +721,9 @@ Http09Transaction::_process_write_vio()
SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread());
IOBufferReader *reader = this->_write_vio.get_reader();
+ if (!reader) {
+ return 0;
+ }
if (this->_legacy_request) {
// This branch is for HTTP/0.9
@@ -830,7 +744,7 @@ Http09Transaction::_process_write_vio()
while (total_written < bytes_avail) {
int64_t data_len = reader->block_read_avail();
- int64_t bytes_written = this->_stream_io->write(reader, data_len);
+ int64_t bytes_written = this->_info.write_vio->get_writer()->write(reader, data_len);
if (bytes_written <= 0) {
break;
}
@@ -844,7 +758,7 @@ Http09Transaction::_process_write_vio()
// is CHUNK_READ_DONE and set FIN flag
if (this->_write_vio.ntodo() == 0) {
// The size of respons to client
- this->_stream_io->write_done();
+ this->_info.write_vio->done();
}
return total_written;
diff --git a/proxy/http3/Http3Transaction.h b/proxy/http3/Http3Transaction.h
index 8dccccf..b1ddbb6 100644
--- a/proxy/http3/Http3Transaction.h
+++ b/proxy/http3/Http3Transaction.h
@@ -25,6 +25,7 @@
#include "I_VConnection.h"
#include "ProxyTransaction.h"
+#include "quic/QUICStreamVCAdapter.h"
#include "Http3FrameDispatcher.h"
#include "Http3FrameCollector.h"
@@ -34,6 +35,7 @@ class Http09Session;
class Http3Session;
class Http3HeaderFramer;
class Http3DataFramer;
+class Http3HeaderVIOAdaptor;
class Http3StreamDataVIOAdaptor;
class HQTransaction : public ProxyTransaction
@@ -41,7 +43,7 @@ class HQTransaction : public ProxyTransaction
public:
using super = ProxyTransaction;
- HQTransaction(HQSession *session, QUICStreamIO *stream_io);
+ HQTransaction(HQSession *session, QUICStreamVCAdapter::IOInfo &info);
virtual ~HQTransaction();
// Implement ProxyClienTransaction interface
@@ -77,15 +79,13 @@ protected:
EThread *_thread = nullptr;
Event *_cross_thread_event = nullptr;
- MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
- QUICStreamIO *_stream_io = nullptr;
+ MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
+ QUICStreamVCAdapter::IOInfo &_info;
VIO _read_vio;
VIO _write_vio;
Event *_read_event = nullptr;
Event *_write_event = nullptr;
-
- HTTPHdr _header; ///< HTTP header buffer for decoding
};
class Http3Transaction : public HQTransaction
@@ -93,7 +93,7 @@ class Http3Transaction : public HQTransaction
public:
using super = HQTransaction;
- Http3Transaction(Http3Session *session, QUICStreamIO *stream_io);
+ Http3Transaction(Http3Session *session, QUICStreamVCAdapter::IOInfo &info);
~Http3Transaction();
int state_stream_open(int event, void *data) override;
@@ -111,15 +111,12 @@ private:
int64_t _process_read_vio() override;
int64_t _process_write_vio() override;
- ParseResult _convert_header_from_3_to_1_1(HTTPHdr *hdr);
- int _on_qpack_decode_complete();
-
// These are for HTTP/3
Http3FrameDispatcher _frame_dispatcher;
Http3FrameCollector _frame_collector;
Http3FrameGenerator *_header_framer = nullptr;
Http3FrameGenerator *_data_framer = nullptr;
- Http3FrameHandler *_header_handler = nullptr;
+ Http3HeaderVIOAdaptor *_header_handler = nullptr;
Http3StreamDataVIOAdaptor *_data_handler = nullptr;
};
@@ -131,7 +128,7 @@ class Http09Transaction : public HQTransaction
public:
using super = HQTransaction;
- Http09Transaction(Http09Session *session, QUICStreamIO *stream_io);
+ Http09Transaction(Http09Session *session, QUICStreamVCAdapter::IOInfo &info);
~Http09Transaction();
int state_stream_open(int event, void *data) override;
diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc
index eaaa1a6..ca937f7 100644
--- a/proxy/http3/QPACK.cc
+++ b/proxy/http3/QPACK.cc
@@ -149,22 +149,47 @@ QPACK::QPACK(QUICConnection *qc, uint32_t max_header_list_size, uint16_t max_tab
QPACK::~QPACK() {}
+void
+QPACK::on_new_stream(QUICStream &stream)
+{
+ auto *info = new QUICStreamVCAdapter::IOInfo(stream);
+
+ switch (stream.direction()) {
+ case QUICStreamDirection::BIDIRECTIONAL:
+ // ink_assert(!"QPACK does not use bidirectional streams");
+ // QPACK offline interop uses stream 0 as a encoder stream.
+ info->setup_write_vio(this);
+ info->setup_read_vio(this);
+ break;
+ case QUICStreamDirection::SEND:
+ info->setup_write_vio(this);
+ break;
+ case QUICStreamDirection::RECEIVE:
+ info->setup_read_vio(this);
+ break;
+ default:
+ ink_assert(false);
+ break;
+ }
+
+ stream.set_io_adapter(&info->adapter);
+}
+
int
QPACK::event_handler(int event, Event *data)
{
- VIO *vio = reinterpret_cast<VIO *>(data);
- QUICStreamIO *stream_io = this->_find_stream_io(vio);
+ VIO *vio = reinterpret_cast<VIO *>(data);
int ret;
switch (event) {
case VC_EVENT_READ_READY:
- ret = this->_on_read_ready(*stream_io);
+ ret = this->_on_read_ready(vio);
break;
case VC_EVENT_READ_COMPLETE:
ret = EVENT_DONE;
break;
case VC_EVENT_WRITE_READY:
- ret = this->_on_write_ready(*stream_io);
+ ret = this->_on_write_ready(vio);
break;
case VC_EVENT_WRITE_COMPLETE:
ret = EVENT_DONE;
@@ -254,17 +279,15 @@ QPACK::decode(uint64_t stream_id, const uint8_t *header_block, size_t header_blo
}
void
-QPACK::set_encoder_stream(QUICStreamIO *stream_io)
+QPACK::set_encoder_stream(QUICStreamId id)
{
- this->_encoder_stream_id = stream_io->stream_id();
- this->set_stream(stream_io);
+ this->_encoder_stream_id = id;
}
void
-QPACK::set_decoder_stream(QUICStreamIO *stream_io)
+QPACK::set_decoder_stream(QUICStreamId id)
{
- this->_decoder_stream_id = stream_io->stream_id();
- this->set_stream(stream_io);
+ this->_decoder_stream_id = id;
}
void
@@ -1008,27 +1031,32 @@ QPACK::_abort_decode()
}
int
-QPACK::_on_read_ready(QUICStreamIO &stream_io)
+QPACK::_on_read_ready(VIO *vio)
{
- QUICStreamId stream_id = stream_io.stream_id();
+ int nread = 0;
+ QUICStreamId stream_id = static_cast<QUICStreamVCAdapter *>(vio->vc_server)->stream().id();
+
if (stream_id == this->_decoder_stream_id) {
- return this->_on_decoder_stream_read_ready(stream_io);
+ nread = this->_on_decoder_stream_read_ready(*vio->get_reader());
} else if (stream_id == this->_encoder_stream_id) {
- return this->_on_encoder_stream_read_ready(stream_io);
+ nread = this->_on_encoder_stream_read_ready(*vio->get_reader());
} else {
ink_assert(!"The stream ID must match either encoder stream id or decoder stream id");
- return EVENT_DONE;
}
+
+ vio->ndone += nread;
+ return EVENT_DONE;
}
int
-QPACK::_on_write_ready(QUICStreamIO &stream_io)
+QPACK::_on_write_ready(VIO *vio)
{
- QUICStreamId stream_id = stream_io.stream_id();
+ QUICStreamId stream_id = static_cast<QUICStreamVCAdapter *>(vio->vc_server)->stream().id();
+
if (stream_id == this->_decoder_stream_id) {
- return this->_on_decoder_write_ready(stream_io);
+ return this->_on_decoder_write_ready(*vio->get_writer());
} else if (stream_id == this->_encoder_stream_id) {
- return this->_on_encoder_write_ready(stream_io);
+ return this->_on_encoder_write_ready(*vio->get_writer());
} else {
ink_assert(!"The stream ID must match either decoder stream id or decoder stream id");
return EVENT_DONE;
@@ -1036,13 +1064,14 @@ QPACK::_on_write_ready(QUICStreamIO &stream_io)
}
int
-QPACK::_on_decoder_stream_read_ready(QUICStreamIO &stream_io)
+QPACK::_on_decoder_stream_read_ready(IOBufferReader &reader)
{
- uint8_t buf;
- if (stream_io.peek(&buf, 1) > 0) {
+ if (reader.is_read_avail_more_than(0)) {
+ uint8_t buf;
+ reader.memcpy(&buf, 1);
if (buf & 0x80) { // Header Acknowledgement
uint64_t stream_id;
- if (this->_read_header_acknowledgement(stream_io, stream_id) >= 0) {
+ if (this->_read_header_acknowledgement(reader, stream_id) >= 0) {
QPACKDebug("Received Header Acknowledgement: stream_id=%" PRIu64, stream_id);
this->_update_largest_known_received_index_by_stream_id(stream_id);
this->_update_reference_counts(stream_id);
@@ -1050,14 +1079,14 @@ QPACK::_on_decoder_stream_read_ready(QUICStreamIO &stream_io)
}
} else if (buf & 0x40) { // Stream Cancellation
uint64_t stream_id;
- if (this->_read_stream_cancellation(stream_io, stream_id) >= 0) {
+ if (this->_read_stream_cancellation(reader, stream_id) >= 0) {
QPACKDebug("Received Stream Cancellation: stream_id=%" PRIu64, stream_id);
this->_update_reference_counts(stream_id);
this->_references.erase(stream_id);
}
} else { // Table State Synchronize
uint16_t insert_count;
- if (this->_read_table_state_synchronize(stream_io, insert_count) >= 0) {
+ if (this->_read_table_state_synchronize(reader, insert_count) >= 0) {
QPACKDebug("Received Table State Synchronize: inserted_count=%d", insert_count);
this->_update_largest_known_received_index_by_insert_count(insert_count);
}
@@ -1068,18 +1097,18 @@ QPACK::_on_decoder_stream_read_ready(QUICStreamIO &stream_io)
}
int
-QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io)
+QPACK::_on_encoder_stream_read_ready(IOBufferReader &reader)
{
- uint8_t buf;
-
- while (stream_io.peek(&buf, 1) > 0) {
+ while (reader.is_read_avail_more_than(0)) {
+ uint8_t buf;
+ reader.memcpy(&buf, 1);
if (buf & 0x80) { // Insert With Name Reference
bool is_static;
uint16_t index;
Arena arena;
char *value;
uint16_t value_len;
- if (this->_read_insert_with_name_ref(stream_io, is_static, index, arena, &value, value_len) < 0) {
+ if (this->_read_insert_with_name_ref(reader, is_static, index, arena, &value, value_len) < 0) {
this->_abort_decode();
return EVENT_DONE;
}
@@ -1091,7 +1120,7 @@ QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io)
uint16_t name_len;
char *value;
uint16_t value_len;
- if (this->_read_insert_without_name_ref(stream_io, arena, &name, name_len, &value, value_len) < 0) {
+ if (this->_read_insert_without_name_ref(reader, arena, &name, name_len, &value, value_len) < 0) {
this->_abort_decode();
return EVENT_DONE;
}
@@ -1099,7 +1128,7 @@ QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io)
this->_dynamic_table.insert_entry(name, name_len, value, value_len);
} else if (buf & 0x20) { // Dynamic Table Size Update
uint16_t max_size;
- if (this->_read_dynamic_table_size_update(stream_io, max_size) < 0) {
+ if (this->_read_dynamic_table_size_update(reader, max_size) < 0) {
this->_abort_decode();
return EVENT_DONE;
}
@@ -1107,7 +1136,7 @@ QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io)
this->_dynamic_table.update_size(max_size);
} else { // Duplicates
uint16_t index;
- if (this->_read_duplicate(stream_io, index) < 0) {
+ if (this->_read_duplicate(reader, index) < 0) {
this->_abort_decode();
return EVENT_DONE;
}
@@ -1122,17 +1151,17 @@ QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io)
}
int
-QPACK::_on_decoder_write_ready(QUICStreamIO &stream_io)
+QPACK::_on_decoder_write_ready(MIOBuffer &writer)
{
- int64_t written_len = stream_io.write(this->_decoder_stream_sending_instructions_reader, INT64_MAX);
+ int64_t written_len = writer.write(this->_decoder_stream_sending_instructions_reader, INT64_MAX);
this->_decoder_stream_sending_instructions_reader->consume(written_len);
return written_len;
}
int
-QPACK::_on_encoder_write_ready(QUICStreamIO &stream_io)
+QPACK::_on_encoder_write_ready(MIOBuffer &writer)
{
- int64_t written_len = stream_io.write(this->_encoder_stream_sending_instructions_reader, INT64_MAX);
+ int64_t written_len = writer.write(this->_encoder_stream_sending_instructions_reader, INT64_MAX);
this->_encoder_stream_sending_instructions_reader->consume(written_len);
return written_len;
}
@@ -1611,14 +1640,14 @@ QPACK::_write_stream_cancellation(uint64_t stream_id)
}
int
-QPACK::_read_insert_with_name_ref(QUICStreamIO &stream_io, bool &is_static, uint16_t &index, Arena &arena, char **value,
+QPACK::_read_insert_with_name_ref(IOBufferReader &reader, bool &is_static, uint16_t &index, Arena &arena, char **value,
uint16_t &value_len)
{
size_t read_len = 0;
int ret;
uint8_t input[16384];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
// S flag
is_static = input[0] & 0x40;
@@ -1638,20 +1667,20 @@ QPACK::_read_insert_with_name_ref(QUICStreamIO &stream_io, bool &is_static, uint
value_len = tmp;
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_insert_without_name_ref(QUICStreamIO &stream_io, Arena &arena, char **name, uint16_t &name_len, char **value,
+QPACK::_read_insert_without_name_ref(IOBufferReader &reader, Arena &arena, char **name, uint16_t &name_len, char **value,
uint16_t &value_len)
{
size_t read_len = 0;
int ret;
uint8_t input[16384];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
// Name
uint64_t tmp;
@@ -1668,19 +1697,19 @@ QPACK::_read_insert_without_name_ref(QUICStreamIO &stream_io, Arena &arena, char
value_len = tmp;
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_duplicate(QUICStreamIO &stream_io, uint16_t &index)
+QPACK::_read_duplicate(IOBufferReader &reader, uint16_t &index)
{
size_t read_len = 0;
int ret;
uint8_t input[16];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
// Index
uint64_t tmp;
@@ -1690,19 +1719,19 @@ QPACK::_read_duplicate(QUICStreamIO &stream_io, uint16_t &index)
index = tmp;
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_dynamic_table_size_update(QUICStreamIO &stream_io, uint16_t &max_size)
+QPACK::_read_dynamic_table_size_update(IOBufferReader &reader, uint16_t &max_size)
{
size_t read_len = 0;
int ret;
uint8_t input[16];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
uint64_t tmp;
// Max Size
@@ -1712,19 +1741,19 @@ QPACK::_read_dynamic_table_size_update(QUICStreamIO &stream_io, uint16_t &max_si
max_size = tmp;
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_table_state_synchronize(QUICStreamIO &stream_io, uint16_t &insert_count)
+QPACK::_read_table_state_synchronize(IOBufferReader &reader, uint16_t &insert_count)
{
size_t read_len = 0;
int ret;
uint8_t input[16];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
uint64_t tmp;
// Insert Count
@@ -1734,19 +1763,19 @@ QPACK::_read_table_state_synchronize(QUICStreamIO &stream_io, uint16_t &insert_c
insert_count = tmp;
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_header_acknowledgement(QUICStreamIO &stream_io, uint64_t &stream_id)
+QPACK::_read_header_acknowledgement(IOBufferReader &reader, uint64_t &stream_id)
{
size_t read_len = 0;
int ret;
uint8_t input[16];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
// Stream ID
// FIXME xpack_decode_integer does not support uint64_t
@@ -1755,19 +1784,19 @@ QPACK::_read_header_acknowledgement(QUICStreamIO &stream_io, uint64_t &stream_id
}
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
int
-QPACK::_read_stream_cancellation(QUICStreamIO &stream_io, uint64_t &stream_id)
+QPACK::_read_stream_cancellation(IOBufferReader &reader, uint64_t &stream_id)
{
size_t read_len = 0;
int ret;
uint8_t input[16];
- int input_len;
- input_len = stream_io.peek(input, sizeof(input));
+ uint8_t *p = reinterpret_cast<uint8_t *>(reader.memcpy(input, sizeof(input)));
+ int input_len = p - input;
// Stream ID
// FIXME xpack_decode_integer does not support uint64_t
@@ -1776,7 +1805,7 @@ QPACK::_read_stream_cancellation(QUICStreamIO &stream_io, uint64_t &stream_id)
}
read_len += ret;
- stream_io.consume(read_len);
+ reader.consume(read_len);
return 0;
}
diff --git a/proxy/http3/QPACK.h b/proxy/http3/QPACK.h
index e81b4ab..4324450 100644
--- a/proxy/http3/QPACK.h
+++ b/proxy/http3/QPACK.h
@@ -33,6 +33,7 @@
#include "MIME.h"
#include "HTTP.h"
#include "QUICApplication.h"
+#include "QUICStreamVCAdapter.h"
#include "QUICConnection.h"
class HTTPHdr;
@@ -48,6 +49,8 @@ public:
QPACK(QUICConnection *qc, uint32_t max_header_list_size, uint16_t max_table_size, uint16_t max_blocking_streams);
virtual ~QPACK();
+ void on_new_stream(QUICStream &stream) override;
+
int event_handler(int event, Event *data);
/*
@@ -66,8 +69,8 @@ public:
int cancel(uint64_t stream_id);
- void set_encoder_stream(QUICStreamIO *stream_io);
- void set_decoder_stream(QUICStreamIO *stream_io);
+ void set_encoder_stream(QUICStreamId id);
+ void set_decoder_stream(QUICStreamId id);
void update_max_header_list_size(uint32_t max_header_list_size);
void update_max_table_size(uint16_t max_table_size);
@@ -266,21 +269,21 @@ private:
void _update_reference_counts(uint64_t stream_id);
// Encoder Stream
- int _read_insert_with_name_ref(QUICStreamIO &stream_io, bool &is_static, uint16_t &index, Arena &arena, char **value,
+ int _read_insert_with_name_ref(IOBufferReader &reader, bool &is_static, uint16_t &index, Arena &arena, char **value,
uint16_t &value_len);
- int _read_insert_without_name_ref(QUICStreamIO &stream_io, Arena &arena, char **name, uint16_t &name_len, char **value,
+ int _read_insert_without_name_ref(IOBufferReader &reader, Arena &arena, char **name, uint16_t &name_len, char **value,
uint16_t &value_len);
- int _read_duplicate(QUICStreamIO &stream_io, uint16_t &index);
- int _read_dynamic_table_size_update(QUICStreamIO &stream_io, uint16_t &max_size);
+ int _read_duplicate(IOBufferReader &reader, uint16_t &index);
+ int _read_dynamic_table_size_update(IOBufferReader &reader, uint16_t &max_size);
int _write_insert_with_name_ref(uint16_t index, bool dynamic, const char *value, uint16_t value_len);
int _write_insert_without_name_ref(const char *name, int name_len, const char *value, uint16_t value_len);
int _write_duplicate(uint16_t index);
int _write_dynamic_table_size_update(uint16_t max_size);
// Decoder Stream
- int _read_table_state_synchronize(QUICStreamIO &stream_io, uint16_t &insert_count);
- int _read_header_acknowledgement(QUICStreamIO &stream_io, uint64_t &stream_id);
- int _read_stream_cancellation(QUICStreamIO &stream_io, uint64_t &stream_id);
+ int _read_table_state_synchronize(IOBufferReader &reader, uint16_t &insert_count);
+ int _read_header_acknowledgement(IOBufferReader &reader, uint64_t &stream_id);
+ int _read_stream_cancellation(IOBufferReader &reader, uint64_t &stream_id);
int _write_table_state_synchronize(uint16_t insert_count);
int _write_header_acknowledgement(uint64_t stream_id);
int _write_stream_cancellation(uint64_t stream_id);
@@ -317,13 +320,13 @@ private:
uint16_t _calc_postbase_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index);
void _attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len, bool never_index);
- int _on_read_ready(QUICStreamIO &stream_io);
- int _on_decoder_stream_read_ready(QUICStreamIO &stream_io);
- int _on_encoder_stream_read_ready(QUICStreamIO &stream_io);
+ int _on_read_ready(VIO *vio);
+ int _on_decoder_stream_read_ready(IOBufferReader &reader);
+ int _on_encoder_stream_read_ready(IOBufferReader &reader);
- int _on_write_ready(QUICStreamIO &stream_io);
- int _on_decoder_write_ready(QUICStreamIO &stream_io);
- int _on_encoder_write_ready(QUICStreamIO &stream_io);
+ int _on_write_ready(VIO *vio);
+ int _on_decoder_write_ready(MIOBuffer &writer);
+ int _on_encoder_write_ready(MIOBuffer &writer);
// Stream numbers
// FIXME How are these stream ids negotiated? In interop, encoder stream id have to be 0 and decoder stream id must not be used.
diff --git a/proxy/http3/test/main.cc b/proxy/http3/test/main.cc
index 247e118..b0d4fa1 100644
--- a/proxy/http3/test/main.cc
+++ b/proxy/http3/test/main.cc
@@ -32,6 +32,8 @@
#include "RecordsConfig.h"
#include "Http3Config.h"
+#define TEST_THREADS 1
+
struct EventProcessorListener : Catch::TestEventListenerBase {
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
@@ -48,6 +50,12 @@ struct EventProcessorListener : Catch::TestEventListenerBase {
RecProcessInit(RECM_STAND_ALONE);
LibRecordsConfigInit();
+ ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION);
+ eventProcessor.start(TEST_THREADS);
+
+ Thread *main_thread = new EThread;
+ main_thread->set_specific();
+
Http3Config::startup();
}
};
diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc
index 9aa4efd..68b93b5 100644
--- a/proxy/http3/test/test_Http3Frame.cc
+++ b/proxy/http3/test/test_Http3Frame.cc
@@ -90,7 +90,11 @@ TEST_CASE("Store DATA Frame", "[http3]")
Http3DataFrame data_frame(std::move(payload1), 4);
CHECK(data_frame.length() == 4);
- data_frame.store(buf, &len);
+ auto ibb = data_frame.to_io_buffer_block();
+ IOBufferReader reader;
+ reader.block = ibb.get();
+ len = reader.read_avail();
+ reader.read(buf, sizeof(buf));
CHECK(len == 6);
CHECK(memcmp(buf, expected1, len) == 0);
}
@@ -115,7 +119,11 @@ TEST_CASE("Store HEADERS Frame", "[http3]")
Http3HeadersFrame hdrs_frame(std::move(header_block), 4);
CHECK(hdrs_frame.length() == 4);
- hdrs_frame.store(buf, &len);
+ auto ibb = hdrs_frame.to_io_buffer_block();
+ IOBufferReader reader;
+ reader.block = ibb.get();
+ len = reader.read_avail();
+ reader.read(buf, sizeof(buf));
CHECK(len == 6);
CHECK(memcmp(buf, expected1, len) == 0);
}
@@ -169,7 +177,11 @@ TEST_CASE("Store SETTINGS Frame", "[http3]")
uint8_t buf[32] = {0};
size_t len;
- settings_frame.store(buf, &len);
+ auto ibb = settings_frame.to_io_buffer_block();
+ IOBufferReader reader;
+ reader.block = ibb.get();
+ len = reader.read_avail();
+ reader.read(buf, sizeof(buf));
CHECK(len == sizeof(expected));
CHECK(memcmp(buf, expected, len) == 0);
}
@@ -190,7 +202,11 @@ TEST_CASE("Store SETTINGS Frame", "[http3]")
uint8_t buf[32] = {0};
size_t len;
- settings_frame.store(buf, &len);
+ auto ibb = settings_frame.to_io_buffer_block();
+ IOBufferReader reader;
+ reader.block = ibb.get();
+ len = reader.read_avail();
+ reader.read(buf, sizeof(buf));
CHECK(len == sizeof(expected));
CHECK(memcmp(buf, expected, len) == 0);
}
diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc
index 167ab7f..3faee2a 100644
--- a/proxy/http3/test/test_QPACK.cc
+++ b/proxy/http3/test/test_QPACK.cc
@@ -76,16 +76,18 @@ public:
void
write(const uint8_t *buf, size_t buf_len, QUICOffset offset, bool last)
{
- this->_write_to_read_vio(offset, buf, buf_len, last);
- this->_signal_read_event();
+ this->_adapter->write(offset, buf, buf_len, last);
+ this->_adapter->encourge_read();
}
size_t
read(uint8_t *buf, size_t buf_len)
{
- this->_signal_write_event();
- IOBufferReader *reader = this->_write_vio.get_reader();
- return reader->read(buf, buf_len);
+ this->_adapter->encourge_read();
+ auto ibb = this->_adapter->read(buf_len);
+ IOBufferReader reader;
+ reader.block = ibb;
+ return reader.read(buf, buf_len);
}
};
@@ -295,9 +297,11 @@ test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am
QUICApplicationDriver driver;
QPACK *qpack = new QPACK(driver.get_connection(), UINT32_MAX, dts, mbs);
TestQUICStream *encoder_stream = new TestQUICStream(0);
- TestQUICStream *decoder_stream = new TestQUICStream(9999);
- qpack->set_stream(encoder_stream);
- qpack->set_stream(decoder_stream);
+ TestQUICStream *decoder_stream = new TestQUICStream(10);
+ qpack->on_new_stream(*encoder_stream);
+ qpack->on_new_stream(*decoder_stream);
+ qpack->set_encoder_stream(encoder_stream->id());
+ qpack->set_decoder_stream(decoder_stream->id());
uint64_t stream_id = 1;
MIOBuffer *header_block = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
@@ -354,7 +358,7 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am
QUICApplicationDriver driver;
QPACK *qpack = new QPACK(driver.get_connection(), UINT32_MAX, dts, mbs);
TestQUICStream *encoder_stream = new TestQUICStream(0);
- qpack->set_stream(encoder_stream);
+ qpack->on_new_stream(*encoder_stream);
int offset = 0;
uint8_t *block = nullptr;
diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc
index 04fb44d..8b3301a 100644
--- a/src/traffic_quic/quic_client.cc
+++ b/src/traffic_quic/quic_client.cc
@@ -152,6 +152,31 @@ Http09ClientApp::Http09ClientApp(QUICNetVConnection *qvc, const QUICClientConfig
}
void
+Http09ClientApp::on_new_stream(QUICStream &stream)
+{
+ auto ret = this->_streams.emplace(stream.id(), stream);
+ auto &info = ret.first->second;
+
+ switch (stream.direction()) {
+ case QUICStreamDirection::BIDIRECTIONAL:
+ info.setup_read_vio(this);
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::SEND:
+ info.setup_write_vio(this);
+ break;
+ case QUICStreamDirection::RECEIVE:
+ info.setup_read_vio(this);
+ break;
+ default:
+ ink_assert(false);
+ break;
+ }
+
+ stream.set_io_adapter(&info.adapter);
+}
+
+void
Http09ClientApp::start()
{
if (this->_config->output[0] != 0x0) {
@@ -183,11 +208,11 @@ Http09ClientApp::_do_http_request()
Http09ClientAppDebug("\n%s", request);
- QUICStreamIO *stream_io = this->_find_stream_io(stream_id);
-
- stream_io->write(reinterpret_cast<uint8_t *>(request), request_len);
- stream_io->write_done();
- stream_io->write_reenable();
+ auto ite = this->_streams.find(stream_id);
+ VIO *write_vio = ite->second.write_vio;
+ write_vio->get_writer()->write(reinterpret_cast<uint8_t *>(request), request_len);
+ write_vio->done();
+ write_vio->reenable();
}
int
@@ -195,10 +220,10 @@ Http09ClientApp::main_event_handler(int event, Event *data)
{
Http09ClientAppVDebug("%s (%d)", get_vc_event_name(event), event);
- VIO *vio = reinterpret_cast<VIO *>(data);
- QUICStreamIO *stream_io = this->_find_stream_io(vio);
+ VIO *vio = reinterpret_cast<VIO *>(data->cookie);
+ QUICStreamVCAdapter *adapter = static_cast<QUICStreamVCAdapter *>(vio->vc_server);
- if (stream_io == nullptr) {
+ if (adapter == nullptr) {
Http09ClientAppDebug("Unknown Stream");
return -1;
}
@@ -217,8 +242,10 @@ Http09ClientApp::main_event_handler(int event, Event *data)
uint8_t buf[8192] = {0};
int64_t nread;
- while ((nread = stream_io->read(buf, sizeof(buf))) > 0) {
+ auto reader = vio->get_reader();
+ while ((nread = reader->read(buf, sizeof(buf))) > 0) {
std::cout.write(reinterpret_cast<char *>(buf), nread);
+ vio->ndone += nread;
}
std::cout.flush();
@@ -227,7 +254,7 @@ Http09ClientApp::main_event_handler(int event, Event *data)
std::cout.rdbuf(default_stream);
}
- if (stream_io->is_read_done() && this->_config->close) {
+ if (vio->ntodo() == 0 && this->_config->close) {
// Connection Close Exercise
this->_qc->close_quic_connection(
QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::NO_ERROR, "Close Exercise")));
@@ -278,7 +305,7 @@ Http3ClientApp::start()
this->_resp_buf = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
IOBufferReader *resp_buf_reader = _resp_buf->alloc_reader();
- this->_resp_handler = new RespHandler(this->_config, resp_buf_reader, [&](void) {
+ this->_resp_handler = new RespHandler(this->_config, resp_buf_reader, [&](void) {
if (this->_config->close) {
// Connection Close Exercise
this->_qc->close_quic_connection(
@@ -288,6 +315,7 @@ Http3ClientApp::start()
this->_qc->reset_quic_connection();
}
});
+ this->_req_generator = new ReqGenerator();
super::start();
this->_do_http_request();
@@ -304,10 +332,10 @@ Http3ClientApp::_do_http_request()
ink_abort("Could not create bidi stream : %s", error->msg);
}
- QUICStreamIO *stream_io = this->_find_stream_io(stream_id);
+ auto ite = this->_streams.find(stream_id);
// TODO: create Http3ServerTransaction
- Http3Transaction *txn = new Http3Transaction(this->_ssn, stream_io);
+ Http3Transaction *txn = new Http3Transaction(this->_ssn, ite->second);
SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread());
// TODO: fix below issue with H2 origin conn stuff
@@ -337,7 +365,7 @@ Http3ClientApp::_do_http_request()
// TODO: check write avail size
int64_t nbytes = this->_req_buf->write(request, request_len);
IOBufferReader *buf_start = this->_req_buf->alloc_reader();
- txn->do_io_write(this, nbytes, buf_start);
+ txn->do_io_write(this->_req_generator, nbytes, buf_start);
}
//
@@ -407,3 +435,14 @@ RespHandler::main_event_handler(int event, Event *data)
return EVENT_CONT;
}
+
+ReqGenerator::ReqGenerator() : Continuation(new_ProxyMutex())
+{
+ SET_HANDLER(&ReqGenerator::main_event_handler);
+}
+
+int
+ReqGenerator::main_event_handler(int event, Event *data)
+{
+ return EVENT_CONT;
+}
diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h
index fc12dbc..3a52450 100644
--- a/src/traffic_quic/quic_client.h
+++ b/src/traffic_quic/quic_client.h
@@ -61,6 +61,13 @@ private:
std::function<void()> _on_complete;
};
+class ReqGenerator : public Continuation
+{
+public:
+ ReqGenerator();
+ int main_event_handler(int event, Event *data);
+};
+
class QUICClient : public Continuation
{
public:
@@ -81,6 +88,8 @@ class Http09ClientApp : public QUICApplication
public:
Http09ClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config);
+ void on_new_stream(QUICStream &stream) override;
+
void start();
int main_event_handler(int event, Event *data);
@@ -89,6 +98,7 @@ private:
const QUICClientConfig *_config = nullptr;
const char *_filename = nullptr;
+ std::unordered_map<QUICStreamId, QUICStreamVCAdapter::IOInfo> _streams;
};
class Http3ClientApp : public Http3App
@@ -106,6 +116,7 @@ private:
void _do_http_request();
RespHandler *_resp_handler = nullptr;
+ ReqGenerator *_req_generator = nullptr;
const QUICClientConfig *_config = nullptr;
MIOBuffer *_req_buf = nullptr;
diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc
index f3ceaa6..4ee2f5f 100644
--- a/src/traffic_quic/traffic_quic.cc
+++ b/src/traffic_quic/traffic_quic.cc
@@ -277,6 +277,11 @@ HttpDebugNames::get_api_hook_name(TSHttpHookID t)
{
return "dummy";
}
+const char *
+HttpDebugNames::get_event_name(int)
+{
+ return "dummy";
+}
#include "HttpSM.h"
HttpSM::HttpSM() : Continuation(nullptr), vc_table(this) {}