Files
palemoon27/ipc/netd/Netd.cpp
T
roytam1 c317230594 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1242724: add an export of runnable_utils.h unless/until it gets moved to xpcom/mfbt r=glandium (1d5e839f99)
- Bug 1223240 - Make it easier to set up top-level protocols (r=jld) (3beaf4a6fa)
- Bug 1194259: Make ICE IP restriction to default routes work in E10S r=jesup,mcmanus,drno (cbe463cf27)
- Bug 1239584, Part 1 - Add nsIPushNotifier and nsIPushMessage interfaces. r=dragana (7b71518e7d)
- Bug 1239584, Part 2 - Remove message manager usage from `PushService.jsm`. r=dragana (f76ab36278)
- Bug 1210211 - Part 3: Test for push notification quota with web notifications. r=kitcambridge (f37472f9b2)
- Bug 1189998, Part 3 - Update consolidated Push tests. r=mt (fae3b02e6e)
- Bug 1225968 - Refactor data delivery tests to support addition of new tests, r=kitcambridge (3163083135)
- Bug 1225968 - Adding more messages to the push message tests, r=kitcambridge (7e1bac99ba)
- Bug 1239558 - Exempt system Push subscriptions from quota and permissions checks. r=dragana (0dd8399414)
- Bug 1239584, Part 3 - Update tests. r=dragana (937e339387)
- Bug 1165256 - Make appcache fully work with OriginAttribues. r=jduell (91d666752a)
- reapply Bug 1232506: Make dom/devicestorage really work with e10s. r=alchen (bd77941ea9)
- Bug 1236433 - Part 1: Provide a Native Wrapper to Allow Fallback Whenproperty_get/set is Unavailable; r=edgar (f9026a7f50)
- Bug 1168959 - Memory-safety bugs in NetworkUtils.cpp generally. r=fabrice (13c6c14168)
- Bug 1236433 - Part 2: Adopt Wrapper in Network Utilities; r=edgar (dde58ea083)
- Bug 1209654 - Modify the type of the threshold of addAlarm() and getAllAlarms() to long long from long, and add test cases. r=ettseng, r=bz (79c7e31440)
- Bug 1000040 - Part 1: Add required APIs for Ethernet; r=vicamo,bholley (fcff7c8078)
- Bug 1231306 - Handle plugin state changes correctly in content process (r=jimm) (1f2daa6ad4)
- Bug 1213454: Ensure that mSupportsAsyncInit is propagated from content process; r=jimm (e86f36fe0a)
- Bug 1246574 - Store sandbox level to nsPluginTag for e10s. r=jimm (04617c8d28)
- Bug 1201904 - Force windowless mode for Flash when sandbox level >= 2. r=bsmedberg (662c6612a2)
- Bug 1233619 (part 1) - Remove unneeded gfxContext argument from EndUpdate() and EndUpdateBackground() functions. r=roc. (1f74728aec)
- Bug 1233619 (part 2) - Moz2Dify BeginUpdate() and BeginUpdateBackground() functions. r=roc. (36accc1499)
- Bug 1243656 - Use async for RequestCommitOrCancel. r=masayuki (aa57ea37dc)
- Bug 1243268 - Support ImmSetCandidateWindow(CFS_EXCLUDE) on plugin process. r=masayuki (78975bd3e4)
- Bug 1235573 - Don't post GCS_RESULTSTR when plugin doesn't handle WM_IME_COMPOSITION correctly. r=masayuki (11690062a3)
- Bug 1173371 Part 1: Take Chromium commit 0e49d029d5a1a25d971880b9e44d67ac70b31a80 for sandbox code. r=aklotz (517cb91822)
- Bug 1157864 - Record chromium patch applied in previous commit. r=me (dc1e63191b)
- Bug 1173371 Part 2: Change Chromium sandbox to allow rules for files on network drives to be added. a=aklotz (2bd72777e5)
- Bug 1173371 Part 3: Add sandbox policy rule to allow read access to the Firefox program directory when it is on a network drive. r=aklotz (c0a180d4b8)
- Bug 1244774: Correct wchar_t/char16_t VS2015 compilation problem caused by patches for bug 1173371. r=jimm (d5326694f8)
2023-08-17 14:45:22 +08:00

379 lines
9.5 KiB
C++

