From bd752af44315268b3318d671b555f1eb6bf71adc Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Mon, 10 Dec 2012 09:13:55 -0500 Subject: [PATCH] Bug 783205 - Networking Dashboard. r=mcmanus, r=jorendorff, sr=biesi --- media/mtransport/nr_socket_prsock.h | 2 + .../test/sockettransportservice_unittest.cpp | 3 + media/mtransport/transportlayerprsock.h | 3 + netwerk/base/public/Makefile.in | 2 + netwerk/base/public/nsASocketHandler.h | 7 + netwerk/base/public/nsIDashboard.idl | 40 ++ .../base/public/nsIDashboardEventNotifier.idl | 23 + netwerk/base/src/Dashboard.cpp | 415 ++++++++++++++++++ netwerk/base/src/Dashboard.h | 119 +++++ netwerk/base/src/DashboardTypes.h | 48 ++ netwerk/base/src/Makefile.in | 8 + netwerk/base/src/nsServerSocket.h | 2 + netwerk/base/src/nsSocketTransport2.h | 2 + .../base/src/nsSocketTransportService2.cpp | 39 ++ netwerk/base/src/nsSocketTransportService2.h | 7 + netwerk/build/nsNetCID.h | 13 + netwerk/build/nsNetModule.cpp | 10 + netwerk/dns/nsDNSService2.cpp | 8 + netwerk/dns/nsHostResolver.cpp | 53 +++ netwerk/dns/nsHostResolver.h | 7 + netwerk/dns/nsIDNSService.idl | 19 +- netwerk/protocol/http/HttpInfo.cpp | 15 + netwerk/protocol/http/HttpInfo.h | 22 + netwerk/protocol/http/Makefile.in | 2 + netwerk/protocol/http/nsHttpConnection.h | 1 + netwerk/protocol/http/nsHttpConnectionMgr.cpp | 34 ++ netwerk/protocol/http/nsHttpConnectionMgr.h | 7 + .../protocol/websocket/WebSocketChannel.cpp | 57 ++- netwerk/protocol/websocket/WebSocketChannel.h | 5 + 29 files changed, 971 insertions(+), 2 deletions(-) create mode 100644 netwerk/base/public/nsIDashboard.idl create mode 100644 netwerk/base/public/nsIDashboardEventNotifier.idl create mode 100644 netwerk/base/src/Dashboard.cpp create mode 100644 netwerk/base/src/Dashboard.h create mode 100644 netwerk/base/src/DashboardTypes.h create mode 100644 netwerk/protocol/http/HttpInfo.cpp create mode 100644 netwerk/protocol/http/HttpInfo.h diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h index 149725f0b18..e649d788d87 100644 --- a/media/mtransport/nr_socket_prsock.h +++ b/media/mtransport/nr_socket_prsock.h @@ -75,6 +75,8 @@ public: virtual void OnSocketReady(PRFileDesc *fd, int16_t outflags); virtual void OnSocketDetached(PRFileDesc *fd); virtual void IsLocal(bool *aIsLocal); + virtual uint64_t ByteCountSent() { return 0; } + virtual uint64_t ByteCountReceived() { return 0; } // nsISupports methods NS_DECL_ISUPPORTS diff --git a/media/mtransport/test/sockettransportservice_unittest.cpp b/media/mtransport/test/sockettransportservice_unittest.cpp index b1c19e292ac..9b612a6898c 100644 --- a/media/mtransport/test/sockettransportservice_unittest.cpp +++ b/media/mtransport/test/sockettransportservice_unittest.cpp @@ -129,6 +129,9 @@ class SocketHandler : public nsASocketHandler { *aIsLocal = false; } + virtual uint64_t ByteCountSent() { return 0; } + virtual uint64_t ByteCountReceived() { return 0; } + NS_DECL_ISUPPORTS private: diff --git a/media/mtransport/transportlayerprsock.h b/media/mtransport/transportlayerprsock.h index 2a1c25eec79..ac8eb20112a 100644 --- a/media/mtransport/transportlayerprsock.h +++ b/media/mtransport/transportlayerprsock.h @@ -82,6 +82,9 @@ class TransportLayerPrsock : public TransportLayer { *aIsLocal = false; } + virtual uint64_t ByteCountSent() { return 0; } + virtual uint64_t ByteCountReceived() { return 0; } + // nsISupports methods NS_DECL_ISUPPORTS diff --git a/netwerk/base/public/Makefile.in b/netwerk/base/public/Makefile.in index c82328101cc..342d5738252 100644 --- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -30,6 +30,8 @@ SDK_XPIDLSRCS = \ $(NULL) XPIDLSRCS = \ + nsIDashboard.idl \ + nsIDashboardEventNotifier.idl \ nsIApplicationCache.idl \ nsIApplicationCacheChannel.idl \ nsIApplicationCacheContainer.idl \ diff --git a/netwerk/base/public/nsASocketHandler.h b/netwerk/base/public/nsASocketHandler.h index 3e2efe95231..ff459bbb2de 100644 --- a/netwerk/base/public/nsASocketHandler.h +++ b/netwerk/base/public/nsASocketHandler.h @@ -67,6 +67,13 @@ public: // connections. // virtual void IsLocal(bool *aIsLocal) = 0; + + + // + // returns the number of bytes sent/transmitted over the socket + // + virtual uint64_t ByteCountSent() = 0; + virtual uint64_t ByteCountReceived() = 0; }; #endif // !nsASocketHandler_h__ diff --git a/netwerk/base/public/nsIDashboard.idl b/netwerk/base/public/nsIDashboard.idl new file mode 100644 index 00000000000..e04bc2a6e2a --- /dev/null +++ b/netwerk/base/public/nsIDashboard.idl @@ -0,0 +1,40 @@ +/* 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" +#include "nsIDashboardEventNotifier.idl" + +/* A JavaScript callback function that takes a JSON as its parameter. + * The returned JSON contains arrays with data + */ +[scriptable, function, uuid(19d7f24f-a95a-4fd9-87e2-d96e9e4b1f6d)] +interface NetDashboardCallback : nsISupports +{ + void onDashboardDataAvailable(in jsval data); +}; + +/* The dashboard service. + * The async API returns JSONs, which hold arrays with the required info. + * Only one request of each type may be pending at any time. + */ +[scriptable, uuid(c79eb3c6-091a-45a6-8544-5a8d1ab79537)] +interface nsIDashboard : nsISupports +{ + /* Arrays: host, port, tcp, active, socksent, sockreceived + * Values: sent, received */ + void requestSockets(in NetDashboardCallback cb); + + /* Arrays: host, port, spdy, ssl + * Array of arrays: active, idle */ + void requestHttpConnections(in NetDashboardCallback cb); + + /* Arrays: hostport, encrypted, msgsent, msgreceived, sentsize, receivedsize */ + void requestWebsocketConnections(in NetDashboardCallback cb); + + /* Arrays: hostname, family, hostaddr, expiration */ + void requestDNSInfo(in NetDashboardCallback cb); + + /* When true, the service will log websocket events */ + attribute boolean enableLogging; +}; diff --git a/netwerk/base/public/nsIDashboardEventNotifier.idl b/netwerk/base/public/nsIDashboardEventNotifier.idl new file mode 100644 index 00000000000..d84fd2ed4f7 --- /dev/null +++ b/netwerk/base/public/nsIDashboardEventNotifier.idl @@ -0,0 +1,23 @@ +/* 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" + +[builtinclass, uuid(24fdfcbe-54cb-4997-8392-3c476126ea3b)] +interface nsIDashboardEventNotifier : nsISupports +{ + /* These methods are called to register a websocket event with the dashboard + * + * A host is identified by the (aHost, aSerial) pair. + * aHost: the host's name: example.com + * aSerial: a number that uniquely identifies the websocket + * + * aEncrypted: if the connection is encrypted + * aLength: the length of the message in bytes + */ + void addHost(in ACString aHost, in unsigned long aSerial, in boolean aEncrypted); + void removeHost(in ACString aHost, in unsigned long aSerial); + void newMsgSent(in ACString aHost, in unsigned long aSerial, in unsigned long aLength); + void newMsgReceived(in ACString aHost, in unsigned long aSerial, in unsigned long aLength); +}; diff --git a/netwerk/base/src/Dashboard.cpp b/netwerk/base/src/Dashboard.cpp new file mode 100644 index 00000000000..b272e8ee197 --- /dev/null +++ b/netwerk/base/src/Dashboard.cpp @@ -0,0 +1,415 @@ +/* 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 "nsContentUtils.h" +#include "mozilla/net/Dashboard.h" +#include "mozilla/net/HttpInfo.h" + +namespace mozilla { +namespace net { + +NS_IMPL_THREADSAFE_ISUPPORTS2(Dashboard, nsIDashboard, nsIDashboardEventNotifier) + +#define CREATE_ARRAY_OBJECT(object) \ +JSObject* object = JS_NewArrayObject(cx, 0, nullptr); \ +if (!object) \ + return NS_ERROR_OUT_OF_MEMORY ; \ + +#define SET_ELEMENT(object, func, param, index) \ +if (!JS_DefineElement(cx, object, index, func(param), \ + nullptr, nullptr, JSPROP_ENUMERATE)) \ + return NS_ERROR_OUT_OF_MEMORY; \ + +#define SET_PROPERTY(finalObject, object, property) \ +val = OBJECT_TO_JSVAL(object); \ +if (!JS_DefineProperty(cx, finalObject, #property, \ + val, nullptr, nullptr, JSPROP_ENUMERATE)) \ + return NS_ERROR_OUT_OF_MEMORY; \ + +Dashboard::Dashboard() +{ + mEnableLogging = false; +} + +Dashboard::~Dashboard() +{ +} + +NS_IMETHODIMP +Dashboard::RequestSockets(NetDashboardCallback* cb) +{ + if (mSock.cb) + return NS_ERROR_FAILURE; + mSock.cb = cb; + mSock.data.Clear(); + mSock.thread = NS_GetCurrentThread(); + + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetSocketsDispatch); + gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + return NS_OK; +} + +void +Dashboard::GetSocketsDispatch() +{ + if (gSocketTransportService) + gSocketTransportService->GetSocketConnections(&mSock.data); + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetSockets); + mSock.thread->Dispatch(event, NS_DISPATCH_NORMAL); +} + +nsresult +Dashboard::GetSockets() +{ + jsval val; + JSContext* cx = nsContentUtils::GetSafeJSContext(); + JSAutoRequest request(cx); + + JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr); + if (!finalObject) + return NS_ERROR_OUT_OF_MEMORY; + + CREATE_ARRAY_OBJECT(hostJs); + CREATE_ARRAY_OBJECT(portJs); + CREATE_ARRAY_OBJECT(activeJs); + CREATE_ARRAY_OBJECT(sentJs); + CREATE_ARRAY_OBJECT(receivedJs); + CREATE_ARRAY_OBJECT(tcpJs); + CREATE_ARRAY_OBJECT(sockSentJs); + CREATE_ARRAY_OBJECT(sockRecJs); + mSock.totalSent = 0; + mSock.totalRecv = 0; + + for (uint32_t i = 0; i < mSock.data.Length(); i++) { + JSString* hostString = JS_NewStringCopyZ(cx, mSock.data[i].host.get()); + SET_ELEMENT(hostJs, STRING_TO_JSVAL, hostString, i); + SET_ELEMENT(portJs, INT_TO_JSVAL, mSock.data[i].port, i); + SET_ELEMENT(activeJs, BOOLEAN_TO_JSVAL, mSock.data[i].active, i); + SET_ELEMENT(tcpJs, INT_TO_JSVAL, mSock.data[i].tcp, i); + SET_ELEMENT(sockSentJs, DOUBLE_TO_JSVAL, (double) mSock.data[i].sent, i); + SET_ELEMENT(sockRecJs, DOUBLE_TO_JSVAL, (double) mSock.data[i].received, i); + mSock.totalSent += mSock.data[i].sent; + mSock.totalRecv += mSock.data[i].received; + } + + SET_ELEMENT(sentJs, DOUBLE_TO_JSVAL, (double) mSock.totalSent, 0); + SET_ELEMENT(receivedJs, DOUBLE_TO_JSVAL, (double) mSock.totalRecv, 0); + + SET_PROPERTY(finalObject, hostJs, host); + SET_PROPERTY(finalObject, portJs, port); + SET_PROPERTY(finalObject, activeJs, active); + SET_PROPERTY(finalObject, tcpJs, tcp); + SET_PROPERTY(finalObject, sockSentJs, socksent); + SET_PROPERTY(finalObject, sockRecJs, sockreceived); + SET_PROPERTY(finalObject, sentJs, sent); + SET_PROPERTY(finalObject, receivedJs, received); + + val = OBJECT_TO_JSVAL(finalObject); + mSock.cb->OnDashboardDataAvailable(val); + mSock.cb = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP +Dashboard::RequestHttpConnections(NetDashboardCallback* cb) +{ + if (mHttp.cb) + return NS_ERROR_FAILURE; + mHttp.cb = cb; + mHttp.data.Clear(); + mHttp.thread = NS_GetCurrentThread(); + + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetHttpDispatch); + gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + return NS_OK; +} + +void +Dashboard::GetHttpDispatch() +{ + HttpInfo::GetHttpConnectionData(&mHttp.data); + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetHttpConnections); + mHttp.thread->Dispatch(event, NS_DISPATCH_NORMAL); +} + + +nsresult +Dashboard::GetHttpConnections() +{ + jsval val; + JSContext* cx = nsContentUtils::GetSafeJSContext(); + JSAutoRequest request(cx); + + JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr); + if (!finalObject) + return NS_ERROR_OUT_OF_MEMORY; + + CREATE_ARRAY_OBJECT(hostJs); + CREATE_ARRAY_OBJECT(portJs); + CREATE_ARRAY_OBJECT(activeJs); + CREATE_ARRAY_OBJECT(idleJs); + CREATE_ARRAY_OBJECT(spdyJs); + CREATE_ARRAY_OBJECT(sslJs); + + for (uint32_t i = 0; i < mHttp.data.Length(); i++) { + JSString* hostString = JS_NewStringCopyZ(cx, mHttp.data[i].host.get()); + SET_ELEMENT(hostJs, STRING_TO_JSVAL, hostString, i); + SET_ELEMENT(portJs, INT_TO_JSVAL, mHttp.data[i].port, i); + + JSObject* rtt_Active = JS_NewArrayObject(cx, 0, nullptr); + JSObject* timeToLive_Active = JS_NewArrayObject(cx, 0, nullptr); + for (uint32_t j = 0; j < mHttp.data[i].active.Length(); j++) { + SET_ELEMENT(rtt_Active, INT_TO_JSVAL, mHttp.data[i].active[j].rtt, j); + SET_ELEMENT(timeToLive_Active, INT_TO_JSVAL, mHttp.data[i].active[j].ttl, j); + } + JSObject* active = JS_NewObject(cx, nullptr, nullptr, nullptr); + SET_PROPERTY(active, rtt_Active, rtt); + SET_PROPERTY(active, timeToLive_Active, ttl); + SET_ELEMENT(activeJs, OBJECT_TO_JSVAL, active, i); + + JSObject* rtt_Idle = JS_NewArrayObject(cx, 0, nullptr); + JSObject* timeToLive_Idle = JS_NewArrayObject(cx, 0, nullptr); + for (uint32_t j = 0; j < mHttp.data[i].idle.Length(); j++) { + SET_ELEMENT(rtt_Idle, INT_TO_JSVAL, mHttp.data[i].idle[j].rtt, j); + SET_ELEMENT(timeToLive_Idle, INT_TO_JSVAL, mHttp.data[i].idle[j].ttl, j); + } + JSObject* idle = JS_NewObject(cx, nullptr, nullptr, nullptr); + SET_PROPERTY(idle, rtt_Idle, rtt); + SET_PROPERTY(idle, timeToLive_Idle, ttl); + SET_ELEMENT(idleJs, OBJECT_TO_JSVAL, idle, i); + + SET_ELEMENT(spdyJs, BOOLEAN_TO_JSVAL, mHttp.data[i].spdy, i); + SET_ELEMENT(sslJs, BOOLEAN_TO_JSVAL, mHttp.data[i].ssl, i); + } + + SET_PROPERTY(finalObject, hostJs, host); + SET_PROPERTY(finalObject, portJs, port); + SET_PROPERTY(finalObject, activeJs, active); + SET_PROPERTY(finalObject, idleJs, idle); + SET_PROPERTY(finalObject, spdyJs, spdy); + SET_PROPERTY(finalObject, sslJs, ssl); + + val = OBJECT_TO_JSVAL(finalObject); + mHttp.cb->OnDashboardDataAvailable(val); + mHttp.cb = nullptr; + + return NS_OK; +} + + +NS_IMETHODIMP +Dashboard::GetEnableLogging(bool* value) +{ + *value = mEnableLogging; + return NS_OK; +} + +NS_IMETHODIMP +Dashboard::SetEnableLogging(const bool value) +{ + mEnableLogging = value; + return NS_OK; +} + +NS_IMETHODIMP +Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted) +{ + if (mEnableLogging) { + mozilla::MutexAutoLock lock(mWs.lock); + LogData data(nsCString(aHost), aSerial, aEncrypted); + if (mWs.data.Contains(data)) + return NS_OK; + if (!mWs.data.AppendElement(data)) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial) +{ + if (mEnableLogging) { + mozilla::MutexAutoLock lock(mWs.lock); + int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); + if (index == -1) + return NS_ERROR_FAILURE; + mWs.data.RemoveElementAt(index); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, uint32_t aLength) +{ + if (mEnableLogging) { + mozilla::MutexAutoLock lock(mWs.lock); + int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); + if (index == -1) + return NS_ERROR_FAILURE; + mWs.data[index].mMsgSent++; + mWs.data[index].mSizeSent += aLength; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, uint32_t aLength) +{ + if (mEnableLogging) { + mozilla::MutexAutoLock lock(mWs.lock); + int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); + if (index == -1) + return NS_ERROR_FAILURE; + mWs.data[index].mMsgReceived++; + mWs.data[index].mSizeReceived += aLength; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +Dashboard::RequestWebsocketConnections(NetDashboardCallback* cb) +{ + if (mWs.cb) + return NS_ERROR_FAILURE; + mWs.cb = cb; + mWs.thread = NS_GetCurrentThread(); + + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetWebSocketConnections); + mWs.thread->Dispatch(event, NS_DISPATCH_NORMAL); + return NS_OK; +} + +nsresult +Dashboard::GetWebSocketConnections() +{ + jsval val; + JSString* jsstring; + JSContext* cx = nsContentUtils::GetSafeJSContext(); + JSAutoRequest request(cx); + + JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr); + if (!finalObject) + return NS_ERROR_OUT_OF_MEMORY; + + CREATE_ARRAY_OBJECT(hostJs); + CREATE_ARRAY_OBJECT(msgSentJs); + CREATE_ARRAY_OBJECT(msgRecvJs); + CREATE_ARRAY_OBJECT(sizeSentJs); + CREATE_ARRAY_OBJECT(sizeRecvJs); + CREATE_ARRAY_OBJECT(encryptJs); + + mozilla::MutexAutoLock lock(mWs.lock); + for (uint32_t i = 0; i < mWs.data.Length(); i++) { + jsstring = JS_NewStringCopyN(cx, mWs.data[i].mHost.get(), mWs.data[i].mHost.Length()); + SET_ELEMENT(hostJs, STRING_TO_JSVAL, jsstring, i); + SET_ELEMENT(msgSentJs, INT_TO_JSVAL, mWs.data[i].mMsgSent, i); + SET_ELEMENT(msgRecvJs, INT_TO_JSVAL, mWs.data[i].mMsgReceived, i); + SET_ELEMENT(sizeSentJs, DOUBLE_TO_JSVAL, (double) mWs.data[i].mSizeSent, i); + SET_ELEMENT(sizeRecvJs, DOUBLE_TO_JSVAL, (double) mWs.data[i].mSizeReceived, i); + SET_ELEMENT(encryptJs, BOOLEAN_TO_JSVAL, mWs.data[i].mEncrypted, i); + } + + SET_PROPERTY(finalObject, hostJs, hostport); + SET_PROPERTY(finalObject, msgSentJs, msgsent); + SET_PROPERTY(finalObject, msgRecvJs, msgreceived); + SET_PROPERTY(finalObject, sizeSentJs, sentsize); + SET_PROPERTY(finalObject, sizeRecvJs, receivedsize); + SET_PROPERTY(finalObject, encryptJs, encrypted); + + val = OBJECT_TO_JSVAL(finalObject); + mWs.cb->OnDashboardDataAvailable(val); + mWs.cb = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP +Dashboard::RequestDNSInfo(NetDashboardCallback* cb) +{ + if (mDns.cb) + return NS_ERROR_FAILURE; + mDns.cb = cb; + nsresult rv; + mDns.data.Clear(); + mDns.thread = NS_GetCurrentThread(); + + if (!mDns.serv) { + mDns.serv = do_GetService("@mozilla.org/network/dns-service;1", &rv); + if (NS_FAILED(rv)) + return rv; + } + + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetDnsInfoDispatch); + gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + return NS_OK; +} + +void +Dashboard::GetDnsInfoDispatch() +{ + if (mDns.serv) + mDns.serv->GetDNSCacheEntries(&mDns.data); + nsCOMPtr event = NS_NewRunnableMethod(this, &Dashboard::GetDNSCacheEntries); + mDns.thread->Dispatch(event, NS_DISPATCH_NORMAL); +} + +nsresult +Dashboard::GetDNSCacheEntries() +{ + jsval val; + JSContext* cx = nsContentUtils::GetSafeJSContext(); + JSAutoRequest request(cx); + + JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr); + if (!finalObject) + return NS_ERROR_OUT_OF_MEMORY; + + CREATE_ARRAY_OBJECT(nameJs); + CREATE_ARRAY_OBJECT(addrJs); + CREATE_ARRAY_OBJECT(familyJs); + CREATE_ARRAY_OBJECT(expiresJs); + + for (uint32_t i = 0; i < mDns.data.Length(); i++) { + JSString* hostnameString = JS_NewStringCopyZ(cx, mDns.data[i].hostname.get()); + SET_ELEMENT(nameJs, STRING_TO_JSVAL, hostnameString, i); + + JSObject* addrObject = JS_NewObject(cx, nullptr, nullptr, nullptr); + if (!addrObject) + return NS_ERROR_OUT_OF_MEMORY; + + for (uint32_t j = 0; j < mDns.data[i].hostaddr.Length(); j++) { + JSString* addrString = JS_NewStringCopyZ(cx, mDns.data[i].hostaddr[j].get()); + SET_ELEMENT(addrObject, STRING_TO_JSVAL, addrString, j); + } + + SET_ELEMENT(addrJs, OBJECT_TO_JSVAL, addrObject, i); + + JSString* familyString; + if (mDns.data[i].family == PR_AF_INET6) + familyString = JS_NewStringCopyZ(cx, "ipv6"); + else + familyString = JS_NewStringCopyZ(cx, "ipv4"); + + SET_ELEMENT(familyJs, STRING_TO_JSVAL, familyString, i); + SET_ELEMENT(expiresJs, DOUBLE_TO_JSVAL, (double) mDns.data[i].expiration, i); + } + + SET_PROPERTY(finalObject, nameJs, hostname); + SET_PROPERTY(finalObject, addrJs, hostaddr); + SET_PROPERTY(finalObject, familyJs, family); + SET_PROPERTY(finalObject, expiresJs, expiration); + + val = OBJECT_TO_JSVAL(finalObject); + mDns.cb->OnDashboardDataAvailable(val); + mDns.cb = nullptr; + + return NS_OK; +} + +} } // namespace mozilla::net diff --git a/netwerk/base/src/Dashboard.h b/netwerk/base/src/Dashboard.h new file mode 100644 index 00000000000..d02b63419aa --- /dev/null +++ b/netwerk/base/src/Dashboard.h @@ -0,0 +1,119 @@ +/* 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 nsDashboard_h__ +#define nsDashboard_h__ + +#include "nsIDashboard.h" +#include "nsIDashboardEventNotifier.h" +#include "nsTArray.h" +#include "nsString.h" +#include "jsapi.h" +#include "nsIDNSService.h" +#include "nsIServiceManager.h" +#include "nsIThread.h" +#include "nsSocketTransport2.h" +#include "mozilla/net/DashboardTypes.h" + +namespace mozilla { +namespace net { + +class Dashboard: + public nsIDashboard, + public nsIDashboardEventNotifier +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDASHBOARD + NS_DECL_NSIDASHBOARDEVENTNOTIFIER + + Dashboard(); +private: + virtual ~Dashboard(); + + void GetSocketsDispatch(); + void GetHttpDispatch(); + void GetDnsInfoDispatch(); + + /* Helper methods that pass the JSON to the callback function. */ + nsresult GetSockets(); + nsresult GetHttpConnections(); + nsresult GetWebSocketConnections(); + nsresult GetDNSCacheEntries(); + +private: + struct SocketData + { + uint64_t totalSent; + uint64_t totalRecv; + nsTArray data; + nsCOMPtr cb; + nsIThread* thread; + }; + + struct HttpData { + nsTArray data; + nsCOMPtr cb; + nsIThread* thread; + }; + + struct LogData + { + LogData(nsCString host, uint32_t serial, bool encryption): + mHost(host), + mSerial(serial), + mMsgSent(0), + mMsgReceived(0), + mSizeSent(0), + mSizeReceived(0), + mEncrypted(encryption) + { } + nsCString mHost; + uint32_t mSerial; + uint32_t mMsgSent; + uint32_t mMsgReceived; + uint64_t mSizeSent; + uint64_t mSizeReceived; + bool mEncrypted; + bool operator==(const LogData& a) const + { + return mHost.Equals(a.mHost) && (mSerial == a.mSerial); + } + }; + + struct WebSocketData + { + WebSocketData():lock("Dashboard.webSocketData") + { + } + uint32_t IndexOf(nsCString hostname, uint32_t mSerial) + { + LogData temp(hostname, mSerial, false); + return data.IndexOf(temp); + } + nsTArray data; + mozilla::Mutex lock; + nsCOMPtr cb; + nsIThread* thread; + }; + + struct DnsData + { + nsCOMPtr serv; + nsTArray data; + nsCOMPtr cb; + nsIThread* thread; + }; + + bool mEnableLogging; + + struct SocketData mSock; + struct HttpData mHttp; + struct WebSocketData mWs; + struct DnsData mDns; + +}; + +} } // namespace mozilla::net +#endif // nsDashboard_h__ diff --git a/netwerk/base/src/DashboardTypes.h b/netwerk/base/src/DashboardTypes.h new file mode 100644 index 00000000000..5d534943926 --- /dev/null +++ b/netwerk/base/src/DashboardTypes.h @@ -0,0 +1,48 @@ +/* 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 nsDashboardTypes__ +#define nsDashboardTypes__ + +namespace mozilla { +namespace net { + +struct SocketInfo +{ + nsCString host; + uint64_t sent; + uint64_t received; + uint16_t port; + bool active; + bool tcp; +}; + +struct DNSCacheEntries +{ + nsCString hostname; + nsTArray hostaddr; + int8_t family; + int64_t expiration; +}; + +struct HttpConnInfo +{ + uint32_t ttl; + uint32_t rtt; +}; + +struct HttpRetParams +{ + nsCString host; + nsTArray active; + nsTArray idle; + uint32_t counter; + uint16_t port; + bool spdy; + bool ssl; +}; + +} } + +#endif // nsDashboardTypes__ diff --git a/netwerk/base/src/Makefile.in b/netwerk/base/src/Makefile.in index 7ebd512c282..b7ed7f14d93 100644 --- a/netwerk/base/src/Makefile.in +++ b/netwerk/base/src/Makefile.in @@ -21,6 +21,13 @@ EXPORTS = \ nsURLHelper.h \ $(NULL) +EXPORTS_NAMESPACES = mozilla/net + +EXPORTS_mozilla/net = \ + Dashboard.h \ + DashboardTypes.h \ + $(NULL) + CPPSRCS = \ nsTransportUtils.cpp \ nsAsyncStreamCopier.cpp \ @@ -67,6 +74,7 @@ CPPSRCS = \ nsPreloadedStream.cpp \ nsStreamListenerWrapper.cpp \ ProxyAutoConfig.cpp \ + Dashboard.cpp \ NetworkActivityMonitor.cpp \ $(NULL) diff --git a/netwerk/base/src/nsServerSocket.h b/netwerk/base/src/nsServerSocket.h index 54ef304ac6e..4018f135004 100644 --- a/netwerk/base/src/nsServerSocket.h +++ b/netwerk/base/src/nsServerSocket.h @@ -24,6 +24,8 @@ public: virtual void OnSocketDetached(PRFileDesc *fd); virtual void IsLocal(bool *aIsLocal); + virtual uint64_t ByteCountSent() { return 0; } + virtual uint64_t ByteCountReceived() { return 0; } nsServerSocket(); // This must be public to support older compilers (xlC_r on AIX) diff --git a/netwerk/base/src/nsSocketTransport2.h b/netwerk/base/src/nsSocketTransport2.h index c1c6c19471e..15126b9ea02 100644 --- a/netwerk/base/src/nsSocketTransport2.h +++ b/netwerk/base/src/nsSocketTransport2.h @@ -131,6 +131,8 @@ public: // called when a socket event is handled void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param); + uint64_t ByteCountReceived() { return mInput.ByteCount(); } + uint64_t ByteCountSent() { return mOutput.ByteCount(); } protected: virtual ~nsSocketTransport(); diff --git a/netwerk/base/src/nsSocketTransportService2.cpp b/netwerk/base/src/nsSocketTransportService2.cpp index 9807a150ccd..3bfb5f497c9 100644 --- a/netwerk/base/src/nsSocketTransportService2.cpp +++ b/netwerk/base/src/nsSocketTransportService2.cpp @@ -34,6 +34,7 @@ void StopSSLServerCertVerificationThreads(); } } // namespace mozilla::psm using namespace mozilla; +using namespace mozilla::net; #if defined(PR_LOGGING) PRLogModuleInfo *gSocketTransportLog = nullptr; @@ -1014,3 +1015,41 @@ nsSocketTransportService::DiscoverMaxCount() return PR_SUCCESS; } + +void +nsSocketTransportService::AnalyzeConnection(nsTArray *data, + struct SocketContext *context, bool aActive) +{ + PRFileDesc *aFD = context->mFD; + bool tcp = (PR_GetDescType(aFD) == PR_DESC_SOCKET_TCP); + + PRNetAddr peer_addr; + PR_GetPeerName(aFD, &peer_addr); + + char host[64] = {0}; + PR_NetAddrToString(&peer_addr, host, sizeof(host)); + + uint16_t port; + if (peer_addr.raw.family == PR_AF_INET) + port = peer_addr.inet.port; + else + port = peer_addr.ipv6.port; + port = PR_ntohs(port); + uint64_t sent = context->mHandler->ByteCountSent(); + uint64_t received = context->mHandler->ByteCountReceived(); + SocketInfo info = { nsCString(host), sent, received, port, aActive, tcp }; + + data->AppendElement(info); +} + +void +nsSocketTransportService::GetSocketConnections(nsTArray *data) +{ + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); + for (uint32_t i = 0; i < mActiveCount; i++) + AnalyzeConnection(data, &mActiveList[i], true); + for (uint32_t i = 0; i < mIdleCount; i++) + AnalyzeConnection(data, &mIdleList[i], false); +} + + diff --git a/netwerk/base/src/nsSocketTransportService2.h b/netwerk/base/src/nsSocketTransportService2.h index 7fdec908169..7e2045b4947 100644 --- a/netwerk/base/src/nsSocketTransportService2.h +++ b/netwerk/base/src/nsSocketTransportService2.h @@ -19,6 +19,7 @@ #include "nsASocketHandler.h" #include "nsIObserver.h" #include "mozilla/Mutex.h" +#include "mozilla/net/DashboardTypes.h" //----------------------------------------------------------------------------- @@ -73,6 +74,9 @@ public: return mActiveCount + mIdleCount < gMaxCount; } + // Called by the networking dashboard + // Fills the passed array with socket information + void GetSocketConnections(nsTArray *); protected: virtual ~nsSocketTransportService(); @@ -183,6 +187,9 @@ private: void ProbeMaxCount(); #endif bool mProbedMaxCount; + + void AnalyzeConnection(nsTArray *data, + SocketContext *context, bool aActive); }; extern nsSocketTransportService *gSocketTransportService; diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index 633c0368356..a5bf8ce47e6 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -867,6 +867,19 @@ NS_NETWORK_SOCKET_CONTRACTID_PREFIX "starttls" +#define NS_DASHBOARD_CLASSNAME \ + "Dashboard" +#define NS_DASHBOARD_CONTRACTID \ + "@mozilla.org/network/dashboard;1" +#define NS_DASHBOARD_CID \ +{ /*c79eb3c6-091a-45a6-8544-5a8d1ab79537 */ \ + 0xc79eb3c6, \ + 0x091a, \ + 0x45a6, \ + { 0x85, 0x44, 0x5a, 0x8d, 0x1a, 0xb7, 0x95, 0x37 } \ +} + + /****************************************************************************** * netwerk/cookie classes */ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 08714d8af58..832ee6994ce 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -232,6 +232,13 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpBasicAuth) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpDigestAuth) #endif // !NECKO_PROTOCOL_http +#include "mozilla/net/Dashboard.h" +namespace mozilla { +namespace net { + NS_GENERIC_FACTORY_CONSTRUCTOR(Dashboard) +} +} + #ifdef NECKO_PROTOCOL_res // resource #include "nsResProtocolHandler.h" @@ -694,6 +701,7 @@ NS_DEFINE_NAMED_CID(NS_BUFFEREDOUTPUTSTREAM_CID); NS_DEFINE_NAMED_CID(NS_MIMEINPUTSTREAM_CID); NS_DEFINE_NAMED_CID(NS_PROTOCOLPROXYSERVICE_CID); NS_DEFINE_NAMED_CID(NS_STREAMCONVERTERSERVICE_CID); +NS_DEFINE_NAMED_CID(NS_DASHBOARD_CID); #ifdef BUILD_APPLEFILE_DECODER NS_DEFINE_NAMED_CID(NS_APPLEFILEDECODER_CID); #endif @@ -826,6 +834,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_MIMEINPUTSTREAM_CID, false, NULL, nsMIMEInputStreamConstructor }, { &kNS_PROTOCOLPROXYSERVICE_CID, true, NULL, nsProtocolProxyServiceConstructor }, { &kNS_STREAMCONVERTERSERVICE_CID, false, NULL, CreateNewStreamConvServiceFactory }, + { &kNS_DASHBOARD_CID, false, NULL, mozilla::net::DashboardConstructor }, #ifdef BUILD_APPLEFILE_DECODER { &kNS_APPLEFILEDECODER_CID, false, NULL, nsAppleFileDecoderConstructor }, #endif @@ -962,6 +971,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_MIMEINPUTSTREAM_CONTRACTID, &kNS_MIMEINPUTSTREAM_CID }, { NS_PROTOCOLPROXYSERVICE_CONTRACTID, &kNS_PROTOCOLPROXYSERVICE_CID }, { NS_STREAMCONVERTERSERVICE_CONTRACTID, &kNS_STREAMCONVERTERSERVICE_CID }, + { NS_DASHBOARD_CONTRACTID, &kNS_DASHBOARD_CID }, #ifdef BUILD_APPLEFILE_DECODER { NS_IAPPLEFILEDECODER_CONTRACTID, &kNS_APPLEFILEDECODER_CID }, #endif diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index e87094db13d..7af99e987b4 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -853,3 +853,11 @@ nsDNSService::GetAFForLookup(const nsACString &host, uint32_t flags) return af; } + +NS_IMETHODIMP +nsDNSService::GetDNSCacheEntries(nsTArray *args) +{ + NS_ENSURE_TRUE(mResolver, NS_ERROR_NOT_INITIALIZED); + mResolver->GetDNSCacheEntries(args); + return NS_OK; +} diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index f925067abbc..c0f76536d46 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -38,6 +38,7 @@ #include "mozilla/Telemetry.h" using namespace mozilla; +using namespace mozilla::net; //---------------------------------------------------------------------------- @@ -1026,3 +1027,55 @@ nsHostResolver::Create(uint32_t maxCacheEntries, *result = res; return rv; } + +PLDHashOperator +CacheEntryEnumerator(PLDHashTable *table, PLDHashEntryHdr *entry, + uint32_t number, void *arg) +{ + nsHostDBEnt *ent = static_cast (entry); + nsTArray *args = + static_cast *> (arg); + nsHostRecord *rec = ent->rec; + // Without addr_info, there is no meaning of adding this entry + if (rec->addr_info) { + DNSCacheEntries info; + const char *hostname; + PRNetAddr addr; + + if (rec->host) + hostname = rec->host; + else // No need to add this entry if no host name is there + return PL_DHASH_NEXT; + + uint32_t now = NowInMinutes(); + info.expiration = ((int64_t) rec->expiration - now) * 60; + + // We only need valid DNS cache entries + if (info.expiration <= 0) + return PL_DHASH_NEXT; + + info.family = rec->af; + info.hostname = hostname; + + { + MutexAutoLock lock(rec->addr_info_lock); + void *ptr = PR_EnumerateAddrInfo(nullptr, rec->addr_info, 0, &addr); + while (ptr) { + char buf[64]; + if (PR_NetAddrToString(&addr, buf, sizeof(buf)) == PR_SUCCESS) + info.hostaddr.AppendElement(buf); + ptr = PR_EnumerateAddrInfo(ptr, rec->addr_info, 0, &addr); + } + } + + args->AppendElement(info); + } + + return PL_DHASH_NEXT; +} + +void +nsHostResolver::GetDNSCacheEntries(nsTArray *args) +{ + PL_DHashTableEnumerate(&mDB, CacheEntryEnumerator, args); +} diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 7a592f075cf..6de07d6f755 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -17,6 +17,7 @@ #include "nsIDNSListener.h" #include "nsString.h" #include "nsTArray.h" +#include "mozilla/net/DashboardTypes.h" class nsHostResolver; class nsHostRecord; @@ -275,6 +276,12 @@ private: bool mShutdown; PRIntervalTime mLongIdleTimeout; PRIntervalTime mShortIdleTimeout; + +public: + /* + * Called by the networking dashboard via the DnsService2 + */ + void GetDNSCacheEntries(nsTArray *); }; #endif // nsHostResolver_h__ diff --git a/netwerk/dns/nsIDNSService.idl b/netwerk/dns/nsIDNSService.idl index c24afb9a075..c3ebd2ee23e 100644 --- a/netwerk/dns/nsIDNSService.idl +++ b/netwerk/dns/nsIDNSService.idl @@ -9,10 +9,20 @@ interface nsIEventTarget; interface nsIDNSRecord; interface nsIDNSListener; +%{C++ +#include "nsTArray.h" + +namespace mozilla { namespace net { + struct DNSCacheEntries; +} } +%} + +[ptr] native EntriesArray(nsTArray); + /** * nsIDNSService */ -[scriptable, uuid(F6E05CC3-8A13-463D-877F-D59B20B59724)] +[scriptable, uuid(f1971942-19db-44bf-81e8-d15df220a39f)] interface nsIDNSService : nsISupports { /** @@ -73,6 +83,13 @@ interface nsIDNSService : nsISupports nsIDNSRecord resolve(in AUTF8String aHostName, in unsigned long aFlags); + /** + * The method takes a pointer to an nsTArray + * and fills it with cache entry data + * Called by the networking dashboard + */ + [noscript] void getDNSCacheEntries(in EntriesArray args); + /** * @return the hostname of the operating system. */ diff --git a/netwerk/protocol/http/HttpInfo.cpp b/netwerk/protocol/http/HttpInfo.cpp new file mode 100644 index 00000000000..a26132d5544 --- /dev/null +++ b/netwerk/protocol/http/HttpInfo.cpp @@ -0,0 +1,15 @@ +/* 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 "nsHttpHandler.h" +#include "HttpInfo.h" + + +void +mozilla::net::HttpInfo:: +GetHttpConnectionData(nsTArray* args) +{ + if (gHttpHandler) + gHttpHandler->ConnMgr()->GetConnectionData(args); +} diff --git a/netwerk/protocol/http/HttpInfo.h b/netwerk/protocol/http/HttpInfo.h new file mode 100644 index 00000000000..dfbdae80247 --- /dev/null +++ b/netwerk/protocol/http/HttpInfo.h @@ -0,0 +1,22 @@ +/* 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 "mozilla/net/DashboardTypes.h" + +#ifndef nsHttpInfo__ +#define nsHttpInfo__ + +namespace mozilla { +namespace net { + +class HttpInfo +{ +public: + /* Calls getConnectionData method in nsHttpConnectionMgr. */ + static void GetHttpConnectionData(nsTArray *); +}; + +} } // namespace mozilla::net + +#endif // nsHttpInfo__ diff --git a/netwerk/protocol/http/Makefile.in b/netwerk/protocol/http/Makefile.in index cb8b0103e98..3820134d429 100644 --- a/netwerk/protocol/http/Makefile.in +++ b/netwerk/protocol/http/Makefile.in @@ -45,6 +45,7 @@ EXPORTS_mozilla/net += \ HttpChannelParent.h \ HttpChannelChild.h \ PHttpChannelParams.h \ + HttpInfo.h \ $(NULL) EXPORTS = \ @@ -78,6 +79,7 @@ CPPSRCS = \ HttpChannelParent.cpp \ HttpChannelChild.cpp \ HttpChannelParentListener.cpp \ + HttpInfo.cpp \ NullHttpTransaction.cpp \ ASpdySession.cpp \ SpdySession2.cpp \ diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index f644e1d2dd0..f35304a9367 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -131,6 +131,7 @@ public: bool UsingSpdy() { return !!mUsingSpdyVersion; } bool EverUsedSpdy() { return mEverUsedSpdy; } + PRIntervalTime Rtt() { return mRtt; } // true when connection SSL NPN phase is complete and we know // authoritatively whether UsingSpdy() or not. diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 68401cb830c..db0d609ddeb 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -3187,6 +3187,40 @@ nsConnectionEntry::MaxPipelineDepth(nsAHttpTransaction::Classifier aClass) return mGreenDepth; } +PLDHashOperator +nsHttpConnectionMgr::ReadConnectionEntry(const nsACString &key, + nsAutoPtr &ent, + void *aArg) +{ + nsTArray *args = static_cast *> (aArg); + HttpRetParams data; + data.host = ent->mConnInfo->Host(); + data.port = ent->mConnInfo->Port(); + for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) { + HttpConnInfo info; + info.ttl = ent->mActiveConns[i]->TimeToLive(); + info.rtt = ent->mActiveConns[i]->Rtt(); + data.active.AppendElement(info); + } + for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) { + HttpConnInfo info; + info.ttl = ent->mIdleConns[i]->TimeToLive(); + info.rtt = ent->mIdleConns[i]->Rtt(); + data.active.AppendElement(info); + } + data.spdy = ent->mUsingSpdy; + data.ssl = ent->mConnInfo->UsingSSL(); + args->AppendElement(data); + return PL_DHASH_NEXT; +} + +bool +nsHttpConnectionMgr::GetConnectionData(nsTArray *aArg) +{ + mCT.Enumerate(ReadConnectionEntry, aArg); + return true; +} + uint32_t nsHttpConnectionMgr::nsConnectionEntry::UnconnectedHalfOpens() { diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h index acb18928e29..a27b9598959 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.h +++ b/netwerk/protocol/http/nsHttpConnectionMgr.h @@ -19,6 +19,7 @@ #include "nsISocketTransportService.h" #include "mozilla/TimeStamp.h" #include "mozilla/Attributes.h" +#include "mozilla/net/DashboardTypes.h" #include "nsIObserver.h" #include "nsITimer.h" @@ -223,6 +224,7 @@ public: bool SupportsPipelining(nsHttpConnectionInfo *); + bool GetConnectionData(nsTArray *); private: virtual ~nsHttpConnectionMgr(); @@ -611,6 +613,11 @@ private: nsTHashtable mAlternateProtocolHash; static PLDHashOperator TrimAlternateProtocolHash(nsCStringHashKey *entry, void *closure); + + static PLDHashOperator ReadConnectionEntry(const nsACString &key, + nsAutoPtr &ent, + void *aArg); + // Read Timeout Tick handlers void ActivateTimeoutTick(); void TimeoutTick(); diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index b49fd6c2b56..224f59aea84 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -912,6 +912,8 @@ private: // WebSocketChannel //----------------------------------------------------------------------------- +uint32_t WebSocketChannel::sSerialSeed = 0; + WebSocketChannel::WebSocketChannel() : mPort(0), mCloseTimeout(20000), @@ -949,7 +951,8 @@ WebSocketChannel::WebSocketChannel() : mCurrentOutSent(0), mCompressor(nullptr), mDynamicOutputSize(0), - mDynamicOutput(nullptr) + mDynamicOutput(nullptr), + mConnectionLogService(nullptr) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); @@ -959,6 +962,13 @@ WebSocketChannel::WebSocketChannel() : sWebSocketAdmissions = new nsWSAdmissionManager(); mFramePtr = mBuffer = static_cast(moz_xmalloc(mBufferSize)); + + nsresult rv; + mConnectionLogService = do_GetService("@mozilla.org/network/dashboard;1",&rv); + if (NS_FAILED(rv)) + LOG(("Failed to initiate dashboard service.")); + + mSerial = sSerialSeed++; } WebSocketChannel::~WebSocketChannel() @@ -1320,6 +1330,15 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count) } NS_DispatchToMainThread(new CallOnMessageAvailable(this, utf8Data, -1)); + nsresult rv; + if (mConnectionLogService) { + nsAutoCString host; + rv = mURI->GetHostPort(host); + if (NS_SUCCEEDED(rv)) { + mConnectionLogService->NewMsgReceived(host, mSerial, count); + LOG(("Added new msg received for %s",host.get())); + } + } } } else if (opcode & kControlFrameMask) { // control frames @@ -1401,6 +1420,16 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count) nsCString binaryData((const char *)payload, payloadLength); NS_DispatchToMainThread(new CallOnMessageAvailable(this, binaryData, payloadLength)); + // To add the header to 'Networking Dashboard' log + nsresult rv; + if (mConnectionLogService) { + nsAutoCString host; + rv = mURI->GetHostPort(host); + if (NS_SUCCEEDED(rv)) { + mConnectionLogService->NewMsgReceived(host, mSerial, count); + LOG(("Added new received msg for %s",host.get())); + } + } } } else if (opcode != kContinuation) { /* unknown opcode */ @@ -1814,6 +1843,14 @@ WebSocketChannel::CleanupConnection() mTransport = nullptr; } + nsresult rv; + if (mConnectionLogService) { + nsAutoCString host; + rv = mURI->GetHostPort(host); + if (NS_SUCCEEDED(rv)) + mConnectionLogService->RemoveHost(host, mSerial); + } + DecrementSessionCount(); } @@ -2638,6 +2675,14 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI, if (NS_FAILED(rv)) return rv; + if (mConnectionLogService) { + nsAutoCString host; + rv = mURI->GetHostPort(host); + if (NS_SUCCEEDED(rv)) { + mConnectionLogService->AddHost(host, mSerial, BaseWebSocketChannel::mEncrypted); + } + } + rv = ApplyForAdmission(); if (NS_FAILED(rv)) return rv; @@ -2734,6 +2779,16 @@ WebSocketChannel::SendMsgCommon(const nsACString *aMsg, bool aIsBinary, return NS_ERROR_FILE_TOO_BIG; } + nsresult rv; + if (mConnectionLogService) { + nsAutoCString host; + rv = mURI->GetHostPort(host); + if (NS_SUCCEEDED(rv)) { + mConnectionLogService->NewMsgSent(host, mSerial, aLength); + LOG(("Added new msg sent for %s",host.get())); + } + } + return mSocketThread->Dispatch( aStream ? new OutboundEnqueuer(this, new OutboundMessage(aStream, aLength)) : new OutboundEnqueuer(this, diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index d53cb5ac300..45366273584 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -26,6 +26,7 @@ #include "nsIHttpChannelInternal.h" #include "nsIRandomGenerator.h" #include "BaseWebSocketChannel.h" +#include "nsIDashboardEventNotifier.h" #include "nsCOMPtr.h" #include "nsString.h" @@ -242,6 +243,10 @@ private: nsWSCompression *mCompressor; uint32_t mDynamicOutputSize; uint8_t *mDynamicOutput; + + nsCOMPtr mConnectionLogService; + uint32_t mSerial; + static uint32_t sSerialSeed; }; class WebSocketSSLChannel : public WebSocketChannel