tests/settings_test
config.*
!plugins/connman/config.h
+plugins/connman/settings-agent.conf
!packaging/settingsd.socket
*.tar.*
doc/doxygen
Boston, MA 02110-1301 USA
])
-AC_INIT([settingsd], [0.3], [ossama.othman@intel.com])
+AC_INIT([settingsd], [0.4], [ossama.othman@intel.com])
AM_INIT_AUTOMAKE([1.11.1 foreign -Wall -Werror -Wno-portability silent-rules])
LT_INIT([disable-static dlopen])
* formatted event data.
*/
bool send_event(
- std::function<void(JsonBuilder *)> event_builder);
+ std::function<void(JsonBuilder *)> event_builder) const;
private:
* The appropriate "header" information will be prepended to the
* event.
*/
- unique_ptr<JsonBuilder> begin_event();
+ unique_ptr<JsonBuilder> begin_event() const;
/**
* End the JSON formatted event to the Settings app request.
*/
- void end_event(unique_ptr<JsonBuilder> const & builder);
+ void end_event(unique_ptr<JsonBuilder> const & builder) const;
private:
};
};
-
// GVariant traits specialization.
template<>
struct traits<GVariant>
* JSON formatted response data.
*/
bool send_response(
- std::function<void(JsonBuilder *)> response_builder);
+ std::function<void(JsonBuilder *)> response_builder) const;
/**
* Send error response to Settings app.
*
* @param[in] error_message Free form error message.
*/
- bool send_error(std::string error_message);
+ bool send_error(std::string error_message) const;
/**
* The settings type/ID associated with the request and
*/
void add_string_value(JsonBuilder * builder,
std::string const & name,
- std::string const & value);
+ std::string const & value) const;
/**
* Begin the JSON formatted response to the Settings app
*
* @param[in] result @c "succeeded" or @c "failed"
*/
- unique_ptr<JsonBuilder> begin_response(char const * result);
+ unique_ptr<JsonBuilder> begin_response(char const * result) const;
/**
* End the JSON formatted response to the Settings app request.
*/
- void end_response(unique_ptr<JsonBuilder> const & builder);
+ void end_response(unique_ptr<JsonBuilder> const & builder) const;
private:
* pre-marshalled (in-memory) payload.
*/
bool send_payload(char const * send_type,
- unique_ptr<JsonBuilder> const & builder);
+ unique_ptr<JsonBuilder> const & builder) const;
/**
* Check if the WebSocket instance @a wsi corresponds to this
bool
ivi::settings::event_callback::send_event(
- std::function<void(JsonBuilder *)> event_builder)
+ std::function<void(JsonBuilder *)> event_builder) const
{
unique_ptr<JsonBuilder> const builder = begin_event();
}
ivi::settings::unique_ptr<JsonBuilder>
-ivi::settings::event_callback::begin_event()
+ivi::settings::event_callback::begin_event() const
{
// Construct JSON event string.
unique_ptr<JsonBuilder> safe_builder(json_builder_new());
void
ivi::settings::event_callback::end_event(
- ivi::settings::unique_ptr<JsonBuilder> const & builder)
+ ivi::settings::unique_ptr<JsonBuilder> const & builder) const
{
json_builder_end_object(builder.get());
}
bool
ivi::settings::manager::send_event(
- unique_ptr<JsonBuilder> const & builder)
+ unique_ptr<JsonBuilder> const & builder) const
{
bool success = true;
*
* @return @c true on success.
*/
- bool send_event(unique_ptr<JsonBuilder> const & builder);
+ bool send_event(unique_ptr<JsonBuilder> const & builder) const;
private:
map_type settings_;
/// Mutex used to synchronize access to the send_callback list.
- std::mutex mutex_;
+ mutable std::mutex mutex_;
/**
* List of client WebSockets to be used for sending events to
bool
ivi::settings::response_callback::send_response(
- std::function<void(JsonBuilder *)> response_builder)
+ std::function<void(JsonBuilder *)> response_builder) const
{
unique_ptr<JsonBuilder> const builder = begin_response("succeeded");
}
bool
-ivi::settings::response_callback::send_error(std::string error_message)
+ivi::settings::response_callback::send_error(
+ std::string error_message) const
{
unique_ptr<JsonBuilder> builder = begin_response("failed");
ivi::settings::response_callback::add_string_value(
JsonBuilder * builder,
std::string const & name,
- std::string const & value)
+ std::string const & value) const
{
json_builder_set_member_name(builder, name.c_str());
if (value.empty())
}
ivi::settings::unique_ptr<JsonBuilder>
-ivi::settings::response_callback::begin_response(char const * result)
+ivi::settings::response_callback::begin_response(
+ char const * result) const
{
// Construct JSON response.
unique_ptr<JsonBuilder> safe_builder(json_builder_new());
void
ivi::settings::response_callback::end_response(
- ivi::settings::unique_ptr<JsonBuilder> const & builder)
+ ivi::settings::unique_ptr<JsonBuilder> const & builder) const
{
json_builder_end_object(builder.get());
}
bool
ivi::settings::send_callback::send_payload(
char const * send_type,
- unique_ptr<JsonBuilder> const & builder)
+ unique_ptr<JsonBuilder> const & builder) const
{
unique_ptr<JsonGenerator> const generator(json_generator_new());
unique_ptr<JsonNode> const root(json_builder_get_root(builder.get()));
+* Wed Dec 11 2013 Ossama Othman <ossama.othman@intel.com> accepted/tizen/20131207.002830@9d8e1e0
+- Bump version to 0.4.
+- Fix TIVI-{1191,1192,2108} by implementing a connman 'Agent'.
+
* Wed Dec 04 2013 Ossama Othman <ossama.othman@intel.com> accepted/tizen_ivi_stable/20131119.040308@7e5f66d
- Bump version to 0.3.
- Support technology PropertyChanged signal reporting again.
Name: settingsd
Summary: Tizen IVI Settings Daemon
-Version: 0.3
+Version: 0.4
Release: 1
Group: Application Framework/Settings
License: LGPL-2.1
%{_libdir}/libsettings.so.*
%{pkglibdir}/*.so
%config %{_sysconfdir}/%{name}/*
+%config %{_sysconfdir}/dbus-1/system.d/settings-agent.conf
%{_unitdir_user}/settingsd.service
%{_unitdir_user}/settingsd.socket
%{_unitdir_user}/sockets.target.wants/settingsd.socket
IVI_SETTINGS_PLUGIN_LIBRARY = $(top_builddir)/lib/libsettings.la
-connman_la_SOURCES = \
- dbus_connection.cpp \
- connman.cpp \
- connman_manager.cpp \
- connman_service.cpp \
- connman_technology.cpp \
- service.cpp \
- technology.cpp \
- clock.cpp \
- registration.cpp \
- subscription_manager.cpp
+## The D-Bus name that will be owned by the settings daemon's connman
+## Agent.
+IVI_SETTINGS_CONNMAN_AGENT_DBUS_NAME = \
+ "$(IVI_SETTINGS_DBUS_NAME).connman.Agent"
+
+connman_la_SOURCES = \
+ dbus_connection.cpp \
+ connman.cpp \
+ connman_manager.cpp \
+ connman_service.cpp \
+ connman_technology.cpp \
+ service.cpp \
+ technology.cpp \
+ clock.cpp \
+ agent.cpp \
+ registration.cpp \
+ subscription_manager.cpp \
$(BUILT_SOURCES)
connman_la_CXXFLAGS = \
$(IVI_SETTINGS_PLUGIN_CXXFLAGS) \
connman_la_CFLAGS = \
$(IVI_SETTINGS_PLUGIN_CFLAGS) \
$(GIO_CFLAGS)
-connman_la_CPPFLAGS = $(IVI_SETTINGS_PLUGIN_CPPFLAGS)
+connman_la_CPPFLAGS = \
+ $(IVI_SETTINGS_PLUGIN_CPPFLAGS) \
+ -DIVI_SETTINGS_CONNMAN_AGENT_DBUS_NAME='$(IVI_SETTINGS_CONNMAN_AGENT_DBUS_NAME)'
connman_la_LIBADD = $(IVI_SETTINGS_PLUGIN_LIBRARY)
connman_la_LDFLAGS = -no-undefined \
-module \
service.hpp \
technology.hpp \
clock.hpp \
+ agent.hpp \
subscription_manager.hpp
dbus_codegen_verbose = $(dbus_codegen_verbose_$(V))
agent-glue.c \
agent-glue.h
-CLEANFILES = $(BUILT_SOURCES)
+dbussystemconf_DATA = settings-agent.conf
+dbussystemconfdir = $(sysconfdir)/dbus-1/system.d/
+
+## Silent mode output for settingsd config file generation.
+config_verbose = $(config_verbose_$(V))
+config_verbose_ = $(config_verbose_$(AM_DEFAULT_VERBOSITY))
+config_verbose_0 = @echo CONFGEN $@;
+
+agent_name = $(IVI_SETTINGS_CONNMAN_AGENT_DBUS_NAME)
+
+## The configure script won't fully expand $libdir so leverage `make'
+## based variable expansion instead.
+settings-agent.conf: Makefile settings-agent.conf.in
+ $(config_verbose)rm -f $@ $@.tmp; \
+ srcdir=''; \
+ test -f ./$@.in || srcdir=$(srcdir)/; \
+ sed \
+ -e 's,@agent_name[@],$(agent_name),g' \
+ $${srcdir}$@.in >$@.tmp; \
+ chmod 644 $@.tmp; \
+ mv $@.tmp $@
+
+
+CLEANFILES = $(BUILT_SOURCES) settings-agent.conf
dist-hook:
cd $(distdir); rm -f $(BUILT_SOURCES)
-EXTRA_DIST = agent.xml
+EXTRA_DIST = agent.xml settings-agent.conf.in
--- /dev/null
+/**
+ * @file agent.cpp
+ *
+ * @brief Settings daemon D-Bus connection adapter.
+ *
+ * @author Michael Leibowitz @<michael.leibowitz@@intel.com@>
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @copyright @par
+ * Copyright 2013 Intel Corporation All Rights Reserved.
+ * @par
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ * @par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * @par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "agent.hpp"
+#include "../../lib/config.hpp"
+
+#include <settingsd/glib_traits.hpp>
+#include <settingsd/unique_ptr.hpp>
+
+#include <cstring>
+#include <string>
+#include <algorithm>
+#include <stdexcept>
+
+
+namespace
+{
+ // --------------------------------------------------------------
+ // D-Bus Name Acquisition
+ // --------------------------------------------------------------
+ /**
+ * @brief Callback function invoked when a D-Bus name is acquired.
+ *
+ * @param[in] connection The D-Bus connection on which the name was
+ * acquired.
+ * @param[in] name The name being owned.
+ * @param[in] user_data User-provided data.
+ */
+ void
+ on_name_acquired(GDBusConnection * /* connection */,
+ gchar const * name,
+ gpointer /* user_data */)
+ {
+ g_debug("Name \"%s\" acquired on D-Bus.\n", name);
+ }
+
+ /**
+ * @brief Callback function invoked when a D-Bus name is no longer
+ * owned or the D-Bus connection has been closed.
+ *
+ * @param[in] connection The D-Bus connection on which the name was
+ * acquired.
+ * @param[in] name The name being owned.
+ * @param[in] user_data User-provided data.
+ *
+ */
+ void
+ on_name_lost(GDBusConnection * /* connection */,
+ gchar const * name,
+ gpointer /* user_data */)
+ {
+ // This can happen if the appropriate D-Bus policy is not
+ // installed, for example.
+ throw std::runtime_error(std::string("Lost name \"")
+ + name + "\" on D-Bus!");
+ }
+
+ // --------------------------------------------------------------
+ // Connman Agent Handlers
+ // --------------------------------------------------------------
+ /**
+ * @class agent_operation_handler
+ *
+ * @brief Handle agent operations through given callback.
+ *
+ * This class factors out common connection data retrieval code, and
+ * performs Agent operations through the given callback.
+ */
+ class agent_operation_handler
+ {
+ typedef ivi::settings::agent agent;
+ typedef agent::user_data data_type;
+
+ // Prevent copying.
+ agent_operation_handler(agent_operation_handler const &) = delete;
+ void operator=(agent_operation_handler const &) = delete;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * @param[in] service D-Bus object path for connman service
+ * @param[in] user_data User/connection data
+ * @param[in] callback Callback that implements Agent operation
+ */
+ agent_operation_handler(
+ gchar const * service,
+ gpointer user_data,
+ std::function<void(ivi::settings::agent::connect_data const &)>
+ callback)
+ : data_(static_cast<data_type *>(user_data))
+ , guard_(data_->lock)
+ , iterator_(data_->info.find(service))
+ {
+ // data_ should never be null!
+
+ if (iterator_ != data_->info.end())
+ callback(iterator_->second);
+ }
+
+ /// Destructor
+ ~agent_operation_handler()
+ {
+ // Done with the connection data. Remove it from the map.
+ if (iterator_ != data_->info.end())
+ data_->info.erase(iterator_);
+ }
+
+ private:
+ /// User/connection data.
+ data_type * const data_;
+
+ /**
+ * Synchronize access to the user/connection data map.
+ *
+ * @note This lock will be held for the life of the
+ * @c agent_operation_handler object, i.e. for the duration
+ * of the operation. This is needed to synchronize the map
+ * @c erase() operation in the destructor. The erase()
+ * operation is performed in the destructor to ensure
+ * element removal occurs if an exception is thrown by the
+ * callback.
+ */
+ std::lock_guard<std::mutex> guard_;
+
+ /// Map iterator that points to the connection data.
+ agent::user_data::map_type::iterator const iterator_;
+ };
+
+ bool
+ on_handle_release(Agent * object,
+ GDBusMethodInvocation * invocation,
+ gpointer /* user_data */)
+ {
+ agent_complete_release(object, invocation);
+ return true;
+ }
+
+ bool
+ on_handle_report_error(Agent * object,
+ GDBusMethodInvocation * invocation,
+ gchar const * service,
+ gchar const * error,
+ gpointer user_data)
+ {
+ using ivi::settings::agent;
+
+ agent_operation_handler(service,
+ user_data,
+ [error](agent::connect_data const & d){
+ d.response.send_error(std::string(error));
+ });
+
+ agent_complete_report_error(object, invocation);
+
+ return true;
+ }
+
+ bool
+ on_handle_request_browser(Agent * object,
+ GDBusMethodInvocation * invocation,
+ gchar const * /* service */,
+ gchar const * /* url */,
+ gpointer /* user_data */)
+ {
+ agent_complete_request_browser(object, invocation);
+ return true;
+ }
+
+ bool
+ on_handle_request_input(Agent * object,
+ GDBusMethodInvocation * invocation,
+ gchar const * service,
+ GVariant * fields,
+ gpointer user_data)
+ {
+ using ivi::settings::agent;
+
+ agent_operation_handler(
+ service,
+ user_data,
+ [object, invocation, fields](agent::connect_data const & d){
+ using ivi::settings::unique_ptr;
+
+ // Prepare to build a dictionary, i.e. an array of
+ // dictionary entries, "a{sv}".
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+
+ bool error_occurred = false;
+ bool found_field = false;
+
+ // Extract requested mandatory and alternate fields.
+ GVariantIter * vi = nullptr;
+ g_variant_get(fields, "a{sv}", &vi);
+ unique_ptr<GVariantIter> const iter(vi);
+
+ gchar * fname = nullptr;
+ GVariant * fvalue = nullptr;
+
+ /**
+ * @todo Refactor this GVariant dictionary iteration code.
+ */
+ while (g_variant_iter_next(vi, "{sv}", &fname, &fvalue)) {
+ //
+ unique_ptr<gchar> const field(fname);
+ unique_ptr<GVariant> const arguments(fvalue);
+
+ GVariantIter * ai = nullptr;
+ g_variant_get(arguments.get(), "a{sv}", &ai);
+ unique_ptr<GVariantIter> const iter(ai);
+
+ gchar * argname = nullptr;
+ GVariant * argvalue = nullptr;
+
+ while (g_variant_iter_next(ai, "{sv}", &argname, &argvalue)) {
+ unique_ptr<gchar> const name(argname);
+ unique_ptr<GVariant> const value(argvalue);
+
+ // Determine which requested fields are mandatory.
+ if (strcmp(argname, "Requirement") == 0
+ && strcmp(g_variant_get_string(argvalue, nullptr),
+ "mandatory") == 0) {
+ // Check if we were supplied the required field, and add
+ // it to the dictionary result.
+ auto const i = d.info.find(fname);
+ if (i != d.info.end()) {
+ // Note that the dictionary is of the form a{sv} so
+ // we wrap the dictionary string value in a variant.
+ g_variant_builder_add_value(
+ &builder,
+ g_variant_new_dict_entry(
+ g_variant_new_string(fname),
+ g_variant_new_variant(
+ g_variant_new_string(i->second.c_str()))));
+
+ /**
+ * @todo Is there any way to tell if an entry was
+ * added to the indefinite array being
+ * constructed through the glib GVariant builder
+ * interface? We can't get rid of this flag if
+ * that is the case.
+ */
+ found_field = true;
+ } else {
+ std::string err(
+ std::string("Required connection field \"")
+ + fname
+ + "\" not supplied.");
+
+ /**
+ * @todo This send_error() call is probably
+ * redundant. Look into removing it.
+ */
+ d.response.send_error(err);
+
+ /**
+ * @bug Register a settingsd-specific error during
+ * initialization via
+ * @c g_dbus_error_register_error(), and use it
+ * in this call instead.
+ */
+ g_dbus_method_invocation_return_dbus_error(
+ invocation,
+ "net.connman.Agent.Error.Canceled",
+ err.c_str());
+
+ error_occurred = true;
+
+ return;
+ }
+ }
+ }
+ }
+
+ if (!error_occurred) {
+ GVariant * dictionary = nullptr;
+
+ // We can't call g_variant_builder_end() if no children
+ // (dictionary entries) were added to the indefinite array
+ // being constructed through the builder.
+ if (found_field)
+ dictionary = g_variant_builder_end(&builder);
+
+ // The method return value will contain a dictionary,
+ // i.e. "a{sv}", of the requested input fields.
+ agent_complete_request_input(object, invocation, dictionary);
+ }
+ });
+
+ return true;
+ }
+
+ bool
+ on_handle_cancel(Agent * object,
+ GDBusMethodInvocation * invocation,
+ gpointer /* user_data */)
+ {
+ agent_complete_cancel(object, invocation);
+ return true;
+ }
+}
+
+// ----------------------------------------------------------------
+
+ivi::settings::agent::agent(GDBusConnection * connection)
+ : owner_id_(
+ // The bus name will be of the form:
+ // "org.tizen.settingsd.connman.Agent"
+ g_bus_own_name_on_connection(connection,
+ IVI_SETTINGS_CONNMAN_AGENT_DBUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_name_acquired,
+ on_name_lost,
+ nullptr, // user_data,
+ nullptr))
+ , interface_(agent_skeleton_new())
+ , object_path_("/" IVI_SETTINGS_DBUS_NAME "/connman/Agent")
+ , data_()
+{
+ // Construct object path of the form:
+ // /org/tizen/settingsd/connman/Agent"
+ std::replace(object_path_.begin(), object_path_.end(), '.', '/');
+
+ // Connect the signal handlers corresponding to the Agent
+ // interface.
+ g_signal_connect(interface_,
+ "handle-release",
+ G_CALLBACK(on_handle_release),
+ &data_);
+
+ g_signal_connect(interface_,
+ "handle-report-error",
+ G_CALLBACK(on_handle_report_error),
+ &data_);
+
+ g_signal_connect(interface_,
+ "handle-request-browser",
+ G_CALLBACK(on_handle_request_browser),
+ &data_);
+
+ g_signal_connect(interface_,
+ "handle-request-input",
+ G_CALLBACK(on_handle_request_input),
+ &data_);
+
+ g_signal_connect(interface_,
+ "handle-cancel",
+ G_CALLBACK(on_handle_cancel),
+ &data_);
+
+ // Export the interface on the bus.
+ GError * error = nullptr;
+ if (!g_dbus_interface_skeleton_export(
+ G_DBUS_INTERFACE_SKELETON(interface_),
+ connection,
+ object_path_.c_str(),
+ &error)) {
+ unique_ptr<GError> safe_error(error);
+ throw std::runtime_error(error->message);
+ }
+}
+
+ivi::settings::agent::~agent()
+{
+ if (interface_ != nullptr) {
+ g_dbus_interface_skeleton_unexport(
+ G_DBUS_INTERFACE_SKELETON(interface_));
+ g_object_unref(interface_);
+ }
+
+ g_bus_unown_name(owner_id_);
+}
+
+bool
+ivi::settings::agent::register_connect_data(
+ char const * service_path,
+ std::map<std::string, std::string> && info,
+ response_callback const & response)
+{
+ connect_data data(std::move(info), response);
+
+ std::lock_guard<std::mutex> guard(data_.lock);
+
+ auto const result =
+ data_.info.insert(
+ std::make_pair(service_path, std::move(data)));
+
+ return result.second;
+}
+
+bool
+ivi::settings::agent::deregister_connect_data(char const * service_path)
+{
+ std::lock_guard<std::mutex> guard(data_.lock);
+
+ return data_.info.erase(service_path) == 1;
+}
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/**
+ * @file agent.hpp
+ *
+ * @brief Connman agent implementation header.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @copyright @par
+ * Copyright 2013 Intel Corporation All Rights Reserved.
+ * @par
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * @par
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ * @par
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * @note This is an internal header.
+ */
+
+#ifndef IVI_SETTINGS_AGENT_HPP
+#define IVI_SETTINGS_AGENT_HPP
+
+#include "agent-glue.h"
+
+#include <settingsd/response_callback.hpp>
+
+#include <string>
+#include <map>
+#include <mutex>
+
+
+namespace ivi
+{
+ namespace settings
+ {
+ class agent
+ {
+ public:
+
+ typedef std::map<std::string, std::string> connect_info_map_type;
+
+ /**
+ * Constructor.
+ *
+ * @param[in] connection D-Bus connection on which agent will be
+ * exported.
+ */
+ agent(GDBusConnection *connection);
+
+ /// Destructor.
+ ~agent();
+
+ /**
+ * Register data that may be needed when handling Connman Agent
+ * method calls.
+ */
+ bool register_connect_data(char const * service_path,
+ connect_info_map_type && info,
+ response_callback const & response);
+
+ /**
+ * Deregister connectio data.
+ */
+ bool deregister_connect_data(char const * service_path);
+
+ /// Get D-Bus object path for this @c Agent.
+ char const *
+ object_path() const
+ {
+ return object_path_.c_str();
+ }
+
+ /**
+ * @struct connect_data
+ *
+ * @brief Connman Service object-specific connect data.
+ *
+ * An instance of this structure will be created each time a
+ * Connman connection operation will be performed in case
+ * Connman needs additional information, such as a passphrase,
+ * to complete a connection.
+ */
+ struct connect_data
+ {
+ /**
+ * Constructor.
+ *
+ * @param[in] info_map Map of Connman Agent API field name to
+ * value.
+ * @param[in] resp Callback object through which responses
+ * will be sent to the caller
+ * (e.g. Settings app).
+ */
+ connect_data(connect_info_map_type && info_map,
+ response_callback const & resp)
+ : info(info_map)
+ , response(resp)
+ {
+ }
+
+ /// Move constructor.
+ connect_data(connect_data && other)
+ : info(std::move(other.info))
+ , response(other.response)
+ {
+ }
+
+ /// Disallow copy construction and assignment.
+ connect_data(connect_data const &) = delete;
+ void operator=(connect_data const &) = delete;
+
+ /**
+ * Map of Connman Agent API field name to value.
+ */
+ std::map<std::string, std::string> info;
+
+ /**
+ * The response callback through errors will be sent to the
+ * caller.
+ */
+ response_callback response;
+ };
+
+ /**
+ * @struct user_data
+ *
+ * @brief Wrapper for data passed to Connman Agent method
+ * handlers.
+ */
+ struct user_data
+ {
+ /// Synchronize access to the response/request data map.
+ std::mutex lock;
+
+ typedef std::map<std::string, connect_data> map_type;
+
+ /**
+ * Map of service D-Bus object path to request/response
+ * data.
+ */
+ map_type info;
+ };
+
+ private:
+
+ /**
+ * @name Prevent copying
+ */
+ //@{
+ agent(agent const &) = delete;
+ agent & operator=(agent const &) = delete;
+ //@}
+
+ private:
+
+ /// ID corresponding to owned name on D-Bus system bus.
+ guint const owner_id_;
+
+ /// GDBus Agent skeleton object.
+ Agent * const interface_;
+
+ /// D-Bus object path for this @c Agent.
+ std::string object_path_;
+
+ /// Service connect map, data, etc.
+ user_data data_;
+
+ };
+ }
+}
+
+#endif /* IVI_SETTINGS_AGENT_HPP */
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
<method name="RequestInput">
<arg name="service" direction="in" type="o"/>
<arg name="fields" direction="in" type="a{sv}"/>
+ <arg name="response" direction="out" type="a{sv}"/>
</method>
<method name="Cancel"/>
#include <settingsd/glib_traits.hpp>
#include <settingsd/json_glib_traits.hpp>
#include <settingsd/unique_ptr.hpp>
+#include <settingsd/dbus_signal_callback.hpp>
#include <cstring>
#include <boost/lexical_cast.hpp>
ivi::settings::clock::clock(GDBusConnection * connection,
event_callback const & e)
- : connman_("net.connman.Clock", "/", connection, e)
+ : connman_("net.connman.Clock", "/", connection)
+ , event_callback_(e)
+ , subscription_id_(
+ g_dbus_connection_signal_subscribe(
+ connection,
+ nullptr,
+ connman_.interface_name(),
+ "PropertyChanged",
+ connman_.object_path(),
+ nullptr,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_dbus_signal,
+ &event_callback_,
+ nullptr))
{
}
ivi::settings::clock::~clock()
{
+ g_dbus_connection_signal_unsubscribe(
+ connman_.connection(),
+ subscription_id_);
}
std::string const &
#include "connman.hpp"
#include <settingsd/plugin.hpp>
+#include <settingsd/event_callback.hpp>
#include <json-glib/json-glib.h>
/// Underlying connman proxy.
connman connman_;
+ /// Callback through which events will be sent to clients.
+ event_callback event_callback_;
+
+ /// PropertyChanged signal subscription ID.
+ guint const subscription_id_;
+
};
}
#include <settingsd/glib_traits.hpp>
#include <settingsd/unique_ptr.hpp>
-#include <settingsd/dbus_signal_callback.hpp>
#include <cstring>
#include <string>
ivi::settings::connman::connman(char const * interface,
char const * path,
- GDBusConnection * connection,
- event_callback const & e)
+ GDBusConnection * connection)
: proxy_(nullptr)
- , event_callback_(e)
- , subscription_id_(0)
{
static char const name[] = "net.connman"; // Service
throw std::runtime_error(error->message);
}
-
- // Listen for changes to properties.
- subscription_id_ =
- g_dbus_connection_signal_subscribe(
- connection,
- nullptr,
- interface,
- "PropertyChanged",
- path,
- nullptr,
- G_DBUS_SIGNAL_FLAGS_NONE,
- on_dbus_signal,
- &event_callback_,
- nullptr);
}
ivi::settings::connman::~connman()
{
- if (proxy_ != nullptr) {
- g_dbus_connection_signal_unsubscribe(
- g_dbus_proxy_get_connection(G_DBUS_PROXY(proxy_)),
- subscription_id_);
-
+ if (proxy_ != nullptr)
g_object_unref(proxy_);
- }
}
GVariant *
#ifndef IVI_SETTINGS_CONNMAN_HPP
#define IVI_SETTINGS_CONNMAN_HPP
-#include <settingsd/event_callback.hpp>
-
#include <gio/gio.h>
* @param[in] interface Connman D-Bus interface.
* @param[in] path Connman D-Bus object path.
* @param[in] connection Underlying D-Bus connection.
- * @param[in] e Callback through which events will be
- * sent to clients.
*/
connman(char const * interface,
char const * path,
- GDBusConnection * connection,
- event_callback const & e);
+ GDBusConnection * connection);
/// Destructor.
~connman();
/// The proxy used to access the Connman D-Bus API.
GDBusProxy * proxy_;
- /// Callback through which events will be sent to clients.
- event_callback event_callback_;
-
- /// PropertyChanged signal subscription ID.
- guint subscription_id_;
-
};
}
#include <settingsd/unique_ptr.hpp>
#include <cstring>
+#include <stdexcept>
// ----------------------------------------------------------------------
event_callback const & e)
: connman_("net.connman.Manager", // Interface
"/", // Object path
- connection,
- e)
+ connection)
, data_(connection, e)
, technology_added_id_(subscribe_to_signal(connection,
"TechnologyAdded",
"ServicesChanged",
on_dbus_signal,
&data_.callback))
+ , agent_(connection)
{
// The ServicesChanged signal parameters are:
//
* method.
*/
// Subscribe to PropertyChanged signal for all technologies.
- constexpr gint const timeout = 5000; // milliseconds
GError * error = nullptr;
unique_ptr<GVariant> const dictionary(
- g_dbus_proxy_call_sync(connman_.proxy(),
- "GetTechnologies",
- nullptr, // No parameters
- G_DBUS_CALL_FLAGS_NONE,
- timeout,
- nullptr, // Not cancellable
- &error));
+ call_method("GetTechnologies",
+ nullptr, // No parameters,
+ error));
+
unique_ptr<GError> safe_error(error);
if (dictionary != nullptr) {
tech_path);
}
}
+
+ // Register the Agent implementation responsible for handling input
+ // requests for secure and hidden networks.
+ if (!g_variant_is_object_path(agent_.object_path())) {
+ throw std::runtime_error(std::string("Invalid Agent object path: ")
+ + agent_.object_path());
+ }
+
+ error = nullptr;
+ unique_ptr<GVariant> const ret(
+ call_method("RegisterAgent",
+ g_variant_new("(o)",
+ agent_.object_path()),
+ error));
+
+ if (ret == nullptr) {
+ safe_error.reset(error);
+
+ throw std::runtime_error(
+ std::string("Unable to register agent: ") + error->message);
+ }
}
ivi::settings::connman_manager::~connman_manager()
{
+ // Unregister agent.
+ if (g_variant_is_object_path(agent_.object_path())) {
+ GError * error = nullptr;
+
+ unique_ptr<GVariant> const ret(
+ call_method("UnregisterAgent",
+ g_variant_new("(o)",
+ agent_.object_path()),
+ error));
+
+ if (ret == nullptr) {
+ unique_ptr<GError> const safe_error(error);
+
+ g_warning("Unable to unregister agent: %s\n", error->message);
+ }
+ }
+
+ // Unsubscribe from ServicesChanged, TechnologyRemoved and
+ // TechnologyAdded signals.
g_dbus_connection_signal_unsubscribe(connman_.connection(),
services_changed_id_);
g_dbus_connection_signal_unsubscribe(connman_.connection(),
}
}
+bool
+ivi::settings::connman_manager::register_connect_data(
+ char const * service_path,
+ std::map<std::string, std::string> && info,
+ response_callback const & response)
+{
+ return agent_.register_connect_data(service_path,
+ std::move(info),
+ response);
+}
+
+bool
+ivi::settings::connman_manager::deregister_connect_data(
+ char const * service_path)
+{
+ return agent_.deregister_connect_data(service_path);
+}
+
GVariant *
ivi::settings::connman_manager::get_properties(
std::string const & technology,
GError *& error) const
{
- constexpr gint const timeout = 5000; // milliseconds
-
unique_ptr<GVariant> const dictionary(
- g_dbus_proxy_call_sync(connman_.proxy(),
- "GetTechnologies",
- nullptr, // No parameters
- G_DBUS_CALL_FLAGS_NONE,
- timeout,
- nullptr, // Not cancellable
- &error));
+ call_method("GetTechnologies",
+ nullptr, // No parameters,
+ error));
if (dictionary != nullptr) {
GVariantIter * i = nullptr;
unique_ptr<GVariant> const tmp(
g_variant_get_child_value(child.get(), 0));
- char const * object =
+ char const * const object =
g_variant_get_string(tmp.get(), nullptr);
// The technology is found at end the object path,
ivi::settings::connman_manager::get_services(
response_callback & response) const
{
- call_method("GetServices", response);
+ constexpr char name[] = "GetServices";
+ GError * error = nullptr;
+
+ unique_ptr<GVariant> ret(call_method(name,
+ nullptr, // No parameters
+ error));
+
+ unique_ptr<GError> safe_error(error);
+
+ handle_return_value(name, ret.get(), error, response);
}
void
ivi::settings::connman_manager::get_technologies(
response_callback & response) const
{
- call_method("GetTechnologies", response);
+ constexpr char name[] = "GetTechnologies";
+ GError * error = nullptr;
+
+ unique_ptr<GVariant> ret(call_method(name,
+ nullptr, // No parameters
+ error));
+
+ unique_ptr<GError> safe_error(error);
+
+ handle_return_value(name, ret.get(), error, response);
}
-void
+GVariant *
ivi::settings::connman_manager::call_method(
char const * name,
- response_callback & response) const
+ GVariant * parameters,
+ GError *& error) const
{
constexpr gint const timeout = 5000; // milliseconds
- GError * error = nullptr;
- unique_ptr<GVariant> ret(
+ return
g_dbus_proxy_call_sync(connman_.proxy(),
name,
- nullptr, // No parameters
+ parameters,
G_DBUS_CALL_FLAGS_NONE,
timeout,
nullptr, // Not cancellable
- &error));
-
- unique_ptr<GError> safe_error(error);
+ &error);
+}
+void
+ivi::settings::connman_manager::handle_return_value(
+ char const * name,
+ GVariant * ret,
+ GError * error,
+ response_callback & response) const
+{
if (ret != nullptr) {
response.send_response(
- [&ret](JsonBuilder * builder)
+ [ret](JsonBuilder * builder)
{
/**
* @todo Can @c json_gvariant_serialize() ever return a nullptr?
*/
JsonNode * const value =
- json_gvariant_serialize(ret.get());
+ json_gvariant_serialize(ret);
json_builder_set_member_name(builder, "value");
json_builder_add_value(builder, value);
nullptr);
}
-
// Local Variables:
// mode:c++
// c-basic-offset:2
#include "connman.hpp"
#include "subscription_manager.hpp"
+#include "agent.hpp"
#include <settingsd/plugin.hpp>
#include <settingsd/event_callback.hpp>
//@}
/**
+ * Register data that may be needed when handling Connman Agent
+ * method calls.
+ */
+ bool register_connect_data(char const * service_path,
+ std::map<std::string, std::string> && info,
+ response_callback const & response);
+
+ /**
+ * Deregister connection data.
+ */
+ bool deregister_connect_data(char const * service_path);
+
+ /**
* Get the properties for a specific technology.
*
* @param[in] technology Connman technology for which properties
void get_technologies(response_callback & response) const;
/**
- * Call the method @a name on the connman Manager object. This
- * method is meant to be used for @c GetServices and
- * @c GetTechnologies requests.
+ * Call the method @a name on the connman Manager object.
+ *
+ * @param[in] name The connman Manager object method
+ * name.
+ * @param[in] parameters Method parameters.
+ * @param[inout] error Pointer to error object containing
+ * failure related information. Caller
+ * must deallocate if it is not null.
*
- * @param[in] name The connman Manager object method
- * name.
- * @param[inout] response Callback used to inform the caller of
- * the results.
+ * @return Variant containing result of underlying Connman
+ * Manager D-Bus call. The caller must release the
+ * returned @c GVariant.
*/
- void call_method(char const * name,
- response_callback & response) const;
+ GVariant * call_method(char const * name,
+ GVariant * parameters,
+ GError *& error) const;
+
+
+ /**
+ * Send response or error to client that initiated the request.
+ */
+ void handle_return_value(char const * name,
+ GVariant * ret,
+ GError * error,
+ response_callback & response) const;
typedef void (*ivi_signal_callback)(GDBusConnection * connection,
char const * sender_name,
/// ServicesChanged signal subscription ID.
guint const services_changed_id_;
+ /**
+ * The connman Agent implemention that handles secure and
+ * hidden network related requests.
+ */
+ agent agent_;
+
};
}
ivi::settings::connman_service::connman_service(
GDBusConnection * connection,
- event_callback const & e)
+ connman_manager & manager)
: connection_(connection)
- , event_callback_(e)
+ , manager_(manager)
{
}
json_reader_end_element(reader);
if (path != nullptr) {
- service s(path, connection_, event_callback_);
- s.handle_request(name, reader, response);
+ service s(path, connection_);
+ s.handle_request(name, reader, manager_, response);
}
}
json_reader_end_member(reader);
#include "connman.hpp"
#include <settingsd/plugin.hpp>
-#include <settingsd/event_callback.hpp>
#include <gio/gio.h>
/// Constructor.
connman_service(GDBusConnection * connection,
- event_callback const & e);
+ connman_manager & manager);
/// Destructor.
~connman_service();
/// The underlying D-Bus connection.
GDBusConnection * const connection_;
- /// Callback through which events will be sent to clients.
- event_callback event_callback_;
+ /**
+ * The object used to register connection information for use
+ * by the Connman Agent.
+ */
+ connman_manager & manager_;
};
ivi::settings::connman_technology::connman_technology(
GDBusConnection * connection,
- connman_manager & manager,
- event_callback const & e)
+ connman_manager & manager)
: connman_("net.connman.Technology", // Interface
"/", // Object path
- connection,
- e)
+ connection)
, manager_(manager)
- , event_callback_(e)
{
}
json_reader_end_element(reader);
if (path != nullptr) {
- technology t(path,
- connman_.connection(),
- manager_,
- event_callback_);
+ technology t(path, connman_.connection(), manager_);
t.handle_request(name, reader, response);
}
}
#include "connman.hpp"
#include <settingsd/plugin.hpp>
-#include <settingsd/event_callback.hpp>
#include <gio/gio.h>
/// Constructor.
connman_technology(GDBusConnection * connection,
- connman_manager & manager,
- event_callback const & e);
+ connman_manager & manager);
/// Destructor.
~connman_technology();
/// The proxy used to access the connman Manager D-Bus API.
connman_manager & manager_;
- /// Callback through which events will be sent to clients.
- event_callback event_callback_;
-
};
}
std::unique_ptr<ivi::settings::plugin> manager(mgr);
std::unique_ptr<ivi::settings::plugin> service(
- new ivi::settings::connman_service(connection, e));
+ new ivi::settings::connman_service(connection, *mgr));
std::unique_ptr<ivi::settings::plugin> technology(
- new ivi::settings::connman_technology(connection, *mgr, e));
+ new ivi::settings::connman_technology(connection, *mgr));
std::unique_ptr<ivi::settings::plugin> clk(
new ivi::settings::clock(connection, e));
ivi::settings::service::service(std::string service_path,
- GDBusConnection * connection,
- event_callback const & e)
+ GDBusConnection * connection)
: connman_("net.connman.Service", // Interface
service_path.c_str(), // Object path
- connection,
- e)
+ connection)
{
}
void
ivi::settings::service::handle_request(char const * name,
JsonReader * reader,
+ connman_manager & manager,
response_callback & response)
{
if (name != nullptr) {
if (strcmp(name, "connect") == 0)
- connect(reader, response);
+ connect(reader, manager, response);
else if (strcmp(name, "disconnect") == 0)
- disconnect(reader, response);
+ disconnect(reader, manager, response);
else {
response.send_error(
std::string("Unrecognized connman service request name: ")
}
void
-ivi::settings::service::connect(JsonReader * /* reader */,
+ivi::settings::service::connect(JsonReader * reader,
+ connman_manager & manager,
response_callback response)
{
+ bool successful_parse = false;
+
+ typedef agent::connect_info_map_type map_type;
+ map_type info;
+
+ // The service connection information is found in the second array
+ // element.
+ if (json_reader_read_element(reader, 1)
+ && json_reader_is_object(reader)) {
+ gint const count = json_reader_count_members(reader);
+ for (gint i = 0; i < count; ++i) {
+ if (json_reader_read_element(reader, i)) {
+ char const * const name = json_reader_get_member_name(reader);
+ char const * const value = json_reader_get_string_value(reader);
+
+ if (name != nullptr && value != nullptr)
+ info.insert(std::make_pair(name, value));
+ }
+ json_reader_end_element(reader);
+ }
+
+ // This cast is safe.
+ if (static_cast<gint>(info.size()) == count) {
+ successful_parse = true;
+ }
+ }
+ json_reader_end_element(reader);
+
+ if (!successful_parse) {
+ response.send_error("Unable to parse service connection information.");
+ return;
+ }
+
+ if (!manager.register_connect_data(connman_.object_path(),
+ std::move(info),
+ response)) {
+ response.send_error("Unable to register connection information.");
+ return;
+ }
+
call_method("Connect", response);
}
void
ivi::settings::service::disconnect(JsonReader * reader,
+ connman_manager & manager,
response_callback response)
{
bool null = false;
}
call_method("Disconnect", response);
+
+ manager.deregister_connect_data(connman_.object_path());
}
void
ivi::settings::service::call_method(char const * name,
response_callback response)
{
- constexpr gint const timeout = 10000; // milliseconds
+ constexpr gint const timeout = 15000; // milliseconds
GError * error = nullptr;
unique_ptr<GVariant> const ret(
* sent to clients.
*/
service(std::string service_path,
- GDBusConnection * connection,
- event_callback const & e);
+ GDBusConnection * connection);
/**
* Handle connman Service object request.
*/
void handle_request(char const * name,
JsonReader * reader,
+ connman_manager & manager,
response_callback & response);
private:
/// Connect to the service.
void connect(JsonReader * reader,
+ connman_manager & manager,
response_callback response);
/// Disconnect from the service.
void disconnect(JsonReader * reader,
+ connman_manager & manager,
response_callback response);
/**
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<!-- D-Bus policy for settingsd connman Agent implementation. -->
+<busconfig>
+ <policy context="default">
+ <allow own=@agent_name@/>
+ <allow send_destination=@agent_name@/>
+ <allow send_destination="net.connman"
+ send_interface="net.connman.Manager"/>
+ </policy>
+</busconfig>
#include "technology.hpp"
#include "connman_manager.hpp"
-#include "service.hpp"
#include <settingsd/response_callback.hpp>
#include <settingsd/glib_traits.hpp>
ivi::settings::technology::technology(char const * path,
GDBusConnection * connection,
- connman_manager & manager,
- event_callback const & e)
+ connman_manager & manager)
: connman_("net.connman.Technology", // Interface
path, // Object path
- connection,
- e)
+ connection)
, manager_(manager)
- , event_callback_(e)
{
}
* @param[in] path The connman technology object path.
* @param[in] connection Underlying D-Bus connection.
* @param[in] manager Connman manager proxy.
- * @param[in] e Callback through which events will be
- * sent to clients.
*/
technology(char const * path,
GDBusConnection * connection,
- connman_manager & manager,
- event_callback const & e);
-
+ connman_manager & manager);
/**
* Handle connman technology-specific request.
/// The proxy used to access the connman Manager D-Bus API.
connman_manager & manager_;
- /// Callback through which events will be sent to clients.
- event_callback event_callback_;
-
};
}