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