1 // Copyright 2014 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file provides internal implementation details of dispatching D-Bus 6 // method calls to a D-Bus object methods by reading the expected parameter 7 // values from D-Bus message buffer then invoking a native C++ callback with 8 // those parameters passed in. If the callback returns a value, that value is 9 // sent back to the caller of D-Bus method via the response message. 10 11 // This is achieved by redirecting the parsing of parameter values from D-Bus 12 // message buffer to DBusParamReader helper class. 13 // DBusParamReader de-serializes the parameter values from the D-Bus message 14 // and calls the provided native C++ callback with those arguments. 15 // However it expects the callback with a simple signature like this: 16 // void callback(Args...); 17 // The method handlers for DBusObject, on the other hand, have one of the 18 // following signatures: 19 // void handler(Args...); 20 // ReturnType handler(Args...); 21 // bool handler(ErrorPtr* error, Args...); 22 // void handler(std::unique_ptr<DBusMethodResponse<T1, T2,...>>, Args...); 23 // 24 // To make this all work, we craft a simple callback suitable for 25 // DBusParamReader using a lambda in DBusInvoker::Invoke() and redirect the call 26 // to the appropriate method handler using additional data captured by the 27 // lambda object. 28 29 #ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ 30 #define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ 31 32 #include <memory> 33 #include <string> 34 #include <type_traits> 35 #include <utility> 36 37 #include <brillo/dbus/data_serialization.h> 38 #include <brillo/dbus/dbus_method_response.h> 39 #include <brillo/dbus/dbus_param_reader.h> 40 #include <brillo/dbus/dbus_param_writer.h> 41 #include <brillo/dbus/utils.h> 42 #include <brillo/errors/error.h> 43 #include <dbus/message.h> 44 45 namespace brillo { 46 namespace dbus_utils { 47 48 // This is an abstract base class to allow dispatching a native C++ callback 49 // method when a corresponding D-Bus method is called. 50 class DBusInterfaceMethodHandlerInterface { 51 public: 52 virtual ~DBusInterfaceMethodHandlerInterface() = default; 53 54 // Returns true if the method has been handled synchronously (whether or not 55 // a success or error response message had been sent). 56 virtual void HandleMethod(::dbus::MethodCall* method_call, 57 ResponseSender sender) = 0; 58 }; 59 60 // This is a special implementation of DBusInterfaceMethodHandlerInterface for 61 // extremely simple synchronous method handlers that cannot possibly fail 62 // (that is, they do not send an error response). 63 // The handler is expected to take an arbitrary number of arguments of type 64 // |Args...| which can contain both inputs (passed in by value or constant 65 // reference) and outputs (passed in as pointers)... 66 // It may also return a single value of type R (or could be a void function if 67 // no return value is to be sent to the caller). If the handler has a return 68 // value, then it cannot have any output parameters in its parameter list. 69 // The signature of the callback handler is expected to be: 70 // R(Args...) 71 template<typename R, typename... Args> 72 class SimpleDBusInterfaceMethodHandler 73 : public DBusInterfaceMethodHandlerInterface { 74 public: 75 // A constructor that takes a |handler| to be called when HandleMethod() 76 // virtual function is invoked. SimpleDBusInterfaceMethodHandler(const base::Callback<R (Args...)> & handler)77 explicit SimpleDBusInterfaceMethodHandler( 78 const base::Callback<R(Args...)>& handler) : handler_(handler) {} 79 HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)80 void HandleMethod(::dbus::MethodCall* method_call, 81 ResponseSender sender) override { 82 DBusMethodResponse<R> method_response(method_call, sender); 83 auto invoke_callback = [this, &method_response](const Args&... args) { 84 method_response.Return(handler_.Run(args...)); 85 }; 86 87 ErrorPtr param_reader_error; 88 ::dbus::MessageReader reader(method_call); 89 // The handler is expected a return value, don't allow output parameters. 90 if (!DBusParamReader<false, Args...>::Invoke( 91 invoke_callback, &reader, ¶m_reader_error)) { 92 // Error parsing method arguments. 93 method_response.ReplyWithError(param_reader_error.get()); 94 } 95 } 96 97 private: 98 // C++ callback to be called when a DBus method is dispatched. 99 base::Callback<R(Args...)> handler_; 100 DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler); 101 }; 102 103 // Specialization of SimpleDBusInterfaceMethodHandlerInterface for 104 // R=void (methods with no return values). 105 template<typename... Args> 106 class SimpleDBusInterfaceMethodHandler<void, Args...> 107 : public DBusInterfaceMethodHandlerInterface { 108 public: 109 // A constructor that takes a |handler| to be called when HandleMethod() 110 // virtual function is invoked. SimpleDBusInterfaceMethodHandler(const base::Callback<void (Args...)> & handler)111 explicit SimpleDBusInterfaceMethodHandler( 112 const base::Callback<void(Args...)>& handler) : handler_(handler) {} 113 HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)114 void HandleMethod(::dbus::MethodCall* method_call, 115 ResponseSender sender) override { 116 DBusMethodResponseBase method_response(method_call, sender); 117 auto invoke_callback = [this, &method_response](const Args&... args) { 118 handler_.Run(args...); 119 auto response = method_response.CreateCustomResponse(); 120 ::dbus::MessageWriter writer(response.get()); 121 DBusParamWriter::AppendDBusOutParams(&writer, args...); 122 method_response.SendRawResponse(std::move(response)); 123 }; 124 125 ErrorPtr param_reader_error; 126 ::dbus::MessageReader reader(method_call); 127 if (!DBusParamReader<true, Args...>::Invoke( 128 invoke_callback, &reader, ¶m_reader_error)) { 129 // Error parsing method arguments. 130 method_response.ReplyWithError(param_reader_error.get()); 131 } 132 } 133 134 private: 135 // C++ callback to be called when a DBus method is dispatched. 136 base::Callback<void(Args...)> handler_; 137 DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler); 138 }; 139 140 // An implementation of DBusInterfaceMethodHandlerInterface for simple 141 // synchronous method handlers that may fail and return an error response 142 // message. 143 // The handler is expected to take an arbitrary number of arguments of type 144 // |Args...| which can contain both inputs (passed in by value or constant 145 // reference) and outputs (passed in as pointers)... 146 // In case of an error, the handler must return false and set the error details 147 // into the |error| object provided. 148 // The signature of the callback handler is expected to be: 149 // bool(ErrorPtr*, Args...) 150 template<typename... Args> 151 class SimpleDBusInterfaceMethodHandlerWithError 152 : public DBusInterfaceMethodHandlerInterface { 153 public: 154 // A constructor that takes a |handler| to be called when HandleMethod() 155 // virtual function is invoked. SimpleDBusInterfaceMethodHandlerWithError(const base::Callback<bool (ErrorPtr *,Args...)> & handler)156 explicit SimpleDBusInterfaceMethodHandlerWithError( 157 const base::Callback<bool(ErrorPtr*, Args...)>& handler) 158 : handler_(handler) {} 159 HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)160 void HandleMethod(::dbus::MethodCall* method_call, 161 ResponseSender sender) override { 162 DBusMethodResponseBase method_response(method_call, sender); 163 auto invoke_callback = [this, &method_response](const Args&... args) { 164 ErrorPtr error; 165 if (!handler_.Run(&error, args...)) { 166 method_response.ReplyWithError(error.get()); 167 } else { 168 auto response = method_response.CreateCustomResponse(); 169 ::dbus::MessageWriter writer(response.get()); 170 DBusParamWriter::AppendDBusOutParams(&writer, args...); 171 method_response.SendRawResponse(std::move(response)); 172 } 173 }; 174 175 ErrorPtr param_reader_error; 176 ::dbus::MessageReader reader(method_call); 177 if (!DBusParamReader<true, Args...>::Invoke( 178 invoke_callback, &reader, ¶m_reader_error)) { 179 // Error parsing method arguments. 180 method_response.ReplyWithError(param_reader_error.get()); 181 } 182 } 183 184 private: 185 // C++ callback to be called when a DBus method is dispatched. 186 base::Callback<bool(ErrorPtr*, Args...)> handler_; 187 DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithError); 188 }; 189 190 // An implementation of SimpleDBusInterfaceMethodHandlerWithErrorAndMessage 191 // which is almost identical to SimpleDBusInterfaceMethodHandlerWithError with 192 // the exception that the callback takes an additional parameter - raw D-Bus 193 // message used to invoke the method handler. 194 // The handler is expected to take an arbitrary number of arguments of type 195 // |Args...| which can contain both inputs (passed in by value or constant 196 // reference) and outputs (passed in as pointers)... 197 // In case of an error, the handler must return false and set the error details 198 // into the |error| object provided. 199 // The signature of the callback handler is expected to be: 200 // bool(ErrorPtr*, dbus::Message*, Args...) 201 template<typename... Args> 202 class SimpleDBusInterfaceMethodHandlerWithErrorAndMessage 203 : public DBusInterfaceMethodHandlerInterface { 204 public: 205 // A constructor that takes a |handler| to be called when HandleMethod() 206 // virtual function is invoked. SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(const base::Callback<bool (ErrorPtr *,::dbus::Message *,Args...)> & handler)207 explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage( 208 const base::Callback<bool(ErrorPtr*, ::dbus::Message*, Args...)>& handler) 209 : handler_(handler) {} 210 HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)211 void HandleMethod(::dbus::MethodCall* method_call, 212 ResponseSender sender) override { 213 DBusMethodResponseBase method_response(method_call, sender); 214 auto invoke_callback = 215 [this, method_call, &method_response](const Args&... args) { 216 ErrorPtr error; 217 if (!handler_.Run(&error, method_call, args...)) { 218 method_response.ReplyWithError(error.get()); 219 } else { 220 auto response = method_response.CreateCustomResponse(); 221 ::dbus::MessageWriter writer(response.get()); 222 DBusParamWriter::AppendDBusOutParams(&writer, args...); 223 method_response.SendRawResponse(std::move(response)); 224 } 225 }; 226 227 ErrorPtr param_reader_error; 228 ::dbus::MessageReader reader(method_call); 229 if (!DBusParamReader<true, Args...>::Invoke( 230 invoke_callback, &reader, ¶m_reader_error)) { 231 // Error parsing method arguments. 232 method_response.ReplyWithError(param_reader_error.get()); 233 } 234 } 235 236 private: 237 // C++ callback to be called when a DBus method is dispatched. 238 base::Callback<bool(ErrorPtr*, ::dbus::Message*, Args...)> handler_; 239 DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithErrorAndMessage); 240 }; 241 242 // An implementation of DBusInterfaceMethodHandlerInterface for more generic 243 // (and possibly asynchronous) method handlers. The handler is expected 244 // to take an arbitrary number of input arguments of type |Args...| and send 245 // the method call response (including a possible error response) using 246 // the provided DBusMethodResponse object. 247 // The signature of the callback handler is expected to be: 248 // void(std::unique_ptr<DBusMethodResponse<RetTypes...>, Args...) 249 template<typename Response, typename... Args> 250 class DBusInterfaceMethodHandler : public DBusInterfaceMethodHandlerInterface { 251 public: 252 // A constructor that takes a |handler| to be called when HandleMethod() 253 // virtual function is invoked. DBusInterfaceMethodHandler(const base::Callback<void (std::unique_ptr<Response>,Args...)> & handler)254 explicit DBusInterfaceMethodHandler( 255 const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler) 256 : handler_(handler) {} 257 258 // This method forwards the call to |handler_| after extracting the required 259 // arguments from the DBus message buffer specified in |method_call|. 260 // The output parameters of |handler_| (if any) are sent back to the called. HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)261 void HandleMethod(::dbus::MethodCall* method_call, 262 ResponseSender sender) override { 263 auto invoke_callback = [this, method_call, &sender](const Args&... args) { 264 std::unique_ptr<Response> response(new Response(method_call, sender)); 265 handler_.Run(std::move(response), args...); 266 }; 267 268 ErrorPtr param_reader_error; 269 ::dbus::MessageReader reader(method_call); 270 if (!DBusParamReader<false, Args...>::Invoke( 271 invoke_callback, &reader, ¶m_reader_error)) { 272 // Error parsing method arguments. 273 DBusMethodResponseBase method_response(method_call, sender); 274 method_response.ReplyWithError(param_reader_error.get()); 275 } 276 } 277 278 private: 279 // C++ callback to be called when a D-Bus method is dispatched. 280 base::Callback<void(std::unique_ptr<Response>, Args...)> handler_; 281 282 DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandler); 283 }; 284 285 // An implementation of DBusInterfaceMethodHandlerWithMessage which is almost 286 // identical to AddSimpleMethodHandlerWithError with the exception that the 287 // callback takes an additional parameter - raw D-Bus message. 288 // The handler is expected to take an arbitrary number of input arguments of 289 // type |Args...| and send the method call response (including a possible error 290 // response) using the provided DBusMethodResponse object. 291 // The signature of the callback handler is expected to be: 292 // void(std::unique_ptr<DBusMethodResponse<RetTypes...>, dbus::Message*, 293 // Args...); 294 template<typename Response, typename... Args> 295 class DBusInterfaceMethodHandlerWithMessage 296 : public DBusInterfaceMethodHandlerInterface { 297 public: 298 // A constructor that takes a |handler| to be called when HandleMethod() 299 // virtual function is invoked. DBusInterfaceMethodHandlerWithMessage(const base::Callback<void (std::unique_ptr<Response>,::dbus::Message *,Args...)> & handler)300 explicit DBusInterfaceMethodHandlerWithMessage( 301 const base::Callback< 302 void(std::unique_ptr<Response>, ::dbus::Message*, Args...)>& handler) 303 : handler_(handler) {} 304 305 // This method forwards the call to |handler_| after extracting the required 306 // arguments from the DBus message buffer specified in |method_call|. 307 // The output parameters of |handler_| (if any) are sent back to the called. HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)308 void HandleMethod(::dbus::MethodCall* method_call, 309 ResponseSender sender) override { 310 auto invoke_callback = [this, method_call, &sender](const Args&... args) { 311 std::unique_ptr<Response> response(new Response(method_call, sender)); 312 handler_.Run(std::move(response), method_call, args...); 313 }; 314 315 ErrorPtr param_reader_error; 316 ::dbus::MessageReader reader(method_call); 317 if (!DBusParamReader<false, Args...>::Invoke( 318 invoke_callback, &reader, ¶m_reader_error)) { 319 // Error parsing method arguments. 320 DBusMethodResponseBase method_response(method_call, sender); 321 method_response.ReplyWithError(param_reader_error.get()); 322 } 323 } 324 325 private: 326 // C++ callback to be called when a D-Bus method is dispatched. 327 base::Callback<void(std::unique_ptr<Response>, ::dbus::Message*, Args...)> 328 handler_; 329 330 DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandlerWithMessage); 331 }; 332 333 // An implementation of DBusInterfaceMethodHandlerInterface that has custom 334 // processing of both input and output parameters. This class is used by 335 // DBusObject::AddRawMethodHandler and expects the callback to be of the 336 // following signature: 337 // void(dbus::MethodCall*, ResponseSender) 338 // It will be up to the callback to parse the input parameters from the 339 // message buffer and construct the D-Bus Response object. 340 class RawDBusInterfaceMethodHandler 341 : public DBusInterfaceMethodHandlerInterface { 342 public: 343 // A constructor that takes a |handler| to be called when HandleMethod() 344 // virtual function is invoked. RawDBusInterfaceMethodHandler(const base::Callback<void (::dbus::MethodCall *,ResponseSender)> & handler)345 RawDBusInterfaceMethodHandler( 346 const base::Callback<void(::dbus::MethodCall*, ResponseSender)>& handler) 347 : handler_(handler) {} 348 HandleMethod(::dbus::MethodCall * method_call,ResponseSender sender)349 void HandleMethod(::dbus::MethodCall* method_call, 350 ResponseSender sender) override { 351 handler_.Run(method_call, sender); 352 } 353 354 private: 355 // C++ callback to be called when a D-Bus method is dispatched. 356 base::Callback<void(::dbus::MethodCall*, ResponseSender)> handler_; 357 358 DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler); 359 }; 360 361 } // namespace dbus_utils 362 } // namespace brillo 363 364 #endif // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ 365