GCC Code Coverage Report


Directory: ./
File: src/server.cc
Date: 2024-09-11 11:37:19
Exec Total Coverage
Lines: 102 240 42.5%
Branches: 79 417 18.9%

Line Branch Exec Source
1 // Copyright (C) 2009, 2010 by Florent Lamiraux, Thomas Moulard, JRL.
2 //
3
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // 1. Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 // DAMAGE.
27 //
28 // This software is provided "as is" without warranty of any kind,
29 // either expressed or implied, including but not limited to the
30 // implied warranties of fitness for a particular purpose.
31 //
32 // See the COPYING file for more information.
33
34 #include "hpp/corbaserver/server.hh"
35
36 #include <dlfcn.h>
37 #include <errno.h>
38 #include <pthread.h>
39 #include <stdlib.h>
40
41 #include <hpp/corbaserver/server-plugin.hh>
42 #include <hpp/core/plugin.hh>
43 #include <hpp/util/debug.hh>
44 #include <hpp/util/exception-factory.hh>
45 #include <iostream>
46
47 #include "basic-server.hh"
48 #include "hpp/corbaserver/conversions.hh"
49 #include "hpp/corbaserver/servant-base.hh"
50 #include "hpp/corbaserver/tools-idl.hh"
51
52 namespace hpp {
53 namespace corbaServer {
54 using CORBA::Exception;
55 using CORBA::Object_var;
56 using CORBA::SystemException;
57 using omniORB::fatalException;
58
59 namespace {
60 void usage(const char* app) {
61 std::cerr
62 << "Usage: " << app << " [options] ...\n"
63 << " --name <name> \n"
64 << " --host <host> \n"
65 << " --port <port> \n"
66 << " --help \n"
67 << " --verbosity <level>\twhere level is a positive integer between 0 "
68 "(no logs) to 50 (very verbose).\n"
69 << " --benchmark \tenable benchmarking (written in the logs).\n"
70 << " --single-thread \n"
71 << " --multi-thread \n"
72 << "\n"
73 "Environment variables:\n"
74 "- HPP_LOGGINGDIR: change the directory where logs are written.\n"
75 "- HPP_HOST: change the default host.\n"
76 "- HPP_PORT: change the default port.\n"
77 << std::flush;
78 }
79
80 8 std::string endPoint(const std::string& host, const int port) {
81
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::ostringstream oss;
82
4/8
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
8 oss << "::" << host << ':' << port;
83
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
16 return oss.str();
84 8 }
85 } // end of anonymous namespace.
86
87 class Tools : public virtual POA_hpp::Tools {
88 public:
89
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 Tools() : server_(NULL) {};
90
91 8 void setServer(Server* server) { server_ = server; }
92
93 virtual CORBA::Boolean loadServerPlugin(const char* context,
94 const char* pluginName) {
95 try {
96 std::string c(context), pn(pluginName);
97 return server_->loadPlugin(c, pn);
98 } catch (const std::exception& e) {
99 throw hpp::Error(e.what());
100 }
101 }
102
103 virtual CORBA::Boolean createContext(const char* context) {
104 try {
105 std::string c(context);
106 return server_->createContext(c);
107 } catch (const std::exception& e) {
108 throw hpp::Error(e.what());
109 }
110 }
111
112 virtual Names_t* getContexts() {
113 try {
114 std::vector<std::string> contexts(server_->getContexts());
115 return toNames_t(contexts);
116 } catch (const std::exception& e) {
117 throw hpp::Error(e.what());
118 }
119 }
120
121 bool deleteContext(const char* context) {
122 try {
123 std::string c(context);
124 return server_->deleteContext(c);
125 } catch (const std::exception& e) {
126 throw hpp::Error(e.what());
127 }
128 }
129
130 27 CORBA::Object_ptr getServer(const char* contextName, const char* pluginName,
131 const char* objectName) {
132 try {
133
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 std::string c(contextName);
134
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 std::string p(pluginName);
135
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 std::string o(objectName);
136
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
54 return server_->getServer(c, p, o);
137
0/2
✗ Branch 6 not taken.
✗ Branch 7 not taken.
27 } catch (const std::exception& e) {
138 throw hpp::Error(e.what());
139 }
140 }
141
142 virtual void deleteServant(const char* id) {
143 try {
144 CORBA::Object_ptr obj = server_->orb()->string_to_object(id);
145 PortableServer::ObjectId_var objectId =
146 server_->poa()->reference_to_id(obj);
147 // Remove reference in servant object map
148 ServantBase_var servant = server_->poa()->id_to_servant(objectId.in());
149 server_->removeServant(servant.in());
150 // Deactivate object
151 server_->poa()->deactivate_object(objectId.in());
152 } catch (const std::exception& e) {
153 throw hpp::Error(e.what());
154 } catch (PortableServer::POA::ObjectNotActive const& e) {
155 // This allows to call `deleteServant` twice on the
156 // same object. OmniORB and Python does not offer a nice mechanism
157 // to avoid calling this method twice. We simply warn because
158 // there should be no harm in continuing the program since
159 // the request was to delete an object which has already been
160 // deleted.
161 hppDout(warning,
162 "Trying to delete an non existant servant. Object not active: "
163 << id);
164 }
165 }
166
167 virtual void deleteAllServants() override {
168 try {
169 server_->clearServantsMap();
170 } catch (const std::exception& e) {
171 throw hpp::Error(e.what());
172 }
173 }
174
175 1 virtual Names_t* getAllServants() override {
176 try {
177
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<std::string> names{server_->getAllObjectIds()};
178
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return toNames_t(names);
179
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } catch (const std::exception& e) {
180 throw hpp::Error(e.what());
181 }
182 }
183
184 8 virtual void shutdown() { server_->requestShutdown(false); }
185
186 private:
187 Server* server_;
188 };
189
190 Server::Server(core::ProblemSolverPtr_t problemSolver, int argc,
191 const char* argv[], bool inMultiThread)
192 : multiThread_(inMultiThread),
193 nameService_(false),
194 problemSolverMap_(new ProblemSolverMap(problemSolver)) {
195 parseArguments(argc, argv);
196 initialize();
197 }
198
199 8 Server::Server(core::ProblemSolverPtr_t problemSolver, bool inMultiThread)
200 8 : multiThread_(inMultiThread),
201 8 nameService_(false),
202
4/8
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
8 problemSolverMap_(new ProblemSolverMap(problemSolver)) {}
203
204 8 void Server::initialize() {
205
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (!nameService_) tools_->initOmniINSPOA("hpp-corbaserver");
206 8 tools_->initRootPOA(multiThread_);
207 8 tools_->implementation().setServer(this);
208 8 }
209
210 8 Server::~Server() {}
211
212 8 bool Server::parseArguments(int argc, const char* argv[]) {
213
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 mainContextId_ = "corbaserver";
214
215
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 std::string host = "localhost";
216 8 int port = 13331;
217 8 bool endPointSet = false;
218 // Read environment variables
219 8 char* env = getenv("HPP_HOST");
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (env != NULL) {
221 host = env;
222 endPointSet = true;
223 }
224 8 env = getenv("HPP_PORT");
225
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (env != NULL) {
226 1 port = atoi(env);
227 1 endPointSet = true;
228 }
229
230
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ORBendPoint = endPoint(host, port);
231
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 for (int i = 1; i < argc; ++i) {
233 if (strcmp(argv[i], "--name") == 0) {
234 if (i < argc - 1) {
235 mainContextId_ = argv[i + 1];
236 ++i;
237 } else
238 usage(argv[0]);
239 std::cout << "Server main context: " << mainContextId_ << std::endl;
240 } else if (strcmp(argv[i], "--help") == 0) {
241 usage(argv[0]);
242 return false;
243 } else if (strcmp(argv[i], "--single-thread") == 0) {
244 multiThread_ = false;
245 std::cout << "Switched to single thread mode." << std::endl;
246 } else if (strcmp(argv[i], "--multi-thread") == 0) {
247 std::cout << "Switched to multi-thread mode." << std::endl;
248 multiThread_ = true;
249 } else if (strcmp(argv[i], "--use-name-service") == 0) {
250 std::cout << "Using name service." << std::endl;
251 nameService_ = true;
252 } else if (strcmp(argv[i], "--host") == 0) {
253 host = argv[++i];
254 ORBendPoint = endPoint(host, port);
255 endPointSet = true;
256 } else if (strcmp(argv[i], "--port") == 0) {
257 port = atoi(argv[++i]);
258 ORBendPoint = endPoint(host, port);
259 endPointSet = true;
260 } else if (strcmp(argv[i], "-ORBendPoint") == 0) {
261 ORBendPoint = argv[++i];
262 endPointSet = true;
263 } else if (strcmp(argv[i], "--verbosity") == 0) {
264 int verbosityLevel = atoi(argv[++i]);
265 ::hpp::debug::setVerbosityLevel(verbosityLevel);
266 } else if (strcmp(argv[i], "--benchmark") == 0) {
267 ::hpp::debug::enableBenchmark(true);
268 }
269 }
270
5/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
8 if (endPointSet) std::cout << "End point: " << ORBendPoint << std::endl;
271
272 8 const char* options[][2] = {{"endPoint", ORBendPoint.c_str()}, {0, 0}};
273
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 tools_ = new corba::Server<Tools>(argc, argv, "", options);
274
275 8 return true;
276 8 }
277
278 8 void Server::startCorbaServer() {
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (nameService_)
280 tools_->startCorbaServer("hpp", "tools");
281 else
282 8 tools_->startCorbaServer();
283
284 // Creation of main context
285 8 createContext(mainContextId());
286 8 }
287
288 8 bool Server::createContext(const std::string& name) {
289
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
8 if (contexts_.find(name) != contexts_.end()) return false;
290
291 8 getContext(name);
292 8 return true;
293 }
294
295 std::vector<std::string> Server::getContexts() const {
296 std::vector<std::string> contexts;
297 contexts.reserve(contexts_.size());
298 for (auto const& pair : contexts_) contexts.push_back(pair.first);
299 return contexts;
300 }
301
302 bool Server::deleteContext(const std::string& name) {
303 return static_cast<bool>(contexts_.erase(name));
304 }
305
306 core::ProblemSolverPtr_t Server::problemSolver() {
307 return problemSolverMap_->selected();
308 }
309
310 ProblemSolverMapPtr_t Server::problemSolverMap() { return problemSolverMap_; }
311
312 8 Server::Context& Server::getContext(const std::string& name) {
313
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
8 if (contexts_.find(name) != contexts_.end()) {
314 return contexts_[name];
315 }
316
317 8 Context context;
318
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 context.main = ServerPluginPtr_t(new BasicServer(this));
319
3/6
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 ProblemSolverMapPtr_t psm(new ProblemSolverMap(*problemSolverMap_));
320 8 context.main->setProblemSolverMap(psm);
321
2/4
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 context.main->startCorbaServer("hpp", name);
322
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 context.plugins[""] = context.main;
323
324
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 return contexts_.insert(std::make_pair(name, context)).first->second;
325 8 }
326
327 27 CORBA::Object_ptr Server::getServer(const std::string& contextName,
328 const std::string& pluginName,
329 const std::string& objectName) {
330
2/4
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
27 if (contexts_.find(contextName) == contexts_.end())
331 throw std::invalid_argument("No context " + contextName);
332
333
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 const Context& context = contexts_[contextName];
334
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 ServerPluginMap_t::const_iterator _plugin = context.plugins.find(pluginName);
335
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if (_plugin == context.plugins.end())
336 throw std::invalid_argument("No plugin " + pluginName);
337
338
1/2
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
54 return _plugin->second->servant(objectName);
339 }
340
341 bool Server::loadPlugin(const std::string& contextName,
342 const std::string& libFilename) {
343 // Load the plugin
344 std::string lib = core::plugin::findPluginLibrary(libFilename);
345
346 typedef ::hpp::corbaServer::ServerPlugin* (*PluginFunction_t)(Server*);
347
348 // Clear old errors
349 const char* error = dlerror();
350 // void* library = dlopen(lib.c_str(), RTLD_NOW|RTLD_GLOBAL);
351 void* library = dlopen(lib.c_str(), RTLD_NOW);
352 error = dlerror();
353 if (error != NULL) {
354 HPP_THROW(std::runtime_error,
355 "Error loading library " << lib << ": " << error);
356 }
357 if (library == NULL) {
358 // uncaught error ?
359 HPP_THROW(std::runtime_error,
360 "Unknown error while loading library " << lib << ".");
361 }
362
363 PluginFunction_t function =
364 reinterpret_cast<PluginFunction_t>(dlsym(library, "createServerPlugin"));
365 error = dlerror();
366 if (error != NULL) {
367 HPP_THROW(std::runtime_error,
368 "Error loading library " << lib << ": " << error);
369 }
370 if (function == NULL) {
371 HPP_THROW(std::runtime_error,
372 "Symbol createServerPlugin of (correctly loaded) library "
373 << lib << " is NULL.");
374 }
375
376 // Get the context.
377 Context& context = getContext(contextName);
378
379 ServerPluginPtr_t plugin(function(this));
380 if (!plugin) return false;
381 const std::string name = plugin->name();
382 if (context.plugins.find(name) != context.plugins.end()) {
383 hppDout(info, "Plugin " << lib << " already loaded.");
384 return false;
385 }
386 context.plugins[name] = plugin;
387 plugin->setProblemSolverMap(context.main->problemSolverMap());
388 plugin->startCorbaServer("hpp", contextName);
389
390 // I don't think we should do that because the symbols should not be
391 // removed... dlclose (library);
392
393 return true;
394 }
395
396 /// \brief If CORBA requests are pending, process them
397 8 int Server::processRequest(bool loop) { return tools_->processRequest(loop); }
398
399
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 void Server::requestShutdown(bool wait) { orb()->shutdown(wait); }
400
401 11 PortableServer::Servant Server::getServant(ServantKey servantKey) const {
402 11 PortableServer::Servant servant = NULL;
403
404 11 ReadWriteLock* lock = const_cast<ReadWriteLock*>(&this->lock_);
405
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 lock->readLock();
406
407 ServantKeyToServantMap_t::const_iterator _servant =
408
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 servantKeyToServantMap_.find(servantKey);
409
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9 times.
11 if (_servant != servantKeyToServantMap_.end()) servant = _servant->second;
410
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 lock->readUnlock();
411 11 return servant;
412 }
413
414 9 void Server::addServantKeyAndServant(ServantKey servantKey,
415 PortableServer::Servant servant) {
416
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 lock_.writeLock();
417 typedef std::pair<ServantToServantKeyMap_t::iterator, bool> Ret_t;
418 Ret_t ret =
419
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 servantToServantKeyMap_.insert(std::make_pair(servant, servantKey));
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ret.second) // Object not added because it already exists
421 {
422 std::cerr << "An servant object was lost." << std::endl;
423 ret.first->second = servantKey;
424 }
425
426 typedef std::pair<ServantKeyToServantMap_t::iterator, bool> Ret2_t;
427 Ret2_t ret2 =
428
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 servantKeyToServantMap_.insert(std::make_pair(servantKey, servant));
429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ret2.second) ret2.first->second = servant;
430
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 lock_.writeUnlock();
431 9 }
432
433 void Server::removeServant(PortableServer::Servant servant) {
434 lock_.writeLock();
435 ServantToServantKeyMap_t::iterator _it =
436 servantToServantKeyMap_.find(servant);
437 if (_it != servantToServantKeyMap_.end()) {
438 servantKeyToServantMap_.erase(_it->second);
439 servantToServantKeyMap_.erase(_it);
440 }
441 lock_.writeUnlock();
442 }
443
444 void Server::clearServantsMap() {
445 PortableServer::POA_var _poa(poa());
446 lock_.writeLock();
447 for (const auto& pair : servantKeyToServantMap_) {
448 PortableServer::ObjectId_var objectId = _poa->servant_to_id(pair.second);
449 _poa->deactivate_object(objectId.in());
450 }
451 servantKeyToServantMap_.clear();
452 servantToServantKeyMap_.clear();
453 lock_.writeUnlock();
454 }
455
456 1 std::vector<std::string> Server::getAllObjectIds() {
457 1 std::vector<std::string> objectIds;
458
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 PortableServer::POA_var _poa(poa());
459
460
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lock_.readLock();
461
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 objectIds.reserve(servantKeyToServantMap_.size());
462
2/2
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
2 for (const auto& pair : servantKeyToServantMap_) {
463
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 PortableServer::ObjectId_var objectId = _poa->servant_to_id(pair.second);
464 1 objectIds.emplace_back(
465
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
1 orb()->object_to_string(_poa->id_to_reference(objectId)));
466 1 }
467
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lock_.readUnlock();
468 2 return objectIds;
469 1 }
470
471 } // end of namespace corbaServer.
472 } // end of namespace hpp.
473