GCC Code Coverage Report


Directory: ./
File: pdserv-1.1.0/src/msrproto/Server.cpp
Date: 2024-12-15 04:08:34
Exec Total Coverage
Lines: 1 206 0.5%
Branches: 0 462 0.0%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright 2010 Richard Hacker (lerichi at gmx dot net)
6 *
7 * This file is part of the pdserv library.
8 *
9 * The pdserv library is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * The pdserv library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 * License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with the pdserv library. If not, see <http://www.gnu.org/licenses/>.
21 *
22 *****************************************************************************/
23
24 #include "config.h"
25
26 #include "Server.h"
27 #include "Channel.h"
28 #include "Event.h"
29 #include "TimeSignal.h"
30 #include "StatSignal.h"
31 #include "Parameter.h"
32 #include "Session.h"
33 #include "../Main.h"
34 #include "../Task.h"
35 #include "../Signal.h"
36 #include "../ProcessParameter.h"
37
38 #include <cerrno>
39 #include <algorithm>
40 #include <commoncpp/tcp.h>
41 #include <log4cplus/loggingmacros.h>
42
43 using namespace MsrProto;
44
45 /////////////////////////////////////////////////////////////////////////////
46 Server::Server(const PdServ::Main *main, const PdServ::Config &config):
47 main(main),
48 log(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("msr"))),
49 mutex(1)
50 {
51 port = config["port"].toUInt();
52 itemize = config["splitvectors"].toUInt();
53
54 log_debug("port=%u", port);
55
56 DirectoryNode* baseDir = this;
57 if (config["pathprefix"])
58 baseDir = create(config["pathprefix"].toString(main->name));
59
60 for (size_t i = 0; i < main->numTasks(); ++i)
61 createChannels(baseDir, i);
62
63 createParameters(baseDir);
64 createEvents();
65
66 start();
67 }
68
69 /////////////////////////////////////////////////////////////////////////////
70 void Server::createChannels(DirectoryNode* baseDir, size_t taskIdx)
71 {
72 const PdServ::Task *task = main->getTask(taskIdx);
73 Channel* c;
74
75 log4cplus::tostringstream msg;
76 LOG4CPLUS_TRACE(log,
77 LOG4CPLUS_TEXT("Create channels for task ") << taskIdx
78 << LOG4CPLUS_TEXT(", Ts=") << task->sampleTime);
79
80 const PdServ::Task::Signals& signals = task->getSignals();
81
82 // Reserve at least signal count and additionally 4 Taskinfo signals
83 channels.reserve(channels.size() + signals.size() + 4);
84
85 for (PdServ::Task::Signals::const_iterator it = signals.begin();
86 it != signals.end(); it++) {
87 c = new Channel(*it,
88 channels.size(), (*it)->dtype, (*it)->dim, 0, 0);
89
90 char hidden;
91 if (itemize)
92 baseDir->traditionalPathInsert(c, (*it)->path, hidden);
93 else
94 baseDir->pathInsert(c, (*it)->path);
95
96 c->hidden = hidden == 'c' or hidden == 'k' or hidden == 1;
97
98 channels.push_back(c);
99
100 if (itemize)
101 createChildren(c);
102 }
103
104 DirectoryNode* taskInfo = create("Taskinfo");
105
106 std::ostringstream os;
107 os << taskIdx;
108 DirectoryNode* t = taskInfo->create(os.str());
109
110 c = new TimeSignal(task, channels.size());
111 channels.push_back(c);
112 t->insert(c, "TaskTime");
113
114 c = new StatSignal(task, StatSignal::ExecTime, channels.size());
115 channels.push_back(c);
116 t->insert(c, "ExecTime");
117
118 c = new StatSignal(task, StatSignal::Period, channels.size());
119 channels.push_back(c);
120 t->insert(c, "Period");
121
122 c = new StatSignal(task, StatSignal::Overrun, channels.size());
123 channels.push_back(c);
124 t->insert(c, "Overrun");
125 }
126
127 /////////////////////////////////////////////////////////////////////////////
128 void Server::createEvents ()
129 {
130 LOG4CPLUS_TRACE(log,
131 LOG4CPLUS_TEXT("Create events"));
132
133 const PdServ::Main::Events mainEvents = main->getEvents();
134 this->events.reserve(mainEvents.size());
135
136 for (PdServ::Main::Events::const_iterator it = mainEvents.begin();
137 it != mainEvents.end(); ++it)
138 this->events.push_back(new Event(*it));
139 }
140
141 /////////////////////////////////////////////////////////////////////////////
142 void Server::createParameters(DirectoryNode* baseDir)
143 {
144 LOG4CPLUS_TRACE(log,
145 LOG4CPLUS_TEXT("Create parameters"));
146
147 const PdServ::Main::ProcessParameters& mainParam = main->getParameters();
148
149 parameters.reserve(parameters.size() + mainParam.size());
150
151 PdServ::Main::ProcessParameters::const_iterator it;
152 for (it = mainParam.begin(); it != mainParam.end(); ++it) {
153 Parameter* p = new Parameter(*it,
154 parameters.size(), (*it)->dtype, (*it)->dim, 0, 0);
155
156 char hidden;
157 if (itemize)
158 baseDir->traditionalPathInsert(p, (*it)->path, hidden);
159 else
160 baseDir->pathInsert(p, (*it)->path);
161
162 p->hidden = hidden == 'p' or hidden == 1;
163
164 parameters.push_back(p);
165 parameterMap[*it] = p;
166
167 if (itemize)
168 createChildren(p);
169 }
170
171 // if (!root.find<Parameter>("/Taskinfo/Abtastfrequenz")) {
172 // }
173
174 }
175
176 /////////////////////////////////////////////////////////////////////////////
177 Server::~Server()
178 {
179 for (std::set<Session*>::iterator it = sessions.begin();
180 it != sessions.end(); it++)
181 delete *it;
182 }
183
184 /////////////////////////////////////////////////////////////////////////////
185 void Server::initial()
186 {
187 LOG4CPLUS_INFO_STR(log, LOG4CPLUS_TEXT("Initializing MSR server"));
188 }
189
190 /////////////////////////////////////////////////////////////////////////////
191 void Server::final()
192 {
193 LOG4CPLUS_INFO_STR(log, LOG4CPLUS_TEXT("Exiting MSR server"));
194 }
195
196 /////////////////////////////////////////////////////////////////////////////
197 void Server::run()
198 {
199 ost::TCPSocket *server = 0;
200
201 ost::tpport_t port = this->port ? this->port : 2345;
202
203 do {
204 try {
205 server = new ost::TCPSocket(ost::IPV4Address("0.0.0.0"), port);
206 }
207 catch (ost::Socket *s) {
208 long err = s->getSystemError();
209 if (this->port or err != EADDRINUSE) {
210 LOG4CPLUS_ERROR(log,
211 LOG4CPLUS_TEXT("Socket failure on port ") << port
212 << LOG4CPLUS_TEXT(": ")
213 << LOG4CPLUS_C_STR_TO_TSTRING(::strerror(err)));
214 return;
215 }
216 LOG4CPLUS_DEBUG(log,
217 LOG4CPLUS_TEXT("Port ") << port
218 << LOG4CPLUS_TEXT(" is busy"));
219 port++;
220 }
221 } while (!server);
222
223 LOG4CPLUS_INFO(log, LOG4CPLUS_TEXT("Server started on port ") << port);
224 while (server->isPendingConnection()) {
225 try {
226 LOG4CPLUS_TRACE_STR(log,
227 LOG4CPLUS_TEXT("New client connection"));
228 Session *s = new Session(this, server);
229
230 ost::SemaphoreLock lock(mutex);
231 sessions.insert(s);
232 }
233 catch (ost::Socket *s) {
234 LOG4CPLUS_FATAL(log,
235 LOG4CPLUS_TEXT("Socket failure: ")
236 << LOG4CPLUS_C_STR_TO_TSTRING(
237 ::strerror(s->getSystemError())));
238 }
239 }
240 }
241
242 /////////////////////////////////////////////////////////////////////////////
243 void Server::broadcast(Session *s, const struct timespec& ts,
244 const std::string& action, const std::string &message)
245 {
246 ost::SemaphoreLock lock(mutex);
247 for (std::set<Session*>::iterator it = sessions.begin();
248 it != sessions.end(); it++)
249 (*it)->broadcast(s, ts, action, message);
250 }
251
252 /////////////////////////////////////////////////////////////////////////////
253 void Server::sessionClosed(Session *s)
254 {
255 ost::SemaphoreLock lock(mutex);
256 sessions.erase(s);
257 }
258
259 /////////////////////////////////////////////////////////////////////////////
260 void Server::getSessionStatistics(
261 std::list<PdServ::SessionStatistics>& stats) const
262 {
263 ost::SemaphoreLock lock(mutex);
264 for (std::set<Session*>::iterator it = sessions.begin();
265 it != sessions.end(); it++) {
266 PdServ::SessionStatistics s;
267 (*it)->getSessionStatistics(s);
268 stats.push_back(s);
269 }
270 }
271
272 /////////////////////////////////////////////////////////////////////////////
273 void Server::setAic(const Parameter *p)
274 {
275 ost::SemaphoreLock lock(mutex);
276 for (std::set<Session*>::iterator it = sessions.begin();
277 it != sessions.end(); it++)
278 (*it)->setAIC(p);
279 }
280
281 /////////////////////////////////////////////////////////////////////////////
282 void Server::parameterChanged(const PdServ::Parameter *mainParam,
283 size_t offset, size_t count)
284 {
285 const Parameter *p = find(mainParam);
286
287 ost::SemaphoreLock lock(mutex);
288 for (std::set<Session*>::iterator it = sessions.begin();
289 it != sessions.end(); it++)
290 (*it)->parameterChanged(p);
291
292 const Variable::List *children = p->getChildren();
293 if (!children)
294 return;
295
296 for (Variable::List::const_iterator it = children->begin();
297 it != children->end(); ++it) {
298 const Parameter *child = static_cast<const Parameter*>(*it);
299 if (child->offset >= offset
300 and (child->offset + child->memSize - 1 < offset + count)) {
301 for (std::set<Session*>::iterator it = sessions.begin();
302 it != sessions.end(); it++)
303 (*it)->parameterChanged(child);
304 }
305 }
306 }
307
308 /////////////////////////////////////////////////////////////////////////////
309 const Channel* Server::getChannel(size_t n) const
310 {
311 return n < channels.size() ? channels[n] : 0;
312 }
313
314 /////////////////////////////////////////////////////////////////////////////
315 const Server::Channels& Server::getChannels() const
316 {
317 return channels;
318 }
319
320 /////////////////////////////////////////////////////////////////////////////
321 const Parameter* Server::getParameter(size_t n) const
322 {
323 return n < parameters.size() ? parameters[n] : 0;
324 }
325
326 /////////////////////////////////////////////////////////////////////////////
327 const Server::Parameters& Server::getParameters() const
328 {
329 return parameters;
330 }
331
332 /////////////////////////////////////////////////////////////////////////////
333 const Parameter *Server::find( const PdServ::Parameter *p) const
334 {
335 return parameterMap.find(p)->second;
336 }
337
338 /////////////////////////////////////////////////////////////////////////////
339 const Server::Events& Server::getEvents() const
340 {
341 return events;
342 }
343
344 /////////////////////////////////////////////////////////////////////////////
345 void Server::createChildren(Variable* var)
346 {
347 if (var->dim.isScalar() and var->dtype.isPrimary())
348 return;
349
350 LOG4CPLUS_TRACE(log,
351 LOG4CPLUS_TEXT("Create children for ")
352 << LOG4CPLUS_STRING_TO_TSTRING(var->variable->path));
353
354 if (var->dtype.isPrimary())
355 createVectorChildren(var, var, std::string(),
356 var->dtype, var->dim, 0, 0);
357 else
358 createCompoundChildren(var, var, var->dtype, var->dim, 0, 0);
359 }
360
361 /////////////////////////////////////////////////////////////////////////////
362 size_t Server::createVectorChildren (Variable* var,
363 DirectoryNode* dir, const std::string& name,
364 const PdServ::DataType& dtype,
365 const PdServ::DataType::DimType& dim, size_t dimIdx, size_t offset)
366 {
367 if (dimIdx + 1 < dim.size()) {
368 if (!name.empty())
369 dir = new DirectoryNode(dir, name);
370
371 size_t begin = offset;
372 for (size_t i = 0; i < dim[dimIdx]; ++i) {
373 std::ostringstream os;
374 os << i;
375 offset += createVectorChildren(var, dir, os.str(),
376 dtype, dim, dimIdx + 1, offset);
377 }
378
379 return offset - begin;
380 }
381
382 if (!name.empty())
383 dir = createChild(var, dir, name, dtype, dim.back(), offset);
384
385 if (!dim.isScalar()) {
386 for (size_t i = 0; i < dim.back(); ++i) {
387 std::ostringstream os;
388 os << i;
389 createChild(var, dir, os.str(), dtype, 1, offset);
390 offset += dtype.size;
391 }
392 }
393
394 return dim.back() * dtype.size;
395 }
396
397 /////////////////////////////////////////////////////////////////////////////
398 size_t Server::createCompoundChildren (Variable* var,
399 DirectoryNode* dir, const PdServ::DataType& dtype,
400 const PdServ::DataType::DimType& dim, size_t dimIdx, size_t offset)
401 {
402 if (dimIdx < dim.size() and !dim.isScalar()) {
403 size_t begin = offset;
404 for (size_t i = 0; i < dim[dimIdx]; ++i) {
405 std::ostringstream os;
406 os << i;
407 offset += createCompoundChildren(
408 var, new DirectoryNode(dir, os.str()),
409 dtype, dim, dimIdx + 1, offset);
410 }
411
412 return offset - begin;
413 }
414
415 const PdServ::DataType::FieldList& fieldList = dtype.getFieldList();
416 PdServ::DataType::FieldList::const_iterator it;
417 for (it = fieldList.begin(); it != fieldList.end(); ++it) {
418
419 if ( (*it)->type.isPrimary())
420 createVectorChildren(var, dir, (*it)->name,
421 (*it)->type, (*it)->dim, 0, offset + (*it)->offset);
422 else
423 createCompoundChildren(var,
424 new DirectoryNode(dir, (*it)->name),
425 (*it)->type, (*it)->dim, 0, offset + (*it)->offset);
426 }
427
428 return dim.nelem * dtype.size;
429 }
430
431 /////////////////////////////////////////////////////////////////////////////
432 DirectoryNode* Server::createChild (Variable* var,
433 DirectoryNode* dir, const std::string& name,
434 const PdServ::DataType& dtype, size_t nelem, size_t offset)
435 {
436 Channel *c = dynamic_cast<Channel* >(var);
437 Parameter *p = dynamic_cast<Parameter*>(var);
438
439 if (c) {
440 c = new Channel(c->signal, channels.size(), dtype,
441 PdServ::DataType::DimType(1,&nelem), offset, c);
442 channels.push_back(c);
443 dir->insert(c, name);
444 return c;
445 }
446
447 if (p) {
448 p = new Parameter(p->mainParam, parameters.size(), dtype,
449 PdServ::DataType::DimType(1,&nelem), offset, p);
450 parameters.push_back(p);
451 dir->insert(p, name);
452 return p;
453 }
454
455 return 0;
456 3 }
457