Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c851e76

Browse filesBrowse files
amyssnippetaduh95
authored andcommitted
net: add setTOS and getTOS to Socket
PR-URL: #61503 Fixes: #61489 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 83dfd0b commit c851e76
Copy full SHA for c851e76

5 files changed

+429-86Lines changed: 429 additions & 86 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/net.md‎

Copy file name to clipboardExpand all lines: doc/api/net.md
+43Lines changed: 43 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,9 @@ it to interact with the client.
743743
<!-- YAML
744744
added: v0.3.4
745745
changes:
746+
- version: REPLACEME
747+
pr-url: https://github.com/nodejs/node/pull/61503
748+
description: Added `typeOfService` option.
746749
- version: v15.14.0
747750
pr-url: https://github.com/nodejs/node/pull/37735
748751
description: AbortSignal support was added.
@@ -784,6 +787,7 @@ changes:
784787
otherwise ignored. **Default:** `false`.
785788
* `signal` {AbortSignal} An Abort signal that may be used to destroy the
786789
socket.
790+
* `typeOfService` {number} The initial Type of Service (TOS) value.
787791
* `writable` {boolean} Allow writes on the socket when an `fd` is passed,
788792
otherwise ignored. **Default:** `false`.
789793
* Returns: {net.Socket}
@@ -1457,6 +1461,45 @@ If `timeout` is 0, then the existing idle timeout is disabled.
14571461
The optional `callback` parameter will be added as a one-time listener for the
14581462
[`'timeout'`][] event.
14591463

1464+
### `socket.getTypeOfService()`
1465+
1466+
<!-- YAML
1467+
added: REPLACEME
1468+
-->
1469+
1470+
* Returns: {integer} The current TOS value.
1471+
1472+
Returns the current Type of Service (TOS) field for IPv4 packets or Traffic
1473+
Class for IPv6 packets for this socket.
1474+
1475+
`setTypeOfService()` may be called before the socket is connected; the value
1476+
will be cached and applied when the socket establishes a connection.
1477+
`getTypeOfService()` will return the currently set value even before connection.
1478+
1479+
On some platforms (e.g., Linux), certain TOS/ECN bits may be masked or ignored,
1480+
and behavior can differ between IPv4 and IPv6 or dual-stack sockets. Callers
1481+
should verify platform-specific semantics.
1482+
1483+
### `socket.setTypeOfService(tos)`
1484+
1485+
<!-- YAML
1486+
added: REPLACEME
1487+
-->
1488+
1489+
* `tos` {integer} The TOS value to set (0-255).
1490+
* Returns: {net.Socket} The socket itself.
1491+
1492+
Sets the Type of Service (TOS) field for IPv4 packets or Traffic Class for IPv6
1493+
Packets sent from this socket. This can be used to prioritize network traffic.
1494+
1495+
`setTypeOfService()` may be called before the socket is connected; the value
1496+
will be cached and applied when the socket establishes a connection.
1497+
`getTypeOfService()` will return the currently set value even before connection.
1498+
1499+
On some platforms (e.g., Linux), certain TOS/ECN bits may be masked or ignored,
1500+
and behavior can differ between IPv4 and IPv6 or dual-stack sockets. Callers
1501+
should verify platform-specific semantics.
1502+
14601503
### `socket.timeout`
14611504

14621505
<!-- YAML
Collapse file

‎lib/net.js‎

Copy file name to clipboardExpand all lines: lib/net.js
+68Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const {
5757
const assert = require('internal/assert');
5858
const {
5959
UV_EADDRINUSE,
60+
UV_EBADF,
6061
UV_EINVAL,
6162
UV_ENOTCONN,
6263
UV_ECANCELED,
@@ -358,6 +359,7 @@ const kBytesWritten = Symbol('kBytesWritten');
358359
const kSetNoDelay = Symbol('kSetNoDelay');
359360
const kSetKeepAlive = Symbol('kSetKeepAlive');
360361
const kSetKeepAliveInitialDelay = Symbol('kSetKeepAliveInitialDelay');
362+
const kSetTOS = Symbol('kSetTOS');
361363

362364
function Socket(options) {
363365
if (!(this instanceof Socket)) return new Socket(options);
@@ -473,6 +475,10 @@ function Socket(options) {
473475
this[kSetNoDelay] = Boolean(options.noDelay);
474476
this[kSetKeepAlive] = Boolean(options.keepAlive);
475477
this[kSetKeepAliveInitialDelay] = ~~(options.keepAliveInitialDelay / 1000);
478+
if (options.typeOfService !== undefined) {
479+
validateInt32(options.typeOfService, 'options.typeOfService', 0, 255);
480+
}
481+
this[kSetTOS] = options.typeOfService;
476482

477483
// Shut down the socket when we're finished with it.
478484
this.on('end', onReadableStreamEnd);
@@ -652,6 +658,59 @@ Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
652658
};
653659

654660

661+
Socket.prototype.setTypeOfService = function(tos) {
662+
if (NumberIsNaN(tos)) {
663+
throw new ERR_INVALID_ARG_TYPE('tos', 'number', tos);
664+
}
665+
validateInt32(tos, 'tos', 0, 255);
666+
667+
if (!this._handle) {
668+
this[kSetTOS] = tos;
669+
return this;
670+
}
671+
672+
if (!this._handle.setTypeOfService) {
673+
this[kSetTOS] = tos;
674+
return this;
675+
}
676+
677+
if (tos !== this[kSetTOS]) {
678+
this[kSetTOS] = tos;
679+
const err = this._handle.setTypeOfService(tos);
680+
// On Windows, setting TOS is often restricted or returns error codes even if partially applied.
681+
// We treat this as a "best effort" operation and do not throw on Windows.
682+
if (err && !isWindows) {
683+
throw new ErrnoException(err, 'setTypeOfService');
684+
}
685+
}
686+
687+
return this;
688+
};
689+
690+
691+
Socket.prototype.getTypeOfService = function() {
692+
if (!this._handle) {
693+
// Return cached value if set, otherwise default to 0
694+
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
695+
}
696+
697+
if (!this._handle.getTypeOfService) {
698+
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
699+
}
700+
701+
const res = this._handle.getTypeOfService();
702+
if (typeof res === 'number' && res < 0) {
703+
// On Windows, getsockopt(IP_TOS) often fails. In that case, fall back
704+
// to the cached value we attempted to set, or 0.
705+
if (isWindows) {
706+
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
707+
}
708+
throw new ErrnoException(res, 'getTypeOfService');
709+
}
710+
return res;
711+
};
712+
713+
655714
Socket.prototype.address = function() {
656715
return this._getsockname();
657716
};
@@ -1627,6 +1686,15 @@ function afterConnect(status, handle, req, readable, writable) {
16271686
self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
16281687
}
16291688

1689+
if (self[kSetTOS] !== undefined && self._handle.setTypeOfService) {
1690+
const err = self._handle.setTypeOfService(self[kSetTOS]);
1691+
// On Windows, setting TOS is best-effort. If it fails, we shouldn't destroy
1692+
// the connection or emit an error, as the socket is otherwise healthy.
1693+
if (err && err !== UV_EBADF && !isWindows) {
1694+
self.emit('error', new ErrnoException(err, 'setTypeOfService'));
1695+
}
1696+
}
1697+
16301698
self.emit('connect');
16311699
self.emit('ready');
16321700

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.