Compare commits

...

7 Commits

Author SHA1 Message Date
e199dc58cf Dont use deprecated api 2025-02-12 17:23:42 +01:00
ad7731d900 Fix out of memory access in parser 2023-07-04 19:09:53 +02:00
101dd1c2ba Add boost asio integration 2022-10-30 18:35:47 +01:00
299e6940cd Improve ABI 2022-10-30 18:17:51 +01:00
3f825ffb30 Force event loop to re-enter processing to handle queued messages 2022-09-04 23:26:14 +02:00
35bffd0f25 build: don't include libsystemd as shared pkg-config dep when statically linked (#283)
This works whether `BUILD_LIBSYSTEMD` is `ON` or the separate build of
libsystemd picked up by pkg-config is static. The Gentoo Linux package
requires the latter.

This change also handles `BUILD_SHARED_LIBS` being `OFF`. In this case,
the libsystemd dependency does need to be included, even though it is
static.

CMake does not allow you to build shared and static libraries
simultaneously (with a single `add_library` call), but this change
declares the libsystemd dependency as `Requires.private` rather than
omitting it entirely. This is in case someone builds and installs both a
static and shared build and then calls `pkg-config --static sdbus-c++`.
The static build needs to be installed first so that the pkg-config
file from the shared build takes precedence.
2022-09-03 22:54:06 +02:00
e33a890ce7 docs: fix send_destination property (#284) 2022-08-26 16:49:51 +02:00
10 changed files with 105 additions and 7 deletions

View File

@ -81,6 +81,7 @@ set(SDBUSCPP_PUBLIC_HDRS
${SDBUSCPP_INCLUDE_DIR}/Types.h ${SDBUSCPP_INCLUDE_DIR}/Types.h
${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h ${SDBUSCPP_INCLUDE_DIR}/TypeTraits.h
${SDBUSCPP_INCLUDE_DIR}/Flags.h ${SDBUSCPP_INCLUDE_DIR}/Flags.h
${SDBUSCPP_INCLUDE_DIR}/SdbusAsio.h
${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h) ${SDBUSCPP_INCLUDE_DIR}/sdbus-c++.h)
set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS}) set(SDBUSCPP_SRCS ${SDBUSCPP_CPP_SRCS} ${SDBUSCPP_HDR_SRCS} ${SDBUSCPP_PUBLIC_HDRS})
@ -210,6 +211,11 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/sdbus-c++-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++
COMPONENT dev) COMPONENT dev)
if(BUILD_SHARED_LIBS AND (BUILD_LIBSYSTEMD OR Systemd_LINK_LIBRARIES MATCHES "/libsystemd\.a(;|$)"))
set(PKGCONFIG_REQS ".private")
else()
set(PKGCONFIG_REQS "")
endif()
configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY) configure_file(pkgconfig/sdbus-c++.pc.in pkgconfig/sdbus-c++.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/sdbus-c++.pc install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/sdbus-c++.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev) DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT dev)

View File

@ -41,7 +41,7 @@ Typical default D-Bus configuration does not allow to register services except e
<busconfig> <busconfig>
<policy user="root"> <policy user="root">
<allow own="org.sdbuscpp.concatenator"/> <allow own="org.sdbuscpp.concatenator"/>
<allow send_destination="org.sdbuscpp"/> <allow send_destination="org.sdbuscpp.concatenator"/>
<allow send_interface="org.sdbuscpp.concatenator"/> <allow send_interface="org.sdbuscpp.concatenator"/>
</policy> </policy>
</busconfig> </busconfig>

View File

