|
@@ -0,0 +1,1699 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Tarek Ziadé <tarek@mozilla.com>
|
|
|
+# Date 1528834970 25200
|
|
|
+# Node ID 1d8ffa02b2af02b23a34f426466a8f26395ac0d2
|
|
|
+# Parent 23ab9d4fe794988e9b1d85472daca3c1b796b633
|
|
|
+Bug 1447931 - NetworkActivity becomes IOActivity - r=baku,mak,valentin
|
|
|
+
|
|
|
+Generalizes NetworkActivity so it can be used for sockets but also disk files.
|
|
|
+The host/port data becomes a single location string prefixed with socket://
|
|
|
+or file:// and we're not using the FD as the identifier anymore.
|
|
|
+
|
|
|
+IOActivityMonitor is now used in three places:
|
|
|
+
|
|
|
+- nsFileStreams for plain files
|
|
|
+- TelemetryVFS for sqlite files
|
|
|
+- nsSocketTransport & nsUDPSocket for UDP & TCP sockets
|
|
|
+
|
|
|
+MozReview-Commit-ID: GNu5o400PaV
|
|
|
+
|
|
|
+diff --git a/dom/tests/browser/dummy.html b/dom/tests/browser/dummy.html
|
|
|
+--- a/dom/tests/browser/dummy.html
|
|
|
++++ b/dom/tests/browser/dummy.html
|
|
|
+@@ -1,9 +1,13 @@
|
|
|
++<!doctype html>
|
|
|
+ <html>
|
|
|
+ <head>
|
|
|
+ <title>Dummy test page</title>
|
|
|
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <p>Dummy test page</p>
|
|
|
++<script>
|
|
|
++ localStorage.setItem("foo", "bar");
|
|
|
++</script>
|
|
|
+ </body>
|
|
|
+ </html>
|
|
|
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
|
|
|
+--- a/modules/libpref/init/all.js
|
|
|
++++ b/modules/libpref/init/all.js
|
|
|
+@@ -5412,21 +5412,23 @@ pref("memory.dump_reports_on_oom", false
|
|
|
+
|
|
|
+ // Number of stack frames to capture in createObjectURL for about:memory.
|
|
|
+ pref("memory.blob_report.stack_frames", 0);
|
|
|
+
|
|
|
+ // Disable idle observer fuzz, because only privileged content can access idle
|
|
|
+ // observers (bug 780507).
|
|
|
+ pref("dom.idle-observers-api.fuzz_time.disabled", true);
|
|
|
+
|
|
|
+-// Minimum delay in milliseconds between network activity notifications (0 means
|
|
|
+-// no notifications). The delay is the same for both download and upload, though
|
|
|
++// Minimum delay in milliseconds between I/O activity notifications (0 means
|
|
|
++// no notifications). I/O activity includes socket and disk files.
|
|
|
++//
|
|
|
++// The delay is the same for both read and write, though
|
|
|
+ // they are handled separately. This pref is only read once at startup:
|
|
|
+ // a restart is required to enable a new value.
|
|
|
+-pref("network.activity.intervalMilliseconds", 0);
|
|
|
++pref("io.activity.intervalMilliseconds", 0);
|
|
|
+
|
|
|
+ // 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
|
|
|
+ // for the scripts to interfere with each other. A restart is required for this
|
|
|
+ // to take effect.
|
|
|
+ pref("jsloader.shareGlobal", false);
|
|
|
+
|
|
|
+ // When we're asked to take a screenshot, don't wait more than 2000ms for the
|
|
|
+diff --git a/netwerk/base/NetworkActivityMonitor.cpp b/netwerk/base/IOActivityMonitor.cpp
|
|
|
+rename from netwerk/base/NetworkActivityMonitor.cpp
|
|
|
+rename to netwerk/base/IOActivityMonitor.cpp
|
|
|
+--- a/netwerk/base/NetworkActivityMonitor.cpp
|
|
|
++++ b/netwerk/base/IOActivityMonitor.cpp
|
|
|
+@@ -1,369 +1,444 @@
|
|
|
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
+ *
|
|
|
+ * 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 "NetworkActivityMonitor.h"
|
|
|
++#include "IOActivityMonitor.h"
|
|
|
+ #include "nsIObserverService.h"
|
|
|
+ #include "nsPISocketTransportService.h"
|
|
|
+ #include "nsPrintfCString.h"
|
|
|
+ #include "nsSocketTransport2.h"
|
|
|
+ #include "nsSocketTransportService2.h"
|
|
|
+ #include "nsThreadUtils.h"
|
|
|
+ #include "mozilla/Services.h"
|
|
|
+ #include "prerror.h"
|
|
|
+ #include "prio.h"
|
|
|
+ #include "prmem.h"
|
|
|
+ #include <vector>
|
|
|
+
|
|
|
+-
|
|
|
+ using namespace mozilla::net;
|
|
|
+
|
|
|
+-
|
|
|
+-struct SocketActivity {
|
|
|
+- PROsfd fd;
|
|
|
+- uint32_t port;
|
|
|
+- nsString host;
|
|
|
+- uint32_t rx;
|
|
|
+- uint32_t tx;
|
|
|
+-};
|
|
|
+-
|
|
|
+-mozilla::StaticRefPtr<NetworkActivityMonitor> gInstance;
|
|
|
++mozilla::StaticRefPtr<IOActivityMonitor> gInstance;
|
|
|
+ static PRDescIdentity sNetActivityMonitorLayerIdentity;
|
|
|
+ static PRIOMethods sNetActivityMonitorLayerMethods;
|
|
|
+ static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
|
|
|
+
|
|
|
++// Maximum number of activities entries in the monitoring class
|
|
|
++#define MAX_ACTIVITY_ENTRIES 1000
|
|
|
++
|
|
|
++
|
|
|
++// ActivityMonitorSecret is stored in the activity monitor layer
|
|
|
++// and provides a method to get the location.
|
|
|
++//
|
|
|
++// A location can be :
|
|
|
++// - a TCP or UDP socket. The form will be socket://ip:port
|
|
|
++// - a File. The form will be file://path
|
|
|
++//
|
|
|
++// For other cases, the location will be fd://number
|
|
|
++class ActivityMonitorSecret final
|
|
|
++{
|
|
|
++public:
|
|
|
++ // constructor used for sockets
|
|
|
++ explicit ActivityMonitorSecret(PRFileDesc* aFd) {
|
|
|
++ mFd = aFd;
|
|
|
++ mLocationSet = false;
|
|
|
++ }
|
|
|
++
|
|
|
++ // constructor used for files
|
|
|
++ explicit ActivityMonitorSecret(PRFileDesc* aFd, const char* aLocation) {
|
|
|
++ mFd = aFd;
|
|
|
++ mLocation.AppendPrintf("file://%s", aLocation);
|
|
|
++ mLocationSet = true;
|
|
|
++ }
|
|
|
++
|
|
|
++ nsCString getLocation() {
|
|
|
++ if (!mLocationSet) {
|
|
|
++ LazySetLocation();
|
|
|
++ }
|
|
|
++ return mLocation;
|
|
|
++ }
|
|
|
++private:
|
|
|
++ // Called to set the location using the FD on the first getLocation() usage
|
|
|
++ // which is typically when a socket is opened. If done earlier, at
|
|
|
++ // construction time, the host won't be bound yet.
|
|
|
++ //
|
|
|
++ // If the location is a file, it needs to be initialized in the
|
|
|
++ // constructor.
|
|
|
++ void LazySetLocation() {
|
|
|
++ mLocationSet = true;
|
|
|
++ PRFileDesc* extract = mFd;
|
|
|
++ while (PR_GetDescType(extract) == PR_DESC_LAYERED) {
|
|
|
++ if (!extract->lower) {
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ extract = extract->lower;
|
|
|
++ }
|
|
|
++
|
|
|
++ PRDescType fdType = PR_GetDescType(extract);
|
|
|
++ // we should not use LazySetLocation for files
|
|
|
++ MOZ_ASSERT(fdType != PR_DESC_FILE);
|
|
|
++
|
|
|
++ switch (fdType) {
|
|
|
++ case PR_DESC_SOCKET_TCP:
|
|
|
++ case PR_DESC_SOCKET_UDP: {
|
|
|
++ mLocation.AppendPrintf("socket://");
|
|
|
++ PRNetAddr addr;
|
|
|
++ PRStatus status = PR_GetSockName(mFd, &addr);
|
|
|
++ if (NS_WARN_IF(status == PR_FAILURE)) {
|
|
|
++ mLocation.AppendPrintf("unknown");
|
|
|
++ break;
|
|
|
++ }
|
|
|
++
|
|
|
++ // grabbing the host
|
|
|
++ char netAddr[mozilla::net::kNetAddrMaxCStrBufSize] = {0};
|
|
|
++ status = PR_NetAddrToString(&addr, netAddr, sizeof(netAddr) - 1);
|
|
|
++ if (NS_WARN_IF(status == PR_FAILURE) || netAddr[0] == 0) {
|
|
|
++ mLocation.AppendPrintf("unknown");
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ mLocation.Append(netAddr);
|
|
|
++
|
|
|
++ // adding the port
|
|
|
++ uint16_t port;
|
|
|
++ if (addr.raw.family == PR_AF_INET) {
|
|
|
++ port = addr.inet.port;
|
|
|
++ } else {
|
|
|
++ port = addr.ipv6.port;
|
|
|
++ }
|
|
|
++ mLocation.AppendPrintf(":%d", port);
|
|
|
++ } break;
|
|
|
++
|
|
|
++ // for all other cases, we just send back fd://<value>
|
|
|
++ default: {
|
|
|
++ mLocation.AppendPrintf("fd://%d", PR_FileDesc2NativeHandle(mFd));
|
|
|
++ }
|
|
|
++ } // end switch
|
|
|
++ }
|
|
|
++private:
|
|
|
++ nsCString mLocation;
|
|
|
++ bool mLocationSet;
|
|
|
++ PRFileDesc* mFd;
|
|
|
++};
|
|
|
++
|
|
|
++// FileDesc2Location converts a PRFileDesc into a "location" by
|
|
|
++// grabbing the ActivityMonitorSecret in layer->secret
|
|
|
++static nsAutoCString
|
|
|
++FileDesc2Location(PRFileDesc *fd)
|
|
|
++{
|
|
|
++ nsAutoCString location;
|
|
|
++ PRFileDesc *monitorLayer = PR_GetIdentitiesLayer(fd, sNetActivityMonitorLayerIdentity);
|
|
|
++ if (!monitorLayer) {
|
|
|
++ location.AppendPrintf("unknown");
|
|
|
++ return location;
|
|
|
++ }
|
|
|
++
|
|
|
++ ActivityMonitorSecret* secret = (ActivityMonitorSecret*)monitorLayer->secret;
|
|
|
++ location.AppendPrintf("%s", secret->getLocation().get());
|
|
|
++ return location;
|
|
|
++}
|
|
|
++
|
|
|
++//
|
|
|
++// Wrappers around the socket APIS
|
|
|
++//
|
|
|
+ static PRStatus
|
|
|
+ nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- PRStatus ret;
|
|
|
+- PRErrorCode code;
|
|
|
+- ret = fd->lower->methods->connect(fd->lower, addr, timeout);
|
|
|
+- if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
|
|
|
+- code == PR_IN_PROGRESS_ERROR) {
|
|
|
+- NetworkActivityMonitor::RegisterFd(fd, addr);
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, 0);
|
|
|
+- }
|
|
|
+- return ret;
|
|
|
++ return fd->lower->methods->connect(fd->lower, addr, timeout);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static PRStatus
|
|
|
+ nsNetMon_Close(PRFileDesc *fd)
|
|
|
+ {
|
|
|
+ if (!fd) {
|
|
|
+ return PR_FAILURE;
|
|
|
+ }
|
|
|
+- NetworkActivityMonitor::UnregisterFd(fd);
|
|
|
+ PRFileDesc* layer = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
|
|
|
+ MOZ_RELEASE_ASSERT(layer &&
|
|
|
+ layer->identity == sNetActivityMonitorLayerIdentity,
|
|
|
+ "NetActivityMonitor Layer not on top of stack");
|
|
|
++
|
|
|
++ if (layer->secret) {
|
|
|
++ delete (ActivityMonitorSecret *)layer->secret;
|
|
|
++ layer->secret = nullptr;
|
|
|
++ }
|
|
|
+ layer->dtor(layer);
|
|
|
+ return fd->methods->close(fd);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->read(fd->lower, buf, len);
|
|
|
++ int32_t ret = fd->lower->methods->read(fd->lower, buf, len);
|
|
|
+ if (ret >= 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, len);
|
|
|
++ IOActivityMonitor::Read(fd, len);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->write(fd->lower, buf, len);
|
|
|
++ int32_t ret = fd->lower->methods->write(fd->lower, buf, len);
|
|
|
+ if (ret > 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, len);
|
|
|
++ IOActivityMonitor::Write(fd, len);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_Writev(PRFileDesc *fd,
|
|
|
+ const PRIOVec *iov,
|
|
|
+ int32_t size,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
|
|
++ int32_t ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
|
|
+ if (ret > 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, size);
|
|
|
++ IOActivityMonitor::Write(fd, size);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_Recv(PRFileDesc *fd,
|
|
|
+ void *buf,
|
|
|
+ int32_t amount,
|
|
|
+ int flags,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
|
|
+- if (ret >= 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
|
|
++ int32_t ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
|
|
++ if (ret > 0) {
|
|
|
++ IOActivityMonitor::Read(fd, amount);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_Send(PRFileDesc *fd,
|
|
|
+ const void *buf,
|
|
|
+ int32_t amount,
|
|
|
+ int flags,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
|
|
++ int32_t ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
|
|
+ if (ret > 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
|
|
++ IOActivityMonitor::Write(fd, amount);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_RecvFrom(PRFileDesc *fd,
|
|
|
+ void *buf,
|
|
|
+ int32_t amount,
|
|
|
+ int flags,
|
|
|
+ PRNetAddr *addr,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->recvfrom(fd->lower,
|
|
|
+- buf,
|
|
|
+- amount,
|
|
|
+- flags,
|
|
|
+- addr,
|
|
|
+- timeout);
|
|
|
+- if (ret >= 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
|
|
++ int32_t ret = fd->lower->methods->recvfrom(fd->lower, buf, amount, flags,
|
|
|
++ addr, timeout);
|
|
|
++ if (ret > 0) {
|
|
|
++ IOActivityMonitor::Read(fd, amount);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_SendTo(PRFileDesc *fd,
|
|
|
+ const void *buf,
|
|
|
+ int32_t amount,
|
|
|
+ int flags,
|
|
|
+ const PRNetAddr *addr,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = fd->lower->methods->sendto(fd->lower,
|
|
|
+- buf,
|
|
|
+- amount,
|
|
|
+- flags,
|
|
|
+- addr,
|
|
|
+- timeout);
|
|
|
++ int32_t ret = fd->lower->methods->sendto(fd->lower, buf, amount, flags,
|
|
|
++ addr, timeout);
|
|
|
+ if (ret > 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
|
|
++ IOActivityMonitor::Write(fd, amount);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int32_t
|
|
|
+ nsNetMon_AcceptRead(PRFileDesc *listenSock,
|
|
|
+ PRFileDesc **acceptedSock,
|
|
|
+ PRNetAddr **peerAddr,
|
|
|
+ void *buf,
|
|
|
+ int32_t amount,
|
|
|
+ PRIntervalTime timeout)
|
|
|
+ {
|
|
|
+- int32_t ret;
|
|
|
+- ret = listenSock->lower->methods->acceptread(listenSock->lower,
|
|
|
+- acceptedSock,
|
|
|
+- peerAddr,
|
|
|
+- buf,
|
|
|
+- amount,
|
|
|
+- timeout);
|
|
|
++ int32_t ret = listenSock->lower->methods->acceptread(listenSock->lower, acceptedSock,
|
|
|
++ peerAddr, buf, amount, timeout);
|
|
|
+ if (ret > 0) {
|
|
|
+- NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, listenSock, amount);
|
|
|
++ IOActivityMonitor::Read(listenSock, amount);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+-NS_IMPL_ISUPPORTS(NetworkData, nsINetworkActivityData);
|
|
|
++//
|
|
|
++// Class IOActivityData
|
|
|
++//
|
|
|
++NS_IMPL_ISUPPORTS(IOActivityData, nsIIOActivityData);
|
|
|
+
|
|
|
+ NS_IMETHODIMP
|
|
|
+-NetworkData::GetHost(nsAString& aHost) {
|
|
|
+- aHost = mHost;
|
|
|
++IOActivityData::GetLocation(nsACString& aLocation) {
|
|
|
++ aLocation = mActivity.location;
|
|
|
+ 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;
|
|
|
++IOActivityData::GetRx(int32_t* aRx) {
|
|
|
++ *aRx = mActivity.rx;
|
|
|
+ return NS_OK;
|
|
|
+ };
|
|
|
+
|
|
|
+ NS_IMETHODIMP
|
|
|
+-NetworkData::GetFd(int32_t* aFd) {
|
|
|
+- *aFd = mFd;
|
|
|
++IOActivityData::GetTx(int32_t* aTx) {
|
|
|
++ *aTx = mActivity.tx;
|
|
|
+ return NS_OK;
|
|
|
+ };
|
|
|
+
|
|
|
+-class NotifyNetworkActivity : public mozilla::Runnable {
|
|
|
++//
|
|
|
++// Class NotifyIOActivity
|
|
|
++//
|
|
|
++// Runnable that takes the activities per FD and location
|
|
|
++// and converts them into IOActivity elements.
|
|
|
++//
|
|
|
++// These elements get notified.
|
|
|
++//
|
|
|
++class NotifyIOActivity : public mozilla::Runnable {
|
|
|
++
|
|
|
+ public:
|
|
|
+- explicit NotifyNetworkActivity(NetworkActivity* aActivity)
|
|
|
+- : mozilla::Runnable("NotifyNetworkActivity")
|
|
|
+-
|
|
|
++ static already_AddRefed<nsIRunnable>
|
|
|
++ Create(Activities& aActivities, const mozilla::MutexAutoLock& aProofOfLock)
|
|
|
+ {
|
|
|
+- 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);
|
|
|
++ RefPtr<NotifyIOActivity> runnable = new NotifyIOActivity();
|
|
|
++
|
|
|
++ for (auto iter = aActivities.Iter(); !iter.Done(); iter.Next()) {
|
|
|
++ IOActivity* activity = iter.Data();
|
|
|
++ if (!activity->Inactive()) {
|
|
|
++ if (NS_WARN_IF(!runnable->mActivities.AppendElement(*activity, mozilla::fallible))) {
|
|
|
++ return nullptr;
|
|
|
++ }
|
|
|
+ }
|
|
|
+ }
|
|
|
++ nsCOMPtr<nsIRunnable> result(runnable);
|
|
|
++ return result.forget();
|
|
|
+ }
|
|
|
+
|
|
|
+ NS_IMETHODIMP
|
|
|
+ Run() override
|
|
|
+ {
|
|
|
+ MOZ_ASSERT(NS_IsMainThread());
|
|
|
+-
|
|
|
+ if (mActivities.Length() == 0) {
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
+ if (!obs) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+-
|
|
|
++ nsCOMPtr<nsIIOActivityData> data = new IOActivityData(mActivities[i]);
|
|
|
+ nsresult rv = array->AppendElement(data);
|
|
|
+ if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+ }
|
|
|
+- obs->NotifyObservers(array, NS_NETWORK_ACTIVITY, nullptr);
|
|
|
++ obs->NotifyObservers(array, NS_IO_ACTIVITY, nullptr);
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
++
|
|
|
+ private:
|
|
|
+- nsTArray<SocketActivity> mActivities;
|
|
|
++ explicit NotifyIOActivity()
|
|
|
++ : mozilla::Runnable("NotifyIOActivity")
|
|
|
++ {
|
|
|
++ }
|
|
|
++
|
|
|
++ FallibleTArray<IOActivity> mActivities;
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+-NS_IMPL_ISUPPORTS(NetworkActivityMonitor, nsITimerCallback, nsINamed)
|
|
|
++//
|
|
|
++// Class IOActivityMonitor
|
|
|
++//
|
|
|
++NS_IMPL_ISUPPORTS(IOActivityMonitor, nsITimerCallback, nsINamed)
|
|
|
+
|
|
|
+-NetworkActivityMonitor::NetworkActivityMonitor()
|
|
|
++IOActivityMonitor::IOActivityMonitor()
|
|
|
+ : mInterval(PR_INTERVAL_NO_TIMEOUT)
|
|
|
+- , mLock("NetworkActivityMonitor::mLock")
|
|
|
++ , mLock("IOActivityMonitor::mLock")
|
|
|
+ {
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- MOZ_ASSERT(!mon, "multiple NetworkActivityMonitor instances!");
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ MOZ_ASSERT(!mon, "multiple IOActivityMonitor instances!");
|
|
|
+ }
|
|
|
+
|
|
|
+ NS_IMETHODIMP
|
|
|
+-NetworkActivityMonitor::Notify(nsITimer* aTimer)
|
|
|
++IOActivityMonitor::Notify(nsITimer* aTimer)
|
|
|
+ {
|
|
|
+ mozilla::MutexAutoLock lock(mLock);
|
|
|
+- 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);
|
|
|
++ nsCOMPtr<nsIRunnable> ev = NotifyIOActivity::Create(mActivities, lock);
|
|
|
++ nsresult rv = SystemGroup::EventTargetFor(TaskCategory::Performance)->Dispatch(ev.forget());
|
|
|
++ if (NS_FAILED(rv)) {
|
|
|
++ NS_WARNING("NS_DispatchToMainThread failed");
|
|
|
++ return rv;
|
|
|
++ }
|
|
|
++ // Reset the counters, remove inactive activities
|
|
|
++ for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
|
|
|
++ IOActivity* activity = iter.Data();
|
|
|
++ if (activity->Inactive()) {
|
|
|
++ iter.Remove();
|
|
|
++ } else {
|
|
|
++ activity->Reset();
|
|
|
++ }
|
|
|
+ }
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
++// static
|
|
|
+ NS_IMETHODIMP
|
|
|
+-NetworkActivityMonitor::GetName(nsACString& aName)
|
|
|
++IOActivityMonitor::GetName(nsACString& aName)
|
|
|
+ {
|
|
|
+- aName.AssignLiteral("NetworkActivityMonitor");
|
|
|
++ aName.AssignLiteral("IOActivityMonitor");
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
++bool
|
|
|
++IOActivityMonitor::IsActive()
|
|
|
++{
|
|
|
++ return gInstance != nullptr;
|
|
|
++}
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::Init(int32_t aInterval)
|
|
|
++IOActivityMonitor::Init(int32_t aInterval)
|
|
|
+ {
|
|
|
+- nsresult rv = NS_OK;
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- if (mon) {
|
|
|
++ if (IsActive()) {
|
|
|
+ return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
+ }
|
|
|
+- mon = new NetworkActivityMonitor();
|
|
|
+- rv = mon->Init_Internal(aInterval);
|
|
|
++ RefPtr<IOActivityMonitor> mon = new IOActivityMonitor();
|
|
|
++ nsresult rv = mon->Init_Internal(aInterval);
|
|
|
+ if (NS_SUCCEEDED(rv)) {
|
|
|
+ gInstance = mon;
|
|
|
+- } else {
|
|
|
+- rv = NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::Shutdown()
|
|
|
++IOActivityMonitor::Init_Internal(int32_t aInterval)
|
|
|
+ {
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- if (!mon) {
|
|
|
+- return NS_ERROR_NOT_INITIALIZED;
|
|
|
+- }
|
|
|
+- mon->Shutdown_Internal();
|
|
|
+- gInstance = nullptr;
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+-NetworkActivityMonitor::Init_Internal(int32_t aInterval)
|
|
|
+-{
|
|
|
++ // wraps the socket APIs
|
|
|
+ if (!sNetActivityMonitorLayerMethodsPtr) {
|
|
|
+ sNetActivityMonitorLayerIdentity =
|
|
|
+ PR_GetUniqueIdentity("network activity monitor layer");
|
|
|
+ sNetActivityMonitorLayerMethods = *PR_GetDefaultIOMethods();
|
|
|
+ sNetActivityMonitorLayerMethods.connect = nsNetMon_Connect;
|
|
|
+ sNetActivityMonitorLayerMethods.read = nsNetMon_Read;
|
|
|
+ sNetActivityMonitorLayerMethods.write = nsNetMon_Write;
|
|
|
+ sNetActivityMonitorLayerMethods.writev = nsNetMon_Writev;
|
|
|
+@@ -381,133 +456,168 @@ NetworkActivityMonitor::Init_Internal(in
|
|
|
+ mTimer = NS_NewTimer();
|
|
|
+ if (!mTimer) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+ return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::Shutdown_Internal()
|
|
|
++IOActivityMonitor::Shutdown()
|
|
|
+ {
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!mon) {
|
|
|
++ return NS_ERROR_NOT_INITIALIZED;
|
|
|
++ }
|
|
|
++ return mon->Shutdown_Internal();
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
++IOActivityMonitor::Shutdown_Internal()
|
|
|
++{
|
|
|
++ mozilla::MutexAutoLock lock(mLock);
|
|
|
+ mTimer->Cancel();
|
|
|
++ mActivities.Clear();
|
|
|
++ gInstance = nullptr;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
|
|
++IOActivityMonitor::MonitorSocket(PRFileDesc *aFd)
|
|
|
+ {
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- if (!mon) {
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!IsActive()) {
|
|
|
++ return NS_OK;
|
|
|
++ }
|
|
|
++ PRFileDesc* layer;
|
|
|
++ PRStatus status;
|
|
|
++ layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
|
|
++ sNetActivityMonitorLayerMethodsPtr);
|
|
|
++ if (!layer) {
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++
|
|
|
++ ActivityMonitorSecret* secret = new ActivityMonitorSecret(aFd);
|
|
|
++ layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
|
|
|
++ status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
|
|
|
++
|
|
|
++ if (status == PR_FAILURE) {
|
|
|
++ delete secret;
|
|
|
++ PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++ return NS_OK;
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
++IOActivityMonitor::MonitorFile(PRFileDesc *aFd, const char* aPath)
|
|
|
++{
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!IsActive()) {
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+ PRFileDesc* layer;
|
|
|
+ PRStatus status;
|
|
|
+ layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
|
|
+ sNetActivityMonitorLayerMethodsPtr);
|
|
|
+ if (!layer) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+- status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
|
|
|
++ ActivityMonitorSecret* secret = new ActivityMonitorSecret(aFd, aPath);
|
|
|
++ layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
|
|
|
+
|
|
|
++ status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
|
|
|
+ if (status == PR_FAILURE) {
|
|
|
++ delete secret;
|
|
|
+ PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
++
|
|
|
++ return NS_OK;
|
|
|
++}
|
|
|
++
|
|
|
++IOActivity*
|
|
|
++IOActivityMonitor::GetActivity(const nsACString& aLocation)
|
|
|
++{
|
|
|
++ mLock.AssertCurrentThreadOwns();
|
|
|
++ if (auto entry = mActivities.Lookup(aLocation)) {
|
|
|
++ // already registered
|
|
|
++ return entry.Data();
|
|
|
++ }
|
|
|
++ // Creating a new IOActivity. Notice that mActivities will
|
|
|
++ // grow indefinitely, which is OK since we won't have
|
|
|
++ // but a few hundreds entries at the most, but we
|
|
|
++ // want to assert we have at the most 1000 entries
|
|
|
++ MOZ_ASSERT(mActivities.Count() < MAX_ACTIVITY_ENTRIES);
|
|
|
++
|
|
|
++ // Entries are removed in the timer when they are inactive.
|
|
|
++ IOActivity* activity = new IOActivity(aLocation);
|
|
|
++ if (NS_WARN_IF(!mActivities.Put(aLocation, activity, fallible))) {
|
|
|
++ delete activity;
|
|
|
++ return nullptr;
|
|
|
++ }
|
|
|
++ return activity;
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
++IOActivityMonitor::Write(const nsACString& aLocation, uint32_t aAmount)
|
|
|
++{
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!mon) {
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++ return mon->Write_Internal(aLocation, aAmount);
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
++IOActivityMonitor::Write(PRFileDesc *fd, uint32_t aAmount)
|
|
|
++{
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!mon) {
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++ return mon->Write(FileDesc2Location(fd), aAmount);
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
++IOActivityMonitor::Write_Internal(const nsACString& aLocation, uint32_t aAmount)
|
|
|
++{
|
|
|
++ mozilla::MutexAutoLock lock(mLock);
|
|
|
++ IOActivity* activity = GetActivity(aLocation);
|
|
|
++ if (!activity) {
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++ activity->tx += aAmount;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr) {
|
|
|
+- MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
++IOActivityMonitor::Read(PRFileDesc *fd, uint32_t aAmount)
|
|
|
++{
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
+ if (!mon) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+-
|
|
|
+- 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");
|
|
|
+- }
|
|
|
+- return mon->RegisterFd_Internal(osfd, NS_ConvertUTF8toUTF16(host), port);
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+-NetworkActivityMonitor::UnregisterFd(PRFileDesc *aFd)
|
|
|
+-{
|
|
|
+- MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- if (!mon) {
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+- }
|
|
|
+- PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
|
|
+- if (NS_WARN_IF(osfd == -1)) {
|
|
|
+- return ErrorAccordingToNSPR(PR_GetError());
|
|
|
+- }
|
|
|
+- return mon->UnregisterFd_Internal(osfd);
|
|
|
++ return mon->Read(FileDesc2Location(fd), aAmount);
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::UnregisterFd_Internal(PROsfd aOsfd)
|
|
|
++IOActivityMonitor::Read(const nsACString& aLocation, uint32_t aAmount)
|
|
|
+ {
|
|
|
+- mozilla::MutexAutoLock lock(mLock);
|
|
|
+- // XXX indefinitely growing list
|
|
|
+- mActivity.active.Put(aOsfd, false);
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+-NetworkActivityMonitor::RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port)
|
|
|
+-{
|
|
|
+- mozilla::MutexAutoLock lock(mLock);
|
|
|
+- 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;
|
|
|
++ RefPtr<IOActivityMonitor> mon(gInstance);
|
|
|
++ if (!mon) {
|
|
|
++ return NS_ERROR_FAILURE;
|
|
|
++ }
|
|
|
++ return mon->Read_Internal(aLocation, aAmount);
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-NetworkActivityMonitor::DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount)
|
|
|
++IOActivityMonitor::Read_Internal(const nsACString& aLocation, uint32_t aAmount)
|
|
|
+ {
|
|
|
+- MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
|
+- RefPtr<NetworkActivityMonitor> mon(gInstance);
|
|
|
+- if (!mon) {
|
|
|
++ mozilla::MutexAutoLock lock(mLock);
|
|
|
++ IOActivity* activity = GetActivity(aLocation);
|
|
|
++ if (!activity) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+- PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
|
|
+- if (NS_WARN_IF(osfd == -1)) {
|
|
|
+- return ErrorAccordingToNSPR(PR_GetError());
|
|
|
+- }
|
|
|
+- return mon->DataInOut_Internal(osfd, aDirection, aAmount);
|
|
|
+-}
|
|
|
+-
|
|
|
+-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);
|
|
|
+- }
|
|
|
++ activity->rx += aAmount;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+diff --git a/netwerk/base/NetworkActivityMonitor.h b/netwerk/base/IOActivityMonitor.h
|
|
|
+rename from netwerk/base/NetworkActivityMonitor.h
|
|
|
+rename to netwerk/base/IOActivityMonitor.h
|
|
|
+--- a/netwerk/base/NetworkActivityMonitor.h
|
|
|
++++ b/netwerk/base/IOActivityMonitor.h
|
|
|
+@@ -1,96 +1,122 @@
|
|
|
+ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
+ *
|
|
|
+ * 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/. */
|
|
|
+
|
|
|
+-#ifndef NetworkActivityMonitor_h___
|
|
|
+-#define NetworkActivityMonitor_h___
|
|
|
++#ifndef IOActivityMonitor_h___
|
|
|
++#define IOActivityMonitor_h___
|
|
|
+
|
|
|
+ #include "nsCOMPtr.h"
|
|
|
+ #include "nscore.h"
|
|
|
++#include "nsClassHashtable.h"
|
|
|
+ #include "nsDataHashtable.h"
|
|
|
+ #include "nsHashKeys.h"
|
|
|
+-#include "nsINetworkActivityData.h"
|
|
|
++#include "nsIIOActivityData.h"
|
|
|
+ #include "nsISupports.h"
|
|
|
+ #include "nsITimer.h"
|
|
|
+ #include "prinrval.h"
|
|
|
+ #include "prio.h"
|
|
|
+ #include "private/pprio.h"
|
|
|
+ #include <stdint.h>
|
|
|
+
|
|
|
+ namespace mozilla { namespace net {
|
|
|
+
|
|
|
+-typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketBytes;
|
|
|
+-typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketPort;
|
|
|
+-typedef nsDataHashtable<nsUint32HashKey, nsString> SocketHost;
|
|
|
+-typedef nsDataHashtable<nsUint32HashKey, bool> SocketActive;
|
|
|
++//
|
|
|
++// IOActivity keeps track of the amount of data
|
|
|
++// sent and received for an FD / Location
|
|
|
++//
|
|
|
++struct IOActivity {
|
|
|
++ // the resource location, can be:
|
|
|
++ // - socket://ip:port
|
|
|
++ // - file://absolute/path
|
|
|
++ nsCString location;
|
|
|
+
|
|
|
++ // bytes received/read (rx) and sent/written (tx)
|
|
|
++ uint32_t rx;
|
|
|
++ uint32_t tx;
|
|
|
+
|
|
|
+-struct NetworkActivity {
|
|
|
+- SocketPort port;
|
|
|
+- SocketHost host;
|
|
|
+- SocketBytes rx;
|
|
|
+- SocketBytes tx;
|
|
|
+- SocketActive active;
|
|
|
++ explicit IOActivity(const nsACString& aLocation) {
|
|
|
++ location.Assign(aLocation);
|
|
|
++ rx = 0;
|
|
|
++ tx = 0;
|
|
|
++ }
|
|
|
++
|
|
|
++ // Returns true if no data was transferred
|
|
|
++ bool Inactive() {
|
|
|
++ return rx == 0 && tx == 0;
|
|
|
++ }
|
|
|
++
|
|
|
++ // Sets the data to zero
|
|
|
++ void Reset() {
|
|
|
++ rx = 0;
|
|
|
++ tx = 0;
|
|
|
++ }
|
|
|
+ };
|
|
|
+
|
|
|
++typedef nsClassHashtable<nsCStringHashKey, IOActivity> Activities;
|
|
|
+
|
|
|
+-class NetworkData final : public nsINetworkActivityData
|
|
|
++// XPCOM Wrapper for an IOActivity
|
|
|
++class IOActivityData final : public nsIIOActivityData
|
|
|
+ {
|
|
|
+ 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) {}
|
|
|
++ NS_DECL_NSIIOACTIVITYDATA
|
|
|
++ explicit IOActivityData(IOActivity aActivity)
|
|
|
++ : mActivity(aActivity) {}
|
|
|
+ private:
|
|
|
+- ~NetworkData() = default;
|
|
|
+-
|
|
|
+- nsString mHost;
|
|
|
+- int32_t mPort;
|
|
|
+- int32_t mFd;
|
|
|
+- int32_t mRx;
|
|
|
+- int32_t mTx;
|
|
|
++ ~IOActivityData() = default;
|
|
|
++ IOActivity mActivity;
|
|
|
+ };
|
|
|
+
|
|
|
+-
|
|
|
+-class NetworkActivityMonitor final
|
|
|
++// IOActivityMonitor has several roles:
|
|
|
++// - maintains an IOActivity per resource and updates it
|
|
|
++// - sends a dump of the activities to observers that wants
|
|
|
++// to get that info, via a timer
|
|
|
++class IOActivityMonitor final
|
|
|
+ : public nsITimerCallback
|
|
|
+ , public nsINamed
|
|
|
+ {
|
|
|
+ public:
|
|
|
+- enum Direction {
|
|
|
+- kUpload = 0,
|
|
|
+- kDownload = 1
|
|
|
+- };
|
|
|
+-
|
|
|
+- NetworkActivityMonitor();
|
|
|
++ IOActivityMonitor();
|
|
|
+
|
|
|
+ NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
+ NS_DECL_NSITIMERCALLBACK
|
|
|
+ NS_DECL_NSINAMED
|
|
|
+
|
|
|
++ // initializes and destroys the singleton
|
|
|
+ static nsresult Init(int32_t aInterval);
|
|
|
+ static nsresult Shutdown();
|
|
|
+- static nsresult AttachIOLayer(PRFileDesc *fd);
|
|
|
+- static nsresult DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount);
|
|
|
+- static nsresult RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr);
|
|
|
+- static nsresult UnregisterFd(PRFileDesc *aFd);
|
|
|
++
|
|
|
++ // collect amounts of data that are written/read by location
|
|
|
++ static nsresult Read(const nsACString& location, uint32_t aAmount);
|
|
|
++ static nsresult Write(const nsACString& location, uint32_t aAmount);
|
|
|
++
|
|
|
++ static nsresult MonitorFile(PRFileDesc *aFd, const char* aPath);
|
|
|
++ static nsresult MonitorSocket(PRFileDesc *aFd);
|
|
|
++ static nsresult Read(PRFileDesc *fd, uint32_t aAmount);
|
|
|
++ static nsresult Write(PRFileDesc *fd, uint32_t aAmount);
|
|
|
++
|
|
|
++ static bool IsActive();
|
|
|
+ private:
|
|
|
+- virtual ~NetworkActivityMonitor() = default;
|
|
|
++ virtual ~IOActivityMonitor() = default;
|
|
|
+ nsresult Init_Internal(int32_t aInterval);
|
|
|
+ nsresult Shutdown_Internal();
|
|
|
+- nsresult RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port);
|
|
|
+- nsresult UnregisterFd_Internal(PROsfd aOsfd);
|
|
|
+- nsresult DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount);
|
|
|
+- uint32_t mInterval;
|
|
|
+- NetworkActivity mActivity;
|
|
|
+- nsCOMPtr<nsITimer> mTimer;
|
|
|
+- Mutex mLock;
|
|
|
++
|
|
|
++ IOActivity* GetActivity(const nsACString& location);
|
|
|
++ nsresult Write_Internal(const nsACString& location, uint32_t aAmount);
|
|
|
++ nsresult Read_Internal(const nsACString& location, uint32_t aAmount);
|
|
|
++
|
|
|
++ Activities mActivities;
|
|
|
++
|
|
|
++ // timer used to send notifications
|
|
|
++ uint32_t mInterval;
|
|
|
++ nsCOMPtr<nsITimer> mTimer;
|
|
|
++ // protects mActivities accesses
|
|
|
++ Mutex mLock;
|
|
|
+ };
|
|
|
+
|
|
|
+ } // namespace net
|
|
|
+ } // namespace mozilla
|
|
|
+
|
|
|
+-#endif /* NetworkActivityMonitor_h___ */
|
|
|
++#endif /* IOActivityMonitor_h___ */
|
|
|
+diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build
|
|
|
+--- a/netwerk/base/moz.build
|
|
|
++++ b/netwerk/base/moz.build
|
|
|
+@@ -47,28 +47,28 @@ XPIDL_SOURCES += [
|
|
|
+ 'nsIForcePendingChannel.idl',
|
|
|
+ 'nsIFormPOSTActionChannel.idl',
|
|
|
+ 'nsIHttpAuthenticatorCallback.idl',
|
|
|
+ 'nsIHttpPushListener.idl',
|
|
|
+ 'nsIIncrementalDownload.idl',
|
|
|
+ 'nsIIncrementalStreamLoader.idl',
|
|
|
+ 'nsIInputStreamChannel.idl',
|
|
|
+ 'nsIInputStreamPump.idl',
|
|
|
++ 'nsIIOActivityData.idl',
|
|
|
+ 'nsIIOService.idl',
|
|
|
+ 'nsIIOService2.idl',
|
|
|
+ 'nsILoadContextInfo.idl',
|
|
|
+ 'nsILoadGroup.idl',
|
|
|
+ 'nsILoadGroupChild.idl',
|
|
|
+ 'nsILoadInfo.idl',
|
|
|
+ 'nsIMIMEInputStream.idl',
|
|
|
+ 'nsIMultiPartChannel.idl',
|
|
|
+ 'nsINestedURI.idl',
|
|
|
+ 'nsINetAddr.idl',
|
|
|
+ 'nsINetUtil.idl',
|
|
|
+- 'nsINetworkActivityData.idl',
|
|
|
+ 'nsINetworkInfoService.idl',
|
|
|
+ 'nsINetworkInterceptController.idl',
|
|
|
+ 'nsINetworkLinkService.idl',
|
|
|
+ 'nsINetworkPredictor.idl',
|
|
|
+ 'nsINetworkPredictorVerifier.idl',
|
|
|
+ 'nsINetworkProperties.idl',
|
|
|
+ 'nsINullChannel.idl',
|
|
|
+ 'nsIParentChannel.idl',
|
|
|
+@@ -170,16 +170,17 @@ EXPORTS.mozilla += [
|
|
|
+ ]
|
|
|
+
|
|
|
+ EXPORTS.mozilla.net += [
|
|
|
+ 'CaptivePortalService.h',
|
|
|
+ 'ChannelDiverterChild.h',
|
|
|
+ 'ChannelDiverterParent.h',
|
|
|
+ 'Dashboard.h',
|
|
|
+ 'DashboardTypes.h',
|
|
|
++ 'IOActivityMonitor.h',
|
|
|
+ 'MemoryDownloader.h',
|
|
|
+ 'MozURL.h',
|
|
|
+ 'PartiallySeekableInputStream.h',
|
|
|
+ 'Predictor.h',
|
|
|
+ 'ReferrerPolicy.h',
|
|
|
+ 'SimpleChannelParent.h',
|
|
|
+ 'TCPFastOpen.h',
|
|
|
+ ]
|
|
|
+@@ -187,21 +188,21 @@ EXPORTS.mozilla.net += [
|
|
|
+ UNIFIED_SOURCES += [
|
|
|
+ 'ArrayBufferInputStream.cpp',
|
|
|
+ 'BackgroundFileSaver.cpp',
|
|
|
+ 'CaptivePortalService.cpp',
|
|
|
+ 'ChannelDiverterChild.cpp',
|
|
|
+ 'ChannelDiverterParent.cpp',
|
|
|
+ 'Dashboard.cpp',
|
|
|
+ 'EventTokenBucket.cpp',
|
|
|
++ 'IOActivityMonitor.cpp',
|
|
|
+ 'LoadContextInfo.cpp',
|
|
|
+ 'LoadInfo.cpp',
|
|
|
+ 'MemoryDownloader.cpp',
|
|
|
+ 'MozURL.cpp',
|
|
|
+- 'NetworkActivityMonitor.cpp',
|
|
|
+ 'nsAsyncRedirectVerifyHelper.cpp',
|
|
|
+ 'nsAsyncStreamCopier.cpp',
|
|
|
+ 'nsAuthInformationHolder.cpp',
|
|
|
+ 'nsBase64Encoder.cpp',
|
|
|
+ 'nsBaseChannel.cpp',
|
|
|
+ 'nsBaseContentStream.cpp',
|
|
|
+ 'nsBufferedStreams.cpp',
|
|
|
+ 'nsChannelClassifier.cpp',
|
|
|
+diff --git a/netwerk/base/nsFileStreams.cpp b/netwerk/base/nsFileStreams.cpp
|
|
|
+--- a/netwerk/base/nsFileStreams.cpp
|
|
|
++++ b/netwerk/base/nsFileStreams.cpp
|
|
|
+@@ -10,30 +10,36 @@
|
|
|
+ #elif defined(XP_WIN)
|
|
|
+ #include <windows.h>
|
|
|
+ #include "nsILocalFileWin.h"
|
|
|
+ #else
|
|
|
+ // XXX add necessary include file for ftruncate (or equivalent)
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #include "private/pprio.h"
|
|
|
++#include "prerror.h"
|
|
|
+
|
|
|
++#include "IOActivityMonitor.h"
|
|
|
+ #include "nsFileStreams.h"
|
|
|
+ #include "nsIFile.h"
|
|
|
+ #include "nsReadLine.h"
|
|
|
+ #include "nsIClassInfoImpl.h"
|
|
|
++#include "nsLiteralString.h"
|
|
|
++#include "nsSocketTransport2.h" // for ErrorAccordingToNSPR()
|
|
|
+ #include "mozilla/ipc/InputStreamUtils.h"
|
|
|
+ #include "mozilla/Unused.h"
|
|
|
+ #include "mozilla/FileUtils.h"
|
|
|
+ #include "nsNetCID.h"
|
|
|
+ #include "nsXULAppAPI.h"
|
|
|
+
|
|
|
+ typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
|
|
|
+
|
|
|
+ using namespace mozilla::ipc;
|
|
|
++using namespace mozilla::net;
|
|
|
++
|
|
|
+ using mozilla::DebugOnly;
|
|
|
+ using mozilla::Maybe;
|
|
|
+ using mozilla::Nothing;
|
|
|
+ using mozilla::Some;
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////
|
|
|
+ // nsFileStreamBase
|
|
|
+
|
|
|
+@@ -347,17 +353,32 @@ nsFileStreamBase::DoOpen()
|
|
|
+ } else
|
|
|
+ #endif // XP_WIN
|
|
|
+ {
|
|
|
+ rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags,
|
|
|
+ mOpenParams.perm,
|
|
|
+ &fd);
|
|
|
+ }
|
|
|
+
|
|
|
++ if (rv == NS_OK && IOActivityMonitor::IsActive()) {
|
|
|
++ auto nativePath = mOpenParams.localFile->NativePath();
|
|
|
++ if (!nativePath.IsEmpty()) {
|
|
|
++ // registering the file to the activity monitor
|
|
|
++ #ifdef XP_WIN
|
|
|
++ // 16 bits unicode
|
|
|
++ IOActivityMonitor::MonitorFile(fd, NS_ConvertUTF16toUTF8(nativePath.get()).get());
|
|
|
++ #else
|
|
|
++ // 8 bit unicode
|
|
|
++ IOActivityMonitor::MonitorFile(fd, nativePath.get());
|
|
|
++ #endif
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
+ CleanUpOpen();
|
|
|
++
|
|
|
+ if (NS_FAILED(rv)) {
|
|
|
+ mState = eError;
|
|
|
+ mErrorValue = rv;
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+
|
|
|
+ mFD = fd;
|
|
|
+ mState = eOpened;
|
|
|
+diff --git a/netwerk/base/nsINetworkActivityData.idl b/netwerk/base/nsIIOActivityData.idl
|
|
|
+rename from netwerk/base/nsINetworkActivityData.idl
|
|
|
+rename to netwerk/base/nsIIOActivityData.idl
|
|
|
+--- a/netwerk/base/nsINetworkActivityData.idl
|
|
|
++++ b/netwerk/base/nsIIOActivityData.idl
|
|
|
+@@ -5,17 +5,15 @@
|
|
|
+ #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
|
|
|
++interface nsIIOActivityData : nsISupports
|
|
|
+ {
|
|
|
+- readonly attribute DOMString host;
|
|
|
+- readonly attribute long port;
|
|
|
++ readonly attribute AUTF8String location;
|
|
|
+ readonly attribute long rx;
|
|
|
+ readonly attribute long tx;
|
|
|
+- readonly attribute long fd;
|
|
|
+ };
|
|
|
+
|
|
|
+diff --git a/netwerk/base/nsPISocketTransportService.idl b/netwerk/base/nsPISocketTransportService.idl
|
|
|
+--- a/netwerk/base/nsPISocketTransportService.idl
|
|
|
++++ b/netwerk/base/nsPISocketTransportService.idl
|
|
|
+@@ -44,18 +44,18 @@ interface nsPISocketTransportService : n
|
|
|
+ /**
|
|
|
+ * Controls the default retransmission count for keepalive probes.
|
|
|
+ */
|
|
|
+ readonly attribute long keepaliveProbeCount;
|
|
|
+ };
|
|
|
+
|
|
|
+ %{C++
|
|
|
+ /*
|
|
|
+- * Network activity: we send out this topic no more than every
|
|
|
++ * I/O activity: we send out this topic no more than every
|
|
|
+ * intervalMilliseconds (as set by the
|
|
|
+- * "network.activity.intervalMilliseconds" preference: if 0 no notifications
|
|
|
+- * are sent) if the network is currently active (i.e. we're sending/receiving
|
|
|
+- * data to/from the socket).
|
|
|
++ * "io.activity.intervalMilliseconds" preference: if 0 no notifications
|
|
|
++ * are sent) if the I/O is currently active (i.e. we're sending/receiving
|
|
|
++ * data to/from the socket or writing/reading to/from a file).
|
|
|
+ */
|
|
|
+-#define NS_NETWORK_ACTIVITY "network-activity"
|
|
|
++#define NS_IO_ACTIVITY "io-activity"
|
|
|
+
|
|
|
+
|
|
|
+ %}
|
|
|
+diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp
|
|
|
+--- a/netwerk/base/nsSocketTransport2.cpp
|
|
|
++++ b/netwerk/base/nsSocketTransport2.cpp
|
|
|
+@@ -14,17 +14,17 @@
|
|
|
+ #include "nsTransportUtils.h"
|
|
|
+ #include "nsProxyInfo.h"
|
|
|
+ #include "nsNetCID.h"
|
|
|
+ #include "nsNetUtil.h"
|
|
|
+ #include "nsAutoPtr.h"
|
|
|
+ #include "nsCOMPtr.h"
|
|
|
+ #include "plstr.h"
|
|
|
+ #include "prerr.h"
|
|
|
+-#include "NetworkActivityMonitor.h"
|
|
|
++#include "IOActivityMonitor.h"
|
|
|
+ #include "NSSErrorsService.h"
|
|
|
+ #include "mozilla/dom/ToJSValue.h"
|
|
|
+ #include "mozilla/net/NeckoChild.h"
|
|
|
+ #include "nsThreadUtils.h"
|
|
|
+ #include "nsISocketProviderService.h"
|
|
|
+ #include "nsISocketProvider.h"
|
|
|
+ #include "nsISSLSocketControl.h"
|
|
|
+ #include "nsIPipe.h"
|
|
|
+@@ -1361,18 +1361,18 @@ nsSocketTransport::InitiateSocket()
|
|
|
+ bool usingSSL;
|
|
|
+
|
|
|
+ rv = BuildSocket(fd, proxyTransparent, usingSSL);
|
|
|
+ if (NS_FAILED(rv)) {
|
|
|
+ SOCKET_LOG((" BuildSocket failed [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+
|
|
|
+- // Attach network activity monitor
|
|
|
+- NetworkActivityMonitor::AttachIOLayer(fd);
|
|
|
++ // create proxy via IOActivityMonitor
|
|
|
++ IOActivityMonitor::MonitorSocket(fd);
|
|
|
+
|
|
|
+ PRStatus status;
|
|
|
+
|
|
|
+ // Make the socket non-blocking...
|
|
|
+ PRSocketOptionData opt;
|
|
|
+ opt.option = PR_SockOpt_Nonblocking;
|
|
|
+ opt.value.non_blocking = true;
|
|
|
+ status = PR_SetSocketOption(fd, &opt);
|
|
|
+diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp
|
|
|
+--- a/netwerk/base/nsSocketTransportService2.cpp
|
|
|
++++ b/netwerk/base/nsSocketTransportService2.cpp
|
|
|
+@@ -1,16 +1,16 @@
|
|
|
+ // vim:set sw=4 sts=4 et cin:
|
|
|
+ /* 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 "nsSocketTransportService2.h"
|
|
|
+ #include "nsSocketTransport2.h"
|
|
|
+-#include "NetworkActivityMonitor.h"
|
|
|
++#include "IOActivityMonitor.h"
|
|
|
+ #include "mozilla/IntegerPrintfMacros.h"
|
|
|
+ #include "mozilla/Preferences.h"
|
|
|
+ #include "nsIOService.h"
|
|
|
+ #include "nsASocketHandler.h"
|
|
|
+ #include "nsError.h"
|
|
|
+ #include "prnetdb.h"
|
|
|
+ #include "prerror.h"
|
|
|
+ #include "nsIPrefService.h"
|
|
|
+@@ -43,17 +43,17 @@ static Atomic<PRThread*, Relaxed> gSocke
|
|
|
+
|
|
|
+ #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 1000U
|
|
|
+ #define SOCKET_LIMIT_MIN 50U
|
|
|
+-#define INTERVAL_PREF "network.activity.intervalMilliseconds"
|
|
|
++#define IO_ACTIVITY_INTERVAL_PREF "io.activity.intervalMilliseconds"
|
|
|
+ #define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
|
|
|
+ #define POLL_BUSY_WAIT_PERIOD "network.sts.poll_busy_wait_period"
|
|
|
+ #define POLL_BUSY_WAIT_PERIOD_TIMEOUT "network.sts.poll_busy_wait_period_timeout"
|
|
|
+ #define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
|
|
|
+ #define POLLABLE_EVENT_TIMEOUT "network.sts.pollable_event_timeout"
|
|
|
+
|
|
|
+ #define REPAIR_POLLABLE_EVENT_TIME 10
|
|
|
+
|
|
|
+@@ -709,17 +709,17 @@ nsSocketTransportService::ShutdownThread
|
|
|
+ obsSvc->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mAfterWakeUpTimer) {
|
|
|
+ mAfterWakeUpTimer->Cancel();
|
|
|
+ mAfterWakeUpTimer = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+- NetworkActivityMonitor::Shutdown();
|
|
|
++ IOActivityMonitor::Shutdown();
|
|
|
+
|
|
|
+ mInitialized = false;
|
|
|
+ mShuttingDown = false;
|
|
|
+
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ NS_IMETHODIMP
|
|
|
+@@ -1373,22 +1373,22 @@ nsSocketTransportService::Observe(nsISup
|
|
|
+ SOCKET_LOG(("nsSocketTransportService::Observe topic=%s", topic));
|
|
|
+
|
|
|
+ if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
|
|
+ UpdatePrefs();
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!strcmp(topic, "profile-initial-state")) {
|
|
|
+- int32_t interval = Preferences::GetInt(INTERVAL_PREF, 0);
|
|
|
++ int32_t interval = Preferences::GetInt(IO_ACTIVITY_INTERVAL_PREF, 0);
|
|
|
+ if (interval <= 0) {
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+- return net::NetworkActivityMonitor::Init(interval);
|
|
|
++ return net::IOActivityMonitor::Init(interval);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!strcmp(topic, "last-pb-context-exited")) {
|
|
|
+ nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(
|
|
|
+ "net::nsSocketTransportService::ClosePrivateConnections",
|
|
|
+ this,
|
|
|
+ &nsSocketTransportService::ClosePrivateConnections);
|
|
|
+ nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
|
|
|
+diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp
|
|
|
+--- a/netwerk/base/nsUDPSocket.cpp
|
|
|
++++ b/netwerk/base/nsUDPSocket.cpp
|
|
|
+@@ -15,17 +15,17 @@
|
|
|
+ #include "nsError.h"
|
|
|
+ #include "nsNetCID.h"
|
|
|
+ #include "nsNetUtil.h"
|
|
|
+ #include "nsIOService.h"
|
|
|
+ #include "prnetdb.h"
|
|
|
+ #include "prio.h"
|
|
|
+ #include "nsNetAddr.h"
|
|
|
+ #include "nsNetSegmentUtils.h"
|
|
|
+-#include "NetworkActivityMonitor.h"
|
|
|
++#include "IOActivityMonitor.h"
|
|
|
+ #include "nsServiceManagerUtils.h"
|
|
|
+ #include "nsStreamUtils.h"
|
|
|
+ #include "nsIPipe.h"
|
|
|
+ #include "prerror.h"
|
|
|
+ #include "nsThreadUtils.h"
|
|
|
+ #include "nsIDNSRecord.h"
|
|
|
+ #include "nsIDNSService.h"
|
|
|
+ #include "nsICancelable.h"
|
|
|
+@@ -676,18 +676,18 @@ nsUDPSocket::InitWithAddress(const NetAd
|
|
|
+ if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
|
|
|
+ {
|
|
|
+ NS_WARNING("cannot get socket name");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ PRNetAddrToNetAddr(&addr, &mAddr);
|
|
|
+
|
|
|
+- // create proxy via NetworkActivityMonitor
|
|
|
+- NetworkActivityMonitor::AttachIOLayer(mFD);
|
|
|
++ // create proxy via IOActivityMonitor
|
|
|
++ IOActivityMonitor::MonitorSocket(mFD);
|
|
|
+
|
|
|
+ // wait until AsyncListen is called before polling the socket for
|
|
|
+ // client connections.
|
|
|
+ return NS_OK;
|
|
|
+
|
|
|
+ fail:
|
|
|
+ Close();
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+diff --git a/netwerk/test/browser/browser.ini b/netwerk/test/browser/browser.ini
|
|
|
+--- a/netwerk/test/browser/browser.ini
|
|
|
++++ b/netwerk/test/browser/browser.ini
|
|
|
+@@ -5,9 +5,10 @@ support-files =
|
|
|
+ [browser_about_cache.js]
|
|
|
+ [browser_NetUtil.js]
|
|
|
+ [browser_child_resource.js]
|
|
|
+ skip-if = !crashreporter || (e10s && debug && os == "linux" && bits == 64) || debug # Bug 1370783
|
|
|
+ [browser_post_file.js]
|
|
|
+ [browser_nsIFormPOSTActionChannel.js]
|
|
|
+ skip-if = e10s # protocol handler and channel does not work in content process
|
|
|
+ [browser_resource_navigation.js]
|
|
|
++[browser_test_io_activity.js]
|
|
|
+ [browser_cookie_sync_across_tabs.js]
|
|
|
+diff --git a/netwerk/test/browser/browser_test_io_activity.js b/netwerk/test/browser/browser_test_io_activity.js
|
|
|
+new file mode 100644
|
|
|
+--- /dev/null
|
|
|
++++ b/netwerk/test/browser/browser_test_io_activity.js
|
|
|
+@@ -0,0 +1,53 @@
|
|
|
++/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
|
++/* vim: set ts=2 et sw=2 tw=80: */
|
|
|
++/* 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/. */
|
|
|
++
|
|
|
++const TEST_URL = "http://example.com/browser/dom/tests/browser/dummy.html";
|
|
|
++
|
|
|
++
|
|
|
++add_task(async function test() {
|
|
|
++
|
|
|
++ SpecialPowers.setIntPref('io.activity.intervalMilliseconds', 50);
|
|
|
++ waitForExplicitFinish();
|
|
|
++
|
|
|
++ // grab events..
|
|
|
++ let gotSocket = false;
|
|
|
++ let gotFile = false;
|
|
|
++ let gotSqlite = false;
|
|
|
++ let gotEmptyData = false;
|
|
|
++
|
|
|
++ let networkActivity = function(subject, topic, value) {
|
|
|
++ subject.QueryInterface(Ci.nsIMutableArray);
|
|
|
++ let enumerator = subject.enumerate();
|
|
|
++ while (enumerator.hasMoreElements()) {
|
|
|
++ let data = enumerator.getNext();
|
|
|
++ data = data.QueryInterface(Ci.nsIIOActivityData);
|
|
|
++ gotEmptyData = data.rx == 0 && data.tx == 0 && !gotEmptyData
|
|
|
++ gotSocket = data.location.startsWith("socket://127.0.0.1:") || gotSocket;
|
|
|
++ gotFile = data.location.endsWith(".js") || gotFile;
|
|
|
++ gotSqlite = data.location.endsWith("places.sqlite") || gotSqlite;
|
|
|
++ }
|
|
|
++ };
|
|
|
++
|
|
|
++ Services.obs.addObserver(networkActivity, "io-activity");
|
|
|
++
|
|
|
++ // why do I have to do this ??
|
|
|
++ Services.obs.notifyObservers(null, "profile-initial-state", null);
|
|
|
++
|
|
|
++ await BrowserTestUtils.withNewTab({ gBrowser, url: "http://example.com" },
|
|
|
++ async function(browser) {
|
|
|
++ // wait until we get the events back
|
|
|
++ await BrowserTestUtils.waitForCondition(() => {
|
|
|
++ return gotSocket && gotFile && gotSqlite && !gotEmptyData;
|
|
|
++ }, "wait for events to come in", 250, 5);
|
|
|
++
|
|
|
++ ok(gotSocket, "A socket was used");
|
|
|
++ ok(gotFile, "A file was used");
|
|
|
++ ok(gotSqlite, "A sqlite DB was used");
|
|
|
++ ok(!gotEmptyData, "Every I/O event had data");
|
|
|
++ });
|
|
|
++
|
|
|
++ SpecialPowers.clearUserPref('io.activity.intervalMilliseconds');
|
|
|
++});
|
|
|
+diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini
|
|
|
+--- a/netwerk/test/unit/xpcshell.ini
|
|
|
++++ b/netwerk/test/unit/xpcshell.ini
|
|
|
+@@ -16,17 +16,16 @@ support-files =
|
|
|
+ data/test_readline7.txt
|
|
|
+ data/test_readline8.txt
|
|
|
+ data/signed_win.exe
|
|
|
+ socks_client_subprocess.js
|
|
|
+ test_link.desktop
|
|
|
+ test_link.url
|
|
|
+ ../../dns/effective_tld_names.dat
|
|
|
+
|
|
|
+-[test_network_activity.js]
|
|
|
+ [test_nsIBufferedOutputStream_writeFrom_block.js]
|
|
|
+ [test_cache2-00-service-get.js]
|
|
|
+ [test_cache2-01-basic.js]
|
|
|
+ [test_cache2-01a-basic-readonly.js]
|
|
|
+ [test_cache2-01b-basic-datasize.js]
|
|
|
+ [test_cache2-01c-basic-hasmeta-only.js]
|
|
|
+ [test_cache2-01d-basic-not-wanted.js]
|
|
|
+ [test_cache2-01e-basic-bypass-if-busy.js]
|
|
|
+diff --git a/storage/TelemetryVFS.cpp b/storage/TelemetryVFS.cpp
|
|
|
+--- a/storage/TelemetryVFS.cpp
|
|
|
++++ b/storage/TelemetryVFS.cpp
|
|
|
+@@ -7,16 +7,17 @@
|
|
|
+ #include <string.h>
|
|
|
+ #include "mozilla/Telemetry.h"
|
|
|
+ #include "mozilla/Preferences.h"
|
|
|
+ #include "sqlite3.h"
|
|
|
+ #include "nsThreadUtils.h"
|
|
|
+ #include "mozilla/dom/quota/PersistenceType.h"
|
|
|
+ #include "mozilla/dom/quota/QuotaManager.h"
|
|
|
+ #include "mozilla/dom/quota/QuotaObject.h"
|
|
|
++#include "mozilla/net/IOActivityMonitor.h"
|
|
|
+ #include "mozilla/IOInterposer.h"
|
|
|
+
|
|
|
+ // The last VFS version for which this file has been updated.
|
|
|
+ #define LAST_KNOWN_VFS_VERSION 3
|
|
|
+
|
|
|
+ // The last io_methods version for which this file has been updated.
|
|
|
+ #define LAST_KNOWN_IOMETHODS_VERSION 3
|
|
|
+
|
|
|
+@@ -29,16 +30,17 @@
|
|
|
+ * locking is slower than POSIX locking, so we do not want to do it by default.
|
|
|
+ */
|
|
|
+ #define PREF_NFS_FILESYSTEM "storage.nfs_filesystem"
|
|
|
+
|
|
|
+ namespace {
|
|
|
+
|
|
|
+ using namespace mozilla;
|
|
|
+ using namespace mozilla::dom::quota;
|
|
|
++using namespace mozilla::net;
|
|
|
+
|
|
|
+ struct Histograms {
|
|
|
+ const char *name;
|
|
|
+ const Telemetry::HistogramID readB;
|
|
|
+ const Telemetry::HistogramID writeB;
|
|
|
+ const Telemetry::HistogramID readMS;
|
|
|
+ const Telemetry::HistogramID writeMS;
|
|
|
+ const Telemetry::HistogramID syncMS;
|
|
|
+@@ -145,16 +147,19 @@ struct telemetry_file {
|
|
|
+
|
|
|
+ // quota object for this file
|
|
|
+ RefPtr<QuotaObject> quotaObject;
|
|
|
+
|
|
|
+ // The chunk size for this file. See the documentation for
|
|
|
+ // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
|
|
|
+ int fileChunkSize;
|
|
|
+
|
|
|
++ // The filename
|
|
|
++ char* location;
|
|
|
++
|
|
|
+ // This contains the vfs that actually does work
|
|
|
+ sqlite3_file pReal[1];
|
|
|
+ };
|
|
|
+
|
|
|
+ const char*
|
|
|
+ DatabasePathFromWALPath(const char *zWALName)
|
|
|
+ {
|
|
|
+ /**
|
|
|
+@@ -353,16 +358,17 @@ xClose(sqlite3_file *pFile)
|
|
|
+ { // Scope for IOThreadAutoTimer
|
|
|
+ IOThreadAutoTimer ioTimer(IOInterposeObserver::OpClose);
|
|
|
+ rc = p->pReal->pMethods->xClose(p->pReal);
|
|
|
+ }
|
|
|
+ if( rc==SQLITE_OK ){
|
|
|
+ delete p->base.pMethods;
|
|
|
+ p->base.pMethods = nullptr;
|
|
|
+ p->quotaObject = nullptr;
|
|
|
++ delete[] p->location;
|
|
|
+ #ifdef DEBUG
|
|
|
+ p->fileChunkSize = 0;
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+@@ -370,16 +376,19 @@ xClose(sqlite3_file *pFile)
|
|
|
+ */
|
|
|
+ int
|
|
|
+ xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
|
|
|
+ {
|
|
|
+ telemetry_file *p = (telemetry_file *)pFile;
|
|
|
+ IOThreadAutoTimer ioTimer(p->histograms->readMS, IOInterposeObserver::OpRead);
|
|
|
+ int rc;
|
|
|
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
|
|
|
++ if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
|
|
|
++ IOActivityMonitor::Read(nsDependentCString(p->location), iAmt);
|
|
|
++ }
|
|
|
+ // sqlite likes to read from empty files, this is normal, ignore it.
|
|
|
+ if (rc != SQLITE_IOERR_SHORT_READ)
|
|
|
+ Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ ** Return the current file-size of a telemetry_file.
|
|
|
+@@ -405,16 +414,20 @@ xWrite(sqlite3_file *pFile, const void *
|
|
|
+ int rc;
|
|
|
+ if (p->quotaObject) {
|
|
|
+ MOZ_ASSERT(INT64_MAX - iOfst >= iAmt);
|
|
|
+ if (!p->quotaObject->MaybeUpdateSize(iOfst + iAmt, /* aTruncate */ false)) {
|
|
|
+ return SQLITE_FULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
|
|
|
++ if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
|
|
|
++ IOActivityMonitor::Write(nsDependentCString(p->location), iAmt);
|
|
|
++ }
|
|
|
++
|
|
|
+ Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0);
|
|
|
+ if (p->quotaObject && rc != SQLITE_OK) {
|
|
|
+ NS_WARNING("xWrite failed on a quota-controlled file, attempting to "
|
|
|
+ "update its current size...");
|
|
|
+ sqlite_int64 currentSize;
|
|
|
+ if (xFileSize(pFile, ¤tSize) == SQLITE_OK) {
|
|
|
+ p->quotaObject->MaybeUpdateSize(currentSize, /* aTruncate */ true);
|
|
|
+ }
|
|
|
+@@ -656,16 +669,26 @@ xOpen(sqlite3_vfs* vfs, const char *zNam
|
|
|
+ }
|
|
|
+ p->histograms = h;
|
|
|
+
|
|
|
+ MaybeEstablishQuotaControl(zName, p, flags);
|
|
|
+
|
|
|
+ rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
|
|
|
+ if( rc != SQLITE_OK )
|
|
|
+ return rc;
|
|
|
++
|
|
|
++ if (zName) {
|
|
|
++ p->location = new char[7 + strlen(zName) + 1];
|
|
|
++ strcpy(p->location, "file://");
|
|
|
++ strcpy(p->location + 7, zName);
|
|
|
++ } else {
|
|
|
++ p->location = new char[8];
|
|
|
++ strcpy(p->location, "file://");
|
|
|
++ }
|
|
|
++
|
|
|
+ if( p->pReal->pMethods ){
|
|
|
+ sqlite3_io_methods *pNew = new sqlite3_io_methods;
|
|
|
+ const sqlite3_io_methods *pSub = p->pReal->pMethods;
|
|
|
+ memset(pNew, 0, sizeof(*pNew));
|
|
|
+ // If the io_methods version is higher than the last known one, you should
|
|
|
+ // update this VFS adding appropriate IO methods for any methods added in
|
|
|
+ // the version change.
|
|
|
+ pNew->iVersion = pSub->iVersion;
|