Fixed and enhanced QoS structures.

pull/436/head
David Hall 2023-10-19 19:53:09 -06:00
parent 9734721440
commit aba2edf270
5 changed files with 58 additions and 12 deletions

View File

@ -118,7 +118,7 @@ public static partial class Qwave
// QOS_OBJECT_HDR, *LPQOS_OBJECT_HDR;
[PInvokeData("qos.h", MSDNShortId = "NS:qos.__unnamed_struct_0")]
[StructLayout(LayoutKind.Sequential)]
public struct QOS_OBJECT_HDR
public struct QOS_OBJECT_HDR : IQoSObjectHdr
{
/// <summary>
/// <para>Specifies the type of object to which <c>QOS_OBJECT_HDR</c> is attached. The following values are valid for <c>QOS_OBJECT_HDR</c>:</para>
@ -145,6 +145,9 @@ public static partial class Qwave
var ot = CorrespondingTypeAttribute.CanGet<QOS_OBJ_TYPE>(typeof(T), out var e) ? e : throw new ArgumentException();
return new() { ObjectType = ot, ObjectLength = (uint)Marshal.SizeOf(typeof(T)) };
}
/// <summary>An instance of <see cref="QOS_OBJECT_HDR"/> used for the end of a list.</summary>
public static readonly QOS_OBJECT_HDR EndOfList = Init<QOS_OBJECT_HDR>();
}
/// <summary>The QOS object <c>QOS_SD_MODE</c> defines the behavior of the traffic control-packet shaper component.</summary>

View File

@ -228,7 +228,7 @@ public static partial class Qwave
}
ret.Write(native);
if (bufLen > 0)
if (bufLen > 0 && ParamBuffer.HasValue)
{
ret.Write(ParamBuffer.Value.Buffer, false, bufOffset);
}

View File

@ -1973,6 +1973,25 @@ public static partial class Traffic
/// criteria). Note that the <c>Mask</c> member must be of the same type as the <c>Pattern</c> member.
/// </summary>
public IntPtr Mask;
/// <summary>Creates a <see cref="TC_GEN_FILTER"/> instance.</summary>
/// <typeparam name="T">The type of the pattern.</typeparam>
/// <param name="AddressType">The filter type to be applied with the filter.</param>
/// <param name="Pattern">Indicates the specific format of the pattern to be applied to the filter, such as IP_PATTERN.</param>
/// <param name="Mask">A bitmask applied to the bits designated in the <c>Pattern</c> member.</param>
/// <param name="memAlloc">The memory allocated too the <paramref name="Pattern"/> and <paramref name="Mask"/> fields.</param>
/// <returns>
/// A complete <see cref="TC_GEN_FILTER"/> instance. Do not dispose the value returned in <paramref name="memAlloc"/> until this
/// structure is no longer needed.
/// </returns>
public static TC_GEN_FILTER Create<T>(NDIS_PROTOCOL_ID AddressType, in T Pattern, in T Mask, out SafeHandle memAlloc) where T : struct
{
var sz = Marshal.SizeOf(typeof(T));
SafeNativeArray<T> parts = new(new T[] { Pattern, Mask });
memAlloc = parts;
var ptrs = parts.GetPointers();
return new TC_GEN_FILTER { AddressType = AddressType, PatternSize = (uint)sz, Pattern = ptrs[0], Mask = ptrs[1] };
}
}
/// <summary>
@ -2086,14 +2105,15 @@ public static partial class Traffic
if (managedObject is not TC_GEN_FLOW f)
throw new ArgumentException("Only objects of type TC_GEN_FLOW can be marshaled.");
int objLen = f.TcObjects?.Length ?? 0;
SafeCoTaskMemStruct<INT_TC_GEN_FLOW> pFlow = new(new INT_TC_GEN_FLOW() { SendingFlowspec = f.SendingFlowspec, ReceivingFlowspec = f.ReceivingFlowspec, TcObjectsLength = objLen });
pFlow.Size += f.TcObjects?.Sum(o => Marshal.SizeOf(o.GetType())) ?? 0;
int objByteLen = f.TcObjects?.Sum(o => Marshal.SizeOf(o.GetType())) ?? 0;
SafeCoTaskMemStruct<INT_TC_GEN_FLOW> pFlow = new(new INT_TC_GEN_FLOW() { SendingFlowspec = f.SendingFlowspec, ReceivingFlowspec = f.ReceivingFlowspec, TcObjectsLength = objByteLen });
pFlow.Size += objByteLen;
if (objLen > 0)
{
var oPtr = pFlow.GetFieldAddress(nameof(TcObjects));
for (int i = 0; i < objLen; i++)
{
oPtr.Write(f.TcObjects[i]);
oPtr.Write(f.TcObjects![i]);
oPtr = oPtr.Offset(Marshal.SizeOf(f.TcObjects[i].GetType()));
}
}

