Skip to content

Commit 9dfdfbf

Browse files
authored
Replace the remaining uses of Marshal.PtrToStructure in core networking (#70900)
* Rename ICMP interop to match Windows SDK names
1 parent 0666d9d commit 9dfdfbf

File tree

10 files changed

+154
-107
lines changed

10 files changed

+154
-107
lines changed

src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.FIXED_INFO.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,34 @@ internal static partial class IpHlpApi
1212
public const int MAX_DOMAIN_NAME_LEN = 128;
1313
public const int MAX_SCOPE_ID_LEN = 256;
1414

15-
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
16-
public struct FIXED_INFO
15+
[StructLayout(LayoutKind.Sequential)]
16+
public unsafe struct FIXED_INFO
1717
{
18-
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_HOSTNAME_LEN + 4)]
19-
public string hostName;
20-
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_DOMAIN_NAME_LEN + 4)]
21-
public string domainName;
18+
private fixed byte _hostName[MAX_HOSTNAME_LEN + 4];
19+
public string HostName => CreateString(ref _hostName[0], MAX_HOSTNAME_LEN + 4);
20+
21+
private fixed byte _domainName[MAX_DOMAIN_NAME_LEN + 4];
22+
public string DomainName => CreateString(ref _domainName[0], MAX_DOMAIN_NAME_LEN + 4);
23+
2224
public IntPtr currentDnsServer; // IpAddressList*
2325
public IP_ADDR_STRING DnsServerList;
2426
public uint nodeType;
25-
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_SCOPE_ID_LEN + 4)]
26-
public string scopeId;
27-
public bool enableRouting;
28-
public bool enableProxy;
29-
public bool enableDns;
27+
28+
private fixed byte _scopeId[MAX_SCOPE_ID_LEN + 4];
29+
public string ScopeId => CreateString(ref _scopeId[0], MAX_SCOPE_ID_LEN + 4);
30+
31+
public uint enableRouting;
32+
public uint enableProxy;
33+
public uint enableDns;
34+
35+
private static string CreateString(ref byte firstByte, int maxLength)
36+
{
37+
fixed (byte* ptr = &firstByte)
38+
{
39+
int terminator = new ReadOnlySpan<byte>(ptr, maxLength).IndexOf((byte)0);
40+
return Marshal.PtrToStringAnsi((IntPtr)ptr, (terminator >= 0) ? terminator : maxLength);
41+
}
42+
}
3043
}
3144
}
3245
}

src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ internal static partial class IpHlpApi
1313
internal const int IP_STATUS_BASE = 11000;
1414

