mirror of https://github.com/dahall/Vanara.git
Added nullability to QoS and test. Fixed bug in TC_GEN_FLOW.
parent
d22ec676a0
commit
5dad85375d
|
@ -1,7 +1,3 @@
|
|||
global using System;
|
||||
global using System.Runtime.InteropServices;
|
||||
global using Vanara.Extensions;
|
||||
global using Vanara.InteropServices;
|
||||
global using static Vanara.PInvoke.Ws2_32;
|
||||
global using IN_ADDR_IPV4 = Vanara.PInvoke.Ws2_32.IN_ADDR;
|
||||
global using IN_ADDR_IPV6 = Vanara.PInvoke.Ws2_32.IN6_ADDR;
|
||||
|
@ -118,7 +114,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 +141,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>
|
||||
|
|
|
@ -202,7 +202,7 @@ public static partial class Qwave
|
|||
|
||||
SizeT IVanaraMarshaler.GetNativeSize() => Marshal.SizeOf(typeof(ACTUAL));
|
||||
|
||||
SafeAllocatedMemoryHandle IVanaraMarshaler.MarshalManagedToNative(object managedObject)
|
||||
SafeAllocatedMemoryHandle IVanaraMarshaler.MarshalManagedToNative(object? managedObject)
|
||||
{
|
||||
if (managedObject is not CONTROL_SERVICE cs)
|
||||
{
|
||||
|
@ -224,13 +224,13 @@ public static partial class Qwave
|
|||
}
|
||||
else
|
||||
{
|
||||
native.union.ParamBuffer = new() { ParameterId = ParamBuffer.Value.ParameterId, Length = 8U + (uint)bufLen };
|
||||
native.union.ParamBuffer = new() { ParameterId = ParamBuffer!.Value.ParameterId, Length = 8U + (uint)bufLen };
|
||||
}
|
||||
|
||||
ret.Write(native);
|
||||
if (bufLen > 0)
|
||||
if (bufLen > 0 && ParamBuffer.HasValue)
|
||||
{
|
||||
ret.Write(ParamBuffer.Value.Buffer, false, bufOffset);
|
||||
ret.Write(ParamBuffer!.Value.Buffer!, false, bufOffset);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -239,7 +239,7 @@ public static partial class Qwave
|
|||
private static readonly int bufOffset = Marshal.OffsetOf(typeof(ACTUAL), "union").ToInt32() +
|
||||
Marshal.OffsetOf(typeof(UNION.DUMMYBUF), "Buffer").ToInt32();
|
||||
|
||||
object IVanaraMarshaler.MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes)
|
||||
object? IVanaraMarshaler.MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes)
|
||||
{
|
||||
if (pNativeData == IntPtr.Zero || allocatedBytes == 0)
|
||||
{
|
||||
|
@ -255,7 +255,7 @@ public static partial class Qwave
|
|||
else
|
||||
{
|
||||
PARAM_BUFFER pb = new() { ParameterId = actual.union.ParamBuffer.ParameterId, Length = actual.union.ParamBuffer.Length };
|
||||
pb.Buffer = pNativeData.ToByteArray((int)pb.Length - 8, bufOffset, allocatedBytes);
|
||||
pb.Buffer = pNativeData.ToByteArray((int)pb.Length - 8, bufOffset, allocatedBytes)!;
|
||||
ret.ParamBuffer = pb;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -172,7 +172,7 @@ public static partial class Traffic
|
|||
// Buffer ) {...}
|
||||
[PInvokeData("traffic.h", MSDNShortId = "NC:traffic.TCI_NOTIFY_HANDLER")]
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = false)]
|
||||
public delegate void TCI_NOTIFY_HANDLER([In] IntPtr ClRegCtx, [In] IntPtr ClIfcCtx, TC_NOTIFY Event, [In] IntPtr SubCode,
|
||||
public delegate void TCI_NOTIFY_HANDLER([In] IntPtr ClRegCtx, [In, Optional] IntPtr ClIfcCtx, TC_NOTIFY Event, [In] IntPtr SubCode,
|
||||
uint BufSize, [In] IntPtr Buffer);
|
||||
|
||||
/// <summary>Describes the notification event.</summary>
|
||||
|
@ -697,7 +697,7 @@ public static partial class Traffic
|
|||
/// <para><c>Note</c> Use of the <c>TcEnumerateFlows</c> function requires administrative privilege.</para>
|
||||
/// </remarks>
|
||||
[PInvokeData("traffic.h", MSDNShortId = "NF:traffic.TcEnumerateFlows")]
|
||||
public static ENUMERATION_BUFFER_MGD TcEnumerateFlows(HIFC IfcHandle, uint pFlowCount = 0xFFFF)
|
||||
public static ENUMERATION_BUFFER_MGD? TcEnumerateFlows(HIFC IfcHandle, uint pFlowCount = 0xFFFF)
|
||||
{
|
||||
HFLOWENUM hEnum = default;
|
||||
uint bufSz = 1024, cnt;
|
||||
|
@ -1484,7 +1484,7 @@ public static partial class Traffic
|
|||
public IntPtr pFlow;
|
||||
|
||||
/// <summary>The corresponding <see cref="TC_GEN_FLOW"/> structure.</summary>
|
||||
public TC_GEN_FLOW Flow => pFlow.ToStructure<TC_GEN_FLOW>();
|
||||
public TC_GEN_FLOW Flow => pFlow.ToStructure<TC_GEN_FLOW>()!;
|
||||
|
||||
/// <summary>Specifies the number of filters associated with the flow.</summary>
|
||||
public uint NumberOfFilters;
|
||||
|
@ -1511,7 +1511,7 @@ public static partial class Traffic
|
|||
[PInvokeData("traffic.h", MSDNShortId = "NS:traffic._ENUMERATION_BUFFER")]
|
||||
public class ENUMERATION_BUFFER_MGD
|
||||
{
|
||||
private ENUMERATION_BUFFER_MGD() { }
|
||||
private ENUMERATION_BUFFER_MGD() => throw new NotImplementedException();
|
||||
|
||||
internal ENUMERATION_BUFFER_MGD(IntPtr ptr)
|
||||
{
|
||||
|
@ -1972,6 +1972,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>
|
||||
|
@ -1998,7 +2017,7 @@ public static partial class Traffic
|
|||
public class TC_GEN_FILTER_MGD_UNK : TC_GEN_FILTER_MGD_BASE
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the specific format of the pattern to be applied to the filter, such as IP_PATTERN. The pattern specifies which bits of
|
||||
/// Indicates the specific format of the pattern to be applied to the filter, such as <see cref="IP_PATTERN"/>. The pattern specifies which bits of
|
||||
/// a given packet should be evaluated when determining whether a packet is included in the filter.
|
||||
/// </summary>
|
||||
public byte[] Pattern;
|
||||
|
@ -2013,8 +2032,8 @@ public static partial class Traffic
|
|||
internal TC_GEN_FILTER_MGD_UNK(in TC_GEN_FILTER f)
|
||||
{
|
||||
AddressType = f.AddressType;
|
||||
Pattern = f.Pattern.ToByteArray((int)f.PatternSize);
|
||||
Mask = f.Mask.ToByteArray((int)f.PatternSize);
|
||||
Pattern = f.Pattern.ToByteArray((int)f.PatternSize) ?? new byte[0];
|
||||
Mask = f.Mask.ToByteArray((int)f.PatternSize) ?? new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2076,30 +2095,31 @@ public static partial class Traffic
|
|||
/// <para>QOS_SHAPING_RATE</para>
|
||||
/// <para>QOS_OBJECT_END_OF_LIST</para>
|
||||
/// </summary>
|
||||
public IQoSObjectHdr[] TcObjects;
|
||||
public IQoSObjectHdr[]? TcObjects;
|
||||
|
||||
SizeT IVanaraMarshaler.GetNativeSize() => Marshal.SizeOf(typeof(INT_TC_GEN_FLOW));
|
||||
|
||||
SafeAllocatedMemoryHandle IVanaraMarshaler.MarshalManagedToNative(object managedObject)
|
||||
SafeAllocatedMemoryHandle IVanaraMarshaler.MarshalManagedToNative(object? managedObject)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
return pFlow;
|
||||
}
|
||||
|
||||
object IVanaraMarshaler.MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes)
|
||||
object? IVanaraMarshaler.MarshalNativeToManaged(IntPtr pNativeData, SizeT allocatedBytes)
|
||||
{
|
||||
var f = pNativeData.ToStructure<INT_TC_GEN_FLOW>(allocatedBytes);
|
||||
TC_GEN_FLOW ret = new() { SendingFlowspec = f.SendingFlowspec, ReceivingFlowspec = f.ReceivingFlowspec, TcObjects = new IQoSObjectHdr[f.TcObjectsLength] };
|
||||
|
@ -2171,15 +2191,15 @@ public static partial class Traffic
|
|||
|
||||
/// <summary>Pointer to the client-callback function ClAddFlowComplete.</summary>
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public TCI_ADD_FLOW_COMPLETE_HANDLER ClAddFlowCompleteHandler;
|
||||
public TCI_ADD_FLOW_COMPLETE_HANDLER? ClAddFlowCompleteHandler;
|
||||
|
||||
/// <summary>Pointer to the client-callback function ClModifyFlowComplete.</summary>
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public TCI_MOD_FLOW_COMPLETE_HANDLER ClModifyFlowCompleteHandler;
|
||||
public TCI_MOD_FLOW_COMPLETE_HANDLER? ClModifyFlowCompleteHandler;
|
||||
|
||||
/// <summary>Pointer to the client-callback function ClDeleteFlowComplete.</summary>
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public TCI_DEL_FLOW_COMPLETE_HANDLER ClDeleteFlowCompleteHandler;
|
||||
public TCI_DEL_FLOW_COMPLETE_HANDLER? ClDeleteFlowCompleteHandler;
|
||||
}
|
||||
|
||||
/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HCLIENT"/> that is disposed using <see cref="TcDeregisterClient"/>.</summary>
|
||||
|
|
|
@ -169,9 +169,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>
|
||||
|
|
|
@ -7,6 +7,7 @@ using static Vanara.PInvoke.Traffic;
|
|||
using static Vanara.PInvoke.Ws2_32;
|
||||
|
||||
namespace Vanara.PInvoke.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class QoSTests
|
||||
{
|
||||
|
@ -67,16 +68,19 @@ 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();
|
||||
mem.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -119,12 +123,12 @@ public class QoSTests
|
|||
using var pin = new PinnedObject(dscp);
|
||||
Assert.That(QOSSetFlow(hQos, flowId, QOS_SET_FLOW.QOSSetOutgoingDSCPValue, 4, pin), ResultIs.Successful);
|
||||
|
||||
uint[] flowIds = null;
|
||||
uint[]? flowIds = null;
|
||||
Assert.That(() => flowIds = QOSEnumerateFlows(hQos), Throws.Nothing);
|
||||
Assert.That(flowIds, Is.Not.Empty);
|
||||
flowIds.WriteValues();
|
||||
flowIds!.WriteValues();
|
||||
|
||||
Assert.That(() => QOSQueryFlow<ulong>(hQos, flowIds[0], QOS_QUERY_FLOW.QOSQueryOutgoingRate, false).WriteValues(), Throws.Nothing);
|
||||
Assert.That(() => QOSQueryFlow<ulong>(hQos, flowIds![0], QOS_QUERY_FLOW.QOSQueryOutgoingRate, false).WriteValues(), Throws.Nothing);
|
||||
|
||||
Assert.That(QOSRemoveSocketFromFlow(hQos, socket.Handle, flowId), ResultIs.Successful);
|
||||
|
||||
|
|
Loading…
Reference in New Issue