Line data Source code
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/. */
6 :
7 : #include "DBusHelpers.h"
8 : #include "mozilla/ipc/DBusMessageRefPtr.h"
9 : #include "mozilla/ipc/DBusPendingCallRefPtr.h"
10 : #include "mozilla/ipc/DBusWatcher.h"
11 : #include "mozilla/RefPtr.h"
12 : #include "mozilla/UniquePtr.h"
13 : #include "mozilla/Unused.h"
14 : #include "nsThreadUtils.h"
15 :
16 : #undef CHROMIUM_LOG
17 : #if defined(MOZ_WIDGET_GONK)
18 : #include <android/log.h>
19 : #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
20 : #else
21 : #define CHROMIUM_LOG(args...) printf(args);
22 : #endif
23 :
24 : namespace mozilla {
25 : namespace ipc {
26 :
27 : //
28 : // DBus I/O
29 : //
30 :
31 : namespace {
32 :
33 : class Notification final
34 : {
35 : public:
36 0 : Notification(DBusReplyCallback aCallback, void* aData)
37 0 : : mCallback(aCallback)
38 0 : , mData(aData)
39 0 : { }
40 :
41 : // Callback function for DBus replies. Only run it on I/O thread.
42 : //
43 0 : static void Handle(DBusPendingCall* aCall, void* aData)
44 : {
45 0 : MOZ_ASSERT(!NS_IsMainThread());
46 :
47 0 : RefPtr<DBusPendingCall> call = already_AddRefed<DBusPendingCall>(aCall);
48 :
49 0 : UniquePtr<Notification> ntfn(static_cast<Notification*>(aData));
50 :
51 0 : RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
52 0 : dbus_pending_call_steal_reply(call));
53 :
54 : // The reply can be null if the timeout has been reached.
55 0 : if (reply) {
56 0 : ntfn->RunCallback(reply);
57 : }
58 :
59 0 : dbus_pending_call_cancel(call);
60 0 : }
61 :
62 : private:
63 0 : void RunCallback(DBusMessage* aMessage)
64 : {
65 0 : if (mCallback) {
66 0 : mCallback(aMessage, mData);
67 : }
68 0 : }
69 :
70 : DBusReplyCallback mCallback;
71 : void* mData;
72 : };
73 :
74 : static already_AddRefed<DBusMessage>
75 0 : BuildDBusMessage(const char* aDestination,
76 : const char* aPath,
77 : const char* aIntf,
78 : const char* aFunc,
79 : int aFirstArgType,
80 : va_list aArgs)
81 : {
82 0 : RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
83 0 : dbus_message_new_method_call(aDestination, aPath, aIntf, aFunc));
84 :
85 0 : if (!msg) {
86 0 : CHROMIUM_LOG("dbus_message_new_method_call failed");
87 0 : return nullptr;
88 : }
89 :
90 0 : auto success = dbus_message_append_args_valist(msg, aFirstArgType, aArgs);
91 :
92 0 : if (!success) {
93 0 : CHROMIUM_LOG("dbus_message_append_args_valist failed");
94 0 : return nullptr;
95 : }
96 :
97 0 : return msg.forget();
98 : }
99 :
100 : } // anonymous namespace
101 :
102 : nsresult
103 0 : DBusWatchConnection(DBusConnection* aConnection)
104 : {
105 0 : MOZ_ASSERT(!NS_IsMainThread());
106 0 : MOZ_ASSERT(aConnection);
107 :
108 : auto success =
109 : dbus_connection_set_watch_functions(aConnection,
110 : DBusWatcher::AddWatchFunction,
111 : DBusWatcher::RemoveWatchFunction,
112 : DBusWatcher::ToggleWatchFunction,
113 0 : aConnection, nullptr);
114 0 : if (!success) {
115 0 : CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
116 0 : return NS_ERROR_FAILURE;
117 : }
118 :
119 0 : return NS_OK;
120 : }
121 :
122 : void
123 0 : DBusUnwatchConnection(DBusConnection* aConnection)
124 : {
125 0 : MOZ_ASSERT(!NS_IsMainThread());
126 0 : MOZ_ASSERT(aConnection);
127 :
128 : auto success = dbus_connection_set_watch_functions(aConnection,
129 : nullptr, nullptr, nullptr,
130 0 : nullptr, nullptr);
131 0 : if (!success) {
132 0 : CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
133 : }
134 0 : }
135 :
136 : nsresult
137 0 : DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage)
138 : {
139 0 : MOZ_ASSERT(!NS_IsMainThread());
140 0 : MOZ_ASSERT(aConnection);
141 0 : MOZ_ASSERT(aMessage);
142 :
143 0 : auto success = dbus_connection_send(aConnection, aMessage, nullptr);
144 :
145 0 : if (!success) {
146 0 : CHROMIUM_LOG("dbus_connection_send failed");
147 0 : return NS_ERROR_FAILURE;
148 : }
149 :
150 0 : return NS_OK;
151 : }
152 :
153 : nsresult
154 0 : DBusSendMessageWithReply(DBusConnection* aConnection,
155 : DBusReplyCallback aCallback, void* aData,
156 : int aTimeout,
157 : DBusMessage* aMessage)
158 : {
159 0 : MOZ_ASSERT(!NS_IsMainThread());
160 0 : MOZ_ASSERT(aConnection);
161 0 : MOZ_ASSERT(aMessage);
162 :
163 0 : UniquePtr<Notification> ntfn = MakeUnique<Notification>(aCallback, aData);
164 :
165 0 : auto call = static_cast<DBusPendingCall*>(nullptr);
166 :
167 : auto success = dbus_connection_send_with_reply(aConnection,
168 : aMessage,
169 : &call,
170 0 : aTimeout);
171 0 : if (!success) {
172 0 : CHROMIUM_LOG("dbus_connection_send_with_reply failed");
173 0 : return NS_ERROR_FAILURE;
174 : }
175 :
176 0 : success = dbus_pending_call_set_notify(call, Notification::Handle,
177 0 : ntfn.get(), nullptr);
178 0 : if (!success) {
179 0 : CHROMIUM_LOG("dbus_pending_call_set_notify failed");
180 0 : return NS_ERROR_FAILURE;
181 : }
182 :
183 0 : Unused << ntfn.release(); // Picked up in |Notification::Handle|
184 :
185 0 : return NS_OK;
186 : }
187 :
188 : nsresult
189 0 : DBusSendMessageWithReply(DBusConnection* aConnection,
190 : DBusReplyCallback aCallback,
191 : void* aData,
192 : int aTimeout,
193 : const char* aDestination,
194 : const char* aPath,
195 : const char* aIntf,
196 : const char* aFunc,
197 : int aFirstArgType,
198 : va_list aArgs)
199 : {
200 0 : MOZ_ASSERT(!NS_IsMainThread());
201 0 : MOZ_ASSERT(aConnection);
202 :
203 : RefPtr<DBusMessage> msg =
204 0 : BuildDBusMessage(aDestination, aPath, aIntf, aFunc, aFirstArgType, aArgs);
205 :
206 0 : if (!msg) {
207 0 : return NS_ERROR_FAILURE;
208 : }
209 :
210 0 : return DBusSendMessageWithReply(aConnection, aCallback, aData, aTimeout, msg);
211 : }
212 :
213 : nsresult
214 0 : DBusSendMessageWithReply(DBusConnection* aConnection,
215 : DBusReplyCallback aCallback,
216 : void* aData,
217 : int aTimeout,
218 : const char* aDestination,
219 : const char* aPath,
220 : const char* aIntf,
221 : const char* aFunc,
222 : int aFirstArgType,
223 : ...)
224 : {
225 0 : MOZ_ASSERT(!NS_IsMainThread());
226 0 : MOZ_ASSERT(aConnection);
227 :
228 : va_list args;
229 0 : va_start(args, aFirstArgType);
230 :
231 : auto rv = DBusSendMessageWithReply(aConnection,
232 : aCallback, aData,
233 : aTimeout,
234 : aDestination, aPath, aIntf, aFunc,
235 0 : aFirstArgType, args);
236 0 : va_end(args);
237 :
238 0 : if (NS_FAILED(rv)) {
239 0 : return rv;
240 : }
241 :
242 0 : return NS_OK;
243 : }
244 :
245 : }
246 : }
|