Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
eb53d09
net: add setTOS and getTOS to Socket
amyssnippet Jan 24, 2026
9e7a183
added doc
amyssnippet Jan 24, 2026
14b3fb0
fixed some lint issues
amyssnippet Jan 24, 2026
f339cd0
already complete with validation and platform specific tests
amyssnippet Jan 24, 2026
d32f212
added: REPLACEME
amyssnippet Jan 24, 2026
71ecbd7
common.mustCall used
amyssnippet Jan 24, 2026
c0407b2
undo: unrelated header was removed irrelevantly
amyssnippet Jan 24, 2026
8439cfd
fix: resolve windows compilation and linter issues
amyssnippet Jan 25, 2026
fe329db
rollback to tcp only
amyssnippet Jan 25, 2026
778580a
fix: ensure getTOS returns numeric default when handle lacks getTOS
amyssnippet Jan 26, 2026
efb5f88
fix: handle setTOS errors in afterConnect and use options.tos
amyssnippet Jan 26, 2026
8dce839
fix: capture errno immediately after getsockopt failures
amyssnippet Jan 26, 2026
1fb4683
fix: use correct length type for Windows getsockopt and fix DSCP mask…
amyssnippet Jan 26, 2026
1084571
fix: validate options.tos in constructor
amyssnippet Jan 26, 2026
0a90f1c
fix: use validateInt32 for options.tos and standardize GetTOS error
amyssnippet Jan 26, 2026
603445d
fix: remove unused errno_val in TCPWrap::GetTOS POSIX path
amyssnippet Jan 26, 2026
f22a74c
test: add boundary value assertions for TOS
amyssnippet Jan 26, 2026
b272fda
test: add pre-connect TOS caching test
amyssnippet Jan 26, 2026
c6f1153
doc: add notes for setTOS and getTOS about pre-connect caching and OS…
amyssnippet Jan 26, 2026
fe14b34
fix: import UV_EBADF and remove duplicate mask declaration
amyssnippet Jan 26, 2026
041c30a
fix: update TOS cache when handle lacks setTOS
amyssnippet Jan 26, 2026
7516aff
doc: clarify pre-connect TOS test comment
amyssnippet Jan 26, 2026
83d875c
refined: comments
amyssnippet Jan 26, 2026
c03162b
doc: remove prohibited 'Note that' phrases
amyssnippet Jan 26, 2026
b884430
fix: reorder includes for Windows compatibility and add missing POSIX…
amyssnippet Jan 26, 2026
c39d13e
fix: resolve windows header order and doc lint errors
amyssnippet Jan 26, 2026
98747a7
feat: rename setTOS/getTOS to setTypeOfService/getTypeOfService for A…
amyssnippet Jan 26, 2026
551a5d3
fix: update internal handle calls to use new TypeOfService method names
amyssnippet Jan 26, 2026
2bb4591
win vs2022 ci fix
amyssnippet Jan 27, 2026
a2d4c36
added: todo for libuv api
amyssnippet Jan 27, 2026
b04b62f
fixed:win vs2022 lint ci
amyssnippet Jan 27, 2026
569debb
feat: rename C++ methods from SetTOS/GetTOS to SetTypeOfService/GetTy…
amyssnippet Jan 27, 2026
e33561d
docs: update net.md for typeOfService option and fix lib/net.js const…
amyssnippet Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,9 @@ it to interact with the client.
<!-- YAML
added: v0.3.4
changes:
- version: ADDME
pr-url: https://github.com/nodejs/node/pull/61503
description: Added `typeOfService` option.
- version: v15.14.0
pr-url: https://github.com/nodejs/node/pull/37735
description: AbortSignal support was added.
Expand Down Expand Up @@ -788,6 +791,7 @@ changes:
otherwise ignored. **Default:** `false`.
* `signal` {AbortSignal} An Abort signal that may be used to destroy the
socket.
* `typeOfService` {number} The initial Type of Service (TOS) value.
* `writable` {boolean} Allow writes on the socket when an `fd` is passed,
otherwise ignored. **Default:** `false`.
* Returns: {net.Socket}
Expand Down Expand Up @@ -1461,6 +1465,45 @@ If `timeout` is 0, then the existing idle timeout is disabled.
The optional `callback` parameter will be added as a one-time listener for the
[`'timeout'`][] event.

### `socket.getTypeOfService()`

<!-- YAML
added: REPLACEME
-->

* Returns: {integer} The current TOS value.

Returns the current Type of Service (TOS) field for IPv4 packets or Traffic
Class for IPv6 packets for this socket.

