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

mendersoftware / mender / 1480778148

03 Oct 2024 06:26PM UTC coverage: 76.372% (+0.06%) from 76.31%
1480778148

push

gitlab-ci

danielskinstad
fix: explicitly initialize ssl

From the OpenSSL man pages:
Numerous internal OpenSSL functions call OPENSSL_init_ssl().
Therefore, in order to perform nondefault initialisation,
OPENSSL_init_ssl() MUST be called by application code prior to any other OpenSSL function calls.
See: https://docs.openssl.org/3.3/man3/OPENSSL_init_ssl/#description

This fixes errors where e.g. the openssl config configures ssl_conf,
which requires ssl to be initialized.

Ticket: MEN-7549
Changelog: Fix error while loading OpenSSL config file, by explicitly
initializing the SSL context prior to loading. Without the explicit
initialisation of SSL, the config might not be properly loaded if e.g.
it has sections specifying ssl settings. This was the case with the
example configuration for OpenSSL 1.1.1w from Debian Bullseye.

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

1 of 2 new or added lines in 1 file covered. (50.0%)

97 existing lines in 3 files now uncovered.

7350 of 9624 relevant lines covered (76.37%)

11242.72 hits per line

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

84.62
/src/common/state_machine.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_STATE_MACHINE_HPP
16
#define MENDER_COMMON_STATE_MACHINE_HPP
17

18
#include <queue>
19
#include <unordered_map>
20
#include <unordered_set>
21

22
#include <common/common.hpp>
23
#include <common/events.hpp>
24
#include <common/log.hpp>
25

