Adding scripts for using ctsTraffic in ways I've found useful in verifying the correctness of a network stack configuration. Added a new option to prove useful, and addressed some ReSharper fixes

This commit is contained in:
Keith Horton 2024-02-11 23:27:33 -08:00
Родитель 88a4151979
Коммит 27d9239167
89 изменённых файлов: 3432 добавлений и 2856 удалений

Просмотреть файл

@ -129,6 +129,11 @@ uint32_t ConsoleVerbosity() noexcept
{
return 0;
}
TcpShutdownType GetShutdownType() noexcept
{
return ctsConfig::g_configSettings->TcpShutdown;
}
}
///

Просмотреть файл

@ -370,12 +370,12 @@
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -19,6 +19,9 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -370,12 +370,12 @@
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -131,6 +131,11 @@ uint32_t ConsoleVerbosity() noexcept
{
return 0;
}
TcpShutdownType GetShutdownType() noexcept
{
return ctsConfig::g_configSettings->TcpShutdown;
}
}
///

Просмотреть файл

@ -369,12 +369,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -19,6 +19,9 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -179,6 +179,11 @@ uint32_t ConsoleVerbosity() noexcept
{
return 0;
}
TcpShutdownType GetShutdownType() noexcept
{
return ctsConfig::g_configSettings->TcpShutdown;
}
}
///

Просмотреть файл

@ -371,12 +371,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -177,6 +177,11 @@ uint32_t ConsoleVerbosity() noexcept
{
return 0;
}
TcpShutdownType GetShutdownType() noexcept
{
return TcpShutdownType::GracefulShutdown;
}
}
///
@ -469,7 +474,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Push;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = false;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -529,7 +534,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Push;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = false;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -602,7 +607,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Push;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = true;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -662,7 +667,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Push;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = true;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -735,7 +740,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Push;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = true;
ctsConfig::g_configSettings->ShouldVerifyBuffers = false;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -803,7 +808,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Pull;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = false;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -861,7 +866,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Pull;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = false;
ctsConfig::g_configSettings->ShouldVerifyBuffers = true;
ctsConfig::g_configSettings->PrePostRecvs = 1;
@ -919,7 +924,7 @@ public:
{
ctsConfig::g_configSettings->IoPattern = ctsConfig::IoPatternType::Pull;
ctsConfig::g_configSettings->Protocol = ctsConfig::ProtocolType::TCP;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::ServerSideShutdown;
ctsConfig::g_configSettings->TcpShutdown = ctsConfig::TcpShutdownType::NoShutdownOptionSet;
ctsConfig::g_configSettings->UseSharedBuffer = true;
ctsConfig::g_configSettings->ShouldVerifyBuffers = false;
ctsConfig::g_configSettings->PrePostRecvs = 1;

Просмотреть файл

@ -371,12 +371,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -384,12 +384,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -371,12 +371,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -380,12 +380,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -4,6 +4,9 @@
<ClCompile Include="..\..\ctsTraffic\ctsSocketBroker.cpp" />
<ClCompile Include="ctsSocketBrokerUnitTest.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -60,7 +60,7 @@ shared_ptr<ctsIoPattern> ctsIoPattern::MakeIoPattern()
return nullptr;
}
wsIOResult ctsSetLingertoResetSocket(SOCKET) noexcept
wsIOResult ctsSetLingerToResetSocket(SOCKET) noexcept
{
return wsIOResult();
}

Просмотреть файл

@ -373,12 +373,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -63,7 +63,7 @@ void ctsSocketState::CompleteState(DWORD) noexcept
Logger::WriteMessage(L"ctsSocketState::complete_state\n");
}
wsIOResult ctsSetLingertoResetSocket(SOCKET) noexcept
wsIOResult ctsSetLingerToResetSocket(SOCKET) noexcept
{
return wsIOResult();
}

Просмотреть файл

@ -370,12 +370,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Просмотреть файл

@ -369,12 +369,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230202.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230202.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Двоичные данные
Releases/2.0.3.3/arm64/ctsPerf.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/arm64/ctsPerf.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/arm64/ctsTraffic.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/arm64/ctsTraffic.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x64/ctsPerf.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x64/ctsPerf.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x64/ctsTraffic.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x64/ctsTraffic.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x86/ctsPerf.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x86/ctsPerf.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x86/ctsTraffic.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Releases/2.0.3.3/x86/ctsTraffic.pdb Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,63 @@
@echo off
REM
REM
REM Copyright (c) Microsoft Corporation
REM All rights reserved.
REM
REM Licensed 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
REM
REM THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
REM
REM See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
REM
REM
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo This validation script will verify TCP connection reliability at scale (hundreds, to thousands, of connections/second)
echo Note: the -PortScalability:on option requires ctsTraffic version 2.0.3.3
echo .
echo This can be run on any number of clients targeting the same server (or targeting multiple servers, if desired).
echo .
echo Because this will be cycling through connections very quickly, I would recommend a lower connection count, such as 15 (what I defaulted to below)
echo ... but feel free to modify -Connections as needed for targeting specific scenarios
echo .
echo Note: this is set to run for 1,800,000 ms (30 minutes) - this can be modified to match your target goals
echo .
echo This script expects there to be almost no errors under NetError's or DataError's
echo ... there should be zero errors on the server
echo ... there may be a few bind failed (10048) errors on the client, as we are rapid cycling through a range of local ports
echo ... but these should be fairly rare
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------------------
if '%1' == '' (
echo Must specify server or client as the first argument
goto :exit
)
if /i '%1' NEQ 'server' (
if /i '%1' NEQ 'client' (
echo Must specify server or client
goto :exit
)
if '%2' == '' (
echo client must specify the target server name or IP address
goto :exit
)
)
set TimeToRun=1800000
set Options= -Protocol:tcp -Pattern:duplex -Verify:data -Transfer:0xff
if '%1' == 'server' (
ctsTraffic.exe -Listen:* %Options% -ConsoleVerbosity:1
)
if '%1' == 'client' (
ctsTraffic.exe -Target:%2 %Options% -localport:[12345,12400] -Shutdown:rude -PortScalability:on -Connections:15 -ConsoleVerbosity:2 -TimeLimit:%TimeToRun%
)
:exit

Просмотреть файл

@ -0,0 +1,65 @@
@echo off
REM
REM
REM Copyright (c) Microsoft Corporation
REM All rights reserved.
REM
REM Licensed 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
REM
REM THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
REM
REM See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
REM
REM
echo ----------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------
echo This validation script will verify handling TCP connection states at scale (1000 concurrent connections being closed or RST randomly)
echo .
echo Having connections randomly terminated locally and remotely has been found to be an effective way to find reliability issues in drivers and filters.
echo .
echo This can be run on any number of clients targeting the same server (or targeting multiple servers, if desired).
echo .
echo I would recommend a minimum of 1000 concurrent connections to focus on stressing handling connection failures.
echo ... but feel free to modify -Connections as needed for targeting specific scenarios
echo .
echo Note: this sets the Transfer size to be randomly chosen with each connection (-Transfer:[0xff,0xffffff])
echo ... random transfer size will naturally cause either the client or the server to closesocket() while IO is in flight
echo .
echo Note: this is set to run for 1,800,000 ms (30 minutes) - this can be modified to match your target goals
echo .
echo This script expects there to be many NetError's and DataError's - we are intentionally injecting failures in all connections
echo ----------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------
if '%1' == '' (
echo Must specify server or client as the first argument
goto :exit
)
if /i '%1' NEQ 'server' (
if /i '%1' NEQ 'client' (
echo Must specify server or client
goto :exit
)
if '%2' == '' (
echo client must specify the target server name or IP address
goto :exit
)
)
set TimeToRun=1800000
set Options= -Protocol:tcp -Pattern:duplex -Verify:connection -Transfer:[0xff,0xffffff]
if '%1' == 'server' (
ctsTraffic.exe -Listen:* %Options% -ConsoleVerbosity:1
)
if '%1' == 'client' (
ctsTraffic.exe -Target:%2 %Options% -Shutdown:random -Connections:1000 -ConsoleVerbosity:1 -TimeLimit:%TimeToRun%
)
:exit

Просмотреть файл

@ -0,0 +1,68 @@
@echo off
REM
REM
REM Copyright (c) Microsoft Corporation
REM All rights reserved.
REM
REM Licensed 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
REM
REM THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
REM
REM See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
REM
REM
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo This validation script will verify TCP data and connection integrity at scale (hundreds of concurrent connections) at line rate
echo This will also randomly have client connections terminate with an RST, or a full 4-way FIN (both are perfectly fine ways to terminate a connection)
echo ... note this -Shutdown:random option requires ctsTraffic version 2.0.3.3
echo .
echo Full-duplex with data validation has been found to be an effective way to find IO issues in drivers and filters.
echo .
echo This can be run on any number of clients targeting the same server (or targeting multiple servers, if desired).
echo .
echo Note: that this is defaulting to a relatively small transfer-size per connection
echo ... ctsTraffic default is 0x40000000 - 1TB, here I chose 0x10000000 - 256MB
echo ... this can be modified as needed to match a targeted scenario
echo .
echo I would recommend a minimum of 200 concurrent connections to push the system to maximize data and connection integrity tests.
echo ... but feel free to modify -Connections as needed for targeting specific scenarios
echo .
echo Note: this is set to run for 1,800,000 ms (30 minutes) - this can be modified to match your target goals
echo .
echo This script expects there to be *zero* NetError's or DataError's - every connection should completed successfully (the Completed column)
echo .
echo ----------------------------------------------------------------------------------------------------------------------------------------
echo ----------------------------------------------------------------------------------------------------------------------------------------
if '%1' == '' (
echo Must specify server or client as the first argument
goto :exit
)
if /i '%1' NEQ 'server' (
if /i '%1' NEQ 'client' (
echo Must specify server or client
goto :exit
)
if '%2' == '' (
echo client must specify the target server name or IP address
goto :exit
)
)
set TimeToRun=1800000
set Options= -Protocol:tcp -Pattern:duplex -Verify:data -Transfer:0x10000000
if '%1' == 'server' (
ctsTraffic.exe -Listen:* %Options% -ConsoleVerbosity:1
)
if '%1' == 'client' (
ctsTraffic.exe -Target:%2 %Options% -Shutdown:random -Connections:200 -ConsoleVerbosity:2 -TimeLimit:%TimeToRun%
)
:exit

Просмотреть файл

@ -62,7 +62,7 @@ public:
// Generates a new random floating-point number in the range [lowerInclusiveBound, upperInclusiveBound].
//
// The result is chosen according to a uniformaly random distribution of real numbers, not a uniformly
// The result is chosen according to a uniformly random distribution of real numbers, not a uniformly
// random distribution of those numbers representable as RealTs. That is, even though a double can represent
// more distinct values in the range [0.0, 1.0] than it can in the range [99.0, 100.0], uniform_real(0.0, 100.0)
// will return a number in those two ranges equally often.

Просмотреть файл

