TIVI-1924: Initial commit of IVI settings daemon.
[profile/ivi/settings-daemon.git] / plugins / connman / connman.cpp
1 /**
2  * @file connman.cpp
3  *
4  * @brief Connman-based settings plugin.
5  *
6  * @author Ossama Othman @<ossama.othman@@intel.com@>
7  *
8  * @copyright @par
9  * Copyright 2013 Intel Corporation All Rights Reserved.
10  * @par
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation;
14  * version 2.1 of the License.
15  * @par
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  * @par
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA  02110-1301  USA
25  */
26
27 #include "connman.hpp"
28
29 #include <settingsd/reverse_lock.hpp>
30
31 #include <cstring>
32 #include <string>
33 #include <stdexcept>
34
35
36 namespace
37 {
38   void
39   on_property_changed(GDBusConnection * /* connection */,
40                       char const * /* sender_name */,
41                       char const * /* object_path */,
42                       char const * /* interface_name */,
43                       char const * /* signal_name */,
44                       GVariant   * parameters,
45                       gpointer     user_data)
46   {
47     // Notify callers about the scan results.
48     typedef ivi::settings::connman::user_data user_data_type;
49
50     user_data_type * const data = static_cast<user_data_type *>(user_data);
51
52     std::lock_guard<std::mutex> lock(data->mutex);
53     auto const end = data->promises.end();
54     for (auto i = data->promises.begin(); i != end; ) {
55       gchar    * pname  = nullptr;
56       GVariant * pvalue = nullptr;
57
58       g_variant_get(parameters, "(sv)", &pname, &pvalue);
59
60       using namespace ivi::settings;
61
62       smart_ptr<gchar> name(pname);
63       smart_ptr<GVariant> value(pvalue);
64
65       auto & p = *i;
66
67       // Set the value in the promise if the desired property name
68       // matches.
69       if (strcmp(p.first, pname) == 0) {
70         {
71           // Release the mutex during the promise::set_value()
72           // call/notification so that we don't unnecessarily block
73           // threads attempting to get a property_changed promise.
74           typedef ivi::settings::reverse_lock<std::mutex> reverse_lock;
75           reverse_lock reverse(data->mutex);
76
77           std::lock_guard<reverse_lock> kcol(reverse);
78
79           p.second->set_value(std::move(value));
80         }
81
82         // Done with the pointer to the promise.  Remove it from the
83         // list now since we already have an iterator to it.
84         i = data->promises.erase(i);
85       } else {
86         // Nothing to erase.  Advance to the next list element.
87         ++i;
88       }
89     }
90   }
91 }
92
93 // ---------------------------------------------------------------
94
95 ivi::settings::connman::connman(char const * interface,
96                                 char const * path)
97   : proxy_(nullptr)
98   , mutex_()
99   , promises_()
100   , data_(mutex_, promises_)
101   , subscription_id_(0)
102 {
103   static char const name[] = "net.connman";  // Service
104
105   GError * error = nullptr;
106
107   proxy_ =
108     g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
109                                    G_DBUS_PROXY_FLAGS_NONE,
110                                    nullptr, // GDBusInterfaceInfo
111                                    name,
112                                    path,
113                                    interface,
114                                    nullptr, // GCancellable
115                                    &error);
116
117   smart_ptr<GError> safe_error(error);
118
119   if (proxy_ == nullptr) {
120     g_printerr("Unable to create D-Bus proxy for (\"%s\", \"%s\"): %s\n",
121                interface,
122                path,
123                error->message);
124
125     throw std::runtime_error(error->message);
126   }
127
128   // Listen for changes to properties.
129   subscription_id_ =
130       g_dbus_connection_signal_subscribe(
131         g_dbus_proxy_get_connection(G_DBUS_PROXY(proxy_)),
132         nullptr,
133         interface,
134         "PropertyChanged",
135         path,
136         nullptr,
137         G_DBUS_SIGNAL_FLAGS_NONE,
138         on_property_changed,
139         &data_,
140         nullptr);
141 }
142
143 ivi::settings::connman::~connman()
144 {
145   if (proxy_ != nullptr) {
146     g_dbus_connection_signal_unsubscribe(
147       g_dbus_proxy_get_connection(G_DBUS_PROXY(proxy_)),
148       subscription_id_);
149
150     g_object_unref(proxy_);
151   }
152 }
153
154 GVariant *
155 ivi::settings::connman::set_property(char const * property,
156                                      GVariant * value,
157                                      GError *& error)
158 {
159   static gint const timeout = 5000;  // milliseconds
160
161   return g_dbus_proxy_call_sync(proxy_,
162                                 "SetProperty",     // Method name
163                                 g_variant_new("(sv)",
164                                               property,
165                                               value),
166                                 G_DBUS_CALL_FLAGS_NONE,
167                                 timeout,
168                                 nullptr,  // Not cancellable
169                                 &error);
170 }
171
172 ivi::settings::connman::shared_promise_type
173 ivi::settings::connman::get_property_changed_promise(
174   char const * property)
175 {
176   // This promise must exist long enough for the value to retrieved
177   // from the future.  Use a shared_ptr<> to make that possible.
178   shared_promise_type promise = std::make_shared<promise_type>();
179
180   {
181     std::lock_guard<std::mutex> lock(mutex_);
182
183     // Add a new std::promise to the promises list.  The promise will
184     // only be used once, and will be removed once its value has been
185     // set.
186     promises_.push_back(std::make_pair(property, promise));
187   }
188
189   return promise;
190 }
191
192
193 // Local Variables:
194 // mode:c++
195 // c-basic-offset:2
196 // indent-tabs-mode: nil
197 // End: