5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <connman/agent.h>
32 #include <connman/setting.h>
36 static DBusConnection *connection = NULL;
37 static guint agent_watch = 0;
38 static gchar *agent_path = NULL;
39 static gchar *agent_sender = NULL;
41 struct connman_agent {
45 DBusPendingCall *call;
47 agent_queue_cb callback;
48 struct connman_agent_driver *driver;
51 static GList *agent_queue = NULL;
52 static struct connman_agent *agent_request = NULL;
53 static GSList *driver_list = NULL;
55 void connman_agent_get_info(const char **sender, const char **path)
57 *sender = agent_sender;
61 static void agent_data_free(struct connman_agent *data)
65 if (data->user_context != NULL) {
66 if (data->driver != NULL && data->driver->context_unref != NULL)
67 data->driver->context_unref(data->user_context);
69 if (data->msg != NULL)
70 dbus_message_unref(data->msg);
71 if (data->call != NULL)
72 dbus_pending_call_cancel(data->call);
77 static void agent_receive_message(DBusPendingCall *call, void *user_data);
79 static int agent_send_next_request(void)
81 if (agent_request != NULL)
84 if (agent_queue == NULL)
87 agent_request = agent_queue->data;
88 agent_queue = g_list_remove(agent_queue, agent_request);
90 if (dbus_connection_send_with_reply(connection, agent_request->msg,
92 agent_request->timeout) == FALSE)
95 if (agent_request->call == NULL)
98 if (dbus_pending_call_set_notify(agent_request->call,
99 agent_receive_message, agent_request, NULL) == FALSE)
102 dbus_message_unref(agent_request->msg);
103 agent_request->msg = NULL;
107 agent_data_free(agent_request);
108 agent_request = NULL;
112 static int agent_send_cancel(struct connman_agent *agent)
114 DBusMessage *message;
116 if (agent_sender == NULL || agent == NULL || agent->driver == NULL)
119 message = dbus_message_new_method_call(agent_sender, agent_path,
120 agent->driver->interface, "Cancel");
121 if (message != NULL) {
122 dbus_message_set_no_reply(message, TRUE);
123 g_dbus_send_message(connection, message);
127 connman_warn("Failed to send Cancel message to agent");
131 static void agent_receive_message(DBusPendingCall *call, void *user_data)
133 struct connman_agent *queue_data = user_data;
137 DBG("waiting for %p received %p", agent_request, queue_data);
139 if (agent_request != queue_data) {
140 connman_error("Agent callback expected %p got %p",
141 agent_request, queue_data);
145 reply = dbus_pending_call_steal_reply(call);
146 dbus_pending_call_unref(call);
147 queue_data->call = NULL;
149 if (dbus_message_is_error(reply,
150 "org.freedesktop.DBus.Error.Timeout") == TRUE ||
151 dbus_message_is_error(reply,
152 "org.freedesktop.DBus.Error.TimedOut") == TRUE) {
153 agent_send_cancel(queue_data->user_context);
156 queue_data->callback(reply, queue_data->user_data);
157 dbus_message_unref(reply);
159 agent_data_free(queue_data);
160 agent_request = NULL;
162 err = agent_send_next_request();
164 DBG("send next request failed (%s/%d)", strerror(-err), -err);
167 static struct connman_agent_driver *get_driver(void)
169 return g_slist_nth_data(driver_list, 0);
172 int connman_agent_queue_message(void *user_context,
173 DBusMessage *msg, int timeout,
174 agent_queue_cb callback, void *user_data)
176 struct connman_agent *queue_data;
177 struct connman_agent_driver *driver;
180 if (user_context == NULL || callback == NULL)
183 queue_data = g_new0(struct connman_agent, 1);
184 if (queue_data == NULL)
187 driver = get_driver();
188 DBG("driver %p", driver);
190 if (driver != NULL && driver->context_ref != NULL)
191 queue_data->user_context = driver->context_ref(user_context);
193 queue_data->user_context = user_context;
195 queue_data->msg = dbus_message_ref(msg);
196 queue_data->timeout = timeout;
197 queue_data->callback = callback;
198 queue_data->user_data = user_data;
199 agent_queue = g_list_append(agent_queue, queue_data);
201 err = agent_send_next_request();
203 DBG("send next request failed (%s/%d)", strerror(-err), -err);
208 void connman_agent_cancel(void *user_context)
211 struct connman_agent *queued_req;
214 DBG("context %p", user_context);
218 while (item != NULL) {
219 next = g_list_next(item);
220 queued_req = item->data;
222 if (queued_req->user_context == user_context ||
223 user_context == NULL) {
224 agent_data_free(queued_req);
225 agent_queue = g_list_delete_link(agent_queue, item);
231 if (agent_request == NULL)
234 if (agent_request->user_context != user_context &&
235 user_context != NULL)
238 agent_send_cancel(agent_request);
240 agent_data_free(agent_request);
241 agent_request = NULL;
243 err = agent_send_next_request();
245 DBG("send next request failed (%s/%d)", strerror(-err), -err);
248 static void agent_free(void)
251 g_dbus_remove_watch(connection, agent_watch);
255 g_free(agent_sender);
261 connman_agent_cancel(NULL);
264 static void agent_disconnect(DBusConnection *conn, void *data)
266 DBG("data %p", data);
270 int connman_agent_register(const char *sender, const char *path)
272 DBG("sender %s path %s", sender, path);
273 if (agent_path != NULL)
276 agent_sender = g_strdup(sender);
277 agent_path = g_strdup(path);
279 agent_watch = g_dbus_add_disconnect_watch(connection, sender,
280 agent_disconnect, NULL, NULL);
285 int connman_agent_unregister(const char *sender, const char *path)
287 DBG("sender %s path %s", sender, path);
289 if (agent_path == NULL)
293 g_dbus_remove_watch(connection, agent_watch);
300 struct report_error_data {
302 report_error_cb_t callback;
306 static void report_error_reply(DBusMessage *reply, void *user_data)
308 struct report_error_data *report_error = user_data;
309 gboolean retry = FALSE;
310 const char *dbus_err;
312 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
313 dbus_err = dbus_message_get_error_name(reply);
314 if (dbus_err != NULL &&
316 CONNMAN_AGENT_INTERFACE ".Error.Retry") == 0)
320 report_error->callback(report_error->user_context, retry,
321 report_error->user_data);
322 g_free(report_error);
325 int connman_agent_report_error(void *user_context, const char *path,
327 report_error_cb_t callback, void *user_data)
329 DBusMessage *message;
330 DBusMessageIter iter;
331 struct report_error_data *report_error;
334 if (user_context == NULL || agent_path == NULL || error == NULL ||
338 message = dbus_message_new_method_call(agent_sender, agent_path,
339 CONNMAN_AGENT_INTERFACE,
344 dbus_message_iter_init_append(message, &iter);
346 dbus_message_iter_append_basic(&iter,
347 DBUS_TYPE_OBJECT_PATH, &path);
348 dbus_message_iter_append_basic(&iter,
349 DBUS_TYPE_STRING, &error);
351 report_error = g_try_new0(struct report_error_data, 1);
352 if (report_error == NULL) {
353 dbus_message_unref(message);
357 report_error->user_context = user_context;
358 report_error->callback = callback;
359 report_error->user_data = user_data;
361 err = connman_agent_queue_message(user_context, message,
362 connman_timeout_input_request(),
363 report_error_reply, report_error);
364 if (err < 0 && err != -EBUSY) {
365 DBG("error %d sending error request", err);
366 g_free(report_error);
367 dbus_message_unref(message);
371 dbus_message_unref(message);
376 static gint compare_priority(gconstpointer a, gconstpointer b)
378 const struct connman_agent_driver *driver1 = a;
379 const struct connman_agent_driver *driver2 = b;
381 return driver2->priority - driver1->priority;
385 * connman_agent_driver_register:
386 * @driver: Agent driver definition
388 * Register a new agent driver
390 * Returns: %0 on success
392 int connman_agent_driver_register(struct connman_agent_driver *driver)
394 DBG("Registering driver %p name %s", driver, driver->name);
396 driver_list = g_slist_insert_sorted(driver_list, driver,
403 * connman_agent_driver_unregister:
404 * @driver: Agent driver definition
406 * Remove a previously registered agent driver
408 void connman_agent_driver_unregister(struct connman_agent_driver *driver)
412 DBG("Unregistering driver %p name %s", driver, driver->name);
414 for (list = driver_list; list; list = list->next) {
415 DBusMessage *message;
417 if (driver == list->data)
420 message = dbus_message_new_method_call(agent_sender, agent_path,
421 driver->interface, "Release");
422 if (message != NULL) {
423 dbus_message_set_no_reply(message, TRUE);
424 g_dbus_send_message(connection, message);
430 driver_list = g_slist_remove(driver_list, driver);
433 int __connman_agent_init(void)
437 connection = connman_dbus_get_connection();
438 if (connection == NULL)
444 void __connman_agent_cleanup(void)
448 if (connection == NULL)
452 g_dbus_remove_watch(connection, agent_watch);
454 dbus_connection_unref(connection);