@ -78,6 +78,11 @@ namespace sdbus {
*/ */
uint64_t timeout_usec; uint64_t timeout_usec;
/*!
* The read fd to be monitored by the event loop.
*/
int event_fd;
/*! /*!
* Get the event poll timeout. * Get the event poll timeout.
* *

View File

@ -0,0 +1,67 @@
#pragma once
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
#include <memory>
#include <sdbus-c++/sdbus-c++.h>
class SdbusAsio final : boost::noncopyable {
public:
explicit SdbusAsio(boost::asio::io_context& io_context,
std::unique_ptr<sdbus::IConnection> conn = sdbus::createDefaultBusConnection())
: conn_ { std::move(conn) }
, timer_ { io_context }
, dbus_desc_ { io_context }
, event_desc_ { io_context }
{
auto poll_data = conn_->getEventLoopPollData();
dbus_desc_.async_wait(boost::asio::posix::stream_descriptor::wait_read,
[this](const boost::system::error_code&) { processRead(); });
dbus_desc_.assign(poll_data.fd);
event_desc_.async_read_some(boost::asio::null_buffers(), [this](auto&, auto) { processEvent(); });
event_desc_.assign(poll_data.event_fd);
if (poll_data.timeout_usec != UINT64_MAX) {
timer_.async_wait([this](boost::system::error_code const&) { processTimeout(); });
timer_.expires_after(boost::posix_time::microsec(poll_data.timeout_usec));
}
}
std::shared_ptr<sdbus::IConnection> getConnection() { return conn_; }
private:
void process()
{
for (auto i = 0; i < DBUS_PROCESS_MAX; i++) {
if (!conn_->processPendingRequest()) {
break;
}
}
}
void processRead()
{
process();
dbus_desc_.async_wait(boost::asio::posix::stream_descriptor::wait_read,
[this](const boost::system::error_code&) { processRead(); });
}
void processEvent()
{
process();
event_desc_.async_read_some(boost::asio::null_buffers(), [this](auto, auto) { processEvent(); });
}
void processTimeout()
{
process();
timer_.async_wait([this](boost::system::error_code const&) { processTimeout(); });
}
static constexpr auto DBUS_PROCESS_MAX = 32;
std::shared_ptr<sdbus::IConnection> conn_;
boost::asio::deadline_timer timer_;
boost::asio::posix::stream_descriptor dbus_desc_;
boost::asio::posix::stream_descriptor event_desc_;
};

View File

@ -5,7 +5,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @PROJECT_NAME@ Name: @PROJECT_NAME@
Description: C++ library on top of sd-bus, a systemd D-Bus library Description: C++ library on top of sd-bus, a systemd D-Bus library
Requires: libsystemd Requires@PKGCONFIG_REQS@: libsystemd
Version: @SDBUSCPP_VERSION@ Version: @SDBUSCPP_VERSION@
Libs: -L${libdir} -l@PROJECT_NAME@ Libs: -L${libdir} -l@PROJECT_NAME@
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@ -75,11 +75,16 @@ Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
, bus_(openPseudoBus()) , bus_(openPseudoBus())
{ {
assert(iface_ != nullptr); assert(iface_ != nullptr);
eventFd_.fd = eventfd(0, 0);
assert(eventFd_.fd >= 0);
} }
Connection::~Connection() Connection::~Connection()
{ {
Connection::leaveEventLoop(); Connection::leaveEventLoop();
if (0 <= eventFd_.fd) {
close(eventFd_.fd);
}
} }
void Connection::requestName(const std::string& name) void Connection::requestName(const std::string& name)
@ -141,7 +146,7 @@ Connection::PollData Connection::getEventLoopPollData() const
auto r = iface_->sd_bus_get_poll_data(bus_.get(), &pollData); auto r = iface_->sd_bus_get_poll_data(bus_.get(), &pollData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r); SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
return {pollData.fd, pollData.events, pollData.timeout_usec}; return {pollData.fd, pollData.events, pollData.timeout_usec, eventFd_.fd};
} }
const ISdBus& Connection::getSdBusInterface() const const ISdBus& Connection::getSdBusInterface() const
@ -445,6 +450,11 @@ void Connection::notifyEventLoopToExit() const
notifyEventLoop(loopExitFd_.fd); notifyEventLoop(loopExitFd_.fd);
} }
void Connection::notifyEventLoop() const
{
notifyEventLoop(eventFd_.fd);
}
void Connection::notifyEventLoopNewTimeout() const void Connection::notifyEventLoopNewTimeout() const
{ {
// The extra notifications for new timeouts are only needed if calls are made asynchronously to the event loop. // The extra notifications for new timeouts are only needed if calls are made asynchronously to the event loop.

View File

@ -139,6 +139,7 @@ namespace sdbus::internal {
void notifyEventLoop(int fd) const; void notifyEventLoop(int fd) const;
void notifyEventLoopToExit() const; void notifyEventLoopToExit() const;
void clearEventLoopNotification(int fd) const; void clearEventLoopNotification(int fd) const;
void notifyEventLoop() const override;
void notifyEventLoopNewTimeout() const override; void notifyEventLoopNewTimeout() const override;
private: private:

View File

@ -90,6 +90,7 @@ namespace sdbus::internal {
, sd_bus_message_handler_t callback , sd_bus_message_handler_t callback
, void* userData ) = 0; , void* userData ) = 0;
virtual void notifyEventLoop() const = 0;
virtual void notifyEventLoopNewTimeout() const = 0; virtual void notifyEventLoopNewTimeout() const = 0;
virtual MethodReply tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout) = 0; virtual MethodReply tryCallMethodSynchronously(const MethodCall& message, uint64_t timeout) = 0;
}; };

View File

@ -782,6 +782,10 @@ MethodReply MethodCall::sendWithReply(uint64_t timeout) const
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r); SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
// Force event loop to re-enter processing to handle queued messages
SDBUS_THROW_ERROR_IF(connection_ == nullptr, "Invalid use of MethodCall API", ENOTSUP);
connection_->notifyEventLoop();
return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message); return Factory::create<MethodReply>(sdbusReply, sdbus_, adopt_message);
} }
@ -790,6 +794,10 @@ MethodReply MethodCall::sendWithNoReply() const
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr); auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r); SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
// Force event loop to re-enter processing to handle queued messages
SDBUS_THROW_ERROR_IF(connection_ == nullptr, "Invalid use of MethodCall API", ENOTSUP);
connection_->notifyEventLoop();
return Factory::create<MethodReply>(); // No reply return Factory::create<MethodReply>(); // No reply
} }

View File

@ -292,12 +292,12 @@ void Document::Expat::character_data_handler(void* data, const XML_Char* chars,
nod = &(nod->children.back()); nod = &(nod->children.back());
} }
int x = 0, y = len - 1; int offset = 0, count = len;
while (isspace(chars[y]) && y > 0) --y; while (count > 0 && isspace(chars[count - 1])) --count;
while (isspace(chars[x]) && x < y) ++x; while (offset < count && isspace(chars[offset])) { ++offset; --count; }
nod->cdata = std::string(chars, x, y + 1); nod->cdata = std::string{chars + offset, static_cast<std::string::size_type>(count)};
} }
void Document::Expat::end_element_handler(void* data, const XML_Char* /*name*/) void Document::Expat::end_element_handler(void* data, const XML_Char* /*name*/)