Bug 783205 - Networking Dashboard. r=mcmanus, r=jorendorff, sr=biesi
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 10 Dec 2012 09:13:55 -0500
changeset 115522 45907821616d
parent 115521 c2b28290a53c
child 115523 ded1b2e2d6be
push id24015
push useremorley@mozilla.com
push dateTue, 11 Dec 2012 15:51:15 +0000
treeherdermozilla-central@87f8165c5a0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, jorendorff, biesi
bugs783205
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 783205 - Networking Dashboard. r=mcmanus, r=jorendorff, sr=biesi
media/mtransport/nr_socket_prsock.h
media/mtransport/test/sockettransportservice_unittest.cpp
media/mtransport/transportlayerprsock.h
netwerk/base/public/Makefile.in
netwerk/base/public/nsASocketHandler.h
netwerk/base/public/nsIDashboard.idl
netwerk/base/public/nsIDashboardEventNotifier.idl
netwerk/base/src/Dashboard.cpp
netwerk/base/src/Dashboard.h
netwerk/base/src/DashboardTypes.h
netwerk/base/src/Makefile.in
netwerk/base/src/nsServerSocket.h
netwerk/base/src/nsSocketTransport2.h
netwerk/base/src/nsSocketTransportService2.cpp
netwerk/base/src/nsSocketTransportService2.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/dns/nsHostResolver.h
netwerk/dns/nsIDNSService.idl
netwerk/protocol/http/HttpInfo.cpp
netwerk/protocol/http/HttpInfo.h
netwerk/protocol/http/Makefile.in
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -70,16 +70,18 @@ public:
   virtual ~NrSocket() {
     PR_Close(fd_);
   }
 
   // Implement nsASocket
   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
 
   // Implementations of the async_event APIs
   int async_wait(int how, NR_async_cb cb, void *cb_arg,
                  char *function, int line);
   int cancel(int how);
--- a/media/mtransport/test/sockettransportservice_unittest.cpp
+++ b/media/mtransport/test/sockettransportservice_unittest.cpp
@@ -124,16 +124,19 @@ class SocketHandler : public nsASocketHa
 
   void OnSocketDetached(PRFileDesc *fd) {}
 
   void IsLocal(bool *aIsLocal) {
     // TODO(jesup): better check? Does it matter? (likely no)
     *aIsLocal = false;
   }
 
+  virtual uint64_t ByteCountSent() { return 0; }
+  virtual uint64_t ByteCountReceived() { return 0; }
+
   NS_DECL_ISUPPORTS
 
  private:
   SocketTransportServiceTest *test_;
 };
 
 NS_IMPL_ISUPPORTS0(SocketHandler)
 
--- a/media/mtransport/transportlayerprsock.h
+++ b/media/mtransport/transportlayerprsock.h
@@ -77,16 +77,19 @@ class TransportLayerPrsock : public Tran
         PR_Close(fd_);
       }
 
       virtual void IsLocal(bool *aIsLocal) {
         // TODO(jesup): better check? Does it matter? (likely no)
         *aIsLocal = false;
       }
 
+      virtual uint64_t ByteCountSent() { return 0; }
+      virtual uint64_t ByteCountReceived() { return 0; }
+
       // nsISupports methods
       NS_DECL_ISUPPORTS
 
       private:
       TransportLayerPrsock *prsock_;
       PRFileDesc *fd_;
    private:
     DISALLOW_COPY_ASSIGN(SocketHandler);
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -25,16 +25,18 @@ SDK_XPIDLSRCS   = \
 		nsIURI.idl \
 		nsIURL.idl \
 		nsIFileURL.idl \
 		nsIUploadChannel.idl \
 		nsITraceableChannel.idl \
 		$(NULL)
 
 XPIDLSRCS	= \
+		nsIDashboard.idl \
+		nsIDashboardEventNotifier.idl \
 		nsIApplicationCache.idl \
 		nsIApplicationCacheChannel.idl \
 		nsIApplicationCacheContainer.idl \
 		nsIApplicationCacheService.idl \
 		nsIAuthInformation.idl \
 		nsIAuthPrompt.idl \
 		nsIAuthPrompt2.idl \
 		nsIAuthPromptAdapterFactory.idl \
