You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bn...@apache.org on 2023/10/18 22:35:33 UTC
[trafficserver] branch master updated: Move mgmt, iocore, proxy to src/ and include/ (#10638)
This is an automated email from the ASF dual-hosted git repository.
bneradt 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 16cb2dd04f Move mgmt, iocore, proxy to src/ and include/ (#10638)
16cb2dd04f is described below
commit 16cb2dd04f8a4a0cb8f63223033ae72a135f6ca8
Author: Zhengxi Li <lz...@hotmail.com>
AuthorDate: Wed Oct 18 18:35:28 2023 -0400
Move mgmt, iocore, proxy to src/ and include/ (#10638)
This replaces PR #10558
Some highlights:
* The P_ files are left in src/
* The I_ prefixes in public header files are removed
Note: the include path cleanup would be left for another PR.
---
.gitignore | 93 +-
CMakeLists.txt | 11 +-
ci/jenkins/bin/autest.sh | 2 +-
contrib/python/compare_RecordsConfigcc.py | 2 +-
doc/Doxyfile | 3 -
include/api/InkAPIInternal.h | 8 +-
include/iocore/aio/AIO.h | 85 +
include/iocore/aio/AIO_fault_injection.h | 72 +
include/iocore/cache/Cache.h | 223 +
include/iocore/cache/CacheDefs.h | 143 +
include/iocore/cache/CacheEvacuateDocVC.h | 72 +
include/iocore/cache/CacheVC.h | 335 +
.../iocore}/cache/HttpTransactCache.h | 0
.../I_Store.h => include/iocore/cache/Store.h | 0
include/iocore/dns/DNS.h | 36 +
{iocore => include/iocore}/dns/DNSEventIO.h | 0
include/iocore/dns/DNSProcessor.h | 231 +
{iocore => include/iocore}/dns/SRV.h | 0
include/iocore/dns/SplitDNS.h | 36 +
.../iocore/dns/SplitDNSProcessor.h | 0
include/iocore/eventsystem/Action.h | 196 +
include/iocore/eventsystem/ConfigProcessor.h | 117 +
include/iocore/eventsystem/Continuation.h | 281 +
include/iocore/eventsystem/EThread.h | 644 ++
include/iocore/eventsystem/Event.h | 292 +
include/iocore/eventsystem/EventProcessor.h | 402 +
include/iocore/eventsystem/EventSystem.h | 51 +
.../iocore/eventsystem/IOBuffer.h | 0
include/iocore/eventsystem/Lock.h | 681 ++
include/iocore/eventsystem/MIOBufferWriter.h | 189 +
include/iocore/eventsystem/PriorityEventQueue.h | 122 +
.../iocore/eventsystem/Processor.h | 0
include/iocore/eventsystem/ProtectedQueue.h | 54 +
.../iocore/eventsystem/ProxyAllocator.h | 0
include/iocore/eventsystem/RecProcess.h | 40 +
.../iocore/eventsystem/SocketManager.h | 0
include/iocore/eventsystem/Tasks.h | 38 +
include/iocore/eventsystem/Thread.h | 170 +
include/iocore/eventsystem/VConnection.h | 413 +
include/iocore/eventsystem/VIO.h | 223 +
include/iocore/hostdb/HostDB.h | 41 +
include/iocore/hostdb/HostDBProcessor.h | 887 ++
include/iocore/hostdb/HostFile.h | 52 +
.../iocore}/io_uring/IOUringEventIO.h | 0
.../iocore/io_uring/IO_URING.h | 0
include/iocore/net/AcceptOptions.h | 90 +
.../iocore}/net/AsyncSignalEventIO.h | 0
{iocore => include/iocore}/net/BIO_fastopen.h | 0
{iocore => include/iocore}/net/BoringSSLUtils.h | 0
{iocore => include/iocore}/net/EventIO.h | 0
include/iocore/net/Net.h | 91 +
{iocore => include/iocore}/net/NetAcceptEventIO.h | 0
include/iocore/net/NetEvent.h | 141 +
include/iocore/net/NetHandler.h | 236 +
include/iocore/net/NetProcessor.h | 184 +
include/iocore/net/NetTimeout.h | 263 +
include/iocore/net/NetVCOptions.h | 318 +
include/iocore/net/NetVConnection.h | 703 ++
include/iocore/net/PollCont.h | 43 +
include/iocore/net/PreWarm.h | 50 +
{iocore => include/iocore}/net/ProxyProtocol.h | 0
.../iocore}/net/QUICMultiCertConfigLoader.h | 0
{iocore => include/iocore}/net/QUICSupport.h | 0
{iocore => include/iocore}/net/ReadWriteEventIO.h | 0
.../iocore}/net/SNIActionPerformer.h | 0
{iocore => include/iocore}/net/SSLAPIHooks.h | 0
{iocore => include/iocore}/net/SSLDiags.h | 0
{iocore => include/iocore}/net/SSLDynlock.h | 0
{iocore => include/iocore}/net/SSLInternal.h | 0
{iocore => include/iocore}/net/SSLSNIConfig.h | 0
include/iocore/net/SSLSessionCache.h | 218 +
{iocore => include/iocore}/net/SSLSessionTicket.h | 0
include/iocore/net/SSLStats.h | 106 +
{iocore => include/iocore}/net/SSLTypes.h | 0
include/iocore/net/SessionAccept.h | 79 +
iocore/net/I_Socks.h => include/iocore/net/Socks.h | 0
include/iocore/net/TLSALPNSupport.h | 104 +
{iocore => include/iocore}/net/TLSBasicSupport.h | 0
.../iocore}/net/TLSCertSwitchSupport.h | 0
.../iocore}/net/TLSEarlyDataSupport.h | 0
{iocore => include/iocore}/net/TLSSNISupport.h | 0
.../iocore}/net/TLSSessionResumptionSupport.h | 0
{iocore => include/iocore}/net/TLSTunnelSupport.h | 0
include/iocore/net/UDPConnection.h | 114 +
{iocore => include/iocore}/net/UDPEventIO.h | 0
include/iocore/net/UDPNet.h | 111 +
include/iocore/net/UDPPacket.h | 158 +
{iocore => include/iocore}/net/YamlSNIConfig.h | 0
{iocore => include/iocore}/net/quic/MTHashTable.h | 0
{iocore => include/iocore}/net/quic/Mock.h | 0
.../iocore}/net/quic/QUICAckFrameCreator.h | 0
.../iocore}/net/quic/QUICAddrVerifyState.h | 0
.../iocore}/net/quic/QUICAltConnectionManager.h | 0
include/iocore/net/quic/QUICApplication.h | 50 +
.../iocore}/net/quic/QUICApplicationMap.h | 0
.../iocore}/net/quic/QUICBidirectionalStream.h | 0
{iocore => include/iocore}/net/quic/QUICConfig.h | 0
.../iocore}/net/quic/QUICCongestionController.h | 0
include/iocore/net/quic/QUICConnection.h | 75 +
.../iocore}/net/quic/QUICConnectionTable.h | 0
{iocore => include/iocore}/net/quic/QUICContext.h | 0
.../iocore}/net/quic/QUICCryptoStream.h | 0
.../iocore}/net/quic/QUICDebugNames.h | 0
{iocore => include/iocore}/net/quic/QUICEchoApp.h | 0
include/iocore/net/quic/QUICEvents.h | 39 +
include/iocore/net/quic/QUICFlowController.h | 156 +
include/iocore/net/quic/QUICFrame.h | 911 ++
.../iocore}/net/quic/QUICFrameDispatcher.h | 0
.../iocore}/net/quic/QUICFrameGenerator.h | 0
.../iocore}/net/quic/QUICFrameHandler.h | 0
.../iocore}/net/quic/QUICFrameRetransmitter.h | 0
{iocore => include/iocore}/net/quic/QUICGlobals.h | 0
{iocore => include/iocore}/net/quic/QUICHKDF.h | 0
.../iocore}/net/quic/QUICHandshake.h | 0
.../iocore}/net/quic/QUICHandshakeProtocol.h | 0
.../iocore}/net/quic/QUICIncomingFrameBuffer.h | 0
{iocore => include/iocore}/net/quic/QUICIntUtil.h | 0
.../iocore}/net/quic/QUICKeyGenerator.h | 0
include/iocore/net/quic/QUICLossDetector.h | 183 +
.../net/quic/QUICNewRenoCongestionController.h | 0
include/iocore/net/quic/QUICPacket.h | 561 ++
.../iocore}/net/quic/QUICPacketFactory.h | 0
.../iocore}/net/quic/QUICPacketHeaderProtector.h | 0
.../iocore/net/quic/QUICPacketPayloadProtector.h | 53 +
.../iocore}/net/quic/QUICPacketProtectionKeyInfo.h | 0
include/iocore/net/quic/QUICPacketReceiveQueue.h | 56 +
include/iocore/net/quic/QUICPadder.h | 57 +
.../iocore}/net/quic/QUICPathManager.h | 0
.../iocore}/net/quic/QUICPathValidator.h | 0
include/iocore/net/quic/QUICPinger.h | 52 +
.../iocore}/net/quic/QUICResetTokenTable.h | 0
.../iocore}/net/quic/QUICRetryIntegrityTag.h | 0
{iocore => include/iocore}/net/quic/QUICStats.h | 0
include/iocore/net/quic/QUICStream.h | 106 +
.../iocore}/net/quic/QUICStreamAdapter.h | 0
.../iocore}/net/quic/QUICStreamFactory.h | 0
.../iocore}/net/quic/QUICStreamManager.h | 0
.../iocore}/net/quic/QUICStreamManager_native.h | 0
.../iocore}/net/quic/QUICStreamManager_quiche.h | 0
.../iocore}/net/quic/QUICStreamState.h | 0
include/iocore/net/quic/QUICStreamVCAdapter.h | 106 +
.../iocore}/net/quic/QUICStream_native.h | 0
.../iocore}/net/quic/QUICStream_quiche.h | 0
include/iocore/net/quic/QUICTLS.h | 128 +
.../iocore}/net/quic/QUICTokenCreator.h | 0
.../net/quic/QUICTransferProgressProvider.h | 0
.../iocore}/net/quic/QUICTransportParameters.h | 0
include/iocore/net/quic/QUICTypes.h | 673 ++
.../iocore}/net/quic/QUICUnidirectionalStream.h | 0
.../iocore}/net/quic/QUICVersionNegotiator.h | 0
{iocore => include/iocore}/net/quic/qlog/QLog.h | 0
.../iocore}/net/quic/qlog/QLogEvent.h | 0
.../iocore}/net/quic/qlog/QLogFrame.h | 0
.../iocore}/net/quic/qlog/QLogListener.h | 0
.../iocore}/net/quic/qlog/QLogUtils.h | 0
.../I_Machine.h => include/iocore/utils/Machine.h | 0
include/iocore/utils/OneWayMultiTunnel.h | 134 +
include/iocore/utils/OneWayTunnel.h | 211 +
{iocore => include/iocore}/utils/diags.i | 0
{mgmt => include/mgmt}/config/FileManager.h | 0
{mgmt => include/mgmt}/rpc/config/JsonRPCConfig.h | 0
.../mgmt}/rpc/handlers/common/ErrorUtils.h | 0
include/mgmt/rpc/handlers/common/RecordsUtils.h | 102 +
{mgmt => include/mgmt}/rpc/handlers/common/Utils.h | 0
include/mgmt/rpc/handlers/common/convert.h | 179 +
.../mgmt}/rpc/handlers/config/Configuration.h | 0
.../mgmt}/rpc/handlers/plugins/Plugins.h | 0
.../mgmt}/rpc/handlers/records/Records.h | 0
.../mgmt}/rpc/handlers/server/Server.h | 0
.../mgmt}/rpc/handlers/storage/Storage.h | 0
{mgmt => include/mgmt}/rpc/jsonrpc/Context.h | 0
{mgmt => include/mgmt}/rpc/jsonrpc/Defs.h | 0
{mgmt => include/mgmt}/rpc/jsonrpc/JsonRPC.h | 0
.../mgmt}/rpc/jsonrpc/JsonRPCManager.h | 0
.../mgmt}/rpc/jsonrpc/error/RPCError.h | 0
.../mgmt}/rpc/jsonrpc/json/YAMLCodec.h | 0
{mgmt => include/mgmt}/rpc/server/CommBase.h | 0
include/mgmt/rpc/server/IPCSocketServer.h | 144 +
{mgmt => include/mgmt}/rpc/server/RPCServer.h | 0
include/proxy/CacheControl.h | 130 +
{proxy => include/proxy}/ControlBase.h | 0
{proxy => include/proxy}/ControlMatcher.h | 0
include/proxy/HostStatus.h | 239 +
{proxy => include/proxy}/HttpAPIHooks.h | 0
{proxy => include/proxy}/IPAllow.h | 0
include/proxy/Milestones.h | 104 +
{proxy => include/proxy}/ParentConsistentHash.h | 0
{proxy => include/proxy}/ParentRoundRobin.h | 0
include/proxy/ParentSelection.h | 482 ++
{proxy => include/proxy}/Plugin.h | 0
include/proxy/PluginVC.h | 276 +
{proxy => include/proxy}/PoolableSession.h | 0
include/proxy/ProtocolProbeSessionAccept.h | 72 +
{proxy => include/proxy}/ProxySession.h | 0
{proxy => include/proxy}/ProxyTransaction.h | 0
include/proxy/RegressionSM.h | 78 +
include/proxy/ReverseProxy.h | 60 +
{proxy => include/proxy}/Show.h | 0
include/proxy/StatPages.h | 121 +
include/proxy/Transform.h | 107 +
{proxy => include/proxy}/TransformInternal.h | 0
{proxy => include/proxy}/hdrs/HTTP.h | 0
{proxy => include/proxy}/hdrs/HdrHeap.h | 0
{proxy => include/proxy}/hdrs/HdrToken.h | 0
{proxy => include/proxy}/hdrs/HdrUtils.h | 0
{proxy => include/proxy}/hdrs/HeaderValidator.h | 0
{proxy => include/proxy}/hdrs/HttpCompat.h | 0
{proxy => include/proxy}/hdrs/HuffmanCodec.h | 0
{proxy => include/proxy}/hdrs/MIME.h | 0
{proxy => include/proxy}/hdrs/URL.h | 0
{proxy => include/proxy}/hdrs/VersionConverter.h | 0
{proxy => include/proxy}/hdrs/XPACK.h | 0
{proxy => include/proxy}/http/ConnectingEntry.h | 0
{proxy => include/proxy}/http/Http1ClientSession.h | 0
.../proxy}/http/Http1ClientTransaction.h | 0
{proxy => include/proxy}/http/Http1ServerSession.h | 0
.../proxy}/http/Http1ServerTransaction.h | 0
{proxy => include/proxy}/http/Http1Transaction.h | 0
{proxy => include/proxy}/http/HttpBodyFactory.h | 0
include/proxy/http/HttpCacheSM.h | 244 +
include/proxy/http/HttpConfig.h | 860 ++
.../proxy}/http/HttpConnectionCount.h | 0
{proxy => include/proxy}/http/HttpDebugNames.h | 0
include/proxy/http/HttpPages.h | 86 +
{proxy => include/proxy}/http/HttpProxyAPIEnums.h | 0
.../proxy}/http/HttpProxyServerMain.h | 0
include/proxy/http/HttpSM.h | 814 ++
include/proxy/http/HttpSessionAccept.h | 197 +
include/proxy/http/HttpSessionManager.h | 140 +
include/proxy/http/HttpTransact.h | 1156 +++
.../proxy}/http/HttpTransactHeaders.h | 0
include/proxy/http/HttpTunnel.h | 626 ++
include/proxy/http/HttpUserAgent.h | 268 +
include/proxy/http/HttpVCTable.h | 83 +
{proxy => include/proxy}/http/PreWarmAlgorithm.h | 0
{proxy => include/proxy}/http/PreWarmConfig.h | 0
include/proxy/http/PreWarmManager.h | 339 +
{proxy => include/proxy}/http/remap/AclFiltering.h | 0
.../proxy}/http/remap/NextHopConsistentHash.h | 0
.../proxy}/http/remap/NextHopRoundRobin.h | 0
.../proxy}/http/remap/NextHopSelectionStrategy.h | 0
.../proxy}/http/remap/NextHopStrategyFactory.h | 0
include/proxy/http/remap/PluginDso.h | 176 +
.../proxy}/http/remap/PluginFactory.h | 0
{proxy => include/proxy}/http/remap/RemapConfig.h | 0
include/proxy/http/remap/RemapHitCount.h | 30 +
.../proxy}/http/remap/RemapPluginInfo.h | 0
include/proxy/http/remap/RemapPlugins.h | 69 +
include/proxy/http/remap/RemapProcessor.h | 53 +
{proxy => include/proxy}/http/remap/UrlMapping.h | 0
.../proxy}/http/remap/UrlMappingPathIndex.h | 0
{proxy => include/proxy}/http/remap/UrlRewrite.h | 0
{proxy => include/proxy}/http2/HPACK.h | 0
include/proxy/http2/HTTP2.h | 427 +
.../proxy}/http2/Http2ClientSession.h | 0
.../proxy}/http2/Http2CommonSession.h | 0
.../proxy}/http2/Http2CommonSessionInternal.h | 0
.../proxy}/http2/Http2ConnectionState.h | 0
{proxy => include/proxy}/http2/Http2DebugNames.h | 0
.../proxy}/http2/Http2DependencyTree.h | 0
include/proxy/http2/Http2Frame.h | 256 +
include/proxy/http2/Http2FrequencyCounter.h | 42 +
.../proxy}/http2/Http2ServerSession.h | 0
include/proxy/http2/Http2SessionAccept.h | 54 +
{proxy => include/proxy}/http2/Http2Stream.h | 0
{proxy => include/proxy}/http3/Http09App.h | 0
{proxy => include/proxy}/http3/Http3.h | 0
{proxy => include/proxy}/http3/Http3App.h | 0
{proxy => include/proxy}/http3/Http3Config.h | 0
{proxy => include/proxy}/http3/Http3DataFramer.h | 0
{proxy => include/proxy}/http3/Http3DebugNames.h | 0
{proxy => include/proxy}/http3/Http3Frame.h | 0
.../proxy}/http3/Http3FrameCollector.h | 0
.../proxy}/http3/Http3FrameDispatcher.h | 0
.../proxy}/http3/Http3FrameGenerator.h | 0
{proxy => include/proxy}/http3/Http3FrameHandler.h | 0
{proxy => include/proxy}/http3/Http3HeaderFramer.h | 0
.../proxy}/http3/Http3HeaderVIOAdaptor.h | 0
.../proxy}/http3/Http3ProtocolEnforcer.h | 0
{proxy => include/proxy}/http3/Http3Session.h | 0
include/proxy/http3/Http3SessionAccept.h | 54 +
.../proxy}/http3/Http3SettingsHandler.h | 0
.../proxy}/http3/Http3StreamDataVIOAdaptor.h | 0
include/proxy/http3/Http3Transaction.h | 164 +
{proxy => include/proxy}/http3/Http3Types.h | 0
include/proxy/http3/QPACK.h | 342 +
include/proxy/logging/Log.h | 235 +
{proxy => include/proxy}/logging/LogAccess.h | 0
{proxy => include/proxy}/logging/LogBuffer.h | 0
{proxy => include/proxy}/logging/LogBufferSink.h | 0
include/proxy/logging/LogConfig.h | 222 +
{proxy => include/proxy}/logging/LogField.h | 0
.../proxy}/logging/LogFieldAliasMap.h | 0
{proxy => include/proxy}/logging/LogFile.h | 0
{proxy => include/proxy}/logging/LogFilter.h | 0
{proxy => include/proxy}/logging/LogFormat.h | 0
{proxy => include/proxy}/logging/LogLimits.h | 0
{proxy => include/proxy}/logging/LogObject.h | 0
{proxy => include/proxy}/logging/LogUtils.h | 0
.../proxy}/logging/RolledLogDeleter.h | 0
{proxy => include/proxy}/logging/YamlLogConfig.h | 0
.../proxy}/logging/YamlLogConfigDecoders.h | 0
{proxy => include/proxy}/shared/DiagsConfig.h | 0
include/records/I_RecCore.h | 262 -
include/records/I_RecDefs.h | 184 -
include/records/I_RecLocal.h | 36 -
include/records/I_RecProcess.h | 146 -
include/records/P_RecCore.h | 2 +-
include/records/P_RecDefs.h | 2 +-
include/records/P_RecProcess.h | 2 +-
include/records/RecCore.h | 262 +
include/records/RecDefs.h | 184 +
include/records/{I_RecHttp.h => RecHttp.h} | 0
include/records/RecLocal.h | 36 +
include/records/{I_RecMutex.h => RecMutex.h} | 0
include/records/RecProcess.h | 146 +
.../records/{I_RecordsConfig.h => RecordsConfig.h} | 0
include/shared/rpc/RPCClient.h | 2 +-
include/ts/InkAPIPrivateIOCore.h | 4 +-
include/tscore/{I_Layout.h => Layout.h} | 0
include/tscore/{I_Version.h => Version.h} | 0
iocore/CMakeLists.txt | 39 -
iocore/aio/AIO.cc | 633 --
iocore/aio/AIO_fault_injection.cc | 122 -
iocore/aio/AIO_fault_injection.h | 72 -
iocore/aio/CMakeLists.txt | 32 -
iocore/aio/I_AIO.h | 85 -
iocore/aio/P_AIO.h | 142 -
iocore/aio/test_AIO.cc | 557 --
iocore/cache/CMakeLists.txt | 66 -
iocore/cache/Cache.cc | 1960 -----
iocore/cache/CacheEvacuateDocVC.cc | 211 -
iocore/cache/CacheEvacuateDocVC.h | 72 -
iocore/cache/CacheHosting.cc | 1126 ---
iocore/cache/CachePages.cc | 694 --
iocore/cache/CachePagesInternal.cc | 342 -
iocore/cache/CacheVC.cc | 1086 ---
iocore/cache/CacheVC.h | 335 -
iocore/cache/I_Cache.h | 223 -
iocore/cache/I_CacheDefs.h | 143 -
iocore/cache/P_Cache.h | 42 -
iocore/cache/P_CacheDir.h | 338 -
iocore/cache/P_CacheDisk.h | 125 -
iocore/cache/P_RamCache.h | 44 -
iocore/cache/RamCacheCLFUS.cc | 790 --
iocore/cache/Store.cc | 511 --
iocore/cache/Vol.cc | 918 --
iocore/cache/test/CacheTestHandler.cc | 86 -
iocore/cache/test/main.cc | 367 -
iocore/cache/test/main.h | 258 -
iocore/cache/test/stub.cc | 83 -
iocore/dns/CMakeLists.txt | 26 -
iocore/dns/DNS.cc | 1989 -----
iocore/dns/I_DNS.h | 36 -
iocore/dns/I_DNSProcessor.h | 231 -
iocore/dns/I_SplitDNS.h | 36 -
iocore/dns/P_DNS.h | 38 -
iocore/dns/P_DNSConnection.h | 150 -
iocore/dns/P_DNSProcessor.h | 314 -
iocore/dns/P_SplitDNS.h | 40 -
iocore/dns/test_I_DNS.cc | 43 -
iocore/eventsystem/CMakeLists.txt | 53 -
iocore/eventsystem/ConfigProcessor.h | 117 -
iocore/eventsystem/EventSystem.cc | 66 -
iocore/eventsystem/I_Action.h | 196 -
iocore/eventsystem/I_Continuation.h | 281 -
iocore/eventsystem/I_EThread.h | 644 --
iocore/eventsystem/I_Event.h | 292 -
iocore/eventsystem/I_EventProcessor.h | 402 -
iocore/eventsystem/I_EventSystem.h | 51 -
iocore/eventsystem/I_Lock.h | 681 --
iocore/eventsystem/I_MIOBufferWriter.h | 189 -
iocore/eventsystem/I_PriorityEventQueue.h | 122 -
iocore/eventsystem/I_ProtectedQueue.h | 54 -
iocore/eventsystem/I_Tasks.h | 38 -
iocore/eventsystem/I_Thread.h | 170 -
iocore/eventsystem/I_VConnection.h | 413 -
iocore/eventsystem/I_VIO.h | 223 -
iocore/eventsystem/MIOBufferWriter.cc | 124 -
iocore/eventsystem/P_EventSystem.h | 50 -
iocore/eventsystem/P_Freer.h | 134 -
iocore/eventsystem/P_ProtectedQueue.h | 83 -
iocore/eventsystem/P_Thread.h | 49 -
iocore/eventsystem/P_UnixEThread.h | 261 -
iocore/eventsystem/P_UnixEventProcessor.h | 200 -
iocore/eventsystem/P_UnixSocketManager.h | 291 -
iocore/eventsystem/P_VConnection.h | 95 -
iocore/eventsystem/P_VIO.h | 123 -
iocore/eventsystem/ProxyAllocator.cc | 61 -
iocore/eventsystem/RecProcess.cc | 194 -
iocore/eventsystem/RecProcess.h | 40 -
iocore/eventsystem/RecRawStatsImpl.cc | 257 -
iocore/eventsystem/Tasks.cc | 44 -
iocore/eventsystem/unit_tests/test_EventSystem.cc | 119 -
iocore/eventsystem/unit_tests/test_IOBuffer.cc | 398 -
.../eventsystem/unit_tests/test_MIOBufferWriter.cc | 200 -
iocore/hostdb/CMakeLists.txt | 28 -
iocore/hostdb/HostDB.cc | 2160 -----
iocore/hostdb/HostDBInfo.cc | 84 -
iocore/hostdb/HostFile.h | 52 -
iocore/hostdb/I_HostDB.h | 41 -
iocore/hostdb/I_HostDBProcessor.h | 887 --
iocore/hostdb/P_HostDB.h | 49 -
iocore/hostdb/P_HostDBProcessor.h | 313 -
iocore/hostdb/P_RefCountCache.h | 600 --
iocore/hostdb/test_I_HostDB.cc | 50 -
iocore/hostdb/test_RefCountCache.cc | 293 -
iocore/io_uring/IOUringEventIO.cc | 41 -
iocore/io_uring/io_uring.cc | 226 -
iocore/io_uring/unit_tests/test_diskIO.cc | 282 -
iocore/net/ALPNSupport.cc | 146 -
iocore/net/AcceptOptions.h | 90 -
iocore/net/AsyncSignalEventIO.cc | 48 -
iocore/net/BIO_fastopen.cc | 212 -
iocore/net/CMakeLists.txt | 134 -
iocore/net/I_Net.h | 91 -
iocore/net/I_NetProcessor.h | 184 -
iocore/net/I_NetVConnection.h | 703 --
iocore/net/I_SessionAccept.h | 79 -
iocore/net/I_UDPConnection.h | 114 -
iocore/net/I_UDPNet.h | 111 -
iocore/net/I_UDPPacket.h | 158 -
iocore/net/NetEvent.h | 141 -
iocore/net/NetHandler.cc | 585 --
iocore/net/NetHandler.h | 236 -
iocore/net/NetTimeout.h | 263 -
iocore/net/NetVCOptions.cc | 70 -
iocore/net/NetVCOptions.h | 318 -
iocore/net/P_ALPNSupport.h | 104 -
iocore/net/P_Net.h | 114 -
iocore/net/P_NetAccept.h | 126 -
iocore/net/P_NetVConnection.h | 104 -
iocore/net/P_QUICNetVConnection_native.h | 400 -
iocore/net/P_QUICNetVConnection_quiche.h | 218 -
iocore/net/P_QUICNextProtocolAccept_native.h | 59 -
iocore/net/P_QUICNextProtocolAccept_quiche.h | 59 -
iocore/net/P_SNIActionPerformer.h | 582 --
iocore/net/P_SSLNetVConnection.h | 510 --
iocore/net/P_SSLNextProtocolAccept.h | 66 -
iocore/net/P_SSLNextProtocolSet.h | 62 -
iocore/net/P_SSLUtils.h | 216 -
iocore/net/P_Socks.h | 142 -
iocore/net/P_UDPConnection.h | 134 -
iocore/net/P_UDPNet.h | 367 -
iocore/net/P_UnixNetProcessor.h | 68 -
iocore/net/P_UnixNetState.h | 54 -
iocore/net/P_UnixNetVConnection.h | 360 -
iocore/net/PollCont.h | 43 -
iocore/net/PreWarm.h | 50 -
iocore/net/ProxyProtocol.cc | 508 --
iocore/net/QUICNetProcessor.cc | 229 -
iocore/net/QUICNetProcessor_quiche.cc | 252 -
iocore/net/QUICNetVConnection.cc | 2461 ------
iocore/net/QUICPacketHandler_quiche.cc | 348 -
iocore/net/SSLCertLookup.cc | 587 --
iocore/net/SSLClientUtils.cc | 324 -
iocore/net/SSLConfig.cc | 1034 ---
iocore/net/SSLNetProcessor.cc | 108 -
iocore/net/SSLNetVConnection.cc | 2647 ------
iocore/net/SSLSNIConfig.cc | 403 -
iocore/net/SSLSessionCache.h | 218 -
iocore/net/SSLStats.h | 106 -
iocore/net/SSLUtils.cc | 2619 ------
iocore/net/Socks.cc | 696 --
iocore/net/UnixNet.cc | 201 -
iocore/net/UnixNetPages.cc | 247 -
iocore/net/UnixUDPNet.cc | 1835 ----
iocore/net/YamlSNIConfig.cc | 554 --
iocore/net/quic/CMakeLists.txt | 39 -
iocore/net/quic/QUICAckFrameCreator.cc | 391 -
iocore/net/quic/QUICApplication.h | 50 -
iocore/net/quic/QUICConfig.cc | 519 --
iocore/net/quic/QUICConnection.h | 75 -
iocore/net/quic/QUICDebugNames.cc | 343 -
iocore/net/quic/QUICEvents.h | 39 -
iocore/net/quic/QUICFlowController.h | 156 -
iocore/net/quic/QUICFrame.h | 911 --
iocore/net/quic/QUICLossDetector.h | 183 -
iocore/net/quic/QUICPacket.h | 561 --
iocore/net/quic/QUICPacketPayloadProtector.h | 53 -
iocore/net/quic/QUICPacketReceiveQueue.cc | 200 -
iocore/net/quic/QUICPacketReceiveQueue.h | 56 -
iocore/net/quic/QUICPadder.h | 57 -
iocore/net/quic/QUICPinger.h | 52 -
iocore/net/quic/QUICStream.h | 106 -
iocore/net/quic/QUICStreamVCAdapter.cc | 322 -
iocore/net/quic/QUICStreamVCAdapter.h | 106 -
iocore/net/quic/QUICTLS.h | 128 -
iocore/net/quic/QUICTransferProgressProvider.cc | 83 -
iocore/net/quic/QUICTypes.cc | 861 --
iocore/net/quic/QUICTypes.h | 673 --
iocore/net/quic/test/event_processor_main.cc | 64 -
iocore/net/quic/test/main.cc | 60 -
iocore/net/quic/test/test_QUICType.cc | 150 -
iocore/net/test_I_UDPNet.cc | 234 -
iocore/net/unit_tests/unit_test_main.cc | 74 -
iocore/utils/CMakeLists.txt | 26 -
iocore/utils/I_OneWayMultiTunnel.h | 134 -
iocore/utils/I_OneWayTunnel.h | 211 -
iocore/utils/Machine.cc | 255 -
iocore/utils/OneWayMultiTunnel.cc | 257 -
iocore/utils/OneWayTunnel.cc | 391 -
mgmt/config/CMakeLists.txt | 29 -
mgmt/config/FileManager.cc | 435 -
mgmt/rpc/CMakeLists.txt | 66 -
mgmt/rpc/config/JsonRPCConfig.cc | 104 -
mgmt/rpc/handlers/common/RecordsUtils.h | 102 -
mgmt/rpc/handlers/common/convert.h | 179 -
mgmt/rpc/handlers/config/Configuration.cc | 204 -
mgmt/rpc/server/IPCSocketServer.cc | 525 --
mgmt/rpc/server/IPCSocketServer.h | 144 -
mgmt/rpc/server/unit_tests/test_rpcserver.cc | 561 --
plugins/experimental/memcache/tsmemcache.cc | 4 +-
plugins/experimental/memcache/tsmemcache.h | 8 +-
proxy/CMakeLists.txt | 76 -
proxy/CacheControl.h | 130 -
proxy/HostStatus.cc | 533 --
proxy/HostStatus.h | 239 -
proxy/Milestones.h | 104 -
proxy/ParentSelection.cc | 1916 -----
proxy/ParentSelection.h | 482 --
proxy/Plugin.cc | 367 -
proxy/PluginVC.h | 276 -
proxy/ProtocolProbeSessionAccept.cc | 216 -
proxy/ProtocolProbeSessionAccept.h | 72 -
proxy/RegressionSM.h | 78 -
proxy/ReverseProxy.h | 60 -
proxy/StatPages.h | 121 -
proxy/Transform.h | 107 -
proxy/hdrs/CMakeLists.txt | 67 -
proxy/hdrs/HdrHeap.cc | 1202 ---
proxy/hdrs/unit_tests/test_mime.cc | 251 -
proxy/http/CMakeLists.txt | 80 -
proxy/http/HttpBodyFactory.cc | 1165 ---
proxy/http/HttpCacheSM.h | 244 -
proxy/http/HttpConfig.cc | 1498 ----
proxy/http/HttpConfig.h | 860 --
proxy/http/HttpDebugNames.cc | 664 --
proxy/http/HttpPages.h | 86 -
proxy/http/HttpSM.cc | 8797 -------------------
proxy/http/HttpSM.h | 814 --
proxy/http/HttpSessionAccept.cc | 90 -
proxy/http/HttpSessionAccept.h | 197 -
proxy/http/HttpSessionManager.h | 140 -
proxy/http/HttpTransact.cc | 8905 --------------------
proxy/http/HttpTransact.h | 1156 ---
proxy/http/HttpTransactHeaders.cc | 1306 ---
proxy/http/HttpTunnel.h | 626 --
proxy/http/HttpUserAgent.h | 268 -
proxy/http/HttpVCTable.cc | 136 -
proxy/http/HttpVCTable.h | 83 -
proxy/http/PreWarmManager.cc | 1173 ---
proxy/http/PreWarmManager.h | 339 -
proxy/http/remap/CMakeLists.txt | 49 -
proxy/http/remap/NextHopConsistentHash.cc | 512 --
proxy/http/remap/NextHopSelectionStrategy.cc | 424 -
proxy/http/remap/PluginDso.h | 176 -
proxy/http/remap/RemapConfig.cc | 1365 ---
proxy/http/remap/RemapHitCount.h | 30 -
proxy/http/remap/RemapPlugins.h | 69 -
proxy/http/remap/RemapProcessor.h | 53 -
proxy/http/remap/UrlMapping.cc | 204 -
proxy/http/remap/UrlRewrite.cc | 966 ---
proxy/http/remap/unit-tests/nexthop_test_stubs.cc | 211 -
proxy/http/remap/unit-tests/test_PluginFactory.cc | 1429 ----
proxy/http/unit_tests/CMakeLists.txt | 45 -
proxy/http/unit_tests/main.cc | 60 -
proxy/http/unit_tests/test_HttpTransact.cc | 590 --
proxy/http/unit_tests/test_HttpUserAgent.cc | 93 -
proxy/http/unit_tests/unit_test_main.cc | 30 -
proxy/http2/CMakeLists.txt | 76 -
proxy/http2/HTTP2.h | 427 -
proxy/http2/Http2Frame.h | 256 -
proxy/http2/Http2FrequencyCounter.h | 42 -
proxy/http2/Http2SessionAccept.cc | 90 -
proxy/http2/Http2SessionAccept.h | 54 -
proxy/http2/test_HPACK.cc | 429 -
proxy/http2/unit_tests/main.cc | 65 -
proxy/http3/CMakeLists.txt | 87 -
proxy/http3/Http3HeaderFramer.cc | 115 -
proxy/http3/Http3HeaderVIOAdaptor.cc | 149 -
proxy/http3/Http3SessionAccept.cc | 101 -
proxy/http3/Http3SessionAccept.h | 54 -
proxy/http3/Http3StreamDataVIOAdaptor.cc | 74 -
proxy/http3/Http3Transaction.h | 164 -
proxy/http3/QPACK.h | 342 -
proxy/http3/test/main.cc | 62 -
proxy/http3/test/main_qpack.cc | 107 -
proxy/logging/CMakeLists.txt | 53 -
proxy/logging/Log.cc | 1413 ----
proxy/logging/Log.h | 235 -
proxy/logging/LogAccess.cc | 3297 --------
proxy/logging/LogConfig.cc | 815 --
proxy/logging/LogConfig.h | 222 -
proxy/logging/LogFile.cc | 772 --
proxy/logging/LogStandalone.cc | 210 -
proxy/logging/unit-tests/benchmark_LogObject.cc | 194 -
proxy/private/SSLProxySession.cc | 39 -
proxy/shared/DiagsConfig.cc | 378 -
src/api/APIHook.cc | 4 +-
src/api/APIHooks.cc | 4 +-
src/api/CMakeLists.txt | 19 +-
src/api/InkAPI.cc | 18 +-
src/api/InkAPITest.cc | 4 +-
src/api/InkContInternal.cc | 12 +-
src/api/InkIOCoreAPI.cc | 8 +-
src/iocore/CMakeLists.txt | 39 +
{iocore => src/iocore}/Makefile.am | 0
src/iocore/aio/AIO.cc | 633 ++
src/iocore/aio/AIO_fault_injection.cc | 122 +
src/iocore/aio/CMakeLists.txt | 32 +
{iocore => src/iocore}/aio/Inline.cc | 0
{iocore => src/iocore}/aio/Makefile.am | 0
src/iocore/aio/P_AIO.h | 142 +
{iocore => src/iocore}/aio/sample.cfg | 0
src/iocore/aio/test_AIO.cc | 557 ++
{iocore => src/iocore}/aio/test_AIO.sample | 0
src/iocore/cache/CMakeLists.txt | 72 +
src/iocore/cache/Cache.cc | 1960 +++++
{iocore => src/iocore}/cache/CacheDir.cc | 0
{iocore => src/iocore}/cache/CacheDisk.cc | 0
src/iocore/cache/CacheEvacuateDocVC.cc | 211 +
src/iocore/cache/CacheHosting.cc | 1126 +++
{iocore => src/iocore}/cache/CacheHttp.cc | 0
src/iocore/cache/CachePages.cc | 694 ++
src/iocore/cache/CachePagesInternal.cc | 342 +
{iocore => src/iocore}/cache/CacheRead.cc | 0
{iocore => src/iocore}/cache/CacheTest.cc | 0
src/iocore/cache/CacheVC.cc | 1086 +++
{iocore => src/iocore}/cache/CacheVol.cc | 0
{iocore => src/iocore}/cache/CacheWrite.cc | 0
{iocore => src/iocore}/cache/HttpTransactCache.cc | 0
{iocore => src/iocore}/cache/Makefile.am | 0
{iocore => src/iocore}/cache/Notes | 0
src/iocore/cache/P_Cache.h | 42 +
{iocore => src/iocore}/cache/P_CacheArray.h | 0
src/iocore/cache/P_CacheDir.h | 338 +
src/iocore/cache/P_CacheDisk.h | 125 +
{iocore => src/iocore}/cache/P_CacheHosting.h | 0
{iocore => src/iocore}/cache/P_CacheHttp.h | 0
{iocore => src/iocore}/cache/P_CacheInternal.h | 0
{iocore => src/iocore}/cache/P_CacheStats.h | 0
{iocore => src/iocore}/cache/P_CacheTest.h | 0
{iocore => src/iocore}/cache/P_CacheVol.h | 0
src/iocore/cache/P_RamCache.h | 44 +
src/iocore/cache/RamCacheCLFUS.cc | 790 ++
{iocore => src/iocore}/cache/RamCacheLRU.cc | 0
src/iocore/cache/Store.cc | 511 ++
src/iocore/cache/Vol.cc | 918 ++
src/iocore/cache/test/CacheTestHandler.cc | 86 +
.../iocore}/cache/test/CacheTestHandler.h | 0
src/iocore/cache/test/main.cc | 367 +
src/iocore/cache/test/main.h | 258 +
{iocore => src/iocore}/cache/test/storage.config | 0
src/iocore/cache/test/stub.cc | 83 +
.../iocore}/cache/test/test_Alternate_L_to_S.cc | 0
.../cache/test/test_Alternate_L_to_S_remove_L.cc | 0
.../cache/test/test_Alternate_L_to_S_remove_S.cc | 0
.../iocore}/cache/test/test_Alternate_S_to_L.cc | 0
.../cache/test/test_Alternate_S_to_L_remove_L.cc | 0
.../cache/test/test_Alternate_S_to_L_remove_S.cc | 0
{iocore => src/iocore}/cache/test/test_Cache.cc | 0
.../iocore}/cache/test/test_Disk_Failure.cc | 0
.../iocore}/cache/test/test_Disk_Init_Failure.cc | 0
.../iocore}/cache/test/test_Populated_Cache.cc | 0
.../test/test_Populated_Cache_Disk_Failure.cc | 0
{iocore => src/iocore}/cache/test/test_RWW.cc | 0
.../iocore}/cache/test/test_Update_L_to_S.cc | 0
.../iocore}/cache/test/test_Update_S_to_L.cc | 0
.../iocore}/cache/test/test_Update_header.cc | 0
.../iocore}/cache/test/var/trafficserver/guard.txt | 0
src/iocore/dns/CMakeLists.txt | 34 +
src/iocore/dns/DNS.cc | 1989 +++++
{iocore => src/iocore}/dns/DNSConnection.cc | 0
{iocore => src/iocore}/dns/DNSEventIO.cc | 0
{iocore => src/iocore}/dns/Inline.cc | 0
{iocore => src/iocore}/dns/Makefile.am | 0
src/iocore/dns/P_DNS.h | 38 +
src/iocore/dns/P_DNSConnection.h | 150 +
src/iocore/dns/P_DNSProcessor.h | 314 +
src/iocore/dns/P_SplitDNS.h | 40 +
{iocore => src/iocore}/dns/P_SplitDNSProcessor.h | 0
{iocore => src/iocore}/dns/SplitDNS.cc | 0
src/iocore/dns/test_I_DNS.cc | 43 +
{iocore => src/iocore}/dns/test_P_DNS.cc | 0
src/iocore/eventsystem/CMakeLists.txt | 55 +
.../iocore}/eventsystem/ConfigProcessor.cc | 0
src/iocore/eventsystem/EventSystem.cc | 66 +
{iocore => src/iocore}/eventsystem/IOBuffer.cc | 0
{iocore => src/iocore}/eventsystem/Inline.cc | 0
{iocore => src/iocore}/eventsystem/Lock.cc | 0
src/iocore/eventsystem/MIOBufferWriter.cc | 124 +
{iocore => src/iocore}/eventsystem/Makefile.am | 0
{iocore => src/iocore}/eventsystem/PQ-List.cc | 0
src/iocore/eventsystem/P_EventSystem.h | 50 +
src/iocore/eventsystem/P_Freer.h | 134 +
{iocore => src/iocore}/eventsystem/P_IOBuffer.h | 0
src/iocore/eventsystem/P_ProtectedQueue.h | 83 +
src/iocore/eventsystem/P_Thread.h | 49 +
src/iocore/eventsystem/P_UnixEThread.h | 261 +
{iocore => src/iocore}/eventsystem/P_UnixEvent.h | 0
src/iocore/eventsystem/P_UnixEventProcessor.h | 200 +
src/iocore/eventsystem/P_UnixSocketManager.h | 291 +
src/iocore/eventsystem/P_VConnection.h | 95 +
src/iocore/eventsystem/P_VIO.h | 123 +
{iocore => src/iocore}/eventsystem/Processor.cc | 0
.../iocore}/eventsystem/ProtectedQueue.cc | 0
src/iocore/eventsystem/ProxyAllocator.cc | 61 +
src/iocore/eventsystem/RecProcess.cc | 194 +
src/iocore/eventsystem/RecRawStatsImpl.cc | 257 +
.../iocore}/eventsystem/SocketManager.cc | 0
src/iocore/eventsystem/Tasks.cc | 44 +
{iocore => src/iocore}/eventsystem/Thread.cc | 0
{iocore => src/iocore}/eventsystem/UnixEThread.cc | 0
{iocore => src/iocore}/eventsystem/UnixEvent.cc | 0
.../iocore}/eventsystem/UnixEventProcessor.cc | 0
.../eventsystem/unit_tests/test_EventSystem.cc | 119 +
src/iocore/eventsystem/unit_tests/test_IOBuffer.cc | 398 +
.../eventsystem/unit_tests/test_MIOBufferWriter.cc | 200 +
src/iocore/hostdb/CMakeLists.txt | 36 +
src/iocore/hostdb/HostDB.cc | 2160 +++++
src/iocore/hostdb/HostDBInfo.cc | 84 +
{iocore => src/iocore}/hostdb/HostFile.cc | 0
{iocore => src/iocore}/hostdb/Inline.cc | 0
{iocore => src/iocore}/hostdb/Makefile.am | 0
src/iocore/hostdb/P_HostDB.h | 49 +
src/iocore/hostdb/P_HostDBProcessor.h | 313 +
src/iocore/hostdb/P_RefCountCache.h | 600 ++
{iocore => src/iocore}/hostdb/RefCountCache.cc | 0
{iocore => src/iocore}/hostdb/test_HostFile.cc | 0
src/iocore/hostdb/test_I_HostDB.cc | 50 +
{iocore => src/iocore}/hostdb/test_P_HostDB.cc | 0
src/iocore/hostdb/test_RefCountCache.cc | 293 +
{iocore => src/iocore}/io_uring/CMakeLists.txt | 0
src/iocore/io_uring/IOUringEventIO.cc | 41 +
{iocore => src/iocore}/io_uring/Makefile.am | 0
{iocore => src/iocore}/io_uring/P_IO_URING.h | 0
src/iocore/io_uring/io_uring.cc | 226 +
src/iocore/io_uring/unit_tests/test_diskIO.cc | 282 +
src/iocore/net/ALPNSupport.cc | 146 +
src/iocore/net/AsyncSignalEventIO.cc | 48 +
src/iocore/net/BIO_fastopen.cc | 212 +
{iocore => src/iocore}/net/BoringSSLUtils.cc | 0
src/iocore/net/CMakeLists.txt | 138 +
{iocore => src/iocore}/net/Connection.cc | 0
{iocore => src/iocore}/net/EventIO.cc | 0
{iocore => src/iocore}/net/Inline.cc | 0
{iocore => src/iocore}/net/Makefile.am | 0
{iocore => src/iocore}/net/Net.cc | 0
{iocore => src/iocore}/net/NetAcceptEventIO.cc | 0
src/iocore/net/NetHandler.cc | 585 ++
src/iocore/net/NetVCOptions.cc | 70 +
{iocore => src/iocore}/net/NetVCTest.cc | 0
{iocore => src/iocore}/net/NetVConnection.cc | 0
{iocore => src/iocore}/net/OCSPStapling.cc | 0
{iocore => src/iocore}/net/P_CompletionUtil.h | 0
{iocore => src/iocore}/net/P_Connection.h | 0
src/iocore/net/P_Net.h | 114 +
src/iocore/net/P_NetAccept.h | 126 +
{iocore => src/iocore}/net/P_NetVCTest.h | 0
src/iocore/net/P_NetVConnection.h | 104 +
{iocore => src/iocore}/net/P_OCSPStapling.h | 0
.../iocore}/net/P_QUICClosedConCollector.h | 0
{iocore => src/iocore}/net/P_QUICNet.h | 0
{iocore => src/iocore}/net/P_QUICNetProcessor.h | 0
.../iocore}/net/P_QUICNetProcessor_native.h | 0
.../iocore}/net/P_QUICNetProcessor_quiche.h | 0
{iocore => src/iocore}/net/P_QUICNetVConnection.h | 0
src/iocore/net/P_QUICNetVConnection_native.h | 400 +
src/iocore/net/P_QUICNetVConnection_quiche.h | 218 +
.../iocore}/net/P_QUICNextProtocolAccept.h | 0
src/iocore/net/P_QUICNextProtocolAccept_native.h | 59 +
src/iocore/net/P_QUICNextProtocolAccept_quiche.h | 59 +
{iocore => src/iocore}/net/P_QUICPacketHandler.h | 0
.../iocore}/net/P_QUICPacketHandler_native.h | 0
.../iocore}/net/P_QUICPacketHandler_quiche.h | 0
src/iocore/net/P_SNIActionPerformer.h | 582 ++
{iocore => src/iocore}/net/P_SSLCertLookup.h | 0
.../iocore}/net/P_SSLClientCoordinator.h | 0
{iocore => src/iocore}/net/P_SSLClientUtils.h | 0
{iocore => src/iocore}/net/P_SSLConfig.h | 0
{iocore => src/iocore}/net/P_SSLNetAccept.h | 0
{iocore => src/iocore}/net/P_SSLNetProcessor.h | 0
src/iocore/net/P_SSLNetVConnection.h | 510 ++
src/iocore/net/P_SSLNextProtocolAccept.h | 66 +
src/iocore/net/P_SSLNextProtocolSet.h | 62 +
{iocore => src/iocore}/net/P_SSLSecret.h | 0
src/iocore/net/P_SSLUtils.h | 216 +
src/iocore/net/P_Socks.h | 142 +
{iocore => src/iocore}/net/P_TLSKeyLogger.h | 0
src/iocore/net/P_UDPConnection.h | 134 +
{iocore => src/iocore}/net/P_UDPIOEvent.h | 0
src/iocore/net/P_UDPNet.h | 367 +
{iocore => src/iocore}/net/P_UnixCompletionUtil.h | 0
{iocore => src/iocore}/net/P_UnixNet.h | 0
src/iocore/net/P_UnixNetProcessor.h | 68 +
src/iocore/net/P_UnixNetState.h | 54 +
src/iocore/net/P_UnixNetVConnection.h | 360 +
{iocore => src/iocore}/net/P_UnixPollDescriptor.h | 0
{iocore => src/iocore}/net/P_UnixUDPConnection.h | 0
{iocore => src/iocore}/net/PollCont.cc | 0
src/iocore/net/ProxyProtocol.cc | 508 ++
.../iocore}/net/QUICClosedConCollector.cc | 0
.../iocore}/net/QUICMultiCertConfigLoader.cc | 0
{iocore => src/iocore}/net/QUICNet.cc | 0
src/iocore/net/QUICNetProcessor.cc | 229 +
src/iocore/net/QUICNetProcessor_quiche.cc | 252 +
src/iocore/net/QUICNetVConnection.cc | 2461 ++++++
.../iocore}/net/QUICNetVConnection_quiche.cc | 0
.../iocore}/net/QUICNextProtocolAccept.cc | 0
.../iocore}/net/QUICNextProtocolAccept_quiche.cc | 0
{iocore => src/iocore}/net/QUICPacketHandler.cc | 0
src/iocore/net/QUICPacketHandler_quiche.cc | 348 +
{iocore => src/iocore}/net/QUICSupport.cc | 0
{iocore => src/iocore}/net/ReadWriteEventIO.cc | 0
{iocore => src/iocore}/net/SNIActionPerformer.cc | 0
{iocore => src/iocore}/net/SSLAPIHooks.cc | 0
src/iocore/net/SSLCertLookup.cc | 587 ++
{iocore => src/iocore}/net/SSLClientCoordinator.cc | 0
src/iocore/net/SSLClientUtils.cc | 324 +
src/iocore/net/SSLConfig.cc | 1034 +++
{iocore => src/iocore}/net/SSLDiags.cc | 0
{iocore => src/iocore}/net/SSLDynlock.cc | 0
{iocore => src/iocore}/net/SSLInternal.cc | 0
{iocore => src/iocore}/net/SSLNetAccept.cc | 0
src/iocore/net/SSLNetProcessor.cc | 108 +
src/iocore/net/SSLNetVConnection.cc | 2647 ++++++
.../iocore}/net/SSLNextProtocolAccept.cc | 0
{iocore => src/iocore}/net/SSLNextProtocolSet.cc | 0
src/iocore/net/SSLSNIConfig.cc | 403 +
{iocore => src/iocore}/net/SSLSecret.cc | 0
{iocore => src/iocore}/net/SSLSessionCache.cc | 0
{iocore => src/iocore}/net/SSLSessionTicket.cc | 0
{iocore => src/iocore}/net/SSLStats.cc | 0
src/iocore/net/SSLUtils.cc | 2619 ++++++
src/iocore/net/Socks.cc | 696 ++
{iocore => src/iocore}/net/TLSBasicSupport.cc | 0
{iocore => src/iocore}/net/TLSCertSwitchSupport.cc | 0
{iocore => src/iocore}/net/TLSEarlyDataSupport.cc | 0
{iocore => src/iocore}/net/TLSKeyLogger.cc | 0
{iocore => src/iocore}/net/TLSSNISupport.cc | 0
.../iocore}/net/TLSSessionResumptionSupport.cc | 0
{iocore => src/iocore}/net/TLSTunnelSupport.cc | 0
{iocore => src/iocore}/net/UDPEventIO.cc | 0
{iocore => src/iocore}/net/UDPIOEvent.cc | 0
{iocore => src/iocore}/net/UnixConnection.cc | 0
src/iocore/net/UnixNet.cc | 201 +
{iocore => src/iocore}/net/UnixNetAccept.cc | 0
src/iocore/net/UnixNetPages.cc | 247 +
{iocore => src/iocore}/net/UnixNetProcessor.cc | 0
{iocore => src/iocore}/net/UnixNetVConnection.cc | 0
{iocore => src/iocore}/net/UnixUDPConnection.cc | 0
src/iocore/net/UnixUDPNet.cc | 1835 ++++
src/iocore/net/YamlSNIConfig.cc | 554 ++
{iocore => src/iocore}/net/libinknet_stub.cc | 0
src/iocore/net/quic/CMakeLists.txt | 44 +
{iocore => src/iocore}/net/quic/Makefile.am | 0
src/iocore/net/quic/QUICAckFrameCreator.cc | 391 +
.../iocore}/net/quic/QUICAddrVerifyState.cc | 0
.../iocore}/net/quic/QUICAltConnectionManager.cc | 0
{iocore => src/iocore}/net/quic/QUICApplication.cc | 0
.../iocore}/net/quic/QUICApplicationMap.cc | 0
.../iocore}/net/quic/QUICBidirectionalStream.cc | 0
src/iocore/net/quic/QUICConfig.cc | 519 ++
.../iocore}/net/quic/QUICConnectionTable.cc | 0
{iocore => src/iocore}/net/quic/QUICContext.cc | 0
.../iocore}/net/quic/QUICCryptoStream.cc | 0
src/iocore/net/quic/QUICDebugNames.cc | 343 +
{iocore => src/iocore}/net/quic/QUICEchoApp.cc | 0
.../iocore}/net/quic/QUICFlowController.cc | 0
{iocore => src/iocore}/net/quic/QUICFrame.cc | 0
.../iocore}/net/quic/QUICFrameDispatcher.cc | 0
.../iocore}/net/quic/QUICFrameGenerator.cc | 0
.../iocore}/net/quic/QUICFrameRetransmitter.cc | 0
{iocore => src/iocore}/net/quic/QUICGlobals.cc | 0
{iocore => src/iocore}/net/quic/QUICHKDF.cc | 0
{iocore => src/iocore}/net/quic/QUICHandshake.cc | 0
.../iocore}/net/quic/QUICIncomingFrameBuffer.cc | 0
{iocore => src/iocore}/net/quic/QUICIntUtil.cc | 0
.../iocore}/net/quic/QUICKeyGenerator.cc | 0
.../iocore}/net/quic/QUICKeyGenerator_boringssl.cc | 0
.../iocore}/net/quic/QUICKeyGenerator_openssl.cc | 0
.../iocore}/net/quic/QUICLossDetector.cc | 0
.../net/quic/QUICNewRenoCongestionController.cc | 0
{iocore => src/iocore}/net/quic/QUICPacket.cc | 0
.../iocore}/net/quic/QUICPacketFactory.cc | 0
.../iocore}/net/quic/QUICPacketHeaderProtector.cc | 0
.../quic/QUICPacketHeaderProtector_boringssl.cc | 0
.../net/quic/QUICPacketHeaderProtector_openssl.cc | 0
.../iocore}/net/quic/QUICPacketPayloadProtector.cc | 0
.../quic/QUICPacketPayloadProtector_boringssl.cc | 0
.../net/quic/QUICPacketPayloadProtector_openssl.cc | 0
.../net/quic/QUICPacketProtectionKeyInfo.cc | 0
src/iocore/net/quic/QUICPacketReceiveQueue.cc | 200 +
{iocore => src/iocore}/net/quic/QUICPadder.cc | 0
{iocore => src/iocore}/net/quic/QUICPathManager.cc | 0
.../iocore}/net/quic/QUICPathValidator.cc | 0
{iocore => src/iocore}/net/quic/QUICPinger.cc | 0
.../iocore}/net/quic/QUICResetTokenTable.cc | 0
.../iocore}/net/quic/QUICRetryIntegrityTag.cc | 0
{iocore => src/iocore}/net/quic/QUICStream.cc | 0
.../iocore}/net/quic/QUICStreamAdapter.cc | 0
{iocore => src/iocore}/net/quic/QUICStreamBase.cc | 0
.../iocore}/net/quic/QUICStreamFactory.cc | 0
.../iocore}/net/quic/QUICStreamManager.cc | 0
.../iocore}/net/quic/QUICStreamManager_native.cc | 0
.../iocore}/net/quic/QUICStreamManager_quiche.cc | 0
{iocore => src/iocore}/net/quic/QUICStreamState.cc | 0
src/iocore/net/quic/QUICStreamVCAdapter.cc | 322 +
.../iocore}/net/quic/QUICStream_quiche.cc | 0
{iocore => src/iocore}/net/quic/QUICTLS.cc | 0
.../iocore}/net/quic/QUICTLS_boringssl.cc | 0
{iocore => src/iocore}/net/quic/QUICTLS_openssl.cc | 0
.../iocore}/net/quic/QUICTokenCreator.cc | 0
.../net/quic/QUICTransferProgressProvider.cc | 83 +
.../iocore}/net/quic/QUICTransportParameters.cc | 0
src/iocore/net/quic/QUICTypes.cc | 861 ++
.../iocore}/net/quic/QUICUnidirectionalStream.cc | 0
.../iocore}/net/quic/QUICVersionNegotiator.cc | 0
{iocore => src/iocore}/net/quic/qlog/QLog.cc | 0
{iocore => src/iocore}/net/quic/qlog/QLogEvent.cc | 0
{iocore => src/iocore}/net/quic/qlog/QLogFrame.cc | 0
src/iocore/net/quic/test/event_processor_main.cc | 64 +
src/iocore/net/quic/test/main.cc | 60 +
{iocore => src/iocore}/net/quic/test/server_cert.h | 0
.../net/quic/test/test_QUICAckFrameCreator.cc | 0
.../net/quic/test/test_QUICAddrVerifyState.cc | 0
.../net/quic/test/test_QUICAltConnectionManager.cc | 0
.../net/quic/test/test_QUICFlowController.cc | 0
.../iocore}/net/quic/test/test_QUICFrame.cc | 0
.../net/quic/test/test_QUICFrameDispatcher.cc | 0
.../net/quic/test/test_QUICFrameRetransmitter.cc | 0
.../net/quic/test/test_QUICHandshakeProtocol.cc | 0
.../net/quic/test/test_QUICIncomingFrameBuffer.cc | 0
.../iocore}/net/quic/test/test_QUICInvariants.cc | 0
.../iocore}/net/quic/test/test_QUICKeyGenerator.cc | 0
.../iocore}/net/quic/test/test_QUICLossDetector.cc | 0
.../iocore}/net/quic/test/test_QUICPacket.cc | 0
.../net/quic/test/test_QUICPacketFactory.cc | 0
.../quic/test/test_QUICPacketHeaderProtector.cc | 0
.../net/quic/test/test_QUICPathValidator.cc | 0
.../iocore}/net/quic/test/test_QUICPinger.cc | 0
.../iocore}/net/quic/test/test_QUICStream.cc | 0
.../net/quic/test/test_QUICStreamManager.cc | 0
.../iocore}/net/quic/test/test_QUICStreamState.cc | 0
.../net/quic/test/test_QUICTransportParameters.cc | 0
src/iocore/net/quic/test/test_QUICType.cc | 150 +
.../iocore}/net/quic/test/test_QUICTypeUtil.cc | 0
.../net/quic/test/test_QUICVersionNegotiator.cc | 0
.../iocore}/net/quic/test_MTHashTable.cc | 0
{iocore => src/iocore}/net/test_I_Net.cc | 0
src/iocore/net/test_I_UDPNet.cc | 234 +
{iocore => src/iocore}/net/test_P_Net.cc | 0
{iocore => src/iocore}/net/test_certlookup.cc | 0
.../iocore}/net/unit_tests/sni_conf_test.yaml | 0
.../net/unit_tests/sni_conf_test_bad_port_0-1.yaml | 0
.../sni_conf_test_bad_port_1-yowzers2.yaml | 0
.../net/unit_tests/sni_conf_test_bad_port_3-.yaml | 0
.../sni_conf_test_bad_port_65535-65536.yaml | 0
.../sni_conf_test_bad_port_8080-433.yaml | 0
.../sni_conf_test_bad_port_yowzers-1.yaml | 0
.../iocore}/net/unit_tests/test_ProxyProtocol.cc | 0
.../iocore}/net/unit_tests/test_SSLSNIConfig.cc | 0
.../iocore}/net/unit_tests/test_YamlSNIConfig.cc | 0
src/iocore/net/unit_tests/unit_test_main.cc | 74 +
src/iocore/utils/CMakeLists.txt | 32 +
src/iocore/utils/Machine.cc | 255 +
{iocore => src/iocore}/utils/Makefile.am | 0
src/iocore/utils/OneWayMultiTunnel.cc | 257 +
src/iocore/utils/OneWayTunnel.cc | 391 +
{mgmt => src/mgmt}/Makefile.am | 0
{mgmt => src/mgmt}/config/AddConfigFilesHere.cc | 0
src/mgmt/config/CMakeLists.txt | 36 +
src/mgmt/config/FileManager.cc | 435 +
{mgmt => src/mgmt}/config/Makefile.am | 0
src/mgmt/rpc/CMakeLists.txt | 86 +
{mgmt => src/mgmt}/rpc/Makefile.am | 0
src/mgmt/rpc/config/JsonRPCConfig.cc | 104 +
.../mgmt}/rpc/handlers/common/RecordsUtils.cc | 0
src/mgmt/rpc/handlers/config/Configuration.cc | 204 +
{mgmt => src/mgmt}/rpc/handlers/plugins/Plugins.cc | 0
{mgmt => src/mgmt}/rpc/handlers/records/Records.cc | 0
{mgmt => src/mgmt}/rpc/handlers/server/Server.cc | 0
{mgmt => src/mgmt}/rpc/handlers/storage/Storage.cc | 0
{mgmt => src/mgmt}/rpc/jsonrpc/Context.cc | 0
{mgmt => src/mgmt}/rpc/jsonrpc/JsonRPCManager.cc | 0
{mgmt => src/mgmt}/rpc/jsonrpc/error/RPCError.cc | 0
.../rpc/jsonrpc/unit_tests/test_basic_protocol.cc | 0
.../mgmt}/rpc/jsonrpc/unit_tests/unit_test_main.cc | 0
.../schema/admin_lookup_records_params_schema.json | 0
.../mgmt}/rpc/schema/jsonrpc_request_schema.json | 0
.../mgmt}/rpc/schema/jsonrpc_response_schema.json | 0
.../mgmt}/rpc/schema/success_response_schema.json | 0
{mgmt => src/mgmt}/rpc/server/CommBase.cc | 0
src/mgmt/rpc/server/IPCSocketServer.cc | 525 ++
{mgmt => src/mgmt}/rpc/server/RPCServer.cc | 0
src/mgmt/rpc/server/unit_tests/test_rpcserver.cc | 561 ++
.../mgmt}/rpc/server/unit_tests/unit_test_main.cc | 0
src/proxy/CMakeLists.txt | 82 +
{proxy => src/proxy}/CacheControl.cc | 0
{proxy => src/proxy}/ControlBase.cc | 0
{proxy => src/proxy}/ControlMatcher.cc | 0
src/proxy/HostStatus.cc | 533 ++
{proxy => src/proxy}/HttpAPIHooks.cc | 0
{proxy => src/proxy}/IPAllow.cc | 0
{proxy => src/proxy}/Makefile.am | 0
{proxy => src/proxy}/ParentConsistentHash.cc | 0
{proxy => src/proxy}/ParentRoundRobin.cc | 0
src/proxy/ParentSelection.cc | 1916 +++++
{proxy => src/proxy}/ParentSelectionStrategy.cc | 0
src/proxy/Plugin.cc | 367 +
{proxy => src/proxy}/PluginVC.cc | 0
src/proxy/ProtocolProbeSessionAccept.cc | 216 +
{proxy => src/proxy}/ProxySession.cc | 0
{proxy => src/proxy}/ProxyTransaction.cc | 0
{proxy => src/proxy}/README-stats.otl | 0
{proxy => src/proxy}/RegressionSM.cc | 0
{proxy => src/proxy}/ReverseProxy.cc | 0
{proxy => src/proxy}/StatPages.cc | 0
{proxy => src/proxy}/Transform.cc | 0
{proxy => src/proxy}/example_prep.sh | 0
src/proxy/hdrs/CMakeLists.txt | 67 +
{proxy => src/proxy}/hdrs/HTTP.cc | 0
src/proxy/hdrs/HdrHeap.cc | 1202 +++
{proxy => src/proxy}/hdrs/HdrTSOnly.cc | 0
{proxy => src/proxy}/hdrs/HdrToken.cc | 0
{proxy => src/proxy}/hdrs/HdrUtils.cc | 0
{proxy => src/proxy}/hdrs/HeaderValidator.cc | 0
{proxy => src/proxy}/hdrs/HttpCompat.cc | 0
{proxy => src/proxy}/hdrs/HuffmanCodec.cc | 0
{proxy => src/proxy}/hdrs/MIME.cc | 0
{proxy => src/proxy}/hdrs/Makefile.am | 0
{proxy => src/proxy}/hdrs/URL.cc | 0
{proxy => src/proxy}/hdrs/VersionConverter.cc | 0
{proxy => src/proxy}/hdrs/XPACK.cc | 0
{proxy => src/proxy}/hdrs/load_http_hdr.cc | 0
{proxy => src/proxy}/hdrs/test_urlhash.cc | 0
.../proxy}/hdrs/unit_tests/test_HdrHeap.cc | 0
.../proxy}/hdrs/unit_tests/test_HdrUtils.cc | 0
{proxy => src/proxy}/hdrs/unit_tests/test_Hdrs.cc | 0
.../proxy}/hdrs/unit_tests/test_HeaderValidator.cc | 0
.../proxy}/hdrs/unit_tests/test_Huffmancode.cc | 0
{proxy => src/proxy}/hdrs/unit_tests/test_URL.cc | 0
{proxy => src/proxy}/hdrs/unit_tests/test_XPACK.cc | 0
src/proxy/hdrs/unit_tests/test_mime.cc | 251 +
.../proxy}/hdrs/unit_tests/unit_test_main.cc | 0
src/proxy/http/CMakeLists.txt | 94 +
{proxy => src/proxy}/http/ConnectingEntry.cc | 0
{proxy => src/proxy}/http/ForwardedConfig.cc | 0
{proxy => src/proxy}/http/Http1ClientSession.cc | 0
.../proxy}/http/Http1ClientTransaction.cc | 0
{proxy => src/proxy}/http/Http1ServerSession.cc | 0
.../proxy}/http/Http1ServerTransaction.cc | 0
src/proxy/http/HttpBodyFactory.cc | 1165 +++
{proxy => src/proxy}/http/HttpCacheSM.cc | 0
src/proxy/http/HttpConfig.cc | 1498 ++++
{proxy => src/proxy}/http/HttpConnectionCount.cc | 0
src/proxy/http/HttpDebugNames.cc | 664 ++
{proxy => src/proxy}/http/HttpPages.cc | 0
{proxy => src/proxy}/http/HttpProxyServerMain.cc | 0
src/proxy/http/HttpSM.cc | 8797 +++++++++++++++++++
src/proxy/http/HttpSessionAccept.cc | 90 +
{proxy => src/proxy}/http/HttpSessionManager.cc | 0
src/proxy/http/HttpTransact.cc | 8905 ++++++++++++++++++++
src/proxy/http/HttpTransactHeaders.cc | 1306 +++
{proxy => src/proxy}/http/HttpTunnel.cc | 0
src/proxy/http/HttpVCTable.cc | 136 +
{proxy => src/proxy}/http/Makefile.am | 0
{proxy => src/proxy}/http/PreWarmConfig.cc | 0
src/proxy/http/PreWarmManager.cc | 1173 +++
{proxy => src/proxy}/http/README.via | 0
.../proxy}/http/RegressionHttpTransact.cc | 0
{proxy => src/proxy}/http/TestUrl.cc | 0
{proxy => src/proxy}/http/remap/AclFiltering.cc | 0
src/proxy/http/remap/CMakeLists.txt | 56 +
{proxy => src/proxy}/http/remap/Makefile.am | 0
src/proxy/http/remap/NextHopConsistentHash.cc | 512 ++
.../proxy}/http/remap/NextHopHealthStatus.cc | 0
.../proxy}/http/remap/NextHopRoundRobin.cc | 0
src/proxy/http/remap/NextHopSelectionStrategy.cc | 424 +
.../proxy}/http/remap/NextHopStrategyFactory.cc | 0
{proxy => src/proxy}/http/remap/PluginDso.cc | 0
{proxy => src/proxy}/http/remap/PluginFactory.cc | 0
src/proxy/http/remap/RemapConfig.cc | 1365 +++
{proxy => src/proxy}/http/remap/RemapHitCount.cc | 0
{proxy => src/proxy}/http/remap/RemapPluginInfo.cc | 0
{proxy => src/proxy}/http/remap/RemapPlugins.cc | 0
{proxy => src/proxy}/http/remap/RemapProcessor.cc | 0
src/proxy/http/remap/UrlMapping.cc | 204 +
.../proxy}/http/remap/UrlMappingPathIndex.cc | 0
src/proxy/http/remap/UrlRewrite.cc | 966 +++
.../proxy}/http/remap/unit-tests/combined.yaml | 0
.../remap/unit-tests/consistent-hash-tests.yaml | 0
.../proxy}/http/remap/unit-tests/hosts.yaml | 0
.../http/remap/unit-tests/nexthop_test_stubs.cc | 211 +
.../http/remap/unit-tests/nexthop_test_stubs.h | 0
.../proxy}/http/remap/unit-tests/peering.yaml | 0
.../http/remap/unit-tests/plugin_init_fail.cc | 0
.../http/remap/unit-tests/plugin_instinit_fail.cc | 0
.../proxy}/http/remap/unit-tests/plugin_misc_cb.cc | 0
.../unit-tests/plugin_missing_deleteinstance.cc | 0
.../remap/unit-tests/plugin_missing_doremap.cc | 0
.../http/remap/unit-tests/plugin_missing_init.cc | 0
.../remap/unit-tests/plugin_missing_newinstance.cc | 0
.../http/remap/unit-tests/plugin_required_cb.cc | 0
.../http/remap/unit-tests/plugin_testing_calls.cc | 0
.../http/remap/unit-tests/plugin_testing_common.cc | 0
.../http/remap/unit-tests/plugin_testing_common.h | 0
.../http/remap/unit-tests/round-robin-tests.yaml | 0
.../http/remap/unit-tests/simple-strategy.yaml | 0
.../remap/unit-tests/strategies-dir/01-hosts.yaml | 0
.../remap/unit-tests/strategies-dir/02-groups.yaml | 0
.../unit-tests/strategies-dir/03-strategies.yaml | 0
.../proxy}/http/remap/unit-tests/strategy.yaml | 0
.../remap/unit-tests/test_NextHopConsistentHash.cc | 0
.../remap/unit-tests/test_NextHopRoundRobin.cc | 0
.../unit-tests/test_NextHopStrategyFactory.cc | 0
.../proxy}/http/remap/unit-tests/test_PluginDso.cc | 0
.../http/remap/unit-tests/test_PluginFactory.cc | 1429 ++++
.../http/remap/unit-tests/test_RemapPlugin.cc | 0
{proxy => src/proxy}/http/stats.memo | 0
{proxy => src/proxy}/http/test_http_client.pl | 0
{proxy => src/proxy}/http/test_proxy.pl | 0
{proxy => src/proxy}/http/test_socket_close.cc | 0
{proxy => src/proxy}/http/testheaders.cc | 0
src/proxy/http/unit_tests/CMakeLists.txt | 50 +
src/proxy/http/unit_tests/main.cc | 60 +
.../proxy}/http/unit_tests/test_ForwardedConfig.cc | 0
src/proxy/http/unit_tests/test_HttpTransact.cc | 590 ++
src/proxy/http/unit_tests/test_HttpUserAgent.cc | 93 +
.../proxy}/http/unit_tests/test_PreWarm.cc | 0
.../http/unit_tests/test_error_page_selection.cc | 0
src/proxy/http/unit_tests/unit_test_main.cc | 30 +
src/proxy/http2/CMakeLists.txt | 82 +
{proxy => src/proxy}/http2/HPACK.cc | 0
{proxy => src/proxy}/http2/HTTP2.cc | 0
{proxy => src/proxy}/http2/Http2ClientSession.cc | 0
{proxy => src/proxy}/http2/Http2CommonSession.cc | 0
{proxy => src/proxy}/http2/Http2ConnectionState.cc | 0
{proxy => src/proxy}/http2/Http2DebugNames.cc | 0
{proxy => src/proxy}/http2/Http2Frame.cc | 0
.../proxy}/http2/Http2FrequencyCounter.cc | 0
{proxy => src/proxy}/http2/Http2ServerSession.cc | 0
src/proxy/http2/Http2SessionAccept.cc | 90 +
{proxy => src/proxy}/http2/Http2Stream.cc | 0
{proxy => src/proxy}/http2/Makefile.am | 0
.../proxy}/http2/hpack-tests/story_00.json | 0
.../proxy}/http2/hpack-tests/story_01.json | 0
.../proxy}/http2/hpack-tests/story_02.json | 0
.../proxy}/http2/hpack-tests/story_03.json | 0
.../proxy}/http2/hpack-tests/story_04.json | 0
.../proxy}/http2/hpack-tests/story_05.json | 0
.../proxy}/http2/hpack-tests/story_06.json | 0
.../proxy}/http2/hpack-tests/story_07.json | 0
.../proxy}/http2/hpack-tests/story_08.json | 0
.../proxy}/http2/hpack-tests/story_09.json | 0
.../proxy}/http2/hpack-tests/story_10.json | 0
.../proxy}/http2/hpack-tests/story_11.json | 0
.../proxy}/http2/hpack-tests/story_12.json | 0
.../proxy}/http2/hpack-tests/story_13.json | 0
.../proxy}/http2/hpack-tests/story_14.json | 0
.../proxy}/http2/hpack-tests/story_15.json | 0
.../proxy}/http2/hpack-tests/story_16.json | 0
.../proxy}/http2/hpack-tests/story_17.json | 0
.../proxy}/http2/hpack-tests/story_18.json | 0
.../proxy}/http2/hpack-tests/story_19.json | 0
.../proxy}/http2/hpack-tests/story_20.json | 0
.../proxy}/http2/hpack-tests/story_21.json | 0
.../proxy}/http2/hpack-tests/story_22.json | 0
.../proxy}/http2/hpack-tests/story_23.json | 0
.../proxy}/http2/hpack-tests/story_24.json | 0
.../proxy}/http2/hpack-tests/story_25.json | 0
.../proxy}/http2/hpack-tests/story_26.json | 0
.../proxy}/http2/hpack-tests/story_27.json | 0
.../proxy}/http2/hpack-tests/story_28.json | 0
.../proxy}/http2/hpack-tests/story_29.json | 0
.../proxy}/http2/hpack-tests/story_30.json | 0
.../proxy}/http2/hpack-tests/story_31.json | 0
src/proxy/http2/test_HPACK.cc | 429 +
src/proxy/http2/unit_tests/main.cc | 65 +
.../proxy}/http2/unit_tests/test_HTTP2.cc | 0
.../http2/unit_tests/test_HpackIndexingTable.cc | 0
.../http2/unit_tests/test_Http2DependencyTree.cc | 0
.../proxy}/http2/unit_tests/test_Http2Frame.cc | 0
.../http2/unit_tests/test_Http2FrequencyCounter.cc | 0
src/proxy/http3/CMakeLists.txt | 100 +
{proxy => src/proxy}/http3/Http09App.cc | 0
{proxy => src/proxy}/http3/Http3.cc | 0
{proxy => src/proxy}/http3/Http3App.cc | 0
{proxy => src/proxy}/http3/Http3Config.cc | 0
{proxy => src/proxy}/http3/Http3DataFramer.cc | 0
{proxy => src/proxy}/http3/Http3DebugNames.cc | 0
{proxy => src/proxy}/http3/Http3Frame.cc | 0
{proxy => src/proxy}/http3/Http3FrameCollector.cc | 0
{proxy => src/proxy}/http3/Http3FrameDispatcher.cc | 0
src/proxy/http3/Http3HeaderFramer.cc | 115 +
src/proxy/http3/Http3HeaderVIOAdaptor.cc | 149 +
.../proxy}/http3/Http3ProtocolEnforcer.cc | 0
{proxy => src/proxy}/http3/Http3Session.cc | 0
src/proxy/http3/Http3SessionAccept.cc | 101 +
{proxy => src/proxy}/http3/Http3SettingsHandler.cc | 0
src/proxy/http3/Http3StreamDataVIOAdaptor.cc | 74 +
{proxy => src/proxy}/http3/Http3Transaction.cc | 0
{proxy => src/proxy}/http3/Http3Types.cc | 0
{proxy => src/proxy}/http3/Makefile.am | 0
{proxy => src/proxy}/http3/QPACK.cc | 0
{proxy => src/proxy}/http3/test/Mock.h | 0
src/proxy/http3/test/main.cc | 62 +
src/proxy/http3/test/main_qpack.cc | 107 +
{proxy => src/proxy}/http3/test/stub.cc | 0
{proxy => src/proxy}/http3/test/test_Http3Frame.cc | 0
.../proxy}/http3/test/test_Http3FrameDispatcher.cc | 0
{proxy => src/proxy}/http3/test/test_QPACK.cc | 0
src/proxy/logging/CMakeLists.txt | 62 +
src/proxy/logging/Log.cc | 1413 ++++
src/proxy/logging/LogAccess.cc | 3297 ++++++++
{proxy => src/proxy}/logging/LogAccessTest.cc | 0
{proxy => src/proxy}/logging/LogAccessTest.h | 0
{proxy => src/proxy}/logging/LogBuffer.cc | 0
src/proxy/logging/LogConfig.cc | 815 ++
{proxy => src/proxy}/logging/LogField.cc | 0
{proxy => src/proxy}/logging/LogFieldAliasMap.cc | 0
src/proxy/logging/LogFile.cc | 772 ++
{proxy => src/proxy}/logging/LogFilter.cc | 0
{proxy => src/proxy}/logging/LogFormat.cc | 0
{proxy => src/proxy}/logging/LogObject.cc | 0
src/proxy/logging/LogStandalone.cc | 210 +
{proxy => src/proxy}/logging/LogUtils.cc | 0
{proxy => src/proxy}/logging/Makefile.am | 0
{proxy => src/proxy}/logging/RolledLogDeleter.cc | 0
{proxy => src/proxy}/logging/YamlLogConfig.cc | 0
.../proxy}/logging/YamlLogConfigDecoders.cc | 0
.../logging/unit-tests/benchmark_LogObject.cc | 194 +
.../proxy}/logging/unit-tests/test_LogUtils.cc | 0
.../proxy}/logging/unit-tests/test_LogUtils.h | 0
.../logging/unit-tests/test_RolledLogDeleter.cc | 0
{proxy => src/proxy}/private/Makefile.inc | 0
src/proxy/private/SSLProxySession.cc | 39 +
{proxy => src/proxy}/private/SSLProxySession.h | 0
{proxy => src/proxy}/shared/CMakeLists.txt | 0
src/proxy/shared/DiagsConfig.cc | 378 +
{proxy => src/proxy}/shared/Makefile.am | 0
src/records/CMakeLists.txt | 5 +-
src/records/RecConfigParse.cc | 2 +-
src/records/RecCore.cc | 4 +-
src/records/RecHttp.cc | 4 +-
src/records/RecMessage.cc | 2 +-
src/records/RecMutex.cc | 2 +-
src/records/RecUtils.cc | 2 +-
src/records/RecYAMLDecoder.cc | 2 +-
src/records/RecordsConfig.cc | 2 +-
src/records/RecordsConfigUtils.cc | 2 +-
src/records/test_I_RecProcess.cc | 2 +-
src/records/test_RecordsConfig.cc | 2 +-
src/records/unit_tests/test_RecHttp.cc | 2 +-
.../unit_tests/unit_test_main_on_eventsystem.cc | 4 +-
src/tests/CMakeLists.txt | 69 +-
src/traffic_cache_tool/CacheDefs.h | 2 +-
src/traffic_cache_tool/CacheScan.cc | 8 +-
src/traffic_cache_tool/CacheScan.h | 2 +-
src/traffic_crashlog/traffic_crashlog.cc | 8 +-
src/traffic_ctl/traffic_ctl.cc | 2 +-
src/traffic_layout/engine.cc | 6 +-
src/traffic_layout/info.cc | 6 +-
src/traffic_layout/traffic_layout.cc | 2 +-
src/traffic_logcat/CMakeLists.txt | 1 +
src/traffic_logcat/logcat.cc | 2 +-
src/traffic_logstats/CMakeLists.txt | 1 +
src/traffic_logstats/logstats.cc | 4 +-
src/traffic_quic/quic_client.h | 4 +-
src/traffic_quic/traffic_quic.cc | 6 +-
src/traffic_server/CMakeLists.txt | 14 +-
src/traffic_server/Crash.cc | 6 +-
src/traffic_server/EventName.cc | 6 +-
src/traffic_server/SocksProxy.cc | 2 +-
src/traffic_server/traffic_server.cc | 8 +-
src/traffic_top/traffic_top.cc | 4 +-
src/traffic_via/traffic_via.cc | 2 +-
src/tscore/ArgParser.cc | 2 +-
src/tscore/Layout.cc | 2 +-
src/tscore/Regression.cc | 2 +-
src/tscore/Version.cc | 2 +-
src/tscore/ink_args.cc | 2 +-
src/tscore/runroot.cc | 2 +-
src/tscore/unit_tests/test_Version.cc | 2 +-
src/tscore/unit_tests/test_layout.cc | 2 +-
tests/fuzzing/CMakeLists.txt | 13 +-
tests/fuzzing/fuzz_rec_http.cc | 2 +-
.../gold_tests/jsonrpc/jsonrpc_api_schema.test.py | 2 +-
tests/gold_tests/jsonrpc/plugins/CMakeLists.txt | 2 +-
.../jsonrpc/plugins/jsonrpc_plugin_handler_test.cc | 2 +-
tools/benchmark/benchmark_ProxyAllocator.cc | 4 +-
tools/jtest/jtest.cc | 2 +-
1293 files changed, 111842 insertions(+), 111687 deletions(-)
diff --git a/.gitignore b/.gitignore
index d851e8385b..8ed8ac5e6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,43 +107,43 @@ src/records/test_librecords_on_eventsystem
src/api/test_Metrics
lib/perl/lib/Apache/TS.pm
-iocore/net/test_certlookup
-iocore/net/test_UDPNet
-iocore/net/test_libinknet
-iocore/net/quic/test_*
-iocore/aio/test_AIO
-iocore/eventsystem/test_IOBuffer
-iocore/eventsystem/test_EventSystem
-iocore/eventsystem/test_MIOBufferWriter
-
-iocore/hostdb/test_RefCountCache
-iocore/hostdb/test_HostFile
-
-proxy/hdrs/test_mime
-proxy/hdrs/test_Huffmancode
-proxy/hdrs/test_proxy_hdrs
-proxy/hdrs/test_hdr_heap
-proxy/hdrs/test_Huffmancode
-proxy/hdrs/test_XPACK
-proxy/http/test_HttpTransact
-proxy/http/remap/test_NextHopRoundRobin
-proxy/http/remap/test_NextHopStrategyFactory
-proxy/http/remap/test_PluginDso
-proxy/http/remap/test_PluginFactory
-proxy/http/remap/test_RemapPluginInfo
-proxy/http/test_proxy_http
-proxy/http/test_PreWarm
-proxy/http/remap/test_*
-proxy/http2/test_libhttp2
-proxy/http2/test_Http2DependencyTree
-proxy/http2/test_Http2FrequencyCounter
-proxy/http2/test_HPACK
-proxy/http2/hpack-tests/results
-proxy/http3/test_libhttp3
-proxy/http3/test_qpack
-proxy/logging/test_LogUtils
-proxy/logging/test_LogUtils2
-proxy/logging/test_RolledLogDeleter
+src/iocore/net/test_certlookup
+src/iocore/net/test_UDPNet
+src/iocore/net/test_libinknet
+src/iocore/net/quic/test_*
+src/iocore/aio/test_AIO
+src/iocore/eventsystem/test_IOBuffer
+src/iocore/eventsystem/test_EventSystem
+src/iocore/eventsystem/test_MIOBufferWriter
+
+src/iocore/hostdb/test_RefCountCache
+src/iocore/hostdb/test_HostFile
+
+src/proxy/hdrs/test_mime
+src/proxy/hdrs/test_Huffmancode
+src/proxy/hdrs/test_proxy_hdrs
+src/proxy/hdrs/test_hdr_heap
+src/proxy/hdrs/test_Huffmancode
+src/proxy/hdrs/test_XPACK
+src/proxy/http/test_HttpTransact
+src/proxy/http/remap/test_NextHopRoundRobin
+src/proxy/http/remap/test_NextHopStrategyFactory
+src/proxy/http/remap/test_PluginDso
+src/proxy/http/remap/test_PluginFactory
+src/proxy/http/remap/test_RemapPluginInfo
+src/proxy/http/test_proxy_http
+src/proxy/http/test_PreWarm
+src/proxy/http/remap/test_*
+src/proxy/http2/test_libhttp2
+src/proxy/http2/test_Http2DependencyTree
+src/proxy/http2/test_Http2FrequencyCounter
+src/proxy/http2/test_HPACK
+src/proxy/http2/hpack-tests/results
+src/proxy/http3/test_libhttp3
+src/proxy/http3/test_qpack
+src/proxy/logging/test_LogUtils
+src/proxy/logging/test_LogUtils2
+src/proxy/logging/test_RolledLogDeleter
plugins/authproxy/authproxy_test
plugins/esi/*_test
@@ -162,17 +162,10 @@ tools/benchmark/benchmark_FreeList
tools/benchmark/benchmark_ProxyAllocator
tools/benchmark/benchmark_SharedMutex
-mgmt/rpc/overridable_txn_vars.cc
-mgmt/rpc/IPCSocketClient.cc
-mgmt/rpc/test_jsonrpc
-mgmt/rpc/test_jsonrpcserver
-mgmt/tools/traffic_mcast_snoop
-mgmt/tools/traffic_net_config
-mgmt/tools/traffic_shmem_clean
-mgmt/tools/traffic_time_config
-mgmt/tools/traffic_vip_config
-mgmt/tools/shmem_clean
-mgmt/utils/test_mgmt_utils
+src/mgmt/rpc/overridable_txn_vars.cc
+src/mgmt/rpc/IPCSocketClient.cc
+src/mgmt/rpc/test_jsonrpc
+src/mgmt/rpc/test_jsonrpcserver
libtool
m4/libtool.m4
@@ -228,5 +221,5 @@ tests/gold_tests/bigobj/push_request
tests/gold_tests/chunked_encoding/smuggle-client
tests/gold_tests/tls/ssl-post
-iocore/cache/test_*
-iocore/cache/test/var/trafficserver/cache.db
+src/iocore/cache/test_*
+src/iocore/cache/test/var/trafficserver/cache.db
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b88568d8d..64b1bd45db 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -572,10 +572,10 @@ add_subdirectory(src/tscpp/util)
add_subdirectory(src/tscpp/api)
add_subdirectory(src/tscore)
add_subdirectory(src/records)
-add_subdirectory(iocore)
-add_subdirectory(proxy)
-add_subdirectory(mgmt/config)
-add_subdirectory(mgmt/rpc)
+add_subdirectory(src/iocore)
+add_subdirectory(src/proxy)
+add_subdirectory(src/mgmt/config)
+add_subdirectory(src/mgmt/rpc)
add_subdirectory(src/api)
add_subdirectory(src/traffic_crashlog)
add_subdirectory(src/traffic_server)
@@ -647,11 +647,8 @@ endfunction(add_clang_format_target)
add_clang_format_target(src)
add_clang_format_target(example)
-add_clang_format_target(iocore)
add_clang_format_target(include)
-add_clang_format_target(mgmt)
add_clang_format_target(plugins)
-add_clang_format_target(proxy)
add_clang_format_target(tools)
add_clang_format_target(tests)
diff --git a/ci/jenkins/bin/autest.sh b/ci/jenkins/bin/autest.sh
index 995b472ea8..455379f2cc 100755
--- a/ci/jenkins/bin/autest.sh
+++ b/ci/jenkins/bin/autest.sh
@@ -23,7 +23,7 @@ sleep 30
git branch --contains ${ghprbActualCommit} > /dev/null
if [ $? = 0 -a ! -z "$ghprbActualCommit" ]; then
- git diff HEAD~1 --name-only | egrep -E '^(build|iocore|proxy|tests|include|mgmt|plugins|proxy|src)/' > /dev/null
+ git diff HEAD~1 --name-only | egrep -E '^(build|tests|include|plugins|src)/' > /dev/null
if [ $? = 1 ]; then
echo "No relevant files changed, skipping run"
exit 0
diff --git a/contrib/python/compare_RecordsConfigcc.py b/contrib/python/compare_RecordsConfigcc.py
index 2eebce3096..8fc3a852a4 100755
--- a/contrib/python/compare_RecordsConfigcc.py
+++ b/contrib/python/compare_RecordsConfigcc.py
@@ -45,7 +45,7 @@ rc_in = {} # records.config.in values
rc_doc = {} # documented values
# Process RecordsConfig.cc
-with open(f"{src_dir}/mgmt/RecordsConfig.cc") as fh:
+with open(f"{src_dir}/src/mgmt/RecordsConfig.cc") as fh:
cc_re = re.compile(r'\{RECT_(?:CONFIG|LOCAL), "([^"]+)", RECD_([A-Z]+), (.+?), ')
for line in fh:
m = cc_re.search(line)
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 4cde23176a..b8022942e6 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -747,10 +747,7 @@ WARN_LOGFILE =
INPUT = mainpage.doc \
../include \
- ../iocore \
../src/records \
- ../mgmt \
- ../proxy \
../src
# This tag can be used to specify the character encoding of the source files
diff --git a/include/api/InkAPIInternal.h b/include/api/InkAPIInternal.h
index 4d2f31695d..086bcffd84 100644
--- a/include/api/InkAPIInternal.h
+++ b/include/api/InkAPIInternal.h
@@ -23,14 +23,14 @@
#pragma once
-#include "I_EventSystem.h"
+#include "EventSystem.h"
#include "URL.h"
-#include "I_Net.h"
+#include "Net.h"
#include "HTTP.h"
#include "tscore/List.h"
#include "ConfigProcessor.h"
-#include "I_Cache.h"
-#include "I_Tasks.h"
+#include "Cache.h"
+#include "Tasks.h"
#include "Plugin.h"
#include "api/APIHook.h"
diff --git a/include/iocore/aio/AIO.h b/include/iocore/aio/AIO.h
new file mode 100644
index 0000000000..6d793a5ffa
--- /dev/null
+++ b/include/iocore/aio/AIO.h
@@ -0,0 +1,85 @@
+/** @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.
+ */
+
+/****************************************************************************
+
+ Async Disk IO operations.
+
+
+
+ ****************************************************************************/
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "EventSystem.h"
+#include "records/RecProcess.h"
+
+static constexpr ts::ModuleVersion AIO_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+#define AIO_EVENT_DONE (AIO_EVENT_EVENTS_START + 0)
+
+#define LIO_READ 0x1
+#define LIO_WRITE 0x2
+
+enum AIOBackend {
+ AIO_BACKEND_AUTO = 0,
+ AIO_BACKEND_THREAD = 1,
+ AIO_BACKEND_IO_URING = 2,
+};
+
+struct ink_aiocb {
+ int aio_fildes = -1; /* file descriptor or status: AIO_NOT_IN_PROGRESS */
+ void *aio_buf = nullptr; /* buffer location */
+ size_t aio_nbytes = 0; /* length of transfer */
+ off_t aio_offset = 0; /* file offset */
+
+ int aio_lio_opcode = 0; /* listio operation */
+ int aio_state = 0; /* state flag for List I/O */
+};
+
+bool ink_aio_thread_num_set(int thread_num);
+
+// AIOCallback::thread special values
+#define AIO_CALLBACK_THREAD_ANY ((EThread *)0) // any regular event thread
+#define AIO_CALLBACK_THREAD_AIO ((EThread *)-1)
+
+struct AIOCallback : public Continuation {
+ // set before calling aio_read/aio_write
+ ink_aiocb aiocb;
+ Action action;
+ EThread *thread = AIO_CALLBACK_THREAD_ANY;
+ AIOCallback *then = nullptr;
+ // set on return from aio_read/aio_write
+ int64_t aio_result = 0;
+
+ int ok();
+ AIOCallback() {}
+};
+
+void ink_aio_init(ts::ModuleVersion version, AIOBackend backend = AIO_BACKEND_AUTO);
+void ink_aio_set_err_callback(Continuation *error_callback);
+
+int ink_aio_read(AIOCallback *op,
+ int fromAPI = 0); // fromAPI is a boolean to indicate if this is from an API call such as upload proxy feature
+int ink_aio_write(AIOCallback *op, int fromAPI = 0);
+AIOCallback *new_AIOCallback();
diff --git a/include/iocore/aio/AIO_fault_injection.h b/include/iocore/aio/AIO_fault_injection.h
new file mode 100644
index 0000000000..c95693a524
--- /dev/null
+++ b/include/iocore/aio/AIO_fault_injection.h
@@ -0,0 +1,72 @@
+/** @file
+
+ A mechanism to simulate disk failure by injecting faults in userspace.
+
+ @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 "Continuation.h"
+#include "Lock.h"
+#include "tscore/ink_assert.h"
+#include "tscore/ink_mutex.h"
+#include <cerrno>
+#include <fcntl.h>
+#include <filesystem>
+#include <regex>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+// We need a way to simulate failures determininstically to test disk
+// initialization
+
+static constexpr auto TAG{"fault"};
+
+class AIOFaultInjection
+{
+ struct IOFault {
+ int err_no;
+ bool skip_io;
+ };
+ using IOFaults = std::unordered_map<int, IOFault>;
+
+ struct IOFaultState {
+ std::size_t op_count = 0;
+ };
+
+ std::unordered_map<std::string, IOFaults> _faults_by_regex;
+ std::unordered_map<int, IOFaults &> _faults_by_fd;
+ std::unordered_map<int, IOFaultState> _state_by_fd;
+
+ void _decrement_op_count(int fd);
+ IOFault _op_result(int fd);
+
+ std::mutex _mutex;
+
+public:
+ void inject_fault(const char *path_regex, int op_index, IOFault fault);
+
+ int open(const char *pathname, int flags, mode_t mode);
+ ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
+ ssize_t pwrite(int fd, const void *buf, size_t n, off_t offset);
+};
+
+extern AIOFaultInjection aioFaultInjection;
diff --git a/include/iocore/cache/Cache.h b/include/iocore/cache/Cache.h
new file mode 100644
index 0000000000..faaacc1475
--- /dev/null
+++ b/include/iocore/cache/Cache.h
@@ -0,0 +1,223 @@
+/** @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 "tscore/ink_platform.h"
+#include "EventSystem.h"
+#include "AIO.h"
+#include "CacheDefs.h"
+#include "Store.h"
+
+static constexpr ts::ModuleVersion CACHE_MODULE_VERSION(1, 0);
+
+#define CACHE_WRITE_OPT_OVERWRITE 0x0001
+#define CACHE_WRITE_OPT_CLOSE_COMPLETE 0x0002
+#define CACHE_WRITE_OPT_SYNC (CACHE_WRITE_OPT_CLOSE_COMPLETE | 0x0004)
+#define CACHE_WRITE_OPT_OVERWRITE_SYNC (CACHE_WRITE_OPT_SYNC | CACHE_WRITE_OPT_OVERWRITE)
+
+#define SCAN_KB_PER_SECOND 8192 // 1TB/8MB = 131072 = 36 HOURS to scan a TB
+
+#define RAM_CACHE_ALGORITHM_CLFUS 0
+#define RAM_CACHE_ALGORITHM_LRU 1
+
+#define CACHE_COMPRESSION_NONE 0
+#define CACHE_COMPRESSION_FASTLZ 1
+#define CACHE_COMPRESSION_LIBZ 2
+#define CACHE_COMPRESSION_LIBLZMA 3
+
+enum { RAM_HIT_COMPRESS_NONE = 1, RAM_HIT_COMPRESS_FASTLZ, RAM_HIT_COMPRESS_LIBZ, RAM_HIT_COMPRESS_LIBLZMA, RAM_HIT_LAST_ENTRY };
+
+struct CacheVC;
+class CacheEvacuateDocVC;
+struct CacheDisk;
+struct OverridableHttpConfigParams;
+class URL;
+class HTTPHdr;
+class HTTPInfo;
+
+using CacheHTTPHdr = HTTPHdr;
+using CacheURL = URL;
+using CacheHTTPInfo = HTTPInfo;
+
+struct CacheProcessor : public Processor {
+ CacheProcessor()
+ : min_stripe_version(CACHE_DB_MAJOR_VERSION, CACHE_DB_MINOR_VERSION),
+ max_stripe_version(CACHE_DB_MAJOR_VERSION, CACHE_DB_MINOR_VERSION)
+
+ {
+ }
+
+ int start(int n_cache_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+ virtual int start_internal(int flags = 0);
+ void stop();
+
+ int dir_check(bool fix);
+
+ Action *lookup(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+ const char *hostname = nullptr, int host_len = 0);
+ Action *open_read(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+ const char *hostname = nullptr, int host_len = 0);
+ Action *open_write(Continuation *cont, CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+ int expected_size = CACHE_EXPECTED_SIZE, int options = 0, time_t pin_in_cache = (time_t)0,
+ char *hostname = nullptr, int host_len = 0);
+ Action *remove(Continuation *cont, const CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_NONE,
+ const char *hostname = nullptr, int host_len = 0);
+ Action *scan(Continuation *cont, char *hostname = nullptr, int host_len = 0, int KB_per_second = SCAN_KB_PER_SECOND);
+ Action *lookup(Continuation *cont, const HttpCacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+ Action *open_read(Continuation *cont, const HttpCacheKey *key, CacheHTTPHdr *request, const OverridableHttpConfigParams *params,
+ time_t pin_in_cache = (time_t)0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+ Action *open_write(Continuation *cont, int expected_size, const HttpCacheKey *key, CacheHTTPHdr *request, CacheHTTPInfo *old_info,
+ time_t pin_in_cache = (time_t)0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+ Action *remove(Continuation *cont, const HttpCacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP);
+ Action *link(Continuation *cont, CacheKey *from, CacheKey *to, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP,
+ char *hostname = nullptr, int host_len = 0);
+
+ Action *deref(Continuation *cont, CacheKey *key, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP, char *hostname = nullptr,
+ int host_len = 0);
+
+ /** Mark physical disk/device/file as offline.
+ All stripes for this device are disabled.
+
+ @return @c true if there are any storage devices remaining online, @c false if not.
+
+ @note This is what is called if a disk is disabled due to I/O errors.
+ */
+ bool mark_storage_offline(CacheDisk *d, bool admin = false);
+
+ /** Find the storage for a @a path.
+ If @a len is 0 then @a path is presumed null terminated.
+ @return @c nullptr if the path does not match any defined storage.
+ */
+ CacheDisk *find_by_path(const char *path, int len = 0);
+
+ /** Check if there are any online storage devices.
+ If this returns @c false then the cache should be disabled as there is no storage available.
+ */
+ bool has_online_storage() const;
+
+ static int IsCacheEnabled();
+
+ static bool IsCacheReady(CacheFragType type);
+
+ /// Type for callback function.
+ using CALLBACK_FUNC = void (*)();
+ /** Lifecycle callback.
+
+ The function @a cb is called after cache initialization has
+ finished and the cache is ready or has failed.
+
+ @internal If we need more lifecycle callbacks, this should be
+ generalized ala the standard hooks style, with a type enum used
+ to specific the callback type and passed to the callback
+ function.
+ */
+ void afterInitCallbackSet(CALLBACK_FUNC cb);
+
+ // private members
+ void diskInitialized();
+
+ void cacheInitialized();
+
+ int
+ waitForCache() const
+ {
+ return wait_for_cache;
+ }
+
+ static uint32_t cache_ready;
+ static int initialized;
+ static int start_done;
+ static bool clear;
+ static bool fix;
+ static bool check;
+ static int start_internal_flags;
+ static int auto_clear_flag;
+
+ ts::VersionNumber min_stripe_version;
+ ts::VersionNumber max_stripe_version;
+
+ CALLBACK_FUNC cb_after_init = nullptr;
+ int wait_for_cache = 0;
+};
+
+inline void
+CacheProcessor::afterInitCallbackSet(CALLBACK_FUNC cb)
+{
+ cb_after_init = cb;
+}
+
+struct CacheVConnection : public VConnection {
+ VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override = 0;
+ virtual VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset) = 0;
+ VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override = 0;
+ void do_io_close(int lerrno = -1) override = 0;
+ void reenable(VIO *avio) override = 0;
+ void reenable_re(VIO *avio) override = 0;
+ void
+ do_io_shutdown(ShutdownHowTo_t howto) override
+ {
+ (void)howto;
+ ink_assert(!"CacheVConnection::do_io_shutdown unsupported");
+ }
+
+ virtual int get_header(void **ptr, int *len) = 0;
+ virtual int set_header(void *ptr, int len) = 0;
+ virtual int get_single_data(void **ptr, int *len) = 0;
+
+ virtual void set_http_info(CacheHTTPInfo *info) = 0;
+ virtual void get_http_info(CacheHTTPInfo **info) = 0;
+
+ virtual bool is_ram_cache_hit() const = 0;
+ virtual bool set_pin_in_cache(time_t t) = 0;
+ virtual time_t get_pin_in_cache() = 0;
+ virtual int64_t get_object_size() = 0;
+ virtual bool
+ is_compressed_in_ram() const
+ {
+ return false;
+ }
+
+ virtual int
+ get_volume_number() const
+ {
+ return -1;
+ }
+
+ virtual const char *
+ get_disk_path() const
+ {
+ return nullptr;
+ }
+
+ /** Test if the VC can support pread.
+ @return @c true if @c do_io_pread will work, @c false if not.
+ */
+ virtual bool is_pread_capable() = 0;
+
+ CacheVConnection();
+};
+
+void ink_cache_init(ts::ModuleVersion version);
+extern CacheProcessor cacheProcessor;
+extern Continuation *cacheRegexDeleteCont;
diff --git a/include/iocore/cache/CacheDefs.h b/include/iocore/cache/CacheDefs.h
new file mode 100644
index 0000000000..6cfded4f40
--- /dev/null
+++ b/include/iocore/cache/CacheDefs.h
@@ -0,0 +1,143 @@
+/** @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 "Event.h"
+#include "VConnection.h"
+#include "tscore/Version.h"
+#include "tscore/CryptoHash.h"
+
+#define CACHE_INIT_FAILED -1
+#define CACHE_INITIALIZING 0
+#define CACHE_INITIALIZED 1
+
+#define CACHE_ALT_INDEX_DEFAULT -1
+#define CACHE_ALT_REMOVED -2
+
+static const uint8_t CACHE_DB_MAJOR_VERSION = 24;
+static const uint8_t CACHE_DB_MINOR_VERSION = 2;
+// This is used in various comparisons because otherwise if the minor version is 0,
+// the compile fails because the condition is always true or false. Running it through
+// VersionNumber prevents that.
+extern const ts::VersionNumber CACHE_DB_VERSION;
+
+static const uint8_t CACHE_DIR_MAJOR_VERSION = 18;
+static const uint8_t CACHE_DIR_MINOR_VERSION = 0;
+
+#define CACHE_DB_FDS 128
+
+// opcodes
+#define CACHE_OPEN_READ 1
+#define CACHE_OPEN_READ_BUFFER 2
+#define CACHE_OPEN_READ_LONG 3
+#define CACHE_OPEN_READ_BUFFER_LONG 4
+#define CACHE_OPEN_WRITE 5
+#define CACHE_OPEN_WRITE_BUFFER 6
+#define CACHE_OPEN_WRITE_LONG 7
+#define CACHE_OPEN_WRITE_BUFFER_LONG 8
+#define CACHE_UPDATE 9
+#define CACHE_REMOVE 10
+#define CACHE_LINK 11
+#define CACHE_DEREF 12
+#define CACHE_LOOKUP_OP 13
+
+enum CacheType {
+ CACHE_NONE_TYPE = 0, // for empty disk fragments
+ CACHE_HTTP_TYPE = 1,
+ CACHE_RTSP_TYPE = 2
+};
+
+// NOTE: All the failures are ODD, and one greater than the success
+// Some of these must match those in <ts/ts.h>
+enum CacheEventType {
+ CACHE_EVENT_LOOKUP = CACHE_EVENT_EVENTS_START + 0,
+ CACHE_EVENT_LOOKUP_FAILED = CACHE_EVENT_EVENTS_START + 1,
+ CACHE_EVENT_OPEN_READ = CACHE_EVENT_EVENTS_START + 2,
+ CACHE_EVENT_OPEN_READ_FAILED = CACHE_EVENT_EVENTS_START + 3,
+ // 4-7 unused
+ CACHE_EVENT_OPEN_WRITE = CACHE_EVENT_EVENTS_START + 8,
+ CACHE_EVENT_OPEN_WRITE_FAILED = CACHE_EVENT_EVENTS_START + 9,
+ CACHE_EVENT_REMOVE = CACHE_EVENT_EVENTS_START + 12,
+ CACHE_EVENT_REMOVE_FAILED = CACHE_EVENT_EVENTS_START + 13,
+ CACHE_EVENT_UPDATE,
+ CACHE_EVENT_UPDATE_FAILED,
+ CACHE_EVENT_LINK,
+ CACHE_EVENT_LINK_FAILED,
+ CACHE_EVENT_DEREF,
+ CACHE_EVENT_DEREF_FAILED,
+ CACHE_EVENT_SCAN = CACHE_EVENT_EVENTS_START + 20,
+ CACHE_EVENT_SCAN_FAILED = CACHE_EVENT_EVENTS_START + 21,
+ CACHE_EVENT_SCAN_OBJECT = CACHE_EVENT_EVENTS_START + 22,
+ CACHE_EVENT_SCAN_OPERATION_BLOCKED = CACHE_EVENT_EVENTS_START + 23,
+ CACHE_EVENT_SCAN_OPERATION_FAILED = CACHE_EVENT_EVENTS_START + 24,
+ CACHE_EVENT_SCAN_DONE = CACHE_EVENT_EVENTS_START + 25,
+ //////////////////////////
+ // Internal error codes //
+ //////////////////////////
+ CACHE_EVENT_RESPONSE = CACHE_EVENT_EVENTS_START + 50,
+ CACHE_EVENT_RESPONSE_MSG,
+ CACHE_EVENT_RESPONSE_RETRY
+};
+
+enum CacheScanResult {
+ CACHE_SCAN_RESULT_CONTINUE = EVENT_CONT,
+ CACHE_SCAN_RESULT_DONE = EVENT_DONE,
+ CACHE_SCAN_RESULT_DELETE = 10,
+ CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES,
+ CACHE_SCAN_RESULT_UPDATE,
+ CACHE_SCAN_RESULT_RETRY
+};
+
+enum CacheDataType {
+ CACHE_DATA_HTTP_INFO = VCONNECTION_CACHE_DATA_BASE,
+ CACHE_DATA_KEY,
+ CACHE_DATA_RAM_CACHE_HIT_FLAG,
+};
+
+enum CacheFragType {
+ CACHE_FRAG_TYPE_NONE = 0,
+ CACHE_FRAG_TYPE_UNUSED_1 = 1, //. Because of the history we need to occupy a space
+ CACHE_FRAG_TYPE_RTSP = 2, ///< Should be removed once Cache Toolkit is implemented.
+ CACHE_FRAG_TYPE_HTTP = 3,
+ NUM_CACHE_FRAG_TYPES = 4
+};
+
+using CacheKey = CryptoHash;
+
+struct HttpCacheKey {
+ int hostlen;
+ const char *hostname;
+ CacheKey hash;
+ CacheKey hash2;
+};
+
+#define CACHE_ALLOW_MULTIPLE_WRITES 1
+#define CACHE_EXPECTED_SIZE 32768
+
+/* uses of the CacheKey
+ word(0) - cache partition segment
+ word(1) - cache partition bucket
+ word(2) - tag (lower bits), hosttable hash (upper bits)
+ word(3) - ram cache hash, lookaside cache
+ */
diff --git a/include/iocore/cache/CacheEvacuateDocVC.h b/include/iocore/cache/CacheEvacuateDocVC.h
new file mode 100644
index 0000000000..13cbc99cd9
--- /dev/null
+++ b/include/iocore/cache/CacheEvacuateDocVC.h
@@ -0,0 +1,72 @@
+/** @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 "P_CacheDir.h"
+*/
+
+#include "CacheVC.h"
+
+// eventsystem
+#include "Continuation.h"
+#include "EThread.h"
+#include "Event.h"
+#include "ProxyAllocator.h"
+
+// tscore
+#include "tscore/ink_assert.h"
+
+// ts
+#include "ts/DbgCtl.h"
+
+class CacheEvacuateDocVC : public CacheVC
+{
+public:
+ int evacuateDocDone(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */);
+ int evacuateReadHead(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */);
+};
+
+extern ClassAllocator<CacheEvacuateDocVC> cacheEvacuateDocVConnectionAllocator;
+
+inline CacheEvacuateDocVC *
+new_CacheEvacuateDocVC(Continuation *cont)
+{
+ EThread *t = cont->mutex->thread_holding;
+ CacheEvacuateDocVC *c = THREAD_ALLOC(cacheEvacuateDocVConnectionAllocator, t);
+ c->vector.data.data = &c->vector.data.fast_data[0];
+ c->_action = cont;
+ c->mutex = cont->mutex;
+ c->start_time = ink_get_hrtime();
+ c->setThreadAffinity(t);
+ ink_assert(c->trigger == nullptr);
+ static DbgCtl dbg_ctl{"cache_new"};
+ Dbg(dbg_ctl, "new %p", c);
+#ifdef CACHE_STAT_PAGES
+ ink_assert(!c->stat_link.next);
+ ink_assert(!c->stat_link.prev);
+#endif
+ dir_clear(&c->dir);
+ return c;
+}
diff --git a/include/iocore/cache/CacheVC.h b/include/iocore/cache/CacheVC.h
new file mode 100644
index 0000000000..fc9fd60a5f
--- /dev/null
+++ b/include/iocore/cache/CacheVC.h
@@ -0,0 +1,335 @@
+/** @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
+
+/*
+// inkcache
+#include "Cache.h"
+#include "P_CacheDir.h"
+#include "P_CacheVol.h"
+*/
+#include "P_CacheHttp.h"
+
+// aio
+#include "AIO.h"
+
+// inkevent
+#include "Action.h"
+#include "Continuation.h"
+#include "Event.h"
+#include "IOBuffer.h"
+#include "VIO.h"
+
+// tscore
+#include "tscore/ink_hrtime.h"
+#include "tscore/List.h"
+#include "tscore/Ptr.h"
+
+#include <cstdint>
+
+struct Vol;
+
+struct CacheVC : public CacheVConnection {
+ CacheVC();
+
+ VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
+ VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset) override;
+ VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override;
+ void do_io_close(int lerrno = -1) override;
+ void reenable(VIO *avio) override;
+ void reenable_re(VIO *avio) override;
+ bool get_data(int i, void *data) override;
+ bool set_data(int i, void *data) override;
+
+ bool
+ is_ram_cache_hit() const override
+ {
+ ink_assert(vio.op == VIO::READ);
+ return !f.not_from_ram_cache;
+ }
+
+ int
+ get_header(void **ptr, int *len) override
+ {
+ if (first_buf) {
+ Doc *doc = (Doc *)first_buf->data();
+ *ptr = doc->hdr();
+ *len = doc->hlen;
+ return 0;
+ }
+
+ return -1;
+ }
+
+ int
+ set_header(void *ptr, int len) override
+ {
+ header_to_write = ptr;
+ header_to_write_len = len;
+ return 0;
+ }
+
+ int
+ get_single_data(void **ptr, int *len) override
+ {
+ if (first_buf) {
+ Doc *doc = (Doc *)first_buf->data();
+ if (doc->data_len() == doc->total_len) {
+ *ptr = doc->data();
+ *len = doc->data_len();
+ return 0;
+ }
+ }
+
+ return -1;
+ }
+
+ int
+ get_volume_number() const override
+ {
+ if (vol && vol->cache_vol) {
+ return vol->cache_vol->vol_number;
+ }
+
+ return -1;
+ }
+
+ const char *
+ get_disk_path() const override
+ {
+ if (vol && vol->disk) {
+ return vol->disk->path;
+ }
+
+ return nullptr;
+ }
+
+ bool
+ is_compressed_in_ram() const override
+ {
+ ink_assert(vio.op == VIO::READ);
+ return f.compressed_in_ram;
+ }
+
+ bool writer_done();
+ int calluser(int event);
+ int callcont(int event);
+ int die();
+ int dead(int event, Event *e);
+
+ int handleReadDone(int event, Event *e);
+ int handleRead(int event, Event *e);
+ int do_read_call(CacheKey *akey);
+ int handleWrite(int event, Event *e);
+ int handleWriteLock(int event, Event *e);
+ int do_write_call();
+ int do_write_lock();
+ int do_write_lock_call();
+ int do_sync(uint32_t target_write_serial);
+
+ int openReadClose(int event, Event *e);
+ int openReadReadDone(int event, Event *e);
+ int openReadMain(int event, Event *e);
+ int openReadStartEarliest(int event, Event *e);
+ int openReadVecWrite(int event, Event *e);
+ int openReadStartHead(int event, Event *e);
+ int openReadFromWriter(int event, Event *e);
+ int openReadFromWriterMain(int event, Event *e);
+ int openReadFromWriterFailure(int event, Event *);
+ int openReadChooseWriter(int event, Event *e);
+ int openReadDirDelete(int event, Event *e);
+
+ int openWriteCloseDir(int event, Event *e);
+ int openWriteCloseHeadDone(int event, Event *e);
+ int openWriteCloseHead(int event, Event *e);
+ int openWriteCloseDataDone(int event, Event *e);
+ int openWriteClose(int event, Event *e);
+ int openWriteRemoveVector(int event, Event *e);
+ int openWriteWriteDone(int event, Event *e);
+ int openWriteOverwrite(int event, Event *e);
+ int openWriteMain(int event, Event *e);
+ int openWriteStartDone(int event, Event *e);
+ int openWriteStartBegin(int event, Event *e);
+
+ int updateVector(int event, Event *e);
+ int updateReadDone(int event, Event *e);
+ int updateVecWrite(int event, Event *e);
+
+ int removeEvent(int event, Event *e);
+
+ int scanVol(int event, Event *e);
+ int scanObject(int event, Event *e);
+ int scanUpdateDone(int event, Event *e);
+ int scanOpenWrite(int event, Event *e);
+ int scanRemoveDone(int event, Event *e);
+
+ int
+ is_io_in_progress()
+ {
+ return io.aiocb.aio_fildes != AIO_NOT_IN_PROGRESS;
+ }
+ void
+ set_io_not_in_progress()
+ {
+ io.aiocb.aio_fildes = AIO_NOT_IN_PROGRESS;
+ }
+ void
+ set_agg_write_in_progress()
+ {
+ io.aiocb.aio_fildes = AIO_AGG_WRITE_IN_PROGRESS;
+ }
+
+ void cancel_trigger();
+ int64_t get_object_size() override;
+ void set_http_info(CacheHTTPInfo *info) override;
+ void get_http_info(CacheHTTPInfo **info) override;
+ /** Get the fragment table.
+ @return The address of the start of the fragment table,
+ or @c nullptr if there is no fragment table.
+ */
+ virtual HTTPInfo::FragOffset *get_frag_table();
+ /** Load alt pointers and do fixups if needed.
+ @return Length of header data used for alternates.
+ */
+ virtual uint32_t load_http_info(CacheHTTPInfoVector *info, struct Doc *doc, RefCountObj *block_ptr = nullptr);
+ bool is_pread_capable() override;
+ bool set_pin_in_cache(time_t time_pin) override;
+ time_t get_pin_in_cache() override;
+
+ // number of bytes to memset to 0 in the CacheVC when we free
+ // it. All member variables starting from vio are memset to 0.
+ // This variable is initialized in CacheVC constructor.
+ static int size_to_init;
+
+ // Start Region A
+ // This set of variables are not reset when the cacheVC is freed.
+ // A CacheVC must set these to the correct values whenever needed
+ // These are variables that are always set to the correct values
+ // before being used by the CacheVC
+ CacheKey key, first_key, earliest_key, update_key;
+ Dir dir, earliest_dir, overwrite_dir, first_dir;
+ // end Region A
+
+ // Start Region B
+ // These variables are individually cleared or reset when the
+ // CacheVC is freed. All these variables must be reset/cleared
+ // in free_CacheVC.
+ Action _action;
+ CacheHTTPHdr request;
+ CacheHTTPInfoVector vector;
+ CacheHTTPInfo alternate;
+ Ptr<IOBufferData> buf;
+ Ptr<IOBufferData> first_buf;
+ Ptr<IOBufferBlock> blocks; // data available to write
+ Ptr<IOBufferBlock> writer_buf;
+
+ OpenDirEntry *od = nullptr;
+ AIOCallbackInternal io;
+ int alternate_index = CACHE_ALT_INDEX_DEFAULT; // preferred position in vector
+ LINK(CacheVC, opendir_link);
+#ifdef CACHE_STAT_PAGES
+ LINK(CacheVC, stat_link);
+#endif
+ // end Region B
+
+ // Start Region C
+ // These variables are memset to 0 when the structure is freed.
+ // The size of this region is size_to_init which is initialized
+ // in the CacheVC constructor. It assumes that vio is the start
+ // of this region.
+ // NOTE: NOTE: NOTE: If vio is NOT the start, then CHANGE the
+ // size_to_init initialization
+ VIO vio;
+ CacheFragType frag_type;
+ CacheHTTPInfo *info;
+ CacheHTTPInfoVector *write_vector;
+ const OverridableHttpConfigParams *params;
+ int header_len; // for communicating with agg_copy
+ int frag_len; // for communicating with agg_copy
+ uint32_t write_len; // for communicating with agg_copy
+ uint32_t agg_len; // for communicating with aggWrite
+ uint32_t write_serial; // serial of the final write for SYNC
+ Vol *vol;
+ Dir *last_collision;
+ Event *trigger;
+ CacheKey *read_key;
+ ContinuationHandler save_handler;
+ time_t pin_in_cache;
+ ink_hrtime start_time;
+ int op_type; // Index into the metrics array for this operation, rather than a CacheOpType (fewer casts)
+ int recursive;
+ int closed;
+ uint64_t seek_to; // pread offset
+ int64_t offset; // offset into 'blocks' of data to write
+ int64_t writer_offset; // offset of the writer for reading from a writer
+ int64_t length; // length of data available to write
+ int64_t doc_pos; // read position in 'buf'
+ uint64_t write_pos; // length written
+ uint64_t total_len; // total length written and available to write
+ uint64_t doc_len; // total_length (of the selected alternate for HTTP)
+ uint64_t update_len;
+ int fragment;
+ int scan_msec_delay;
+ CacheVC *write_vc;
+ char *hostname;
+ int host_len;
+ int header_to_write_len;
+ void *header_to_write;
+ short writer_lock_retry;
+ union {
+ uint32_t flags;
+ struct {
+ unsigned int use_first_key : 1;
+ unsigned int overwrite : 1; // overwrite first_key Dir if it exists
+ unsigned int close_complete : 1; // WRITE_COMPLETE is final
+ unsigned int sync : 1; // write to be committed to durable storage before WRITE_COMPLETE
+ unsigned int evacuator : 1;
+ unsigned int single_fragment : 1;
+ unsigned int evac_vector : 1;
+ unsigned int lookup : 1;
+ unsigned int update : 1;
+ unsigned int remove : 1;
+ unsigned int remove_aborted_writers : 1;
+ unsigned int open_read_timeout : 1; // UNUSED
+ unsigned int data_done : 1;
+ unsigned int read_from_writer_called : 1;
+ unsigned int not_from_ram_cache : 1; // entire object was from ram cache
+ unsigned int rewrite_resident_alt : 1;
+ unsigned int readers : 1;
+ unsigned int doc_from_ram_cache : 1;
+ unsigned int hit_evacuate : 1;
+ unsigned int compressed_in_ram : 1; // compressed state in ram cache
+ unsigned int allow_empty_doc : 1; // used for cache empty http document
+ } f;
+ };
+ // BTF optimization used to skip reading stuff in cache partition that doesn't contain any
+ // dir entries.
+ char *scan_vol_map;
+ // BTF fix to handle objects that overlapped over two different reads,
+ // this is how much we need to back up the buffer to get the start of the overlapping object.
+ off_t scan_fix_buffer_offset;
+ // end region C
+};
+
+LINK_DEFINITION(CacheVC, opendir_link)
diff --git a/iocore/cache/HttpTransactCache.h b/include/iocore/cache/HttpTransactCache.h
similarity index 100%
rename from iocore/cache/HttpTransactCache.h
rename to include/iocore/cache/HttpTransactCache.h
diff --git a/iocore/cache/I_Store.h b/include/iocore/cache/Store.h
similarity index 100%
rename from iocore/cache/I_Store.h
rename to include/iocore/cache/Store.h
diff --git a/include/iocore/dns/DNS.h b/include/iocore/dns/DNS.h
new file mode 100644
index 0000000000..b34fa61713
--- /dev/null
+++ b/include/iocore/dns/DNS.h
@@ -0,0 +1,36 @@
+/** @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.
+ */
+
+/****************************************************************************
+
+ DNS.h
+
+
+ ****************************************************************************/
+
+#pragma once
+
+#include "EventSystem.h"
+#include "HostDB.h"
+#include "Net.h"
+#include "DNSProcessor.h"
diff --git a/iocore/dns/DNSEventIO.h b/include/iocore/dns/DNSEventIO.h
similarity index 100%
rename from iocore/dns/DNSEventIO.h
rename to include/iocore/dns/DNSEventIO.h
diff --git a/include/iocore/dns/DNSProcessor.h b/include/iocore/dns/DNSProcessor.h
new file mode 100644
index 0000000000..5f455dda40
--- /dev/null
+++ b/include/iocore/dns/DNSProcessor.h
@@ -0,0 +1,231 @@
+/** @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 "tscore/ink_resolver.h"
+#include "EventSystem.h"
+#include "SRV.h"
+
+// Events
+#define DNS_EVENT_LOOKUP DNS_EVENT_EVENTS_START
+
+const int DOMAIN_SERVICE_PORT = NAMESERVER_PORT;
+
+const int MAX_DNS_REQUEST_LEN = NS_PACKETSZ;
+const int MAX_DNS_RESPONSE_LEN = 65536;
+const int DNS_RR_MAX_COUNT = (MAX_DNS_RESPONSE_LEN - HFIXEDSZ + RRFIXEDSZ - 1) / RRFIXEDSZ;
+const int DNS_MAX_ALIASES = DNS_RR_MAX_COUNT;
+const int DNS_MAX_ADDRS = DNS_RR_MAX_COUNT;
+const int DNS_HOSTBUF_SIZE = MAX_DNS_RESPONSE_LEN;
+
+/**
+ All buffering required to handle a DNS receipt. For asynchronous DNS,
+ only one HostEntBuf will exist in the system. For synchronous DNS,
+ one will exist per call until the user deletes them.
+
+*/
+struct HostEnt : RefCountObj {
+ struct hostent ent = {.h_name = nullptr, .h_aliases = nullptr, .h_addrtype = 0, .h_length = 0, .h_addr_list = nullptr};
+ uint32_t ttl = 0;
+ int packet_size = 0;
+ char buf[MAX_DNS_RESPONSE_LEN] = {0};
+ u_char *host_aliases[DNS_MAX_ALIASES] = {nullptr};
+ u_char *h_addr_ptrs[DNS_MAX_ADDRS + 1] = {nullptr};
+ u_char hostbuf[DNS_HOSTBUF_SIZE] = {0};
+ SRVHosts srv_hosts;
+ bool good = true;
+ bool isNameError();
+ void free() override;
+};
+
+extern EventType ET_DNS;
+
+struct DNSHandler;
+
+/** Data for a DNS query.
+ * This is either a name for a standard query or an IP address for reverse DNS.
+ * Its type should be indicated by other parameters, generally the query type.
+ * - T_PTR: IP Address
+ * - T_A, T_SRV: Name
+ */
+union DNSQueryData {
+ std::string_view name; ///< Look up a name.
+ IpAddr const *addr; ///< Reverse DNS lookup.
+
+ DNSQueryData(std::string_view tv) : name(tv) {}
+ DNSQueryData(IpAddr const *a) : addr(a) {}
+};
+
+struct DNSProcessor : public Processor {
+ // Public Interface
+ //
+
+ /// Options for host name resolution.
+ struct Options {
+ using self_type = Options; ///< Self reference type.
+
+ /// Query handler to use.
+ /// Default: single threaded handler.
+ DNSHandler *handler = nullptr;
+ /// Query timeout value.
+ /// Default: @c DEFAULT_DNS_TIMEOUT (or as set in records.yaml)
+ int timeout = 0; ///< Timeout value for request.
+ /// Host resolution style.
+ /// Default: IPv4, IPv6 ( @c HOST_RES_IPV4 )
+ HostResStyle host_res_style = HOST_RES_IPV4;
+
+ /// Default constructor.
+ Options();
+
+ /// Set @a handler option.
+ /// @return This object.
+ self_type &setHandler(DNSHandler *handler);
+
+ /// Set @a timeout option.
+ /// @return This object.
+ self_type &setTimeout(int timeout);
+
+ /// Set host query @a style option.
+ /// @return This object.
+ self_type &setHostResStyle(HostResStyle style);
+
+ /// Reset to default constructed values.
+ /// @return This object.
+ self_type &reset();
+ };
+
+ // DNS lookup
+ // calls: cont->handleEvent( DNS_EVENT_LOOKUP, HostEnt *ent) on success
+ // cont->handleEvent( DNS_EVENT_LOOKUP, nullptr) on failure
+ // NOTE: the HostEnt *block is freed when the function returns
+ //
+
+ Action *gethostbyname(Continuation *cont, const char *name, Options const &opt);
+ Action *gethostbyname(Continuation *cont, std::string_view name, Options const &opt);
+ Action *getSRVbyname(Continuation *cont, const char *name, Options const &opt);
+ Action *getSRVbyname(Continuation *cont, std::string_view name, Options const &opt);
+ Action *gethostbyaddr(Continuation *cont, IpAddr const *ip, Options const &opt);
+
+ // Processor API
+ //
+ /* currently dns system uses event threads
+ * dont pass any value to the call */
+ int start(int no_of_extra_dns_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+ // Open/close a link to a 'named' (done in start())
+ //
+ void open(sockaddr const *ns = nullptr);
+
+ DNSProcessor();
+
+ // private:
+ //
+ EThread *thread = nullptr;
+ DNSHandler *handler = nullptr;
+ ts_imp_res_state l_res;
+ IpEndpoint local_ipv6;
+ IpEndpoint local_ipv4;
+
+ /** Internal implementation for all getXbyY methods.
+ For host resolution queries pass @c T_A for @a type. It will be adjusted
+ as needed based on @a opt.host_res_style.
+
+ For address resolution ( @a type is @c T_PTR ), @a x should be a
+ @c sockaddr cast to @c char @c const* .
+ */
+ Action *getby(DNSQueryData x, int type, Continuation *cont, Options const &opt);
+
+ void dns_init();
+};
+
+//
+// Global data
+//
+extern DNSProcessor dnsProcessor;
+
+//
+// Inline Functions
+//
+
+inline Action *
+DNSProcessor::getSRVbyname(Continuation *cont, const char *name, Options const &opt)
+{
+ return getby(std::string_view(name), T_SRV, cont, opt);
+}
+
+inline Action *
+DNSProcessor::getSRVbyname(Continuation *cont, std::string_view name, Options const &opt)
+{
+ return getby(name, T_SRV, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyname(Continuation *cont, const char *name, Options const &opt)
+{
+ return getby(std::string_view(name), T_A, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyname(Continuation *cont, std::string_view name, Options const &opt)
+{
+ return getby(name, T_A, cont, opt);
+}
+
+inline Action *
+DNSProcessor::gethostbyaddr(Continuation *cont, IpAddr const *addr, Options const &opt)
+{
+ return getby(addr, T_PTR, cont, opt);
+}
+
+inline DNSProcessor::Options::Options() {}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setHandler(DNSHandler *h)
+{
+ handler = h;
+ return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setTimeout(int t)
+{
+ timeout = t;
+ return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::setHostResStyle(HostResStyle style)
+{
+ host_res_style = style;
+ return *this;
+}
+
+inline DNSProcessor::Options &
+DNSProcessor::Options::reset()
+{
+ *this = Options();
+ return *this;
+}
+
+void ink_dns_init(ts::ModuleVersion version);
diff --git a/iocore/dns/SRV.h b/include/iocore/dns/SRV.h
similarity index 100%
rename from iocore/dns/SRV.h
rename to include/iocore/dns/SRV.h
diff --git a/include/iocore/dns/SplitDNS.h b/include/iocore/dns/SplitDNS.h
new file mode 100644
index 0000000000..d5ef0a0ba1
--- /dev/null
+++ b/include/iocore/dns/SplitDNS.h
@@ -0,0 +1,36 @@
+/** @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.
+ */
+
+/*****************************************************************************
+ *
+ * I_SplitDNS.h - Interface to DNS server selection
+ *
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include "SplitDNSProcessor.h"
+#include "tscore/Version.h"
+
+static constexpr ts::ModuleVersion SPLITDNS_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
diff --git a/iocore/dns/I_SplitDNSProcessor.h b/include/iocore/dns/SplitDNSProcessor.h
similarity index 100%
rename from iocore/dns/I_SplitDNSProcessor.h
rename to include/iocore/dns/SplitDNSProcessor.h
diff --git a/include/iocore/eventsystem/Action.h b/include/iocore/eventsystem/Action.h
new file mode 100644
index 0000000000..666c1c7de4
--- /dev/null
+++ b/include/iocore/eventsystem/Action.h
@@ -0,0 +1,196 @@
+/** @file
+
+ Generic interface which enables any event or async activity to be cancelled
+
+ @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 "tscore/ink_platform.h"
+#include "Thread.h"
+#include "Continuation.h"
+
+/**
+ Represents an operation initiated on a Processor.
+
+ The Action class is an abstract representation of an operation
+ being executed by some Processor. A reference to an Action object
+ allows you to cancel an ongoing asynchronous operation before it
+ completes. This means that the Continuation specified for the
+ operation will not be called back.
+
+ Actions or classes derived from Action are the typical return
+ type of methods exposed by Processors in the Event System and
+ throughout the IO Core libraries.
+
+ The canceller of an action must be the state machine that will
+ be called back by the task and that state machine's lock must be
+ held while calling cancel.
+
+ Processor implementers:
+
+ You must ensure that no events are sent to the state machine after
+ the operation has been cancelled appropriately.
+
+ Returning an Action:
+
+ Processor functions that are asynchronous must return actions to
+ allow the calling state machine to cancel the task before completion.
+ Because some processor functions are reentrant, they can call
+ back the state machine before the returning from the call that
+ creates the actions. To handle this case, special values are
+ returned in place of an action to indicate to the state machine
+ that the action is already completed.
+
+ - @b ACTION_RESULT_DONE The processor has completed the task
+ and called the state machine back inline.
+ - @b ACTION_RESULT_INLINE Not currently used.
+ - @b ACTION_RESULT_IO_ERROR Not currently used.
+
+ To make matters more complicated, it's possible if the result is
+ ACTION_RESULT_DONE that state machine deallocated itself on the
+ reentrant callback. Thus, state machine implementers MUST either
+ use a scheme to never deallocate their machines on reentrant
+ callbacks OR immediately check the returned action when creating
+ an asynchronous task and if it is ACTION_RESULT_DONE neither read
+ nor write any state variables. With either method, it's imperative
+ that the returned action always be checked for special values and
+ the value handled accordingly.
+
+ Allocation policy:
+
+ Actions are allocated by the Processor performing the actions.
+ It is the processor's responsibility to handle deallocation once
+ the action is complete or cancelled. A state machine MUST NOT
+ access an action once the operation that returned the Action has
+ completed or it has cancelled the Action.
+
+ Action pointer sanity checks must also check whether the lowest
+ bit of the pointer is 1. If it is 1, then the value must not be
+ treated as a pointer, and should be used as one of the values
+ defined below (e.g. ACTION_RESULT_DONE).
+
+*/
+class Action
+{
+public:
+ /**
+ Continuation that initiated this action.
+
+ The reference to the initiating continuation is only used to
+ verify that the action is being cancelled by the correct
+ continuation. This field should not be accessed or modified
+ directly by the state machine.
+
+ */
+ Continuation *continuation = nullptr;
+
+ /**
+ Reference to the Continuation's lock.
+
+ Keeps a reference to the Continuation's lock to preserve the
+ access to the cancelled field valid even when the state machine
+ has been deallocated. This field should not be accessed or
+ modified directly by the state machine.
+
+ */
+ Ptr<ProxyMutex> mutex;
+
+ /**
+ Internal flag used to indicate whether the action has been
+ cancelled.
+
+ This flag is set after a call to cancel or cancel_action and
+ it should not be accessed or modified directly by the state
+ machine.
+
+ */
+ bool cancelled = false;
+
+ /**
+ Cancels the asynchronous operation represented by this action.
+
+ This method is called by state machines willing to cancel an
+ ongoing asynchronous operation. Classes derived from Action may
+ perform additional steps before flagging this action as cancelled.
+ There are certain rules that must be followed in order to cancel
+ an action (see the Remarks section).
+
+ @param c Continuation associated with this Action.
+
+ */
+ virtual void
+ cancel(Continuation *c = nullptr)
+ {
+ ink_assert(!c || c == continuation);
+ ink_assert(!cancelled);
+ cancelled = true;
+ }
+
+ /**
+ Cancels the asynchronous operation represented by this action.
+
+ This method is called by state machines willing to cancel an
+ ongoing asynchronous operation. There are certain rules that
+ must be followed in order to cancel an action (see the Remarks
+ section).
+
+ @param c Continuation associated with this Action.
+
+ */
+ void
+ cancel_action(Continuation *c = nullptr)
+ {
+ ink_assert(!c || c == continuation);
+ ink_assert(!cancelled);
+ cancelled = true;
+ }
+
+ Continuation *
+ operator=(Continuation *acont)
+ {
+ continuation = acont;
+ if (acont) {
+ mutex = acont->mutex;
+ } else {
+ mutex = nullptr;
+ }
+ return acont;
+ }
+
+ /**
+ Constructor of the Action object. Processor implementers are
+ responsible for associating this action with the proper
+ Continuation.
+
+ */
+ Action() {}
+ virtual ~Action() {}
+};
+
+#define ACTION_RESULT_DONE MAKE_ACTION_RESULT(1)
+#define ACTION_IO_ERROR MAKE_ACTION_RESULT(2)
+
+// Use these classes by
+// #define ACTION_RESULT_HOST_DB_OFFLINE
+// MAKE_ACTION_RESULT(ACTION_RESULT_HOST_DB_BASE + 0)
+
+#define MAKE_ACTION_RESULT(_x) (Action *)(((uintptr_t)((_x << 1) + 1)))
diff --git a/include/iocore/eventsystem/ConfigProcessor.h b/include/iocore/eventsystem/ConfigProcessor.h
new file mode 100644
index 0000000000..ea6d33abf1
--- /dev/null
+++ b/include/iocore/eventsystem/ConfigProcessor.h
@@ -0,0 +1,117 @@
+/** @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 <atomic>
+
+#include "Tasks.h"
+
+class ProxyMutex;
+
+#define MAX_CONFIGS 100
+
+using ConfigInfo = RefCountObj;
+
+class ConfigProcessor
+{
+public:
+ ConfigProcessor() = default;
+
+ enum {
+ // The number of seconds to wait before garbage collecting stale ConfigInfo objects. There's
+ // no good reason to tune this, outside of regression tests, so don't.
+ CONFIG_PROCESSOR_RELEASE_SECS = 60
+ };
+
+ template <typename ClassType, typename ConfigType> struct scoped_config {
+ scoped_config() : ptr(ClassType::acquire()) {}
+ ~scoped_config() { ClassType::release(ptr); }
+ operator bool() const { return ptr != nullptr; }
+ operator const ConfigType *() const { return ptr; }
+ const ConfigType *
+ operator->() const
+ {
+ return ptr;
+ }
+
+ private:
+ ConfigType *ptr;
+ };
+
+ unsigned int set(unsigned int id, ConfigInfo *info, unsigned timeout_secs = CONFIG_PROCESSOR_RELEASE_SECS);
+ ConfigInfo *get(unsigned int id);
+ void release(unsigned int id, ConfigInfo *data);
+
+public:
+ std::atomic<ConfigInfo *> infos[MAX_CONFIGS] = {nullptr};
+ std::atomic<int> ninfos{0};
+};
+
+// A Continuation wrapper that calls the static reconfigure() method of the given class.
+template <typename UpdateClass> struct ConfigUpdateContinuation : public Continuation {
+ int
+ update(int /* etype */, void * /* data */)
+ {
+ UpdateClass::reconfigure();
+ delete this;
+ return EVENT_DONE;
+ }
+
+ ConfigUpdateContinuation(Ptr<ProxyMutex> &m) : Continuation(m.get()) { SET_HANDLER(&ConfigUpdateContinuation::update); }
+};
+
+template <typename UpdateClass>
+int
+ConfigScheduleUpdate(Ptr<ProxyMutex> &mutex)
+{
+ eventProcessor.schedule_imm(new ConfigUpdateContinuation<UpdateClass>(mutex), ET_TASK);
+ return 0;
+}
+
+template <typename UpdateClass> struct ConfigUpdateHandler {
+ ConfigUpdateHandler() : mutex(new_ProxyMutex()) {}
+ // The mutex member is ref-counted so should not explicitly free it
+ ~ConfigUpdateHandler() {}
+ int
+ attach(const char *name)
+ {
+ return REC_RegisterConfigUpdateFunc(name, ConfigUpdateHandler::update, this);
+ }
+
+private:
+ static int
+ update(const char *name, RecDataT /* data_type ATS_UNUSED */, RecData /* data ATS_UNUSED */, void *cookie)
+ {
+ ConfigUpdateHandler *self = static_cast<ConfigUpdateHandler *>(cookie);
+
+ Dbg(_dbg_ctl, "%s(%s)", __PRETTY_FUNCTION__, name);
+ return ConfigScheduleUpdate<UpdateClass>(self->mutex);
+ }
+
+ Ptr<ProxyMutex> mutex;
+
+ inline static DbgCtl _dbg_ctl{"config"};
+};
+
+extern ConfigProcessor configProcessor;
diff --git a/include/iocore/eventsystem/Continuation.h b/include/iocore/eventsystem/Continuation.h
new file mode 100644
index 0000000000..984819e357
--- /dev/null
+++ b/include/iocore/eventsystem/Continuation.h
@@ -0,0 +1,281 @@
+/** @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.
+
+ @section details Details
+
+ Continuations have a handleEvent() method to invoke them. Users
+ can determine the behavior of a Continuation by supplying a
+ "ContinuationHandler" (member function name) which is invoked
+ when events arrive. This function can be changed with the
+ "setHandler" method.
+
+ Continuations can be subclassed to add additional state and
+ methods.
+
+ */
+
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "tscore/List.h"
+#include "Lock.h"
+#include "tscore/ContFlags.h"
+
+class Continuation;
+class ContinuationQueue;
+class Processor;
+class ProxyMutex;
+class EThread;
+class Event;
+
+extern EThread *this_ethread();
+extern EThread *this_event_thread();
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Constants and Type Definitions
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#define CONTINUATION_EVENT_NONE 0
+
+#define CONTINUATION_DONE 0
+#define CONTINUATION_CONT 1
+
+using ContinuationHandler = int (Continuation::*)(int, void *);
+
+// Convert event handler pointer fp to type ContinuationHandler, but with a compiler error if class C is not
+// derived from the class Continuation.
+//
+template <class C, typename T>
+constexpr ContinuationHandler
+continuation_handler_void_ptr(int (C::*fp)(int, T *))
+{
+ auto fp2 = reinterpret_cast<int (C::*)(int, void *)>(fp);
+
+ // We keep this a static_cast for added static type analysis from the
+ // compiler. If a compiler warning is generated for the following line of
+ // code of the type "-Werror=shift-negative-value", then this may be an issue
+ // with multiple inheritance of the C templated type. Make sure that for type
+ // C the Continuation parent is listed first (either directly or indirectly
+ // via the inheritance tree) before any other parent in the multiple class
+ // hierarchy of C.
+ return static_cast<ContinuationHandler>(fp2);
+}
+
+// Overload for nullptr.
+//
+constexpr ContinuationHandler
+continuation_handler_void_ptr(std::nullptr_t)
+{
+#undef X
+#if !defined(__GNUC__)
+#define X 1
+#else
+#define X (__GNUC__ > 7)
+#endif
+#if X
+ static_assert(!static_cast<ContinuationHandler>(nullptr));
+#endif
+#undef X
+
+ return static_cast<ContinuationHandler>(nullptr);
+}
+
+class force_VFPT_to_top
+{
+public:
+ virtual ~force_VFPT_to_top() {}
+};
+
+/**
+ Base class for all state machines to receive notification of
+ events.
+
+ The Continuation class represents the main abstraction mechanism
+ used throughout the IO Core Event System to communicate its users
+ the occurrence of an event. A Continuation is a lightweight data
+ structure that implements a single method with which the user is
+ called back.
+
+ Continuations are typically subclassed in order to implement
+ event-driven state machines. By including additional state and
+ methods, continuations can combine state with control flow, and
+ they are generally used to support split-phase, event-driven
+ control flow.
+
+ Given the multithreaded nature of the Event System, every
+ continuation carries a reference to a ProxyMutex object to protect
+ its state and ensure atomic operations. This ProxyMutex object
+ must be allocated by continuation-derived classes or by clients
+ of the IO Core Event System and it is required as a parameter to
+ the Continuation's class constructor.
+
+*/
+
+class Continuation : private force_VFPT_to_top
+{
+public:
+ /**
+ The current continuation handler function.
+
+ The current handler should not be set directly. In order to
+ change it, first acquire the Continuation's lock and then use
+ the SET_HANDLER macro which takes care of the type casting
+ issues.
+
+ */
+ ContinuationHandler handler = nullptr;
+
+#ifdef DEBUG
+ const char *handler_name = nullptr;
+#endif
+
+ /**
+ The Continuation's lock.
+
+ A reference counted pointer to the Continuation's lock. This
+ lock is initialized in the constructor and should not be set
+ directly.
+
+ TODO: make this private.
+
+ */
+ Ptr<ProxyMutex> mutex;
+
+ ProxyMutex *
+ getMutex() const
+ {
+ return mutex.get();
+ }
+
+ /**
+ Link to other continuations.
+
+ A doubly-linked element to allow Lists of Continuations to be
+ assembled.
+
+ */
+ LINK(Continuation, link);
+
+ /**
+ Contains values for debug_override and future flags that
+ needs to be thread local while this continuation is running
+ */
+ ContFlags control_flags;
+
+ EThread *thread_affinity = nullptr;
+
+ bool
+ setThreadAffinity(EThread *ethread)
+ {
+ if (ethread != nullptr) {
+ thread_affinity = ethread;
+ return true;
+ }
+ return false;
+ }
+
+ EThread *
+ getThreadAffinity()
+ {
+ return thread_affinity;
+ }
+
+ void
+ clearThreadAffinity()
+ {
+ thread_affinity = nullptr;
+ }
+
+ /**
+ Receives the event code and data for an Event.
+
+ This function receives the event code and data for an event and
+ forwards them to the current continuation handler. The processor
+ calling back the continuation is responsible for acquiring its
+ lock. If the lock is present and not held, this method will assert.
+
+ @param event Event code to be passed at callback (Processor specific).
+ @param data General purpose data related to the event code (Processor specific).
+ @return State machine and processor specific return code.
+
+ */
+ TS_INLINE int
+ handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = nullptr)
+ {
+ // If there is a lock, we must be holding it on entry
+ ink_release_assert(!mutex || mutex->thread_holding == this_ethread());
+ return (this->*handler)(event, data);
+ }
+
+protected:
+ /**
+ Constructor of the Continuation object. It should not be used
+ directly. Instead create an object of a derived type.
+
+ @param amutex Lock to be set for this Continuation.
+
+ */
+ explicit Continuation(ProxyMutex *amutex = nullptr);
+ explicit Continuation(Ptr<ProxyMutex> &amutex);
+};
+
+/**
+ Sets the Continuation's handler. The preferred mechanism for
+ setting the Continuation's handler.
+
+ @param _h Pointer to the function used to callback with events.
+
+*/
+#ifdef DEBUG
+#define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h), handler_name = #_h)
+#else
+#define SET_HANDLER(_h) (handler = continuation_handler_void_ptr(_h))
+#endif
+
+/**
+ Sets a Continuation's handler.
+
+ The preferred mechanism for setting the Continuation's handler.
+
+ @param _c Pointer to a Continuation whose handler is being set.
+ @param _h Pointer to the function used to callback with events.
+
+*/
+#ifdef DEBUG
+#define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h), _c->handler_name = #_h)
+#else
+#define SET_CONTINUATION_HANDLER(_c, _h) (_c->handler = continuation_handler_void_ptr(_h))
+#endif
+
+inline Continuation::Continuation(Ptr<ProxyMutex> &amutex) : mutex(amutex)
+{
+ // Pick up the control flags from the creating thread
+ this->control_flags.set_flags(get_cont_flags().get_flags());
+}
+
+inline Continuation::Continuation(ProxyMutex *amutex) : mutex(amutex)
+{
+ // Pick up the control flags from the creating thread
+ this->control_flags.set_flags(get_cont_flags().get_flags());
+}
diff --git a/include/iocore/eventsystem/EThread.h b/include/iocore/eventsystem/EThread.h
new file mode 100644
index 0000000000..e547656688
--- /dev/null
+++ b/include/iocore/eventsystem/EThread.h
@@ -0,0 +1,644 @@
+/** @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 "tscore/ink_platform.h"
+#include "tscore/ink_rand.h"
+#include "tscore/Version.h"
+#include "Thread.h"
+#include "PriorityEventQueue.h"
+#include "ProtectedQueue.h"
+#include "tscpp/util/Histogram.h"
+
+// TODO: This would be much nicer to have "run-time" configurable (or something)
+#define PER_THREAD_DATA (1024 * 1024)
+
+// This is not used by the cache anymore, it uses proxy.config.cache.mutex_retry_delay
+// instead.
+#define MUTEX_RETRY_DELAY HRTIME_MSECONDS(20)
+
+class DiskHandler;
+struct EventIO;
+
+class ServerSessionPool;
+class PreWarmQueue;
+
+class Event;
+class Continuation;
+class ConnectingPool;
+
+enum ThreadType {
+ REGULAR = 0,
+ DEDICATED,
+};
+
+/**
+ Event System specific type of thread.
+
+ The EThread class is the type of thread created and managed by
+ the Event System. It is one of the available interfaces for
+ scheduling events in the event system (another two are the Event
+ and EventProcessor classes).
+
+ In order to handle events, each EThread object has two event
+ queues, one external and one internal. The external queue is
+ provided for users of the EThread (clients) to append events to
+ that particular thread. Since it can be accessed by other threads
+ at the same time, operations using it must proceed in an atomic
+ fashion.
+
+ The internal queue, in the other hand, is used exclusively by the
+ EThread to process timed events within a certain time frame. These
+ events are queued internally and they may come from the external
+ queue as well.
+
+ Scheduling Interface:
+
+ There are eight scheduling functions provided by EThread and
+ they are a wrapper around their counterparts in EventProcessor.
+
+ @see EventProcessor
+ @see Event
+
+*/
+class EThread : public Thread
+{
+public:
+ static thread_local EThread *this_ethread_ptr;
+
+ /** Default wait interval for polling or delaying
+
+ This used to be known as net_config_poll_timeout, but was being used
+ (and externed) through the codebase so was causing problems with linking.
+
+ It is still configured as "proxy.config.net.poll_timeout" for now
+ */
+ static int default_wait_interval_ms;
+
+ /** Handler for tail of event loop.
+
+ The event loop should not spin. To avoid that a tail handler is called to block for a limited time.
+ This is a protocol class that defines the interface to the handler.
+ */
+ class LoopTailHandler
+ {
+ public:
+ /** Called at the end of the event loop to block.
+ @a timeout is the maximum length of time (in ns) to block.
+ */
+ virtual int waitForActivity(ink_hrtime timeout) = 0;
+ /** Unblock.
+
+ This is required to unblock (wake up) the block created by calling @a cb.
+ */
+ virtual void signalActivity() = 0;
+
+ virtual ~LoopTailHandler() {}
+ };
+
+ /*-------------------------------------------------------*\
+ | Common Interface |
+ \*-------------------------------------------------------*/
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ as soon as possible.
+
+ Forwards to the EventProcessor the schedule of the callback to
+ the continuation 'c' as soon as possible. The event is assigned
+ to EThread.
+
+ @param c Continuation to be called back as soon as possible.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return Reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_imm(Continuation *c, int callback_event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ at the given timeout.
+
+ Forwards the request to the EventProcessor to schedule the
+ callback to the continuation 'c' at the time specified in
+ 'atimeout_at'. The event is assigned to this EThread.
+
+ @param c Continuation to be called back at the time specified
+ in 'atimeout_at'.
+ @param atimeout_at Time value at which to callback.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_at(Continuation *c, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ after the timeout elapses.
+
+ Instructs the EventProcessor to schedule the callback to the
+ continuation 'c' after the time specified in atimeout_in elapses.
+ The event is assigned to this EThread.
+
+ @param c Continuation to be called back after the timeout elapses.
+ @param atimeout_in Amount of time after which to callback.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_in(Continuation *c, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ periodically.
+
+ Schedules the callback to the continuation 'c' in the EventProcessor
+ to occur every time 'aperiod' elapses. It is scheduled on this
+ EThread.
+
+ @param c Continuation to call back every time 'aperiod' elapses.
+ @param aperiod Duration of the time period between callbacks.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the Remarks section in the
+ EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_every(Continuation *c, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ as soon as possible.
+
+ Schedules the callback to the continuation 'c' as soon as
+ possible. The event is assigned to this EThread.
+
+ @param c Continuation to be called back as soon as possible.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_imm_local(Continuation *c, int callback_event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ at the given timeout.
+
+ Schedules the callback to the continuation 'c' at the time
+ specified in 'atimeout_at'. The event is assigned to this
+ EThread.
+
+ @param c Continuation to be called back at the time specified
+ in 'atimeout_at'.
+ @param atimeout_at Time value at which to callback.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_at_local(Continuation *c, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ after the timeout elapses.
+
+ Schedules the callback to the continuation 'c' after the time
+ specified in atimeout_in elapses. The event is assigned to this
+ EThread.
+
+ @param c Continuation to be called back after the timeout elapses.
+ @param atimeout_in Amount of time after which to callback.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the Remarks section in the
+ EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_in_local(Continuation *c, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on this EThread to receive an event
+ periodically.
+
+ Schedules the callback to the continuation 'c' to occur every
+ time 'aperiod' elapses. It is scheduled on this EThread.
+
+ @param c Continuation to call back every time 'aperiod' elapses.
+ @param aperiod Duration of the time period between callbacks.
+ @param callback_event Event code to be passed back to the
+ continuation's handler. See the Remarks section in the
+ EventProcessor class.
+ @param cookie User-defined value or pointer to be passed back
+ in the Event's object cookie field.
+ @return A reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_every_local(Continuation *c, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = nullptr);
+
+ /** Schedule an event called once when the thread is spawned.
+
+ This is useful only for regular threads and if called before @c Thread::start. The event will be
+ called first before the event loop.
+
+ @Note This will override the event for a dedicate thread so that this is called instead of the
+ event passed to the constructor.
+ */
+ Event *schedule_spawn(Continuation *c, int ev = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+ // Set the tail handler.
+ void set_tail_handler(LoopTailHandler *handler);
+
+ void set_specific() override;
+
+ /* private */
+
+ Event *schedule_local(Event *e);
+
+ InkRand generator = static_cast<uint64_t>(ink_get_hrtime() ^ reinterpret_cast<uintptr_t>(this));
+
+ /*-------------------------------------------------------*\
+ | UNIX Interface |
+ \*-------------------------------------------------------*/
+
+ EThread();
+ EThread(ThreadType att, int anid);
+ EThread(ThreadType att, Event *e);
+ EThread(const EThread &) = delete;
+ EThread &operator=(const EThread &) = delete;
+ ~EThread() override;
+
+ Event *schedule(Event *e);
+
+ /** Block of memory to allocate thread specific data e.g. stat system arrays. */
+ char thread_private[PER_THREAD_DATA];
+
+ /** Private Data for the Disk Processor. */
+ DiskHandler *diskHandler = nullptr;
+
+ /** Private Data for AIO. */
+ Que(Continuation, link) aio_ops;
+
+ ProtectedQueue EventQueueExternal;
+ PriorityEventQueue EventQueue;
+
+ static constexpr int NO_ETHREAD_ID = -1;
+ int id = NO_ETHREAD_ID;
+ unsigned int event_types = 0;
+ bool is_event_type(EventType et);
+ void set_event_type(EventType et);
+
+ // Private Interface
+
+ void execute() override;
+ void execute_regular();
+ void process_queue(Que(Event, link) * NegativeQueue, int *ev_count, int *nq_count);
+ void process_event(Event *e, int calling_code);
+ void free_event(Event *e);
+ LoopTailHandler *tail_cb = &DEFAULT_TAIL_HANDLER;
+
+#if HAVE_EVENTFD
+ int evfd = ts::NO_FD;
+#else
+ int evpipe[2];
+#endif
+ EventIO *ep = nullptr;
+
+ ThreadType tt = REGULAR;
+ /** Initial event to call, before any scheduling.
+
+ For dedicated threads this is the only event called.
+ For regular threads this is called first before the event loop starts.
+ @internal For regular threads this is used by the EventProcessor to get called back after
+ the thread starts but before any other events can be dispatched to provide initializations
+ needed for the thread.
+ */
+ Event *start_event = nullptr;
+
+ ServerSessionPool *server_session_pool = nullptr;
+ PreWarmQueue *prewarm_queue = nullptr;
+ ConnectingPool *connecting_pool = nullptr;
+
+ /** Default handler used until it is overridden.
+
+ This uses the cond var wait in @a ExternalQueue.
+ */
+ class DefaultTailHandler : public LoopTailHandler
+ {
+ explicit DefaultTailHandler(ProtectedQueue &q) : _q(q) {}
+
+ int
+ waitForActivity(ink_hrtime timeout) override
+ {
+ _q.wait(ink_get_hrtime() + timeout);
+ return 0;
+ }
+ void
+ signalActivity() override
+ {
+ /* Try to acquire the `EThread::lock` of the Event Thread:
+ * - Acquired, indicating that the Event Thread is sleep,
+ * must send a wakeup signal to the Event Thread.
+ * - Failed, indicating that the Event Thread is busy, do nothing.
+ */
+ (void)_q.try_signal();
+ }
+
+ ProtectedQueue &_q;
+
+ friend class EThread;
+ } DEFAULT_TAIL_HANDLER = DefaultTailHandler(EventQueueExternal);
+
+ struct Metrics {
+ using self_type = Metrics; ///< Self reference type.
+
+ /// Information about loops within the same time slice.
+ struct Slice {
+ using self_type = Slice;
+
+ /// Data for timing of the loop.
+ struct Duration {
+ ink_hrtime _start = 0; ///< The time of the first loop for this sample. Used to mark valid entries.
+ ink_hrtime _min = INT64_MAX; ///< Shortest loop time.
+ ink_hrtime _max = 0; ///< Longest loop time.
+ Duration() = default;
+ } _duration;
+
+ /// Events in the slice.
+ struct Events {
+ int _min = INT_MAX; ///< Minimum # of events in a loop.
+ int _max = 0; ///< Maximum # of events in a loop.
+ int _total = 0; ///< Total # of events.
+ Events() {}
+ } _events;
+
+ int _count = 0; ///< # of times the loop executed.
+ int _wait = 0; ///< # of timed wait for events
+
+ /** Record the loop start time.
+ *
+ * @param t Start time.
+ * @return @a this
+ */
+ self_type &record_loop_start(ink_hrtime t);
+
+ /** Record event loop duration.
+ *
+ * @param delta Duration of the loop.
+ * @return @a this.
+ */
+ self_type &record_loop_duration(ink_hrtime delta);
+
+ /** Record number of events in a loop.
+ *
+ * @param count Event count.
+ * @return
+ */
+ self_type &record_event_count(int count);
+
+ /// Add @a that to @a this data.
+ /// This embodies the custom logic per member concerning whether each is a sum, min, or max.
+ Slice &operator+=(Slice const &that);
+
+ /** Slice related statistics.
+ THE ORDER IS VERY SENSITIVE.
+ More than one part of the code depends on this exact order. Be careful and thorough when changing.
+ */
+ enum class STAT_ID {
+ LOOP_COUNT, ///< # of event loops executed.
+ LOOP_EVENTS, ///< # of events
+ LOOP_EVENTS_MIN, ///< min # of events dispatched in a loop
+ LOOP_EVENTS_MAX, ///< max # of events dispatched in a loop
+ LOOP_WAIT, ///< # of loops that did a conditional wait.
+ LOOP_TIME_MIN, ///< Shortest time spent in loop.
+ LOOP_TIME_MAX, ///< Longest time spent in loop.
+ };
+ /// Number of statistics for a slice.
+ static constexpr unsigned N_STAT_ID = unsigned(STAT_ID::LOOP_TIME_MAX) + 1;
+
+ /// Statistic name stems.
+ /// These will be qualified by time scale.
+ static char const *const STAT_NAME[N_STAT_ID];
+
+ Slice() = default;
+ };
+
+ /** The number of slices.
+ This is a circular buffer, with one slice per second. We have a bit more than the required 1000
+ to provide sufficient slop for cross thread reading of the data (as only the current slice
+ is being updated).
+ */
+ static constexpr int N_SLICES = 1024;
+ /// The slices.
+ std::array<Slice, N_SLICES> _slice;
+
+ Slice *volatile current_slice = nullptr; ///< The current slice.
+
+ /** The number of time scales used in the event statistics.
+ Currently these are 10s, 100s, 1000s.
+ */
+ static constexpr unsigned N_TIMESCALES = 3;
+
+ /// # of samples for each time scale.
+ static constexpr std::array<unsigned, 3> SLICE_SAMPLE_COUNT = {10, 100, 1000};
+
+ /// Total # of stats created for slice metrics.
+ static constexpr unsigned N_SLICE_STATS = Slice::N_STAT_ID * N_TIMESCALES;
+
+ /// Back up the metric pointer, wrapping as needed.
+ Slice *prev_slice(Slice *current);
+ /// Advance the metric pointer, wrapping as needed.
+ Slice *next_slice(Slice *current);
+
+ /** Record a loop time sample in the histogram.
+ *
+ * @param delta Loop time.
+ * @return @a this
+ */
+ self_type &record_loop_time(ink_hrtime delta);
+
+ /** Record total api sample in the histogram.
+ *
+ * @param delta Duration.
+ * @return @a this
+ */
+ self_type &record_api_time(ink_hrtime delta);
+
+ /// Do any accumulated data decay that's required.
+ self_type &decay();
+
+ /// Base name for event loop histogram stats.
+ /// The actual stats are determined by the @c Histogram properties.
+ static constexpr swoc::TextView LOOP_HISTOGRAM_STAT_STEM = "proxy.process.eventloop.time.";
+ /// Base bucket size for @c Graph
+ static constexpr ts_milliseconds LOOP_HISTOGRAM_BUCKET_SIZE{5};
+
+ /// Histogram type. 7,2 provides a reasonable range (5-2560 ms) and accuracy.
+ using Graph = ts::Histogram<7, 2>;
+ Graph _loop_timing; ///< Event loop timings.
+ /// Base name for event loop histogram stats.
+ /// The actual stats are determined by the @c Histogram properties.
+ static constexpr swoc::TextView API_HISTOGRAM_STAT_STEM = "proxy.process.api.time.";
+ /// Base bucket size in milliseconds for plugin API timings.
+ static constexpr ts_milliseconds API_HISTOGRAM_BUCKET_SIZE{1};
+ Graph _api_timing; ///< Plugin API callout timings.
+
+ /// Data in the histogram needs to decay over time. To avoid races and locks the
+ /// summarizing thread bumps this to indicate a decay is needed and doesn't update if
+ /// this is non-zero. The event loop does the decay and decrements the count.
+ std::atomic<unsigned> _decay_count = 0;
+ /// Decay this often.
+ static inline std::chrono::duration _decay_delay = std::chrono::seconds{90};
+ /// Time of last decay.
+ static inline ts_clock::time_point _last_decay_time;
+
+ /// Total number of metric based statistics.
+ static constexpr unsigned N_STATS = N_SLICE_STATS + 2 * Graph::N_BUCKETS;
+
+ /// Summarize this instance into a global instance.
+ void summarize(self_type &global);
+ };
+
+ Metrics metrics;
+};
+
+// --- Inline implementation
+
+inline auto
+EThread::Metrics::Slice::record_loop_start(ink_hrtime t) -> self_type &
+{
+ _duration._start = t;
+ return *this;
+}
+
+inline auto
+EThread::Metrics::Slice::record_loop_duration(ink_hrtime delta) -> self_type &
+{
+ if (delta > _duration._max) {
+ _duration._max = delta;
+ }
+ if (delta < _duration._min) {
+ _duration._min = delta;
+ }
+ return *this;
+}
+
+inline auto
+EThread::Metrics::Slice::record_event_count(int count) -> self_type &
+{
+ if (count < _events._min) {
+ _events._min = count;
+ }
+ if (count > _events._max) {
+ _events._max = _count;
+ }
+ _events._total += count;
+ return *this;
+}
+
+inline EThread::Metrics::Slice *
+EThread::Metrics::prev_slice(EThread::Metrics::Slice *current)
+{
+ return --current < _slice.data() ? &_slice[N_SLICES - 1] : current;
+}
+
+inline EThread::Metrics::Slice *
+EThread::Metrics::next_slice(EThread::Metrics::Slice *current)
+{
+ return ++current > &_slice[N_SLICES - 1] ? _slice.data() : current;
+}
+
+inline auto
+EThread::Metrics::record_loop_time(ink_hrtime delta) -> self_type &
+{
+ static auto constexpr DIVISOR = std::chrono::duration_cast<ts_nanoseconds>(LOOP_HISTOGRAM_BUCKET_SIZE).count();
+ current_slice->record_loop_duration(delta);
+ _loop_timing(delta / DIVISOR);
+ return *this;
+}
+
+inline auto
+EThread::Metrics::record_api_time(ink_hrtime delta) -> self_type &
+{
+ static auto constexpr DIVISOR = std::chrono::duration_cast<ts_nanoseconds>(LOOP_HISTOGRAM_BUCKET_SIZE).count();
+ _api_timing(delta / DIVISOR);
+ return *this;
+}
+
+inline auto
+EThread::Metrics::decay() -> self_type &
+{
+ while (_decay_count) {
+ _loop_timing.decay();
+ _api_timing.decay();
+ --_decay_count;
+ }
+ return *this;
+}
+
+/**
+ This is used so that we dont use up operator new(size_t, void *)
+ which users might want to define for themselves.
+
+*/
+class ink_dummy_for_new
+{
+};
+
+inline void *
+operator new(size_t, ink_dummy_for_new *p)
+{
+ return (void *)p;
+}
+#define ETHREAD_GET_PTR(thread, offset) ((void *)((char *)(thread) + (offset)))
+
+extern EThread *this_ethread();
+
+extern int thread_max_heartbeat_mseconds;
diff --git a/include/iocore/eventsystem/Event.h b/include/iocore/eventsystem/Event.h
new file mode 100644
index 0000000000..2e84ad8d76
--- /dev/null
+++ b/include/iocore/eventsystem/Event.h
@@ -0,0 +1,292 @@
+/** @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 "tscore/ink_platform.h"
+#include "Action.h"
+
+//
+// Defines
+//
+
+#define MAX_EVENTS_PER_THREAD 100000
+
+// Events
+
+#define EVENT_NONE CONTINUATION_EVENT_NONE // 0
+#define EVENT_IMMEDIATE 1
+#define EVENT_INTERVAL 2
+#define EVENT_ERROR 3
+#define EVENT_CALL 4 // used internally in state machines
+#define EVENT_POLL 5 // negative event; activated on poll or epoll
+
+// Event callback return functions
+
+#define EVENT_DONE CONTINUATION_DONE // 0
+#define EVENT_CONT CONTINUATION_CONT // 1
+#define EVENT_RETURN 5
+#define EVENT_RESTART 6
+#define EVENT_RESTART_DELAYED 7
+
+// Event numbers block allocation
+// ** ALL NEW EVENT TYPES SHOULD BE ALLOCATED FROM BLOCKS LISTED HERE! **
+
+#define VC_EVENT_EVENTS_START 100
+#define NET_EVENT_EVENTS_START 200
+#define DISK_EVENT_EVENTS_START 300
+#define HOSTDB_EVENT_EVENTS_START 500
+#define DNS_EVENT_EVENTS_START 600
+#define CONFIG_EVENT_EVENTS_START 800
+#define LOG_EVENT_EVENTS_START 900
+#define REFCOUNT_CACHE_EVENT_EVENTS_START 1000
+#define CACHE_EVENT_EVENTS_START 1100
+#define CACHE_DIRECTORY_EVENT_EVENTS_START 1200
+#define CACHE_DB_EVENT_EVENTS_START 1300
+#define HTTP_NET_CONNECTION_EVENT_EVENTS_START 1400
+#define HTTP_NET_VCONNECTION_EVENT_EVENTS_START 1500
+#define GC_EVENT_EVENTS_START 1600
+#define TRANSFORM_EVENTS_START 2000
+#define STAT_PAGES_EVENTS_START 2100
+#define HTTP_SESSION_EVENTS_START 2200
+#define HTTP2_SESSION_EVENTS_START 2250
+#define HTTP_TUNNEL_EVENTS_START 2300
+#define HTTP_SCH_UPDATE_EVENTS_START 2400
+#define QUIC_EVENT_EVENTS_START 2500
+#define HTTP3_SESSION_EVENTS_START 2600
+#define QPACK_EVENT_EVENTS_START 2700
+#define NT_ASYNC_CONNECT_EVENT_EVENTS_START 3000
+#define NT_ASYNC_IO_EVENT_EVENTS_START 3100
+#define RAFT_EVENT_EVENTS_START 3200
+#define SIMPLE_EVENT_EVENTS_START 3300
+#define UPDATE_EVENT_EVENTS_START 3500
+#define AIO_EVENT_EVENTS_START 3900
+#define BLOCK_CACHE_EVENT_EVENTS_START 4000
+#define UTILS_EVENT_EVENTS_START 5000
+#define INK_API_EVENT_EVENTS_START 60000
+#define SRV_EVENT_EVENTS_START 62000
+#define REMAP_EVENT_EVENTS_START 63000
+
+// define misc events here
+#define ONE_WAY_TUNNEL_EVENT_PEER_CLOSE (SIMPLE_EVENT_EVENTS_START + 1)
+
+using EventType = int;
+const int ET_CALL = 0;
+const int MAX_EVENT_TYPES = 8; // conservative, these are dynamically allocated
+
+class EThread;
+
+/**
+ A type of Action returned by the EventProcessor. The Event class
+ is the type of Action returned by the EventProcessor as a result
+ of scheduling an operation. Unlike asynchronous operations
+ represented by actions, events never call reentrantly.
+
+ Besides being able to cancel an event (because it is an action),
+ you can also reschedule it once received.
+
+ <b>Remarks</b>
+
+ When rescheduling an event through any of the Event class
+ scheduling functions, state machines must not make these calls
+ in other thread other than the one that called them back. They
+ also must have acquired the continuation's lock before calling
+ any of the scheduling functions.
+
+ The rules for canceling an event are the same as those for
+ actions:
+
+ The canceler of an event must be the state machine that will be
+ called back by the task and that state machine's lock must be
+ held while calling cancel. Any reference to that event object
+ (ie. pointer) held by the state machine must not be used after
+ the cancellation.
+
+ Event Codes:
+
+ At the completion of an event, state machines use the event code
+ passed in through the Continuation's handler function to distinguish
+ the type of event and handle the data parameter accordingly. State
+ machine implementers should be careful when defining the event
+ codes since they can impact on other state machines presents. For
+ this reason, this numbers are usually allocated from a common
+ pool.
+
+ Time values:
+
+ The scheduling functions use a time parameter typed as ink_hrtime
+ for specifying the timeouts or periods. This is a nanosecond value
+ supported by libts and you should use the time functions and
+ macros defined in ink_hrtime.h.
+
+ The difference between the timeout specified for schedule_at and
+ schedule_in is that in the former it is an absolute value of time
+ that is expected to be in the future where in the latter it is
+ an amount of time to add to the current time (obtained with
+ ink_get_hrtime).
+
+*/
+class Event : public Action
+{
+public:
+ ///////////////////////////////////////////////////////////
+ // Common Interface //
+ ///////////////////////////////////////////////////////////
+
+ /**
+ Reschedules this event immediately. Instructs the event object
+ to reschedule itself as soon as possible in the EventProcessor.
+
+ @param callback_event Event code to return at the completion
+ of this event. See the Remarks section.
+
+ */
+ void schedule_imm(int callback_event = EVENT_IMMEDIATE);
+
+ /**
+ Reschedules this event to callback at time 'atimeout_at'.
+ Instructs the event object to reschedule itself at the time
+ specified in atimeout_at on the EventProcessor.
+
+ @param atimeout_at Time at which to call the callback. See the Remarks section.
+ @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+ */
+ void schedule_at(ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL);
+
+ /**
+ Reschedules this event to callback at time 'atimeout_at'.
+ Instructs the event object to reschedule itself at the time
+ specified in atimeout_at on the EventProcessor.
+
+ @param atimeout_in Time at which to call the callback. See the Remarks section.
+ @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+ */
+ void schedule_in(ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL);
+
+ /**
+ Reschedules this event to callback every 'aperiod'. Instructs
+ the event object to reschedule itself to callback every 'aperiod'
+ from now.
+
+ @param aperiod Time period at which to call the callback. See the Remarks section.
+ @param callback_event Event code to return at the completion of this event. See the Remarks section.
+
+ */
+ void schedule_every(ink_hrtime aperiod, int callback_event = EVENT_INTERVAL);
+
+ // inherited from Action::cancel
+ // virtual void cancel(Continuation * c = nullptr);
+
+#ifdef ENABLE_EVENT_TRACKER
+ void set_location();
+ const void *get_location() const;
+#endif
+
+ void free();
+
+ EThread *ethread = nullptr;
+
+ unsigned int in_the_prot_queue : 1;
+ unsigned int in_the_priority_queue : 1;
+ unsigned int immediate : 1;
+ unsigned int globally_allocated : 1;
+ unsigned int in_heap : 4;
+ int callback_event = 0;
+
+ ink_hrtime timeout_at = 0;
+ ink_hrtime period = 0;
+
+ /**
+ This field can be set when an event is created. It is returned
+ as part of the Event structure to the continuation when handleEvent
+ is called.
+
+ */
+ void *cookie = nullptr;
+
+ // Private
+
+ Event();
+
+ Event *init(Continuation *c, ink_hrtime atimeout_at = 0, ink_hrtime aperiod = 0);
+
+#ifdef ENABLE_TIME_TRACE
+ ink_hrtime start_time;
+#endif
+
+ // noncopyable: prevent unauthorized copies (Not implemented)
+ Event(const Event &) = delete;
+ Event &operator=(const Event &) = delete;
+
+private:
+ void *operator new(size_t size); // use the fast allocators
+
+#ifdef ENABLE_EVENT_TRACKER
+ /**
+ Address of who scheduled this event
+ To get symbols, use backtrace_symbols(3) or external tools like `addr2line(1)` (Linux) or `atos(1)`(BSD).
+ */
+ const void *_location = nullptr;
+#endif
+
+public:
+ LINK(Event, link);
+
+ /*-------------------------------------------------------*\
+ | UNIX/non-NT Interface |
+ \*-------------------------------------------------------*/
+
+#ifdef ONLY_USED_FOR_FIB_AND_BIN_HEAP
+ void *node_pointer;
+ void
+ set_node_pointer(void *x)
+ {
+ node_pointer = x;
+ }
+ void *
+ get_node_pointer()
+ {
+ return node_pointer;
+ }
+#endif
+
+#if defined(__GNUC__)
+ ~Event() override {}
+#endif
+};
+
+//
+// Event Allocator
+//
+extern ClassAllocator<Event> eventAllocator;
+
+#define EVENT_ALLOC(_a, _t) THREAD_ALLOC(_a, _t)
+#define EVENT_FREE(_p, _a, _t) \
+ _p->mutex = nullptr; \
+ if (_p->globally_allocated) \
+ ::_a.free(_p); \
+ else \
+ THREAD_FREE(_p, _a, _t)
diff --git a/include/iocore/eventsystem/EventProcessor.h b/include/iocore/eventsystem/EventProcessor.h
new file mode 100644
index 0000000000..61fafcff35
--- /dev/null
+++ b/include/iocore/eventsystem/EventProcessor.h
@@ -0,0 +1,402 @@
+/** @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 "tscore/ink_platform.h"
+#include "Continuation.h"
+#include "Processor.h"
+#include "Event.h"
+#include <atomic>
+
+#ifdef TS_MAX_THREADS_IN_EACH_THREAD_TYPE
+constexpr int MAX_THREADS_IN_EACH_TYPE = TS_MAX_THREADS_IN_EACH_THREAD_TYPE;
+#else
+constexpr int MAX_THREADS_IN_EACH_TYPE = 3071;
+#endif
+
+#ifdef TS_MAX_NUMBER_EVENT_THREADS
+constexpr int MAX_EVENT_THREADS = TS_MAX_NUMBER_EVENT_THREADS;
+#else
+constexpr int MAX_EVENT_THREADS = 4096;
+#endif
+
+class EThread;
+
+/**
+ Main processor for the Event System. The EventProcessor is the core
+ component of the Event System. Once started, it is responsible for
+ creating and managing groups of threads that execute user-defined
+ tasks asynchronously at a given time or periodically.
+
+ The EventProcessor provides a set of scheduling functions through
+ which you can specify continuations to be called back by one of its
+ threads. These function calls do not block. Instead they return an
+ Event object and schedule the callback to the continuation passed in at
+ a later or specific time, as soon as possible or at certain intervals.
+
+ Singleton model:
+
+ Every executable that imports and statically links against the
+ EventSystem library is provided with a global instance of the
+ EventProcessor called eventProcessor. Therefore, it is not necessary to
+ create instances of the EventProcessor class because it was designed
+ as a singleton. It is important to note that none of its functions
+ are reentrant.
+
+ Thread Groups (Event types):
+
+ When the EventProcessor is started, the first group of threads is spawned and it is assigned the
+ special id ET_CALL. Depending on the complexity of the state machine or protocol, you may be
+ interested in creating additional threads and the EventProcessor gives you the ability to create a
+ single thread or an entire group of threads. In the former case, you call spawn_thread and the
+ thread is independent of the thread groups and it exists as long as your continuation handle
+ executes and there are events to process. In the latter, you call @c registerEventType to get an
+ event type and then @c spawn_event_theads which creates the threads in the group of that
+ type. Such threads require events to be scheduled on a specific thread in the group or for the
+ group in general using the event type. Note that between these two calls @c
+ EThread::schedule_spawn can be used to set up per thread initialization.
+
+ Callback event codes:
+
+ @b UNIX: For all of the scheduling functions, the callback_event
+ parameter is not used. On a callback, the event code passed in to
+ the continuation handler is always EVENT_IMMEDIATE.
+
+ @b NT: The value of the event code passed in to the continuation
+ handler is the value provided in the callback_event parameter.
+
+ Event allocation policy:
+
+ Events are allocated and deallocated by the EventProcessor. A state
+ machine may access the returned, non-recurring event until it is
+ cancelled or the callback from the event is complete. For recurring
+ events, the Event may be accessed until it is cancelled. Once the event
+ is complete or cancelled, it's the eventProcessor's responsibility to
+ deallocate it.
+
+*/
+class EventProcessor : public Processor
+{
+public:
+ /** Register an event type with @a name.
+
+ This must be called to get an event type to pass to @c spawn_event_threads
+ @see spawn_event_threads
+ */
+ EventType register_event_type(char const *name);
+
+ /**
+ Spawn an additional thread for calling back the continuation. Spawns
+ a dedicated thread (EThread) that calls back the continuation passed
+ in as soon as possible.
+
+ @param cont continuation that the spawn thread will call back
+ immediately.
+ @return event object representing the start of the thread.
+
+ */
+ Event *spawn_thread(Continuation *cont, const char *thr_name, size_t stacksize = 0);
+
+ /** Spawn a group of @a n_threads event dispatching threads.
+
+ The threads run an event loop which dispatches events scheduled for a specific thread or the event type.
+
+ @return EventType or thread id for the new group of threads (@a ev_type)
+
+ */
+ EventType spawn_event_threads(EventType ev_type, int n_threads, size_t stacksize = DEFAULT_STACKSIZE);
+
+ /// Convenience overload.
+ /// This registers @a name as an event type using @c registerEventType and then calls the real @c spawn_event_threads
+ EventType spawn_event_threads(const char *name, int n_thread, size_t stacksize = DEFAULT_STACKSIZE);
+
+ /**
+ Schedules the continuation on a specific EThread to receive an event
+ at the given timeout. Requests the EventProcessor to schedule
+ the callback to the continuation 'c' at the time specified in
+ 'atimeout_at'. The event is assigned to the specified EThread.
+
+ @param c Continuation to be called back at the time specified in
+ 'atimeout_at'.
+ @param atimeout_at time value at which to callback.
+ @param ethread EThread on which to schedule the event.
+ @param callback_event code to be passed back to the continuation's
+ handler. See the Remarks section.
+ @param cookie user-defined value or pointer to be passed back in
+ the Event's object cookie field.
+ @return reference to an Event object representing the scheduling
+ of this callback.
+
+ */
+ Event *schedule_imm(Continuation *c, EventType event_type = ET_CALL, int callback_event = EVENT_IMMEDIATE,
+ void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on a specific thread group to receive an
+ event at the given timeout. Requests the EventProcessor to schedule
+ the callback to the continuation 'c' at the time specified in
+ 'atimeout_at'. The callback is handled by a thread in the specified
+ thread group (event_type).
+
+ @param c Continuation to be called back at the time specified in
+ 'atimeout_at'.
+ @param atimeout_at Time value at which to callback.
+ @param event_type thread group id (or event type) specifying the
+ group of threads on which to schedule the callback.
+ @param callback_event code to be passed back to the continuation's
+ handler. See the Remarks section.
+ @param cookie user-defined value or pointer to be passed back in
+ the Event's object cookie field.
+ @return reference to an Event object representing the scheduling of
+ this callback.
+
+ */
+ Event *schedule_at(Continuation *c, ink_hrtime atimeout_at, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+ void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on a specific thread group to receive an
+ event after the specified timeout elapses. Requests the EventProcessor
+ to schedule the callback to the continuation 'c' after the time
+ specified in 'atimeout_in' elapses. The callback is handled by a
+ thread in the specified thread group (event_type).
+
+ @param c Continuation to call back aftert the timeout elapses.
+ @param atimeout_in amount of time after which to callback.
+ @param event_type Thread group id (or event type) specifying the
+ group of threads on which to schedule the callback.
+ @param callback_event code to be passed back to the continuation's
+ handler. See the Remarks section.
+ @param cookie user-defined value or pointer to be passed back in
+ the Event's object cookie field.
+ @return reference to an Event object representing the scheduling of
+ this callback.
+
+ */
+ Event *schedule_in(Continuation *c, ink_hrtime atimeout_in, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+ void *cookie = nullptr);
+
+ /**
+ Schedules the continuation on a specific thread group to receive
+ an event periodically. Requests the EventProcessor to schedule the
+ callback to the continuation 'c' every time 'aperiod' elapses. The
+ callback is handled by a thread in the specified thread group
+ (event_type).
+
+ @param c Continuation to call back every time 'aperiod' elapses.
+ @param aperiod duration of the time period between callbacks.
+ @param event_type thread group id (or event type) specifying the
+ group of threads on which to schedule the callback.
+ @param callback_event code to be passed back to the continuation's
+ handler. See the Remarks section.
+ @param cookie user-defined value or pointer to be passed back in
+ the Event's object cookie field.
+ @return reference to an Event object representing the scheduling of
+ this callback.
+
+ */
+ Event *schedule_every(Continuation *c, ink_hrtime aperiod, EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL,
+ void *cookie = nullptr);
+
+ ////////////////////////////////////////////
+ // reschedule an already scheduled event. //
+ // may be called directly or called by //
+ // schedule_xxx Event member functions. //
+ // The returned value may be different //
+ // from the argument e. //
+ ////////////////////////////////////////////
+
+ Event *reschedule_imm(Event *e, int callback_event = EVENT_IMMEDIATE);
+ Event *reschedule_at(Event *e, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL);
+ Event *reschedule_in(Event *e, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL);
+ Event *reschedule_every(Event *e, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL);
+
+ /// Schedule an @a event on continuation @a c when a thread of type @a ev_type is spawned.
+ /// The @a cookie is attached to the event instance passed to the continuation.
+ /// @return The scheduled event.
+ Event *schedule_spawn(Continuation *c, EventType ev_type, int event = EVENT_IMMEDIATE, void *cookie = nullptr);
+
+ /// Schedule the function @a f to be called in a thread of type @a ev_type when it is spawned.
+ Event *schedule_spawn(void (*f)(EThread *), EventType ev_type);
+
+ /// Schedule an @a event on continuation @a c to be called when a thread is spawned by this processor.
+ /// The @a cookie is attached to the event instance passed to the continuation.
+ /// @return The scheduled event.
+ // Event *schedule_spawn(Continuation *c, int event, void *cookie = NULL);
+
+ EventProcessor();
+ ~EventProcessor() override;
+ EventProcessor(const EventProcessor &) = delete;
+ EventProcessor &operator=(const EventProcessor &) = delete;
+
+ /**
+ Initializes the EventProcessor and its associated threads. Spawns the
+ specified number of threads, initializes their state information and
+ sets them running. It creates the initial thread group, represented
+ by the event type ET_CALL.
+
+ @return 0 if successful, and a negative value otherwise.
+
+ */
+ int start(int n_net_threads, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+ /**
+ Stop the EventProcessor. Attempts to stop the EventProcessor and
+ all of the threads in each of the thread groups.
+
+ */
+ void shutdown() override;
+
+ /**
+ Allocates size bytes on the event threads. This function is thread
+ safe.
+
+ @param size bytes to be allocated.
+
+ */
+ off_t allocate(int size);
+
+ /**
+ An array of pointers to all of the EThreads handled by the
+ EventProcessor. An array of pointers to all of the EThreads created
+ throughout the existence of the EventProcessor instance.
+
+ */
+ EThread *all_ethreads[MAX_EVENT_THREADS];
+
+ /// Data kept for each thread group.
+ /// The thread group ID is the index into an array of these and so is not stored explicitly.
+ struct ThreadGroupDescriptor {
+ std::string _name; ///< Name for the thread group.
+ int _count = 0; ///< # of threads of this type.
+ std::atomic<int> _started = 0; ///< # of started threads of this type.
+ uint64_t _next_round_robin = 0; ///< Index of thread to use for events assigned to this group.
+ Que(Event, link) _spawnQueue; ///< Events to dispatch when thread is spawned.
+ EThread *_thread[MAX_THREADS_IN_EACH_TYPE] = {}; ///< The actual threads in this group.
+ std::function<void()> _afterStartCallback = nullptr;
+ };
+
+ /// Storage for per group data.
+ ThreadGroupDescriptor thread_group[MAX_EVENT_TYPES];
+
+ /// Number of defined thread groups.
+ int n_thread_groups = 0;
+
+ /**
+ Total number of threads controlled by this EventProcessor. This is
+ the count of all the EThreads spawn by this EventProcessor, excluding
+ those created by spawn_thread
+
+ */
+ int n_ethreads = 0;
+
+ bool has_tg_started(int etype);
+
+ /*------------------------------------------------------*\
+ | Unix & non NT Interface |
+ \*------------------------------------------------------*/
+
+ Event *schedule(Event *e, EventType etype);
+ EThread *assign_thread(EventType etype);
+ EThread *assign_affinity_by_type(Continuation *cont, EventType etype);
+
+ EThread *all_dthreads[MAX_EVENT_THREADS];
+ int n_dthreads = 0; // No. of dedicated threads
+ int thread_data_used = 0;
+
+ /// Provide container style access to just the active threads, not the entire array.
+ class active_threads_type
+ {
+ using iterator = EThread *const *; ///< Internal iterator type, pointer to array element.
+ public:
+ iterator
+ begin() const
+ {
+ return _begin;
+ }
+
+ iterator
+ end() const
+ {
+ return _end;
+ }
+
+ private:
+ iterator _begin; ///< Start of threads.
+ iterator _end; ///< End of threads.
+ /// Construct from base of the array (@a start) and the current valid count (@a n).
+ active_threads_type(iterator start, int n) : _begin(start), _end(start + n) {}
+ friend class EventProcessor;
+ };
+
+ // These can be used in container for loops and other range operations.
+ active_threads_type
+ active_ethreads() const
+ {
+ return {all_ethreads, n_ethreads};
+ }
+
+ active_threads_type
+ active_dthreads() const
+ {
+ return {all_dthreads, n_dthreads};
+ }
+
+ active_threads_type
+ active_group_threads(int type) const
+ {
+ ThreadGroupDescriptor const &group{thread_group[type]};
+ return {group._thread, group._count};
+ }
+
+private:
+ void initThreadState(EThread *);
+
+ /// Used to generate a callback at the start of thread execution.
+ class ThreadInit : public Continuation
+ {
+ using self = ThreadInit;
+ EventProcessor *_evp;
+
+ public:
+ explicit ThreadInit(EventProcessor *evp) : _evp(evp) { SET_HANDLER(&self::init); }
+
+ int
+ init(int /* event ATS_UNUSED */, Event *ev)
+ {
+ _evp->initThreadState(ev->ethread);
+ return 0;
+ }
+ };
+ friend class ThreadInit;
+ ThreadInit thread_initializer;
+
+ // Lock write access to the dedicated thread vector.
+ // @internal Not a @c ProxyMutex - that's a whole can of problems due to initialization ordering.
+ ink_mutex dedicated_thread_spawn_mutex;
+};
+
+extern class EventProcessor eventProcessor;
+
+void thread_started(EThread *);
diff --git a/include/iocore/eventsystem/EventSystem.h b/include/iocore/eventsystem/EventSystem.h
new file mode 100644
index 0000000000..63144a293d
--- /dev/null
+++ b/include/iocore/eventsystem/EventSystem.h
@@ -0,0 +1,51 @@
+/** @file
+
+ Event subsystem
+
+ @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
+#define _I_EventSystem_h
+
+#include "tscore/ink_platform.h"
+#include "ts/apidefs.h"
+
+#include "IOBuffer.h"
+#include "Action.h"
+#include "Continuation.h"
+#include "EThread.h"
+#include "Event.h"
+#include "EventProcessor.h"
+
+#include "Lock.h"
+#include "PriorityEventQueue.h"
+#include "Processor.h"
+#include "ProtectedQueue.h"
+#include "Thread.h"
+#include "VIO.h"
+#include "VConnection.h"
+#include "records/RecProcess.h"
+#include "SocketManager.h"
+#include "RecProcess.h"
+
+static constexpr ts::ModuleVersion EVENT_SYSTEM_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+void ink_event_system_init(ts::ModuleVersion version);
diff --git a/iocore/eventsystem/I_IOBuffer.h b/include/iocore/eventsystem/IOBuffer.h
similarity index 100%
rename from iocore/eventsystem/I_IOBuffer.h
rename to include/iocore/eventsystem/IOBuffer.h
diff --git a/include/iocore/eventsystem/Lock.h b/include/iocore/eventsystem/Lock.h
new file mode 100644
index 0000000000..61edd616bf
--- /dev/null
+++ b/include/iocore/eventsystem/Lock.h
@@ -0,0 +1,681 @@
+/** @file
+
+ Basic locks for threads
+
+ @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 "tscore/ink_platform.h"
+#include "tscore/Diags.h"
+#include "Thread.h"
+
+#define MAX_LOCK_TIME HRTIME_MSECONDS(200)
+#define THREAD_MUTEX_THREAD_HOLDING (-1024 * 1024)
+
+/*------------------------------------------------------*\
+| Macros |
+\*------------------------------------------------------*/
+
+/**
+ Blocks until the lock to the ProxyMutex is acquired.
+
+ This macro performs a blocking call until the lock to the ProxyMutex
+ is acquired. This call allocates a special object that holds the
+ lock to the ProxyMutex only for the scope of the function or
+ region. It is a good practice to delimit such scope explicitly
+ with '{' and '}'.
+
+ @param _l Arbitrary name for the lock to use in this call
+ @param _m A pointer to (or address of) a ProxyMutex object
+ @param _t The current EThread executing your code.
+
+*/
+
+// A weak version of the SCOPED_MUTEX_LOCK macro, allows the mutex to be a nullptr.
+#ifdef DEBUG
+#define WEAK_SCOPED_MUTEX_LOCK(_l, _m, _t) WeakMutexLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t);
+#else // DEBUG
+#define WEAK_SCOPED_MUTEX_LOCK(_l, _m, _t) WeakMutexLock _l(_m, _t);
+#endif // DEBUG
+
+#ifdef DEBUG
+#define SCOPED_MUTEX_LOCK(_l, _m, _t) MutexLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else // DEBUG
+#define SCOPED_MUTEX_LOCK(_l, _m, _t) MutexLock _l(_m, _t)
+#endif // DEBUG
+
+/**
+ Attempts to acquire the lock to the ProxyMutex.
+
+ This macro attempts to acquire the lock to the specified ProxyMutex
+ object in a non-blocking manner. After using the macro you can
+ see if it was successful by comparing the lock variable with true
+ or false (the variable name passed in the _l parameter).
+
+ @param _l Arbitrary name for the lock to use in this call (lock variable)
+ @param _m A pointer to (or address of) a ProxyMutex object
+ @param _t The current EThread executing your code.
+
+*/
+
+#ifdef DEBUG
+#define WEAK_MUTEX_TRY_LOCK(_l, _m, _t) WeakMutexTryLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t);
+#else // DEBUG
+#define WEAK_MUTEX_TRY_LOCK(_l, _m, _t) WeakMutexTryLock _l(_m, _t);
+#endif // DEBUG
+
+#ifdef DEBUG
+#define MUTEX_TRY_LOCK(_l, _m, _t) MutexTryLock _l(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else // DEBUG
+#define MUTEX_TRY_LOCK(_l, _m, _t) MutexTryLock _l(_m, _t)
+#endif // DEBUG
+
+/**
+ Releases the lock on a ProxyMutex.
+
+ This macro releases the lock on the ProxyMutex, provided it is
+ currently held. The lock must have been successfully acquired
+ with one of the MUTEX macros.
+
+ @param _l Arbitrary name for the lock to use in this call (lock
+ variable) It must be the same name as the one used to acquire the
+ lock.
+
+*/
+#define MUTEX_RELEASE(_l) (_l).release()
+
+/////////////////////////////////////
+// DEPRECATED DEPRECATED DEPRECATED
+#ifdef DEBUG
+#define MUTEX_TAKE_TRY_LOCK(_m, _t) Mutex_trylock(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#else
+#define MUTEX_TAKE_TRY_LOCK(_m, _t) Mutex_trylock(_m, _t)
+#endif
+
+#ifdef DEBUG
+#define MUTEX_TAKE_LOCK(_m, _t) Mutex_lock(MakeSourceLocation(), (char *)nullptr, _m, _t)
+#define MUTEX_TAKE_LOCK_FOR(_m, _t, _c) Mutex_lock(MakeSourceLocation(), nullptr, _m, _t)
+#else
+#define MUTEX_TAKE_LOCK(_m, _t) Mutex_lock(_m, _t)
+#define MUTEX_TAKE_LOCK_FOR(_m, _t, _c) Mutex_lock(_m, _t)
+#endif // DEBUG
+
+#define MUTEX_UNTAKE_LOCK(_m, _t) Mutex_unlock(_m, _t)
+// DEPRECATED DEPRECATED DEPRECATED
+/////////////////////////////////////
+
+class EThread;
+using EThreadPtr = EThread *;
+
+#if DEBUG
+extern void lock_waiting(const SourceLocation &, const char *handler);
+extern void lock_holding(const SourceLocation &, const char *handler);
+extern void lock_taken(const SourceLocation &, const char *handler);
+#endif
+
+/**
+ Lock object used in continuations and threads.
+
+ The ProxyMutex class is the main synchronization object used
+ throughout the Event System. It is a reference counted object
+ that provides mutually exclusive access to a resource. Since the
+ Event System is multithreaded by design, the ProxyMutex is required
+ to protect data structures and state information that could
+ otherwise be affected by the action of concurrent threads.
+
+ A ProxyMutex object has an ink_mutex member (defined in ink_mutex.h)
+ which is a wrapper around the platform dependent mutex type. This
+ member allows the ProxyMutex to provide the functionality required
+ by the users of the class without the burden of platform specific
+ function calls.
+
+ The ProxyMutex also has a reference to the current EThread holding
+ the lock as a back pointer for verifying that it is released
+ correctly.
+
+ Acquiring/Releasing locks:
+
+ Included with the ProxyMutex class, there are several macros that
+ allow you to lock/unlock the underlying mutex object.
+
+*/
+class ProxyMutex : public RefCountObj
+{
+public:
+ /**
+ Underlying mutex object.
+
+ The platform independent mutex for the ProxyMutex class. You
+ must not modify or set it directly.
+
+ */
+ // coverity[uninit_member]
+ ink_mutex the_mutex;
+
+ /**
+ Backpointer to owning thread.
+
+ This is a pointer to the thread currently holding the mutex
+ lock. You must not modify or set this value directly.
+
+ */
+ EThreadPtr thread_holding;
+
+ int nthread_holding;
+
+#ifdef DEBUG
+ ink_hrtime hold_time;
+ SourceLocation srcloc;
+ const char *handler;
+
+#ifdef MAX_LOCK_TAKEN
+ int taken;
+#endif // MAX_LOCK_TAKEN
+
+#ifdef LOCK_CONTENTION_PROFILING
+ int total_acquires, blocking_acquires, nonblocking_acquires, successful_nonblocking_acquires, unsuccessful_nonblocking_acquires;
+ void print_lock_stats(int flag);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+ void free() override;
+
+ /**
+ Constructor - use new_ProxyMutex() instead.
+
+ The constructor of a ProxyMutex object. Initializes the state
+ of the object but leaves the initialization of the mutex member
+ until it is needed (through init()). Do not use this constructor,
+ the preferred mechanism for creating a ProxyMutex is via the
+ new_ProxyMutex function, which provides a faster allocation.
+
+ */
+ ProxyMutex()
+#ifdef DEBUG
+ : srcloc(nullptr, nullptr, 0)
+#endif
+ {
+ thread_holding = nullptr;
+ nthread_holding = 0;
+#ifdef DEBUG
+ hold_time = 0;
+ handler = nullptr;
+#ifdef MAX_LOCK_TAKEN
+ taken = 0;
+#endif // MAX_LOCK_TAKEN
+#ifdef LOCK_CONTENTION_PROFILING
+ total_acquires = 0;
+ blocking_acquires = 0;
+ nonblocking_acquires = 0;
+ successful_nonblocking_acquires = 0;
+ unsuccessful_nonblocking_acquires = 0;
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+ // coverity[uninit_member]
+ }
+
+ /**
+ Initializes the underlying mutex object.
+
+ After constructing your ProxyMutex object, use this function
+ to initialize the underlying mutex object with an optional name.
+
+ @param name Name to identify this ProxyMutex. Its use depends
+ on the given platform.
+
+ */
+ void
+ init(const char *name = "UnnamedMutex")
+ {
+ ink_mutex_init(&the_mutex);
+ }
+};
+
+// The ClassAllocator for ProxyMutexes
+extern ClassAllocator<ProxyMutex> mutexAllocator;
+
+inline bool
+Mutex_trylock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif
+ ProxyMutex *m, EThread *t)
+{
+ ink_assert(t != nullptr);
+ ink_assert(t == reinterpret_cast<EThread *>(this_thread()));
+ if (m->thread_holding != t) {
+ if (!ink_mutex_try_acquire(&m->the_mutex)) {
+#ifdef DEBUG
+ lock_waiting(m->srcloc, m->handler);
+#ifdef LOCK_CONTENTION_PROFILING
+ m->unsuccessful_nonblocking_acquires++;
+ m->nonblocking_acquires++;
+ m->total_acquires++;
+ m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+ return false;
+ }
+ m->thread_holding = t;
+#ifdef DEBUG
+ m->srcloc = location;
+ m->handler = ahandler;
+ m->hold_time = ink_get_hrtime();
+#ifdef MAX_LOCK_TAKEN
+ m->taken++;
+#endif // MAX_LOCK_TAKEN
+#endif // DEBUG
+ }
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+ m->successful_nonblocking_acquires++;
+ m->nonblocking_acquires++;
+ m->total_acquires++;
+ m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+ m->nthread_holding++;
+ return true;
+}
+
+inline bool
+Mutex_trylock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif
+ Ptr<ProxyMutex> &m, EThread *t)
+{
+ return Mutex_trylock(
+#ifdef DEBUG
+ location, ahandler,
+#endif
+ m.get(), t);
+}
+
+inline int
+Mutex_lock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif
+ ProxyMutex *m, EThread *t)
+{
+ ink_assert(t != nullptr);
+ if (m->thread_holding != t) {
+ ink_mutex_acquire(&m->the_mutex);
+ m->thread_holding = t;
+ ink_assert(m->thread_holding);
+#ifdef DEBUG
+ m->srcloc = location;
+ m->handler = ahandler;
+ m->hold_time = ink_get_hrtime();
+#ifdef MAX_LOCK_TAKEN
+ m->taken++;
+#endif // MAX_LOCK_TAKEN
+#endif // DEBUG
+ }
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+ m->blocking_acquires++;
+ m->total_acquires++;
+ m->print_lock_stats(0);
+#endif // LOCK_CONTENTION_PROFILING
+#endif // DEBUG
+ m->nthread_holding++;
+ return true;
+}
+
+inline int
+Mutex_lock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif
+ Ptr<ProxyMutex> &m, EThread *t)
+{
+ return Mutex_lock(
+#ifdef DEBUG
+ location, ahandler,
+#endif
+ m.get(), t);
+}
+
+inline void
+Mutex_unlock(ProxyMutex *m, EThread *t)
+{
+ if (m->nthread_holding) {
+ ink_assert(t == m->thread_holding);
+ m->nthread_holding--;
+ if (!m->nthread_holding) {
+#ifdef DEBUG
+ if (ink_get_hrtime() - m->hold_time > MAX_LOCK_TIME)
+ lock_holding(m->srcloc, m->handler);
+#ifdef MAX_LOCK_TAKEN
+ if (m->taken > MAX_LOCK_TAKEN)
+ lock_taken(m->srcloc, m->handler);
+#endif // MAX_LOCK_TAKEN
+ m->srcloc = SourceLocation(nullptr, nullptr, 0);
+ m->handler = nullptr;
+#endif // DEBUG
+ ink_assert(m->thread_holding);
+ m->thread_holding = nullptr;
+ ink_mutex_release(&m->the_mutex);
+ }
+ }
+}
+
+inline void
+Mutex_unlock(Ptr<ProxyMutex> &m, EThread *t)
+{
+ Mutex_unlock(m.get(), t);
+}
+
+class WeakMutexLock
+{
+private:
+ Ptr<ProxyMutex> m;
+ bool locked_p{false};
+
+public:
+ WeakMutexLock() = default;
+
+ WeakMutexLock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+ Ptr<ProxyMutex> &am, EThread *t)
+ : m(am), locked_p(true)
+ {
+ if (m.get()) {
+ Mutex_lock(
+#ifdef DEBUG
+ location, ahandler,
+#endif // DEBUG
+ m, t);
+ }
+ }
+
+ WeakMutexLock(WeakMutexLock &) = delete;
+ WeakMutexLock &operator=(const WeakMutexLock &) = delete;
+ WeakMutexLock(WeakMutexLock &&) = delete;
+
+ WeakMutexLock &
+ operator=(WeakMutexLock &&orig)
+ {
+ if (&orig != this) {
+ std::swap(m, orig.m);
+ std::swap(locked_p, orig.locked_p);
+ }
+ return *this;
+ }
+
+ void
+ release()
+ {
+ if (locked_p && m.get()) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ locked_p = false;
+ }
+
+ ~WeakMutexLock() { this->release(); }
+};
+
+/** Scoped lock class for ProxyMutex
+ */
+class MutexLock
+{
+private:
+ Ptr<ProxyMutex> m{};
+ bool locked_p{false};
+
+public:
+ MutexLock() = default;
+
+ MutexLock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+ Ptr<ProxyMutex> &am, EThread *t)
+ : m(am), locked_p(true)
+ {
+ Mutex_lock(
+#ifdef DEBUG
+ location, ahandler,
+#endif // DEBUG
+ m, t);
+ }
+
+ MutexLock(MutexLock &) = delete;
+ MutexLock &operator=(const MutexLock &) = delete;
+ MutexLock(MutexLock &&) = delete;
+
+ MutexLock &
+ operator=(MutexLock &&orig)
+ {
+ if (&orig != this) {
+ std::swap(m, orig.m);
+ std::swap(locked_p, orig.locked_p);
+ }
+ return *this;
+ }
+
+ void
+ release()
+ {
+ if (locked_p) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ locked_p = false;
+ }
+
+ ~MutexLock() { this->release(); }
+};
+
+/** Scoped try lock class for ProxyMutex
+ */
+class WeakMutexTryLock
+{
+private:
+ Ptr<ProxyMutex> m;
+ bool lock_acquired{false};
+
+public:
+ WeakMutexTryLock() = default;
+
+ WeakMutexTryLock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+ Ptr<ProxyMutex> &am, EThread *t)
+ : m(am)
+ {
+ if (m.get()) {
+ lock_acquired = Mutex_trylock(
+#ifdef DEBUG
+ location, ahandler,
+#endif // DEBUG
+ m, t);
+ } else {
+ lock_acquired = true;
+ }
+ }
+
+ WeakMutexTryLock(WeakMutexTryLock &) = delete;
+ WeakMutexTryLock &operator=(const WeakMutexTryLock &) = delete;
+ WeakMutexTryLock(WeakMutexTryLock &&) = delete;
+
+ WeakMutexTryLock &
+ operator=(WeakMutexTryLock &&orig)
+ {
+ if (&orig != this) {
+ std::swap(m, orig.m);
+ std::swap(lock_acquired, orig.lock_acquired);
+ }
+ return *this;
+ }
+
+ ~WeakMutexTryLock()
+ {
+ if (lock_acquired && m.get()) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ lock_acquired = false;
+ }
+
+ /** Spin till lock is acquired
+ */
+ void
+ acquire(EThread *t)
+ {
+ lock_acquired = true;
+ if (m.get()) {
+ MUTEX_TAKE_LOCK(m, t);
+ }
+ }
+
+ void
+ release()
+ {
+ if (lock_acquired && m.get()) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ lock_acquired = false;
+ }
+
+ bool
+ is_locked() const
+ {
+ return lock_acquired;
+ }
+
+ const ProxyMutex *
+ get_mutex() const
+ {
+ return m.get();
+ }
+};
+
+/** Scoped try lock class for ProxyMutex
+ */
+class MutexTryLock
+{
+private:
+ Ptr<ProxyMutex> m;
+ bool lock_acquired{false};
+
+public:
+ MutexTryLock() = default;
+
+ MutexTryLock(
+#ifdef DEBUG
+ const SourceLocation &location, const char *ahandler,
+#endif // DEBUG
+ Ptr<ProxyMutex> &am, EThread *t)
+ : m(am)
+ {
+ lock_acquired = Mutex_trylock(
+#ifdef DEBUG
+ location, ahandler,
+#endif // DEBUG
+ m, t);
+ }
+
+ MutexTryLock(MutexTryLock &) = delete;
+ MutexTryLock &operator=(const MutexTryLock &) = delete;
+ MutexTryLock(MutexTryLock &&) = delete;
+
+ MutexTryLock &
+ operator=(MutexTryLock &&orig)
+ {
+ if (&orig != this) {
+ std::swap(m, orig.m);
+ std::swap(lock_acquired, orig.lock_acquired);
+ }
+ return *this;
+ }
+
+ ~MutexTryLock()
+ {
+ if (lock_acquired) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ }
+
+ /** Spin till lock is acquired
+ */
+ void
+ acquire(EThread *t)
+ {
+ MUTEX_TAKE_LOCK(m, t);
+ lock_acquired = true;
+ }
+
+ void
+ release()
+ {
+ if (lock_acquired) {
+ Mutex_unlock(m, m->thread_holding);
+ }
+ lock_acquired = false;
+ }
+
+ bool
+ is_locked() const
+ {
+ return lock_acquired;
+ }
+
+ const ProxyMutex *
+ get_mutex() const
+ {
+ return m.get();
+ }
+};
+
+inline void
+ProxyMutex::free()
+{
+#ifdef DEBUG
+#ifdef LOCK_CONTENTION_PROFILING
+ print_lock_stats(1);
+#endif
+#endif
+ ink_mutex_destroy(&the_mutex);
+ mutexAllocator.free(this);
+}
+
+// TODO should take optional mutex "name" identifier, to pass along to the init() fun
+/**
+ Creates a new ProxyMutex object.
+
+ This is the preferred mechanism for constructing objects of the
+ ProxyMutex class. It provides you with faster allocation than
+ that of the normal constructor.
+
+ @return A pointer to a ProxyMutex object appropriate for the build
+ environment.
+
+*/
+inline ProxyMutex *
+new_ProxyMutex()
+{
+ ProxyMutex *m = mutexAllocator.alloc();
+ m->init();
+ return m;
+}
diff --git a/include/iocore/eventsystem/MIOBufferWriter.h b/include/iocore/eventsystem/MIOBufferWriter.h
new file mode 100644
index 0000000000..5aa47e2597
--- /dev/null
+++ b/include/iocore/eventsystem/MIOBufferWriter.h
@@ -0,0 +1,189 @@
+/** @file
+
+ Buffer Writer for an MIOBuffer.
+
+ @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 <cstring>
+#include <iosfwd>
+
+#include "tscore/ink_assert.h"
+
+#if defined(UNIT_TEST_BUFFER_WRITER)
+#undef ink_assert
+#define ink_assert ink_release_assert
+#endif
+
+#include "tscpp/util/ts_bw.h"
+
+#if !defined(UNIT_TEST_BUFFER_WRITER)
+#include "IOBuffer.h"
+#endif
+
+/** BufferWriter interface on top of IOBuffer blocks.
+
+ @internal This should be changed to IOBufferChain once I port that to open source.
+ */
+class MIOBufferWriter : public swoc::BufferWriter
+{
+ using self_type = MIOBufferWriter; ///< Self reference type.
+ using super_type = swoc::BufferWriter;
+
+public:
+ explicit MIOBufferWriter(MIOBuffer *miob) : _miob(miob) {}
+
+ using super_type::write;
+
+ self_type &write(const void *data_, size_t length) override;
+
+ self_type &
+ write(char c) override
+ {
+ return this->write(&c, 1);
+ }
+
+ bool
+ error() const override
+ {
+ return false;
+ }
+
+ char *
+ aux_data() override
+ {
+ IOBufferBlock *iobbPtr = _miob->first_write_block();
+
+ if (!iobbPtr) {
+ return nullptr;
+ }
+
+ return iobbPtr->end();
+ }
+
+ size_t
+ remaining() const
+ {
+ if (IOBufferBlock *iobbPtr = _miob->first_write_block(); iobbPtr) {
+ return iobbPtr->write_avail();
+ }
+ return 0;
+ }
+
+ swoc::MemSpan<char>
+ aux_span()
+ {
+ if (IOBufferBlock *iobbPtr = _miob->first_write_block(); iobbPtr) {
+ return {iobbPtr->end(), size_t(iobbPtr->write_avail())};
+ }
+ return {};
+ }
+
+ // Write the first n characters that have been placed in the auxiliary buffer. This call invalidates the auxiliary buffer.
+ // This function should not be called if no auxiliary buffer is available.
+ //
+ bool
+ commit(size_t n) override
+ {
+ if (n) {
+ IOBufferBlock *iobbPtr = _miob->first_write_block();
+
+ ink_assert(iobbPtr and (n <= size_t(iobbPtr->write_avail())));
+
+ iobbPtr->fill(n);
+
+ _numWritten += n;
+ }
+
+ return true;
+ }
+
+ // No fixed limit on capacity.
+ //
+ size_t
+ capacity() const override
+ {
+ return (~size_t(0));
+ }
+
+ size_t
+ extent() const override
+ {
+ return _numWritten;
+ }
+
+ // Not useful in this derived class.
+ //
+ self_type &restrict(size_t) override { return *this; }
+
+ // Not useful in this derived class.
+ //
+ self_type &
+ restore(size_t) override
+ {
+ return *this;
+ }
+
+ // This must not be called for this derived class.
+ const char *
+ data() const override
+ {
+ ink_assert(false);
+ return nullptr;
+ }
+
+ // This must not be called for this derived class.
+ self_type &
+ discard(size_t) override
+ {
+ ink_assert(false);
+ return *this;
+ }
+
+ // This must not be called for this derived class.
+ self_type &
+ copy(size_t, size_t, size_t) override
+ {
+ ink_assert(false);
+ return *this;
+ }
+
+ /// Output the buffer contents to the @a stream.
+ /// @return The destination stream.
+ std::ostream &operator>>(std::ostream &stream) const override;
+ /// Output the buffer contents to the file for file descriptor @a fd.
+ /// @return The number of bytes written.
+ ssize_t operator>>(int fd) const;
+
+protected:
+ MIOBuffer *_miob;
+
+private:
+ size_t _numWritten = 0;
+
+ virtual void
+ addBlock()
+ {
+ _miob->add_block();
+ }
+ // INTERNAL - Overload removed, make sure it's not used.
+ self_type &write(size_t n);
+};
diff --git a/include/iocore/eventsystem/PriorityEventQueue.h b/include/iocore/eventsystem/PriorityEventQueue.h
new file mode 100644
index 0000000000..505e0a0e7e
--- /dev/null
+++ b/include/iocore/eventsystem/PriorityEventQueue.h
@@ -0,0 +1,122 @@
+/** @file
+
+ Queue of Events sorted by the "at_timeout" field
+
+ @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 "tscore/ink_platform.h"
+#include "Event.h"
+
+// <5ms, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120
+#define N_PQ_LIST 10
+#define PQ_BUCKET_TIME(_i) (HRTIME_MSECONDS(5) << (_i))
+
+class EThread;
+
+struct PriorityEventQueue {
+ Que(Event, link) after[N_PQ_LIST];
+ ink_hrtime last_check_time;
+ uint32_t last_check_buckets;
+
+ void
+ enqueue(Event *e, ink_hrtime now)
+ {
+ ink_hrtime t = e->timeout_at - now;
+ int i = 0;
+ // equivalent but faster
+ if (t <= PQ_BUCKET_TIME(3)) {
+ if (t <= PQ_BUCKET_TIME(1)) {
+ if (t <= PQ_BUCKET_TIME(0)) {
+ i = 0;
+ } else {
+ i = 1;
+ }
+ } else {
+ if (t <= PQ_BUCKET_TIME(2)) {
+ i = 2;
+ } else {
+ i = 3;
+ }
+ }
+ } else {
+ if (t <= PQ_BUCKET_TIME(7)) {
+ if (t <= PQ_BUCKET_TIME(5)) {
+ if (t <= PQ_BUCKET_TIME(4)) {
+ i = 4;
+ } else {
+ i = 5;
+ }
+ } else {
+ if (t <= PQ_BUCKET_TIME(6)) {
+ i = 6;
+ } else {
+ i = 7;
+ }
+ }
+ } else {
+ if (t <= PQ_BUCKET_TIME(8)) {
+ i = 8;
+ } else {
+ i = 9;
+ }
+ }
+ }
+ e->in_the_priority_queue = 1;
+ e->in_heap = i;
+ after[i].enqueue(e);
+ }
+
+ void
+ remove(Event *e)
+ {
+ ink_assert(e->in_the_priority_queue);
+ e->in_the_priority_queue = 0;
+ after[e->in_heap].remove(e);
+ }
+
+ Event *
+ dequeue_ready(ink_hrtime t)
+ {
+ (void)t;
+ Event *e = after[0].dequeue();
+ if (e) {
+ ink_assert(e->in_the_priority_queue);
+ e->in_the_priority_queue = 0;
+ }
+ return e;
+ }
+
+ void check_ready(ink_hrtime now, EThread *t);
+
+ ink_hrtime
+ earliest_timeout()
+ {
+ for (int i = 0; i < N_PQ_LIST; i++) {
+ if (after[i].head) {
+ return last_check_time + (PQ_BUCKET_TIME(i) / 2);
+ }
+ }
+ return last_check_time + HRTIME_FOREVER;
+ }
+
+ PriorityEventQueue();
+};
diff --git a/iocore/eventsystem/I_Processor.h b/include/iocore/eventsystem/Processor.h
similarity index 100%
rename from iocore/eventsystem/I_Processor.h
rename to include/iocore/eventsystem/Processor.h
diff --git a/include/iocore/eventsystem/ProtectedQueue.h b/include/iocore/eventsystem/ProtectedQueue.h
new file mode 100644
index 0000000000..1c971faf4c
--- /dev/null
+++ b/include/iocore/eventsystem/ProtectedQueue.h
@@ -0,0 +1,54 @@
+/** @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.
+ */
+
+/****************************************************************************
+
+ Protected Queue, a FIFO queue with the following functionality:
+ (1). Multiple threads could be simultaneously trying to enqueue
+ and dequeue. Hence the queue needs to be protected with mutex.
+ (2). In case the queue is empty, dequeue() sleeps for a specified
+ amount of time, or until a new element is inserted, whichever
+ is earlier
+
+
+ ****************************************************************************/
+#pragma once
+
+#include "tscore/ink_platform.h"
+#include "Event.h"
+struct ProtectedQueue {
+ void enqueue(Event *e);
+ void signal();
+ int try_signal(); // Use non blocking lock and if acquired, signal
+ void enqueue_local(Event *e); // Safe when called from the same thread
+ Event *dequeue_local();
+ void dequeue_external(); // Dequeue any external events.
+ void wait(ink_hrtime timeout); // Wait for @a timeout nanoseconds on a condition variable if there are no events.
+
+ InkAtomicList al;
+ ink_mutex lock;
+ ink_cond might_have_data;
+ Que(Event, link) localQueue;
+
+ ProtectedQueue();
+};
diff --git a/iocore/eventsystem/I_ProxyAllocator.h b/include/iocore/eventsystem/ProxyAllocator.h
similarity index 100%
rename from iocore/eventsystem/I_ProxyAllocator.h
rename to include/iocore/eventsystem/ProxyAllocator.h
diff --git a/include/iocore/eventsystem/RecProcess.h b/include/iocore/eventsystem/RecProcess.h
new file mode 100644
index 0000000000..59b04e508b
--- /dev/null
+++ b/include/iocore/eventsystem/RecProcess.h
@@ -0,0 +1,40 @@
+/** @file
+
+Public RecProcess declarations
+
+ @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 "records/RecDefs.h"
+#include "tscore/Diags.h"
+
+//-------------------------------------------------------------------------
+// Initialization/Starting
+//-------------------------------------------------------------------------
+int RecProcessInit(Diags *diags = nullptr);
+int RecProcessStart();
+
+//-------------------------------------------------------------------------
+// Setters for manipulating internal sleep intervals
+//-------------------------------------------------------------------------
+void RecProcess_set_raw_stat_sync_interval_ms(int ms);
+void RecProcess_set_config_update_interval_ms(int ms);
+void RecProcess_set_remote_sync_interval_ms(int ms);
diff --git a/iocore/eventsystem/I_SocketManager.h b/include/iocore/eventsystem/SocketManager.h
similarity index 100%
rename from iocore/eventsystem/I_SocketManager.h
rename to include/iocore/eventsystem/SocketManager.h
diff --git a/include/iocore/eventsystem/Tasks.h b/include/iocore/eventsystem/Tasks.h
new file mode 100644
index 0000000000..84ff2515ca
--- /dev/null
+++ b/include/iocore/eventsystem/Tasks.h
@@ -0,0 +1,38 @@
+/** @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 "EventSystem.h"
+
+extern EventType ET_TASK;
+
+class TasksProcessor : public Processor
+{
+public:
+ EventType register_event_type();
+ int start(int task_threads, size_t stacksize = DEFAULT_STACKSIZE) override;
+};
+
+extern TasksProcessor tasksProcessor;
diff --git a/include/iocore/eventsystem/Thread.h b/include/iocore/eventsystem/Thread.h
new file mode 100644
index 0000000000..97d427ab08
--- /dev/null
+++ b/include/iocore/eventsystem/Thread.h
@@ -0,0 +1,170 @@
+/** @file
+
+ Thread
+
+ @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.
+
+ @section details Details
+
+ Thread class provides the basic functionality for threads. Typically,
+ there will be additional derived classes. Having a common base class
+ for all threads is useful in many cases. I discuss below the use of
+ Threads in the context of Event Subsystem. Hopefully this would be
+ typical of other situations.
+
+ EventProcessor needs to create a bunch of threads. It declares a
+ class called EThread, derived from Thread. It is the responsibility of
+ the EventProcessor to create and manage all the threads needed in the
+ Event Subsystem (Note: we have removed the original ThreadManager class
+ which used to create and manage *all* the threads in the system). By
+ monitoring, we mean checking the heartbeat of each thread and the
+ number of threads in the system etc.
+
+ A derived class should either provide the function (and arguments)
+ needed by the Thread class (see start()), or should define the virtual
+ function execute().
+
+ The Thread class maintains a thread_key which registers *all*
+ the threads in the system (that have been created using Thread or
+ a derived class), using thread specific data calls. Whenever, you
+ call this_thread() you get a pointer to the Thread that is currently
+ executing you. Additionally, the EThread class (derived from Thread)
+ maintains its own independent key. All (and only) the threads created
+ in the Event Subsystem are registered with this key. Thus, whenever you
+ call this_ethread() you get a pointer to EThread. If you happen to call
+ this_ethread() from inside a thread which is not an EThread, you will
+ get a nullptr value (since that thread will not be registered with the
+ EThread key). This will hopefully make the use of this_ethread() safer.
+ Note that an event created with EThread can also call this_thread(),
+ in which case, it will get a pointer to Thread (rather than to EThread).
+
+ */
+
+#pragma once
+
+#include <functional>
+
+#include "ProxyAllocator.h"
+#include "tscore/Ptr.h"
+#include "tscore/ink_platform.h"
+#include "tscore/ink_thread.h"
+
+class ProxyMutex;
+
+constexpr int MAX_THREAD_NAME_LENGTH = 16;
+
+/// The signature of a function to be called by a thread.
+using ThreadFunction = std::function<void()>;
+
+/**
+ Base class for the threads in the Event System. Thread is the base
+ class for all the thread classes in the Event System. Objects of the
+ Thread class represent spawned or running threads and provide minimal
+ information for its derived classes. Thread objects have a reference
+ to a ProxyMutex, that is used for atomic operations internally, and
+ an ink_thread member that is used to identify the thread in the system.
+
+ You should not create an object of the Thread class, they are typically
+ instantiated after some thread startup mechanism exposed by a processor,
+ but even then you would probably deal with processor functions and
+ not the Thread object itself.
+
+*/
+class Thread
+{
+public:
+ /**
+ System-wide thread identifier. The thread identifier is represented
+ by the platform independent type ink_thread and it is the system-wide
+ value assigned to each thread. It is exposed as a convenience for
+ processors and you should not modify it directly.
+
+ */
+ // NOLINTNEXTLINE(modernize-use-nullptr)
+ ink_thread tid = 0;
+
+ /**
+ Thread lock to ensure atomic operations. The thread lock available
+ to derived classes to ensure atomic operations and protect critical
+ regions. Do not modify this member directly.
+
+ */
+ Ptr<ProxyMutex> mutex;
+
+ virtual void set_specific() = 0;
+
+ static thread_local Thread *this_thread_ptr;
+
+ // For THREAD_ALLOC
+ ProxyAllocator eventAllocator;
+ ProxyAllocator netVCAllocator;
+ ProxyAllocator sslNetVCAllocator;
+ ProxyAllocator quicNetVCAllocator;
+ ProxyAllocator http1ClientSessionAllocator;
+ ProxyAllocator http2ClientSessionAllocator;
+ ProxyAllocator http2ServerSessionAllocator;
+ ProxyAllocator http2StreamAllocator;
+ ProxyAllocator httpSMAllocator;
+ ProxyAllocator quicClientSessionAllocator;
+ ProxyAllocator httpServerSessionAllocator;
+ ProxyAllocator hdrHeapAllocator;
+ ProxyAllocator strHeapAllocator;
+ ProxyAllocator cacheVConnectionAllocator;
+ ProxyAllocator cacheEvacuateDocVConnectionAllocator;
+ ProxyAllocator openDirEntryAllocator;
+ ProxyAllocator ramCacheCLFUSEntryAllocator;
+ ProxyAllocator ramCacheLRUEntryAllocator;
+ ProxyAllocator evacuationBlockAllocator;
+ ProxyAllocator ioDataAllocator;
+ ProxyAllocator ioAllocator;
+ ProxyAllocator ioBlockAllocator;
+ ProxyAllocator preWarmSMAllocator;
+ // From InkAPI (plugins wrappers)
+ ProxyAllocator apiHookAllocator;
+ ProxyAllocator INKContAllocator;
+ ProxyAllocator INKVConnAllocator;
+ ProxyAllocator mHandleAllocator;
+
+ /** Start the underlying thread.
+
+ The thread name is set to @a name. The stack for the thread is either @a stack or, if that is
+ @c nullptr a stack of size @a stacksize is allocated and used. If @a f is present and valid it
+ is called in the thread context. Otherwise the method @c execute is invoked.
+ */
+ void start(const char *name, void *stack, size_t stacksize, ThreadFunction const &f = ThreadFunction());
+
+ virtual void execute() = 0;
+
+ /** Get the current ATS high resolution time.
+ This gets a cached copy of the time so it is very fast and reasonably accurate.
+ The cached time is updated every time the actual operating system time is fetched which is
+ at least every 10ms and generally more frequently.
+
+ @note The cached copy is thread local which means each thread need to update the cached copy by itself.
+ */
+
+ Thread(const Thread &) = delete;
+ Thread &operator=(const Thread &) = delete;
+ virtual ~Thread();
+
+protected:
+ Thread();
+};
+
+extern Thread *this_thread();
diff --git a/include/iocore/eventsystem/VConnection.h b/include/iocore/eventsystem/VConnection.h
new file mode 100644
index 0000000000..d81a630d8d
--- /dev/null
+++ b/include/iocore/eventsystem/VConnection.h
@@ -0,0 +1,413 @@
+/** @file
+
+ Public VConnection declaration and associated declarations
+
+ @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 "tscore/ink_platform.h"
+#include "tscore/PluginUserArgs.h"
+#include "EventSystem.h"
+
+#if !defined(I_VIO_h)
+#error "include VIO.h"
+#endif
+
+//
+// Data Types
+//
+#define VCONNECTION_CACHE_DATA_BASE 0
+#define VCONNECTION_NET_DATA_BASE 100
+#define VCONNECTION_API_DATA_BASE 200
+
+//
+// Event signals
+//
+
+#define VC_EVENT_NONE EVENT_NONE
+
+/** When a Continuation is first scheduled on a processor. */
+#define VC_EVENT_IMMEDIATE EVENT_IMMEDIATE
+
+#define VC_EVENT_READ_READY VC_EVENT_EVENTS_START
+
+/**
+ Any data in the associated buffer *will be written* when the
+ Continuation returns.
+
+*/
+#define VC_EVENT_WRITE_READY (VC_EVENT_EVENTS_START + 1)
+
+#define VC_EVENT_READ_COMPLETE (VC_EVENT_EVENTS_START + 2)
+#define VC_EVENT_WRITE_COMPLETE (VC_EVENT_EVENTS_START + 3)
+
+/**
+ No more data (end of stream). It should be interpreted by a
+ protocol engine as either a COMPLETE or ERROR.
+
+*/
+#define VC_EVENT_EOS (VC_EVENT_EVENTS_START + 4)
+
+#define VC_EVENT_ERROR EVENT_ERROR
+
+/**
+ VC_EVENT_INACTIVITY_TIMEOUT indicates that the operation (read or write) has:
+ -# been enabled for more than the inactivity timeout period
+ (for a read, there has been space in the buffer)
+ (for a write, there has been data in the buffer)
+ -# no progress has been made
+ (for a read, no data has been read from the connection)
+ (for a write, no data has been written to the connection)
+
+*/
+#define VC_EVENT_INACTIVITY_TIMEOUT (VC_EVENT_EVENTS_START + 5)
+
+/**
+ Total time for some operation has been exceeded, regardless of any
+ intermediate progress.
+
+*/
+#define VC_EVENT_ACTIVE_TIMEOUT (VC_EVENT_EVENTS_START + 6)
+
+//
+// Event names
+//
+
+//
+// VC_EVENT_READ_READ occurs when data *has been written* into
+// the associated buffer.
+//
+// VC_EVENT_ERROR indicates that some error has occurred. The
+// "data" will be either 0 if the errno is unavailable or errno.
+//
+// VC_EVENT_INTERVAL indicates that an interval timer has expired.
+//
+
+//
+// Event return codes
+//
+#define VC_EVENT_DONE CONTINUATION_DONE
+#define VC_EVENT_CONT CONTINUATION_CONT
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Support Data Structures
+//
+//////////////////////////////////////////////////////////////////////////////
+
+/** Used in VConnection::shutdown(). */
+enum ShutdownHowTo_t {
+ IO_SHUTDOWN_READ = 0,
+ IO_SHUTDOWN_WRITE,
+ IO_SHUTDOWN_READWRITE,
+};
+
+/** Used in VConnection::get_data(). */
+enum TSApiDataType {
+ TS_API_DATA_READ_VIO = VCONNECTION_API_DATA_BASE,
+ TS_API_DATA_WRITE_VIO,
+ TS_API_DATA_OUTPUT_VC,
+ TS_API_DATA_CLOSED,
+ TS_API_DATA_LAST ///< Used by other classes to extend the enum values.
+};
+
+typedef struct tsapi_vio *TSVIO;
+
+/**
+ Base class for the connection classes that provide IO capabilities.
+
+ The VConnection class is an abstract representation of a uni or
+ bi-directional data conduit returned by a Processor. In a sense,
+ they serve a similar purpose to file descriptors. A VConnection
+ is a pure base class that defines methods to perform stream IO.
+ It is also a Continuation that is called back from processors.
+
+*/
+class VConnection : public Continuation
+{
+public:
+ ~VConnection() override;
+
+ /**
+ Read data from the VConnection.
+
+ Called by a state machine to read data from the VConnection.
+ Processors implementing read functionality take out lock, put
+ new bytes on the buffer and call the continuation back before
+ releasing the lock in order to enable the state machine to
+ handle transfer schemes where the end of a given transaction
+ is marked by a special character (ie: NNTP).
+
+ <b>Possible Event Codes</b>
+
+ On the callback to the continuation, the VConnection may use
+ on of the following values for the event code:
+
+ <table border="1">
+ <tr>
+ <td align="center"><b>Event code</b></td>
+ <td align="center"><b>Meaning</b></td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_READ_READY</td>
+ <td>Data has been added to the buffer or the buffer is full</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_READ_COMPLETE</td>
+ <td>The amount of data indicated by 'nbytes' has been read into the
+ buffer</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_EOS</td>
+ <td>The stream being read from has been shutdown</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_ERROR</td>
+ <td>An error occurred during the read</td>
+ </tr>
+ </table>
+
+ @param c Continuation to be called back with events.
+ @param nbytes Number of bytes to read. If unknown, nbytes must
+ be set to INT64_MAX.
+ @param buf buffer to read into.
+ @return VIO representing the scheduled IO operation.
+
+ */
+ virtual VIO *do_io_read(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) = 0;
+
+ /**
+ Write data to the VConnection.
+
+ This method is called by a state machine to write data to the
+ VConnection.
+
+ <b>Possible Event Codes</b>
+
+ On the callback to the continuation, the VConnection may use
+ on of the following event codes:
+
+ <table border="1">
+ <tr>
+ <td align="center"><b>Event code</b></td>
+ <td align="center"><b>Meaning</b></td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_WRITE_READY</td>
+ <td>Data was written from the reader or there are no bytes available
+ for the reader to write.</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_WRITE_COMPLETE</td>
+ <td>The amount of data indicated by 'nbytes' has been written to the
+ VConnection</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_INACTIVITY_TIMEOUT</td>
+ <td>No activity was performed for a certain period.</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_ACTIVE_TIMEOUT</td>
+ <td>Write operation continued beyond a time limit.</td>
+ </tr>
+ <tr>
+ <td>VC_EVENT_ERROR</td>
+ <td>An error occurred during the write</td>
+ </tr>
+ </table>
+
+ @param c Continuation to be called back with events.
+ @param nbytes Number of bytes to write. If unknown, nbytes must
+ be set to INT64_MAX.
+ @param buf Reader whose data is to be read from.
+ @param owner
+ @return VIO representing the scheduled IO operation.
+
+ */
+ virtual VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = nullptr,
+ bool owner = false) = 0;
+
+ /**
+ Indicate that the VConnection is no longer needed.
+
+ Once the state machine has finished using this VConnection, it
+ must call this function to indicate that the VConnection can
+ be deallocated. After a close has been called, the VConnection
+ and underlying processor must not send any more events related
+ to this VConnection to the state machine. Likewise, the state
+ machine must not access the VConnection or any VIOs obtained
+ from it after calling this method.
+
+ @param lerrno indicates where a close is a normal close or an
+ abort. The difference between a normal close and an abort
+ depends on the underlying type of the VConnection.
+
+ */
+ virtual void do_io_close(int lerrno = -1) = 0;
+
+ /**
+ Terminate one or both directions of the VConnection.
+
+ Indicates that one or both sides of the VConnection should be
+ terminated. After this call is issued, no further I/O can be
+ done on the specified direction of the connection. The processor
+ must not send any further events (including timeout events) to
+ the state machine, and the state machine must not use any VIOs
+ from a shutdown direction of the connection. Even if both sides
+ of a connection are shutdown, the state machine must still call
+ do_io_close() when it wishes the VConnection to be deallocated.
+
+ <b>Possible howto values</b>
+
+ <table border="1">
+ <tr>
+ <td align="center"><b>Value</b></td>
+ <td align="center"><b>Meaning</b></td>
+ </tr>
+ <tr>
+ <td>IO_SHUTDOWN_READ</td>
+ <td>Indicates that this VConnection should not generate any more
+ read events</td>
+ </tr>
+ <tr>
+ <td>IO_SHUTDOWN_WRITE</td>
+ <td>Indicates that this VConnection should not generate any more
+ write events</td>
+ </tr>
+ <tr>
+ <td>IO_SHUTDOWN_READWRITE</td>
+ <td>Indicates that this VConnection should not generate any more
+ read nor write events</td>
+ </tr>
+ </table>
+
+ @param howto Specifies which direction of the VConnection to
+ shutdown.
+
+ */
+ virtual void do_io_shutdown(ShutdownHowTo_t howto) = 0;
+
+ explicit VConnection(ProxyMutex *aMutex);
+ explicit VConnection(Ptr<ProxyMutex> &aMutex);
+
+ // Private
+ // Set continuation on a given vio. The public interface
+ // is through VIO::set_continuation()
+ virtual void set_continuation(VIO *vio, Continuation *cont);
+
+ // Reenable a given vio. The public interface is through VIO::reenable
+ virtual void reenable(VIO *vio);
+ virtual void reenable_re(VIO *vio);
+
+ /**
+ Convenience function to retrieve information from VConnection.
+
+ This function is provided as a convenience for state machines
+ to transmit information from/to a VConnection without breaking
+ the VConnection abstraction. Its behavior varies depending on
+ the type of VConnection being used.
+
+ @param id Identifier associated to interpret the data field
+ @param data Value or pointer with state machine or VConnection data.
+ @return True if the operation is successful.
+
+ */
+ virtual bool
+ get_data(int id, void *data)
+ {
+ (void)id;
+ (void)data;
+ return false;
+ }
+
+ /**
+ Convenience function to set information into the VConnection.
+
+ This function is provided as a convenience for state machines
+ to transmit information from/to a VConnection without breaking
+ the VConnection abstraction. Its behavior varies depending on
+ the type of VConnection being used.
+
+ @param id Identifier associated to interpret the data field.
+ @param data Value or pointer with state machine or VConnection data.
+ @return True if the operation is successful.
+
+ */
+ virtual bool
+ set_data(int id, void *data)
+ {
+ (void)id;
+ (void)data;
+ return false;
+ }
+
+ // This function should be called when the VConnection is a tunnel endpoint. By default, a VConnection does not care if it
+ // is a tunnel endpoint.
+ virtual void
+ mark_as_tunnel_endpoint()
+ {
+ }
+
+ /**
+ The error code from the last error.
+
+ Indicates the last error on the VConnection. They are either
+ system error codes or from the InkErrno.h file.
+
+ */
+ int lerrno;
+};
+
+struct DummyVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VCONN> {
+ VIO *
+ do_io_write(Continuation * /* c ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */, IOBufferReader * /* buf ATS_UNUSED */,
+ bool /* owner ATS_UNUSED */) override
+ {
+ ink_assert(!"VConnection::do_io_write -- "
+ "cannot use default implementation");
+ return nullptr;
+ }
+
+ VIO *
+ do_io_read(Continuation * /* c ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */, MIOBuffer * /* buf ATS_UNUSED */) override
+ {
+ ink_assert(!"VConnection::do_io_read -- "
+ "cannot use default implementation");
+ return nullptr;
+ }
+
+ void
+ do_io_close(int /* alerrno ATS_UNUSED */) override
+ {
+ ink_assert(!"VConnection::do_io_close -- "
+ "cannot use default implementation");
+ }
+
+ void
+ do_io_shutdown(ShutdownHowTo_t /* howto ATS_UNUSED */) override
+ {
+ ink_assert(!"VConnection::do_io_shutdown -- "
+ "cannot use default implementation");
+ }
+
+ explicit DummyVConnection(ProxyMutex *m) : VConnection(m) {}
+};
diff --git a/include/iocore/eventsystem/VIO.h b/include/iocore/eventsystem/VIO.h
new file mode 100644
index 0000000000..8099b212c1
--- /dev/null
+++ b/include/iocore/eventsystem/VIO.h
@@ -0,0 +1,223 @@
+/** @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
+#define I_VIO_h
+
+#if !defined(I_IOBuffer_h)
+#error "include IOBuffer.h"
+#endif
+
+class Continuation;
+class VConnection;
+class ProxyMutex;
+
+/**
+ Descriptor for an IO operation.
+
+ A VIO is a descriptor for an in progress IO operation. It is
+ returned from do_io_read() and do_io_write() methods on VConnections.
+ Through the VIO, the state machine can monitor the progress of
+ an operation and reenable the operation when data becomes available.
+
+ The VIO operation represents several types of operations, and
+ they can be identified through the 'op' member. It can take any
+ of the following values:
+
+ <table>
+ <tr>
+ <td align="center"><b>Constant</b></td>
+ <td align="center"><b>Meaning</b></td>
+ </tr>
+ <tr><td>READ</td><td>The VIO represents a read operation</td></tr>
+ <tr><td>WRITE</td><td>The VIO represents a write operation</td></tr>
+ <tr><td>CLOSE</td><td>The VIO represents the request to close the
+ VConnection</td></tr>
+ <tr><td>ABORT</td><td></td></tr>
+ <tr><td>SHUTDOWN_READ</td><td></td></tr>
+ <tr><td>SHUTDOWN_WRITE</td><td></td></tr>
+ <tr><td>SHUTDOWN_READWRITE</td><td></td></tr>
+ <tr><td>SEEK</td><td></td></tr>
+ <tr><td>PREAD</td><td></td></tr>
+ <tr><td>PWRITE</td><td></td></tr>
+ <tr><td>STAT</td><td></td></tr>
+ </table>
+
+*/
+class VIO
+{
+public:
+ explicit VIO(int aop);
+ VIO();
+ ~VIO() {}
+
+ /** Interface for the VConnection that owns this handle. */
+ Continuation *get_continuation() const;
+ void set_continuation(Continuation *cont);
+
+ /**
+ Set nbytes to be what is current available.
+
+ Interface to set nbytes to be ndone + buffer.reader()->read_avail()
+ if a reader is set.
+ */
+ void done();
+
+ /**
+ Determine the number of bytes remaining.
+
+ Convenience function to determine how many bytes the operation
+ has remaining.
+
+ @return The number of bytes to be processed by the operation.
+
+ */
+ int64_t ntodo() const;
+
+ /////////////////////
+ // buffer settings //
+ /////////////////////
+ void set_writer(MIOBuffer *writer);
+ void set_reader(IOBufferReader *reader);
+ MIOBuffer *get_writer() const;
+ IOBufferReader *get_reader() const;
+
+ /**
+ Reenable the IO operation.
+
+ Interface that the state machine uses to reenable an I/O
+ operation. Reenable tells the VConnection that more data is
+ available for the operation and that it should try to continue
+ the operation in progress. I/O operations become disabled when
+ they can make no forward progress. For a read this means that
+ it's buffer is full. For a write, that it's buffer is empty.
+ If reenable is called and progress is still not possible, it
+ is ignored and no events are generated. However, unnecessary
+ reenables (ones where no progress can be made) should be avoided
+ as they hurt system throughput and waste CPU.
+
+ */
+ void reenable();
+
+ /**
+ Reenable the IO operation.
+
+ Interface that the state machine uses to reenable an I/O
+ operation. Reenable tells the VConnection that more data is
+ available for the operation and that it should try to continue
+ the operation in progress. I/O operations become disabled when
+ they can make no forward progress. For a read this means that
+ it's buffer is full. For a write, that it's buffer is empty.
+ If reenable is called and progress is still not possible, it
+ is ignored and no events are generated. However, unnecessary
+ reenables (ones where no progress can be made) should be avoided
+ as they hurt system throughput and waste CPU.
+
+ */
+ void reenable_re();
+
+ void disable();
+ bool is_disabled() const;
+
+ enum {
+ NONE = 0,
+ READ,
+ WRITE,
+ CLOSE,
+ ABORT,
+ SHUTDOWN_READ,
+ SHUTDOWN_WRITE,
+ SHUTDOWN_READWRITE,
+ SEEK,
+ PREAD,
+ PWRITE,
+ STAT,
+ };
+
+ /**
+ Continuation to callback.
+
+ Used by the VConnection to store who is the continuation to
+ call with events for this operation.
+
+ */
+ Continuation *cont = nullptr;
+
+ /**
+ Number of bytes to be done for this operation.
+
+ The total number of bytes this operation must complete.
+
+ */
+ int64_t nbytes = 0;
+
+ /**
+ Number of bytes already completed.
+
+ The number of bytes that already have been completed for the
+ operation. Processor can update this value only if they hold
+ the lock.
+
+ */
+ int64_t ndone = 0;
+
+ /**
+ Type of operation.
+
+ The type of operation that this VIO represents.
+
+ */
+ int op = VIO::NONE;
+
+ // This is a little odd location, but this saves on padding, and an entire cache line
+private:
+ bool _disabled = false;
+
+public:
+ /**
+ Provides access to the reader or writer for this operation.
+
+ Contains a pointer to the IOBufferReader if the operation is a
+ write and a pointer to a MIOBuffer if the operation is a read.
+
+ */
+ MIOBufferAccessor buffer;
+
+ /**
+ Internal backpointer to the VConnection for use in the reenable
+ functions.
+
+ */
+ VConnection *vc_server = nullptr;
+
+ /**
+ Reference to the state machine's mutex.
+
+ Maintains a reference to the state machine's mutex to allow
+ processors to safely lock the operation even if the state machine
+ has closed the VConnection and deallocated itself.
+
+ */
+ Ptr<ProxyMutex> mutex;
+};
diff --git a/include/iocore/hostdb/HostDB.h b/include/iocore/hostdb/HostDB.h
new file mode 100644
index 0000000000..61c488c50e
--- /dev/null
+++ b/include/iocore/hostdb/HostDB.h
@@ -0,0 +1,41 @@
+/** @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.
+ */
+
+/****************************************************************************
+
+ I_HostDB.h
+
+
+ ****************************************************************************/
+
+#pragma once
+
+#include "EventSystem.h"
+#include "Net.h"
+
+#include "HostDBProcessor.h"
+
+// TS-1925: switch from MMH to MD5 hash; bumped to version 2
+// switch from MD5 to SHA256 hash; bumped to version 3
+// 2.1: Switched to mark RR elements.
+static constexpr ts::ModuleVersion HOSTDB_MODULE_PUBLIC_VERSION(3, 1);
diff --git a/include/iocore/hostdb/HostDBProcessor.h b/include/iocore/hostdb/HostDBProcessor.h
new file mode 100644
index 0000000000..760a8924dc
--- /dev/null
+++ b/include/iocore/hostdb/HostDBProcessor.h
@@ -0,0 +1,887 @@
+/** @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 <chrono>
+#include <atomic>
+
+#include "tscore/HashFNV.h"
+#include "tscore/ink_time.h"
+#include "tscore/CryptoHash.h"
+#include "tscore/ink_align.h"
+#include "tscore/ink_inet.h"
+#include "tscore/ink_resolver.h"
+#include "tscore/HTTPVersion.h"
+
+#include "swoc/MemSpan.h"
+
+#include "EventSystem.h"
+#include "SRV.h"
+
+// Event returned on a lookup
+#define EVENT_HOST_DB_LOOKUP (HOSTDB_EVENT_EVENTS_START + 0)
+#define EVENT_HOST_DB_IP_REMOVED (HOSTDB_EVENT_EVENTS_START + 1)
+#define EVENT_HOST_DB_GET_RESPONSE (HOSTDB_EVENT_EVENTS_START + 2)
+
+#define EVENT_SRV_LOOKUP (SRV_EVENT_EVENTS_START + 0)
+#define EVENT_SRV_IP_REMOVED (SRV_EVENT_EVENTS_START + 1)
+#define EVENT_SRV_GET_RESPONSE (SRV_EVENT_EVENTS_START + 2)
+
+//
+// Data
+//
+struct HostDBContinuation;
+struct ResolveInfo;
+
+//
+// The host database stores host information, most notably the
+// IP address.
+//
+// Since host information is relatively small, we can afford to have
+// a reasonable size memory cache, and use a (relatively) sparse
+// disk representation to decrease # of seeks.
+//
+extern int hostdb_enable;
+/** Epoch timestamp of the current hosts file check.
+ *
+ * This also functions as a cached version of ts_clock::now(). Since it is
+ * updated in backgroundEvent which runs every second, it should be
+ * approximately accurate to a second.
+ */
+extern std::atomic<ts_time> hostdb_current_timestamp;
+
+/** How long before any DNS response is consided stale, regardless of DNS TTL.
+ * This corresponds to proxy.config.hostdb.verify_after.
+ */
+extern unsigned int hostdb_ip_stale_interval;
+extern unsigned int hostdb_ip_timeout_interval;
+extern unsigned int hostdb_ip_fail_timeout_interval;
+extern unsigned int hostdb_serve_stale_but_revalidate;
+extern unsigned int hostdb_round_robin_max_count;
+
+extern int hostdb_max_iobuf_index;
+
+static inline unsigned int
+makeHostHash(const char *string)
+{
+ ink_assert(string && *string);
+
+ if (string && *string) {
+ ATSHash32FNV1a fnv;
+ fnv.update(string, strlen(string), ATSHash::nocase());
+ fnv.final();
+ return fnv.get();
+ }
+
+ return 0;
+}
+
+//
+// Types
+//
+
+class HostDBRecord;
+
+/// Information for an SRV record.
+struct SRVInfo {
+ unsigned int srv_offset : 16; ///< Memory offset from @c HostDBInfo to name.
+ unsigned int srv_weight : 16;
+ unsigned int srv_priority : 16;
+ unsigned int srv_port : 16;
+ unsigned int key;
+};
+
+/// Type of data stored.
+enum class HostDBType : uint8_t {
+ UNSPEC, ///< No valid data.
+ ADDR, ///< IP address.
+ SRV, ///< SRV record.
+ HOST ///< Hostname (reverse DNS)
+};
+char const *name_of(HostDBType t);
+
+/** Information about a single target.
+ */
+struct HostDBInfo {
+ using self_type = HostDBInfo; ///< Self reference type.
+
+ /// Default constructor.
+ HostDBInfo() = default;
+
+ HostDBInfo &operator=(HostDBInfo const &that);
+
+ /// Absolute time of when this target failed.
+ /// A value of zero (@c TS_TIME_ZERO ) indicates no failure.
+ ts_time last_fail_time() const;
+
+ /// Target is alive - no known failure.
+ bool is_alive();
+
+ /// Target has failed and is still in the blocked time window.
+ bool is_down(ts_time now, ts_seconds fail_window);
+
+ /** Select this target.
+ *
+ * @param now Current time.
+ * @param fail_window Failure window.
+ * @return Status of the selection.
+ *
+ * If a zombie is selected the failure time is updated to make it appear down to other threads in a thread safe
+ * manner. The caller should check @c last_fail_time to see if a zombie was selected.
+ */
+ bool select(ts_time now, ts_seconds fail_window);
+
+ /// Check if this info is valid.
+ bool is_valid() const;
+
+ /// Mark this info as invalid.
+ void invalidate();
+
+ /** Mark the entry as down.
+ *
+ * @param now Time of the failure.
+ * @return @c true if @a this was marked down, @c false if not.
+ *
+ * This can return @c false if the entry is already marked down, in which case the failure time is not updated.
+ */
+ bool mark_down(ts_time now);
+
+ /** Mark the target as up / alive.
+ *
+ * @return Previous alive state of the target.
+ */
+ bool mark_up();
+
+ char const *srvname() const;
+
+ /** Migrate data after a DNS update.
+ *
+ * @param that Source item.
+ *
+ * This moves only specific state information, it is not a generic copy.
+ */
+ void migrate_from(self_type const &that);
+
+ /// A target is either an IP address or an SRV record.
+ /// The type should be indicated by @c flags.f.is_srv;
+ union {
+ IpAddr ip; ///< IP address / port data.
+ SRVInfo srv; ///< SRV record.
+ } data{IpAddr{}};
+
+ /// Data that migrates after updated DNS records are processed.
+ /// @see migrate_from
+ /// @{
+ /// Last time a failure was recorded.
+ std::atomic<ts_time> last_failure{TS_TIME_ZERO};
+ /// Count of connection failures
+ std::atomic<uint8_t> fail_count{0};
+ /// Expected HTTP version of the target based on earlier transactions.
+ HTTPVersion http_version = HTTP_INVALID;
+ /// @}
+
+ self_type &assign(IpAddr const &addr);
+
+protected:
+ self_type &assign(sa_family_t af, void const *addr);
+ self_type &assign(SRV const *srv, char const *name);
+
+ HostDBType type = HostDBType::UNSPEC; ///< Invalid data.
+
+ friend HostDBContinuation;
+};
+
+inline HostDBInfo &
+HostDBInfo::operator=(HostDBInfo const &that)
+{
+ if (this != &that) {
+ memcpy(static_cast<void *>(this), static_cast<const void *>(&that), sizeof(*this));
+ }
+ return *this;
+}
+
+inline ts_time
+HostDBInfo::last_fail_time() const
+{
+ return last_failure;
+}
+
+inline bool
+HostDBInfo::is_alive()
+{
+ return this->last_fail_time() == TS_TIME_ZERO;
+}
+
+inline bool
+HostDBInfo::is_down(ts_time now, ts_seconds fail_window)
+{
+ auto last_fail = this->last_fail_time();
+ return (last_fail != TS_TIME_ZERO) && (last_fail + fail_window < now);
+}
+
+inline bool
+HostDBInfo::mark_up()
+{
+ auto t = last_failure.exchange(TS_TIME_ZERO);
+ return t != TS_TIME_ZERO;
+}
+
+inline bool
+HostDBInfo::mark_down(ts_time now)
+{
+ auto t0{TS_TIME_ZERO};
+ return last_failure.compare_exchange_strong(t0, now);
+}
+
+inline bool
+HostDBInfo::select(ts_time now, ts_seconds fail_window)
+{
+ auto t0 = this->last_fail_time();
+ if (t0 == TS_TIME_ZERO) {
+ return true; // it's alive and so is valid for selection.
+ }
+ // Success means this is a zombie and this thread updated the failure time.
+ return (t0 + fail_window < now) && last_failure.compare_exchange_strong(t0, now);
+}
+
+inline void
+HostDBInfo::migrate_from(HostDBInfo::self_type const &that)
+{
+ this->last_failure = that.last_failure.load();
+ this->http_version = that.http_version;
+}
+
+inline bool
+HostDBInfo::is_valid() const
+{
+ return type != HostDBType::UNSPEC;
+}
+
+inline void
+HostDBInfo::invalidate()
+{
+ type = HostDBType::UNSPEC;
+}
+
+// ----
+/** Root item for HostDB.
+ * This is the container for HostDB data. It is always an array of @c HostDBInfo instances plus metadata.
+ * All strings are C-strings and therefore don't need a distinct size.
+ *
+ */
+class HostDBRecord : public RefCountObj
+{
+ friend struct HostDBContinuation;
+ friend struct ShowHostDB;
+ using self_type = HostDBRecord;
+
+ /// Size of the IO buffer block owned by @a this.
+ /// If negative @a this is in not allocated memory.
+ int _iobuffer_index{-1};
+ /// Actual size of the data.
+ unsigned _record_size = sizeof(self_type);
+
+public:
+ HostDBRecord() = default;
+ HostDBRecord(self_type const &that) = delete;
+
+ using Handle = Ptr<HostDBRecord>; ///< Shared pointer type to hold an instance.
+
+ /** Allocate an instance from the IOBuffers.
+ *
+ * @param query_name Name of the query for the record.
+ * @param rr_count Number of info instances.
+ * @param srv_name_size Storage for SRV names, if any.
+ * @return An instance sufficient to hold the specified data.
+ *
+ * The query name will stored and initialized, and the info instances initialized.
+ */
+ static self_type *alloc(swoc::TextView query_name, unsigned rr_count, size_t srv_name_size = 0);
+
+ /// Type of data stored in this record.
+ HostDBType record_type = HostDBType::UNSPEC;
+
+ /// IP family of this record.
+ sa_family_t af_family = AF_UNSPEC;
+
+ /// Offset from @a this to the VLA.
+ unsigned short rr_offset = 0;
+
+ /// Number of @c HostDBInfo instances.
+ unsigned short rr_count = 0;
+
+ /// Timing data for switch records in the RR.
+ std::atomic<ts_time> rr_ctime{TS_TIME_ZERO};
+
+ /// Hash key.
+ uint64_t key{0};
+
+ /// When the DNS response was received.
+ ts_time ip_timestamp;
+
+ /// Valid duration of the DNS response data.
+ /// In the code this functions as the TTL in HostDB calculations, but may not
+ /// be the response's TTL based upon configuration such as
+ /// proxy.config.hostdb.ttl_mode.
+ ts_seconds ip_timeout_interval;
+
+ /** Atomically advance the round robin index.
+ *
+ * If multiple threads call this simultaneously each thread will get a distinct return value.
+ *
+ * @return The new round robin index.
+ */
+ unsigned next_rr();
+
+ /** Pick the next round robin and update the record atomically.
+ *
+ * @note This may select a zombie server and reserve it for the caller, therefore the caller must
+ * attempt to connect to the selected target if possible.
+ *
+ * @param now Current time to use for aliveness calculations.
+ * @param fail_window Blackout time for down servers.
+ * @return Status of the updated target.
+ *
+ * If the return value is @c HostDBInfo::Status::DOWN this means all targets are down and there is
+ * no valid upstream.
+ *
+ * @note Concurrency - this is not done under lock and depends on the caller for correct use.
+ * For strict round robin, it is a feature that every call will get a distinct index. For
+ * timed round robin, the caller must arrange to have only one thread call this per time interval.
+ */
+ HostDBInfo *select_next_rr(ts_time now, ts_seconds fail_window);
+
+ /// Check if this record is of SRV targets.
+ bool is_srv() const;
+
+ /** Query name for the record.
+ * @return A C-string.
+ * If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
+ * Otherwise this is the name used in the DNS query.
+ */
+ char const *name() const;
+
+ /** Query name for the record.
+ * @return A view.
+ * If this is a @c HOST record, this is the resolved named and the query was based on the IP address.
+ * Otherwise this is the name used in the DNS query.
+ * @note Although not included in the view, the name is always nul terminated and the string can
+ * be used as a C-string.
+ */
+ swoc::TextView name_view() const;
+
+ /// Get the array of info instances.
+ swoc::MemSpan<HostDBInfo> rr_info();
+
+ /** Find a host record by IP address.
+ *
+ * @param addr Address key.
+ * @return A pointer to the info instance if a match is found, @c nullptr if not.
+ */
+ HostDBInfo *find(sockaddr const *addr);
+
+ /** Select an upstream target.
+ *
+ * @param now Current time.
+ * @param fail_window Down server blackout time.
+ * @param hash_addr Inbound remote IP address.
+ * @return A selected target, or @c nullptr if there are no valid targets.
+ *
+ * This accounts for the round robin setting. The default is to use "client affinity" in
+ * which case @a hash_addr is as a hash seed to select the target.
+ *
+ * This may select a zombie target, which can be detected by checking the target's last
+ * failure time. If it is not @c TS_TIME_ZERO the target is a zombie. Other transactions will
+ * be blocked from selecting that target until @a fail_window time has passed.
+ *
+ * In cases other than strict round robin, a base target is selected. If valid, that is returned,
+ * but if not then the targets in this record are searched until a valid one is found. The result
+ * is this can be called to select a target for failover when a previous target fails.
+ */
+ HostDBInfo *select_best_http(ts_time now, ts_seconds fail_window, sockaddr const *hash_addr);
+ HostDBInfo *select_best_srv(char *target, InkRand *rand, ts_time now, ts_seconds fail_window);
+
+ bool is_failed() const;
+
+ void set_failed();
+
+ /// @return The time point when the item expires.
+ ts_time expiry_time() const;
+
+ /// @return The age of the DNS response.
+ ts_seconds ip_age() const;
+
+ /// @return How long before the DNS response becomes stale (i.e., exceeds @a
+ /// ip_timeout_interval from the time of the response).
+ ts_seconds ip_time_remaining() const;
+
+ /// @return Whether the age of the DNS response exceeds @a the user's
+ /// configured proxy.config.hostdb.verify_after value.
+ bool is_ip_configured_stale() const;
+
+ /** Whether we have exceeded the DNS response's TTL (i.e., whether the DNS
+ * response is stale). */
+ bool is_ip_timeout() const;
+
+ bool is_ip_fail_timeout() const;
+
+ void refresh_ip();
+
+ /** Whether the DNS response can still be used per
+ * proxy.config.hostdb.serve_stale_for configuration.
+ *
+ * @return False if serve_stale_for is not configured or if the DNS
+ * response's age is less than TTL + the serve_stale_for value. Note that
+ * this function will return true for DNS responses whose age is less than
+ * TTL (i.e., for responses that are not yet stale).
+ */
+ bool serve_stale_but_revalidate() const;
+
+ /// Deallocate @a this.
+ void free() override;
+
+ /** The current round robin index.
+ *
+ * @return The current index.
+ *
+ * @note The internal index may be out of range due to concurrency constraints - this insures the
+ * returned value is in range.
+ */
+ unsigned short rr_idx() const;
+
+ /** Offset from the current round robin index.
+ *
+ * @param delta Distance from the current index.
+ * @return The effective index.
+ */
+ unsigned short rr_idx(unsigned short delta) const;
+
+ /// The index of @a target in this record.
+ int index_of(HostDBInfo const *target) const;
+
+ /** Allocation and initialize an instance from a serialized buffer.
+ *
+ * @param buff Serialization data.
+ * @param size Size of @a buff.
+ * @return An instance initialized from @a buff.
+ */
+ static self_type *unmarshall(char *buff, unsigned size);
+
+ /// Database version.
+ static constexpr ts::VersionNumber Version{3, 0};
+
+protected:
+ /// Current active info.
+ /// @note This value may be out of range due to the difficulty of synchronization, therefore
+ /// must always be taken modulus @c rr_count when used. Use the @c rr_idx() method unless
+ /// raw access is required.
+ std::atomic<unsigned short> _rr_idx = 0;
+
+ /** Access an internal object at @a offset.
+ *
+ * @tparam T Type of object.
+ * @param offset Offset of object.
+ * @return A pointer to the object of type @a T.
+ *
+ * @a offset is applied to @a this record and the result cast to a pointer to @a T.
+ *
+ * @note @a offset based at @a this.
+ */
+ template <typename T>
+ T *
+ apply_offset(unsigned offset)
+ {
+ return reinterpret_cast<T *>(reinterpret_cast<char *>(this) + offset);
+ }
+
+ template <typename T>
+ T const *
+ apply_offset(unsigned offset) const
+ {
+ return reinterpret_cast<T const *>(reinterpret_cast<char const *>(this) + offset);
+ }
+
+ union {
+ uint16_t all;
+ struct {
+ unsigned failed_p : 1; ///< DNS error.
+ } f;
+ } flags{0};
+};
+
+struct HostDBCache;
+struct HostDBHash;
+
+// Prototype for inline completion function or
+// getbyname_imm()
+using cb_process_result_pfn = void (Continuation::*)(HostDBRecord *r);
+
+Action *iterate(Continuation *cont);
+
+/** Information for doing host resolution for a request.
+ *
+ * This is effectively a state object for a request attempting to connect upstream. Information about its attempt
+ * that are local to the request are kept here, while shared data is accessed via the @c HostDBInfo pointers.
+ *
+ * A primitive version of the IP address generator concept.
+ */
+struct ResolveInfo {
+ using self_type = ResolveInfo; ///< Self reference type.
+
+ /// Not quite sure what this is for.
+ enum UpstreamResolveStyle { UNDEFINED_LOOKUP, ORIGIN_SERVER, PARENT_PROXY, HOST_NONE };
+
+ /** Origin server address source selection.
+
+ If config says to use CTA (client target addr) state is TRY_CLIENT, otherwise it
+ remains the default. If the connect fails then we switch to a USE. We go to USE_HOSTDB if (1)
+ the HostDB lookup is successful and (2) some address other than the CTA is available to try.
+ Otherwise we keep retrying on the CTA (USE_CLIENT) up to the max retry value. In essence we
+ try to treat the CTA as if it were another RR value in the HostDB record.
+ */
+ enum class OS_Addr {
+ TRY_DEFAULT, ///< Initial state, use what config says.
+ TRY_HOSTDB, ///< Try HostDB data.
+ TRY_CLIENT, ///< Try client target addr.
+ USE_HOSTDB, ///< Force use of HostDB target address.
+ USE_CLIENT, ///< Force client target addr.
+ USE_API ///< Use the API provided address.
+ };
+
+ ResolveInfo() = default;
+ ~ResolveInfo() = default;
+
+ /// Keep a reference to the base HostDB object, so it doesn't get GC'd.
+ Ptr<HostDBRecord> record;
+ HostDBInfo *active = nullptr; ///< Active host record.
+
+ /// Working address. The meaning / source of the value depends on other elements.
+ /// This is the "resolved" address if @a resolved_p is @c true.
+ IpEndpoint addr;
+
+ int attempts = 0; ///< Number of connection attempts.
+
+ char const *lookup_name = nullptr;
+ char srv_hostname[MAXDNAME] = {0};
+ const sockaddr *inbound_remote_addr = nullptr; ///< Remote address of inbound client - used for hashing.
+ in_port_t srv_port = 0; ///< Port from SRV lookup or API call.
+
+ OS_Addr os_addr_style = OS_Addr::TRY_DEFAULT;
+ HostResStyle host_res_style = HOST_RES_IPV4;
+ UpstreamResolveStyle looking_up = UNDEFINED_LOOKUP;
+
+ HTTPVersion http_version = HTTP_INVALID;
+
+ bool resolved_p = false; ///< If there is a valid, resolved address in @a addr.
+
+ /// Flag for @a addr being set externally.
+ // bool api_addr_set_p = false;
+
+ /*** Set to true by default. If use_client_target_address is set
+ * to 1, this value will be set to false if the client address is
+ * not in the DNS pool */
+ bool cta_validated_p = true;
+
+ bool set_active(HostDBInfo *info);
+
+ bool set_active(sockaddr const *s);
+
+ bool set_active(std::nullptr_t);
+
+ /** Force a resolved address.
+ *
+ * @param sa Address to use for the upstream.
+ * @return @c true if successful, @c false if error.
+ *
+ * This fails if @a sa isn't a valid IP address.
+ */
+ bool set_upstream_address(const sockaddr *sa);
+
+ bool set_upstream_address(IpAddr const &ip_addr);
+
+ void set_upstream_port(in_port_t port);
+
+ /** Check and (if possible) immediately resolve the upstream address without consulting the HostDB.
+ * The cases where this is successful are
+ * - The address is already resolved (@a resolved_p is @c true).
+ * - The upstream was set explicitly.
+ * - The hostname is a valid IP address.
+ *
+ * @return @c true if the upstream address was resolved, @c false if not.
+ */
+ bool resolve_immediate();
+
+ /** Mark the active target as down.
+ *
+ * @param now Time of failure.
+ * @return @c true if the server was marked as down, @c false if not.
+ *
+ */
+ bool mark_active_server_down(ts_time now);
+
+ /** Mark the active target as alive.
+ *
+ * @return @c true if the target changed state.
+ */
+ bool mark_active_server_alive();
+
+ /// Select / resolve to the next RR entry for the record.
+ bool select_next_rr();
+
+ bool is_srv() const;
+};
+
+/** The Host Database access interface. */
+struct HostDBProcessor : public Processor {
+ // Public Interface
+
+ // Lookup Hostinfo by name
+ // cont->handleEvent( EVENT_HOST_DB_LOOKUP, HostDBInfo * ); on success
+ // cont->handleEVent( EVENT_HOST_DB_LOOKUP, 0); on failure
+ // Failure occurs when the host cannot be DNS-ed
+ // NOTE: Will call the continuation back before returning if data is in the
+ // cache. The HostDBInfo * becomes invalid when the callback returns.
+ // The HostDBInfo may be changed during the callback.
+
+ enum {
+ HOSTDB_DO_NOT_FORCE_DNS = 0,
+ HOSTDB_ROUND_ROBIN = 0,
+ HOSTDB_FORCE_DNS_RELOAD = 1,
+ HOSTDB_FORCE_DNS_ALWAYS = 2,
+ HOSTDB_DO_NOT_ROUND_ROBIN = 4
+ };
+
+ /// Optional parameters for getby...
+ struct Options {
+ using self = Options; ///< Self reference type.
+ int port = 0; ///< Target service port (default 0 -> don't care)
+ int flags = HOSTDB_DO_NOT_FORCE_DNS; ///< Processing flags (default HOSTDB_DO_NOT_FORCE_DNS)
+ int timeout = 0; ///< Timeout value (default 0 -> default timeout)
+ HostResStyle host_res_style = HOST_RES_IPV4; ///< How to query host (default HOST_RES_IPV4)
+
+ Options() {}
+ /// Set the flags.
+ self &
+ setFlags(int f)
+ {
+ flags = f;
+ return *this;
+ }
+ };
+
+ /// Default options.
+ static Options const DEFAULT_OPTIONS;
+
+ HostDBProcessor() {}
+ Action *getbyname_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
+
+ Action *getbynameport_re(Continuation *cont, const char *hostname, int len, Options const &opt = DEFAULT_OPTIONS);
+
+ Action *getSRVbyname_imm(Continuation *cont, cb_process_result_pfn process_srv_info, const char *hostname, int len,
+ Options const &opt = DEFAULT_OPTIONS);
+
+ Action *getbyname_imm(Continuation *cont, cb_process_result_pfn process_hostdb_info, const char *hostname, int len,
+ Options const &opt = DEFAULT_OPTIONS);
+
+ Action *iterate(Continuation *cont);
+
+ /** Lookup Hostinfo by addr */
+ Action *getbyaddr_re(Continuation *cont, sockaddr const *aip);
+
+ /** Configuration. */
+ static int hostdb_strict_round_robin;
+ static int hostdb_timed_round_robin;
+
+ // Processor Interface
+ /* hostdb does not use any dedicated event threads
+ * currently. Dont pass any value to start
+ */
+ int start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE) override;
+
+ // clear_and_start is the same start, except the persistent database is cleared first.
+ int clear_and_start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE);
+
+ // Private
+ HostDBCache *cache();
+
+private:
+ int init();
+
+ Action *getby(Continuation *cont, cb_process_result_pfn cb_process_result, HostDBHash &hash, Options const &opt);
+};
+
+inline bool
+HostDBRecord::is_srv() const
+{
+ return HostDBType::SRV == record_type;
+}
+
+inline char const *
+HostDBRecord::name() const
+{
+ return this->apply_offset<char const>(sizeof(self_type));
+}
+
+inline swoc::TextView
+HostDBRecord::name_view() const
+{
+ return {this->name(), swoc::TextView::npos};
+}
+
+inline ts_time
+HostDBRecord::expiry_time() const
+{
+ return ip_timestamp + ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate);
+}
+
+inline ts_seconds
+HostDBRecord::ip_age() const
+{
+ static constexpr ts_seconds ZERO{0};
+ static constexpr ts_seconds MAX{0x7FFFFFFF};
+
+ return std::clamp(std::chrono::duration_cast<ts_seconds>(hostdb_current_timestamp.load() - ip_timestamp), ZERO, MAX);
+}
+
+inline ts_seconds
+HostDBRecord::ip_time_remaining() const
+{
+ static constexpr ts_seconds ZERO{0};
+ static constexpr ts_seconds MAX{0x7FFFFFFF};
+ return std::clamp(std::chrono::duration_cast<ts_seconds>(ip_timeout_interval - this->ip_age()), ZERO, MAX);
+}
+
+inline bool
+HostDBRecord::is_ip_configured_stale() const
+{
+ return (
+ ((ip_timeout_interval >= ts_seconds(2 * hostdb_ip_stale_interval)) && (ip_age() >= ts_seconds(hostdb_ip_stale_interval))));
+}
+
+inline bool
+HostDBRecord::is_ip_timeout() const
+{
+ return ip_age() >= ip_timeout_interval;
+}
+
+inline bool
+HostDBRecord::is_ip_fail_timeout() const
+{
+ return ip_age() >= ts_seconds(hostdb_ip_fail_timeout_interval);
+}
+
+inline void
+HostDBRecord::refresh_ip()
+{
+ ip_timestamp = hostdb_current_timestamp;
+}
+
+inline swoc::MemSpan<HostDBInfo>
+HostDBRecord::rr_info()
+{
+ return {this->apply_offset<HostDBInfo>(rr_offset), rr_count};
+}
+
+inline bool
+HostDBRecord::is_failed() const
+{
+ return flags.f.failed_p;
+}
+
+inline void
+HostDBRecord::set_failed()
+{
+ flags.f.failed_p = true;
+}
+
+inline unsigned short
+HostDBRecord::rr_idx() const
+{
+ return _rr_idx % rr_count;
+}
+
+inline unsigned short
+HostDBRecord::rr_idx(unsigned short delta) const
+{
+ return (_rr_idx + delta) % rr_count;
+}
+
+inline int
+HostDBRecord::index_of(HostDBInfo const *target) const
+{
+ return target ? target - this->apply_offset<HostDBInfo>(rr_offset) : -1;
+}
+
+// --
+
+inline bool
+ResolveInfo::set_active(sockaddr const *s)
+{
+ return this->set_active(record->find(s));
+}
+
+inline bool
+ResolveInfo::mark_active_server_alive()
+{
+ return active->mark_up();
+}
+
+inline bool
+ResolveInfo::mark_active_server_down(ts_time now)
+{
+ return active != nullptr && active->mark_down(now);
+}
+
+inline bool
+ResolveInfo::set_active(std::nullptr_t)
+{
+ active = nullptr;
+ resolved_p = false;
+ return false;
+}
+
+inline bool
+ResolveInfo::set_upstream_address(sockaddr const *sa)
+{
+ return resolved_p = addr.assign(sa).isValid();
+}
+
+inline void
+ResolveInfo::set_upstream_port(in_port_t port)
+{
+ srv_port = port;
+}
+
+inline bool
+ResolveInfo::is_srv() const
+{
+ return record && record->is_srv();
+}
+// ---
+
+void run_HostDBTest();
+
+extern HostDBProcessor hostDBProcessor;
+
+void ink_hostdb_init(ts::ModuleVersion version);
diff --git a/include/iocore/hostdb/HostFile.h b/include/iocore/hostdb/HostFile.h
new file mode 100644
index 0000000000..cbc71e5d61
--- /dev/null
+++ b/include/iocore/hostdb/HostFile.h
@@ -0,0 +1,52 @@
+/** @file
+
+ HostFile class for processing a hosts file
+
+ @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 "swoc/swoc_file.h"
+
+#include "HostDBProcessor.h"
+#include "swoc/TextView.h"
+
+#include <memory>
+#include <unordered_map>
+
+struct HostFileRecord {
+ HostDBRecord::Handle record_4;
+ HostDBRecord::Handle record_6;
+};
+
+struct HostFile {
+ using HostFileForwardMap = std::unordered_map<swoc::TextView, HostFileRecord, std::hash<std::string_view>>;
+ using HostFileReverseMap = std::unordered_map<IpAddr, HostDBRecord::Handle, IpAddr::Hasher>;
+
+ HostFile(ts_seconds ttl) : ttl(ttl) {}
+
+ HostDBRecord::Handle lookup(const HostDBHash &hash);
+
+ ts_seconds ttl;
+ HostFileForwardMap forward;
+ HostFileReverseMap reverse;
+};
+
+std::shared_ptr<HostFile> ParseHostFile(swoc::file::path const &path, ts_seconds interval);
diff --git a/iocore/io_uring/IOUringEventIO.h b/include/iocore/io_uring/IOUringEventIO.h
similarity index 100%
rename from iocore/io_uring/IOUringEventIO.h
rename to include/iocore/io_uring/IOUringEventIO.h
diff --git a/iocore/io_uring/I_IO_URING.h b/include/iocore/io_uring/IO_URING.h
similarity index 100%
rename from iocore/io_uring/I_IO_URING.h
rename to include/iocore/io_uring/IO_URING.h
diff --git a/include/iocore/net/AcceptOptions.h b/include/iocore/net/AcceptOptions.h
new file mode 100644
index 0000000000..8c26f25919
--- /dev/null
+++ b/include/iocore/net/AcceptOptions.h
@@ -0,0 +1,90 @@
+/** @file
+
+ This file implements an I/O Processor for network I/O
+
+ @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 "tscore/ink_inet.h"
+
+#include "Event.h"
+
+struct AcceptOptions {
+ using self = AcceptOptions; ///< Self reference type.
+
+ /// Port on which to listen.
+ /// 0 => don't care, which is useful if the socket is already bound.
+ int local_port = 0;
+ /// Local address to bind for accept.
+ /// If not set -> any address.
+ IpAddr local_ip;
+ /// IP address family.
+ /// @note Ignored if an explicit incoming address is set in the
+ /// the configuration (@c local_ip). If neither is set IPv4 is used.
+ int ip_family = AF_INET;
+ /// Should we use accept threads? If so, how many?
+ int accept_threads = -1;
+ /** If @c true, the continuation is called back with
+ @c NET_EVENT_ACCEPT_SUCCEED
+ or @c NET_EVENT_ACCEPT_FAILED on success and failure resp.
+ */
+ bool localhost_only = false;
+ /// Are frequent accepts expected?
+ /// Default: @c false.
+ bool frequent_accept = true;
+
+ /// Socket receive buffer size.
+ /// 0 => OS default.
+ int recv_bufsize = 0;
+ /// Socket transmit buffer size.
+ /// 0 => OS default.
+ int send_bufsize = 0;
+ /// defer accept for @c sockopt.
+ /// 0 => OS default.
+ int defer_accept = 0;
+ /// Socket options for @c sockopt.
+ /// 0 => do not set options.
+ uint32_t sockopt_flags = 0;
+ uint32_t packet_mark = 0;
+ uint32_t packet_tos = 0;
+ uint32_t packet_notsent_lowat = 0;
+
+ int tfo_queue_length = 0;
+
+ /** Transparency on client (user agent) connection.
+ @internal This is irrelevant at a socket level (since inbound
+ transparency must be set up when the listen socket is created)
+ but it's critical that the connection handling logic knows
+ whether the inbound (client / user agent) connection is
+ transparent.
+ */
+ bool f_inbound_transparent = false;
+
+ /** MPTCP enabled on listener.
+ @internal For logging and metrics purposes to know whether the
+ listener enabled MPTCP or not.
+ */
+ bool f_mptcp = false;
+
+ /// Proxy Protocol enabled
+ bool f_proxy_protocol = false;
+};
diff --git a/iocore/net/AsyncSignalEventIO.h b/include/iocore/net/AsyncSignalEventIO.h
similarity index 100%
rename from iocore/net/AsyncSignalEventIO.h
rename to include/iocore/net/AsyncSignalEventIO.h
diff --git a/iocore/net/BIO_fastopen.h b/include/iocore/net/BIO_fastopen.h
similarity index 100%
rename from iocore/net/BIO_fastopen.h
rename to include/iocore/net/BIO_fastopen.h
diff --git a/iocore/net/BoringSSLUtils.h b/include/iocore/net/BoringSSLUtils.h
similarity index 100%
rename from iocore/net/BoringSSLUtils.h
rename to include/iocore/net/BoringSSLUtils.h
diff --git a/iocore/net/EventIO.h b/include/iocore/net/EventIO.h
similarity index 100%
rename from iocore/net/EventIO.h
rename to include/iocore/net/EventIO.h
diff --git a/include/iocore/net/Net.h b/include/iocore/net/Net.h
new file mode 100644
index 0000000000..d24f29f910
--- /dev/null
+++ b/include/iocore/net/Net.h
@@ -0,0 +1,91 @@
+/** @file
+
+ Net subsystem
+
+ @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.
+
+ @section details Details
+
+ Net subsystem is a layer on top the operations system network apis. It
+ provides an interface for accepting/creating new connection oriented
+ (TCP) and connection less (UDP) connections and for reading/writing
+ data through these. The net system can manage 1000s of connections
+ very efficiently. Another advantage of using the net system is that
+ the SMs dont have be concerned about differences in the net apis of
+ various operations systems.
+
+ SMs use the netProcessor global object of the Net System to create new
+ connections or to accept incoming connections. When a new connection
+ is created the SM gets a NetVConnection which is a handle for the
+ underlying connections. The SM can then use the NetVConnection to get
+ properties of the connection, read and write data. Net system also
+ has socks and ssl support.
+
+ */
+#pragma once
+
+#include "tscore/Version.h"
+#include "EventSystem.h"
+#include <netinet/in.h>
+
+#ifndef UIO_MAXIOV
+#define NET_MAX_IOV 16 // UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1)
+#else
+#define NET_MAX_IOV UIO_MAXIOV
+#endif
+
+static constexpr ts::ModuleVersion NET_SYSTEM_MODULE_PUBLIC_VERSION(1, 0, ts::ModuleVersion::PUBLIC);
+
+static constexpr int NO_FD = -1;
+
+// All in milli-seconds
+extern int net_event_period;
+extern int net_accept_period;
+extern int net_retry_delay;
+extern int net_throttle_delay;
+
+extern std::string_view net_ccp_in;
+extern std::string_view net_ccp_out;
+
+#define NET_EVENT_OPEN (NET_EVENT_EVENTS_START)
+#define NET_EVENT_OPEN_FAILED (NET_EVENT_EVENTS_START + 1)
+#define NET_EVENT_ACCEPT (NET_EVENT_EVENTS_START + 2)
+#define NET_EVENT_ACCEPT_SUCCEED (NET_EVENT_EVENTS_START + 3)
+#define NET_EVENT_ACCEPT_FAILED (NET_EVENT_EVENTS_START + 4)
+#define NET_EVENT_CANCEL (NET_EVENT_EVENTS_START + 5)
+#define NET_EVENT_DATAGRAM_READ_COMPLETE (NET_EVENT_EVENTS_START + 6)
+#define NET_EVENT_DATAGRAM_READ_ERROR (NET_EVENT_EVENTS_START + 7)
+#define NET_EVENT_DATAGRAM_WRITE_COMPLETE (NET_EVENT_EVENTS_START + 8)
+#define NET_EVENT_DATAGRAM_WRITE_ERROR (NET_EVENT_EVENTS_START + 9)
+#define NET_EVENT_DATAGRAM_READ_READY (NET_EVENT_EVENTS_START + 10)
+#define NET_EVENT_DATAGRAM_OPEN (NET_EVENT_EVENTS_START + 11)
+#define NET_EVENT_DATAGRAM_ERROR (NET_EVENT_EVENTS_START + 12)
+#define NET_EVENT_ACCEPT_INTERNAL (NET_EVENT_EVENTS_START + 22)
+#define NET_EVENT_CONNECT_INTERNAL (NET_EVENT_EVENTS_START + 23)
+
+#define MAIN_ACCEPT_PORT -1
+
+/*
+ * Net system uses event threads
+ * so, the net thread group id is the event thread group id
+ */
+
+#define ET_NET ET_CALL
+
+void ink_net_init(ts::ModuleVersion version);
diff --git a/iocore/net/NetAcceptEventIO.h b/include/iocore/net/NetAcceptEventIO.h
similarity index 100%
rename from iocore/net/NetAcceptEventIO.h
rename to include/iocore/net/NetAcceptEventIO.h
diff --git a/include/iocore/net/NetEvent.h b/include/iocore/net/NetEvent.h
new file mode 100644
index 0000000000..33d767a2dc
--- /dev/null
+++ b/include/iocore/net/NetEvent.h
@@ -0,0 +1,141 @@
+/** @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 <atomic>
+
+#include "EventSystem.h"
+#include "P_UnixNetState.h"
+#include "EventIO.h"
+#include "ReadWriteEventIO.h"
+
+class NetHandler;
+
+// this class is used to NetHandler to hide some detail of NetEvent.
+// To combine the `UDPConenction` and `NetEvent`. NetHandler should
+// callback to net_read_io or net_write_io when net event happen.
+class NetEvent
+{
+public:
+ NetEvent() = default;
+ virtual ~NetEvent() {}
+ virtual void net_read_io(NetHandler *nh, EThread *lthread) = 0;
+ virtual void net_write_io(NetHandler *nh, EThread *lthread) = 0;
+ virtual void free_thread(EThread *t) = 0;
+
+ // since we want this class to be independent from VConnection, Continutaion. There should be
+ // a pure virtual function which connect sub class and NetHandler.
+ virtual int callback(int event = CONTINUATION_EVENT_NONE, void *data = nullptr) = 0;
+
+ // Duplicate with `NetVConnection::set_inactivity_timeout`
+ // TODO: more abstraction.
+ virtual void set_inactivity_timeout(ink_hrtime timeout_in) = 0;
+ virtual void set_default_inactivity_timeout(ink_hrtime timeout_in) = 0;
+ virtual bool is_default_inactivity_timeout() = 0;
+
+ // get this vc's thread
+ virtual EThread *get_thread() = 0;
+
+ // Close when EventIO close;
+ virtual int close() = 0;
+
+ bool has_error() const;
+ void set_error_from_socket();
+
+ // get fd
+ virtual int get_fd() = 0;
+ virtual Ptr<ProxyMutex> &get_mutex() = 0;
+ virtual ContFlags &get_control_flags() = 0;
+
+ ReadWriteEventIO ep{};
+ NetState read{};
+ NetState write{};
+
+ int closed = 0;
+ int error = 0;
+ NetHandler *nh = nullptr;
+
+ /** The explicitly set inactivity timeout duration in seconds.
+ *
+ * 0 means no timeout.
+ */
+ ink_hrtime inactivity_timeout_in = 0;
+
+ /** The fallback inactivity timeout which is applied if no other timeouts are
+ * set. That is, this timeout is used if inactivity_timeout_in is 0.
+ *
+ * A value of 0 means no timeout. A value of -1 means that no default timeout
+ * has been set yet. This is initialized to -1 instead of 0 so that the
+ * inactivity cop can distinguish between no value having been set and a
+ * value of 0 having been set by some override plugin.
+ */
+ std::atomic<ink_hrtime> default_inactivity_timeout_in = -1;
+
+ /** The active timeout duration in seconds. */
+ ink_hrtime active_timeout_in = 0;
+
+ /** The time of the next inactivity timeout. */
+ ink_hrtime next_inactivity_timeout_at = 0;
+
+ /** The time of the next activity timeout. */
+ ink_hrtime next_activity_timeout_at = 0;
+ ink_hrtime submit_time = 0;
+
+ /** Whether the current timeout is a default inactivity timeout. */
+ bool use_default_inactivity_timeout = false;
+
+ LINK(NetEvent, open_link);
+ LINK(NetEvent, cop_link);
+ LINKM(NetEvent, read, ready_link)
+ SLINKM(NetEvent, read, enable_link)
+ LINKM(NetEvent, write, ready_link)
+ SLINKM(NetEvent, write, enable_link)
+ LINK(NetEvent, keep_alive_queue_link);
+ LINK(NetEvent, active_queue_link);
+
+ /// Values for @a f.shutdown
+ static constexpr unsigned SHUTDOWN_READ = 1;
+ static constexpr unsigned SHUTDOWN_WRITE = 2;
+
+ union {
+ unsigned int flags = 0;
+ struct {
+ unsigned int got_local_addr : 1;
+ unsigned int shutdown : 2;
+ } f;
+ };
+};
+
+inline bool
+NetEvent::has_error() const
+{
+ return error != 0;
+}
+
+inline void
+NetEvent::set_error_from_socket()
+{
+ socklen_t errlen = sizeof(error);
+ getsockopt(this->get_fd(), SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
+}
diff --git a/include/iocore/net/NetHandler.h b/include/iocore/net/NetHandler.h
new file mode 100644
index 0000000000..1e953b92b3
--- /dev/null
+++ b/include/iocore/net/NetHandler.h
@@ -0,0 +1,236 @@
+/** @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 "Continuation.h"
+#include "EThread.h"
+#include "NetEvent.h"
+
+//
+// NetHandler
+//
+// A NetHandler handles the Network IO operations. It maintains
+// lists of operations at multiples of it's periodicity.
+//
+
+/**
+ NetHandler is the processor of NetEvent for the Net sub-system. The NetHandler
+ is the core component of the Net sub-system. Once started, it is responsible
+ for polling socket fds and perform the I/O tasks in NetEvent.
+
+ The NetHandler is executed periodically to perform read/write tasks for
+ NetVConnection. The NetHandler::mainNetEvent() should be viewed as a part of
+ EThread::execute() loop. This is the reason that Net System is a sub-system.
+
+ By get_NetHandler(this_ethread()), you can get the NetHandler object that
+ runs inside the current EThread and then @c startIO / @c stopIO which
+ assign/release a NetEvent to/from NetHandler. Before you call these functions,
+ holding the mutex of this NetHandler is required.
+
+ The NetVConnection provides a set of do_io functions through which you can
+ specify continuations to be called back by its NetHandler. These function
+ calls do not block. Instead they return an VIO object and schedule the
+ callback to the continuation passed in when there are I/O events occurred.
+
+ Multi-thread scheduler:
+
+ The NetHandler should be viewed as multi-threaded schedulers which process
+ NetEvents from their queues. If vc wants to be managed by NetHandler, the vc
+ should be derived from NetEvent. The vc can be made of NetProcessor
+ (allocate_vc) either by directly adding a NetEvent to the queue
+ (NetHandler::startIO), or more conveniently, calling a method service call
+ (NetProcessor::connect_re) which synthesizes the NetEvent and places it in the
+ queue.
+
+ Callback event codes:
+
+ These event codes for do_io_read and reenable(read VIO) task:
+ VC_EVENT_READ_READY, VC_EVENT_READ_COMPLETE,
+ VC_EVENT_EOS, VC_EVENT_ERROR
+
+ These event codes for do_io_write and reenable(write VIO) task:
+ VC_EVENT_WRITE_READY, VC_EVENT_WRITE_COMPLETE
+ VC_EVENT_ERROR
+
+ There is no event and callback for do_io_shutdown / do_io_close task.
+
+ NetVConnection allocation policy:
+
+ VCs are allocated by the NetProcessor and deallocated by NetHandler.
+ A state machine may access the returned, non-recurring NetEvent / VIO until
+ it is closed by do_io_close. For recurring NetEvent, the NetEvent may be
+ accessed until it is closed. Once the NetEvent is closed, it's the
+ NetHandler's responsibility to deallocate it.
+
+ Before assign to NetHandler or after release from NetHandler, it's the
+ NetEvent's responsibility to deallocate itself.
+
+ */
+class NetHandler : public Continuation, public EThread::LoopTailHandler
+{
+ using self_type = NetHandler; ///< Self reference type.
+public:
+ // @a thread and @a trigger_event are redundant - you can get the former from
+ // the latter. If we don't get rid of @a trigger_event we should remove @a
+ // thread.
+ EThread *thread = nullptr;
+ Event *trigger_event = nullptr;
+ QueM(NetEvent, NetState, read, ready_link) read_ready_list;
+ QueM(NetEvent, NetState, write, ready_link) write_ready_list;
+ Que(NetEvent, open_link) open_list;
+ DList(NetEvent, cop_link) cop_list;
+ ASLLM(NetEvent, NetState, read, enable_link) read_enable_list;
+ ASLLM(NetEvent, NetState, write, enable_link) write_enable_list;
+ Que(NetEvent, keep_alive_queue_link) keep_alive_queue;
+ uint32_t keep_alive_queue_size = 0;
+ Que(NetEvent, active_queue_link) active_queue;
+ uint32_t active_queue_size = 0;
+
+ /// configuration settings for managing the active and keep-alive queues
+ struct Config {
+ uint32_t max_connections_in = 0;
+ uint32_t max_requests_in = 0;
+ uint32_t inactive_threshold_in = 0;
+ uint32_t transaction_no_activity_timeout_in = 0;
+ uint32_t keep_alive_no_activity_timeout_in = 0;
+ uint32_t default_inactivity_timeout = 0;
+ uint32_t additional_accepts = 0;
+
+ /** Return the address of the first value in this struct.
+
+ Doing updates is much easier if we treat this config struct as an array.
+ Making it a method means the knowledge of which member is the first one
+ is localized to this struct, not scattered about.
+ */
+ uint32_t &
+ operator[](int n)
+ {
+ return *(&max_connections_in + n);
+ }
+ };
+ /** Static global config, set and updated per process.
+
+ This is updated asynchronously and then events are sent to the NetHandler
+ instances per thread to copy to the per thread config at a convenient time.
+ Because these are updated independently from the command line, the update
+ events just copy a single value from the global to the local. This
+ mechanism relies on members being identical types.
+ */
+ static Config global_config;
+ Config config; ///< Per thread copy of the @c global_config
+ // Active and keep alive queue values that depend on other configuration
+ // values. These are never updated directly, they are computed from other
+ // config values.
+ uint32_t max_connections_per_thread_in = 0;
+ uint32_t max_requests_per_thread_in = 0;
+ /// Number of configuration items in @c Config.
+ static constexpr int CONFIG_ITEM_COUNT = sizeof(Config) / sizeof(uint32_t);
+ /// Which members of @c Config the per thread values depend on.
+ /// If one of these is updated, the per thread values must also be updated.
+ static const std::bitset<CONFIG_ITEM_COUNT> config_value_affects_per_thread_value;
+ /// Set of thread types in which nethandlers are active.
+ /// This enables signaling the correct instances when the configuration is
+ /// updated. Event type threads that use @c NetHandler must set the
+ /// corresponding bit.
+ static std::bitset<std::numeric_limits<unsigned int>::digits> active_thread_types;
+
+ int mainNetEvent(int event, Event *data);
+ int waitForActivity(ink_hrtime timeout) override;
+ void process_enabled_list();
+ void process_ready_list();
+ void manage_keep_alive_queue();
+ bool manage_active_queue(NetEvent *ne, bool ignore_queue_size);
+ void add_to_keep_alive_queue(NetEvent *ne);
+ void remove_from_keep_alive_queue(NetEvent *ne);
+ bool add_to_active_queue(NetEvent *ne);
+ void remove_from_active_queue(NetEvent *ne);
+ int get_additional_accepts();
+
+ /// Per process initialization logic.
+ static void init_for_process();
+ /// Update configuration values that are per thread and depend on other
+ /// configuration values.
+ void configure_per_thread_values();
+
+ /**
+ Start to handle read & write event on a NetEvent.
+ Initial the socket fd of ne for polling system.
+ Only be called when holding the mutex of this NetHandler.
+
+ @param ne NetEvent to be managed by this NetHandler.
+ @return 0 on success, ne->nh set to this NetHandler.
+ -ERRNO on failure.
+ */
+ int startIO(NetEvent *ne);
+ /**
+ Stop to handle read & write event on a NetEvent.
+ Remove the socket fd of ne from polling system.
+ Only be called when holding the mutex of this NetHandler and must call
+ stopCop(ne) first.
+
+ @param ne NetEvent to be released.
+ @return ne->nh set to nullptr.
+ */
+ void stopIO(NetEvent *ne);
+
+ /**
+ Start to handle active timeout and inactivity timeout on a NetEvent.
+ Put the ne into open_list. All NetEvents in the open_list is checked for
+ timeout by InactivityCop. Only be called when holding the mutex of this
+ NetHandler and must call startIO(ne) first.
+
+ @param ne NetEvent to be managed by InactivityCop
+ */
+ void startCop(NetEvent *ne);
+ /**
+ Stop to handle active timeout and inactivity on a NetEvent.
+ Remove the ne from open_list and cop_list.
+ Also remove the ne from keep_alive_queue and active_queue if its context is
+ IN. Only be called when holding the mutex of this NetHandler.
+
+ @param ne NetEvent to be released.
+ */
+ void stopCop(NetEvent *ne);
+
+ // Signal the epoll_wait to terminate.
+ void signalActivity() override;
+
+ /**
+ Release a ne and free it.
+
+ @param ne NetEvent to be detached.
+ */
+ void free_netevent(NetEvent *ne);
+
+ NetHandler();
+
+ inline static DbgCtl dbg_ctl_socket{"socket"};
+ inline static DbgCtl dbg_ctl_iocore_net{"iocore_net"};
+
+private:
+ void _close_ne(NetEvent *ne, ink_hrtime now, int &handle_event, int &closed, int &total_idle_time, int &total_idle_count);
+
+ /// Static method used as the callback for runtime configuration updates.
+ static int update_nethandler_config(const char *name, RecDataT, RecData data, void *);
+};
diff --git a/include/iocore/net/NetProcessor.h b/include/iocore/net/NetProcessor.h
new file mode 100644
index 0000000000..154195e5b9
--- /dev/null
+++ b/include/iocore/net/NetProcessor.h
@@ -0,0 +1,184 @@
+/** @file
+
+ This file implements an I/O Processor for network I/O
+
+ @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 "EventSystem.h"
+#include "Socks.h"
+#include "NetVConnection.h"
+#include "AcceptOptions.h"
+struct socks_conf_struct;
+#define NET_CONNECT_TIMEOUT 30
+
+struct NetVCOptions;
+
+/**
+ This is the heart of the Net system. Provides common network APIs,
+ like accept, connect etc. It performs network I/O on behalf of a
+ state machine.
+
+*/
+class NetProcessor : public Processor
+{
+public:
+ /** Options for @c accept.
+ */
+ using AcceptOptions = ::AcceptOptions;
+
+ /**
+ Accept connections on a port.
+
+ Callbacks:
+ - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is
+ called for each new connection
+ - cont->handleEvent(EVENT_ERROR,-errno) on a bad error
+
+ Re-entrant callbacks (based on callback_on_open flag):
+ - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful
+ accept init
+ - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept
+ init failure
+
+ @param cont Continuation to be called back with events this
+ continuation is not locked on callbacks and so the handler must
+ be re-entrant.
+ @param opt Accept options.
+ @return Action, that can be cancelled to cancel the accept. The
+ port becomes free immediately.
+ */
+ virtual Action *accept(Continuation *cont, AcceptOptions const &opt = DEFAULT_ACCEPT_OPTIONS) = 0;
+
+ /**
+ Accepts incoming connections on port. Accept connections on port.
+ Accept is done on all net threads and throttle limit is imposed
+ if frequent_accept flag is true. This is similar to the accept
+ method described above. The only difference is that the list
+ of parameter that is takes is limited.
+
+ Callbacks:
+ - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is called for each new connection
+ - cont->handleEvent(EVENT_ERROR,-errno) on a bad error
+
+ Re-entrant callbacks (based on callback_on_open flag):
+ - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful accept init
+ - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept init failure
+
+ @param cont Continuation to be called back with events this
+ continuation is not locked on callbacks and so the handler must
+ be re-entrant.
+ @param listen_socket_in if passed, used for listening.
+ @param opt Accept options.
+ @return Action, that can be cancelled to cancel the accept. The
+ port becomes free immediately.
+
+ */
+ virtual Action *main_accept(Continuation *cont, SOCKET listen_socket_in, AcceptOptions const &opt = DEFAULT_ACCEPT_OPTIONS) = 0;
+
+ virtual void stop_accept() = 0;
+
+ /**
+ Open a NetVConnection for connection oriented I/O. Connects
+ through sockserver if netprocessor is configured to use socks
+ or is socks parameters to the call are set.
+
+ Re-entrant callbacks:
+ - On success calls: c->handleEvent(NET_EVENT_OPEN, NetVConnection *)
+ - On failure calls: c->handleEvent(NET_EVENT_OPEN_FAILED, -errno)
+
+ @note Connection may not have been established when cont is
+ call back with success. If this behaviour is desired use
+ synchronous connect connet_s method.
+
+ @param cont Continuation to be called back with events.
+ @param addr target address and port to connect to.
+ @param options @see NetVCOptions.
+
+ */
+ virtual Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions const &options) = 0;
+
+ /**
+ Initializes the net processor. This must be called before the event threads are started.
+
+ */
+ virtual void init() = 0;
+
+ virtual void init_socks() = 0;
+
+ virtual NetVConnection *allocate_vc(EThread *) = 0;
+
+ /** Private constructor. */
+ NetProcessor(){};
+
+ /** Private destructor. */
+ ~NetProcessor() override{};
+
+ /** This is MSS for connections we accept (client connections). */
+ static int accept_mss;
+
+ //
+ // The following are required by the SOCKS protocol:
+ //
+ // Either the configuration variables will give your a regular
+ // expression for all the names that are to go through the SOCKS
+ // server, or will give you a list of domain names which should *not* go
+ // through SOCKS. If the SOCKS option is set to false then, these
+ // variables (regular expression or list) should be set
+ // appropriately. If it is set to TRUE then, in addition to supplying
+ // the regular expression or the list, the user should also give the
+ // the ip address and port number for the SOCKS server (use
+ // appropriate defaults)
+
+ /* shared by regular netprocessor and ssl netprocessor */
+ static socks_conf_struct *socks_conf_stuff;
+
+ /// Default options instance.
+ static AcceptOptions const DEFAULT_ACCEPT_OPTIONS;
+
+ // noncopyable
+ NetProcessor(const NetProcessor &) = delete;
+ NetProcessor &operator=(const NetProcessor &) = delete;
+};
+
+/**
+ Global NetProcessor singleton object for making net calls. All
+ net processor calls like connect, accept, etc are made using this
+ object.
+
+ @code
+ netProcessor.accept(my_cont, ...);
+ netProcessor.connect_re(my_cont, ...);
+ @endcode
+
+*/
+extern NetProcessor &netProcessor;
+
+/**
+ Global netProcessor singleton object for making ssl enabled net
+ calls. As far as the SM is concerned this behaves exactly like
+ netProcessor. The only difference is that the connections are
+ over ssl.
+
+*/
+extern NetProcessor &sslNetProcessor;
+extern NetProcessor &quicNetProcessor;
diff --git a/include/iocore/net/NetTimeout.h b/include/iocore/net/NetTimeout.h
new file mode 100644
index 0000000000..904c76d637
--- /dev/null
+++ b/include/iocore/net/NetTimeout.h
@@ -0,0 +1,263 @@
+/** @file
+
+ NetTimeout
+
+ @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 "tscore/List.h"
+#include "tscore/ink_hrtime.h"
+
+#include "EventSystem.h"
+
+/**
+ NetTimeout - handle active & inactive timeout
+ */
+class NetTimeout
+{
+public:
+ void set_active_timeout(ink_hrtime timeout_in);
+ void set_inactive_timeout(ink_hrtime timeout_in);
+ void cancel_active_timeout();
+ void cancel_inactive_timeout();
+ void reset_active_timeout();
+ void reset_inactive_timeout();
+ bool is_active_timeout_expired(ink_hrtime now);
+ bool is_inactive_timeout_expired(ink_hrtime now);
+ ink_hrtime idle_time(ink_hrtime now);
+ void update_inactivity();
+
+private:
+ ink_hrtime _active_timeout_in = 0;
+ ink_hrtime _inactive_timeout_in = 0;
+ ink_hrtime _next_active_timeout_at = 0;
+ ink_hrtime _next_inactive_timeout_at = 0;
+};
+
+/**
+ ActivityCop - Check activity of T in the List in every @f seconds
+
+ T have to handle VC_EVENT_ACTIVE_TIMEOUT and VC_EVENT_INACTIVITY_TIMEOUT events.
+
+ TODO: add concepts like below with C++20
+ ```
+ template <class T, class List = DLL<T>>
+ concept Timeoutable = requires(T *t, List *list, ink_hrtime time) {
+ t->handleEvent();
+ t->head;
+ {list->next(t)} -> std::convertible_to<T *>;
+ {t->is_active_timeout_expired(time)} -> std::same_as<bool>;
+ {t->is_inactive_timeout_expired(time)} -> std::same_as<bool>;
+ };
+ ```
+ */
+template <class T, class List = DLL<T>> class ActivityCop : public Continuation
+{
+public:
+ ActivityCop(){};
+ ActivityCop(Ptr<ProxyMutex> &m, List *l, int f);
+
+ void start();
+ void stop();
+ int check_activity(int event, Event *e);
+
+private:
+ Event *_event = nullptr;
+ List *_list = nullptr;
+ int _freq = 1;
+};
+
+////
+// Inline functions
+
+//
+// NetTimeout
+//
+inline void
+NetTimeout::set_active_timeout(ink_hrtime timeout_in)
+{
+ if (timeout_in == 0) {
+ return;
+ }
+
+ _active_timeout_in = timeout_in;
+ _next_active_timeout_at = ink_get_hrtime() + timeout_in;
+}
+
+inline void
+NetTimeout::set_inactive_timeout(ink_hrtime timeout_in)
+{
+ if (timeout_in == 0) {
+ return;
+ }
+
+ _inactive_timeout_in = timeout_in;
+ _next_inactive_timeout_at = ink_get_hrtime() + timeout_in;
+}
+
+inline void
+NetTimeout::cancel_active_timeout()
+{
+ _active_timeout_in = 0;
+ _next_active_timeout_at = 0;
+}
+
+inline void
+NetTimeout::cancel_inactive_timeout()
+{
+ _inactive_timeout_in = 0;
+ _next_inactive_timeout_at = 0;
+}
+
+inline void
+NetTimeout::reset_active_timeout()
+{
+ if (_active_timeout_in == 0) {
+ return;
+ }
+
+ _next_active_timeout_at = ink_get_hrtime() + _active_timeout_in;
+}
+
+inline void
+NetTimeout::reset_inactive_timeout()
+{
+ if (_inactive_timeout_in == 0) {
+ return;
+ }
+
+ _next_inactive_timeout_at = ink_get_hrtime() + _inactive_timeout_in;
+}
+
+inline bool
+NetTimeout::is_active_timeout_expired(ink_hrtime now)
+{
+ ink_assert(now > 0);
+
+ if (_active_timeout_in == 0) {
+ return false;
+ }
+
+ if (0 < _next_active_timeout_at && _next_active_timeout_at < now) {
+ Debug("activity_cop", "active timeout cont=%p now=%" PRId64 " timeout_at=%" PRId64 " timeout_in=%" PRId64, this,
+ ink_hrtime_to_sec(now), ink_hrtime_to_sec(_next_active_timeout_at), ink_hrtime_to_sec(_active_timeout_in));
+ return true;
+ }
+
+ return false;
+}
+
+inline bool
+NetTimeout::is_inactive_timeout_expired(ink_hrtime now)
+{
+ ink_assert(now > 0);
+
+ if (_inactive_timeout_in == 0) {
+ return false;
+ }
+
+ if (0 < _next_inactive_timeout_at && _next_inactive_timeout_at < now) {
+ Debug("activity_cop", "inactive timeout cont=%p now=%" PRId64 " timeout_at=%" PRId64 " timeout_in=%" PRId64, this,
+ ink_hrtime_to_sec(now), ink_hrtime_to_sec(_next_inactive_timeout_at), ink_hrtime_to_sec(_inactive_timeout_in));
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ Return how log this was inactive.
+ */
+inline ink_hrtime
+NetTimeout::idle_time(ink_hrtime now)
+{
+ if (now < _next_inactive_timeout_at) {
+ return 0;
+ }
+
+ return ink_hrtime_to_sec((now - _next_inactive_timeout_at) + _inactive_timeout_in);
+}
+
+inline void
+NetTimeout::update_inactivity()
+{
+ if (_inactive_timeout_in == 0) {
+ return;
+ }
+
+ _next_inactive_timeout_at = ink_get_hrtime() + _inactive_timeout_in;
+}
+
+//
+// ActivityCop
+//
+template <class T, class List>
+inline ActivityCop<T, List>::ActivityCop(Ptr<ProxyMutex> &m, List *l, int f) : Continuation(m.get()), _list(l), _freq(f)
+{
+ SET_HANDLER((&ActivityCop<T, List>::check_activity));
+}
+
+template <class T, class List>
+inline void
+ActivityCop<T, List>::start()
+{
+ _event = this_ethread()->schedule_every(this, HRTIME_SECONDS(_freq));
+}
+
+template <class T, class List>
+inline void
+ActivityCop<T, List>::stop()
+{
+ _event->cancel();
+}
+
+template <class T, class List>
+inline int
+ActivityCop<T, List>::check_activity(int /* event */, Event *e)
+{
+ ink_hrtime now = ink_get_hrtime();
+
+ // Traverse list & check inactivity or activity
+ T *t = _list->head;
+ while (t) {
+ T *next = _list->next(t);
+ if (t->mutex == nullptr) {
+ t = next;
+ continue;
+ }
+
+ MUTEX_TRY_LOCK(lock, t->mutex, this_ethread());
+ if (!lock.is_locked()) {
+ t = next;
+ continue;
+ }
+
+ if (t->is_inactive_timeout_expired(now)) {
+ t->handleEvent(VC_EVENT_INACTIVITY_TIMEOUT, e);
+ } else if (t->is_active_timeout_expired(now)) {
+ t->handleEvent(VC_EVENT_ACTIVE_TIMEOUT, e);
+ }
+
+ t = next;
+ }
+
+ return EVENT_DONE;
+}
diff --git a/include/iocore/net/NetVCOptions.h b/include/iocore/net/NetVCOptions.h
new file mode 100644
index 0000000000..d2d8eba879
--- /dev/null
+++ b/include/iocore/net/NetVCOptions.h
@@ -0,0 +1,318 @@
+/** @file
+
+ NetVConnection options class
+
+ @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 "tscore/ink_inet.h"
+#include "EventSystem.h"
+#include "Event.h"
+#include "YamlSNIConfig.h"
+
+#include <cstdint>
+
+struct NetVCOptions {
+ using self = NetVCOptions; ///< Self reference type.
+
+ /// Values for valid IP protocols.
+ enum ip_protocol_t {
+ USE_TCP, ///< TCP protocol.
+ USE_UDP ///< UDP protocol.
+ };
+
+ /// IP (TCP or UDP) protocol to use on socket.
+ ip_protocol_t ip_proto;
+
+ /** IP address family.
+
+ This is used for inbound connections only if @c local_ip is not
+ set, which is sometimes more convenient for the client. This
+ defaults to @c AF_INET so if the client sets neither this nor @c
+ local_ip then IPv4 is used.
+
+ For outbound connections this is ignored and the family of the
+ remote address used.
+
+ @note This is (inconsistently) called "domain" and "protocol" in
+ other places. "family" is used here because that's what the
+ standard IP data structures use.
+
+ */
+ uint16_t ip_family;
+
+ /** The set of ways in which the local address should be bound.
+
+ The protocol is set by the contents of @a local_addr regardless
+ of this value. @c ANY_ADDR will override only the address.
+
+ @note The difference between @c INTF_ADDR and @c FOREIGN_ADDR is
+ whether transparency is enabled on the socket. It is the
+ client's responsibility to set this correctly based on whether
+ the address in @a local_addr is associated with an interface on
+ the local system ( @c INTF_ADDR ) or is owned by a foreign
+ system ( @c FOREIGN_ADDR ). A binding style of @c ANY_ADDR
+ causes the value in @a local_addr to be ignored.
+
+ The IP address and port are separate because most clients treat
+ these independently. For the same reason @c IpAddr is used
+ to be clear that it contains no port data.
+
+ @see local_addr
+ @see addr_binding
+ */
+ enum addr_bind_style {
+ ANY_ADDR, ///< Bind to any available local address (don't care, default).
+ INTF_ADDR, ///< Bind to interface address in @a local_addr.
+ FOREIGN_ADDR ///< Bind to foreign address in @a local_addr.
+ };
+
+ /** Local address for the connection.
+
+ For outbound connections this must have the same family as the
+ remote address (which is not stored in this structure). For
+ inbound connections the family of this value overrides @a
+ ip_family if set.
+
+ @note Ignored if @a addr_binding is @c ANY_ADDR.
+ @see addr_binding
+ @see ip_family
+ */
+ IpAddr local_ip;
+
+ /** Local port for connection.
+ Set to 0 for "don't care" (default).
+ */
+ uint16_t local_port;
+
+ /// How to bind the local address.
+ /// @note Default is @c ANY_ADDR.
+ addr_bind_style addr_binding;
+
+ /// Make the socket blocking on I/O (default: @c false)
+ // TODO: make this const. We don't use blocking
+ bool f_blocking = false;
+ /// Make socket block on connect (default: @c false)
+ // TODO: make this const. We don't use blocking
+ bool f_blocking_connect = false;
+
+ // Use TCP Fast Open on this socket. The connect(2) call will be omitted.
+ bool f_tcp_fastopen = false;
+
+ /// Control use of SOCKS.
+ /// Set to @c NO_SOCKS to disable use of SOCKS. Otherwise SOCKS is
+ /// used if available.
+ unsigned char socks_support;
+ /// Version of SOCKS to use.
+ unsigned char socks_version;
+
+ int socket_recv_bufsize;
+ int socket_send_bufsize;
+
+ /// Configuration options for sockets.
+ /// @note These are not identical to internal socket options but
+ /// specifically defined for configuration. These are mask values
+ /// and so must be powers of 2.
+ uint32_t sockopt_flags;
+ /// Value for TCP no delay for @c sockopt_flags.
+ static uint32_t const SOCK_OPT_NO_DELAY = 1;
+ /// Value for keep alive for @c sockopt_flags.
+ static uint32_t const SOCK_OPT_KEEP_ALIVE = 2;
+ /// Value for linger on for @c sockopt_flags
+ static uint32_t const SOCK_OPT_LINGER_ON = 4;
+ /// Value for TCP Fast open @c sockopt_flags
+ static uint32_t const SOCK_OPT_TCP_FAST_OPEN = 8;
+ /// Value for SO_MARK @c sockopt_flags
+ static uint32_t const SOCK_OPT_PACKET_MARK = 16;
+ /// Value for IP_TOS @c sockopt_flags
+ static uint32_t const SOCK_OPT_PACKET_TOS = 32;
+ /// Value for TCP_NOTSENT_LOWAT @c sockopt_flags
+ static uint32_t const SOCK_OPT_TCP_NOTSENT_LOWAT = 64;
+
+ uint32_t packet_mark;
+ uint32_t packet_tos;
+ uint32_t packet_notsent_lowat;
+
+ EventType etype;
+
+ /** ALPN protocol-lists. The format is OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings)
+ https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html
+ */
+ std::string_view alpn_protos;
+ /** Server name to use for SNI data on an outbound connection.
+ */
+ ats_scoped_str sni_servername;
+ /** FQDN used to connect to the origin. May be different
+ * than sni_servername if pristine host headers are used
+ */
+ ats_scoped_str ssl_servername;
+
+ /** Server host name from client's request to use for SNI data on an outbound connection.
+ */
+ ats_scoped_str sni_hostname;
+
+ /**
+ * Client certificate to use in response to OS's certificate request
+ */
+ ats_scoped_str ssl_client_cert_name;
+ /*
+ * File containing private key matching certificate
+ */
+ const char *ssl_client_private_key_name = nullptr;
+ /*
+ * File containing CA certs for verifying origin's cert
+ */
+ const char *ssl_client_ca_cert_name = nullptr;
+ /*
+ * Directory containing CA certs for verifying origin's cert
+ */
+ const char *ssl_client_ca_cert_path = nullptr;
+
+ bool tls_upstream = false;
+
+ unsigned char alpn_protocols_array[MAX_ALPN_STRING];
+ int alpn_protocols_array_size = 0;
+
+ /**
+ * Set to DISABLED, PERFMISSIVE, or ENFORCED
+ * Controls how the server certificate verification is handled
+ */
+ YamlSNIConfig::Policy verifyServerPolicy = YamlSNIConfig::Policy::DISABLED;
+
+ /**
+ * Bit mask of which features of the server certificate should be checked
+ * Currently SIGNATURE and NAME
+ */
+ YamlSNIConfig::Property verifyServerProperties = YamlSNIConfig::Property::NONE;
+
+ /// Reset all values to defaults.
+ void reset();
+
+ void set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags, unsigned long _packet_mark = 0,
+ unsigned long _packet_tos = 0, unsigned long _packet_notsent_lowat = 0);
+
+ NetVCOptions() { reset(); }
+ ~NetVCOptions() {}
+
+ /** Set the SNI server name.
+ A local copy is made of @a name.
+ */
+ self &
+ set_sni_servername(const char *name, size_t len)
+ {
+ IpEndpoint ip;
+
+ // Literal IPv4 and IPv6 addresses are not permitted in "HostName".(rfc6066#section-3)
+ if (name && len && ats_ip_pton(std::string_view(name, len), &ip) != 0) {
+ sni_servername = ats_strndup(name, len);
+ } else {
+ sni_servername = nullptr;
+ }
+ return *this;
+ }
+
+ self &
+ set_ssl_client_cert_name(const char *name)
+ {
+ if (name) {
+ ssl_client_cert_name = ats_strdup(name);
+ } else {
+ ssl_client_cert_name = nullptr;
+ }
+ return *this;
+ }
+
+ self &
+ set_ssl_servername(const char *name)
+ {
+ if (name) {
+ ssl_servername = ats_strdup(name);
+ } else {
+ ssl_servername = nullptr;
+ }
+ return *this;
+ }
+
+ self &
+ set_sni_hostname(const char *name, size_t len)
+ {
+ IpEndpoint ip;
+
+ // Literal IPv4 and IPv6 addresses are not permitted in "HostName".(rfc6066#section-3)
+ if (name && len && ats_ip_pton(std::string_view(name, len), &ip) != 0) {
+ sni_hostname = ats_strndup(name, len);
+ } else {
+ sni_hostname = nullptr;
+ }
+ return *this;
+ }
+
+ self &
+ operator=(self const &that)
+ {
+ if (&that != this) {
+ /*
+ * It is odd but necessary to null the scoped string pointer here
+ * and then explicitly call release on them in the string assignments
+ * below.
+ * We a memcpy from that to this. This will put that's string pointers into
+ * this's memory. Therefore we must first explicitly null out
+ * this's original version of the string. The release after the
+ * memcpy removes the extra reference to that's copy of the string
+ * Removing the release will eventually cause a double free crash
+ */
+ sni_servername = nullptr; // release any current name.
+ ssl_servername = nullptr;
+ sni_hostname = nullptr;
+ ssl_client_cert_name = nullptr;
+ memcpy(static_cast<void *>(this), &that, sizeof(self));
+ if (that.sni_servername) {
+ sni_servername.release(); // otherwise we'll free the source string.
+ this->sni_servername = ats_strdup(that.sni_servername);
+ }
+ if (that.ssl_servername) {
+ ssl_servername.release(); // otherwise we'll free the source string.
+ this->ssl_servername = ats_strdup(that.ssl_servername);
+ }
+ if (that.sni_hostname) {
+ sni_hostname.release(); // otherwise we'll free the source string.
+ this->sni_hostname = ats_strdup(that.sni_hostname);
+ }
+ if (that.ssl_client_cert_name) {
+ this->ssl_client_cert_name.release(); // otherwise we'll free the source string.
+ this->ssl_client_cert_name = ats_strdup(that.ssl_client_cert_name);
+ }
+ }
+ return *this;
+ }
+
+ std::string_view get_family_string() const;
+
+ std::string_view get_proto_string() const;
+
+ /// @name Debugging
+ //@{
+ /// Convert @a s to its string equivalent.
+ static const char *toString(addr_bind_style s);
+ //@}
+
+ // noncopyable
+ NetVCOptions(const NetVCOptions &) = delete;
+};
diff --git a/include/iocore/net/NetVConnection.h b/include/iocore/net/NetVConnection.h
new file mode 100644
index 0000000000..757222acc4
--- /dev/null
+++ b/include/iocore/net/NetVConnection.h
@@ -0,0 +1,703 @@
+/** @file
+
+ This file implements an I/O Processor for network I/O
+
+ @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 "NetVCOptions.h"
+#include "ProxyProtocol.h"
+#include "Net.h"
+
+#include <string_view>
+#include <optional>
+
+#include "tscore/ink_inet.h"
+#include "Action.h"
+#include "VConnection.h"
+#include "Event.h"
+#include "tscore/List.h"
+#include "IOBuffer.h"
+#include "Socks.h"
+#include "ts/apidefs.h"
+#include "YamlSNIConfig.h"
+#include "swoc/TextView.h"
+
+#define CONNECT_SUCCESS 1
+#define CONNECT_FAILURE 0
+
+#define SSL_EVENT_SERVER 0
+#define SSL_EVENT_CLIENT 1
+
+// Indicator the context for a NetVConnection
+typedef enum {
+ NET_VCONNECTION_UNSET = 0,
+ NET_VCONNECTION_IN, // Client <--> ATS, Client-Side
+ NET_VCONNECTION_OUT, // ATS <--> Server, Server-Side
+} NetVConnectionContext_t;
+
+/**
+ A VConnection for a network socket. Abstraction for a net connection.
+ Similar to a socket descriptor VConnections are IO handles to
+ streams. In one sense, they serve a purpose similar to file
+ descriptors. Unlike file descriptors, VConnections allow for a
+ stream IO to be done based on a single read or write call.
+
+*/
+class NetVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VCONN>
+{
+public:
+ /**
+ Initiates read. Thread safe, may be called when not handling
+ an event from the NetVConnection, or the NetVConnection creation
+ callback.
+
+ Callbacks: non-reentrant, c's lock taken during callbacks.
+
+ <table>
+ <tr><td>c->handleEvent(VC_EVENT_READ_READY, vio)</td><td>data added to buffer</td></tr>
+ <tr><td>c->handleEvent(VC_EVENT_READ_COMPLETE, vio)</td><td>finished reading nbytes of data</td></tr>
+ <tr><td>c->handleEvent(VC_EVENT_EOS, vio)</td><td>the stream has been shutdown</td></tr>
+ <tr><td>c->handleEvent(VC_EVENT_ERROR, vio)</td><td>error</td></tr>
+ </table>
+
+ The vio returned during callbacks is the same as the one returned
+ by do_io_read(). The vio can be changed only during call backs
+ from the vconnection.
+
+ @param c continuation to be called back after (partial) read
+ @param nbytes no of bytes to read, if unknown set to INT64_MAX
+ @param buf buffer to put the data into
+ @return vio
+
+ */
+ VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override = 0;
+
+ /**
+ Initiates write. Thread-safe, may be called when not handling
+ an event from the NetVConnection, or the NetVConnection creation
+ callback.
+
+ Callbacks: non-reentrant, c's lock taken during callbacks.
+
+ <table>
+ <tr>
+ <td>c->handleEvent(VC_EVENT_WRITE_READY, vio)</td>
+ <td>signifies data has written from the reader or there are no bytes available for the reader to write.</td>
+ </tr>
+ <tr>
+ <td>c->handleEvent(VC_EVENT_WRITE_COMPLETE, vio)</td>
+ <td>signifies the amount of data indicated by nbytes has been read from the buffer</td>
+ </tr>
+ <tr>
+ <td>c->handleEvent(VC_EVENT_ERROR, vio)</td>
+ <td>signified that error occurred during write.</td>
+ </tr>
+ </table>
+
+ The vio returned during callbacks is the same as the one returned
+ by do_io_write(). The vio can be changed only during call backs
+ from the vconnection. The vconnection deallocates the reader
+ when it is destroyed.
+
+ @param c continuation to be called back after (partial) write
+ @param nbytes no of bytes to write, if unknown must be set to INT64_MAX
+ @param buf source of data
+ @param owner
+ @return vio pointer
+
+ */
+ VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override = 0;
+
+ /**
+ Closes the vconnection. A state machine MUST call do_io_close()
+ when it has finished with a VConnection. do_io_close() indicates
+ that the VConnection can be deallocated. After a close has been
+ called, the VConnection and underlying processor must NOT send
+ any more events related to this VConnection to the state machine.
+ Likewise, state machine must not access the VConnection or
+ any returned VIOs after calling close. lerrno indicates whether
+ a close is a normal close or an abort. The difference between
+ a normal close and an abort depends on the underlying type of
+ the VConnection. Passing VIO::CLOSE for lerrno indicates a
+ normal close while passing VIO::ABORT indicates an abort.
+
+ @param lerrno VIO:CLOSE for regular close or VIO::ABORT for aborts
+
+ */
+ void do_io_close(int lerrno = -1) override = 0;
+
+ /**
+ Shuts down read side, write side, or both. do_io_shutdown() can
+ be used to terminate one or both sides of the VConnection. The
+ howto is one of IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE,
+ IO_SHUTDOWN_READWRITE. Once a side of a VConnection is shutdown,
+ no further I/O can be done on that side of the connections and
+ the underlying processor MUST NOT send any further events
+ (INCLUDING TIMEOUT EVENTS) to the state machine. The state machine
+ MUST NOT use any VIOs from a shutdown side of a connection.
+ Even if both sides of a connection are shutdown, the state
+ machine MUST still call do_io_close() when it wishes the
+ VConnection to be deallocated.
+
+ @param howto IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE, IO_SHUTDOWN_READWRITE
+
+ */
+ void do_io_shutdown(ShutdownHowTo_t howto) override = 0;
+
+ /**
+ Return the server name that is appropriate for the network VC type
+ */
+ virtual const char *
+ get_server_name() const
+ {
+ return nullptr;
+ }
+
+ ////////////////////////////////////////////////////////////
+ // Set the timeouts associated with this connection. //
+ // active_timeout is for the total elapsed time of //
+ // the connection. //
+ // inactivity_timeout is the elapsed time from the time //
+ // a read or a write was scheduled during which the //
+ // connection was unable to sink/provide data. //
+ // calling these functions repeatedly resets the timeout. //
+ // These functions are NOT THREAD-SAFE, and may only be //
+ // called when handing an event from this NetVConnection,//
+ // or the NetVConnection creation callback. //
+ ////////////////////////////////////////////////////////////
+
+ /**
+ Sets time after which SM should be notified.
+
+ Sets the amount of time (in nanoseconds) after which the state
+ machine using the NetVConnection should receive a
+ VC_EVENT_ACTIVE_TIMEOUT event. The timeout is value is ignored
+ if neither the read side nor the write side of the connection
+ is currently active. The timer is reset if the function is
+ called repeatedly This call can be used by SMs to make sure
+ that it does not keep any connections open for a really long
+ time.
+
+ Timeout semantics:
+
+ Should a timeout occur, the state machine for the read side of
+ the NetVConnection is signaled first assuming that a read has
+ been initiated on the NetVConnection and that the read side of
+ the NetVConnection has not been shutdown. Should either of the
+ two conditions not be met, the NetProcessor will attempt to
+ signal the write side. If a timeout is sent to the read side
+ state machine and its handler, return EVENT_DONE, a timeout
+ will not be sent to the write side. Should the return from the
+ handler not be EVENT_DONE and the write side state machine is
+ different (in terms of pointer comparison) from the read side
+ state machine, the NetProcessor will try to signal the write
+ side state machine as well. To signal write side, a write must
+ have been initiated on it and the write must not have been
+ shutdown.
+
+ Receiving a timeout is only a notification that the timer has
+ expired. The NetVConnection is still usable. Further timeouts
+ of the type signaled will not be generated unless the timeout
+ is reset via the set_active_timeout() or set_inactivity_timeout()
+ interfaces.
+
+ */
+ virtual void set_active_timeout(ink_hrtime timeout_in) = 0;
+
+ /**
+ Sets time after which SM should be notified if the requested
+ IO could not be performed. Sets the amount of time (in nanoseconds),
+ if the NetVConnection is idle on both the read or write side,
+ after which the state machine using the NetVConnection should
+ receive a VC_EVENT_INACTIVITY_TIMEOUT event. Either read or
+ write traffic will cause timer to be reset. Calling this function
+ again also resets the timer. The timeout is value is ignored
+ if neither the read side nor the write side of the connection
+ is currently active. See section on timeout semantics above.
+
+ */
+ virtual void set_inactivity_timeout(ink_hrtime timeout_in) = 0;
+ virtual void set_default_inactivity_timeout(ink_hrtime timeout_in) = 0;
+ virtual bool is_default_inactivity_timeout() = 0;
+
+ /**
+ Clears the active timeout. No active timeouts will be sent until
+ set_active_timeout() is used to reset the active timeout.
+
+ */
+ virtual void cancel_active_timeout() = 0;
+
+ /**
+ Clears the inactivity timeout. No inactivity timeouts will be sent (aside
+ from the default inactivity timeout) until set_inactivity_timeout() is used
+ to reset the inactivity timeout.
+
+ */
+ virtual void cancel_inactivity_timeout() = 0;
+
+ /** Set the action to use a continuation.
+ The action continuation will be called with an event if there is no pending I/O operation
+ to receive the event.
+
+ Pass @c nullptr to disable.
+
+ @internal Subclasses should implement this if they support actions. This abstract class does
+ not. If the subclass doesn't have an action this method is silently ignored.
+ */
+ virtual void
+ set_action(Continuation *)
+ {
+ return;
+ }
+
+ virtual void add_to_keep_alive_queue() = 0;
+
+ virtual void remove_from_keep_alive_queue() = 0;
+
+ virtual bool add_to_active_queue() = 0;
+
+ /** @return the current active_timeout value in nanosecs */
+ virtual ink_hrtime get_active_timeout() = 0;
+
+ /** @return current inactivity_timeout value in nanosecs */
+ virtual ink_hrtime get_inactivity_timeout() = 0;
+
+ /** Force an @a event if a write operation empties the write buffer.
+
+ This event will be sent to the VIO, the same place as other IO events.
+ Use an @a event value of 0 to cancel the trap.
+
+ The event is sent only the next time the write buffer is emptied, not
+ every future time. The event is sent only if otherwise no event would
+ be generated.
+ */
+ virtual void trapWriteBufferEmpty(int event = VC_EVENT_WRITE_READY);
+
+ /** Returns local sockaddr storage. */
+ sockaddr const *get_local_addr();
+ IpEndpoint const &get_local_endpoint();
+
+ /** Returns local port. */
+ uint16_t get_local_port();
+
+ /** Returns remote sockaddr storage. */
+ sockaddr const *get_remote_addr();
+ IpEndpoint const &get_remote_endpoint();
+
+ /** Returns remote port. */
+ uint16_t get_remote_port();
+
+ /** Set the context of NetVConnection.
+ * The context is ONLY set once and will not be changed.
+ *
+ * @param context The context to be set.
+ */
+ void
+ set_context(NetVConnectionContext_t context)
+ {
+ ink_assert(NET_VCONNECTION_UNSET == netvc_context);
+ netvc_context = context;
+ }
+
+ /** Get the context.
+ * @return the context of current NetVConnection
+ */
+ NetVConnectionContext_t
+ get_context() const
+ {
+ return netvc_context;
+ }
+
+ /**
+ * Returns true if the network protocol
+ * supports a client provided SNI value
+ */
+ virtual bool
+ support_sni() const
+ {
+ return false;
+ }
+
+ virtual const char *
+ get_sni_servername() const
+ {
+ return nullptr;
+ }
+
+ virtual bool
+ peer_provided_cert() const
+ {
+ return false;
+ }
+
+ virtual int
+ provided_cert() const
+ {
+ return 0;
+ }
+
+ /** Structure holding user options. */
+ NetVCOptions options;
+
+ /** Attempt to push any changed options down */
+ virtual void apply_options() = 0;
+
+ //
+ // Private
+ //
+
+ // The following variable used to obtain host addr when transparency
+ // is enabled by SocksProxy
+ SocksAddrType socks_addr;
+
+ unsigned int attributes = 0;
+ EThread *thread = nullptr;
+
+ /// PRIVATE: The public interface is VIO::reenable()
+ void reenable(VIO *vio) override = 0;
+
+ /// PRIVATE: The public interface is VIO::reenable()
+ void reenable_re(VIO *vio) override = 0;
+
+ /// PRIVATE
+ ~NetVConnection() override {}
+ /**
+ PRIVATE: instances of NetVConnection cannot be created directly
+ by the state machines. The objects are created by NetProcessor
+ calls like accept connect_re() etc. The constructor is public
+ just to avoid compile errors.
+
+ */
+ NetVConnection();
+
+ virtual SOCKET get_socket() = 0;
+
+ /** Set the TCP congestion control algorithm */
+ virtual int set_tcp_congestion_control(int side) = 0;
+
+ /** Set local sock addr struct. */
+ virtual void set_local_addr() = 0;
+
+ /** Set remote sock addr struct. */
+ virtual void set_remote_addr() = 0;
+
+ /** Set remote sock addr struct. */
+ virtual void set_remote_addr(const sockaddr *) = 0;
+
+ /** Set the MPTCP state for this connection */
+ virtual void set_mptcp_state() = 0;
+
+ // for InkAPI
+ bool
+ get_is_internal_request() const
+ {
+ return is_internal_request;
+ }
+
+ void
+ set_is_internal_request(bool val = false)
+ {
+ is_internal_request = val;
+ }
+
+ bool
+ get_is_unmanaged_request() const
+ {
+ return is_unmanaged_request;
+ }
+
+ void
+ set_is_unmanaged_request(bool val = false)
+ {
+ is_unmanaged_request = val;
+ }
+
+ /// Get the transparency state.
+ bool
+ get_is_transparent() const
+ {
+ return is_transparent;
+ }
+
+ /// Get the MPTCP state of the VC.
+ std::optional<bool>
+ get_mptcp_state() const
+ {
+ return mptcp_state;
+ }
+
+ /// Set the transparency state.
+ void
+ set_is_transparent(bool state = true)
+ {
+ is_transparent = state;
+ }
+
+ /// Get the proxy protocol enabled flag
+ bool
+ get_is_proxy_protocol() const
+ {
+ return is_proxy_protocol;
+ }
+ /// Set the proxy protocol enabled flag on the port
+ void
+ set_is_proxy_protocol(bool state = true)
+ {
+ is_proxy_protocol = state;
+ }
+
+ virtual int
+ populate_protocol(std::string_view *results, int n) const
+ {
+ return 0;
+ }
+
+ virtual const char *
+ protocol_contains(std::string_view prefix) const
+ {
+ return nullptr;
+ }
+
+ // noncopyable
+ NetVConnection(const NetVConnection &) = delete;
+ NetVConnection &operator=(const NetVConnection &) = delete;
+
+ ProxyProtocolVersion
+ get_proxy_protocol_version() const
+ {
+ return pp_info.version;
+ }
+
+ sockaddr const *get_proxy_protocol_addr(const ProxyProtocolData) const;
+
+ sockaddr const *
+ get_proxy_protocol_src_addr() const
+ {
+ return get_proxy_protocol_addr(ProxyProtocolData::SRC);
+ }
+
+ uint16_t
+ get_proxy_protocol_src_port() const
+ {
+ return ats_ip_port_host_order(this->get_proxy_protocol_addr(ProxyProtocolData::SRC));
+ }
+
+ sockaddr const *
+ get_proxy_protocol_dst_addr() const
+ {
+ return get_proxy_protocol_addr(ProxyProtocolData::DST);
+ }
+
+ uint16_t
+ get_proxy_protocol_dst_port() const
+ {
+ return ats_ip_port_host_order(this->get_proxy_protocol_addr(ProxyProtocolData::DST));
+ };
+
+ void set_proxy_protocol_info(const ProxyProtocol &src);
+ const ProxyProtocol &get_proxy_protocol_info() const;
+
+ bool has_proxy_protocol(IOBufferReader *);
+ bool has_proxy_protocol(char *, int64_t *);
+
+ template <typename S> S *get_service() const;
+
+protected:
+ enum class Service : uint8_t {
+ TLS_ALPN,
+ TLS_Basic,
+ TLS_CertSwitch,
+ TLS_EarlyData,
+ TLS_SNI,
+ TLS_SessionResumption,
+ TLS_Tunnel,
+ QUIC,
+ N_SERVICES,
+ };
+
+ IpEndpoint local_addr;
+ IpEndpoint remote_addr;
+ ProxyProtocol pp_info;
+
+ bool got_local_addr = false;
+ bool got_remote_addr = false;
+
+ bool is_internal_request = false;
+ bool is_unmanaged_request = false;
+ /// Set if this connection is transparent.
+ bool is_transparent = false;
+ /// Set if proxy protocol is enabled
+ bool is_proxy_protocol = false;
+ /// This is essentially a tri-state, we leave it undefined to mean no MPTCP support
+ std::optional<bool> mptcp_state;
+ /// Set if the next write IO that empties the write buffer should generate an event.
+ int write_buffer_empty_event = 0;
+ /// NetVConnection Context.
+ NetVConnectionContext_t netvc_context = NET_VCONNECTION_UNSET;
+
+ template <typename S> void _set_service(S *instance);
+
+private:
+ void *_services[static_cast<unsigned int>(Service::N_SERVICES)] = {
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ };
+
+ void *_get_service(enum Service mixin_index) const;
+ void _set_service(enum Service mixin_index, void *instance);
+};
+
+inline NetVConnection::NetVConnection() : VConnection(nullptr)
+
+{
+ ink_zero(local_addr);
+ ink_zero(remote_addr);
+}
+
+inline void
+NetVConnection::trapWriteBufferEmpty(int event)
+{
+ write_buffer_empty_event = event;
+}
+
+inline void *
+NetVConnection::_get_service(enum NetVConnection::Service service) const
+{
+ return _services[static_cast<unsigned int>(service)];
+}
+
+inline void
+NetVConnection::_set_service(enum NetVConnection::Service service, void *instance)
+{
+ this->_services[static_cast<unsigned int>(service)] = instance;
+}
+
+class ALPNSupport;
+template <>
+inline ALPNSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<ALPNSupport *>(this->_get_service(NetVConnection::Service::TLS_ALPN));
+}
+template <>
+inline void
+NetVConnection::_set_service(ALPNSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_ALPN, instance);
+}
+
+class TLSBasicSupport;
+template <>
+inline TLSBasicSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSBasicSupport *>(this->_get_service(NetVConnection::Service::TLS_Basic));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSBasicSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_Basic, instance);
+}
+
+class TLSEarlyDataSupport;
+template <>
+inline TLSEarlyDataSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSEarlyDataSupport *>(this->_get_service(NetVConnection::Service::TLS_EarlyData));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSEarlyDataSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_EarlyData, instance);
+}
+
+class TLSCertSwitchSupport;
+template <>
+inline TLSCertSwitchSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSCertSwitchSupport *>(this->_get_service(NetVConnection::Service::TLS_CertSwitch));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSCertSwitchSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_CertSwitch, instance);
+}
+
+class TLSSNISupport;
+template <>
+inline TLSSNISupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSSNISupport *>(this->_get_service(NetVConnection::Service::TLS_SNI));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSNISupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_SNI, instance);
+}
+
+class TLSSessionResumptionSupport;
+template <>
+inline TLSSessionResumptionSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSSessionResumptionSupport *>(this->_get_service(NetVConnection::Service::TLS_SessionResumption));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSessionResumptionSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_SessionResumption, instance);
+}
+
+class TLSTunnelSupport;
+template <>
+inline TLSTunnelSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<TLSTunnelSupport *>(this->_get_service(NetVConnection::Service::TLS_Tunnel));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSTunnelSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::TLS_Tunnel, instance);
+}
+
+class QUICSupport;
+template <>
+inline QUICSupport *
+NetVConnection::get_service() const
+{
+ return static_cast<QUICSupport *>(this->_get_service(NetVConnection::Service::QUIC));
+}
+template <>
+inline void
+NetVConnection::_set_service(QUICSupport *instance)
+{
+ this->_set_service(NetVConnection::Service::QUIC, instance);
+}
diff --git a/include/iocore/net/PollCont.h b/include/iocore/net/PollCont.h
new file mode 100644
index 0000000000..93bd0cccaa
--- /dev/null
+++ b/include/iocore/net/PollCont.h
@@ -0,0 +1,43 @@
+/** @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 "Continuation.h"
+#include "Net.h"
+
+class NetHandler;
+struct PollDescriptor;
+
+struct PollCont : public Continuation {
+ NetHandler *net_handler;
+ PollDescriptor *pollDescriptor;
+ PollDescriptor *nextPollDescriptor;
+ int poll_timeout;
+
+ PollCont(Ptr<ProxyMutex> &m, int pt = EThread::default_wait_interval_ms);
+ PollCont(Ptr<ProxyMutex> &m, NetHandler *nh, int pt = EThread::default_wait_interval_ms);
... 221758 lines suppressed ...