|
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/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" |
|
20 |
|
21 using mozilla::AutoSafeJSContext; |
|
22 using mozilla::dom::Sequence; |
|
23 |
|
24 namespace mozilla { |
|
25 namespace net { |
|
26 |
|
27 class SocketData |
|
28 : public nsISupports |
|
29 { |
|
30 public: |
|
31 NS_DECL_THREADSAFE_ISUPPORTS |
|
32 |
|
33 SocketData() |
|
34 { |
|
35 mTotalSent = 0; |
|
36 mTotalRecv = 0; |
|
37 mThread = nullptr; |
|
38 } |
|
39 |
|
40 virtual ~SocketData() |
|
41 { |
|
42 } |
|
43 |
|
44 uint64_t mTotalSent; |
|
45 uint64_t mTotalRecv; |
|
46 nsTArray<SocketInfo> mData; |
|
47 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
48 nsIThread *mThread; |
|
49 }; |
|
50 |
|
51 NS_IMPL_ISUPPORTS0(SocketData) |
|
52 |
|
53 |
|
54 class HttpData |
|
55 : public nsISupports |
|
56 { |
|
57 public: |
|
58 NS_DECL_THREADSAFE_ISUPPORTS |
|
59 |
|
60 HttpData() |
|
61 { |
|
62 mThread = nullptr; |
|
63 } |
|
64 |
|
65 virtual ~HttpData() |
|
66 { |
|
67 } |
|
68 |
|
69 nsTArray<HttpRetParams> mData; |
|
70 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
71 nsIThread *mThread; |
|
72 }; |
|
73 |
|
74 NS_IMPL_ISUPPORTS0(HttpData) |
|
75 |
|
76 |
|
77 class WebSocketRequest |
|
78 : public nsISupports |
|
79 { |
|
80 public: |
|
81 NS_DECL_THREADSAFE_ISUPPORTS |
|
82 |
|
83 WebSocketRequest() |
|
84 { |
|
85 mThread = nullptr; |
|
86 } |
|
87 |
|
88 virtual ~WebSocketRequest() |
|
89 { |
|
90 } |
|
91 |
|
92 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
93 nsIThread *mThread; |
|
94 }; |
|
95 |
|
96 NS_IMPL_ISUPPORTS0(WebSocketRequest) |
|
97 |
|
98 |
|
99 class DnsData |
|
100 : public nsISupports |
|
101 { |
|
102 public: |
|
103 NS_DECL_THREADSAFE_ISUPPORTS |
|
104 |
|
105 DnsData() |
|
106 { |
|
107 mThread = nullptr; |
|
108 } |
|
109 |
|
110 virtual ~DnsData() |
|
111 { |
|
112 } |
|
113 |
|
114 nsTArray<DNSCacheEntries> mData; |
|
115 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
116 nsIThread *mThread; |
|
117 }; |
|
118 |
|
119 NS_IMPL_ISUPPORTS0(DnsData) |
|
120 |
|
121 |
|
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 |
|
130 |
|
131 void StartTimer(uint32_t aTimeout); |
|
132 void StopTimer(); |
|
133 |
|
134 ConnectionData(Dashboard *target) |
|
135 { |
|
136 mThread = nullptr; |
|
137 mDashboard = target; |
|
138 } |
|
139 |
|
140 virtual ~ConnectionData() |
|
141 { |
|
142 if (mTimer) { |
|
143 mTimer->Cancel(); |
|
144 } |
|
145 } |
|
146 |
|
147 nsCOMPtr<nsISocketTransport> mSocket; |
|
148 nsCOMPtr<nsIInputStream> mStreamIn; |
|
149 nsCOMPtr<nsITimer> mTimer; |
|
150 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
151 nsIThread *mThread; |
|
152 Dashboard *mDashboard; |
|
153 |
|
154 nsCString mHost; |
|
155 uint32_t mPort; |
|
156 const char *mProtocol; |
|
157 uint32_t mTimeout; |
|
158 |
|
159 nsString mStatus; |
|
160 }; |
|
161 |
|
162 NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback) |
|
163 |
|
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 } |
|
171 |
|
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); |
|
177 |
|
178 return NS_OK; |
|
179 } |
|
180 |
|
181 NS_IMETHODIMP |
|
182 ConnectionData::Notify(nsITimer *aTimer) |
|
183 { |
|
184 MOZ_ASSERT(aTimer == mTimer); |
|
185 |
|
186 if (mSocket) { |
|
187 mSocket->Close(NS_ERROR_ABORT); |
|
188 mSocket = nullptr; |
|
189 mStreamIn = nullptr; |
|
190 } |
|
191 |
|
192 mTimer = nullptr; |
|
193 |
|
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); |
|
199 |
|
200 return NS_OK; |
|
201 } |
|
202 |
|
203 void |
|
204 ConnectionData::StartTimer(uint32_t aTimeout) |
|
205 { |
|
206 if (!mTimer) { |
|
207 mTimer = do_CreateInstance("@mozilla.org/timer;1"); |
|
208 } |
|
209 |
|
210 mTimer->InitWithCallback(this, aTimeout * 1000, |
|
211 nsITimer::TYPE_ONE_SHOT); |
|
212 } |
|
213 |
|
214 void |
|
215 ConnectionData::StopTimer() |
|
216 { |
|
217 if (mTimer) { |
|
218 mTimer->Cancel(); |
|
219 mTimer = nullptr; |
|
220 } |
|
221 } |
|
222 |
|
223 |
|
224 class LookupHelper; |
|
225 |
|
226 class LookupArgument |
|
227 : public nsISupports |
|
228 { |
|
229 public: |
|
230 NS_DECL_THREADSAFE_ISUPPORTS |
|
231 |
|
232 LookupArgument(nsIDNSRecord *aRecord, LookupHelper *aHelper) |
|
233 { |
|
234 mRecord = aRecord; |
|
235 mHelper = aHelper; |
|
236 } |
|
237 |
|
238 virtual ~LookupArgument() |
|
239 { |
|
240 } |
|
241 |
|
242 nsCOMPtr<nsIDNSRecord> mRecord; |
|
243 nsRefPtr<LookupHelper> mHelper; |
|
244 }; |
|
245 |
|
246 NS_IMPL_ISUPPORTS0(LookupArgument) |
|
247 |
|
248 |
|
249 class LookupHelper |
|
250 : public nsIDNSListener |
|
251 { |
|
252 public: |
|
253 NS_DECL_THREADSAFE_ISUPPORTS |
|
254 NS_DECL_NSIDNSLISTENER |
|
255 |
|
256 LookupHelper() { |
|
257 } |
|
258 |
|
259 virtual ~LookupHelper() |
|
260 { |
|
261 if (mCancel) { |
|
262 mCancel->Cancel(NS_ERROR_ABORT); |
|
263 } |
|
264 } |
|
265 |
|
266 nsresult ConstructAnswer(LookupArgument *aArgument); |
|
267 public: |
|
268 nsCOMPtr<nsICancelable> mCancel; |
|
269 nsMainThreadPtrHandle<NetDashboardCallback> mCallback; |
|
270 nsIThread *mThread; |
|
271 nsresult mStatus; |
|
272 }; |
|
273 |
|
274 NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener) |
|
275 |
|
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; |
|
283 |
|
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); |
|
289 |
|
290 return NS_OK; |
|
291 } |
|
292 |
|
293 nsresult |
|
294 LookupHelper::ConstructAnswer(LookupArgument *aArgument) |
|
295 { |
|
296 |
|
297 nsIDNSRecord *aRecord = aArgument->mRecord; |
|
298 AutoSafeJSContext cx; |
|
299 |
|
300 mozilla::dom::DNSLookupDict dict; |
|
301 dict.mAddress.Construct(); |
|
302 |
|
303 Sequence<nsString> &addresses = dict.mAddress.Value(); |
|
304 |
|
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 } |
|
319 |
|
320 JS::RootedValue val(cx); |
|
321 if (!dict.ToObject(cx, &val)) { |
|
322 return NS_ERROR_FAILURE; |
|
323 } |
|
324 |
|
325 this->mCallback->OnDashboardDataAvailable(val); |
|
326 |
|
327 return NS_OK; |
|
328 } |
|
329 |
|
330 NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier) |
|
331 |
|
332 Dashboard::Dashboard() |
|
333 { |
|
334 mEnableLogging = false; |
|
335 } |
|
336 |
|
337 Dashboard::~Dashboard() |
|
338 { |
|
339 } |
|
340 |
|
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 } |
|
354 |
|
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 } |
|
370 |
|
371 nsresult |
|
372 Dashboard::GetSockets(SocketData *aSocketData) |
|
373 { |
|
374 nsRefPtr<SocketData> socketData = aSocketData; |
|
375 AutoSafeJSContext cx; |
|
376 |
|
377 mozilla::dom::SocketsDict dict; |
|
378 dict.mSockets.Construct(); |
|
379 dict.mSent = 0; |
|
380 dict.mReceived = 0; |
|
381 |
|
382 Sequence<mozilla::dom::SocketElement> &sockets = dict.mSockets.Value(); |
|
383 |
|
384 uint32_t length = socketData->mData.Length(); |
|
385 if (!sockets.SetCapacity(length)) { |
|
386 JS_ReportOutOfMemory(cx); |
|
387 return NS_ERROR_OUT_OF_MEMORY; |
|
388 } |
|
389 |
|
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 } |
|
401 |
|
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); |
|
408 |
|
409 return NS_OK; |
|
410 } |
|
411 |
|
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(); |
|
419 |
|
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 } |
|
426 |
|
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 } |
|
438 |
|
439 |
|
440 nsresult |
|
441 Dashboard::GetHttpConnections(HttpData *aHttpData) |
|
442 { |
|
443 nsRefPtr<HttpData> httpData = aHttpData; |
|
444 AutoSafeJSContext cx; |
|
445 |
|
446 mozilla::dom::HttpConnDict dict; |
|
447 dict.mConnections.Construct(); |
|
448 |
|
449 using mozilla::dom::HalfOpenInfoDict; |
|
450 using mozilla::dom::HttpConnectionElement; |
|
451 using mozilla::dom::HttpConnInfo; |
|
452 Sequence<HttpConnectionElement> &connections = dict.mConnections.Value(); |
|
453 |
|
454 uint32_t length = httpData->mData.Length(); |
|
455 if (!connections.SetCapacity(length)) { |
|
456 JS_ReportOutOfMemory(cx); |
|
457 return NS_ERROR_OUT_OF_MEMORY; |
|
458 } |
|
459 |
|
460 for (uint32_t i = 0; i < httpData->mData.Length(); i++) { |
|
461 HttpConnectionElement &connection = *connections.AppendElement(); |
|
462 |
|
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; |
|
467 |
|
468 connection.mActive.Construct(); |
|
469 connection.mIdle.Construct(); |
|
470 connection.mHalfOpens.Construct(); |
|
471 |
|
472 Sequence<HttpConnInfo> &active = connection.mActive.Value(); |
|
473 Sequence<HttpConnInfo> &idle = connection.mIdle.Value(); |
|
474 Sequence<HalfOpenInfoDict> &halfOpens = connection.mHalfOpens.Value(); |
|
475 |
|
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 } |
|
482 |
|
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 } |
|
490 |
|
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 } |
|
497 |
|
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 } |
|
503 |
|
504 JS::RootedValue val(cx); |
|
505 if (!dict.ToObject(cx, &val)) { |
|
506 return NS_ERROR_FAILURE; |
|
507 } |
|
508 |
|
509 httpData->mCallback->OnDashboardDataAvailable(val); |
|
510 |
|
511 return NS_OK; |
|
512 } |
|
513 |
|
514 NS_IMETHODIMP |
|
515 Dashboard::GetEnableLogging(bool *value) |
|
516 { |
|
517 *value = mEnableLogging; |
|
518 return NS_OK; |
|
519 } |
|
520 |
|
521 NS_IMETHODIMP |
|
522 Dashboard::SetEnableLogging(const bool value) |
|
523 { |
|
524 mEnableLogging = value; |
|
525 return NS_OK; |
|
526 } |
|
527 |
|
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 } |
|
544 |
|
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 } |
|
558 |
|
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 } |
|
573 |
|
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 } |
|
588 |
|
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(); |
|
596 |
|
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 } |
|
603 |
|
604 nsresult |
|
605 Dashboard::GetWebSocketConnections(WebSocketRequest *aWsRequest) |
|
606 { |
|
607 nsRefPtr<WebSocketRequest> wsRequest = aWsRequest; |
|
608 AutoSafeJSContext cx; |
|
609 |
|
610 mozilla::dom::WebSocketDict dict; |
|
611 dict.mWebsockets.Construct(); |
|
612 Sequence<mozilla::dom::WebSocketElement> &websockets = |
|
613 dict.mWebsockets.Value(); |
|
614 |
|
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 } |
|
621 |
|
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 } |
|
631 |
|
632 JS::RootedValue val(cx); |
|
633 if (!dict.ToObject(cx, &val)) { |
|
634 return NS_ERROR_FAILURE; |
|
635 } |
|
636 wsRequest->mCallback->OnDashboardDataAvailable(val); |
|
637 |
|
638 return NS_OK; |
|
639 } |
|
640 |
|
641 NS_IMETHODIMP |
|
642 Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback) |
|
643 { |
|
644 nsRefPtr<DnsData> dnsData = new DnsData(); |
|
645 dnsData->mCallback = |
|
646 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true); |
|
647 |
|
648 nsresult rv; |
|
649 dnsData->mData.Clear(); |
|
650 dnsData->mThread = NS_GetCurrentThread(); |
|
651 |
|
652 if (!mDnsService) { |
|
653 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv); |
|
654 if (NS_FAILED(rv)) { |
|
655 return rv; |
|
656 } |
|
657 } |
|
658 |
|
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 } |
|
665 |
|
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 } |
|
679 |
|
680 nsresult |
|
681 Dashboard::GetDNSCacheEntries(DnsData *dnsData) |
|
682 { |
|
683 AutoSafeJSContext cx; |
|
684 |
|
685 mozilla::dom::DNSCacheDict dict; |
|
686 dict.mEntries.Construct(); |
|
687 Sequence<mozilla::dom::DnsCacheEntry> &entries = dict.mEntries.Value(); |
|
688 |
|
689 uint32_t length = dnsData->mData.Length(); |
|
690 if (!entries.SetCapacity(length)) { |
|
691 JS_ReportOutOfMemory(cx); |
|
692 return NS_ERROR_OUT_OF_MEMORY; |
|
693 } |
|
694 |
|
695 for (uint32_t i = 0; i < dnsData->mData.Length(); i++) { |
|
696 mozilla::dom::DnsCacheEntry &entry = *entries.AppendElement(); |
|
697 entry.mHostaddr.Construct(); |
|
698 |
|
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 } |
|
704 |
|
705 CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname); |
|
706 entry.mExpiration = dnsData->mData[i].expiration; |
|
707 |
|
708 for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) { |
|
709 CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], |
|
710 *addrs.AppendElement()); |
|
711 } |
|
712 |
|
713 if (dnsData->mData[i].family == PR_AF_INET6) { |
|
714 CopyASCIItoUTF16("ipv6", entry.mFamily); |
|
715 } else { |
|
716 CopyASCIItoUTF16("ipv4", entry.mFamily); |
|
717 } |
|
718 } |
|
719 |
|
720 JS::RootedValue val(cx); |
|
721 if (!dict.ToObject(cx, &val)) { |
|
722 return NS_ERROR_FAILURE; |
|
723 } |
|
724 dnsData->mCallback->OnDashboardDataAvailable(val); |
|
725 |
|
726 return NS_OK; |
|
727 } |
|
728 |
|
729 NS_IMETHODIMP |
|
730 Dashboard::RequestDNSLookup(const nsACString &aHost, |
|
731 NetDashboardCallback *aCallback) |
|
732 { |
|
733 nsresult rv; |
|
734 |
|
735 if (!mDnsService) { |
|
736 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv); |
|
737 if (NS_FAILED(rv)) { |
|
738 return rv; |
|
739 } |
|
740 } |
|
741 |
|
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 } |
|
751 |
|
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 } |
|
772 |
|
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 } |
|
785 |
|
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; |
|
797 |
|
798 connectionData->mCallback = |
|
799 new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true); |
|
800 connectionData->mThread = NS_GetCurrentThread(); |
|
801 |
|
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 } |
|
811 |
|
812 return NS_OK; |
|
813 } |
|
814 |
|
815 nsresult |
|
816 Dashboard::GetConnectionStatus(ConnectionData *aConnectionData) |
|
817 { |
|
818 nsRefPtr<ConnectionData> connectionData = aConnectionData; |
|
819 AutoSafeJSContext cx; |
|
820 |
|
821 mozilla::dom::ConnStatusDict dict; |
|
822 dict.mStatus = connectionData->mStatus; |
|
823 |
|
824 JS::RootedValue val(cx); |
|
825 if (!dict.ToObject(cx, &val)) |
|
826 return NS_ERROR_FAILURE; |
|
827 |
|
828 connectionData->mCallback->OnDashboardDataAvailable(val); |
|
829 |
|
830 return NS_OK; |
|
831 } |
|
832 |
|
833 nsresult |
|
834 Dashboard::TestNewConnection(ConnectionData *aConnectionData) |
|
835 { |
|
836 nsRefPtr<ConnectionData> connectionData = aConnectionData; |
|
837 |
|
838 nsresult rv; |
|
839 if (!connectionData->mHost.Length() || |
|
840 !net_IsValidHostName(connectionData->mHost)) { |
|
841 return NS_ERROR_UNKNOWN_HOST; |
|
842 } |
|
843 |
|
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 } |
|
859 |
|
860 rv = connectionData->mSocket->SetEventSink(connectionData, |
|
861 NS_GetCurrentThread()); |
|
862 if (NS_FAILED(rv)) { |
|
863 return rv; |
|
864 } |
|
865 |
|
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 } |
|
872 |
|
873 connectionData->StartTimer(connectionData->mTimeout); |
|
874 |
|
875 return rv; |
|
876 } |
|
877 |
|
878 typedef struct |
|
879 { |
|
880 nsresult key; |
|
881 const char *error; |
|
882 } ErrorEntry; |
|
883 |
|
884 #undef ERROR |
|
885 #define ERROR(key, val) {key, #key} |
|
886 |
|
887 ErrorEntry errors[] = { |
|
888 #include "ErrorList.h" |
|
889 }; |
|
890 |
|
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 |
|
901 |
|
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 } |
|
910 |
|
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 } |
|
916 |
|
917 return nullptr; |
|
918 } |
|
919 |
|
920 } } // namespace mozilla::net |