/* 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 "Netd.h"
#include <android/log.h>
#include <cutils/sockets.h>
#include <fcntl.h>
#include <sys/socket.h>
#include "android/log.h"
#include "nsWhitespaceTokenizer.h"
#include "nsXULAppAPI.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Snprintf.h"
#include "SystemProperty.h"
#define NETD_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
#define ICS_SYS_USB_RNDIS_MAC "/sys/class/android_usb/android0/f_rndis/ethaddr"
#define INVALID_SOCKET -1
#define MAX_RECONNECT_TIMES 10
using mozilla::system::Property;
namespace {
RefPtr<mozilla::ipc::NetdClient> gNetdClient;
RefPtr<mozilla::ipc::NetdConsumer> gNetdConsumer;
class StopNetdConsumer : public nsRunnable {
public:
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
gNetdConsumer = nullptr;
return NS_OK;
}
};
bool
InitRndisAddress()
{
char mac[20];
char serialno[] = "1234567890ABCDEF";
static const int kEthernetAddressLength = 6;
char address[kEthernetAddressLength];
int i = 0;
int ret = 0;
int length = 0;
mozilla::ScopedClose fd;
fd.rwget() = open(ICS_SYS_USB_RNDIS_MAC, O_WRONLY);
if (fd.rwget() == -1) {
NETD_LOG("Unable to open file %s.", ICS_SYS_USB_RNDIS_MAC);
return false;
}
Property::Get("ro.serialno", serialno, "1234567890ABCDEF");
memset(address, 0, sizeof(address));
// First byte is 0x02 to signify a locally administered address.
address[0] = 0x02;
length = strlen(serialno);
for (i = 0; i < length; i++) {
address[i % (kEthernetAddressLength - 1) + 1] ^= serialno[i];
}
snprintf_literal(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
address[0], address[1], address[2],
address[3], address[4], address[5]);
length = strlen(mac);
ret = write(fd.get(), mac, length);
if (ret != length) {
NETD_LOG("Fail to write file %s.", ICS_SYS_USB_RNDIS_MAC);
return false;
}
return true;
}
} // namespace
namespace mozilla {
namespace ipc {
NetdClient::NetdClient()
: LineWatcher('\0', MAX_COMMAND_SIZE)
, mIOLoop(MessageLoopForIO::current())
, mSocket(INVALID_SOCKET)
, mCurrentWriteOffset(0)
, mReConnectTimes(0)
{
MOZ_COUNT_CTOR(NetdClient);
}
NetdClient::~NetdClient()
{
MOZ_COUNT_DTOR(NetdClient);
}
bool
NetdClient::OpenSocket()
{
mSocket.rwget() = socket_local_client("netd",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (mSocket.rwget() < 0) {
NETD_LOG("Error connecting to : netd (%s) - will retry", strerror(errno));
return false;
}
// Add FD_CLOEXEC flag.
int flags = fcntl(mSocket.get(), F_GETFD);
if (flags == -1) {
NETD_LOG("Error doing fcntl with F_GETFD command(%s)", strerror(errno));
return false;
}
flags |= FD_CLOEXEC;
if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
NETD_LOG("Error doing fcntl with F_SETFD command(%s)", strerror(errno));
return false;
}
// Set non-blocking.
if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
NETD_LOG("Error set non-blocking socket(%s)", strerror(errno));
return false;
}
if (!MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
true,
MessageLoopForIO::WATCH_READ,
&mReadWatcher,
this)) {
NETD_LOG("Error set socket read watcher(%s)", strerror(errno));
return false;
}
if (!mOutgoingQ.empty()) {
MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
false,
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this);
}
NETD_LOG("Connected to netd");
return true;
}
void NetdClient::OnLineRead(int aFd, nsDependentCSubstring& aMessage)
{
// Set errno to 0 first. For preventing to use the stale version of errno.
errno = 0;
// We found a line terminator. Each line is formatted as an
// integer response code followed by the rest of the line.
// Fish out the response code.
int responseCode = strtol(aMessage.Data(), nullptr, 10);
if (!errno) {
NetdCommand* response = new NetdCommand();
// Passing all the response message, including the line terminator.
response->mSize = aMessage.Length();
memcpy(response->mData, aMessage.Data(), aMessage.Length());
gNetdConsumer->MessageReceived(response);
}
if (!responseCode) {
NETD_LOG("Can't parse netd's response");
}
}
void
NetdClient::OnFileCanWriteWithoutBlocking(int aFd)
{
MOZ_ASSERT(aFd == mSocket.get());
WriteNetdCommand();
}
void
NetdClient::OnError()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
mReadWatcher.StopWatchingFileDescriptor();
mWriteWatcher.StopWatchingFileDescriptor();
mSocket.dispose();
mCurrentWriteOffset = 0;
mCurrentNetdCommand = nullptr;
while (!mOutgoingQ.empty()) {
delete mOutgoingQ.front();
mOutgoingQ.pop();
}
Start();
}
// static
void
NetdClient::Start()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
if (!gNetdClient) {
NETD_LOG("Netd Client is not initialized");
return;
}
if (!gNetdClient->OpenSocket()) {
// Socket open failed, try again in a second.
NETD_LOG("Fail to connect to Netd");
if (++gNetdClient->mReConnectTimes > MAX_RECONNECT_TIMES) {
NETD_LOG("Fail to connect to Netd after retry %d times", MAX_RECONNECT_TIMES);
return;
}
MessageLoopForIO::current()->
PostDelayedTask(FROM_HERE,
NewRunnableFunction(NetdClient::Start),
1000);
return;
}
gNetdClient->mReConnectTimes = 0;
}
// static
void
NetdClient::SendNetdCommandIOThread(NetdCommand* aMessage)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(aMessage);
if (!gNetdClient) {
NETD_LOG("Netd Client is not initialized");
return;
}
gNetdClient->mOutgoingQ.push(aMessage);
if (gNetdClient->mSocket.get() == INVALID_SOCKET) {
NETD_LOG("Netd connection is not established, push the message to queue");
return;
}
gNetdClient->WriteNetdCommand();
}
void
NetdClient::WriteNetdCommand()
{
if (!mCurrentNetdCommand) {
mCurrentWriteOffset = 0;
mCurrentNetdCommand = mOutgoingQ.front();
mOutgoingQ.pop();
}
while (mCurrentWriteOffset < mCurrentNetdCommand->mSize) {
ssize_t write_amount = mCurrentNetdCommand->mSize - mCurrentWriteOffset;
ssize_t written = write(mSocket.get(),
mCurrentNetdCommand->mData + mCurrentWriteOffset,
write_amount);
if (written < 0) {
NETD_LOG("Cannot write to network, error %d\n", (int) written);
OnError();
return;
}
if (written > 0) {
mCurrentWriteOffset += written;
}
if (written != write_amount) {
NETD_LOG("WriteNetdCommand fail !!! Write is not completed");
break;
}
}
if (mCurrentWriteOffset != mCurrentNetdCommand->mSize) {
MessageLoopForIO::current()->
WatchFileDescriptor(mSocket.get(),
false,
MessageLoopForIO::WATCH_WRITE,
&mWriteWatcher,
this);
return;
}
mCurrentNetdCommand = nullptr;
}
static void
InitNetdIOThread()
{
bool result;
char propValue[Property::VALUE_MAX_LENGTH];
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
MOZ_ASSERT(!gNetdClient);
Property::Get("ro.build.version.sdk", propValue, "0");
// Assign rndis address for usb tethering in ICS.
if (atoi(propValue) >= 15) {
result = InitRndisAddress();
// We don't return here because InitRnsisAddress() function is related to
// usb tethering only. Others service such as wifi tethering still need
// to use ipc to communicate with netd.
if (!result) {
NETD_LOG("fail to give rndis interface an address");
}
}
gNetdClient = new NetdClient();
gNetdClient->Start();
}
static void
ShutdownNetdIOThread()
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
nsCOMPtr<nsIRunnable> shutdownEvent = new StopNetdConsumer();
gNetdClient = nullptr;
NS_DispatchToMainThread(shutdownEvent);
}
void
StartNetd(NetdConsumer* aNetdConsumer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aNetdConsumer);
MOZ_ASSERT(gNetdConsumer == nullptr);
gNetdConsumer = aNetdConsumer;
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(InitNetdIOThread));
}
void
StopNetd()
{
MOZ_ASSERT(NS_IsMainThread());
nsIThread* currentThread = NS_GetCurrentThread();
NS_ASSERTION(currentThread, "This should never be null!");
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(ShutdownNetdIOThread));
while (gNetdConsumer) {
if (!NS_ProcessNextEvent(currentThread)) {
NS_WARNING("Something bad happened!");
break;
}
}
}
/**************************************************************************
*
* This function runs in net worker Thread context. The net worker thread
* is created in dom/system/gonk/NetworkManager.js
*
**************************************************************************/
void
SendNetdCommand(NetdCommand* aMessage)
{
MOZ_ASSERT(aMessage);
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(NetdClient::SendNetdCommandIOThread, aMessage));
}
} // namespace ipc
} // namespace mozilla