Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
5 #include "mozilla/dom/NetDashboardBinding.h"
6 #include "mozilla/net/Dashboard.h"
7 #include "mozilla/net/HttpInfo.h"
8 #include "nsCxPusher.h"
9 #include "nsHttp.h"
10 #include "nsICancelable.h"
11 #include "nsIDNSService.h"
12 #include "nsIDNSRecord.h"
13 #include "nsIInputStream.h"
14 #include "nsISocketTransport.h"
15 #include "nsIThread.h"
16 #include "nsProxyRelease.h"
17 #include "nsSocketTransportService2.h"
18 #include "nsThreadUtils.h"
19 #include "nsURLHelper.h"
21 using mozilla::AutoSafeJSContext;
22 using mozilla::dom::Sequence;
24 namespace mozilla {
25 namespace net {
27 class SocketData
28 : public nsISupports
29 {
30 public:
31 NS_DECL_THREADSAFE_ISUPPORTS
33 SocketData()
34 {
35 mTotalSent = 0;
36 mTotalRecv = 0;
37 mThread = nullptr;
38 }
40 virtual ~SocketData()
41 {
42 }
44 uint64_t mTotalSent;
45 uint64_t mTotalRecv;
46 nsTArray<SocketInfo> mData;
47 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
48 nsIThread *mThread;
49 };
51 NS_IMPL_ISUPPORTS0(SocketData)
54 class HttpData
55 : public nsISupports
56 {
57 public:
58 NS_DECL_THREADSAFE_ISUPPORTS
60 HttpData()
61 {
62 mThread = nullptr;
63 }
65 virtual ~HttpData()
66 {
67 }
69 nsTArray<HttpRetParams> mData;
70 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
71 nsIThread *mThread;
72 };
74 NS_IMPL_ISUPPORTS0(HttpData)
77 class WebSocketRequest
78 : public nsISupports
79 {
80 public:
81 NS_DECL_THREADSAFE_ISUPPORTS
83 WebSocketRequest()
84 {
85 mThread = nullptr;
86 }
88 virtual ~WebSocketRequest()
89 {
90 }
92 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
93 nsIThread *mThread;
94 };
96 NS_IMPL_ISUPPORTS0(WebSocketRequest)
99 class DnsData
100 : public nsISupports
101 {
102 public:
103 NS_DECL_THREADSAFE_ISUPPORTS
105 DnsData()
106 {
107 mThread = nullptr;
108 }
110 virtual ~DnsData()
111 {
112 }
114 nsTArray<DNSCacheEntries> mData;
115 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
116 nsIThread *mThread;
117 };
119 NS_IMPL_ISUPPORTS0(DnsData)
122 class ConnectionData
123 : public nsITransportEventSink
124 , public nsITimerCallback
125 {
126 public:
127 NS_DECL_THREADSAFE_ISUPPORTS
128 NS_DECL_NSITRANSPORTEVENTSINK
129 NS_DECL_NSITIMERCALLBACK
131 void StartTimer(uint32_t aTimeout);
132 void StopTimer();
134 ConnectionData(Dashboard *target)
135 {
136 mThread = nullptr;
137 mDashboard = target;
138 }
140 virtual ~ConnectionData()
141 {
142 if (mTimer) {
143 mTimer->Cancel();
144 }
145 }
147 nsCOMPtr<nsISocketTransport> mSocket;
148 nsCOMPtr<nsIInputStream> mStreamIn;
149 nsCOMPtr<nsITimer> mTimer;
150 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
151 nsIThread *mThread;
152 Dashboard *mDashboard;
154 nsCString mHost;
155 uint32_t mPort;
156 const char *mProtocol;
157 uint32_t mTimeout;
159 nsString mStatus;
160 };
162 NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback)
164 NS_IMETHODIMP
165 ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
166 uint64_t aProgress, uint64_t aProgressMax)
167 {
168 if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
169 StopTimer();
170 }
172 CopyASCIItoUTF16(Dashboard::GetErrorString(aStatus), mStatus);
173 nsCOMPtr<nsIRunnable> event =
174 NS_NewRunnableMethodWithArg<nsRefPtr<ConnectionData> >
175 (mDashboard, &Dashboard::GetConnectionStatus, this);
176 mThread->Dispatch(event, NS_DISPATCH_NORMAL);
178 return NS_OK;
179 }
181 NS_IMETHODIMP
182 ConnectionData::Notify(nsITimer *aTimer)
183 {
184 MOZ_ASSERT(aTimer == mTimer);
186 if (mSocket) {
187 mSocket->Close(NS_ERROR_ABORT);
188 mSocket = nullptr;
189 mStreamIn = nullptr;
190 }
192 mTimer = nullptr;
194 mStatus.Assign(NS_LITERAL_STRING("NS_ERROR_NET_TIMEOUT"));
195 nsCOMPtr<nsIRunnable> event =
196 NS_NewRunnableMethodWithArg<nsRefPtr<ConnectionData> >
197 (mDashboard, &Dashboard::GetConnectionStatus, this);
198 mThread->Dispatch(event, NS_DISPATCH_NORMAL);
200 return NS_OK;
201 }
203 void
204 ConnectionData::StartTimer(uint32_t aTimeout)
205 {
206 if (!mTimer) {
207 mTimer = do_CreateInstance("@mozilla.org/timer;1");
208 }
210 mTimer->InitWithCallback(this, aTimeout * 1000,
211 nsITimer::TYPE_ONE_SHOT);
212 }
214 void
215 ConnectionData::StopTimer()
216 {
217 if (mTimer) {
218 mTimer->Cancel();
219 mTimer = nullptr;
220 }
221 }
224 class LookupHelper;
226 class LookupArgument
227 : public nsISupports
228 {
229 public:
230 NS_DECL_THREADSAFE_ISUPPORTS
232 LookupArgument(nsIDNSRecord *aRecord, LookupHelper *aHelper)
233 {
234 mRecord = aRecord;
235 mHelper = aHelper;
236 }
238 virtual ~LookupArgument()
239 {
240 }
242 nsCOMPtr<nsIDNSRecord> mRecord;
243 nsRefPtr<LookupHelper> mHelper;
244 };
246 NS_IMPL_ISUPPORTS0(LookupArgument)
249 class LookupHelper
250 : public nsIDNSListener
251 {
252 public:
253 NS_DECL_THREADSAFE_ISUPPORTS
254 NS_DECL_NSIDNSLISTENER
256 LookupHelper() {
257 }
259 virtual ~LookupHelper()
260 {
261 if (mCancel) {
262 mCancel->Cancel(NS_ERROR_ABORT);
263 }
264 }
266 nsresult ConstructAnswer(LookupArgument *aArgument);
267 public:
268 nsCOMPtr<nsICancelable> mCancel;
269 nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
270 nsIThread *mThread;
271 nsresult mStatus;
272 };
274 NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener)
276 NS_IMETHODIMP
277 LookupHelper::OnLookupComplete(nsICancelable *aRequest,
278 nsIDNSRecord *aRecord, nsresult aStatus)
279 {
280 MOZ_ASSERT(aRequest == mCancel);
281 mCancel = nullptr;
282 mStatus = aStatus;
284 nsRefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
285 nsCOMPtr<nsIRunnable> event =
286 NS_NewRunnableMethodWithArg<nsRefPtr<LookupArgument> >(
287 this, &LookupHelper::ConstructAnswer, arg);
288 mThread->Dispatch(event, NS_DISPATCH_NORMAL);
290 return NS_OK;
291 }
293 nsresult
294 LookupHelper::ConstructAnswer(LookupArgument *aArgument)
295 {
297 nsIDNSRecord *aRecord = aArgument->mRecord;
298 AutoSafeJSContext cx;
300 mozilla::dom::DNSLookupDict dict;
301 dict.mAddress.Construct();
303 Sequence<nsString> &addresses = dict.mAddress.Value();
305 if (NS_SUCCEEDED(mStatus)) {
306 dict.mAnswer = true;
307 bool hasMore;
308 aRecord->HasMore(&hasMore);
309 while (hasMore) {
310 nsCString nextAddress;
311 aRecord->GetNextAddrAsString(nextAddress);
312 CopyASCIItoUTF16(nextAddress, *addresses.AppendElement());
313 aRecord->HasMore(&hasMore);
314 }
315 } else {
316 dict.mAnswer = false;
317 CopyASCIItoUTF16(Dashboard::GetErrorString(mStatus), dict.mError);
318 }
320 JS::RootedValue val(cx);
321 if (!dict.ToObject(cx, &val)) {
322 return NS_ERROR_FAILURE;
323 }
325 this->mCallback->OnDashboardDataAvailable(val);
327 return NS_OK;
328 }
330 NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
332 Dashboard::Dashboard()
333 {
334 mEnableLogging = false;
335 }
337 Dashboard::~Dashboard()
338 {
339 }
341 NS_IMETHODIMP
342 Dashboard::RequestSockets(NetDashboardCallback *aCallback)
343 {
344 nsRefPtr<SocketData> socketData = new SocketData();
345 socketData->mCallback =
346 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
347 socketData->mThread = NS_GetCurrentThread();
348 nsCOMPtr<nsIRunnable> event =
349 NS_NewRunnableMethodWithArg<nsRefPtr<SocketData> >
350 (this, &Dashboard::GetSocketsDispatch, socketData);
351 gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
352 return NS_OK;
353 }
355 nsresult
356 Dashboard::GetSocketsDispatch(SocketData *aSocketData)
357 {
358 nsRefPtr<SocketData> socketData = aSocketData;
359 if (gSocketTransportService) {
360 gSocketTransportService->GetSocketConnections(&socketData->mData);
361 socketData->mTotalSent = gSocketTransportService->GetSentBytes();
362 socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes();
363 }
364 nsCOMPtr<nsIRunnable> event =
365 NS_NewRunnableMethodWithArg<nsRefPtr<SocketData> >
366 (this, &Dashboard::GetSockets, socketData);
367 socketData->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
368 return NS_OK;
369 }
371 nsresult
372 Dashboard::GetSockets(SocketData *aSocketData)
373 {
374 nsRefPtr<SocketData> socketData = aSocketData;
375 AutoSafeJSContext cx;
377 mozilla::dom::SocketsDict dict;
378 dict.mSockets.Construct();
379 dict.mSent = 0;
380 dict.mReceived = 0;
382 Sequence<mozilla::dom::SocketElement> &sockets = dict.mSockets.Value();
384 uint32_t length = socketData->mData.Length();
385 if (!sockets.SetCapacity(length)) {
386 JS_ReportOutOfMemory(cx);
387 return NS_ERROR_OUT_OF_MEMORY;
388 }
390 for (uint32_t i = 0; i < socketData->mData.Length(); i++) {
391 mozilla::dom::SocketElement &mSocket = *sockets.AppendElement();
392 CopyASCIItoUTF16(socketData->mData[i].host, mSocket.mHost);
393 mSocket.mPort = socketData->mData[i].port;
394 mSocket.mActive = socketData->mData[i].active;
395 mSocket.mTcp = socketData->mData[i].tcp;
396 mSocket.mSent = (double) socketData->mData[i].sent;
397 mSocket.mReceived = (double) socketData->mData[i].received;
398 dict.mSent += socketData->mData[i].sent;
399 dict.mReceived += socketData->mData[i].received;
400 }
402 dict.mSent += socketData->mTotalSent;
403 dict.mReceived += socketData->mTotalRecv;
404 JS::RootedValue val(cx);
405 if (!dict.ToObject(cx, &val))
406 return NS_ERROR_FAILURE;
407 socketData->mCallback->OnDashboardDataAvailable(val);
409 return NS_OK;
410 }
412 NS_IMETHODIMP
413 Dashboard::RequestHttpConnections(NetDashboardCallback *aCallback)
414 {
415 nsRefPtr<HttpData> httpData = new HttpData();
416 httpData->mCallback =
417 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
418 httpData->mThread = NS_GetCurrentThread();
420 nsCOMPtr<nsIRunnable> event =
421 NS_NewRunnableMethodWithArg<nsRefPtr<HttpData> >
422 (this, &Dashboard::GetHttpDispatch, httpData);
423 gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
424 return NS_OK;
425 }
427 nsresult
428 Dashboard::GetHttpDispatch(HttpData *aHttpData)
429 {
430 nsRefPtr<HttpData> httpData = aHttpData;
431 HttpInfo::GetHttpConnectionData(&httpData->mData);
432 nsCOMPtr<nsIRunnable> event =
433 NS_NewRunnableMethodWithArg<nsRefPtr<HttpData> >
434 (this, &Dashboard::GetHttpConnections, httpData);
435 httpData->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
436 return NS_OK;
437 }
440 nsresult
441 Dashboard::GetHttpConnections(HttpData *aHttpData)
442 {
443 nsRefPtr<HttpData> httpData = aHttpData;
444 AutoSafeJSContext cx;
446 mozilla::dom::HttpConnDict dict;
447 dict.mConnections.Construct();
449 using mozilla::dom::HalfOpenInfoDict;
450 using mozilla::dom::HttpConnectionElement;
451 using mozilla::dom::HttpConnInfo;
452 Sequence<HttpConnectionElement> &connections = dict.mConnections.Value();
454 uint32_t length = httpData->mData.Length();
455 if (!connections.SetCapacity(length)) {
456 JS_ReportOutOfMemory(cx);
457 return NS_ERROR_OUT_OF_MEMORY;
458 }
460 for (uint32_t i = 0; i < httpData->mData.Length(); i++) {
461 HttpConnectionElement &connection = *connections.AppendElement();
463 CopyASCIItoUTF16(httpData->mData[i].host, connection.mHost);
464 connection.mPort = httpData->mData[i].port;
465 connection.mSpdy = httpData->mData[i].spdy;
466 connection.mSsl = httpData->mData[i].ssl;
468 connection.mActive.Construct();
469 connection.mIdle.Construct();
470 connection.mHalfOpens.Construct();
472 Sequence<HttpConnInfo> &active = connection.mActive.Value();
473 Sequence<HttpConnInfo> &idle = connection.mIdle.Value();
474 Sequence<HalfOpenInfoDict> &halfOpens = connection.mHalfOpens.Value();
476 if (!active.SetCapacity(httpData->mData[i].active.Length()) ||
477 !idle.SetCapacity(httpData->mData[i].idle.Length()) ||
478 !halfOpens.SetCapacity(httpData->mData[i].halfOpens.Length())) {
479 JS_ReportOutOfMemory(cx);
480 return NS_ERROR_OUT_OF_MEMORY;
481 }
483 for (uint32_t j = 0; j < httpData->mData[i].active.Length(); j++) {
484 HttpConnInfo &info = *active.AppendElement();
485 info.mRtt = httpData->mData[i].active[j].rtt;
486 info.mTtl = httpData->mData[i].active[j].ttl;
487 info.mProtocolVersion =
488 httpData->mData[i].active[j].protocolVersion;
489 }
491 for (uint32_t j = 0; j < httpData->mData[i].idle.Length(); j++) {
492 HttpConnInfo &info = *idle.AppendElement();
493 info.mRtt = httpData->mData[i].idle[j].rtt;
494 info.mTtl = httpData->mData[i].idle[j].ttl;
495 info.mProtocolVersion = httpData->mData[i].idle[j].protocolVersion;
496 }
498 for (uint32_t j = 0; j < httpData->mData[i].halfOpens.Length(); j++) {
499 HalfOpenInfoDict &info = *halfOpens.AppendElement();
500 info.mSpeculative = httpData->mData[i].halfOpens[j].speculative;
501 }
502 }
504 JS::RootedValue val(cx);
505 if (!dict.ToObject(cx, &val)) {
506 return NS_ERROR_FAILURE;
507 }
509 httpData->mCallback->OnDashboardDataAvailable(val);
511 return NS_OK;
512 }
514 NS_IMETHODIMP
515 Dashboard::GetEnableLogging(bool *value)
516 {
517 *value = mEnableLogging;
518 return NS_OK;
519 }
521 NS_IMETHODIMP
522 Dashboard::SetEnableLogging(const bool value)
523 {
524 mEnableLogging = value;
525 return NS_OK;
526 }
528 NS_IMETHODIMP
529 Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted)
530 {
531 if (mEnableLogging) {
532 mozilla::MutexAutoLock lock(mWs.lock);
533 LogData mData(nsCString(aHost), aSerial, aEncrypted);
534 if (mWs.data.Contains(mData)) {
535 return NS_OK;
536 }
537 if (!mWs.data.AppendElement(mData)) {
538 return NS_ERROR_OUT_OF_MEMORY;
539 }
540 return NS_OK;
541 }
542 return NS_ERROR_FAILURE;
543 }
545 NS_IMETHODIMP
546 Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial)
547 {
548 if (mEnableLogging) {
549 mozilla::MutexAutoLock lock(mWs.lock);
550 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
551 if (index == -1)
552 return NS_ERROR_FAILURE;
553 mWs.data.RemoveElementAt(index);
554 return NS_OK;
555 }
556 return NS_ERROR_FAILURE;
557 }
559 NS_IMETHODIMP
560 Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
561 {
562 if (mEnableLogging) {
563 mozilla::MutexAutoLock lock(mWs.lock);
564 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
565 if (index == -1)
566 return NS_ERROR_FAILURE;
567 mWs.data[index].mMsgSent++;
568 mWs.data[index].mSizeSent += aLength;
569 return NS_OK;
570 }
571 return NS_ERROR_FAILURE;
572 }
574 NS_IMETHODIMP
575 Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
576 {
577 if (mEnableLogging) {
578 mozilla::MutexAutoLock lock(mWs.lock);
579 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
580 if (index == -1)
581 return NS_ERROR_FAILURE;
582 mWs.data[index].mMsgReceived++;
583 mWs.data[index].mSizeReceived += aLength;
584 return NS_OK;
585 }
586 return NS_ERROR_FAILURE;
587 }
589 NS_IMETHODIMP
590 Dashboard::RequestWebsocketConnections(NetDashboardCallback *aCallback)
591 {
592 nsRefPtr<WebSocketRequest> wsRequest = new WebSocketRequest();
593 wsRequest->mCallback =
594 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
595 wsRequest->mThread = NS_GetCurrentThread();
597 nsCOMPtr<nsIRunnable> event =
598 NS_NewRunnableMethodWithArg<nsRefPtr<WebSocketRequest> >
599 (this, &Dashboard::GetWebSocketConnections, wsRequest);
600 wsRequest->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
601 return NS_OK;
602 }
604 nsresult
605 Dashboard::GetWebSocketConnections(WebSocketRequest *aWsRequest)
606 {
607 nsRefPtr<WebSocketRequest> wsRequest = aWsRequest;
608 AutoSafeJSContext cx;
610 mozilla::dom::WebSocketDict dict;
611 dict.mWebsockets.Construct();
612 Sequence<mozilla::dom::WebSocketElement> &websockets =
613 dict.mWebsockets.Value();
615 mozilla::MutexAutoLock lock(mWs.lock);
616 uint32_t length = mWs.data.Length();
617 if (!websockets.SetCapacity(length)) {
618 JS_ReportOutOfMemory(cx);
619 return NS_ERROR_OUT_OF_MEMORY;
620 }
622 for (uint32_t i = 0; i < mWs.data.Length(); i++) {
623 mozilla::dom::WebSocketElement &websocket = *websockets.AppendElement();
624 CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport);
625 websocket.mMsgsent = mWs.data[i].mMsgSent;
626 websocket.mMsgreceived = mWs.data[i].mMsgReceived;
627 websocket.mSentsize = mWs.data[i].mSizeSent;
628 websocket.mReceivedsize = mWs.data[i].mSizeReceived;
629 websocket.mEncrypted = mWs.data[i].mEncrypted;
630 }
632 JS::RootedValue val(cx);
633 if (!dict.ToObject(cx, &val)) {
634 return NS_ERROR_FAILURE;
635 }
636 wsRequest->mCallback->OnDashboardDataAvailable(val);
638 return NS_OK;
639 }
641 NS_IMETHODIMP
642 Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback)
643 {
644 nsRefPtr<DnsData> dnsData = new DnsData();
645 dnsData->mCallback =
646 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
648 nsresult rv;
649 dnsData->mData.Clear();
650 dnsData->mThread = NS_GetCurrentThread();
652 if (!mDnsService) {
653 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
654 if (NS_FAILED(rv)) {
655 return rv;
656 }
657 }
659 nsCOMPtr<nsIRunnable> event =
660 NS_NewRunnableMethodWithArg<nsRefPtr<DnsData> >
661 (this, &Dashboard::GetDnsInfoDispatch, dnsData);
662 gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
663 return NS_OK;
664 }
666 nsresult
667 Dashboard::GetDnsInfoDispatch(DnsData *aDnsData)
668 {
669 nsRefPtr<DnsData> dnsData = aDnsData;
670 if (mDnsService) {
671 mDnsService->GetDNSCacheEntries(&dnsData->mData);
672 }
673 nsCOMPtr<nsIRunnable> event =
674 NS_NewRunnableMethodWithArg<nsRefPtr<DnsData> >
675 (this, &Dashboard::GetDNSCacheEntries, dnsData);
676 dnsData->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
677 return NS_OK;
678 }
680 nsresult
681 Dashboard::GetDNSCacheEntries(DnsData *dnsData)
682 {
683 AutoSafeJSContext cx;
685 mozilla::dom::DNSCacheDict dict;
686 dict.mEntries.Construct();
687 Sequence<mozilla::dom::DnsCacheEntry> &entries = dict.mEntries.Value();
689 uint32_t length = dnsData->mData.Length();
690 if (!entries.SetCapacity(length)) {
691 JS_ReportOutOfMemory(cx);
692 return NS_ERROR_OUT_OF_MEMORY;
693 }
695 for (uint32_t i = 0; i < dnsData->mData.Length(); i++) {
696 mozilla::dom::DnsCacheEntry &entry = *entries.AppendElement();
697 entry.mHostaddr.Construct();
699 Sequence<nsString> &addrs = entry.mHostaddr.Value();
700 if (!addrs.SetCapacity(dnsData->mData[i].hostaddr.Length())) {
701 JS_ReportOutOfMemory(cx);
702 return NS_ERROR_OUT_OF_MEMORY;
703 }
705 CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname);
706 entry.mExpiration = dnsData->mData[i].expiration;
708 for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) {
709 CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j],
710 *addrs.AppendElement());
711 }
713 if (dnsData->mData[i].family == PR_AF_INET6) {
714 CopyASCIItoUTF16("ipv6", entry.mFamily);
715 } else {
716 CopyASCIItoUTF16("ipv4", entry.mFamily);
717 }
718 }
720 JS::RootedValue val(cx);
721 if (!dict.ToObject(cx, &val)) {
722 return NS_ERROR_FAILURE;
723 }
724 dnsData->mCallback->OnDashboardDataAvailable(val);
726 return NS_OK;
727 }
729 NS_IMETHODIMP
730 Dashboard::RequestDNSLookup(const nsACString &aHost,
731 NetDashboardCallback *aCallback)
732 {
733 nsresult rv;
735 if (!mDnsService) {
736 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
737 if (NS_FAILED(rv)) {
738 return rv;
739 }
740 }
742 nsRefPtr<LookupHelper> helper = new LookupHelper();
743 helper->mCallback =
744 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
745 helper->mThread = NS_GetCurrentThread();
746 rv = mDnsService->AsyncResolve(aHost, 0, helper.get(),
747 NS_GetCurrentThread(),
748 getter_AddRefs(helper->mCancel));
749 return rv;
750 }
752 void
753 HttpConnInfo::SetHTTP1ProtocolVersion(uint8_t pv)
754 {
755 switch (pv) {
756 case NS_HTTP_VERSION_0_9:
757 protocolVersion.Assign(NS_LITERAL_STRING("http/0.9"));
758 break;
759 case NS_HTTP_VERSION_1_0:
760 protocolVersion.Assign(NS_LITERAL_STRING("http/1.0"));
761 break;
762 case NS_HTTP_VERSION_1_1:
763 protocolVersion.Assign(NS_LITERAL_STRING("http/1.1"));
764 break;
765 case NS_HTTP_VERSION_2_0:
766 protocolVersion.Assign(NS_LITERAL_STRING("http/2.0"));
767 break;
768 default:
769 protocolVersion.Assign(NS_LITERAL_STRING("unknown protocol version"));
770 }
771 }
773 void
774 HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
775 {
776 if (pv == SPDY_VERSION_3) {
777 protocolVersion.Assign(NS_LITERAL_STRING("spdy/3"));
778 } else if (pv == SPDY_VERSION_31) {
779 protocolVersion.Assign(NS_LITERAL_STRING("spdy/3.1"));
780 } else {
781 MOZ_ASSERT (pv == NS_HTTP2_DRAFT_VERSION);
782 protocolVersion.Assign(NS_LITERAL_STRING(NS_HTTP2_DRAFT_TOKEN));
783 }
784 }
786 NS_IMETHODIMP
787 Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
788 const char *aProtocol, uint32_t aTimeout,
789 NetDashboardCallback *aCallback)
790 {
791 nsresult rv;
792 nsRefPtr<ConnectionData> connectionData = new ConnectionData(this);
793 connectionData->mHost = aHost;
794 connectionData->mPort = aPort;
795 connectionData->mProtocol = aProtocol;
796 connectionData->mTimeout = aTimeout;
798 connectionData->mCallback =
799 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
800 connectionData->mThread = NS_GetCurrentThread();
802 rv = TestNewConnection(connectionData);
803 if (NS_FAILED(rv)) {
804 CopyASCIItoUTF16(GetErrorString(rv), connectionData->mStatus);
805 nsCOMPtr<nsIRunnable> event =
806 NS_NewRunnableMethodWithArg<nsRefPtr<ConnectionData> >
807 (this, &Dashboard::GetConnectionStatus, connectionData);
808 connectionData->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
809 return rv;
810 }
812 return NS_OK;
813 }
815 nsresult
816 Dashboard::GetConnectionStatus(ConnectionData *aConnectionData)
817 {
818 nsRefPtr<ConnectionData> connectionData = aConnectionData;
819 AutoSafeJSContext cx;
821 mozilla::dom::ConnStatusDict dict;
822 dict.mStatus = connectionData->mStatus;
824 JS::RootedValue val(cx);
825 if (!dict.ToObject(cx, &val))
826 return NS_ERROR_FAILURE;
828 connectionData->mCallback->OnDashboardDataAvailable(val);
830 return NS_OK;
831 }
833 nsresult
834 Dashboard::TestNewConnection(ConnectionData *aConnectionData)
835 {
836 nsRefPtr<ConnectionData> connectionData = aConnectionData;
838 nsresult rv;
839 if (!connectionData->mHost.Length() ||
840 !net_IsValidHostName(connectionData->mHost)) {
841 return NS_ERROR_UNKNOWN_HOST;
842 }
844 if (connectionData->mProtocol &&
845 NS_LITERAL_STRING("ssl").EqualsASCII(connectionData->mProtocol)) {
846 rv = gSocketTransportService->CreateTransport(
847 &connectionData->mProtocol, 1, connectionData->mHost,
848 connectionData->mPort, nullptr,
849 getter_AddRefs(connectionData->mSocket));
850 } else {
851 rv = gSocketTransportService->CreateTransport(
852 nullptr, 0, connectionData->mHost,
853 connectionData->mPort, nullptr,
854 getter_AddRefs(connectionData->mSocket));
855 }
856 if (NS_FAILED(rv)) {
857 return rv;
858 }
860 rv = connectionData->mSocket->SetEventSink(connectionData,
861 NS_GetCurrentThread());
862 if (NS_FAILED(rv)) {
863 return rv;
864 }
866 rv = connectionData->mSocket->OpenInputStream(
867 nsITransport::OPEN_BLOCKING, 0, 0,
868 getter_AddRefs(connectionData->mStreamIn));
869 if (NS_FAILED(rv)) {
870 return rv;
871 }
873 connectionData->StartTimer(connectionData->mTimeout);
875 return rv;
876 }
878 typedef struct
879 {
880 nsresult key;
881 const char *error;
882 } ErrorEntry;
884 #undef ERROR
885 #define ERROR(key, val) {key, #key}
887 ErrorEntry errors[] = {
888 #include "ErrorList.h"
889 };
891 ErrorEntry socketTransportStatuses[] = {
892 ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
893 ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
894 ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
895 ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
896 ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
897 ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
898 ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
899 };
900 #undef ERROR
902 const char *
903 Dashboard::GetErrorString(nsresult rv)
904 {
905 int length = sizeof(socketTransportStatuses) / sizeof(ErrorEntry);
906 for (int i = 0;i < length;i++)
907 if (socketTransportStatuses[i].key == rv) {
908 return socketTransportStatuses[i].error;
909 }
911 length = sizeof(errors) / sizeof(ErrorEntry);
912 for (int i = 0;i < length;i++)
913 if (errors[i].key == rv) {
914 return errors[i].error;
915 }
917 return nullptr;
918 }
920 } } // namespace mozilla::net