summaryrefslogtreecommitdiff
path: root/brillo/dbus/dbus_object_internal_impl.h
blob: 5f174d42d644fa04dd8695546e1945501e6a991f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file provides internal implementation details of dispatching D-Bus
// method calls to a D-Bus object methods by reading the expected parameter
// values from D-Bus message buffer then invoking a native C++ callback with
// those parameters passed in. If the callback returns a value, that value is
// sent back to the caller of D-Bus method via the response message.

// This is achieved by redirecting the parsing of parameter values from D-Bus
// message buffer to DBusParamReader helper class.
// DBusParamReader de-serializes the parameter values from the D-Bus message
// and calls the provided native C++ callback with those arguments.
// However it expects the callback with a simple signature like this:
//    void callback(Args...);
// The method handlers for DBusObject, on the other hand, have one of the
// following signatures:
//    void handler(Args...);
//    ReturnType handler(Args...);
//    bool handler(ErrorPtr* error, Args...);
//    void handler(std::unique_ptr<DBusMethodResponse<T1, T2,...>>, Args...);
//
// To make this all work, we craft a simple callback suitable for
// DBusParamReader using a lambda in DBusInvoker::Invoke() and redirect the call
// to the appropriate method handler using additional data captured by the
// lambda object.

#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
#define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_

#include <memory>
#include <string>
#include <type_traits>

#include <brillo/dbus/data_serialization.h>
#include <brillo/dbus/dbus_method_response.h>
#include <brillo/dbus/dbus_param_reader.h>
#include <brillo/dbus/dbus_param_writer.h>
#include <brillo/dbus/utils.h>
#include <brillo/errors/error.h>
#include <dbus/message.h>

namespace brillo {
namespace dbus_utils {

// This is an abstract base class to allow dispatching a native C++ callback
// method when a corresponding D-Bus method is called.
class DBusInterfaceMethodHandlerInterface {
 public:
  virtual ~DBusInterfaceMethodHandlerInterface() = default;

