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 "NetworkWorker.h"
6 #include "NetworkUtils.h"
7 #include <nsThreadUtils.h>
8 #include "mozilla/ModuleUtils.h"
9 #include "mozilla/ClearOnShutdown.h"
10 #include "nsXULAppAPI.h"
11 #include "nsCxPusher.h"
13 #define NS_NETWORKWORKER_CID \
14 { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} }
16 using namespace mozilla;
17 using namespace mozilla::dom;
18 using namespace mozilla::ipc;
20 namespace mozilla {
22 nsCOMPtr<nsIThread> gWorkerThread;
24 // The singleton network worker, to be used on the main thread.
25 StaticRefPtr<NetworkWorker> gNetworkWorker;
27 // The singleton networkutils class, that can be used on any thread.
28 static nsAutoPtr<NetworkUtils> gNetworkUtils;
30 // Runnable used dispatch command result on the main thread.
31 class NetworkResultDispatcher : public nsRunnable
32 {
33 public:
34 NetworkResultDispatcher(const NetworkResultOptions& aResult)
35 {
36 MOZ_ASSERT(!NS_IsMainThread());
38 #define COPY_FIELD(prop) mResult.prop = aResult.prop;
39 COPY_FIELD(mId)
40 COPY_FIELD(mRet)
41 COPY_FIELD(mBroadcast)
42 COPY_FIELD(mTopic)
43 COPY_FIELD(mReason)
44 COPY_FIELD(mResultCode)
45 COPY_FIELD(mResultReason)
46 COPY_FIELD(mError)
47 COPY_FIELD(mRxBytes)
48 COPY_FIELD(mTxBytes)
49 COPY_FIELD(mDate)
50 COPY_FIELD(mEnable)
51 COPY_FIELD(mResult)
52 COPY_FIELD(mSuccess)
53 COPY_FIELD(mCurExternalIfname)
54 COPY_FIELD(mCurInternalIfname)
55 #undef COPY_FIELD
56 }
58 NS_IMETHOD Run()
59 {
60 MOZ_ASSERT(NS_IsMainThread());
62 if (gNetworkWorker) {
63 gNetworkWorker->DispatchNetworkResult(mResult);
64 }
65 return NS_OK;
66 }
67 private:
68 NetworkResultOptions mResult;
69 };
71 // Runnable used dispatch netd command on the worker thread.
72 class NetworkCommandDispatcher : public nsRunnable
73 {
74 public:
75 NetworkCommandDispatcher(const NetworkParams& aParams)
76 : mParams(aParams)
77 {
78 MOZ_ASSERT(NS_IsMainThread());
79 }
81 NS_IMETHOD Run()
82 {
83 MOZ_ASSERT(!NS_IsMainThread());
85 if (gNetworkUtils) {
86 gNetworkUtils->ExecuteCommand(mParams);
87 }
88 return NS_OK;
89 }
90 private:
91 NetworkParams mParams;
92 };
94 // Runnable used dispatch netd result on the worker thread.
95 class NetdEventRunnable : public nsRunnable
96 {
97 public:
98 NetdEventRunnable(NetdCommand* aCommand)
99 : mCommand(aCommand)
100 {
101 MOZ_ASSERT(!NS_IsMainThread());
102 }
104 NS_IMETHOD Run()
105 {
106 MOZ_ASSERT(!NS_IsMainThread());
108 if (gNetworkUtils) {
109 gNetworkUtils->onNetdMessage(mCommand);
110 }
111 return NS_OK;
112 }
114 private:
115 nsAutoPtr<NetdCommand> mCommand;
116 };
118 class NetdMessageConsumer : public NetdConsumer
119 {
120 public:
121 NetdMessageConsumer()
122 {
123 MOZ_ASSERT(NS_IsMainThread());
124 }
126 void MessageReceived(NetdCommand* aCommand)
127 {
128 MOZ_ASSERT(!NS_IsMainThread());
130 nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand);
131 if (gWorkerThread) {
132 gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
133 }
134 }
135 };
137 NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker)
139 NetworkWorker::NetworkWorker()
140 {
141 MOZ_ASSERT(NS_IsMainThread());
142 MOZ_ASSERT(!gNetworkWorker);
143 }
145 NetworkWorker::~NetworkWorker()
146 {
147 MOZ_ASSERT(!gNetworkWorker);
148 MOZ_ASSERT(!mListener);
149 }
151 already_AddRefed<NetworkWorker>
152 NetworkWorker::FactoryCreate()
153 {
154 if (XRE_GetProcessType() != GeckoProcessType_Default) {
155 return nullptr;
156 }
158 MOZ_ASSERT(NS_IsMainThread());
160 if (!gNetworkWorker) {
161 gNetworkWorker = new NetworkWorker();
162 ClearOnShutdown(&gNetworkWorker);
164 gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult);
165 ClearOnShutdown(&gNetworkUtils);
166 }
168 nsRefPtr<NetworkWorker> worker = gNetworkWorker.get();
169 return worker.forget();
170 }
172 NS_IMETHODIMP
173 NetworkWorker::Start(nsINetworkEventListener* aListener)
174 {
175 MOZ_ASSERT(NS_IsMainThread());
176 MOZ_ASSERT(aListener);
178 if (mListener) {
179 return NS_OK;
180 }
182 nsresult rv;
184 rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread));
185 if (NS_FAILED(rv)) {
186 NS_WARNING("Can't create network control thread");
187 return NS_ERROR_FAILURE;
188 }
190 StartNetd(new NetdMessageConsumer());
191 mListener = aListener;
193 return NS_OK;
194 }
196 NS_IMETHODIMP
197 NetworkWorker::Shutdown()
198 {
199 MOZ_ASSERT(NS_IsMainThread());
201 if (!mListener) {
202 return NS_OK;
203 }
205 StopNetd();
207 gWorkerThread->Shutdown();
208 gWorkerThread = nullptr;
210 mListener = nullptr;
211 return NS_OK;
212 }
214 // Receive command from main thread (NetworkService.js).
215 NS_IMETHODIMP
216 NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
217 {
218 MOZ_ASSERT(NS_IsMainThread());
220 NetworkCommandOptions options;
221 if (!options.Init(aCx, aOptions)) {
222 NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand");
223 return NS_ERROR_FAILURE;
224 }
226 // Dispatch the command to the control thread.
227 NetworkParams NetworkParams(options);
228 nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
229 if (gWorkerThread) {
230 gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
231 }
232 return NS_OK;
233 }
235 void
236 NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
237 {
238 MOZ_ASSERT(NS_IsMainThread());
240 mozilla::AutoSafeJSContext cx;
241 JS::RootedValue val(cx);
243 if (!aOptions.ToObject(cx, &val)) {
244 return;
245 }
247 // Call the listener with a JS value.
248 if (mListener) {
249 mListener->OnEvent(val);
250 }
251 }
253 // Callback function from network worker thread to update result on main thread.
254 void
255 NetworkWorker::NotifyResult(NetworkResultOptions& aResult)
256 {
257 MOZ_ASSERT(!NS_IsMainThread());
259 nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult);
260 NS_DispatchToMainThread(runnable);
261 }
263 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker,
264 NetworkWorker::FactoryCreate)
266 NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID);
268 static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = {
269 { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor },
270 { nullptr }
271 };
273 static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = {
274 { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID },
275 { nullptr }
276 };
278 static const mozilla::Module kNetworkWorkerModule = {
279 mozilla::Module::kVersion,
280 kNetworkWorkerCIDs,
281 kNetworkWorkerContracts,
282 nullptr
283 };
285 } // namespace mozilla
287 NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;