Bug 444328 - Add support for TCP keepalive in the Socket Transport Service r=mcmanus

This commit is contained in:
Steve Workman 2014-02-06 11:51:38 -08:00
Родитель 230ba19414
Коммит 9b9ae0b4f1
8 изменённых файлов: 599 добавлений и 3 удалений

Просмотреть файл

@ -4059,6 +4059,22 @@ pref("stagefright.disabled", false);
// The default TCP send window on Windows is too small, and autotuning only occurs on receive
pref("network.tcp.sendbuffer", 131072);
#endif
// TCP Keepalive
pref("network.tcp.keepalive.enabled", true);
// Default idle time before first TCP keepalive probe; same time for interval
// between successful probes. Can be overridden in socket transport API.
// Win, Linux and Mac.
pref("network.tcp.keepalive.idle_time", 600); // seconds; 10 mins
// Default timeout for retransmission of unack'd keepalive probes.
// Win and Linux only; not configurable on Mac.
#if defined(XP_UNIX) && !defined(XP_MACOSX) || defined(XP_WIN)
pref("network.tcp.keepalive.retry_interval", 1); // seconds
#endif
// Default maximum probe retransmissions.
// Linux only; not configurable on Win and Mac; fixed at 10 and 8 respectively.
#ifdef XP_UNIX && !defined(XP_MACOSX)
pref("network.tcp.keepalive.probe_count", 4);
#endif
// Whether to disable acceleration for all widgets.
pref("layers.acceleration.disabled", false);

Просмотреть файл

@ -81,6 +81,11 @@ public:
*aKeepWhenOffline = false;
}
//
// called when global pref for keepalive has changed.
//
virtual void OnKeepaliveEnabledPrefChange(bool aEnabled) { }
//
// returns the number of bytes sent/transmitted over the socket
//

Просмотреть файл

@ -27,7 +27,7 @@ native NetAddr(mozilla::net::NetAddr);
* NOTE: This is a free-threaded interface, meaning that the methods on
* this interface may be called from any thread.
*/
[scriptable, uuid(A8318027-0DDC-4E60-A89B-D81AFE3B5020)]
[scriptable, uuid(3F41704C-CD5D-4537-8C4C-7B2EBFC5D972)]
interface nsISocketTransport : nsITransport
{
/**
@ -198,4 +198,11 @@ interface nsISocketTransport : nsITransport
*/
attribute unsigned long recvBufferSize;
attribute unsigned long sendBufferSize;
/**
* TCP keepalive configuration (support varies by platform).
*/
attribute boolean keepaliveEnabled;
void setKeepaliveVals(in long keepaliveIdleTime,
in long keepaliveRetryInterval);
};

Просмотреть файл

