GeezerVison is showing github.com — net: support TCP_KEEPINTVL and TCP_KEEPCNT in setKeepAlive · nodejs/node@45494d5
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/http.md +2-2Lines changed: 2 additions & 2 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -3745,7 +3745,7 @@ changes: | 3745 | 3745 | **Default:** `false`. | 3746 | 3746 | * `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality | 3747 | 3747 | on the socket immediately after a new incoming connection is received, | 3748 | | - similarly on what is done in \[`socket.setKeepAlive([enable][, initialDelay])`]\[`socket.setKeepAlive(enable, initialDelay)`]. | | 3748 | + similarly on what is done in [`socket.setKeepAlive()`][]. | 3749 | 3749 | **Default:** `false`. | 3750 | 3750 | * `keepAliveInitialDelay` {number} If set to a positive number, it sets the | 3751 | 3751 | initial delay before the first keepalive probe is sent on an idle socket. | @@ -4761,7 +4761,7 @@ const agent2 = new http.Agent({ proxyEnv: process.env }); | 4761 | 4761 | [`server.timeout`]: #servertimeout | 4762 | 4762 | [`setHeader(name, value)`]: #requestsetheadername-value | 4763 | 4763 | [`socket.connect()`]: net.md#socketconnectoptions-connectlistener | 4764 | | -[`socket.setKeepAlive()`]: net.md#socketsetkeepaliveenable-initialdelay | | 4764 | +[`socket.setKeepAlive()`]: net.md#socketsetkeepalive | 4765 | 4765 | [`socket.setNoDelay()`]: net.md#socketsetnodelaynodelay | 4766 | 4766 | [`socket.setTimeout()`]: net.md#socketsettimeouttimeout-callback | 4767 | 4767 | [`socket.unref()`]: net.md#socketunref | |
Collapse file Copy file name to clipboardExpand all lines: doc/api/net.md +73-16Lines changed: 73 additions & 16 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1378,11 +1378,76 @@ added: v0.1.90 | 1378 | 1378 | Set the encoding for the socket as a [Readable Stream][]. See | 1379 | 1379 | [`readable.setEncoding()`][] for more information. | 1380 | 1380 |
| 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])` | 1382 | 1443 |
| 1383 | 1444 | <!-- YAML | 1384 | 1445 | added: v0.1.92 | 1385 | 1446 | 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`. | 1386 | 1451 | - version: | 1387 | 1452 | - v13.12.0 | 1388 | 1453 | - v12.17.0 | @@ -1392,22 +1457,12 @@ changes: | 1392 | 1457 |
| 1393 | 1458 | * `enable` {boolean} **Default:** `false` | 1394 | 1459 | * `initialDelay` {number} **Default:** `0` | | 1460 | +* `interval` {number} **Default:** `1000` | | 1461 | +* `count` {number} **Default:** `10` | 1395 | 1462 | * Returns: {net.Socket} The socket itself. | 1396 | 1463 |
| 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. | 1411 | 1466 |
| 1412 | 1467 | ### `socket.setNoDelay([noDelay])` | 1413 | 1468 |
| @@ -2074,7 +2129,9 @@ net.isIPv6('fhqwhgads'); // returns false | 2074 | 2129 | [`socket.pause()`]: #socketpause | 2075 | 2130 | [`socket.resume()`]: #socketresume | 2076 | 2131 | [`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 | 2078 | 2135 | [`socket.setTimeout()`]: #socketsettimeouttimeout-callback | 2079 | 2136 | [`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback | 2080 | 2137 | [`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/net.js +2Lines changed: 2 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -103,6 +103,8 @@ module.exports = { | 103 | 103 | kSetNoDelay: Symbol('kSetNoDelay'), | 104 | 104 | kSetKeepAlive: Symbol('kSetKeepAlive'), | 105 | 105 | kSetKeepAliveInitialDelay: Symbol('kSetKeepAliveInitialDelay'), | | 106 | + kSetKeepAliveInterval: Symbol('kSetKeepAliveInterval'), | | 107 | + kSetKeepAliveCount: Symbol('kSetKeepAliveCount'), | 106 | 108 | isIP, | 107 | 109 | isIPv4, | 108 | 110 | isIPv6, | |
Collapse file Copy file name to clipboardExpand all lines: lib/net.js +24-4Lines changed: 24 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -51,6 +51,8 @@ const { | 51 | 51 | kSetNoDelay, | 52 | 52 | kSetKeepAlive, | 53 | 53 | kSetKeepAliveInitialDelay, | | 54 | + kSetKeepAliveInterval, | | 55 | + kSetKeepAliveCount, | 54 | 56 | isIP, | 55 | 57 | isIPv4, | 56 | 58 | isIPv6, | @@ -630,13 +632,25 @@ Socket.prototype.setNoDelay = function(enable) { | 630 | 632 | }; | 631 | 633 |
| 632 | 634 |
| 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 | + } | 634 | 644 | enable = Boolean(enable); | 635 | 645 | const initialDelay = ~~(initialDelayMsecs / 1000); | | 646 | + const interval = intervalMsecs === undefined ? | | 647 | + undefined : ~~(intervalMsecs / 1000); | 636 | 648 |
| 637 | 649 | if (!this._handle) { | 638 | 650 | this[kSetKeepAlive] = enable; | 639 | 651 | this[kSetKeepAliveInitialDelay] = initialDelay; | | 652 | + this[kSetKeepAliveInterval] = interval; | | 653 | + this[kSetKeepAliveCount] = count; | 640 | 654 | return this; | 641 | 655 | } | 642 | 656 |
| @@ -647,12 +661,16 @@ Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) { | 647 | 661 | if (enable !== this[kSetKeepAlive] || | 648 | 662 | ( | 649 | 663 | enable && | 650 | | - this[kSetKeepAliveInitialDelay] !== initialDelay | | 664 | + (this[kSetKeepAliveInitialDelay] !== initialDelay || | | 665 | + this[kSetKeepAliveInterval] !== interval || | | 666 | + this[kSetKeepAliveCount] !== count) | 651 | 667 | ) | 652 | 668 | ) { | 653 | 669 | this[kSetKeepAlive] = enable; | 654 | 670 | 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); | 656 | 674 | } | 657 | 675 |
| 658 | 676 | return this; | @@ -1676,7 +1694,9 @@ function afterConnect(status, handle, req, readable, writable) { | 1676 | 1694 | } | 1677 | 1695 |
| 1678 | 1696 | 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]); | 1680 | 1700 | } | 1681 | 1701 |
| 1682 | 1702 | if (self[kSetTOS] !== undefined && self._handle.setTypeOfService) { | |
Collapse file Copy file name to clipboardExpand all lines: src/tcp_wrap.cc +8-1Lines changed: 8 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -209,7 +209,14 @@ void TCPWrap::SetKeepAlive(const FunctionCallbackInfo<Value>& args) { | 209 | 209 | int enable; | 210 | 210 | if (!args[0]->Int32Value(env->context()).To(&enable)) return; | 211 | 211 | 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); | 213 | 220 | args.GetReturnValue().Set(err); | 214 | 221 | } | 215 | 222 |
| |
Collapse file Copy file name to clipboard +106Lines changed: 106 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const common = require('../common'); | | 4 | +const assert = require('assert'); | | 5 | +const net = require('net'); | | 6 | + | | 7 | +// Verifies that setKeepAlive() forwards the keepalive probe interval | | 8 | +// (TCP_KEEPINTVL) and probe count (TCP_KEEPCNT) to the handle. The interval is | | 9 | +// converted from milliseconds to whole seconds, mirroring the initialDelay | | 10 | +// handling and uv_tcp_keepalive_ex(). | | 11 | + | | 12 | +// Explicit setKeepAlive(enable, initialDelay, interval, count) forwards all | | 13 | +// four values, converting milliseconds to seconds for the delays. | | 14 | +{ | | 15 | + const server = net.createServer(); | | 16 | + server.listen(0, common.mustCall(() => { | | 17 | + const client = net.connect( | | 18 | + { port: server.address().port }, | | 19 | + common.mustCall(() => { | | 20 | + client._handle.setKeepAlive = common.mustCall( | | 21 | + (enable, delay, interval, count) => { | | 22 | + assert.strictEqual(enable, true); | | 23 | + assert.strictEqual(delay, 5); | | 24 | + assert.strictEqual(interval, 10); | | 25 | + assert.strictEqual(count, 9); | | 26 | + }); | | 27 | + client.setKeepAlive(true, 5000, 10000, 9); | | 28 | + client.end(); | | 29 | + })); | | 30 | + | | 31 | + client.on('end', common.mustCall(() => server.close())); | | 32 | + })); | | 33 | +} | | 34 | + | | 35 | +// Omitting interval/count passes undefined through; the handle applies the | | 36 | +// libuv defaults (1s interval, 10 probes). | | 37 | +{ | | 38 | + const server = net.createServer(); | | 39 | + server.listen(0, common.mustCall(() => { | | 40 | + const client = net.connect( | | 41 | + { port: server.address().port }, | | 42 | + common.mustCall(() => { | | 43 | + client._handle.setKeepAlive = common.mustCall( | | 44 | + (enable, delay, interval, count) => { | | 45 | + assert.strictEqual(enable, true); | | 46 | + assert.strictEqual(delay, 5); | | 47 | + assert.strictEqual(interval, undefined); | | 48 | + assert.strictEqual(count, undefined); | | 49 | + }); | | 50 | + client.setKeepAlive(true, 5000); | | 51 | + client.end(); | | 52 | + })); | | 53 | + | | 54 | + client.on('end', common.mustCall(() => server.close())); | | 55 | + })); | | 56 | +} | | 57 | + | | 58 | +// An options object as the first argument is equivalent to the positional | | 59 | +// form, forwarding enable/initialDelay/interval/count to the handle. | | 60 | +{ | | 61 | + const server = net.createServer(); | | 62 | + server.listen(0, common.mustCall(() => { | | 63 | + const client = net.connect( | | 64 | + { port: server.address().port }, | | 65 | + common.mustCall(() => { | | 66 | + client._handle.setKeepAlive = common.mustCall( | | 67 | + (enable, delay, interval, count) => { | | 68 | + assert.strictEqual(enable, true); | | 69 | + assert.strictEqual(delay, 5); | | 70 | + assert.strictEqual(interval, 10); | | 71 | + assert.strictEqual(count, 9); | | 72 | + }); | | 73 | + client.setKeepAlive({ | | 74 | + enable: true, | | 75 | + initialDelay: 5000, | | 76 | + interval: 10000, | | 77 | + count: 9, | | 78 | + }); | | 79 | + client.end(); | | 80 | + })); | | 81 | + | | 82 | + client.on('end', common.mustCall(() => server.close())); | | 83 | + })); | | 84 | +} | | 85 | + | | 86 | +// Omitted options properties behave like omitted positional arguments. | | 87 | +{ | | 88 | + const server = net.createServer(); | | 89 | + server.listen(0, common.mustCall(() => { | | 90 | + const client = net.connect( | | 91 | + { port: server.address().port }, | | 92 | + common.mustCall(() => { | | 93 | + client._handle.setKeepAlive = common.mustCall( | | 94 | + (enable, delay, interval, count) => { | | 95 | + assert.strictEqual(enable, true); | | 96 | + assert.strictEqual(delay, 5); | | 97 | + assert.strictEqual(interval, undefined); | | 98 | + assert.strictEqual(count, undefined); | | 99 | + }); | | 100 | + client.setKeepAlive({ enable: true, initialDelay: 5000 }); | | 101 | + client.end(); | | 102 | + })); | | 103 | + | | 104 | + client.on('end', common.mustCall(() => server.close())); | | 105 | + })); | | 106 | +} |
|