--- a/netwerk/base/public/nsASocketHandler.h
+++ b/netwerk/base/public/nsASocketHandler.h
@@ -62,11 +62,18 @@ public:
     virtual void OnSocketDetached(PRFileDesc *fd) = 0;
 
     //
     // called to determine if the socket is for a local peer.
     // when used for server sockets, indicates if it only accepts local
     // 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__
new file mode 100644
--- /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;
+};
new file mode 100644
--- /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);
+};
new file mode 100644
--- /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<nsIRunnable> 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<nsIRunnable> 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<nsIRunnable> event = NS_NewRunnableMethod(this, &Dashboard::GetHttpDispatch);
+    gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
+    return NS_OK;
+}
+
+void
+Dashboard::GetHttpDispatch()
+{
+    HttpInfo::GetHttpConnectionData(&mHttp.data);
+    nsCOMPtr<nsIRunnable> 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<nsIRunnable> 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<nsIRunnable> 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<nsIRunnable> 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
new file mode 100644
--- /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<SocketInfo> data;
+        nsCOMPtr<NetDashboardCallback> cb;
+        nsIThread* thread;
+    };
+
+    struct HttpData {
+        nsTArray<HttpRetParams> data;
+        nsCOMPtr<NetDashboardCallback> 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<LogData> data;
+        mozilla::Mutex lock;
+        nsCOMPtr<NetDashboardCallback> cb;
+        nsIThread* thread;
+    };
+
+    struct DnsData
+    {
+        nsCOMPtr<nsIDNSService> serv;
+        nsTArray<DNSCacheEntries> data;
+        nsCOMPtr<NetDashboardCallback> cb;
+        nsIThread* thread;
+    };
+
+    bool mEnableLogging;
+
+    struct SocketData mSock;
+    struct HttpData mHttp;
+    struct WebSocketData mWs;
+    struct DnsData mDns;
+
+};
+
+} } // namespace mozilla::net
+#endif // nsDashboard_h__
new file mode 100644
--- /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<nsCString> hostaddr;
+    int8_t family;
+    int64_t expiration;
+};
+
+struct HttpConnInfo
+{
+    uint32_t ttl;
+    uint32_t rtt;
+};
+
+struct HttpRetParams
+{
+    nsCString host;
+    nsTArray<HttpConnInfo>   active;
+    nsTArray<HttpConnInfo>   idle;
+    uint32_t  counter;
+    uint16_t  port;
+    bool      spdy;
+    bool      ssl;
+};
+
+} }
+
+#endif // nsDashboardTypes__
--- a/netwerk/base/src/Makefile.in
+++ b/netwerk/base/src/Makefile.in
@@ -16,16 +16,23 @@ MODULE		= necko
 LIBRARY_NAME	= neckobase_s
 LIBXUL_LIBRARY  = 1
 
 EXPORTS = \
 		nsMIMEInputStream.h \
 		nsURLHelper.h \
 		$(NULL)
 
+EXPORTS_NAMESPACES = mozilla/net
+
+EXPORTS_mozilla/net = \
+		Dashboard.h \
+		DashboardTypes.h \
+		$(NULL)
+
 CPPSRCS		= \
 		nsTransportUtils.cpp \
 		nsAsyncStreamCopier.cpp \
 		nsAsyncRedirectVerifyHelper.cpp \
 		nsAuthInformationHolder.cpp \
 		nsBaseChannel.cpp \
 		nsBaseContentStream.cpp \
 		nsBufferedStreams.cpp \
@@ -62,16 +69,17 @@ CPPSRCS		= \
 		nsNetStrings.cpp \
 		nsBase64Encoder.cpp \
 		nsSerializationHelper.cpp \
 		nsDNSPrefetch.cpp \
 		RedirectChannelRegistrar.cpp \
 		nsPreloadedStream.cpp \
 		nsStreamListenerWrapper.cpp \
 		ProxyAutoConfig.cpp \
+		Dashboard.cpp \
 		NetworkActivityMonitor.cpp \
 		$(NULL)
 
 LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/base
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 	CPPSRCS += nsURLHelperOS2.cpp
 else
--- a/netwerk/base/src/nsServerSocket.h
+++ b/netwerk/base/src/nsServerSocket.h
@@ -19,16 +19,18 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVERSOCKET
 
   // nsASocketHandler methods:
   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; }
   nsServerSocket();
 
   // This must be public to support older compilers (xlC_r on AIX)
   virtual ~nsServerSocket();
 
 private:
   void OnMsgClose();
   void OnMsgAttach();
