1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/Hal.h"
9 #include "ConnectionWorker.h"
10 #include "mozilla/dom/WorkerPrivate.h"
11 #include "mozilla/dom/WorkerRef.h"
12 #include "mozilla/dom/WorkerRunnable.h"
13 #include "mozilla/dom/WorkerScope.h"
15 namespace mozilla::dom::network
{
17 class ConnectionProxy final
: public hal::NetworkObserver
{
19 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConnectionProxy
)
21 static already_AddRefed
<ConnectionProxy
> Create(
22 WorkerPrivate
* aWorkerPrivate
, ConnectionWorker
* aConnection
) {
23 RefPtr
<ConnectionProxy
> proxy
= new ConnectionProxy(aConnection
);
25 RefPtr
<StrongWorkerRef
> workerRef
= StrongWorkerRef::Create(
26 aWorkerPrivate
, "ConnectionProxy", [proxy
]() { proxy
->Shutdown(); });
27 if (NS_WARN_IF(!workerRef
)) {
31 proxy
->mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
32 return proxy
.forget();
35 ThreadSafeWorkerRef
* WorkerRef() const { return mWorkerRef
; }
37 // For IObserver - main-thread only.
38 void Notify(const hal::NetworkInformation
& aNetworkInfo
) override
;
42 void Update(ConnectionType aType
, bool aIsWifi
, uint32_t aDHCPGateway
) {
43 MOZ_ASSERT(mConnection
);
44 MOZ_ASSERT(IsCurrentThreadRunningWorker());
45 mConnection
->Update(aType
, aIsWifi
, aDHCPGateway
, true);
49 explicit ConnectionProxy(ConnectionWorker
* aConnection
)
50 : mConnection(aConnection
) {}
52 ~ConnectionProxy() = default;
54 // Raw pointer because the ConnectionWorker keeps alive the proxy.
55 // This is touched only on the worker-thread and it's nullified when the
56 // shutdown procedure starts.
57 ConnectionWorker
* mConnection
;
59 RefPtr
<ThreadSafeWorkerRef
> mWorkerRef
;
64 // This class initializes the hal observer on the main-thread.
65 class InitializeRunnable
: public WorkerMainThreadRunnable
{
67 // raw pointer because this is a sync runnable.
68 ConnectionProxy
* mProxy
;
69 hal::NetworkInformation
& mNetworkInfo
;
72 InitializeRunnable(WorkerPrivate
* aWorkerPrivate
, ConnectionProxy
* aProxy
,
73 hal::NetworkInformation
& aNetworkInfo
)
74 : WorkerMainThreadRunnable(aWorkerPrivate
,
75 "ConnectionWorker :: Initialize"_ns
),
77 mNetworkInfo(aNetworkInfo
) {
79 aWorkerPrivate
->AssertIsOnWorkerThread();
82 bool MainThreadRun() override
{
83 MOZ_ASSERT(NS_IsMainThread());
84 hal::RegisterNetworkObserver(mProxy
);
85 hal::GetCurrentNetworkInformation(&mNetworkInfo
);
90 // This class turns down the hal observer on the main-thread.
91 class ShutdownRunnable
: public WorkerMainThreadRunnable
{
93 // raw pointer because this is a sync runnable.
94 ConnectionProxy
* mProxy
;
97 ShutdownRunnable(WorkerPrivate
* aWorkerPrivate
, ConnectionProxy
* aProxy
)
98 : WorkerMainThreadRunnable(aWorkerPrivate
,
99 "ConnectionWorker :: Shutdown"_ns
),
102 aWorkerPrivate
->AssertIsOnWorkerThread();
105 bool MainThreadRun() override
{
106 MOZ_ASSERT(NS_IsMainThread());
107 hal::UnregisterNetworkObserver(mProxy
);
112 class NotifyRunnable
: public WorkerRunnable
{
114 RefPtr
<ConnectionProxy
> mProxy
;
116 const ConnectionType mConnectionType
;
118 const uint32_t mDHCPGateway
;
121 NotifyRunnable(WorkerPrivate
* aWorkerPrivate
, ConnectionProxy
* aProxy
,
122 ConnectionType aType
, bool aIsWifi
, uint32_t aDHCPGateway
)
123 : WorkerRunnable(aWorkerPrivate
),
125 mConnectionType(aType
),
127 mDHCPGateway(aDHCPGateway
) {
129 MOZ_ASSERT(NS_IsMainThread());
132 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
133 aWorkerPrivate
->AssertIsOnWorkerThread();
134 mProxy
->Update(mConnectionType
, mIsWifi
, mDHCPGateway
);
139 } // anonymous namespace
142 already_AddRefed
<ConnectionWorker
> ConnectionWorker::Create(
143 WorkerPrivate
* aWorkerPrivate
, ErrorResult
& aRv
) {
144 bool shouldResistFingerprinting
=
145 aWorkerPrivate
->GlobalScope()->ShouldResistFingerprinting();
146 RefPtr
<ConnectionWorker
> c
= new ConnectionWorker(shouldResistFingerprinting
);
147 c
->mProxy
= ConnectionProxy::Create(aWorkerPrivate
, c
);
149 aRv
.ThrowTypeError("The Worker thread is shutting down.");
153 hal::NetworkInformation networkInfo
;
154 RefPtr
<InitializeRunnable
> runnable
=
155 new InitializeRunnable(aWorkerPrivate
, c
->mProxy
, networkInfo
);
157 runnable
->Dispatch(Canceling
, aRv
);
158 if (NS_WARN_IF(aRv
.Failed())) {
162 c
->Update(static_cast<ConnectionType
>(networkInfo
.type()),
163 networkInfo
.isWifi(), networkInfo
.dhcpGateway(), false);
167 ConnectionWorker::ConnectionWorker(bool aShouldResistFingerprinting
)
168 : Connection(nullptr, aShouldResistFingerprinting
) {
169 MOZ_ASSERT(IsCurrentThreadRunningWorker());
172 ConnectionWorker::~ConnectionWorker() { Shutdown(); }
174 void ConnectionWorker::ShutdownInternal() {
175 MOZ_ASSERT(IsCurrentThreadRunningWorker());
179 void ConnectionProxy::Notify(const hal::NetworkInformation
& aNetworkInfo
) {
180 MOZ_ASSERT(NS_IsMainThread());
182 RefPtr
<NotifyRunnable
> runnable
=
183 new NotifyRunnable(mWorkerRef
->Private(), this,
184 static_cast<ConnectionType
>(aNetworkInfo
.type()),
185 aNetworkInfo
.isWifi(), aNetworkInfo
.dhcpGateway());
186 runnable
->Dispatch();
189 void ConnectionProxy::Shutdown() {
190 MOZ_ASSERT(IsCurrentThreadRunningWorker());
192 // Already shut down.
197 mConnection
= nullptr;
199 RefPtr
<ShutdownRunnable
> runnable
=
200 new ShutdownRunnable(mWorkerRef
->Private(), this);
203 // This runnable _must_ be executed.
204 runnable
->Dispatch(Killing
, rv
);
205 if (NS_WARN_IF(rv
.Failed())) {
206 rv
.SuppressException();
209 mWorkerRef
= nullptr;
212 } // namespace mozilla::dom::network