service_manager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, Willow Garage, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice,
7  * this list of conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution.
11  * * Neither the names of Willow Garage, Inc. nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <cstdio>
29 #include "ros/service_manager.h"
30 #include "ros/xmlrpc_manager.h"
31 #include "ros/connection_manager.h"
32 #include "ros/poll_manager.h"
36 #include "ros/this_node.h"
37 #include "ros/network.h"
38 #include "ros/master.h"
41 #include "ros/init.h"
42 #include "ros/connection.h"
43 #include "ros/file_log.h"
44 
45 #include "xmlrpcpp/XmlRpc.h"
46 
47 #include <ros/console.h>
48 
49 using namespace XmlRpc; // A battle to be fought later
50 using namespace std; // sigh
51 
52 namespace ros
53 {
54 
55 const ServiceManagerPtr& ServiceManager::instance()
56 {
57  static ServiceManagerPtr service_manager = boost::make_shared<ServiceManager>();
58  return service_manager;
59 }
60 
61 ServiceManager::ServiceManager()
62 : shutting_down_(false)
63 {
64 }
65 
67 {
68  shutdown();
69 }
70 
72 {
73  shutting_down_ = false;
74 
78 
79 }
80 
82 {
83  boost::recursive_mutex::scoped_lock shutdown_lock(shutting_down_mutex_);
84  if (shutting_down_)
85  {
86  return;
87  }
88 
89  shutting_down_ = true;
90 
91  ROSCPP_LOG_DEBUG("ServiceManager::shutdown(): unregistering our advertised services");
92  {
93  boost::mutex::scoped_lock ss_lock(service_publications_mutex_);
94 
95  for (L_ServicePublication::iterator i = service_publications_.begin();
96  i != service_publications_.end(); ++i)
97  {
98  unregisterService((*i)->getName());
99  //ROSCPP_LOG_DEBUG( "shutting down service %s", (*i)->getName().c_str());
100  (*i)->drop();
101  }
102  service_publications_.clear();
103  }
104 
105  L_ServiceServerLink local_service_clients;
106  {
107  boost::mutex::scoped_lock lock(service_server_links_mutex_);
108  local_service_clients.swap(service_server_links_);
109  }
110 
111  {
112  L_ServiceServerLink::iterator it = local_service_clients.begin();
113  L_ServiceServerLink::iterator end = local_service_clients.end();
114  for (; it != end; ++it)
115  {
116  (*it)->getConnection()->drop(Connection::Destructing);
117  }
118 
119  local_service_clients.clear();
120  }
121 
122 }
123 
125 {
126  boost::recursive_mutex::scoped_lock shutdown_lock(shutting_down_mutex_);
127  if (shutting_down_)
128  {
129  return false;
130  }
131 
132  {
133  boost::mutex::scoped_lock lock(service_publications_mutex_);
134 
135  if (isServiceAdvertised(ops.service))
136  {
137  ROS_ERROR("Tried to advertise a service that is already advertised in this node [%s]", ops.service.c_str());
138  return false;
139  }
140 
141  ServicePublicationPtr pub(boost::make_shared<ServicePublication>(ops.service, ops.md5sum, ops.datatype, ops.req_datatype, ops.res_datatype, ops.helper, ops.callback_queue, ops.tracked_object));
142  service_publications_.push_back(pub);
143  }
144 
145  XmlRpcValue args, result, payload;
146  args[0] = this_node::getName();
147  args[1] = ops.service;
148  char uri_buf[1024];
149  snprintf(uri_buf, sizeof(uri_buf), "rosrpc://%s:%d",
150  network::getHost().c_str(), connection_manager_->getTCPPort());
151  args[2] = string(uri_buf);
152  args[3] = xmlrpc_manager_->getServerURI();
153  master::execute("registerService", args, result, payload, true);
154 
155  return true;
156 }
157 
158 bool ServiceManager::unadvertiseService(const string &serv_name)
159 {
160  boost::recursive_mutex::scoped_lock shutdown_lock(shutting_down_mutex_);
161  if (shutting_down_)
162  {
163  return false;
164  }
165 
167  {
168  boost::mutex::scoped_lock lock(service_publications_mutex_);
169 
170  for (L_ServicePublication::iterator i = service_publications_.begin();
171  i != service_publications_.end(); ++i)
172  {
173  if((*i)->getName() == serv_name && !(*i)->isDropped())
174  {
175  pub = *i;
176  service_publications_.erase(i);
177  break;
178  }
179  }
180  }
181 
182  if (pub)
183  {
184  unregisterService(pub->getName());
185  ROSCPP_LOG_DEBUG( "shutting down service [%s]", pub->getName().c_str());
186  pub->drop();
187  return true;
188  }
189 
190  return false;
191 }
192 
193 bool ServiceManager::unregisterService(const std::string& service)
194 {
195  XmlRpcValue args, result, payload;
196  args[0] = this_node::getName();
197  args[1] = service;
198  char uri_buf[1024];
199  snprintf(uri_buf, sizeof(uri_buf), "rosrpc://%s:%d",
200  network::getHost().c_str(), connection_manager_->getTCPPort());
201  args[2] = string(uri_buf);
202 
203  return master::execute("unregisterService", args, result, payload, false);
204 }
205 
206 bool ServiceManager::isServiceAdvertised(const string& serv_name)
207 {
208  for (L_ServicePublication::iterator s = service_publications_.begin(); s != service_publications_.end(); ++s)
209  {
210  if (((*s)->getName() == serv_name) && !(*s)->isDropped())
211  {
212  return true;
213  }
214  }
215 
216  return false;
217 }
218 
220 {
221  boost::mutex::scoped_lock lock(service_publications_mutex_);
222 
223  for (L_ServicePublication::iterator t = service_publications_.begin();
224  t != service_publications_.end(); ++t)
225  {
226  if ((*t)->getName() == service)
227  {
228  return *t;
229  }
230  }
231 
232  return ServicePublicationPtr();
233 }
234 
235 ServiceServerLinkPtr ServiceManager::createServiceServerLink(const std::string& service, bool persistent,
236  const std::string& request_md5sum, const std::string& response_md5sum,
237  const M_string& header_values)
238 {
239 
240  boost::recursive_mutex::scoped_lock shutdown_lock(shutting_down_mutex_);
241  if (shutting_down_)
242  {
243  return ServiceServerLinkPtr();
244  }
245 
246  uint32_t serv_port;
247  std::string serv_host;
248  if (!lookupService(service, serv_host, serv_port))
249  {
250  return ServiceServerLinkPtr();
251  }
252 
253  TransportTCPPtr transport(boost::make_shared<TransportTCP>(&poll_manager_->getPollSet()));
254 
255  // Make sure to initialize the connection *before* transport->connect()
256  // is called, otherwise we might miss a connect error (see #434).
257  ConnectionPtr connection(boost::make_shared<Connection>());
258  connection_manager_->addConnection(connection);
259  connection->initialize(transport, false, HeaderReceivedFunc());
260 
261  if (transport->connect(serv_host, serv_port))
262  {
263  ServiceServerLinkPtr client(boost::make_shared<ServiceServerLink>(service, persistent, request_md5sum, response_md5sum, header_values));
264 
265  {
266  boost::mutex::scoped_lock lock(service_server_links_mutex_);
267  service_server_links_.push_back(client);
268  }
269 
270  client->initialize(connection);
271 
272  return client;
273  }
274 
275  ROSCPP_LOG_DEBUG("Failed to connect to service [%s] (mapped=[%s]) at [%s:%d]", service.c_str(), service.c_str(), serv_host.c_str(), serv_port);
276 
277  return ServiceServerLinkPtr();
278 }
279 
281 {
282  // Guard against this getting called as a result of shutdown() dropping all connections (where shutting_down_mutex_ is already locked)
283  if (shutting_down_)
284  {
285  return;
286  }
287 
288  boost::recursive_mutex::scoped_lock shutdown_lock(shutting_down_mutex_);
289  // Now check again, since the state may have changed between pre-lock/now
290  if (shutting_down_)
291  {
292  return;
293  }
294 
295  boost::mutex::scoped_lock lock(service_server_links_mutex_);
296 
297  L_ServiceServerLink::iterator it = std::find(service_server_links_.begin(), service_server_links_.end(), client);
298  if (it != service_server_links_.end())
299  {
300  service_server_links_.erase(it);
301  }
302 }
303 
304 bool ServiceManager::lookupService(const string &name, string &serv_host, uint32_t &serv_port)
305 {
306  XmlRpcValue args, result, payload;
307  args[0] = this_node::getName();
308  args[1] = name;
309  if (!master::execute("lookupService", args, result, payload, false))
310  return false;
311 
312  string serv_uri(payload);
313  if (!serv_uri.length()) // shouldn't happen. but let's be sure.
314  {
315  ROS_ERROR("lookupService: Empty server URI returned from master");
316 
317  return false;
318  }
319 
320  if (!network::splitURI(serv_uri, serv_host, serv_port))
321  {
322  ROS_ERROR("lookupService: Bad service uri [%s]", serv_uri.c_str());
323 
324  return false;
325  }
326 
327  return true;
328 }
329 
330 } // namespace ros
331 
CallbackQueueInterface * callback_queue
Queue to add callbacks to. If NULL, the global callback queue will be used.
std::string md5sum
MD5 of the service.
ConnectionManagerPtr connection_manager_
volatile bool shutting_down_
L_ServiceServerLink service_server_links_
ServicePublicationPtr lookupServicePublication(const std::string &service)
Lookup an advertised service.
bool lookupService(const std::string &name, std::string &serv_host, uint32_t &serv_port)
Lookup the host/port of a service.
L_ServicePublication service_publications_
XmlRpcServer s
void removeServiceServerLink(const ServiceServerLinkPtr &client)
Remove the specified service client from our list.
VoidConstPtr tracked_object
An object whose destruction will prevent the callback associated with this service from being called...
ROSCPP_DECL bool splitURI(const std::string &uri, std::string &host, uint32_t &port)
Definition: network.cpp:55
bool unadvertiseService(const std::string &serv_name)
Unadvertise a service.
ROSCPP_DECL const std::string & getName()
Returns the name of the current node.
Definition: this_node.cpp:81
std::list< ServiceServerLinkPtr > L_ServiceServerLink
Definition: forwards.h:87
PollManagerPtr poll_manager_
boost::function< bool(const ConnectionPtr &, const Header &)> HeaderReceivedFunc
Definition: connection.h:62
std::string res_datatype
Response message datatype.
Encapsulates all options available for creating a ServiceServer.
std::map< std::string, std::string > M_string
#define ROSCPP_LOG_DEBUG(...)
Definition: file_log.h:35
ServiceCallbackHelperPtr helper
Helper object used for creating messages and calling callbacks.
ROSCPP_DECL const std::string & getHost()
Definition: network.cpp:50
static const ConnectionManagerPtr & instance()
bool advertiseService(const AdvertiseServiceOptions &ops)
ROSCPP_DECL bool execute(const std::string &method, const XmlRpc::XmlRpcValue &request, XmlRpc::XmlRpcValue &response, XmlRpc::XmlRpcValue &payload, bool wait_for_master)
Execute an XMLRPC call on the master.
Definition: master.cpp:179
boost::mutex service_server_links_mutex_
bool unregisterService(const std::string &service)
static const PollManagerPtr & instance()
bool isServiceAdvertised(const std::string &serv_name)
boost::shared_ptr< ServiceServerLink > ServiceServerLinkPtr
Definition: forwards.h:85
static const XMLRPCManagerPtr & instance()
boost::mutex service_publications_mutex_
boost::recursive_mutex shutting_down_mutex_
ServiceServerLinkPtr createServiceServerLink(const std::string &service, bool persistent, const std::string &request_md5sum, const std::string &response_md5sum, const M_string &header_values)
Create a new client to the specified service. If a client to that service already exists...
XMLRPCManagerPtr xmlrpc_manager_
boost::shared_ptr< ServicePublication > ServicePublicationPtr
Definition: forwards.h:81
std::string datatype
Datatype of the service.
#define ROS_ERROR(...)
std::string req_datatype
Request message datatype.


roscpp
Author(s): Morgan Quigley, Josh Faust, Brian Gerkey, Troy Straszheim, Dirk Thomas
autogenerated on Mon Nov 2 2020 03:52:26