[TIVI-2848] Fix tethering configuration.
[profile/ivi/settings-daemon.git] / plugins / connman / technology.cpp
1 /**
2  * @file technology.cpp
3  *
4  * @brief Connman technology request handling.
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 "technology.hpp"
28 #include "connman_manager.hpp"
29
30 #include <settingsd/response_callback.hpp>
31 #include <settingsd/glib_traits.hpp>
32 #include <settingsd/json_glib_traits.hpp>
33 #include <settingsd/unique_ptr.hpp>
34
35 #include <cstring>
36
37 ivi::settings::technology::technology(char const * path,
38                                       GDBusConnection * connection,
39                                       connman_manager & manager)
40   : connman_("net.connman.Technology",     // Interface
41              path,                         // Object path
42              connection)
43   , manager_(manager)
44 {
45 }
46
47 void
48 ivi::settings::technology::handle_request(char const * name,
49                                           JsonReader * reader,
50                                           response_callback & response)
51 {
52   if (name != nullptr) {
53     if (strcmp(name, "is_enabled") == 0)
54       get_powered(reader, response);
55     else if (strcmp(name, "enable") == 0)
56       set_powered(reader, response);
57     else if (strcmp(name, "scan") == 0)
58       scan(reader, response);
59     else if (strcmp(name, "tethering") == 0)
60       set_tethering(reader, response);
61     else {
62       response.send_error(
63         std::string("Unrecognized connman technology request name: ")
64         + name);
65     }
66   }
67 }
68
69 void
70 ivi::settings::technology::get_powered(JsonReader * reader,
71                                        response_callback & response)
72 {
73   bool null = false;
74   // The value is the second array element.
75   if (json_reader_read_element(reader, 1)) {
76     null = json_reader_get_null_value(reader);
77   }
78   json_reader_end_element(reader);
79
80   if (!null) {
81     response.send_error(
82       "connman::technology is_enabled parameter is not null.");
83     return;
84   }
85
86   unique_ptr<GVariant> const property(
87     get_property("Powered", G_VARIANT_TYPE_BOOLEAN, response));
88
89   if (property != nullptr) {
90     bool const powered = g_variant_get_boolean(property.get());
91
92     response.send_response(
93       [powered](JsonBuilder * builder)
94       {
95         json_builder_set_member_name(builder, "value");
96         json_builder_add_boolean_value(builder, powered);
97       });
98   }
99
100   // Error responses handled in get_property() method.
101 }
102
103 void
104 ivi::settings::technology::set_powered(JsonReader * reader,
105                                        response_callback & response)
106 {
107   bool enable = false;
108   // The value is the second array element.
109   if (json_reader_read_element(reader, 1)) {
110     enable = json_reader_get_boolean_value(reader);
111   }
112   json_reader_end_element(reader);
113
114   constexpr char const name[] = "Powered";
115
116   GError * error = nullptr;
117
118   unique_ptr<GVariant> ret(
119     connman_.set_property(name,
120                           g_variant_new_boolean(enable),
121                           error));
122
123   unique_ptr<GError> safe_error(error);
124
125   if (ret != nullptr) {
126       // Nothing to add to successful response.
127       response.send_response(
128         [](JsonBuilder * /* builder */) {});
129   } else if (error != nullptr) {
130     response.send_error(
131       std::string("Unable to set connman::technology powered state: ")
132       + error->message);
133   } else {
134     response.send_error(
135       "Malformed connman::technology enable request value.");
136   }
137 }
138
139 void
140 ivi::settings::technology::set_tethering(JsonReader * reader,
141                                          response_callback & response)
142 {
143   bool const have_enabled = json_reader_read_member(reader, "enabled");
144   bool enabled = false;
145   if (have_enabled) {
146     enabled = json_reader_get_boolean_value(reader);
147     json_reader_end_element(reader);
148   } else {
149     response.send_error(
150       "connman::technology tether \"enabled\" parameter is null.");
151     // We have to call json_reader_end_element() before we return
152     json_reader_end_element(reader);
153     return;
154   }
155
156   unique_ptr<GError> identifier_error;
157   unique_ptr<GError> passphrase_error;
158   bool identifier_res = true;  // Identifier not always needed.
159   bool passphrase_res = true;  // Passphrase not always needed.
160
161   // Check if we have a tethering identifier and passphrase if we are
162   // enabling tethering.
163   if (enabled) {
164     // --------------------
165     // Tethering identifier
166     // --------------------
167     char const * ssid = nullptr;
168     if (json_reader_read_member(reader, "ssid")) {
169       ssid = json_reader_get_string_value(reader);
170     }
171     json_reader_end_element(reader);
172
173     if (ssid != nullptr) {
174       constexpr char const identifier[] = "TetheringIdentifier";
175       GError * error = nullptr;
176       identifier_res = this->set_property(identifier,
177                                           g_variant_new_string(ssid),
178                                           response,
179                                           error);
180       identifier_error.reset(error);
181     }
182
183     // --------------------
184     // Tethering passphrase
185     // --------------------
186     char const * password = nullptr;
187     if (json_reader_read_member(reader, "password")) {
188       password = json_reader_get_string_value(reader);
189     }
190     json_reader_end_element(reader);
191
192     if (password != nullptr) {
193       constexpr char const passphrase[] = "TetheringPassphrase";
194       GError * error = nullptr;
195       passphrase_res = this->set_property(passphrase,
196                                           g_variant_new_string(password),
197                                           response,
198                                           error);
199       passphrase_error.reset(error);
200     }
201   }
202
203   // ----------------
204   // Tethering status
205   // ----------------
206   // Set "enabled" after passphrase and SSID have been set.
207   // Otherwise Connman may issue an invalid argument error.
208   constexpr char const tethering[] = "Tethering";
209   bool enabled_res = false;
210   GError * error = nullptr;
211   enabled_res = this->set_property(tethering,
212                                    g_variant_new_boolean(enabled),
213                                    response,
214                                    error);
215   unique_ptr<GError> enabled_error(error);
216
217   // ----------------------------
218   // Send final response or error
219   // ----------------------------
220   if (enabled_res && identifier_res && passphrase_res) {
221     response.send_response(
222       [enabled](JsonBuilder * builder) {
223         json_builder_set_member_name(builder, "value");
224         json_builder_add_boolean_value(builder, enabled);
225       });
226   } else {
227     char const * failed_part = nullptr;
228     error = nullptr;
229
230     if (!enabled_res) {
231       error = enabled_error.get();
232       failed_part = "status";
233     } else if (!identifier_res) {
234       error = identifier_error.get();
235       failed_part = "identifier";
236     } else if (!passphrase_res) {
237       error = passphrase_error.get();
238       failed_part = "passphrase";
239     }
240
241     if (error != nullptr) {
242       response.send_error(
243         std::string("Unable to set connman::technology tethering ")
244         + failed_part
245         + std::string(": ")
246         + error->message);
247     } else {
248       response.send_error(
249         std::string("Malformed connman::technology tethering ")
250         + failed_part);
251     }
252   }
253 }
254
255 bool
256 ivi::settings::technology::set_property(char const * name,
257                                    GVariant * value,
258                                    response_callback /* response */,
259                                    GError *& error)
260 {
261   unique_ptr<GVariant> const ret(
262     connman_.set_property(name, value, error));
263
264   return ret != nullptr;
265 }
266
267 void
268 ivi::settings::technology::scan(JsonReader * reader,
269                                 response_callback & response)
270 {
271   bool null = false;
272   // The value is the second array element.
273   if (json_reader_read_element(reader, 1)) {
274     null = json_reader_get_null_value(reader);
275   }
276   json_reader_end_element(reader);
277
278   if (!null) {
279     response.send_error(
280       "connman::technology scan parameter is not null.");
281     return;
282   }
283
284   // The scan could take a while.
285   constexpr gint const timeout = 10000;  // milliseconds
286   GError * error = nullptr;
287
288   unique_ptr<GVariant> const ret(
289     g_dbus_proxy_call_sync(connman_.proxy(),
290                            "Scan",
291                            nullptr,  // No parameters
292                            G_DBUS_CALL_FLAGS_NONE,
293                            timeout,
294                            nullptr,  // Not cancellable
295                            &error));
296
297   unique_ptr<GError> safe_error(error);
298
299   if (ret != nullptr) {
300     manager_.get_services(response);
301   } else if (error != nullptr) {
302     response.send_error(
303       std::string("Unable to scan connman::technology: ")
304       + error->message);
305   } else {
306     response.send_error(
307       "Malformed connman::technology scan request value.");
308   }
309 }
310
311 GVariant *
312 ivi::settings::technology::get_property(char const * name,
313                                         GVariantType const * type,
314                                         response_callback & response)
315 {
316   GError * error = nullptr;
317
318   std::string tech(connman_.object_path());
319   auto const n = tech.rfind('/');
320   if (n == std::string::npos) {
321     response.send_error(
322       "Unable to determine Connman technology.  Malformed object path.");
323
324     return nullptr;
325   }
326
327   tech = tech.substr(n + 1);
328
329   unique_ptr<GVariant> const properties(
330     manager_.get_properties(tech.c_str(), error));
331
332   unique_ptr<GError> safe_error(error);
333
334   unique_ptr<GVariant> property;
335   if (properties != nullptr) {
336     property.reset(
337       g_variant_lookup_value(properties.get(), name, type));
338
339     if (property == nullptr) {
340       response.send_error(
341         "Internal " + tech
342         + "error: \"" + name + "\" property lookup failed.");
343     }
344   } else if (error != nullptr) {
345     response.send_error(
346       "Unable to get " + tech + "properties: "
347       + error->message);
348   } else {
349     // This scenario will occur if the technology doesn't exist on
350     // the platform.  For example, attempting to retrieve the wifi
351     // "Powered" property on a platform without supported hardware
352     // will result in this error.
353     response.send_error(
354       "Connman technology properties are not available.");
355   }
356
357   return property.release();
358 }
359
360
361 // Local Variables:
362 // mode:c++
363 // c-basic-offset:2
364 // indent-tabs-mode: nil
365 // End: