ipc/ril/Ril.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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 #include "mozilla/ipc/Ril.h"
michael@0 8
michael@0 9 #include <fcntl.h>
michael@0 10 #include <sys/socket.h>
michael@0 11 #include <sys/un.h>
michael@0 12 #include <netdb.h> // For gethostbyname.
michael@0 13
michael@0 14 #undef CHROMIUM_LOG
michael@0 15 #if defined(MOZ_WIDGET_GONK)
michael@0 16 #include <android/log.h>
michael@0 17 #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
michael@0 18 #else
michael@0 19 #define CHROMIUM_LOG(args...) printf(args);
michael@0 20 #endif
michael@0 21
michael@0 22 #include "jsfriendapi.h"
michael@0 23 #include "mozilla/ArrayUtils.h"
michael@0 24 #include "nsTArray.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* RIL_SOCKET_NAME = "/dev/socket/rilproxy";
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 RIL_TEST_PORT = 6200;
michael@0 37
michael@0 38 nsTArray<nsRefPtr<mozilla::ipc::RilConsumer> > sRilConsumers;
michael@0 39
michael@0 40 class ConnectWorkerToRIL : public WorkerTask
michael@0 41 {
michael@0 42 public:
michael@0 43 ConnectWorkerToRIL()
michael@0 44 { }
michael@0 45
michael@0 46 virtual bool RunTask(JSContext *aCx);
michael@0 47 };
michael@0 48
michael@0 49 class SendRilSocketDataTask : public nsRunnable
michael@0 50 {
michael@0 51 public:
michael@0 52 SendRilSocketDataTask(unsigned long aClientId,
michael@0 53 UnixSocketRawData *aRawData)
michael@0 54 : mRawData(aRawData)
michael@0 55 , mClientId(aClientId)
michael@0 56 { }
michael@0 57
michael@0 58 NS_IMETHOD Run()
michael@0 59 {
michael@0 60 MOZ_ASSERT(NS_IsMainThread());
michael@0 61
michael@0 62 if (sRilConsumers.Length() <= mClientId ||
michael@0 63 !sRilConsumers[mClientId] ||
michael@0 64 sRilConsumers[mClientId]->GetConnectionStatus() != SOCKET_CONNECTED) {
michael@0 65 // Probably shuting down.
michael@0 66 delete mRawData;
michael@0 67 return NS_OK;
michael@0 68 }
michael@0 69
michael@0 70 sRilConsumers[mClientId]->SendSocketData(mRawData);
michael@0 71 return NS_OK;
michael@0 72 }
michael@0 73
michael@0 74 private:
michael@0 75 UnixSocketRawData *mRawData;
michael@0 76 unsigned long mClientId;
michael@0 77 };
michael@0 78
michael@0 79 bool
michael@0 80 PostToRIL(JSContext *aCx,
michael@0 81 unsigned aArgc,
michael@0 82 JS::Value *aVp)
michael@0 83 {
michael@0 84 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
michael@0 85 NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
michael@0 86
michael@0 87 if (args.length() != 2) {
michael@0 88 JS_ReportError(aCx, "Expecting two arguments with the RIL message");
michael@0 89 return false;
michael@0 90 }
michael@0 91
michael@0 92 int clientId = args[0].toInt32();
michael@0 93 JS::Value v = args[1];
michael@0 94
michael@0 95 JSAutoByteString abs;
michael@0 96 void *data;
michael@0 97 size_t size;
michael@0 98 if (JSVAL_IS_STRING(v)) {
michael@0 99 JS::Rooted<JSString*> str(aCx, v.toString());
michael@0 100 if (!abs.encodeUtf8(aCx, str)) {
michael@0 101 return false;
michael@0 102 }
michael@0 103
michael@0 104 data = abs.ptr();
michael@0 105 size = abs.length();
michael@0 106 } else if (!JSVAL_IS_PRIMITIVE(v)) {
michael@0 107 JSObject *obj = JSVAL_TO_OBJECT(v);
michael@0 108 if (!JS_IsTypedArrayObject(obj)) {
michael@0 109 JS_ReportError(aCx, "Object passed in wasn't a typed array");
michael@0 110 return false;
michael@0 111 }
michael@0 112
michael@0 113 uint32_t type = JS_GetArrayBufferViewType(obj);
michael@0 114 if (type != js::ArrayBufferView::TYPE_INT8 &&
michael@0 115 type != js::ArrayBufferView::TYPE_UINT8 &&
michael@0 116 type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
michael@0 117 JS_ReportError(aCx, "Typed array data is not octets");
michael@0 118 return false;
michael@0 119 }
michael@0 120
michael@0 121 size = JS_GetTypedArrayByteLength(obj);
michael@0 122 data = JS_GetArrayBufferViewData(obj);
michael@0 123 } else {
michael@0 124 JS_ReportError(aCx,
michael@0 125 "Incorrect argument. Expecting a string or a typed array");
michael@0 126 return false;
michael@0 127 }
michael@0 128
michael@0 129 UnixSocketRawData* raw = new UnixSocketRawData(data, size);
michael@0 130
michael@0 131 nsRefPtr<SendRilSocketDataTask> task =
michael@0 132 new SendRilSocketDataTask(clientId, raw);
michael@0 133 NS_DispatchToMainThread(task);
michael@0 134 return true;
michael@0 135 }
michael@0 136
michael@0 137 bool
michael@0 138 ConnectWorkerToRIL::RunTask(JSContext *aCx)
michael@0 139 {
michael@0 140 // Set up the postRILMessage on the function for worker -> RIL thread
michael@0 141 // communication.
michael@0 142 NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
michael@0 143 NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
michael@0 144 JS::Rooted<JSObject*> workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
michael@0 145
michael@0 146 // Check whether |postRILMessage| has been defined. No one but this class
michael@0 147 // should ever define |postRILMessage| in a RIL worker, so we call to
michael@0 148 // |JS_LookupProperty| instead of |JS_GetProperty| here.
michael@0 149 JS::Rooted<JS::Value> val(aCx);
michael@0 150 if (!JS_LookupProperty(aCx, workerGlobal, "postRILMessage", &val)) {
michael@0 151 JS_ReportPendingException(aCx);
michael@0 152 return false;
michael@0 153 }
michael@0 154
michael@0 155 // |JS_LookupProperty| could still return JS_TRUE with an "undefined"
michael@0 156 // |postRILMessage|, so we have to make sure that with an additional call
michael@0 157 // to |JS_TypeOfValue|.
michael@0 158 if (JSTYPE_FUNCTION == JS_TypeOfValue(aCx, val)) {
michael@0 159 return true;
michael@0 160 }
michael@0 161
michael@0 162 return !!JS_DefineFunction(aCx, workerGlobal,
michael@0 163 "postRILMessage", PostToRIL, 2, 0);
michael@0 164 }
michael@0 165
michael@0 166 class DispatchRILEvent : public WorkerTask
michael@0 167 {
michael@0 168 public:
michael@0 169 DispatchRILEvent(unsigned long aClient,
michael@0 170 UnixSocketRawData* aMessage)
michael@0 171 : mClientId(aClient)
michael@0 172 , mMessage(aMessage)
michael@0 173 { }
michael@0 174
michael@0 175 virtual bool RunTask(JSContext *aCx);
michael@0 176
michael@0 177 private:
michael@0 178 unsigned long mClientId;
michael@0 179 nsAutoPtr<UnixSocketRawData> mMessage;
michael@0 180 };
michael@0 181
michael@0 182 bool
michael@0 183 DispatchRILEvent::RunTask(JSContext *aCx)
michael@0 184 {
michael@0 185 JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
michael@0 186
michael@0 187 JS::Rooted<JSObject*> array(aCx, JS_NewUint8Array(aCx, mMessage->mSize));
michael@0 188 if (!array) {
michael@0 189 return false;
michael@0 190 }
michael@0 191 memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
michael@0 192
michael@0 193 JS::AutoValueArray<2> args(aCx);
michael@0 194 args[0].setNumber((uint32_t)mClientId);
michael@0 195 args[1].setObject(*array);
michael@0 196
michael@0 197 JS::Rooted<JS::Value> rval(aCx);
michael@0 198 return JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
michael@0 199 }
michael@0 200
michael@0 201 class RilConnector : public mozilla::ipc::UnixSocketConnector
michael@0 202 {
michael@0 203 public:
michael@0 204 RilConnector(unsigned long aClientId) : mClientId(aClientId)
michael@0 205 {}
michael@0 206
michael@0 207 virtual ~RilConnector()
michael@0 208 {}
michael@0 209
michael@0 210 virtual int Create();
michael@0 211 virtual bool CreateAddr(bool aIsServer,
michael@0 212 socklen_t& aAddrSize,
michael@0 213 sockaddr_any& aAddr,
michael@0 214 const char* aAddress);
michael@0 215 virtual bool SetUp(int aFd);
michael@0 216 virtual bool SetUpListenSocket(int aFd);
michael@0 217 virtual void GetSocketAddr(const sockaddr_any& aAddr,
michael@0 218 nsAString& aAddrStr);
michael@0 219
michael@0 220 private:
michael@0 221 unsigned long mClientId;
michael@0 222 };
michael@0 223
michael@0 224 int
michael@0 225 RilConnector::Create()
michael@0 226 {
michael@0 227 MOZ_ASSERT(!NS_IsMainThread());
michael@0 228
michael@0 229 int fd = -1;
michael@0 230
michael@0 231 #if defined(MOZ_WIDGET_GONK)
michael@0 232 fd = socket(AF_LOCAL, SOCK_STREAM, 0);
michael@0 233 #else
michael@0 234 // If we can't hit a local loopback, fail later in connect.
michael@0 235 fd = socket(AF_INET, SOCK_STREAM, 0);
michael@0 236 #endif
michael@0 237
michael@0 238 if (fd < 0) {
michael@0 239 NS_WARNING("Could not open ril socket!");
michael@0 240 return -1;
michael@0 241 }
michael@0 242
michael@0 243 if (!SetUp(fd)) {
michael@0 244 NS_WARNING("Could not set up socket!");
michael@0 245 }
michael@0 246 return fd;
michael@0 247 }
michael@0 248
michael@0 249 bool
michael@0 250 RilConnector::CreateAddr(bool aIsServer,
michael@0 251 socklen_t& aAddrSize,
michael@0 252 sockaddr_any& aAddr,
michael@0 253 const char* aAddress)
michael@0 254 {
michael@0 255 // We never open ril socket as server.
michael@0 256 MOZ_ASSERT(!aIsServer);
michael@0 257 uint32_t af;
michael@0 258 #if defined(MOZ_WIDGET_GONK)
michael@0 259 af = AF_LOCAL;
michael@0 260 #else
michael@0 261 af = AF_INET;
michael@0 262 #endif
michael@0 263 switch (af) {
michael@0 264 case AF_LOCAL:
michael@0 265 aAddr.un.sun_family = af;
michael@0 266 if(strlen(aAddress) > sizeof(aAddr.un.sun_path)) {
michael@0 267 NS_WARNING("Address too long for socket struct!");
michael@0 268 return false;
michael@0 269 }
michael@0 270 strcpy((char*)&aAddr.un.sun_path, aAddress);
michael@0 271 aAddrSize = strlen(aAddress) + offsetof(struct sockaddr_un, sun_path) + 1;
michael@0 272 break;
michael@0 273 case AF_INET:
michael@0 274 aAddr.in.sin_family = af;
michael@0 275 aAddr.in.sin_port = htons(RIL_TEST_PORT + mClientId);
michael@0 276 aAddr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
michael@0 277 aAddrSize = sizeof(sockaddr_in);
michael@0 278 break;
michael@0 279 default:
michael@0 280 NS_WARNING("Socket type not handled by connector!");
michael@0 281 return false;
michael@0 282 }
michael@0 283 return true;
michael@0 284 }
michael@0 285
michael@0 286 bool
michael@0 287 RilConnector::SetUp(int aFd)
michael@0 288 {
michael@0 289 // Nothing to do here.
michael@0 290 return true;
michael@0 291 }
michael@0 292
michael@0 293 bool
michael@0 294 RilConnector::SetUpListenSocket(int aFd)
michael@0 295 {
michael@0 296 // Nothing to do here.
michael@0 297 return true;
michael@0 298 }
michael@0 299
michael@0 300 void
michael@0 301 RilConnector::GetSocketAddr(const sockaddr_any& aAddr,
michael@0 302 nsAString& aAddrStr)
michael@0 303 {
michael@0 304 MOZ_CRASH("This should never be called!");
michael@0 305 }
michael@0 306
michael@0 307 } // anonymous namespace
michael@0 308
michael@0 309 namespace mozilla {
michael@0 310 namespace ipc {
michael@0 311
michael@0 312 RilConsumer::RilConsumer(unsigned long aClientId,
michael@0 313 WorkerCrossThreadDispatcher* aDispatcher)
michael@0 314 : mDispatcher(aDispatcher)
michael@0 315 , mClientId(aClientId)
michael@0 316 , mShutdown(false)
michael@0 317 {
michael@0 318 // Only append client id after RIL_SOCKET_NAME when it's not connected to
michael@0 319 // the first(0) rilproxy for compatibility.
michael@0 320 if (!aClientId) {
michael@0 321 mAddress = RIL_SOCKET_NAME;
michael@0 322 } else {
michael@0 323 struct sockaddr_un addr_un;
michael@0 324 snprintf(addr_un.sun_path, sizeof addr_un.sun_path, "%s%lu",
michael@0 325 RIL_SOCKET_NAME, aClientId);
michael@0 326 mAddress = addr_un.sun_path;
michael@0 327 }
michael@0 328
michael@0 329 ConnectSocket(new RilConnector(mClientId), mAddress.get());
michael@0 330 }
michael@0 331
michael@0 332 nsresult
michael@0 333 RilConsumer::Register(unsigned int aClientId,
michael@0 334 WorkerCrossThreadDispatcher* aDispatcher)
michael@0 335 {
michael@0 336 MOZ_ASSERT(NS_IsMainThread());
michael@0 337
michael@0 338 sRilConsumers.EnsureLengthAtLeast(aClientId + 1);
michael@0 339
michael@0 340 if (sRilConsumers[aClientId]) {
michael@0 341 NS_WARNING("RilConsumer already registered");
michael@0 342 return NS_ERROR_FAILURE;
michael@0 343 }
michael@0 344
michael@0 345 nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
michael@0 346 if (!aDispatcher->PostTask(connection)) {
michael@0 347 NS_WARNING("Failed to connect worker to ril");
michael@0 348 return NS_ERROR_UNEXPECTED;
michael@0 349 }
michael@0 350
michael@0 351 // Now that we're set up, connect ourselves to the RIL thread.
michael@0 352 sRilConsumers[aClientId] = new RilConsumer(aClientId, aDispatcher);
michael@0 353 return NS_OK;
michael@0 354 }
michael@0 355
michael@0 356 void
michael@0 357 RilConsumer::Shutdown()
michael@0 358 {
michael@0 359 MOZ_ASSERT(NS_IsMainThread());
michael@0 360
michael@0 361 for (unsigned long i = 0; i < sRilConsumers.Length(); i++) {
michael@0 362 nsRefPtr<RilConsumer>& instance = sRilConsumers[i];
michael@0 363 if (!instance) {
michael@0 364 continue;
michael@0 365 }
michael@0 366
michael@0 367 instance->mShutdown = true;
michael@0 368 instance->CloseSocket();
michael@0 369 instance = nullptr;
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 void
michael@0 374 RilConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
michael@0 375 {
michael@0 376 MOZ_ASSERT(NS_IsMainThread());
michael@0 377
michael@0 378 nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(mClientId, aMessage.forget()));
michael@0 379 mDispatcher->PostTask(dre);
michael@0 380 }
michael@0 381
michael@0 382 void
michael@0 383 RilConsumer::OnConnectSuccess()
michael@0 384 {
michael@0 385 // Nothing to do here.
michael@0 386 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
michael@0 387 }
michael@0 388
michael@0 389 void
michael@0 390 RilConsumer::OnConnectError()
michael@0 391 {
michael@0 392 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
michael@0 393 CloseSocket();
michael@0 394 }
michael@0 395
michael@0 396 void
michael@0 397 RilConsumer::OnDisconnect()
michael@0 398 {
michael@0 399 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
michael@0 400 if (!mShutdown) {
michael@0 401 ConnectSocket(new RilConnector(mClientId), mAddress.get(),
michael@0 402 GetSuggestedConnectDelayMs());
michael@0 403 }
michael@0 404 }
michael@0 405
michael@0 406 } // namespace ipc
michael@0 407 } // namespace mozilla

mercurial