Skip to content

Commit 1c4add8

Browse files
Christoph BauerChristoph Bauer
Christoph Bauer
authored and
Christoph Bauer
committed
Tcp Keepalive for Linux (NET8.0)
New Target .NET 8.0 Fixes setup of Tcp Keepalive under Linux
1 parent 0af4d61 commit 1c4add8

23 files changed

+95
-83
lines changed

src/NetMQ.Tests/ClientServer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public async void AsyncWithCancellationToken()
8282
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReceiveStringAsync(source.Token));
8383
}
8484

85-
#if NETCOREAPP3_1
85+
#if NET8_0_OR_GREATER
8686

8787
[Fact(Timeout = 120)]
8888
public async void AsyncEnumerableCanceled()

src/NetMQ/Annotations.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.
22

3-
#if !NETSTANDARD2_1
3+
#if !NETSTANDARD2_1 && !NET8_0_OR_GREATER
44

55
namespace System.Diagnostics.CodeAnalysis
66
{

src/NetMQ/AsyncReceiveExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
1+
#if NET8_0_OR_GREATER || NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
22

33
using System;
44
using System.Collections.Generic;

src/NetMQ/Core/Mechanisms/CurveClientMechanism.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ PullMsgResult ProduceInitiate(ref Msg msg)
189189

190190
VouchNoncePrefix.CopyTo(vouchNonce);
191191
using var rng = RandomNumberGenerator.Create();
192-
#if NETSTANDARD2_1
192+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
193193
rng.GetBytes(vouchNonce.Slice(8));
194194
#else
195195
byte[] temp = new byte[16];

src/NetMQ/Core/Mechanisms/CurveServerMechanism.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ PullMsgResult ProduceWelcome(ref Msg msg)
157157
// 8-byte prefix plus 16-byte random nonce
158158
CookieNoncePrefix.CopyTo(cookieNonce);
159159
using var rng = RandomNumberGenerator.Create();
160-
#if NETSTANDARD2_1
160+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
161161
rng.GetBytes(cookieNonce.Slice(8));
162162
#else
163163
byte[] temp = new byte[16];
@@ -184,7 +184,7 @@ PullMsgResult ProduceWelcome(ref Msg msg)
184184
// Create full nonce for encryption
185185
// 8-byte prefix plus 16-byte random nonce
186186
WelcomeNoncePrefix.CopyTo(welcomeNonce);
187-
#if NETSTANDARD2_1
187+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
188188
rng.GetBytes(welcomeNonce.Slice(8));
189189
#else
190190
rng.GetBytes(temp);

src/NetMQ/Core/Transports/Pgm/PgmSocket.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ internal void Init()
9797
Debug.WriteLine(xMsg);
9898

9999
// If running on Microsoft Windows, suggest to the developer that he may need to install MSMQ in order to get PGM socket support.
100-
#if NETSTANDARD1_1_OR_GREATER
100+
#if NET8_0_OR_GREATER || NETSTANDARD1_1_OR_GREATER
101101
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
102102
#else
103103
bool isWindows = true;

src/NetMQ/Core/Transports/Tcp/TcpConnector.cs

+8
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@ public void OutCompleted(SocketError socketError, int bytesTransferred)
248248
// Set the TCP keep-alive option values to the underlying socket.
249249
m_s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, m_options.TcpKeepalive);
250250

251+
252+
#if NET8_0_OR_GREATER
253+
if (m_options.TcpKeepaliveIdle != -1)
254+
m_s.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, m_options.TcpKeepaliveIdle / 1000);
255+
if (m_options.TcpKeepaliveIntvl != -1)
256+
m_s.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, m_options.TcpKeepaliveIntvl / 1000);
257+
#else
251258
if (m_options.TcpKeepaliveIdle != -1 && m_options.TcpKeepaliveIntvl != -1)
252259
{
253260
// Write the TCP keep-alive options to a byte-array, to feed to the IOControl method..
@@ -261,6 +268,7 @@ public void OutCompleted(SocketError socketError, int bytesTransferred)
261268

262269
m_s.IOControl(IOControlCode.KeepAliveValues, (byte[])bytes, null);
263270
}
271+
#endif
264272
}
265273

266274
// Create the engine object for this connection.

src/NetMQ/Core/Transports/Tcp/TcpListener.cs

