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

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

mercurial