Compare commits

...

17 Commits

Author SHA1 Message Date
d68be891ee Revert modification for clang, for now it fails on gcc 2018-03-15 17:16:23 +01:00
10d0da9067 Update ChangeLog for v0.2.4 2018-03-15 16:06:05 +00:00
2564bbfb21 Add object proxy factory overload that takes unique_ptr to connection 2018-03-15 17:03:49 +01:00
e1cf50d2cd Bump up version to 0.2.4 2018-03-15 15:33:34 +00:00
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
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
47139527f4 Update using-sdbus-c++.md 2018-02-27 08:45:40 +00:00
b22cac9a63 Try to clarify connection to the systems bus vs. session bus in the tutorial 2018-02-27 08:43:08 +00:00
b81c4b494c Add clang workaround comment 2018-02-27 08:26:42 +00:00
7e61a83d09 Merge pull request #2 from lejcik/master
Fix proposal for clang compilation issue
2018-02-27 08:57:48 +01:00
dc5ec014eb Added constructor for sdbus::Struct 2017-12-18 19:19:27 +01:00
f559fc0663 Added a test case that fails to compile with clang 2017-12-18 19:15:40 +01:00
b5866fe5e9 Fix handling of interrupt when polling 2017-12-14 12:58:50 +01:00
96684ce37f Add design diagram and make additional adjustments in the tutorial 2017-12-14 10:43:41 +01:00
55d8084729 Add class diagram 2017-12-14 10:30:55 +01:00
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
7fbc0e360d Close file descriptor of event loop's semaphore on exec 2017-12-06 13:52:40 +01:00
12 changed files with 206 additions and 18 deletions

View File

@ -0,0 +1,10 @@
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)

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
-------

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, 4)
m4_define([sdbus_cpp_version],
[sdbus_cpp_version_major.sdbus_cpp_version_minor.sdbus_cpp_version_micro])

BIN
doc/sdbus-c++-class-diagram.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

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

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";

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
*

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() + "}";

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,13 @@ namespace sdbus {
public:
using std::tuple<_ValueTypes...>::tuple;
// Workaround for clang (where the above constructor inheritance doesn't work)
// However, with this ctor, it doesn't work on gcc :-( TODO Investigate proper solution.
//Struct(const std::tuple<_ValueTypes...>& t)
// : std::tuple<_ValueTypes...>(t)
//{
//}
template <std::size_t _I>
auto& get()
{

View File

@ -59,7 +59,7 @@ Connection::Connection(Connection::BusType type)
if (r < 0)
SDBUS_THROW_ERROR("Failed to flush system bus on opening", -r);
r = eventfd(0, EFD_SEMAPHORE);
r = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create event object", -errno);
runFd_ = r;
}
@ -113,6 +113,8 @@ void Connection::enterProcessingLoop()
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
r = poll(fds, fdsCount, usec == (uint64_t) -1 ? -1 : (usec+999)/1000);
if (r < 0 && errno == EINTR)
continue;
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
if (fds[1].revents & POLLIN)

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 )
{

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)));
}