  // Returns true if the method has been handled synchronously (whether or not
  // a success or error response message had been sent).
  virtual void HandleMethod(dbus::MethodCall* method_call,
                            ResponseSender sender) = 0;
};

// This is a special implementation of DBusInterfaceMethodHandlerInterface for
// extremely simple synchronous method handlers that cannot possibly fail
// (that is, they do not send an error response).
// The handler is expected to take an arbitrary number of arguments of type
// |Args...| which can contain both inputs (passed in by value or constant
// reference) and outputs (passed in as pointers)...
// It may also return a single value of type R (or could be a void function if
// no return value is to be sent to the caller). If the handler has a return
// value, then it cannot have any output parameters in its parameter list.
// The signature of the callback handler is expected to be:
//    R(Args...)
template<typename R, typename... Args>
class SimpleDBusInterfaceMethodHandler
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit SimpleDBusInterfaceMethodHandler(
      const base::Callback<R(Args...)>& handler) : handler_(handler) {}

  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    DBusMethodResponse<R> method_response(method_call, sender);
    auto invoke_callback = [this, &method_response](const Args&... args) {
      method_response.Return(handler_.Run(args...));
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    // The handler is expected a return value, don't allow output parameters.
    if (!DBusParamReader<false, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a DBus method is dispatched.
  base::Callback<R(Args...)> handler_;
  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
};

// Specialization of SimpleDBusInterfaceMethodHandlerInterface for
// R=void (methods with no return values).
template<typename... Args>
class SimpleDBusInterfaceMethodHandler<void, Args...>
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit SimpleDBusInterfaceMethodHandler(
      const base::Callback<void(Args...)>& handler) : handler_(handler) {}

  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    DBusMethodResponseBase method_response(method_call, sender);
    auto invoke_callback = [this, &method_response](const Args&... args) {
      handler_.Run(args...);
      auto response = method_response.CreateCustomResponse();
      dbus::MessageWriter writer(response.get());
      DBusParamWriter::AppendDBusOutParams(&writer, args...);
      method_response.SendRawResponse(std::move(response));
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    if (!DBusParamReader<true, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a DBus method is dispatched.
  base::Callback<void(Args...)> handler_;
  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
};

// An implementation of DBusInterfaceMethodHandlerInterface for simple
// synchronous method handlers that may fail and return an error response
// message.
// The handler is expected to take an arbitrary number of arguments of type
// |Args...| which can contain both inputs (passed in by value or constant
// reference) and outputs (passed in as pointers)...
// In case of an error, the handler must return false and set the error details
// into the |error| object provided.
// The signature of the callback handler is expected to be:
//    bool(ErrorPtr*, Args...)
template<typename... Args>
class SimpleDBusInterfaceMethodHandlerWithError
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit SimpleDBusInterfaceMethodHandlerWithError(
      const base::Callback<bool(ErrorPtr*, Args...)>& handler)
      : handler_(handler) {}

  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    DBusMethodResponseBase method_response(method_call, sender);
    auto invoke_callback = [this, &method_response](const Args&... args) {
      ErrorPtr error;
      if (!handler_.Run(&error, args...)) {
        method_response.ReplyWithError(error.get());
      } else {
        auto response = method_response.CreateCustomResponse();
        dbus::MessageWriter writer(response.get());
        DBusParamWriter::AppendDBusOutParams(&writer, args...);
        method_response.SendRawResponse(std::move(response));
      }
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    if (!DBusParamReader<true, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a DBus method is dispatched.
  base::Callback<bool(ErrorPtr*, Args...)> handler_;
  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithError);
};

// An implementation of SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
// which is almost identical to SimpleDBusInterfaceMethodHandlerWithError with
// the exception that the callback takes an additional parameter - raw D-Bus
// message used to invoke the method handler.
// The handler is expected to take an arbitrary number of arguments of type
// |Args...| which can contain both inputs (passed in by value or constant
// reference) and outputs (passed in as pointers)...
// In case of an error, the handler must return false and set the error details
// into the |error| object provided.
// The signature of the callback handler is expected to be:
//    bool(ErrorPtr*, dbus::Message*, Args...)
template<typename... Args>
class SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(
      const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>& handler)
      : handler_(handler) {}

  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    DBusMethodResponseBase method_response(method_call, sender);
    auto invoke_callback =
        [this, method_call, &method_response](const Args&... args) {
      ErrorPtr error;
      if (!handler_.Run(&error, method_call, args...)) {
        method_response.ReplyWithError(error.get());
      } else {
        auto response = method_response.CreateCustomResponse();
        dbus::MessageWriter writer(response.get());
        DBusParamWriter::AppendDBusOutParams(&writer, args...);
        method_response.SendRawResponse(std::move(response));
      }
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    if (!DBusParamReader<true, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a DBus method is dispatched.
  base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)> handler_;
  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithErrorAndMessage);
};

// An implementation of DBusInterfaceMethodHandlerInterface for more generic
// (and possibly asynchronous) method handlers. The handler is expected
// to take an arbitrary number of input arguments of type |Args...| and send
// the method call response (including a possible error response) using
// the provided DBusMethodResponse object.
// The signature of the callback handler is expected to be:
//    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, Args...)
template<typename Response, typename... Args>
class DBusInterfaceMethodHandler : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit DBusInterfaceMethodHandler(
      const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler)
      : handler_(handler) {}

  // This method forwards the call to |handler_| after extracting the required
  // arguments from the DBus message buffer specified in |method_call|.
  // The output parameters of |handler_| (if any) are sent back to the called.
  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    auto invoke_callback = [this, method_call, &sender](const Args&... args) {
      std::unique_ptr<Response> response(new Response(method_call, sender));
      handler_.Run(std::move(response), args...);
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    if (!DBusParamReader<false, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      DBusMethodResponseBase method_response(method_call, sender);
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a D-Bus method is dispatched.
  base::Callback<void(std::unique_ptr<Response>, Args...)> handler_;

  DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandler);
};

// An implementation of DBusInterfaceMethodHandlerWithMessage which is almost
// identical to AddSimpleMethodHandlerWithError with the exception that the
// callback takes an additional parameter - raw D-Bus message.
// The handler is expected to take an arbitrary number of input arguments of
// type |Args...| and send the method call response (including a possible error
// response) using the provided DBusMethodResponse object.
// The signature of the callback handler is expected to be:
//    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, dbus::Message*,
//         Args...);
template<typename Response, typename... Args>
class DBusInterfaceMethodHandlerWithMessage
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  explicit DBusInterfaceMethodHandlerWithMessage(
      const base::Callback<void(std::unique_ptr<Response>, dbus::Message*,
                                Args...)>& handler)
      : handler_(handler) {}

  // This method forwards the call to |handler_| after extracting the required
  // arguments from the DBus message buffer specified in |method_call|.
  // The output parameters of |handler_| (if any) are sent back to the called.
  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    auto invoke_callback = [this, method_call, &sender](const Args&... args) {
      std::unique_ptr<Response> response(new Response(method_call, sender));
      handler_.Run(std::move(response), method_call, args...);
    };

    ErrorPtr param_reader_error;
    dbus::MessageReader reader(method_call);
    if (!DBusParamReader<false, Args...>::Invoke(
            invoke_callback, &reader, &param_reader_error)) {
      // Error parsing method arguments.
      DBusMethodResponseBase method_response(method_call, sender);
      method_response.ReplyWithError(param_reader_error.get());
    }
  }

 private:
  // C++ callback to be called when a D-Bus method is dispatched.
  base::Callback<void(std::unique_ptr<Response>,
                      dbus::Message*, Args...)> handler_;

  DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandlerWithMessage);
};

// An implementation of DBusInterfaceMethodHandlerInterface that has custom
// processing of both input and output parameters. This class is used by
// DBusObject::AddRawMethodHandler and expects the callback to be of the
// following signature:
//    void(dbus::MethodCall*, ResponseSender)
// It will be up to the callback to parse the input parameters from the
// message buffer and construct the D-Bus Response object.
class RawDBusInterfaceMethodHandler
    : public DBusInterfaceMethodHandlerInterface {
 public:
  // A constructor that takes a |handler| to be called when HandleMethod()
  // virtual function is invoked.
  RawDBusInterfaceMethodHandler(
      const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler)
      : handler_(handler) {}

  void HandleMethod(dbus::MethodCall* method_call,
                    ResponseSender sender) override {
    handler_.Run(method_call, sender);
  }

 private:
  // C++ callback to be called when a D-Bus method is dispatched.
  base::Callback<void(dbus::MethodCall*, ResponseSender)> handler_;

  DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler);
};

}  // namespace dbus_utils
}  // namespace brillo

#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_