Compare commits

...
28 Commits
Author SHA1 Message Date
Stanislav Angelovic b041f76bfc Update changelog for v0.2.6 2018-06-24 21:27:58 +02:00
Stanislav Angelovic f1ff05cb6f Bump up micro revision number 2018-06-22 12:36:14 +02:00
Stanislav Angelovič 44be60555d Merge pull request #11 from lukasdurfina/fix-memory-leak
Fix leak in Message due to missing unref of sd_bus_message
2018-06-19 12:18:55 +02:00
Lukas Durfina dfdc6b153e Message: fix missing release of sd_bus_message 2018-06-19 08:56:28 +02:00
Stanislav Angelovic fd3799dbc3 Fix sdbus::Struct initialization problem in newer compilers - use make_struct 2018-06-06 11:49:02 +02:00
Stanislav Angelovič 24b2f2bda3 Update ChangeLog for v0.2.5 2018-06-05 14:09:35 +00:00
Stanislav Angelovič d40fdf1b1c Merge pull request #10 from marek-szanyi/feature/fix_gcc_compiling
Among inherited c-tors, provide explicit Struct c-tor from tuple, since that is needed according to the standard
2018-06-05 16:04:35 +02:00
Marek Szanyi a395adbecf Change in logic when constructor is available 2018-06-05 15:52:59 +02:00
Marek Szanyi dafd7a791a Provide compiler specific ctor for Struct 2018-05-29 13:36:49 +02:00
Stanislav Angelovic 83ae4cf5ae Bump up micro revision number 2018-05-25 20:48:56 +02:00
Stanislav Angelovic b535198571 Little code cleanups and refactorings 2018-05-25 20:48:20 +02:00
Stanislav Angelovic d68be891ee Revert modification for clang, for now it fails on gcc 2018-03-15 17:16:23 +01:00
Stanislav Angelovič 10d0da9067 Update ChangeLog for v0.2.4 2018-03-15 16:06:05 +00:00
Stanislav Angelovic 2564bbfb21 Add object proxy factory overload that takes unique_ptr to connection 2018-03-15 17:03:49 +01:00
Stanislav Angelovič e1cf50d2cd Bump up version to 0.2.4 2018-03-15 15:33:34 +00:00
Stanislav Angelovič db5e9dc963 Merge pull request #6 from Kistler-Group/bugfix/fix-static-assert-problem-in-x64-google-tests
Make Variant conversion operator only present for true D-Bus types
2018-03-15 16:31:24 +01:00
Stanislav Angelovic 933e8e204d Make sure that Variant conversion operator is only present for true D-Bus type represntations in C++ 2018-03-15 16:22:06 +01:00
Stanislav Angelovič 47139527f4 Update using-sdbus-c++.md 2018-02-27 08:45:40 +00:00
Stanislav Angelovič b22cac9a63 Try to clarify connection to the systems bus vs. session bus in the tutorial 2018-02-27 08:43:08 +00:00
Stanislav Angelovič b81c4b494c Add clang workaround comment 2018-02-27 08:26:42 +00:00
Stanislav Angelovič 7e61a83d09 Merge pull request #2 from lejcik/master
Fix proposal for clang compilation issue
2018-02-27 08:57:48 +01:00
Viliam Lejcik dc5ec014eb Added constructor for sdbus::Struct 2017-12-18 19:19:27 +01:00
Viliam Lejcik f559fc0663 Added a test case that fails to compile with clang 2017-12-18 19:15:40 +01:00
Stanislav Angelovic b5866fe5e9 Fix handling of interrupt when polling 2017-12-14 12:58:50 +01:00
Stanislav Angelovič 96684ce37f Add design diagram and make additional adjustments in the tutorial 2017-12-14 10:43:41 +01:00
Stanislav Angelovic 55d8084729 Add class diagram 2017-12-14 10:30:55 +01:00
Stanislav Angelovič be754eb991 Merge pull request #1 from granxarixia/master
Close file descriptor of event loop's semaphore on exec
2017-12-06 15:26:57 +01:00
Michal Hucko 7fbc0e360d Close file descriptor of event loop's semaphore on exec 2017-12-06 13:52:40 +01:00
18 changed files with 534 additions and 255 deletions
+17
View File
@@ -0,0 +1,17 @@
v0.2.3
- Initially published version
v0.2.4
- Fixed closing of file descriptor of event loop's semaphore on exec
- Fixed interrupt handling when polling
- Improved tutorial
- Fixed issue with googlemock
- Added object proxy factory overload that takes unique_ptr to a connection
- Workaround: Clang compilation error when compiling sdbus::Struct (seems like an issue of Clang)
v0.2.5
- Real fix for issue with sdbus::Struct inherited constructors
- Little code refactorings and improvements
v0.2.6
- Fixed memory leak in Message copy operations
+1 -1
View File
@@ -36,7 +36,7 @@ References/documentation
Contributing
------------
Contributions that increase the library quality, functionality, or fix issues are very welcome. To introduce a change, please submit a merge request with a description.
Contributions that increase the library quality, functionality, or fix issues are very welcome. To introduce a change, please submit a pull request with a description.
Contact
-------
+1 -1
View File
@@ -5,7 +5,7 @@ AC_PREREQ(2.61)
# even micro numbers indicate released versions
m4_define(sdbus_cpp_version_major, 0)
m4_define(sdbus_cpp_version_minor, 2)
m4_define(sdbus_cpp_version_micro, 3)
m4_define(sdbus_cpp_version_micro, 6)
m4_define([sdbus_cpp_version],
[sdbus_cpp_version_major.sdbus_cpp_version_minor.sdbus_cpp_version_micro])
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+59
View File
@@ -0,0 +1,59 @@
@startuml
package "Public API" <<frame>> #DDDDDD {
interface IConnection {
+requestName()
+enterProcessLoop()
+leaveProcessLoop()
}
interface IObject {
+registerMethod()
+emitSignal()
}
interface IObjectProxy {
+callMethod()
+subscribeToSignal()
}
class Message {
+serialize(...)
+deserialize(...)
+send()
Type msgType
}
}
interface IConnectionInternal {
+addObjectVTable()
+createMethodCall()
+createSignal()
}
class Connection {
}
class Object {
IConnectionInternal& connection
string objectPath
List interfaces
List methods
}
class ObjectProxy {
IConnectionInternal& connection
string destination
string objectPath
}
IConnection <|-- Connection
IConnectionInternal <|- Connection
IObject <|-- Object
IObjectProxy <|-- ObjectProxy
Connection <-- Object : "use"
Connection <-- ObjectProxy : "use"
Message <.. Object : "send/receive"
Message <.. ObjectProxy : "send/receive"
@enduml
+35 -14
View File
@@ -75,17 +75,36 @@ Error signalling and propagation
The exception object carries the error name and error message with it.
sdbus-c++ design
----------------
The following diagram illustrates the major entities in sdbus-c++.
![class](sdbus-c++-class-diagram.png)
`IConnection` represents the concept of a D-Bus connection. You can connect to either the system bus or a session bus. Services can assign unique service names to those connections. A processing loop can be run on the connection.
`IObject` represents the concept of an object that exposes its methods, signals and properties. Its responsibilities are:
* registering (possibly multiple) interfaces and methods, signals, properties on those interfaces,
* emitting signals.
`IObjectProxy` represents the concept of the proxy, which is a view of the `Object` from the client side. Its responsibilities are:
* invoking remote methods of the corresponding object,
* registering handlers for signals.
`Message` class represents a message, which is the fundamental DBus concept. The message can be
* a method call (with serialized parameters),
* a method reply (with serialized return values),
* or a signal (with serialized parameters).
Multiple layers of sdbus-c++ API
-------------------------------
sdbus-c++ API comes in two layers:
* the basic layer, which is almost pure wrapper layer on top of sd-bus, using mechanisms that are native to C++,
* the convenience layer, building on top of the basic layer, which aims at providing shorter, safer, and more expressive way of writing the
client code.
* [the basic layer](#implementing-the-concatenator-example-using-basic-sdbus-c-api-layer), which is a simple wrapper layer on top of sd-bus, using mechanisms that are native to C++ (e.g. serialization/deserialization of data from messages),
* [the convenience layer](#implementing-the-concatenator-example-using-convenience-sdbus-c-api-layer), building on top of the basic layer, which aims at alleviating users from unnecessary details and enables them to write shorter, safer, and more expressive code.
sdbus-c++ also ships with a stub generator tool that converts D-Bus IDL in XML format into stub code for the adaptor as well as proxy part.
Hierarchically, these stubs provide yet another layer of convenience (the "stubs layer"), making it possible for D-Bus RPC calls to look like
native C++ calls on a local object.
sdbus-c++ also ships with a stub generator tool that converts D-Bus IDL in XML format into stub code for the adaptor as well as proxy part. Hierarchically, these stubs provide yet another layer of convenience (the "stubs layer"), making it possible for D-Bus RPC calls to completely look like native C++ calls on a local object.
An example: Number concatenator
-------------------------------
@@ -151,9 +170,9 @@ void concatenate(sdbus::Message& msg, sdbus::Message& reply)
int main(int argc, char *argv[])
{
// Create D-Bus connection and requests name on it.
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.sdbuscpp.concatenator";
auto connection = sdbus::createConnection(serviceName);
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create concatenator D-Bus object.
const char* objectPath = "/org/sdbuscpp/concatenator";
@@ -191,7 +210,9 @@ void onConcatenated(sdbus::Message& signalMsg)
int main(int argc, char *argv[])
{
// Create proxy object for the concatenator object on the server side
// Create proxy object for the concatenator object on the server side. Since we don't pass
// the D-Bus connection object to the proxy constructor, the proxy will internally create
// its own connection to the system bus.
const char* destinationName = "org.sdbuscpp.concatenator";
const char* objectPath = "/org/sdbuscpp/concatenator";
auto concatenatorProxy = sdbus::createObjectProxy(destinationName, objectPath);
@@ -237,7 +258,7 @@ int main(int argc, char *argv[])
```
The object proxy is created without explicitly providing a D-Bus connection as an argument in its factory function. In that case, the proxy
will create its own connection and listen to signals on it in a separate thread. That means the `onConcatenated` method is invoked always
will create its own connection to the *system* bus and listen to signals on it in a separate thread. That means the `onConcatenated` method is invoked always
in the context of a thread different from the main thread.
Implementing the Concatenator example using convenience sdbus-c++ API layer
@@ -291,9 +312,9 @@ std::string concatenate(const std::vector<int> numbers, const std::string& separ
int main(int argc, char *argv[])
{
// Create D-Bus connection and requests name on it.
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.sdbuscpp.concatenator";
auto connection = sdbus::createConnection(serviceName);
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create concatenator D-Bus object.
const char* objectPath = "/org/sdbuscpp/concatenator";
@@ -565,9 +586,9 @@ publishing the object.
int main(int argc, char *argv[])
{
// Create D-Bus connection and requests name on it.
// Create D-Bus connection to the system bus and requests name on it.
const char* serviceName = "org.sdbuscpp.concatenator";
auto connection = sdbus::createConnection(serviceName);
auto connection = sdbus::createSystemBusConnection(serviceName);
// Create concatenator D-Bus object.
const char* objectPath = "/org/sdbuscpp/concatenator";
+21
View File
@@ -225,6 +225,27 @@ namespace sdbus {
, std::string destination
, std::string objectPath );
/*!
* @brief Creates object proxy instance
*
* @param[in] connection D-Bus connection to be used by the proxy object
* @param[in] destination Bus name that provides a D-Bus object
* @param[in] objectPath Path of the D-Bus object
* @return Pointer to the object proxy instance
*
* The provided connection will be used by the proxy to issue calls against the object,
* and signals, if any, will be subscribed to on this connection. Object proxy becomes
* an exclusive owner of this connection.
*
* Code example:
* @code
* auto proxy = sdbus::createObjectProxy(std::move(connection), "com.kistler.foo", "/com/kistler/foo");
* @endcode
*/
std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( std::unique_ptr<sdbus::IConnection>&& connection
, std::string destination
, std::string objectPath );
/*!
* @brief Creates object proxy instance that uses its own D-Bus connection
*
+44
View File
@@ -53,6 +53,8 @@ namespace sdbus {
template <typename _T>
struct signature_of
{
static constexpr bool is_valid = false;
static const std::string str()
{
// sizeof(_T) < 0 is here to make compiler not being able to figure out
@@ -65,6 +67,8 @@ namespace sdbus {
template <>
struct signature_of<void>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "";
@@ -74,6 +78,8 @@ namespace sdbus {
template <>
struct signature_of<bool>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "b";
@@ -83,6 +89,8 @@ namespace sdbus {
template <>
struct signature_of<uint8_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "y";
@@ -92,6 +100,8 @@ namespace sdbus {
template <>
struct signature_of<int16_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "n";
@@ -101,6 +111,8 @@ namespace sdbus {
template <>
struct signature_of<uint16_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "q";
@@ -110,6 +122,8 @@ namespace sdbus {
template <>
struct signature_of<int32_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "i";
@@ -119,6 +133,8 @@ namespace sdbus {
template <>
struct signature_of<uint32_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "u";
@@ -128,6 +144,8 @@ namespace sdbus {
template <>
struct signature_of<int64_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "x";
@@ -137,6 +155,8 @@ namespace sdbus {
template <>
struct signature_of<uint64_t>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "t";
@@ -146,6 +166,8 @@ namespace sdbus {
template <>
struct signature_of<double>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "d";
@@ -155,6 +177,8 @@ namespace sdbus {
template <>
struct signature_of<char*>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "s";
@@ -164,6 +188,8 @@ namespace sdbus {
template <>
struct signature_of<const char*>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "s";
@@ -173,6 +199,8 @@ namespace sdbus {
template <std::size_t _N>
struct signature_of<char[_N]>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "s";
@@ -182,6 +210,8 @@ namespace sdbus {
template <std::size_t _N>
struct signature_of<const char[_N]>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "s";
@@ -191,6 +221,8 @@ namespace sdbus {
template <>
struct signature_of<std::string>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "s";
@@ -200,6 +232,8 @@ namespace sdbus {
template <typename... _ValueTypes>
struct signature_of<Struct<_ValueTypes...>>
{
static constexpr bool is_valid = true;
static const std::string str()
{
std::initializer_list<std::string> signatures{signature_of<_ValueTypes>::str()...};
@@ -215,6 +249,8 @@ namespace sdbus {
template <>
struct signature_of<Variant>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "v";
@@ -224,6 +260,8 @@ namespace sdbus {
template <>
struct signature_of<ObjectPath>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "o";
@@ -233,6 +271,8 @@ namespace sdbus {
template <>
struct signature_of<Signature>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "g";
@@ -242,6 +282,8 @@ namespace sdbus {
template <typename _Element>
struct signature_of<std::vector<_Element>>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "a" + signature_of<_Element>::str();
@@ -251,6 +293,8 @@ namespace sdbus {
template <typename _Key, typename _Value>
struct signature_of<std::map<_Key, _Value>>
{
static constexpr bool is_valid = true;
static const std::string str()
{
return "a{" + signature_of<_Key>::str() + signature_of<_Value>::str() + "}";
+12 -1
View File
@@ -68,7 +68,8 @@ namespace sdbus {
return val;
}
template <typename _ValueType>
// Only allow conversion operator for true D-Bus type representations in C++
template <typename _ValueType, typename = std::enable_if_t<signature_of<_ValueType>::is_valid>>
operator _ValueType() const
{
return get<_ValueType>();
@@ -97,6 +98,16 @@ namespace sdbus {
public:
using std::tuple<_ValueTypes...>::tuple;
// Disable constructor if an older then 7.1.0 version of GCC is used
#if !((defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !(__GNUC__ > 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 0)))))
Struct() = default;
explicit Struct(const std::tuple<_ValueTypes...>& t)
: std::tuple<_ValueTypes...>(t)
{
}
#endif
template <std::size_t _I>
auto& get()
{
+137 -71
View File
@@ -32,91 +32,48 @@
#include <poll.h>
#include <sys/eventfd.h>
namespace {
std::map<sdbus::internal::Connection::BusType, int(*)(sd_bus **)> busTypeToFactory
{
{sdbus::internal::Connection::BusType::eSystem, &sd_bus_open_system},
{sdbus::internal::Connection::BusType::eSession, &sd_bus_open_user}
};
}
namespace sdbus { namespace internal {
Connection::Connection(Connection::BusType type)
: busType_(type)
{
sd_bus* bus{};
auto r = busTypeToFactory[busType_](&bus);
if (r < 0)
SDBUS_THROW_ERROR("Failed to open system bus", -r);
auto bus = openBus(busType_);
bus_.reset(bus);
// Process all requests that are part of the initial handshake,
// like processing the Hello message response, authentication etc.,
// to avoid connection authentication timeout in dbus daemon.
r = sd_bus_flush(bus_.get());
if (r < 0)
SDBUS_THROW_ERROR("Failed to flush system bus on opening", -r);
finishHandshake(bus);
r = eventfd(0, EFD_SEMAPHORE);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create event object", -errno);
runFd_ = r;
exitLoopFd_ = createProcessingExitDescriptor();
}
Connection::~Connection()
{
leaveProcessingLoop();
close(runFd_);
closeProcessingExitDescriptor(exitLoopFd_);
}
void Connection::requestName(const std::string& name)
{
auto r = sd_bus_request_name(bus_.get(), name.c_str(), 0);
if (r < 0)
SDBUS_THROW_ERROR("Failed to request bus name", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
}
void Connection::releaseName(const std::string& name)
{
auto r = sd_bus_release_name(bus_.get(), name.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to release bus name", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
}
void Connection::enterProcessingLoop()
{
int semaphoreFd = runFd_;
short int semaphoreEvents = POLLIN;
while (true)
{
/* Process requests */
int r = sd_bus_process(bus_.get(), nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
if (r > 0) /* we processed a request, try to process another one, right-away */
continue;
auto processed = processPendingRequest(bus_.get());
if (processed)
continue; // Process next one
r = sd_bus_get_fd(bus_.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
auto sdbusFd = r;
r = sd_bus_get_events(bus_.get());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
short int sdbusEvents = r;
struct pollfd fds[] = {{sdbusFd, sdbusEvents, 0}, {semaphoreFd, semaphoreEvents, 0}};
/* Wait for the next request to process */
uint64_t usec;
sd_bus_get_timeout(bus_.get(), &usec);
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
r = poll(fds, fdsCount, usec == (uint64_t) -1 ? -1 : (usec+999)/1000);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
if (fds[1].revents & POLLIN)
break;
auto success = waitForNextRequest(bus_.get(), exitLoopFd_);
if (!success)
break; // Exit processing loop
}
}
@@ -127,12 +84,8 @@ void Connection::enterProcessingLoopAsync()
void Connection::leaveProcessingLoop()
{
assert(runFd_ >= 0);
uint64_t value = 1;
write(runFd_, &value, sizeof(value));
if (asyncLoopThread_.joinable())
asyncLoopThread_.join();
notifyProcessingLoopToExit();
joinWithProcessingLoop();
}
void* Connection::addObjectVTable( const std::string& objectPath
@@ -141,14 +94,15 @@ void* Connection::addObjectVTable( const std::string& objectPath
, void* userData )
{
sd_bus_slot *slot{};
auto r = sd_bus_add_object_vtable( bus_.get()
, &slot
, objectPath.c_str()
, interfaceName.c_str()
, static_cast<const sd_bus_vtable*>(vtable)
, userData );
if (r < 0)
SDBUS_THROW_ERROR("Failed to register object vtable", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register object vtable", -r);
return slot;
}
@@ -164,15 +118,18 @@ sdbus::Message Connection::createMethodCall( const std::string& destination
, const std::string& methodName ) const
{
sd_bus_message *sdbusMsg{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); }; // Returned message will become an owner of sdbusMsg
// Returned message will become an owner of sdbusMsg
SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); };
auto r = sd_bus_message_new_method_call( bus_.get()
, &sdbusMsg
, destination.c_str()
, objectPath.c_str()
, interfaceName.c_str()
, methodName.c_str() );
if (r < 0)
SDBUS_THROW_ERROR("Failed to create method call", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method call", -r);
return Message(sdbusMsg, Message::Type::eMethodCall);
}
@@ -182,14 +139,17 @@ sdbus::Message Connection::createSignal( const std::string& objectPath
, const std::string& signalName ) const
{
sd_bus_message *sdbusSignal{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusSignal); }; // Returned message will become an owner of sdbusSignal
// Returned message will become an owner of sdbusSignal
SCOPE_EXIT{ sd_bus_message_unref(sdbusSignal); };
auto r = sd_bus_message_new_signal( bus_.get()
, &sdbusSignal
, objectPath.c_str()
, interfaceName.c_str()
, signalName.c_str() );
if (r < 0)
SDBUS_THROW_ERROR("Failed to create signal", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
return Message(sdbusSignal, Message::Type::eSignal);
}
@@ -201,10 +161,11 @@ void* Connection::registerSignalHandler( const std::string& objectPath
, void* userData )
{
sd_bus_slot *slot{};
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
auto r = sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
if (r < 0)
SDBUS_THROW_ERROR("Failed to register signal handler", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
return slot;
}
@@ -219,15 +180,120 @@ std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
return std::make_unique<sdbus::internal::Connection>(busType_);
}
sd_bus* Connection::openBus(Connection::BusType type)
{
static std::map<sdbus::internal::Connection::BusType, int(*)(sd_bus **)> busTypeToFactory
{
{sdbus::internal::Connection::BusType::eSystem, &sd_bus_open_system},
{sdbus::internal::Connection::BusType::eSession, &sd_bus_open_user}
};
sd_bus* bus{};
auto r = busTypeToFactory[type](&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
assert(bus != nullptr);
return bus;
}
void Connection::finishHandshake(sd_bus* bus)
{
// Process all requests that are part of the initial handshake,
// like processing the Hello message response, authentication etc.,
// to avoid connection authentication timeout in dbus daemon.
assert(bus != nullptr);
auto r = sd_bus_flush(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
}
int Connection::createProcessingExitDescriptor()
{
// Mechanism for graceful termination of processing loop
auto r = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create event object", -errno);
return r;
}
void Connection::closeProcessingExitDescriptor(int fd)
{
close(fd);
}
void Connection::notifyProcessingLoopToExit()
{
assert(exitLoopFd_ >= 0);
uint64_t value = 1;
write(exitLoopFd_, &value, sizeof(value));
}
void Connection::joinWithProcessingLoop()
{
if (asyncLoopThread_.joinable())
asyncLoopThread_.join();
}
bool Connection::processPendingRequest(sd_bus* bus)
{
assert(bus != nullptr);
int r = sd_bus_process(bus, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
return r > 0;
}
bool Connection::waitForNextRequest(sd_bus* bus, int exitFd)
{
assert(bus != nullptr);
assert(exitFd != 0);
auto r = sd_bus_get_fd(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
auto sdbusFd = r;
r = sd_bus_get_events(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus events", -r);
short int sdbusEvents = r;
uint64_t usec;
sd_bus_get_timeout(bus, &usec);
struct pollfd fds[] = {{sdbusFd, sdbusEvents, 0}, {exitFd, POLLIN, 0}};
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
r = poll(fds, fdsCount, usec == (uint64_t) -1 ? -1 : (usec+999)/1000);
if (r < 0 && errno == EINTR)
return true; // Try again
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
if (fds[1].revents & POLLIN)
return false; // Got exit notification
return true;
}
std::string Connection::composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName )
{
std::string filter;
filter += "type='signal',";
filter += "interface='" + interfaceName + "',";
filter += "member='" + signalName + "',";
filter += "path='" + objectPath + "'";
return filter;
}
+9 -1
View File
@@ -80,14 +80,22 @@ namespace sdbus { namespace internal {
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
private:
static sd_bus* openBus(Connection::BusType type);
static void finishHandshake(sd_bus* bus);
static int createProcessingExitDescriptor();
static void closeProcessingExitDescriptor(int fd);
static bool processPendingRequest(sd_bus* bus);
static bool waitForNextRequest(sd_bus* bus, int exitFd);
static std::string composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName );
void notifyProcessingLoopToExit();
void joinWithProcessingLoop();
private:
std::unique_ptr<sd_bus, decltype(&sd_bus_flush_close_unref)> bus_{nullptr, &sd_bus_flush_close_unref};
std::thread asyncLoopThread_;
std::atomic<int> runFd_{-1};
std::atomic<int> exitLoopFd_{-1};
BusType busType_;
static constexpr const uint64_t POLL_TIMEOUT_USEC = 500000;
+3 -1
View File
@@ -25,6 +25,7 @@
#include <sdbus-c++/Error.h>
#include <systemd/sd-bus.h>
#include "ScopeGuard.h"
namespace sdbus
{
@@ -32,9 +33,10 @@ namespace sdbus
{
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
sd_bus_error_set_errno(&sdbusError, errNo);
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
std::string name(sdbusError.name);
std::string message(customMsg + " (" + sdbusError.message + ")");
sd_bus_error_free(&sdbusError);
return sdbus::Error(name, message);
}
}
+72 -100
View File
@@ -48,6 +48,9 @@ Message::Message(const Message& other) noexcept
Message& Message::operator=(const Message& other) noexcept
{
if (msg_)
sd_bus_message_unref((sd_bus_message*)msg_);
msg_ = other.msg_;
type_ = other.type_;
ok_ = other.ok_;
@@ -64,6 +67,9 @@ Message::Message(Message&& other) noexcept
Message& Message::operator=(Message&& other) noexcept
{
if (msg_)
sd_bus_message_unref((sd_bus_message*)msg_);
msg_ = other.msg_;
other.msg_ = nullptr;
type_ = other.type_;
@@ -85,8 +91,7 @@ Message& Message::operator<<(bool item)
int intItem = item;
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a bool value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a bool value", -r);
return *this;
}
@@ -94,8 +99,7 @@ Message& Message::operator<<(bool item)
Message& Message::operator<<(int16_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a int16_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int16_t value", -r);
return *this;
}
@@ -103,8 +107,7 @@ Message& Message::operator<<(int16_t item)
Message& Message::operator<<(int32_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a int32_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int32_t value", -r);
return *this;
}
@@ -112,8 +115,7 @@ Message& Message::operator<<(int32_t item)
Message& Message::operator<<(int64_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a int64_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a int64_t value", -r);
return *this;
}
@@ -121,8 +123,7 @@ Message& Message::operator<<(int64_t item)
Message& Message::operator<<(uint8_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a byte value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a byte value", -r);
return *this;
}
@@ -130,8 +131,7 @@ Message& Message::operator<<(uint8_t item)
Message& Message::operator<<(uint16_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a uint16_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint16_t value", -r);
return *this;
}
@@ -139,8 +139,7 @@ Message& Message::operator<<(uint16_t item)
Message& Message::operator<<(uint32_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a uint32_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint32_t value", -r);
return *this;
}
@@ -148,8 +147,7 @@ Message& Message::operator<<(uint32_t item)
Message& Message::operator<<(uint64_t item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a uint64_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a uint64_t value", -r);
return *this;
}
@@ -157,8 +155,7 @@ Message& Message::operator<<(uint64_t item)
Message& Message::operator<<(double item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a double value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a double value", -r);
return *this;
}
@@ -166,8 +163,7 @@ Message& Message::operator<<(double item)
Message& Message::operator<<(const char* item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item);
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a C-string value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a C-string value", -r);
return *this;
}
@@ -175,8 +171,7 @@ Message& Message::operator<<(const char* item)
Message& Message::operator<<(const std::string& item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, item.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize a string value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize a string value", -r);
return *this;
}
@@ -191,8 +186,7 @@ Message& Message::operator<<(const Variant &item)
Message& Message::operator<<(const ObjectPath &item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, item.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize an ObjectPath value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an ObjectPath value", -r);
return *this;
}
@@ -200,8 +194,7 @@ Message& Message::operator<<(const ObjectPath &item)
Message& Message::operator<<(const Signature &item)
{
auto r = sd_bus_message_append_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, item.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to serialize an Signature value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to serialize an Signature value", -r);
return *this;
}
@@ -213,8 +206,8 @@ Message& Message::operator>>(bool& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BOOLEAN, &intItem);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a bool value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a bool value", -r);
item = static_cast<bool>(intItem);
@@ -226,8 +219,8 @@ Message& Message::operator>>(int16_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT16, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a int16_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a int16_t value", -r);
return *this;
}
@@ -237,8 +230,8 @@ Message& Message::operator>>(int32_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT32, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a int32_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a int32_t value", -r);
return *this;
}
@@ -248,8 +241,8 @@ Message& Message::operator>>(int64_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_INT64, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a bool value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a bool value", -r);
return *this;
}
@@ -259,8 +252,8 @@ Message& Message::operator>>(uint8_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_BYTE, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a byte value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a byte value", -r);
return *this;
}
@@ -270,8 +263,8 @@ Message& Message::operator>>(uint16_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT16, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a uint16_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint16_t value", -r);
return *this;
}
@@ -281,8 +274,8 @@ Message& Message::operator>>(uint32_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT32, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a uint32_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint32_t value", -r);
return *this;
}
@@ -292,8 +285,8 @@ Message& Message::operator>>(uint64_t& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_UINT64, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a uint64_t value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a uint64_t value", -r);
return *this;
}
@@ -303,8 +296,8 @@ Message& Message::operator>>(double& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_DOUBLE, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a double value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a double value", -r);
return *this;
}
@@ -314,8 +307,8 @@ Message& Message::operator>>(char*& item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_STRING, &item);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a string value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a string value", -r);
return *this;
}
@@ -350,8 +343,8 @@ Message& Message::operator>>(ObjectPath &item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_OBJECT_PATH, &str);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize an ObjectPath value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize an ObjectPath value", -r);
if (str != nullptr)
item = str;
@@ -365,8 +358,8 @@ Message& Message::operator>>(Signature &item)
auto r = sd_bus_message_read_basic((sd_bus_message*)msg_, SD_BUS_TYPE_SIGNATURE, &str);
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to deserialize a Signature value", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to deserialize a Signature value", -r);
if (str != nullptr)
item = str;
@@ -378,8 +371,7 @@ Message& Message::operator>>(Signature &item)
Message& Message::openContainer(const std::string& signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to open a container", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a container", -r);
return *this;
}
@@ -387,8 +379,7 @@ Message& Message::openContainer(const std::string& signature)
Message& Message::closeContainer()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to close a container", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a container", -r);
return *this;
}
@@ -396,8 +387,7 @@ Message& Message::closeContainer()
Message& Message::openDictEntry(const std::string& signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to open a dictionary entry", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a dictionary entry", -r);
return *this;
}
@@ -405,8 +395,7 @@ Message& Message::openDictEntry(const std::string& signature)
Message& Message::closeDictEntry()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to close a dictionary entry", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a dictionary entry", -r);
return *this;
}
@@ -414,8 +403,7 @@ Message& Message::closeDictEntry()
Message& Message::openVariant(const std::string& signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to open a variant", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a variant", -r);
return *this;
}
@@ -423,8 +411,7 @@ Message& Message::openVariant(const std::string& signature)
Message& Message::closeVariant()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to close a variant", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a variant", -r);
return *this;
}
@@ -432,8 +419,7 @@ Message& Message::closeVariant()
Message& Message::openStruct(const std::string& signature)
{
auto r = sd_bus_message_open_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
if (r < 0)
SDBUS_THROW_ERROR("Failed to open a struct", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open a struct", -r);
return *this;
}
@@ -441,8 +427,7 @@ Message& Message::openStruct(const std::string& signature)
Message& Message::closeStruct()
{
auto r = sd_bus_message_close_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to close a struct", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to close a struct", -r);
return *this;
}
@@ -453,8 +438,8 @@ Message& Message::enterContainer(const std::string& signature)
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_ARRAY, signature.c_str());
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to enter a container", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a container", -r);
return *this;
}
@@ -462,8 +447,7 @@ Message& Message::enterContainer(const std::string& signature)
Message& Message::exitContainer()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to exit a container", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a container", -r);
return *this;
}
@@ -473,8 +457,8 @@ Message& Message::enterDictEntry(const std::string& signature)
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_DICT_ENTRY, signature.c_str());
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to enter a dictionary entry", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a dictionary entry", -r);
return *this;
}
@@ -482,8 +466,7 @@ Message& Message::enterDictEntry(const std::string& signature)
Message& Message::exitDictEntry()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to exit a dictionary entry", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a dictionary entry", -r);
return *this;
}
@@ -493,8 +476,8 @@ Message& Message::enterVariant(const std::string& signature)
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_VARIANT, signature.c_str());
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to enter a variant", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a variant", -r);
return *this;
}
@@ -502,8 +485,7 @@ Message& Message::enterVariant(const std::string& signature)
Message& Message::exitVariant()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to exit a variant", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a variant", -r);
return *this;
}
@@ -513,8 +495,8 @@ Message& Message::enterStruct(const std::string& signature)
auto r = sd_bus_message_enter_container((sd_bus_message*)msg_, SD_BUS_TYPE_STRUCT, signature.c_str());
if (r == 0)
ok_ = false;
else if (r < 0)
SDBUS_THROW_ERROR("Failed to enter a struct", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to enter a struct", -r);
return *this;
}
@@ -522,8 +504,7 @@ Message& Message::enterStruct(const std::string& signature)
Message& Message::exitStruct()
{
auto r = sd_bus_message_exit_container((sd_bus_message*)msg_);
if (r < 0)
SDBUS_THROW_ERROR("Failed to exit a struct", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to exit a struct", -r);
return *this;
}
@@ -542,8 +523,7 @@ void Message::clearFlags()
void Message::copyTo(Message& destination, bool complete) const
{
auto r = sd_bus_message_copy((sd_bus_message*)destination.msg_, (sd_bus_message*)msg_, complete);
if (r < 0)
SDBUS_THROW_ERROR("Failed to copy the message", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to copy the message", -r);
}
void Message::seal()
@@ -551,15 +531,13 @@ void Message::seal()
const auto messageCookie = 1;
const auto sealTimeout = 0;
auto r = sd_bus_message_seal((sd_bus_message*)msg_, messageCookie, sealTimeout);
if (r < 0)
SDBUS_THROW_ERROR("Failed to seal the message", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to seal the message", -r);
}
void Message::rewind(bool complete)
{
auto r = sd_bus_message_rewind((sd_bus_message*)msg_, complete);
if (r < 0)
SDBUS_THROW_ERROR("Failed to rewind the message", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
}
Message Message::send() const
@@ -585,16 +563,14 @@ Message Message::send() const
else if (type_ == Type::eMethodReply)
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
if (r < 0)
SDBUS_THROW_ERROR("Failed to send reply", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send reply", -r);
return Message();
}
else if (type_ == Type::eSignal)
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
if (r < 0)
SDBUS_THROW_ERROR("Failed to emit signal", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
return Message();
}
@@ -610,8 +586,7 @@ Message Message::createReply() const
sd_bus_message *sdbusReply{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
auto r = sd_bus_message_new_method_return((sd_bus_message*)msg_, &sdbusReply);
if (r < 0)
SDBUS_THROW_ERROR("Failed to create method reply", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
assert(sdbusReply != nullptr);
@@ -633,8 +608,7 @@ void Message::peekType(std::string& type, std::string& contents) const
char typeSig;
const char* contentsSig;
auto r = sd_bus_message_peek_type((sd_bus_message*)msg_, &typeSig, &contentsSig);
if (r < 0)
SDBUS_THROW_ERROR("Failed to peek message type", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to peek message type", -r);
type = typeSig;
contents = contentsSig;
}
@@ -661,14 +635,12 @@ Message createPlainMessage()
sd_bus* bus{};
SCOPE_EXIT{ sd_bus_unref(bus); }; // sdbusMsg will hold reference to the bus
r = sd_bus_default_system(&bus);
if (r < 0)
SDBUS_THROW_ERROR("Failed to get default system bus", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get default system bus", -r);
sd_bus_message* sdbusMsg{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); }; // Returned message will become an owner of sdbusMsg
r = sd_bus_message_new(bus, &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID);
if (r < 0)
SDBUS_THROW_ERROR("Failed to create a new message", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a new message", -r);
return Message(sdbusMsg, Message::Type::ePlainMessage);
}
+71 -43
View File
@@ -103,49 +103,8 @@ void Object::finishRegistration()
const auto& interfaceName = item.first;
auto& interfaceData = item.second;
auto& vtable = interfaceData.vtable_;
assert(vtable.empty());
vtable.push_back(createVTableStartItem());
for (const auto& item : interfaceData.methods_)
{
const auto& methodName = item.first;
const auto& methodData = item.second;
vtable.push_back(createVTableMethodItem( methodName.c_str()
, methodData.inputArgs_.c_str()
, methodData.outputArgs_.c_str()
, &Object::sdbus_method_callback ));
}
for (const auto& item : interfaceData.signals_)
{
const auto& signalName = item.first;
const auto& signalData = item.second;
vtable.push_back(createVTableSignalItem( signalName.c_str()
, signalData.signature_.c_str() ));
}
for (const auto& item : interfaceData.properties_)
{
const auto& propertyName = item.first;
const auto& propertyData = item.second;
if (!propertyData.setCallback_)
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback ));
else
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback
, &Object::sdbus_property_set_callback ));
}
vtable.push_back(createVTableEndItem());
// Tell, don't ask
auto slot = (sd_bus_slot*) connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], this);
interfaceData.slot_.reset(slot);
interfaceData.slot_.get_deleter() = [this](void *slot){ connection_.removeObjectVTable(slot); };
const auto& vtable = createInterfaceVTable(interfaceData);
activateInterfaceVTable(interfaceName, interfaceData, vtable);
}
}
@@ -160,6 +119,75 @@ void Object::emitSignal(const sdbus::Message& message)
message.send();
}
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
{
auto& vtable = interfaceData.vtable_;
assert(vtable.empty());
vtable.push_back(createVTableStartItem());
registerMethodsToVTable(interfaceData, vtable);
registerSignalsToVTable(interfaceData, vtable);
registerPropertiesToVTable(interfaceData, vtable);
vtable.push_back(createVTableEndItem());
return vtable;
}
void Object::registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
{
for (const auto& item : interfaceData.methods_)
{
const auto& methodName = item.first;
const auto& methodData = item.second;
vtable.push_back(createVTableMethodItem( methodName.c_str()
, methodData.inputArgs_.c_str()
, methodData.outputArgs_.c_str()
, &Object::sdbus_method_callback ));
}
}
void Object::registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
{
for (const auto& item : interfaceData.signals_)
{
const auto& signalName = item.first;
const auto& signalData = item.second;
vtable.push_back(createVTableSignalItem( signalName.c_str()
, signalData.signature_.c_str() ));
}
}
void Object::registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable)
{
for (const auto& item : interfaceData.properties_)
{
const auto& propertyName = item.first;
const auto& propertyData = item.second;
if (!propertyData.setCallback_)
vtable.push_back(createVTablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback ));
else
vtable.push_back(createVTableWritablePropertyItem( propertyName.c_str()
, propertyData.signature_.c_str()
, &Object::sdbus_property_get_callback
, &Object::sdbus_property_set_callback ));
}
}
void Object::activateInterfaceVTable( const std::string& interfaceName
, InterfaceData& interfaceData
, const std::vector<sd_bus_vtable>& vtable )
{
// Tell, don't ask
auto slot = (sd_bus_slot*) connection_.addObjectVTable(objectPath_, interfaceName, &vtable[0], this);
interfaceData.slot_.reset(slot);
interfaceData.slot_.get_deleter() = [this](void *slot){ connection_.removeObjectVTable(slot); };
}
int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
{
Message message(sdbusMessage, Message::Type::eMethodCall);
+28 -20
View File
@@ -71,26 +71,6 @@ namespace internal {
void emitSignal(const sdbus::Message& message) override;
private:
static int sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_property_get_callback( sd_bus *bus
, const char *objectPath
, const char *interface
, const char *property
, sd_bus_message *sdbusReply
, void *userData
, sd_bus_error *retError );
static int sdbus_property_set_callback( sd_bus *bus
, const char *objectPath
, const char *interface
, const char *property
, sd_bus_message *sdbusValue
, void *userData
, sd_bus_error *retError );
private:
sdbus::internal::IConnection& connection_;
std::string objectPath_;
using InterfaceName = std::string;
struct InterfaceData
{
@@ -120,6 +100,34 @@ namespace internal {
std::unique_ptr<void, std::function<void(void*)>> slot_;
};
static const std::vector<sd_bus_vtable>& createInterfaceVTable(InterfaceData& interfaceData);
static void registerMethodsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
static void registerSignalsToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
static void registerPropertiesToVTable(const InterfaceData& interfaceData, std::vector<sd_bus_vtable>& vtable);
void activateInterfaceVTable( const std::string& interfaceName
, InterfaceData& interfaceData
, const std::vector<sd_bus_vtable>& vtable );
static int sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_property_get_callback( sd_bus *bus
, const char *objectPath
, const char *interface
, const char *property
, sd_bus_message *sdbusReply
, void *userData
, sd_bus_error *retError );
static int sdbus_property_set_callback( sd_bus *bus
, const char *objectPath
, const char *interface
, const char *property
, sd_bus_message *sdbusValue
, void *userData
, sd_bus_error *retError );
private:
sdbus::internal::IConnection& connection_;
std::string objectPath_;
std::map<InterfaceName, InterfaceData> interfaces_;
};
+14
View File
@@ -166,6 +166,20 @@ std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( IConnection& connection
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( std::unique_ptr<IConnection>&& connection
, std::string destination
, std::string objectPath )
{
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
connection.release();
return std::make_unique<sdbus::internal::ObjectProxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
, std::move(destination)
, std::move(objectPath) );
}
std::unique_ptr<sdbus::IObjectProxy> createObjectProxy( std::string destination
, std::string objectPath )
{
+1 -2
View File
@@ -72,8 +72,7 @@ protected:
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() const
{
sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> x{STRING_VALUE, {{{INT32_VALUE, INT32_VALUE}}}};
return x;
return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map<int32_t, int32_t>{{INT32_VALUE, INT32_VALUE}}));
}
int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b)
+9
View File
@@ -203,3 +203,12 @@ TEST(CopiesOfVariant, SerializeToAndDeserializeFromMessageSuccessfully)
ASSERT_THAT(receivedVariant2.get<decltype(value)>(), Eq(value));
ASSERT_THAT(receivedVariant3.get<decltype(value)>(), Eq(value));
}
TEST(AStruct, CreatesStructFromTuple)
{
std::tuple<int32_t, std::string> value{1234, "abcd"};
sdbus::Struct<int32_t, std::string> valueStruct{value};
ASSERT_THAT(std::get<0>(valueStruct), Eq(std::get<0>(value)));
ASSERT_THAT(std::get<1>(valueStruct), Eq(std::get<1>(value)));
}