dom/wifi/WifiProxyService.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:7f48105f3295
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 "WifiProxyService.h"
6 #include "nsServiceManagerUtils.h"
7 #include "mozilla/ModuleUtils.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "nsXULAppAPI.h"
10 #include "WifiUtils.h"
11 #include "nsCxPusher.h"
12
13 #ifdef MOZ_TASK_TRACER
14 #include "GeckoTaskTracer.h"
15 using namespace mozilla::tasktracer;
16 #endif
17
18 #define NS_WIFIPROXYSERVICE_CID \
19 { 0xc6c9be7e, 0x744f, 0x4222, {0xb2, 0x03, 0xcd, 0x55, 0xdf, 0xc8, 0xbc, 0x12} }
20
21 using namespace mozilla;
22 using namespace mozilla::dom;
23
24 namespace mozilla {
25
26 // The singleton Wifi service, to be used on the main thread.
27 static StaticRefPtr<WifiProxyService> gWifiProxyService;
28
29 // The singleton supplicant class, that can be used on any thread.
30 static nsAutoPtr<WpaSupplicant> gWpaSupplicant;
31
32 // Runnable used dispatch the WaitForEvent result on the main thread.
33 class WifiEventDispatcher : public nsRunnable
34 {
35 public:
36 WifiEventDispatcher(const nsAString& aEvent, const nsACString& aInterface)
37 : mEvent(aEvent)
38 , mInterface(aInterface)
39 {
40 MOZ_ASSERT(!NS_IsMainThread());
41 }
42
43 NS_IMETHOD Run()
44 {
45 MOZ_ASSERT(NS_IsMainThread());
46 gWifiProxyService->DispatchWifiEvent(mEvent, mInterface);
47 return NS_OK;
48 }
49
50 private:
51 nsString mEvent;
52 nsCString mInterface;
53 };
54
55 // Runnable used to call WaitForEvent on the event thread.
56 class EventRunnable : public nsRunnable
57 {
58 public:
59 EventRunnable(const nsACString& aInterface)
60 : mInterface(aInterface)
61 {
62 MOZ_ASSERT(NS_IsMainThread());
63 }
64
65 NS_IMETHOD Run()
66 {
67 MOZ_ASSERT(!NS_IsMainThread());
68 nsAutoString event;
69 gWpaSupplicant->WaitForEvent(event, mInterface);
70 if (!event.IsEmpty()) {
71 #ifdef MOZ_TASK_TRACER
72 // Make wifi initialization events to be the source events of TaskTracer,
73 // and originate the rest correlation tasks from here.
74 AutoSourceEvent taskTracerEvent(SourceEventType::WIFI);
75 AddLabel("%s %s", mInterface.get(), NS_ConvertUTF16toUTF8(event).get());
76 #endif
77 nsCOMPtr<nsIRunnable> runnable = new WifiEventDispatcher(event, mInterface);
78 NS_DispatchToMainThread(runnable);
79 }
80 return NS_OK;
81 }
82
83 private:
84 nsCString mInterface;
85 };
86
87 // Runnable used dispatch the Command result on the main thread.
88 class WifiResultDispatcher : public nsRunnable
89 {
90 public:
91 WifiResultDispatcher(WifiResultOptions& aResult, const nsACString& aInterface)
92 : mInterface(aInterface)
93 {
94 MOZ_ASSERT(!NS_IsMainThread());
95
96 // XXX: is there a better way to copy webidl dictionnaries?
97 // the copy constructor is private.
98 #define COPY_FIELD(prop) mResult.prop = aResult.prop;
99
100 COPY_FIELD(mId)
101 COPY_FIELD(mStatus)
102 COPY_FIELD(mReply)
103 COPY_FIELD(mRoute)
104 COPY_FIELD(mError)
105 COPY_FIELD(mValue)
106 COPY_FIELD(mIpaddr_str)
107 COPY_FIELD(mGateway_str)
108 COPY_FIELD(mDns1_str)
109 COPY_FIELD(mDns2_str)
110 COPY_FIELD(mMask_str)
111 COPY_FIELD(mServer_str)
112 COPY_FIELD(mVendor_str)
113 COPY_FIELD(mLease)
114 COPY_FIELD(mMask)
115 COPY_FIELD(mIpaddr)
116 COPY_FIELD(mGateway)
117 COPY_FIELD(mDns1)
118 COPY_FIELD(mDns2)
119 COPY_FIELD(mServer)
120
121 #undef COPY_FIELD
122 }
123
124 NS_IMETHOD Run()
125 {
126 MOZ_ASSERT(NS_IsMainThread());
127 gWifiProxyService->DispatchWifiResult(mResult, mInterface);
128 return NS_OK;
129 }
130
131 private:
132 WifiResultOptions mResult;
133 nsCString mInterface;
134 };
135
136 // Runnable used to call SendCommand on the control thread.
137 class ControlRunnable : public nsRunnable
138 {
139 public:
140 ControlRunnable(CommandOptions aOptions, const nsACString& aInterface)
141 : mOptions(aOptions)
142 , mInterface(aInterface)
143 {
144 MOZ_ASSERT(NS_IsMainThread());
145 }
146
147 NS_IMETHOD Run()
148 {
149 WifiResultOptions result;
150 if (gWpaSupplicant->ExecuteCommand(mOptions, result, mInterface)) {
151 nsCOMPtr<nsIRunnable> runnable = new WifiResultDispatcher(result, mInterface);
152 NS_DispatchToMainThread(runnable);
153 }
154 return NS_OK;
155 }
156 private:
157 CommandOptions mOptions;
158 nsCString mInterface;
159 };
160
161 NS_IMPL_ISUPPORTS(WifiProxyService, nsIWifiProxyService)
162
163 WifiProxyService::WifiProxyService()
164 {
165 MOZ_ASSERT(NS_IsMainThread());
166 MOZ_ASSERT(!gWifiProxyService);
167 }
168
169 WifiProxyService::~WifiProxyService()
170 {
171 MOZ_ASSERT(!gWifiProxyService);
172 }
173
174 already_AddRefed<WifiProxyService>
175 WifiProxyService::FactoryCreate()
176 {
177 if (XRE_GetProcessType() != GeckoProcessType_Default) {
178 return nullptr;
179 }
180
181 MOZ_ASSERT(NS_IsMainThread());
182
183 if (!gWifiProxyService) {
184 gWifiProxyService = new WifiProxyService();
185 ClearOnShutdown(&gWifiProxyService);
186
187 gWpaSupplicant = new WpaSupplicant();
188 ClearOnShutdown(&gWpaSupplicant);
189 }
190
191 nsRefPtr<WifiProxyService> service = gWifiProxyService.get();
192 return service.forget();
193 }
194
195 NS_IMETHODIMP
196 WifiProxyService::Start(nsIWifiEventListener* aListener,
197 const char ** aInterfaces,
198 uint32_t aNumOfInterfaces)
199 {
200 MOZ_ASSERT(NS_IsMainThread());
201 MOZ_ASSERT(aListener);
202
203 nsresult rv;
204
205 // Since EventRunnable runs in the manner of blocking, we have to
206 // spin a thread for each interface.
207 // (See the WpaSupplicant::WaitForEvent)
208 mEventThreadList.SetLength(aNumOfInterfaces);
209 for (uint32_t i = 0; i < aNumOfInterfaces; i++) {
210 mEventThreadList[i].mInterface = aInterfaces[i];
211 rv = NS_NewThread(getter_AddRefs(mEventThreadList[i].mThread));
212 if (NS_FAILED(rv)) {
213 NS_WARNING("Can't create wifi event thread");
214 Shutdown();
215 return NS_ERROR_FAILURE;
216 }
217 }
218
219 rv = NS_NewThread(getter_AddRefs(mControlThread));
220 if (NS_FAILED(rv)) {
221 NS_WARNING("Can't create wifi control thread");
222 Shutdown();
223 return NS_ERROR_FAILURE;
224 }
225
226 mListener = aListener;
227
228 return NS_OK;
229 }
230
231 NS_IMETHODIMP
232 WifiProxyService::Shutdown()
233 {
234 MOZ_ASSERT(NS_IsMainThread());
235 for (size_t i = 0; i < mEventThreadList.Length(); i++) {
236 if (mEventThreadList[i].mThread) {
237 mEventThreadList[i].mThread->Shutdown();
238 mEventThreadList[i].mThread = nullptr;
239 }
240 }
241 mEventThreadList.Clear();
242 if (mControlThread) {
243 mControlThread->Shutdown();
244 mControlThread = nullptr;
245 }
246 return NS_OK;
247 }
248
249 NS_IMETHODIMP
250 WifiProxyService::SendCommand(JS::Handle<JS::Value> aOptions,
251 const nsACString& aInterface,
252 JSContext* aCx)
253 {
254 MOZ_ASSERT(NS_IsMainThread());
255 WifiCommandOptions options;
256
257 if (!options.Init(aCx, aOptions)) {
258 NS_WARNING("Bad dictionary passed to WifiProxyService::SendCommand");
259 return NS_ERROR_FAILURE;
260 }
261
262 // Dispatch the command to the control thread.
263 CommandOptions commandOptions(options);
264 nsCOMPtr<nsIRunnable> runnable = new ControlRunnable(commandOptions, aInterface);
265 mControlThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
266 return NS_OK;
267 }
268
269 NS_IMETHODIMP
270 WifiProxyService::WaitForEvent(const nsACString& aInterface)
271 {
272 MOZ_ASSERT(NS_IsMainThread());
273
274 // Dispatch to the event thread which has the given interface name
275 for (size_t i = 0; i < mEventThreadList.Length(); i++) {
276 if (mEventThreadList[i].mInterface.Equals(aInterface)) {
277 nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
278 mEventThreadList[i].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
279 return NS_OK;
280 }
281 }
282
283 return NS_ERROR_FAILURE;
284 }
285
286 void
287 WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
288 {
289 MOZ_ASSERT(NS_IsMainThread());
290
291 mozilla::AutoSafeJSContext cx;
292 JS::Rooted<JS::Value> val(cx);
293
294 if (!aOptions.ToObject(cx, &val)) {
295 return;
296 }
297
298 // Call the listener with a JS value.
299 mListener->OnCommand(val, aInterface);
300 }
301
302 void
303 WifiProxyService::DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface)
304 {
305 MOZ_ASSERT(NS_IsMainThread());
306 nsAutoString event;
307 if (StringBeginsWith(aEvent, NS_LITERAL_STRING("IFNAME"))) {
308 // Jump over IFNAME for gonk-kk.
309 event = Substring(aEvent, aEvent.FindChar(' ') + 1);
310 }
311 else {
312 event = aEvent;
313 }
314 // Call the listener.
315 mListener->OnWaitEvent(event, aInterface);
316 }
317
318 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
319 WifiProxyService::FactoryCreate)
320
321 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
322
323 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
324 { &kNS_WIFIPROXYSERVICE_CID, false, nullptr, WifiProxyServiceConstructor },
325 { nullptr }
326 };
327
328 static const mozilla::Module::ContractIDEntry kWifiProxyServiceContracts[] = {
329 { "@mozilla.org/wifi/service;1", &kNS_WIFIPROXYSERVICE_CID },
330 { nullptr }
331 };
332
333 static const mozilla::Module kWifiProxyServiceModule = {
334 mozilla::Module::kVersion,
335 kWifiProxyServiceCIDs,
336 kWifiProxyServiceContracts,
337 nullptr
338 };
339
340 } // namespace mozilla
341
342 NSMODULE_DEFN(WifiProxyServiceModule) = &kWifiProxyServiceModule;

mercurial