2014-01-29 03:38:50 -08:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "NetworkWorker.h"
|
|
|
|
#include "NetworkUtils.h"
|
|
|
|
#include <nsThreadUtils.h>
|
|
|
|
#include "mozilla/ModuleUtils.h"
|
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2014-08-14 18:47:15 -07:00
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
2014-06-11 12:38:55 -07:00
|
|
|
#include "mozilla/dom/ToJSValue.h"
|
2014-01-29 03:38:50 -08:00
|
|
|
#include "nsXULAppAPI.h"
|
|
|
|
|
|
|
|
#define NS_NETWORKWORKER_CID \
|
|
|
|
{ 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} }
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::dom;
|
|
|
|
using namespace mozilla::ipc;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
nsCOMPtr<nsIThread> gWorkerThread;
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
// The singleton network worker, to be used on the main thread.
|
|
|
|
StaticRefPtr<NetworkWorker> gNetworkWorker;
|
|
|
|
|
|
|
|
// The singleton networkutils class, that can be used on any thread.
|
|
|
|
static nsAutoPtr<NetworkUtils> gNetworkUtils;
|
|
|
|
|
|
|
|
// Runnable used dispatch command result on the main thread.
|
|
|
|
class NetworkResultDispatcher : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NetworkResultDispatcher(const NetworkResultOptions& aResult)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
|
|
|
#define COPY_FIELD(prop) mResult.prop = aResult.prop;
|
|
|
|
COPY_FIELD(mId)
|
|
|
|
COPY_FIELD(mRet)
|
|
|
|
COPY_FIELD(mBroadcast)
|
|
|
|
COPY_FIELD(mTopic)
|
|
|
|
COPY_FIELD(mReason)
|
|
|
|
COPY_FIELD(mResultCode)
|
|
|
|
COPY_FIELD(mResultReason)
|
|
|
|
COPY_FIELD(mError)
|
|
|
|
COPY_FIELD(mEnable)
|
|
|
|
COPY_FIELD(mResult)
|
|
|
|
COPY_FIELD(mSuccess)
|
|
|
|
COPY_FIELD(mCurExternalIfname)
|
|
|
|
COPY_FIELD(mCurInternalIfname)
|
|
|
|
#undef COPY_FIELD
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2014-04-11 07:27:55 -07:00
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
if (gNetworkWorker) {
|
|
|
|
gNetworkWorker->DispatchNetworkResult(mResult);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
NetworkResultOptions mResult;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Runnable used dispatch netd command on the worker thread.
|
|
|
|
class NetworkCommandDispatcher : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NetworkCommandDispatcher(const NetworkParams& aParams)
|
|
|
|
: mParams(aParams)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
2014-04-11 07:27:55 -07:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
if (gNetworkUtils) {
|
|
|
|
gNetworkUtils->ExecuteCommand(mParams);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
NetworkParams mParams;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Runnable used dispatch netd result on the worker thread.
|
|
|
|
class NetdEventRunnable : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NetdEventRunnable(NetdCommand* aCommand)
|
|
|
|
: mCommand(aCommand)
|
2014-04-11 07:27:55 -07:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
}
|
2014-01-29 03:38:50 -08:00
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
2014-04-11 07:27:55 -07:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
if (gNetworkUtils) {
|
|
|
|
gNetworkUtils->onNetdMessage(mCommand);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsAutoPtr<NetdCommand> mCommand;
|
|
|
|
};
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
class NetdMessageConsumer : public NetdConsumer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NetdMessageConsumer()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
|
|
|
void MessageReceived(NetdCommand* aCommand)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand);
|
|
|
|
if (gWorkerThread) {
|
|
|
|
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker)
|
2014-01-29 03:38:50 -08:00
|
|
|
|
|
|
|
NetworkWorker::NetworkWorker()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!gNetworkWorker);
|
|
|
|
}
|
|
|
|
|
|
|
|
NetworkWorker::~NetworkWorker()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!gNetworkWorker);
|
2014-04-11 07:27:55 -07:00
|
|
|
MOZ_ASSERT(!mListener);
|
2014-01-29 03:38:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<NetworkWorker>
|
|
|
|
NetworkWorker::FactoryCreate()
|
|
|
|
{
|
|
|
|
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
if (!gNetworkWorker) {
|
|
|
|
gNetworkWorker = new NetworkWorker();
|
|
|
|
ClearOnShutdown(&gNetworkWorker);
|
|
|
|
|
|
|
|
gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult);
|
|
|
|
ClearOnShutdown(&gNetworkUtils);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<NetworkWorker> worker = gNetworkWorker.get();
|
|
|
|
return worker.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
NetworkWorker::Start(nsINetworkEventListener* aListener)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(aListener);
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
if (mListener) {
|
|
|
|
return NS_OK;
|
2014-01-29 03:38:50 -08:00
|
|
|
}
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread));
|
2014-01-29 03:38:50 -08:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Can't create network control thread");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
StartNetd(new NetdMessageConsumer());
|
2014-01-29 03:38:50 -08:00
|
|
|
mListener = aListener;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
NetworkWorker::Shutdown()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
if (!mListener) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
StopNetd();
|
|
|
|
|
2014-04-11 07:27:55 -07:00
|
|
|
gWorkerThread->Shutdown();
|
|
|
|
gWorkerThread = nullptr;
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
mListener = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Receive command from main thread (NetworkService.js).
|
|
|
|
NS_IMETHODIMP
|
|
|
|
NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
NetworkCommandOptions options;
|
|
|
|
if (!options.Init(aCx, aOptions)) {
|
|
|
|
NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2014-05-19 00:52:02 -07:00
|
|
|
// Dispatch the command to the control thread.
|
2014-07-09 22:29:47 -07:00
|
|
|
NetworkParams NetworkParams(options);
|
2014-01-29 03:38:50 -08:00
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
|
2014-04-11 07:27:55 -07:00
|
|
|
if (gWorkerThread) {
|
|
|
|
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
2014-01-29 03:38:50 -08:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
mozilla::AutoSafeJSContext cx;
|
|
|
|
JS::RootedValue val(cx);
|
|
|
|
|
2014-06-11 12:38:55 -07:00
|
|
|
if (!ToJSValue(cx, aOptions, &val)) {
|
2014-01-29 03:38:50 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call the listener with a JS value.
|
|
|
|
if (mListener) {
|
|
|
|
mListener->OnEvent(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Callback function from network worker thread to update result on main thread.
|
|
|
|
void
|
|
|
|
NetworkWorker::NotifyResult(NetworkResultOptions& aResult)
|
|
|
|
{
|
2014-04-11 07:27:55 -07:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
2014-01-29 03:38:50 -08:00
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult);
|
|
|
|
NS_DispatchToMainThread(runnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker,
|
|
|
|
NetworkWorker::FactoryCreate)
|
|
|
|
|
|
|
|
NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID);
|
|
|
|
|
|
|
|
static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = {
|
|
|
|
{ &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor },
|
|
|
|
{ nullptr }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = {
|
|
|
|
{ "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID },
|
|
|
|
{ nullptr }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const mozilla::Module kNetworkWorkerModule = {
|
|
|
|
mozilla::Module::kVersion,
|
|
|
|
kNetworkWorkerCIDs,
|
|
|
|
kNetworkWorkerContracts,
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;
|