Skip to content

Commit 566ea2f

Browse files
Further reduce use of unsafe code
1 parent 7b9722f commit 566ea2f

File tree

4 files changed

+48
-56
lines changed

4 files changed

+48
-56
lines changed

src/Servers/HttpSys/src/NativeMethods.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,5 @@ HttpSetRequestQueueProperty
5757
HttpSetUrlGroupProperty
5858
HttpSetUrlGroupProperty
5959
SetFileCompletionNotificationModes
60+
SOCKADDR_IN
61+
SOCKADDR_IN6
Lines changed: 41 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,73 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Diagnostics.Contracts;
54
using System.Net;
6-
using System.Net.Sockets;
5+
using Windows.Win32.Networking.WinSock;
76

87
namespace Microsoft.AspNetCore.HttpSys.Internal;
98

10-
internal sealed class SocketAddress
9+
internal abstract class SocketAddress
1110
{
12-
private const int NumberOfIPv6Labels = 8;
13-
private const int IPv6AddressSize = 28;
14-
private const int IPv4AddressSize = 16;
15-
private const int WriteableOffset = 2;
11+
internal abstract int GetPort();
1612

17-
private readonly byte[] _buffer;
18-
private readonly int _size;
13+
internal abstract IPAddress? GetIPAddress();
1914

20-
private SocketAddress(AddressFamily family, int size)
15+
internal static unsafe SocketAddress? CopyOutAddress(SOCKADDR* pSockaddr)
2116
{
22-
ArgumentOutOfRangeException.ThrowIfLessThan(size, WriteableOffset);
23-
Family = family;
24-
_size = size;
25-
// Sized to match the native structure
26-
_buffer = new byte[((size / IntPtr.Size) + 2) * IntPtr.Size]; // sizeof DWORD
17+
// Per https://learn.microsoft.com/windows/win32/api/ws2def/ns-ws2def-sockaddr,
18+
// use the SOCKADDR* pointer only to read the address family, then cast the pointer to
19+
// the appropriate family type and continue processing.
20+
return pSockaddr->sa_family switch
21+
{
22+
ADDRESS_FAMILY.AF_INET => new SocketAddressIPv4(*(SOCKADDR_IN*)pSockaddr),
23+
ADDRESS_FAMILY.AF_INET6 => new SocketAddressIPv6(*(SOCKADDR_IN6*)pSockaddr),
24+
_ => null
25+
};
2726
}
2827

29-
internal AddressFamily Family { get; }
30-
31-
internal int GetPort()
28+
private sealed class SocketAddressIPv4 : SocketAddress
3229
{
33-
return (_buffer[2] << 8 & 0xFF00) | (_buffer[3]);
34-
}
30+
private readonly SOCKADDR_IN _sockaddr;
3531

36-
internal IPAddress? GetIPAddress()
37-
{
38-
if (Family == AddressFamily.InterNetworkV6)
32+
internal SocketAddressIPv4(in SOCKADDR_IN sockaddr)
3933
{
40-
return GetIpv6Address();
34+
_sockaddr = sockaddr;
4135
}
42-
else if (Family == AddressFamily.InterNetwork)
36+
37+
internal override int GetPort()
4338
{
44-
return GetIPv4Address();
39+
// sin_port is network byte order
40+
return IPAddress.NetworkToHostOrder(_sockaddr.sin_port);
4541
}
46-
else
42+
43+
internal override IPAddress? GetIPAddress()
4744
{
48-
return null;
45+
// address is network byte order
46+
return new IPAddress(_sockaddr.sin_addr.S_un.S_addr);
4947
}
5048
}
5149

52-
private IPAddress GetIpv6Address()
53-
{
54-
Contract.Assert(_size >= IPv6AddressSize);
55-
var bytes = new byte[NumberOfIPv6Labels * 2];
56-
Array.Copy(_buffer, 8, bytes, 0, NumberOfIPv6Labels * 2);
57-
return new IPAddress(bytes); // TODO: Does scope id matter?
58-
}
59-
60-
private IPAddress GetIPv4Address()
50+
private sealed class SocketAddressIPv6 : SocketAddress
6151
{
62-
Contract.Assert(_size >= IPv4AddressSize);
63-
return new IPAddress(new byte[] { _buffer[4], _buffer[5], _buffer[6], _buffer[7] });
64-
}
52+
private readonly SOCKADDR_IN6 _sockaddr;
6553

66-
internal static unsafe SocketAddress? CopyOutAddress(IntPtr address)
67-
{
68-
AddressFamily family = (AddressFamily)(*((ushort*)address));
69-
int? addressSize = family switch
54+
internal SocketAddressIPv6(in SOCKADDR_IN6 sockaddr)
7055
{
71-
AddressFamily.InterNetwork => IPv4AddressSize,
72-
AddressFamily.InterNetworkV6 => IPv6AddressSize,
73-
_ => null
74-
};
56+
_sockaddr = sockaddr;
57+
}
7558

76-
if (!addressSize.HasValue)
59+
internal override int GetPort()
7760
{
78-
return null;
61+
// sin6_port is network byte order
62+
return IPAddress.NetworkToHostOrder(_sockaddr.sin6_port);
7963
}
8064

81-
var sockAddress = new SocketAddress(family, addressSize.Value);
82-
new ReadOnlySpan<byte>((byte*)address, addressSize.Value).Slice(sizeof(ushort)).CopyTo(sockAddress._buffer.AsSpan(sizeof(ushort)));
83-
return sockAddress;
65+
internal override IPAddress? GetIPAddress()
66+
{
67+
// address is network byte order
68+
// when CsWin32 gets support for inline arrays, remove 'AsReadOnlySpan' call below.
69+
// https://github.com/microsoft/CsWin32/issues/1086
70+
return new IPAddress(_sockaddr.sin6_addr.u.Byte.AsReadOnlySpan()); // TODO: Does scope id matter?
71+
}
8472
}
8573
}

src/Shared/HttpSys/RequestProcessing/NativeRequestContext.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,14 +650,14 @@ private void GetUnknownHeadersHelper(IDictionary<string, StringValues> unknownHe
650650

651651
private SocketAddress? GetEndPointHelper(bool localEndpoint, HTTP_REQUEST_V1* request, byte* pMemoryBlob)
652652
{
653-
var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress;
653+
var source = localEndpoint ? request->Address.pLocalAddress : request->Address.pRemoteAddress;
654654

655655
if (source == null)
656656
{
657657
return null;
658658
}
659-
var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source);
660-
return SocketAddress.CopyOutAddress(address);
659+
660+
return SocketAddress.CopyOutAddress(source);
661661
}
662662

663663
internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
// https://github.com/microsoft/cswin32
22
Windows.Win32.Networking.HttpServer
3+
SOCKADDR_IN
4+
SOCKADDR_IN6

0 commit comments

Comments
 (0)