• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1019451413

28 Sep 2023 10:09AM UTC coverage: 78.477%. Remained the same
1019451413

push

gitlab-ci

kacf
chore: Make our `optional` use compatible with C++17.

If the standard is pre-C++17, we use the `optional-lite` library, else
we use the one in `std`.

Signed-off-by: Kristian Amlie <kristian.amlie@northern.tech>

17 of 17 new or added lines in 6 files covered. (100.0%)

5546 of 7067 relevant lines covered (78.48%)

11103.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/common/dbus.hpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#ifndef MENDER_COMMON_DBUS_HPP
16
#define MENDER_COMMON_DBUS_HPP
17

18
#include <config.h>
19

20
#include <functional>
21
#include <memory>
22
#include <string>
23
#include <unordered_map>
24
#include <utility>
25
#include <vector>
26

27
#ifdef MENDER_USE_ASIO_LIBDBUS
28
#include <dbus/dbus.h>
29
#endif // MENDER_USE_ASIO_LIBDBUS
30

31
#include <common/error.hpp>
32
#include <common/expected.hpp>
33
#include <common/events.hpp>
34
#include <common/optional.hpp>
35

36
namespace mender {
37
namespace common {
38
namespace dbus {
39

40
namespace error = mender::common::error;
41
namespace expected = mender::common::expected;
42
namespace events = mender::common::events;
43

44
using namespace std;
45

46
enum DBusErrorCode {
47
        NoError = 0,
48
        ConnectionError,
49
        MessageError,
50
        ReplyError,
51
        ValueError,
52
};
53

54
class DBusErrorCategoryClass : public std::error_category {
55
public:
56
        const char *name() const noexcept override;
57
        string message(int code) const override;
58
};
59
extern const DBusErrorCategoryClass DBusErrorCategory;
60

61
error::Error MakeError(DBusErrorCode code, const string &msg);
62

63
template <typename ReplyType>
64
using DBusCallReplyHandler = function<void(ReplyType)>;
65

66
template <typename SignalValueType>
67
using DBusSignalHandler = function<void(SignalValueType)>;
68

69
// Might need something like
70
//   struct {string iface; string signal;}
71
// in the future.
72
using SignalSpec = string;
73

74
using StringPair = std::pair<string, string>;
75
using ExpectedStringPair = expected::expected<StringPair, error::Error>;
76

77
class DBusPeer : public events::EventLoopObject {
78
public:
79
        explicit DBusPeer(events::EventLoop &loop) :
11✔
80
                loop_ {loop} {};
11✔
81

82
        virtual ~DBusPeer() {};
×
83

84
#ifdef MENDER_USE_ASIO_LIBDBUS
85
        // These take an instance of this class as the *data argument and need to
86
        // access its private members. But they cannot be private member functions,
87
        // we need them to be plain C functions.
88
        friend void HandleDispatch(DBusConnection *conn, DBusDispatchStatus status, void *data);
89
        friend dbus_bool_t AddDBusWatch(DBusWatch *w, void *data);
90
        friend dbus_bool_t AddDBusTimeout(DBusTimeout *t, void *data);
91
#endif // MENDER_USE_ASIO_LIBDBUS
92

93
protected:
94
        events::EventLoop &loop_;
95

96
#ifdef MENDER_USE_ASIO_LIBDBUS
97
        // Cannot initialize this in the constructor to a real connection because
98
        // the connecting can fail.
99
        unique_ptr<DBusConnection, decltype(&dbus_connection_unref)> dbus_conn_ {
100
                nullptr, [](DBusConnection *conn) {
11✔
101
                        if (dbus_connection_get_is_connected(conn)) {
11✔
102
                                dbus_connection_close(conn);
11✔
103
                        }
104
                        dbus_connection_unref(conn);
11✔
105
                }};
11✔
106
#endif // MENDER_USE_ASIO_LIBDBUS
107

108
        virtual error::Error InitializeConnection();
109
};
110

111
// Note: Not a thread-safe class, create multiple instances if needed. However,
112
// the implementation based on libdbus is likely to suffer from potential race
113
// conditions in the library itself.
114
class DBusClient : public DBusPeer {
115
public:
116
        explicit DBusClient(events::EventLoop &loop) :
7✔
117
                DBusPeer(loop) {};
7✔
118

119
        template <typename ReplyType>
120
        error::Error CallMethod(
121
                const string &destination,
122
                const string &path,
123
                const string &iface,
124
                const string &method,
125
                DBusCallReplyHandler<ReplyType> handler);
126

127
        template <typename SignalValueType>
128
        error::Error RegisterSignalHandler(
129
                const string &iface, const string &signal, DBusSignalHandler<SignalValueType> handler);
130
        void UnregisterSignalHandler(const string &iface, const string &signal);
131

132
#ifdef MENDER_USE_ASIO_LIBDBUS
133
        // see DBusPeer's friends for some details
134
        friend DBusHandlerResult MsgFilter(
135
                DBusConnection *connection, DBusMessage *message, void *data);
136
#endif // MENDER_USE_ASIO_LIBDBUS
137

138
private:
139
        unordered_map<SignalSpec, DBusSignalHandler<expected::ExpectedString>> signal_handlers_string_;
140
        unordered_map<SignalSpec, DBusSignalHandler<ExpectedStringPair>> signal_handlers_string_pair_;
141

142
        error::Error InitializeConnection() override;
143

144
        template <typename SignalValueType>
145
        void AddSignalHandler(const string &spec, DBusSignalHandler<SignalValueType> handler);
146

147
        template <typename SignalValueType>
148
        optional<DBusSignalHandler<SignalValueType>> GetSignalHandler(const SignalSpec &spec);
149
};
150

151
// Might need something like
152
//   struct {string service; string iface; string method;}
153
// in the future.
154
using MethodSpec = string;
155

156
template <typename ReturnType>
157
using DBusMethodHandler = function<ReturnType(void)>;
158

159
class DBusObject {
160
public:
161
        explicit DBusObject(const string &path) :
4✔
162
                path_ {path} {};
4✔
163

164
        const string &GetPath() {
165
                return path_;
166
        }
167

168
        template <typename ReturnType>
169
        void AddMethodHandler(
170
                const string &service,
171
                const string &interface,
172
                const string &method,
173
                DBusMethodHandler<ReturnType> handler);
174

175
        friend DBusHandlerResult HandleMethodCall(
176
                DBusConnection *connection, DBusMessage *message, void *data);
177

178
private:
179
        const string path_;
180

181
        unordered_map<MethodSpec, DBusMethodHandler<expected::ExpectedString>> method_handlers_string_;
182
        unordered_map<MethodSpec, DBusMethodHandler<ExpectedStringPair>> method_handlers_string_pair_;
183
        unordered_map<MethodSpec, DBusMethodHandler<expected::ExpectedBool>> method_handlers_bool_;
184

185
        template <typename ReturnType>
186
        optional<DBusMethodHandler<ReturnType>> GetMethodHandler(const MethodSpec &spec);
187
};
188

189
using DBusObjectPtr = shared_ptr<DBusObject>;
190

191
class DBusServer : public DBusPeer {
192
public:
193
        explicit DBusServer(events::EventLoop &loop, const string &service_name) :
4✔
194
                DBusPeer(loop),
195
                service_name_ {service_name} {};
8✔
196

197
        ~DBusServer() override;
198

199
        error::Error AdvertiseObject(DBusObjectPtr obj);
200

201
        // Only a convenience version for tests. Double-check that obj outlives the
202
        // DBusServer!
203
        error::Error AdvertiseObject(DBusObject &obj) {
4✔
204
                return AdvertiseObject(shared_ptr<DBusObject> {&obj, [](DBusObject *obj) {}});
8✔
205
        }
206

207
        template <typename SignalValueType>
208
        error::Error EmitSignal(
209
                const string &path, const string &iface, const string &signal, SignalValueType value);
210

211
        friend DBusHandlerResult HandleMethodCall(
212
                DBusConnection *connection, DBusMessage *message, void *data);
213

214
private:
215
        string service_name_;
216
        vector<DBusObjectPtr> objects_;
217

218
        error::Error InitializeConnection() override;
219
};
220

221
} // namespace dbus
222
} // namespace common
223
} // namespace mender
224

225
#endif // MENDER_COMMON_DBUS_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc