Tizen 2.0 Release
[framework/connectivity/neard.git] / src / device.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2011  Intel Corporation. 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 <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30
31 #include <glib.h>
32
33 #include <gdbus.h>
34
35 #include "near.h"
36
37 struct near_device {
38         char *path;
39
40         uint32_t adapter_idx;
41         uint32_t target_idx;
42
43         uint8_t nfcid[NFC_MAX_NFCID1_LEN];
44         uint8_t nfcid_len;
45
46         size_t data_length;
47         uint8_t *data;
48
49         uint32_t n_records;
50         GList *records;
51
52         DBusMessage *push_msg; /* Push pending message */
53 };
54
55 static DBusConnection *connection = NULL;
56
57 static GHashTable *device_hash;
58
59 static GSList *driver_list = NULL;
60
61 static void free_device(gpointer data)
62 {
63         struct near_device *device = data;
64         GList *list;
65
66         DBG("device %p", device);
67
68         for (list = device->records; list; list = list->next) {
69                 struct near_ndef_record *record = list->data;
70
71                 __near_ndef_record_free(record);
72         }
73
74         g_list_free(device->records);
75         g_free(device->path);
76         g_free(device->data);
77         g_free(device);
78 }
79
80 struct near_device *near_device_get_device(uint32_t adapter_idx,
81                                                 uint32_t target_idx)
82 {
83         struct near_device *device;
84         char *path;
85
86         DBG("");
87
88         path = g_strdup_printf("%s/nfc%d/device%d", NFC_PATH,
89                                         adapter_idx, target_idx);
90         if (path == NULL)
91                 return NULL;
92
93         device = g_hash_table_lookup(device_hash, path);
94         g_free(path);
95
96         /* TODO refcount */
97         return device;
98 }
99
100 void __near_device_remove(struct near_device *device)
101 {
102         char *path = device->path;
103
104         DBG("path %s", device->path);
105
106         if (g_hash_table_lookup(device_hash, device->path) == NULL)
107                 return;
108
109         g_dbus_unregister_interface(connection, device->path,
110                                                 NFC_DEVICE_INTERFACE);
111
112         g_hash_table_remove(device_hash, path);
113 }
114
115 const char *__near_device_get_path(struct near_device *device)
116 {
117         return device->path;
118 }
119
120 uint32_t __neard_device_get_idx(struct near_device *device)
121 {
122         return device->target_idx;
123 }
124
125 static void append_records(DBusMessageIter *iter, void *user_data)
126 {
127         struct near_device *device = user_data;
128         GList *list;
129
130         DBG("");
131
132         for (list = device->records; list; list = list->next) {
133                 struct near_ndef_record *record = list->data;
134                 char *path;
135
136                 path = __near_ndef_record_get_path(record);
137                 if (path == NULL)
138                         continue;
139
140                 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
141                                                         &path);
142         }
143 }
144
145 static DBusMessage *get_properties(DBusConnection *conn,
146                                         DBusMessage *msg, void *data)
147 {
148         struct near_device *device = data;
149         DBusMessage *reply;
150         DBusMessageIter array, dict;
151
152         DBG("conn %p", conn);
153
154         reply = dbus_message_new_method_return(msg);
155         if (reply == NULL)
156                 return NULL;
157
158         dbus_message_iter_init_append(reply, &array);
159
160         near_dbus_dict_open(&array, &dict);
161
162         near_dbus_dict_append_array(&dict, "Records",
163                                 DBUS_TYPE_OBJECT_PATH, append_records, device);
164
165         near_dbus_dict_close(&array, &dict);
166
167         return reply;
168 }
169
170 static DBusMessage *set_property(DBusConnection *conn,
171                                         DBusMessage *msg, void *data)
172 {
173         DBG("conn %p", conn);
174
175         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
176 }
177
178 static void push_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
179 {
180         struct near_device *device;
181         DBusConnection *conn;
182         DBusMessage *reply;
183
184         DBG("Push status %d", status);
185
186         conn = near_dbus_get_connection();
187         device = near_device_get_device(adapter_idx, target_idx);
188
189         if (conn == NULL || device == NULL)
190                 return;
191
192         if (status != 0) {
193                 reply = __near_error_failed(device->push_msg, EINVAL);
194                 if (reply != NULL)
195                         g_dbus_send_message(conn, reply);
196         } else {
197                 g_dbus_send_reply(conn, device->push_msg, DBUS_TYPE_INVALID);
198         }
199
200         dbus_message_unref(device->push_msg);
201         device->push_msg = NULL;
202 }
203
204 static char *sn_from_message(DBusMessage *msg)
205 {
206         DBusMessageIter iter;
207         DBusMessageIter arr_iter;
208
209         DBG("");
210
211         dbus_message_iter_init(msg, &iter);
212         dbus_message_iter_recurse(&iter, &arr_iter);
213
214         while (dbus_message_iter_get_arg_type(&arr_iter) !=
215                                                 DBUS_TYPE_INVALID) {
216                 const char *key, *value;
217                 DBusMessageIter ent_iter;
218                 DBusMessageIter var_iter;
219
220                 dbus_message_iter_recurse(&arr_iter, &ent_iter);
221                 dbus_message_iter_get_basic(&ent_iter, &key);
222
223                 if (g_strcmp0(key, "Type") != 0) {
224                         dbus_message_iter_next(&arr_iter);
225                         continue;
226                 }
227
228                 dbus_message_iter_next(&ent_iter);
229                 dbus_message_iter_recurse(&ent_iter, &var_iter);
230
231                 switch (dbus_message_iter_get_arg_type(&var_iter)) {
232                 case DBUS_TYPE_STRING:
233                         dbus_message_iter_get_basic(&var_iter, &value);
234
235                         if (g_strcmp0(value, "Text") == 0)
236                                 return NEAR_DEVICE_SN_SNEP;
237                         else if (g_strcmp0(value, "URI") == 0)
238                                 return NEAR_DEVICE_SN_SNEP;
239                         else if (g_strcmp0(value, "SmartPoster") == 0)
240                                 return NEAR_DEVICE_SN_SNEP;
241                         else if (g_strcmp0(value, "Handover") == 0)
242                                 return NEAR_DEVICE_SN_HANDOVER;
243                         else
244                                 return NULL;
245
246                         break;
247                 }
248
249                 dbus_message_iter_next(&arr_iter);
250         }
251
252         return NULL;
253 }
254
255 static DBusMessage *push_ndef(DBusConnection *conn,
256                                 DBusMessage *msg, void *data)
257 {
258         struct near_device *device = data;
259         struct near_ndef_message *ndef;
260         char *service_name;
261         int err;
262
263         DBG("conn %p", conn);
264
265         if (device->push_msg)
266                 return __near_error_in_progress(msg);
267
268         device->push_msg = dbus_message_ref(msg);
269
270         service_name = sn_from_message(msg);
271         if (service_name == NULL) {
272                 err = -EINVAL;
273                 goto error;
274         }
275
276         ndef = __ndef_build_from_message(msg);
277         if (ndef == NULL) {
278                 err = -EINVAL;
279                 goto error;
280         }
281
282         err = __near_device_push(device, ndef, service_name, push_cb);
283         if (err < 0)
284                 goto error;
285
286         g_free(ndef);
287         g_free(ndef->data);
288
289         return NULL;
290
291 error:
292         dbus_message_unref(device->push_msg);
293         device->push_msg = NULL;
294
295         return __near_error_failed(msg, -err);
296 }
297
298 static const GDBusMethodTable device_methods[] = {
299         { GDBUS_METHOD("GetProperties",
300                                 NULL, GDBUS_ARGS({"properties", "a{sv}"}),
301                                 get_properties) },
302         { GDBUS_METHOD("SetProperty",
303                                 GDBUS_ARGS({"name", "s"}, {"value", "v"}),
304                                 NULL, set_property) },
305         { GDBUS_ASYNC_METHOD("Push", GDBUS_ARGS({"attributes", "a{sv}"}),
306                                                         NULL, push_ndef) },
307         { },
308 };
309
310 static const GDBusSignalTable device_signals[] = {
311         { GDBUS_SIGNAL("PropertyChanged",
312                                 GDBUS_ARGS({"name", "s"}, {"value", "v"})) },
313         { }
314 };
315
316 int near_device_add_data(uint32_t adapter_idx, uint32_t target_idx,
317                         uint8_t *data, size_t data_length)
318 {
319         struct near_device *device;
320
321         device = near_device_get_device(adapter_idx, target_idx);
322         if (device == NULL)
323                 return -ENODEV;
324
325         device->data_length = data_length;
326         device->data = g_try_malloc0(data_length);
327         if (device->data == NULL)
328                 return -ENOMEM;
329
330         if (data != NULL)
331                 memcpy(device->data, data, data_length);
332
333         return 0;
334 }
335
336 int near_device_add_records(struct near_device *device, GList *records,
337                                 near_device_io_cb cb, int status)
338 {
339         GList *list;
340         struct near_ndef_record *record;
341         char *path;
342
343         DBG("records %p", records);
344
345         for (list = records; list; list = list->next) {
346                 record = list->data;
347
348                 path = g_strdup_printf("%s/nfc%d/device%d/record%d",
349                                         NFC_PATH, device->adapter_idx,
350                                         device->target_idx, device->n_records);
351
352                 if (path == NULL)
353                         continue;
354
355                 __near_ndef_record_register(record, path);
356
357                 device->n_records++;
358                 device->records = g_list_append(device->records, record);
359         }
360
361         __near_agent_ndef_parse_records(device->records);
362
363         if (cb != NULL)
364                 cb(device->adapter_idx, device->target_idx, status);
365
366         g_list_free(records);
367
368         return 0;
369 }
370
371 struct near_device *__near_device_add(uint32_t adapter_idx, uint32_t target_idx,
372                                         uint8_t *nfcid, uint8_t nfcid_len)
373 {
374         struct near_device *device;
375         char *path;
376
377         device = near_device_get_device(adapter_idx, target_idx);
378         if (device != NULL)
379                 return NULL;
380
381         device = g_try_malloc0(sizeof(struct near_device));
382         if (device == NULL)
383                 return NULL;
384
385         device->path = g_strdup_printf("%s/nfc%d/device%d", NFC_PATH,
386                                         adapter_idx, target_idx);
387         if (device->path == NULL) {
388                 g_free(device);
389                 return NULL;
390         }
391         device->adapter_idx = adapter_idx;
392         device->target_idx = target_idx;
393         device->n_records = 0;
394
395         if (nfcid_len <= NFC_MAX_NFCID1_LEN && nfcid_len > 0) {
396                 device->nfcid_len = nfcid_len;
397                 memcpy(device->nfcid, nfcid, nfcid_len);
398         }
399
400         path = g_strdup(device->path);
401         if (path == NULL) {
402                 g_free(device);
403                 return NULL;
404         }
405
406         g_hash_table_insert(device_hash, path, device);
407
408         DBG("connection %p", connection);
409
410         g_dbus_register_interface(connection, device->path,
411                                         NFC_DEVICE_INTERFACE,
412                                         device_methods, device_signals,
413                                                         NULL, device, NULL);
414
415         return device;
416 }
417
418 int __near_device_listen(struct near_device *device, near_device_io_cb cb)
419 {
420         GSList *list;
421
422         DBG("");
423
424         for (list = driver_list; list; list = list->next) {
425                 struct near_device_driver *driver = list->data;
426
427                 return driver->listen(device->adapter_idx, cb);
428         }
429
430         return 0;
431 }
432
433 int __near_device_push(struct near_device *device,
434                         struct near_ndef_message *ndef, char *service_name,
435                         near_device_io_cb cb)
436 {
437         GSList *list;
438
439         DBG("");
440
441         if (__near_adapter_get_dep_state(device->adapter_idx) == FALSE) {
442                 near_error("DEP link is not established");
443                 return -ENOLINK;
444         }
445
446         for (list = driver_list; list; list = list->next) {
447                 struct near_device_driver *driver = list->data;
448
449                 return driver->push(device->adapter_idx, device->target_idx,
450                                         ndef, service_name, cb);
451         }
452
453         return 0;
454 }
455
456 static gint cmp_prio(gconstpointer a, gconstpointer b)
457 {
458         const struct near_tag_driver *driver1 = a;
459         const struct near_tag_driver *driver2 = b;
460
461         return driver2->priority - driver1->priority;
462 }
463
464 int near_device_driver_register(struct near_device_driver *driver)
465 {
466         DBG("");
467
468         if (driver->listen == NULL)
469                 return -EINVAL;
470
471         driver_list = g_slist_insert_sorted(driver_list, driver, cmp_prio);
472
473         __near_adapter_listen(driver);
474
475         return 0;
476 }
477
478 void near_device_driver_unregister(struct near_device_driver *driver)
479 {
480         DBG("");
481
482         driver_list = g_slist_remove(driver_list, driver);
483 }
484
485 int __near_device_init(void)
486 {
487         DBG("");
488
489         connection = near_dbus_get_connection();
490
491         device_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
492                                                 g_free, free_device);
493
494         return 0;
495 }
496
497 void __near_device_cleanup(void)
498 {
499         DBG("");
500
501         g_hash_table_destroy(device_hash);
502         device_hash = NULL;
503 }