dundee: Monitor DeviceAdded/DeviceRemoved signal
[platform/upstream/connman.git] / plugins / dundee.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27
28 #include <gdbus.h>
29
30 #define CONNMAN_API_SUBJECT_TO_CHANGE
31 #include <connman/plugin.h>
32 #include <connman/device.h>
33 #include <connman/network.h>
34 #include <connman/dbus.h>
35
36 #define DUNDEE_SERVICE                  "org.ofono.dundee"
37 #define DUNDEE_MANAGER_INTERFACE        DUNDEE_SERVICE ".Manager"
38
39 #define DEVICE_ADDED                    "DeviceAdded"
40 #define DEVICE_REMOVED                  "DeviceRemoved"
41
42 static DBusConnection *connection;
43
44 static GHashTable *dundee_devices = NULL;
45
46 struct dundee_data {
47         char *path;
48 };
49
50 static void device_destroy(gpointer data)
51 {
52         struct dundee_data *info = data;
53
54         g_free(info->path);
55
56         g_free(info);
57 }
58
59 static int network_probe(struct connman_network *network)
60 {
61         DBG("network %p", network);
62
63         return 0;
64 }
65
66 static void network_remove(struct connman_network *network)
67 {
68         DBG("network %p", network);
69 }
70
71 static int network_connect(struct connman_network *network)
72 {
73         DBG("network %p", network);
74
75         return 0;
76 }
77
78 static int network_disconnect(struct connman_network *network)
79 {
80         DBG("network %p", network);
81
82         return 0;
83 }
84
85 static struct connman_network_driver network_driver = {
86         .name           = "network",
87         .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN,
88         .probe          = network_probe,
89         .remove         = network_remove,
90         .connect        = network_connect,
91         .disconnect     = network_disconnect,
92 };
93
94 static int dundee_probe(struct connman_device *device)
95 {
96         DBG("device %p", device);
97
98         return 0;
99 }
100
101 static void dundee_remove(struct connman_device *device)
102 {
103         DBG("device %p", device);
104 }
105
106 static int dundee_enable(struct connman_device *device)
107 {
108         DBG("device %p", device);
109
110         return 0;
111 }
112
113 static int dundee_disable(struct connman_device *device)
114 {
115         DBG("device %p", device);
116
117         return 0;
118 }
119
120 static struct connman_device_driver dundee_driver = {
121         .name           = "dundee",
122         .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
123         .probe          = dundee_probe,
124         .remove         = dundee_remove,
125         .enable         = dundee_enable,
126         .disable        = dundee_disable,
127 };
128
129 static void add_device(const char *path, DBusMessageIter *properties)
130 {
131         struct dundee_data *info;
132
133         info = g_hash_table_lookup(dundee_devices, path);
134         if (info != NULL)
135                 return;
136
137         info = g_try_new0(struct dundee_data, 1);
138         if (info == NULL)
139                 return;
140
141         info->path = g_strdup(path);
142
143         g_hash_table_insert(dundee_devices, g_strdup(path), info);
144 }
145
146 static gboolean device_added(DBusConnection *connection, DBusMessage *message,
147                                 void *user_data)
148 {
149         DBusMessageIter iter, properties;
150         const char *path;
151         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
152                 DBUS_TYPE_ARRAY_AS_STRING
153                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
154                 DBUS_TYPE_STRING_AS_STRING
155                 DBUS_TYPE_VARIANT_AS_STRING
156                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
157
158         if (dbus_message_has_signature(message, signature) == FALSE) {
159                 connman_error("dundee signature does not match");
160                 return TRUE;
161         }
162
163         DBG("");
164
165         if (dbus_message_iter_init(message, &iter) == FALSE)
166                 return TRUE;
167
168         dbus_message_iter_get_basic(&iter, &path);
169
170         dbus_message_iter_next(&iter);
171         dbus_message_iter_recurse(&iter, &properties);
172
173         add_device(path, &properties);
174
175         return TRUE;
176 }
177
178 static void remove_device(DBusConnection *connection, const char *path)
179 {
180         DBG("path %s", path);
181
182         g_hash_table_remove(dundee_devices, path);
183 }
184
185 static gboolean device_removed(DBusConnection *connection, DBusMessage *message,
186                                 void *user_data)
187 {
188         const char *path;
189         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
190
191         if (dbus_message_has_signature(message, signature) == FALSE) {
192                 connman_error("dundee signature does not match");
193                 return TRUE;
194         }
195
196         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
197                                 DBUS_TYPE_INVALID);
198         remove_device(connection, path);
199         return TRUE;
200 }
201
202 static void dundee_connect(DBusConnection *connection, void *user_data)
203 {
204         DBG("connection %p", connection);
205
206         dundee_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
207                                         g_free, device_destroy);
208 }
209
210 static void dundee_disconnect(DBusConnection *connection, void *user_data)
211 {
212         DBG("connection %p", connection);
213
214         g_hash_table_destroy(dundee_devices);
215         dundee_devices = NULL;
216 }
217
218 static guint watch;
219 static guint added_watch;
220 static guint removed_watch;
221
222 static int dundee_init(void)
223 {
224         int err;
225
226         connection = connman_dbus_get_connection();
227         if (connection == NULL)
228                 return -EIO;
229
230         watch = g_dbus_add_service_watch(connection, DUNDEE_SERVICE,
231                         dundee_connect, dundee_disconnect, NULL, NULL);
232
233         added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
234                                                 DUNDEE_MANAGER_INTERFACE,
235                                                 DEVICE_ADDED, device_added,
236                                                 NULL, NULL);
237
238         removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
239                                                 DUNDEE_MANAGER_INTERFACE,
240                                                 DEVICE_REMOVED, device_removed,
241                                                 NULL, NULL);
242
243         if (watch == 0 || added_watch == 0 || removed_watch == 0) {
244                 err = -EIO;
245                 goto remove;
246         }
247
248         err = connman_network_driver_register(&network_driver);
249         if (err < 0)
250                 goto remove;
251
252         err = connman_device_driver_register(&dundee_driver);
253         if (err < 0) {
254                 connman_network_driver_unregister(&network_driver);
255                 goto remove;
256         }
257
258         return 0;
259
260 remove:
261         g_dbus_remove_watch(connection, watch);
262         g_dbus_remove_watch(connection, added_watch);
263         g_dbus_remove_watch(connection, removed_watch);
264
265         dbus_connection_unref(connection);
266
267         return err;
268 }
269
270 static void dundee_exit(void)
271 {
272         g_dbus_remove_watch(connection, watch);
273         g_dbus_remove_watch(connection, added_watch);
274         g_dbus_remove_watch(connection, removed_watch);
275
276         connman_device_driver_unregister(&dundee_driver);
277         connman_network_driver_unregister(&network_driver);
278
279         dbus_connection_unref(connection);
280 }
281
282 CONNMAN_PLUGIN_DEFINE(dundee, "Dundee plugin", VERSION,
283                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dundee_init, dundee_exit)