+58-50
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ You should have received a copy of the GNU Lesser General Public License
2222
using System;
2323
using System.Diagnostics;
2424
using System.Net.Sockets;
25-
#if NETSTANDARD2_0 || NETSTANDARD2_1
25+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
2626
using System.Runtime.InteropServices;
2727
#endif
2828
using AsyncIO;
@@ -45,12 +45,12 @@ internal class TcpListener : Own, IProactorEvents
4545
/// </summary>
4646
private AsyncSocket? m_handle;
4747

48-
/*
49-
/// <summary>
50-
/// socket being accepted
51-
/// </summary>
52-
private AsyncSocket m_acceptedSocket;
53-
*/
48+
/*
49+
/// <summary>
50+
/// socket being accepted
51+
/// </summary>
52+
private AsyncSocket m_acceptedSocket;
53+
*/
5454

5555
/// <summary>
5656
/// Socket the listener belongs to.
@@ -107,7 +107,7 @@ protected override void ProcessPlug()
107107
protected override void ProcessTerm(int linger)
108108
{
109109
Assumes.NotNull(m_handle);
110-
110+
111111
m_ioObject.SetHandler(this);
112112
m_ioObject.RemoveSocket(m_handle);
113113
Close();
@@ -141,7 +141,7 @@ public virtual void SetAddress(string addr)
141141
}
142142
}
143143

144-
#if NETSTANDARD2_0 || NETSTANDARD2_1
144+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1
145145
// This command is failing on linux
146146
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
147147
m_handle.ExclusiveAddressUse = false;
@@ -194,68 +194,76 @@ public void InCompleted(SocketError socketError, int bytesTransferred)
194194
switch (socketError)
195195
{
196196
case SocketError.Success:
197-
{
198-
// TODO: check TcpFilters
199-
var acceptedSocket = m_handle.GetAcceptedSocket();
197+
{
198+
// TODO: check TcpFilters
199+
var acceptedSocket = m_handle.GetAcceptedSocket();
200200

201201
acceptedSocket.NoDelay = true;
202202

203-
if (m_options.TcpKeepalive != -1)
204-
{
205-
acceptedSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, m_options.TcpKeepalive);
206-
207-
if (m_options.TcpKeepaliveIdle != -1 && m_options.TcpKeepaliveIntvl != -1)
203+
if (m_options.TcpKeepalive != -1)
208204
{
209-
var bytes = new ByteArraySegment(new byte[12]);
205+
acceptedSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, m_options.TcpKeepalive);
206+
#if NET8_0_OR_GREATER
207+
if (m_options.TcpKeepaliveIdle != -1)
208+
acceptedSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, m_options.TcpKeepaliveIdle / 1000);
209+
if (m_options.TcpKeepaliveIntvl != -1)
210+
acceptedSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, m_options.TcpKeepaliveIntvl / 1000);
211+
#else
212+
213+
if (m_options.TcpKeepaliveIdle != -1 && m_options.TcpKeepaliveIntvl != -1)
214+
{
215+
var bytes = new ByteArraySegment(new byte[12]);
216+
217+
Endianness endian = BitConverter.IsLittleEndian ? Endianness.Little : Endianness.Big;
210218

211-
Endianness endian = BitConverter.IsLittleEndian ? Endianness.Little : Endianness.Big;
219+
bytes.PutInteger(endian, m_options.TcpKeepalive, 0);
220+
bytes.PutInteger(endian, m_options.TcpKeepaliveIdle, 4);
221+
bytes.PutInteger(endian, m_options.TcpKeepaliveIntvl, 8);
212222

213-
bytes.PutInteger(endian, m_options.TcpKeepalive, 0);
214-
bytes.PutInteger(endian, m_options.TcpKeepaliveIdle, 4);
215-
bytes.PutInteger(endian, m_options.TcpKeepaliveIntvl, 8);
223+
acceptedSocket.IOControl(IOControlCode.KeepAliveValues, (byte[])bytes, null);
224+
}
225+
#endif
216226

217-
acceptedSocket.IOControl(IOControlCode.KeepAliveValues, (byte[])bytes, null);
218227
}
219-
}
220228

221-
// Create the engine object for this connection.
222-
var engine = new StreamEngine(acceptedSocket, m_options, m_endpoint);
229+
// Create the engine object for this connection.
230+
var engine = new StreamEngine(acceptedSocket, m_options, m_endpoint);
223231

