net: support TCP_KEEPINTVL and TCP_KEEPCNT in setKeepAlive · nodejs/node@45494d5 · GitHub
Skip to content

Commit 45494d5

Browse files
guybedfordaduh95
authored andcommitted
net: support TCP_KEEPINTVL and TCP_KEEPCNT in setKeepAlive
Signed-off-by: Guy Bedford <guybedford@gmail.com> PR-URL: #63825 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
1 parent 4438cb5 commit 45494d5

6 files changed

Lines changed: 215 additions & 23 deletions

File tree

doc/api/http.md

Lines changed: 2 additions & 2 deletions

doc/api/net.md

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,11 +1378,76 @@ added: v0.1.90
13781378
Set the encoding for the socket as a [Readable Stream][]. See
13791379
[`readable.setEncoding()`][] for more information.
13801380

1381-
### `socket.setKeepAlive([enable][, initialDelay])`
1381+
### `socket.setKeepAlive()`
1382+
1383+
Enable/disable keep-alive functionality, and optionally configure the
1384+
keepalive probe timing. Returns the socket itself.
1385+
1386+
Possible signatures:
1387+
1388+
* [`socket.setKeepAlive([options])`][`socket.setKeepAlive(options)`]
1389+
* [`socket.setKeepAlive([enable][, initialDelay][, interval][, count])`][`socket.setKeepAlive(enable)`]
1390+
1391+
Enabling keep-alive sets the initial delay before the first keepalive probe is
1392+
sent on an idle socket.
1393+
1394+
Set `initialDelay` (in milliseconds) to set the delay between the last
1395+
data packet received and the first keepalive probe. Setting `0` for
1396+
`initialDelay` will leave the value unchanged from the default
1397+
(or previous) setting.
1398+
1399+
Set `interval` (in milliseconds) to set the delay between successive
1400+
keepalive probes once they begin (`TCP_KEEPINTVL`). Set `count` to the
1401+
number of unacknowledged probes sent before the connection is dropped
1402+
(`TCP_KEEPCNT`). Both are only applied when keep-alive is enabled.
1403+
Omitting `interval` or `count` uses the defaults of `1000` ms and `10`.
1404+
As with `initialDelay`, a non-positive `interval` or `count` leaves the
1405+
corresponding system default unchanged.
1406+
1407+
`initialDelay` and `interval` are specified in milliseconds but the
1408+
underlying socket options are configured in whole seconds; the values are
1409+
divided by `1000` and rounded down before being applied.
1410+
1411+
Enabling the keep-alive functionality will set the following socket options:
1412+
1413+
* `SO_KEEPALIVE=1`
1414+
* `TCP_KEEPIDLE=initialDelay / 1000`
1415+
* `TCP_KEEPCNT=count`
1416+
* `TCP_KEEPINTVL=interval / 1000`
1417+
1418+
On Windows versions older than build 1709, keep-alive is configured through
1419+
`SIO_KEEPALIVE_VALS`, which has no probe-count field, so `count` is ignored on
1420+
those platforms.
1421+
1422+
#### `socket.setKeepAlive([options])`
1423+
1424+
<!-- YAML
1425+
added: REPLACEME
1426+
-->
1427+
1428+
* `options` {Object}
1429+
* `enable` {boolean} **Default:** `false`
1430+
* `initialDelay` {number} **Default:** `0`
1431+
* `interval` {number} **Default:** `1000`
1432+
* `count` {number} **Default:** `10`
1433+
* Returns: {net.Socket} The socket itself.
1434+
1435+
Configure keep-alive using an options object. See [`socket.setKeepAlive()`][]
1436+
for a description of each property.
1437+
1438+
```js
1439+
socket.setKeepAlive({ enable: true, initialDelay: 1000, interval: 1000, count: 10 });
1440+
```
1441+
1442+
#### `socket.setKeepAlive([enable][, initialDelay][, interval][, count])`
13821443

13831444
<!-- YAML
13841445
added: v0.1.92
13851446
changes:
1447+
- version: REPLACEME
1448+
pr-url: https://github.com/nodejs/node/pull/63825
1449+
description: Added the `interval` and `count` arguments to configure
1450+
`TCP_KEEPINTVL` and `TCP_KEEPCNT`.
13861451
- version:
13871452
- v13.12.0
13881453
- v12.17.0
@@ -1392,22 +1457,12 @@ changes:
13921457

13931458
* `enable` {boolean} **Default:** `false`
13941459
* `initialDelay` {number} **Default:** `0`
1460+
* `interval` {number} **Default:** `1000`
1461+
* `count` {number} **Default:** `10`
13951462
* Returns: {net.Socket} The socket itself.
13961463

1397-
Enable/disable keep-alive functionality, and optionally set the initial
1398-
delay before the first keepalive probe is sent on an idle socket.
1399-
1400-
Set `initialDelay` (in milliseconds) to set the delay between the last
1401-
data packet received and the first keepalive probe. Setting `0` for
1402-
`initialDelay` will leave the value unchanged from the default
1403-
(or previous) setting.
1404-
1405-
Enabling the keep-alive functionality will set the following socket options:
1406-
1407-
* `SO_KEEPALIVE=1`
1408-
* `TCP_KEEPIDLE=initialDelay`
1409-
* `TCP_KEEPCNT=10`
1410-
* `TCP_KEEPINTVL=1`
1464+
Configure keep-alive using positional arguments. See
1465+
[`socket.setKeepAlive()`][] for a description of each argument.
14111466