@ -10,7 +10,7 @@
* This is a private interface used by the internals of the networking library.
* It will never be frozen. Do not use it in external code.
*/
[scriptable, uuid(32de7b6e-90c3-11e1-b57e-001fbc092072)]
[scriptable, uuid(bc5869e7-53a6-4195-8ab8-32e7116b87dd)]
interface nsPISocketTransportService : nsISocketTransportService
{
@ -36,6 +36,21 @@ interface nsPISocketTransportService : nsISocketTransportService
* Setting it offline will cause non-local socket detachment.
*/
attribute boolean offline;
/**
* Controls the default timeout (in seconds) for sending keepalive probes.
*/
readonly attribute long keepaliveIdleTime;
/**
* Controls the default interval (in seconds) between retrying keepalive probes.
*/
readonly attribute long keepaliveRetryInterval;
/**
* Controls the default retransmission count for keepalive probes.
*/
readonly attribute long keepaliveProbeCount;
};
%{C++

Просмотреть файл

@ -38,10 +38,23 @@
#include "nsICancelable.h"
#include <algorithm>
#include "nsPrintfCString.h"
#if defined(XP_WIN)
#include "nsNativeConnectionHelper.h"
#endif
/* Following inclusions required for keepalive config not supported by NSPR. */
#include "private/pprio.h"
#if defined(XP_WIN)
#include <Winsock2.h>
#include <Mstcpip.h>
#elif defined(XP_UNIX)
#include <errno.h>
#include <netinet/tcp.h>
#endif
/* End keepalive config inclusions. */
using namespace mozilla;
using namespace mozilla::net;
@ -754,6 +767,10 @@ nsSocketTransport::nsSocketTransport()
, mInput(MOZ_THIS_IN_INITIALIZER_LIST())
, mOutput(MOZ_THIS_IN_INITIALIZER_LIST())
, mQoSBits(0x00)
, mKeepaliveEnabled(false)
, mKeepaliveIdleTimeS(-1)
, mKeepaliveRetryIntervalS(-1)
, mKeepaliveProbeCount(-1)
{
SOCKET_LOG(("creating nsSocketTransport @%p\n", this));
@ -1542,6 +1559,14 @@ nsSocketTransport::OnSocketConnected()
mFDconnected = true;
}
// Ensure keepalive is configured correctly if previously enabled.
if (mKeepaliveEnabled) {
nsresult rv = SetKeepaliveEnabledInternal(true);
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveEnabledInternal failed rv[0x%x]", rv));
}
}
MOZ_EVENT_TRACER_DONE(this, "net::tcp::connect");
SendStatus(NS_NET_STATUS_CONNECTED_TO);
@ -2392,6 +2417,204 @@ nsSocketTransport::SetConnectionFlags(uint32_t value)
return NS_OK;
}
void
nsSocketTransport::OnKeepaliveEnabledPrefChange(bool aEnabled)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
// The global pref toggles keepalive as a system feature; it only affects
// an individual socket if keepalive has been specifically enabled for it.
// So, ensure keepalive is configured correctly if previously enabled.
if (mKeepaliveEnabled) {
nsresult rv = SetKeepaliveEnabledInternal(aEnabled);
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveEnabledInternal [%s] failed rv[0x%x]",
aEnabled ? "enable" : "disable", rv));
}
}
}
nsresult
nsSocketTransport::SetKeepaliveEnabledInternal(bool aEnable)
{
MOZ_ASSERT(mKeepaliveIdleTimeS > 0 ||
mKeepaliveIdleTimeS <= kMaxTCPKeepIdle);
MOZ_ASSERT(mKeepaliveRetryIntervalS > 0 ||
mKeepaliveRetryIntervalS <= kMaxTCPKeepIntvl);
MOZ_ASSERT(mKeepaliveProbeCount > 0 ||
mKeepaliveProbeCount <= kMaxTCPKeepCount);
PRFileDescAutoLock fd(this);
if (NS_WARN_IF(!fd.IsInitialized())) {
return NS_ERROR_NOT_INITIALIZED;
}
// Only enable if keepalives are globally enabled, but ensure other
// options are set correctly on the fd.
bool enable = aEnable && gSocketTransportService->IsKeepaliveEnabled();
nsresult rv = fd.SetKeepaliveVals(enable,
mKeepaliveIdleTimeS,
mKeepaliveRetryIntervalS,
mKeepaliveProbeCount);
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveVals failed rv[0x%x]", rv));
return rv;
}
rv = fd.SetKeepaliveEnabled(enable);
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveEnabled failed rv[0x%x]", rv));
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::GetKeepaliveEnabled(bool *aResult)
{
MOZ_ASSERT(aResult);
*aResult = mKeepaliveEnabled;
return NS_OK;
}
nsresult
nsSocketTransport::EnsureKeepaliveValsAreInitialized()
{
nsresult rv = NS_OK;
int32_t val = -1;
if (mKeepaliveIdleTimeS == -1) {
rv = gSocketTransportService->GetKeepaliveIdleTime(&val);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mKeepaliveIdleTimeS = val;
}
if (mKeepaliveRetryIntervalS == -1) {
rv = gSocketTransportService->GetKeepaliveRetryInterval(&val);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mKeepaliveRetryIntervalS = val;
}
if (mKeepaliveProbeCount == -1) {
rv = gSocketTransportService->GetKeepaliveProbeCount(&val);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mKeepaliveProbeCount = val;
}
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::SetKeepaliveEnabled(bool aEnable)
{
#if defined(XP_WIN) || defined(XP_UNIX) || defined(XP_MACOSX)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (aEnable == mKeepaliveEnabled) {
SOCKET_LOG(("nsSocketTransport::SetKeepaliveEnabled [%p] already %s.",
this, aEnable ? "enabled" : "disabled"));
return NS_OK;
}
nsresult rv = NS_OK;
if (aEnable) {
rv = EnsureKeepaliveValsAreInitialized();
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveEnabled [%p] "
"error [0x%x] initializing keepalive vals",
this, rv));
return rv;
}
}
SOCKET_LOG(("nsSocketTransport::SetKeepaliveEnabled [%p] "
"%s, idle time[%ds] retry interval[%ds] packet count[%d]: "
"globally %s.",
this, aEnable ? "enabled" : "disabled",
mKeepaliveIdleTimeS, mKeepaliveRetryIntervalS,
mKeepaliveProbeCount,
gSocketTransportService->IsKeepaliveEnabled() ?
"enabled" : "disabled"));
// Set mKeepaliveEnabled here so that state is maintained; it is possible
// that we're in between fds, e.g. the 1st IP address failed, so we're about
// to retry on a 2nd from the DNS record.
mKeepaliveEnabled = aEnable;
rv = SetKeepaliveEnabledInternal(aEnable);
if (NS_WARN_IF(NS_FAILED(rv))) {
SOCKET_LOG((" SetKeepaliveEnabledInternal failed rv[0x%x]", rv));
return rv;
}
return NS_OK;
#else /* !(defined(XP_WIN) || defined(XP_UNIX) || defined(XP_MACOSX)) */
SOCKET_LOG(("nsSocketTransport::SetKeepaliveEnabled unsupported platform"));
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
nsSocketTransport::SetKeepaliveVals(int32_t aIdleTime,
int32_t aRetryInterval)
{
#if defined(XP_WIN) || defined(XP_UNIX) || defined(XP_MACOSX)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (NS_WARN_IF(aIdleTime <= 0 || kMaxTCPKeepIdle < aIdleTime)) {
return NS_ERROR_INVALID_ARG;
}
if (NS_WARN_IF(aRetryInterval <= 0 ||
kMaxTCPKeepIntvl < aRetryInterval)) {
return NS_ERROR_INVALID_ARG;
}
if (aIdleTime == mKeepaliveIdleTimeS &&
aRetryInterval == mKeepaliveRetryIntervalS) {
SOCKET_LOG(("nsSocketTransport::SetKeepaliveVals [%p] idle time "
"already %ds and retry interval already %ds.",
this, mKeepaliveIdleTimeS,
mKeepaliveRetryIntervalS));
return NS_OK;
}
mKeepaliveIdleTimeS = aIdleTime;
mKeepaliveRetryIntervalS = aRetryInterval;
nsresult rv = NS_OK;
if (mKeepaliveProbeCount == -1) {
int32_t val = -1;
nsresult rv = gSocketTransportService->GetKeepaliveProbeCount(&val);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mKeepaliveProbeCount = val;
}
SOCKET_LOG(("nsSocketTransport::SetKeepaliveVals [%p] "
"keepalive %s, idle time[%ds] retry interval[%ds] "
"packet count[%d]",
this, mKeepaliveEnabled ? "enabled" : "disabled",
mKeepaliveIdleTimeS, mKeepaliveRetryIntervalS,
mKeepaliveProbeCount));
PRFileDescAutoLock fd(this);
if (NS_WARN_IF(!fd.IsInitialized())) {
return NS_ERROR_NULL_POINTER;
}
rv = fd.SetKeepaliveVals(mKeepaliveEnabled,
mKeepaliveIdleTimeS,
mKeepaliveRetryIntervalS,
mKeepaliveProbeCount);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
#else
SOCKET_LOG(("nsSocketTransport::SetKeepaliveVals unsupported platform"));
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
#ifdef ENABLE_SOCKET_TRACING
@ -2465,3 +2688,169 @@ nsSocketTransport::TraceOutBuf(const char *buf, int32_t n)
}
#endif
static void LogNSPRError(const char* aPrefix, const void *aObjPtr)
{
#if defined(PR_LOGGING) && defined(DEBUG)
PRErrorCode errCode = PR_GetError();
int errLen = PR_GetErrorTextLength();
nsAutoCString errStr;
if (errLen > 0) {
errStr.SetLength(errLen);
PR_GetErrorText(errStr.BeginWriting());
}
NS_WARNING(nsPrintfCString(
"%s [%p] NSPR error[0x%x] %s.",
aPrefix ? aPrefix : "nsSocketTransport", aObjPtr, errCode,
errLen > 0 ? errStr.BeginReading() : "<no error text>").get());
#endif
}
nsresult
nsSocketTransport::PRFileDescAutoLock::SetKeepaliveEnabled(bool aEnable)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
MOZ_ASSERT(!(aEnable && !gSocketTransportService->IsKeepaliveEnabled()),
"Cannot enable keepalive if global pref is disabled!");
if (aEnable && !gSocketTransportService->IsKeepaliveEnabled()) {
return NS_ERROR_ILLEGAL_VALUE;
}
PRSocketOptionData opt;
opt.option = PR_SockOpt_Keepalive;
opt.value.keep_alive = aEnable;
PRStatus status = PR_SetSocketOption(mFd, &opt);
if (NS_WARN_IF(status != PR_SUCCESS)) {
LogNSPRError("nsSocketTransport::PRFileDescAutoLock::SetKeepaliveEnabled",
mSocketTransport);
return ErrorAccordingToNSPR(PR_GetError());
}
return NS_OK;
}
static void LogOSError(const char *aPrefix, const void *aObjPtr)
{
#if defined(PR_LOGGING) && defined(DEBUG)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
#ifdef XP_WIN
DWORD errCode = WSAGetLastError();
LPVOID errMessage;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &errMessage,
0, NULL);
#else
int errCode = errno;
char *errMessage = strerror(errno);
#endif
NS_WARNING(nsPrintfCString(
"%s [%p] OS error[0x%x] %s",
aPrefix ? aPrefix : "nsSocketTransport", aObjPtr, errCode,
errMessage ? errMessage : "<no error text>").get());
#ifdef XP_WIN
LocalFree(errMessage);
#endif
#endif
}
/* XXX PR_SetSockOpt does not support setting keepalive values, so native
* handles and platform specific apis (setsockopt, WSAIOCtl) are used in this
* file. Requires inclusion of NSPR private/pprio.h, and platform headers.
*/
nsresult
nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals(bool aEnabled,
int aIdleTime,
int aRetryInterval,
int aProbeCount)
{
#if defined(XP_WIN) || defined(XP_UNIX) || defined(XP_MACOSX)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (NS_WARN_IF(aIdleTime <= 0 || kMaxTCPKeepIdle < aIdleTime)) {
return NS_ERROR_INVALID_ARG;
}
if (NS_WARN_IF(aRetryInterval <= 0 ||
kMaxTCPKeepIntvl < aRetryInterval)) {
return NS_ERROR_INVALID_ARG;
}
if (NS_WARN_IF(aProbeCount <= 0 || kMaxTCPKeepCount < aProbeCount)) {
return NS_ERROR_INVALID_ARG;
}
PROsfd sock = PR_FileDesc2NativeHandle(mFd);
if (NS_WARN_IF(sock == -1)) {
LogNSPRError("nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals",
mSocketTransport);
return ErrorAccordingToNSPR(PR_GetError());
}
#endif
#if defined(XP_WIN)
// Windows allows idle time and retry interval to be set; NOT ping count.
struct tcp_keepalive keepalive_vals = {
(int)aEnabled,
// Windows uses msec.
aIdleTime * 1000,
aRetryInterval * 1000
};
DWORD bytes_returned;
int err = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive_vals,
sizeof(keepalive_vals), NULL, 0, &bytes_returned, NULL,
NULL);
if (NS_WARN_IF(err)) {
LogOSError("nsSocketTransport WSAIoctl failed", mSocketTransport);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
#elif defined(XP_MACOSX)
// OS X uses sec; only supports idle time being set.
int err = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE,
&aIdleTime, sizeof(aIdleTime));
if (NS_WARN_IF(err)) {
LogOSError("nsSocketTransport Failed setting TCP_KEEPALIVE",
mSocketTransport);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
#elif defined(XP_UNIX)
// Linux uses sec; supports idle time, retry interval and ping count.
int err = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE,
&aIdleTime, sizeof(aIdleTime));
if (NS_WARN_IF(err)) {
LogOSError("nsSocketTransport Failed setting TCP_KEEPIDLE",
mSocketTransport);
return NS_ERROR_UNEXPECTED;
}
// Linux also has a few extra knobs to tweak
err = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL,
&aRetryInterval, sizeof(aRetryInterval));
if (NS_WARN_IF(err)) {
LogOSError("nsSocketTransport Failed setting TCP_KEEPINTVL",
mSocketTransport);
return NS_ERROR_UNEXPECTED;
}
err = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT,
&aProbeCount, sizeof(aProbeCount));
if (NS_WARN_IF(err)) {
LogOSError("nsSocketTransport Failed setting TCP_KEEPCNT",
mSocketTransport);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
#else
MOZ_ASSERT(false, "nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals "
"called on unsupported platform!");
return NS_ERROR_UNEXPECTED;
#endif
}