--- a/netwerk/base/src/nsSocketTransport2.h
+++ b/netwerk/base/src/nsSocketTransport2.h
@@ -126,16 +126,18 @@ public:
     // nsASocketHandler methods:
     void OnSocketReady(PRFileDesc *, int16_t outFlags); 
     void OnSocketDetached(PRFileDesc *);
     void IsLocal(bool *aIsLocal);
 
     // 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();
 
 private:
 
     // event types
     enum {
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -29,16 +29,17 @@
 namespace mozilla { namespace psm {
 
 void InitializeSSLServerCertVerificationThreads();
 void StopSSLServerCertVerificationThreads();
 
 } } // namespace mozilla::psm
 
 using namespace mozilla;
+using namespace mozilla::net;
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gSocketTransportLog = nullptr;
 #endif
 
 nsSocketTransportService *gSocketTransportService = nullptr;
 PRThread                 *gSocketThread           = nullptr;
 
@@ -1009,8 +1010,46 @@ nsSocketTransportService::DiscoverMaxCou
     // >= XP is confirmed to have at least 1000
     gMaxCount = SOCKET_LIMIT_TARGET;
 #else
     // other platforms are harder to test - so leave at safe legacy value
 #endif
 
     return PR_SUCCESS;
 }
+
+void
+nsSocketTransportService::AnalyzeConnection(nsTArray<SocketInfo> *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<SocketInfo> *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);
+}
+
+
--- a/netwerk/base/src/nsSocketTransportService2.h
+++ b/netwerk/base/src/nsSocketTransportService2.h
@@ -14,16 +14,17 @@
 #include "pldhash.h"
 #include "prinrval.h"
 #include "prlog.h"
 #include "prinit.h"
 #include "prio.h"
 #include "nsASocketHandler.h"
 #include "nsIObserver.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/net/DashboardTypes.h"
 
 //-----------------------------------------------------------------------------
 
 #if defined(PR_LOGGING)
 //
 // set NSPR_LOG_MODULES=nsSocketTransport:5
 //
 extern PRLogModuleInfo *gSocketTransportLog;
@@ -68,16 +69,19 @@ public:
     // limit the number of sockets that can be created by an application.
     // AttachSocket will fail if the limit is exceeded.  consumers should
     // call CanAttachSocket and check the result before creating a socket.
     //
     bool CanAttachSocket() {
         return mActiveCount + mIdleCount < gMaxCount;
     }
 
+    // Called by the networking dashboard
+    // Fills the passed array with socket information
+    void GetSocketConnections(nsTArray<mozilla::net::SocketInfo> *);
 protected:
 
     virtual ~nsSocketTransportService();
 
 private:
 
     //-------------------------------------------------------------------------
     // misc (any thread)
@@ -178,14 +182,17 @@ private:
     nsresult    UpdatePrefs();
     int32_t     mSendBufferSize;
 
     // Socket thread only for dynamically adjusting max socket size
 #if defined(XP_WIN)
     void ProbeMaxCount();
 #endif
     bool mProbedMaxCount;
+
+    void AnalyzeConnection(nsTArray<mozilla::net::SocketInfo> *data,
+                           SocketContext *context, bool aActive);
 };
 
 extern nsSocketTransportService *gSocketTransportService;
 extern PRThread                 *gSocketThread;
 
 #endif // !nsSocketTransportService_h__
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -862,16 +862,29 @@
 
 /* This code produces a normal socket which can be used to initiate the
  * STARTTLS protocol by calling its nsISSLSocketControl->StartTLS()
  */
 #define NS_STARTTLSSOCKETPROVIDER_CONTRACTID \
     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
  */
 
 // service implementing nsICookieManager and nsICookieManager2.
 #define NS_COOKIEMANAGER_CLASSNAME \
     "CookieManager"
 #define NS_COOKIEMANAGER_CONTRACTID \
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -227,16 +227,23 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHt
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpsHandler, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsHttpAuthManager, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpChannelAuthProvider)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpActivityDistributor)
 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"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsResURL)
 #endif
 
 #ifdef NECKO_PROTOCOL_device
