Skip to content

Commit 63f539d

Browse files
committed
Add Socket Polyfills
1 parent 7600a6b commit 63f539d

File tree

24 files changed

+2536
-0
lines changed

24 files changed

+2536
-0
lines changed

src/Consume/Consume.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// used to confirm that all the Polyfilled API actually exist and compile on all target frameworks
2+
3+
14
// ReSharper disable RedundantUsingDirective
25
// ReSharper disable RedundantAssignment
36
// ReSharper disable UnusedVariable
@@ -494,6 +497,19 @@ void HttpContent_Methods(ByteArrayContent target)
494497
}
495498
#endif
496499

500+
#if FeatureValueTask && FeatureMemory
501+
async Task Socket_Methods()
502+
{
503+
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
504+
var endpoint = new IPEndPoint(IPAddress.Loopback, 12345);
505+
await socket.ConnectAsync(endpoint, CancellationToken.None);
506+
var sendBuffer = new ReadOnlyMemory<byte>(new byte[] { 1, 2, 3 });
507+
await socket.SendAsync(sendBuffer, SocketFlags.None, CancellationToken.None);
508+
var receiveBuffer = new Memory<byte>(new byte[10]);
509+
await socket.ReceiveAsync(receiveBuffer, SocketFlags.None, CancellationToken.None);
510+
}
511+
#endif
512+
497513
#if FeatureValueTask
498514
async Task TcpClient_Methods()
499515
{

src/Polyfill/Polyfill_Socket.cs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#if FeatureMemory && FeatureValueTask
2+
3+
namespace Polyfills;
4+
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
static partial class Polyfill
12+
{
13+
/// <summary>
14+
/// Sends data asynchronously from the specified buffer and monitors cancellation requests.
15+
/// </summary>
16+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.sendasync?view=net-10.0
17+
public static ValueTask<int> SendAsync(this Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
18+
{
19+
if (cancellationToken.IsCancellationRequested)
20+
{
21+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
22+
}
23+
24+
return new ValueTask<int>(SendWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
25+
}
26+
27+
static async Task<int> SendWithCancellationAsync(Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
28+
{
29+
using var registration = cancellationToken.Register(() => target.Close());
30+
try
31+
{
32+
var bytes = buffer.ToArray();
33+
// Use synchronous send wrapped in Task to provide a task-based API on older frameworks.
34+
return await Task.FromResult(target.Send(bytes, 0, bytes.Length, socketFlags));
35+
}
36+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
37+
{
38+
throw new OperationCanceledException(cancellationToken);
39+
}
40+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
41+
{
42+
throw new OperationCanceledException(cancellationToken);
43+
}
44+
}
45+
46+
/// <summary>
47+
/// Receives data asynchronously into the specified buffer and monitors cancellation requests.
48+
/// </summary>
49+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receiveasync?view=net-10.0
50+
public static ValueTask<int> ReceiveAsync(this Socket target, Memory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
51+
{
52+
if (cancellationToken.IsCancellationRequested)
53+
{
54+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
55+
}
56+
57+
return new ValueTask<int>(ReceiveWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
58+
}
59+
60+
static async Task<int> ReceiveWithCancellationAsync(Socket target, Memory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
61+
{
62+
using var registration = cancellationToken.Register(() => target.Close());
63+
try
64+
{
65+
var tmp = new byte[buffer.Length];
66+
int received = target.Receive(tmp, 0, tmp.Length, socketFlags);
67+
if (received > 0)
68+
{
69+
tmp.AsSpan(0, received).CopyTo(buffer.Span);
70+
}
71+
72+
return await Task.FromResult(received);
73+
}
74+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
75+
{
76+
throw new OperationCanceledException(cancellationToken);
77+
}
78+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
79+
{
80+
throw new OperationCanceledException(cancellationToken);
81+
}
82+
}
83+
84+
#if FeatureValueTask
85+
/// <summary>
86+
/// Connects the socket to a remote endpoint and monitors cancellation requests.
87+
/// </summary>
88+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.connectasync?view=net-10.0
89+
public static ValueTask ConnectAsync(this Socket target, EndPoint remoteEP, CancellationToken cancellationToken = default)
90+
{
91+
if (cancellationToken.IsCancellationRequested)
92+
{
93+
return new ValueTask(Task.FromCanceled(cancellationToken));
94+
}
95+
96+
return new ValueTask(ConnectWithCancellationAsync(target, remoteEP, cancellationToken));
97+
}
98+
99+
static async Task ConnectWithCancellationAsync(Socket target, EndPoint remoteEP, CancellationToken cancellationToken)
100+
{
101+
using var registration = cancellationToken.Register(() => target.Close());
102+
try
103+
{
104+
// Use synchronous Connect wrapped as a task on older frameworks.
105+
await Task.Run(() => target.Connect(remoteEP)).ConfigureAwait(false);
106+
}
107+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
108+
{
109+
throw new OperationCanceledException(cancellationToken);
110+
}
111+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
112+
{
113+
throw new OperationCanceledException(cancellationToken);
114+
}
115+
}
116+
#endif
117+
}
118+
#endif
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureMemory && FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Sends data asynchronously from the specified buffer and monitors cancellation requests.
14+
/// </summary>
15+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.sendasync?view=net-10.0
16+
public static ValueTask<int> SendAsync(this Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
17+
{
18+
if (cancellationToken.IsCancellationRequested)
19+
{
20+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
21+
}
22+
return new ValueTask<int>(SendWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
23+
}
24+
static async Task<int> SendWithCancellationAsync(Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
25+
{
26+
using var registration = cancellationToken.Register(() => target.Close());
27+
try
28+
{
29+
var bytes = buffer.ToArray();
30+
// Use synchronous send wrapped in Task to provide a task-based API on older frameworks.
31+
return await Task.FromResult(target.Send(bytes, 0, bytes.Length, socketFlags));
32+
}
33+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
34+
{
35+
throw new OperationCanceledException(cancellationToken);
36+
}
37+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
38+
{
39+
throw new OperationCanceledException(cancellationToken);
40+
}
41+
}
42+
/// <summary>
43+
/// Receives data asynchronously into the specified buffer and monitors cancellation requests.
44+
/// </summary>
45+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receiveasync?view=net-10.0
46+
public static ValueTask<int> ReceiveAsync(this Socket target, Memory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
47+
{
48+
if (cancellationToken.IsCancellationRequested)
49+
{
50+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
51+
}
52+
return new ValueTask<int>(ReceiveWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
53+
}
54+
static async Task<int> ReceiveWithCancellationAsync(Socket target, Memory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
55+
{
56+
using var registration = cancellationToken.Register(() => target.Close());
57+
try
58+
{
59+
var tmp = new byte[buffer.Length];
60+
int received = target.Receive(tmp, 0, tmp.Length, socketFlags);
61+
if (received > 0)
62+
{
63+
tmp.AsSpan(0, received).CopyTo(buffer.Span);
64+
}
65+
return await Task.FromResult(received);
66+
}
67+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
68+
{
69+
throw new OperationCanceledException(cancellationToken);
70+
}
71+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
72+
{
73+
throw new OperationCanceledException(cancellationToken);
74+
}
75+
}
76+
#if FeatureValueTask
77+
/// <summary>
78+
/// Connects the socket to a remote endpoint and monitors cancellation requests.
79+
/// </summary>
80+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.connectasync?view=net-10.0
81+
public static ValueTask ConnectAsync(this Socket target, EndPoint remoteEP, CancellationToken cancellationToken = default)
82+
{
83+
if (cancellationToken.IsCancellationRequested)
84+
{
85+
return new ValueTask(Task.FromCanceled(cancellationToken));
86+
}
87+
return new ValueTask(ConnectWithCancellationAsync(target, remoteEP, cancellationToken));
88+
}
89+
static async Task ConnectWithCancellationAsync(Socket target, EndPoint remoteEP, CancellationToken cancellationToken)
90+
{
91+
using var registration = cancellationToken.Register(() => target.Close());
92+
try
93+
{
94+
// Use synchronous Connect wrapped as a task on older frameworks.
95+
await Task.Run(() => target.Connect(remoteEP)).ConfigureAwait(false);
96+
}
97+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
98+
{
99+
throw new OperationCanceledException(cancellationToken);
100+
}
101+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
102+
{
103+
throw new OperationCanceledException(cancellationToken);
104+
}
105+
}
106+
#endif
107+
}
108+
#endif
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureMemory && FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Sends data asynchronously from the specified buffer and monitors cancellation requests.
14+
/// </summary>
15+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.sendasync?view=net-10.0
16+
public static ValueTask<int> SendAsync(this Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
17+
{
18+
if (cancellationToken.IsCancellationRequested)
19+
{
20+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
21+
}
22+
return new ValueTask<int>(SendWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
23+
}
24+
static async Task<int> SendWithCancellationAsync(Socket target, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
25+
{
26+
using var registration = cancellationToken.Register(() => target.Close());
27+
try
28+
{
29+
var bytes = buffer.ToArray();
30+
// Use synchronous send wrapped in Task to provide a task-based API on older frameworks.
31+
return await Task.FromResult(target.Send(bytes, 0, bytes.Length, socketFlags));
32+
}
33+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
34+
{
35+
throw new OperationCanceledException(cancellationToken);
36+
}
37+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
38+
{
39+
throw new OperationCanceledException(cancellationToken);
40+
}
41+
}
42+
/// <summary>
43+
/// Receives data asynchronously into the specified buffer and monitors cancellation requests.
44+
/// </summary>
45+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receiveasync?view=net-10.0
46+
public static ValueTask<int> ReceiveAsync(this Socket target, Memory<byte> buffer, SocketFlags socketFlags = SocketFlags.None, CancellationToken cancellationToken = default)
47+
{
48+
if (cancellationToken.IsCancellationRequested)
49+
{
50+
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
51+
}
52+
return new ValueTask<int>(ReceiveWithCancellationAsync(target, buffer, socketFlags, cancellationToken));
53+
}
54+
static async Task<int> ReceiveWithCancellationAsync(Socket target, Memory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
55+
{
56+
using var registration = cancellationToken.Register(() => target.Close());
57+
try
58+
{
59+
var tmp = new byte[buffer.Length];
60+
int received = target.Receive(tmp, 0, tmp.Length, socketFlags);
61+
if (received > 0)
62+
{
63+
tmp.AsSpan(0, received).CopyTo(buffer.Span);
64+
}
65+
return await Task.FromResult(received);
66+
}
67+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
68+
{
69+
throw new OperationCanceledException(cancellationToken);
70+
}
71+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
72+
{
73+
throw new OperationCanceledException(cancellationToken);
74+
}
75+
}
76+
#if FeatureValueTask
77+
/// <summary>
78+
/// Connects the socket to a remote endpoint and monitors cancellation requests.
79+
/// </summary>
80+
// Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.connectasync?view=net-10.0
81+
public static ValueTask ConnectAsync(this Socket target, EndPoint remoteEP, CancellationToken cancellationToken = default)
82+
{
83+
if (cancellationToken.IsCancellationRequested)
84+
{
85+
return new ValueTask(Task.FromCanceled(cancellationToken));
86+
}
87+
return new ValueTask(ConnectWithCancellationAsync(target, remoteEP, cancellationToken));
88+
}
89+
static async Task ConnectWithCancellationAsync(Socket target, EndPoint remoteEP, CancellationToken cancellationToken)
90+
{
91+
using var registration = cancellationToken.Register(() => target.Close());
92+
try
93+
{
94+
// Use synchronous Connect wrapped as a task on older frameworks.
95+
await Task.Run(() => target.Connect(remoteEP)).ConfigureAwait(false);
96+
}
97+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
98+
{
99+
throw new OperationCanceledException(cancellationToken);
100+
}
101+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
102+
{
103+
throw new OperationCanceledException(cancellationToken);
104+
}
105+
}
106+
#endif
107+
}
108+
#endif

0 commit comments

Comments
 (0)