1// Copyright (c) 2012 The Chromium 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#ifndef DBUS_EXPORTED_OBJECT_H_
6#define DBUS_EXPORTED_OBJECT_H_
7
8#include <dbus/dbus.h>
9
10#include <map>
11#include <string>
12#include <utility>
13
14#include "base/callback.h"
15#include "base/memory/ref_counted.h"
16#include "base/synchronization/waitable_event.h"
17#include "base/threading/platform_thread.h"
18#include "base/time/time.h"
19#include "dbus/dbus_export.h"
20#include "dbus/object_path.h"
21
22namespace dbus {
23
24class Bus;
25class MethodCall;
26class Response;
27class Signal;
28
29// ExportedObject is used to export objects and methods to other D-Bus
30// clients.
31//
32// ExportedObject is a ref counted object, to ensure that |this| of the
33// object is alive when callbacks referencing |this| are called.
34class CHROME_DBUS_EXPORT ExportedObject
35    : public base::RefCountedThreadSafe<ExportedObject> {
36 public:
37  // Client code should use Bus::GetExportedObject() instead of this
38  // constructor.
39  ExportedObject(Bus* bus, const ObjectPath& object_path);
40
41  // Called to send a response from an exported method. |response| is the
42  // response message. Callers should pass NULL in the event of an error that
43  // prevents the sending of a response.
44  typedef base::Callback<void (scoped_ptr<Response> response)> ResponseSender;
45
46  // Called when an exported method is called. |method_call| is the request
47  // message. |sender| is the callback that's used to send a response.
48  //
49  // |method_call| is owned by ExportedObject, hence client code should not
50  // delete |method_call|.
51  typedef base::Callback<void (MethodCall* method_call, ResponseSender sender)>
52      MethodCallCallback;
53
54  // Called when method exporting is done.
55  // |success| indicates whether exporting was successful or not.
56  typedef base::Callback<void (const std::string& interface_name,
57                               const std::string& method_name,
58                               bool success)>
59      OnExportedCallback;
60
61  // Exports the method specified by |interface_name| and |method_name|,
62  // and blocks until exporting is done. Returns true on success.
63  //
64  // |method_call_callback| will be called in the origin thread, when the
65  // exported method is called. As it's called in the origin thread,
66  // |method_callback| can safely reference objects in the origin thread
67  // (i.e. UI thread in most cases).
68  //
69  // IMPORTANT NOTE: You should export all methods before requesting a
70  // service name by Bus::RequestOwnership/AndBlock(). If you do it in the
71  // wrong order (i.e. request a service name then export methods), there
72  // will be a short time period where your service is unable to respond to
73  // method calls because these methods aren't yet exposed. This race is a
74  // real problem as clients may start calling methods of your service as
75  // soon as you acquire a service name, by watching the name owner change.
76  //
77  // BLOCKING CALL.
78  virtual bool ExportMethodAndBlock(const std::string& interface_name,
79                                    const std::string& method_name,
80                                    MethodCallCallback method_call_callback);
81
82  // Requests to export the method specified by |interface_name| and
83  // |method_name|. See Also ExportMethodAndBlock().
84  //
85  // |on_exported_callback| is called when the method is exported or
86  // failed to be exported, in the origin thread.
87  //
88  // Must be called in the origin thread.
89  virtual void ExportMethod(const std::string& interface_name,
90                            const std::string& method_name,
91                            MethodCallCallback method_call_callback,
92                            OnExportedCallback on_exported_callback);
93
94  // Requests to send the signal from this object. The signal will be sent
95  // asynchronously from the message loop in the D-Bus thread.
96  virtual void SendSignal(Signal* signal);
97
98  // Unregisters the object from the bus. The Bus object will take care of
99  // unregistering so you don't have to do this manually.
100  //
101  // BLOCKING CALL.
102  virtual void Unregister();
103
104 protected:
105  // This is protected, so we can define sub classes.
106  virtual ~ExportedObject();
107
108 private:
109  friend class base::RefCountedThreadSafe<ExportedObject>;
110
111  // Helper function for ExportMethod().
112  void ExportMethodInternal(const std::string& interface_name,
113                            const std::string& method_name,
114                            MethodCallCallback method_call_callback,
115                            OnExportedCallback exported_callback);
116
117  // Called when the object is exported.
118  void OnExported(OnExportedCallback on_exported_callback,
119                  const std::string& interface_name,
120                  const std::string& method_name,
121                  bool success);
122
123  // Helper function for SendSignal().
124  void SendSignalInternal(base::TimeTicks start_time,
125                          DBusMessage* signal_message);
126
127  // Registers this object to the bus.
128  // Returns true on success, or the object is already registered.
129  //
130  // BLOCKING CALL.
131  bool Register();
132
133  // Handles the incoming request messages and dispatches to the exported
134  // methods.
135  DBusHandlerResult HandleMessage(DBusConnection* connection,
136                                  DBusMessage* raw_message);
137
138  // Runs the method. Helper function for HandleMessage().
139  void RunMethod(MethodCallCallback method_call_callback,
140                 scoped_ptr<MethodCall> method_call,
141                 base::TimeTicks start_time);
142
143  // Callback invoked by service provider to send a response to a method call.
144  // Can be called immediately from a MethodCallCallback to implement a
145  // synchronous service or called later to implement an asynchronous service.
146  void SendResponse(base::TimeTicks start_time,
147                    scoped_ptr<MethodCall> method_call,
148                    scoped_ptr<Response> response);
149
150  // Called on completion of the method run from SendResponse().
151  // Takes ownership of |method_call| and |response|.
152  void OnMethodCompleted(scoped_ptr<MethodCall> method_call,
153                         scoped_ptr<Response> response,
154                         base::TimeTicks start_time);
155
156  // Called when the object is unregistered.
157  void OnUnregistered(DBusConnection* connection);
158
159  // Redirects the function call to HandleMessage().
160  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
161                                              DBusMessage* raw_message,
162                                              void* user_data);
163
164  // Redirects the function call to OnUnregistered().
165  static void OnUnregisteredThunk(DBusConnection* connection,
166                                  void* user_data);
167
168  scoped_refptr<Bus> bus_;
169  ObjectPath object_path_;
170  bool object_is_registered_;
171
172  // The method table where keys are absolute method names (i.e. interface
173  // name + method name), and values are the corresponding callbacks.
174  typedef std::map<std::string, MethodCallCallback> MethodTable;
175  MethodTable method_table_;
176};
177
178}  // namespace dbus
179
180#endif  // DBUS_EXPORTED_OBJECT_H_
181