Skip to content

Commit 1ab9ad0

Browse files
authored
Merge pull request #1132 from chrbauer/feature/linux-tcp-keepalive
Support Tcp KeepAlive under Linux (.net8 only)
2 parents 87dff51 + 28a4b2c commit 1ab9ad0

File tree

6 files changed

+52
-16
lines changed

6 files changed

+52
-16
lines changed

src/NetMQ.Tests/SocketOptionsTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ public void GetAndSetAllProperties()
7777
socket.Options.TcpKeepalive = true;
7878
Assert.True(socket.Options.TcpKeepalive);
7979

80-
// socket.Options.TcpKeepaliveCnt = 100;
81-
// Assert.Equal(100, socket.Options.TcpKeepaliveCnt);
80+
socket.Options.TcpKeepaliveCnt = 100;
81+
Assert.Equal(100, socket.Options.TcpKeepaliveCnt);
8282

8383
socket.Options.TcpKeepaliveIdle = TimeSpan.FromMilliseconds(100);
8484
Assert.Equal(TimeSpan.FromMilliseconds(100), socket.Options.TcpKeepaliveIdle);

src/NetMQ/Core/Options.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,10 @@ public void SetSocketOption(ZmqSocketOption option, object? optionValue)
452452
TcpKeepalive = tcpKeepalive;
453453
break;
454454

455+
case ZmqSocketOption.TcpKeepaliveCnt:
456+
TcpKeepaliveCnt = Get<int>();
457+
break;
458+
455459
case ZmqSocketOption.DelayAttachOnConnect:
456460
DelayAttachOnConnect = Get<bool>();
457461
break;
@@ -649,6 +653,9 @@ public void SetSocketOption(ZmqSocketOption option, object? optionValue)
649653
case ZmqSocketOption.TcpKeepalive:
650654
return TcpKeepalive;
651655

656+
case ZmqSocketOption.TcpKeepaliveCnt:
657+
return TcpKeepaliveCnt;
658+
652659
case ZmqSocketOption.DelayAttachOnConnect:
653660
return DelayAttachOnConnect;
654661

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@ 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+
#if NET
252+
if (m_options.TcpKeepaliveIdle != -1)
253+
m_s.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, m_options.TcpKeepaliveIdle / 1000);
254+
if (m_options.TcpKeepaliveIntvl != -1)
255+
m_s.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, m_options.TcpKeepaliveIntvl / 1000);
256+
if (m_options.TcpKeepaliveCnt != -1)
257+
m_s.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, m_options.TcpKeepaliveCnt);
258+
#else
251259
if (m_options.TcpKeepaliveIdle != -1 && m_options.TcpKeepaliveIntvl != -1)
252260
{
253261
// Write the TCP keep-alive options to a byte-array, to feed to the IOControl method..
@@ -259,16 +267,9 @@ public void OutCompleted(SocketError socketError, int bytesTransferred)
259267
bytes.PutInteger(endian, m_options.TcpKeepaliveIdle, 4);
260268
bytes.PutInteger(endian, m_options.TcpKeepaliveIntvl, 8);
261269

262-
#if NET
263-
if (!OperatingSystem.IsWindows())
264-
{
265-
throw new InvalidOperationException("Not supported on you platform"); // There is a pull request for .net8.0
266-
267-
}
268-
#endif
269270
m_s.IOControl(IOControlCode.KeepAliveValues, (byte[])bytes, null);
270-
271271
}
272+
#endif
272273
}
273274

274275
// Create the engine object for this connection.

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ public void InCompleted(SocketError socketError, int bytesTransferred)
204204
if (m_options.TcpKeepalive != -1)
205205
{
206206
acceptedSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, m_options.TcpKeepalive);
207+
#if NET
208+
if (m_options.TcpKeepaliveIdle != -1)
209+
acceptedSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, m_options.TcpKeepaliveIdle / 1000);
210+
if (m_options.TcpKeepaliveIntvl != -1)
211+
acceptedSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, m_options.TcpKeepaliveIntvl / 1000);
212+
if (m_options.TcpKeepaliveCnt != -1)
213+
acceptedSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, m_options.TcpKeepaliveCnt);
214+
#else
207215

208216
if (m_options.TcpKeepaliveIdle != -1 && m_options.TcpKeepaliveIntvl != -1)
209217
{
@@ -214,15 +222,11 @@ public void InCompleted(SocketError socketError, int bytesTransferred)
214222
bytes.PutInteger(endian, m_options.TcpKeepalive, 0);
215223
bytes.PutInteger(endian, m_options.TcpKeepaliveIdle, 4);
216224
bytes.PutInteger(endian, m_options.TcpKeepaliveIntvl, 8);
217-
#if NET
218-
if (!OperatingSystem.IsWindows())
219-
{
220-
throw new InvalidOperationException("Not supported on you platform"); // There is a pull request for .net8.0
221225

222-
}
223-
#endif
226+
224227
acceptedSocket.IOControl(IOControlCode.KeepAliveValues, (byte[])bytes, null);
225228
}
229+
#endif
226230
}
227231

228232
// Create the engine object for this connection.

src/NetMQ/Core/ZmqSocketOption.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,15 @@ internal enum ZmqSocketOption
197197
/// </summary>
198198
TcpKeepalive = 34,
199199

200+
/// <summary>
201+
/// The maximum number of keepalive probes TCP should send before dropping the connection.
202+
/// </summary>
203+
/// <remarks>
204+
/// This setting controls how many unacknowledged probes are sent before the connection is considered dead.
205+
/// A value of -1 (the default) means to use the OS default setting.
206+
/// </remarks>
207+
TcpKeepaliveCnt = 35,
208+
200209
/// <summary>
201210
/// The keep-alive time - the duration between two keepalive transmissions in idle condition.
202211
/// </summary>

src/NetMQ/SocketOptions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,21 @@ public bool TcpKeepalive
283283
// See http://api.zeromq.org/3-2:zmq-getsockopt
284284
}
285285

286+
287+
/// <summary>
288+
/// Get or set the maximum number of TCP keepalive probes to send before dropping the connection.
289+
/// </summary>
290+
/// <remarks>
291+
/// This value determines how many unacknowledged keepalive probes TCP should send before assuming the connection is dead.
292+
/// A lower value means faster detection of dead peers, while a higher value allows more tolerance for temporary disruptions.
293+
/// A value of -1 (the default) means to use the OS default setting.
294+
/// </remarks>
295+
public int TcpKeepaliveCnt
296+
{
297+
get => m_socket.GetSocketOption(ZmqSocketOption.TcpKeepaliveCnt);
298+
set => m_socket.SetSocketOption(ZmqSocketOption.TcpKeepaliveCnt, value);
299+
}
300+
286301
/// <summary>
287302
/// Get or set the keep-alive time - the duration between two keepalive transmissions in idle condition.
288303
/// The TCP keepalive period is required by socket implementers to be configurable and by default is

0 commit comments

Comments
 (0)