From 65bbd1acb6a80f94a84404303b87c2798330a11c Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sat, 12 Dec 2020 12:41:26 +0000 Subject: Issue #1695 - Add clamping to websocket polling timeouts. --- modules/libpref/init/all.js | 5 +++++ netwerk/base/nsSocketTransportService2.cpp | 23 ++++++++++++++++++++--- netwerk/base/nsSocketTransportService2.h | 5 +++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 314beac37d..1e60c97c54 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1663,6 +1663,11 @@ pref("network.websocket.timeout.open", 20); // close message pref("network.websocket.timeout.close", 20); +// Setting this to true will clamp the websocket timeout value to a minimum +// regardless if there are pending events on the thread. +// This is a workaround for runaway polling, see issue #1695 +pref("network.websocket.timeout.clamped", false); + // the number of seconds of idle read activity to sustain before sending a // ping probe. 0 to disable. pref("network.websocket.timeout.ping.request", 0); diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index 6631db655e..9563329535 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -42,6 +42,7 @@ Atomic gSocketThread; #define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count" #define SOCKET_LIMIT_TARGET 1000U #define SOCKET_LIMIT_MIN 50U +#define SOCKET_CLAMP_PREF "network.websocket.timeout.clamped" #define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds" #define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls" #define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown" @@ -120,6 +121,7 @@ nsSocketTransportService::nsSocketTransportService() , mKeepaliveEnabledPref(false) , mServingPendingQueue(false) , mMaxTimePerPollIter(100) + , mClampSocketTimeout(false) , mMaxTimeForPrClosePref(PR_SecondsToInterval(5)) , mProbedMaxCount(false) #if defined(XP_WIN) @@ -485,7 +487,11 @@ nsSocketTransportService::Poll(PRIntervalTime ts) mPollList[0].out_flags = 0; pollList = mPollList; pollCount = mActiveCount + 1; - pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PollTimeout(ts); + pollTimeout = IsSocketTimeoutClamped() ? + PR_MillisecondsToInterval(100) : + pendingEvents ? + PR_INTERVAL_NO_WAIT : + PollTimeout(ts); } else { // no pollable event, so busy wait... @@ -494,8 +500,11 @@ nsSocketTransportService::Poll(PRIntervalTime ts) pollList = &mPollList[1]; else pollList = nullptr; - pollTimeout = - pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25); + pollTimeout = IsSocketTimeoutClamped() ? + PR_MillisecondsToInterval(25) : + pendingEvents ? + PR_INTERVAL_NO_WAIT : + PR_MillisecondsToInterval(25); } SOCKET_LOG((" timeout = %i milliseconds\n", @@ -554,6 +563,7 @@ nsSocketTransportService::Init() tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF, this, false); tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF, this, false); tmpPrefService->AddObserver(MAX_TIME_BETWEEN_TWO_POLLS, this, false); + tmpPrefService->AddObserver(SOCKET_CLAMP_PREF, this, false); tmpPrefService->AddObserver(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN, this, false); } UpdatePrefs(); @@ -1150,6 +1160,13 @@ nsSocketTransportService::UpdatePrefs() if (NS_SUCCEEDED(rv) && maxTimePref >= 0) { mMaxTimePerPollIter = maxTimePref; } + + bool socketTimeoutClamped = false; + rv = tmpPrefService->GetBoolPref(SOCKET_CLAMP_PREF, + &socketTimeoutClamped); + if (NS_SUCCEEDED(rv)) { + mClampSocketTimeout = socketTimeoutClamped; + } int32_t maxTimeForPrClosePref; rv = tmpPrefService->GetIntPref(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN, diff --git a/netwerk/base/nsSocketTransportService2.h b/netwerk/base/nsSocketTransportService2.h index 31efec1d92..9360dd905c 100644 --- a/netwerk/base/nsSocketTransportService2.h +++ b/netwerk/base/nsSocketTransportService2.h @@ -116,6 +116,9 @@ public: // Returns true if keepalives are enabled in prefs. bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; } + + // Returns true if socket timeout clamping is enabled in prefs. + bool IsSocketTimeoutClamped() { return mClampSocketTimeout; } PRIntervalTime MaxTimeForPrClosePref() {return mMaxTimeForPrClosePref; } protected: @@ -253,6 +256,8 @@ private: int32_t mKeepaliveProbeCount; // True if TCP keepalive is enabled globally. bool mKeepaliveEnabledPref; + // True if socket polling should be clamped. + bool mClampSocketTimeout; Atomic mServingPendingQueue; Atomic mMaxTimePerPollIter; -- cgit v1.2.3