1515
[StructLayout(LayoutKind.Sequential)]
16-
internal struct IPOptions
16+
internal struct IP_OPTION_INFORMATION
1717
{
1818
internal byte ttl;
1919
internal byte tos;
2020
internal byte flags;
2121
internal byte optionsSize;
2222
internal IntPtr optionsData;
2323

24-
internal IPOptions(PingOptions? options)
24+
internal IP_OPTION_INFORMATION(PingOptions? options)
2525
{
2626
ttl = 128;
2727
tos = 0;
@@ -42,39 +42,38 @@ internal IPOptions(PingOptions? options)
4242
}
4343

4444
[StructLayout(LayoutKind.Sequential)]
45-
internal struct IcmpEchoReply
45+
internal struct ICMP_ECHO_REPLY
4646
{
4747
internal uint address;
4848
internal uint status;
4949
internal uint roundTripTime;
5050
internal ushort dataSize;
5151
internal ushort reserved;
5252
internal IntPtr data;
53-
internal IPOptions options;
53+
internal IP_OPTION_INFORMATION options;
5454
}
5555

5656
[StructLayout(LayoutKind.Sequential, Pack = 1)]
57-
internal struct Ipv6Address
57+
internal unsafe struct IPV6_ADDRESS_EX
5858
{
59-
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
60-
internal byte[] Goo;
61-
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
59+
internal ushort port;
60+
internal uint flowinfo;
61+
6262
// Replying address.
63-
internal byte[] Address;
63+
private fixed byte _Address[16];
64+
internal byte[] Address => MemoryMarshal.CreateReadOnlySpan(ref _Address[0], 16).ToArray();
65+
6466
internal uint ScopeID;
6567
}
6668

6769
[StructLayout(LayoutKind.Sequential)]
68-
internal struct Icmp6EchoReply
70+
internal struct ICMPV6_ECHO_REPLY
6971
{
70-
internal Ipv6Address Address;
72+
internal IPV6_ADDRESS_EX Address;
7173
// Reply IP_STATUS.
7274
internal uint Status;
7375
// RTT in milliseconds.
7476
internal uint RoundTripTime;
75-
internal IntPtr data;
76-
// internal IPOptions options;
77-
// internal IntPtr data; data os after tjos
7877
}
7978

8079
internal sealed class SafeCloseIcmpHandle : SafeHandleZeroOrMinusOneIsInvalid
@@ -101,10 +100,10 @@ protected override bool ReleaseHandle()
101100

102101
[LibraryImport(Interop.Libraries.IpHlpApi, SetLastError = true)]
103102
internal static partial uint IcmpSendEcho2(SafeCloseIcmpHandle icmpHandle, SafeWaitHandle Event, IntPtr apcRoutine, IntPtr apcContext,
104-
uint ipAddress, SafeLocalAllocHandle data, ushort dataSize, ref IPOptions options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
103+
uint ipAddress, SafeLocalAllocHandle data, ushort dataSize, ref IP_OPTION_INFORMATION options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
105104

106105
[LibraryImport(Interop.Libraries.IpHlpApi, SetLastError = true)]
107106
internal static partial uint Icmp6SendEcho2(SafeCloseIcmpHandle icmpHandle, SafeWaitHandle Event, IntPtr apcRoutine, IntPtr apcContext,
108-
byte[] sourceSocketAddress, byte[] destSocketAddress, SafeLocalAllocHandle data, ushort dataSize, ref IPOptions options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
107+
byte[] sourceSocketAddress, byte[] destSocketAddress, SafeLocalAllocHandle data, ushort dataSize, ref IP_OPTION_INFORMATION options, SafeLocalAllocHandle replyBuffer, uint replySize, uint timeout);
109108
}
110109
}

