ipc/netd/Netd.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 file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "Netd.h"
     6 #include <android/log.h>
     7 #include <cutils/sockets.h>
     8 #include <fcntl.h>
     9 #include <sys/socket.h>
    11 #include "cutils/properties.h"
    12 #include "android/log.h"
    14 #include "nsWhitespaceTokenizer.h"
    15 #include "nsXULAppAPI.h"
    16 #include "nsAutoPtr.h"
    17 #include "nsString.h"
    18 #include "nsThreadUtils.h"
    19 #include "mozilla/RefPtr.h"
    22 #define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
    23 #define ICS_SYS_USB_RNDIS_MAC "/sys/class/android_usb/android0/f_rndis/ethaddr"
    24 #define INVALID_SOCKET -1
    25 #define MAX_RECONNECT_TIMES 10
    27 namespace {
    29 mozilla::RefPtr<mozilla::ipc::NetdClient> gNetdClient;
    30 mozilla::RefPtr<mozilla::ipc::NetdConsumer> gNetdConsumer;
    32 class StopNetdConsumer : public nsRunnable {
    33 public:
    34   NS_IMETHOD Run()
    35   {
    36     MOZ_ASSERT(NS_IsMainThread());
    38     gNetdConsumer = nullptr;
    39     return NS_OK;
    40   }
    41 };
    43 bool
    44 InitRndisAddress()
    45 {
    46   char mac[20];
    47   char serialno[] = "1234567890ABCDEF";
    48   static const int kEthernetAddressLength = 6;
    49   char address[kEthernetAddressLength];
    50   int i = 0;
    51   int ret = 0;
    52   int length = 0;
    53   mozilla::ScopedClose fd;
    55   fd.rwget() = open(ICS_SYS_USB_RNDIS_MAC, O_WRONLY);
    56   if (fd.rwget() == -1) {
    57     CHROMIUM_LOG("Unable to open file %s.", ICS_SYS_USB_RNDIS_MAC);
    58     return false;
    59   }
    61   property_get("ro.serialno", serialno, "1234567890ABCDEF");
    63   memset(address, 0, sizeof(address));
    64   // First byte is 0x02 to signify a locally administered address.
    65   address[0] = 0x02;
    66   length = strlen(serialno);
    67   for (i = 0; i < length; i++) {
    68     address[i % (kEthernetAddressLength - 1) + 1] ^= serialno[i];
    69   }
    71   sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
    72           address[0], address[1], address[2],
    73           address[3], address[4], address[5]);
    74   length = strlen(mac);
    75   ret = write(fd.get(), mac, length);
    76   if (ret != length) {
    77     CHROMIUM_LOG("Fail to write file %s.", ICS_SYS_USB_RNDIS_MAC);
    78     return false;
    79   }
    80   return true;
    81 }
    83 } // anonymous namespace
    85 namespace mozilla {
    86 namespace ipc {
    88 NetdClient::NetdClient()
    89   : LineWatcher('\0', MAX_COMMAND_SIZE)
    90   , mIOLoop(MessageLoopForIO::current())
    91   , mSocket(INVALID_SOCKET)
    92   , mCurrentWriteOffset(0)
    93   , mReConnectTimes(0)
    94 {
    95   MOZ_COUNT_CTOR(NetdClient);
    96 }
    98 NetdClient::~NetdClient()
    99 {
   100   MOZ_COUNT_DTOR(NetdClient);
   101 }
   103 bool
   104 NetdClient::OpenSocket()
   105 {
   106   mSocket.rwget() = socket_local_client("netd",
   107                                         ANDROID_SOCKET_NAMESPACE_RESERVED,
   108                                         SOCK_STREAM);
   109   if (mSocket.rwget() < 0) {
   110     CHROMIUM_LOG("Error connecting to : netd (%s) - will retry", strerror(errno));
   111     return false;
   112   }
   113   // Add FD_CLOEXEC flag.
   114   int flags = fcntl(mSocket.get(), F_GETFD);
   115   if (flags == -1) {
   116     CHROMIUM_LOG("Error doing fcntl with F_GETFD command(%s)", strerror(errno));
   117     return false;
   118   }
   119   flags |= FD_CLOEXEC;
   120   if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
   121     CHROMIUM_LOG("Error doing fcntl with F_SETFD command(%s)", strerror(errno));
   122     return false;
   123   }
   124   // Set non-blocking.
   125   if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
   126     CHROMIUM_LOG("Error set non-blocking socket(%s)", strerror(errno));
   127     return false;
   128   }
   129   if (!MessageLoopForIO::current()->
   130       WatchFileDescriptor(mSocket.get(),
   131                           true,
   132                           MessageLoopForIO::WATCH_READ,
   133                           &mReadWatcher,
   134                           this)) {
   135     CHROMIUM_LOG("Error set socket read watcher(%s)", strerror(errno));
   136     return false;
   137   }
   139   if (!mOutgoingQ.empty()) {
   140     MessageLoopForIO::current()->
   141       WatchFileDescriptor(mSocket.get(),
   142                           false,
   143                           MessageLoopForIO::WATCH_WRITE,
   144                           &mWriteWatcher,
   145                           this);
   146   }
   148   CHROMIUM_LOG("Connected to netd");
   149   return true;
   150 }
   152 void NetdClient::OnLineRead(int aFd, nsDependentCSubstring& aMessage)
   153 {
   154   // Set errno to 0 first. For preventing to use the stale version of errno.
   155   errno = 0;
   156   // We found a line terminator. Each line is formatted as an
   157   // integer response code followed by the rest of the line.
   158   // Fish out the response code.
   159   int responseCode = strtol(aMessage.Data(), nullptr, 10);
   160   if (!errno) {
   161     NetdCommand* response = new NetdCommand();
   162     // Passing all the response message, including the line terminator.
   163     response->mSize = aMessage.Length();
   164     memcpy(response->mData, aMessage.Data(), aMessage.Length());
   165     gNetdConsumer->MessageReceived(response);
   166   }
   168   if (!responseCode) {
   169     CHROMIUM_LOG("Can't parse netd's response");
   170   }
   171 }
   173 void
   174 NetdClient::OnFileCanWriteWithoutBlocking(int aFd)
   175 {
   176   MOZ_ASSERT(aFd == mSocket.get());
   177   WriteNetdCommand();
   178 }
   180 void
   181 NetdClient::OnError()
   182 {
   183   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   185   mReadWatcher.StopWatchingFileDescriptor();
   186   mWriteWatcher.StopWatchingFileDescriptor();
   188   mSocket.dispose();
   189   mCurrentWriteOffset = 0;
   190   mCurrentNetdCommand = nullptr;
   191   while (!mOutgoingQ.empty()) {
   192     delete mOutgoingQ.front();
   193     mOutgoingQ.pop();
   194   }
   195   Start();
   196 }
   198 // static
   199 void
   200 NetdClient::Start()
   201 {
   202   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   204   if (!gNetdClient) {
   205     CHROMIUM_LOG("Netd Client is not initialized");
   206     return;
   207   }
   209   if (!gNetdClient->OpenSocket()) {
   210     // Socket open failed, try again in a second.
   211     CHROMIUM_LOG("Fail to connect to Netd");
   212     if (++gNetdClient->mReConnectTimes > MAX_RECONNECT_TIMES) {
   213       CHROMIUM_LOG("Fail to connect to Netd after retry %d times", MAX_RECONNECT_TIMES);
   214       return;
   215     }
   217     MessageLoopForIO::current()->
   218       PostDelayedTask(FROM_HERE,
   219                       NewRunnableFunction(NetdClient::Start),
   220                       1000);
   221     return;
   222   }
   223   gNetdClient->mReConnectTimes = 0;
   224 }
   226 // static
   227 void
   228 NetdClient::SendNetdCommandIOThread(NetdCommand* aMessage)
   229 {
   230   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   231   MOZ_ASSERT(aMessage);
   233   if (!gNetdClient) {
   234     CHROMIUM_LOG("Netd Client is not initialized");
   235     return;
   236   }
   238   gNetdClient->mOutgoingQ.push(aMessage);
   240   if (gNetdClient->mSocket.get() == INVALID_SOCKET) {
   241     CHROMIUM_LOG("Netd connection is not established, push the message to queue");
   242     return;
   243   }
   245   gNetdClient->WriteNetdCommand();
   246 }
   248 void
   249 NetdClient::WriteNetdCommand()
   250 {
   251   if (!mCurrentNetdCommand) {
   252     mCurrentWriteOffset = 0;
   253     mCurrentNetdCommand = mOutgoingQ.front();
   254     mOutgoingQ.pop();
   255   }
   257   while (mCurrentWriteOffset < mCurrentNetdCommand->mSize) {
   258     ssize_t write_amount = mCurrentNetdCommand->mSize - mCurrentWriteOffset;
   259     ssize_t written = write(mSocket.get(),
   260                             mCurrentNetdCommand->mData + mCurrentWriteOffset,
   261                             write_amount);
   262     if (written < 0) {
   263       CHROMIUM_LOG("Cannot write to network, error %d\n", (int) written);
   264       OnError();
   265       return;
   266     }
   268     if (written > 0) {
   269       mCurrentWriteOffset += written;
   270     }
   272     if (written != write_amount) {
   273       CHROMIUM_LOG("WriteNetdCommand fail !!! Write is not completed");
   274       break;
   275     }
   276   }
   278   if (mCurrentWriteOffset != mCurrentNetdCommand->mSize) {
   279     MessageLoopForIO::current()->
   280       WatchFileDescriptor(mSocket.get(),
   281                           false,
   282                           MessageLoopForIO::WATCH_WRITE,
   283                           &mWriteWatcher,
   284                           this);
   285     return;
   286   }
   288   mCurrentNetdCommand = nullptr;
   289 }
   291 static void
   292 InitNetdIOThread()
   293 {
   294   bool result;
   295   char propValue[PROPERTY_VALUE_MAX];
   297   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   298   MOZ_ASSERT(!gNetdClient);
   300   property_get("ro.build.version.sdk", propValue, "0");
   301   // Assign rndis address for usb tethering in ICS.
   302   if (atoi(propValue) >= 15) {
   303     result = InitRndisAddress();
   304     // We don't return here because InitRnsisAddress() function is related to
   305     // usb tethering only. Others service such as wifi tethering still need
   306     // to use ipc to communicate with netd.
   307     if (!result) {
   308       CHROMIUM_LOG("fail to give rndis interface an address");
   309     }
   310   }
   311   gNetdClient = new NetdClient();
   312   gNetdClient->Start();
   313 }
   315 static void
   316 ShutdownNetdIOThread()
   317 {
   318   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   319   nsCOMPtr<nsIRunnable> shutdownEvent = new StopNetdConsumer();
   321   gNetdClient = nullptr;
   323   NS_DispatchToMainThread(shutdownEvent);
   324 }
   326 void
   327 StartNetd(NetdConsumer* aNetdConsumer)
   328 {
   329   MOZ_ASSERT(NS_IsMainThread());
   330   MOZ_ASSERT(aNetdConsumer);
   331   MOZ_ASSERT(gNetdConsumer == nullptr);
   333   gNetdConsumer = aNetdConsumer;
   334   XRE_GetIOMessageLoop()->PostTask(
   335     FROM_HERE,
   336     NewRunnableFunction(InitNetdIOThread));
   337 }
   339 void
   340 StopNetd()
   341 {
   342   MOZ_ASSERT(NS_IsMainThread());
   344   nsIThread* currentThread = NS_GetCurrentThread();
   345   NS_ASSERTION(currentThread, "This should never be null!");
   347   XRE_GetIOMessageLoop()->PostTask(
   348     FROM_HERE,
   349     NewRunnableFunction(ShutdownNetdIOThread));
   351   while (gNetdConsumer) {
   352     if (!NS_ProcessNextEvent(currentThread)) {
   353       NS_WARNING("Something bad happened!");
   354       break;
   355     }
   356   }
   357 }
   359 /**************************************************************************
   360 *
   361 *   This function runs in net worker Thread context. The net worker thread
   362 *   is created in dom/system/gonk/NetworkManager.js
   363 *
   364 **************************************************************************/
   365 void
   366 SendNetdCommand(NetdCommand* aMessage)
   367 {
   368   MOZ_ASSERT(aMessage);
   370   XRE_GetIOMessageLoop()->PostTask(
   371     FROM_HERE,
   372     NewRunnableFunction(NetdClient::SendNetdCommandIOThread, aMessage));
   373 }
   375 } // namespace ipc
   376 } // namespace mozilla

mercurial