@@ -689,16 +696,17 @@ NS_DEFINE_NAMED_CID(NS_STDURLPARSER_CID)
 NS_DEFINE_NAMED_CID(NS_NOAUTHURLPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_AUTHURLPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_STANDARDURL_CID);
 NS_DEFINE_NAMED_CID(NS_BUFFEREDINPUTSTREAM_CID);
 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
 #ifdef NECKO_PROTOCOL_ftp
 NS_DEFINE_NAMED_CID(NS_FTPDIRLISTINGCONVERTER_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_NSINDEXEDTOHTMLCONVERTER_CID);
 NS_DEFINE_NAMED_CID(NS_DIRINDEXPARSER_CID);
@@ -821,16 +829,17 @@ static const mozilla::Module::CIDEntry k
     { &kNS_NOAUTHURLPARSER_CID, false, NULL, nsNoAuthURLParserConstructor },
     { &kNS_AUTHURLPARSER_CID, false, NULL, nsAuthURLParserConstructor },
     { &kNS_STANDARDURL_CID, false, NULL, nsStandardURLConstructor },
     { &kNS_BUFFEREDINPUTSTREAM_CID, false, NULL, nsBufferedInputStream::Create },
     { &kNS_BUFFEREDOUTPUTSTREAM_CID, false, NULL, nsBufferedOutputStream::Create },
     { &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
 #ifdef NECKO_PROTOCOL_ftp
     { &kNS_FTPDIRLISTINGCONVERTER_CID, false, NULL, CreateNewFTPDirListingConv },
 #endif
     { &kNS_NSINDEXEDTOHTMLCONVERTER_CID, false, NULL, nsIndexedToHTML::Create },
     { &kNS_DIRINDEXPARSER_CID, false, NULL, nsDirIndexParserConstructor },
@@ -957,16 +966,17 @@ static const mozilla::Module::ContractID
     { NS_NOAUTHURLPARSER_CONTRACTID, &kNS_NOAUTHURLPARSER_CID },
     { NS_AUTHURLPARSER_CONTRACTID, &kNS_AUTHURLPARSER_CID },
     { NS_STANDARDURL_CONTRACTID, &kNS_STANDARDURL_CID },
     { NS_BUFFEREDINPUTSTREAM_CONTRACTID, &kNS_BUFFEREDINPUTSTREAM_CID },
     { NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &kNS_BUFFEREDOUTPUTSTREAM_CID },
     { 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
 #ifdef NECKO_PROTOCOL_ftp
     { NS_ISTREAMCONVERTER_KEY FTP_TO_INDEX, &kNS_FTPDIRLISTINGCONVERTER_CID },
 #endif
     { NS_ISTREAMCONVERTER_KEY INDEX_TO_HTML, &kNS_NSINDEXEDTOHTMLCONVERTER_CID },
     { NS_DIRINDEXPARSER_CONTRACTID, &kNS_DIRINDEXPARSER_CID },
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -848,8 +848,16 @@ nsDNSService::GetAFForLookup(const nsACS
             }
 
             domain = end + 1;
         } while (*end);
     }
 
     return af;
 }
+
+NS_IMETHODIMP
+nsDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args)
+{
+    NS_ENSURE_TRUE(mResolver, NS_ERROR_NOT_INITIALIZED);
+    mResolver->GetDNSCacheEntries(args);
+    return NS_OK;
+}
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -33,16 +33,17 @@
 #include "nsURLHelper.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
+using namespace mozilla::net;
 
 //----------------------------------------------------------------------------
 
 // Use a persistent thread pool in order to avoid spinning up new threads all the time.
 // In particular, thread creation results in a res_init() call from libc which is 
 // quite expensive.
 //
 // The pool dynamically grows between 0 and MAX_RESOLVER_THREADS in size. New requests
@@ -1021,8 +1022,60 @@ nsHostResolver::Create(uint32_t         
 
     nsresult rv = res->Init();
     if (NS_FAILED(rv))
         NS_RELEASE(res);
 
     *result = res;
     return rv;
 }