src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.IP_ADDR_STRING.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@ internal static partial class Interop
88
{
99
internal static partial class IpHlpApi
1010
{
11-
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
12-
public struct IP_ADDR_STRING
11+
[StructLayout(LayoutKind.Sequential)]
12+
public unsafe struct IP_ADDR_STRING
1313
{
14-
public IntPtr Next; // struct _IpAddressList*
15-
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
16-
public string IpAddress;
17-
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
18-
public string IpMask;
14+
public IP_ADDR_STRING* Next;
15+
public fixed byte IpAddress[16];
16+
public fixed byte IpMask[16];
1917
public uint Context;
2018
}
2119
}

src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.NetworkInformation.cs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,7 @@ internal unsafe struct IpAdapterAddresses
157157

158158
private fixed byte _address[MAX_ADAPTER_ADDRESS_LENGTH];
159159
private uint _addressLength;
160-
internal byte[] Address
161-
{
162-
get
163-
{
164-
fixed (byte* pAddress = _address)
165-
return new ReadOnlySpan<byte>(pAddress, (int)_addressLength).ToArray();
166-
}
167-
}
160+
internal byte[] Address => MemoryMarshal.CreateReadOnlySpan<byte>(ref _address[0], (int)_addressLength).ToArray();
168161

169162
internal AdapterFlags flags;
170163
internal uint mtu;
@@ -173,14 +166,7 @@ internal byte[] Address
173166
internal uint ipv6Index;
174167

175168
private fixed uint _zoneIndices[16];
176-
internal uint[] ZoneIndices
177-
{
178-
get
179-
{
180-
fixed (uint* pZoneIndices = _zoneIndices)
181-
return new ReadOnlySpan<uint>(pZoneIndices, 16).ToArray();
182-
}
183-
}
169+
internal uint[] ZoneIndices => MemoryMarshal.CreateReadOnlySpan<uint>(ref _zoneIndices[0], 16).ToArray();
184170

185171
internal IntPtr firstPrefix;
186172

src/libraries/Common/src/System/Net/NetworkInformation/HostInformationPal.Windows.cs

Lines changed: 86 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,61 +12,113 @@ namespace System.Net.NetworkInformation
1212
internal static class HostInformationPal
1313
{
1414
// Changing this information requires a reboot, so it's safe to cache.
15-
private static Interop.IpHlpApi.FIXED_INFO s_fixedInfo;
16-
private static bool s_fixedInfoInitialized;
15+
private static string? s_hostName;
16+
private static string? s_domainName;
17+
private static uint s_nodeType;
18+
private static string? s_scopeId;
19+
private static bool s_enableRouting;
20+
private static bool s_enableProxy;
21+
private static bool s_enableDns;
22+
23+
private static volatile bool s_initialized;
1724
private static object s_syncObject = new object();
1825

1926
public static string GetHostName()
2027
{
21-
return FixedInfo.hostName;
28+
EnsureInitialized();
29+
return s_hostName!;
2230
}
2331

2432
public static string GetDomainName()
2533
{
26-
return FixedInfo.domainName;
34+
EnsureInitialized();
35+
return s_domainName!;
36+
}
37+
38+
public static uint GetNodeType()
39+
{
40+
EnsureInitialized();
41+
return s_nodeType;
42+
}
43+
44+
public static string GetScopeId()
45+
{
46+
EnsureInitialized();
47+
return s_scopeId!;
48+
}
49+
50+
public static bool GetEnableRouting()
51+
{
52+
EnsureInitialized();
53+
return s_enableRouting;
2754
}
2855

29-
private static unsafe Interop.IpHlpApi.FIXED_INFO GetFixedInfo()
56+
public static bool GetEnableProxy()
3057
{
31-
uint size = 0;
32-
Interop.IpHlpApi.FIXED_INFO fixedInfo = default;
58+
EnsureInitialized();
59+
return s_enableProxy;
60+
}
3361

34-
// First we need to get the size of the buffer
35-
uint result = Interop.IpHlpApi.GetNetworkParams(IntPtr.Zero, &size);
62+
public static bool GetEnableDns()
63+
{
64+
EnsureInitialized();
65+
return s_enableDns;
66+
}
3667

37-
while (result == Interop.IpHlpApi.ERROR_BUFFER_OVERFLOW)
68+
private static void EnsureInitialized()
69+
{
70+
if (!s_initialized)
71+
Initialize();
72+
}
73+
74+
private static unsafe void Initialize()
75+
{
76+
lock (s_syncObject)
3877
{
39-
IntPtr buffer = Marshal.AllocHGlobal((int)size);
40-
try
78+
if (s_initialized)
79+
return;
80+
81+
uint size = 0;
82+
83+
// First we need to get the size of the buffer
84+
uint result = Interop.IpHlpApi.GetNetworkParams(IntPtr.Zero, &size);
85+
86+
while (result == Interop.IpHlpApi.ERROR_BUFFER_OVERFLOW)
4187
{
42-
result = Interop.IpHlpApi.GetNetworkParams(buffer, &size);
43-
if (result == Interop.IpHlpApi.ERROR_SUCCESS)
88+
IntPtr buffer = Marshal.AllocHGlobal((int)size);
89+
try
4490
{
45-
fixedInfo = Marshal.PtrToStructure<Interop.IpHlpApi.FIXED_INFO>(buffer);
91+
result = Interop.IpHlpApi.GetNetworkParams(buffer, &size);
92+
if (result == Interop.IpHlpApi.ERROR_SUCCESS)
93+
{
94+
Interop.IpHlpApi.FIXED_INFO* pFixedInfo = (Interop.IpHlpApi.FIXED_INFO*)buffer;
95+
96+
s_hostName = pFixedInfo->HostName;
97+
s_domainName = pFixedInfo->DomainName;
98+
99+
s_hostName = pFixedInfo->HostName;
100+
s_domainName = pFixedInfo->DomainName;
101+
s_nodeType = pFixedInfo->nodeType;
102+
s_scopeId = pFixedInfo->ScopeId;
103+
s_enableRouting = pFixedInfo->enableRouting != 0;
104+
s_enableProxy = pFixedInfo->enableProxy != 0;
105+
s_enableDns = pFixedInfo->enableDns != 0;
106+
107+
s_initialized = true;
108+
}
109+
}
110+
finally
111+
{
112+
Marshal.FreeHGlobal(buffer);
46113
}
47114
}
48-
finally
115+
116+
// If the result include there being no information, we'll still throw
117+
if (result != Interop.IpHlpApi.ERROR_SUCCESS)
49118
{
50-
Marshal.FreeHGlobal(buffer);
119+
throw new Win32Exception((int)result);
51120
}
52121
}
53-
54-
// If the result include there being no information, we'll still throw
55-
if (result != Interop.IpHlpApi.ERROR_SUCCESS)
56-
{
57-
throw new Win32Exception((int)result);
58-
}
59-
60-
return fixedInfo;
61-
}
62-
63-
public static ref readonly Interop.IpHlpApi.FIXED_INFO FixedInfo
64-
{
65-
get
66-
{
67-
LazyInitializer.EnsureInitialized(ref s_fixedInfo, ref s_fixedInfoInitialized, ref s_syncObject, () => GetFixedInfo());
68-
return ref s_fixedInfo;
69-
}
70122
}
71123
}
72124
}