Просмотреть файл

@ -139,6 +139,7 @@ public:
void OnSocketReady(PRFileDesc *, int16_t outFlags);
void OnSocketDetached(PRFileDesc *);
void IsLocal(bool *aIsLocal);
void OnKeepaliveEnabledPrefChange(bool aEnabled) MOZ_OVERRIDE MOZ_FINAL;
// called when a socket event is handled
void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param);
@ -205,8 +206,12 @@ private:
operator PRFileDesc*() {
return mFd;
}
nsresult SetKeepaliveEnabled(bool aEnable);
nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime,
int aRetryInterval, int aProbeCount);
private:
operator PRFileDescAutoLock*() { return nullptr; }
// Weak ptr to nsSocketTransport since this is a stack class only.
nsSocketTransport *mSocketTransport;
PRFileDesc *mFd;
@ -386,6 +391,21 @@ private:
void TraceInBuf(const char *buf, int32_t n);
void TraceOutBuf(const char *buf, int32_t n);
#endif
// Reads prefs to get default keepalive config.
nsresult EnsureKeepaliveValsAreInitialized();
// Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
nsresult SetKeepaliveEnabledInternal(bool aEnable);
// True if keepalive has been enabled by the socket owner. Note: Keepalive
// must also be enabled globally for it to be enabled in TCP.
bool mKeepaliveEnabled;
// Keepalive config (support varies by platform).
int32_t mKeepaliveIdleTimeS;
int32_t mKeepaliveRetryIntervalS;
int32_t mKeepaliveProbeCount;
};
#endif // !nsSocketTransport_h__

