Author: lslezak
Date: Fri Aug 29 15:40:09 2008
New Revision: 50486
URL: http://svn.opensuse.org/viewcvs/yast?rev=50486&view=rev
Log:
- created a base class DBusServerBase for all DBus services, moving the
shared code there
Added:
branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.cc
branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.h
branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.cc
branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.h
branches/tmp/lslezak/core/liby2dbus/src/DBusSignature.cc
branches/tmp/lslezak/core/liby2dbus/src/DBusSignature.h
Modified:
branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.cc
branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.h
branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.cc
branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.h
branches/tmp/lslezak/core/liby2dbus/src/Makefile.am
Modified: branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.cc
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.cc?rev=50486&r1=50485&r2=50486&view=diff
==============================================================================
--- branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.cc (original)
+++ branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.cc Fri Aug 29 15:40:09 2008
@@ -14,36 +14,16 @@
#include
#include
-#ifdef HAVE_POLKIT
-#include "PolKit.h"
-#endif
-
#include
#include
#include
-extern "C"
-{
-// nanosleep()
-#include
-// stat()
-#include
-}
-
-// ostringstream
-#include <sstream>
+#include <functional>
-static bool finish = false;
-
-
-DBusModulesServer::DBusModulesServer(const std::string &name_space)
+DBusModulesServer::DBusModulesServer(const std::string &name_space) : e(this)
{
- dbus_threads_init_default();
-
- y2internal("Starting DBus service for namespace %s", name_space.c_str());
-
// create the namespace
- YBlockPtr block = Bytecode::readModule (name_space);
+ YBlockPtr block = Bytecode::readModule(name_space);
if (block == NULL)
{
@@ -85,319 +65,80 @@
{
}
-
-bool DBusModulesServer::connect()
-{
- if (!ns)
- {
- y2milestone("Could not load the namespace, not connecting to DBus");
- return false;
- }
-
- // connect to DBus, request a service name
- return connection.connect(DBUS_BUS_SYSTEM, "org.opensuse.yast.modules");
-}
-
-// set 30 second timer
-void DBusModulesServer::resetTimer()
+void DBusModulesServer::registerFunctions(const std::string &interface_prefix)
{
- ::alarm(30);
-}
-
-// NOTE: this is a signal handler, do only really necessary tasks here!
-// be aware of non-reentrant functions!
-void sig_timer(int signal, siginfo_t *info, void *data)
-{
- if (signal == SIGALRM)
- {
- // set the finish flag for the main loop
- finish = true;
- }
-}
-
-void DBusModulesServer::registerSignalHandler()
-{
- struct sigaction new_action, old_action;
-
- // use sa_sigaction parameter
- new_action.sa_flags = SA_SIGINFO;
- new_action.sa_sigaction = &sig_timer;
- ::sigemptyset(&new_action.sa_mask);
-
- if (::sigaction(SIGALRM, &new_action, &old_action))
- {
- y2error("Cannot register SIGALRM handler!");
- }
-}
-
-bool DBusModulesServer::canFinish()
-{
- // check if clients are still running,
- // remove finished clients
- for(Clients::iterator it = clients.begin();
- it != clients.end();)
+ if (ns)
{
- DBusCaller caller = it->second;
-
- if (!caller.isRunning())
- {
- Clients::iterator remove_it(it);
-
- // move the current iterator
- it++;
-
- y2milestone("Removing client %s (pid %d) from list", (remove_it->first).c_str(), caller.getPid());
-
- clients.erase(remove_it);
- }
- else
- {
- // the process is still running
- // no need to check the other clients
- // we have to still run for at least this client
- y2debug("Client %s PID %d is still running", (it->first).c_str(), caller.getPid());
- break;
- }
- }
-
- // if there is no client the server can be finished
- return clients.size() == 0;
-}
-
-/**
- * Server that exposes a method call and waits for it to be called
- */
-void DBusModulesServer::run(bool forever)
-{
- y2milestone("Listening for incoming DBus messages...");
-
- if (forever)
- y2milestone("Timer disabled");
- else
- registerSignalHandler();
+ unsigned symbols = ns->symbolCount();
+ unsigned index = 0;
- // mainloop
- while (true)
- {
- // the time is over
- if (finish)
+ while(index < symbols)
{
- y2milestone("Timout signal received");
+ SymbolEntryPtr symbol = ns->symbolEntry(index);
- if (canFinish())
- {
- break;
- }
- else
+ if (symbol)
{
- // reset the flag
- finish = false;
-
- // set a new timer
- resetTimer();
- }
- }
-
- // set 1 second timeout
- connection.setTimeout(1000);
- // try reading a message from DBus
- DBusMsg request(connection.receive());
-
- // check if a message was received
- if (request.empty())
- {
- continue;
- }
-
- // reset the timer when a message is received
- if (! forever)
- resetTimer();
-
- // create a reply to the message
- DBusMsg reply;
-
- y2milestone("Received request from %s: interface: %s, method: %s", request.sender().c_str(),
- request.interface().c_str(), request.method().c_str());
-
- // check this is a method call for the right object, interface & method
- if (request.type() == DBUS_MESSAGE_TYPE_METHOD_CALL && request.interface() == "org.opensuse.yast.modules.Methods" && request.path() == "/Modules")
- {
- std::string method(request.method());
+ // name of the method
+ const char *name = symbol->name();
+ // type
+ constTypePtr type = symbol->type();
- YCPValue arg0;
+ if (type->isFunction())
+ {
+ constFunctionTypePtr fptr = constFunctionTypePtr(type);
- bool check_ok = true;
+ constTypePtr rettype = fptr->returnType();
- if (check_ok)
- {
-/*
- YCPValue arg = request.getYCPValue(1);
- YCPValue opt = request.getYCPValue(2);
-*/
- std::string caller(request.sender());
-/*
-#ifdef HAVE_POLKIT
- std::string arg_str, opt_str;
-
- if (!arg.isNull())
- {
- arg_str = arg->toString();
- }
+ DBusSignature sig;
- if (!opt.isNull())
- {
- opt_str = opt->toString();
- }
+ // add return type
+ std::string rett(Y2Dtype(rettype));
- // PolicyKit check
- if (!isActionAllowed(caller, pth->toString(), method, arg_str, opt_str))
- {
- // access denied
- reply.createError(request, "System policy does not allow you to do the action", DBUS_ERROR_ACCESS_DENIED);
- }
- else
-#endif
-*/ {
- y2debug("Request from: %s", caller.c_str());
- // remember the client
- if (clients.find(caller) == clients.end())
+ if (!rett.empty())
{
- DBusCaller c(caller, connection);
- // insert the dbus name and PID
- Clients::value_type new_client(caller, c);
- y2milestone("Added new client %s (pid %d)", caller.c_str(), c.getPid());
- clients.insert(new_client);
+ sig.retval = DBusArgument("ret", rett);
}
- YCPValue ret;
-
- constTypePtr t = searchFuncType(method);
+ // add parameter types
+ int params = fptr->parameterCount();
+ int parindex = 0;
+ DBusSignature::Params p;
- if (t)
+ bool params_ok = true;
+ while(parindex < params)
{
- constFunctionTypePtr fptr = constFunctionTypePtr(t);
- int reqarg = fptr->parameterCount();
+ std::string partype(Y2Dtype(fptr->parameterType(parindex)));
- if (request.arguments() == reqarg)
+ if (!partype.empty())
{
- // create function call
- Y2Function *y2func = ns->createFunctionCall(method.c_str(), t);
-
- if (y2func)
- {
- int index = 0;
-
- while(index < reqarg)
- {
- YCPValue arg = request.getYCPValue(index);
- y2func->appendParameter(arg);
- index ++;
- }
-
- if (y2func->finishParameters())
- {
- // call the function
- ret = y2func->evaluateCall();
- }
- else
- {
- y2error("Wrong parameters to function %s", method.c_str());
- }
- }
+ DBusArgument param("param", partype);
+ p.push_back(param);
}
else
{
- y2error("Function %s got %d parameters instead of %d", method.c_str(), request.arguments(), fptr->parameterCount());
+ y2warning("Function %s is not exported due to an unsupported parameter type", name);
+ params_ok = false;
+ break;
}
+ parindex++;
}
- reply.createReply(request);
-
- if (!ret.isNull())
+ if (params_ok)
{
- y2milestone("Result: %s", ret->toString().c_str());
- reply.addYCPValue(ret);
+ sig.params = p;
+ // register the function: register_function(object, interface, method, signature, handler)
+ register_method(ns->name(), interface_prefix, name, sig, e);
}
- else
- reply.addYCPValue(YCPVoid());
}
}
- }
- // handle Introspection request from "org.freedesktop.DBus.Introspectable" "Introspect"
- else if (request.isMethodCall(DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
- {
- y2milestone("Requesting path: %s", request.path().c_str());
- // define all exported methods here
- std::string introdata = createIntrospectionData();
-
- const char *introspect = (request.path() != "/Modules") ?
-// introcpection data for the root node
-DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-"<node>"
-" <interface name='org.freedesktop.DBus.Introspectable'>"
-" <method name='Introspect'>"
-" <arg name='xml_data' type='s' direction='out'/>"
-" </method>"
-" </interface>"
-" <node name='Modules'/>"
-"</node>" :
-introdata.c_str();
-
- // create a reply to the request
- reply.createReply(request);
- reply.addString(introspect);
- }
- else if (request.type() == DBUS_MESSAGE_TYPE_METHOD_CALL)
- {
- y2warning("Ignoring unknown interface or method call: interface: %s, method: %s",
- request.interface().c_str(), request.method().c_str());
- // report error
- reply.createError(request, "Unknown object, interface or method", DBUS_ERROR_UNKNOWN_METHOD);
- }
- else if (request.type() == DBUS_MESSAGE_TYPE_ERROR)
- {
- DBusError error;
- dbus_error_init(&error);
-
- dbus_set_error_from_message(&error, request.getMessage());
-
- if (dbus_error_is_set(&error))
- {
- y2error("Received an error: %s: %s", error.name, error.message);
- }
-
- dbus_error_free(&error);
- }
- else if (request.type() == DBUS_MESSAGE_TYPE_SIGNAL)
- {
- y2error("Received a signal: interface: %s method: %s", request.interface().c_str(), request.method().c_str());
- }
-
- // was a reply set?
- if (!reply.empty())
- {
- // send the reply
- if (!connection.send(reply))
- {
- y2error("Cannot send the result");
- }
- else
- {
- y2milestone("Flushing connection...");
- connection.flush();
- y2milestone("...done");
- }
+ index++;
}
-
- y2milestone("Message processed");
}
-
- y2milestone("Finishing the DBus service");
}
-std::string Y2Dtype(constTypePtr type)
+std::string DBusModulesServer::Y2Dtype(constTypePtr type) const
{
YCPValueType vt = type->valueType();
std::string ret;
@@ -411,7 +152,7 @@
case(YT_STRING) : ret = DBUS_TYPE_STRING_AS_STRING; break;
case(YT_PATH) : ret = DBUS_TYPE_STRING_AS_STRING; break;
case(YT_SYMBOL) : ret = DBUS_TYPE_STRING_AS_STRING; break;
- case(YT_LIST) : ret = DBUS_TYPE_ARRAY_AS_STRING; break;
+// case(YT_LIST) : ret = DBUS_TYPE_ARRAY_AS_STRING; break;
default : y2warning("Value type %d is not supported", vt); break;
/*
@@ -435,32 +176,7 @@
return ret;
}
-#ifdef HAVE_POLKIT
-bool DBusModulesServer::isActionAllowed(const std::string &caller, const std::string &path, const std::string &method,
- const std::string &arg, const std::string &opt)
-{
- // create actionId
- static const char *polkit_prefix = "org.opensuse.yast.scr";
- std::string action_id(PolKit::createActionId(polkit_prefix, path, method, arg, opt));
-
- bool ret = false;
-
- // check the policy here
- if (policykit.isDBusUserAuthorized(action_id, caller, connection.getConnection()))
- {
- y2security("User is authorized to do action %s", action_id.c_str());
- ret = true;
- }
- else
- {
- y2security("User is NOT authorized to do action %s", action_id.c_str());
- }
-
- return ret;
-}
-#endif
-
-constTypePtr DBusModulesServer::searchFuncType(const std::string &fname)
+constTypePtr DBusModulesServer::searchFuncType(const std::string &fname) const
{
if (ns)
{
@@ -493,89 +209,70 @@
return NULL;
}
-std::string DBusModulesServer::createIntrospectionData()
+bool DBusModulesServer::connect()
{
- std::string ret(
-DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-"<node>"
-" <interface name='org.freedesktop.DBus.Introspectable'>"
-" <method name='Introspect'>"
-" <arg name='xml_data' type='s' direction='out'/>"
-" </method>"
-" </interface>"
+ registerFunctions("org.opensuse.yast.modules");
+ return DBusServerBase::connect(SYSTEM, "org.opensuse.yast.modules");
+}
-" <interface name='org.opensuse.yast.modules.Methods'>");
+DBusMsg DBusModulesServer::handler(const DBusMsg &request)
+{
+ YCPValue ret;
+ DBusMsg reply;
- if (ns)
+ std::string method = request.method();
+
+ constTypePtr t = searchFuncType(method);
+
+ if (t)
{
- unsigned symbols = ns->symbolCount();
- unsigned index = 0;
+ constFunctionTypePtr fptr = constFunctionTypePtr(t);
+ int reqarg = fptr->parameterCount();
- while(index < symbols)
+ if (request.arguments() == reqarg)
{
- SymbolEntryPtr symbol = ns->symbolEntry(index);
+ // create function call
+ Y2Function *y2func = ns->createFunctionCall(method.c_str(), t);
- if (symbol)
+ if (y2func)
{
- const char *name = symbol->name();
- constTypePtr type = symbol->type();
+ int index = 0;
- if (type->isFunction())
+ while(index < reqarg)
{
- constFunctionTypePtr fptr = constFunctionTypePtr(type);
-
- constTypePtr rettype = fptr->returnType();
-
- std::string method(" <method name='" + std::string(name) + "'>");
-
- // add return type
- std::string rett(Y2Dtype(rettype));
-
- if (!rett.empty())
- {
- method += " <arg name='ret' type='" + rett + "' direction='out'/>";
- }
-
- // add parameter types
- int params = fptr->parameterCount();
- int parindex = 0;
-
- bool params_ok = true;
- while(parindex < params)
- {
- std::string partype(Y2Dtype(fptr->parameterType(parindex)));
-
- if (!partype.empty())
- {
- method += " <arg name='param' type='" + partype + "' direction='in'/>";
- }
- else
- {
- y2warning("Function %s is not exported due to an unsupported parameter type", name);
- params_ok = false;
- break;
- }
-
- parindex++;
- }
+ YCPValue arg = request.getYCPValue(index);
+ y2func->appendParameter(arg);
+ index ++;
+ }
- if (params_ok)
- {
- method += " </method>";
- ret += method;
- }
+ if (y2func->finishParameters())
+ {
+ // call the function
+ ret = y2func->evaluateCall();
+ }
+ else
+ {
+ y2error("Wrong parameters to function %s", method.c_str());
}
}
-
- index++;
+ }
+ else
+ {
+ y2error("Function %s got %d parameters instead of %d", method.c_str(), request.arguments(), fptr->parameterCount());
}
}
+ else
+ {
+ y2internal("Function %s was not found although it was registered", method.c_str());
+ }
- ret +=
-" </interface>"
-"</node>";
-
- return ret;
-}
+ reply.createReply(request);
+ if (!ret.isNull())
+ {
+ y2milestone("Result: %s", ret->toString().c_str());
+ reply.addYCPValue(ret);
+ }
+ return reply;
+}
Modified: branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.h?rev=50486&r1=50485&r2=50486&view=diff
==============================================================================
--- branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.h (original)
+++ branches/tmp/lslezak/core/dbus/namespace_service/DBusModulesServer.h Fri Aug 29 15:40:09 2008
@@ -3,75 +3,57 @@
DBusModulesServer.h
*/
-#ifndef DBUSSERVER_H
-#define DBUSSERVER_H
+#ifndef DBUSMODUELSSERVER_H
+#define DBUSMODULESSERVER_H
#include "config.h"
-#include
-
-#include "DBusConn.h"
-#include "DBusCaller.h"
-
-#ifdef HAVE_POLKIT
-#include "PolKit.h"
-#endif
-
-extern "C"
-{
-#include
-#include
-}
-
-#include <map>
+#include
+#include
#include
+#include <functional>
+
class Y2Namespace;
-class DBusModulesServer
+class DBusModulesServer : public DBusServerBase
{
public:
DBusModulesServer(const std::string &name_space);
- ~DBusModulesServer();
+ virtual ~DBusModulesServer();
+
+ virtual bool connect();
- bool connect();
- /**
- * Runs the server
- * @param forever for debugging, disables exiting after timeout
- */
- void run(bool forever = false);
private:
- DBusConn connection;
+ // the wrapped Yast namespace
+ Y2Namespace *ns;
-#ifdef HAVE_POLKIT
- PolKit policykit;
- bool isActionAllowed(const std::string &caller, const std::string &path,
- const std::string &method, const std::string &arg, const std::string &opt);
-#endif
+ constTypePtr searchFuncType(const std::string &fname) const;
+ std::string Y2Dtype(constTypePtr type) const;
- // SCR access
- Y2Namespace *ns;
+ // register the functions from the namespace to DBus service
+ void registerFunctions(const std::string &interface_prefix);
+
+ DBusMsg handler(const DBusMsg &request);
+
+ class Callback : public std::function
+ {
+ DBusModulesServer *ms;
+
+ public:
- // create introspection data for the namespace
- std::string createIntrospectionData();
-
- constTypePtr searchFuncType(const std::string &fname);
-
- // disable copying
- DBusModulesServer(const DBusModulesServer&);
- DBusModulesServer& operator=(const DBusModulesServer&);
-
- void resetTimer();
- void registerSignalHandler();
- bool canFinish();
+ Callback(DBusModulesServer *s) : ms(s) {}
+ ~Callback() {}
- typedef std::map Clients;
+ DBusMsg operator()(const DBusMsg &request)
+ { return ms ? ms->handler(request) : DBusMsg(); }
+ };
- Clients clients;
+ Callback e;
};
Added: branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.cc
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.cc?rev=50486&view=auto
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.cc (added)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.cc Fri Aug 29 15:40:09 2008
@@ -0,0 +1,30 @@
+
+/*
+ class DBusArgument
+*/
+
+#include "DBusArgument.h"
+
+DBusArgument::DBusArgument(const std::string &arg_name, const std::string &arg_signature) : name(arg_name), signature(arg_signature)
+{
+}
+
+DBusArgument::~DBusArgument()
+{
+}
+
+bool DBusArgument::empty() const
+{
+ return signature.empty();
+}
+
+std::string DBusArgument::asXML(bool direction_in) const
+{
+ if (empty())
+ {
+ return std::string();
+ }
+
+ return std::string("<arg name='" + name + "' type='" + signature + "' direction='" + (direction_in ? "in" : "out") + "'/>");
+}
+
Added: branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.h?rev=50486&view=auto
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.h (added)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusArgument.h Fri Aug 29 15:40:09 2008
@@ -0,0 +1,28 @@
+
+/*
+ class DBusArgument
+*/
+
+#ifndef DBUSARGUMENT_H
+#define DBUSARGUMENT_H
+
+#include <string>
+
+class DBusArgument
+{
+
+ public:
+
+ DBusArgument(const std::string &arg_name = std::string(), const std::string &arg_signature = std::string());
+ ~DBusArgument();
+
+ bool empty() const;
+
+ // default direction is "in" (input parameter)
+ std::string asXML(bool direction_in = true) const;
+
+ std::string name;
+ std::string signature;
+};
+
+#endif
Modified: branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.cc
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.cc?rev=50486&r1=50485&r2=50486&view=diff
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.cc (original)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.cc Fri Aug 29 15:40:09 2008
@@ -442,7 +442,7 @@
}
-YCPValue DBusMsg::getYCPValueRaw(DBusMessageIter *it, const std::string &ycp_type)
+YCPValue DBusMsg::getYCPValueRaw(DBusMessageIter *it, const std::string &ycp_type) const
{
YCPValue ret;
@@ -658,7 +658,7 @@
return ret;
}
-YCPValue DBusMsg::getYCPValue(DBusMessageIter *it)
+YCPValue DBusMsg::getYCPValue(DBusMessageIter *it) const
{
int type = dbus_message_iter_get_arg_type(it);
y2debug("Found DBus type: %d (%c)", type, (char)type);
@@ -739,7 +739,7 @@
return (received_nil) ? YCPVoid() : ret;
}
-YCPValue DBusMsg::getYCPValue(int index)
+YCPValue DBusMsg::getYCPValue(int index) const
{
YCPValue ret = YCPNull();
Modified: branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.h?rev=50486&r1=50485&r2=50486&view=diff
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.h (original)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusMsg.h Fri Aug 29 15:40:09 2008
@@ -43,7 +43,7 @@
bool addDouble(double val);
bool addYCPValue(const YCPValue &val);
- YCPValue getYCPValue(int index);
+ YCPValue getYCPValue(int index) const;
bool isMethodCall(const std::string &interface, const std::string &method) const;
int arguments() const;
@@ -70,8 +70,8 @@
int typeInt(const YCPValue &val) const;
const char * typeStr(const YCPValue &val) const;
- YCPValue getYCPValue(DBusMessageIter *it);
- YCPValue getYCPValueRaw(DBusMessageIter *it, const std::string &ycp_type = std::string());
+ YCPValue getYCPValue(DBusMessageIter *it) const;
+ YCPValue getYCPValueRaw(DBusMessageIter *it, const std::string &ycp_type = std::string()) const;
};
#endif
Added: branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.cc
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.cc?rev=50486&view=auto
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.cc (added)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.cc Fri Aug 29 15:40:09 2008
@@ -0,0 +1,475 @@
+
+/*
+
+ DBus server
+
+ */
+
+#include
+
+#include "DBusServerBase.h"
+#include "DBusMsg.h"
+
+#include
+
+extern "C"
+{
+// nanosleep()
+#include
+// stat()
+#include
+#include
+#include
+}
+
+// ostringstream
+#include <sstream>
+
+// std::pair
+#include <utility>
+
+static bool finish = false;
+
+DBusServerBase::DBusServerBase()
+{
+ dbus_threads_init_default();
+}
+
+DBusServerBase::~DBusServerBase()
+{
+}
+
+
+bool DBusServerBase::connect(DBusType bustype, const std::string &sname)
+{
+ DBusBusType bt = (bustype == SYSTEM) ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION;
+
+ service_name = sname;
+
+ // connect to DBus, request a service name
+ return connection.connect(bt, service_name.c_str());
+}
+
+// set 30 second timer
+void DBusServerBase::resetTimer()
+{
+ ::alarm(30);
+}
+
+// NOTE: this is a signal handler, do only really necessary tasks here!
+// be aware of non-reentrant functions!
+void sig_timer(int signal, siginfo_t *info, void *data)
+{
+ if (signal == SIGALRM)
+ {
+ // set the finish flag for the main loop
+ finish = true;
+ }
+}
+
+void DBusServerBase::registerSignalHandler()
+{
+ struct sigaction new_action, old_action;
+
+ // use sa_sigaction parameter
+ new_action.sa_flags = SA_SIGINFO;
+ new_action.sa_sigaction = &sig_timer;
+ ::sigemptyset(&new_action.sa_mask);
+
+ if (::sigaction(SIGALRM, &new_action, &old_action))
+ {
+ y2error("Cannot register SIGALRM handler!");
+ }
+}
+
+bool DBusServerBase::canFinish()
+{
+ // check if clients are still running,
+ // remove finished clients
+ for(Clients::iterator it = clients.begin();
+ it != clients.end();)
+ {
+ DBusCaller caller = it->second;
+
+ if (!caller.isRunning())
+ {
+ Clients::iterator remove_it(it);
+
+ // move the current iterator
+ it++;
+
+ y2milestone("Removing client %s (pid %d) from list", (remove_it->first).c_str(), caller.getPid());
+
+ clients.erase(remove_it);
+ }
+ else
+ {
+ // the process is still running
+ // no need to check the other clients
+ // we have to still run for at least this client
+ y2debug("Client %s PID %d is still running", (it->first).c_str(), caller.getPid());
+ break;
+ }
+ }
+
+ // if there is no client the server can be finished
+ return clients.size() == 0;
+}
+
+/**
+ * Server that exposes a method call and waits for it to be called
+ */
+void DBusServerBase::run(bool forever)
+{
+ y2milestone("Listening for incoming DBus messages...");
+
+ if (forever)
+ y2milestone("Timer disabled");
+ else
+ registerSignalHandler();
+
+ // mainloop
+ while (true)
+ {
+ // the time is over
+ if (finish)
+ {
+ y2milestone("Timout signal received");
+
+ if (canFinish())
+ {
+ break;
+ }
+ else
+ {
+ // reset the flag
+ finish = false;
+
+ // set a new timer
+ resetTimer();
+ }
+ }
+
+ // set 1 second timeout
+ connection.setTimeout(1000);
+ // try reading a message from DBus
+ DBusMsg request(connection.receive());
+
+ // check if a message was received
+ if (request.empty())
+ {
+ continue;
+ }
+
+ // reset the timer when a message is received
+ if (! forever)
+ resetTimer();
+
+ // create a reply to the message
+ DBusMsg reply;
+
+ y2milestone("Received request from %s: interface: %s, method: %s", request.sender().c_str(),
+ request.interface().c_str(), request.method().c_str());
+
+ // handle Introspection request from "org.freedesktop.DBus.Introspectable" "Introspect"
+ if (request.isMethodCall(DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
+ {
+ y2milestone("Requesting path: %s", request.path().c_str());
+ std::string introspect;
+
+ // root node?
+ if (request.path() == "/")
+ {
+ introspect =
+ // introcpection data for the root node
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>"
+ " <interface name='org.freedesktop.DBus.Introspectable'>"
+ " <method name='Introspect'>"
+ " <arg name='xml_data' type='s' direction='out'/>"
+ " </method>"
+ " </interface>";
+
+ for(Objects::const_iterator i = registered_objects.begin();
+ i != registered_objects.end();
+ ++i)
+ {
+ introspect += " <node name='" + i->first + "'/>";
+ }
+
+ // close the node section
+ introspect += "</node>";
+ }
+ else
+ {
+ introspect =
+ // introcpection data for the root node
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+ "<node>"
+ " <interface name='org.freedesktop.DBus.Introspectable'>"
+ " <method name='Introspect'>"
+ " <arg name='xml_data' type='s' direction='out'/>"
+ " </method>"
+ " </interface>";
+
+ std::string objname = request.path();
+
+ // remove the slash at the beginning
+ if (objname.size() > 0 && objname[0] == '/')
+ {
+ objname.erase(objname.begin());
+ }
+
+ // return properties of the registered object only
+ Objects::const_iterator i = registered_objects.find(objname);
+
+ if (i == registered_objects.end())
+ {
+ y2warning("Requested object %s is not registered", objname.c_str());
+ }
+ else
+ {
+ ObjectData od = i->second;
+
+ // iterate over the interfaces
+ for(ObjectData::const_iterator ii = od.begin();
+ ii != od.end();
+ ++ii)
+ {
+ introspect += " <interface name='" + ii->first + "'>";
+
+ InterfaceData id = ii->second;
+
+ // iterate over all methods
+ for(InterfaceData::const_iterator iii = id.begin();
+ iii != id.end();
+ ++iii)
+ {
+ // iterate over the methods in the interface
+ introspect += " <method name='" + iii->first + "'>";
+
+ // iterate over all parameters
+ DBusSignature sig = iii->second.second;
+
+ // add somthing like "<arg name='xml_data' type='s' direction='out'/>"
+ introspect += sig.asXML();
+
+ introspect += " </method>";
+ }
+
+ introspect += " </interface>";
+ }
+
+ }
+ }
+
+ // create a reply to the request
+ reply.createReply(request);
+ reply.addString(introspect.c_str());
+ }
+ else if (request.type() == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ // TODO check the policy
+
+ // find the registered object
+ std::string objname = request.path();
+
+ // remove the slash at the beginning
+ if (objname.size() > 0 && objname[0] == '/')
+ {
+ objname.erase(objname.begin());
+ }
+
+ // search the object
+ Objects::const_iterator i = registered_objects.find(objname);
+
+ bool found = false;
+
+ if (i != registered_objects.end())
+ {
+ ObjectData::const_iterator ii = i->second.find(request.interface());
+
+ if (ii != i->second.end())
+ {
+ InterfaceData::const_iterator iii = ii->second.find(request.method());
+
+ if (iii != ii->second.end())
+ {
+ MethodData md = iii->second;
+ methodHandler mh = md.first;
+
+ y2milestone("Evaluating method: object %s interface: %s, method: %s",
+ request.path().c_str(), request.interface().c_str(), request.method().c_str());
+
+ // call the registered callback
+ found = true;
+ reply = mh(request);
+ }
+ else
+ {
+ y2warning("Object %s does not provide method %s in interface %s",
+ objname.c_str(), request.path().c_str(), request.interface().c_str());
+ }
+ }
+ else
+ {
+ y2warning("Object %s does not provide interface %s",
+ objname.c_str(), request.interface().c_str());
+ }
+ }
+ else
+ {
+ y2warning("Object %s is not registered", objname.c_str());
+ }
+
+ if (!found)
+ {
+ // report error
+ reply.createError(request, "Unknown object, interface or method", DBUS_ERROR_UNKNOWN_METHOD);
+ }
+ }
+ else if (request.type() == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ DBusError error;
+ dbus_error_init(&error);
+
+ dbus_set_error_from_message(&error, request.getMessage());
+
+ if (dbus_error_is_set(&error))
+ {
+ y2error("Received an error: %s: %s", error.name, error.message);
+ }
+
+ dbus_error_free(&error);
+ }
+ else if (request.type() == DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ // singals are not supported
+ y2error("Received a signal: interface: %s method: %s", request.interface().c_str(), request.method().c_str());
+ }
+
+ // was a reply set?
+ if (!reply.empty())
+ {
+ // send the reply
+ if (!connection.send(reply))
+ {
+ y2error("Cannot send the result");
+ }
+ else
+ {
+ y2milestone("Flushing connection...");
+ connection.flush();
+ y2milestone("...done");
+ }
+ }
+
+ y2milestone("Message processed");
+ }
+
+ y2milestone("Finishing the DBus service");
+}
+
+void DBusServerBase::register_method(const Object &obj, const Interface &intf, const Method &m, const DBusSignature &sig, methodHandler h)
+{
+ y2milestone("Registering DBus path: object %s interface %s method %s...", obj.c_str(), intf.c_str(), m.c_str());
+ Objects::iterator i = registered_objects.find(obj);
+
+ // create a new data item
+ MethodData md = std::make_pair(h, sig);
+
+ if (i == registered_objects.end())
+ {
+ // create a new object
+ InterfaceData id;
+ id[m] = md;
+
+ ObjectData od;
+ od[intf] = id;
+
+ registered_objects[obj] = od;
+ }
+ else
+ {
+ ObjectData od = i->second;
+
+ // search the interface
+ ObjectData::iterator ii = od.find(intf);
+
+ if (ii == od.end())
+ {
+ // the interface is not registered
+ // create a new object
+ InterfaceData id;
+ id[m] = md;
+
+ od[intf] = id;
+
+ registered_objects[obj] = od;
+ }
+ else
+ {
+ InterfaceData id = ii->second;
+
+ // search the method
+ InterfaceData::iterator iii = id.find(m);
+
+ if (iii == id.end())
+ {
+ // the method is not registered
+ // create a new object
+ id[m] = md;
+
+ od[intf] = id;
+
+ registered_objects[obj] = od;
+ }
+ else
+ {
+ y2warning("Object %s has already registered method %s in interface %s, updating...", obj.c_str(), m.c_str(), intf.c_str());
+
+ // update the registered data
+ id[m] = md;
+
+ od[intf] = id;
+
+ registered_objects[obj] = od;
+ }
+ }
+ }
+}
+
+
+/*
+#ifdef HAVE_POLKIT
+bool DBusServerBase::isActionAllowed(const std::string &caller, const std::string &path, const std::string &method,
+ const std::string &arg, const std::string &opt)
+{
+ // create actionId
+ static const char *polkit_prefix = "org.opensuse.yast.scr";
+ std::string action_id(PolKit::createActionId(polkit_prefix, path, method, arg, opt));
+
+ bool ret = false;
+
+ // check the policy here
+ if (policykit.isDBusUserAuthorized(action_id, caller, connection.getConnection()))
+ {
+ y2security("User is authorized to do action %s", action_id.c_str());
+ ret = true;
+ }
+ else
+ {
+ y2security("User is NOT authorized to do action %s", action_id.c_str());
+ }
+
+ return ret;
+}
+#endif
+*/
+
+
+std::string DBusServerBase::createActionId(const DBusMsg &msg)
+{
+ //TODO FIXME
+ return std::string();
+}
Added: branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.h
URL: http://svn.opensuse.org/viewcvs/yast/branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.h?rev=50486&view=auto
==============================================================================
--- branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.h (added)
+++ branches/tmp/lslezak/core/liby2dbus/src/DBusServerBase.h Fri Aug 29 15:40:09 2008
@@ -0,0 +1,93 @@
+
+/*
+ DBusServerBase.h
+*/
+
+#ifndef DBUSSERVERBASE_H
+#define DBUSSERVERBASE_H
+
+#include "config.h"
+
+extern "C"
+{
+#include
+#include
+}
+
+#include "DBusConn.h"
+#include "DBusCaller.h"
+#include "DBusSignature.h"
+
+#ifdef HAVE_POLKIT
+#include "PolKit.h"
+#endif
+
+#include <functional>
+
+#include <map>
+
+class DBusServerBase
+{
+ public:
+
+ DBusServerBase();
+ virtual ~DBusServerBase();
+
+ virtual bool connect() = 0;
+
+ /**
+ * Runs the server
+ * @param forever for debugging, disables exiting after timeout
+ */
+ void run(bool forever = false);
+
+
+ protected:
+ enum DBusType{ SESSION, SYSTEM };
+
+ bool connect(DBusType bustype, const std::string &sname);
+
+ typedef std::string Object;
+ typedef std::string Interface;
+ typedef std::string Method;
+
+ typedef std::function methodHandler;
+
+ void register_method(const Object &obj, const Interface &i, const Method &m, const DBusSignature &sig, methodHandler h);
+
+ // create PolicyKit action ID for the received message
+ virtual std::string createActionId(const DBusMsg &msg);
+
+ std::string service_name;
+
+
+ private:
+
+ // disable copying
+ DBusServerBase(const DBusServerBase&);
+ DBusServerBase& operator=(const DBusServerBase&);
+
+ void resetTimer();
+ void registerSignalHandler();
+ bool canFinish();
+
+ typedef std::pair MethodData;
+ typedef std::map InterfaceData;
+ typedef std::map ObjectData;
+ typedef std::map