GCC Code Coverage Report


Directory: ./
File: pdcom5/src/msrproto/ProtocolHandler.h
Date: 2024-12-15 04:08:34
Exec Total Coverage
Lines: 29 33 87.9%
Branches: 21 103 20.4%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright (C) 2015-2016 Richard Hacker (lerichi at gmx dot net)
4 *
5 * This file is part of the PdCom library.
6 *
7 * The PdCom library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * The PdCom library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *****************************************************************************/
21
22 #ifndef PD_MSRPROTOCOLHANDLER_H
23 #define PD_MSRPROTOCOLHANDLER_H
24
25 #include "../Future.h"
26 #include "../Process.h"
27 #include "../ProtocolHandler.h"
28 #include "../StreambufLayer.h"
29 #include "../Subscription.h"
30 #include "DataConverter.h"
31 #include "PeriodicSubscriptions.h"
32 #include "Variable.h"
33 #include "expat_wrapper.h"
34
35 #include <list>
36 #include <memory>
37 #include <ostream>
38 #include <pdcom5/MessageManagerBase.h>
39 #include <queue>
40 #include <stddef.h>
41 #include <string>
42 #include <unordered_map>
43
44 namespace PdCom { namespace impl { namespace MsrProto {
45 class Channel;
46 class Parameter;
47 class PollSubscription;
48 class PeriodicSubscription;
49 class PendingSubscription;
50 class EventSubscription;
51 class Variable;
52
53 156 class XmlStream
54 {
55 std::ostream os;
56
57 public:
58 XmlStream(PdCom::impl::Process *process, std::streambuf *buf);
59 void lock();
60 void unlock();
61 PdCom::impl::Process *process;
62
63 template <typename T>
64 15678 XmlStream &operator<<(T &&t)
65 {
66 try {
67
13/31
✓ Branch 4 taken 52 times.
✓ Branch 5 taken 5915 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 66 times.
✗ Branch 14 not taken.
✓ Branch 22 taken 243 times.
✗ Branch 23 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✓ Branch 42 taken 142 times.
✗ Branch 43 not taken.
✓ Branch 49 taken 59 times.
✗ Branch 50 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✓ Branch 62 taken 613 times.
✗ Branch 63 not taken.
✓ Branch 68 taken 18 times.
✗ Branch 69 not taken.
✓ Branch 74 taken 66 times.
✗ Branch 75 not taken.
✓ Branch 80 taken 662 times.
✗ Branch 81 not taken.
✓ Branch 86 taken 803 times.
✗ Branch 87 not taken.
✓ Branch 93 taken 2395 times.
✗ Branch 94 not taken.
✓ Branch 100 taken 4644 times.
✗ Branch 101 not taken.
15678 os << std::forward<T>(t);
68 }
69 catch (std::ios_base::failure const &ex) {
70 throw PdCom::WriteFailure(ex.what());
71 }
72
0/28
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
15678 return *this;
73 }
74
75 554 XmlStream &flush()
76 {
77 554 os.flush();
78 554 return *this;
79 }
80 };
81
82 167 class ChannelSubscriptions
83 {
84 public:
85 using GroupId = unsigned int;
86 using ChannelId = unsigned int;
87 using SubscriptionMap = std::unordered_map<ChannelId, SubscriptionSet<>>;
88
89 static constexpr const char *xsadId = "xsadQ";
90 static constexpr const char *xsodId = "xsodQ";
91
92 166 virtual ~ChannelSubscriptions() = default;
93
94
95 virtual std::shared_ptr<PdCom::impl::Subscription> subscribeEvent(
96 PdCom::Subscription *subscription,
97 std::shared_ptr<const Variable> _var,
98 PdCom::Subscriber &subscriber,
99 const PdCom::Selector &selector,
100 bool notify_pending,
101 XmlStream &cout) = 0;
102 virtual std::shared_ptr<PdCom::impl::Subscription> subscribePeriodic(
103 PdCom::Subscription *subscription,
104 std::shared_ptr<const Variable> _var,
105 PdCom::Subscriber &subscriber,
106 const PdCom::Selector &selector,
107 bool notify_pending,
108 XmlStream &cout) = 0;
109
110 virtual void unsubscribeEvent(const Variable &var, XmlStream &cout) = 0;
111 virtual void unsubscribePeriodic(
112 PdCom::Transmission tm,
113 const Variable &var,
114 XmlStream &cout) = 0;
115
116 virtual void xsadAck(Process *) {}
117 virtual void xsodAck() {}
118
119
120 virtual PeriodicSubscriptionsBase::DataReceiveHandle startNewDataRecieving(
121 GroupId index,
122 VariableCache::Lock lock,
123 std::chrono::nanoseconds ts) = 0;
124
125 virtual void
126 dump(std::vector<PdCom::Process::SubscriptionInfo> &ans,
127 const std::unordered_map<unsigned, Channel *> &channels) const;
128
129
130 4 const SubscriptionMap &getEventMap() const { return event_; }
131
132 protected:
133 SubscriptionMap event_;
134 };
135
136
2/4
✓ Branch 19 taken 157 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 157 times.
✗ Branch 24 not taken.
469 class ChannelSubscriptionsWithGroup final : public ChannelSubscriptions
137 {
138 public:
139 std::shared_ptr<PdCom::impl::Subscription> subscribeEvent(
140 PdCom::Subscription *subscription,
141 std::shared_ptr<const Variable> _var,
142 PdCom::Subscriber &subscriber,
143 const PdCom::Selector &selector,
144 bool notify_pending,
145 XmlStream &cout) override;
146 std::shared_ptr<PdCom::impl::Subscription> subscribePeriodic(
147 PdCom::Subscription *subscription,
148 std::shared_ptr<const Variable> _var,
149 PdCom::Subscriber &subscriber,
150 const PdCom::Selector &selector,
151 bool notify_pending,
152 XmlStream &cout) override;
153
154 void unsubscribeEvent(const Variable &var, XmlStream &cout) override;
155 void unsubscribePeriodic(
156 PdCom::Transmission tm,
157 const Variable &var,
158 XmlStream &cout) override;
159
160 void xsadAck(Process *process) override;
161 void xsodAck() override;
162
163
164 341 PeriodicSubscriptionsBase::DataReceiveHandle startNewDataRecieving(
165 GroupId index,
166 VariableCache::Lock lock,
167 std::chrono::nanoseconds ts) override
168 {
169 return periodic_subscriptions_with_group_.startNewDataRecieving(
170
1/2
✓ Branch 6 taken 341 times.
✗ Branch 7 not taken.
341 index, std::move(lock), ts);
171 }
172
173 void
174 dump(std::vector<PdCom::Process::SubscriptionInfo> &ans,
175 const std::unordered_map<unsigned, Channel *> &channels)
176 const override;
177
178 private:
179 struct xsad_details
180 {
181 unsigned int group_id, channel_id;
182 };
183 std::queue<xsad_details> xsadQ;
184 std::queue<GroupId> xsodQ;
185
186 PeriodicSubscriptionsWithGroup periodic_subscriptions_with_group_;
187 };
188
189
190
1/2
✓ Branch 17 taken 10 times.
✗ Branch 18 not taken.
30 class ChannelSubscriptionsWithoutGroup final : public ChannelSubscriptions
191 {
192 public:
193 std::shared_ptr<PdCom::impl::Subscription> subscribeEvent(
194 PdCom::Subscription *subscription,
195 std::shared_ptr<const Variable> _var,
196 PdCom::Subscriber &subscriber,
197 const PdCom::Selector &selector,
198 bool notify_pending,
199 XmlStream &cout) override;
200 std::shared_ptr<PdCom::impl::Subscription> subscribePeriodic(
201 PdCom::Subscription *subscription,
202 std::shared_ptr<const Variable> _var,
203 PdCom::Subscriber &subscriber,
204 const PdCom::Selector &selector,
205 bool notify_pending,
206 XmlStream &cout) override;
207
208 void unsubscribeEvent(const Variable &var, XmlStream &cout) override;
209 void unsubscribePeriodic(
210 PdCom::Transmission tm,
211 const Variable &var,
212 XmlStream &cout) override;
213
214 void xsadAck(Process *process) override;
215
216 42 PeriodicSubscriptionsBase::DataReceiveHandle startNewDataRecieving(
217 GroupId /* index */,
218 VariableCache::Lock lock,
219 std::chrono::nanoseconds ts) override
220 {
221 return periodic_subscriptions_without_group_.startNewDataRecieving(
222
1/2
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
42 std::move(lock), ts);
223 }
224
225 void
226 dump(std::vector<PdCom::Process::SubscriptionInfo> &ans,
227 const std::unordered_map<unsigned, Channel *> &channels)
228 const override;
229
230 private:
231 std::queue<std::pair<bool /*event*/, GroupId>> xsadQ;
232 PeriodicSubscriptionWithoutGroup periodic_subscriptions_without_group_;
233 };
234
235
236 class ProtocolHandler :
237 public PdCom::impl::ProtocolHandler,
238 public PdCom::impl::StreambufLayer,
239 protected ExpatWrapper<ProtocolHandler, true>
240 {
241 public:
242 ProtocolHandler(PdCom::impl::Process *process, IOLayer *io);
243 ~ProtocolHandler();
244
245 using ExpatWrapper<ProtocolHandler, true>::parse;
246
247 static constexpr int ReadBufferSize = 8192;
248
249
250 void getMessage(uint32_t seqNo) override;
251 void getActiveMessages() override;
252
253 std::shared_ptr<impl::Subscription> subscribe(
254 PdCom::Subscription *subscription,
255 const std::string &path,
256 PdCom::Subscriber &subscriber,
257 const PdCom::Selector &selector) override;
258 std::shared_ptr<impl::Subscription> subscribe(
259 PdCom::Subscription *subscription,
260 std::shared_ptr<const impl::Variable> var,
261 PdCom::Subscriber &subscriber,
262 const PdCom::Selector &selector,
263 bool notify_pending);
264 56 std::shared_ptr<impl::Subscription> subscribe(
265 PdCom::Subscription *subscription,
266 std::shared_ptr<const impl::Variable> var,
267 PdCom::Subscriber &subscriber,
268 const PdCom::Selector &selector) override
269 {
270
1/2
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
56 return subscribe(subscription, var, subscriber, selector, true);
271 }
272 void unsubscribe(EventSubscription &) noexcept;
273 void unsubscribe(PeriodicSubscription &) noexcept;
274 void cancelSubscriptions() override;
275
276 void pollChannel(PollSubscription &sub);
277 void pollParameter(PollSubscription &sub);
278 void pollVariable(const impl::Variable &var, VariablePollPromise &&promise)
279 override;
280 PdCom::Variable::SetValueFuture writeParameter(
281 const Parameter &p,
282 const void *src,
283 TypeInfo::DataType src_type,
284 size_t idx,
285 size_t n);
286
287 std::vector<PdCom::Process::SubscriptionInfo>
288 getActiveSubscriptions() const override;
289
290 private:
291 bool polite = false;
292 bool protocolError = false;
293 std::chrono::nanoseconds dataTime = {};
294
295 std::string m_name;
296 std::string m_version;
297
298 XmlStream cout;
299
300 const std::shared_ptr<DirNode> root;
301
302 // Structures required for list command
303 std::queue<std::string> listQ;
304 bool processListRequest();
305 enum { Uncached, InProgress, Cached } fullListing = Uncached;
306
307 std::queue<std::string> findQ;
308 bool processFindRequest();
309
310 // Structures required for login (return true on successful login)
311 bool processLogin(const char **atts);
312
313 struct Feature
314 {
315 bool pushparameters, binparameters, eventchannels, statistics, pmtime,
316 group, history, aic, messages, quiet, list, exclusive, polite,
317 xsap, login;
318 unsigned eventid;
319 void operator=(const char *list);
320 };
321 Feature feature = {};
322
323
324 using SubscriptionMap =
325 std::unordered_map<unsigned int /* id */, SubscriptionSet<>>;
326
327 65 struct SubscriptionPendingPoll
328 {
329 const unsigned int id_;
330 SubscriptionSet<> subscriptions_;
331 };
332 626 struct SubscriptionPendingPollList : std::list<SubscriptionPendingPoll>
333 {
334 bool
335 append(unsigned int id_, const std::shared_ptr<PollSubscription> &sub);
336 } subscription_pending_channel_polls_,
337 subscription_pending_parameter_polls_;
338
339
1/2
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
14 struct VariablePendingPoll
340 {
341 std::vector<VariablePollPromise> promises_;
342 const unsigned int id_;
343 const bool is_parameter_;
344
345 8 VariablePendingPoll(
346 VariablePollPromise p,
347 unsigned int id,
348 8 bool is_parameter) :
349 8 promises_(), id_(id), is_parameter_(is_parameter)
350 {
351
1/2
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 promises_.push_back(std::move(p));
352 8 }
353 };
354 class VariablePendingPollList
355 {
356 std::list<VariablePendingPoll> polls_;
357
358 public:
359 157 VariablePendingPollList() = default;
360 bool append(const Variable &var, VariablePollPromise promise);
361
362 void processResult(
363 Variable const &var,
364 const char *data,
365 std::chrono::nanoseconds ts);
366
367 ~VariablePendingPollList();
368 } variable_pending_polls_;
369
370 std::unique_ptr<ChannelSubscriptions> channel_subscriptions_;
371 SubscriptionMap parameter_event_;
372
373
374 VariableCache variable_cache_;
375 impl::Subscription::SubscriberNotifier subscriber_notifier_;
376
377 DataEncoder encoder_;
378
379 PeriodicSubscriptionsBase::DataReceiveHandle periodic_receive_handle_;
380
381 std::unordered_map<
382 PdCom::Transmission,
383 std::set<
384 std::shared_ptr<const Variable>,
385 std::owner_less<std::shared_ptr<const Variable>>>>
386 cancelations_;
387
388 78 struct PendingRequest
389 {
390 const std::string path_;
391 SubscriptionSet<PendingSubscription> subscriptions_;
392 };
393 std::list<PendingRequest> pending_queue_;
394 std::queue<unsigned int /* parameter id */> xsapQ;
395
396 using ChannelMap = std::unordered_map<unsigned, Channel *>;
397 ChannelMap channel;
398 using ParameterMap = std::unordered_map<unsigned, Parameter *>;
399 ParameterMap parameter;
400
401 class PendingSetValues
402 {
403 std::queue<PdCom::Promise<PdCom::Exception const &>> queue_;
404
405 public:
406 157 PendingSetValues() = default;
407
408 PdCom::Variable::SetValueFuture push();
409 void pop();
410
411 ~PendingSetValues();
412
413 } pending_set_values_;
414
415
416 enum {
417 StartUp,
418 Idle,
419 GetListing,
420 WaitForConnected,
421 WaitForLogin,
422 GetVariableFields,
423 ReadData,
424 ReadEvent,
425 ReadDataOrEvent,
426 GetActiveMessages,
427 ReadClientStatistics,
428 } state = StartUp;
429
430
431 std::queue<uint32_t> seqNoQ;
432 uint32_t messageSeqNo;
433 std::vector<PdCom::Message> messageList;
434 std::vector<PdCom::ClientStatistics> client_statistics;
435
436 void setPolite(bool state);
437
438 /** Read a variable tag */
439 static const TypeInfo *getDataType(const char **atts, SizeInfo &size_info);
440 Parameter *getParameter(const char **atts);
441 Channel *getChannel(const char **atts);
442
443 // callbacks for xml parser
444 friend class ExpatWrapper<ProtocolHandler, true>;
445 void startElement(const char *name, const char **atts);
446 void endElement(const char *name);
447 void xmlError(const char *);
448
449 void xsapAck();
450 void pendingAck(Variable *);
451 void pollParameter(size_t index, const char *id);
452 void pollChannel(size_t index, const char *id);
453
454 // Reimplemented from PdCom::ProtocolHandler
455 bool asyncData() override;
456 bool find(const std::string &path) override;
457 bool list(const std::string &directory) override;
458 void getClientStatistics() override;
459 void logout() override;
460 bool login(const char *mech, const char *clientData) override;
461
462 void ping() override;
463 std::string name() const override;
464 std::string version() const override;
465
466 void
467 broadcast(const std::string &message, const std::string &attr) override;
468 void processBroadcast(const char **atts);
469
470 void readEventData(const char *name, const char **atts);
471 void readPeriodicData(const char *name, const char **atts);
472 };
473
474
475 }}} // namespace PdCom::impl::MsrProto
476
477 #endif // PD_MSRPROTOCOLHANDLER_H
478