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:
Родитель
88a4151979
Коммит
27d9239167
|
@ -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>
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -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.aps
Двоичный файл не отображается.
Двоичные данные
ctsPerf/ctsPerf.rc
Двоичные данные
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
Двоичные данные
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>
|
Загрузка…
Ссылка в новой задаче