зеркало из https://github.com/mozilla/gecko-dev.git
Bug 444328 - Enable TCP Keepalive for short and long-lived HTTP Connections (exc. SPDY, WebSockets) r=mcmanus
This commit is contained in:
Родитель
9b9ae0b4f1
Коммит
121f9e83ae
|
@ -1011,6 +1011,16 @@ pref("network.http.pacing.requests.min-parallelism", 6);
|
|||
pref("network.http.pacing.requests.hz", 100);
|
||||
pref("network.http.pacing.requests.burst", 32);
|
||||
|
||||
// TCP Keepalive config for HTTP connections.
|
||||
pref("network.http.tcp_keepalive.short_lived_connections", true);
|
||||
// Max time from initial request during which conns are considered short-lived.
|
||||
pref("network.http.tcp_keepalive.short_lived_time", 60);
|
||||
// Idle time of TCP connection until first keepalive probe sent.
|
||||
pref("network.http.tcp_keepalive.short_lived_idle_time", 10);
|
||||
|
||||
pref("network.http.tcp_keepalive.long_lived_connections", true);
|
||||
pref("network.http.tcp_keepalive.long_lived_idle_time", 600);
|
||||
|
||||
// default values for FTP
|
||||
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
|
||||
// Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsHttpHandler.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsISocketTransport.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
#include "nsISSLSocketControl.h"
|
||||
#include "sslt.h"
|
||||
#include "nsStringStream.h"
|
||||
|
@ -71,6 +72,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mLastHttpResponseVersion(NS_HTTP_VERSION_1_1)
|
||||
, mTransactionCaps(0)
|
||||
, mResponseTimeoutEnabled(false)
|
||||
, mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
|
||||
{
|
||||
LOG(("Creating nsHttpConnection @%x\n", this));
|
||||
}
|
||||
|
@ -223,6 +225,13 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
}
|
||||
}
|
||||
|
||||
// Disable TCP Keepalives - use SPDY ping instead.
|
||||
rv = DisableTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("nsHttpConnection::StartSpdy [%p] DisableTCPKeepalives failed "
|
||||
"rv[0x%x]", this, rv));
|
||||
}
|
||||
|
||||
mSupportsPipelining = false; // dont use http/1 pipelines with spdy
|
||||
mTransaction = mSpdySession;
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
|
@ -351,6 +360,15 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
|||
|
||||
rv = OnOutputStreamReady(mSocketOut);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv2 = StartShortLivedTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv2))) {
|
||||
LOG(("nsHttpConnection::Activate [%p] "
|
||||
"StartShortLivedTCPKeepalives failed rv2[0x%x]",
|
||||
this, rv));
|
||||
}
|
||||
}
|
||||
|
||||
failed_activation:
|
||||
if (NS_FAILED(rv)) {
|
||||
mTransaction = nullptr;
|
||||
|
@ -450,6 +468,12 @@ nsHttpConnection::Close(nsresult reason)
|
|||
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
// Ensure TCP keepalive timer is stopped.
|
||||
if (mTCPKeepaliveTransitionTimer) {
|
||||
mTCPKeepaliveTransitionTimer->Cancel();
|
||||
mTCPKeepaliveTransitionTimer = nullptr;
|
||||
}
|
||||
|
||||
if (NS_FAILED(reason)) {
|
||||
if (mIdleMonitoring)
|
||||
EndIdleMonitoring();
|
||||
|
@ -929,6 +953,21 @@ nsHttpConnection::TakeTransport(nsISocketTransport **aTransport,
|
|||
if (mInputOverflow)
|
||||
mSocketIn = mInputOverflow.forget();
|
||||
|
||||
// Change TCP Keepalive frequency to long-lived if currently short-lived.
|
||||
if (mTCPKeepaliveConfig == kTCPKeepaliveShortLivedConfig) {
|
||||
if (mTCPKeepaliveTransitionTimer) {
|
||||
mTCPKeepaliveTransitionTimer->Cancel();
|
||||
mTCPKeepaliveTransitionTimer = nullptr;
|
||||
}
|
||||
nsresult rv = StartLongLivedTCPKeepalives();
|
||||
LOG(("nsHttpConnection::TakeTransport [%p] calling "
|
||||
"StartLongLivedTCPKeepalives", this));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("nsHttpConnection::TakeTransport [%p] "
|
||||
"StartLongLivedTCPKeepalives failed rv[0x%x]", this, rv));
|
||||
}
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aTransport = mSocketTransport);
|
||||
NS_IF_ADDREF(*aInputStream = mSocketIn);
|
||||
NS_IF_ADDREF(*aOutputStream = mSocketOut);
|
||||
|
@ -1040,6 +1079,31 @@ nsHttpConnection::ReadTimeoutTick(PRIntervalTime now)
|
|||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::UpdateTCPKeepalive(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aTimer);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
nsHttpConnection *self = static_cast<nsHttpConnection*>(aClosure);
|
||||
|
||||
if (NS_WARN_IF(self->mUsingSpdyVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not reduce keepalive probe frequency for idle connections.
|
||||
if (self->mIdleMonitoring) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = self->StartLongLivedTCPKeepalives();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
LOG(("nsHttpConnection::UpdateTCPKeepalive [%p] "
|
||||
"StartLongLivedTCPKeepalives failed rv[0x%x]",
|
||||
self, rv));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::GetSecurityInfo(nsISupports **secinfo)
|
||||
{
|
||||
|
@ -1565,6 +1629,149 @@ nsHttpConnection::ReportDataUsage(bool allowDefer)
|
|||
mUnreportedBytesRead = mUnreportedBytesWritten = 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::StartShortLivedTCPKeepalives()
|
||||
{
|
||||
MOZ_ASSERT(!mUsingSpdyVersion, "Don't use TCP Keepalive with SPDY!");
|
||||
if (NS_WARN_IF(mUsingSpdyVersion)) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(mSocketTransport);
|
||||
if (!mSocketTransport) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
int32_t idleTimeS = -1;
|
||||
int32_t retryIntervalS = -1;
|
||||
if (gHttpHandler->TCPKeepaliveEnabledForShortLivedConns()) {
|
||||
// Set the idle time.
|
||||
idleTimeS = gHttpHandler->GetTCPKeepaliveShortLivedIdleTime();
|
||||
LOG(("nsHttpConnection::StartShortLivedTCPKeepalives[%p] "
|
||||
"idle time[%ds].", this, idleTimeS));
|
||||
|
||||
retryIntervalS =
|
||||
std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
|
||||
rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(true);
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveShortLivedConfig;
|
||||
} else {
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(false);
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Start a timer to move to long-lived keepalive config.
|
||||
if(!mTCPKeepaliveTransitionTimer) {
|
||||
mTCPKeepaliveTransitionTimer =
|
||||
do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
|
||||
if (mTCPKeepaliveTransitionTimer) {
|
||||
int32_t time = gHttpHandler->GetTCPKeepaliveShortLivedTime();
|
||||
|
||||
// Adjust |time| to ensure a full set of keepalive probes can be sent
|
||||
// at the end of the short-lived phase.
|
||||
if (gHttpHandler->TCPKeepaliveEnabledForShortLivedConns()) {
|
||||
if (NS_WARN_IF(!gSocketTransportService)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
int32_t probeCount = -1;
|
||||
rv = gSocketTransportService->GetKeepaliveProbeCount(&probeCount);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(probeCount <= 0)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
// Add time for final keepalive probes, and 2 seconds for a buffer.
|
||||
time += ((probeCount) * retryIntervalS) - (time % idleTimeS) + 2;
|
||||
}
|
||||
mTCPKeepaliveTransitionTimer->InitWithFuncCallback(
|
||||
nsHttpConnection::UpdateTCPKeepalive,
|
||||
this,
|
||||
(uint32_t)time*1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
} else {
|
||||
NS_WARNING("nsHttpConnection::StartShortLivedTCPKeepalives failed to "
|
||||
"create timer.");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::StartLongLivedTCPKeepalives()
|
||||
{
|
||||
MOZ_ASSERT(!mUsingSpdyVersion, "Don't use TCP Keepalive with SPDY!");
|
||||
if (NS_WARN_IF(mUsingSpdyVersion)) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(mSocketTransport);
|
||||
if (!mSocketTransport) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (gHttpHandler->TCPKeepaliveEnabledForLongLivedConns()) {
|
||||
// Increase the idle time.
|
||||
int32_t idleTimeS = gHttpHandler->GetTCPKeepaliveLongLivedIdleTime();
|
||||
LOG(("nsHttpConnection::StartLongLivedTCPKeepalives[%p] idle time[%ds]",
|
||||
this, idleTimeS));
|
||||
|
||||
int32_t retryIntervalS =
|
||||
std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
|
||||
rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Ensure keepalive is enabled, if current status is disabled.
|
||||
if (mTCPKeepaliveConfig == kTCPKeepaliveDisabled) {
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveLongLivedConfig;
|
||||
} else {
|
||||
rv = mSocketTransport->SetKeepaliveEnabled(false);
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnection::DisableTCPKeepalives()
|
||||
{
|
||||
MOZ_ASSERT(mSocketTransport);
|
||||
if (!mSocketTransport) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
LOG(("nsHttpConnection::DisableTCPKeepalives [%p]", this));
|
||||
if (mTCPKeepaliveConfig != kTCPKeepaliveDisabled) {
|
||||
nsresult rv = mSocketTransport->SetKeepaliveEnabled(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
|
||||
}
|
||||
if (mTCPKeepaliveTransitionTimer) {
|
||||
mTCPKeepaliveTransitionTimer->Cancel();
|
||||
mTCPKeepaliveTransitionTimer = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
class nsISocketTransport;
|
||||
|
||||
|
@ -148,6 +149,11 @@ public:
|
|||
// other connections.
|
||||
uint32_t ReadTimeoutTick(PRIntervalTime now);
|
||||
|
||||
// For Active and Idle connections, this will be called when
|
||||
// mTCPKeepaliveTransitionTimer fires, to check if the TCP keepalive config
|
||||
// should move from short-lived (fast-detect) to long-lived.
|
||||
static void UpdateTCPKeepalive(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
nsAHttpTransaction::Classifier Classification() { return mClassification; }
|
||||
void Classify(nsAHttpTransaction::Classifier newclass)
|
||||
{
|
||||
|
@ -169,6 +175,13 @@ public:
|
|||
bool IsExperienced() { return mExperienced; }
|
||||
|
||||
private:
|
||||
// Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use.
|
||||
enum TCPKeepaliveConfig {
|
||||
kTCPKeepaliveDisabled = 0,
|
||||
kTCPKeepaliveShortLivedConfig,
|
||||
kTCPKeepaliveLongLivedConfig
|
||||
};
|
||||
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStartSSL();
|
||||
|
||||
|
@ -196,7 +209,12 @@ private:
|
|||
// used to inform nsIHttpDataUsage of transfer
|
||||
void ReportDataUsage(bool);
|
||||
|
||||
private:
|
||||
// Used to set TCP keepalives for fast detection of dead connections during
|
||||
// an initial period, and slower detection for long-lived connections.
|
||||
nsresult StartShortLivedTCPKeepalives();
|
||||
nsresult StartLongLivedTCPKeepalives();
|
||||
nsresult DisableTCPKeepalives();
|
||||
|
||||
nsCOMPtr<nsISocketTransport> mSocketTransport;
|
||||
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
|
||||
|
@ -280,6 +298,10 @@ private:
|
|||
uint32_t mTransactionCaps;
|
||||
|
||||
bool mResponseTimeoutEnabled;
|
||||
|
||||
// Flag to indicate connection is in inital keepalive period (fast detect).
|
||||
uint32_t mTCPKeepaliveConfig;
|
||||
nsCOMPtr<nsITimer> mTCPKeepaliveTransitionTimer;
|
||||
};
|
||||
|
||||
}} // namespace mozilla::net
|
||||
|
|
|
@ -207,6 +207,11 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mRequestTokenBucketHz(100)
|
||||
, mRequestTokenBucketBurst(32)
|
||||
, mCriticalRequestPrioritization(true)
|
||||
, mTCPKeepaliveShortLivedEnabled(false)
|
||||
, mTCPKeepaliveShortLivedTimeS(60)
|
||||
, mTCPKeepaliveShortLivedIdleTimeS(10)
|
||||
, mTCPKeepaliveLongLivedEnabled(false)
|
||||
, mTCPKeepaliveLongLivedIdleTimeS(600)
|
||||
, mEthernetBytesRead(0)
|
||||
, mEthernetBytesWritten(0)
|
||||
, mCellBytesRead(0)
|
||||
|
@ -286,7 +291,8 @@ nsHttpHandler::Init()
|
|||
prefBranch->AddObserver(DONOTTRACK_HEADER_ENABLED, this, true);
|
||||
prefBranch->AddObserver(DONOTTRACK_HEADER_VALUE, this, true);
|
||||
prefBranch->AddObserver(TELEMETRY_ENABLED, this, true);
|
||||
|
||||
prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.short_lived_connections"), this, true);
|
||||
prefBranch->AddObserver(HTTP_PREF("tcp_keepalive.long_lived_connections"), this, true);
|
||||
PrefsChanged(prefBranch, nullptr);
|
||||
}
|
||||
|
||||
|
@ -1422,6 +1428,47 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
|||
RequestTokenBucketBurst());
|
||||
}
|
||||
|
||||
// Keepalive values for initial and idle connections.
|
||||
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_connections"))) {
|
||||
rv = prefs->GetBoolPref(
|
||||
HTTP_PREF("tcp_keepalive.short_lived_connections"), &cVar);
|
||||
if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveShortLivedEnabled) {
|
||||
mTCPKeepaliveShortLivedEnabled = cVar;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_time"))) {
|
||||
rv = prefs->GetIntPref(
|
||||
HTTP_PREF("tcp_keepalive.short_lived_time"), &val);
|
||||
if (NS_SUCCEEDED(rv) && val > 0)
|
||||
mTCPKeepaliveShortLivedTimeS = clamped(val, 1, 300); // Max 5 mins.
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.short_lived_idle_time"))) {
|
||||
rv = prefs->GetIntPref(
|
||||
HTTP_PREF("tcp_keepalive.short_lived_idle_time"), &val);
|
||||
if (NS_SUCCEEDED(rv) && val > 0)
|
||||
mTCPKeepaliveShortLivedIdleTimeS = clamped(val,
|
||||
1, kMaxTCPKeepIdle);
|
||||
}
|
||||
|
||||
// Keepalive values for Long-lived Connections.
|
||||
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_connections"))) {
|
||||
rv = prefs->GetBoolPref(
|
||||
HTTP_PREF("tcp_keepalive.long_lived_connections"), &cVar);
|
||||
if (NS_SUCCEEDED(rv) && cVar != mTCPKeepaliveLongLivedEnabled) {
|
||||
mTCPKeepaliveLongLivedEnabled = cVar;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("tcp_keepalive.long_lived_idle_time"))) {
|
||||
rv = prefs->GetIntPref(
|
||||
HTTP_PREF("tcp_keepalive.long_lived_idle_time"), &val);
|
||||
if (NS_SUCCEEDED(rv) && val > 0)
|
||||
mTCPKeepaliveLongLivedIdleTimeS = clamped(val,
|
||||
1, kMaxTCPKeepIdle);
|
||||
}
|
||||
|
||||
#undef PREF_CHANGED
|
||||
#undef MULTI_PREF_CHANGED
|
||||
}
|
||||
|
|
|
@ -120,6 +120,33 @@ public:
|
|||
|
||||
bool PromptTempRedirect() { return mPromptTempRedirect; }
|
||||
|
||||
// TCP Keepalive configuration values.
|
||||
|
||||
// Returns true if TCP keepalive should be enabled for short-lived conns.
|
||||
bool TCPKeepaliveEnabledForShortLivedConns() {
|
||||
return mTCPKeepaliveShortLivedEnabled;
|
||||
}
|
||||
// Return time (secs) that a connection is consider short lived (for TCP
|
||||
// keepalive purposes). After this time, the connection is long-lived.
|
||||
int32_t GetTCPKeepaliveShortLivedTime() {
|
||||
return mTCPKeepaliveShortLivedTimeS;
|
||||
}
|
||||
// Returns time (secs) before first TCP keepalive probes should be sent;
|
||||
// same time used between successful keepalive probes.
|
||||
int32_t GetTCPKeepaliveShortLivedIdleTime() {
|
||||
return mTCPKeepaliveShortLivedIdleTimeS;
|
||||
}
|
||||
|
||||
// Returns true if TCP keepalive should be enabled for long-lived conns.
|
||||
bool TCPKeepaliveEnabledForLongLivedConns() {
|
||||
return mTCPKeepaliveLongLivedEnabled;
|
||||
}
|
||||
// Returns time (secs) before first TCP keepalive probes should be sent;
|
||||
// same time used between successful keepalive probes.
|
||||
int32_t GetTCPKeepaliveLongLivedIdleTime() {
|
||||
return mTCPKeepaliveLongLivedIdleTimeS;
|
||||
}
|
||||
|
||||
nsHttpAuthCache *AuthCache(bool aPrivate) {
|
||||
return aPrivate ? &mPrivateAuthCache : &mAuthCache;
|
||||
}
|
||||
|
@ -464,6 +491,20 @@ private:
|
|||
// for 1 minute for most requests.
|
||||
TimeStamp mCacheSkippedUntil;
|
||||
|
||||
// TCP Keepalive configuration values.
|
||||
|
||||
// True if TCP keepalive is enabled for short-lived conns.
|
||||
bool mTCPKeepaliveShortLivedEnabled;
|
||||
// Time (secs) indicating how long a conn is considered short-lived.
|
||||
int32_t mTCPKeepaliveShortLivedTimeS;
|
||||
// Time (secs) before first keepalive probe; between successful probes.
|
||||
int32_t mTCPKeepaliveShortLivedIdleTimeS;
|
||||
|
||||
// True if TCP keepalive is enabled for long-lived conns.
|
||||
bool mTCPKeepaliveLongLivedEnabled;
|
||||
// Time (secs) before first keepalive probe; between successful probes.
|
||||
int32_t mTCPKeepaliveLongLivedIdleTimeS;
|
||||
|
||||
private:
|
||||
// For Rate Pacing Certain Network Events. Only assign this pointer on
|
||||
// socket thread.
|
||||
|
|
Загрузка…
Ссылка в новой задаче