diff --git a/CHANGELOG.md b/CHANGELOG.md index 45b24b01b4..035a8f8841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog -### Next +### 3.13.20 +- Add server side ICE consent checks to detect silent WebRTC disconnections ([PR #1332](https://github.com/versatica/mediasoup/pull/1332)). - Fix regression (crash) in transport-cc feedback generation ([PR #1339](https://github.com/versatica/mediasoup/pull/1339)). ### 3.13.19 diff --git a/node/src/Router.ts b/node/src/Router.ts index 7b87818bf7..56245fe877 100644 --- a/node/src/Router.ts +++ b/node/src/Router.ts @@ -454,6 +454,7 @@ export class Router< numSctpStreams = { OS: 1024, MIS: 1024 }, maxSctpMessageSize = 262144, sctpSendBufferSize = 262144, + iceConsentTimeout = 30, appData, }: WebRtcTransportOptions): Promise< WebRtcTransport @@ -596,7 +597,8 @@ export class Router< enableUdp, enableTcp, preferUdp, - preferTcp + preferTcp, + iceConsentTimeout ); const requestOffset = new FbsRouter.CreateWebRtcTransportRequestT( diff --git a/node/src/WebRtcTransport.ts b/node/src/WebRtcTransport.ts index bdfb534e59..1e0a8d5b49 100644 --- a/node/src/WebRtcTransport.ts +++ b/node/src/WebRtcTransport.ts @@ -96,6 +96,11 @@ export type WebRtcTransportOptionsBase = { */ preferTcp?: boolean; + /** + * ICE consent timeout (in seconds). If 0 it is disabled. Default 30. + */ + iceConsentTimeout?: number; + /** * Initial available outgoing bitrate (in bps). Default 600000. */ @@ -836,7 +841,6 @@ function createConnectRequest({ // Serialize DtlsParameters. This can throw. const dtlsParametersOffset = serializeDtlsParameters(builder, dtlsParameters); - // Create request. return FbsWebRtcTransport.ConnectRequest.createConnectRequest( builder, dtlsParametersOffset diff --git a/node/src/test/test-WebRtcTransport.ts b/node/src/test/test-WebRtcTransport.ts index 72bfd48e4a..c605c05cb5 100644 --- a/node/src/test/test-WebRtcTransport.ts +++ b/node/src/test/test-WebRtcTransport.ts @@ -299,12 +299,16 @@ test('webRtcTransport.connect() succeeds', async () => { }; await expect( - webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters }) + webRtcTransport.connect({ + dtlsParameters: dtlsRemoteParameters, + }) ).resolves.toBeUndefined(); // Must fail if connected. await expect( - webRtcTransport.connect({ dtlsParameters: dtlsRemoteParameters }) + webRtcTransport.connect({ + dtlsParameters: dtlsRemoteParameters, + }) ).rejects.toThrow(Error); expect(webRtcTransport.dtlsParameters.role).toBe('server'); diff --git a/package-lock.json b/package-lock.json index 1a81802f6e..68cbfb37cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mediasoup", - "version": "3.13.19", + "version": "3.13.20", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mediasoup", - "version": "3.13.19", + "version": "3.13.20", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -21,12 +21,12 @@ "@octokit/rest": "^20.0.2", "@types/debug": "^4.1.12", "@types/jest": "^29.5.12", - "@types/node": "^20.11.17", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@types/node": "^20.11.19", + "@typescript-eslint/eslint-plugin": "^7.0.2", + "@typescript-eslint/parser": "^7.0.2", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-jest": "^27.8.0", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", "marked": "^12.0.0", @@ -1626,9 +1626,9 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" }, "node_modules/@types/node": { - "version": "20.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", - "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "version": "20.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", + "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1662,16 +1662,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz", - "integrity": "sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.2.tgz", + "integrity": "sha512-/XtVZJtbaphtdrWjr+CJclaCVGPtOdBpFEnvtNf/jRV0IiEemRrL0qABex/nEt8isYcnFacm3nPHYQwL+Wb7qg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/type-utils": "7.0.1", - "@typescript-eslint/utils": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/type-utils": "7.0.2", + "@typescript-eslint/utils": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1697,13 +1697,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1714,9 +1714,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1727,13 +1727,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1755,17 +1755,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", - "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", "semver": "^7.5.4" }, "engines": { @@ -1780,12 +1780,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1821,15 +1821,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.1.tgz", - "integrity": "sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", + "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4" }, "engines": { @@ -1849,13 +1849,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1866,9 +1866,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1879,13 +1879,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1907,12 +1907,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1965,13 +1965,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.1.tgz", - "integrity": "sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz", + "integrity": "sha512-IKKDcFsKAYlk8Rs4wiFfEwJTQlHcdn8CLwLaxwd6zb8HNiMcQIFX9sWax2k4Cjj7l7mGS5N1zl7RCHOVwHq2VQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/utils": "7.0.1", + "@typescript-eslint/typescript-estree": "7.0.2", + "@typescript-eslint/utils": "7.0.2", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1992,13 +1992,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2009,9 +2009,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2022,13 +2022,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2050,17 +2050,17 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", - "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", "semver": "^7.5.4" }, "engines": { @@ -2075,12 +2075,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3003,9 +3003,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.8.0.tgz", - "integrity": "sha512-347hVFiu4ZKMYl5xFp0X81gLNwBdno0dl0CMpUMjwuAux9X/M2a7z+ab2VHmPL6XCT87q8nv1vaVzhIO4TE/hw==", + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -7514,9 +7514,9 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" }, "@types/node": { - "version": "20.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", - "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "version": "20.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", + "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", "dev": true, "requires": { "undici-types": "~5.26.4" @@ -7550,16 +7550,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz", - "integrity": "sha512-OLvgeBv3vXlnnJGIAgCLYKjgMEU+wBGj07MQ/nxAaON+3mLzX7mJbhRYrVGiVvFiXtwFlkcBa/TtmglHy0UbzQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.2.tgz", + "integrity": "sha512-/XtVZJtbaphtdrWjr+CJclaCVGPtOdBpFEnvtNf/jRV0IiEemRrL0qABex/nEt8isYcnFacm3nPHYQwL+Wb7qg==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/type-utils": "7.0.1", - "@typescript-eslint/utils": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/type-utils": "7.0.2", + "@typescript-eslint/utils": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7569,29 +7569,29 @@ }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" } }, "@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7601,27 +7601,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", - "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" } }, @@ -7646,42 +7646,42 @@ } }, "@typescript-eslint/parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.1.tgz", - "integrity": "sha512-8GcRRZNzaHxKzBPU3tKtFNing571/GwPBeCvmAUw0yBtfE2XVd0zFKJIMSWkHJcPQi0ekxjIts6L/rrZq5cxGQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", + "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" } }, "@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7691,12 +7691,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" } }, @@ -7731,41 +7731,41 @@ } }, "@typescript-eslint/type-utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.1.tgz", - "integrity": "sha512-YtT9UcstTG5Yqy4xtLiClm1ZpM/pWVGFnkAa90UfdkkZsR1eP2mR/1jbHeYp8Ay1l1JHPyGvoUYR6o3On5Nhmw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz", + "integrity": "sha512-IKKDcFsKAYlk8Rs4wiFfEwJTQlHcdn8CLwLaxwd6zb8HNiMcQIFX9sWax2k4Cjj7l7mGS5N1zl7RCHOVwHq2VQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.0.1", - "@typescript-eslint/utils": "7.0.1", + "@typescript-eslint/typescript-estree": "7.0.2", + "@typescript-eslint/utils": "7.0.2", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.1.tgz", - "integrity": "sha512-v7/T7As10g3bcWOOPAcbnMDuvctHzCFYCG/8R4bK4iYzdFqsZTbXGln0cZNVcwQcwewsYU2BJLay8j0/4zOk4w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1" + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2" } }, "@typescript-eslint/types": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.1.tgz", - "integrity": "sha512-uJDfmirz4FHib6ENju/7cz9SdMSkeVvJDK3VcMFvf/hAShg8C74FW+06MaQPODHfDJp/z/zHfgawIJRjlu0RLg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", + "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.1.tgz", - "integrity": "sha512-SO9wHb6ph0/FN5OJxH4MiPscGah5wjOd0RRpaLvuBv9g8565Fgu0uMySFEPqwPHiQU90yzJ2FjRYKGrAhS1xig==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", + "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/visitor-keys": "7.0.1", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/visitor-keys": "7.0.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7775,27 +7775,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.1.tgz", - "integrity": "sha512-oe4his30JgPbnv+9Vef1h48jm0S6ft4mNwi9wj7bX10joGn07QRfqIqFHoMiajrtoU88cIhXf8ahwgrcbNLgPA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.1", - "@typescript-eslint/types": "7.0.1", - "@typescript-eslint/typescript-estree": "7.0.1", + "@typescript-eslint/scope-manager": "7.0.2", + "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.1.tgz", - "integrity": "sha512-hwAgrOyk++RTXrP4KzCg7zB2U0xt7RUU0ZdMSCsqF3eKUwkdXUMyTb0qdCuji7VIbcpG62kKTU9M1J1c9UpFBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", + "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.0.1", + "@typescript-eslint/types": "7.0.2", "eslint-visitor-keys": "^3.4.1" } }, @@ -8459,9 +8459,9 @@ "requires": {} }, "eslint-plugin-jest": { - "version": "27.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.8.0.tgz", - "integrity": "sha512-347hVFiu4ZKMYl5xFp0X81gLNwBdno0dl0CMpUMjwuAux9X/M2a7z+ab2VHmPL6XCT87q8nv1vaVzhIO4TE/hw==", + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" diff --git a/package.json b/package.json index 57689dbc1b..c429646220 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mediasoup", - "version": "3.13.19", + "version": "3.13.20", "description": "Cutting Edge WebRTC Video Conferencing", "contributors": [ "IƱaki Baz Castillo (https://inakibaz.me)", @@ -110,12 +110,12 @@ "@octokit/rest": "^20.0.2", "@types/debug": "^4.1.12", "@types/jest": "^29.5.12", - "@types/node": "^20.11.17", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@types/node": "^20.11.19", + "@typescript-eslint/eslint-plugin": "^7.0.2", + "@typescript-eslint/parser": "^7.0.2", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-jest": "^27.8.0", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", "marked": "^12.0.0", diff --git a/rust/src/messages.rs b/rust/src/messages.rs index c05eed1e08..d06fcaaf52 100644 --- a/rust/src/messages.rs +++ b/rust/src/messages.rs @@ -669,6 +669,7 @@ pub(crate) struct RouterCreateWebrtcTransportData { enable_tcp: bool, prefer_udp: bool, prefer_tcp: bool, + ice_consent_timeout: u8, enable_sctp: bool, num_sctp_streams: NumSctpStreams, max_sctp_message_size: u32, @@ -701,6 +702,7 @@ impl RouterCreateWebrtcTransportData { enable_tcp: webrtc_transport_options.enable_tcp, prefer_udp: webrtc_transport_options.prefer_udp, prefer_tcp: webrtc_transport_options.prefer_tcp, + ice_consent_timeout: webrtc_transport_options.ice_consent_timeout, enable_sctp: webrtc_transport_options.enable_sctp, num_sctp_streams: webrtc_transport_options.num_sctp_streams, max_sctp_message_size: webrtc_transport_options.max_sctp_message_size, @@ -726,6 +728,7 @@ impl RouterCreateWebrtcTransportData { enable_tcp: self.enable_tcp, prefer_udp: self.prefer_udp, prefer_tcp: self.prefer_tcp, + ice_consent_timeout: self.ice_consent_timeout, } } } diff --git a/rust/src/router/webrtc_transport.rs b/rust/src/router/webrtc_transport.rs index a50a9dfa31..e3f8c3babe 100644 --- a/rust/src/router/webrtc_transport.rs +++ b/rust/src/router/webrtc_transport.rs @@ -129,6 +129,9 @@ pub struct WebRtcTransportOptions { /// Prefer TCP. /// Default false. pub prefer_tcp: bool, + /// ICE consent timeout (in seconds). If 0 it is disabled. + /// Default 30. + pub ice_consent_timeout: u8, /// Create a SCTP association. /// Default false. pub enable_sctp: bool, @@ -155,6 +158,7 @@ impl WebRtcTransportOptions { enable_tcp: false, prefer_udp: false, prefer_tcp: false, + ice_consent_timeout: 30, enable_sctp: false, num_sctp_streams: NumSctpStreams::default(), max_sctp_message_size: 262_144, @@ -172,6 +176,7 @@ impl WebRtcTransportOptions { enable_tcp: true, prefer_udp: false, prefer_tcp: false, + ice_consent_timeout: 30, enable_sctp: false, num_sctp_streams: NumSctpStreams::default(), max_sctp_message_size: 262_144, diff --git a/worker/Dockerfile.alpine b/worker/Dockerfile.alpine index b9b8e563ca..04689b61f0 100644 --- a/worker/Dockerfile.alpine +++ b/worker/Dockerfile.alpine @@ -15,7 +15,6 @@ ENV KEEP_BUILD_ARTIFACTS="1" # https://github.com/versatica/mediasoup/issues/1334 ENV MESON_ARGS="-Dms_disable_liburing=true" - WORKDIR /mediasoup CMD ["ash"] diff --git a/worker/fbs/webRtcTransport.fbs b/worker/fbs/webRtcTransport.fbs index 4c12fb968c..4d66c7a511 100644 --- a/worker/fbs/webRtcTransport.fbs +++ b/worker/fbs/webRtcTransport.fbs @@ -23,6 +23,7 @@ table WebRtcTransportOptions { enable_tcp: bool = true; prefer_udp: bool = false; prefer_tcp: bool = false; + ice_consent_timeout: uint8 = 30; } enum FingerprintAlgorithm: uint8 { diff --git a/worker/fuzzer/src/RTC/FuzzerStunPacket.cpp b/worker/fuzzer/src/RTC/FuzzerStunPacket.cpp index 2110f8f0e1..37d567778d 100644 --- a/worker/fuzzer/src/RTC/FuzzerStunPacket.cpp +++ b/worker/fuzzer/src/RTC/FuzzerStunPacket.cpp @@ -1,6 +1,9 @@ #include "RTC/FuzzerStunPacket.hpp" #include "RTC/StunPacket.hpp" +static constexpr size_t StunSerializeBufferSize{ 65536 }; +thread_local static uint8_t StunSerializeBuffer[StunSerializeBufferSize]; + void Fuzzer::RTC::StunPacket::Fuzz(const uint8_t* data, size_t len) { if (!::RTC::StunPacket::IsStun(data, len)) @@ -21,6 +24,7 @@ void Fuzzer::RTC::StunPacket::Fuzz(const uint8_t* data, size_t len) packet->GetData(); packet->GetSize(); packet->SetUsername("foo", 3); + packet->SetPassword("lalala"); packet->SetPriority(123); packet->SetIceControlling(123); packet->SetIceControlled(123); @@ -37,13 +41,21 @@ void Fuzzer::RTC::StunPacket::Fuzz(const uint8_t* data, size_t len) packet->GetErrorCode(); packet->HasMessageIntegrity(); packet->HasFingerprint(); - packet->CheckAuthentication("foo", "bar"); - // TODO: packet->CreateSuccessResponse(); // This cannot be easily tested. - // TODO: packet->CreateErrorResponse(); // This cannot be easily tested. - packet->Authenticate("lalala"); - // TODO: Cannot test Serialize() because we don't know the exact required - // buffer size (setters above may change the total size). - // TODO: packet->Serialize(); + packet->CheckAuthentication("foo", "xxx"); + + if (packet->GetClass() == ::RTC::StunPacket::Class::REQUEST) + { + auto* successResponse = packet->CreateSuccessResponse(); + auto* errorResponse = packet->CreateErrorResponse(444); + + delete successResponse; + delete errorResponse; + } + + if (len < StunSerializeBufferSize - 1000) + { + packet->Serialize(StunSerializeBuffer); + } delete packet; } diff --git a/worker/include/RTC/IceServer.hpp b/worker/include/RTC/IceServer.hpp index bde22a4642..72d7710363 100644 --- a/worker/include/RTC/IceServer.hpp +++ b/worker/include/RTC/IceServer.hpp @@ -2,15 +2,17 @@ #define MS_RTC_ICE_SERVER_HPP #include "common.hpp" +#include "Utils.hpp" #include "FBS/webRtcTransport.h" #include "RTC/StunPacket.hpp" #include "RTC/TransportTuple.hpp" +#include "handles/TimerHandle.hpp" #include #include namespace RTC { - class IceServer + class IceServer : public TimerHandle::Listener { public: enum class IceState @@ -53,8 +55,12 @@ namespace RTC }; public: - IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password); - ~IceServer(); + IceServer( + Listener* listener, + const std::string& usernameFragment, + const std::string& password, + uint8_t consentTimeoutSec); + ~IceServer() override; public: void ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple); @@ -74,28 +80,7 @@ namespace RTC { return this->selectedTuple; } - void RestartIce(const std::string& usernameFragment, const std::string& password) - { - if (!this->oldUsernameFragment.empty()) - { - this->listener->OnIceServerLocalUsernameFragmentRemoved(this, this->oldUsernameFragment); - } - - this->oldUsernameFragment = this->usernameFragment; - this->usernameFragment = usernameFragment; - - this->oldPassword = this->password; - this->password = password; - - this->remoteNomination = 0u; - - // Notify the listener. - this->listener->OnIceServerLocalUsernameFragmentAdded(this, usernameFragment); - - // NOTE: Do not call listener->OnIceServerLocalUsernameFragmentRemoved() - // yet with old usernameFragment. Wait until we receive a STUN packet - // with the new one. - } + void RestartIce(const std::string& usernameFragment, const std::string& password); bool IsValidTuple(const RTC::TransportTuple* tuple) const; void RemoveTuple(RTC::TransportTuple* tuple); /** @@ -105,6 +90,9 @@ namespace RTC void MayForceSelectedTuple(const RTC::TransportTuple* tuple); private: + void ProcessStunRequest(RTC::StunPacket* request, RTC::TransportTuple* tuple); + void ProcessStunIndication(RTC::StunPacket* indication); + void ProcessStunResponse(RTC::StunPacket* response); void HandleTuple( RTC::TransportTuple* tuple, bool hasUseCandidate, bool hasNomination, uint32_t nomination); /** @@ -120,19 +108,37 @@ namespace RTC * NOTE: The given tuple MUST be already stored within the list. */ void SetSelectedTuple(RTC::TransportTuple* storedTuple); + bool IsConsentCheckSupported() const + { + return this->consentTimeoutMs != 0u; + } + bool IsConsentCheckRunning() const + { + return (this->consentCheckTimer && this->consentCheckTimer->IsActive()); + } + void StartConsentCheck(); + void RestartConsentCheck(); + void StopConsentCheck(); + + /* Pure virtual methods inherited from TimerHandle::Listener. */ + public: + void OnTimer(TimerHandle* timer) override; private: // Passed by argument. Listener* listener{ nullptr }; - // Others. std::string usernameFragment; std::string password; + uint16_t consentTimeoutMs{ 30000u }; + // Others. std::string oldUsernameFragment; std::string oldPassword; IceState state{ IceState::NEW }; uint32_t remoteNomination{ 0u }; std::list tuples; RTC::TransportTuple* selectedTuple{ nullptr }; + TimerHandle* consentCheckTimer{ nullptr }; + uint64_t lastConsentRequestReceivedAtMs{ 0u }; }; } // namespace RTC diff --git a/worker/include/RTC/StunPacket.hpp b/worker/include/RTC/StunPacket.hpp index ab4846e237..1d781fff43 100644 --- a/worker/include/RTC/StunPacket.hpp +++ b/worker/include/RTC/StunPacket.hpp @@ -50,7 +50,7 @@ namespace RTC { OK = 0, UNAUTHORIZED = 1, - BAD_REQUEST = 2 + BAD_MESSAGE = 2 }; public: @@ -95,6 +95,10 @@ namespace RTC { return this->size; } + const uint8_t* GetTransactionId() const + { + return this->transactionId; + } void SetUsername(const char* username, size_t len) { this->username.assign(username, len); @@ -127,6 +131,10 @@ namespace RTC { this->errorCode = errorCode; } + void SetSoftware(const char* software, size_t len) + { + this->software.assign(software, len); + } void SetMessageIntegrity(const uint8_t* messageIntegrity) { this->messageIntegrity = messageIntegrity; @@ -139,6 +147,7 @@ namespace RTC { return this->username; } + void SetPassword(const std::string& password); uint32_t GetPriority() const { return this->priority; @@ -171,6 +180,10 @@ namespace RTC { return this->errorCode; } + std::string GetSoftware() const + { + return this->software; + } bool HasMessageIntegrity() const { return (this->messageIntegrity != nullptr); @@ -180,10 +193,11 @@ namespace RTC return this->hasFingerprint; } Authentication CheckAuthentication( - const std::string& localUsername, const std::string& localPassword); + // The first username fragment in the USERNAME attribute. + const std::string& usernameFragment1, + const std::string& password); StunPacket* CreateSuccessResponse(); StunPacket* CreateErrorResponse(uint16_t errorCode); - void Authenticate(const std::string& password); void Serialize(uint8_t* buffer); private: @@ -194,7 +208,8 @@ namespace RTC uint8_t* data{ nullptr }; // Pointer to binary data. size_t size{ 0u }; // The full message size (including header). // STUN attributes. - std::string username; // Less than 513 bytes. + std::string username; // Less than 513 bytes. + std::string password; uint32_t priority{ 0u }; // 4 bytes unsigned integer. uint64_t iceControlling{ 0u }; // 8 bytes unsigned integer. uint64_t iceControlled{ 0u }; // 8 bytes unsigned integer. @@ -205,7 +220,7 @@ namespace RTC bool hasFingerprint{ false }; // 4 bytes. const struct sockaddr* xorMappedAddress{ nullptr }; // 8 or 20 bytes. uint16_t errorCode{ 0u }; // 4 bytes (no reason phrase). - std::string password; + std::string software; // Less than 763 bytes. }; } // namespace RTC diff --git a/worker/src/RTC/IceServer.cpp b/worker/src/RTC/IceServer.cpp index e486b4629b..756cae8eb5 100644 --- a/worker/src/RTC/IceServer.cpp +++ b/worker/src/RTC/IceServer.cpp @@ -2,6 +2,7 @@ // #define MS_LOG_DEV_LEVEL 3 #include "RTC/IceServer.hpp" +#include "DepLibUV.hpp" #include "Logger.hpp" namespace RTC @@ -11,6 +12,8 @@ namespace RTC static constexpr size_t StunSerializeBufferSize{ 65536 }; thread_local static uint8_t StunSerializeBuffer[StunSerializeBufferSize]; static constexpr size_t MaxTuples{ 8 }; + static constexpr uint8_t ConsentCheckMinTimeoutSec{ 10u }; + static constexpr uint8_t ConsentCheckMaxTimeoutSec{ 60u }; /* Class methods. */ IceServer::IceState IceStateFromFbs(FBS::WebRtcTransport::IceState state) @@ -67,11 +70,40 @@ namespace RTC /* Instance methods. */ - IceServer::IceServer(Listener* listener, const std::string& usernameFragment, const std::string& password) + IceServer::IceServer( + Listener* listener, + const std::string& usernameFragment, + const std::string& password, + uint8_t consentTimeoutSec) : listener(listener), usernameFragment(usernameFragment), password(password) { MS_TRACE(); + if (consentTimeoutSec == 0u) + { + // 0 means disabled so it's a valid value. + } + else if (consentTimeoutSec < ConsentCheckMinTimeoutSec) + { + MS_WARN_TAG( + ice, + "consentTimeoutSec cannot be lower than %" PRIu8 " seconds, fixing it", + ConsentCheckMinTimeoutSec); + + consentTimeoutSec = ConsentCheckMinTimeoutSec; + } + else if (consentTimeoutSec > ConsentCheckMaxTimeoutSec) + { + MS_WARN_TAG( + ice, + "consentTimeoutSec cannot be higher than %" PRIu8 " seconds, fixing it", + ConsentCheckMaxTimeoutSec); + + consentTimeoutSec = ConsentCheckMaxTimeoutSec; + } + + this->consentTimeoutMs = consentTimeoutSec * 1000; + // Notify the listener. this->listener->OnIceServerLocalUsernameFragmentAdded(this, usernameFragment); } @@ -90,6 +122,7 @@ namespace RTC this->listener->OnIceServerLocalUsernameFragmentRemoved(this, this->oldUsernameFragment); } + // Clear all tuples. for (const auto& it : this->tuples) { auto* storedTuple = const_cast(std::addressof(it)); @@ -98,296 +131,383 @@ namespace RTC this->listener->OnIceServerTupleRemoved(this, storedTuple); } + // Clear all tuples. + // NOTE: Do it after notifying the listener since the listener may need to + // use/read the tuple being removed so we cannot free it yet. this->tuples.clear(); + + // Unset selected tuple. + this->selectedTuple = nullptr; + + // Delete the ICE consent check timer. + delete this->consentCheckTimer; + this->consentCheckTimer = nullptr; } void IceServer::ProcessStunPacket(RTC::StunPacket* packet, RTC::TransportTuple* tuple) { MS_TRACE(); - // Must be a Binding method. - if (packet->GetMethod() != RTC::StunPacket::Method::BINDING) + switch (packet->GetClass()) { - if (packet->GetClass() == RTC::StunPacket::Class::REQUEST) + case RTC::StunPacket::Class::REQUEST: { - MS_WARN_TAG( - ice, - "unknown method %#.3x in STUN Request => 400", - static_cast(packet->GetMethod())); + ProcessStunRequest(packet, tuple); - // Reply 400. - RTC::StunPacket* response = packet->CreateErrorResponse(400); + break; + } - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + case RTC::StunPacket::Class::INDICATION: + { + ProcessStunIndication(packet); - delete response; + break; } - else + + case RTC::StunPacket::Class::SUCCESS_RESPONSE: + case RTC::StunPacket::Class::ERROR_RESPONSE: { - MS_WARN_TAG( - ice, - "ignoring STUN Indication or Response with unknown method %#.3x", - static_cast(packet->GetMethod())); + ProcessStunResponse(packet); + + break; } - return; + default: + { + MS_WARN_TAG(ice, "unknown STUN class %" PRIu16 ", discarded", packet->GetClass()); + } } + } - // Must use FINGERPRINT (optional for ICE STUN indications). - if (!packet->HasFingerprint() && packet->GetClass() != RTC::StunPacket::Class::INDICATION) + void IceServer::RestartIce(const std::string& usernameFragment, const std::string& password) + { + MS_TRACE(); + + if (!this->oldUsernameFragment.empty()) { - if (packet->GetClass() == RTC::StunPacket::Class::REQUEST) - { - MS_WARN_TAG(ice, "STUN Binding Request without FINGERPRINT => 400"); + this->listener->OnIceServerLocalUsernameFragmentRemoved(this, this->oldUsernameFragment); + } - // Reply 400. - RTC::StunPacket* response = packet->CreateErrorResponse(400); + this->oldUsernameFragment = this->usernameFragment; + this->usernameFragment = usernameFragment; - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + this->oldPassword = this->password; + this->password = password; - delete response; - } - else + this->remoteNomination = 0u; + + // Notify the listener. + this->listener->OnIceServerLocalUsernameFragmentAdded(this, usernameFragment); + + // NOTE: Do not call listener->OnIceServerLocalUsernameFragmentRemoved() + // yet with old usernameFragment. Wait until we receive a STUN packet + // with the new one. + + // Restart ICE consent check (if running) to give some time to the + // client to establish ICE again. + if (IsConsentCheckSupported() && IsConsentCheckRunning()) + { + RestartConsentCheck(); + } + } + + bool IceServer::IsValidTuple(const RTC::TransportTuple* tuple) const + { + MS_TRACE(); + + return HasTuple(tuple) != nullptr; + } + + void IceServer::RemoveTuple(RTC::TransportTuple* tuple) + { + MS_TRACE(); + + RTC::TransportTuple* removedTuple{ nullptr }; + + // Find the removed tuple. + auto it = this->tuples.begin(); + + for (; it != this->tuples.end(); ++it) + { + RTC::TransportTuple* storedTuple = std::addressof(*it); + + if (storedTuple->Compare(tuple)) { - MS_WARN_TAG(ice, "ignoring STUN Binding Response without FINGERPRINT"); + removedTuple = storedTuple; + + break; } + } + // If not found, ignore. + if (!removedTuple) + { return; } - switch (packet->GetClass()) - { - case RTC::StunPacket::Class::REQUEST: - { - // USERNAME, MESSAGE-INTEGRITY and PRIORITY are required. - if (!packet->HasMessageIntegrity() || (packet->GetPriority() == 0u) || packet->GetUsername().empty()) - { - MS_WARN_TAG(ice, "mising required attributes in STUN Binding Request => 400"); + // Notify the listener. + this->listener->OnIceServerTupleRemoved(this, removedTuple); - // Reply 400. - RTC::StunPacket* response = packet->CreateErrorResponse(400); + // Remove it from the list of tuples. + // NOTE: Do it after notifying the listener since the listener may need to + // use/read the tuple being removed so we cannot free it yet. + this->tuples.erase(it); - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + // If this is the selected tuple, do things. + if (removedTuple == this->selectedTuple) + { + this->selectedTuple = nullptr; - delete response; + // Mark the first tuple as selected tuple (if any) but only if state was + // 'connected' or 'completed'. + if ( + (this->state == IceState::CONNECTED || this->state == IceState::COMPLETED) && + this->tuples.begin() != this->tuples.end()) + { + SetSelectedTuple(std::addressof(*this->tuples.begin())); - return; + // Restart ICE consent check to let the client send new consent requests + // on the new selected tuple. + if (IsConsentCheckSupported()) + { + RestartConsentCheck(); } + } + // Or just emit 'disconnected'. + else + { + // Update state. + this->state = IceState::DISCONNECTED; - // Check authentication. - switch (packet->CheckAuthentication(this->usernameFragment, this->password)) - { - case RTC::StunPacket::Authentication::OK: - { - if (!this->oldUsernameFragment.empty() && !this->oldPassword.empty()) - { - MS_DEBUG_TAG(ice, "new ICE credentials applied"); + // Reset remote nomination. + this->remoteNomination = 0u; - // Notify the listener. - this->listener->OnIceServerLocalUsernameFragmentRemoved(this, this->oldUsernameFragment); + // Notify the listener. + this->listener->OnIceServerDisconnected(this); - this->oldUsernameFragment.clear(); - this->oldPassword.clear(); - } + if (IsConsentCheckSupported() && IsConsentCheckRunning()) + { + StopConsentCheck(); + } + } + } + } - break; - } + void IceServer::ProcessStunRequest(RTC::StunPacket* request, RTC::TransportTuple* tuple) + { + MS_TRACE(); - case RTC::StunPacket::Authentication::UNAUTHORIZED: - { - // We may have changed our usernameFragment and password, so check - // the old ones. - // clang-format off - if ( - !this->oldUsernameFragment.empty() && - !this->oldPassword.empty() && - packet->CheckAuthentication(this->oldUsernameFragment, this->oldPassword) == RTC::StunPacket::Authentication::OK - ) - // clang-format on - { - MS_DEBUG_TAG(ice, "using old ICE credentials"); + MS_DEBUG_DEV("processing STUN request"); - break; - } + // Must be a Binding method. + if (request->GetMethod() != RTC::StunPacket::Method::BINDING) + { + MS_WARN_TAG( + ice, + "STUN request with unknown method %#.3x => 400", + static_cast(request->GetMethod())); - MS_WARN_TAG(ice, "wrong authentication in STUN Binding Request => 401"); + // Reply 400. + RTC::StunPacket* response = request->CreateErrorResponse(400); - // Reply 401. - RTC::StunPacket* response = packet->CreateErrorResponse(401); + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + delete response; - delete response; + return; + } - return; - } + // Must have FINGERPRINT attribute. + if (!request->HasFingerprint()) + { + MS_WARN_TAG(ice, "STUN Binding request without FINGERPRINT attribute => 400"); - case RTC::StunPacket::Authentication::BAD_REQUEST: - { - MS_WARN_TAG(ice, "cannot check authentication in STUN Binding Request => 400"); + // Reply 400. + RTC::StunPacket* response = request->CreateErrorResponse(400); - // Reply 400. - RTC::StunPacket* response = packet->CreateErrorResponse(400); + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + delete response; - delete response; + return; + } - return; - } - } + // PRIORITY attribute is required. + if (request->GetPriority() == 0u) + { + MS_WARN_TAG(ice, "STUN Binding request without PRIORITY attribute => 400"); - // The remote peer must be ICE controlling. - if (packet->GetIceControlled()) - { - MS_WARN_TAG(ice, "peer indicates ICE-CONTROLLED in STUN Binding Request => 487"); + // Reply 400. + RTC::StunPacket* response = request->CreateErrorResponse(400); - // Reply 487 (Role Conflict). - RTC::StunPacket* response = packet->CreateErrorResponse(487); + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - response->Serialize(StunSerializeBuffer); - this->listener->OnIceServerSendStunPacket(this, response, tuple); + delete response; - delete response; + return; + } - return; - } + // Check authentication. + switch (request->CheckAuthentication(this->usernameFragment, this->password)) + { + case RTC::StunPacket::Authentication::OK: + { + if (!this->oldUsernameFragment.empty() && !this->oldPassword.empty()) + { + MS_DEBUG_TAG(ice, "new ICE credentials applied"); - MS_DEBUG_DEV( - "processing STUN Binding Request [Priority:%" PRIu32 ", UseCandidate:%s]", - static_cast(packet->GetPriority()), - packet->HasUseCandidate() ? "true" : "false"); + // Notify the listener. + this->listener->OnIceServerLocalUsernameFragmentRemoved(this, this->oldUsernameFragment); - // Create a success response. - RTC::StunPacket* response = packet->CreateSuccessResponse(); + this->oldUsernameFragment.clear(); + this->oldPassword.clear(); + } - // Add XOR-MAPPED-ADDRESS. - response->SetXorMappedAddress(tuple->GetRemoteAddress()); + break; + } - // Authenticate the response. - if (this->oldPassword.empty()) - { - response->Authenticate(this->password); - } - else + case RTC::StunPacket::Authentication::UNAUTHORIZED: + { + // We may have changed our usernameFragment and password, so check the + // old ones. + // clang-format off + if ( + !this->oldUsernameFragment.empty() && + !this->oldPassword.empty() && + request->CheckAuthentication( + this->oldUsernameFragment, this->oldPassword + ) == RTC::StunPacket::Authentication::OK + ) + // clang-format on { - response->Authenticate(this->oldPassword); + MS_DEBUG_TAG(ice, "using old ICE credentials"); + + break; } - // Send back. + MS_WARN_TAG(ice, "wrong authentication in STUN Binding request => 401"); + + // Reply 401. + RTC::StunPacket* response = request->CreateErrorResponse(401); + response->Serialize(StunSerializeBuffer); this->listener->OnIceServerSendStunPacket(this, response, tuple); delete response; - uint32_t nomination{ 0u }; - - if (packet->HasNomination()) - { - nomination = packet->GetNomination(); - } - - // Handle the tuple. - HandleTuple(tuple, packet->HasUseCandidate(), packet->HasNomination(), nomination); - - break; + return; } - case RTC::StunPacket::Class::INDICATION: + case RTC::StunPacket::Authentication::BAD_MESSAGE: { - MS_DEBUG_TAG(ice, "STUN Binding Indication processed"); + MS_WARN_TAG(ice, "cannot check authentication in STUN Binding request => 400"); - break; - } - - case RTC::StunPacket::Class::SUCCESS_RESPONSE: - { - MS_DEBUG_TAG(ice, "STUN Binding Success Response processed"); + // Reply 400. + RTC::StunPacket* response = request->CreateErrorResponse(400); - break; - } + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - case RTC::StunPacket::Class::ERROR_RESPONSE: - { - MS_DEBUG_TAG(ice, "STUN Binding Error Response processed"); + delete response; - break; + return; } } - } - bool IceServer::IsValidTuple(const RTC::TransportTuple* tuple) const - { - MS_TRACE(); + // The remote peer must be ICE controlling. + if (request->GetIceControlled()) + { + MS_WARN_TAG(ice, "peer indicates ICE-CONTROLLED in STUN Binding request => 487"); - return HasTuple(tuple) != nullptr; - } + // Reply 487 (Role Conflict). + RTC::StunPacket* response = request->CreateErrorResponse(487); - void IceServer::RemoveTuple(RTC::TransportTuple* tuple) - { - MS_TRACE(); + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - RTC::TransportTuple* removedTuple{ nullptr }; + delete response; - // Find the removed tuple. - auto it = this->tuples.begin(); + return; + } - for (; it != this->tuples.end(); ++it) - { - RTC::TransportTuple* storedTuple = std::addressof(*it); + MS_DEBUG_DEV( + "valid STUN Binding request [priority:%" PRIu32 ", useCandidate:%s]", + static_cast(request->GetPriority()), + request->HasUseCandidate() ? "true" : "false"); - if (storedTuple->Compare(tuple)) - { - removedTuple = storedTuple; + // Create a success response. + RTC::StunPacket* response = request->CreateSuccessResponse(); - break; - } - } + // Add XOR-MAPPED-ADDRESS. + response->SetXorMappedAddress(tuple->GetRemoteAddress()); - // If not found, ignore. - if (!removedTuple) + // Authenticate the response. + if (this->oldPassword.empty()) { - return; + response->SetPassword(this->password); + } + else + { + response->SetPassword(this->oldPassword); } - // Notify the listener. - this->listener->OnIceServerTupleRemoved(this, removedTuple); + // Send back. + response->Serialize(StunSerializeBuffer); + this->listener->OnIceServerSendStunPacket(this, response, tuple); - // Remove it from the list of tuples. - // NOTE: Do it after notifying the listener since the listener may need to - // use/read the tuple being removed so we cannot free it yet. - this->tuples.erase(it); + delete response; - // If this is the selected tuple, do things. - if (removedTuple == this->selectedTuple) + uint32_t nomination{ 0u }; + + if (request->HasNomination()) { - this->selectedTuple = nullptr; + nomination = request->GetNomination(); + } - // Mark the first tuple as selected tuple (if any). - if (this->tuples.begin() != this->tuples.end()) + // Handle the tuple. + HandleTuple(tuple, request->HasUseCandidate(), request->HasNomination(), nomination); + + // If state is 'connected' or 'completed' after handling the tuple, then + // start or restart ICE consent check (if supported). + if (IsConsentCheckSupported() && (this->state == IceState::CONNECTED || this->state == IceState::COMPLETED)) + { + if (IsConsentCheckRunning()) { - SetSelectedTuple(std::addressof(*this->tuples.begin())); + RestartConsentCheck(); } - // Or just emit 'disconnected'. else { - // Update state. - this->state = IceState::DISCONNECTED; - - // Reset remote nomination. - this->remoteNomination = 0u; - - // Notify the listener. - this->listener->OnIceServerDisconnected(this); + StartConsentCheck(); } } } + void IceServer::ProcessStunIndication(RTC::StunPacket* indication) + { + MS_TRACE(); + + MS_DEBUG_DEV("STUN indication received, discarded"); + + // Nothig else to do. We just discard STUN indications. + } + + void IceServer::ProcessStunResponse(RTC::StunPacket* response) + { + MS_TRACE(); + + const std::string responseType = response->GetClass() == RTC::StunPacket::Class::SUCCESS_RESPONSE + ? "success" + : std::to_string(response->GetErrorCode()) + " error"; + + MS_DEBUG_DEV("processing STUN %s response received, discarded", responseType.c_str()); + + // Nothig else to do. We just discard STUN responses because we do not + // generate STUN requests. + } + void IceServer::MayForceSelectedTuple(const RTC::TransportTuple* tuple) { MS_TRACE(); @@ -408,7 +528,6 @@ namespace RTC return; } - // Mark it as selected tuple. SetSelectedTuple(storedTuple); } @@ -437,12 +556,12 @@ namespace RTC // Store the tuple. auto* storedTuple = AddTuple(tuple); - // Mark it as selected tuple. - SetSelectedTuple(storedTuple); - // Update state. this->state = IceState::CONNECTED; + // Mark it as selected tuple. + SetSelectedTuple(storedTuple); + // Notify the listener. this->listener->OnIceServerConnected(this); } @@ -461,12 +580,12 @@ namespace RTC hasNomination ? "true" : "false", nomination); - // Mark it as selected tuple. - SetSelectedTuple(storedTuple); - // Update state. this->state = IceState::COMPLETED; + // Mark it as selected tuple. + SetSelectedTuple(storedTuple); + // Update nomination. if (hasNomination && nomination > this->remoteNomination) { @@ -499,12 +618,12 @@ namespace RTC // Store the tuple. auto* storedTuple = AddTuple(tuple); - // Mark it as selected tuple. - SetSelectedTuple(storedTuple); - // Update state. this->state = IceState::CONNECTED; + // Mark it as selected tuple. + SetSelectedTuple(storedTuple); + // Notify the listener. this->listener->OnIceServerConnected(this); } @@ -523,12 +642,12 @@ namespace RTC hasNomination ? "true" : "false", nomination); - // Mark it as selected tuple. - SetSelectedTuple(storedTuple); - // Update state. this->state = IceState::COMPLETED; + // Mark it as selected tuple. + SetSelectedTuple(storedTuple); + // Update nomination. if (hasNomination && nomination > this->remoteNomination) { @@ -571,12 +690,12 @@ namespace RTC if ((hasNomination && nomination > this->remoteNomination) || !hasNomination) { - // Mark it as selected tuple. - SetSelectedTuple(storedTuple); - // Update state. this->state = IceState::COMPLETED; + // Mark it as selected tuple. + SetSelectedTuple(storedTuple); + // Update nomination. if (hasNomination && nomination > this->remoteNomination) { @@ -627,7 +746,7 @@ namespace RTC } } - inline RTC::TransportTuple* IceServer::AddTuple(RTC::TransportTuple* tuple) + RTC::TransportTuple* IceServer::AddTuple(RTC::TransportTuple* tuple) { MS_TRACE(); @@ -635,7 +754,7 @@ namespace RTC if (storedTuple) { - MS_DEBUG_DEV('tuple already exists'); + MS_DEBUG_DEV("tuple already exists"); return storedTuple; } @@ -695,7 +814,7 @@ namespace RTC return storedTuple; } - inline RTC::TransportTuple* IceServer::HasTuple(const RTC::TransportTuple* tuple) const + RTC::TransportTuple* IceServer::HasTuple(const RTC::TransportTuple* tuple) const { MS_TRACE(); @@ -719,7 +838,7 @@ namespace RTC return nullptr; } - inline void IceServer::SetSelectedTuple(RTC::TransportTuple* storedTuple) + void IceServer::SetSelectedTuple(RTC::TransportTuple* storedTuple) { MS_TRACE(); @@ -734,4 +853,88 @@ namespace RTC // Notify the listener. this->listener->OnIceServerSelectedTuple(this, this->selectedTuple); } + + void IceServer::StartConsentCheck() + { + MS_TRACE(); + + MS_ASSERT(IsConsentCheckSupported(), "ICE consent check not supported"); + MS_ASSERT(!IsConsentCheckRunning(), "ICE consent check already running"); + MS_ASSERT(this->selectedTuple, "no selected tuple"); + + // Create the ICE consent check timer if it doesn't exist. + if (!this->consentCheckTimer) + { + this->consentCheckTimer = new TimerHandle(this); + } + + this->consentCheckTimer->Start(this->consentTimeoutMs); + } + + void IceServer::RestartConsentCheck() + { + MS_TRACE(); + + MS_ASSERT(IsConsentCheckSupported(), "ICE consent check not supported"); + MS_ASSERT(IsConsentCheckRunning(), "ICE consent check not running"); + MS_ASSERT(this->selectedTuple, "no selected tuple"); + + this->consentCheckTimer->Restart(); + } + + void IceServer::StopConsentCheck() + { + MS_TRACE(); + + MS_ASSERT(IsConsentCheckSupported(), "ICE consent check not supported"); + MS_ASSERT(IsConsentCheckRunning(), "ICE consent check not running"); + + this->consentCheckTimer->Stop(); + } + + inline void IceServer::OnTimer(TimerHandle* timer) + { + MS_TRACE(); + + if (timer == this->consentCheckTimer) + { + MS_ASSERT(IsConsentCheckSupported(), "ICE consent check not supported"); + + // State must be 'connected' or 'completed'. + MS_ASSERT( + this->state == IceState::COMPLETED || this->state == IceState::CONNECTED, + "ICE consent check timer fired but state is neither 'completed' nor 'connected'"); + + // There should be a selected tuple. + MS_ASSERT(this->selectedTuple, "ICE consent check timer fired but there is not selected tuple"); + + MS_WARN_TAG(ice, "ICE consent expired due to timeout, moving to 'disconnected' state"); + + // Update state. + this->state = IceState::DISCONNECTED; + + // Reset remote nomination. + this->remoteNomination = 0u; + + // Clear all tuples. + for (const auto& it : this->tuples) + { + auto* storedTuple = const_cast(std::addressof(it)); + + // Notify the listener. + this->listener->OnIceServerTupleRemoved(this, storedTuple); + } + + // Clear all tuples. + // NOTE: Do it after notifying the listener since the listener may need to + // use/read the tuple being removed so we cannot free it yet. + this->tuples.clear(); + + // Unset selected tuple. + this->selectedTuple = nullptr; + + // Notify the listener. + this->listener->OnIceServerDisconnected(this); + } + } } // namespace RTC diff --git a/worker/src/RTC/KeyFrameRequestManager.cpp b/worker/src/RTC/KeyFrameRequestManager.cpp index 1112901b49..540414ae0c 100644 --- a/worker/src/RTC/KeyFrameRequestManager.cpp +++ b/worker/src/RTC/KeyFrameRequestManager.cpp @@ -4,7 +4,7 @@ #include "RTC/KeyFrameRequestManager.hpp" #include "Logger.hpp" -static constexpr uint32_t KeyFrameRetransmissionWaitTime{ 1000 }; +static constexpr uint32_t KeyFrameRetransmissionWaitTime{ 1000u }; /* PendingKeyFrameInfo methods. */ diff --git a/worker/src/RTC/StunPacket.cpp b/worker/src/RTC/StunPacket.cpp index 518ca8ff97..6747afebd1 100644 --- a/worker/src/RTC/StunPacket.cpp +++ b/worker/src/RTC/StunPacket.cpp @@ -24,23 +24,21 @@ namespace RTC return nullptr; } - /* - The message type field is decomposed further into the following - structure: - - 0 1 - 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ - |M |M |M|M|M|C|M|M|M|C|M|M|M|M| - |11|10|9|8|7|1|6|5|4|0|3|2|1|0| - +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ - - Figure 3: Format of STUN Message Type Field - - Here the bits in the message type field are shown as most significant - (M11) through least significant (M0). M11 through M0 represent a 12- - bit encoding of the method. C1 and C0 represent a 2-bit encoding of - the class. + /** + * The message type field is decomposed further into the following + * structure: + * + * 0 1 + * 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + * |M |M |M|M|M|C|M|M|M|C|M|M|M|M| + * |11|10|9|8|7|1|6|5|4|0|3|2|1|0| + * +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Here the bits in the message type field are shown as most significant + * (M11) through least significant (M0). M11 through M0 represent a 12-bit + * encoding of the method. C1 and C0 represent a 2-bit encoding of the + * class. */ // Get type field. @@ -49,7 +47,8 @@ namespace RTC // Get length field. const uint16_t msgLength = Utils::Byte::Get2Bytes(data, 2); - // length field must be total size minus header's 20 bytes, and must be multiple of 4 Bytes. + // length field must be total size minus header's 20 bytes, and must be + // multiple of 4 Bytes. if ((static_cast(msgLength) != len - 20) || ((msgLength & 0x03) != 0)) { MS_WARN_TAG( @@ -67,35 +66,38 @@ namespace RTC // Get STUN class. const uint16_t msgClass = ((data[0] & 0x01) << 1) | ((data[1] & 0x10) >> 4); - // Create a new StunPacket (data + 8 points to the received TransactionID field). + // Create a new StunPacket (data + 8 points to the received TransactionID + // field). auto* packet = new StunPacket( static_cast(msgClass), static_cast(msgMethod), data + 8, data, len); - /* - STUN Attributes - - After the STUN header are zero or more attributes. Each attribute - MUST be TLV encoded, with a 16-bit type, 16-bit length, and value. - Each STUN attribute MUST end on a 32-bit boundary. As mentioned - above, all fields in an attribute are transmitted most significant - bit first. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Value (variable) .... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + /** + * STUN Attributes + * + * After the STUN header are zero or more attributes. Each attribute MUST + * be TLV encoded, with a 16-bit type, 16-bit length, and value. Each STUN + * attribute MUST end on a 32-bit boundary. As mentioned above, all fields + * in an attribute are transmitted most significant bit first. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Value (variable) .... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ // Start looking for attributes after STUN header (Byte #20). size_t pos{ 20 }; - // Flags (positions) for special MESSAGE-INTEGRITY and FINGERPRINT attributes. + // Flags (positions) for special MESSAGE-INTEGRITY and FINGERPRINT + // attributes. bool hasMessageIntegrity{ false }; bool hasFingerprint{ false }; - size_t fingerprintAttrPos; // Will point to the beginning of the attribute. - uint32_t fingerprint; // Holds the value of the FINGERPRINT attribute. + // Will point to the beginning of the attribute. + size_t fingerprintAttrPos; + // Holds the value of the FINGERPRINT attribute. + uint32_t fingerprint; // Ensure there are at least 4 remaining bytes (attribute with 0 length). while (pos + 4 <= len) @@ -285,6 +287,24 @@ namespace RTC break; } + case Attribute::SOFTWARE: + { + // Ensure attribute length is less than 763 bytes. + if (attrLength >= 763) + { + MS_WARN_TAG( + ice, "attribute SOFTWARE must be less than 763 bytes length, packet discarded"); + + delete packet; + return nullptr; + } + + packet->SetSoftware( + reinterpret_cast(attrValuePos), static_cast(attrLength)); + + break; + } + default:; } @@ -351,16 +371,16 @@ namespace RTC switch (this->klass) { case Class::REQUEST: - klass = "Request"; + klass = "request"; break; case Class::INDICATION: - klass = "Indication"; + klass = "indication"; break; case Class::SUCCESS_RESPONSE: - klass = "SuccessResponse"; + klass = "success response"; break; case Class::ERROR_RESPONSE: - klass = "ErrorResponse"; + klass = "error response"; break; } if (this->method == Method::BINDING) @@ -374,14 +394,11 @@ namespace RTC } MS_DUMP(" size: %zu bytes", this->size); - char transactionId[25]; + auto transactionId1 = Utils::Byte::Get4Bytes(this->transactionId, 0); + auto transactionId2 = Utils::Byte::Get8Bytes(this->transactionId, 4); - for (int i{ 0 }; i < 12; ++i) - { - // NOTE: n must be 3 because snprintf adds a \0 after printed chars. - std::snprintf(transactionId + (i * 2), 3, "%.2x", this->transactionId[i]); - } - MS_DUMP(" transactionId: %s", transactionId); + MS_DUMP(" transactionId (first 4 bytes): %" PRIu32, transactionId1); + MS_DUMP(" transactionId (last 8 bytes): %" PRIu64, transactionId2); if (this->errorCode != 0u) { MS_DUMP(" errorCode: %" PRIu16, this->errorCode); @@ -406,6 +423,10 @@ namespace RTC { MS_DUMP(" useCandidate"); } + if (!this->software.empty()) + { + MS_DUMP(" software: %s", this->software.c_str()); + } if (this->xorMappedAddress != nullptr) { int family; @@ -435,8 +456,21 @@ namespace RTC MS_DUMP(""); } + void StunPacket::SetPassword(const std::string& password) + { + // Just for request, indication and success response messages. + if (this->klass == Class::ERROR_RESPONSE) + { + MS_ERROR("cannot set password for error responses"); + + return; + } + + this->password = password; + } + StunPacket::Authentication StunPacket::CheckAuthentication( - const std::string& localUsername, const std::string& localPassword) + const std::string& usernameFragment1, const std::string& password) { MS_TRACE(); @@ -445,46 +479,82 @@ namespace RTC case Class::REQUEST: case Class::INDICATION: { - // Both USERNAME and MESSAGE-INTEGRITY must be present. - if (!this->messageIntegrity || this->username.empty()) + // usernameFragment1 must be given. + if (usernameFragment1.empty()) + { + MS_WARN_TAG(ice, "usernameFragment1 not given, cannot authenticate request or indication"); + + return Authentication::BAD_MESSAGE; + } + + // USERNAME attribute must be present. + if (this->username.empty()) + { + MS_WARN_TAG(ice, "missing USERNAME attribute, cannot authenticate request or indication"); + + return Authentication::BAD_MESSAGE; + } + + // MESSAGE-INTEGRITY attribute must be present. + if (!this->messageIntegrity) { - return Authentication::BAD_REQUEST; + MS_WARN_TAG( + ice, "missing MESSAGE-INTEGRITY attribute, cannot authenticate request or indication"); + + return Authentication::BAD_MESSAGE; } - // Check that USERNAME attribute begins with our local username plus ":". - const size_t localUsernameLen = localUsername.length(); + // Check that the USERNAME attribute begins with the first username + // fragment plus ":". + const size_t usernameFragment1Len = usernameFragment1.length(); if ( - this->username.length() <= localUsernameLen || this->username.at(localUsernameLen) != ':' || - (this->username.compare(0, localUsernameLen, localUsername) != 0)) + this->username.length() <= usernameFragment1Len || + this->username.at(usernameFragment1Len) != ':' || + this->username.compare(0, usernameFragment1Len, usernameFragment1) != 0) { return Authentication::UNAUTHORIZED; } break; } - // This method cannot check authentication in received responses (as we - // are ICE-Lite and don't generate requests). + case Class::SUCCESS_RESPONSE: case Class::ERROR_RESPONSE: { - MS_ERROR("cannot check authentication for a STUN response"); + // MESSAGE-INTEGRITY attribute must be present. + if (!this->messageIntegrity) + { + MS_WARN_TAG(ice, "missing MESSAGE-INTEGRITY attribute, cannot authenticate response"); - return Authentication::BAD_REQUEST; + return Authentication::BAD_MESSAGE; + } + + break; + } + + default: + { + MS_WARN_TAG(ice, "unknown STUN class %" PRIu16 ", cannot authenticate", this->klass); + + return Authentication::BAD_MESSAGE; } } - // If there is FINGERPRINT it must be discarded for MESSAGE-INTEGRITY calculation, - // so the header length field must be modified (and later restored). + // If there is FINGERPRINT it must be discarded for MESSAGE-INTEGRITY + // calculation, so the header length field must be modified (and later + // restored). if (this->hasFingerprint) { - // Set the header length field: full size - header length (20) - FINGERPRINT length (8). + // Set the header length field: full size - header length (20) - + // FINGERPRINT length (8). Utils::Byte::Set2Bytes(this->data, 2, static_cast(this->size - 20 - 8)); } - // Calculate the HMAC-SHA1 of the message according to MESSAGE-INTEGRITY rules. - const uint8_t* computedMessageIntegrity = Utils::Crypto::GetHmacSha1( - localPassword, this->data, (this->messageIntegrity - 4) - this->data); + // Calculate the HMAC-SHA1 of the message according to MESSAGE-INTEGRITY + // rules. + const uint8_t* computedMessageIntegrity = + Utils::Crypto::GetHmacSha1(password, this->data, (this->messageIntegrity - 4) - this->data); Authentication result; @@ -513,7 +583,7 @@ namespace RTC MS_ASSERT( this->klass == Class::REQUEST, - "attempt to create a success response for a non Request STUN packet"); + "attempt to create a success response for a non request STUN packet"); return new StunPacket(Class::SUCCESS_RESPONSE, this->method, this->transactionId, nullptr, 0); } @@ -524,7 +594,7 @@ namespace RTC MS_ASSERT( this->klass == Class::REQUEST, - "attempt to create an error response for a non Request STUN packet"); + "attempt to create an error response for a non request STUN packet"); auto* response = new StunPacket(Class::ERROR_RESPONSE, this->method, this->transactionId, nullptr, 0); @@ -534,19 +604,6 @@ namespace RTC return response; } - void StunPacket::Authenticate(const std::string& password) - { - // Just for Request, Indication and SuccessResponse messages. - if (this->klass == Class::ERROR_RESPONSE) - { - MS_ERROR("cannot set password for ErrorResponse messages"); - - return; - } - - this->password = password; - } - void StunPacket::Serialize(uint8_t* buffer) { MS_TRACE(); @@ -807,7 +864,8 @@ namespace RTC Utils::Byte::Set2Bytes(buffer, 2, static_cast(this->size - 20 - 8)); } - // Calculate the HMAC-SHA1 of the packet according to MESSAGE-INTEGRITY rules. + // Calculate the HMAC-SHA1 of the packet according to MESSAGE-INTEGRITY + // rules. const uint8_t* computedMessageIntegrity = Utils::Crypto::GetHmacSha1(this->password, buffer, pos); diff --git a/worker/src/RTC/Transport.cpp b/worker/src/RTC/Transport.cpp index 830b31ddb7..ea5426970f 100644 --- a/worker/src/RTC/Transport.cpp +++ b/worker/src/RTC/Transport.cpp @@ -3083,8 +3083,8 @@ namespace RTC /* * The interval between RTCP packets is varied randomly over the range - * [1.0,1.5] times the calculated interval to avoid unintended synchronization - * of all participants. + * [1.0, 1.5] times the calculated interval to avoid unintended + * synchronization of all participants. */ interval *= static_cast(Utils::Crypto::GetRandomUInt(10, 15)) / 10; diff --git a/worker/src/RTC/WebRtcServer.cpp b/worker/src/RTC/WebRtcServer.cpp index bd1c095c13..362b43d455 100644 --- a/worker/src/RTC/WebRtcServer.cpp +++ b/worker/src/RTC/WebRtcServer.cpp @@ -499,7 +499,7 @@ namespace RTC if (this->mapTupleWebRtcTransport.find(tuple->hash) == this->mapTupleWebRtcTransport.end()) { - MS_WARN_TAG(ice, "tuple hash not found in the table"); + MS_DEBUG_TAG(ice, "tuple hash not found in the table"); return; } diff --git a/worker/src/RTC/WebRtcTransport.cpp b/worker/src/RTC/WebRtcTransport.cpp index c718c1179a..a5deb26fe0 100644 --- a/worker/src/RTC/WebRtcTransport.cpp +++ b/worker/src/RTC/WebRtcTransport.cpp @@ -160,9 +160,11 @@ namespace RTC iceLocalPreferenceDecrement += 100; } + auto iceConsentTimeout = options->iceConsentTimeout(); + // Create a ICE server. this->iceServer = new RTC::IceServer( - this, Utils::Crypto::GetRandomString(32), Utils::Crypto::GetRandomString(32)); + this, Utils::Crypto::GetRandomString(32), Utils::Crypto::GetRandomString(32), iceConsentTimeout); // Create a DTLS transport. this->dtlsTransport = new RTC::DtlsTransport(this); @@ -227,9 +229,11 @@ namespace RTC MS_THROW_TYPE_ERROR("empty iceCandidates"); } + auto iceConsentTimeout = options->iceConsentTimeout(); + // Create a ICE server. this->iceServer = new RTC::IceServer( - this, Utils::Crypto::GetRandomString(32), Utils::Crypto::GetRandomString(32)); + this, Utils::Crypto::GetRandomString(32), Utils::Crypto::GetRandomString(32), iceConsentTimeout); // Create a DTLS transport. this->dtlsTransport = new RTC::DtlsTransport(this); @@ -435,7 +439,8 @@ namespace RTC MS_THROW_ERROR("connect() already called"); } - const auto* body = request->data->body_as(); + const auto* body = request->data->body_as(); + const auto* dtlsParameters = body->dtlsParameters(); RTC::DtlsTransport::Fingerprint dtlsRemoteFingerprint;