blob: 0cc65c3c427a27c83969d5c11d584d3c0544ec56 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/*
2 *
3 * D-Bus++ - C++ bindings for D-Bus
4 *
5 * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28/* Project */
29#include <dbus-c++/eventloop-integration.h>
30#include <dbus-c++/debug.h>
31#include <dbus-c++/pipe.h>
32
33/* DBus */
34#include <dbus/dbus.h>
35
36/* STD */
37#include <string.h>
38#include <cassert>
39#include <sys/poll.h>
40#include <fcntl.h>
41
42using namespace DBus;
43using namespace std;
44
45BusTimeout::BusTimeout(Timeout::Internal *ti, BusDispatcher *bd)
46 : Timeout(ti), DefaultTimeout(Timeout::interval(), true, bd)
47{
48 DefaultTimeout::enabled(Timeout::enabled());
49}
50
51void BusTimeout::toggle()
52{
53 debug_log("timeout %p toggled (%s)", this, Timeout::enabled() ? "on" : "off");
54
55 DefaultTimeout::enabled(Timeout::enabled());
56}
57
58BusWatch::BusWatch(Watch::Internal *wi, BusDispatcher *bd)
59 : Watch(wi), DefaultWatch(Watch::descriptor(), 0, bd)
60{
61 int flags = POLLHUP | POLLERR;
62
63 if (Watch::flags() & DBUS_WATCH_READABLE)
64 flags |= POLLIN;
65 if (Watch::flags() & DBUS_WATCH_WRITABLE)
66 flags |= POLLOUT;
67
68 DefaultWatch::flags(flags);
69 DefaultWatch::enabled(Watch::enabled());
70}
71
72void BusWatch::toggle()
73{
74 debug_log("watch %p toggled (%s)", this, Watch::enabled() ? "on" : "off");
75
76 DefaultWatch::enabled(Watch::enabled());
77}
78
79BusDispatcher::BusDispatcher() :
80 _running(false)
81{
82 // pipe to create a new fd used to unlock a dispatcher at any
83 // moment (used by leave function)
84 int ret = pipe(_pipe);
85 if (ret == -1) throw Error("PipeError:errno", toString(errno).c_str());
86
87 _fdunlock[0] = _pipe[0];
88 _fdunlock[1] = _pipe[1];
89}
90
91void BusDispatcher::enter()
92{
93 debug_log("entering dispatcher %p", this);
94
95 _running = true;
96
97 while (_running)
98 {
99 do_iteration();
100
101 for (std::list <Pipe *>::iterator p_it = pipe_list.begin();
102 p_it != pipe_list.end();
103 ++p_it)
104 {
105 Pipe *read_pipe = *p_it;
106 char buffer[1024]; // TODO: should be max pipe size
107 unsigned int nbytes = 0;
108
109 while (read_pipe->read(buffer, nbytes) > 0)
110 {
111 read_pipe->_handler(read_pipe->_data, buffer, nbytes);
112 }
113
114 }
115 }
116
117 debug_log("leaving dispatcher %p", this);
118}
119
120void BusDispatcher::leave()
121{
122 _running = false;
123
124 int ret = write(_fdunlock[1], "exit", strlen("exit"));
125 if (ret == -1) throw Error("WriteError:errno", toString(errno).c_str());
126
127 close(_fdunlock[1]);
128 close(_fdunlock[0]);
129}
130
131Pipe *BusDispatcher::add_pipe(void(*handler)(const void *data, void *buffer, unsigned int nbyte), const void *data)
132{
133 Pipe *new_pipe = new Pipe(handler, data);
134 pipe_list.push_back(new_pipe);
135
136 return new_pipe;
137}
138
139void BusDispatcher::del_pipe(Pipe *pipe)
140{
141 pipe_list.remove(pipe);
142 delete pipe;
143}
144
145void BusDispatcher::do_iteration()
146{
147 dispatch_pending();
148 dispatch();
149}
150
151Timeout *BusDispatcher::add_timeout(Timeout::Internal *ti)
152{
153 BusTimeout *bt = new BusTimeout(ti, this);
154
155 bt->expired = new Callback<BusDispatcher, void, DefaultTimeout &>(this, &BusDispatcher::timeout_expired);
156 bt->data(bt);
157
158 debug_log("added timeout %p (%s) (%d millies)",
159 bt,
160 ((Timeout *)bt)->enabled() ? "on" : "off",
161 ((Timeout *)bt)->interval()
162 );
163
164 return bt;
165}
166
167void BusDispatcher::rem_timeout(Timeout *t)
168{
169 debug_log("removed timeout %p", t);
170
171 delete t;
172}
173
174Watch *BusDispatcher::add_watch(Watch::Internal *wi)
175{
176 BusWatch *bw = new BusWatch(wi, this);
177
178 bw->ready = new Callback<BusDispatcher, void, DefaultWatch &>(this, &BusDispatcher::watch_ready);
179 bw->data(bw);
180
181 debug_log("added watch %p (%s) fd=%d flags=%d",
182 bw, ((Watch *)bw)->enabled() ? "on" : "off", ((Watch *)bw)->descriptor(), ((Watch *)bw)->flags());
183
184 return bw;
185}
186
187void BusDispatcher::rem_watch(Watch *w)
188{
189 debug_log("removed watch %p", w);
190
191 delete w;
192}
193
194void BusDispatcher::timeout_expired(DefaultTimeout &et)
195{
196 debug_log("timeout %p expired", &et);
197
198 BusTimeout *timeout = reinterpret_cast<BusTimeout *>(et.data());
199
200 timeout->handle();
201}
202
203void BusDispatcher::watch_ready(DefaultWatch &ew)
204{
205 BusWatch *watch = reinterpret_cast<BusWatch *>(ew.data());
206
207 debug_log("watch %p ready, flags=%d state=%d",
208 watch, ((Watch *)watch)->flags(), watch->state()
209 );
210
211 int flags = 0;
212
213 if (watch->state() & POLLIN)
214 flags |= DBUS_WATCH_READABLE;
215 if (watch->state() & POLLOUT)
216 flags |= DBUS_WATCH_WRITABLE;
217 if (watch->state() & POLLHUP)
218 flags |= DBUS_WATCH_HANGUP;
219 if (watch->state() & POLLERR)
220 flags |= DBUS_WATCH_ERROR;
221
222 watch->handle(flags);
223}
224