@ -692,7 +692,7 @@ inline bool ctSockaddr::writeCompleteAddress(CHAR (&address)[FixedStringLength],
auto* const end = address + addressLength;
if (auto* pScopePtr = std::find(address, end, '%'); pScopePtr != end)
{
if (auto* pMovePtr = std::find(address, end, ']'); pMovePtr != end)
if (const auto* pMovePtr = std::find(address, end, ']'); pMovePtr != end)
{
while (pMovePtr != end)
{

Просмотреть файл

@ -51,7 +51,7 @@ namespace ctl { namespace Details
}
auto wsaCleanupOnExit = wil::scope_exit([&]() noexcept { WSACleanup(); });
// check to see if need to create a temp socket
// check to see if we need to create a temp socket
const wil::unique_socket localSocket{socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)};
if (INVALID_SOCKET == localSocket.get())
{

Просмотреть файл

@ -65,7 +65,7 @@ inline std::string convert_to_string(const std::wstring& wstr)
}
std::string buf(len, '\0');
len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buf[0], len, nullptr, nullptr);
len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, buf.data(), len, nullptr, nullptr);
if (len == 0)
{
THROW_WIN32_MSG(GetLastError(), "WideCharToMultiByte");
@ -90,7 +90,7 @@ inline std::wstring convert_to_wstring(const std::string& str)
}
std::wstring buf(len, L'\0');
len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &buf[0], len);
len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, buf.data(), len);
if (len == 0)
{
THROW_WIN32_MSG(GetLastError(), "MultiByteToWideChar");

Просмотреть файл

@ -229,12 +229,6 @@ public:
template <typename FunctorType>
HRESULT submit_and_wait(FunctorType&& functor) noexcept try
{
// this is not applicable for flat queues
if constexpr (GrowthPolicy == ctThreadpoolGrowthPolicy::Flat)
{
FAIL_FAST_MSG("submit_and_wait only supported with Growable queues");
}
if constexpr (GrowthPolicy == ctThreadpoolGrowthPolicy::Growable)
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
@ -248,6 +242,9 @@ public:
}
return hr;
}
// this is not applicable for flat queues
FAIL_FAST_MSG("submit_and_wait only supported with Growable queues");
}
CATCH_RETURN()
@ -262,7 +259,7 @@ public:
for (const auto& work : m_workItems)
{
// signal that these are canceled before we shutdown the TP which they could be scheduled
// signal that these are canceled before we shut down the TP which they could be scheduled
if (const auto* pWaitableWorkitem = std::get_if<WaitableFunctionT>(&work))
{
(*pWaitableWorkitem)->abort();

Просмотреть файл

@ -34,7 +34,7 @@ See the Apache Version 2.0 License for specific language governing permissions a
namespace ctl
{
// class ctWmiClassObject
// Exposes enumerating properties of a WMI Provider through an property_iterator interface.
// Exposes enumerating properties of a WMI Provider through a property_iterator interface.
class ctWmiClassObject
{
private:
@ -83,12 +83,12 @@ public:
[[nodiscard]] property_iterator property_begin(bool fNonSystemPropertiesOnly = true) const
{
return property_iterator(m_wbemClassObject, fNonSystemPropertiesOnly);
return {m_wbemClassObject, fNonSystemPropertiesOnly};
}
[[nodiscard]] static property_iterator property_end() noexcept
{
return property_iterator();
return {};
}
//

Просмотреть файл

@ -115,7 +115,7 @@ public:
}
// Allows for executing a WMI query against the WMI service for an enumeration of WMI objects.
// Assumes the query of of the WQL query language.
// Assumes the query of the WQL query language.
const ctWmiEnumerate& query(_In_ PCWSTR query)
{
THROW_IF_FAILED(m_wbemServices->ExecQuery(
@ -145,7 +145,7 @@ public:
return end();
}
THROW_IF_FAILED(m_wbemEnumerator->Reset());
return iterator(m_wbemServices, m_wbemEnumerator);
return {m_wbemServices, m_wbemEnumerator};
}
iterator end() const noexcept
@ -160,7 +160,7 @@ public:
return cend();
}
THROW_IF_FAILED(m_wbemEnumerator->Reset());
return iterator(m_wbemServices, m_wbemEnumerator);
return {m_wbemServices, m_wbemEnumerator};
}
iterator cend() const noexcept

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -81,7 +81,7 @@ public:
[[nodiscard]] static iterator end() noexcept
{
return iterator();
return {};
}
// A forward iterator to enable forward-traversing instances of the queried WMI provider

Просмотреть файл

@ -968,7 +968,7 @@ namespace ctsPerf { namespace Details
{
// IPv4
RefreshIPv4Data();
auto* const pIpv4TcpTable = reinterpret_cast<PMIB_TCPTABLE>(&m_tcpTable[0]);
auto* const pIpv4TcpTable = reinterpret_cast<PMIB_TCPTABLE>(m_tcpTable.data());
for (auto count = 0ul; count < pIpv4TcpTable->dwNumEntries; ++count)
{
auto* const tableEntry = &pIpv4TcpTable->table[count];
@ -1000,7 +1000,7 @@ namespace ctsPerf { namespace Details
// IPv6
RefreshIPv6Data();
auto* const pIpv6TcpTable = reinterpret_cast<PMIB_TCP6TABLE>(&m_tcpTable[0]);
auto* const pIpv6TcpTable = reinterpret_cast<PMIB_TCP6TABLE>(m_tcpTable.data());
for (auto count = 0ul; count < pIpv6TcpTable->dwNumEntries; ++count)
{
auto* const tableEntry = &pIpv6TcpTable->table[count];
@ -1064,17 +1064,17 @@ namespace ctsPerf { namespace Details
{
m_tcpTable.resize(m_tcpTable.capacity());
auto table_size = static_cast<DWORD>(m_tcpTable.size());
ZeroMemory(&m_tcpTable[0], table_size);
ZeroMemory(m_tcpTable.data(), table_size);
ULONG error = GetTcpTable(
reinterpret_cast<PMIB_TCPTABLE>(&m_tcpTable[0]),
reinterpret_cast<PMIB_TCPTABLE>(m_tcpTable.data()),
&table_size,
FALSE); // no need to sort them
if (ERROR_INSUFFICIENT_BUFFER == error)
{
m_tcpTable.resize(table_size);
error = GetTcpTable(
reinterpret_cast<PMIB_TCPTABLE>(&m_tcpTable[0]),
reinterpret_cast<PMIB_TCPTABLE>(m_tcpTable.data()),
&table_size,
FALSE); // no need to sort them
}
@ -1088,17 +1088,17 @@ namespace ctsPerf { namespace Details
{
m_tcpTable.resize(m_tcpTable.capacity());
auto table_size = static_cast<DWORD>(m_tcpTable.size());
ZeroMemory(&m_tcpTable[0], table_size);
ZeroMemory(m_tcpTable.data(), table_size);
ULONG error = GetTcp6Table(
reinterpret_cast<PMIB_TCP6TABLE>(&m_tcpTable[0]),
reinterpret_cast<PMIB_TCP6TABLE>(m_tcpTable.data()),
&table_size,
FALSE); // no need to sort them
if (ERROR_INSUFFICIENT_BUFFER == error)
{
m_tcpTable.resize(table_size);
error = GetTcp6Table(
reinterpret_cast<PMIB_TCP6TABLE>(&m_tcpTable[0]),
reinterpret_cast<PMIB_TCP6TABLE>(m_tcpTable.data()),
&table_size,
FALSE); // no need to sort them
}

Двоичные данные
ctsPerf/ctsPerf.aps

Двоичный файл не отображается.

Двоичные данные
ctsPerf/ctsPerf.rc

Двоичный файл не отображается.

Просмотреть файл

@ -422,12 +422,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231028.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>

Двоичные данные
ctsTraffic/Resource.rc

Двоичный файл не отображается.

Просмотреть файл

@ -419,8 +419,8 @@ namespace details
sizeof listeningSocket);
FAIL_FAST_IF_MSG(
err != 0,
"setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed [%d], accept socket [%p], listen socket [%p]",
WSAGetLastError(), reinterpret_cast<void*>(m_acceptSocket.get()), reinterpret_cast<void*>(listeningSocket));
"setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed [%d], accept socket [%zu], listen socket [%zu]",
WSAGetLastError(), m_acceptSocket.get(), listeningSocket);
SOCKADDR_INET* localAddr{};
auto localAddrLen = static_cast<int>(sizeof SOCKADDR_INET);
@ -535,7 +535,7 @@ namespace details
//
//
// An accepted socket is being requested
// - if have one queued, return that
// - if there is one queued, return that
// - else store the weak_ptr<ctsSocket> to be fulfilled later
//
//
@ -569,7 +569,7 @@ void ctsAcceptEx(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
try { details::g_acceptExImpl.m_pendedAcceptRequests.push(weakSocket); }
catch (...)
{
// fail the caller if can't save this request
// fail the caller if we can't save this request
error = WSAENOBUFS;
}
}
@ -593,7 +593,7 @@ void ctsAcceptEx(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
}
//
// if did not defer the accept request and we have a new accepted socket,
// if did not defer the accept request, and we have a new accepted socket,
// complete this socket state
//
if (acceptedConnection.m_acceptSocket.get() != INVALID_SOCKET)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -35,162 +35,170 @@ See the Apache Version 2.0 License for specific language governing permissions a
#include "ctsStatistics.hpp"
namespace ctsTraffic
{
//
// Forward declaring ctsSocket project headers cannot be included due to circular references
//
// In the ctsTraffic namespace, typedef for all function types
// - function pointers, functors, lambdas, etc.
//
class ctsSocket;
using ctsSocketFunction = std::function<void (std::weak_ptr<ctsSocket>)>;
namespace ctsConfig
{
//
// Declaring enum types in the ctsConfig namespace
// - to be referenced by ctsConfig functions
// Forward declaring ctsSocket project headers cannot be included due to circular references
//
enum class ProtocolType
{
NoProtocolSet,
TCP,
UDP
};
enum class TcpShutdownType
{
NoShutdownOptionSet,
ServerSideShutdown,
GracefulShutdown,
HardShutdown
};
enum class IoPatternType
{
NoIoSet,
Push,
Pull,
PushPull,
Duplex,
MediaStream
};
enum class StatusFormatting
{
NoFormattingSet,
ClearText,
Csv,
ConsoleOutput
};
// cannot be an enum class and have the below operator overloads work correctly
enum OptionType
{
NoOptionSet = 0x0000,
LoopbackFastPath = 0x0001,
Keepalive = 0x0002,
NonBlockingIo = 0x0004,
HandleInlineIocp = 0x0008,
ReuseUnicastPort = 0x0010,
SetRecvBuf = 0x0020,
SetSendBuf = 0x0040,
EnableCircularQueueing = 0x0080,
MsgWaitAll = 0x0100,
// next enum = 0x0200
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// In the ctsTraffic namespace, typedef for all function types
// - function pointers, functors, lambdas, etc.
//
// custom operators for the OptionType enum (since it's an to be used as a bitmask)
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class ctsSocket;
using ctsSocketFunction = std::function<void (std::weak_ptr<ctsSocket>)>;
// OR
inline OptionType operator|(const OptionType& lhs, const OptionType& rhs) noexcept
namespace ctsConfig
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}
//
// Declaring enum types in the ctsConfig namespace
// - to be referenced by ctsConfig functions
//
enum class ExitProcessType : LONG
{
Running,
Normal,
Rude
};
inline OptionType& operator|=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs | rhs;
return lhs;
}
enum class ProtocolType
{
NoProtocolSet,
TCP,
UDP
};
// AND
inline OptionType operator&(const OptionType& lhs, const OptionType& rhs) noexcept
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}
enum class TcpShutdownType
{
NoShutdownOptionSet,
GracefulShutdown,
HardShutdown,
Random
};
inline OptionType& operator&=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs & rhs;
return lhs;
}
enum class IoPatternType
{
NoIoSet,
Push,
Pull,
PushPull,
Duplex,
MediaStream
};
// XOR
inline OptionType operator^(const OptionType& lhs, const OptionType& rhs) noexcept
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) ^ static_cast<uint32_t>(rhs));
}
enum class StatusFormatting
{
NoFormattingSet,
ClearText,
Csv,
ConsoleOutput
};
inline OptionType& operator^=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs ^ rhs;
return lhs;
}
// cannot be an enum class and have the below operator overloads work correctly
enum OptionType
{
NoOptionSet = 0x0000,
LoopbackFastPath = 0x0001,
KeepAlive = 0x0002,
NonBlockingIo = 0x0004,
HandleInlineIocp = 0x0008,
ReuseUnicastPort = 0x0010,
SetRecvBuf = 0x0020,
SetSendBuf = 0x0040,
EnableCircularQueueing = 0x0080,
MsgWaitAll = 0x0100,
PortScalability = 0x0200
// next enum = 0x0400
};
// NOT
inline OptionType operator~(const OptionType& lhs) noexcept
{
return static_cast<OptionType>(~static_cast<uint32_t>(lhs));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// custom operators for the OptionType enum (since it's to be used as a bitmask)
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Members within the ctsConfig namespace that can be accessed anywhere within ctsTraffic
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Startup(int argc, _In_reads_(argc) const wchar_t** argv);
void Shutdown() noexcept;
// OR
inline OptionType operator|(const OptionType& lhs, const OptionType& rhs) noexcept
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}
enum class PrintUsageOption
{
Default,
Tcp,
Udp,
Logging,
Advanced
};
inline OptionType& operator|=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs | rhs;
return lhs;
}
void PrintUsage(PrintUsageOption option = PrintUsageOption::Default);
void PrintSettings();
// AND
inline OptionType operator&(const OptionType& lhs, const OptionType& rhs) noexcept
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}
void PrintLegend() noexcept;
inline OptionType& operator&=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs & rhs;
return lhs;
}
struct JitterFrameEntry
{
uint32_t m_bytesReceived = 0UL;
int64_t m_sequenceNumber = 0LL;
int64_t m_senderQpc = 0LL;
int64_t m_senderQpf = 0LL;
int64_t m_receiverQpc = 0LL;
int64_t m_receiverQpf = 0LL;
double m_estimatedTimeInFlightMs = 0;
};
// XOR
inline OptionType operator^(const OptionType& lhs, const OptionType& rhs) noexcept
{
return static_cast<OptionType>(static_cast<uint32_t>(lhs) ^ static_cast<uint32_t>(rhs));
}
void PrintJitterUpdate(const JitterFrameEntry& currentFrame, const JitterFrameEntry& previousFrame) noexcept;
inline OptionType& operator^=(OptionType& lhs, const OptionType& rhs) noexcept
{
lhs = lhs ^ rhs;
return lhs;
}
void __cdecl PrintSummary(_In_ _Printf_format_string_ PCWSTR text, ...) noexcept;
void PrintStatusUpdate() noexcept;
void PrintErrorInfo(_In_ _Printf_format_string_ PCWSTR text, ...) noexcept;
void PrintErrorIfFailed(_In_ PCSTR what, uint32_t why) noexcept;
// Override will always print to console regardless of settings (important if can't even start)
void PrintErrorInfoOverride(_In_ PCWSTR text) noexcept;
// NOT
inline OptionType operator~(const OptionType& lhs) noexcept
{
return static_cast<OptionType>(~static_cast<uint32_t>(lhs));
}
// Putting PrintDebugInfo as a macro to avoid running any code for debug printing if not necessary
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Members within the ctsConfig namespace that can be accessed anywhere within ctsTraffic
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Startup(int argc, _In_reads_(argc) const wchar_t** argv);
void Shutdown(ExitProcessType type) noexcept;
enum class PrintUsageOption
{
Default,
Tcp,
Udp,
Logging,
Advanced
};
void PrintUsage(PrintUsageOption option = PrintUsageOption::Default);
void PrintSettings();
void PrintLegend() noexcept;
struct JitterFrameEntry
{
uint32_t m_bytesReceived = 0UL;
int64_t m_sequenceNumber = 0LL;
int64_t m_senderQpc = 0LL;
int64_t m_senderQpf = 0LL;
int64_t m_receiverQpc = 0LL;
int64_t m_receiverQpf = 0LL;
double m_estimatedTimeInFlightMs = 0;
};
void PrintJitterUpdate(const JitterFrameEntry& currentFrame, const JitterFrameEntry& previousFrame) noexcept;
void __cdecl PrintSummary(_In_ _Printf_format_string_ PCWSTR text, ...) noexcept;
void PrintStatusUpdate() noexcept;
void PrintErrorInfo(_In_ _Printf_format_string_ PCWSTR text, ...) noexcept;
void PrintErrorIfFailed(_In_ PCSTR what, uint32_t why) noexcept;
// Override will always print to console regardless of settings (important if can't even start)
void PrintErrorInfoOverride(_In_ PCWSTR text) noexcept;
// Putting PrintDebugInfo as a macro to avoid running any code for debug printing if not necessary
#define PRINT_DEBUG_INFO(fmt, ...) \
do \
{ \
@ -202,217 +210,240 @@ namespace ctsConfig
} \
while ((void)0, 0)
constexpr DWORD Win32FromHresult(HRESULT hr) noexcept
{
if (HRESULT_SEVERITY(hr) == SEVERITY_ERROR && HRESULT_FACILITY(hr) == FACILITY_WIN32)
constexpr DWORD Win32FromHresult(HRESULT hr) noexcept
{
return HRESULT_CODE(hr);
if (HRESULT_SEVERITY(hr) == SEVERITY_ERROR && HRESULT_FACILITY(hr) == FACILITY_WIN32)
{
return HRESULT_CODE(hr);
}
return hr;
}
return hr;
}
DWORD PrintThrownException() noexcept;
void PrintException(DWORD why, _In_ PCWSTR what, _In_ PCWSTR where) noexcept;
// Override will always print to console regardless of settings (important if can't even start)
void PrintExceptionOverride(_In_ PCSTR exceptionText) noexcept;
DWORD PrintThrownException() noexcept;
void PrintException(DWORD why, _In_ PCWSTR what, _In_ PCWSTR where) noexcept;
// Override will always print to console regardless of settings (important if can't even start)
void PrintExceptionOverride(_In_ PCSTR exceptionText) noexcept;
void PrintNewConnection(const ctl::ctSockaddr& localAddr, const ctl::ctSockaddr& remoteAddr) noexcept;
void PrintConnectionResults(const ctl::ctSockaddr& localAddr, const ctl::ctSockaddr& remoteAddr, uint32_t error, const ctsTcpStatistics& stats) noexcept;
void PrintConnectionResults(const ctl::ctSockaddr& localAddr, const ctl::ctSockaddr& remoteAddr, uint32_t error, const ctsUdpStatistics& stats) noexcept;
void PrintConnectionResults(uint32_t error) noexcept;
void PrintTcpDetails(const ctl::ctSockaddr& localAddr, const ctl::ctSockaddr& remoteAddr, SOCKET socket, const ctsTcpStatistics& stats) noexcept;
void PrintNewConnection(const ctl::ctSockaddr& localAddr, const ctl::ctSockaddr& remoteAddr) noexcept;
constexpr void PrintTcpDetails(const ctl::ctSockaddr&, const ctl::ctSockaddr&, SOCKET, const ctsUdpStatistics&) noexcept
{
// must implement ctsUdpStatistics as a no-op for the caller's template to compile
}
void PrintConnectionResults(uint32_t error) noexcept;
void PrintConnectionResults(
const ctl::ctSockaddr& localAddr,
const ctl::ctSockaddr& remoteAddr,
uint32_t error,
const ctsTcpStatistics& stats) noexcept;
void PrintConnectionResults(
const ctl::ctSockaddr& localAddr,
const ctl::ctSockaddr& remoteAddr,
uint32_t error,
const ctsUdpStatistics& stats) noexcept;
// Get* functions
int64_t GetTcpBytesPerSecond() noexcept;
uint32_t GetMaxBufferSize() noexcept;
uint32_t GetMinBufferSize() noexcept;
uint32_t GetBufferSize() noexcept;
uint64_t GetTransferSize() noexcept;
float GetStatusTimeStamp() noexcept;
int32_t GetListenBacklog() noexcept;
bool IsListening() noexcept;
// Set* functions
int32_t SetPreBindOptions(SOCKET socket, const ctl::ctSockaddr& localAddress) noexcept;
int32_t SetPreConnectOptions(SOCKET) noexcept;
// for the MediaStream pattern
struct MediaStreamSettings
{
// set by ctsConfig from command-line arguments
int64_t BitsPerSecond = 0;
uint32_t FramesPerSecond = 0;
uint32_t BufferDepthSeconds = 0;
uint32_t StreamLengthSeconds = 0;
// internally calculated
uint32_t FrameSizeBytes = 0;
uint32_t StreamLengthFrames = 0;
uint32_t BufferedFrames = 0;
uint64_t CalculateTransferSize()
void PrintTcpDetails(
const ctl::ctSockaddr& localAddr,
const ctl::ctSockaddr& remoteAddr,
SOCKET socket,
const ctsTcpStatistics& stats) noexcept;
constexpr void PrintTcpDetails(
const ctl::ctSockaddr&,
const ctl::ctSockaddr&,
SOCKET,
const ctsUdpStatistics&) noexcept
{
FAIL_FAST_IF_MSG(
0LL == BitsPerSecond,
"BitsPerSecond cannot be set to zero");
FAIL_FAST_IF_MSG(
0 == FramesPerSecond,
"FramesPerSecond cannot be set to zero");
FAIL_FAST_IF_MSG(
0 == StreamLengthSeconds,
"StreamLengthSeconds cannot be set to zero");
FAIL_FAST_IF_MSG(
BitsPerSecond % 8LL != 0LL,
"The BitsPerSecond value (%lld) must be evenly divisible by 8", BitsPerSecond);
// must implement ctsUdpStatistics as a no-op for the caller's template to compile
}
// number of frames to keep buffered - only relevant on the client
if (!IsListening())
// Get* functions
int64_t GetTcpBytesPerSecond() noexcept;
uint32_t GetMaxBufferSize() noexcept;
uint32_t GetMinBufferSize() noexcept;
uint32_t GetBufferSize() noexcept;
uint64_t GetTransferSize() noexcept;
float GetStatusTimeStamp() noexcept;
int32_t GetListenBacklog() noexcept;
bool IsListening() noexcept;
TcpShutdownType GetShutdownType() noexcept;
// Set* functions
int32_t SetPreBindOptions(SOCKET socket, const ctl::ctSockaddr& localAddress) noexcept;
int32_t SetPreConnectOptions(SOCKET) noexcept;
// for the MediaStream pattern
struct MediaStreamSettings
{
// set by ctsConfig from command-line arguments
int64_t BitsPerSecond = 0;
uint32_t FramesPerSecond = 0;
uint32_t BufferDepthSeconds = 0;
uint32_t StreamLengthSeconds = 0;
// internally calculated
uint32_t FrameSizeBytes = 0;
uint32_t StreamLengthFrames = 0;
uint32_t BufferedFrames = 0;
uint64_t CalculateTransferSize()
{
FAIL_FAST_IF_MSG(
0 == BufferDepthSeconds,
"BufferDepthSeconds cannot be set to zero");
0LL == BitsPerSecond,
"BitsPerSecond cannot be set to zero");
FAIL_FAST_IF_MSG(
0 == FramesPerSecond,
"FramesPerSecond cannot be set to zero");
FAIL_FAST_IF_MSG(
0 == StreamLengthSeconds,
"StreamLengthSeconds cannot be set to zero");
FAIL_FAST_IF_MSG(
BitsPerSecond % 8LL != 0LL,
"The BitsPerSecond value (%lld) must be evenly divisible by 8", BitsPerSecond);
BufferedFrames = BufferDepthSeconds * FramesPerSecond;
if (BufferedFrames < BufferDepthSeconds || BufferedFrames < FramesPerSecond)
// number of frames to keep buffered - only relevant on the client
if (!IsListening())
{
throw std::invalid_argument("The total buffered frames exceed the maximum allowed : review -BufferDepth and -FrameRate");
FAIL_FAST_IF_MSG(
0 == BufferDepthSeconds,
"BufferDepthSeconds cannot be set to zero");
BufferedFrames = BufferDepthSeconds * FramesPerSecond;
if (BufferedFrames < BufferDepthSeconds || BufferedFrames < FramesPerSecond)
{
throw std::invalid_argument(
"The total buffered frames exceed the maximum allowed : review -BufferDepth and -FrameRate");
}
}
const auto totalStreamLengthFrames = StreamLengthSeconds * FramesPerSecond;
if (totalStreamLengthFrames > MAXULONG32)
{
throw std::invalid_argument(
"The total stream length in frame-count exceeds the maximum allowed to be streamed (2^32)");
}
// convert rate to bytes / second -> calculate the total # of bytes
auto totalStreamLengthBytes = BitsPerSecond / 8ULL * StreamLengthSeconds;
// guarantee that the total stream length aligns evenly with total_frames
if (totalStreamLengthBytes % totalStreamLengthFrames != 0)
{
totalStreamLengthBytes -= totalStreamLengthBytes % totalStreamLengthFrames;
}
const auto totalFrameSizeBytes = totalStreamLengthBytes / totalStreamLengthFrames;
if (totalFrameSizeBytes > MAXULONG32)
{
throw std::invalid_argument(
"The frame size in bytes exceeds the maximum allowed to be streamed (2^32)");
}
FrameSizeBytes = static_cast<uint32_t>(totalFrameSizeBytes);
if (FrameSizeBytes < 40)
{
throw std::invalid_argument("The frame size is too small - it must be at least 40 bytes");
}
StreamLengthFrames = static_cast<uint32_t>(totalStreamLengthFrames);
// guarantee frame alignment
FAIL_FAST_IF_MSG(
static_cast<uint64_t>(FrameSizeBytes) * static_cast<uint64_t>(StreamLengthFrames) !=
totalStreamLengthBytes,
"FrameSizeBytes (%u) * StreamLengthFrames (%u) != TotalStreamLength (%llx)",
FrameSizeBytes, StreamLengthFrames, totalStreamLengthBytes);
return totalStreamLengthBytes;
}
};
const auto totalStreamLengthFrames = StreamLengthSeconds * FramesPerSecond;
if (totalStreamLengthFrames > MAXULONG32)
{
throw std::invalid_argument("The total stream length in frame-count exceeds the maximum allowed to be streamed (2^32)");
}
const MediaStreamSettings& GetMediaStream() noexcept;
// convert rate to bytes / second -> calculate the total # of bytes
auto totalStreamLengthBytes = BitsPerSecond / 8ULL * StreamLengthSeconds;
// guarantee that the total stream length aligns evenly with total_frames
if (totalStreamLengthBytes % totalStreamLengthFrames != 0)
{
totalStreamLengthBytes -= totalStreamLengthBytes % totalStreamLengthFrames;
}
const auto totalFrameSizeBytes = totalStreamLengthBytes / totalStreamLengthFrames;
if (totalFrameSizeBytes > MAXULONG32)
{
throw std::invalid_argument("The frame size in bytes exceeds the maximum allowed to be streamed (2^32)");
}
FrameSizeBytes = static_cast<uint32_t>(totalFrameSizeBytes);
if (FrameSizeBytes < 40)
{
throw std::invalid_argument("The frame size is too small - it must be at least 40 bytes");
}
StreamLengthFrames = static_cast<uint32_t>(totalStreamLengthFrames);
// guarantee frame alignment
FAIL_FAST_IF_MSG(
static_cast<uint64_t>(FrameSizeBytes) * static_cast<uint64_t>(StreamLengthFrames) != totalStreamLengthBytes,
"FrameSizeBytes (%u) * StreamLengthFrames (%u) != TotalStreamLength (%llx)",
FrameSizeBytes, StreamLengthFrames, totalStreamLengthBytes);
return totalStreamLengthBytes;
}
};
const MediaStreamSettings& GetMediaStream() noexcept;
struct ctsConfigSettings
{
// dynamically initialize status details with current qpc
ctsConfigSettings() noexcept :
ConnectionStatusDetails(ctl::ctTimer::snap_qpc_as_msec())
struct ctsConfigSettings
{
}
// dynamically initialize status details with current qpc
ctsConfigSettings() noexcept :
ConnectionStatusDetails(ctl::ctTimer::snap_qpc_as_msec())
{
}
~ctsConfigSettings() noexcept = default;
// non-copyable
ctsConfigSettings(const ctsConfigSettings&) = delete;
ctsConfigSettings& operator=(const ctsConfigSettings&) = delete;
ctsConfigSettings(ctsConfigSettings&&) = delete;
ctsConfigSettings& operator=(ctsConfigSettings&&) = delete;
~ctsConfigSettings() noexcept = default;
// non-copyable
ctsConfigSettings(const ctsConfigSettings&) = delete;
ctsConfigSettings& operator=(const ctsConfigSettings&) = delete;
ctsConfigSettings(ctsConfigSettings&&) = delete;
ctsConfigSettings& operator=(ctsConfigSettings&&) = delete;
HANDLE CtrlCHandle = nullptr;
PTP_CALLBACK_ENVIRON pTpEnvironment = nullptr;
HANDLE CtrlCHandle = nullptr;
PTP_CALLBACK_ENVIRON pTpEnvironment = nullptr;
ctsSocketFunction CreateFunction;
ctsSocketFunction ConnectFunction;
ctsSocketFunction AcceptFunction;
ctsSocketFunction IoFunction;
ctsSocketFunction ClosingFunction; // optional
ctsSocketFunction CreateFunction;
ctsSocketFunction ConnectFunction;
ctsSocketFunction AcceptFunction;
ctsSocketFunction IoFunction;
ctsSocketFunction ClosingFunction; // optional
ProtocolType Protocol = ProtocolType::NoProtocolSet;
TcpShutdownType TcpShutdown = TcpShutdownType::NoShutdownOptionSet;
IoPatternType IoPattern = IoPatternType::NoIoSet;
OptionType Options = NoOptionSet;
ProtocolType Protocol = ProtocolType::NoProtocolSet;
TcpShutdownType TcpShutdown = TcpShutdownType::NoShutdownOptionSet;
IoPatternType IoPattern = IoPatternType::NoIoSet;
OptionType Options = NoOptionSet;
uint32_t SocketFlags = 0;
uint32_t SocketFlags = 0;
uint64_t Iterations = 0;
uint64_t ServerExitLimit = 0;
uint32_t AcceptLimit = 0;
uint32_t ConnectionLimit = 0;
uint32_t ConnectionThrottleLimit = 0;
uint64_t Iterations = 0;
uint64_t ServerExitLimit = 0;
uint32_t AcceptLimit = 0;
uint32_t ConnectionLimit = 0;
uint32_t ConnectionThrottleLimit = 0;
std::vector<ctl::ctSockaddr> ListenAddresses{};
std::vector<ctl::ctSockaddr> TargetAddresses{};
std::vector<ctl::ctSockaddr> BindAddresses{};
std::vector<std::wstring> TargetAddressStrings{};
std::vector<ctl::ctSockaddr> ListenAddresses{};
std::vector<ctl::ctSockaddr> TargetAddresses{};
std::vector<ctl::ctSockaddr> BindAddresses{};
std::vector<std::wstring> TargetAddressStrings{};
// stats for status updates and summaries
ctsConnectionStatistics ConnectionStatusDetails;
ctsTcpStatistics TcpStatusDetails;
ctsUdpStatistics UdpStatusDetails;
// stats for status updates and summaries
ctsConnectionStatistics ConnectionStatusDetails;
ctsTcpStatistics TcpStatusDetails;
ctsUdpStatistics UdpStatusDetails;
uint32_t StatusUpdateFrequencyMilliseconds = 0;
uint32_t StatusUpdateFrequencyMilliseconds = 0;
int64_t TcpBytesPerSecondPeriod = 100LL;
int64_t StartTimeMilliseconds = 0;
int64_t TcpBytesPerSecondPeriod = 100LL;
int64_t StartTimeMilliseconds = 0;
uint32_t TimeLimit = 0;
uint32_t PauseAtEnd = 0;
uint32_t PrePostRecvs = 0;
uint32_t PrePostSends = 0;
uint32_t RecvBufValue = 0;
uint32_t SendBufValue = 0;
uint32_t KeepAliveValue = 0;
uint32_t TimeLimit = 0;
uint32_t PauseAtEnd = 0;
uint32_t PrePostRecvs = 0;
uint32_t PrePostSends = 0;
uint32_t RecvBufValue = 0;
uint32_t SendBufValue = 0;
uint32_t KeepAliveValue = 0;
uint32_t PushBytes = 0;
uint32_t PullBytes = 0;
uint32_t PushBytes = 0;
uint32_t PullBytes = 0;
std::optional<uint32_t> BurstCount;
std::optional<uint32_t> BurstDelay;
std::optional<uint32_t> BurstCount;
std::optional<uint32_t> BurstDelay;
uint32_t OutgoingIfIndex = 0;
uint32_t OutgoingIfIndex = 0;
uint16_t LocalPortLow = 0;
uint16_t LocalPortHigh = 0;
uint16_t Port = 0;
uint16_t LocalPortLow = 0;
uint16_t LocalPortHigh = 0;
uint16_t Port = 0;
bool UseSharedBuffer = false;
bool ShouldVerifyBuffers = false;
bool UseSharedBuffer = false;
bool ShouldVerifyBuffers = false;
static constexpr DWORD c_CriticalSectionSpinlock = 200ul;
};
static constexpr DWORD c_CriticalSectionSpinlock = 200ul;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Settings is defined in ctsConfig.cpp
/// - it's made available to all consumers of ctsConfig.h through extern
///
////////////////////////////////////////////////////////////////////////////////////////////////////
extern ctsConfigSettings* g_configSettings;
////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Settings is defined in ctsConfig.cpp
/// - it's made available to all consumers of ctsConfig.h through extern
///
////////////////////////////////////////////////////////////////////////////////////////////////////
extern ctsConfigSettings* g_configSettings;
SOCKET CreateSocket(int af, int type, int protocol, DWORD dwFlags);
bool ShutdownCalled() noexcept;
uint32_t ConsoleVerbosity() noexcept;
} // namespace ctsConfig
SOCKET CreateSocket(int af, int type, int protocol, DWORD dwFlags);
bool ShutdownCalled() noexcept;
uint32_t ConsoleVerbosity() noexcept;
} // namespace ctsConfig
} // namespace ctsTraffic

