Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add SendTo/ReceiveFrom with SocketAddress #88970

Merged
merged 18 commits into from
Aug 1, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static partial class Winsock
[LibraryImport(Interop.Libraries.Ws2_32, SetLastError = true)]
internal static partial SocketError WSAConnect(
SafeSocketHandle socketHandle,
byte[] socketAddress,
Span<byte> socketAddress,
Copy link
Member

@stephentoub stephentoub Aug 1, 2023

Choose a reason for hiding this comment

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

Should we make the actual LibraryImport private, with an internal wrapper that doesn't take socketAddressSize? e.g.

[LibraryImport(Interop.Libraries.Ws2_32, SetLastError = true)]
private static partial SocketError WSAConnect(
    SafeSocketHandle socketHandle,
    Span<byte> socketAddress,
    int socketAddressSize,
    IntPtr inBuffer,
    IntPtr outBuffer,
    IntPtr sQOS,
    IntPtr gQOS);

internal static SocketError WSAConnect(
    SafeSocketHandle socketHandle,
    Span<byte> socketAddress,
    IntPtr inBuffer,
    IntPtr outBuffer,
    IntPtr sQOS,
    IntPtr gQOS) =>
    WSAConnect(socketHandle, socketAddress, socketAddress.Length, inBuffer, outBuffer, sQOS, gQOS);

?

Though reading further that might make it a bit inconsistent with some of the other overloads. It's just a bit strange to see both the span and length passed in.

wfurt marked this conversation as resolved.
Show resolved Hide resolved
int socketAddressSize,
IntPtr inBuffer,
IntPtr outBuffer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static partial class Winsock
[LibraryImport(Interop.Libraries.Ws2_32, SetLastError = true)]
internal static partial IntPtr accept(
SafeSocketHandle socketHandle,
byte[] socketAddress,
Span<byte> socketAddress,
ref int socketAddressSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ internal static partial class Winsock
[LibraryImport(Interop.Libraries.Ws2_32, SetLastError = true)]
internal static unsafe partial int recvfrom(
SafeSocketHandle socketHandle,
byte* pinnedBuffer,
Span<byte> pinnedBuffer,
int len,
SocketFlags socketFlags,
byte[] socketAddress,
Span<byte> socketAddress,
ref int socketAddressSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal static unsafe partial int sendto(
byte* pinnedBuffer,
int len,
SocketFlags socketFlags,
byte[] socketAddress,
ReadOnlySpan<byte> socketAddress,
int socketAddressSize);
}
}
14 changes: 14 additions & 0 deletions src/libraries/Common/src/System/Net/SocketAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public int Size
{
return InternalSize;
}
set
{
ArgumentOutOfRangeException.ThrowIfGreaterThan(value, Buffer.Length);
wfurt marked this conversation as resolved.
Show resolved Hide resolved
InternalSize = value;
}
}

// Access to unmanaged serialized data. This doesn't
Expand Down Expand Up @@ -96,6 +101,7 @@ public SocketAddress(AddressFamily family, int size)
size = (size + IntPtr.Size - 1) / IntPtr.Size * IntPtr.Size + IntPtr.Size;
#endif
Buffer = new byte[size];
Buffer[0] = (byte)InternalSize;

SocketAddressPal.SetAddressFamily(Buffer, family);
}
Expand Down Expand Up @@ -139,6 +145,14 @@ internal SocketAddress(AddressFamily addressFamily, ReadOnlySpan<byte> buffer)
SocketAddressPal.SetAddressFamily(Buffer, addressFamily);
}

public Memory<byte> SocketBuffer
wfurt marked this conversation as resolved.
Show resolved Hide resolved
{
get
{
return new Memory<byte>(Buffer, 0, InternalSize);
}
}

