Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
4 :
5 : #include "mozilla/dom/NetDashboardBinding.h"
6 : #include "mozilla/dom/ToJSValue.h"
7 : #include "mozilla/ErrorNames.h"
8 : #include "mozilla/net/Dashboard.h"
9 : #include "mozilla/net/HttpInfo.h"
10 : #include "nsHttp.h"
11 : #include "nsICancelable.h"
12 : #include "nsIDNSService.h"
13 : #include "nsIDNSRecord.h"
14 : #include "nsIInputStream.h"
15 : #include "nsISocketTransport.h"
16 : #include "nsIThread.h"
17 : #include "nsProxyRelease.h"
18 : #include "nsSocketTransportService2.h"
19 : #include "nsThreadUtils.h"
20 : #include "nsURLHelper.h"
21 : #include "mozilla/Logging.h"
22 : #include "nsIOService.h"
23 : #include "../cache2/CacheFileUtils.h"
24 :
25 : using mozilla::AutoSafeJSContext;
26 : using mozilla::dom::Sequence;
27 : using mozilla::dom::ToJSValue;
28 :
29 : namespace mozilla {
30 : namespace net {
31 :
32 : class SocketData
33 : : public nsISupports
34 : {
35 : public:
36 : NS_DECL_THREADSAFE_ISUPPORTS
37 :
38 0 : SocketData()
39 0 : {
40 0 : mTotalSent = 0;
41 0 : mTotalRecv = 0;
42 0 : mEventTarget = nullptr;
43 0 : }
44 :
45 : uint64_t mTotalSent;
46 : uint64_t mTotalRecv;
47 : nsTArray<SocketInfo> mData;
48 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
49 : nsIEventTarget *mEventTarget;
50 :
51 : private:
52 0 : virtual ~SocketData()
53 0 : {
54 0 : }
55 : };
56 :
57 : static void GetErrorString(nsresult rv, nsAString& errorString);
58 :
59 0 : NS_IMPL_ISUPPORTS0(SocketData)
60 :
61 :
62 : class HttpData
63 : : public nsISupports
64 : {
65 0 : virtual ~HttpData()
66 0 : {
67 0 : }
68 :
69 : public:
70 : NS_DECL_THREADSAFE_ISUPPORTS
71 :
72 0 : HttpData()
73 0 : {
74 0 : mEventTarget = nullptr;
75 0 : }
76 :
77 : nsTArray<HttpRetParams> mData;
78 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
79 : nsIEventTarget *mEventTarget;
80 : };
81 :
82 0 : NS_IMPL_ISUPPORTS0(HttpData)
83 :
84 :
85 : class WebSocketRequest
86 : : public nsISupports
87 : {
88 0 : virtual ~WebSocketRequest()
89 0 : {
90 0 : }
91 :
92 : public:
93 : NS_DECL_THREADSAFE_ISUPPORTS
94 :
95 0 : WebSocketRequest()
96 0 : {
97 0 : mEventTarget = nullptr;
98 0 : }
99 :
100 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
101 : nsIEventTarget *mEventTarget;
102 : };
103 :
104 0 : NS_IMPL_ISUPPORTS0(WebSocketRequest)
105 :
106 :
107 : class DnsData
108 : : public nsISupports
109 : {
110 0 : virtual ~DnsData()
111 0 : {
112 0 : }
113 :
114 : public:
115 : NS_DECL_THREADSAFE_ISUPPORTS
116 :
117 0 : DnsData()
118 0 : {
119 0 : mEventTarget = nullptr;
120 0 : }
121 :
122 : nsTArray<DNSCacheEntries> mData;
123 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
124 : nsIEventTarget *mEventTarget;
125 : };
126 :
127 0 : NS_IMPL_ISUPPORTS0(DnsData)
128 :
129 :
130 : class ConnectionData
131 : : public nsITransportEventSink
132 : , public nsITimerCallback
133 : {
134 0 : virtual ~ConnectionData()
135 0 : {
136 0 : if (mTimer) {
137 0 : mTimer->Cancel();
138 : }
139 0 : }
140 :
141 : public:
142 : NS_DECL_THREADSAFE_ISUPPORTS
143 : NS_DECL_NSITRANSPORTEVENTSINK
144 : NS_DECL_NSITIMERCALLBACK
145 :
146 : void StartTimer(uint32_t aTimeout);
147 : void StopTimer();
148 :
149 0 : explicit ConnectionData(Dashboard *target)
150 0 : {
151 0 : mEventTarget = nullptr;
152 0 : mDashboard = target;
153 0 : }
154 :
155 : nsCOMPtr<nsISocketTransport> mSocket;
156 : nsCOMPtr<nsIInputStream> mStreamIn;
157 : nsCOMPtr<nsITimer> mTimer;
158 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
159 : nsIEventTarget *mEventTarget;
160 : Dashboard *mDashboard;
161 :
162 : nsCString mHost;
163 : uint32_t mPort;
164 : const char *mProtocol;
165 : uint32_t mTimeout;
166 :
167 : nsString mStatus;
168 : };
169 :
170 0 : NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback)
171 :
172 :
173 : class RcwnData
174 : : public nsISupports
175 : {
176 0 : virtual ~RcwnData()
177 0 : {
178 0 : }
179 :
180 : public:
181 : NS_DECL_THREADSAFE_ISUPPORTS
182 :
183 0 : RcwnData()
184 0 : {
185 0 : mEventTarget = nullptr;
186 0 : }
187 :
188 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
189 : nsIEventTarget *mEventTarget;
190 : };
191 :
192 0 : NS_IMPL_ISUPPORTS0(RcwnData)
193 :
194 : NS_IMETHODIMP
195 0 : ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
196 : int64_t aProgress, int64_t aProgressMax)
197 : {
198 0 : if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
199 0 : StopTimer();
200 : }
201 :
202 0 : GetErrorString(aStatus, mStatus);
203 0 : mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
204 0 : ("net::Dashboard::GetConnectionStatus",
205 : mDashboard, &Dashboard::GetConnectionStatus, this),
206 0 : NS_DISPATCH_NORMAL);
207 :
208 0 : return NS_OK;
209 : }
210 :
211 : NS_IMETHODIMP
212 0 : ConnectionData::Notify(nsITimer *aTimer)
213 : {
214 0 : MOZ_ASSERT(aTimer == mTimer);
215 :
216 0 : if (mSocket) {
217 0 : mSocket->Close(NS_ERROR_ABORT);
218 0 : mSocket = nullptr;
219 0 : mStreamIn = nullptr;
220 : }
221 :
222 0 : mTimer = nullptr;
223 :
224 0 : mStatus.AssignLiteral(u"NS_ERROR_NET_TIMEOUT");
225 0 : mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
226 0 : ("net::Dashboard::GetConnectionStatus",
227 : mDashboard, &Dashboard::GetConnectionStatus, this),
228 0 : NS_DISPATCH_NORMAL);
229 :
230 0 : return NS_OK;
231 : }
232 :
233 : void
234 0 : ConnectionData::StartTimer(uint32_t aTimeout)
235 : {
236 0 : if (!mTimer) {
237 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1");
238 : }
239 :
240 0 : mTimer->InitWithCallback(this, aTimeout * 1000,
241 0 : nsITimer::TYPE_ONE_SHOT);
242 0 : }
243 :
244 : void
245 0 : ConnectionData::StopTimer()
246 : {
247 0 : if (mTimer) {
248 0 : mTimer->Cancel();
249 0 : mTimer = nullptr;
250 : }
251 0 : }
252 :
253 :
254 : class LookupHelper;
255 :
256 : class LookupArgument
257 : : public nsISupports
258 : {
259 0 : virtual ~LookupArgument()
260 0 : {
261 0 : }
262 :
263 : public:
264 : NS_DECL_THREADSAFE_ISUPPORTS
265 :
266 0 : LookupArgument(nsIDNSRecord *aRecord, LookupHelper *aHelper)
267 0 : {
268 0 : mRecord = aRecord;
269 0 : mHelper = aHelper;
270 0 : }
271 :
272 : nsCOMPtr<nsIDNSRecord> mRecord;
273 : RefPtr<LookupHelper> mHelper;
274 : };
275 :
276 0 : NS_IMPL_ISUPPORTS0(LookupArgument)
277 :
278 :
279 : class LookupHelper
280 : : public nsIDNSListener
281 : {
282 0 : virtual ~LookupHelper()
283 0 : {
284 0 : if (mCancel) {
285 0 : mCancel->Cancel(NS_ERROR_ABORT);
286 : }
287 0 : }
288 :
289 : public:
290 : NS_DECL_THREADSAFE_ISUPPORTS
291 : NS_DECL_NSIDNSLISTENER
292 :
293 0 : LookupHelper() {
294 0 : }
295 :
296 : nsresult ConstructAnswer(LookupArgument *aArgument);
297 : public:
298 : nsCOMPtr<nsICancelable> mCancel;
299 : nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
300 : nsIEventTarget *mEventTarget;
301 : nsresult mStatus;
302 : };
303 :
304 0 : NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener)
305 :
306 : NS_IMETHODIMP
307 0 : LookupHelper::OnLookupComplete(nsICancelable *aRequest,
308 : nsIDNSRecord *aRecord, nsresult aStatus)
309 : {
310 0 : MOZ_ASSERT(aRequest == mCancel);
311 0 : mCancel = nullptr;
312 0 : mStatus = aStatus;
313 :
314 0 : RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
315 0 : mEventTarget->Dispatch(NewRunnableMethod<RefPtr<LookupArgument>>
316 0 : ("net::LookupHelper::ConstructAnswer",
317 : this, &LookupHelper::ConstructAnswer, arg),
318 0 : NS_DISPATCH_NORMAL);
319 :
320 0 : return NS_OK;
321 : }
322 :
323 : nsresult
324 0 : LookupHelper::ConstructAnswer(LookupArgument *aArgument)
325 : {
326 0 : nsIDNSRecord *aRecord = aArgument->mRecord;
327 0 : AutoSafeJSContext cx;
328 :
329 0 : mozilla::dom::DNSLookupDict dict;
330 0 : dict.mAddress.Construct();
331 :
332 0 : Sequence<nsString> &addresses = dict.mAddress.Value();
333 :
334 0 : if (NS_SUCCEEDED(mStatus)) {
335 0 : dict.mAnswer = true;
336 : bool hasMore;
337 0 : aRecord->HasMore(&hasMore);
338 0 : while (hasMore) {
339 0 : nsString* nextAddress = addresses.AppendElement(fallible);
340 0 : if (!nextAddress) {
341 0 : return NS_ERROR_OUT_OF_MEMORY;
342 : }
343 :
344 0 : nsCString nextAddressASCII;
345 0 : aRecord->GetNextAddrAsString(nextAddressASCII);
346 0 : CopyASCIItoUTF16(nextAddressASCII, *nextAddress);
347 0 : aRecord->HasMore(&hasMore);
348 : }
349 : } else {
350 0 : dict.mAnswer = false;
351 0 : GetErrorString(mStatus, dict.mError);
352 : }
353 :
354 0 : JS::RootedValue val(cx);
355 0 : if (!ToJSValue(cx, dict, &val)) {
356 0 : return NS_ERROR_FAILURE;
357 : }
358 :
359 0 : this->mCallback->OnDashboardDataAvailable(val);
360 :
361 0 : return NS_OK;
362 : }
363 :
364 0 : NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
365 :
366 0 : Dashboard::Dashboard()
367 : {
368 0 : mEnableLogging = false;
369 0 : }
370 :
371 0 : Dashboard::~Dashboard()
372 : {
373 0 : }
374 :
375 : NS_IMETHODIMP
376 0 : Dashboard::RequestSockets(NetDashboardCallback *aCallback)
377 : {
378 0 : RefPtr<SocketData> socketData = new SocketData();
379 0 : socketData->mCallback =
380 : new nsMainThreadPtrHolder<NetDashboardCallback>(
381 0 : "NetDashboardCallback", aCallback, true);
382 0 : socketData->mEventTarget = GetCurrentThreadEventTarget();
383 0 : gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
384 0 : ("net::Dashboard::GetSocketsDispatch",
385 : this, &Dashboard::GetSocketsDispatch, socketData),
386 0 : NS_DISPATCH_NORMAL);
387 0 : return NS_OK;
388 : }
389 :
390 : nsresult
391 0 : Dashboard::GetSocketsDispatch(SocketData *aSocketData)
392 : {
393 0 : RefPtr<SocketData> socketData = aSocketData;
394 0 : if (gSocketTransportService) {
395 0 : gSocketTransportService->GetSocketConnections(&socketData->mData);
396 0 : socketData->mTotalSent = gSocketTransportService->GetSentBytes();
397 0 : socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes();
398 : }
399 0 : socketData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
400 0 : ("net::Dashboard::GetSockets",
401 : this, &Dashboard::GetSockets, socketData),
402 0 : NS_DISPATCH_NORMAL);
403 0 : return NS_OK;
404 : }
405 :
406 : nsresult
407 0 : Dashboard::GetSockets(SocketData *aSocketData)
408 : {
409 0 : RefPtr<SocketData> socketData = aSocketData;
410 0 : AutoSafeJSContext cx;
411 :
412 0 : mozilla::dom::SocketsDict dict;
413 0 : dict.mSockets.Construct();
414 0 : dict.mSent = 0;
415 0 : dict.mReceived = 0;
416 :
417 0 : Sequence<mozilla::dom::SocketElement> &sockets = dict.mSockets.Value();
418 :
419 0 : uint32_t length = socketData->mData.Length();
420 0 : if (!sockets.SetCapacity(length, fallible)) {
421 0 : JS_ReportOutOfMemory(cx);
422 0 : return NS_ERROR_OUT_OF_MEMORY;
423 : }
424 :
425 0 : for (uint32_t i = 0; i < socketData->mData.Length(); i++) {
426 0 : dom::SocketElement &mSocket = *sockets.AppendElement(fallible);
427 0 : CopyASCIItoUTF16(socketData->mData[i].host, mSocket.mHost);
428 0 : mSocket.mPort = socketData->mData[i].port;
429 0 : mSocket.mActive = socketData->mData[i].active;
430 0 : mSocket.mTcp = socketData->mData[i].tcp;
431 0 : mSocket.mSent = (double) socketData->mData[i].sent;
432 0 : mSocket.mReceived = (double) socketData->mData[i].received;
433 0 : dict.mSent += socketData->mData[i].sent;
434 0 : dict.mReceived += socketData->mData[i].received;
435 : }
436 :
437 0 : dict.mSent += socketData->mTotalSent;
438 0 : dict.mReceived += socketData->mTotalRecv;
439 0 : JS::RootedValue val(cx);
440 0 : if (!ToJSValue(cx, dict, &val))
441 0 : return NS_ERROR_FAILURE;
442 0 : socketData->mCallback->OnDashboardDataAvailable(val);
443 :
444 0 : return NS_OK;
445 : }
446 :
447 : NS_IMETHODIMP
448 0 : Dashboard::RequestHttpConnections(NetDashboardCallback *aCallback)
449 : {
450 0 : RefPtr<HttpData> httpData = new HttpData();
451 0 : httpData->mCallback =
452 : new nsMainThreadPtrHolder<NetDashboardCallback>(
453 0 : "NetDashboardCallback", aCallback, true);
454 0 : httpData->mEventTarget = GetCurrentThreadEventTarget();
455 :
456 0 : gSocketTransportService->Dispatch(
457 0 : NewRunnableMethod<RefPtr<HttpData>>("net::Dashboard::GetHttpDispatch",
458 : this,
459 : &Dashboard::GetHttpDispatch,
460 : httpData),
461 0 : NS_DISPATCH_NORMAL);
462 0 : return NS_OK;
463 : }
464 :
465 : nsresult
466 0 : Dashboard::GetHttpDispatch(HttpData *aHttpData)
467 : {
468 0 : RefPtr<HttpData> httpData = aHttpData;
469 0 : HttpInfo::GetHttpConnectionData(&httpData->mData);
470 0 : httpData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<HttpData>>
471 0 : ("net::Dashboard::GetHttpConnections",
472 : this, &Dashboard::GetHttpConnections, httpData),
473 0 : NS_DISPATCH_NORMAL);
474 0 : return NS_OK;
475 : }
476 :
477 :
478 : nsresult
479 0 : Dashboard::GetHttpConnections(HttpData *aHttpData)
480 : {
481 0 : RefPtr<HttpData> httpData = aHttpData;
482 0 : AutoSafeJSContext cx;
483 :
484 0 : mozilla::dom::HttpConnDict dict;
485 0 : dict.mConnections.Construct();
486 :
487 : using mozilla::dom::HalfOpenInfoDict;
488 : using mozilla::dom::HttpConnectionElement;
489 : using mozilla::dom::HttpConnInfo;
490 0 : Sequence<HttpConnectionElement> &connections = dict.mConnections.Value();
491 :
492 0 : uint32_t length = httpData->mData.Length();
493 0 : if (!connections.SetCapacity(length, fallible)) {
494 0 : JS_ReportOutOfMemory(cx);
495 0 : return NS_ERROR_OUT_OF_MEMORY;
496 : }
497 :
498 0 : for (uint32_t i = 0; i < httpData->mData.Length(); i++) {
499 0 : HttpConnectionElement &connection = *connections.AppendElement(fallible);
500 :
501 0 : CopyASCIItoUTF16(httpData->mData[i].host, connection.mHost);
502 0 : connection.mPort = httpData->mData[i].port;
503 0 : connection.mSpdy = httpData->mData[i].spdy;
504 0 : connection.mSsl = httpData->mData[i].ssl;
505 :
506 0 : connection.mActive.Construct();
507 0 : connection.mIdle.Construct();
508 0 : connection.mHalfOpens.Construct();
509 :
510 0 : Sequence<HttpConnInfo> &active = connection.mActive.Value();
511 0 : Sequence<HttpConnInfo> &idle = connection.mIdle.Value();
512 0 : Sequence<HalfOpenInfoDict> &halfOpens = connection.mHalfOpens.Value();
513 :
514 0 : if (!active.SetCapacity(httpData->mData[i].active.Length(), fallible) ||
515 0 : !idle.SetCapacity(httpData->mData[i].idle.Length(), fallible) ||
516 0 : !halfOpens.SetCapacity(httpData->mData[i].halfOpens.Length(),
517 : fallible)) {
518 0 : JS_ReportOutOfMemory(cx);
519 0 : return NS_ERROR_OUT_OF_MEMORY;
520 : }
521 :
522 0 : for (uint32_t j = 0; j < httpData->mData[i].active.Length(); j++) {
523 0 : HttpConnInfo &info = *active.AppendElement(fallible);
524 0 : info.mRtt = httpData->mData[i].active[j].rtt;
525 0 : info.mTtl = httpData->mData[i].active[j].ttl;
526 : info.mProtocolVersion =
527 0 : httpData->mData[i].active[j].protocolVersion;
528 : }
529 :
530 0 : for (uint32_t j = 0; j < httpData->mData[i].idle.Length(); j++) {
531 0 : HttpConnInfo &info = *idle.AppendElement(fallible);
532 0 : info.mRtt = httpData->mData[i].idle[j].rtt;
533 0 : info.mTtl = httpData->mData[i].idle[j].ttl;
534 0 : info.mProtocolVersion = httpData->mData[i].idle[j].protocolVersion;
535 : }
536 :
537 0 : for (uint32_t j = 0; j < httpData->mData[i].halfOpens.Length(); j++) {
538 0 : HalfOpenInfoDict &info = *halfOpens.AppendElement(fallible);
539 0 : info.mSpeculative = httpData->mData[i].halfOpens[j].speculative;
540 : }
541 : }
542 :
543 0 : JS::RootedValue val(cx);
544 0 : if (!ToJSValue(cx, dict, &val)) {
545 0 : return NS_ERROR_FAILURE;
546 : }
547 :
548 0 : httpData->mCallback->OnDashboardDataAvailable(val);
549 :
550 0 : return NS_OK;
551 : }
552 :
553 : NS_IMETHODIMP
554 0 : Dashboard::GetEnableLogging(bool *value)
555 : {
556 0 : *value = mEnableLogging;
557 0 : return NS_OK;
558 : }
559 :
560 : NS_IMETHODIMP
561 0 : Dashboard::SetEnableLogging(const bool value)
562 : {
563 0 : mEnableLogging = value;
564 0 : return NS_OK;
565 : }
566 :
567 : NS_IMETHODIMP
568 0 : Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted)
569 : {
570 0 : if (mEnableLogging) {
571 0 : mozilla::MutexAutoLock lock(mWs.lock);
572 0 : LogData mData(nsCString(aHost), aSerial, aEncrypted);
573 0 : if (mWs.data.Contains(mData)) {
574 0 : return NS_OK;
575 : }
576 0 : if (!mWs.data.AppendElement(mData)) {
577 0 : return NS_ERROR_OUT_OF_MEMORY;
578 : }
579 0 : return NS_OK;
580 : }
581 0 : return NS_ERROR_FAILURE;
582 : }
583 :
584 : NS_IMETHODIMP
585 0 : Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial)
586 : {
587 0 : if (mEnableLogging) {
588 0 : mozilla::MutexAutoLock lock(mWs.lock);
589 0 : int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
590 0 : if (index == -1)
591 0 : return NS_ERROR_FAILURE;
592 0 : mWs.data.RemoveElementAt(index);
593 0 : return NS_OK;
594 : }
595 0 : return NS_ERROR_FAILURE;
596 : }
597 :
598 : NS_IMETHODIMP
599 0 : Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
600 : {
601 0 : if (mEnableLogging) {
602 0 : mozilla::MutexAutoLock lock(mWs.lock);
603 0 : int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
604 0 : if (index == -1)
605 0 : return NS_ERROR_FAILURE;
606 0 : mWs.data[index].mMsgSent++;
607 0 : mWs.data[index].mSizeSent += aLength;
608 0 : return NS_OK;
609 : }
610 0 : return NS_ERROR_FAILURE;
611 : }
612 :
613 : NS_IMETHODIMP
614 0 : Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
615 : {
616 0 : if (mEnableLogging) {
617 0 : mozilla::MutexAutoLock lock(mWs.lock);
618 0 : int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
619 0 : if (index == -1)
620 0 : return NS_ERROR_FAILURE;
621 0 : mWs.data[index].mMsgReceived++;
622 0 : mWs.data[index].mSizeReceived += aLength;
623 0 : return NS_OK;
624 : }
625 0 : return NS_ERROR_FAILURE;
626 : }
627 :
628 : NS_IMETHODIMP
629 0 : Dashboard::RequestWebsocketConnections(NetDashboardCallback *aCallback)
630 : {
631 0 : RefPtr<WebSocketRequest> wsRequest = new WebSocketRequest();
632 0 : wsRequest->mCallback =
633 : new nsMainThreadPtrHolder<NetDashboardCallback>(
634 0 : "NetDashboardCallback", aCallback, true);
635 0 : wsRequest->mEventTarget = GetCurrentThreadEventTarget();
636 :
637 0 : wsRequest->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<WebSocketRequest>>
638 0 : ("net::Dashboard::GetWebSocketConnections",
639 : this, &Dashboard::GetWebSocketConnections, wsRequest),
640 0 : NS_DISPATCH_NORMAL);
641 0 : return NS_OK;
642 : }
643 :
644 : nsresult
645 0 : Dashboard::GetWebSocketConnections(WebSocketRequest *aWsRequest)
646 : {
647 0 : RefPtr<WebSocketRequest> wsRequest = aWsRequest;
648 0 : AutoSafeJSContext cx;
649 :
650 0 : mozilla::dom::WebSocketDict dict;
651 0 : dict.mWebsockets.Construct();
652 : Sequence<mozilla::dom::WebSocketElement> &websockets =
653 0 : dict.mWebsockets.Value();
654 :
655 0 : mozilla::MutexAutoLock lock(mWs.lock);
656 0 : uint32_t length = mWs.data.Length();
657 0 : if (!websockets.SetCapacity(length, fallible)) {
658 0 : JS_ReportOutOfMemory(cx);
659 0 : return NS_ERROR_OUT_OF_MEMORY;
660 : }
661 :
662 0 : for (uint32_t i = 0; i < mWs.data.Length(); i++) {
663 0 : dom::WebSocketElement &websocket = *websockets.AppendElement(fallible);
664 0 : CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport);
665 0 : websocket.mMsgsent = mWs.data[i].mMsgSent;
666 0 : websocket.mMsgreceived = mWs.data[i].mMsgReceived;
667 0 : websocket.mSentsize = mWs.data[i].mSizeSent;
668 0 : websocket.mReceivedsize = mWs.data[i].mSizeReceived;
669 0 : websocket.mEncrypted = mWs.data[i].mEncrypted;
670 : }
671 :
672 0 : JS::RootedValue val(cx);
673 0 : if (!ToJSValue(cx, dict, &val)) {
674 0 : return NS_ERROR_FAILURE;
675 : }
676 0 : wsRequest->mCallback->OnDashboardDataAvailable(val);
677 :
678 0 : return NS_OK;
679 : }
680 :
681 : NS_IMETHODIMP
682 0 : Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback)
683 : {
684 0 : RefPtr<DnsData> dnsData = new DnsData();
685 0 : dnsData->mCallback =
686 : new nsMainThreadPtrHolder<NetDashboardCallback>(
687 0 : "NetDashboardCallback", aCallback, true);
688 :
689 : nsresult rv;
690 0 : dnsData->mData.Clear();
691 0 : dnsData->mEventTarget = GetCurrentThreadEventTarget();
692 :
693 0 : if (!mDnsService) {
694 0 : mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
695 0 : if (NS_FAILED(rv)) {
696 0 : return rv;
697 : }
698 : }
699 :
700 0 : gSocketTransportService->Dispatch(
701 0 : NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDnsInfoDispatch",
702 : this,
703 : &Dashboard::GetDnsInfoDispatch,
704 : dnsData),
705 0 : NS_DISPATCH_NORMAL);
706 0 : return NS_OK;
707 : }
708 :
709 : nsresult
710 0 : Dashboard::GetDnsInfoDispatch(DnsData *aDnsData)
711 : {
712 0 : RefPtr<DnsData> dnsData = aDnsData;
713 0 : if (mDnsService) {
714 0 : mDnsService->GetDNSCacheEntries(&dnsData->mData);
715 : }
716 0 : dnsData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<DnsData>>
717 0 : ("net::Dashboard::GetDNSCacheEntries",
718 : this, &Dashboard::GetDNSCacheEntries, dnsData),
719 0 : NS_DISPATCH_NORMAL);
720 0 : return NS_OK;
721 : }
722 :
723 : nsresult
724 0 : Dashboard::GetDNSCacheEntries(DnsData *dnsData)
725 : {
726 0 : AutoSafeJSContext cx;
727 :
728 0 : mozilla::dom::DNSCacheDict dict;
729 0 : dict.mEntries.Construct();
730 0 : Sequence<mozilla::dom::DnsCacheEntry> &entries = dict.mEntries.Value();
731 :
732 0 : uint32_t length = dnsData->mData.Length();
733 0 : if (!entries.SetCapacity(length, fallible)) {
734 0 : JS_ReportOutOfMemory(cx);
735 0 : return NS_ERROR_OUT_OF_MEMORY;
736 : }
737 :
738 0 : for (uint32_t i = 0; i < dnsData->mData.Length(); i++) {
739 0 : dom::DnsCacheEntry &entry = *entries.AppendElement(fallible);
740 0 : entry.mHostaddr.Construct();
741 :
742 0 : Sequence<nsString> &addrs = entry.mHostaddr.Value();
743 0 : if (!addrs.SetCapacity(dnsData->mData[i].hostaddr.Length(), fallible)) {
744 0 : JS_ReportOutOfMemory(cx);
745 0 : return NS_ERROR_OUT_OF_MEMORY;
746 : }
747 :
748 0 : CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname);
749 0 : entry.mExpiration = dnsData->mData[i].expiration;
750 :
751 0 : for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) {
752 0 : nsString* addr = addrs.AppendElement(fallible);
753 0 : if (!addr) {
754 0 : JS_ReportOutOfMemory(cx);
755 0 : return NS_ERROR_OUT_OF_MEMORY;
756 : }
757 0 : CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], *addr);
758 : }
759 :
760 0 : if (dnsData->mData[i].family == PR_AF_INET6) {
761 0 : CopyASCIItoUTF16("ipv6", entry.mFamily);
762 : } else {
763 0 : CopyASCIItoUTF16("ipv4", entry.mFamily);
764 : }
765 : }
766 :
767 0 : JS::RootedValue val(cx);
768 0 : if (!ToJSValue(cx, dict, &val)) {
769 0 : return NS_ERROR_FAILURE;
770 : }
771 0 : dnsData->mCallback->OnDashboardDataAvailable(val);
772 :
773 0 : return NS_OK;
774 : }
775 :
776 : NS_IMETHODIMP
777 0 : Dashboard::RequestDNSLookup(const nsACString &aHost,
778 : NetDashboardCallback *aCallback)
779 : {
780 : nsresult rv;
781 :
782 0 : if (!mDnsService) {
783 0 : mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
784 0 : if (NS_FAILED(rv)) {
785 0 : return rv;
786 : }
787 : }
788 :
789 0 : RefPtr<LookupHelper> helper = new LookupHelper();
790 0 : helper->mCallback =
791 : new nsMainThreadPtrHolder<NetDashboardCallback>(
792 0 : "NetDashboardCallback", aCallback, true);
793 0 : helper->mEventTarget = GetCurrentThreadEventTarget();
794 0 : OriginAttributes attrs;
795 0 : rv = mDnsService->AsyncResolveNative(aHost, 0, helper.get(),
796 0 : NS_GetCurrentThread(), attrs,
797 0 : getter_AddRefs(helper->mCancel));
798 0 : return rv;
799 : }
800 :
801 : NS_IMETHODIMP
802 0 : Dashboard::RequestRcwnStats(NetDashboardCallback *aCallback)
803 : {
804 0 : RefPtr<RcwnData> rcwnData = new RcwnData();
805 0 : rcwnData->mEventTarget = GetCurrentThreadEventTarget();
806 0 : rcwnData->mCallback =
807 : new nsMainThreadPtrHolder<NetDashboardCallback>(
808 0 : "NetDashboardCallback", aCallback, true);
809 :
810 0 : return rcwnData->mEventTarget->Dispatch(
811 0 : NewRunnableMethod<RefPtr<RcwnData>>("net::Dashboard::GetRcwnData",
812 : this, &Dashboard::GetRcwnData, rcwnData),
813 0 : NS_DISPATCH_NORMAL);
814 : }
815 :
816 : nsresult
817 0 : Dashboard::GetRcwnData(RcwnData *aData)
818 : {
819 0 : AutoSafeJSContext cx;
820 0 : mozilla::dom::RcwnStatus dict;
821 :
822 0 : dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber();
823 0 : dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
824 0 : dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
825 :
826 : uint32_t cacheSlow, cacheNotSlow;
827 0 : CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow, &cacheNotSlow);
828 0 : dict.mCacheSlowCount = cacheSlow;
829 0 : dict.mCacheNotSlowCount = cacheNotSlow;
830 :
831 0 : dict.mPerfStats.Construct();
832 0 : Sequence<mozilla::dom::RcwnPerfStats> &perfStats = dict.mPerfStats.Value();
833 0 : uint32_t length = CacheFileUtils::CachePerfStats::LAST;
834 0 : if (!perfStats.SetCapacity(length, fallible)) {
835 0 : JS_ReportOutOfMemory(cx);
836 0 : return NS_ERROR_OUT_OF_MEMORY;
837 : }
838 :
839 0 : for (uint32_t i = 0; i < length; i++) {
840 : CacheFileUtils::CachePerfStats::EDataType perfType =
841 0 : static_cast<CacheFileUtils::CachePerfStats::EDataType>(i);
842 0 : dom::RcwnPerfStats &elem = *perfStats.AppendElement(fallible);
843 0 : elem.mAvgShort = CacheFileUtils::CachePerfStats::GetAverage(perfType, false);
844 0 : elem.mAvgLong = CacheFileUtils::CachePerfStats::GetAverage(perfType, true);
845 0 : elem.mStddevLong = CacheFileUtils::CachePerfStats::GetStdDev(perfType, true);
846 : }
847 :
848 0 : JS::RootedValue val(cx);
849 0 : if (!ToJSValue(cx, dict, &val)) {
850 0 : return NS_ERROR_FAILURE;
851 : }
852 :
853 0 : aData->mCallback->OnDashboardDataAvailable(val);
854 :
855 0 : return NS_OK;
856 : }
857 :
858 : void
859 0 : HttpConnInfo::SetHTTP1ProtocolVersion(uint8_t pv)
860 : {
861 0 : switch (pv) {
862 : case NS_HTTP_VERSION_0_9:
863 0 : protocolVersion.AssignLiteral(u"http/0.9");
864 0 : break;
865 : case NS_HTTP_VERSION_1_0:
866 0 : protocolVersion.AssignLiteral(u"http/1.0");
867 0 : break;
868 : case NS_HTTP_VERSION_1_1:
869 0 : protocolVersion.AssignLiteral(u"http/1.1");
870 0 : break;
871 : case NS_HTTP_VERSION_2_0:
872 0 : protocolVersion.AssignLiteral(u"http/2.0");
873 0 : break;
874 : default:
875 0 : protocolVersion.AssignLiteral(u"unknown protocol version");
876 : }
877 0 : }
878 :
879 : void
880 0 : HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
881 : {
882 0 : MOZ_ASSERT (pv == HTTP_VERSION_2);
883 0 : protocolVersion.Assign(u"h2");
884 0 : }
885 :
886 : NS_IMETHODIMP
887 0 : Dashboard::GetLogPath(nsACString &aLogPath)
888 : {
889 0 : aLogPath.SetCapacity(2048);
890 0 : uint32_t len = LogModule::GetLogFile(aLogPath.BeginWriting(), 2048);
891 0 : aLogPath.SetLength(len);
892 0 : return NS_OK;
893 : }
894 :
895 : NS_IMETHODIMP
896 0 : Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
897 : const char *aProtocol, uint32_t aTimeout,
898 : NetDashboardCallback *aCallback)
899 : {
900 : nsresult rv;
901 0 : RefPtr<ConnectionData> connectionData = new ConnectionData(this);
902 0 : connectionData->mHost = aHost;
903 0 : connectionData->mPort = aPort;
904 0 : connectionData->mProtocol = aProtocol;
905 0 : connectionData->mTimeout = aTimeout;
906 :
907 0 : connectionData->mCallback =
908 : new nsMainThreadPtrHolder<NetDashboardCallback>(
909 0 : "NetDashboardCallback", aCallback, true);
910 0 : connectionData->mEventTarget = GetCurrentThreadEventTarget();
911 :
912 0 : rv = TestNewConnection(connectionData);
913 0 : if (NS_FAILED(rv)) {
914 0 : mozilla::net::GetErrorString(rv, connectionData->mStatus);
915 0 : connectionData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
916 0 : ("net::Dashboard::GetConnectionStatus",
917 : this, &Dashboard::GetConnectionStatus, connectionData),
918 0 : NS_DISPATCH_NORMAL);
919 0 : return rv;
920 : }
921 :
922 0 : return NS_OK;
923 : }
924 :
925 : nsresult
926 0 : Dashboard::GetConnectionStatus(ConnectionData *aConnectionData)
927 : {
928 0 : RefPtr<ConnectionData> connectionData = aConnectionData;
929 0 : AutoSafeJSContext cx;
930 :
931 0 : mozilla::dom::ConnStatusDict dict;
932 0 : dict.mStatus = connectionData->mStatus;
933 :
934 0 : JS::RootedValue val(cx);
935 0 : if (!ToJSValue(cx, dict, &val))
936 0 : return NS_ERROR_FAILURE;
937 :
938 0 : connectionData->mCallback->OnDashboardDataAvailable(val);
939 :
940 0 : return NS_OK;
941 : }
942 :
943 : nsresult
944 0 : Dashboard::TestNewConnection(ConnectionData *aConnectionData)
945 : {
946 0 : RefPtr<ConnectionData> connectionData = aConnectionData;
947 :
948 : nsresult rv;
949 0 : if (!connectionData->mHost.Length() ||
950 0 : !net_IsValidHostName(connectionData->mHost)) {
951 0 : return NS_ERROR_UNKNOWN_HOST;
952 : }
953 :
954 0 : if (connectionData->mProtocol &&
955 0 : NS_LITERAL_STRING("ssl").EqualsASCII(connectionData->mProtocol)) {
956 0 : rv = gSocketTransportService->CreateTransport(
957 0 : &connectionData->mProtocol, 1, connectionData->mHost,
958 0 : connectionData->mPort, nullptr,
959 0 : getter_AddRefs(connectionData->mSocket));
960 : } else {
961 0 : rv = gSocketTransportService->CreateTransport(
962 0 : nullptr, 0, connectionData->mHost,
963 0 : connectionData->mPort, nullptr,
964 0 : getter_AddRefs(connectionData->mSocket));
965 : }
966 0 : if (NS_FAILED(rv)) {
967 0 : return rv;
968 : }
969 :
970 0 : rv = connectionData->mSocket->SetEventSink(connectionData,
971 0 : GetCurrentThreadEventTarget());
972 0 : if (NS_FAILED(rv)) {
973 0 : return rv;
974 : }
975 :
976 0 : rv = connectionData->mSocket->OpenInputStream(
977 : nsITransport::OPEN_BLOCKING, 0, 0,
978 0 : getter_AddRefs(connectionData->mStreamIn));
979 0 : if (NS_FAILED(rv)) {
980 0 : return rv;
981 : }
982 :
983 0 : connectionData->StartTimer(connectionData->mTimeout);
984 :
985 0 : return rv;
986 : }
987 :
988 : typedef struct
989 : {
990 : nsresult key;
991 : const char *error;
992 : } ErrorEntry;
993 :
994 : #undef ERROR
995 : #define ERROR(key, val) {key, #key}
996 :
997 : ErrorEntry socketTransportStatuses[] = {
998 : ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
999 : ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
1000 : ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
1001 : ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
1002 : ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)),
1003 : ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)),
1004 : ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
1005 : ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
1006 : ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
1007 : };
1008 : #undef ERROR
1009 :
1010 :
1011 : static void
1012 0 : GetErrorString(nsresult rv, nsAString& errorString)
1013 : {
1014 0 : for (size_t i = 0; i < ArrayLength(socketTransportStatuses); ++i) {
1015 0 : if (socketTransportStatuses[i].key == rv) {
1016 0 : errorString.AssignASCII(socketTransportStatuses[i].error);
1017 0 : return;
1018 : }
1019 : }
1020 0 : nsAutoCString errorCString;
1021 0 : mozilla::GetErrorName(rv, errorCString);
1022 0 : CopyUTF8toUTF16(errorCString, errorString);
1023 : }
1024 :
1025 : } // namespace net
1026 : } // namespace mozilla
|