`setTypeOfService()` may be called before the socket is connected; the value
will be cached and applied when the socket establishes a connection.
`getTypeOfService()` will return the currently set value even before connection.

On some platforms (e.g., Linux), certain TOS/ECN bits may be masked or ignored,
and behavior can differ between IPv4 and IPv6 or dual-stack sockets. Callers
should verify platform-specific semantics.

### `socket.setTypeOfService(tos)`

<!-- YAML
added: REPLACEME
-->

* `tos` {integer} The TOS value to set (0-255).
* Returns: {net.Socket} The socket itself.

Sets the Type of Service (TOS) field for IPv4 packets or Traffic Class for IPv6
Packets sent from this socket. This can be used to prioritize network traffic.

`setTypeOfService()` may be called before the socket is connected; the value
will be cached and applied when the socket establishes a connection.
`getTypeOfService()` will return the currently set value even before connection.

On some platforms (e.g., Linux), certain TOS/ECN bits may be masked or ignored,
and behavior can differ between IPv4 and IPv6 or dual-stack sockets. Callers
should verify platform-specific semantics.

### `socket.timeout`

<!-- YAML
Expand Down
68 changes: 68 additions & 0 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const {
const assert = require('internal/assert');
const {
UV_EADDRINUSE,
UV_EBADF,
UV_EINVAL,
UV_ENOTCONN,
UV_ECANCELED,
Expand Down Expand Up @@ -358,6 +359,7 @@ const kBytesWritten = Symbol('kBytesWritten');
const kSetNoDelay = Symbol('kSetNoDelay');
const kSetKeepAlive = Symbol('kSetKeepAlive');
const kSetKeepAliveInitialDelay = Symbol('kSetKeepAliveInitialDelay');
const kSetTOS = Symbol('kSetTOS');

function Socket(options) {
if (!(this instanceof Socket)) return new Socket(options);
Expand Down Expand Up @@ -473,6 +475,10 @@ function Socket(options) {
this[kSetNoDelay] = Boolean(options.noDelay);
this[kSetKeepAlive] = Boolean(options.keepAlive);
this[kSetKeepAliveInitialDelay] = ~~(options.keepAliveInitialDelay / 1000);
if (options.typeOfService !== undefined) {
validateInt32(options.typeOfService, 'options.typeOfService', 0, 255);
}
this[kSetTOS] = options.typeOfService;

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


Socket.prototype.setTypeOfService = function(tos) {
if (NumberIsNaN(tos)) {
throw new ERR_INVALID_ARG_TYPE('tos', 'number', tos);
}
validateInt32(tos, 'tos', 0, 255);

if (!this._handle) {
this[kSetTOS] = tos;
return this;
}

if (!this._handle.setTypeOfService) {
this[kSetTOS] = tos;
return this;
}

if (tos !== this[kSetTOS]) {
this[kSetTOS] = tos;
const err = this._handle.setTypeOfService(tos);
// On Windows, setting TOS is often restricted or returns error codes even if partially applied.
// We treat this as a "best effort" operation and do not throw on Windows.
if (err && !isWindows) {
throw new ErrnoException(err, 'setTypeOfService');
}
}

return this;
};


Socket.prototype.getTypeOfService = function() {
if (!this._handle) {
// Return cached value if set, otherwise default to 0
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
}

if (!this._handle.getTypeOfService) {
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
}

const res = this._handle.getTypeOfService();
if (typeof res === 'number' && res < 0) {
// On Windows, getsockopt(IP_TOS) often fails. In that case, fall back
// to the cached value we attempted to set, or 0.
if (isWindows) {
return this[kSetTOS] !== undefined ? this[kSetTOS] : 0;
}
throw new ErrnoException(res, 'getTypeOfService');
}
return res;
};


Socket.prototype.address = function() {
return this._getsockname();
};
Expand Down Expand Up @@ -1619,6 +1678,15 @@ function afterConnect(status, handle, req, readable, writable) {
self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
}

if (self[kSetTOS] !== undefined && self._handle.setTypeOfService) {
const err = self._handle.setTypeOfService(self[kSetTOS]);
// On Windows, setting TOS is best-effort. If it fails, we shouldn't destroy
// the connection or emit an error, as the socket is otherwise healthy.
if (err && err !== UV_EBADF && !isWindows) {
self.emit('error', new ErrnoException(err, 'setTypeOfService'));
}
}

self.emit('connect');
self.emit('ready');

Expand Down
Loading