internal IPAddress GetIPAddress()
{
if (Family == AddressFamily.InterNetworkV6)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,8 @@ public SocketAddress(System.Net.Sockets.AddressFamily family) { }
public SocketAddress(System.Net.Sockets.AddressFamily family, int size) { }
public System.Net.Sockets.AddressFamily Family { get { throw null; } }
public byte this[int offset] { get { throw null; } set { } }
public int Size { get { throw null; } }
public int Size { get { throw null; } set { } }
public System.Memory<byte> SocketBuffer { get { throw null; } }
public override bool Equals(object? comparand) { throw null; }
public override int GetHashCode() { throw null; }
public override string ToString() { throw null; }
Expand Down
10 changes: 8 additions & 2 deletions src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ public partial class LingerOption
public LingerOption(bool enable, int seconds) { }
public bool Enabled { get { throw null; } set { } }
public int LingerTime { get { throw null; } set { } }
public override bool Equals(object? comparand) { throw null; }
public override int GetHashCode() { throw null; }
}
public partial class MulticastOption
{
Expand Down Expand Up @@ -223,7 +225,7 @@ public enum ProtocolType
public sealed partial class SafeSocketHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
public SafeSocketHandle() : base (default(bool)) { }
public SafeSocketHandle(System.IntPtr preexistingHandle, bool ownsHandle) : base (default(bool)) { }
public SafeSocketHandle(nint preexistingHandle, bool ownsHandle) : base (default(bool)) { }
wfurt marked this conversation as resolved.
Show resolved Hide resolved
public override bool IsInvalid { get { throw null; } }
protected override bool ReleaseHandle() { throw null; }
}
Expand Down Expand Up @@ -272,7 +274,7 @@ public Socket(System.Net.Sockets.SocketType socketType, System.Net.Sockets.Proto
public bool DualMode { get { throw null; } set { } }
public bool EnableBroadcast { get { throw null; } set { } }
public bool ExclusiveAddressUse { get { throw null; } set { } }
public System.IntPtr Handle { get { throw null; } }
public nint Handle { get { throw null; } }
public bool IsBound { get { throw null; } }
[System.Diagnostics.CodeAnalysis.DisallowNullAttribute]
public System.Net.Sockets.LingerOption? LingerState { get { throw null; } set { } }
Expand Down Expand Up @@ -398,6 +400,7 @@ public void Listen(int backlog) { }
public int ReceiveFrom(byte[] buffer, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; }
public int ReceiveFrom(System.Span<byte> buffer, ref System.Net.EndPoint remoteEP) { throw null; }
public int ReceiveFrom(System.Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, ref System.Net.EndPoint remoteEP) { throw null; }
public int ReceiveFrom(System.Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress remoteSA) { throw null; }
public System.Threading.Tasks.Task<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.ArraySegment<byte> buffer, System.Net.EndPoint remoteEndPoint) { throw null; }
public System.Threading.Tasks.Task<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.ArraySegment<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint) { throw null; }
public System.Threading.Tasks.ValueTask<System.Net.Sockets.SocketReceiveFromResult> ReceiveFromAsync(System.Memory<byte> buffer, System.Net.EndPoint remoteEndPoint, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
Expand Down Expand Up @@ -442,6 +445,7 @@ public void SendFile(string? fileName, System.ReadOnlySpan<byte> preBuffer, Syst
public int SendTo(byte[] buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; }
public int SendTo(System.ReadOnlySpan<byte> buffer, System.Net.EndPoint remoteEP) { throw null; }
public int SendTo(System.ReadOnlySpan<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; }
public int SendTo(System.ReadOnlySpan<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.SocketAddress remoteSA) { throw null; }
public System.Threading.Tasks.Task<int> SendToAsync(System.ArraySegment<byte> buffer, System.Net.EndPoint remoteEP) { throw null; }
public System.Threading.Tasks.Task<int> SendToAsync(System.ArraySegment<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEP) { throw null; }
public bool SendToAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; }
Expand Down Expand Up @@ -811,6 +815,8 @@ public sealed partial class UnixDomainSocketEndPoint : System.Net.EndPoint
public UnixDomainSocketEndPoint(string path) { }
public override System.Net.Sockets.AddressFamily AddressFamily { get { throw null; } }
public override System.Net.EndPoint Create(System.Net.SocketAddress socketAddress) { throw null; }
public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public override System.Net.SocketAddress Serialize() { throw null; }
public override string ToString() { throw null; }
}
Expand Down
104 changes: 97 additions & 7 deletions src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1014,13 +1014,15 @@ public Socket Accept()
// This may throw ObjectDisposedException.
SafeSocketHandle acceptedSocketHandle;
SocketError errorCode;
int socketAddressLen;
try
{
errorCode = SocketPal.Accept(
_handle,
socketAddress.Buffer,
ref socketAddress.InternalSize,
socketAddress.SocketBuffer,
out socketAddressLen,
out acceptedSocketHandle);
socketAddress.Size = socketAddressLen;
}
catch (Exception ex)
{
Expand Down Expand Up @@ -1282,7 +1284,7 @@ public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags,
Internals.SocketAddress socketAddress = Serialize(ref remoteEP);

int bytesTransferred;
SocketError errorCode = SocketPal.SendTo(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, socketAddress.Size, out bytesTransferred);
SocketError errorCode = SocketPal.SendTo(_handle, buffer, offset, size, socketFlags, socketAddress.SocketBuffer, out bytesTransferred);

// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
Expand Down Expand Up @@ -1354,7 +1356,7 @@ public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags socketFlags, EndPoint r
Internals.SocketAddress socketAddress = Serialize(ref remoteEP);

int bytesTransferred;
SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.Buffer, socketAddress.Size, out bytesTransferred);
SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, socketAddress.SocketBuffer, out bytesTransferred);

// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
Expand All @@ -1375,6 +1377,42 @@ public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags socketFlags, EndPoint r
return bytesTransferred;
}