26
namespace mender {
27
namespace common {
28
namespace state_machine {
29

30
using namespace std;
31

32
namespace common = mender::common;
33
namespace events = mender::common::events;
34
namespace log = mender::common::log;
35

36
template <typename ContextType, typename EventType>
37
class StateMachineRunner;
38

39
template <typename EventType>
40
class EventPoster {
80✔
41
public:
42
        virtual ~EventPoster() {
43
        }
44

45
        virtual void PostEvent(EventType event) = 0;
46
};
47

48
template <typename ContextType, typename EventType>
49
class State {
560✔
50
public:
51
        virtual ~State() {
52
        }
53

54
        virtual void OnEnter(ContextType &ctx, EventPoster<EventType> &poster) = 0;
55
};
56

57
enum class TransitionFlag {
58
        Immediate,
59
        Deferred,
60
};
61

62
template <typename ContextType, typename EventType>
63
class StateMachine {
64
public:
65
        StateMachine(State<ContextType, EventType> &start_state) :
80✔
66
                current_state_(&start_state) {
80✔
67
        }
80✔
68
        StateMachine(StateMachine &) = delete;
69

70
        void SetState(State<ContextType, EventType> &state) {
71
                current_state_ = &state;
80✔
72
                state_entered_ = false;
80✔
73
        }
74

75
private:
76
        struct TransitionCondition {
77
                // Note: Comparing address-of states. We don't want to rely on comparison operators
78
                // in the states themselves, and we just want to know if they are different
79
                // instances.
80
                State<ContextType, EventType> *state;
81
                EventType event;
82

83
                bool operator==(const TransitionCondition &t) const {
948✔
84
                        return state == t.state && event == t.event;
948✔
85
                }
86
        };
87

88
        class Hasher {
89
        public:
90
                size_t operator()(const TransitionCondition &obj) const {
91
                        return std::hash<State<ContextType, EventType> *>()(obj.state)
5,908✔
92
                                   ^ std::hash<int>()(static_cast<int>(obj.event));
5,908✔
93
                }
94
        };
95

96
        State<ContextType, EventType> *current_state_;
97
        bool state_entered_ {false};
98

99
        unordered_map<TransitionCondition, State<ContextType, EventType> *, Hasher> transitions_;
100
        unordered_set<EventType> deferred_events_;
101

102
        friend class StateMachineRunner<ContextType, EventType>;
103

104
public:
105
        void AddTransition(
4,971✔
106
                State<ContextType, EventType> &source_state,
107
                EventType event,
108
                State<ContextType, EventType> &target_state,
109
                TransitionFlag flag) {
110
                transitions_[TransitionCondition {&source_state, event}] = &target_state;
4,971✔
111
                if (flag == TransitionFlag::Deferred) {
4,971✔
112
                        // Event is involved in at least one deferred transition, so mark that.
113
                        deferred_events_.insert(event);
114
                }
115
        }
4,971✔
116
};
117

118
template <typename ContextType, typename EventType>
119
class StateMachineRunner : virtual public EventPoster<EventType> {
120
public:
121
        using IterationCallback = function<void()>;
122

123
        StateMachineRunner(ContextType &ctx) :
80✔
124
                ctx_(ctx) {
160✔
125
        }
80✔
126
        StateMachineRunner(StateMachineRunner &) = delete;
127

128
        ~StateMachineRunner() {
80✔
129
                DetachFromEventLoop();
80✔
130
        }
80✔
131

132
        void PostEvent(EventType event) override {
937✔
133
                event_queue_.push(event);
134
                PostToEventLoop();
937✔
135
        }
937✔
136

137
        // Continously run state machinery on event loop.
138
        void AttachToEventLoop(events::EventLoop &event_loop) {
80✔
139
                DetachFromEventLoop();
80✔
140

141
                cancelled_ = make_shared<bool>(false);
80✔
142

143
                // We don't actually own the object, we are just keeping a pointer to it. Use null
144
                // deleter.
145
                event_loop_.reset(&event_loop, [](events::EventLoop *loop) {});
80✔
146

147
                PostToEventLoop();
80✔
148
        }
80✔
149

150
        void DetachFromEventLoop() {
160✔
151
                if (cancelled_) {
160✔
152
                        *cancelled_ = true;
80✔
153
                        cancelled_.reset();
80✔
154
                }
155
                event_loop_.reset();
160✔
156
        }
160✔
157

158
        void AddStateMachine(StateMachine<ContextType, EventType> &machine) {
80✔
159
                machines_.push_back(&machine);
80✔
160
        }
80✔
161

162
        void SetIterationCallback(IterationCallback callback) {
163
                iteration_callback_ = callback;
164
        }
165

166
private:
167
        void RunOne() {
1,017✔
168
                vector<State<ContextType, EventType> *> to_run;
169

170
                for (auto machine : machines_) {
2,034✔
171
                        if (!machine->state_entered_) {
1,017✔
172
                                to_run.push_back(machine->current_state_);
80✔
173
                                machine->state_entered_ = true;
80✔
174
                        }
175
                }
176

177
                const size_t size = event_queue_.size();
178

179
                for (size_t count = 0; to_run.empty() && count < size; count++) {
1,954✔
180
                        bool deferred = false;
181
                        auto event = event_queue_.front();
937✔
182
                        event_queue_.pop();
183

184
                        for (auto machine : machines_) {
1,874✔
185
                                typename StateMachine<ContextType, EventType>::TransitionCondition cond {
937✔
186
                                        machine->current_state_, event};
937✔
187
                                if (machine->deferred_events_.find(event) != machine->deferred_events_.end()) {
937✔
188
                                        deferred = true;
189
                                }
190

191
                                auto match = machine->transitions_.find(cond);
192
                                if (match == machine->transitions_.end()) {
937✔
193
                                        // No match in this machine, continue.
UNCOV
194
                                        continue;
×
195
                                }
196

197
                                auto &target = match->second;
937✔
198
                                to_run.push_back(target);
937✔
199
                                machine->current_state_ = target;
937✔
200
                        }
201

202
                        if (to_run.empty()) {
937✔
UNCOV
203
                                if (deferred) {
×
204
                                        // Put back in the queue to try later. This won't be tried
205
                                        // again during this run, due to only making `size`
206
                                        // attempts in the for loop.
207
                                        event_queue_.push(event);
208
                                } else {
UNCOV
209
                                        string states = common::BestAvailableTypeName(*machines_[0]->current_state_);
×
UNCOV
210
                                        for (size_t i = 1; i < machines_.size(); i++) {
×
UNCOV
211
                                                states += ", ";
×
UNCOV
212
                                                states += common::BestAvailableTypeName(*machines_[i]->current_state_);
×
213
                                        }
214
                                        log::Fatal(
×
215
                                                "State machine event " + StateEventToString(event)
×
216
                                                + " was not handled by any transition. Current states: " + states
×
UNCOV
217
                                                + ". This is a bug and an irrecoverable error. "
×
218
                                                + "Aborting in the hope that restarting will help.");
×
219
                                }
220
                        }
221
                }
222

223
                if (!to_run.empty()) {
1,017✔
224
                        for (auto &state : to_run) {
2,034✔
225
                                log::Trace("Entering state " + common::BestAvailableTypeName(*state));
2,034✔
226
                                state->OnEnter(ctx_, *this);
1,017✔
227
                        }
228
                        // Since we ran something, there may be more events waiting to
229
                        // execute. OTOH, if we didn't, it either means that there are no events, or
230
                        // it means that all events currently in the queue are deferred, and not
231
                        // actionable until at least one state machine reaches a different state.
232
                        PostToEventLoop();
1,017✔
233
                }
234
        }
1,017✔
235

236
        void PostToEventLoop() {
2,034✔
237
                if (!event_loop_) {
2,034✔
UNCOV
238
                        return;
×
239
                }
240

241
                auto cancelled = cancelled_;
242
                event_loop_->Post([cancelled, this]() {
9,153✔
243
                        if (!*cancelled) {
1,017✔
244
                                RunOne();
1,017✔
245
                        }
246
                });
247
        }
248

249
        ContextType &ctx_;
250

251
        shared_ptr<bool> cancelled_;
252
        vector<StateMachine<ContextType, EventType> *> machines_;
253

254
        queue<EventType> event_queue_;
255

256
        // Would be nice with optional<EventLoop &> reference here, but optional doesn't support
257
        // references. Use a pointer with a null deleter instead.
258
        shared_ptr<events::EventLoop> event_loop_;
259

260
        IterationCallback iteration_callback_;
261
};
262

263
} // namespace state_machine
264
} // namespace common
265
} // namespace mender
266

267
#endif // MENDER_COMMON_STATE_MACHINE_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