rclcpp  master
C++ ROS Client Library API
service.hpp
Go to the documentation of this file.
1 // Copyright 2014 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__SERVICE_HPP_
16 #define RCLCPP__SERVICE_HPP_
17 
18 #include <functional>
19 #include <iostream>
20 #include <memory>
21 #include <sstream>
22 #include <string>
23 
24 #include "rcl/error_handling.h"
25 #include "rcl/service.h"
26 
28 #include "rclcpp/exceptions.hpp"
29 #include "rclcpp/macros.hpp"
33 #include "rclcpp/logging.hpp"
34 #include "rmw/error_handling.h"
35 #include "rmw/rmw.h"
36 #include "tracetools/tracetools.h"
37 
38 namespace rclcpp
39 {
40 
42 {
43 public:
45 
47  explicit ServiceBase(
48  std::shared_ptr<rcl_node_t> node_handle);
49 
51  virtual ~ServiceBase();
52 
54  const char *
56 
60 
63  get_service_handle() const;
64 
67  virtual void handle_request(
68  std::shared_ptr<rmw_request_id_t> request_header,
69  std::shared_ptr<void> request) = 0;
70 
71 protected:
72  RCLCPP_DISABLE_COPY(ServiceBase)
73 
75  rcl_node_t *
77 
79  const rcl_node_t *
80  get_rcl_node_handle() const;
81 
83 
85  bool owns_rcl_handle_ = true;
86 };
87 
88 template<typename ServiceT>
89 class Service : public ServiceBase
90 {
91 public:
93  void (
96 
98  void (
103 
105  std::shared_ptr<rcl_node_t> node_handle,
106  const std::string & service_name,
107  AnyServiceCallback<ServiceT> any_callback,
108  rcl_service_options_t & service_options)
109  : ServiceBase(node_handle), any_callback_(any_callback)
110  {
111  using rosidl_typesupport_cpp::get_service_type_support_handle;
112  auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
113 
114  std::weak_ptr<rcl_node_t> weak_node_handle(node_handle_);
115  // rcl does the static memory allocation here
117  new rcl_service_t, [weak_node_handle](rcl_service_t * service)
118  {
119  auto handle = weak_node_handle.lock();
120  if (handle) {
121  if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
122  RCLCPP_ERROR(
123  rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
124  "Error in destruction of rcl service handle: %s",
125  rcl_get_error_string().str);
126  rcl_reset_error();
127  }
128  } else {
129  RCLCPP_ERROR(
130  rclcpp::get_logger("rclcpp"),
131  "Error in destruction of rcl service handle: "
132  "the Node Handle was destructed too early. You will leak memory");
133  }
134  delete service;
135  });
137 
140  node_handle.get(),
141  service_type_support_handle,
142  service_name.c_str(),
143  &service_options);
144  if (ret != RCL_RET_OK) {
145  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
146  auto rcl_node_handle = get_rcl_node_handle();
147  // this will throw on any validation problem
148  rcl_reset_error();
150  service_name,
151  rcl_node_get_name(rcl_node_handle),
152  rcl_node_get_namespace(rcl_node_handle),
153  true);
154  }
155 
156  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
157  }
158  TRACEPOINT(
159  rclcpp_service_callback_added,
160  (const void *)get_service_handle().get(),
161  (const void *)&any_callback_);
162  }
163 
165  std::shared_ptr<rcl_node_t> node_handle,
166  std::shared_ptr<rcl_service_t> service_handle,
167  AnyServiceCallback<ServiceT> any_callback)
168  : ServiceBase(node_handle),
169  any_callback_(any_callback)
170  {
171  // check if service handle was initialized
172  if (!rcl_service_is_valid(service_handle.get())) {
173  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
174  throw std::runtime_error(
175  std::string("rcl_service_t in constructor argument must be initialized beforehand."));
176  // *INDENT-ON*
177  }
178 
179  service_handle_ = service_handle;
180  TRACEPOINT(
181  rclcpp_service_callback_added,
182  (const void *)get_service_handle().get(),
183  (const void *)&any_callback_);
184  }
185 
187  std::shared_ptr<rcl_node_t> node_handle,
188  rcl_service_t * service_handle,
189  AnyServiceCallback<ServiceT> any_callback)
190  : ServiceBase(node_handle),
191  any_callback_(any_callback)
192  {
193  // check if service handle was initialized
194  if (!rcl_service_is_valid(service_handle)) {
195  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
196  throw std::runtime_error(
197  std::string("rcl_service_t in constructor argument must be initialized beforehand."));
198  // *INDENT-ON*
199  }
200 
201  // In this case, rcl owns the service handle memory
203  service_handle_->impl = service_handle->impl;
204  TRACEPOINT(
205  rclcpp_service_callback_added,
206  (const void *)get_service_handle().get(),
207  (const void *)&any_callback_);
208  }
209 
210  Service() = delete;
211 
212  virtual ~Service()
213  {
214  }
215 
217  {
218  return std::shared_ptr<void>(new typename ServiceT::Request());
219  }
220 
222  {
223  // TODO(wjwwood): This should probably use rmw_request_id's allocator.
224  // (since it is a C type)
226  }
227 
229  std::shared_ptr<rmw_request_id_t> request_header,
230  std::shared_ptr<void> request)
231  {
232  auto typed_request = std::static_pointer_cast<typename ServiceT::Request>(request);
233  auto response = std::shared_ptr<typename ServiceT::Response>(new typename ServiceT::Response);
234  any_callback_.dispatch(request_header, typed_request, response);
235  send_response(request_header, response);
236  }
237 
241  {
242  rcl_ret_t status = rcl_send_response(get_service_handle().get(), req_id.get(), response.get());
243 
244  if (status != RCL_RET_OK) {
245  rclcpp::exceptions::throw_from_rcl_error(status, "failed to send response");
246  }
247  }
248 
249 private:
251 
252  AnyServiceCallback<ServiceT> any_callback_;
253 };
254 
255 } // namespace rclcpp
256 
257 #endif // RCLCPP__SERVICE_HPP_
bool rcl_service_is_valid(const rcl_service_t *service)
Service(std::shared_ptr< rcl_node_t > node_handle, std::shared_ptr< rcl_service_t > service_handle, AnyServiceCallback< ServiceT > any_callback)
Definition: service.hpp:164
#define rcl_get_error_string
void send_response(std::shared_ptr< rmw_request_id_t > req_id, std::shared_ptr< typename ServiceT::Response > response)
Definition: service.hpp:238
rcl_ret_t rcl_service_init(rcl_service_t *service, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_service_options_t *options)
#define RCLCPP_DISABLE_COPY(...)
Definition: macros.hpp:26
#define rcl_reset_error
rmw_ret_t rcl_ret_t
Logger get_logger(const std::string &name)
Return a named logger.
struct rcl_service_impl_t * impl
This header provides the get_node_base_interface() template function.
Definition: allocator_common.hpp:24
std::shared_ptr< rcl_service_t > get_service_handle()
virtual ~ServiceBase()
bool owns_rcl_handle_
Definition: service.hpp:85
Definition: service.hpp:89
virtual void handle_request(std::shared_ptr< rmw_request_id_t > request_header, std::shared_ptr< void > request)=0
std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
ServiceBase(std::shared_ptr< rcl_node_t > node_handle)
#define RCL_RET_OK
void throw_from_rcl_error(rcl_ret_t ret, const std::string &prefix="", const rcl_error_state_t *error_state=nullptr, void(*reset_error)()=rcl_reset_error)
Throw a C++ std::exception which was created based on an rcl error.
rcl_ret_t rcl_send_response(const rcl_service_t *service, rmw_request_id_t *response_header, void *ros_response)
#define RCLCPP_SMART_PTR_DEFINITIONS(...)
Definition: macros.hpp:36
#define RCLCPP_ERROR(logger,...)
Definition: logging.hpp:1418
T static_pointer_cast(T... args)
const char * get_service_name()
std::shared_ptr< rcl_node_t > node_handle_
Definition: service.hpp:82
rcl_ret_t rcl_service_fini(rcl_service_t *service, rcl_node_t *node)
std::shared_ptr< void > create_request()
Definition: service.hpp:216
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
Definition: macros.hpp:51
T get(T... args)
virtual ~Service()
Definition: service.hpp:212
Logger get_node_logger(const rcl_node_t *node)
Return a named logger using an rcl_node_t.
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
virtual std::shared_ptr< rmw_request_id_t > create_request_header()=0
#define RCL_RET_SERVICE_NAME_INVALID
Definition: service.hpp:41
const char * rcl_node_get_name(const rcl_node_t *node)
const char * rcl_node_get_namespace(const rcl_node_t *node)
Service(std::shared_ptr< rcl_node_t > node_handle, rcl_service_t *service_handle, AnyServiceCallback< ServiceT > any_callback)
Definition: service.hpp:186
rcl_service_t rcl_get_zero_initialized_service(void)
rcl_node_t * get_rcl_node_handle()
void handle_request(std::shared_ptr< rmw_request_id_t > request_header, std::shared_ptr< void > request)
Definition: service.hpp:228
virtual std::shared_ptr< void > create_request()=0
std::shared_ptr< rmw_request_id_t > create_request_header()
Definition: service.hpp:221
std::shared_ptr< rcl_service_t > service_handle_
Definition: service.hpp:84
Definition: any_service_callback.hpp:32