+
+PLDHashOperator
+CacheEntryEnumerator(PLDHashTable *table, PLDHashEntryHdr *entry,
+                     uint32_t number, void *arg)
+{
+    nsHostDBEnt *ent = static_cast<nsHostDBEnt *> (entry);
+    nsTArray<DNSCacheEntries> *args =
+        static_cast<nsTArray<DNSCacheEntries> *> (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<DNSCacheEntries> *args)
+{
+    PL_DHashTableEnumerate(&mDB, CacheEntryEnumerator, args);
+}
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -12,16 +12,17 @@
 #include "prnetdb.h"
 #include "pldhash.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
 #include "nsIDNSListener.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "mozilla/net/DashboardTypes.h"
 
 class nsHostResolver;
 class nsHostRecord;
 class nsResolveHostCallback;
 
 #define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY  3
 #define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
 #define MAX_NON_PRIORITY_REQUESTS 150
@@ -270,11 +271,17 @@ private:
     PRCList       mLowQ;
     PRCList       mEvictionQ;
     uint32_t      mEvictionQSize;
     uint32_t      mPendingCount;
     PRTime        mCreationTime;
     bool          mShutdown;
     PRIntervalTime mLongIdleTimeout;
     PRIntervalTime mShortIdleTimeout;
+
+public:
+    /*
+     * Called by the networking dashboard via the DnsService2
+     */
+    void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *);
 };
 
 #endif // nsHostResolver_h__
--- a/netwerk/dns/nsIDNSService.idl
+++ b/netwerk/dns/nsIDNSService.idl
@@ -4,20 +4,30 @@
 
 #include "nsISupports.idl"
 
 interface nsICancelable;
 interface nsIEventTarget;
 interface nsIDNSRecord;
 interface nsIDNSListener;
 
+%{C++
+#include "nsTArray.h"
+
+namespace mozilla { namespace net {
+    struct DNSCacheEntries;
+} }
+%}
+
+[ptr] native EntriesArray(nsTArray<mozilla::net::DNSCacheEntries>);
+
 /**
  * nsIDNSService
  */
-[scriptable, uuid(F6E05CC3-8A13-463D-877F-D59B20B59724)]
+[scriptable, uuid(f1971942-19db-44bf-81e8-d15df220a39f)]
 interface nsIDNSService : nsISupports
 {
     /**
      * kicks off an asynchronous host lookup.
      *
      * @param aHostName
      *        the hostname or IP-address-literal to resolve.
      * @param aFlags
@@ -69,16 +79,23 @@ interface nsIDNSService : nsISupports
      *
      * @return DNS record corresponding to the given hostname.
      * @throws NS_ERROR_UNKNOWN_HOST if host could not be resolved.
      */
     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.
      */
     readonly attribute AUTF8String myHostName;
 
     /*************************************************************************
      * Listed below are the various flags that may be OR'd together to form
      * the aFlags parameter passed to asyncResolve() and resolve().
      */
new file mode 100644
--- /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<HttpRetParams>* args)
+{
+    if (gHttpHandler)
+        gHttpHandler->ConnMgr()->GetConnectionData(args);
+}
new file mode 100644
--- /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<HttpRetParams> *);
+};
+
+} } // namespace mozilla::net
+
+#endif // nsHttpInfo__
--- a/netwerk/protocol/http/Makefile.in
+++ b/netwerk/protocol/http/Makefile.in
@@ -40,16 +40,17 @@ XPIDLSRCS = \
 EXPORTS_mozilla/net = \
   HttpBaseChannel.h \
   $(NULL)
 
 EXPORTS_mozilla/net += \
   HttpChannelParent.h \
   HttpChannelChild.h  \
   PHttpChannelParams.h \
+  HttpInfo.h \
   $(NULL)
 
 EXPORTS = \
   nsHttpResponseHead.h \
   nsHttpHeaderArray.h \
   nsHttp.h \
   nsHttpAtomList.h \
   $(NULL)
@@ -73,16 +74,17 @@ CPPSRCS = \
   HttpBaseChannel.cpp \
   nsHttpChannel.cpp \
   nsHttpPipeline.cpp \
   nsHttpActivityDistributor.cpp \
   nsHttpChannelAuthProvider.cpp \
   HttpChannelParent.cpp \
   HttpChannelChild.cpp \
   HttpChannelParentListener.cpp \
