@@ -55,6 +55,7 @@ const {
5555const assert = require ( 'internal/assert' ) ;
5656const {
5757 UV_EADDRINUSE ,
58+ UV_EBADF ,
5859 UV_EINVAL ,
5960 UV_ENOTCONN ,
6061 UV_ECANCELED ,
@@ -359,6 +360,7 @@ const kBytesWritten = Symbol('kBytesWritten');
359360const kSetNoDelay = Symbol ( 'kSetNoDelay' ) ;
360361const kSetKeepAlive = Symbol ( 'kSetKeepAlive' ) ;
361362const kSetKeepAliveInitialDelay = Symbol ( 'kSetKeepAliveInitialDelay' ) ;
363+ const kSetTOS = Symbol ( 'kSetTOS' ) ;
362364
363365function Socket ( options ) {
364366 if ( ! ( this instanceof Socket ) ) return new Socket ( options ) ;
@@ -474,6 +476,10 @@ function Socket(options) {
474476 this [ kSetNoDelay ] = Boolean ( options . noDelay ) ;
475477 this [ kSetKeepAlive ] = Boolean ( options . keepAlive ) ;
476478 this [ kSetKeepAliveInitialDelay ] = ~ ~ ( options . keepAliveInitialDelay / 1000 ) ;
479+ if ( options . typeOfService !== undefined ) {
480+ validateInt32 ( options . typeOfService , 'options.typeOfService' , 0 , 255 ) ;
481+ }
482+ this [ kSetTOS ] = options . typeOfService ;
477483
478484 // Shut down the socket when we're finished with it.
479485 this . on ( 'end' , onReadableStreamEnd ) ;
@@ -653,6 +659,59 @@ Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
653659} ;
654660
655661
662+ Socket . prototype . setTypeOfService = function ( tos ) {
663+ if ( NumberIsNaN ( tos ) ) {
664+ throw new ERR_INVALID_ARG_TYPE ( 'tos' , 'number' , tos ) ;
665+ }
666+ validateInt32 ( tos , 'tos' , 0 , 255 ) ;
667+
668+ if ( ! this . _handle ) {
669+ this [ kSetTOS ] = tos ;
670+ return this ;
671+ }
672+
673+ if ( ! this . _handle . setTypeOfService ) {
674+ this [ kSetTOS ] = tos ;
675+ return this ;
676+ }
677+
678+ if ( tos !== this [ kSetTOS ] ) {
679+ this [ kSetTOS ] = tos ;
680+ const err = this . _handle . setTypeOfService ( tos ) ;
681+ // On Windows, setting TOS is often restricted or returns error codes even if partially applied.
682+ // We treat this as a "best effort" operation and do not throw on Windows.
683+ if ( err && ! isWindows ) {
684+ throw new ErrnoException ( err , 'setTypeOfService' ) ;
685+ }
686+ }
687+
688+ return this ;
689+ } ;
690+
691+
692+ Socket . prototype . getTypeOfService = function ( ) {
693+ if ( ! this . _handle ) {
694+ // Return cached value if set, otherwise default to 0
695+ return this [ kSetTOS ] !== undefined ? this [ kSetTOS ] : 0 ;
696+ }
697+
698+ if ( ! this . _handle . getTypeOfService ) {
699+ return this [ kSetTOS ] !== undefined ? this [ kSetTOS ] : 0 ;
700+ }
701+
702+ const res = this . _handle . getTypeOfService ( ) ;
703+ if ( typeof res === 'number' && res < 0 ) {
704+ // On Windows, getsockopt(IP_TOS) often fails. In that case, fall back
705+ // to the cached value we attempted to set, or 0.
706+ if ( isWindows ) {
707+ return this [ kSetTOS ] !== undefined ? this [ kSetTOS ] : 0 ;
708+ }
709+ throw new ErrnoException ( res , 'getTypeOfService' ) ;
710+ }
711+ return res ;
712+ } ;
713+
714+
656715Socket . prototype . address = function ( ) {
657716 return this . _getsockname ( ) ;
658717} ;
@@ -1628,6 +1687,15 @@ function afterConnect(status, handle, req, readable, writable) {
16281687 self . _handle . setKeepAlive ( true , self [ kSetKeepAliveInitialDelay ] ) ;
16291688 }
16301689
1690+ if ( self [ kSetTOS ] !== undefined && self . _handle . setTypeOfService ) {
1691+ const err = self . _handle . setTypeOfService ( self [ kSetTOS ] ) ;
1692+ // On Windows, setting TOS is best-effort. If it fails, we shouldn't destroy
1693+ // the connection or emit an error, as the socket is otherwise healthy.
1694+ if ( err && err !== UV_EBADF && ! isWindows ) {
1695+ self . emit ( 'error' , new ErrnoException ( err , 'setTypeOfService' ) ) ;
1696+ }
1697+ }
1698+
16311699 self . emit ( 'connect' ) ;
16321700 self . emit ( 'ready' ) ;
16331701
0 commit comments