Просмотреть файл

@ -35,6 +35,10 @@ nsSocketTransportService *gSocketTransportService = nullptr;
PRThread *gSocketThread = nullptr;
#define SEND_BUFFER_PREF "network.tcp.sendbuffer"
#define KEEPALIVE_ENABLED_PREF "network.tcp.keepalive.enabled"
#define KEEPALIVE_IDLE_TIME_PREF "network.tcp.keepalive.idle_time"
#define KEEPALIVE_RETRY_INTERVAL_PREF "network.tcp.keepalive.retry_interval"
#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
#define SOCKET_LIMIT_TARGET 550U
#define SOCKET_LIMIT_MIN 50U
#define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"
@ -61,6 +65,10 @@ nsSocketTransportService::nsSocketTransportService()
, mSentBytesCount(0)
, mReceivedBytesCount(0)
, mSendBufferSize(0)
, mKeepaliveIdleTimeS(600)
, mKeepaliveRetryIntervalS(1)
, mKeepaliveProbeCount(kDefaultTCPKeepCount)
, mKeepaliveEnabledPref(false)
, mProbedMaxCount(false)
{
#if defined(PR_LOGGING)
@ -463,6 +471,10 @@ nsSocketTransportService::Init()
nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (tmpPrefService) {
tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
tmpPrefService->AddObserver(KEEPALIVE_ENABLED_PREF, this, false);
tmpPrefService->AddObserver(KEEPALIVE_IDLE_TIME_PREF, this, false);
tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF, this, false);
tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF, this, false);
}
UpdatePrefs();
@ -553,6 +565,39 @@ nsSocketTransportService::SetOffline(bool offline)
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransportService::GetKeepaliveIdleTime(int32_t *aKeepaliveIdleTimeS)
{
MOZ_ASSERT(aKeepaliveIdleTimeS);
if (NS_WARN_IF(!aKeepaliveIdleTimeS)) {
return NS_ERROR_NULL_POINTER;
}
*aKeepaliveIdleTimeS = mKeepaliveIdleTimeS;
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransportService::GetKeepaliveRetryInterval(int32_t *aKeepaliveRetryIntervalS)
{
MOZ_ASSERT(aKeepaliveRetryIntervalS);
if (NS_WARN_IF(!aKeepaliveRetryIntervalS)) {
return NS_ERROR_NULL_POINTER;
}
*aKeepaliveRetryIntervalS = mKeepaliveRetryIntervalS;
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransportService::GetKeepaliveProbeCount(int32_t *aKeepaliveProbeCount)
{
MOZ_ASSERT(aKeepaliveProbeCount);
if (NS_WARN_IF(!aKeepaliveProbeCount)) {
return NS_ERROR_NULL_POINTER;
}
*aKeepaliveProbeCount = mKeepaliveProbeCount;
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransportService::CreateTransport(const char **types,
uint32_t typeCount,
@ -909,11 +954,77 @@ nsSocketTransportService::UpdatePrefs()
nsresult rv = tmpPrefService->GetIntPref(SEND_BUFFER_PREF, &bufferSize);
if (NS_SUCCEEDED(rv) && bufferSize > 0)
mSendBufferSize = bufferSize;
// Default TCP Keepalive Values.
int32_t keepaliveIdleTimeS;
rv = tmpPrefService->GetIntPref(KEEPALIVE_IDLE_TIME_PREF,
&keepaliveIdleTimeS);
if (NS_SUCCEEDED(rv))
mKeepaliveIdleTimeS = clamped(keepaliveIdleTimeS,
1, kMaxTCPKeepIdle);
int32_t keepaliveRetryIntervalS;
rv = tmpPrefService->GetIntPref(KEEPALIVE_RETRY_INTERVAL_PREF,
&keepaliveRetryIntervalS);
if (NS_SUCCEEDED(rv))
mKeepaliveRetryIntervalS = clamped(keepaliveRetryIntervalS,
1, kMaxTCPKeepIntvl);
int32_t keepaliveProbeCount;
rv = tmpPrefService->GetIntPref(KEEPALIVE_PROBE_COUNT_PREF,
&keepaliveProbeCount);
if (NS_SUCCEEDED(rv))
mKeepaliveProbeCount = clamped(keepaliveProbeCount,
1, kMaxTCPKeepCount);
bool keepaliveEnabled = false;
rv = tmpPrefService->GetBoolPref(KEEPALIVE_ENABLED_PREF,
&keepaliveEnabled);
if (NS_SUCCEEDED(rv) && keepaliveEnabled != mKeepaliveEnabledPref) {
mKeepaliveEnabledPref = keepaliveEnabled;
OnKeepaliveEnabledPrefChange();
}
}
return NS_OK;
}
void
nsSocketTransportService::OnKeepaliveEnabledPrefChange()
{
// Dispatch to socket thread if we're not executing there.
if (PR_GetCurrentThread() != gSocketThread) {
gSocketTransportService->Dispatch(
NS_NewRunnableMethod(
this, &nsSocketTransportService::OnKeepaliveEnabledPrefChange),
NS_DISPATCH_NORMAL);
return;
}
SOCKET_LOG(("nsSocketTransportService::OnKeepaliveEnabledPrefChange %s",
mKeepaliveEnabledPref ? "enabled" : "disabled"));
// Notify each socket that keepalive has been en/disabled globally.
for (int32_t i = mActiveCount - 1; i >= 0; --i) {
NotifyKeepaliveEnabledPrefChange(&mActiveList[i]);
}
for (int32_t i = mIdleCount - 1; i >= 0; --i) {
NotifyKeepaliveEnabledPrefChange(&mIdleList[i]);
}
}
void
nsSocketTransportService::NotifyKeepaliveEnabledPrefChange(SocketContext *sock)
{
MOZ_ASSERT(sock, "SocketContext cannot be null!");
MOZ_ASSERT(sock->mHandler, "SocketContext does not have a handler!");
if (!sock || !sock->mHandler) {
return;
}
sock->mHandler->OnKeepaliveEnabledPrefChange(mKeepaliveEnabledPref);
}
NS_IMETHODIMP
nsSocketTransportService::Observe(nsISupports *subject,
const char *topic,

Просмотреть файл

@ -38,6 +38,25 @@ extern PRLogModuleInfo *gSocketTransportLog;
//-----------------------------------------------------------------------------
namespace mozilla {
namespace net {
// These maximums are borrowed from the linux kernel.
static const int32_t kMaxTCPKeepIdle = 32767; // ~9 hours.
static const int32_t kMaxTCPKeepIntvl = 32767;
static const int32_t kMaxTCPKeepCount = 127;
static const int32_t kDefaultTCPKeepCount =
#if defined (XP_WIN)
10; // Hardcoded in Windows.
#elif defined (XP_MACOSX)
8; // Hardcoded in OSX.
#else
4; // Specifiable in Linux.
#endif
}
}
//-----------------------------------------------------------------------------
class nsSocketTransportService : public nsPISocketTransportService
, public nsIEventTarget
, public nsIThreadObserver
@ -79,6 +98,9 @@ public:
void GetSocketConnections(nsTArray<mozilla::net::SocketInfo> *);
uint64_t GetSentBytes() { return mSentBytesCount; }
uint64_t GetReceivedBytes() { return mReceivedBytesCount; }
// Returns true if keepalives are enabled in prefs.
bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; }
protected:
virtual ~nsSocketTransportService();
@ -183,9 +205,20 @@ private:
nsEventQueue mPendingSocketQ; // queue of nsIRunnable objects
// Preference Monitor for SendBufferSize
// Preference Monitor for SendBufferSize and Keepalive prefs.
nsresult UpdatePrefs();
int32_t mSendBufferSize;
// Number of seconds of connection is idle before first keepalive ping.
int32_t mKeepaliveIdleTimeS;
// Number of seconds between retries should keepalive pings fail.
int32_t mKeepaliveRetryIntervalS;
// Number of keepalive probes to send.
int32_t mKeepaliveProbeCount;
// True if TCP keepalive is enabled globally.
bool mKeepaliveEnabledPref;
void OnKeepaliveEnabledPrefChange();
void NotifyKeepaliveEnabledPrefChange(SocketContext *sock);
// Socket thread only for dynamically adjusting max socket size
#if defined(XP_WIN)