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 "DBusWatcher.h"
8 #include "mozilla/Unused.h"
9 #include "nsThreadUtils.h"
10 
11 namespace mozilla {
12 namespace ipc {
13 
DBusWatcher(DBusConnection * aConnection,DBusWatch * aWatch)14 DBusWatcher::DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch)
15   : mConnection(aConnection)
16   , mWatch(aWatch)
17 {
18   MOZ_ASSERT(mConnection);
19   MOZ_ASSERT(mWatch);
20 }
21 
~DBusWatcher()22 DBusWatcher::~DBusWatcher()
23 { }
24 
25 DBusConnection*
GetConnection()26 DBusWatcher::GetConnection()
27 {
28   return mConnection;
29 }
30 
31 void
StartWatching()32 DBusWatcher::StartWatching()
33 {
34   MOZ_ASSERT(!NS_IsMainThread());
35 
36   auto flags = dbus_watch_get_flags(mWatch);
37 
38   if (!(flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
39     return;
40   }
41 
42   auto ioLoop = MessageLoopForIO::current();
43 
44   auto fd = dbus_watch_get_unix_fd(mWatch);
45 
46   if (flags & DBUS_WATCH_READABLE) {
47     ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
48                                 &mReadWatcher, this);
49   }
50   if (flags & DBUS_WATCH_WRITABLE) {
51     ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
52                                 &mWriteWatcher, this);
53   }
54 }
55 
56 void
StopWatching()57 DBusWatcher::StopWatching()
58 {
59   MOZ_ASSERT(!NS_IsMainThread());
60 
61   auto flags = dbus_watch_get_flags(mWatch);
62 
63   if (flags & DBUS_WATCH_READABLE) {
64     mReadWatcher.StopWatchingFileDescriptor();
65   }
66   if (flags & DBUS_WATCH_WRITABLE) {
67     mWriteWatcher.StopWatchingFileDescriptor();
68   }
69 }
70 
71 // DBus utility functions, used as function pointers in DBus setup
72 
73 void
FreeFunction(void * aData)74 DBusWatcher::FreeFunction(void* aData)
75 {
76   UniquePtr<DBusWatcher> watcher(static_cast<DBusWatcher*>(aData));
77 }
78 
79 dbus_bool_t
AddWatchFunction(DBusWatch * aWatch,void * aData)80 DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
81 {
82   MOZ_ASSERT(!NS_IsMainThread());
83 
84   auto connection = static_cast<DBusConnection*>(aData);
85 
86   UniquePtr<DBusWatcher> dbusWatcher =
87     MakeUnique<DBusWatcher>(connection, aWatch);
88 
89   dbus_watch_set_data(aWatch, dbusWatcher.get(), DBusWatcher::FreeFunction);
90 
91   if (dbus_watch_get_enabled(aWatch)) {
92     dbusWatcher->StartWatching();
93   }
94 
95   Unused << dbusWatcher.release(); // picked up in |FreeFunction|
96 
97   return TRUE;
98 }
99 
100 void
RemoveWatchFunction(DBusWatch * aWatch,void * aData)101 DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
102 {
103   MOZ_ASSERT(!NS_IsMainThread());
104 
105   auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
106 
107   dbusWatcher->StopWatching();
108 }
109 
110 void
ToggleWatchFunction(DBusWatch * aWatch,void * aData)111 DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
112 {
113   MOZ_ASSERT(!NS_IsMainThread());
114 
115   auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
116 
117   if (dbus_watch_get_enabled(aWatch)) {
118     dbusWatcher->StartWatching();
119   } else {
120     dbusWatcher->StopWatching();
121   }
122 }
123 
124 // I/O-loop callbacks
125 
126 void
OnFileCanReadWithoutBlocking(int aFd)127 DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
128 {
129   MOZ_ASSERT(!NS_IsMainThread());
130 
131   dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
132 
133   DBusDispatchStatus dbusDispatchStatus;
134 
135   do {
136     dbusDispatchStatus = dbus_connection_dispatch(mConnection);
137   } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
138 }
139 
140 void
OnFileCanWriteWithoutBlocking(int aFd)141 DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
142 {
143   MOZ_ASSERT(!NS_IsMainThread());
144 
145   dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
146 }
147 
148 } // namespace ipc
149 } // namespace mozilla
150