Просмотреть файл

@ -153,7 +153,7 @@ namespace ctsTraffic
// every recv will need their own buffer to use
// we must keep track of the raw buffers even with RIO as we need the backing buffers to compare against
m_recvBufferContainer.resize(ctsConfig::GetMaxBufferSize() * recvCount);
auto* const rawRecvBuffer = &m_recvBufferContainer[0];
auto* const rawRecvBuffer = m_recvBufferContainer.data();
for (auto bufferCount = 0ul; bufferCount < recvCount; ++bufferCount)
{

Просмотреть файл

@ -273,7 +273,7 @@ private:
}
};
// RIO buffer Id for sends and recv's
// RIO buffer-Id for send()'s and recv()'s
// cannot use the same RIO_BUFFERID concurrently (not supported by RIO)
std::vector<RioBufferId> m_receivingRioBufferIds;
std::vector<RioBufferId> m_sendingRioBufferIds;

Просмотреть файл

@ -420,7 +420,7 @@ void ctsIoPatternMediaStreamClient::RenderFrame() noexcept
m_headEntry->m_sequenceNumber);
// track the dropped frame
// indicate zero's for the other values so we won't calculate jitter for a dropped datagram
// indicate zero's for the other values, so we won't calculate jitter for a dropped datagram
ctsConfig::JitterFrameEntry droppedFrame;
droppedFrame.m_sequenceNumber = m_headEntry->m_sequenceNumber;
PrintJitterUpdate(droppedFrame, ctsConfig::JitterFrameEntry());
@ -435,7 +435,7 @@ void ctsIoPatternMediaStreamClient::RenderFrame() noexcept
m_headEntry->m_sequenceNumber);
}
// update the current sequence number so it's now the "end" sequence number of the queue (the new max value)
// update the current sequence number, so it's now the "end" sequence number of the queue (the new max value)
m_headEntry->m_sequenceNumber = m_headEntry->m_sequenceNumber + static_cast<int64_t>(m_frameEntries.size());
m_headEntry->m_bytesReceived = 0;

