ipc/nfc/Nfc.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set sw=4 ts=8 et ft=cpp: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* Copyright © 2013, Deutsche Telekom, Inc. */
     9 #include "mozilla/ipc/Nfc.h"
    11 #include <fcntl.h>
    12 #include <sys/socket.h>
    13 #include <sys/un.h>
    15 #undef CHROMIUM_LOG
    16 #if (defined(MOZ_WIDGET_GONK) && defined(DEBUG))
    17 #include <android/log.h>
    18 #define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
    19 #else
    20 #define CHROMIUM_LOG(args...)
    21 #endif
    23 #include "jsfriendapi.h"
    24 #include "mozilla/ArrayUtils.h"
    25 #include "nsThreadUtils.h" // For NS_IsMainThread.
    27 USING_WORKERS_NAMESPACE
    28 using namespace mozilla::ipc;
    30 namespace {
    32 const char* NFC_SOCKET_NAME = "/dev/socket/nfcd";
    34 // Network port to connect to for adb forwarded sockets when doing
    35 // desktop development.
    36 const uint32_t NFC_TEST_PORT = 6400;
    38 nsRefPtr<mozilla::ipc::NfcConsumer> sNfcConsumer;
    40 class ConnectWorkerToNFC : public WorkerTask
    41 {
    42 public:
    43     ConnectWorkerToNFC()
    44     { }
    46     virtual bool RunTask(JSContext* aCx);
    47 };
    49 class SendNfcSocketDataTask : public nsRunnable
    50 {
    51 public:
    52     SendNfcSocketDataTask(UnixSocketRawData* aRawData)
    53         : mRawData(aRawData)
    54     { }
    56     NS_IMETHOD Run()
    57     {
    58         MOZ_ASSERT(NS_IsMainThread());
    60         if (!sNfcConsumer ||
    61             sNfcConsumer->GetConnectionStatus() != SOCKET_CONNECTED) {
    62             // Probably shuting down.
    63             delete mRawData;
    64             return NS_OK;
    65         }
    67         sNfcConsumer->SendSocketData(mRawData);
    68         return NS_OK;
    69     }
    71 private:
    72     UnixSocketRawData* mRawData;
    73 };
    75 bool
    76 PostToNFC(JSContext* aCx,
    77           unsigned aArgc,
    78           JS::Value* aVp)
    79 {
    80     JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
    81     NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
    83     if (args.length() != 1) {
    84         JS_ReportError(aCx, "Expecting one argument with the NFC message");
    85         return false;
    86     }
    88     JS::Value v = args[0];
    90     JSAutoByteString abs;
    91     void* data;
    92     size_t size;
    93     if (JSVAL_IS_STRING(v)) {
    94         JS::Rooted<JSString*> str(aCx, v.toString());
    95         if (!abs.encodeUtf8(aCx, str)) {
    96             return false;
    97         }
    99         data = abs.ptr();
   100         size = abs.length();
   101     } else if (!JSVAL_IS_PRIMITIVE(v)) {
   102         JSObject* obj = JSVAL_TO_OBJECT(v);
   103         if (!JS_IsTypedArrayObject(obj)) {
   104             JS_ReportError(aCx, "Object passed in wasn't a typed array");
   105             return false;
   106         }
   108         uint32_t type = JS_GetArrayBufferViewType(obj);
   109         if (type != js::ArrayBufferView::TYPE_INT8 &&
   110             type != js::ArrayBufferView::TYPE_UINT8 &&
   111             type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
   112             JS_ReportError(aCx, "Typed array data is not octets");
   113             return false;
   114         }
   116         size = JS_GetTypedArrayByteLength(obj);
   117         data = JS_GetArrayBufferViewData(obj);
   118     } else {
   119         JS_ReportError(aCx,
   120                        "Incorrect argument. Expecting a string or a typed array");
   121         return false;
   122     }
   124     UnixSocketRawData* raw = new UnixSocketRawData(data, size);
   126     nsRefPtr<SendNfcSocketDataTask> task =
   127         new SendNfcSocketDataTask(raw);
   128     NS_DispatchToMainThread(task);
   129     return true;
   130 }
   132 bool
   133 ConnectWorkerToNFC::RunTask(JSContext* aCx)
   134 {
   135     // Set up the postNFCMessage on the function for worker -> NFC thread
   136     // communication.
   137     NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
   138     NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
   139     JS::Rooted<JSObject*> workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
   141     return !!JS_DefineFunction(aCx, workerGlobal,
   142                                "postNfcMessage", PostToNFC, 1, 0);
   143 }
   145 class DispatchNFCEvent : public WorkerTask
   146 {
   147 public:
   148     DispatchNFCEvent(UnixSocketRawData* aMessage)
   149         : mMessage(aMessage)
   150     { }
   152     virtual bool RunTask(JSContext* aCx);
   154 private:
   155     nsAutoPtr<UnixSocketRawData> mMessage;
   156 };
   158 bool
   159 DispatchNFCEvent::RunTask(JSContext* aCx)
   160 {
   161     JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
   163     JSObject* array = JS_NewUint8Array(aCx, mMessage->mSize);
   164     if (!array) {
   165         return false;
   166     }
   167     JS::Rooted<JS::Value> arrayVal(aCx, JS::ObjectValue(*array));
   169     memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
   170     JS::Rooted<JS::Value> rval(aCx);
   171     return JS_CallFunctionName(aCx, obj, "onNfcMessage", arrayVal, &rval);
   172 }
   174 class NfcConnector : public mozilla::ipc::UnixSocketConnector
   175 {
   176 public:
   177     NfcConnector()
   178     {}
   180     virtual ~NfcConnector()
   181     {}
   183     virtual int Create();
   184     virtual bool CreateAddr(bool aIsServer,
   185                             socklen_t& aAddrSize,
   186                             sockaddr_any& aAddr,
   187                             const char* aAddress);
   188     virtual bool SetUp(int aFd);
   189     virtual bool SetUpListenSocket(int aFd);
   190     virtual void GetSocketAddr(const sockaddr_any& aAddr,
   191                                nsAString& aAddrStr);
   192 };
   194 int
   195 NfcConnector::Create()
   196 {
   197     MOZ_ASSERT(!NS_IsMainThread());
   199     int fd = -1;
   201 #if defined(MOZ_WIDGET_GONK)
   202     fd = socket(AF_LOCAL, SOCK_STREAM, 0);
   203 #else
   204     // If we can't hit a local loopback, fail later in connect.
   205     fd = socket(AF_INET, SOCK_STREAM, 0);
   206 #endif
   208     if (fd < 0) {
   209         NS_WARNING("Could not open nfc socket!");
   210         return -1;
   211     }
   213     if (!SetUp(fd)) {
   214         NS_WARNING("Could not set up socket!");
   215     }
   216     return fd;
   217 }
   219 bool
   220 NfcConnector::CreateAddr(bool aIsServer,
   221                          socklen_t& aAddrSize,
   222                          sockaddr_any& aAddr,
   223                          const char* aAddress)
   224 {
   225     // We never open nfc socket as server.
   226     MOZ_ASSERT(!aIsServer);
   227     uint32_t af;
   228 #if defined(MOZ_WIDGET_GONK)
   229     af = AF_LOCAL;
   230 #else
   231     af = AF_INET;
   232 #endif
   233     switch (af) {
   234     case AF_LOCAL:
   235         aAddr.un.sun_family = af;
   236         if(strlen(aAddress) > sizeof(aAddr.un.sun_path)) {
   237             NS_WARNING("Address too long for socket struct!");
   238             return false;
   239         }
   240         strcpy((char*)&aAddr.un.sun_path, aAddress);
   241         aAddrSize = strlen(aAddress) + offsetof(struct sockaddr_un, sun_path) + 1;
   242         break;
   243     case AF_INET:
   244         aAddr.in.sin_family = af;
   245         aAddr.in.sin_port = htons(NFC_TEST_PORT);
   246         aAddr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   247         aAddrSize = sizeof(sockaddr_in);
   248         break;
   249     default:
   250         NS_WARNING("Socket type not handled by connector!");
   251         return false;
   252     }
   253     return true;
   254 }
   256 bool
   257 NfcConnector::SetUp(int aFd)
   258 {
   259     // Nothing to do here.
   260     return true;
   261 }
   263 bool
   264 NfcConnector::SetUpListenSocket(int aFd)
   265 {
   266     // Nothing to do here.
   267     return true;
   268 }
   270 void
   271 NfcConnector::GetSocketAddr(const sockaddr_any& aAddr,
   272                             nsAString& aAddrStr)
   273 {
   274     MOZ_CRASH("This should never be called!");
   275 }
   277 } // anonymous namespace
   279 namespace mozilla {
   280 namespace ipc {
   282 NfcConsumer::NfcConsumer(WorkerCrossThreadDispatcher* aDispatcher)
   283     : mDispatcher(aDispatcher)
   284     , mShutdown(false)
   285 {
   286     mAddress = NFC_SOCKET_NAME;
   288     ConnectSocket(new NfcConnector(), mAddress.get());
   289 }
   291 nsresult
   292 NfcConsumer::Register(WorkerCrossThreadDispatcher* aDispatcher)
   293 {
   294     MOZ_ASSERT(NS_IsMainThread());
   296     if (sNfcConsumer) {
   297         return NS_ERROR_FAILURE;
   298     }
   300     nsRefPtr<ConnectWorkerToNFC> connection = new ConnectWorkerToNFC();
   301     if (!aDispatcher->PostTask(connection)) {
   302         return NS_ERROR_UNEXPECTED;
   303     }
   305     // Now that we're set up, connect ourselves to the NFC thread.
   306     sNfcConsumer = new NfcConsumer(aDispatcher);
   307     return NS_OK;
   308 }
   310 void
   311 NfcConsumer::Shutdown()
   312 {
   313     MOZ_ASSERT(NS_IsMainThread());
   315     if (sNfcConsumer) {
   316         sNfcConsumer->mShutdown = true;
   317         sNfcConsumer->CloseSocket();
   318         sNfcConsumer = nullptr;
   319     }
   320 }
   322 void
   323 NfcConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
   324 {
   325     MOZ_ASSERT(NS_IsMainThread());
   327     nsRefPtr<DispatchNFCEvent> dre(new DispatchNFCEvent(aMessage.forget()));
   328     mDispatcher->PostTask(dre);
   329 }
   331 void
   332 NfcConsumer::OnConnectSuccess()
   333 {
   334     // Nothing to do here.
   335     CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
   336 }
   338 void
   339 NfcConsumer::OnConnectError()
   340 {
   341     CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
   342     CloseSocket();
   343 }
   345 void
   346 NfcConsumer::OnDisconnect()
   347 {
   348     CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
   349     if (!mShutdown) {
   350         ConnectSocket(new NfcConnector(), mAddress.get(),
   351                       GetSuggestedConnectDelayMs());
   352     }
   353 }
   355 } // namespace ipc
   356 } // namespace mozilla

mercurial