+  HttpInfo.cpp \
   NullHttpTransaction.cpp \
   ASpdySession.cpp \
   SpdySession2.cpp \
   SpdyStream2.cpp \
   SpdySession3.cpp \
   SpdyStream3.cpp \
   ConnectionDiagnostics.cpp \
   $(NULL)
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -126,16 +126,17 @@ public:
     // connection pool, the nsHttpConnection still reads errors and hangups
     // on the socket so that it can be proactively released if the server
     // initiates a termination. Only call on socket thread.
     void BeginIdleMonitoring();
     void EndIdleMonitoring();
 
     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.
     bool ReportedNPN() { return mReportedSpdy; }
 
     // When the connection is active this is called every 1 second
     void  ReadTimeoutTick(PRIntervalTime now);
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3182,16 +3182,50 @@ nsConnectionEntry::MaxPipelineDepth(nsAH
         return 0;
 
     if (mPipelineState == PS_YELLOW)
         return kPipelineRestricted;
 
     return mGreenDepth;
 }
 
+PLDHashOperator
+nsHttpConnectionMgr::ReadConnectionEntry(const nsACString &key,
+                nsAutoPtr<nsConnectionEntry> &ent,
+                void *aArg)
+{
+    nsTArray<HttpRetParams> *args = static_cast<nsTArray<HttpRetParams> *> (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<mozilla::net::HttpRetParams> *aArg)
+{
+    mCT.Enumerate(ReadConnectionEntry, aArg);
+    return true;
+}
+
 uint32_t
 nsHttpConnectionMgr::nsConnectionEntry::UnconnectedHalfOpens()
 {
     uint32_t unconnectedHalfOpens = 0;
     for (uint32_t i = 0; i < mHalfOpens.Length(); ++i) {
         if (!mHalfOpens[i]->HasConnected())
             ++unconnectedHalfOpens;
     }
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -14,16 +14,17 @@
 #include "nsThreadUtils.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "nsISocketTransportService.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/net/DashboardTypes.h"
 
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsIX509Cert3.h"
 
 class nsHttpPipeline;
 
 class nsIHttpUpgradeListener;
@@ -218,16 +219,17 @@ public:
     // The connection manager needs to know when a normal HTTP connection has been
     // upgraded to SPDY because the dispatch and idle semantics are a little
     // bit different.
     void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
 
     
     bool     SupportsPipelining(nsHttpConnectionInfo *);
 
+    bool GetConnectionData(nsTArray<mozilla::net::HttpRetParams> *);
 private:
     virtual ~nsHttpConnectionMgr();
 
     enum PipeliningState {
         // Host has proven itself pipeline capable through past experience and
         // large pipeline depths are allowed on multiple connections.
         PS_GREEN,
 
@@ -606,16 +608,21 @@ private:
     //
     nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
 
     // mAlternateProtocolHash is used only for spdy/* upgrades for now
     // protected by the monitor
     nsTHashtable<nsCStringHashKey> mAlternateProtocolHash;
     static PLDHashOperator TrimAlternateProtocolHash(nsCStringHashKey *entry,
                                                      void *closure);
+
+    static PLDHashOperator ReadConnectionEntry(const nsACString &key,
+                                               nsAutoPtr<nsConnectionEntry> &ent,
+                                               void *aArg);
+
     // Read Timeout Tick handlers
     void ActivateTimeoutTick();
     void TimeoutTick();
     static PLDHashOperator TimeoutTickCB(const nsACString &key,
                                          nsAutoPtr<nsConnectionEntry> &ent,
                                          void *closure);
 
     // For diagnostics
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -907,16 +907,18 @@ private:
   const static int32_t            kBufferLen = 4096;
   uint8_t                         mBuffer[kBufferLen];
 };
 
 //-----------------------------------------------------------------------------
 // WebSocketChannel
 //-----------------------------------------------------------------------------
 
+uint32_t WebSocketChannel::sSerialSeed = 0;
+
 WebSocketChannel::WebSocketChannel() :
   mPort(0),
   mCloseTimeout(20000),
   mOpenTimeout(20000),
   mConnecting(NOT_CONNECTING),
   mPingTimeout(0),
   mPingResponseTimeout(10000),
   mMaxConcurrentConnections(200),
@@ -944,26 +946,34 @@ WebSocketChannel::WebSocketChannel() :
   mFragmentOpcode(kContinuation),
   mFragmentAccumulator(0),
   mBuffered(0),
   mBufferSize(kIncomingBufferInitialSize),
   mCurrentOut(nullptr),
   mCurrentOutSent(0),
   mCompressor(nullptr),
   mDynamicOutputSize(0),
-  mDynamicOutput(nullptr)
+  mDynamicOutput(nullptr),
+  mConnectionLogService(nullptr)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
   LOG(("WebSocketChannel::WebSocketChannel() %p\n", this));
 
   if (!sWebSocketAdmissions)
     sWebSocketAdmissions = new nsWSAdmissionManager();
 
   mFramePtr = mBuffer = static_cast<uint8_t *>(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()
 {
   LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this));
 
   if (mWasOpened) {
     MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called");
@@ -1315,16 +1325,25 @@ WebSocketChannel::ProcessInput(uint8_t *
 
         // Section 8.1 says to fail connection if invalid utf-8 in text message
         if (!IsUTF8(utf8Data, false)) {
           LOG(("WebSocketChannel:: text frame invalid utf-8\n"));
           return NS_ERROR_CANNOT_CONVERT_DATA;
         }
 
         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
       if (payloadLength > 125) {
         LOG(("WebSocketChannel:: bad control frame code %d length %d\n",
              opcode, payloadLength));
         return NS_ERROR_ILLEGAL_VALUE;
       }
@@ -1396,16 +1415,26 @@ WebSocketChannel::ProcessInput(uint8_t *
         payloadLength = 0;
       }
     } else if (opcode == kBinary) {
       LOG(("WebSocketChannel:: binary frame received\n"));
       if (mListener) {
         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 */
       LOG(("WebSocketChannel:: unknown op code %d\n", opcode));
       return NS_ERROR_ILLEGAL_VALUE;
     }
 
     mFramePtr = payload + payloadLength;
@@ -1809,16 +1838,24 @@ WebSocketChannel::CleanupConnection()
 
   if (mTransport) {
     mTransport->SetSecurityCallbacks(nullptr);
     mTransport->SetEventSink(nullptr, nullptr);
     mTransport->Close(NS_BASE_STREAM_CLOSED);
     mTransport = nullptr;
   }
 
+  nsresult rv;
+  if (mConnectionLogService) {
+    nsAutoCString host;
+    rv = mURI->GetHostPort(host);
+    if (NS_SUCCEEDED(rv))
+      mConnectionLogService->RemoveHost(host, mSerial);
+  }
+
   DecrementSessionCount();
 }
 
 void
 WebSocketChannel::StopSession(nsresult reason)
 {
   LOG(("WebSocketChannel::StopSession() %p [%x]\n", this, reason));
 
@@ -2633,16 +2670,24 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI
 
   mHttpChannel = do_QueryInterface(localChannel, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetupRequest();
   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;
 
   // Only set these if the open was successful:
   //
   mWasOpened = 1;
   mListener = aListener;
@@ -2729,16 +2774,26 @@ WebSocketChannel::SendMsgCommon(const ns
   }
 
   NS_ABORT_IF_FALSE(mMaxMessageSize >= 0, "max message size negative");
   if (aLength > static_cast<uint32_t>(mMaxMessageSize)) {
     LOG(("WebSocketChannel:: Error: message too big\n"));
     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,
                      new OutboundMessage(aIsBinary ? kMsgTypeBinaryString
                                                    : kMsgTypeString,
                                          new nsCString(*aMsg))),
     nsIEventTarget::DISPATCH_NORMAL);
 }
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -21,16 +21,17 @@
 #include "nsIDNSListener.h"
 #include "nsIHttpChannel.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIStringStream.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIRandomGenerator.h"
 #include "BaseWebSocketChannel.h"
+#include "nsIDashboardEventNotifier.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsDeque.h"
 
 namespace mozilla { namespace net {
 
 class OutboundMessage;
@@ -237,16 +238,20 @@ private:
   nsDeque                         mOutgoingPingMessages;
   nsDeque                         mOutgoingPongMessages;
   uint32_t                        mHdrOutToSend;
   uint8_t                        *mHdrOut;
   uint8_t                         mOutHeader[kCopyBreak + 16];
   nsWSCompression                *mCompressor;
   uint32_t                        mDynamicOutputSize;
   uint8_t                        *mDynamicOutput;
+
+  nsCOMPtr<nsIDashboardEventNotifier> mConnectionLogService;
+  uint32_t mSerial;
+  static uint32_t sSerialSeed;
 };
 
 class WebSocketSSLChannel : public WebSocketChannel
 {
 public:
     WebSocketSSLChannel() { BaseWebSocketChannel::mEncrypted = true; }
 protected:
     virtual ~WebSocketSSLChannel() {}