From: Arvin Schnell Date: Fri, 27 Jul 2012 20:20:34 +0000 (+0200) Subject: - work on dbus interface X-Git-Tag: v0.1.3~193 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=8a7debe82e5b8c4d3061c8be03f798036cf1cd80;p=thirdparty%2Fsnapper.git - work on dbus interface --- diff --git a/client/types.h b/client/types.h index 033626f7..da3f7ad1 100644 --- a/client/types.h +++ b/client/types.h @@ -28,8 +28,8 @@ using std::string; using std::list; using std::map; -#include "dbus/DBusConnection.h" #include "dbus/DBusMessage.h" +#include "dbus/DBusConnection.h" #include "snapper/Snapshot.h" #include "snapper/File.h" diff --git a/dbus/DBusConnection.cc b/dbus/DBusConnection.cc index 49651dc9..1d101c3b 100644 --- a/dbus/DBusConnection.cc +++ b/dbus/DBusConnection.cc @@ -58,8 +58,6 @@ namespace DBus void Connection::request_name(const char* name, unsigned int flags) { - boost::lock_guard lock(mutex); - DBusError err; dbus_error_init(&err); @@ -77,20 +75,9 @@ namespace DBus } - void - Connection::read_write(int timeout) - { - // TODO - - dbus_connection_read_write(conn, timeout); - } - - void Connection::send(Message& m) { - boost::lock_guard lock(mutex); - if (!dbus_connection_send(conn, m.get_message(), NULL)) { throw FatalException(); @@ -101,8 +88,6 @@ namespace DBus Message Connection::send_with_reply_and_block(Message& m) { - boost::lock_guard lock(mutex); - DBusError err; dbus_error_init(&err); @@ -121,8 +106,6 @@ namespace DBus void Connection::add_match(const char* rule) { - boost::lock_guard lock(mutex); - DBusError err; dbus_error_init(&err); @@ -136,11 +119,18 @@ namespace DBus } + void + Connection::register_object_path(const char* path, const DBusObjectPathVTable* vtable, + void* user_data) + { + if (!dbus_connection_register_object_path(conn, path, vtable, user_data)) + throw FatalException(); + } + + unsigned long Connection::get_unix_userid(const Message& m) { - boost::lock_guard lock(mutex); - string sender = m.get_sender(); if (sender.empty()) { diff --git a/dbus/DBusConnection.h b/dbus/DBusConnection.h index 0f77a303..80d6cac6 100644 --- a/dbus/DBusConnection.h +++ b/dbus/DBusConnection.h @@ -20,14 +20,13 @@ */ -#ifndef SNAPPER_DBUSCONN_H -#define SNAPPER_DBUSCONN_H +#ifndef SNAPPER_DBUSCONNECTION_H +#define SNAPPER_DBUSCONNECTION_H #include #include -#include #include "DBusMessage.h" @@ -46,19 +45,18 @@ namespace DBus void request_name(const char* name, unsigned int flags); - void read_write(int timeout); - void send(Message& m); Message send_with_reply_and_block(Message& m); void add_match(const char* rule); + void register_object_path(const char* path, const DBusObjectPathVTable* vtable, + void* user_data); + unsigned long get_unix_userid(const Message& m); static string get_unix_username(unsigned long userid); // TODO - boost::mutex mutex; - private: DBusConnection* conn; diff --git a/dbus/DBusMessage.cc b/dbus/DBusMessage.cc index 2141b619..efb75837 100644 --- a/dbus/DBusMessage.cc +++ b/dbus/DBusMessage.cc @@ -33,6 +33,7 @@ namespace DBus : msg(m) { assert(msg); + dbus_message_ref(msg); } diff --git a/dbus/DBusMessage.h b/dbus/DBusMessage.h index c5aa0792..c4f82fa9 100644 --- a/dbus/DBusMessage.h +++ b/dbus/DBusMessage.h @@ -20,8 +20,8 @@ */ -#ifndef SNAPPER_DBUSMSG_H -#define SNAPPER_DBUSMSG_H +#ifndef SNAPPER_DBUSMESSAGE_H +#define SNAPPER_DBUSMESSAGE_H #include diff --git a/dbus/DBusServer.cc b/dbus/DBusServer.cc new file mode 100644 index 00000000..840af5f5 --- /dev/null +++ b/dbus/DBusServer.cc @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2012 Novell, Inc. + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#include +#include + +#include "DBusServer.h" + + +namespace DBus +{ + + Server::Server(DBusBusType type) + : Connection(type), idle_timeout(-1) + { + if (pipe(wakeup_pipe) != 0) + throw FatalException(); + + if (!dbus_connection_set_watch_functions(get_connection(), add_watch, remove_watch, + toggled_watch, this, NULL)) + throw FatalException(); + + if (!dbus_connection_set_timeout_functions(get_connection(), add_timeout, remove_timeout, + toggled_timeout, this, NULL)) + throw FatalException(); + + dbus_connection_set_wakeup_main_function(get_connection(), wakeup_main, this, NULL); + } + + + Server::~Server() + { + close(wakeup_pipe[0]); + close(wakeup_pipe[1]); + } + + + void + DBus::Server::run() + { + reset_idle_count(); + + while (true) + { + vector pollfds; + + { + struct pollfd tmp; + tmp.fd = wakeup_pipe[0]; + tmp.events = POLLIN; + tmp.revents = 0; + pollfds.push_back(tmp); + } + + for (vector::const_iterator it = watches.begin(); it != watches.end(); ++it) + { + if (it->enabled) + { + struct pollfd tmp; + tmp.fd = it->fd; + tmp.events = it->events; + tmp.revents = 0; + pollfds.push_back(tmp); + } + } + + int timeout = -1; + + if (idle_timeout >= 0) + { + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + int time_left = last_action - tmp.tv_sec + idle_timeout; + + if (timeout > time_left * 1000 || timeout == -1) + timeout = time_left * 1000; + } + + int r = poll(&pollfds[0], pollfds.size(), timeout); + if (r == -1) + throw FatalException(); + + { + for (vector::const_iterator it2 = pollfds.begin(); it2 != pollfds.end(); ++it2) + { + if (it2->fd == wakeup_pipe[0] && (it2->revents & POLLIN)) + { + char arbitrary; + read(wakeup_pipe[0], &arbitrary, 1); + } + } + } + + for (vector::const_iterator it = watches.begin(); it != watches.end(); ++it) + { + if (it->enabled) + { + for (vector::const_iterator it2 = pollfds.begin(); it2 != pollfds.end(); ++it2) + { + if (it2->fd == it->fd) + { + if ((it2->revents & POLLIN) && (it->flags & DBUS_WATCH_READABLE)) + dbus_watch_handle(it->dbus_watch, DBUS_WATCH_READABLE); + + if ((it2->revents & POLLOUT) && (it->flags & DBUS_WATCH_WRITABLE)) + dbus_watch_handle(it->dbus_watch, DBUS_WATCH_WRITABLE); + } + } + } + } + + while (dbus_connection_get_dispatch_status(get_connection()) == DBUS_DISPATCH_DATA_REMAINS) + { + dbus_connection_dispatch(get_connection()); + } + + if (idle_timeout >= 0) + { + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + int time_left = last_action - tmp.tv_sec + idle_timeout; + + if (time_left <= 0) + break; + } + } + } + + + void + Server::set_idle_timeout(int s) + { + idle_timeout = s; + } + + + void + Server::reset_idle_count() + { + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + last_action = tmp.tv_sec; + } + + + vector::iterator + Server::find_watch(DBusWatch* dbus_watch) + { + for (vector::iterator it = watches.begin(); it != watches.end(); ++it) + if (it->dbus_watch == dbus_watch) + return it; + + throw FatalException(); + } + + + vector::iterator + Server::find_timeout(DBusTimeout* dbus_timeout) + { + for (vector::iterator it = timeouts.begin(); it != timeouts.end(); ++it) + if (it->dbus_timeout == dbus_timeout) + return it; + + throw FatalException(); + } + + + dbus_bool_t + Server::add_watch(DBusWatch* dbus_watch, void* data) + { + Server* s = static_cast(data); + + Watch tmp; + tmp.enabled = dbus_watch_get_enabled(dbus_watch); + tmp.fd = dbus_watch_get_unix_fd(dbus_watch); + tmp.flags = dbus_watch_get_flags(dbus_watch); + + tmp.events = 0; + if (tmp.flags & DBUS_WATCH_READABLE) + tmp.events |= POLLIN; + if (tmp.flags & DBUS_WATCH_WRITABLE) + tmp.events |= POLLOUT; + + tmp.dbus_watch = dbus_watch; + s->watches.push_back(tmp); + + return true; + } + + + void + Server::remove_watch(DBusWatch* dbus_watch, void* data) + { + Server* s = static_cast(data); + + vector::iterator it = s->find_watch(dbus_watch); + s->watches.erase(it); + } + + + void + Server::toggled_watch(DBusWatch* dbus_watch, void* data) + { + Server* s = static_cast(data); + + vector::iterator it = s->find_watch(dbus_watch); + it->enabled = dbus_watch_get_enabled(dbus_watch); + } + + + dbus_bool_t + Server::add_timeout(DBusTimeout* dbus_timeout, void* data) + { + Server* s = static_cast(data); + + Timeout tmp; + tmp.enabled = dbus_timeout_get_enabled(dbus_timeout); + tmp.interval = dbus_timeout_get_interval(dbus_timeout); + tmp.dbus_timeout = dbus_timeout; + s->timeouts.push_back(tmp); + + return true; + } + + + void + Server::remove_timeout(DBusTimeout* dbus_timeout, void* data) + { + Server* s = static_cast(data); + + vector::iterator it = s->find_timeout(dbus_timeout); + s->timeouts.erase(it); + } + + + void + Server::toggled_timeout(DBusTimeout* dbus_timeout, void* data) + { + Server* s = static_cast(data); + + vector::iterator it = s->find_timeout(dbus_timeout); + it->enabled = dbus_timeout_get_enabled(dbus_timeout); + } + + + void + Server::wakeup_main(void* data) + { + Server* s = static_cast(data); + + const char arbitrary = 42; + write(s->wakeup_pipe[1], &arbitrary, 1); + } + +} diff --git a/dbus/DBusServer.h b/dbus/DBusServer.h new file mode 100644 index 00000000..31cf9fcc --- /dev/null +++ b/dbus/DBusServer.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 Novell, Inc. + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + * + * This program 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, you may + * find current contact information at www.novell.com. + */ + + +#ifndef SNAPPER_DBUSSERVER_H +#define SNAPPER_DBUSSERVER_H + + +#include + +#include "DBusConnection.h" + + +namespace DBus +{ + + class Server : public Connection + { + public: + + Server(DBusBusType type); + ~Server(); + + void run(); + + void set_idle_timeout(int s); + void reset_idle_count(); + + protected: + + struct Watch + { + bool enabled; + int fd; + unsigned int flags; + int events; + DBusWatch* dbus_watch; + }; + + struct Timeout + { + bool enabled; + int interval; + DBusTimeout* dbus_timeout; + }; + + vector watches; + vector timeouts; + int wakeup_pipe[2]; + + vector::iterator find_watch(DBusWatch* dbus_watch); + vector::iterator find_timeout(DBusTimeout* dbus_timeout); + + static dbus_bool_t add_watch(DBusWatch* dbus_watch, void* data); + static void remove_watch(DBusWatch* dbus_watch, void* data); + static void toggled_watch(DBusWatch* dbus_watch, void* data); + + static dbus_bool_t add_timeout(DBusTimeout* dbus_timeout, void* data); + static void remove_timeout(DBusTimeout* dbus_timeout, void* data); + static void toggled_timeout(DBusTimeout* dbus_timeout, void* data); + + static void wakeup_main(void* data); + + int idle_timeout; + time_t last_action; + + }; + +} + + +#endif diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 2eb38964..f67887c9 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -7,6 +7,6 @@ INCLUDES = -I$(top_srcdir) -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include noinst_LTLIBRARIES = libdbus.la libdbus_la_SOURCES = \ + DBusMessage.cc DBusMessage.h \ DBusConnection.cc DBusConnection.h \ - DBusMessage.cc DBusMessage.h - + DBusServer.cc DBusServer.h diff --git a/server/Makefile.am b/server/Makefile.am index 18c99a43..e2185315 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -14,5 +14,5 @@ snapperd_SOURCES = \ Types.cc Types.h snapperd_LDADD = ../snapper/libsnapper.la ../dbus/libdbus.la \ - -ldbus-1 -lboost_thread + -ldbus-1 -lboost_thread -lrt diff --git a/server/snapperd.cc b/server/snapperd.cc index 3077cea4..0fc2bb2f 100644 --- a/server/snapperd.cc +++ b/server/snapperd.cc @@ -37,8 +37,9 @@ #include #include -#include "dbus/DBusConnection.h" #include "dbus/DBusMessage.h" +#include "dbus/DBusConnection.h" +#include "dbus/DBusServer.h" #include "MetaSnapper.h" #include "Client.h" @@ -1193,99 +1194,108 @@ Commands::dispatch(DBus::Connection& conn, DBus::Message& msg) void -listen(DBus::Connection& conn) +unregister_func(DBusConnection* connection, void* data) { - y2mil("Requesting DBus name"); +} - conn.request_name("org.opensuse.Snapper", DBUS_NAME_FLAG_REPLACE_EXISTING); - y2mil("Listening for method calls and signals"); +DBusHandlerResult +message_func1(DBusConnection* connection, DBusMessage* message, void* data) +{ + DBus::Server* s = static_cast(data); - conn.add_match("type='signal', interface='" DBUS_INTERFACE_DBUS "', member='NameOwnerChanged'"); + DBus::Message msg(message); - int idle = 0; - while (++idle < 1000 || !clients.empty()) + if (msg.get_type() == DBUS_MESSAGE_TYPE_METHOD_CALL) { - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); // TODO + y2mil("method call sender:'" << msg.get_sender() << "' path:'" << + msg.get_path() << "' interface:'" << msg.get_interface() << + "' member:'" << msg.get_member() << "'"); + + s->reset_idle_count(); + + if (msg.is_method_call(DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) + { + Commands::introspect(*s, msg); + } + else + { + Clients::iterator client = clients.find(msg.get_sender()); + if (client == clients.end()) + { + y2mil("client connected invisible '" << msg.get_sender() << "'"); + client = client_connected(msg.get_sender()); + s->set_idle_timeout(-1); + } + + client->add_task(*s, msg); + } - boost::unique_lock dbus_lock(conn.mutex); + return DBUS_HANDLER_RESULT_HANDLED; + } - conn.read_write(10); // TODO + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} - DBusMessage* tmp = dbus_connection_pop_message(conn.get_connection()); - if (!tmp) - continue; - dbus_lock.unlock(); +DBusHandlerResult +message_func2(DBusConnection* connection, DBusMessage* message, void* data) +{ + DBus::Server* s = static_cast(data); + + DBus::Message msg(message); - DBus::Message msg(tmp); + if (msg.get_type() == DBUS_MESSAGE_TYPE_SIGNAL) + { + y2mil("signal sender:'" << msg.get_sender() << "' path:'" << + msg.get_path() << "' interface:'" << msg.get_interface() << + "' member:'" << msg.get_member() << "'"); - switch (msg.get_type()) + if (msg.is_signal(DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { - case DBUS_MESSAGE_TYPE_METHOD_CALL: + string name, old_owner, new_owner; + + DBus::Hihi hihi(msg); + hihi >> name >> old_owner >> new_owner; + + if (name == new_owner && old_owner.empty()) { - y2mil("method call sender:'" << msg.get_sender() << "' path:'" << - msg.get_path() << "' interface:'" << msg.get_interface() << - "' member:'" << msg.get_member() << "'"); - - if (msg.is_method_call(DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) - { - Commands::introspect(conn, msg); - break; - } - - Clients::iterator client = clients.find(msg.get_sender()); - if (client == clients.end()) - { - y2mil("client connected invisible '" << msg.get_sender() << "'"); - client = client_connected(msg.get_sender()); - } - - client->add_task(conn, msg); + y2mil("client connected '" << name << "'"); + client_connected(name); + s->reset_idle_count(); + s->set_idle_timeout(-1); } - break; - case DBUS_MESSAGE_TYPE_SIGNAL: + if (name == old_owner && new_owner.empty()) { - y2mil("signal sender:'" << msg.get_sender() << "' path:'" << - msg.get_path() << "' interface:'" << msg.get_interface() << - "' member:'" << msg.get_member() << "'"); - - if (msg.is_signal(DBUS_INTERFACE_DBUS, "NameOwnerChanged")) - { - string name, old_owner, new_owner; - - DBus::Hihi hihi(msg); - hihi >> name >> old_owner >> new_owner; - - if (name == new_owner && old_owner.empty()) - { - y2mil("client connected '" << name << "'"); - client_connected(name); - } - - if (name == old_owner && new_owner.empty()) - { - y2mil("client disconnected '" << name << "'"); - client_disconnected(name); - } - } + y2mil("client disconnected '" << name << "'"); + client_disconnected(name); + if (clients.empty()) + s->set_idle_timeout(30); } - break; - } - idle = 0; + return DBUS_HANDLER_RESULT_HANDLED; + } } - y2mil("Idle - exiting"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } +DBusObjectPathVTable dbus_vtable1 = { + unregister_func, message_func1, NULL, NULL, NULL, NULL +}; + +DBusObjectPathVTable dbus_vtable2 = { + unregister_func, message_func2, NULL, NULL, NULL, NULL +}; + + void log_do(LogLevel level, const string& component, const char* file, const int line, const char* func, const string& text) { - cerr << text << endl; + cout << /* boost::this_thread::get_id() << " " << */ text << endl; } @@ -1298,9 +1308,25 @@ main(int argc, char** argv) setLogDo(&log_do); #endif - DBus::Connection conn(DBUS_BUS_SYSTEM); + dbus_threads_init_default(); + + DBus::Server server(DBUS_BUS_SYSTEM); + + server.set_idle_timeout(30); + + y2mil("Requesting DBus name"); + + server.request_name("org.opensuse.Snapper", DBUS_NAME_FLAG_REPLACE_EXISTING); + + y2mil("Listening for method calls and signals"); + + server.register_object_path(PATH, &dbus_vtable1, &server); + server.register_object_path(DBUS_PATH_DBUS, &dbus_vtable2, &server); + server.add_match("type='signal', interface='" DBUS_INTERFACE_DBUS "', member='NameOwnerChanged'"); + + server.run(); - listen(conn); + y2mil("Exiting"); return 0; } diff --git a/snapper/Logger.cc b/snapper/Logger.cc index fbbff3d0..a6b6e2a7 100644 --- a/snapper/Logger.cc +++ b/snapper/Logger.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include "config.h" @@ -66,6 +67,10 @@ namespace snapper string prefix = sformat("%s %s libsnapper(%d) %s(%s):%d", datetime(time(0), false, true).c_str(), ln[level], getpid(), file, func, line); + static boost::mutex mutex; + + boost::lock_guard lock(mutex); + FILE* f = fopen(filename.c_str(), "a"); if (f) {