GCC Code Coverage Report


Directory: ./
File: pdcom5/src/msrproto/ProtocolHandler.cpp
Date: 2023-11-12 04:06:57
Exec Total Coverage
Lines: 914 1103 82.9%
Branches: 1004 1980 50.7%

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