GCC Code Coverage Report


Directory: ./
File: src/msrproto/ProtocolHandler.cpp
Date: 2024-03-27 13:09:52
Exec Total Coverage
Lines: 834 1135 73.5%
Branches: 896 2028 44.2%

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