14121467
### `socket.setNoDelay([noDelay])`
14131468

@@ -2074,7 +2129,9 @@ net.isIPv6('fhqwhgads'); // returns false
20742129
[`socket.pause()`]: #socketpause
20752130
[`socket.resume()`]: #socketresume
20762131
[`socket.setEncoding()`]: #socketsetencodingencoding
2077-
[`socket.setKeepAlive()`]: #socketsetkeepaliveenable-initialdelay
2132+
[`socket.setKeepAlive()`]: #socketsetkeepalive
2133+
[`socket.setKeepAlive(enable)`]: #socketsetkeepaliveenable-initialdelay-interval-count
2134+
[`socket.setKeepAlive(options)`]: #socketsetkeepaliveoptions
20782135
[`socket.setTimeout()`]: #socketsettimeouttimeout-callback
20792136
[`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback
20802137
[`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode

lib/internal/net.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ module.exports = {
103103
kSetNoDelay: Symbol('kSetNoDelay'),
104104
kSetKeepAlive: Symbol('kSetKeepAlive'),
105105
kSetKeepAliveInitialDelay: Symbol('kSetKeepAliveInitialDelay'),
106+
kSetKeepAliveInterval: Symbol('kSetKeepAliveInterval'),
107+
kSetKeepAliveCount: Symbol('kSetKeepAliveCount'),
106108
isIP,
107109
isIPv4,
108110
isIPv6,

lib/net.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ const {
5151
kSetNoDelay,
5252
kSetKeepAlive,
5353
kSetKeepAliveInitialDelay,
54+
kSetKeepAliveInterval,
55+
kSetKeepAliveCount,
5456
isIP,
5557
isIPv4,
5658
isIPv6,
@@ -630,13 +632,25 @@ Socket.prototype.setNoDelay = function(enable) {
630632
};
631633

632634

633-
Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
635+
Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs,
636+
intervalMsecs, count) {
637+
if (enable !== null && typeof enable === 'object') {
638+
const options = enable;
639+
enable = options.enable;
640+
initialDelayMsecs = options.initialDelay;
641+
intervalMsecs = options.interval;
642+
count = options.count;
643+
}
634644
enable = Boolean(enable);
635645
const initialDelay = ~~(initialDelayMsecs / 1000);
646+
const interval = intervalMsecs === undefined ?
647+
undefined : ~~(intervalMsecs / 1000);
636648

637649
if (!this._handle) {
638650
this[kSetKeepAlive] = enable;
639651
this[kSetKeepAliveInitialDelay] = initialDelay;
652+
this[kSetKeepAliveInterval] = interval;
653+
this[kSetKeepAliveCount] = count;
640654
return this;
641655
}
642656

@@ -647,12 +661,16 @@ Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
647661
if (enable !== this[kSetKeepAlive] ||
648662
(
649663
enable &&
650-
this[kSetKeepAliveInitialDelay] !== initialDelay
664+
(this[kSetKeepAliveInitialDelay] !== initialDelay ||
665+
this[kSetKeepAliveInterval] !== interval ||
666+
this[kSetKeepAliveCount] !== count)
651667
)
652668
) {
653669
this[kSetKeepAlive] = enable;
654670
this[kSetKeepAliveInitialDelay] = initialDelay;
655-
this._handle.setKeepAlive(enable, initialDelay);
671+
this[kSetKeepAliveInterval] = interval;
672+
this[kSetKeepAliveCount] = count;
673+
this._handle.setKeepAlive(enable, initialDelay, interval, count);
656674
}
657675

658676
return this;
@@ -1676,7 +1694,9 @@ function afterConnect(status, handle, req, readable, writable) {
16761694
}
16771695

16781696
if (self[kSetKeepAlive] && self._handle.setKeepAlive) {
1679-
self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
1697+
self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay],
1698+
self[kSetKeepAliveInterval],
1699+
self[kSetKeepAliveCount]);
16801700
}
16811701

16821702
if (self[kSetTOS] !== undefined && self._handle.setTypeOfService) {

src/tcp_wrap.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,14 @@ void TCPWrap::SetKeepAlive(const FunctionCallbackInfo<Value>& args) {
209209
int enable;
210210
if (!args[0]->Int32Value(env->context()).To(&enable)) return;
211211
unsigned int delay = static_cast<unsigned int>(args[1].As<Uint32>()->Value());
212-
int err = uv_tcp_keepalive(&wrap->handle_, enable, delay);
212+
// interval and count are optional. Fall back to the libuv defaults
213+
// (1 second, 10 probes) when they are not provided so that callers using
214+
// the legacy two-argument form of this handle method keep working.
215+
unsigned int interval = 1;
216+
unsigned int count = 10;
217+
if (args[2]->IsUint32()) interval = args[2].As<Uint32>()->Value();
218+
if (args[3]->IsUint32()) count = args[3].As<Uint32>()->Value();
219+
int err = uv_tcp_keepalive_ex(&wrap->handle_, enable, delay, interval, count);
213220
args.GetReturnValue().Set(err);
214221
}
215222

Lines changed: 106 additions & 0 deletions

0 commit comments

Comments
 (0)