Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/libraries/Common/src/System/Net/SocketAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ public SocketAddress(AddressFamily family, int size)
}

InternalSize = size;
Buffer = new byte[(size / IntPtr.Size + 2) * IntPtr.Size];
#if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS
// WSARecvFrom needs a pinned pointer to the 32bit socket address size: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecvfrom
// Allocate IntPtr.Size extra bytes at the end of Buffer ensuring IntPtr.Size alignment, so we don't need to pin anything else.
// The following formula will extend 'size' to the alignment boundary then add IntPtr.Size more bytes.
size = (size + IntPtr.Size - 1) / IntPtr.Size * IntPtr.Size + IntPtr.Size;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

int Extend(int size) => (size + IntPtr.Size - 1) / IntPtr.Size * IntPtr.Size + IntPtr.Size;

for (int i = 10; i < 30; i++) Console.Write($"{i,2} | ");
Console.WriteLine();
for (int i = 10; i < 30; i++) Console.Write($"{Extend(i),2} | ");

Will print:

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
24 | 24 | 24 | 24 | 24 | 24 | 24 | 32 | 32 | 32 | 32 | 32 | 32 | 32 | 32 | 40 | 40 | 40 | 40 | 40 |

Copy link
Member

Choose a reason for hiding this comment

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

Right, the old code did

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
24 | 24 | 24 | 24 | 24 | 24 | 32 | 32 | 32 | 32 | 32 | 32 | 32 | 32 | 40 | 40 | 40 | 40 | 40 | 40 |

Sensible address structure would already be aligned IMHO and we really just need to put int on boundary of its size (e.g. 4) and we need to make sure it fits to the buffer. The new code does it and now we do it only for Windows where it is used.

#endif
Buffer = new byte[size];

SocketAddressPal.SetAddressFamily(Buffer, family);
}
Expand Down Expand Up @@ -171,20 +177,23 @@ internal IPEndPoint GetIPEndPoint()
return new IPEndPoint(GetIPAddress(), GetPort());
}

#if !SYSTEM_NET_PRIMITIVES_DLL && WINDOWS
// For ReceiveFrom we need to pin address size, using reserved Buffer space.
internal void CopyAddressSizeIntoBuffer()
{
Buffer[Buffer.Length - IntPtr.Size] = unchecked((byte)(InternalSize));
Buffer[Buffer.Length - IntPtr.Size + 1] = unchecked((byte)(InternalSize >> 8));
Buffer[Buffer.Length - IntPtr.Size + 2] = unchecked((byte)(InternalSize >> 16));
Buffer[Buffer.Length - IntPtr.Size + 3] = unchecked((byte)(InternalSize >> 24));
int addressSizeOffset = GetAddressSizeOffset();
Buffer[addressSizeOffset] = unchecked((byte)(InternalSize));
Buffer[addressSizeOffset + 1] = unchecked((byte)(InternalSize >> 8));
Buffer[addressSizeOffset + 2] = unchecked((byte)(InternalSize >> 16));
Buffer[addressSizeOffset + 3] = unchecked((byte)(InternalSize >> 24));
}

// Can be called after the above method did work.
internal int GetAddressSizeOffset()
{
return Buffer.Length - IntPtr.Size;
}
#endif

public override bool Equals(object? comparand) =>
comparand is SocketAddress other &&
Expand Down