Bumping manifests a=b2g-bump
[gecko.git] / ipc / ril / Ril.cpp
blob30316e065450f8e6b5449a2106e721890bcad4fc
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
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 #include "mozilla/ipc/Ril.h"
9 #include <fcntl.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #include <netdb.h> // For gethostbyname.
14 #undef CHROMIUM_LOG
15 #if defined(MOZ_WIDGET_GONK)
16 #include <android/log.h>
17 #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
18 #else
19 #define CHROMIUM_LOG(args...) printf(args);
20 #endif
22 #include "jsfriendapi.h"
23 #include "mozilla/ArrayUtils.h"
24 #include "mozilla/ipc/UnixSocketConnector.h"
25 #include "nsTArray.h"
26 #include "nsThreadUtils.h" // For NS_IsMainThread.
28 USING_WORKERS_NAMESPACE
29 using namespace mozilla::ipc;
31 namespace {
33 static const char RIL_SOCKET_NAME[] = "/dev/socket/rilproxy";
35 // Network port to connect to for adb forwarded sockets when doing
36 // desktop development.
37 static const uint32_t RIL_TEST_PORT = 6200;
39 static nsTArray<nsRefPtr<mozilla::ipc::RilConsumer> > sRilConsumers;
41 class ConnectWorkerToRIL MOZ_FINAL : public WorkerTask
43 public:
44 bool RunTask(JSContext* aCx) MOZ_OVERRIDE;
47 class SendRilSocketDataTask MOZ_FINAL : public nsRunnable
49 public:
50 SendRilSocketDataTask(unsigned long aClientId,
51 UnixSocketRawData* aRawData)
52 : mRawData(aRawData)
53 , mClientId(aClientId)
54 { }
56 NS_IMETHOD Run() MOZ_OVERRIDE
58 MOZ_ASSERT(NS_IsMainThread());
60 if (sRilConsumers.Length() <= mClientId ||
61 !sRilConsumers[mClientId] ||
62 sRilConsumers[mClientId]->GetConnectionStatus() != SOCKET_CONNECTED) {
63 // Probably shuting down.
64 delete mRawData;
65 return NS_OK;
68 sRilConsumers[mClientId]->SendSocketData(mRawData);
69 return NS_OK;
72 private:
73 UnixSocketRawData* mRawData;
74 unsigned long mClientId;
77 static bool
78 PostToRIL(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
80 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
81 NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
83 if (args.length() != 2) {
84 JS_ReportError(aCx, "Expecting two arguments with the RIL message");
85 return false;
88 int clientId = args[0].toInt32();
89 JS::Value v = args[1];
91 UnixSocketRawData* raw = nullptr;
93 if (v.isString()) {
94 JSAutoByteString abs;
95 JS::Rooted<JSString*> str(aCx, v.toString());
96 if (!abs.encodeUtf8(aCx, str)) {
97 return false;
100 raw = new UnixSocketRawData(abs.ptr(), abs.length());
101 } else if (!v.isPrimitive()) {
102 JSObject* obj = v.toObjectOrNull();
103 if (!JS_IsTypedArrayObject(obj)) {
104 JS_ReportError(aCx, "Object passed in wasn't a typed array");
105 return false;
108 uint32_t type = JS_GetArrayBufferViewType(obj);
109 if (type != js::Scalar::Int8 &&
110 type != js::Scalar::Uint8 &&
111 type != js::Scalar::Uint8Clamped) {
112 JS_ReportError(aCx, "Typed array data is not octets");
113 return false;
116 JS::AutoCheckCannotGC nogc;
117 size_t size = JS_GetTypedArrayByteLength(obj);
118 void* data = JS_GetArrayBufferViewData(obj, nogc);
119 raw = new UnixSocketRawData(data, size);
120 } else {
121 JS_ReportError(
122 aCx, "Incorrect argument. Expecting a string or a typed array");
123 return false;
126 if (!raw) {
127 JS_ReportError(aCx, "Unable to post to RIL");
128 return false;
131 nsRefPtr<SendRilSocketDataTask> task = new SendRilSocketDataTask(clientId,
132 raw);
133 NS_DispatchToMainThread(task);
134 return true;
137 bool
138 ConnectWorkerToRIL::RunTask(JSContext* aCx)
140 // Set up the postRILMessage on the function for worker -> RIL thread
141 // communication.
142 NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
143 NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
144 JS::Rooted<JSObject*> workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
146 // Check whether |postRILMessage| has been defined. No one but this class
147 // should ever define |postRILMessage| in a RIL worker.
148 JS::Rooted<JS::Value> val(aCx);
149 if (!JS_GetProperty(aCx, workerGlobal, "postRILMessage", &val)) {
150 JS_ReportPendingException(aCx);
151 return false;
154 // Make sure that |postRILMessage| is a function.
155 if (JSTYPE_FUNCTION == JS_TypeOfValue(aCx, val)) {
156 return true;
159 return !!JS_DefineFunction(aCx, workerGlobal, "postRILMessage",
160 PostToRIL, 2, 0);
163 class DispatchRILEvent MOZ_FINAL : public WorkerTask
165 public:
166 DispatchRILEvent(unsigned long aClient, UnixSocketRawData* aMessage)
167 : mClientId(aClient)
168 , mMessage(aMessage)
171 bool RunTask(JSContext* aCx) MOZ_OVERRIDE;
173 private:
174 unsigned long mClientId;
175 nsAutoPtr<UnixSocketRawData> mMessage;
178 bool
179 DispatchRILEvent::RunTask(JSContext* aCx)
181 JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
183 JS::Rooted<JSObject*> array(aCx,
184 JS_NewUint8Array(aCx, mMessage->GetSize()));
185 if (!array) {
186 return false;
189 JS::AutoCheckCannotGC nogc;
190 memcpy(JS_GetArrayBufferViewData(array, nogc),
191 mMessage->GetData(), mMessage->GetSize());
194 JS::AutoValueArray<2> args(aCx);
195 args[0].setNumber((uint32_t)mClientId);
196 args[1].setObject(*array);
198 JS::Rooted<JS::Value> rval(aCx);
199 return JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
202 class RilConnector MOZ_FINAL : public mozilla::ipc::UnixSocketConnector
204 public:
205 RilConnector(unsigned long aClientId)
206 : mClientId(aClientId)
209 int Create() MOZ_OVERRIDE;
210 bool CreateAddr(bool aIsServer,
211 socklen_t& aAddrSize,
212 sockaddr_any& aAddr,
213 const char* aAddress) MOZ_OVERRIDE;
214 bool SetUp(int aFd) MOZ_OVERRIDE;
215 bool SetUpListenSocket(int aFd) MOZ_OVERRIDE;
216 void GetSocketAddr(const sockaddr_any& aAddr,
217 nsAString& aAddrStr) MOZ_OVERRIDE;
219 private:
220 unsigned long mClientId;
224 RilConnector::Create()
226 MOZ_ASSERT(!NS_IsMainThread());
228 int fd = -1;
230 #if defined(MOZ_WIDGET_GONK)
231 fd = socket(AF_LOCAL, SOCK_STREAM, 0);
232 #else
233 // If we can't hit a local loopback, fail later in connect.
234 fd = socket(AF_INET, SOCK_STREAM, 0);
235 #endif
237 if (fd < 0) {
238 NS_WARNING("Could not open ril socket!");
239 return -1;
242 if (!SetUp(fd)) {
243 NS_WARNING("Could not set up socket!");
245 return fd;
248 bool
249 RilConnector::CreateAddr(bool aIsServer,
250 socklen_t& aAddrSize,
251 sockaddr_any& aAddr,
252 const char* aAddress)
254 // We never open ril socket as server.
255 MOZ_ASSERT(!aIsServer);
256 uint32_t af;
257 #if defined(MOZ_WIDGET_GONK)
258 af = AF_LOCAL;
259 #else
260 af = AF_INET;
261 #endif
262 switch (af) {
263 case AF_LOCAL:
264 aAddr.un.sun_family = af;
265 if(strlen(aAddress) > sizeof(aAddr.un.sun_path)) {
266 NS_WARNING("Address too long for socket struct!");
267 return false;
269 strcpy((char*)&aAddr.un.sun_path, aAddress);
270 aAddrSize = strlen(aAddress) + offsetof(struct sockaddr_un, sun_path) + 1;
271 break;
272 case AF_INET:
273 aAddr.in.sin_family = af;
274 aAddr.in.sin_port = htons(RIL_TEST_PORT + mClientId);
275 aAddr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
276 aAddrSize = sizeof(sockaddr_in);
277 break;
278 default:
279 NS_WARNING("Socket type not handled by connector!");
280 return false;
282 return true;
285 bool
286 RilConnector::SetUp(int aFd)
288 // Nothing to do here.
289 return true;
292 bool
293 RilConnector::SetUpListenSocket(int aFd)
295 // Nothing to do here.
296 return true;
299 void
300 RilConnector::GetSocketAddr(const sockaddr_any& aAddr, nsAString& aAddrStr)
302 MOZ_CRASH("This should never be called!");
305 } // anonymous namespace
307 namespace mozilla {
308 namespace ipc {
310 RilConsumer::RilConsumer(unsigned long aClientId,
311 WorkerCrossThreadDispatcher* aDispatcher)
312 : mDispatcher(aDispatcher)
313 , mClientId(aClientId)
314 , mShutdown(false)
316 // Only append client id after RIL_SOCKET_NAME when it's not connected to
317 // the first(0) rilproxy for compatibility.
318 if (!aClientId) {
319 mAddress = RIL_SOCKET_NAME;
320 } else {
321 struct sockaddr_un addr_un;
322 snprintf(addr_un.sun_path, sizeof addr_un.sun_path, "%s%lu",
323 RIL_SOCKET_NAME, aClientId);
324 mAddress = addr_un.sun_path;
327 Connect(new RilConnector(mClientId), mAddress.get());
330 nsresult
331 RilConsumer::Register(unsigned int aClientId,
332 WorkerCrossThreadDispatcher* aDispatcher)
334 MOZ_ASSERT(NS_IsMainThread());
336 sRilConsumers.EnsureLengthAtLeast(aClientId + 1);
338 if (sRilConsumers[aClientId]) {
339 NS_WARNING("RilConsumer already registered");
340 return NS_ERROR_FAILURE;
343 nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
344 if (!aDispatcher->PostTask(connection)) {
345 NS_WARNING("Failed to connect worker to ril");
346 return NS_ERROR_UNEXPECTED;
349 // Now that we're set up, connect ourselves to the RIL thread.
350 sRilConsumers[aClientId] = new RilConsumer(aClientId, aDispatcher);
351 return NS_OK;
354 void
355 RilConsumer::Shutdown()
357 MOZ_ASSERT(NS_IsMainThread());
359 for (unsigned long i = 0; i < sRilConsumers.Length(); i++) {
360 nsRefPtr<RilConsumer>& instance = sRilConsumers[i];
361 if (!instance) {
362 continue;
365 instance->mShutdown = true;
366 instance->Close();
367 instance = nullptr;
371 void
372 RilConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
374 MOZ_ASSERT(NS_IsMainThread());
376 nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(mClientId, aMessage.forget()));
377 mDispatcher->PostTask(dre);
380 void
381 RilConsumer::OnConnectSuccess()
383 // Nothing to do here.
384 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
387 void
388 RilConsumer::OnConnectError()
390 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
391 Close();
394 void
395 RilConsumer::OnDisconnect()
397 CHROMIUM_LOG("RIL[%lu]: %s\n", mClientId, __FUNCTION__);
398 if (!mShutdown) {
399 Connect(new RilConnector(mClientId), mAddress.get(),
400 GetSuggestedConnectDelayMs());
404 ConnectionOrientedSocketIO*
405 RilConsumer::GetIO()
407 return PrepareAccept(new RilConnector(mClientId));
410 } // namespace ipc
411 } // namespace mozilla