View File

@ -171,9 +171,30 @@ public static partial class Ws2_32
public struct FLOWSPEC
{
/// <summary>Represents a FLOWSPEC with all unspecified values.</summary>
public static readonly FLOWSPEC NotSpecified = new() { DelayVariation = QOS_NOT_SPECIFIED, Latency = QOS_NOT_SPECIFIED, MaxSduSize = QOS_NOT_SPECIFIED,
MinimumPolicedSize = QOS_NOT_SPECIFIED, PeakBandwidth = QOS_NOT_SPECIFIED, TokenBucketSize = QOS_NOT_SPECIFIED, TokenRate = QOS_NOT_SPECIFIED,
ServiceType = SERVICETYPE.SERVICETYPE_BESTEFFORT };
public static readonly FLOWSPEC NotSpecified = new(SERVICETYPE.SERVICETYPE_BESTEFFORT);
/// <summary>Initializes a new instance of the <see cref="FLOWSPEC"/> struct.</summary>
/// <param name="delayVariation">The delay variation.</param>
/// <param name="latency">The latency.</param>
/// <param name="maxSduSize">Maximum size of the sdu.</param>
/// <param name="minimumPolicedSize">Minimum size of the policed.</param>
/// <param name="peakBandwidth">The peak bandwidth.</param>
/// <param name="tokenBucketSize">Size of the token bucket.</param>
/// <param name="tokenRate">The token rate.</param>
/// <param name="serviceType">Type of the service.</param>
public FLOWSPEC(SERVICETYPE serviceType, uint tokenRate = QOS_NOT_SPECIFIED, uint delayVariation = QOS_NOT_SPECIFIED,
uint latency = QOS_NOT_SPECIFIED, uint maxSduSize = QOS_NOT_SPECIFIED, uint minimumPolicedSize = QOS_NOT_SPECIFIED,
uint peakBandwidth = QOS_NOT_SPECIFIED, uint tokenBucketSize = QOS_NOT_SPECIFIED)
{
DelayVariation = delayVariation;
Latency = latency;
MaxSduSize = maxSduSize;
MinimumPolicedSize = minimumPolicedSize;
PeakBandwidth = peakBandwidth;
TokenBucketSize = tokenBucketSize;
TokenRate = tokenRate;
ServiceType = serviceType;
}
/// <summary>
/// <para>

View File

@ -69,14 +69,16 @@ public class QoSTests
{
TC_GEN_FLOW flow = new()
{
SendingFlowspec = FLOWSPEC.NotSpecified,
ReceivingFlowspec = FLOWSPEC.NotSpecified,
TcObjects = new IQoSObjectHdr[] { new QOS_DS_CLASS { ObjectHdr = QOS_OBJECT_HDR.Init<QOS_DS_CLASS>(), DSField = 0x28 } }
SendingFlowspec = new FLOWSPEC(SERVICETYPE.SERVICETYPE_GUARANTEED, 10000, maxSduSize: 344, minimumPolicedSize: 12, peakBandwidth: 32000, tokenBucketSize: 680),
ReceivingFlowspec = new(SERVICETYPE.SERVICETYPE_GUARANTEED, 10000),
TcObjects = new IQoSObjectHdr[] { new QOS_DS_CLASS { ObjectHdr = QOS_OBJECT_HDR.Init<QOS_DS_CLASS>(), DSField = 0x2E }, QOS_OBJECT_HDR.EndOfList }
};
Assert.That(TcAddFlow(hIfc, default, default, flow, out var hFlow), ResultIs.Successful);
try
{
TC_GEN_FILTER filter = new() { };
IP_PATTERN pattern = new() { ProtocolId = (byte)IPPROTO.IPPROTO_UDP, tcDstPort = 5000 };
IP_PATTERN mask = new() { ProtocolId = 0xFF, tcDstPort = 0xFFFF };
TC_GEN_FILTER filter = TC_GEN_FILTER.Create(NDIS_PROTOCOL_ID.NDIS_PROTOCOL_ID_TCP_IP, pattern, mask, out var mem);
Assert.That(TcAddFilter(hFlow, filter, out SafeHFILTER hFilt), ResultIs.Successful);
hFilt.Dispose();
}