src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPGlobalProperties.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public override string HostName
1919
{
2020
get
2121
{
22-
return HostInformationPal.FixedInfo.hostName;
22+
return HostInformationPal.GetHostName();
2323
}
2424
}
2525

@@ -28,7 +28,7 @@ public override string DomainName
2828
{
2929
get
3030
{
31-
return HostInformationPal.FixedInfo.domainName;
31+
return HostInformationPal.GetDomainName();
3232
}
3333
}
3434

@@ -48,7 +48,7 @@ public override NetBiosNodeType NodeType
4848
{
4949
get
5050
{
51-
return (NetBiosNodeType)HostInformationPal.FixedInfo.nodeType;
51+
return (NetBiosNodeType)HostInformationPal.GetNodeType();
5252
}
5353
}
5454

@@ -57,7 +57,7 @@ public override string DhcpScopeName
5757
{
5858
get
5959
{
60-
return HostInformationPal.FixedInfo.scopeId;
60+
return HostInformationPal.GetScopeId();
6161
}
6262
}
6363

@@ -66,7 +66,7 @@ public override bool IsWinsProxy
6666
{
6767
get
6868
{
69-
return (HostInformationPal.FixedInfo.enableProxy);
69+
return HostInformationPal.GetEnableProxy();
7070
}
7171
}
7272

src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPInterfaceProperties.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ internal sealed class SystemIPInterfaceProperties : IPInterfaceProperties
2626
private readonly GatewayIPAddressInformationCollection _gatewayAddresses;
2727
private readonly InternalIPAddressCollection _dhcpServers;
2828

29-
internal SystemIPInterfaceProperties(in Interop.IpHlpApi.FIXED_INFO fixedInfo, in Interop.IpHlpApi.IpAdapterAddresses ipAdapterAddresses)
29+
internal SystemIPInterfaceProperties(in Interop.IpHlpApi.IpAdapterAddresses ipAdapterAddresses)
3030
{
3131
_adapterFlags = ipAdapterAddresses.flags;
3232
_dnsSuffix = ipAdapterAddresses.DnsSuffix;
33-
_dnsEnabled = fixedInfo.enableDns;
33+
_dnsEnabled = HostInformationPal.GetEnableDns();
3434
_dynamicDnsEnabled = ((ipAdapterAddresses.flags & Interop.IpHlpApi.AdapterFlags.DnsEnabled) > 0);
3535

3636
_multicastAddresses = SystemMulticastIPAddressInformation.ToMulticastIpAddressInformationCollection(
@@ -58,7 +58,7 @@ internal SystemIPInterfaceProperties(in Interop.IpHlpApi.FIXED_INFO fixedInfo, i
5858

5959
if ((_adapterFlags & Interop.IpHlpApi.AdapterFlags.IPv4Enabled) != 0)
6060
{
61-
_ipv4Properties = new SystemIPv4InterfaceProperties(fixedInfo, ipAdapterAddresses);
61+
_ipv4Properties = new SystemIPv4InterfaceProperties(ipAdapterAddresses);
6262
}
6363

6464
if ((_adapterFlags & Interop.IpHlpApi.AdapterFlags.IPv6Enabled) != 0)

0 commit comments

Comments
 (0)