Skip to content

Commit a8f8c9d

Browse files
committed
Change address alloc from string to pure bytes
1 parent f81b450 commit a8f8c9d

File tree

1 file changed

+20
-24
lines changed

1 file changed

+20
-24
lines changed

Utility/DnsARecordResult.cs

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
11
// ReSharper disable IdentifierTypo
22

33
using System;
4-
using System.IO;
54
using System.Net;
65
using System.Net.Sockets;
76
using System.Runtime.InteropServices;
8-
using System.Runtime.InteropServices.Marshalling;
97

108
namespace Hi3Helper.Plugin.Core.Utility;
119

1210
/// <summary>
1311
/// Unmanaged struct which contains a string which represents both IPv4 or IPv6.
1412
/// </summary>
13+
[StructLayout(LayoutKind.Explicit, Size = 32)]
1514
public unsafe struct DnsARecordResult
1615
{
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+
1722
/// <summary>
1823
/// The version of the IP string. The value must be either 4 (for IPv4) or 6 (for IPv6).
1924
/// </summary>
25+
[FieldOffset(8)]
2026
public int Version;
2127

2228
/// <summary>
23-
/// Pointer to a string represents the IP address.
29+
/// Represents the length of the address data written in bytes.
2430
/// </summary>
25-
public char* AddressString;
31+
[FieldOffset(12)]
32+
public int AddressDataLength;
2633

2734
/// <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.
2936
/// </summary>
30-
public DnsARecordResult* NextResult;
37+
[FieldOffset(16)]
38+
public fixed byte AddressData[16];
3139

3240
/// <summary>
3341
/// 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
93101
{
94102
try
95103
{
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));
106105
}
107106
finally
108107
{
109108
// If the result is not null, free the string and the struct.
110109
if (resultP != null)
111110
{
112-
Marshal.FreeCoTaskMem((nint)resultP->AddressString); // Equivalent to Utf16StringMarshaller.Free
113111
Mem.Free(resultP);
114112
}
115113
}
@@ -165,15 +163,13 @@ public static nint CreateToIntPtr(params ReadOnlySpan<IPAddress> addressSpan)
165163
result = current;
166164
}
167165

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++];
172168

169+
// Write the address data into struct.
173170
// 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);
177173

178174
last = current;
179175
} while (offset < addressSpan.Length); // Repeat the process if there's still another entry

0 commit comments

Comments
 (0)