blob: d4369111b8175bd3cca32fc671226a6b60e1a9c8 [file] [log] [blame]
/*
*
* Connection Manager
*
* Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <gdbus.h>
#include "connman.h"
#define _DBG_AGENT(fmt, arg...) DBG(DBG_AGENT, fmt, ## arg)
struct connman_agent {
guint watch;
gchar *path;
gchar *sender;
};
static DBusConnection *connection = NULL;
static struct connman_agent *agent = NULL;
static void agent_free(struct connman_agent *a)
{
g_free(a->sender);
g_free(a->path);
g_free(a);
if (a == agent)
agent = NULL;
}
static void agent_disconnect(DBusConnection *connection, void *data)
{
struct connman_agent *agent = data;
_DBG_AGENT("agent %p", agent);
agent_free(agent);
}
int __connman_agent_register(const char *sender, const char *path)
{
_DBG_AGENT("sender %s path %s", sender, path);
if (agent != NULL) {
return -EEXIST;
}
agent = g_try_new0(struct connman_agent, 1);
if (agent == NULL) {
return -ENOMEM;
}
agent->sender = g_strdup(sender);
agent->path = g_strdup(path);
agent->watch = g_dbus_add_disconnect_watch(connection, sender,
agent_disconnect, agent, NULL);
return 0;
}
static void __connman_agent_release(struct connman_agent *agent)
{
DBusMessage *message;
_DBG_AGENT("sender %s path %s", agent->sender, agent->path);
message = dbus_message_new_method_call(agent->sender, agent->path,
CONNMAN_AGENT_INTERFACE, "Release");
if (message != NULL) {
dbus_message_set_no_reply(message, TRUE);
g_dbus_send_message(connection, message);
}
}
int __connman_agent_unregister(const char *sender, const char *path)
{
_DBG_AGENT("sender %s path %s", sender, path);
/* TODO(sleffler) verify sender+path match */
__connman_agent_release(agent);
if (agent->watch > 0)
g_dbus_remove_watch(connection, agent->watch);
agent_free(agent);
return 0;
}
struct request_input_reply {
struct connman_service *service;
connman_agent_cb_t callback;
void *user_data;
};
static void request_input_reply(DBusPendingCall *call, void *user_data)
{
struct request_input_reply *request_reply = user_data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_ERROR) {
DBusMessageIter iter, dict;
dbus_message_iter_init(reply, &iter);
dbus_message_iter_recurse(&iter, &dict);
_DBG_AGENT("service %p user_data %p",
request_reply->service, request_reply->user_data);
request_reply->callback(request_reply->service,
request_reply->user_data,
&dict);
} else {
_DBG_AGENT("ERROR %s, service %p user_data %p",
dbus_message_get_error_name(reply),
request_reply->service, request_reply->user_data);
request_reply->callback(request_reply->service,
request_reply->user_data,
NULL);
}
connman_service_unref(request_reply->service);
dbus_message_unref(reply);
g_free(request_reply);
}
int __connman_agent_request_input(struct connman_service *service,
const char *params[], connman_agent_cb_t callback, void *user_data)
{
DBusMessage *message;
const char *path;
DBusMessageIter iter;
DBusMessageIter dict;
DBusPendingCall *call;
struct request_input_reply *request_reply;
const char *key, *value;
int i;
_DBG_AGENT("agent %p service %p callback %p user_data %p",
agent, service, callback, user_data);
if (agent == NULL) {
connman_error("%s: no agent registered", __func__);
return -EINVAL;
}
message = dbus_message_new_method_call(agent->sender, agent->path,
CONNMAN_AGENT_INTERFACE,
"RequestInput");
if (message == NULL) {
connman_error("%s: no memory", __func__);
return -ENOMEM;
}
dbus_message_iter_init_append(message, &iter);
path = __connman_service_get_path(service);
dbus_message_iter_append_basic(&iter,
DBUS_TYPE_OBJECT_PATH, &path);
connman_dbus_dict_open(&iter, &dict);
for (i = 0; (key = params[i]) != NULL; i += 2) {
value = params[i+1];
if (value == NULL)
value = "";
_DBG_AGENT("key %s value %s", key,
connman_log_get_masked_value(key, value));
connman_dbus_dict_append_basic(&dict, key,
DBUS_TYPE_STRING, &value);
}
connman_dbus_dict_close(&iter, &dict);
request_reply = g_try_new0(struct request_input_reply, 1);
if (request_reply == NULL) {
dbus_message_unref(message);
return -ENOMEM;
}
/* TODO(sleffler) deal with timeouts */
if (dbus_connection_send_with_reply(connection, message,
&call, DBUS_TIMEOUT_INFINITE) == FALSE) {
dbus_message_unref(message);
g_free(request_reply);
return -ESRCH;
}
if (call == NULL) {
dbus_message_unref(message);
g_free(request_reply);
return -ESRCH;
}
_DBG_AGENT("setup notify, reply %p", request_reply);
request_reply->service = connman_service_ref(service);
request_reply->callback = callback;
request_reply->user_data = user_data;
dbus_pending_call_set_notify(call, request_input_reply,
request_reply, NULL);
dbus_message_unref(message);
return 0;
}
int __connman_agent_init(void)
{
_DBG_AGENT("");
connection = connman_dbus_get_connection();
return (connection == NULL ? -1 : 0);
}
void __connman_agent_cleanup(void)
{
_DBG_AGENT("agent %p", agent);
if (agent != NULL)
__connman_agent_unregister(agent->sender, agent->path);
if (connection != NULL)
dbus_connection_unref(connection);
}