224-
// Choose I/O thread to run connector in. Given that we are already
225-
// running in an I/O thread, there must be at least one available.
226-
IOThread? ioThread = ChooseIOThread(m_options.Affinity);
232+
// Choose I/O thread to run connector in. Given that we are already
233+
// running in an I/O thread, there must be at least one available.
234+
IOThread? ioThread = ChooseIOThread(m_options.Affinity);
227235

228-
Assumes.NotNull(ioThread);
236+
Assumes.NotNull(ioThread);
229237

230-
// Create and launch a session object.
231-
// TODO: send null in address parameter, is unneeded in this case
232-
SessionBase session = SessionBase.Create(ioThread, false, m_socket, m_options, new Address(m_handle.LocalEndPoint));
233-
session.IncSeqnum();
234-
LaunchChild(session);
238+
// Create and launch a session object.
239+
// TODO: send null in address parameter, is unneeded in this case
240+
SessionBase session = SessionBase.Create(ioThread, false, m_socket, m_options, new Address(m_handle.LocalEndPoint));
241+
session.IncSeqnum();
242+
LaunchChild(session);
235243

236-
SendAttach(session, engine, false);
244+
SendAttach(session, engine, false);
237245

238-
m_socket.EventAccepted(m_endpoint, acceptedSocket);
246+
m_socket.EventAccepted(m_endpoint, acceptedSocket);
239247

240-
Accept();
241-
break;
242-
}
248+
Accept();
249+
break;
250+
}
243251
case SocketError.ConnectionReset:
244252
case SocketError.NoBufferSpaceAvailable:
245253
case SocketError.TooManyOpenSockets:
246-
{
247-
m_socket.EventAcceptFailed(m_endpoint, socketError.ToErrorCode());
254+
{
255+
m_socket.EventAcceptFailed(m_endpoint, socketError.ToErrorCode());
248256

249-
Accept();
250-
break;
251-
}
257+
Accept();
258+
break;
259+
}
252260
default:
253-
{
254-
NetMQException exception = NetMQException.Create(socketError);
261+
{
262+
NetMQException exception = NetMQException.Create(socketError);
255263

256-
m_socket.EventAcceptFailed(m_endpoint, exception.ErrorCode);
257-
throw exception;
258-
}
264+
m_socket.EventAcceptFailed(m_endpoint, exception.ErrorCode);
265+
throw exception;
266+
}
259267
}
260268
}
261269

