dom/wifi/WifiProxyService.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "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"
    13 #ifdef MOZ_TASK_TRACER
    14 #include "GeckoTaskTracer.h"
    15 using namespace mozilla::tasktracer;
    16 #endif
    18 #define NS_WIFIPROXYSERVICE_CID \
    19   { 0xc6c9be7e, 0x744f, 0x4222, {0xb2, 0x03, 0xcd, 0x55, 0xdf, 0xc8, 0xbc, 0x12} }
    21 using namespace mozilla;
    22 using namespace mozilla::dom;
    24 namespace mozilla {
    26 // The singleton Wifi service, to be used on the main thread.
    27 static StaticRefPtr<WifiProxyService> gWifiProxyService;
    29 // The singleton supplicant class, that can be used on any thread.
    30 static nsAutoPtr<WpaSupplicant> gWpaSupplicant;
    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   }
    43   NS_IMETHOD Run()
    44   {
    45     MOZ_ASSERT(NS_IsMainThread());
    46     gWifiProxyService->DispatchWifiEvent(mEvent, mInterface);
    47     return NS_OK;
    48   }
    50 private:
    51   nsString mEvent;
    52   nsCString mInterface;
    53 };
    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   }
    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   }
    83 private:
    84   nsCString mInterface;
    85 };
    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());
    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;
   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)
   121 #undef COPY_FIELD
   122   }
   124   NS_IMETHOD Run()
   125   {
   126     MOZ_ASSERT(NS_IsMainThread());
   127     gWifiProxyService->DispatchWifiResult(mResult, mInterface);
   128     return NS_OK;
   129   }
   131 private:
   132   WifiResultOptions mResult;
   133   nsCString mInterface;
   134 };
   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   }
   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 };
   161 NS_IMPL_ISUPPORTS(WifiProxyService, nsIWifiProxyService)
   163 WifiProxyService::WifiProxyService()
   164 {
   165   MOZ_ASSERT(NS_IsMainThread());
   166   MOZ_ASSERT(!gWifiProxyService);
   167 }
   169 WifiProxyService::~WifiProxyService()
   170 {
   171   MOZ_ASSERT(!gWifiProxyService);
   172 }
   174 already_AddRefed<WifiProxyService>
   175 WifiProxyService::FactoryCreate()
   176 {
   177   if (XRE_GetProcessType() != GeckoProcessType_Default) {
   178     return nullptr;
   179   }
   181   MOZ_ASSERT(NS_IsMainThread());
   183   if (!gWifiProxyService) {
   184     gWifiProxyService = new WifiProxyService();
   185     ClearOnShutdown(&gWifiProxyService);
   187     gWpaSupplicant = new WpaSupplicant();
   188     ClearOnShutdown(&gWpaSupplicant);
   189   }
   191   nsRefPtr<WifiProxyService> service = gWifiProxyService.get();
   192   return service.forget();
   193 }
   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);
   203   nsresult rv;
   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   }
   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   }
   226   mListener = aListener;
   228   return NS_OK;
   229 }
   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 }
   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;
   257   if (!options.Init(aCx, aOptions)) {
   258     NS_WARNING("Bad dictionary passed to WifiProxyService::SendCommand");
   259     return NS_ERROR_FAILURE;
   260   }
   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 }
   269 NS_IMETHODIMP
   270 WifiProxyService::WaitForEvent(const nsACString& aInterface)
   271 {
   272   MOZ_ASSERT(NS_IsMainThread());
   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   }
   283   return NS_ERROR_FAILURE;
   284 }
   286 void
   287 WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
   288 {
   289   MOZ_ASSERT(NS_IsMainThread());
   291   mozilla::AutoSafeJSContext cx;
   292   JS::Rooted<JS::Value> val(cx);
   294   if (!aOptions.ToObject(cx, &val)) {
   295     return;
   296   }
   298   // Call the listener with a JS value.
   299   mListener->OnCommand(val, aInterface);
   300 }
   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 }
   318 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
   319                                          WifiProxyService::FactoryCreate)
   321 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
   323 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
   324   { &kNS_WIFIPROXYSERVICE_CID, false, nullptr, WifiProxyServiceConstructor },
   325   { nullptr }
   326 };
   328 static const mozilla::Module::ContractIDEntry kWifiProxyServiceContracts[] = {
   329   { "@mozilla.org/wifi/service;1", &kNS_WIFIPROXYSERVICE_CID },
   330   { nullptr }
   331 };
   333 static const mozilla::Module kWifiProxyServiceModule = {
   334   mozilla::Module::kVersion,
   335   kWifiProxyServiceCIDs,
   336   kWifiProxyServiceContracts,
   337   nullptr
   338 };
   340 } // namespace mozilla
   342 NSMODULE_DEFN(WifiProxyServiceModule) = &kWifiProxyServiceModule;

mercurial