Просмотреть файл

@ -225,7 +225,7 @@ public:
}
else
{
// otherwise, we still have an on-going connection
// otherwise, we still have an ongoing connection
// - let the protocol determine how to handle this error given its state
UpdateErrorPerProtocol(errorCode);
if (InternalPatternState::ErrorIoFailed == m_internalState)
@ -433,7 +433,7 @@ inline void ctsIoPatternProtocolPolicy<ctsIoPatternProtocolTcpServer>::UpdateErr
if (InternalPatternState::RequestFin == m_internalState &&
(WSAETIMEDOUT == errorCode || WSAECONNRESET == errorCode || WSAECONNABORTED == errorCode))
{
// this is actually OK - the client may have just sent a RST instead of a graceful FIN
// this is actually OK - the client may have just sent an RST instead of a graceful FIN
m_internalState = InternalPatternState::CompletedTransfer;
// must update pended since the IO is no longer pended,
// - but the class doesn't realize this since we are not moving to a failed internal state
@ -450,7 +450,7 @@ inline void ctsIoPatternProtocolPolicy<ctsIoPatternProtocolTcpServer>::UpdateErr
template <>
inline ctsIoPatternType ctsIoPatternProtocolPolicy<ctsIoPatternProtocolUdp>::GetNextPatternTypePerProtocol() const noexcept
{
// if gets here, the state is either completed or failed
// if we get here, the state is either completed or failed
FAIL_FAST_IF_MSG(
!IsCompleted(),
"ctsIOPatternState::get_next_task was called in an invalid state (%d) - should be completed: dt %p ctsTraffic!ctsTraffic::ctsIOPatternProtocolPolicy<ctsIOPatternProtocolUdp>",
@ -594,7 +594,7 @@ inline void ctsIoPatternProtocolPolicy<ctsIoPatternProtocolTcpClient>::Completed
}
else
{
if (ctsConfig::TcpShutdownType::GracefulShutdown == ctsConfig::g_configSettings->TcpShutdown)
if (ctsConfig::TcpShutdownType::GracefulShutdown == ctsConfig::GetShutdownType())
{
PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::completedTask : GracefulShutdown\n");
m_internalState = InternalPatternState::GracefulShutdown;

Просмотреть файл

@ -62,7 +62,7 @@ class ctsIoPatternState
// TCP: instruct the function to call shutdown(SD_SEND) on the socket
GracefulShutdown,
// TCP: force a RST instead of a 4-way-FIN
// TCP: force an RST instead of a 4-way-FIN
HardShutdown,
// TCP: next ask for IO will be a recv for the zero-byte FIN
RequestFin,
@ -278,7 +278,7 @@ inline ctsIoPatternError ctsIoPatternState::UpdateError(DWORD error) noexcept
InternalPatternState::RequestFin == m_internalState &&
(WSAETIMEDOUT == error || WSAECONNRESET == error || WSAECONNABORTED == error))
{
// these errors on the server are OK when we are waiting for a FIN from the client
// these errors on the server are OK when we are waiting for a FIN from the client.
// the client may have just RST instead of a graceful FIN after receiving our status
return ctsIoPatternError::NoError;
}
@ -444,7 +444,7 @@ inline ctsIoPatternError ctsIoPatternState::CompletedTask(const ctsTask& complet
return ctsIoPatternError::TooFewBytes;
}
if (ctsConfig::TcpShutdownType::GracefulShutdown == ctsConfig::g_configSettings->TcpShutdown)
if (ctsConfig::TcpShutdownType::GracefulShutdown == ctsConfig::GetShutdownType())
{
PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (ClientRecvCompletion) : GracefulShutdown\n");
m_internalState = InternalPatternState::GracefulShutdown;

Просмотреть файл

@ -32,244 +32,263 @@ See the Apache Version 2.0 License for specific language governing permissions a
namespace ctsTraffic
{
struct IoImplStatus
{
int m_errorCode = 0;
bool m_continueIo = false;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Internal implementation functions
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IoImplStatus ctsMediaStreamClientIoImpl(
const std::shared_ptr<ctsSocket>& sharedSocket,
SOCKET socket,
const std::shared_ptr<ctsIoPattern>& lockedPattern,
const ctsTask& task) noexcept;
void ctsMediaStreamClientIoCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctsTask& task
) noexcept;
void ctsMediaStreamClientConnectionCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctl::ctSockaddr& targetAddress
) noexcept;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// The function that is registered with ctsTraffic to run Winsock IO using IO Completion Ports
/// - with the specified ctsSocket
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClient(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
{
// attempt to get a reference to the socket
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
struct IoImplStatus
{
return;
}
int m_errorCode = 0;
bool m_continueIo = false;
};
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto lockedPattern = lockedSocket.GetPattern();
if (!lockedPattern || lockedSocket.GetSocket() == INVALID_SOCKET)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Internal implementation functions
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IoImplStatus ctsMediaStreamClientIoImpl(
const std::shared_ptr<ctsSocket>& sharedSocket,
SOCKET socket,
const std::shared_ptr<ctsIoPattern>& lockedPattern,
const ctsTask& task) noexcept;
void ctsMediaStreamClientIoCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctsTask& task
) noexcept;
void ctsMediaStreamClientConnectionCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctl::ctSockaddr& targetAddress
) noexcept;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// The function that is registered with ctsTraffic to run Winsock IO using IO Completion Ports
/// - with the specified ctsSocket
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClient(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
{
return;
}
// always register our ctsIOPattern callback since it's necessary for this IO Pattern
// this callback can be invoked out-of-band directly from the IO Pattern class
lockedPattern->RegisterCallback(
[weakSocket](const ctsTask& task) noexcept {
// attempt to get a reference to the socket
const auto lambdaSharedSocket(weakSocket.lock());
if (!lambdaSharedSocket)
{
return;
}
// hold a reference on the socket
const auto lambdaLockedSocket = lambdaSharedSocket->AcquireSocketLock();
const auto lambdaLockedPattern = lambdaLockedSocket.GetPattern();
if (!lambdaLockedPattern || lambdaLockedSocket.GetSocket() == INVALID_SOCKET)
{
return;
}
//
// the below check with increment_io avoids a possible race-condition:
// - if increment_io() returns 1, it means our IO count in the main loop
// hit an io_count of 0 : which means that main thread will be completing this socket
// - if this OOB callback ever returns 1, we cannot use this socket, since this socket
// will either be completed soon, or will have already been completed
//
// this special scenario exists because the callback doesn't hold a ref-count
// - so this callback could be invoked after the mainline completed
// this is still 'safe' due to the above socket locks
//
// increment IO count while issuing this Impl so we hold a ref-count during this out of band callback
if (lambdaSharedSocket->IncrementIo() > 1)
{
// only running this one task in the OOB callback
// ReSharper disable once CppUseStructuredBinding
const IoImplStatus status = ctsMediaStreamClientIoImpl(lambdaSharedSocket, lambdaLockedSocket.GetSocket(), lambdaLockedPattern, task);
// decrement the IO count that we added before calling the Impl
// - complete_state if this happened to be the final IO refcount
if (lambdaSharedSocket->DecrementIo() == 0)
{
lambdaSharedSocket->CompleteState(status.m_errorCode);
}
}
else
{
// in this case, the io_count in the ctsSocket was zero, so no IO was in flight to interrupt
// just decrement the IO count that we added before calling the Impl (no IO attempted)
lambdaSharedSocket->DecrementIo();
}
});
// increment IO count while issuing this Impl so we hold a ref-count during this out of band callback
sharedSocket->IncrementIo();
IoImplStatus status = ctsMediaStreamClientIoImpl(sharedSocket, lockedSocket.GetSocket(), lockedPattern, lockedPattern->InitiateIo());
while (status.m_continueIo)
{
// invoke the new IO call while holding a refcount to the prior IO in a tight loop
status = ctsMediaStreamClientIoImpl(sharedSocket, lockedSocket.GetSocket(), lockedPattern, lockedPattern->InitiateIo());
}
if (0 == sharedSocket->DecrementIo())
{
sharedSocket->CompleteState(status.m_errorCode);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// The function that is registered with ctsTraffic to 'connect' to the target server by sending a START command
/// using IO Completion Ports
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientConnect(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
{
// attempt to get a reference to the socket
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
return;
}
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
if (lockedSocket.GetSocket() == INVALID_SOCKET)
{
sharedSocket->CompleteState(WSAECONNABORTED);
return;
}
const auto socket = lockedSocket.GetSocket();
const auto error = ctsConfig::SetPreConnectOptions(socket);
ctsConfig::PrintErrorIfFailed("SetPreConnectOptions", error);
if (error != NO_ERROR)
{
sharedSocket->CompleteState(error);
return;
}
const ctl::ctSockaddr targetAddress(sharedSocket->GetRemoteSockaddr());
const ctsTask startTask = ctsMediaStreamMessage::Construct(MediaStreamAction::START);
// Not add-ref'ing the IO on the socket since this is a single send() simulating connect()
const auto response = ctsWSASendTo(
sharedSocket,
lockedSocket.GetSocket(),
startTask,
[weakSocket, targetAddress](OVERLAPPED* ov) noexcept {
ctsMediaStreamClientConnectionCompletionCallback(ov, weakSocket, targetAddress);
});
if (NO_ERROR == response.m_errorCode)
{
// set the local and remote addresses on the socket object
ctl::ctSockaddr localAddr;
auto localAddrLen = localAddr.length();
if (0 == getsockname(socket, localAddr.sockaddr(), &localAddrLen))
// attempt to get a reference to the socket
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
sharedSocket->SetLocalSockaddr(localAddr);
return;
}
sharedSocket->SetRemoteSockaddr(targetAddress);
ctsConfig::PrintNewConnection(localAddr, targetAddress);
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto lockedPattern = lockedSocket.GetPattern();
if (!lockedPattern || lockedSocket.GetSocket() == INVALID_SOCKET)
{
return;
}
PRINT_DEBUG_INFO(
L"\t\tctsMediaStreamClient sent its START message to %ws\n",
targetAddress.writeCompleteAddress().c_str());
// always register our ctsIOPattern callback since it's necessary for this IO Pattern
// this callback can be invoked out-of-band directly from the IO Pattern class
lockedPattern->RegisterCallback(
[weakSocket](const ctsTask& task) noexcept
{
// attempt to get a reference to the socket
const auto lambdaSharedSocket(weakSocket.lock());
if (!lambdaSharedSocket)
{
return;
}
// hold a reference on the socket
const auto lambdaLockedSocket = lambdaSharedSocket->AcquireSocketLock();
const auto lambdaLockedPattern = lambdaLockedSocket.GetPattern();
if (!lambdaLockedPattern || lambdaLockedSocket.GetSocket() == INVALID_SOCKET)
{
return;
}
//
// the below check with increment_io avoids a possible race-condition:
// - if increment_io() returns 1, it means our IO count in the main loop
// hit an io_count of 0 : which means that main thread will be completing this socket
// - if this OOB callback ever returns 1, we cannot use this socket, since this socket
// will either be completed soon, or will have already been completed
//
// this special scenario exists because the callback doesn't hold a ref-count
// - so this callback could be invoked after the mainline completed
// this is still 'safe' due to the above socket locks
//
// increment IO count while issuing this Impl, so we hold a ref-count during this out of band callback
if (lambdaSharedSocket->IncrementIo() > 1)
{
// only running this one task in the OOB callback
// ReSharper disable once CppUseStructuredBinding
const IoImplStatus status = ctsMediaStreamClientIoImpl(
lambdaSharedSocket, lambdaLockedSocket.GetSocket(), lambdaLockedPattern, task);
// decrement the IO count that we added before calling the Impl
// - complete_state if this happened to be the final IO ref-count
if (lambdaSharedSocket->DecrementIo() == 0)
{
lambdaSharedSocket->CompleteState(status.m_errorCode);
}
}
else
{
// in this case, the io_count in the ctsSocket was zero, so no IO was in flight to interrupt
// just decrement the IO count that we added before calling the Impl (no IO attempted)
lambdaSharedSocket->DecrementIo();
}
});
// increment IO count while issuing this Impl, so we hold a ref-count during this out of band callback
sharedSocket->IncrementIo();
IoImplStatus status = ctsMediaStreamClientIoImpl(
sharedSocket,
lockedSocket.GetSocket(),
lockedPattern,
lockedPattern->InitiateIo());
while (status.m_continueIo)
{
// invoke the new IO call while holding a ref-count to the prior IO in a tight loop
status = ctsMediaStreamClientIoImpl(
sharedSocket,
lockedSocket.GetSocket(),
lockedPattern,
lockedPattern->InitiateIo());
}
if (0 == sharedSocket->DecrementIo())
{
sharedSocket->CompleteState(status.m_errorCode);
}
}
// complete only on failure or successfully completed inline (otherwise will complete in the IOCP callback)
if (response.m_errorCode != WSA_IO_PENDING)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// The function that is registered with ctsTraffic to 'connect' to the target server by sending a START command
/// using IO Completion Ports
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientConnect(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
{
sharedSocket->CompleteState(response.m_errorCode);
// attempt to get a reference to the socket
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
return;
}
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
if (lockedSocket.GetSocket() == INVALID_SOCKET)
{
sharedSocket->CompleteState(WSAECONNABORTED);
return;
}
const auto socket = lockedSocket.GetSocket();
const auto error = ctsConfig::SetPreConnectOptions(socket);
ctsConfig::PrintErrorIfFailed("SetPreConnectOptions", error);
if (error != NO_ERROR)
{
sharedSocket->CompleteState(error);
return;
}
const ctl::ctSockaddr targetAddress(sharedSocket->GetRemoteSockaddr());
const ctsTask startTask = ctsMediaStreamMessage::Construct(MediaStreamAction::START);
// Not add-ref'ing the IO on the socket since this is a single send() simulating connect()
const auto response = ctsWSASendTo(
sharedSocket,
lockedSocket.GetSocket(),
startTask,
[weakSocket, targetAddress](OVERLAPPED* ov) noexcept
{
ctsMediaStreamClientConnectionCompletionCallback(ov, weakSocket, targetAddress);
});
if (NO_ERROR == response.m_errorCode)
{
// set the local and remote addresses on the socket object
ctl::ctSockaddr localAddr;
auto localAddrLen = localAddr.length();
if (0 == getsockname(socket, localAddr.sockaddr(), &localAddrLen))
{
sharedSocket->SetLocalSockaddr(localAddr);
}
sharedSocket->SetRemoteSockaddr(targetAddress);
ctsConfig::PrintNewConnection(localAddr, targetAddress);
PRINT_DEBUG_INFO(
L"\t\tctsMediaStreamClient sent its START message to %ws\n",
targetAddress.writeCompleteAddress().c_str());
}
// complete only on failure or successfully completed inline (otherwise will complete in the IOCP callback)
if (response.m_errorCode != WSA_IO_PENDING)
{
sharedSocket->CompleteState(response.m_errorCode);
}
}
}
IoImplStatus ctsMediaStreamClientIoImpl(const std::shared_ptr<ctsSocket>& sharedSocket, SOCKET socket, const std::shared_ptr<ctsIoPattern>& lockedPattern, const ctsTask& task) noexcept
{
IoImplStatus returnStatus;
switch (task.m_ioAction)
IoImplStatus ctsMediaStreamClientIoImpl(
const std::shared_ptr<ctsSocket>& sharedSocket,
SOCKET socket,
const std::shared_ptr<ctsIoPattern>& lockedPattern,
const ctsTask& task) noexcept
{
IoImplStatus returnStatus;
switch (task.m_ioAction)
{
case ctsTaskAction::Send:
[[fallthrough]];
case ctsTaskAction::Recv:
{
// add-ref the IO about to start
sharedSocket->IncrementIo();
auto callback = [weak_reference = std::weak_ptr(sharedSocket), task](OVERLAPPED* ov) noexcept {
ctsMediaStreamClientIoCompletionCallback(ov, weak_reference, task);
};
PCSTR functionName{};
wsIOResult result;
if (ctsTaskAction::Send == task.m_ioAction)
{
functionName = "WSASendTo";
result = ctsWSASendTo(sharedSocket, socket, task, std::move(callback));
}
else if (ctsTaskAction::Recv == task.m_ioAction)
{
functionName = "WSARecvFrom";
result = ctsWSARecvFrom(sharedSocket, socket, task, std::move(callback));
}
else
{
FAIL_FAST_MSG(
"ctsMediaStreamClientIoImpl: received an unexpected IOStatus in the ctsIOTask (%p)", &task);
}
if (WSA_IO_PENDING == result.m_errorCode)
{
// if successful but did not complete inline
returnStatus.m_errorCode = static_cast<int>(result.m_errorCode);
returnStatus.m_continueIo = true;
}
else
{
// IO successfully completed inline and the async completion won't be invoke
// - or the IO failed
if (result.m_errorCode != 0)
// add-ref the IO about to start
sharedSocket->IncrementIo();
auto callback = [weak_reference = std::weak_ptr(sharedSocket), task](OVERLAPPED* ov) noexcept
{
PRINT_DEBUG_INFO(L"\t\tIO Failed: %hs (%u) [ctsMediaStreamClient]\n", functionName, result.m_errorCode);
ctsMediaStreamClientIoCompletionCallback(ov, weak_reference, task);
};
PCSTR functionName{};
wsIOResult result;
if (ctsTaskAction::Send == task.m_ioAction)
{
functionName = "WSASendTo";
result = ctsWSASendTo(sharedSocket, socket, task, std::move(callback));
}
else if (ctsTaskAction::Recv == task.m_ioAction)
{
functionName = "WSARecvFrom";
result = ctsWSARecvFrom(sharedSocket, socket, task, std::move(callback));
}
else
{
FAIL_FAST_MSG(
"ctsMediaStreamClientIoImpl: received an unexpected IOStatus in the ctsIOTask (%p)", &task);
}
switch (const auto protocolStatus = lockedPattern->CompleteIo(task, result.m_bytesTransferred, result.m_errorCode))
if (WSA_IO_PENDING == result.m_errorCode)
{
// if successful but did not complete inline
returnStatus.m_errorCode = static_cast<int>(result.m_errorCode);
returnStatus.m_continueIo = true;
}
else
{
// IO successfully completed inline and the async completion won't be invoked
// - or the IO failed
if (result.m_errorCode != 0)
{
PRINT_DEBUG_INFO(L"\t\tIO Failed: %hs (%u) [ctsMediaStreamClient]\n",
functionName,
result.m_errorCode);
}
switch (const auto protocolStatus = lockedPattern->CompleteIo(
task, result.m_bytesTransferred, result.m_errorCode))
{
case ctsIoStatus::ContinueIo:
// the protocol wants to ignore the error and send more data
returnStatus.m_errorCode = NO_ERROR;
@ -284,9 +303,9 @@ IoImplStatus ctsMediaStreamClientIoImpl(const std::shared_ptr<ctsSocket>& shared
break;
case ctsIoStatus::FailedIo:
// the protocol acknowledged the failure - socket is done with IO
// write out the error
ctsConfig::PrintErrorIfFailed(functionName, result.m_errorCode);
// the protocol acknoledged the failure - socket is done with IO
sharedSocket->CloseSocket();
returnStatus.m_errorCode = static_cast<int>(lockedPattern->GetLastPatternError());
returnStatus.m_continueIo = false;
@ -294,134 +313,140 @@ IoImplStatus ctsMediaStreamClientIoImpl(const std::shared_ptr<ctsSocket>& shared
default:
FAIL_FAST_MSG("ctsMediaStreamClientIoImpl: unknown ctsSocket::IOStatus - %d\n", protocolStatus);
}
// decrement the IO count if failed and/or inlined-completed
const auto ioCount = sharedSocket->DecrementIo();
// IO count should never be zero: callers should be guaranteeing a ref-count before calling Impl
FAIL_FAST_IF_MSG(
0 == ioCount,
"ctsMediaStreamClient : ctsSocket::io_count fell to zero while the Impl function was called (dt %p ctsTraffic::ctsSocket)",
sharedSocket.get());
}
// decrement the IO count if failed and/or inlined-completed
const auto ioCount = sharedSocket->DecrementIo();
// IO count should never be zero: callers should be guaranteeing a refcount before calling Impl
FAIL_FAST_IF_MSG(
0 == ioCount,
"ctsMediaStreamClient : ctsSocket::io_count fell to zero while the Impl function was called (dt %p ctsTraffic::ctsSocket)",
sharedSocket.get());
break;
}
break;
}
case ctsTaskAction::None:
{
// nothing failed, just no more IO right now
returnStatus.m_errorCode = NO_ERROR;
returnStatus.m_continueIo = false;
break;
}
{
// nothing failed, just no more IO right now
returnStatus.m_errorCode = NO_ERROR;
returnStatus.m_continueIo = false;
break;
}
case ctsTaskAction::Abort:
{
// the protocol signaled to immediately stop the stream
lockedPattern->CompleteIo(task, 0, 0);
sharedSocket->CloseSocket();
{
// the protocol signaled to immediately stop the stream
lockedPattern->CompleteIo(task, 0, 0);
sharedSocket->CloseSocket();
returnStatus.m_errorCode = NO_ERROR;
returnStatus.m_continueIo = false;
break;
}
returnStatus.m_errorCode = NO_ERROR;
returnStatus.m_continueIo = false;
break;
}
case ctsTaskAction::FatalAbort:
{
// the protocol indicated to rudely abort the connection
lockedPattern->CompleteIo(task, 0, 0);
sharedSocket->CloseSocket();
{
// the protocol indicated to rudely abort the connection
lockedPattern->CompleteIo(task, 0, 0);
sharedSocket->CloseSocket();
returnStatus.m_errorCode = static_cast<int>(lockedPattern->GetLastPatternError());
returnStatus.m_continueIo = false;
break;
}
returnStatus.m_errorCode = static_cast<int>(lockedPattern->GetLastPatternError());
returnStatus.m_continueIo = false;
break;
}
case ctsTaskAction::GracefulShutdown:
case ctsTaskAction::HardShutdown:
default:
break;
}
return returnStatus;
}
return returnStatus;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// IO Threadpool completion callback
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientIoCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctsTask& task) noexcept
{
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// IO Threadpool completion callback
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientIoCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctsTask& task) noexcept
{
return;
}
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto lockedPattern = lockedSocket.GetPattern();
if (!lockedPattern)
{
sharedSocket->DecrementIo();
sharedSocket->CompleteState(WSAECONNABORTED);
return;
}
const auto socket = lockedSocket.GetSocket();
int gle = NO_ERROR;
DWORD transferred = 0;
// scope to the socket lock
{
if (socket != INVALID_SOCKET)
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
DWORD flags;
if (!WSAGetOverlappedResult(socket, pOverlapped, &transferred, FALSE, &flags))
return;
}
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto lockedPattern = lockedSocket.GetPattern();
if (!lockedPattern)
{
sharedSocket->DecrementIo();
sharedSocket->CompleteState(WSAECONNABORTED);
return;
}
const auto socket = lockedSocket.GetSocket();
int gle = NO_ERROR;
DWORD transferred = 0;
// scope to the socket lock
{
if (socket != INVALID_SOCKET)
{
gle = WSAGetLastError();
DWORD flags;
if (!WSAGetOverlappedResult(socket, pOverlapped, &transferred, FALSE, &flags))
{
gle = WSAGetLastError();
}
}
else
{
// we're intentionally ignoring the error when we have closed it early
// - doing this because that's how we shut down the client after processing all frames
gle = NO_ERROR;
}
}
else
if (gle == WSAEMSGSIZE)
{
// we're intentionally ignoring the error when we have closed it early
// - doing this because that's how we shutdown the client after processing all frames
// something truncated the datagram - don't treat it as a hard-error
// pass the count to the protocol to track it at their layer
ctsConfig::PrintErrorInfo(
L"MediaStream Client: %ws failed with WSAEMSGSIZE: received [%u bytes] - expected [%u bytes]",
task.m_ioAction == ctsTaskAction::Recv ? L"WSARecvFrom" : L"WSASendTo", transferred,
task.m_bufferLength);
gle = NO_ERROR;
}
}
if (gle == WSAEMSGSIZE)
{
// something truncated the datagram - don't treat it as a hard-error
// pass the count to the protocol to track it at their layer
ctsConfig::PrintErrorInfo(L"MediaStream Client: %ws failed with WSAEMSGSIZE: received [%u bytes] - expected [%u bytes]",
task.m_ioAction == ctsTaskAction::Recv ? L"WSARecvFrom" : L"WSASendTo", transferred, task.m_bufferLength);
gle = NO_ERROR;
}
// see if complete_io requests more IO
switch (const ctsIoStatus protocolStatus = lockedPattern->CompleteIo(task, transferred, gle))
{
case ctsIoStatus::ContinueIo:
// see if complete_io requests more IO
switch (const ctsIoStatus protocolStatus = lockedPattern->CompleteIo(task, transferred, gle))
{
// more IO is requested from the protocol
IoImplStatus status;
do
case ctsIoStatus::ContinueIo:
{
// invoke the new IO call while holding a refcount to the prior IO in a tight loop
status = ctsMediaStreamClientIoImpl(sharedSocket, lockedSocket.GetSocket(), lockedPattern, lockedPattern->InitiateIo());
}
while (status.m_continueIo);
// more IO is requested from the protocol
IoImplStatus status;
do
{
// invoke the new IO call while holding a ref-count to the prior IO in a tight loop
status = ctsMediaStreamClientIoImpl(
sharedSocket,
lockedSocket.GetSocket(),
lockedPattern,
lockedPattern->InitiateIo());
}
while (status.m_continueIo);
gle = status.m_errorCode;
break;
}
gle = status.m_errorCode;
break;
}
case ctsIoStatus::CompletedIo:
sharedSocket->CloseSocket();
@ -452,66 +477,66 @@ void ctsMediaStreamClientIoCompletionCallback(
FAIL_FAST_MSG(
"ctsMediaStreamClientIoCompletionCallback: unknown ctsSocket::IOStatus - %d\n",
protocolStatus);
}
// always decrement *after* attempting new IO - the prior IO is now formally "done"
if (sharedSocket->DecrementIo() == 0)
{
// if we have no more IO pended, complete the state
sharedSocket->CompleteState(gle);
}
}
// always decrement *after* attempting new IO - the prior IO is now formally "done"
if (sharedSocket->DecrementIo() == 0)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// IO Threadpool completion callback for the 'connect' request
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientConnectionCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctl::ctSockaddr& targetAddress) noexcept
{
// if we have no more IO pended, complete the state
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
return;
}
int gle = NO_ERROR;
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto socket = lockedSocket.GetSocket();
if (socket == INVALID_SOCKET)
{
gle = WSAECONNABORTED;
}
else
{
// unused
DWORD transferred;
DWORD flags;
if (!WSAGetOverlappedResult(socket, pOverlapped, &transferred, FALSE, &flags))
{
gle = WSAGetLastError();
}
}
ctsConfig::PrintErrorIfFailed("\tWSASendTo (START request)", gle);
if (NO_ERROR == gle)
{
// set the local and remote addresses
ctl::ctSockaddr localAddr;
int localAddrLen = localAddr.length();
if (0 == getsockname(socket, localAddr.sockaddr(), &localAddrLen))
{
sharedSocket->SetLocalSockaddr(localAddr);
}
sharedSocket->SetRemoteSockaddr(targetAddress);
ctsConfig::PrintNewConnection(localAddr, targetAddress);
}
sharedSocket->CompleteState(gle);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// IO Threadpool completion callback for the 'connect' request
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ctsMediaStreamClientConnectionCompletionCallback(
_In_ OVERLAPPED* pOverlapped,
const std::weak_ptr<ctsSocket>& weakSocket,
const ctl::ctSockaddr& targetAddress) noexcept
{
const auto sharedSocket(weakSocket.lock());
if (!sharedSocket)
{
return;
}
int gle = NO_ERROR;
// hold a reference on the socket
const auto lockedSocket = sharedSocket->AcquireSocketLock();
const auto socket = lockedSocket.GetSocket();
if (socket == INVALID_SOCKET)
{
gle = WSAECONNABORTED;
}
else
{
// unused
DWORD transferred;
DWORD flags;
if (!WSAGetOverlappedResult(socket, pOverlapped, &transferred, FALSE, &flags))
{
gle = WSAGetLastError();
}
}
ctsConfig::PrintErrorIfFailed("\tWSASendTo (START request)", gle);
if (NO_ERROR == gle)
{
// set the local and remote addr's
ctl::ctSockaddr localAddr;
int localAddrLen = localAddr.length();
if (0 == getsockname(socket, localAddr.sockaddr(), &localAddrLen))
{
sharedSocket->SetLocalSockaddr(localAddr);
}
sharedSocket->SetRemoteSockaddr(targetAddress);
ctsConfig::PrintNewConnection(localAddr, targetAddress);
}
sharedSocket->CompleteState(gle);
}
} // namespace

Просмотреть файл

@ -249,7 +249,7 @@ public:
m_wsabuffer[3].len = c_udpDatagramQpfLength;
m_wsabuffer[4].buf = const_cast<char*>(sendBuffer);
// the this->wsabuf[4].len field is dependent on bytes_to_send and can change by iterator()
// the "this->wsabuf[4].len" field is dependent on bytes_to_send and can change by iterator()
}
[[nodiscard]] iterator begin() noexcept
@ -402,7 +402,7 @@ struct ctsMediaStreamMessage
rawTask.m_bufferLength, ctsStatistics::ConnectionIdLength + c_udpDatagramProtocolHeaderFlagLength);
ctsTask returnTask{rawTask};
// populate the buffer with the connection Id and protocol field
// populate the buffer with the ConnectionId and protocol field
memcpy_s(returnTask.m_buffer, c_udpDatagramProtocolHeaderFlagLength, &c_udpDatagramProtocolHeaderFlagId, c_udpDatagramProtocolHeaderFlagLength);
memcpy_s(returnTask.m_buffer + c_udpDatagramProtocolHeaderFlagLength, ctsStatistics::ConnectionIdLength, connectionId, ctsStatistics::ConnectionIdLength);

Просмотреть файл

@ -35,7 +35,7 @@ using ctsMediaStreamConnectedSocketIoFunctor = std::function<wsIOResult (ctsMedi
class ctsMediaStreamServerConnectedSocket
{
private:
// the CS is mutable so we can take a lock / release a lock in const methods
// the CS is mutable, so we can take a lock / release a lock in const methods
mutable wil::critical_section m_objectGuard{ctsConfig::ctsConfigSettings::c_CriticalSectionSpinlock};
_Guarded_by_(m_objectGuard) ctsTask m_nextTask;

Просмотреть файл

@ -194,7 +194,7 @@ void ctsMediaStreamServerListeningSocket::RecvCompletion(OVERLAPPED* pOverlapped
ctsConfig::g_configSettings->UdpStatusDetails.m_errorFrames.Increment();
m_priorFailureWasConectionReset = false;
}
// this receive failed - do nothing immediately in response
// this receive-call failed - do nothing immediately in response
// - just attempt to post another recv at the end of this function
}
else

Просмотреть файл

@ -79,7 +79,7 @@ static void ctsReadWriteIocpIoCompletionCallback(
{
case ctsIoStatus::ContinueIo:
// more IO is requested from the protocol
// - invoke the new IO call while holding a refcount to the prior IO
// - invoke the new IO call while holding a ref-count to the prior IO
ctsReadWriteIocp(weakSocket);
break;
@ -233,7 +233,7 @@ void ctsReadWriteIocp(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
const char* functionName = ctsTaskAction::Send == nextIo.m_ioAction ? "WriteFile" : "ReadFile";
PRINT_DEBUG_INFO(L"\t\tIO Failed: %hs (%u) [ctsReadWriteIocp]\n", functionName, ioError);
// call back to the socket that it failed to see if wants more IO
// call back to the socket to inform it that the call failed to see if it wants to request more IO
switch (const ctsIoStatus protocolStatus = lockedPattern->CompleteIo(nextIo, 0, ioError))
{
case ctsIoStatus::ContinueIo:
@ -251,7 +251,7 @@ void ctsReadWriteIocp(const std::weak_ptr<ctsSocket>& weakSocket) noexcept
case ctsIoStatus::FailedIo:
// print the error on failure
ctsConfig::PrintErrorIfFailed(functionName, ioError);
// the protocol acknoledged the failure - socket is done with IO
// the protocol acknowledged the failure - socket is done with IO
ioError = static_cast<int>(lockedPattern->GetLastPatternError());
ioDone = true;
break;

Просмотреть файл

@ -186,7 +186,7 @@ namespace ctsTraffic { namespace Rioiocp
c_exitCompletionKey,
static_cast<OVERLAPPED*>(g_rioNotifySettings.Iocp.Overlapped)))
{
// if can't indicate to exit, kill the process to see why
// if we can't indicate to exit, kill the process to see why
FAIL_FAST_MSG(
"PostQueuedCompletionStatus(%p) failed [%u] to tear down the threadpool",
g_rioNotifySettings.Iocp.IocpHandle, GetLastError());
@ -203,7 +203,7 @@ namespace ctsTraffic { namespace Rioiocp
TRUE,
INFINITE) != WAIT_OBJECT_0)
{
// if can't wait for the worker threads, kill the process to see why
// if we can't wait for the worker threads, kill the process to see why
FAIL_FAST_MSG(
"WaitForMultipleObjects(%p) failed [%u] to wait on the threadpool",
&g_pRioWorkerThreads[0], GetLastError());
@ -381,7 +381,7 @@ namespace ctsTraffic { namespace Rioiocp
uint32_t m_requestQueueRecvSize = m_rioRqGrowthFactor / 2;
uint32_t m_outstandingSends = 0;
uint32_t m_outstandingRecvs = 0;
// pre-allocate all ctsTasks needed so we don't alloc/free with each IO request
// pre-allocate all ctsTasks needed, so we don't alloc/free with each IO request
std::vector<ctsTask> m_tasks;
// Guarantees that there is roon in the RQ for the next IO request
@ -488,7 +488,7 @@ namespace ctsTraffic { namespace Rioiocp
}
// pCompletedTask is pointing to a ctsTask in m_tasks
// update the task so it's now available to be used for future IO
// update the task, so it's now available to be used for future IO
pCompletedTask->m_rioBufferid = RIO_INVALID_BUFFERID;
}

Просмотреть файл

@ -94,7 +94,7 @@ namespace ctsTraffic
switch (const ctsIoStatus protocolStatus = lockedPattern->CompleteIo(task, transferred, gle))
{
case ctsIoStatus::ContinueIo:
// more IO is requested from the protocol : invoke the new IO call while holding a refcount to the prior IO
// more IO is requested from the protocol : invoke the new IO call while holding a ref-count to the prior IO
ctsSendRecvIocp(weakSocket);
break;
@ -218,7 +218,7 @@ namespace ctsTraffic
}
else
{
// process the completion if the API call failed, or if it succeeded and we're handling the completion inline,
// process the completion if the API call failed, or if it succeeded, and we're handling the completion inline,
returnStatus.m_ioStarted = false;
// determine # of bytes transferred, if any
DWORD bytesTransferred = 0;
@ -238,19 +238,19 @@ namespace ctsTraffic
// must cancel the IOCP TP since IO is not pended
ioThreadPool->cancel_request(pOverlapped);
// call back to the socket to see if wants more IO
// call back to the socket to see if it wants more IO
switch (const ctsIoStatus protocolStatus = sharedPattern->CompleteIo(nextIo, bytesTransferred, returnStatus.m_ioErrorcode))
{
case ctsIoStatus::ContinueIo:
// The protocol layer wants to transfer more data
// if prior IO failed, the protocol wants to ignore the error
// if the prior IO request failed, the protocol wants to ignore the error
returnStatus.m_ioErrorcode = NO_ERROR;
returnStatus.m_ioDone = false;
break;
case ctsIoStatus::CompletedIo:
// The protocol layer has successfully complete all IO on this connection
// if prior IO failed, the protocol wants to ignore the error
// if the prior IO request failed, the protocol wants to ignore the error
returnStatus.m_ioErrorcode = NO_ERROR;
returnStatus.m_ioDone = true;
break;
@ -258,7 +258,7 @@ namespace ctsTraffic
case ctsIoStatus::FailedIo:
// write out the error
ctsConfig::PrintErrorIfFailed(functionName, sharedPattern->GetLastPatternError());
// the protocol acknoledged the failure - socket is done with IO
// the protocol acknowledged the failure - socket is done with IO
returnStatus.m_ioErrorcode = sharedPattern->GetLastPatternError();
returnStatus.m_ioDone = true;
break;
@ -315,7 +315,7 @@ namespace ctsTraffic
{
if (0 == sharedSocket->DecrementIo())
{
// this should never be zero since we should be holding a refcount for this callback
// this should never be zero since we should be holding a ref-count for this callback
FAIL_FAST_MSG(
"The refcount of the ctsSocket object (%p) fell to zero during a scheduled callback", sharedSocket.get());
}
@ -359,7 +359,7 @@ namespace ctsTraffic
// IO is always done in the ctsProcessIOTask function,
// - either synchronously or scheduled through a timer object
//
// The IO refcount must be incremented here to hold an IO count on the socket
// The IO ref-count must be incremented here to hold an IO count on the socket
// - so that we won't inadvertently call complete_state() while IO is still being scheduled
//
sharedSocket->IncrementIo();
@ -400,7 +400,7 @@ namespace ctsTraffic
// if no IO was started, decrement the IO counter
if (!status.m_ioStarted)
{
// since IO is not pended, remove the refcount
// since IO is not pended, remove the ref-count
if (0 == sharedSocket->DecrementIo())
{
// this should never be zero as we are holding a reference outside the loop
@ -409,7 +409,7 @@ namespace ctsTraffic
}
}
}
// decrement IO at the end to release the refcount held before the loop
// decrement IO at the end to release the ref-count held before the loop
if (0 == sharedSocket->DecrementIo())
{
sharedSocket->CompleteState(status.m_ioErrorcode);

Просмотреть файл

@ -39,7 +39,7 @@ namespace ctsTraffic
// - so need to ensure that all members are easily copied
// - also means the counter will need to be a ptr
//
// The refcount_sockets vector will optimize in balancing accept calls
// The ref-count_sockets vector will optimize in balancing accept calls
// - across all listeners
//
namespace details
@ -52,7 +52,7 @@ namespace details
// CS guards access to the accepting_sockets vector
wil::critical_section m_acceptingCs{ctsConfig::ctsConfigSettings::c_CriticalSectionSpinlock};
std::vector<LONG> m_listeningSocketsRefcount{};
std::vector<LONG> m_listeningSocketsRefCount{};
_Guarded_by_(m_acceptingCs) std::vector<SOCKET> m_listeningSockets{};
_Guarded_by_(m_acceptingCs) std::vector<std::weak_ptr<ctsSocket>> m_acceptingSockets{};
@ -65,7 +65,7 @@ namespace details
InitializeThreadpoolEnvironment(&m_threadPoolEnvironment);
SetThreadpoolCallbackRunsLong(&m_threadPoolEnvironment);
// can *not* pass the this ptr to the threadpool, since this object can be copied
// can *not* pass the 'this' ptr to the threadpool, since this object can be copied
m_threadPoolWorker = CreateThreadpoolWork(ThreadPoolWorker, this, &m_threadPoolEnvironment);
if (nullptr == m_threadPoolWorker)
{
@ -110,7 +110,7 @@ namespace details
{
throw std::exception("ctsSimpleAccept invoked with no listening addresses specified");
}
m_listeningSocketsRefcount.resize(m_listeningSockets.size(), 0L);
m_listeningSocketsRefCount.resize(m_listeningSockets.size(), 0L);
}
~ctsSimpleAcceptImpl()
@ -168,16 +168,16 @@ namespace details
return;
}
// based off of the refcount, choose a socket that's least used
// based off of the ref-count, choose a socket that's least used
// - not taking a lock: it doesn't have to be that precise
auto lowestRefcount = pimpl->m_listeningSocketsRefcount[0];
auto lowestRefCount = pimpl->m_listeningSocketsRefCount[0];
uint32_t listenerCounter = 0;
uint32_t listenerPosition = 0;
for (const auto& refcount : pimpl->m_listeningSocketsRefcount)
for (const auto& refCount : pimpl->m_listeningSocketsRefCount)
{
if (refcount < lowestRefcount)
if (refCount < lowestRefCount)
{
lowestRefcount = refcount;
lowestRefCount = refCount;
listenerPosition = listenerCounter;
}
++listenerCounter;
@ -193,12 +193,12 @@ namespace details
lock.reset();
// increment the listening socket before calling accept on the blocking socket
::InterlockedIncrement(&pimpl->m_listeningSocketsRefcount[listenerPosition]);
::InterlockedIncrement(&pimpl->m_listeningSocketsRefCount[listenerPosition]);
ctl::ctSockaddr remoteAddr;
auto remoteAddrLen = remoteAddr.length();
const SOCKET newSocket = accept(listener, remoteAddr.sockaddr(), &remoteAddrLen);
auto gle = WSAGetLastError();
::InterlockedDecrement(&pimpl->m_listeningSocketsRefcount[listenerPosition]);
::InterlockedDecrement(&pimpl->m_listeningSocketsRefCount[listenerPosition]);
// if failed complete the ctsSocket and return
if (newSocket == INVALID_SOCKET)
@ -248,14 +248,14 @@ namespace details
// ReSharper disable once CppZeroConstantCanBeReplacedWithNullptr
static INIT_ONCE g_ctsSimpleAcceptImplInitOnce = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK ctsSimpleAcceptImplInitFn(PINIT_ONCE, PVOID perror, PVOID*) noexcept try
static BOOL CALLBACK ctsSimpleAcceptImplInitFn(PINIT_ONCE, PVOID pError, PVOID*) noexcept try
{
g_pimpl = std::make_shared<ctsSimpleAcceptImpl>();
return TRUE;
}
catch (...)
{
*static_cast<DWORD*>(perror) = ctsConfig::PrintThrownException();
*static_cast<DWORD*>(pError) = ctsConfig::PrintThrownException();
return FALSE;
}
}

Просмотреть файл

@ -31,7 +31,7 @@ using namespace std;
// default values are assigned in the class declaration
ctsSocket::ctsSocket(weak_ptr<ctsSocketState> parent) noexcept :
m_parent(move(parent))
m_parent(std::move(parent))
{
}
@ -52,7 +52,7 @@ _No_competing_thread_ ctsSocket::~ctsSocket() noexcept
}
*/
// if the IO pattern is still alive, must delete it once in the d'tor before this object goes away
// if the IO pattern is still alive, must delete it once in the destructor before this object goes away
// - can't reset this in ctsSocket::shutdown since ctsSocket::shutdown can be called from the parent ctsSocketState
// and there may be callbacks still running holding onto a reference to this ctsSocket object
// which causes the potential to AV in the io_pattern
@ -90,7 +90,7 @@ int ctsSocket::CloseSocket(uint32_t errorCode) noexcept
{
// always try to RST if we are closing due to an error
// to best-effort notify the opposite endpoint
const wsIOResult result = ctsSetLingertoResetSocket(m_socket.get());
const wsIOResult result = ctsSetLingerToResetSocket(m_socket.get());
error = static_cast<int>(result.m_errorCode);
}
@ -109,7 +109,7 @@ const shared_ptr<ctThreadIocp>& ctsSocket::GetIocpThreadpool()
{
// use the SOCKET cs to also guard creation of this TP object
const auto lock = m_lock.lock();
// must verify a valid socket first to avoid racing destrying the iocp shared_ptr as we try to create it here
// must verify a valid socket first to avoid racing destroying the iocp shared_ptr as we try to create it here
if (m_socket && !m_tpIocp)
{
m_tpIocp = make_shared<ctThreadIocp>(m_socket.get(), ctsConfig::g_configSettings->pTpEnvironment); // can throw
@ -310,8 +310,8 @@ void ctsSocket::Shutdown() noexcept
// Must destroy these threadpool objects outside the CS to prevent a deadlock
// - from when worker threads attempt to callback this ctsSocket object when IO completes
// Must wait for the threadpool from this method when ctsSocketState calls ctsSocket::shutdown
// - instead of calling this from the d'tor of ctsSocket, as the final reference
// to this ctsSocket might be from a TP thread - in which case this d'tor will deadlock
// - instead of calling this from the destructor of ctsSocket, as the final reference
// to this ctsSocket might be from a TP thread - in which case this destructor will deadlock
// (it will wait for all TP threads to exit, but it is using/blocking on of those TP threads)
m_tpIocp.reset();
m_tpTimer.reset();

Просмотреть файл

@ -143,7 +143,7 @@ public:
void SetIoPattern();
//
// methods for functors to use for refcounting the # of IO they have issued on this socket
// methods for functors to use for ref-counting the # of IO they have issued on this socket
//
int32_t IncrementIo() noexcept;
int32_t DecrementIo() noexcept;
@ -186,7 +186,7 @@ private:
void InitiateIsbNotification() noexcept;
// private members for this socket instance
// mutable is requred to EnterCS/LeaveCS in const methods
// mutable is required to EnterCS/LeaveCS in const methods
mutable wil::critical_section m_lock{ctsConfig::ctsConfigSettings::c_CriticalSectionSpinlock};
_Guarded_by_(m_lock) wil::unique_socket m_socket;

Просмотреть файл

@ -160,7 +160,7 @@ bool ctsSocketBroker::Wait(DWORD milliseconds) const noexcept
auto fReturn = false;
switch (WaitForMultipleObjects(2, arWait, FALSE, milliseconds))
{
// we are done with our sockets, or user hit ctrl'c
// we are done with our sockets, or user hit ctrl-c
// - in either case we need to tell the caller to exit
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
@ -185,7 +185,7 @@ bool ctsSocketBroker::Wait(DWORD milliseconds) const noexcept
//
void ctsSocketBroker::RefreshSockets() noexcept try
{
// removedObjects will delete the closed objects outside of the broker lock
// removedObjects will delete the closed objects outside the broker lock
vector<shared_ptr<ctsSocketState>> removedObjects;
auto exiting = false;
@ -214,7 +214,7 @@ void ctsSocketBroker::RefreshSockets() noexcept try
if (!m_doneEvent.is_signaled())
{
// don't spin up more if the user asked to shutdown
// don't spin up more if the user asked to shut down
// catch up to the expected # of pended connections
while (m_pendingSockets < m_pendingLimit && m_totalConnectionsRemaining > 0)
{

Просмотреть файл

@ -67,7 +67,7 @@ private:
wil::unique_event_nothrow m_doneEvent;
// vector of currently active sockets
// must be shared_ptr since ctsSocketState derives from enable_shared_from_this
// - and thus there must be at least one refcount on that object to call shared_from_this()
// - and thus there must be at least one ref-count on that object to call shared_from_this()
std::vector<std::shared_ptr<ctsSocketState>> m_socketPool{};
// keep a burn-down count as connections are made to know when to be 'done'
ULONGLONG m_totalConnectionsRemaining = 0ULL;

Просмотреть файл

@ -27,7 +27,7 @@ See the Apache Version 2.0 License for specific language governing permissions a
namespace ctsTraffic
{
ctsSocketState::ctsSocketState(std::weak_ptr<ctsSocketBroker> pBroker) :
m_broker(move(pBroker))
m_broker(std::move(pBroker))
{
m_threadPoolWorker.reset(CreateThreadpoolWork(ThreadPoolWorker, this, ctsConfig::g_configSettings->pTpEnvironment));
THROW_LAST_ERROR_IF_NULL(m_threadPoolWorker.get());

Просмотреть файл

@ -36,8 +36,9 @@ ctsSocketBroker* g_socketBroker = nullptr;
BOOL WINAPI CtrlBreakHandlerRoutine(DWORD) noexcept
{
// handle all exit types - notify config that it's time to shutdown
ctsConfig::Shutdown();
// handle all exit types - notify config that it's time to shut down
ctsConfig::PrintSummary(L"\n **** ctrl-break hit -- shutting down ****\n");
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
return TRUE;
}
@ -55,20 +56,20 @@ int __cdecl wmain(int argc, _In_reads_z_(argc) const wchar_t** argv)
{
if (!ctsConfig::Startup(argc, argv))
{
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
err = ERROR_INVALID_DATA;
}
}
catch (const invalid_argument& e)
{
ctsConfig::PrintErrorInfoOverride(wil::str_printf<std::wstring>(L"Invalid argument specified: %hs", e.what()).c_str());
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
err = ERROR_INVALID_DATA;
}
catch (const exception& e)
{
ctsConfig::PrintExceptionOverride(e.what());
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
err = ERROR_INVALID_DATA;
}
@ -114,33 +115,33 @@ int __cdecl wmain(int argc, _In_reads_z_(argc) const wchar_t** argv)
if (!broker->Wait(ctsConfig::g_configSettings->TimeLimit > 0 ? ctsConfig::g_configSettings->TimeLimit : INFINITE))
{
ctsConfig::PrintSummary(L"\n Time-limit of %lu reached\n", ctsConfig::g_configSettings->TimeLimit);
ctsConfig::PrintSummary(L"\n **** Time-limit of %lu reached ****\n", ctsConfig::g_configSettings->TimeLimit);
}
if (ctsConfig::g_configSettings->PauseAtEnd > 0)
{
// stop all status updates being printed to the console and pause before destroying the broker object
statusTimer.reset();
ctsConfig::PrintSummary(L"\n Pausing-At-End for %lu milliseconds\n", ctsConfig::g_configSettings->PauseAtEnd);
ctsConfig::PrintSummary(L"\n **** Pausing-At-End for %lu milliseconds ****\n", ctsConfig::g_configSettings->PauseAtEnd);
Sleep(ctsConfig::g_configSettings->PauseAtEnd);
}
}
catch (const wil::ResultException& e)
{
ctsConfig::PrintExceptionOverride(e.what());
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
return e.GetErrorCode();
}
catch (const bad_alloc&)
{
ctsConfig::PrintErrorInfoOverride(L"ctsTraffic failed: Out of Memory");
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
return ERROR_OUTOFMEMORY;
}
catch (const exception& e)
{
ctsConfig::PrintErrorInfoOverride(wil::str_printf<std::wstring>(L"ctsTraffic failed: %hs", e.what()).c_str());
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Rude);
return ERROR_CANCELLED;
}
@ -149,7 +150,7 @@ int __cdecl wmain(int argc, _In_reads_z_(argc) const wchar_t** argv)
// write out the final status update
ctsConfig::PrintStatusUpdate();
ctsConfig::Shutdown();
ctsConfig::Shutdown(ctsConfig::ExitProcessType::Normal);
ctsConfig::PrintSummary(
L"\n\n"

Просмотреть файл

@ -482,12 +482,12 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231028.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240122.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -252,7 +252,4 @@
<Filter>Resource Files</Filter>
</Manifest>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
</Project>

Просмотреть файл

@ -128,7 +128,7 @@ namespace ctsTraffic
if (NO_ERROR == gle)
{
// setting the socket option to support dual-mode sockets must be done before calling bind
// must enable dual-mode sockets before calling WSAConnectByName so it can connect to either IPv4 or IPv6 addresses
// must enable dual-mode sockets before calling WSAConnectByName, so it can connect to either IPv4 or IPv6 addresses
if (ctsConfig::g_configSettings->ListenAddresses.empty() && !ctsConfig::g_configSettings->TargetAddressStrings.empty())
{
PRINT_DEBUG_INFO(L"\t\tEnabling Dual-mode sockets\n");
@ -154,7 +154,7 @@ namespace ctsTraffic
}
else
{
// sleep up to 5 seconds to allow TCP to cleanup its internal state
// sleep up to 5 seconds to allow TCP to clean up its internal state
constexpr auto bindRetryCount = 5;
for (auto bindRetry = 0; bindRetry < bindRetryCount; ++bindRetry)
{

Просмотреть файл

@ -157,7 +157,7 @@ wsIOResult ctsWSASendTo(
return returnResult;
}
wsIOResult ctsSetLingertoResetSocket(SOCKET socket) noexcept
wsIOResult ctsSetLingerToResetSocket(SOCKET socket) noexcept
{
wsIOResult returnResult{};
linger lingerOption{};

Просмотреть файл

@ -153,6 +153,6 @@ wsIOResult ctsWSASendTo(
const ctsTask& task,
std::function<void(OVERLAPPED*)>&& callback) noexcept;
// Set LINGER options to force a RST when the socket is closed
wsIOResult ctsSetLingertoResetSocket(SOCKET socket) noexcept;
// Set LINGER options to force an RST when the socket is closed
wsIOResult ctsSetLingerToResetSocket(SOCKET socket) noexcept;
}

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231028.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" />
</packages>