session: Refactor session API
[framework/connectivity/connman.git] / src / session.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  BWM CarIT GmbH. All rights reserved.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 static DBusConnection *connection;
32 static GHashTable *session_hash;
33 static connman_bool_t sessionmode;
34
35 struct connman_session {
36         char *owner;
37         char *session_path;
38         char *notify_path;
39         guint notify_watch;
40 };
41
42 static gboolean session_notify_all(gpointer user_data)
43 {
44         struct connman_session *session = user_data;
45         DBusMessage *msg;
46         DBusMessageIter array, dict;
47
48         DBG("session %p owner %s notify_path %s", session,
49                 session->owner, session->notify_path);
50
51         msg = dbus_message_new_method_call(session->owner, session->notify_path,
52                                                 CONNMAN_NOTIFICATION_INTERFACE,
53                                                 "Update");
54         if (msg == NULL) {
55                 connman_error("Could not create notification message");
56                 return FALSE;
57         }
58
59         dbus_message_iter_init_append(msg, &array);
60
61         connman_dbus_dict_open(&array, &dict);
62
63         /* append settings */
64
65         connman_dbus_dict_close(&array, &dict);
66
67         g_dbus_send_message(connection, msg);
68
69         return FALSE;
70 }
71
72 static void cleanup_session(gpointer user_data)
73 {
74         struct connman_session *session = user_data;
75
76         DBG("remove %s", session->session_path);
77
78         g_free(session->owner);
79         g_free(session->session_path);
80         g_free(session->notify_path);
81
82         g_free(session);
83 }
84
85 static void release_session(gpointer key, gpointer value, gpointer user_data)
86 {
87         struct connman_session *session = value;
88         DBusMessage *message;
89
90         DBG("owner %s path %s", session->owner, session->notify_path);
91
92         if (session->notify_watch > 0)
93                 g_dbus_remove_watch(connection, session->notify_watch);
94
95         g_dbus_unregister_interface(connection, session->session_path,
96                                                 CONNMAN_SESSION_INTERFACE);
97
98         message = dbus_message_new_method_call(session->owner,
99                                                 session->notify_path,
100                                                 CONNMAN_NOTIFICATION_INTERFACE,
101                                                 "Release");
102         if (message == NULL)
103                 return;
104
105         dbus_message_set_no_reply(message, TRUE);
106
107         g_dbus_send_message(connection, message);
108 }
109
110 static int session_disconnect(struct connman_session *session)
111 {
112         DBG("session %p, %s", session, session->owner);
113
114         if (session->notify_watch > 0)
115                 g_dbus_remove_watch(connection, session->notify_watch);
116
117         g_dbus_unregister_interface(connection, session->session_path,
118                                                 CONNMAN_SESSION_INTERFACE);
119
120         g_hash_table_remove(session_hash, session->session_path);
121
122         return 0;
123 }
124
125 static void owner_disconnect(DBusConnection *conn, void *user_data)
126 {
127         struct connman_session *session = user_data;
128
129         DBG("session %p, %s died", session, session->owner);
130
131         session_disconnect(session);
132 }
133
134 static DBusMessage *destroy_session(DBusConnection *conn,
135                                         DBusMessage *msg, void *user_data)
136 {
137         struct connman_session *session = user_data;
138
139         DBG("session %p", session);
140
141         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
142 }
143
144 static DBusMessage *connect_session(DBusConnection *conn,
145                                         DBusMessage *msg, void *user_data)
146 {
147         struct connman_session *session = user_data;
148
149         DBG("session %p", session);
150
151         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
152 }
153
154 static DBusMessage *disconnect_session(DBusConnection *conn,
155                                         DBusMessage *msg, void *user_data)
156 {
157         struct connman_session *session = user_data;
158
159         DBG("session %p", session);
160
161         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
162 }
163
164 static DBusMessage *change_session(DBusConnection *conn,
165                                         DBusMessage *msg, void *user_data)
166 {
167         struct connman_session *session = user_data;
168
169         DBG("session %p", session);
170
171         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
172 }
173
174 static GDBusMethodTable session_methods[] = {
175         { "Destroy",    "",   "", destroy_session    },
176         { "Connect",    "",   "", connect_session    },
177         { "Disconnect", "",   "", disconnect_session },
178         { "Change",     "sv", "", change_session     },
179         { },
180 };
181
182 int __connman_session_create(DBusMessage *msg)
183 {
184         const char *owner, *notify_path;
185         char *session_path;
186         DBusMessageIter iter, array;
187         struct connman_session *session;
188         int err;
189
190         owner = dbus_message_get_sender(msg);
191
192         DBG("owner %s", owner);
193
194         dbus_message_iter_init(msg, &iter);
195         dbus_message_iter_recurse(&iter, &array);
196
197         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY)
198                 dbus_message_iter_next(&array);
199
200         dbus_message_iter_next(&iter);
201         dbus_message_iter_get_basic(&iter, &notify_path);
202
203         if (notify_path == NULL) {
204                 session_path = NULL;
205                 err = -EINVAL;
206                 goto err;
207         }
208
209         session_path = g_strdup_printf("/sessions%s", notify_path);
210         if (session_path == NULL) {
211                 err = -ENOMEM;
212                 goto err;
213         }
214
215         session = g_hash_table_lookup(session_hash, session_path);
216         if (session != NULL) {
217                 err = -EEXIST;
218                 goto err;
219         }
220
221         session = g_try_new0(struct connman_session, 1);
222         if (session == NULL) {
223                 err = -ENOMEM;
224                 goto err;
225         }
226
227         session->owner = g_strdup(owner);
228         session->session_path = session_path;
229         session->notify_path = g_strdup(notify_path);
230         session->notify_watch =
231                 g_dbus_add_disconnect_watch(connection, session->owner,
232                                         owner_disconnect, session, NULL);
233
234         g_hash_table_replace(session_hash, session->session_path, session);
235
236         DBG("add %s", session->session_path);
237
238         if (g_dbus_register_interface(connection, session->session_path,
239                                         CONNMAN_SESSION_INTERFACE,
240                                         session_methods, NULL,
241                                         NULL, session, NULL) == FALSE) {
242                 connman_error("Failed to register %s", session->session_path);
243                 g_hash_table_remove(session_hash, session->session_path);
244                 session = NULL;
245
246                 err = -EINVAL;
247                 goto err;
248         }
249
250         g_dbus_send_reply(connection, msg,
251                                 DBUS_TYPE_OBJECT_PATH, &session->session_path,
252                                 DBUS_TYPE_INVALID);
253
254         g_timeout_add_seconds(0, session_notify_all, session);
255
256         return 0;
257
258 err:
259         connman_error("Failed to create session");
260         g_free(session_path);
261
262         return err;
263 }
264
265 int __connman_session_destroy(DBusMessage *msg)
266 {
267         const char *owner, *session_path;
268         struct connman_session *session;
269
270         owner = dbus_message_get_sender(msg);
271
272         DBG("owner %s", owner);
273
274         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
275                                                         DBUS_TYPE_INVALID);
276         if (session_path == NULL)
277                 return -EINVAL;
278
279         session = g_hash_table_lookup(session_hash, session_path);
280         if (session == NULL)
281                 return -EINVAL;
282
283         if (g_strcmp0(owner, session->owner) != 0)
284                 return -EACCES;
285
286         session_disconnect(session);
287
288         return 0;
289 }
290
291 connman_bool_t __connman_session_mode()
292 {
293         return sessionmode;
294 }
295
296 void __connman_session_set_mode(connman_bool_t enable)
297 {
298         DBG("enable %d", enable);
299
300         if (sessionmode == enable)
301                 return;
302
303         sessionmode = enable;
304
305         if (sessionmode == TRUE)
306                 __connman_service_disconnect_all();
307 }
308
309 int __connman_session_init(void)
310 {
311         DBG("");
312
313         connection = connman_dbus_get_connection();
314         if (connection == NULL)
315                 return -1;
316
317         session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
318                                                 NULL, cleanup_session);
319
320         sessionmode = FALSE;
321         return 0;
322 }
323
324 void __connman_session_cleanup(void)
325 {
326         DBG("");
327
328         if (connection == NULL)
329                 return;
330
331         g_hash_table_foreach(session_hash, release_session, NULL);
332         g_hash_table_destroy(session_hash);
333
334         dbus_connection_unref(connection);
335 }