GCC Code Coverage Report


Directory: ./
File: pdcom5/src/msrproto/ProtocolHandler.cpp
Date: 2024-11-17 04:08:36
Exec Total Coverage
Lines: 904 1106 81.7%
Branches: 988 1982 49.8%

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 #include "ProtocolHandler.h"
23
24 #include "../Debug.h"
25 #include "../SpyLayer.h"
26 #include "Channel.h"
27 #include "DirNode.h"
28 #include "Parameter.h"
29 #include "Subscription.h"
30 #include "expat_wrapper_impl.h"
31
32 #include <algorithm>
33 #include <cstring>
34 #include <errno.h>
35 #include <mutex>
36 #include <ostream>
37 #include <pdcom5/Exception.h>
38 #include <pdcom5/Subscriber.h>
39 #include <sstream>
40 #include <stdexcept>
41 #include <typeinfo>
42
43 #if defined _WIN32 || defined __ANDROID__
44 namespace {
45 struct PthreadCancelDisabler
46 {};
47 } // namespace
48
49 #else
50
51 #include <pthread.h>
52 namespace {
53 class PthreadCancelDisabler
54 {
55 int cancel_state_ = 0;
56
57 public:
58 PthreadCancelDisabler()
59 {
60 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state_);
61 }
62 ~PthreadCancelDisabler() { pthread_setcancelstate(cancel_state_, nullptr); }
63 };
64 } // namespace
65
66 #endif
67
68 #ifdef PDC_DEBUG
69 #include <stdlib.h> // getenv(), atoi()
70 #endif
71
72 using PdCom::impl::MsrProto::Channel;
73 using PdCom::impl::MsrProto::ChannelSubscriptionsWithGroup;
74 using PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup;
75 using PdCom::impl::MsrProto::EventSubscription;
76 using PdCom::impl::MsrProto::ExpatWrapper;
77 using PdCom::impl::MsrProto::Parameter;
78 using PdCom::impl::MsrProto::PeriodicSubscription;
79 using PdCom::impl::MsrProto::PollSubscription;
80 using PdCom::impl::MsrProto::ProtocolHandler;
81 using PdCom::impl::MsrProto::Variable;
82 using PdCom::impl::MsrProto::XmlStream;
83
84
85 namespace {
86 struct Attribute
87 { /*{{{*/
88 3828 Attribute(const char **atts) : atts(atts) {}
89
90 7708 const char *find(const char *const arg, const char *const else_return = "")
91 {
92
3/4
✓ Branch 0 taken 27555 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 25639 times.
✓ Branch 5 taken 1916 times.
27555 for (size_t i = 0; arg and atts[i]; i += 2) {
93
4/6
✗ Branch 2 not taken.
✓ Branch 3 taken 25639 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25639 times.
✓ Branch 6 taken 5792 times.
✓ Branch 7 taken 19847 times.
25639 if (!strcmp(atts[i], arg))
94 5792 return atts[i + 1];
95 }
96
97 1916 return else_return;
98 }
99
100 333 bool getString(const char *arg, const char *&val)
101 {
102 333 const char *attr = find(arg, nullptr);
103
104
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 179 times.
333 if (!attr)
105 154 return false;
106
107 179 val = attr;
108 179 return true;
109 };
110
111 2598 bool getUInt(const char *arg, unsigned int &val)
112 {
113 2598 const char *attr = find(arg);
114
115 // Only test for numbers, even leading '+' is ignored
116
3/4
✓ Branch 1 taken 2060 times.
✓ Branch 2 taken 538 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2060 times.
2598 if (*attr < '0' or *attr > '9')
117 538 return false;
118
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2060 times.
2060 val = atol(attr);
120 2060 return true;
121 }
122
123 140 bool getInt(const char *arg, int &val)
124 {
125 140 const char *attr = find(arg);
126
127 // Only test for numbers, even leading '+' is ignored
128
4/6
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 81 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 59 times.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
140 if ((*attr < '0' or *attr > '9') and *attr != '-')
129 81 return false;
130
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 val = atoi(attr);
132 59 return true;
133 }
134
135 377 bool isTrue(const char *arg)
136 {
137 377 unsigned int val;
138
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 377 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
377 return getUInt(arg, val) and val;
139 }
140
141 208 bool getDouble(const char *arg, double &val)
142 {
143 208 const char *attr = find(arg);
144
145
1/2
✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
208 if (*attr)
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 val = atof(attr);
147
148 208 return *attr;
149 }
150
151 541 std::chrono::nanoseconds getTime_ns(const char *arg)
152 {
153 541 const char *attr = find(arg);
154
155 541 int64_t time_ns = 0;
156 541 size_t i = 0;
157 6426 do {
158
6/6
✓ Branch 1 taken 5344 times.
✓ Branch 2 taken 1623 times.
✓ Branch 3 taken 2098 times.
✓ Branch 4 taken 3246 times.
✓ Branch 6 taken 541 times.
✓ Branch 7 taken 1557 times.
6967 if (!*attr or (!i and *attr == '.')) {
159
2/2
✓ Branch 0 taken 541 times.
✓ Branch 1 taken 1623 times.
4328 if (!i)
160 541 i = 10;
161 }
162
2/4
✓ Branch 1 taken 4803 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4803 times.
4803 else if (*attr < '0' or *attr > '9')
163 return std::chrono::nanoseconds {0};
164
165
2/2
✓ Branch 1 taken 6426 times.
✓ Branch 2 taken 541 times.
6967 if (*attr != '.') {
166
3/4
✓ Branch 1 taken 1623 times.
✓ Branch 2 taken 4803 times.
✓ Branch 3 taken 1623 times.
✗ Branch 4 not taken.
6426 if (*attr or i != 10)
167 6426 time_ns *= 10;
168
169
2/2
✓ Branch 1 taken 4803 times.
✓ Branch 2 taken 1623 times.
6426 if (*attr)
170 4803 time_ns += *attr - '0';
171 }
172
173
2/2
✓ Branch 1 taken 5344 times.
✓ Branch 2 taken 1623 times.
6967 if (*attr)
174 5344 ++attr;
175
176
8/8
✓ Branch 1 taken 6426 times.
✓ Branch 2 taken 541 times.
✓ Branch 3 taken 5410 times.
✓ Branch 4 taken 1016 times.
✓ Branch 5 taken 4869 times.
✓ Branch 6 taken 541 times.
✓ Branch 7 taken 6426 times.
✓ Branch 8 taken 541 times.
6967 } while (*attr == '.' or !i or --i);
177
178 541 return std::chrono::nanoseconds {time_ns};
179 }
180
181 50 bool getMessage(const char *tag_name, PdCom::Message &msg, bool hasSeqNo)
182 {
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 const bool is_reset = !strcmp(tag_name, "reset");
184 50 const char *c = nullptr;
185 50 unsigned int u = 0;
186
4/6
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 50 times.
50 if (!getString("name", c) && !getString("path", c)) {
187 log_debug("Missing name in message");
188 return false;
189 }
190
1/2
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
50 msg.path = c;
191
4/6
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 50 times.
50 if (hasSeqNo && !getUInt("seq", u)) {
192 log_debug("Invalid or missing sequence number in message");
193 return false;
194 }
195 50 msg.seqNo = u;
196 // index is optional, set it to -1 if absent.
197 50 msg.index = -1;
198 50 getInt("index", msg.index);
199
1/2
✓ Branch 3 taken 50 times.
✗ Branch 4 not taken.
50 msg.time = getTime_ns("time");
200
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 31 times.
50 if (is_reset) {
201 19 msg.level = PdCom::LogLevel::Reset;
202 19 return true;
203 }
204 // text is also optional
205
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 1 times.
31 if (getString("text", c)) {
206
1/2
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 msg.text = c;
207 }
208 else {
209 1 msg.text = std::string();
210 }
211
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 29 times.
31 if (getUInt("state", u)) {
212 //
213
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!u) {
214 1 msg.level = PdCom::LogLevel::Reset;
215 }
216
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 else if (!strcmp(tag_name, "crit_error"))
217 msg.level = PdCom::LogLevel::Critical;
218
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 else if (!strcmp(tag_name, "error"))
219 1 msg.level = PdCom::LogLevel::Error;
220 else if (!strcmp(tag_name, "warn"))
221 msg.level = PdCom::LogLevel::Warn;
222 else if (!strcmp(tag_name, "info"))
223 msg.level = PdCom::LogLevel::Info;
224 else {
225 log_debug("Invalid event attribute name %s", tag_name);
226 return false;
227 }
228 }
229
3/6
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 29 times.
29 else if (!getUInt("prio", u) || u > 7) {
230 log_debug("Invalid priority in message");
231 return false;
232 }
233 else
234 29 msg.level = static_cast<PdCom::LogLevel>(u);
235 31 return true;
236 }
237
238 5 bool getClientStatistics(PdCom::ClientStatistics &stats)
239 {
240 5 const char *c = nullptr;
241 5 unsigned count = 0;
242 5 double d = 0.0;
243 5 stats = {};
244
245
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (getString("name", c)) {
246
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 stats.name_ = c;
247 }
248
249 // yes, this is a typo. It is what it is.
250
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (getString("apname", c)) {
251
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 stats.application_name_ = c;
252 }
253
254
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (getUInt("countin", count))
255 5 stats.received_bytes_ = count;
256
257
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (getUInt("countout", count))
258 5 stats.sent_bytes_ = count;
259
260
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (getDouble("connectedtime", d))
261 10 stats.connected_time_ =
262
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 std::chrono::duration_cast<std::chrono::nanoseconds>(
263 10 std::chrono::duration<double>(d));
264
265 5 return true;
266 }
267
268 const char **atts;
269 }; /*}}}*/
270 } // namespace
271
272
273 157 XmlStream::XmlStream(PdCom::impl::Process *process, std::streambuf *sb) :
274 157 os(sb), process(process)
275 {
276
1/2
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
157 os.exceptions(std::ios_base::badbit);
277 157 }
278 662 void XmlStream::lock()
279 {
280 662 process->transmitSemaphore(true);
281 662 }
282 662 void XmlStream::unlock()
283 {
284 662 process->transmitSemaphore(false);
285 662 }
286
287
288 namespace {
289 struct XmlCommand
290 { /*{{{*/
291 struct Attribute
292 {
293 // Create an attribute for a command.
294 Attribute(XmlCommand &command, const char *name) : cout(command.cout)
295 {
296 // send the preamble
297 cout << ' ' << name << "=\"";
298 }
299 ~Attribute() noexcept(false) { cout << '"'; }
300
301 XmlStream &cout;
302 };
303
304 662 XmlCommand(XmlStream &cout, const char *command) :
305 662 cout(cout), guard(cout), p_flush(true)
306 {
307
2/4
✓ Branch 3 taken 662 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 662 times.
✗ Branch 8 not taken.
662 cout << '<' << command;
308 662 }
309
310 662 ~XmlCommand() noexcept(false)
311 662 {
312
1/2
✓ Branch 3 taken 662 times.
✗ Branch 4 not taken.
662 cout << ">\r\n";
313
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 662 times.
✓ Branch 3 taken 554 times.
✓ Branch 4 taken 108 times.
662 if (p_flush)
314
1/2
✓ Branch 3 taken 554 times.
✗ Branch 4 not taken.
554 cout.flush();
315 662 }
316
317 485 XmlCommand &addEscapedAttribute(const char *name, const std::string &str)
318 {
319
4/8
✓ Branch 4 taken 485 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 485 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 485 times.
✗ Branch 14 not taken.
✓ Branch 18 taken 485 times.
✗ Branch 19 not taken.
485 cout << ' ' << name << '=' << '"';
320
321
2/2
✓ Branch 8 taken 5154 times.
✓ Branch 9 taken 476 times.
5630 for (const char c : str) {
322
5/5
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 5091 times.
5154 switch (c) {
323 18 case '"':
324
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 cout << "&quot;";
325 18 break;
326 18 case '<':
327
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 cout << "&lt;";
328 18 break;
329 18 case '&':
330
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 cout << "&amp;";
331 18 break;
332 9 case '\0':
333
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 throw PdCom::InvalidArgument("Value must not contain NULL");
334 5091 default:
335
1/2
✓ Branch 3 taken 5091 times.
✗ Branch 4 not taken.
5091 cout << c;
336 }
337 }
338
339
1/2
✓ Branch 4 taken 476 times.
✗ Branch 5 not taken.
476 cout << '"';
340
341 476 return *this;
342 }
343
344 template <typename T>
345 791 XmlCommand &addAttribute(const char *name, T const &val, bool active = true)
346 {
347
8/16
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 31 times.
✓ Branch 6 taken 243 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 142 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 59 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 150 times.
✗ Branch 15 not taken.
791 if (active)
348
35/80
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 48 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 48 times.
✗ Branch 17 not taken.
✓ Branch 21 taken 48 times.
✗ Branch 22 not taken.
✓ Branch 31 taken 52 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 52 times.
✗ Branch 36 not taken.
✓ Branch 39 taken 52 times.
✗ Branch 40 not taken.
✓ Branch 43 taken 52 times.
✗ Branch 44 not taken.
✓ Branch 48 taken 52 times.
✗ Branch 49 not taken.
✓ Branch 58 taken 66 times.
✗ Branch 59 not taken.
✓ Branch 62 taken 66 times.
✗ Branch 63 not taken.
✓ Branch 66 taken 66 times.
✗ Branch 67 not taken.
✓ Branch 70 taken 66 times.
✗ Branch 71 not taken.
✓ Branch 75 taken 66 times.
✗ Branch 76 not taken.
✓ Branch 85 taken 243 times.
✗ Branch 86 not taken.
✓ Branch 89 taken 243 times.
✗ Branch 90 not taken.
✓ Branch 93 taken 243 times.
✗ Branch 94 not taken.
✓ Branch 97 taken 243 times.
✗ Branch 98 not taken.
✓ Branch 102 taken 243 times.
✗ Branch 103 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✓ Branch 139 taken 142 times.
✗ Branch 140 not taken.
✓ Branch 143 taken 142 times.
✗ Branch 144 not taken.
✓ Branch 147 taken 142 times.
✗ Branch 148 not taken.
✓ Branch 151 taken 142 times.
✗ Branch 152 not taken.
✓ Branch 156 taken 142 times.
✗ Branch 157 not taken.
✓ Branch 166 taken 59 times.
✗ Branch 167 not taken.
✓ Branch 170 taken 59 times.
✗ Branch 171 not taken.
✓ Branch 174 taken 59 times.
✗ Branch 175 not taken.
✓ Branch 178 taken 59 times.
✗ Branch 179 not taken.
✓ Branch 183 taken 59 times.
✗ Branch 184 not taken.
✓ Branch 193 taken 150 times.
✗ Branch 194 not taken.
✓ Branch 197 taken 150 times.
✗ Branch 198 not taken.
✓ Branch 201 taken 150 times.
✗ Branch 202 not taken.
✓ Branch 205 taken 150 times.
✗ Branch 206 not taken.
✓ Branch 210 taken 150 times.
✗ Branch 211 not taken.
760 cout << ' ' << name << "=\"" << val << '"';
349 791 return *this;
350 }
351
352 template <typename T>
353 43 XmlCommand &addAttributeStream(const char *name, T &&callback)
354 {
355
3/6
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 43 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 43 times.
✗ Branch 13 not taken.
43 cout << ' ' << name << "=\"";
356 43 callback(cout);
357
1/2
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
43 cout << '"';
358 43 return *this;
359 }
360
361 108 XmlCommand &noFlush()
362 {
363 108 p_flush = false;
364 108 return *this;
365 }
366
367 445 XmlCommand &setId(const char *id)
368 {
369
2/4
✓ Branch 0 taken 445 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 445 times.
✗ Branch 4 not taken.
445 if (id and *id)
370
1/2
✓ Branch 8 taken 445 times.
✗ Branch 9 not taken.
445 cout << " id=\"" << id << '"';
371
372 445 return *this;
373 }
374
375 XmlStream &cout;
376 std::lock_guard<XmlStream> guard;
377 bool p_flush;
378 }; /*}}}*/
379 } // namespace
380
381 ///////////////////////////////////////////////////////////////////////////
382 157 ProtocolHandler::ProtocolHandler(PdCom::impl::Process *process, IOLayer *io) :
383 PdCom::impl::ProtocolHandler(process),
384 StreambufLayer(io),
385 ExpatWrapper<ProtocolHandler, true>(),
386 cout(process, this),
387 root(std::make_shared<DirNode>()),
388
11/22
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 157 times.
✗ Branch 9 not taken.
✓ Branch 28 taken 157 times.
✗ Branch 29 not taken.
✓ Branch 32 taken 157 times.
✗ Branch 33 not taken.
✓ Branch 36 taken 157 times.
✗ Branch 37 not taken.
✓ Branch 43 taken 157 times.
✗ Branch 44 not taken.
✓ Branch 56 taken 157 times.
✗ Branch 57 not taken.
✓ Branch 60 taken 157 times.
✗ Branch 61 not taken.
✓ Branch 79 taken 157 times.
✗ Branch 80 not taken.
✓ Branch 87 taken 157 times.
✗ Branch 88 not taken.
✓ Branch 94 taken 157 times.
✗ Branch 95 not taken.
157 channel_subscriptions_(new ChannelSubscriptionsWithGroup())
389 { /*{{{*/
390
391 #if PDC_DEBUG
392 {
393 char *spy = getenv("SPY");
394 if (spy and atoi(spy))
395 insert(new SpyLayer(io));
396 }
397 #endif
398
399 157 const char buf[] = "<xml>";
400
1/2
✓ Branch 3 taken 157 times.
✗ Branch 4 not taken.
157 ExpatBuffer<sizeof(buf)> inputBuf(*this);
401 157 std::memcpy(inputBuf.fill(), buf, sizeof(buf));
402
2/4
✓ Branch 6 taken 157 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 157 times.
157 if (!parse(std::move(inputBuf), sizeof(buf) - 1, false))
403 throw Exception("setting up xml parser failed");
404 157 } /*}}}*/
405
406 ///////////////////////////////////////////////////////////////////////////
407 312 ProtocolHandler::~ProtocolHandler()
408 { /*{{{*/
409 log_debug("killed %p", static_cast<void *>(this));
410 312 } /*}}}*/
411
412 ///////////////////////////////////////////////////////////////////////////
413 void ProtocolHandler::xmlError(const char *err_msg)
414 { /*{{{*/
415 if (state != StartUp and state != WaitForConnected)
416 throw ProtocolError(std::string("Fatal XML parsing error: ") + err_msg);
417 } /*}}}*/
418
419 #if PDC_DEBUG
420 const char *statename[] = {
421 "StartUp",
422 "Idle",
423 "GetListing",
424 "WaitForConnected",
425 };
426 #endif
427
428 namespace {
429 constexpr const char *message_tags[] = {
430 "crit_error", "error", "warn", "info", "reset",
431 };
432
433 32 bool is_message_tag(const char *name)
434 {
435
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 for (const auto t : message_tags) {
436
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 50 times.
82 if (!strcmp(name, t))
437 32 return true;
438 }
439 return false;
440 }
441 } // namespace
442
443 ///////////////////////////////////////////////////////////////////////////
444 2811 void ProtocolHandler::startElement(const char *name, const char **atts)
445 { /*{{{*/
446 2811 const char *id = nullptr;
447
448
11/13
✗ Branch 3 not taken.
✓ Branch 4 taken 2811 times.
✓ Branch 5 taken 157 times.
✓ Branch 6 taken 155 times.
✓ Branch 7 taken 85 times.
✓ Branch 8 taken 1206 times.
✓ Branch 9 taken 293 times.
✓ Branch 10 taken 846 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 42 times.
✓ Branch 13 taken 18 times.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
2811 switch (state) {
449 157 case StartUp:
450
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 157 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 157 times.
✗ Branch 9 not taken.
157 if (!strcmp(name, "xml") and level() == 1)
451 157 state = WaitForConnected;
452 157 break;
453
454 155 case WaitForConnected:
455
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 155 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 155 times.
✗ Branch 9 not taken.
155 if (!strcmp(name, "connected") and level() == 2) {
456 155 Attribute a(atts);
457 155 feature = a.find("features");
458
1/2
✓ Branch 3 taken 155 times.
✗ Branch 4 not taken.
155 m_name = a.find("app");
459
1/2
✓ Branch 3 taken 155 times.
✗ Branch 4 not taken.
155 m_version = a.find("appversion");
460
461
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 155 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 145 times.
155 if (!feature.group)
462 20 channel_subscriptions_.reset(
463
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
10 new ChannelSubscriptionsWithoutGroup());
464
465 // if login is mandatory, <saslauth> is sent automatically by
466 // server
467
8/10
✗ Branch 3 not taken.
✓ Branch 4 taken 155 times.
✓ Branch 5 taken 145 times.
✓ Branch 6 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 145 times.
✓ Branch 10 taken 28 times.
✓ Branch 11 taken 117 times.
✓ Branch 12 taken 28 times.
✓ Branch 13 taken 127 times.
155 if (feature.login and !strcmp(a.find("login"), "mandatory")) {
468
2/2
✓ Branch 12 taken 27 times.
✓ Branch 13 taken 1 times.
28 if (process->auth_manager_) {
469 27 state = WaitForLogin;
470 27 break;
471 }
472 else
473
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 throw LoginRequired();
474 }
475
2/4
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 127 times.
✗ Branch 6 not taken.
254 XmlCommand(cout, "remote_host")
476
1/2
✓ Branch 3 taken 127 times.
✗ Branch 4 not taken.
254 .addAttribute("access", "allow")
477 .addEscapedAttribute(
478
2/4
✓ Branch 6 taken 127 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 127 times.
✗ Branch 11 not taken.
254 "applicationname", process->applicationName())
479
2/4
✓ Branch 6 taken 127 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 127 times.
✗ Branch 11 not taken.
254 .addEscapedAttribute("hostname", process->hostname())
480
1/2
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
127 .setId("init");
481
482
2/2
✓ Branch 4 taken 127 times.
✓ Branch 5 taken 27 times.
127 state = Idle;
483 }
484 127 break;
485
486 85 case WaitForLogin:
487
4/6
✗ Branch 2 not taken.
✓ Branch 3 taken 85 times.
✓ Branch 4 taken 85 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
✓ Branch 7 taken 62 times.
255 if (level() == 2 and !strcmp(name, "saslauth")
488
3/4
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
✓ Branch 6 taken 23 times.
✓ Branch 7 taken 62 times.
170 and processLogin(atts)) {
489
1/2
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
46 XmlCommand(cout, "remote_host")
490
1/2
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
46 .addAttribute("access", "allow")
491 .addEscapedAttribute(
492
2/4
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
46 "applicationname", process->applicationName())
493
2/4
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 23 times.
✗ Branch 11 not taken.
46 .addEscapedAttribute("hostname", process->hostname())
494
1/2
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 .setId("init");
495
496 23 state = Idle;
497 }
498 85 break;
499
500 1206 case Idle:
501
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1206 times.
1206 if (level() != 2) {
502 log_debug("Unknown XML tag in Idle: %s", name);
503 break;
504 }
505
506 // find() returns "" if id is not found
507 1206 id = Attribute(atts).find("id");
508
509
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1206 times.
✓ Branch 2 taken 385 times.
✓ Branch 3 taken 821 times.
1206 if (!strcmp(name, "data")) {
510 385 Attribute a(atts);
511
512 385 unsigned int dataGroupId = 0;
513 385 a.getUInt("group", dataGroupId);
514
515
1/2
✓ Branch 2 taken 385 times.
✗ Branch 3 not taken.
385 dataTime = a.getTime_ns("time");
516
517
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 385 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 343 times.
385 if (!feature.group) {
518 42 state = ReadDataOrEvent;
519 }
520
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 341 times.
343 else if (!dataGroupId) {
521 // Attribute "group" not found. Event transmission
522 2 state = ReadEvent;
523 }
524 else {
525 341 periodic_receive_handle_ =
526
1/2
✓ Branch 4 taken 341 times.
✗ Branch 5 not taken.
1364 channel_subscriptions_->startNewDataRecieving(
527
1/2
✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
682 dataGroupId, variable_cache_.lock(),
528 1023 dataTime);
529 341 state = ReadData;
530 }
531 }
532
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 821 times.
✓ Branch 2 taken 133 times.
✓ Branch 3 taken 688 times.
821 else if (!strcmp(name, "pu")) {
533 133 unsigned int index;
534
535
5/10
✗ Branch 3 not taken.
✓ Branch 4 taken 133 times.
✓ Branch 5 taken 133 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 133 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 133 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 133 times.
✗ Branch 17 not taken.
133 if (!feature.xsap and Attribute(atts).getUInt("index", index)) {
536
3/4
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 100 times.
399 if (parameter_event_.find(index)
537 399 != parameter_event_.end()) {
538
1/2
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
33 pollParameter(index, "pollParameterEvent");
539 }
540 }
541 }
542
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 688 times.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 611 times.
688 else if (!strcmp(name, "parameter")) {
543 77 Parameter *p = getParameter(atts);
544
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 if (p) {
545 77 Attribute a(atts);
546
1/2
✓ Branch 2 taken 77 times.
✗ Branch 3 not taken.
77 const auto time_ns = a.getTime_ns("mtime");
547 77 unsigned int pm;
548 203 const auto getValue = [&a, p, this]() {
549 42 auto cache = variable_cache_.lock();
550 42 const char *const hexvalue = a.find("hexvalue");
551
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
42 if (hexvalue && *hexvalue)
552
2/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
84 cache[0].readFromHexDec(hexvalue, *p);
553 else
554 cache[0].readFromString(a.find("value"), *p);
555 42 return cache;
556 77 };
557
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 71 times.
154 if (!strcmp(id, "pollParameter")
558
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 71 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
77 and !subscription_pending_parameter_polls_.empty()) {
559 6 auto sub_collection = std::move(
560 12 subscription_pending_parameter_polls_.front());
561 6 subscription_pending_parameter_polls_.pop_front();
562
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 sub_collection.subscriptions_.readData(
563
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
12 getValue()[0].data(), time_ns);
564 }
565
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 68 times.
71 else if (!strcmp(id, "VariablePollParameter")) {
566
1/2
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
6 variable_pending_polls_.processResult(
567
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
6 *p, getValue()[0].data(), time_ns);
568 }
569
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 else if (
570
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 68 times.
68 !feature.xsap
571
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 35 times.
68 and !strcmp(id, "pollParameterEvent")) {
572
2/4
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 33 times.
✗ Branch 8 not taken.
99 parameter_event_[p->index_].readData(
573
2/4
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
66 getValue()[0].data(), time_ns);
574 }
575
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 30 times.
35 else if (!strcmp(id, "pendingParameter"))
576
1/2
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 pendingAck(p);
577
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
30 else if (a.getUInt("pm", pm) && pm == 1) {
578 parameter_event_[p->index_].readData(
579 getValue()[0].data(), time_ns);
580 }
581 }
582 }
583
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 611 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 550 times.
611 else if (!strcmp(name, "channel")) {
584 61 Channel *c = getChannel(atts);
585
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 if (c) {
586
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 54 times.
122 if (!strcmp(id, "pollChannel")
587
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 54 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
61 and !subscription_pending_channel_polls_.empty()) {
588 // can be nullptr if subscription was deleted in the
589 // meantime
590 7 auto channel_poll = std::move(
591 14 subscription_pending_channel_polls_.front());
592 7 subscription_pending_channel_polls_.pop_front();
593 7 Attribute a(atts);
594
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
14 auto cache = variable_cache_.lock();
595
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 if (const auto s = a.find("hexvalue", nullptr))
596
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
7 cache[0].readFromHexDec(s, *c);
597 else
598 cache[0].readFromString(a.find("value"), *c);
599
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 channel_poll.subscriptions_.readData(
600
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 cache[0].data(), a.getTime_ns("time"));
601 }
602
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 else if (!strcmp(id, "VariablePollChannel")) {
603 Attribute a(atts);
604 auto cache = variable_cache_.lock();
605 if (const auto s = a.find("hexvalue", nullptr))
606 cache[0].readFromHexDec(s, *c);
607 else
608 cache[0].readFromString(a.find("value"), *c);
609 variable_pending_polls_.processResult(
610 *c, cache[0].data(), a.getTime_ns("time"));
611 }
612
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 33 times.
54 else if (!strcmp(id, "pendingChannel"))
613 21 pendingAck(c);
614 }
615 }
616
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 550 times.
✓ Branch 2 taken 435 times.
✓ Branch 3 taken 115 times.
550 else if (!strcmp(name, "ack")) {
617 // Check which ack was called
618
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 435 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 387 times.
435 if (!strcmp(id, ChannelSubscriptions::xsadId))
619 48 channel_subscriptions_->xsadAck(process);
620
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 387 times.
387 else if (!strcmp(id, "xsapQ"))
621 xsapAck();
622
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 387 times.
387 else if (!strcmp(id, ChannelSubscriptions::xsodId))
623 channel_subscriptions_->xsodAck();
624
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 387 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 361 times.
387 else if (!strcmp(id, "pendingChannel"))
625 26 pendingAck(nullptr);
626
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 361 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 289 times.
361 else if (!strcmp(id, "findQ"))
627 72 processFindRequest();
628
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 289 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 281 times.
289 else if (!strcmp(id, "listQ")) {
629 8 fullListing = Cached;
630
631 // Process all pending list and find requests
632
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 while (processListRequest())
633 ;
634
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 while (processFindRequest())
635 ;
636 }
637
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 266 times.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 266 times.
281 else if (!strcmp(id, "history") and !seqNoQ.empty()) {
638
2/2
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 6 times.
15 if (messageSeqNo != seqNoQ.front()) {
639 18 PdCom::Message m = {};
640
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 m.seqNo = seqNoQ.front();
641
2/4
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 9 times.
✗ Branch 21 not taken.
9 process->getMessageReply(m);
642 }
643 15 seqNoQ.pop();
644 }
645
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
✓ Branch 2 taken 149 times.
✓ Branch 3 taken 117 times.
266 else if (!strcmp(id, "init"))
646 149 process->connected();
647 }
648
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 10 times.
115 else if (
649
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 97 times.
✓ Branch 5 taken 8 times.
220 !strcmp(name, "listing") or !strcmp(name, "channels")
650
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 89 times.
97 or !strcmp(name, "parameters")) {
651 26 state = GetListing;
652 }
653
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 83 times.
89 else if (!strcmp(name, "saslauth"))
654 6 processLogin(atts);
655
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 80 times.
83 else if (!strcmp(name, "ping"))
656 3 process->pingReply();
657
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 58 times.
80 else if (!strcmp(name, "broadcast"))
658 22 processBroadcast(atts);
659
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 37 times.
58 else if (!strcmp(name, "message_history"))
660 21 state = GetActiveMessages;
661
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 32 times.
37 else if (!strcmp(name, "clients")) {
662 5 state = ReadClientStatistics;
663 5 client_statistics.clear();
664 }
665
3/6
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 15 taken 32 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 32 times.
✗ Branch 18 not taken.
32 else if (is_message_tag(name) and process->message_manager_) {
666 64 PdCom::Message msg = {};
667 32 Attribute a(atts);
668
3/6
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
✗ Branch 9 not taken.
32 if (a.getMessage(name, msg, feature.history)) {
669
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 26 times.
32 if (!strcmp(id, "history")) {
670 6 messageSeqNo = msg.seqNo;
671
1/2
✓ Branch 20 taken 6 times.
✗ Branch 21 not taken.
6 process->getMessageReply(std::move(msg));
672 }
673 else {
674
1/2
✓ Branch 20 taken 26 times.
✗ Branch 21 not taken.
26 process->processMessage(std::move(msg));
675 }
676 }
677 else {
678 log_debug("Failed to parse message");
679 }
680 }
681 1206 break;
682
683 293 case GetListing:
684
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 293 times.
293 if (level() != 3) {
685 log_debug("Unknown XML tag in GetListing: %s", name);
686 break;
687 }
688
689
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 293 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 288 times.
293 if (!strcmp(name, "dir")) {
690 5 const char *path;
691
2/6
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
10 if (Attribute(atts).getString("path", path)
692
10/32
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 5 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 5 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 5 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 5 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 5 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 5 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 5 times.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
10 and !root->find(path)) {
693
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
5 DirNode *node = new DirNode;
694
2/4
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
5 root->insert(std::unique_ptr<DirNode>(node), path);
695 log_debug("Create dir %s", node->path().c_str());
696 }
697 }
698
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 149 times.
✓ Branch 3 taken 139 times.
288 else if (!strcmp(name, "channel"))
699 149 getChannel(atts);
700
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 139 times.
✗ Branch 3 not taken.
139 else if (!strcmp(name, "parameter"))
701 139 getParameter(atts);
702 293 break;
703
704 846 case ReadData:
705
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 846 times.
846 if (level() != 3) {
706 log_debug("Unknown XML tag in ReadData: %s", name);
707 break;
708 }
709
710 846 readPeriodicData(name, atts);
711
712 846 break;
713
714 4 case ReadEvent:
715
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (level() != 3) {
716 log_debug("Unknown XML tag in ReadEvent: %s", name);
717 break;
718 }
719
720 4 readEventData(name, atts);
721
722 4 break;
723
724 42 case ReadDataOrEvent:
725
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 if (level() != 3) {
726 log_debug("Unknown XML tag in ReadDataOrEvent: %s", name);
727 break;
728 }
729
730
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 if (name[0] == 'F') {
731 42 state = ReadData;
732 42 periodic_receive_handle_ =
733
1/2
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
168 channel_subscriptions_->startNewDataRecieving(
734 210 0, variable_cache_.lock(), dataTime);
735 42 readPeriodicData(name, atts);
736 }
737 else if (name[0] == 'E') {
738 state = ReadEvent;
739 readEventData(name, atts);
740 }
741
742 42 break;
743 18 case GetActiveMessages:
744
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if (level() != 3) {
745 log_debug("Unknown XML tag in GetActiveMessages: %s", name);
746 break;
747 }
748
749 {
750 36 Message msg;
751
2/4
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
18 if (Attribute(atts).getMessage(name, msg, true)) {
752
1/2
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 messageList.push_back(std::move(msg));
753 18 }
754 }
755 18 break;
756
757 5 case ReadClientStatistics:
758
4/8
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
5 if (level() != 3 or strcmp(name, "client")) {
759 log_debug("Unknown XML tag in ReadClientStatistics: %s", name);
760 break;
761 }
762
763 {
764 10 PdCom::ClientStatistics stats;
765
2/4
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
5 if (Attribute(atts).getClientStatistics(stats)) {
766
1/2
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 client_statistics.push_back(std::move(stats));
767 }
768 else {
769 log_debug("Drop incomplete <client> tag");
770 5 }
771 }
772 5 break;
773
774 default:
775 break;
776 };
777 2810 } /*}}}*/
778
779 ///////////////////////////////////////////////////////////////////////////
780 2653 void ProtocolHandler::endElement(const char *name)
781 { /*{{{*/
782
7/8
✗ Branch 3 not taken.
✓ Branch 4 taken 2653 times.
✓ Branch 5 taken 319 times.
✓ Branch 6 taken 1271 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 10 times.
✓ Branch 10 taken 1008 times.
2653 switch (state) {
783 319 case GetListing:
784
2/2
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 293 times.
319 if (level() == 2) {
785 26 state = Idle;
786
787 // name is either
788 // - channels
789 // - parameters
790 // - listing
791
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
26 if (!strcmp(name, "listing"))
792 10 processListRequest();
793 }
794
795 319 break;
796
797 1271 case ReadData:
798
6/8
✓ Branch 2 taken 383 times.
✓ Branch 3 taken 888 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 383 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 383 times.
✓ Branch 8 taken 888 times.
✓ Branch 9 taken 383 times.
1271 if (level() != 2 or strcmp(name, "data"))
799 888 break;
800
1/2
✓ Branch 2 taken 383 times.
✗ Branch 3 not taken.
383 if (periodic_receive_handle_) {
801 383 periodic_receive_handle_.endNewDataRecieving();
802 383 periodic_receive_handle_ = {};
803 }
804 383 state = Idle;
805 383 break;
806
807 6 case ReadEvent:
808 case ReadDataOrEvent:
809
6/8
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 4 times.
6 if (level() == 2 and !strcmp(name, "data")) {
810 2 state = Idle;
811 }
812 6 break;
813
814 39 case GetActiveMessages:
815
6/8
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21 times.
✓ Branch 9 taken 18 times.
39 if (level() == 2 and !strcmp(name, "message_history")) {
816 21 state = Idle;
817
1/2
✓ Branch 21 taken 21 times.
✗ Branch 22 not taken.
21 process->activeMessagesReply(std::move(messageList));
818 21 messageList.clear();
819 }
820 39 break;
821
822 10 case ReadClientStatistics:
823
6/8
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 5 times.
10 if (level() == 2 and !strcmp(name, "clients")) {
824 5 state = Idle;
825
1/2
✓ Branch 21 taken 5 times.
✗ Branch 22 not taken.
5 process->clientStatisticsReply(std::move(client_statistics));
826 5 client_statistics.clear();
827 }
828 10 break;
829
830 1008 default:
831 1008 break;
832 }
833 2653 } /*}}}*/
834
835 ///////////////////////////////////////////////////////////////////////////
836 // Arguments:
837 // var: if var == 0, this is a test to check whether path was found
838 // if var != 0, found the variable --> subscribe it
839 52 void ProtocolHandler::pendingAck(Variable *var)
840 { /*{{{*/
841
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
52 if (pending_queue_.empty())
842 throw ProtocolError("Empty pending request queue");
843
844
2/2
✓ Branch 8 taken 52 times.
✓ Branch 9 taken 52 times.
104 for (const auto &weak_sub : pending_queue_.front().subscriptions_) {
845
2/2
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 26 times.
78 auto ps = weak_sub.lock();
846
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
52 if (!ps)
847 26 continue;
848
849
2/2
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 26 times.
52 std::shared_ptr<PdCom::impl::Subscription> new_sub;
850
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (var) {
851
1/2
✓ Branch 11 taken 26 times.
✗ Branch 12 not taken.
182 new_sub = subscribe(
852 26 ps->This_,
853 78 std::static_pointer_cast<const MsrProto::Variable>(
854
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
52 var->shared_from_this()),
855 130 ps->subscriber_, ps->getSelector(), false);
856 }
857
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if (!new_sub) {
858 new_sub = std::make_shared<InvalidSubscription>(
859 ps->This_, ps->subscriber_, process->shared_from_this());
860 process->pending_callbacks_.push_back(
861 {new_sub, PdCom::Subscription::State::Invalid});
862 }
863
1/2
✓ Branch 19 taken 26 times.
✗ Branch 20 not taken.
26 process->replace(ps, new_sub);
864
1/2
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
26 ps->replaceImpl(std::move(new_sub));
865 }
866
867
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (!var) {
868 // End of processing; clean up structures
869 26 pending_queue_.pop_front();
870 }
871 52 } /*}}}*/
872
873 ///////////////////////////////////////////////////////////////////////////
874 void ProtocolHandler::xsapAck()
875 { /*{{{*/
876 if (xsapQ.empty())
877 throw ProtocolError("no pending xsad commands available");
878
879 auto map_it = parameter_event_.find(xsapQ.front());
880 if (map_it != parameter_event_.end()) {
881 map_it->second.broadcastState(
882 PdCom::Subscription::State::Active,
883 process->pending_callbacks_);
884 }
885
886 xsapQ.pop();
887 } /*}}}*/
888
889 ///////////////////////////////////////////////////////////////////////////
890 216 Parameter *ProtocolHandler::getParameter(const char **_atts)
891 { /*{{{*/
892 216 Attribute atts(_atts);
893 216 unsigned index;
894
895
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
216 if (!atts.getUInt("index", index))
896 return 0;
897
898
1/2
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
216 Parameter *&param = parameter[index];
899
2/2
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 42 times.
216 if (!param) {
900 // index="0" name="/Constant/Value" datasize="8" typ="TDBL_LIST"
901 // anz="10" cnum="10" rnum="1" orientation="VECTOR" flags="7"
902 174 const char *name = atts.find("name");
903
904 // Check index and name
905
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if (!*name) {
906 log_debug("Missing index or name for variable. Ignoring");
907 return 0;
908 }
909
910 // Check whether variable exists
911
3/6
✓ Branch 8 taken 174 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 174 times.
✗ Branch 13 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 174 times.
174 if (std::dynamic_pointer_cast<Variable>(root->find(name))) {
912 log_debug("%s exists. Ignoring", name);
913 return 0;
914 }
915
916
1/2
✓ Branch 6 taken 174 times.
✗ Branch 7 not taken.
348 SizeInfo size_info;
917
1/2
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
174 const auto type_info = getDataType(_atts, size_info);
918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
174 if (!type_info) {
919 log_debug("Datatype for %s unspecified. Ignoring", name);
920 return 0;
921 }
922
923 174 unsigned int flags;
924
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if (!atts.getUInt("flags", flags)) {
925 log_debug("Flags for %s unspecified. Ignoring", name);
926 return 0;
927 }
928
929 174 auto shared_param = std::make_shared<Parameter>(
930
1/2
✓ Branch 4 taken 174 times.
✗ Branch 5 not taken.
522 std::move(size_info), type_info, process->shared_from_this(),
931
2/4
✓ Branch 9 taken 174 times.
✗ Branch 10 not taken.
✓ Branch 16 taken 174 times.
✗ Branch 17 not taken.
870 index, flags, atts.find("alias"), atts.isTrue("dir"));
932 174 param = shared_param.get();
933
1/2
✓ Branch 10 taken 174 times.
✗ Branch 11 not taken.
174 root->insert(std::move(shared_param), name);
934 }
935
936 216 return param;
937 } /*}}}*/
938
939 ///////////////////////////////////////////////////////////////////////////
940 210 Channel *ProtocolHandler::getChannel(const char **_atts)
941 { /*{{{*/
942 210 Attribute atts(_atts);
943 210 unsigned index;
944
945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 210 times.
210 if (!atts.getUInt("index", index))
946 return 0;
947
948
1/2
✓ Branch 2 taken 210 times.
✗ Branch 3 not taken.
210 Channel *&chan = channel[index];
949
2/2
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 7 times.
210 if (!chan) {
950 // index="0" name="/Constant/Value" datasize="8" typ="TDBL_LIST"
951 // anz="10" cnum="10" rnum="1" orientation="VECTOR" flags="7"
952 203 const char *name = atts.find("name");
953
954 // Check index and name
955
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
203 if (!*name) {
956 log_debug("Missing index or name for variable. Ignoring");
957 return 0;
958 }
959
960 // Check whether variable exists
961
3/6
✓ Branch 8 taken 203 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 203 times.
✗ Branch 13 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 203 times.
203 if (std::dynamic_pointer_cast<Variable>(root->find(name))) {
962 log_debug("%s exists. Ignoring", name);
963 return 0;
964 }
965
966
1/2
✓ Branch 8 taken 203 times.
✗ Branch 9 not taken.
406 SizeInfo size_info;
967
1/2
✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
203 const auto type_info = getDataType(_atts, size_info);
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 if (!type_info) {
969 log_debug("Datatype for %s unspecified. Ignoring", name);
970 return 0;
971 }
972
973 203 unsigned int bufsize;
974
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
203 if (!atts.getUInt("bufsize", bufsize)) {
975 log_debug("bufsize for %s unspecified. Ignoring", name);
976 return 0;
977 }
978
979 203 double freq;
980
3/6
✓ Branch 1 taken 203 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 203 times.
203 if (!atts.getDouble("HZ", freq) or !freq) {
981 log_debug("HZ for %s unspecified or zero. Ignoring", name);
982 return 0;
983 }
984
985 203 unsigned int taskId = 0;
986 203 atts.getUInt("task", taskId);
987
988 203 auto shared_chan = std::make_shared<Channel>(
989
1/2
✓ Branch 4 taken 203 times.
✗ Branch 5 not taken.
609 std::move(size_info), type_info, process->shared_from_this(),
990 609 index, taskId, 1.0 / freq, atts.find("alias"), bufsize,
991
2/4
✓ Branch 10 taken 203 times.
✗ Branch 11 not taken.
✓ Branch 16 taken 203 times.
✗ Branch 17 not taken.
1421 atts.isTrue("dir"));
992 203 chan = shared_chan.get();
993
1/2
✓ Branch 10 taken 203 times.
✗ Branch 11 not taken.
203 root->insert(std::move(shared_chan), name);
994 }
995
996 210 return chan;
997 } /*}}}*/
998
999 namespace {
1000 struct TypeMap
1001 {
1002 const char *msr_name;
1003 const PdCom::TypeInfo *type_info;
1004 size_t len;
1005 template <size_t N>
1006 constexpr TypeMap(const char (&name)[N], PdCom::TypeInfo const &ti) :
1007 msr_name(&name[0]), type_info(&ti), len(N - 1)
1008 {}
1009 };
1010 } // namespace
1011
1012 ///////////////////////////////////////////////////////////////////////////
1013 const PdCom::TypeInfo *
1014 377 ProtocolHandler::getDataType(const char **atts, PdCom::SizeInfo &size_info)
1015 { /*{{{*/
1016 377 unsigned int rnum = 0;
1017 377 unsigned int cnum = 0;
1018 377 unsigned int count = 0;
1019 377 const char *orientation = 0;
1020 using PdCom::SizeInfo;
1021 using PdCom::TypeInfo;
1022 377 const TypeInfo *ans = nullptr;
1023
1024 static constexpr TypeMap type_map[] = {
1025 {"TDBL", details::TypeInfoTraits<double>::type_info},
1026 {"TINT", details::TypeInfoTraits<int32_t>::type_info},
1027 {"TUINT", details::TypeInfoTraits<uint32_t>::type_info},
1028 {"TCHAR", details::TypeInfoTraits<int8_t>::type_info},
1029 {"TUCHAR", details::TypeInfoTraits<uint8_t>::type_info},
1030 {"TSHORT", details::TypeInfoTraits<int16_t>::type_info},
1031 {"TUSHORT", details::TypeInfoTraits<uint16_t>::type_info},
1032 {"TLINT", details::TypeInfoTraits<int64_t>::type_info},
1033 {"TULINT", details::TypeInfoTraits<uint64_t>::type_info},
1034 {"TFLT", details::TypeInfoTraits<float>::type_info},
1035 };
1036
1037 377 const char *const typeStr = Attribute(atts).find("typ");
1038
1039 // Try and find the name in msr_dtypemap
1040
2/2
✓ Branch 0 taken 3770 times.
✓ Branch 1 taken 377 times.
4147 for (const auto &t : type_map) {
1041
4/6
✗ Branch 2 not taken.
✓ Branch 3 taken 3770 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3770 times.
✓ Branch 6 taken 377 times.
✓ Branch 7 taken 3393 times.
3770 if (!strncmp(typeStr, t.msr_name, t.len))
1042 377 ans = t.type_info;
1043 }
1044
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 377 times.
377 if (!ans)
1045 return nullptr;
1046
1047 // cache variable data
1048
2/2
✓ Branch 1 taken 2940 times.
✓ Branch 2 taken 377 times.
3317 for (int i = 0; atts[i]; i += 2) {
1049
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2940 times.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 2891 times.
2940 if (!strcmp(atts[i], "rnum")) {
1050
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
49 rnum = atoi(atts[i + 1]);
1051 }
1052
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2891 times.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 2842 times.
2891 else if (!strcmp(atts[i], "cnum")) {
1053
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
49 cnum = atoi(atts[i + 1]);
1054 }
1055
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2842 times.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 2793 times.
2842 else if (!strcmp(atts[i], "anz")) {
1056
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
49 count = atoi(atts[i + 1]);
1057 }
1058
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2793 times.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 2744 times.
2793 else if (!strcmp(atts[i], "orientation")) {
1059 49 orientation = atts[i + 1];
1060 }
1061 }
1062
1063
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 328 times.
377 if (orientation) {
1064
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 17 times.
49 if (!strcmp(orientation, "VECTOR")) {
1065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (!count)
1066 return nullptr;
1067
1068 32 size_info = SizeInfo::RowVector(count);
1069 }
1070
3/6
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
17 else if (orientation and !strncmp(orientation, "MATRIX", 6)) {
1071
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if (!(rnum and cnum))
1072 return nullptr;
1073
1074 17 size_info = SizeInfo::Matrix(rnum, cnum);
1075 }
1076 else
1077 return nullptr;
1078 }
1079 else {
1080
3/6
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 328 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 328 times.
328 if (rnum > 1 or cnum > 1 or count > 1)
1081 return nullptr;
1082
1083 328 size_info = SizeInfo::Scalar();
1084 }
1085
1086 377 return ans;
1087 } /*}}}*/
1088
1089 ///////////////////////////////////////////////////////////////////////////
1090 64 bool ProtocolHandler::login(const char *mech, const char *clientData)
1091 { /*{{{*/
1092
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 63 times.
64 if (!feature.login)
1093 1 return false;
1094
1095
2/4
✓ Branch 3 taken 63 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
126 XmlCommand sasl(cout, "auth");
1096
3/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 32 times.
✓ Branch 3 taken 31 times.
✗ Branch 4 not taken.
63 if (mech and *mech)
1097
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 sasl.addAttribute("mech", mech);
1098
1099
4/4
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 31 times.
63 if (clientData and *clientData)
1100
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 sasl.addAttribute("clientdata", clientData);
1101
1102 63 return true;
1103 } /*}}}*/
1104
1105 ///////////////////////////////////////////////////////////////////////////
1106 1 void ProtocolHandler::logout()
1107 { /*{{{*/
1108
2/4
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
1 XmlCommand(cout, "auth").addAttribute("logout", 1);
1109 1 } /*}}}*/
1110
1111 ///////////////////////////////////////////////////////////////////////////
1112 91 bool ProtocolHandler::processLogin(const char **_atts)
1113 { /*{{{*/
1114 // pdserv sends an empty saslauth tag after logout()
1115
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 90 times.
91 if (!*_atts)
1116 1 return false;
1117 90 Attribute atts(_atts);
1118 90 int finished = 0;
1119
6/6
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 86 times.
90 if (atts.getInt("success", finished) and !finished)
1120 4 finished = -1;
1121
1122 90 const char *mechlist = 0;
1123 90 atts.getString("mechlist", mechlist);
1124
1125 90 const char *serverdata = 0;
1126 90 atts.getString("serverdata", serverdata);
1127
1128
1/2
✓ Branch 16 taken 90 times.
✗ Branch 17 not taken.
90 process->loginReply(mechlist, serverdata, finished);
1129 90 return finished > 0;
1130 } /*}}}*/
1131
1132
1133 ///////////////////////////////////////////////////////////////////////////
1134 28 void ProtocolHandler::setPolite(bool state)
1135 { /*{{{*/
1136
3/10
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
28 if (state != polite and feature.polite) {
1137 polite = state;
1138
1139 XmlCommand(cout, "remote_host").addAttribute("polite", state);
1140 }
1141 28 } /*}}}*/
1142
1143 ///////////////////////////////////////////////////////////////////////////
1144 1146 bool ProtocolHandler::asyncData()
1145 { /*{{{*/
1146
1/2
✓ Branch 3 taken 1146 times.
✗ Branch 4 not taken.
1146 ExpatBuffer<ReadBufferSize> inputBuffer(*this);
1147
1148 const auto n =
1149
1/2
✓ Branch 6 taken 1146 times.
✗ Branch 7 not taken.
1146 StreambufLayer::read(inputBuffer.fill<char>(), inputBuffer.size());
1150
4/6
✗ Branch 3 not taken.
✓ Branch 4 taken 1146 times.
✓ Branch 5 taken 1146 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1129 times.
✓ Branch 8 taken 17 times.
1146 if (!protocolError and n > 0)
1151
2/2
✓ Branch 6 taken 1128 times.
✓ Branch 7 taken 1 times.
1130 parse(std::move(inputBuffer), n);
1152 1145 return n != 0;
1153 } /*}}}*/
1154
1155 ///////////////////////////////////////////////////////////////////////////
1156
1157 2458 void ProtocolHandler::cancelSubscriptions()
1158 {
1159
2/2
✓ Branch 6 taken 52 times.
✓ Branch 7 taken 2458 times.
2510 for (auto &kv : cancelations_) {
1160 52 const auto tm = kv.first;
1161
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 52 times.
52 if (tm == PdCom::event_mode) {
1162 for (const auto &var : kv.second) {
1163 if (var->is_parameter_) {
1164 const bool unsubscribe =
1165 parameter_event_.at(var->index_).remove_expired();
1166 if (unsubscribe and feature.xsap) {
1167 XmlCommand(cout, "xsop")
1168 .addAttribute("parameters", var->index_);
1169 }
1170 }
1171 else {
1172 channel_subscriptions_->unsubscribeEvent(*var, cout);
1173 }
1174 }
1175 kv.second.clear();
1176 }
1177
1178
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 else if (tm.getInterval() > 0) {
1179
2/2
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 52 times.
55 for (const auto &var : kv.second) {
1180
1/2
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
3 channel_subscriptions_->unsubscribePeriodic(tm, *var, cout);
1181 }
1182 52 kv.second.clear();
1183 }
1184 }
1185 2458 }
1186 ///////////////////////////////////////////////////////////////////////////
1187 84 bool ProtocolHandler::find(const std::string &path)
1188 { /*{{{*/
1189
1/2
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
168 auto var = std::dynamic_pointer_cast<Variable>(root->find(path));
1190
5/6
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 73 times.
✓ Branch 7 taken 11 times.
✓ Branch 8 taken 73 times.
84 if (var or path.empty()) {
1191
1/2
✓ Branch 21 taken 11 times.
✗ Branch 22 not taken.
11 process->findReply(PdCom::impl::Variable::toUApi(var));
1192 11 return true;
1193 }
1194
1195 // we already have all variables cached, so we know the requested one does
1196 // not exist.
1197
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 73 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 73 times.
73 if (fullListing == Cached) {
1198 process->findReply({});
1199 return true;
1200 }
1201
1202
1/2
✓ Branch 3 taken 73 times.
✗ Branch 4 not taken.
73 findQ.push(path);
1203
1204
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 73 times.
✗ Branch 6 not taken.
73 if (fullListing == Uncached) {
1205 // Do not flush next command
1206
3/6
✓ Branch 3 taken 73 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 73 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 73 times.
✗ Branch 13 not taken.
73 XmlCommand(cout, "rp").addEscapedAttribute("name", path).noFlush();
1207
1208
4/8
✓ Branch 3 taken 73 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 73 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 73 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 73 times.
✗ Branch 15 not taken.
73 XmlCommand(cout, "rk").addEscapedAttribute("name", path).setId("findQ");
1209 }
1210
1211 73 return false;
1212 } /*}}}*/
1213
1214 ///////////////////////////////////////////////////////////////////////////
1215 80 bool ProtocolHandler::processFindRequest()
1216 { /*{{{*/
1217
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 72 times.
80 if (findQ.empty()) // required by listReply!
1218 8 return false;
1219
1220
2/4
✓ Branch 5 taken 72 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 72 times.
✗ Branch 10 not taken.
144 std::shared_ptr<DirNode> node = root->find(findQ.front());
1221
1/2
✓ Branch 23 taken 72 times.
✗ Branch 24 not taken.
144 process->findReply(PdCom::impl::Variable::toUApi(
1222 144 std::dynamic_pointer_cast<PdCom::impl::Variable>(node)));
1223
1/2
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 findQ.pop();
1224
1225 72 return !findQ.empty();
1226 } /*}}}*/
1227
1228 ///////////////////////////////////////////////////////////////////////////
1229 19 bool ProtocolHandler::list(const std::string &dir)
1230 { /*{{{*/
1231 19 listQ.push(dir);
1232
1233
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
19 if (fullListing != Uncached) {
1234 if (fullListing == Cached)
1235 processListRequest();
1236 }
1237
7/8
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 9 times.
✓ Branch 12 taken 10 times.
19 else if (dir.empty() or !feature.list) {
1238 // List everything. First send a <rp> and the state machine
1239 // will send a <rp> thereafter
1240
1/2
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
9 XmlCommand(cout, "rk").noFlush();
1241
2/4
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
9 XmlCommand(cout, "rp").setId("listQ");
1242
1243 9 fullListing = InProgress;
1244 }
1245 else
1246
1/2
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
20 XmlCommand(cout, "list")
1247
1/2
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
20 .addEscapedAttribute("path", dir)
1248
1/2
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 .addAttribute("noderived", 1);
1249
1250
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
19 return fullListing == Cached;
1251 } /*}}}*/
1252
1253 6 void PdCom::impl::MsrProto::ProtocolHandler::getClientStatistics()
1254 {
1255
1/2
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 XmlCommand(cout, "read_statistics");
1256 6 }
1257
1258 ///////////////////////////////////////////////////////////////////////////
1259 18 bool ProtocolHandler::processListRequest()
1260 { /*{{{*/
1261
2/4
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 18 times.
✗ Branch 8 not taken.
36 std::string path = listQ.front();
1262
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 listQ.pop();
1263
1264 36 std::vector<std::string> dirList;
1265
1266 36 DirNode::List list;
1267 18 const bool listall = path.empty();
1268
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 if (listall)
1269
1/2
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
6 root->getAllChildren(list);
1270 else {
1271 // Directory list
1272
1/2
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 std::shared_ptr<DirNode> node = root->find(path);
1273
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (node)
1274
1/2
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
12 node->getChildren(list);
1275 }
1276
1277 36 std::vector<PdCom::Variable> varList;
1278
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 varList.reserve(list.size());
1279
1280
2/2
✓ Branch 5 taken 276 times.
✓ Branch 6 taken 18 times.
294 for (const auto &node : list) {
1281
7/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 258 times.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 12 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 270 times.
276 if (!listall and node->hasChildren())
1282
2/4
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
6 dirList.push_back(node->path());
1283
1284 552 auto v = std::dynamic_pointer_cast<PdCom::impl::Variable>(node);
1285
2/2
✓ Branch 1 taken 218 times.
✓ Branch 2 taken 58 times.
276 if (v)
1286
1/2
✓ Branch 6 taken 218 times.
✗ Branch 7 not taken.
218 varList.emplace_back(impl::Variable::toUApi(v));
1287 }
1288
1289
3/6
✓ Branch 17 taken 18 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 18 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 18 times.
✗ Branch 25 not taken.
18 process->listReply(varList, dirList);
1290
1291 36 return !listQ.empty();
1292 } /*}}}*/
1293
1294 ///////////////////////////////////////////////////////////////////////////
1295 7 void ProtocolHandler::pollChannel(PollSubscription &sub)
1296 { /*{{{*/
1297 14 const auto var_ptr = sub.variable_.lock();
1298
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (!var_ptr)
1299 throw EmptyVariable();
1300 7 const auto index = static_cast<const Variable &>(*var_ptr).index_;
1301
2/4
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
21 if (subscription_pending_channel_polls_.append(
1302
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
14 index, sub.shared_from_this()))
1303
1/2
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 pollChannel(index, "pollChannel");
1304 7 }
1305
1306 7 void ProtocolHandler::pollChannel(size_t index, const char *id)
1307 {
1308
1/2
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
14 XmlCommand(cout, "rk")
1309
1/2
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
14 .addAttribute("index", index)
1310
1/2
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 .addAttribute("hex", 1)
1311
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 .setId(id);
1312 7 } /*}}}*/
1313
1314 6 void ProtocolHandler::pollParameter(PollSubscription &sub)
1315 {
1316 12 const auto var_ptr = sub.variable_.lock();
1317
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (!var_ptr)
1318 throw EmptyVariable();
1319 6 const auto index = static_cast<const Variable &>(*var_ptr).index_;
1320
2/4
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
18 if (subscription_pending_parameter_polls_.append(
1321
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 index, sub.shared_from_this()))
1322
1/2
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 pollParameter(index, "pollParameter");
1323 6 }
1324
1325 ///////////////////////////////////////////////////////////////////////////
1326 47 void ProtocolHandler::pollParameter(size_t index, const char *id)
1327 { /*{{{*/
1328
1/2
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
94 XmlCommand(cout, "rp")
1329
1/2
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
94 .addAttribute("index", index)
1330
1/2
✓ Branch 4 taken 47 times.
✗ Branch 5 not taken.
94 .addAttribute("short", 1)
1331
1/2
✓ Branch 4 taken 47 times.
✗ Branch 5 not taken.
94 .addAttribute("hex", 1)
1332
1/2
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
47 .setId(id);
1333 47 } /*}}}*/
1334
1335 8 void ProtocolHandler::pollVariable(
1336 const PdCom::impl::Variable &_var,
1337 VariablePollPromise &&promise)
1338 {
1339 8 const auto &var = static_cast<const MsrProto::Variable &>(_var);
1340
2/4
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
8 if (variable_pending_polls_.append(var, std::move(promise))) {
1341
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 if (var.is_parameter_)
1342 8 pollParameter(var.index_, "VariablePollParameter");
1343 else
1344 pollChannel(var.index_, "VariablePollChannel");
1345 }
1346 8 }
1347
1348 ///////////////////////////////////////////////////////////////////////////
1349 84 std::shared_ptr<PdCom::impl::Subscription> ProtocolHandler::subscribe(
1350 PdCom::Subscription *subscription,
1351 std::shared_ptr<const PdCom::impl::Variable> _var,
1352 PdCom::Subscriber &subscriber,
1353 const PdCom::Selector &selector,
1354 bool notify_pending)
1355 {
1356 168 auto var = std::dynamic_pointer_cast<const Variable>(_var);
1357
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
84 if (!var)
1358 return nullptr;
1359
2/2
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 80 times.
84 if (subscriber.getTransmission() == PdCom::poll_mode) {
1360 4 auto ans = std::make_shared<PollSubscription>(
1361
1/2
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 var, subscription, subscriber, process->shared_from_this(),
1362
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
12 selector);
1363
1/2
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
4 process->pending_callbacks_.push_back(
1364 {ans, PdCom::Subscription::State::Active});
1365 4 return ans;
1366 }
1367
2/2
✓ Branch 10 taken 34 times.
✓ Branch 11 taken 46 times.
80 else if (subscriber.getTransmission() == PdCom::event_mode) {
1368
3/4
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 31 times.
✓ Branch 7 taken 3 times.
34 if (var->is_parameter_) {
1369 31 auto ans = std::make_shared<EventSubscription>(
1370
1/2
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
62 var, subscription, subscriber, process->shared_from_this(),
1371
1/2
✓ Branch 3 taken 31 times.
✗ Branch 4 not taken.
93 selector);
1372
3/4
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 19 times.
✓ Branch 9 taken 12 times.
31 if (parameter_event_[var->index_].empty()) {
1373 // not yet subscribed
1374
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
19 if (feature.xsap) {
1375 XmlCommand(cout, "xsap")
1376 .addAttribute("parameters", var->index_)
1377 .addAttribute("hex", 1)
1378 .setId("xsapQ");
1379 xsapQ.push(var->index_);
1380 if (notify_pending)
1381 process->pending_callbacks_.push_back(
1382 {ans, PdCom::Subscription::State::Pending});
1383 }
1384 else {
1385
1/2
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
19 parameter_event_[var->index_].currentState =
1386 PdCom::Subscription::State::Active;
1387
1/2
✓ Branch 11 taken 19 times.
✗ Branch 12 not taken.
19 process->pending_callbacks_.push_back(
1388 {ans, PdCom::Subscription::State::Active});
1389 }
1390 }
1391 else {
1392
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (notify_pending
1393
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
12 or parameter_event_[var->index_].currentState
1394 != PdCom::Subscription::State::Pending)
1395
1/2
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
24 process->pending_callbacks_.push_back(
1396
1/2
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 {ans, parameter_event_[var->index_].currentState});
1397 }
1398
2/4
✓ Branch 5 taken 31 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 31 times.
✗ Branch 12 not taken.
31 parameter_event_[var->index_].insert(ans);
1399 31 return ans;
1400 }
1401 else {
1402 3 return channel_subscriptions_->subscribeEvent(
1403 subscription, var, subscriber, selector, notify_pending,
1404
1/2
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
3 cout);
1405 }
1406 }
1407 else {
1408
2/4
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 46 times.
46 if (var->is_parameter_)
1409 return {};
1410 46 return channel_subscriptions_->subscribePeriodic(
1411
1/2
✓ Branch 7 taken 46 times.
✗ Branch 8 not taken.
46 subscription, var, subscriber, selector, notify_pending, cout);
1412 }
1413 }
1414
1415
1416 ///////////////////////////////////////////////////////////////////////////
1417 28 std::shared_ptr<PdCom::impl::Subscription> ProtocolHandler::subscribe(
1418 PdCom::Subscription *subscription,
1419 const std::string &path,
1420 PdCom::Subscriber &subscriber,
1421 const PdCom::Selector &selector)
1422 { /*{{{*/
1423
1/2
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 setPolite(false);
1424
1425
5/6
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 26 times.
✓ Branch 15 taken 26 times.
✓ Branch 16 taken 2 times.
54 if (auto var = std::dynamic_pointer_cast<Variable>(root->find(path))) {
1426
3/4
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 26 times.
✓ Branch 10 taken 2 times.
2 return subscribe(subscription, var, subscriber, selector, false);
1427 }
1428
1429 // Variable is unknown. Find it first. This requires interaction
1430 // with the server, which automatically postpones calls to
1431 // request->subscriber to a later point in time
1432 26 const auto it = std::find_if(
1433 78 pending_queue_.begin(), pending_queue_.end(),
1434
1/2
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
104 [&path](const PendingRequest &pr) { return pr.path_ == path; });
1435
1436 26 auto ans = std::make_shared<PendingSubscription>(
1437
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 subscription, subscriber, process->shared_from_this(),
1438
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
78 selector.impl_);
1439
1440
1/2
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
26 if (it == pending_queue_.end()) {
1441 // Discovery not yet active
1442
2/4
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
52 XmlCommand(cout, "rp")
1443
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 .addAttribute("name", path)
1444
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 .addAttribute("hex", 1)
1445
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
26 .setId("pendingParameter")
1446 26 .noFlush();
1447
2/4
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
52 XmlCommand(cout, "rk")
1448
1/2
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
52 .addAttribute("name", path)
1449
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
26 .setId("pendingChannel");
1450
5/10
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 12 taken 26 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 26 times.
✗ Branch 17 not taken.
✓ Branch 23 taken 26 times.
✓ Branch 24 taken 26 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
26 pending_queue_.push_back({path, {{ans}}});
1451 }
1452 else {
1453 it->subscriptions_.insert(ans);
1454 }
1455
1/2
✓ Branch 11 taken 26 times.
✗ Branch 12 not taken.
26 process->pending_callbacks_.push_back(
1456 {ans, PdCom::Subscription::State::Pending});
1457 26 return ans;
1458 } /*}}}*/
1459
1460 33 void ProtocolHandler::unsubscribe(EventSubscription &s) noexcept
1461 {
1462
1/2
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
66 const auto var_ptr = s.variable_.lock();
1463
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
33 if (!var_ptr)
1464 return;
1465 try {
1466
3/8
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 33 times.
✗ Branch 12 not taken.
✓ Branch 17 taken 33 times.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
99 cancelations_[PdCom::event_mode].insert(
1467 66 std::static_pointer_cast<const Variable>(var_ptr));
1468 }
1469 catch (std::bad_alloc const &) {
1470 // never going to happen
1471 }
1472 }
1473
1474 46 void ProtocolHandler::unsubscribe(PeriodicSubscription &s) noexcept
1475 {
1476
1/2
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
92 const auto var_ptr = s.variable_.lock();
1477
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
46 if (!var_ptr)
1478 return;
1479 try {
1480
2/4
✓ Branch 11 taken 46 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 46 times.
✗ Branch 17 not taken.
92 cancelations_[s.subscriber_.getTransmission()].insert(
1481
1/4
✓ Branch 4 taken 46 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
92 std::static_pointer_cast<const Variable>(var_ptr));
1482 }
1483 catch (std::bad_alloc const &) {
1484 // never going to happen
1485 }
1486 catch (...) {
1487 }
1488 }
1489
1490 ///////////////////////////////////////////////////////////////////////////
1491 4 void ProtocolHandler::ping()
1492 { /*{{{*/
1493
1/2
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 XmlCommand(cout, "ping");
1494 4 } /*}}}*/
1495
1496 ///////////////////////////////////////////////////////////////////////////
1497 14 std::string ProtocolHandler::name() const
1498 { /*{{{*/
1499 14 return m_name;
1500 } /*}}}*/
1501
1502 ///////////////////////////////////////////////////////////////////////////
1503 11 std::string ProtocolHandler::version() const
1504 { /*{{{*/
1505 11 return m_version;
1506 } /*}}}*/
1507
1508 ///////////////////////////////////////////////////////////////////////////
1509 43 PdCom::Variable::SetValueFuture ProtocolHandler::writeParameter(
1510 const Parameter &p,
1511 const void *src,
1512 PdCom::TypeInfo::DataType src_type,
1513 size_t idx,
1514 size_t n)
1515 { /*{{{*/
1516
1/2
✓ Branch 3 taken 43 times.
✗ Branch 4 not taken.
86 XmlCommand(cout, "wp")
1517
1/2
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
86 .addAttribute("index", p.index_)
1518
1/2
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
43 .addAttribute("startindex", idx, idx)
1519 .addAttributeStream(
1520 "hexvalue",
1521 43 [&, this](XmlStream &os) {
1522
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 43 times.
43 encoder_.toHex(*p.type_info, src, src_type, n, os);
1523
1/2
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
129 })
1524
1/2
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
43 .setId("wp");
1525 // TODO(igh-vh) implement parameter setValue notification in msr and
1526 // pdserv
1527 43 return {};
1528 } /*}}}*/
1529
1530 ///////////////////////////////////////////////////////////////////////////
1531 ///////////////////////////////////////////////////////////////////////////
1532 29625 bool fcmp(const char *p, const char *target, size_t len)
1533 {
1534
7/10
✗ Branch 0 not taken.
✓ Branch 1 taken 29625 times.
✓ Branch 2 taken 17345 times.
✓ Branch 3 taken 12280 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 17345 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 17345 times.
✓ Branch 8 taken 1820 times.
✓ Branch 9 taken 15525 times.
29625 return len >= ::strlen(target) && !strncmp(p, target, len);
1535 }
1536
1537 155 void ProtocolHandler::Feature::operator=(const char *str)
1538 { /*{{{*/
1539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
155 if (!str)
1540 return;
1541 155 *this = Feature {};
1542
1543 155 const char *p = str;
1544 size_t len;
1545
1546 1820 do {
1547 1975 p = str;
1548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1975 times.
1975 str = strchr(str, ',');
1549
1550
3/4
✓ Branch 0 taken 1820 times.
✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 155 times.
1975 len = str ? str++ - p : strlen(p);
1551
1552
1/2
✓ Branch 0 taken 1975 times.
✗ Branch 1 not taken.
1975 if (len) {
1553
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "pushparameters", len))
1554 155 pushparameters = true;
1555
1556
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "binparameters", len))
1557 155 binparameters = true;
1558
1559
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "eventchannels", len))
1560 155 eventchannels = true;
1561
1562
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "statistics", len))
1563 155 statistics = true;
1564
1565
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "pmtime", len))
1566 155 pmtime = true;
1567
1568
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "aic", len))
1569 155 aic = true;
1570
1571
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "messages", len))
1572 155 messages = true;
1573
1574
2/2
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1830 times.
1975 if (fcmp(p, "group", len))
1575 145 group = true;
1576
1577
2/2
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1830 times.
1975 if (fcmp(p, "history", len))
1578 145 history = true;
1579
1580
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1975 times.
1975 if (fcmp(p, "quiet", len))
1581 quiet = true;
1582
1583
2/2
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1830 times.
1975 if (fcmp(p, "list", len)) {
1584 145 list = true;
1585 145 group = true;
1586 }
1587
1588
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1975 times.
1975 if (fcmp(p, "exclusive", len))
1589 exclusive = true;
1590
1591
2/2
✓ Branch 1 taken 155 times.
✓ Branch 2 taken 1820 times.
1975 if (fcmp(p, "polite", len))
1592 155 polite = true;
1593
1594 /* feature disabled, because xsap does not work on all
1595 parameters in pdserv (those who are generated with
1596 msr:splitvectors), Hm
1597
1598 if (fcmp(p, "xsap", len))
1599 xsap = true;
1600 */
1601
1602
2/2
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1830 times.
1975 if (fcmp(p, "login", 5))
1603 145 login = true;
1604
1605
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1975 times.
1975 if (fcmp(p, "eventid=", 8))
1606 eventid = strtoul(p + 8, 0, 0);
1607 }
1608
1609
2/2
✓ Branch 0 taken 1820 times.
✓ Branch 1 taken 155 times.
1975 } while (str);
1610 } /*}}}*/
1611
1612
1613 16 void ProtocolHandler::getMessage(uint32_t seqNo)
1614 {
1615
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 15 times.
16 if (!feature.history) {
1616
1/2
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
1 process->getMessageReply({});
1617 }
1618 else {
1619
1/2
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 XmlCommand(cout, "message_history")
1620
1/2
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 .addAttribute("seq", seqNo)
1621
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 .setId("history");
1622 15 seqNoQ.push(seqNo);
1623 }
1624 16 }
1625
1626 22 void ProtocolHandler::getActiveMessages()
1627 {
1628
3/4
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 21 times.
22 if (!feature.history) {
1629
1/2
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
1 process->activeMessagesReply({});
1630 }
1631 else
1632
1/2
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
21 XmlCommand(cout, "message_history");
1633 22 }
1634
1635 29 void ProtocolHandler::broadcast(
1636 const std::string &message,
1637 const std::string &attr)
1638 {
1639
2/4
✓ Branch 3 taken 29 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
58 XmlCommand msg(cout, "broadcast");
1640
2/2
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 9 times.
29 msg.addEscapedAttribute(attr.c_str(), message);
1641 20 }
1642
1643
1644 22 void ProtocolHandler::processBroadcast(const char **atts)
1645 {
1646 22 Attribute a(atts);
1647 22 const char *try_keys[] = {"action", "text"};
1648 22 const char *value = nullptr, *user = nullptr;
1649
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 if (!a.getString("user", user))
1650 22 user = "anonymous";
1651
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 22 times.
33 for (const char *key : try_keys) {
1652
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 11 times.
33 if (a.getString(key, value)) {
1653
5/10
✓ Branch 19 taken 22 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 22 times.
✗ Branch 24 not taken.
✓ Branch 29 taken 22 times.
✗ Branch 30 not taken.
✓ Branch 36 taken 22 times.
✗ Branch 37 not taken.
✓ Branch 40 taken 22 times.
✗ Branch 41 not taken.
22 process->broadcastReply(value, key, a.getTime_ns("time"), user);
1654 22 return;
1655 }
1656 }
1657 }
1658
1659 4 void PdCom::impl::MsrProto::ProtocolHandler::readEventData(
1660 const char *name,
1661 const char **atts)
1662 {
1663
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (name[0] == 'E') {
1664 2 Attribute a(atts);
1665 2 unsigned int index;
1666
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (a.getUInt("c", index)) {
1667 2 const auto map_it =
1668
1/2
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 channel_subscriptions_->getEventMap().find(index);
1669
3/10
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
4 if (map_it != channel_subscriptions_->getEventMap().end()
1670
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 and channel[index]) {
1671
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 auto cache = variable_cache_.lock();
1672
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (const char *d = a.find("d")) {
1673
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 cache[0].readFromBase64(
1674
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 a.find("d"), strlen(d), *channel[index]);
1675
2/4
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
2 map_it->second.readData(cache[0].data(), dataTime);
1676 }
1677 }
1678 }
1679 }
1680 4 }
1681
1682 888 void PdCom::impl::MsrProto::ProtocolHandler::readPeriodicData(
1683 const char *name,
1684 const char **atts)
1685 {
1686
5/6
✓ Branch 1 taken 547 times.
✓ Branch 2 taken 341 times.
✓ Branch 5 taken 547 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 547 times.
✓ Branch 8 taken 341 times.
888 if (name[0] == 'F' and periodic_receive_handle_) {
1687 547 Attribute a(atts);
1688 547 unsigned int index = 0;
1689
4/8
✓ Branch 1 taken 547 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 547 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 547 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 547 times.
✗ Branch 11 not taken.
547 if (a.getUInt("c", index) and channel[index]) {
1690
2/4
✓ Branch 4 taken 547 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 547 times.
✗ Branch 10 not taken.
547 periodic_receive_handle_.readData(*channel[index], a.find("d"));
1691 }
1692 }
1693
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 341 times.
✓ Branch 2 taken 341 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 341 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 341 times.
✗ Branch 9 not taken.
341 else if (!strcmp(name, "time") and periodic_receive_handle_) {
1694
1/2
✓ Branch 6 taken 341 times.
✗ Branch 7 not taken.
341 periodic_receive_handle_.readTimestamps(Attribute(atts).find("d"));
1695 }
1696 888 }
1697
1698 template class PdCom::impl::MsrProto::ExpatWrapper<ProtocolHandler, true>;
1699
1700 13 bool ProtocolHandler::SubscriptionPendingPollList::append(
1701 unsigned int const id,
1702 const std::shared_ptr<PollSubscription> &sub)
1703 {
1704
4/8
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 13 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 13 times.
✗ Branch 20 not taken.
13 for (auto &pp : *this) {
1705 if (pp.id_ == id) {
1706 pp.subscriptions_.insert(sub);
1707 pp.subscriptions_.remove_expired();
1708 return false;
1709 }
1710 }
1711
4/8
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 19 taken 13 times.
✓ Branch 20 taken 13 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
13 push_back({id, {{sub}}});
1712 13 return true;
1713 }
1714
1715 8 bool ProtocolHandler::VariablePendingPollList::append(
1716 const Variable &var,
1717 VariablePollPromise promise)
1718 {
1719
4/8
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✓ Branch 12 taken 8 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 8 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 8 times.
✗ Branch 20 not taken.
8 for (auto &pp : polls_) {
1720 if (pp.id_ == var.index_ and pp.is_parameter_ == var.is_parameter_) {
1721 pp.promises_.push_back(std::move(promise));
1722 return false;
1723 }
1724 }
1725 8 polls_.emplace_back(std::move(promise), var.index_, var.is_parameter_);
1726 8 return true;
1727 }
1728
1729
1730 3 void ProtocolHandler::VariablePendingPollList::processResult(
1731 Variable const &var,
1732 const char *data,
1733 std::chrono::nanoseconds ts)
1734 {
1735
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (polls_.empty())
1736 return;
1737
1/2
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
6 auto head = std::move(polls_.front());
1738 3 polls_.pop_front();
1739
3/6
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
3 if (var.is_parameter_ != head.is_parameter_)
1740 throw ProtocolError("Channel/Parameter poll reply mismatch");
1741
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 if (head.id_ != var.index_)
1742 throw ProtocolError("Got wrong parameter index reply");
1743
2/4
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
6 auto ans = PdCom::VariablePollResult {var.toUApi()};
1744
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 std::copy(
1745
1/2
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 data, data + var.totalSizeInBytes(),
1746 3 reinterpret_cast<char *>(ans.getData()));
1747
2/2
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
6 for (auto &promise : head.promises_)
1748
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 promise.resolve(ans, ts);
1749 }
1750
1751 312 ProtocolHandler::VariablePendingPollList::~VariablePendingPollList()
1752 {
1753 312 const PdCom::ProcessGoneAway ex {};
1754
2/2
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 156 times.
161 for (auto &poll_list : polls_)
1755
2/2
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 5 times.
10 for (auto &pending_poll : poll_list.promises_)
1756 try {
1757
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 pending_poll.reject(ex);
1758 }
1759 catch (...) {
1760 }
1761 156 }
1762
1763 PdCom::Variable::SetValueFuture ProtocolHandler::PendingSetValues::push()
1764 {
1765 auto ans = createFuture<PdCom::Exception const &>();
1766 queue_.push(std::move(ans.second));
1767 return std::move(ans.first);
1768 }
1769
1770 void ProtocolHandler::PendingSetValues::pop()
1771 {
1772 if (queue_.empty())
1773 return;
1774
1775 auto promise = std::move(queue_.front());
1776 queue_.pop();
1777 promise.resolve();
1778 }
1779
1780
1781 312 ProtocolHandler::PendingSetValues::~PendingSetValues()
1782 {
1783 312 auto q = std::move(queue_);
1784 312 const PdCom::ProcessGoneAway ex {};
1785
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 156 times.
156 while (!q.empty()) {
1786 try {
1787 q.front().reject(ex);
1788 }
1789 catch (...) {
1790 }
1791 q.pop();
1792 }
1793 156 }
1794
1795 std::vector<PdCom::Process::SubscriptionInfo>
1796 ProtocolHandler::getActiveSubscriptions() const
1797 {
1798 std::vector<PdCom::Process::SubscriptionInfo> ans;
1799 // parameter event
1800 for (const auto &map : parameter_event_) {
1801 PdCom::Variable v = impl::Variable::toUApi(
1802 std::static_pointer_cast<const MsrProto::Variable>(
1803 parameter.at(map.first)->shared_from_this()));
1804 for (const auto &weak_sub : map.second) {
1805 if (const auto sub = weak_sub.lock()) {
1806 ans.emplace_back(sub->This_, &sub->subscriber_, v);
1807 }
1808 }
1809 }
1810 // channels
1811 channel_subscriptions_->dump(ans, channel);
1812 return ans;
1813 }
1814
1815 std::shared_ptr<PdCom::impl::Subscription>
1816 2 ChannelSubscriptionsWithGroup::subscribeEvent(
1817 PdCom::Subscription *subscription,
1818 std::shared_ptr<const Variable> var,
1819 PdCom::Subscriber &subscriber,
1820 const PdCom::Selector &selector,
1821 bool notify_pending,
1822 XmlStream &cout)
1823 {
1824 4 auto process = var->process.lock();
1825 2 auto ans = std::make_shared<EventSubscription>(
1826
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 var, subscription, subscriber, process, selector);
1827
1828
2/4
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 if (event_[var->index_].empty()) {
1829
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 XmlCommand(cout, "xsad")
1830
1/2
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
4 .addAttribute("channels", var->index_)
1831
1/2
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 .addAttribute("group", 0)
1832
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 .addAttribute("coding", "Base64")
1833
1/2
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 .addAttribute("event", 1)
1834
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 .setId(xsadId);
1835
1/2
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
2 xsadQ.push({0, var->index_});
1836
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (notify_pending)
1837
1/2
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 process->pending_callbacks_.push_back(
1838 {ans, PdCom::Subscription::State::Pending});
1839 }
1840 else {
1841 if (notify_pending
1842 or event_[var->index_].currentState
1843 != PdCom::Subscription::State::Pending)
1844 process->pending_callbacks_.push_back(
1845 {ans, event_[var->index_].currentState});
1846 }
1847
2/4
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 event_[var->index_].insert(ans);
1848 4 return ans;
1849 }
1850
1851 std::shared_ptr<PdCom::impl::Subscription>
1852 42 PdCom::impl::MsrProto::ChannelSubscriptionsWithGroup::subscribePeriodic(
1853 PdCom::Subscription *subscription,
1854 std::shared_ptr<const Variable> var,
1855 PdCom::Subscriber &subscriber,
1856 const PdCom::Selector &selector,
1857 bool notify_pending,
1858 XmlStream &cout)
1859 {
1860 84 auto process = var->process.lock();
1861 42 auto ans = std::make_shared<PeriodicSubscription>(
1862
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
84 var, subscription, subscriber, process, selector);
1863 42 const auto si = periodic_subscriptions_with_group_.add(
1864
1/2
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
42 process->pending_callbacks_, notify_pending, ans);
1865
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 if (si.needs_server_action) {
1866
2/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
84 XmlCommand(cout, "xsad")
1867
1/2
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
84 .addAttribute("channels", var->index_)
1868
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 .addAttribute("group", si.group_id)
1869
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 .addAttribute("coding", "Base64")
1870
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 .addAttribute("reduction", si.decimation_)
1871
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 .addAttribute("blocksize", si.blocksize_)
1872
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 .setId(xsadId);
1873
1/2
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
42 xsadQ.push({si.group_id, var->index_});
1874 }
1875 84 return ans;
1876 }
1877
1878 void ChannelSubscriptionsWithGroup::unsubscribeEvent(
1879 const Variable &var,
1880 XmlStream &cout)
1881 {
1882 const bool unsubscribe = event_.at(var.index_).remove_expired();
1883 if (unsubscribe) {
1884 XmlCommand(cout, "xsod")
1885 .addAttribute("channels", var.index_)
1886 .addAttribute("group", 0);
1887 }
1888 }
1889
1890 1 void ChannelSubscriptionsWithGroup::unsubscribePeriodic(
1891 PdCom::Transmission tm,
1892 const Variable &var,
1893 XmlStream &cout)
1894 {
1895
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 const auto si = periodic_subscriptions_with_group_.remove(var, tm);
1896
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (si.needs_server_action) {
1897
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 xsodQ.push(si.group_id);
1898
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 XmlCommand(cout, "xsod")
1899
1/2
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 .addAttribute("channels", var.index_)
1900
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 .addAttribute("group", si.group_id)
1901
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 .setId(xsodId);
1902 }
1903 1 }
1904
1905 44 void PdCom::impl::MsrProto::ChannelSubscriptionsWithGroup::xsadAck(
1906 Process *process)
1907 {
1908
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 44 times.
44 if (xsadQ.empty())
1909 throw ProtocolError("no pending xsad commands available");
1910
1/2
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
44 const auto ids = xsadQ.front();
1911
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 xsadQ.pop();
1912
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 42 times.
44 if (ids.group_id == 0) {
1913
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
4 const auto map_it = event_.find(ids.channel_id);
1914
1/2
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 if (map_it == event_.end())
1915 return;
1916
2/4
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 map_it->second.broadcastState(
1917 PdCom::Subscription::State::Active,
1918 process->pending_callbacks_);
1919 }
1920 else {
1921
2/4
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
84 periodic_subscriptions_with_group_.subscribeWasConfirmed(
1922 42 process->pending_callbacks_, ids.group_id, ids.channel_id);
1923 }
1924 }
1925
1926 void PdCom::impl::MsrProto::ChannelSubscriptionsWithGroup::xsodAck()
1927 {
1928 if (xsodQ.empty())
1929 throw ProtocolError("no pending xsod commands available");
1930
1931 const auto id = xsodQ.front();
1932 xsodQ.pop();
1933
1934 periodic_subscriptions_with_group_.unsubscribeDone(id);
1935 }
1936
1937 void PdCom::impl::MsrProto::ChannelSubscriptionsWithGroup::dump(
1938 std::vector<PdCom::Process::SubscriptionInfo> &ans,
1939 const std::unordered_map<unsigned, Channel *> &channels) const
1940 {
1941 ChannelSubscriptions::dump(ans, channels);
1942 // channel periodic
1943 periodic_subscriptions_with_group_.dump(ans, channels);
1944 }
1945
1946 std::shared_ptr<PdCom::impl::Subscription>
1947 1 PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup::subscribeEvent(
1948 PdCom::Subscription *subscription,
1949 std::shared_ptr<const Variable> var,
1950 PdCom::Subscriber &subscriber,
1951 const PdCom::Selector &selector,
1952 bool notify_pending,
1953 XmlStream &cout)
1954 {
1955 // can't have periodic and event at the same time
1956
2/4
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 if (periodic_subscriptions_without_group_.hasChannel(var->index_))
1957 1 return {};
1958
1959
1960 auto process = var->process.lock();
1961 auto ans = std::make_shared<EventSubscription>(
1962 var, subscription, subscriber, process, selector);
1963
1964 if (event_[var->index_].empty()) {
1965 event_[var->index_].currentState = PdCom::Subscription::State::Pending;
1966 XmlCommand(cout, "xsad")
1967 .addAttribute("channels", var->index_)
1968 .addAttribute("coding", "Base64")
1969 .addAttribute("event", 1)
1970 .setId(xsadId);
1971 xsadQ.push({true, var->index_});
1972 if (notify_pending)
1973 process->pending_callbacks_.push_back(
1974 {ans, PdCom::Subscription::State::Pending});
1975 }
1976 else {
1977 if (notify_pending
1978 or event_[var->index_].currentState
1979 != PdCom::Subscription::State::Pending)
1980 process->pending_callbacks_.push_back(
1981 {ans, event_[var->index_].currentState});
1982 }
1983 event_[var->index_].insert(ans);
1984 return ans;
1985 }
1986
1987 std::shared_ptr<PdCom::impl::Subscription>
1988 4 ChannelSubscriptionsWithoutGroup::subscribePeriodic(
1989 PdCom::Subscription *subscription,
1990 std::shared_ptr<const Variable> var,
1991 PdCom::Subscriber &subscriber,
1992 const PdCom::Selector &selector,
1993 bool notify_pending,
1994 XmlStream &cout)
1995 {
1996 {
1997
2/4
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
8 const auto it = event_.find(var->index_);
1998
4/10
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
4 if (it != event_.end() && !it->second.empty())
1999 // periodic and event not allowed at the same time.
2000 return {};
2001 }
2002 8 auto process = var->process.lock();
2003 4 auto ans = std::make_shared<PeriodicSubscription>(
2004
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 var, subscription, subscriber, process, selector);
2005 4 const auto si = periodic_subscriptions_without_group_.add(
2006
1/2
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 process->pending_callbacks_, notify_pending, ans);
2007
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (si.needs_server_action) {
2008
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 XmlCommand(cout, "xsad")
2009
1/2
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
8 .addAttribute("channels", var->index_)
2010
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 .addAttribute("coding", "Base64")
2011
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 .addAttribute("reduction", si.decimation_)
2012
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 .addAttribute("blocksize", si.blocksize_)
2013
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 .setId(xsadId);
2014
1/2
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
4 xsadQ.push({false, var->index_});
2015 }
2016 4 return ans;
2017 }
2018
2019 void PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup::unsubscribeEvent(
2020 const Variable &var,
2021 XmlStream &cout)
2022 {
2023 const bool unsubscribe = event_.at(var.index_).remove_expired();
2024 if (unsubscribe) {
2025 XmlCommand(cout, "xsod").addAttribute("channels", var.index_);
2026 }
2027 }
2028
2029 2 void PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup::
2030 unsubscribePeriodic(
2031 PdCom::Transmission /* tm */,
2032 const Variable &var,
2033 XmlStream &cout)
2034 {
2035 2 const auto si = periodic_subscriptions_without_group_.remove(var);
2036
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if (si.needs_server_action) {
2037
2/4
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 XmlCommand(cout, "xsod").addAttribute("channels", var.index_);
2038 }
2039 2 }
2040
2041 4 void PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup::xsadAck(
2042 Process *process)
2043 {
2044
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (xsadQ.empty())
2045 throw ProtocolError("no pending xsad commands available");
2046
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 const auto ids = xsadQ.front();
2047
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 xsadQ.pop();
2048
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (ids.first) {
2049 const auto map_it = event_.find(ids.second);
2050 if (map_it == event_.end())
2051 return;
2052 map_it->second.broadcastState(
2053 PdCom::Subscription::State::Active,
2054 process->pending_callbacks_);
2055 }
2056 else {
2057
2/4
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8 periodic_subscriptions_without_group_.subscribeWasConfirmed(
2058 4 process->pending_callbacks_, ids.second);
2059 }
2060 }
2061
2062 void PdCom::impl::MsrProto::ChannelSubscriptionsWithoutGroup::dump(
2063 std::vector<PdCom::Process::SubscriptionInfo> &ans,
2064 const std::unordered_map<unsigned, Channel *> &channels) const
2065 {
2066 ChannelSubscriptions::dump(ans, channels);
2067 periodic_subscriptions_without_group_.dump(ans, channels);
2068 }
2069
2070 void PdCom::impl::MsrProto::ChannelSubscriptions::dump(
2071 std::vector<PdCom::Process::SubscriptionInfo> &ans,
2072 const std::unordered_map<unsigned, Channel *> &channels) const
2073 {
2074 // channel event
2075 for (const auto &map : event_) {
2076 PdCom::Variable v = impl::Variable::toUApi(
2077 std::static_pointer_cast<const MsrProto::Variable>(
2078 channels.at(map.first)->shared_from_this()));
2079 for (const auto &weak_sub : map.second) {
2080 if (const auto sub = weak_sub.lock()) {
2081 ans.emplace_back(sub->This_, &sub->subscriber_, v);
2082 }
2083 }
2084 }
2085 }
2086