/// <summary>
/// Sends data to a specific endpoint using the specified <see cref="SocketFlags"/>.
/// </summary>
/// <param name="buffer">A span of bytes that contains the data to be sent.</param>
/// <param name="socketFlags">A bitwise combination of the <see cref="SocketFlags"/> values.</param>
/// <param name="remoteSA">The <see cref="EndPoint"/> that represents the destination for the data.</param>
/// <returns>The number of bytes sent.</returns>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is <see langword="null" />.</exception>
/// <exception cref="SocketException">An error occurred when attempting to access the socket.</exception>
/// <exception cref="ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags socketFlags, SocketAddress remoteSA)
wfurt marked this conversation as resolved.
Show resolved Hide resolved
{
ThrowIfDisposed();
ArgumentNullException.ThrowIfNull(remoteSA);

ValidateBlockingMode();

int bytesTransferred;
SocketError errorCode = SocketPal.SendTo(_handle, buffer, socketFlags, remoteSA.SocketBuffer, out bytesTransferred);

// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
UpdateSendSocketErrorForDisposed(ref errorCode);

UpdateStatusAfterSocketErrorAndThrowException(errorCode);
}
else if (SocketsTelemetry.Log.IsEnabled())
{
SocketsTelemetry.Log.BytesSent(bytesTransferred);
if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramSent();
}

return bytesTransferred;
}

// Receives data from a connected socket.
public int Receive(byte[] buffer, int size, SocketFlags socketFlags)
{
Expand Down Expand Up @@ -1681,7 +1719,7 @@ public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFl
Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);

int bytesTransferred;
SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, ref socketAddress.InternalSize, out bytesTransferred);
SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, offset, size, socketFlags, socketAddress.Buffer, out int socketAddressLength, out bytesTransferred);

UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred);
// If the native call fails we'll throw a SocketException.
Expand All @@ -1703,6 +1741,8 @@ public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFl
if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived();
}

socketAddress.Size = socketAddressLength;

if (!socketAddressOriginal.Equals(socketAddress))
{
try
Expand Down Expand Up @@ -1788,7 +1828,7 @@ public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, ref EndPoint
Internals.SocketAddress socketAddressOriginal = IPEndPointExtensions.Serialize(endPointSnapshot);

int bytesTransferred;
SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, socketAddress.Buffer, ref socketAddress.InternalSize, out bytesTransferred);
SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, socketAddress.Buffer, out int socketAddressLength, out bytesTransferred);

UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred);
// If the native call fails we'll throw a SocketException.
Expand All @@ -1810,6 +1850,7 @@ public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, ref EndPoint
if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived();
}

socketAddress.Size = socketAddressLength;
if (!socketAddressOriginal.Equals(socketAddress))
{
try
Expand Down Expand Up @@ -1840,6 +1881,55 @@ public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, ref EndPoint
return bytesTransferred;
}

/// <summary>
/// Receives a datagram into the data buffer, using the specified <see cref="SocketFlags"/>, and stores the endpoint.
/// </summary>
/// <param name="buffer">A span of bytes that is the storage location for received data.</param>
/// <param name="socketFlags">A bitwise combination of the <see cref="SocketFlags"/> values.</param>
/// <param name="remoteSA">An <see cref="SocketAddress"/>, passed by reference, that represents the remote server.</param>
/// <returns>The number of bytes received.</returns>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is <see langword="null" />.</exception>
/// <exception cref="SocketException">An error occurred when attempting to access the socket.</exception>
/// <exception cref="ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
public int ReceiveFrom(Span<byte> buffer, SocketFlags socketFlags, SocketAddress remoteSA)
wfurt marked this conversation as resolved.
Show resolved Hide resolved
{
ThrowIfDisposed();

ValidateBlockingMode();

int bytesTransferred;
SocketError errorCode = SocketPal.ReceiveFrom(_handle, buffer, socketFlags, remoteSA.SocketBuffer, out int socketAddressSize, out bytesTransferred);

UpdateReceiveSocketErrorForDisposed(ref errorCode, bytesTransferred);
// If the native call fails we'll throw a SocketException.
SocketException? socketException = null;
if (errorCode != SocketError.Success)
{
socketException = new SocketException((int)errorCode);
UpdateStatusAfterSocketError(socketException);
if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, socketException);

if (socketException.SocketErrorCode != SocketError.MessageSize)
{
throw socketException;
}
}
else if (SocketsTelemetry.Log.IsEnabled())
{
SocketsTelemetry.Log.BytesReceived(bytesTransferred);
if (SocketType == SocketType.Dgram) SocketsTelemetry.Log.DatagramReceived();
}

if (socketException != null)
{
throw socketException;
}
wfurt marked this conversation as resolved.
Show resolved Hide resolved

remoteSA.Size = socketAddressSize;

return bytesTransferred;
}

public int IOControl(int ioControlCode, byte[]? optionInValue, byte[]? optionOutValue)
{
ThrowIfDisposed();
Expand Down Expand Up @@ -3082,7 +3172,7 @@ private void DoConnect(EndPoint endPointSnapshot, Internals.SocketAddress socket
SocketError errorCode;
try
{
errorCode = SocketPal.Connect(_handle, socketAddress.Buffer, socketAddress.Size);
errorCode = SocketPal.Connect(_handle, socketAddress.SocketBuffer);
}
catch (Exception ex)
{
Expand Down
Loading
Loading