зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1415536 - Extend NotifyNetworkActivity to get sent/received bytes r=baku,valentin
MozReview-Commit-ID: Afdvz0lktY8 --HG-- extra : rebase_source : 900d807ec9a9f5305c07947ced00a6f68192ed9d
This commit is contained in:
Родитель
a5aef799e1
Коммит
8ecfc87eb1
|
@ -5155,7 +5155,7 @@ pref("dom.idle-observers-api.fuzz_time.disabled", true);
|
||||||
// no notifications). The delay is the same for both download and upload, though
|
// no notifications). The delay is the same for both download and upload, though
|
||||||
// they are handled separately. This pref is only read once at startup:
|
// they are handled separately. This pref is only read once at startup:
|
||||||
// a restart is required to enable a new value.
|
// a restart is required to enable a new value.
|
||||||
pref("network.activity.blipIntervalMilliseconds", 0);
|
pref("network.activity.intervalMilliseconds", 0);
|
||||||
|
|
||||||
// If true, reuse the same global for (almost) everything loaded by the component
|
// If true, reuse the same global for (almost) everything loaded by the component
|
||||||
// loader (JS components, JSMs, etc). This saves memory, but makes it possible
|
// loader (JS components, JSMs, etc). This saves memory, but makes it possible
|
||||||
|
|
|
@ -3,18 +3,32 @@
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "NetworkActivityMonitor.h"
|
#include "NetworkActivityMonitor.h"
|
||||||
#include "prmem.h"
|
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
#include "nsPISocketTransportService.h"
|
#include "nsPISocketTransportService.h"
|
||||||
|
#include "nsPrintfCString.h"
|
||||||
|
#include "nsSocketTransport2.h"
|
||||||
#include "nsSocketTransportService2.h"
|
#include "nsSocketTransportService2.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "prerror.h"
|
#include "prerror.h"
|
||||||
|
#include "prio.h"
|
||||||
|
#include "prmem.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
using namespace mozilla::net;
|
using namespace mozilla::net;
|
||||||
|
|
||||||
|
|
||||||
|
struct SocketActivity {
|
||||||
|
PROsfd fd;
|
||||||
|
uint32_t port;
|
||||||
|
nsString host;
|
||||||
|
uint32_t rx;
|
||||||
|
uint32_t tx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static PRStatus
|
static PRStatus
|
||||||
nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||||
{
|
{
|
||||||
|
@ -22,18 +36,29 @@ nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||||
PRErrorCode code;
|
PRErrorCode code;
|
||||||
ret = fd->lower->methods->connect(fd->lower, addr, timeout);
|
ret = fd->lower->methods->connect(fd->lower, addr, timeout);
|
||||||
if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
|
if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
|
||||||
code == PR_IN_PROGRESS_ERROR)
|
code == PR_IN_PROGRESS_ERROR) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
NetworkActivityMonitor::RegisterFd(fd, addr);
|
||||||
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, 0);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PRStatus
|
||||||
|
nsNetMon_Close(PRFileDesc *fd)
|
||||||
|
{
|
||||||
|
NetworkActivityMonitor::UnregisterFd(fd);
|
||||||
|
return fd->lower->methods->close(fd->lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
|
nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
|
||||||
{
|
{
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = fd->lower->methods->read(fd->lower, buf, len);
|
ret = fd->lower->methods->read(fd->lower, buf, len);
|
||||||
if (ret >= 0)
|
if (ret >= 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, len);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +67,9 @@ nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
|
||||||
{
|
{
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = fd->lower->methods->write(fd->lower, buf, len);
|
ret = fd->lower->methods->write(fd->lower, buf, len);
|
||||||
if (ret > 0)
|
if (ret > 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, len);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +81,9 @@ nsNetMon_Writev(PRFileDesc *fd,
|
||||||
{
|
{
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
||||||
if (ret > 0)
|
if (ret > 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, size);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +96,9 @@ nsNetMon_Recv(PRFileDesc *fd,
|
||||||
{
|
{
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
||||||
if (ret >= 0)
|
if (ret >= 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +111,9 @@ nsNetMon_Send(PRFileDesc *fd,
|
||||||
{
|
{
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
||||||
if (ret > 0)
|
if (ret > 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +132,9 @@ nsNetMon_RecvFrom(PRFileDesc *fd,
|
||||||
flags,
|
flags,
|
||||||
addr,
|
addr,
|
||||||
timeout);
|
timeout);
|
||||||
if (ret >= 0)
|
if (ret >= 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +153,9 @@ nsNetMon_SendTo(PRFileDesc *fd,
|
||||||
flags,
|
flags,
|
||||||
addr,
|
addr,
|
||||||
timeout);
|
timeout);
|
||||||
if (ret > 0)
|
if (ret > 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,88 +174,182 @@ nsNetMon_AcceptRead(PRFileDesc *listenSock,
|
||||||
buf,
|
buf,
|
||||||
amount,
|
amount,
|
||||||
timeout);
|
timeout);
|
||||||
if (ret > 0)
|
if (ret > 0) {
|
||||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, listenSock, amount);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(NetworkData, nsINetworkActivityData);
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkData::GetHost(nsAString& aHost) {
|
||||||
|
aHost = mHost;
|
||||||
|
return NS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkData::GetPort(int32_t* aPort) {
|
||||||
|
*aPort = mPort;
|
||||||
|
return NS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkData::GetRx(int32_t* aRx) {
|
||||||
|
*aRx = mRx;
|
||||||
|
return NS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkData::GetTx(int32_t* aTx) {
|
||||||
|
*aTx = mTx;
|
||||||
|
return NS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkData::GetFd(int32_t* aFd) {
|
||||||
|
*aFd = mFd;
|
||||||
|
return NS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
class NotifyNetworkActivity : public mozilla::Runnable {
|
class NotifyNetworkActivity : public mozilla::Runnable {
|
||||||
public:
|
public:
|
||||||
explicit NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection)
|
explicit NotifyNetworkActivity(NetworkActivity* aActivity)
|
||||||
: mozilla::Runnable("NotifyNetworkActivity")
|
: mozilla::Runnable("NotifyNetworkActivity")
|
||||||
, mDirection(aDirection)
|
|
||||||
{}
|
{
|
||||||
NS_IMETHOD Run() override
|
uint32_t rx;
|
||||||
|
uint32_t tx;
|
||||||
|
PROsfd fd;
|
||||||
|
for (auto iter = aActivity->rx.Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
rx = iter.Data();
|
||||||
|
fd = iter.Key();
|
||||||
|
tx = aActivity->tx.Get(fd);
|
||||||
|
if (rx == 0 && tx == 0) {
|
||||||
|
// nothing to do
|
||||||
|
} else {
|
||||||
|
SocketActivity activity;
|
||||||
|
activity.fd = fd;
|
||||||
|
activity.rx = rx;
|
||||||
|
activity.tx = tx;
|
||||||
|
activity.host = aActivity->host.Get(fd);
|
||||||
|
activity.port = aActivity->port.Get(fd);
|
||||||
|
mActivities.AppendElement(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
Run() override
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
if (mActivities.Length() == 0) {
|
||||||
if (!obs)
|
return NS_OK;
|
||||||
return NS_ERROR_FAILURE;
|
}
|
||||||
|
|
||||||
obs->NotifyObservers(nullptr,
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||||
mDirection == NetworkActivityMonitor::kUpload
|
if (!obs) {
|
||||||
? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
|
return NS_ERROR_FAILURE;
|
||||||
: NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,
|
}
|
||||||
nullptr);
|
|
||||||
|
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!array)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned long i = 0; i < mActivities.Length(); i++) {
|
||||||
|
nsCOMPtr<nsINetworkActivityData> data =
|
||||||
|
new NetworkData(mActivities[i].host,
|
||||||
|
mActivities[i].port,
|
||||||
|
mActivities[i].fd,
|
||||||
|
mActivities[i].rx,
|
||||||
|
mActivities[i].tx);
|
||||||
|
|
||||||
|
nsresult rv = array->AppendElement(data);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obs->NotifyObservers(array, NS_NETWORK_ACTIVITY, nullptr);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
NetworkActivityMonitor::Direction mDirection;
|
nsTArray<SocketActivity> mActivities;
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
|
|
||||||
|
mozilla::StaticRefPtr<NetworkActivityMonitor> gInstance;
|
||||||
static PRDescIdentity sNetActivityMonitorLayerIdentity;
|
static PRDescIdentity sNetActivityMonitorLayerIdentity;
|
||||||
static PRIOMethods sNetActivityMonitorLayerMethods;
|
static PRIOMethods sNetActivityMonitorLayerMethods;
|
||||||
static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
|
static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
|
||||||
|
NS_IMPL_ISUPPORTS(NetworkActivityMonitor, nsITimerCallback, nsINamed)
|
||||||
|
|
||||||
NetworkActivityMonitor::NetworkActivityMonitor()
|
NetworkActivityMonitor::NetworkActivityMonitor()
|
||||||
: mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
|
: mInterval(PR_INTERVAL_NO_TIMEOUT)
|
||||||
|
, mLock("NetworkActivityMonitor::mLock")
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(NetworkActivityMonitor);
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
MOZ_ASSERT(!mon, "multiple NetworkActivityMonitor instances!");
|
||||||
NS_ASSERTION(gInstance==nullptr,
|
|
||||||
"multiple NetworkActivityMonitor instances!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkActivityMonitor::~NetworkActivityMonitor()
|
NS_IMETHODIMP
|
||||||
|
NetworkActivityMonitor::Notify(nsITimer* aTimer)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_DTOR(NetworkActivityMonitor);
|
mozilla::MutexAutoLock lock(mLock);
|
||||||
gInstance = nullptr;
|
nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(&mActivity);
|
||||||
|
NS_DispatchToMainThread(ev);
|
||||||
|
// reset the counters
|
||||||
|
for (auto iter = mActivity.host.Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
uint32_t fd = iter.Key();
|
||||||
|
mActivity.tx.Put(fd, 0);
|
||||||
|
mActivity.rx.Put(fd, 0);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
NetworkActivityMonitor::GetName(nsACString& aName)
|
||||||
|
{
|
||||||
|
aName.AssignLiteral("NetworkActivityMonitor");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NetworkActivityMonitor::Init(int32_t blipInterval)
|
NetworkActivityMonitor::Init(int32_t aInterval)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv = NS_OK;
|
||||||
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
if (gInstance)
|
if (mon) {
|
||||||
return NS_ERROR_ALREADY_INITIALIZED;
|
return NS_ERROR_ALREADY_INITIALIZED;
|
||||||
|
} else {
|
||||||
NetworkActivityMonitor * mon = new NetworkActivityMonitor();
|
mon = new NetworkActivityMonitor();
|
||||||
rv = mon->Init_Internal(blipInterval);
|
rv = mon->Init_Internal(aInterval);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
delete mon;
|
gInstance = mon;
|
||||||
return rv;
|
} else {
|
||||||
|
rv = NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return rv;
|
||||||
gInstance = mon;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NetworkActivityMonitor::Shutdown()
|
NetworkActivityMonitor::Shutdown()
|
||||||
{
|
{
|
||||||
if (!gInstance)
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
if (!mon) {
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
delete gInstance;
|
mon->Shutdown_Internal();
|
||||||
|
gInstance = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
|
NetworkActivityMonitor::Init_Internal(int32_t aInterval)
|
||||||
{
|
{
|
||||||
if (!sNetActivityMonitorLayerMethodsPtr) {
|
if (!sNetActivityMonitorLayerMethodsPtr) {
|
||||||
sNetActivityMonitorLayerIdentity =
|
sNetActivityMonitorLayerIdentity =
|
||||||
|
@ -239,27 +364,35 @@ NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
|
||||||
sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom;
|
sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom;
|
||||||
sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo;
|
sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo;
|
||||||
sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
|
sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
|
||||||
|
sNetActivityMonitorLayerMethods.close = nsNetMon_Close;
|
||||||
sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
|
sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBlipInterval = PR_MillisecondsToInterval(blipInterval);
|
// create and fire the timer
|
||||||
// Set the last notification times to time that has just expired, so any
|
mInterval = aInterval;
|
||||||
// activity even right now will trigger notification.
|
mTimer = NS_NewTimer();
|
||||||
mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval;
|
if (!mTimer) {
|
||||||
mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload];
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
NetworkActivityMonitor::Shutdown_Internal()
|
||||||
|
{
|
||||||
|
mTimer->Cancel();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
||||||
{
|
{
|
||||||
if (!gInstance)
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
if (!mon) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
}
|
||||||
PRFileDesc * layer;
|
PRFileDesc * layer;
|
||||||
PRStatus status;
|
PRStatus status;
|
||||||
|
|
||||||
layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
||||||
sNetActivityMonitorLayerMethodsPtr);
|
sNetActivityMonitorLayerMethodsPtr);
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
|
@ -277,25 +410,102 @@ NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NetworkActivityMonitor::DataInOut(Direction direction)
|
NetworkActivityMonitor::RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr) {
|
||||||
{
|
|
||||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||||
|
if (NS_WARN_IF(osfd == -1)) {
|
||||||
|
return ErrorAccordingToNSPR(PR_GetError());
|
||||||
|
}
|
||||||
|
uint16_t port;
|
||||||
|
if (aAddr->raw.family == PR_AF_INET) {
|
||||||
|
port = aAddr->inet.port;
|
||||||
|
} else {
|
||||||
|
port = aAddr->ipv6.port;
|
||||||
|
}
|
||||||
|
char _host[net::kNetAddrMaxCStrBufSize] = {0};
|
||||||
|
nsAutoCString host;
|
||||||
|
if (PR_NetAddrToString(aAddr, _host, sizeof(_host) - 1) == PR_SUCCESS) {
|
||||||
|
host.Assign(_host);
|
||||||
|
} else {
|
||||||
|
host.AppendPrintf("N/A");
|
||||||
|
}
|
||||||
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
if (mon) {
|
||||||
|
return mon->RegisterFd_Internal(osfd, NS_ConvertUTF8toUTF16(host), port);
|
||||||
|
}
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (gInstance) {
|
nsresult
|
||||||
PRIntervalTime now = PR_IntervalNow();
|
NetworkActivityMonitor::UnregisterFd(PRFileDesc *aFd)
|
||||||
if ((now - gInstance->mLastNotificationTime[direction]) >
|
{
|
||||||
gInstance->mBlipInterval) {
|
nsresult rv;
|
||||||
gInstance->mLastNotificationTime[direction] = now;
|
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||||
gInstance->PostNotification(direction);
|
if (NS_WARN_IF(osfd == -1)) {
|
||||||
|
rv = ErrorAccordingToNSPR(PR_GetError());
|
||||||
|
} else {
|
||||||
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
if (mon) {
|
||||||
|
rv = mon->UnregisterFd_Internal(osfd);
|
||||||
|
} else {
|
||||||
|
rv = NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
NetworkActivityMonitor::UnregisterFd_Internal(PROsfd aOsfd)
|
||||||
|
{
|
||||||
|
mozilla::MutexAutoLock lock(mLock);
|
||||||
|
// XXX we should remove scokets that have been unregistered
|
||||||
|
// after some time.
|
||||||
|
mActivity.active.Put(aOsfd, false);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NetworkActivityMonitor::PostNotification(Direction direction)
|
nsresult
|
||||||
|
NetworkActivityMonitor::RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction);
|
mozilla::MutexAutoLock lock(mLock);
|
||||||
NS_DispatchToMainThread(ev);
|
mActivity.port.Put(aOsfd, port);
|
||||||
|
mActivity.host.Put(aOsfd, host);
|
||||||
|
mActivity.rx.Put(aOsfd, 0);
|
||||||
|
mActivity.tx.Put(aOsfd, 0);
|
||||||
|
mActivity.active.Put(aOsfd, true);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
NetworkActivityMonitor::DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount)
|
||||||
|
{
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||||
|
if (mon) {
|
||||||
|
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||||
|
if (NS_WARN_IF(osfd == -1)) {
|
||||||
|
rv = ErrorAccordingToNSPR(PR_GetError());
|
||||||
|
} else {
|
||||||
|
rv = mon->DataInOut_Internal(osfd, aDirection, aAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
NetworkActivityMonitor::DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount)
|
||||||
|
{
|
||||||
|
mozilla::MutexAutoLock lock(mLock);
|
||||||
|
uint32_t current;
|
||||||
|
if (aDirection == NetworkActivityMonitor::kUpload) {
|
||||||
|
current = mActivity.tx.Get(aOsfd);
|
||||||
|
mActivity.tx.Put(aOsfd, aAmount + current);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current = mActivity.rx.Get(aOsfd);
|
||||||
|
mActivity.rx.Put(aOsfd, aAmount + current);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,56 @@
|
||||||
#ifndef NetworkActivityMonitor_h___
|
#ifndef NetworkActivityMonitor_h___
|
||||||
#define NetworkActivityMonitor_h___
|
#define NetworkActivityMonitor_h___
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "nsCOMPtr.h"
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "prio.h"
|
#include "nsDataHashtable.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
#include "nsINetworkActivityData.h"
|
||||||
|
#include "nsISupports.h"
|
||||||
|
#include "nsITimer.h"
|
||||||
#include "prinrval.h"
|
#include "prinrval.h"
|
||||||
|
#include "prio.h"
|
||||||
|
#include "private/pprio.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace mozilla { namespace net {
|
namespace mozilla { namespace net {
|
||||||
|
|
||||||
class NetworkActivityMonitor
|
typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketBytes;
|
||||||
|
typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketPort;
|
||||||
|
typedef nsDataHashtable<nsUint32HashKey, nsString> SocketHost;
|
||||||
|
typedef nsDataHashtable<nsUint32HashKey, bool> SocketActive;
|
||||||
|
|
||||||
|
|
||||||
|
struct NetworkActivity {
|
||||||
|
SocketPort port;
|
||||||
|
SocketHost host;
|
||||||
|
SocketBytes rx;
|
||||||
|
SocketBytes tx;
|
||||||
|
SocketActive active;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkData final : public nsINetworkActivityData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSINETWORKACTIVITYDATA
|
||||||
|
NetworkData(const nsString& aHost, int32_t aPort, int32_t aFd,
|
||||||
|
int32_t aRx, int32_t aTx)
|
||||||
|
: mHost(aHost), mPort(aPort), mFd(aFd), mRx(aRx), mTx(aTx) {}
|
||||||
|
private:
|
||||||
|
~NetworkData() = default;
|
||||||
|
|
||||||
|
nsString mHost;
|
||||||
|
int32_t mPort;
|
||||||
|
int32_t mFd;
|
||||||
|
int32_t mRx;
|
||||||
|
int32_t mTx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkActivityMonitor: public nsITimerCallback
|
||||||
|
, public nsINamed
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Direction {
|
enum Direction {
|
||||||
|
@ -23,21 +65,28 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkActivityMonitor();
|
NetworkActivityMonitor();
|
||||||
~NetworkActivityMonitor();
|
|
||||||
|
|
||||||
static nsresult Init(int32_t blipInterval);
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSITIMERCALLBACK
|
||||||
|
NS_DECL_NSINAMED
|
||||||
|
|
||||||
|
static nsresult Init(int32_t aInterval);
|
||||||
static nsresult Shutdown();
|
static nsresult Shutdown();
|
||||||
|
|
||||||
static nsresult AttachIOLayer(PRFileDesc *fd);
|
static nsresult AttachIOLayer(PRFileDesc *fd);
|
||||||
static nsresult DataInOut(Direction direction);
|
static nsresult DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount);
|
||||||
|
static nsresult RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr);
|
||||||
|
static nsresult UnregisterFd(PRFileDesc *aFd);
|
||||||
private:
|
private:
|
||||||
nsresult Init_Internal(int32_t blipInterval);
|
virtual ~NetworkActivityMonitor() = default;
|
||||||
void PostNotification(Direction direction);
|
nsresult Init_Internal(int32_t aInterval);
|
||||||
|
nsresult Shutdown_Internal();
|
||||||
static NetworkActivityMonitor * gInstance;
|
nsresult RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port);
|
||||||
PRIntervalTime mBlipInterval;
|
nsresult UnregisterFd_Internal(PROsfd aOsfd);
|
||||||
PRIntervalTime mLastNotificationTime[2];
|
nsresult DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount);
|
||||||
|
uint32_t mInterval;
|
||||||
|
NetworkActivity mActivity;
|
||||||
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
|
Mutex mLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
|
|
|
@ -62,6 +62,7 @@ XPIDL_SOURCES += [
|
||||||
'nsINestedURI.idl',
|
'nsINestedURI.idl',
|
||||||
'nsINetAddr.idl',
|
'nsINetAddr.idl',
|
||||||
'nsINetUtil.idl',
|
'nsINetUtil.idl',
|
||||||
|
'nsINetworkActivityData.idl',
|
||||||
'nsINetworkInfoService.idl',
|
'nsINetworkInfoService.idl',
|
||||||
'nsINetworkInterceptController.idl',
|
'nsINetworkInterceptController.idl',
|
||||||
'nsINetworkLinkService.idl',
|
'nsINetworkLinkService.idl',
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep tracks of the bytes that are sent (tx) and received (rx)
|
||||||
|
* into a socket identified by its file descriptor (fd)
|
||||||
|
* for a given host & port.
|
||||||
|
*/
|
||||||
|
[scriptable, builtinclass, uuid(30d5f743-939e-46c6-808a-7ea07c77028e)]
|
||||||
|
interface nsINetworkActivityData : nsISupports
|
||||||
|
{
|
||||||
|
readonly attribute DOMString host;
|
||||||
|
readonly attribute long port;
|
||||||
|
readonly attribute long rx;
|
||||||
|
readonly attribute long tx;
|
||||||
|
readonly attribute long fd;
|
||||||
|
};
|
||||||
|
|
|
@ -49,13 +49,13 @@ interface nsPISocketTransportService : nsIRoutedSocketTransportService
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
/*
|
/*
|
||||||
* Network activity indicator: we send out these topics no more than every
|
* Network activity: we send out this topic no more than every
|
||||||
* blipIntervalMilliseconds (as set by the
|
* intervalMilliseconds (as set by the
|
||||||
* "network.activity.blipIntervalMilliseconds" preference: if 0 no notifications
|
* "network.activity.intervalMilliseconds" preference: if 0 no notifications
|
||||||
* are sent) if the network is currently active (i.e. we're sending/receiving
|
* are sent) if the network is currently active (i.e. we're sending/receiving
|
||||||
* data to/from the socket).
|
* data to/from the socket).
|
||||||
*/
|
*/
|
||||||
#define NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC "network-activity-blip-upload"
|
#define NS_NETWORK_ACTIVITY "network-activity"
|
||||||
#define NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC "network-activity-blip-download"
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -49,7 +49,7 @@ static Atomic<PRThread*, Relaxed> gSocketThread;
|
||||||
#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
|
#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
|
||||||
#define SOCKET_LIMIT_TARGET 1000U
|
#define SOCKET_LIMIT_TARGET 1000U
|
||||||
#define SOCKET_LIMIT_MIN 50U
|
#define SOCKET_LIMIT_MIN 50U
|
||||||
#define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"
|
#define INTERVAL_PREF "network.activity.intervalMilliseconds"
|
||||||
#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
|
#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
|
||||||
#define TELEMETRY_PREF "toolkit.telemetry.enabled"
|
#define TELEMETRY_PREF "toolkit.telemetry.enabled"
|
||||||
#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
|
#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
|
||||||
|
@ -1353,12 +1353,12 @@ nsSocketTransportService::Observe(nsISupports *subject,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(topic, "profile-initial-state")) {
|
if (!strcmp(topic, "profile-initial-state")) {
|
||||||
int32_t blipInterval = Preferences::GetInt(BLIP_INTERVAL_PREF, 0);
|
int32_t interval = Preferences::GetInt(INTERVAL_PREF, 0);
|
||||||
if (blipInterval <= 0) {
|
if (interval <= 0) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return net::NetworkActivityMonitor::Init(blipInterval);
|
return net::NetworkActivityMonitor::Init(interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(topic, "last-pb-context-exited")) {
|
if (!strcmp(topic, "last-pb-context-exited")) {
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
// test for networkactivity
|
||||||
|
//
|
||||||
|
Cu.import("resource://testing-common/httpd.js");
|
||||||
|
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||||
|
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||||
|
|
||||||
|
var httpserver = new HttpServer();
|
||||||
|
var results = [];
|
||||||
|
var prefs = Cc["@mozilla.org/preferences-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPrefBranch);
|
||||||
|
|
||||||
|
|
||||||
|
function createChannel() {
|
||||||
|
var chan = NetUtil.newChannel({
|
||||||
|
uri: "http://localhost:" + httpserver.identity.primaryPort + "/ok",
|
||||||
|
loadUsingSystemPrincipal: true
|
||||||
|
});
|
||||||
|
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||||
|
return httpChan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handler(metadata, response) {
|
||||||
|
var body = "meh";
|
||||||
|
response.setHeader("Content-Type", "text/plain", false);
|
||||||
|
response.setStatusLine(metadata.httpVersion, 200, "OK");
|
||||||
|
response.bodyOutputStream.write(body, body.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkValueAndTrigger(request, data) {
|
||||||
|
// give Firefox 150 ms to send notifications out
|
||||||
|
do_timeout(150, doTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doTest() {
|
||||||
|
prefs.clearUserPref("network.activity.intervalMilliseconds");
|
||||||
|
ok(results.length>0);
|
||||||
|
ok(results[0].host == "127.0.0.1");
|
||||||
|
ok(results[0].rx > 100);
|
||||||
|
httpserver.stop(do_test_finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
// setting up an observer
|
||||||
|
let networkActivity = function(subject, topic, value) {
|
||||||
|
subject.QueryInterface(Ci.nsIMutableArray);
|
||||||
|
let enumerator = subject.enumerate();
|
||||||
|
while (enumerator.hasMoreElements()) {
|
||||||
|
let data = enumerator.getNext();
|
||||||
|
data.QueryInterface(Ci.nsINetworkActivityData);
|
||||||
|
results.push(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Services.obs.addObserver(networkActivity, 'network-activity');
|
||||||
|
|
||||||
|
// send events every 100ms
|
||||||
|
prefs.setIntPref("network.activity.intervalMilliseconds", 100);
|
||||||
|
|
||||||
|
// why do I have to do this ??
|
||||||
|
Services.obs.notifyObservers(null, "profile-initial-state", null);
|
||||||
|
|
||||||
|
do_test_pending();
|
||||||
|
httpserver.registerPathHandler("/ok", handler);
|
||||||
|
httpserver.start(-1);
|
||||||
|
var channel = createChannel();
|
||||||
|
channel.asyncOpen2(new ChannelListener(checkValueAndTrigger, null));
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ support-files =
|
||||||
test_link.url
|
test_link.url
|
||||||
../../dns/effective_tld_names.dat
|
../../dns/effective_tld_names.dat
|
||||||
|
|
||||||
|
[test_network_activity.js]
|
||||||
[test_nsIBufferedOutputStream_writeFrom_block.js]
|
[test_nsIBufferedOutputStream_writeFrom_block.js]
|
||||||
[test_cache2-00-service-get.js]
|
[test_cache2-00-service-get.js]
|
||||||
[test_cache2-01-basic.js]
|
[test_cache2-01-basic.js]
|
||||||
|
|
|
@ -160,7 +160,7 @@ user_pref("dom.use_xbl_scopes_for_remote_xul", true);
|
||||||
|
|
||||||
user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt");
|
user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt");
|
||||||
// Get network events.
|
// Get network events.
|
||||||
user_pref("network.activity.blipIntervalMilliseconds", 250);
|
user_pref("network.activity.intervalMilliseconds", 5000);
|
||||||
|
|
||||||
// We do not wish to display datareporting policy notifications as it might
|
// We do not wish to display datareporting policy notifications as it might
|
||||||
// cause other tests to fail. Tests that wish to test the notification functionality
|
// cause other tests to fail. Tests that wish to test the notification functionality
|
||||||
|
|
Загрузка…
Ссылка в новой задаче