GCC Code Coverage Report


Directory: ./
File: pdcom5/src/msrproto/ProtocolHandler.h
Date: 2023-11-12 04:06:57
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 131 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 12697 XmlStream &operator<<(T &&t)
65 {
66 try {
67
13/31
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 5146 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 68 times.
✗ Branch 14 not taken.
✓ Branch 22 taken 115 times.
✗ Branch 23 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✓ Branch 42 taken 130 times.
✗ Branch 43 not taken.
✓ Branch 49 taken 47 times.
✗ Branch 50 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✓ Branch 62 taken 492 times.
✗ Branch 63 not taken.
✓ Branch 68 taken 18 times.
✗ Branch 69 not taken.
✓ Branch 74 taken 35 times.
✗ Branch 75 not taken.
✓ Branch 80 taken 538 times.
✗ Branch 81 not taken.
✓ Branch 86 taken 568 times.
✗ Branch 87 not taken.
✓ Branch 93 taken 1864 times.
✗ Branch 94 not taken.
✓ Branch 100 taken 3656 times.
✗ Branch 101 not taken.
12697 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.
12697 return *this;
73 }
74
75 460 XmlStream &flush()
76 {
77 460 os.flush();
78 460 return *this;
79 }
80 };
81
82 143 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 142 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 6 const SubscriptionMap &getEventMap() const { return event_; }
131
132 protected:
133 SubscriptionMap event_;
134 };
135
136
2/4
✓ Branch 19 taken 132 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 132 times.
✗ Branch 24 not taken.
394 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 47 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 47 times.
✗ Branch 7 not taken.
47 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 11 times.
✗ Branch 18 not taken.
33 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>
240 {
241 public:
242 ProtocolHandler(PdCom::impl::Process *process, IOLayer *io);
243 ~ProtocolHandler();
244
245 using ExpatWrapper<ProtocolHandler>::parse;
246
247
248 void getMessage(uint32_t seqNo) override;
249 void getActiveMessages() override;
250
251 std::shared_ptr<impl::Subscription> subscribe(
252 PdCom::Subscription *subscription,
253 const std::string &path,
254 PdCom::Subscriber &subscriber,
255 const PdCom::Selector &selector) override;
256 std::shared_ptr<impl::Subscription> subscribe(
257 PdCom::Subscription *subscription,
258 std::shared_ptr<const impl::Variable> var,
259 PdCom::Subscriber &subscriber,
260 const PdCom::Selector &selector,
261 bool notify_pending);
262 42 std::shared_ptr<impl::Subscription> subscribe(
263 PdCom::Subscription *subscription,
264 std::shared_ptr<const impl::Variable> var,
265 PdCom::Subscriber &subscriber,
266 const PdCom::Selector &selector) override
267 {
268
1/2
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
42 return subscribe(subscription, var, subscriber, selector, true);
269 }
270 void unsubscribe(EventSubscription &) noexcept;
271 void unsubscribe(PeriodicSubscription &) noexcept;
272 void cancelSubscriptions() override;
273
274 void pollChannel(PollSubscription &sub);
275 void pollParameter(PollSubscription &sub);
276 void pollVariable(const impl::Variable &var, VariablePollPromise &&promise)
277 override;
278 PdCom::Variable::SetValueFuture writeParameter(
279 const Parameter &p,
280 const void *src,
281 TypeInfo::DataType src_type,
282 size_t idx,
283 size_t n);
284
285 std::vector<PdCom::Process::SubscriptionInfo>
286 getActiveSubscriptions() const override;
287
288 private:
289 bool polite = false;
290 bool protocolError = false;
291 std::chrono::nanoseconds dataTime = {};
292
293 std::string m_name;
294 std::string m_version;
295
296 XmlStream cout;
297
298 const std::shared_ptr<DirNode> root;
299
300 // Structures required for list command
301 std::queue<std::string> listQ;
302 bool processListRequest();
303 enum { Uncached, InProgress, Cached } fullListing = Uncached;
304
305 std::queue<std::string> findQ;
306 bool processFindRequest();
307
308 // Structures required for login (return true on successful login)
309 bool processLogin(const char **atts);
310
311 struct Feature
312 {
313 bool pushparameters, binparameters, eventchannels, statistics, pmtime,
314 group, history, aic, messages, quiet, list, exclusive, polite,
315 xsadgroups, xsap, login;
316 unsigned eventid;
317 void operator=(const char *list);
318 };
319 Feature feature = {};
320
321
322 using SubscriptionMap =
323 std::unordered_map<unsigned int /* id */, SubscriptionSet<>>;
324
325 70 struct SubscriptionPendingPoll
326 {
327 const unsigned int id_;
328 SubscriptionSet<> subscriptions_;
329 };
330 526 struct SubscriptionPendingPollList : std::list<SubscriptionPendingPoll>
331 {
332 bool
333 append(unsigned int id_, const std::shared_ptr<PollSubscription> &sub);
334 } subscription_pending_channel_polls_,
335 subscription_pending_parameter_polls_;
336
337
1/2
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
14 struct VariablePendingPoll
338 {
339 std::vector<VariablePollPromise> promises_;
340 const unsigned int id_;
341 const bool is_parameter_;
342
343 8 VariablePendingPoll(
344 VariablePollPromise p,
345 unsigned int id,
346 8 bool is_parameter) :
347 8 promises_(), id_(id), is_parameter_(is_parameter)
348 {
349
1/2
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 promises_.push_back(std::move(p));
350 8 }
351 };
352 class VariablePendingPollList
353 {
354 std::list<VariablePendingPoll> polls_;
355
356 public:
357 132 VariablePendingPollList() = default;
358 bool append(const Variable &var, VariablePollPromise promise);
359
360 void processResult(
361 Variable const &var,
362 const char *data,
363 std::chrono::nanoseconds ts);
364
365 ~VariablePendingPollList();
366 } variable_pending_polls_;
367
368 std::unique_ptr<ChannelSubscriptions> channel_subscriptions_;
369 SubscriptionMap parameter_event_;
370
371
372 VariableCache variable_cache_;
373 impl::Subscription::SubscriberNotifier subscriber_notifier_;
374
375 DataEncoder encoder_;
376
377 PeriodicSubscriptionsBase::DataReceiveHandle periodic_receive_handle_;
378
379 std::unordered_map<
380 PdCom::Transmission,
381 std::set<
382 std::shared_ptr<const Variable>,
383 std::owner_less<std::shared_ptr<const Variable>>>>
384 cancelations_;
385
386 30 struct PendingRequest
387 {
388 const std::string path_;
389 SubscriptionSet<PendingSubscription> subscriptions_;
390 };
391 std::list<PendingRequest> pending_queue_;
392 std::queue<unsigned int /* parameter id */> xsapQ;
393
394 using ChannelMap = std::unordered_map<unsigned, Channel *>;
395 ChannelMap channel;
396 using ParameterMap = std::unordered_map<unsigned, Parameter *>;
397 ParameterMap parameter;
398
399 class PendingSetValues
400 {
401 std::queue<PdCom::Promise<PdCom::Exception const &>> queue_;
402
403 public:
404 132 PendingSetValues() = default;
405
406 PdCom::Variable::SetValueFuture push();
407 void pop();
408
409 ~PendingSetValues();
410
411 } pending_set_values_;
412
413
414 enum {
415 StartUp,
416 Idle,
417 GetListing,
418 WaitForConnected,
419 WaitForLogin,
420 GetVariableFields,
421 ReadData,
422 ReadEvent,
423 ReadDataOrEvent,
424 GetActiveMessages,
425 ReadClientStatistics,
426 } state = StartUp;
427
428
429 std::queue<uint32_t> seqNoQ;
430 uint32_t messageSeqNo;
431 std::vector<PdCom::Message> messageList;
432 std::vector<PdCom::ClientStatistics> client_statistics;
433
434 void setPolite(bool state);
435
436 /** Read a variable tag */
437 static const TypeInfo *getDataType(const char **atts, SizeInfo &size_info);
438 Parameter *getParameter(const char **atts);
439 Channel *getChannel(const char **atts);
440
441 // callbacks for xml parser
442 friend class ExpatWrapper<ProtocolHandler>;
443 void startElement(const char *name, const char **atts);
444 void endElement(const char *name);
445 void xmlError(const char *);
446
447 void xsapAck();
448 void pendingAck(Variable *);
449 void pollParameter(size_t index, const char *id);
450 void pollChannel(size_t index, const char *id);
451
452 // Reimplemented from PdCom::ProtocolHandler
453 bool asyncData() override;
454 bool find(const std::string &path) override;
455 bool list(const std::string &directory) override;
456 void getClientStatistics() override;
457 void logout() override;
458 bool login(const char *mech, const char *clientData) override;
459
460 void ping() override;
461 std::string name() const override;
462 std::string version() const override;
463
464 void
465 broadcast(const std::string &message, const std::string &attr) override;
466 void processBroadcast(const char **atts);
467
468 void readEventData(const char *name, const char **atts);
469 void readPeriodicData(const char *name, const char **atts);
470 };
471
472
473 }}} // namespace PdCom::impl::MsrProto
474
475 #endif // PD_MSRPROTOCOLHANDLER_H
476