blob: 0cc65c3c427a27c83969d5c11d584d3c0544ec56 [file] [log] [blame]
/*
*
* D-Bus++ - C++ bindings for D-Bus
*
* Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* Project */
#include <dbus-c++/eventloop-integration.h>
#include <dbus-c++/debug.h>
#include <dbus-c++/pipe.h>
/* DBus */
#include <dbus/dbus.h>
/* STD */
#include <string.h>
#include <cassert>
#include <sys/poll.h>
#include <fcntl.h>
using namespace DBus;
using namespace std;
BusTimeout::BusTimeout(Timeout::Internal *ti, BusDispatcher *bd)
: Timeout(ti), DefaultTimeout(Timeout::interval(), true, bd)
{
DefaultTimeout::enabled(Timeout::enabled());
}
void BusTimeout::toggle()
{
debug_log("timeout %p toggled (%s)", this, Timeout::enabled() ? "on" : "off");
DefaultTimeout::enabled(Timeout::enabled());
}
BusWatch::BusWatch(Watch::Internal *wi, BusDispatcher *bd)
: Watch(wi), DefaultWatch(Watch::descriptor(), 0, bd)
{
int flags = POLLHUP | POLLERR;
if (Watch::flags() & DBUS_WATCH_READABLE)
flags |= POLLIN;
if (Watch::flags() & DBUS_WATCH_WRITABLE)
flags |= POLLOUT;
DefaultWatch::flags(flags);
DefaultWatch::enabled(Watch::enabled());
}
void BusWatch::toggle()
{
debug_log("watch %p toggled (%s)", this, Watch::enabled() ? "on" : "off");
DefaultWatch::enabled(Watch::enabled());
}
BusDispatcher::BusDispatcher() :
_running(false)
{
// pipe to create a new fd used to unlock a dispatcher at any
// moment (used by leave function)
int ret = pipe(_pipe);
if (ret == -1) throw Error("PipeError:errno", toString(errno).c_str());
_fdunlock[0] = _pipe[0];
_fdunlock[1] = _pipe[1];
}
void BusDispatcher::enter()
{
debug_log("entering dispatcher %p", this);
_running = true;
while (_running)
{
do_iteration();
for (std::list <Pipe *>::iterator p_it = pipe_list.begin();
p_it != pipe_list.end();
++p_it)
{
Pipe *read_pipe = *p_it;
char buffer[1024]; // TODO: should be max pipe size
unsigned int nbytes = 0;
while (read_pipe->read(buffer, nbytes) > 0)
{
read_pipe->_handler(read_pipe->_data, buffer, nbytes);
}
}
}
debug_log("leaving dispatcher %p", this);
}
void BusDispatcher::leave()
{
_running = false;
int ret = write(_fdunlock[1], "exit", strlen("exit"));
if (ret == -1) throw Error("WriteError:errno", toString(errno).c_str());
close(_fdunlock[1]);
close(_fdunlock[0]);
}
Pipe *BusDispatcher::add_pipe(void(*handler)(const void *data, void *buffer, unsigned int nbyte), const void *data)
{
Pipe *new_pipe = new Pipe(handler, data);
pipe_list.push_back(new_pipe);
return new_pipe;
}
void BusDispatcher::del_pipe(Pipe *pipe)
{
pipe_list.remove(pipe);
delete pipe;
}
void BusDispatcher::do_iteration()
{
dispatch_pending();
dispatch();
}
Timeout *BusDispatcher::add_timeout(Timeout::Internal *ti)
{
BusTimeout *bt = new BusTimeout(ti, this);
bt->expired = new Callback<BusDispatcher, void, DefaultTimeout &>(this, &BusDispatcher::timeout_expired);
bt->data(bt);
debug_log("added timeout %p (%s) (%d millies)",
bt,
((Timeout *)bt)->enabled() ? "on" : "off",
((Timeout *)bt)->interval()
);
return bt;
}
void BusDispatcher::rem_timeout(Timeout *t)
{
debug_log("removed timeout %p", t);
delete t;
}
Watch *BusDispatcher::add_watch(Watch::Internal *wi)
{
BusWatch *bw = new BusWatch(wi, this);
bw->ready = new Callback<BusDispatcher, void, DefaultWatch &>(this, &BusDispatcher::watch_ready);
bw->data(bw);
debug_log("added watch %p (%s) fd=%d flags=%d",
bw, ((Watch *)bw)->enabled() ? "on" : "off", ((Watch *)bw)->descriptor(), ((Watch *)bw)->flags());
return bw;
}
void BusDispatcher::rem_watch(Watch *w)
{
debug_log("removed watch %p", w);
delete w;
}
void BusDispatcher::timeout_expired(DefaultTimeout &et)
{
debug_log("timeout %p expired", &et);
BusTimeout *timeout = reinterpret_cast<BusTimeout *>(et.data());
timeout->handle();
}
void BusDispatcher::watch_ready(DefaultWatch &ew)
{
BusWatch *watch = reinterpret_cast<BusWatch *>(ew.data());
debug_log("watch %p ready, flags=%d state=%d",
watch, ((Watch *)watch)->flags(), watch->state()
);
int flags = 0;
if (watch->state() & POLLIN)
flags |= DBUS_WATCH_READABLE;
if (watch->state() & POLLOUT)
flags |= DBUS_WATCH_WRITABLE;
if (watch->state() & POLLHUP)
flags |= DBUS_WATCH_HANGUP;
if (watch->state() & POLLERR)
flags |= DBUS_WATCH_ERROR;
watch->handle(flags);
}