Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <dbus/dbus.h>
8 #include "base/message_loop.h"
9 #include "nsThreadUtils.h"
10 #include "RawDBusConnection.h"
12 #ifdef CHROMIUM_LOG
13 #undef CHROMIUM_LOG
14 #endif
16 #if defined(MOZ_WIDGET_GONK)
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...) printf(args);
21 #endif
23 namespace mozilla {
24 namespace ipc {
26 //
27 // DBusWatcher
28 //
30 class DBusWatcher : public MessageLoopForIO::Watcher
31 {
32 public:
33 DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
34 : mConnection(aConnection),
35 mWatch(aWatch)
36 {
37 MOZ_ASSERT(mConnection);
38 MOZ_ASSERT(mWatch);
39 }
41 ~DBusWatcher()
42 { }
44 void StartWatching();
45 void StopWatching();
47 static void FreeFunction(void* aData);
48 static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
49 static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
50 static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
52 RawDBusConnection* GetConnection();
54 private:
55 void OnFileCanReadWithoutBlocking(int aFd);
56 void OnFileCanWriteWithoutBlocking(int aFd);
58 // Read watcher for libevent. Only to be accessed on IO Thread.
59 MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
61 // Write watcher for libevent. Only to be accessed on IO Thread.
62 MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
64 // DBus structures
65 RawDBusConnection* mConnection;
66 DBusWatch* mWatch;
67 };
69 RawDBusConnection*
70 DBusWatcher::GetConnection()
71 {
72 return mConnection;
73 }
75 void DBusWatcher::StartWatching()
76 {
77 MOZ_ASSERT(!NS_IsMainThread());
78 MOZ_ASSERT(mWatch);
80 int fd = dbus_watch_get_unix_fd(mWatch);
82 MessageLoopForIO* ioLoop = MessageLoopForIO::current();
84 unsigned int flags = dbus_watch_get_flags(mWatch);
86 if (flags & DBUS_WATCH_READABLE) {
87 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
88 &mReadWatcher, this);
89 }
90 if (flags & DBUS_WATCH_WRITABLE) {
91 ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
92 &mWriteWatcher, this);
93 }
94 }
96 void DBusWatcher::StopWatching()
97 {
98 MOZ_ASSERT(!NS_IsMainThread());
100 unsigned int flags = dbus_watch_get_flags(mWatch);
102 if (flags & DBUS_WATCH_READABLE) {
103 mReadWatcher.StopWatchingFileDescriptor();
104 }
105 if (flags & DBUS_WATCH_WRITABLE) {
106 mWriteWatcher.StopWatchingFileDescriptor();
107 }
108 }
110 // DBus utility functions, used as function pointers in DBus setup
112 void
113 DBusWatcher::FreeFunction(void* aData)
114 {
115 delete static_cast<DBusWatcher*>(aData);
116 }
118 dbus_bool_t
119 DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
120 {
121 MOZ_ASSERT(!NS_IsMainThread());
123 RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
125 DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
126 dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
128 if (dbus_watch_get_enabled(aWatch)) {
129 dbusWatcher->StartWatching();
130 }
132 return TRUE;
133 }
135 void
136 DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
137 {
138 MOZ_ASSERT(!NS_IsMainThread());
140 DBusWatcher* dbusWatcher =
141 static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
142 dbusWatcher->StopWatching();
143 }
145 void
146 DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
147 {
148 MOZ_ASSERT(!NS_IsMainThread());
150 DBusWatcher* dbusWatcher =
151 static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
153 if (dbus_watch_get_enabled(aWatch)) {
154 dbusWatcher->StartWatching();
155 } else {
156 dbusWatcher->StopWatching();
157 }
158 }
160 // I/O-loop callbacks
162 void
163 DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
164 {
165 MOZ_ASSERT(!NS_IsMainThread());
167 dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
169 DBusDispatchStatus dbusDispatchStatus;
170 do {
171 dbusDispatchStatus =
172 dbus_connection_dispatch(mConnection->GetConnection());
173 } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
174 }
176 void
177 DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
178 {
179 MOZ_ASSERT(!NS_IsMainThread());
181 dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
182 }
184 //
185 // Notification
186 //
188 class Notification
189 {
190 public:
191 Notification(DBusReplyCallback aCallback, void* aData)
192 : mCallback(aCallback),
193 mData(aData)
194 { }
196 // Callback function for DBus replies. Only run it on I/O thread.
197 //
198 static void Handle(DBusPendingCall* aCall, void* aData)
199 {
200 MOZ_ASSERT(!NS_IsMainThread());
201 MOZ_ASSERT(MessageLoop::current());
203 nsAutoPtr<Notification> ntfn(static_cast<Notification*>(aData));
205 // The reply can be non-null if the timeout has been reached.
206 DBusMessage* reply = dbus_pending_call_steal_reply(aCall);
208 if (reply) {
209 ntfn->RunCallback(reply);
210 dbus_message_unref(reply);
211 }
213 dbus_pending_call_cancel(aCall);
214 dbus_pending_call_unref(aCall);
215 }
217 private:
218 void RunCallback(DBusMessage* aMessage)
219 {
220 if (mCallback) {
221 mCallback(aMessage, mData);
222 }
223 }
225 DBusReplyCallback mCallback;
226 void* mData;
227 };
229 //
230 // RawDBusConnection
231 //
233 bool RawDBusConnection::sDBusIsInit(false);
235 RawDBusConnection::RawDBusConnection()
236 {
237 }
239 RawDBusConnection::~RawDBusConnection()
240 {
241 }
243 nsresult RawDBusConnection::EstablishDBusConnection()
244 {
245 if (!sDBusIsInit) {
246 dbus_bool_t success = dbus_threads_init_default();
247 NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
248 sDBusIsInit = true;
249 }
250 DBusError err;
251 dbus_error_init(&err);
252 mConnection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
253 if (dbus_error_is_set(&err)) {
254 dbus_error_free(&err);
255 return NS_ERROR_FAILURE;
256 }
257 dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
258 return NS_OK;
259 }
261 bool RawDBusConnection::Watch()
262 {
263 MOZ_ASSERT(!NS_IsMainThread());
264 MOZ_ASSERT(MessageLoop::current());
266 dbus_bool_t success =
267 dbus_connection_set_watch_functions(mConnection,
268 DBusWatcher::AddWatchFunction,
269 DBusWatcher::RemoveWatchFunction,
270 DBusWatcher::ToggleWatchFunction,
271 this, nullptr);
272 NS_ENSURE_TRUE(success == TRUE, false);
274 return true;
275 }
277 void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
278 {
279 if (ptr) {
280 dbus_connection_close(ptr);
281 dbus_connection_unref(ptr);
282 }
283 }
285 bool RawDBusConnection::Send(DBusMessage* aMessage)
286 {
287 MOZ_ASSERT(aMessage);
288 MOZ_ASSERT(!NS_IsMainThread());
289 MOZ_ASSERT(MessageLoop::current());
291 dbus_bool_t success = dbus_connection_send(mConnection,
292 aMessage,
293 nullptr);
294 if (success != TRUE) {
295 dbus_message_unref(aMessage);
296 return false;
297 }
298 return true;
299 }
301 bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
302 void* aData,
303 int aTimeout,
304 DBusMessage* aMessage)
305 {
306 MOZ_ASSERT(aMessage);
307 MOZ_ASSERT(!NS_IsMainThread());
308 MOZ_ASSERT(MessageLoop::current());
310 nsAutoPtr<Notification> ntfn(new Notification(aCallback, aData));
311 NS_ENSURE_TRUE(ntfn, false);
313 DBusPendingCall* call;
315 dbus_bool_t success = dbus_connection_send_with_reply(mConnection,
316 aMessage,
317 &call,
318 aTimeout);
319 NS_ENSURE_TRUE(success == TRUE, false);
321 success = dbus_pending_call_set_notify(call, Notification::Handle,
322 ntfn, nullptr);
323 NS_ENSURE_TRUE(success == TRUE, false);
325 ntfn.forget();
326 dbus_message_unref(aMessage);
328 return true;
329 }
331 bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
332 void* aData,
333 int aTimeout,
334 const char* aDestination,
335 const char* aPath,
336 const char* aIntf,
337 const char* aFunc,
338 int aFirstArgType,
339 ...)
340 {
341 MOZ_ASSERT(!NS_IsMainThread());
342 va_list args;
344 va_start(args, aFirstArgType);
345 DBusMessage* msg = BuildDBusMessage(aDestination, aPath, aIntf, aFunc,
346 aFirstArgType, args);
347 va_end(args);
349 if (!msg) {
350 return false;
351 }
353 return SendWithReply(aCallback, aData, aTimeout, msg);
354 }
356 DBusMessage* RawDBusConnection::BuildDBusMessage(const char* aDestination,
357 const char* aPath,
358 const char* aIntf,
359 const char* aFunc,
360 int aFirstArgType,
361 va_list aArgs)
362 {
363 DBusMessage* msg = dbus_message_new_method_call(aDestination,
364 aPath, aIntf,
365 aFunc);
366 if (!msg) {
367 CHROMIUM_LOG("Could not allocate D-Bus message object!");
368 return nullptr;
369 }
371 /* append arguments */
372 if (!dbus_message_append_args_valist(msg, aFirstArgType, aArgs)) {
373 CHROMIUM_LOG("Could not append argument to method call!");
374 dbus_message_unref(msg);
375 return nullptr;
376 }
378 return msg;
379 }
381 }
382 }