Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[StructLayout(LayoutKind.Sequential)]
public unsafe struct IPEndPointInfo
public struct IPEndPointInfo
{
public fixed byte AddressBytes[16];
public InlineArray16<byte> AddressBytes;
public uint NumAddressBytes;
public uint Port;
private uint __padding; // For native struct-size padding. Does not contain useful data.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Sys
{
[StructLayout(LayoutKind.Sequential)]
public unsafe struct LinkLayerAddressInfo
public struct LinkLayerAddressInfo
{
public int InterfaceIndex;
public fixed byte AddressBytes[8];
public InlineArray8<byte> AddressBytes;
public byte NumAddressBytes;
private byte __padding; // For native struct-size padding. Does not contain useful data.
public ushort HardwareType;
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct IpAddressInfo
public struct IpAddressInfo
{
public int InterfaceIndex;
public fixed byte AddressBytes[16];
public InlineArray16<byte> AddressBytes;
public byte NumAddressBytes;
public byte PrefixLength;
private fixed byte __padding[2];
private InlineArray2<byte> __padding;
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct NetworkInterfaceInfo
public struct NetworkInterfaceInfo
{
public fixed byte Name[16];
public InlineArray16<byte> Name;
public long Speed;
public int InterfaceIndex;
public int Mtu;
public ushort HardwareType;
public byte OperationalState;
public byte NumAddressBytes;
public fixed byte AddressBytes[8];
public InlineArray8<byte> AddressBytes;
public byte SupportsMulticast;
private fixed byte __padding[3];
private InlineArray3<byte> __padding;
}

[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_EnumerateInterfaceAddresses")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

internal static partial class Interop
Expand Down Expand Up @@ -30,37 +32,56 @@ internal bool Equals(in SYSTEMTIME other) =>
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal unsafe struct TIME_DYNAMIC_ZONE_INFORMATION
internal struct TIME_DYNAMIC_ZONE_INFORMATION
{
[InlineArray(32)]
internal struct NameBuffer
{
private char _element0;
}

[InlineArray(128)]
internal struct TimeZoneKeyNameBuffer
{
private char _element0;
}

internal int Bias;
internal fixed char StandardName[32];
internal NameBuffer StandardName;
internal SYSTEMTIME StandardDate;
internal int StandardBias;
internal fixed char DaylightName[32];
internal NameBuffer DaylightName;
internal SYSTEMTIME DaylightDate;
internal int DaylightBias;
internal fixed char TimeZoneKeyName[128];
internal TimeZoneKeyNameBuffer TimeZoneKeyName;
internal byte DynamicDaylightTimeDisabled;

internal string GetTimeZoneKeyName()
{
fixed (char* p = TimeZoneKeyName)
return new string(p);
ReadOnlySpan<char> span = TimeZoneKeyName;
int idx = span.IndexOf('\0');
return new string(idx >= 0 ? span[..idx] : span);
}
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal unsafe struct TIME_ZONE_INFORMATION
internal struct TIME_ZONE_INFORMATION
{
[InlineArray(32)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few of these powers of 2 are also relatively common, from what I've seen.

Might also be worth a centralized define for them like the MAX_PATH case. -- It might in general be interesting to see how many manual InlineArray(...) structs we need and if there is commonality between key sizes to know if a few key extras should be exposed or not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I'll ask github CCA to see what it can unite/deduplicate

internal struct NameBuffer
{
private char _element0;
}

internal int Bias;
internal fixed char StandardName[32];
internal NameBuffer StandardName;
internal SYSTEMTIME StandardDate;
internal int StandardBias;
internal fixed char DaylightName[32];
internal NameBuffer DaylightName;
internal SYSTEMTIME DaylightDate;
internal int DaylightBias;

internal TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi)
internal unsafe TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi)
{
// The start of TIME_DYNAMIC_ZONE_INFORMATION has identical layout as TIME_ZONE_INFORMATION
fixed (TIME_ZONE_INFORMATION* pTo = &this)
Expand All @@ -70,14 +91,16 @@ internal TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi)

internal string GetStandardName()
{
fixed (char* p = StandardName)
return new string(p);
ReadOnlySpan<char> span = StandardName;
int idx = span.IndexOf('\0');
return new string(idx >= 0 ? span[..idx] : span);
}

internal string GetDaylightName()
{
fixed (char* p = DaylightName)
return new string(p);
ReadOnlySpan<char> span = DaylightName;
int idx = span.IndexOf('\0');
return new string(idx >= 0 ? span[..idx] : span);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class NtDll
{
[LibraryImport(Libraries.NtDll)]
private static partial int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);
private static unsafe partial int RtlGetVersion(RTL_OSVERSIONINFOEX* lpVersionInformation);

internal static unsafe int RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi)
{
osvi = default;
osvi.dwOSVersionInfoSize = (uint)sizeof(RTL_OSVERSIONINFOEX);
return RtlGetVersion(ref osvi);
fixed (RTL_OSVERSIONINFOEX* p = &osvi)
return RtlGetVersion(p);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal unsafe struct RTL_OSVERSIONINFOEX
internal struct RTL_OSVERSIONINFOEX
{
internal uint dwOSVersionInfoSize;
internal uint dwMajorVersion;
internal uint dwMinorVersion;
internal uint dwBuildNumber;
internal uint dwPlatformId;
internal fixed char szCSDVersion[128];
#if NET
internal CSDVersionBuffer szCSDVersion;

[InlineArray(128)]
internal struct CSDVersionBuffer
{
private char _element0;
}
#else
internal unsafe fixed char szCSDVersion[128];
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if NET
using System.Runtime.InteropServices.Marshalling;
Expand Down Expand Up @@ -337,14 +338,25 @@ public struct WINHTTP_ASYNC_RESULT
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct WINHTTP_CONNECTION_INFO
public struct WINHTTP_CONNECTION_INFO
{
// This field is actually 4 bytes, but we use nuint to avoid alignment issues for x64.
// If we want to read this field in the future, we need to change type and make sure
// alignment is correct for necessary archs.
public nuint cbSize;
public fixed byte LocalAddress[128];
public fixed byte RemoteAddress[128];
#if NET
public AddressBuffer LocalAddress;
public AddressBuffer RemoteAddress;

[InlineArray(128)]
public struct AddressBuffer
{
private byte _element0;
}
#else
public unsafe fixed byte LocalAddress[128];
public unsafe fixed byte RemoteAddress[128];
#endif
}

[StructLayout(LayoutKind.Sequential)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,11 @@ private static void OnRequestSendingRequest(WinHttpRequestState state)
// See: https://learn.microsoft.com/en-us/windows/win32/api/winhttp/ns-winhttp-winhttp_connection_info
// SOCKADDR_STORAGE can hold either IPv4 or IPv6 address.
// For offset numbers: https://learn.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
#if NET
ReadOnlySpan<byte> remoteAddressSpan = connectionInfo.RemoteAddress;
#else
ReadOnlySpan<byte> remoteAddressSpan = new ReadOnlySpan<byte>(connectionInfo.RemoteAddress, 128);
#endif
AddressFamily addressFamily = (AddressFamily)(remoteAddressSpan[0] + (remoteAddressSpan[1] << 8));
ipAddress = addressFamily switch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal unsafe AndroidNetworkInterface(string name, Interop.Sys.NetworkInterfac
_index = networkInterfaceInfo->InterfaceIndex;
if (networkInterfaceInfo->NumAddressBytes > 0)
{
_physicalAddress = new PhysicalAddress(new ReadOnlySpan<byte>(networkInterfaceInfo->AddressBytes, networkInterfaceInfo->NumAddressBytes).ToArray());
_physicalAddress = new PhysicalAddress(((ReadOnlySpan<byte>)networkInterfaceInfo->AddressBytes)[..networkInterfaceInfo->NumAddressBytes].ToArray());
}

_mtu = networkInterfaceInfo->Mtu;
Expand All @@ -33,7 +33,7 @@ internal unsafe AndroidNetworkInterface(string name, Interop.Sys.NetworkInterfac

internal unsafe void AddAddress(Interop.Sys.IpAddressInfo *addressInfo)
{
var address = new IPAddress(new ReadOnlySpan<byte>(addressInfo->AddressBytes, addressInfo->NumAddressBytes));
var address = new IPAddress(((ReadOnlySpan<byte>)addressInfo->AddressBytes)[..addressInfo->NumAddressBytes]);
if (address.IsIPv6LinkLocal)
{
address.ScopeId = addressInfo->InterfaceIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ private unsafe TcpConnectionInformation[] GetTcpConnections(bool listeners)
continue;
}

IPAddress localIPAddress = new IPAddress(new ReadOnlySpan<byte>(nativeInfo.LocalEndPoint.AddressBytes, checked((int)nativeInfo.LocalEndPoint.NumAddressBytes)));
IPAddress localIPAddress = new IPAddress(((ReadOnlySpan<byte>)nativeInfo.LocalEndPoint.AddressBytes)[..checked((int)nativeInfo.LocalEndPoint.NumAddressBytes)]);
IPEndPoint local = new IPEndPoint(localIPAddress, (int)nativeInfo.LocalEndPoint.Port);

IPAddress remoteIPAddress = nativeInfo.RemoteEndPoint.NumAddressBytes == 0 ?
IPAddress.Any :
new IPAddress(new ReadOnlySpan<byte>(nativeInfo.RemoteEndPoint.AddressBytes, checked((int)nativeInfo.RemoteEndPoint.NumAddressBytes)));
new IPAddress(((ReadOnlySpan<byte>)nativeInfo.RemoteEndPoint.AddressBytes)[..checked((int)nativeInfo.RemoteEndPoint.NumAddressBytes)]);

IPEndPoint remote = new IPEndPoint(remoteIPAddress, (int)nativeInfo.RemoteEndPoint.Port);
connectionInformations[nextResultIndex++] = new SimpleTcpConnectionInformation(local, remote, state);
Expand Down Expand Up @@ -87,7 +87,7 @@ public override unsafe IPEndPoint[] GetActiveUdpListeners()
int port = (int)endPointInfo.Port;
IPAddress ipAddress = endPointInfo.NumAddressBytes == 0 ?
IPAddress.Any :
new IPAddress(new ReadOnlySpan<byte>(endPointInfo.AddressBytes, checked((int)endPointInfo.NumAddressBytes)));
new IPAddress(((ReadOnlySpan<byte>)endPointInfo.AddressBytes)[..checked((int)endPointInfo.NumAddressBytes)]);

endPoints[i] = new IPEndPoint(ipAddress, port);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private static unsafe void OnGatewayFound(void* pContext, Interop.Sys.IpAddressI
{
Context* context = (Context*)pContext;

IPAddress ipAddress = new IPAddress(new ReadOnlySpan<byte>(gatewayAddressInfo->AddressBytes, gatewayAddressInfo->NumAddressBytes));
IPAddress ipAddress = new IPAddress(((ReadOnlySpan<byte>)gatewayAddressInfo->AddressBytes)[..gatewayAddressInfo->NumAddressBytes]);
if (ipAddress.IsIPv6LinkLocal)
{
// For Link-Local addresses add ScopeId as that is not part of the route entry.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static bool IsMulticast(IPAddress address)
/// <returns>A new IPAddress created with the information in the native structure.</returns>
public static unsafe IPAddress GetIPAddressFromNativeInfo(Interop.Sys.IpAddressInfo* addressInfo)
{
IPAddress ipAddress = new IPAddress(new ReadOnlySpan<byte>(addressInfo->AddressBytes, addressInfo->NumAddressBytes));
IPAddress ipAddress = new IPAddress(((ReadOnlySpan<byte>)addressInfo->AddressBytes)[..addressInfo->NumAddressBytes]);
return ipAddress;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static unsafe NetworkInterface[] GetLinuxNetworkInterfaces()

for (int i = 0; i < interfaceCount; i++)
{
var lni = new LinuxNetworkInterface(Utf8StringMarshaller.ConvertToManaged(nii->Name)!, nii->InterfaceIndex, systemProperties);
var lni = new LinuxNetworkInterface(Utf8StringMarshaller.ConvertToManaged((byte*)&nii->Name)!, nii->InterfaceIndex, systemProperties);
lni._interfaceType = (NetworkInterfaceType)nii->HardwareType;
lni._speed = nii->Speed;
lni._operationalStatus = (OperationalStatus)nii->OperationalState;
Expand All @@ -104,7 +104,7 @@ public static unsafe NetworkInterface[] GetLinuxNetworkInterfaces()

if (nii->NumAddressBytes > 0)
{
lni._physicalAddress = new PhysicalAddress(new ReadOnlySpan<byte>(nii->AddressBytes, nii->NumAddressBytes).ToArray());
lni._physicalAddress = new PhysicalAddress(((ReadOnlySpan<byte>)nii->AddressBytes)[..nii->NumAddressBytes].ToArray());
}

interfaces[i] = lni;
Expand All @@ -114,7 +114,7 @@ public static unsafe NetworkInterface[] GetLinuxNetworkInterfaces()

while (addressCount != 0)
{
var address = new IPAddress(new ReadOnlySpan<byte>(ai->AddressBytes, ai->NumAddressBytes));
var address = new IPAddress(((ReadOnlySpan<byte>)ai->AddressBytes)[..ai->NumAddressBytes]);
if (address.IsIPv6LinkLocal)
{
address.ScopeId = ai->InterfaceIndex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private static unsafe AndroidNetworkInterface[] ToAndroidNetworkInterfaceArray(i
var networkInterfaceInfo = (Interop.Sys.NetworkInterfaceInfo*)networkInterfacesPtr;
for (int i = 0; i < interfaceCount; i++, networkInterfaceInfo++)
{
var name = Utf8StringMarshaller.ConvertToManaged(networkInterfaceInfo->Name);
var name = Utf8StringMarshaller.ConvertToManaged((byte*)&networkInterfaceInfo->Name);
networkInterfaces[i] = new AndroidNetworkInterface(name!, networkInterfaceInfo);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,7 @@ protected unsafe void ProcessIpv6Address(Interop.Sys.IpAddressInfo* addressInfo,

protected unsafe void ProcessLinkLayerAddress(Interop.Sys.LinkLayerAddressInfo* llAddr)
{
byte[] macAddress = new byte[llAddr->NumAddressBytes];
fixed (byte* macAddressPtr = macAddress)
{
Buffer.MemoryCopy(llAddr->AddressBytes, macAddressPtr, llAddr->NumAddressBytes, llAddr->NumAddressBytes);
}
byte[] macAddress = ((ReadOnlySpan<byte>)llAddr->AddressBytes)[..llAddr->NumAddressBytes].ToArray();
PhysicalAddress physicalAddress = new PhysicalAddress(macAddress);

_index = llAddr->InterfaceIndex;
Expand Down
Loading
Loading