src/NetMQ/Core/Utils/OpCode.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static bool Open()
2020
string val = Environment.GetEnvironmentVariable("NETQM_SUPPRESS_RDTSC");
2121
if (!string.IsNullOrEmpty(val))
2222
return false;
23-
#if NETSTANDARD1_1_OR_GREATER || NET471_OR_GREATER
23+
#if NET8_0_OR_GREATER || NETSTANDARD1_1_OR_GREATER || NET471_OR_GREATER
2424
if (RuntimeInformation.ProcessArchitecture != Architecture.X86 &&
2525
RuntimeInformation.ProcessArchitecture != Architecture.X64)
2626
{

src/NetMQ/Core/Utils/SpanUtility.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ internal static class SpanUtility
77
{
88
public static string ToAscii(Span<byte> bytes)
99
{
10-
#if NETSTANDARD2_1
10+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
1111
return Encoding.ASCII.GetString(bytes);
1212
#else
1313
return Encoding.ASCII.GetString(bytes.ToArray());

src/NetMQ/GroupSocketExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ public static bool TryReceiveBytes(this IGroupInSocket socket, TimeSpan timeout,
376376

377377
#region AsyncEnumerable
378378

379-
#if NETSTANDARD2_1
379+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
380380
/// <summary>
381381
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.
382382
/// </summary>
@@ -575,7 +575,7 @@ public static bool TryReceiveString(this IGroupInSocket socket, TimeSpan timeout
575575

576576
#region AsyncEnumerable
577577

578-
#if NETSTANDARD2_1
578+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
579579
/// <summary>
580580
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.
581581
/// </summary>

src/NetMQ/NetMQ.csproj

+3-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<Description>A 100% native C# port of the lightweight high performance messaging library ZeroMQ</Description>
55
<Version>4.0.0.0</Version>
6-
<TargetFrameworks>net47;netstandard2.1</TargetFrameworks>
6+
<TargetFrameworks>net47;netstandard21;net8.0</TargetFrameworks>
77
<DebugType>portable</DebugType>
88
<AssemblyOriginatorKeyFile>./NetMQ.snk</AssemblyOriginatorKeyFile>
99
<SignAssembly>true</SignAssembly>
@@ -38,12 +38,8 @@
3838
<PackageReference Include="NaCl.Net" Version="0.1.13" />
3939
</ItemGroup>
4040

41-
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
42-
<PackageReference Include="System.ServiceModel.Primitives" Version="8.1.1" />
43-
</ItemGroup>
44-
45-
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
46-
<PackageReference Include="System.ServiceModel.Primitives" Version="8.1.1" />
41+
<ItemGroup Condition=" '$(TargetFramework)' != '.NETFramework' ">
42+
<PackageReference Include="System.ServiceModel.Primitives" Version="8.1.2" />
4743
</ItemGroup>
4844

4945
<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' ">

src/NetMQ/NetMQRuntime.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
1+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
22

33
using System;
44
using System.Threading;

src/NetMQ/NetMQSocket.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public abstract class NetMQSocket : INetMQSocket
2525
private EventHandler<NetMQSocketEventArgs>? m_sendReady;
2626
private int m_isClosed;
2727

28-
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
28+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
2929
private NetMQRuntime? m_runtime;
3030
#endif
3131

@@ -249,7 +249,7 @@ public void Unbind(string address)
249249
/// <summary>Closes this socket, rendering it unusable. Equivalent to calling <see cref="Dispose()"/>.</summary>
250250
public void Close()
251251
{
252-
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
252+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
253253
if (m_runtime != null)
254254
{
255255
m_runtime.Remove(this);
@@ -391,7 +391,7 @@ public virtual bool TrySend(ref Msg msg, TimeSpan timeout, bool more)
391391

392392
#endregion
393393

394-
#if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
394+
#if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
395395

396396
internal void AttachToRuntime()
397397
{

src/NetMQ/ReceiveThreadSafeSocketExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public static ValueTask<byte[]> ReceiveBytesAsync(this IThreadSafeInSocket socke
119119

120120
#region AsyncEnumerable
121121

122-
#if NETSTANDARD2_1
122+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
123123

124124
/// <summary>
125125
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.
@@ -302,7 +302,7 @@ public static ValueTask<string> ReceiveStringAsync(this IThreadSafeInSocket sock
302302

303303
#region AsyncEnumerable
304304

305-
#if NETSTANDARD2_1
305+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
306306

307307
/// <summary>
308308
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.

src/NetMQ/RoutingIdSocketExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ public static bool TryReceiveBytes(this IRoutingIdSocket socket, TimeSpan timeou
372372

373373
#region AsyncEnumerable
374374

375-
#if NETSTANDARD2_1
375+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
376376

377377
/// <summary>
378378
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.
@@ -564,7 +564,7 @@ public static bool TryReceiveString(this IRoutingIdSocket socket, TimeSpan timeo
564564

565565
#region AsyncEnumerable
566566

567-
#if NETSTANDARD2_1
567+
#if NET8_0_OR_GREATER || NETSTANDARD2_1
568568

569569
/// <summary>
570570
/// Provides a consuming IAsyncEnumerable for receiving messages from the socket.

src/NetMQ/ThreadSafeSocket.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public void Unbind(string address)
200200
/// <summary>Closes this socket, rendering it unusable. Equivalent to calling <see cref="Dispose()"/>.</summary>
201201
public void Close()
202202
{
203-
// #if NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
203+
// #if NET8_0_OR_GREATER || NETSTANDARD2_0 || NETSTANDARD2_1 || NET47
204204
// if (m_runtime != null)
205205
// {
206206
// m_runtime.Remove(this);

src/NetMQ/Utils/EncodingExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#if !NETSTANDARD2_1
1+
#if !NETSTANDARD2_1 && !NET8_0_OR_GREATER
22
using System;
33
using System.Text;
44

src/Performance/NetMQ.SimpleTests/NetMQ.SimpleTests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<OutputType>Exe</OutputType>
66
</PropertyGroup>
77

0 commit comments

Comments
 (0)