|
1 | 1 | // ReSharper disable IdentifierTypo |
2 | 2 |
|
3 | 3 | using System; |
4 | | -using System.IO; |
5 | 4 | using System.Net; |
6 | 5 | using System.Net.Sockets; |
7 | 6 | using System.Runtime.InteropServices; |
8 | | -using System.Runtime.InteropServices.Marshalling; |
9 | 7 |
|
10 | 8 | namespace Hi3Helper.Plugin.Core.Utility; |
11 | 9 |
|
12 | 10 | /// <summary> |
13 | 11 | /// Unmanaged struct which contains a string which represents both IPv4 or IPv6. |
14 | 12 | /// </summary> |
| 13 | +[StructLayout(LayoutKind.Explicit, Size = 32)] |
15 | 14 | public unsafe struct DnsARecordResult |
16 | 15 | { |
| 16 | + /// <summary> |
| 17 | + /// Next entry of the record result. This can be null if no any entries left. |
| 18 | + /// </summary> |
| 19 | + [FieldOffset(0)] |
| 20 | + public DnsARecordResult* NextResult; |
| 21 | + |
17 | 22 | /// <summary> |
18 | 23 | /// The version of the IP string. The value must be either 4 (for IPv4) or 6 (for IPv6). |
19 | 24 | /// </summary> |
| 25 | + [FieldOffset(8)] |
20 | 26 | public int Version; |
21 | 27 |
|
22 | 28 | /// <summary> |
23 | | - /// Pointer to a string represents the IP address. |
| 29 | + /// Represents the length of the address data written in bytes. |
24 | 30 | /// </summary> |
25 | | - public char* AddressString; |
| 31 | + [FieldOffset(12)] |
| 32 | + public int AddressDataLength; |
26 | 33 |
|
27 | 34 | /// <summary> |
28 | | - /// Next entry of the record result. This can be null if no any entries left. |
| 35 | + /// Pointer to a string represents the IP address. |
29 | 36 | /// </summary> |
30 | | - public DnsARecordResult* NextResult; |
| 37 | + [FieldOffset(16)] |
| 38 | + public fixed byte AddressData[16]; |
31 | 39 |
|
32 | 40 | /// <summary> |
33 | 41 | /// Gets an array of <see cref="IPAddress"/> and free the struct data from the pointer. |
@@ -93,23 +101,13 @@ private static IPAddress GetIPAddressFromResultAndDispose(DnsARecordResult* resu |
93 | 101 | { |
94 | 102 | try |
95 | 103 | { |
96 | | - // Get the span representing the string. |
97 | | - ReadOnlySpan<char> addressStringSpan = Mem.CreateSpanFromNullTerminated<char>(resultP->AddressString); |
98 | | - |
99 | | - // Try to parse it. Output as IPAddress. Throw if the string is malformed. |
100 | | - if (!IPAddress.TryParse(addressStringSpan, out IPAddress? value)) |
101 | | - { |
102 | | - throw new InvalidDataException($"IP Address string is not valid! {addressStringSpan}"); |
103 | | - } |
104 | | - |
105 | | - return value; |
| 104 | + return new IPAddress(new ReadOnlySpan<byte>(resultP->AddressData, resultP->AddressDataLength)); |
106 | 105 | } |
107 | 106 | finally |
108 | 107 | { |
109 | 108 | // If the result is not null, free the string and the struct. |
110 | 109 | if (resultP != null) |
111 | 110 | { |
112 | | - Marshal.FreeCoTaskMem((nint)resultP->AddressString); // Equivalent to Utf16StringMarshaller.Free |
113 | 111 | Mem.Free(resultP); |
114 | 112 | } |
115 | 113 | } |
@@ -165,15 +163,13 @@ public static nint CreateToIntPtr(params ReadOnlySpan<IPAddress> addressSpan) |
165 | 163 | result = current; |
166 | 164 | } |
167 | 165 |
|
168 | | - // Get the current IPAddress instance, convert it to string and determine the version. |
169 | | - IPAddress address = addressSpan[offset++]; |
170 | | - string ipAddressString = address.ToString(); |
171 | | - int version = address.AddressFamily == AddressFamily.InterNetworkV6 ? 6 : 4; |
| 166 | + // Get the current IPAddress instance. |
| 167 | + IPAddress address = addressSpan[offset++]; |
172 | 168 |
|
| 169 | + // Write the address data into struct. |
173 | 170 | // Allocate the string, copy it into native memory and set the version |
174 | | - char* stringP = (char*)Utf16StringMarshaller.ConvertToUnmanaged(ipAddressString); |
175 | | - current->Version = version; |
176 | | - current->AddressString = stringP; |
| 171 | + current->Version = address.AddressFamily == AddressFamily.InterNetworkV6 ? 6 : 4; |
| 172 | + address.TryWriteBytes(new Span<byte>(current->AddressData, 16), out current->AddressDataLength); |
177 | 173 |
|
178 | 174 | last = current; |
179 | 175 | } while (offset < addressSpan.Length); // Repeat the process if there's still another entry |
|
0 commit comments