Initialize Tizen 2.3
[framework/connectivity/bluez.git] / mobile / plugins / service.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2010  Nokia Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <bluetooth/bluetooth.h>
34 #include <bluetooth/sdp.h>
35 #include <bluetooth/sdp_lib.h>
36
37 #include <gdbus.h>
38
39 #include "sdpd.h"
40 #include "sdp-xml.h"
41 #include "plugin.h"
42 #include "adapter.h"
43 #include "error.h"
44 #include "log.h"
45
46 #define SERVICE_INTERFACE "org.bluez.Service"
47
48 static DBusConnection *connection;
49
50 struct record_data {
51         uint32_t handle;
52         char *sender;
53         guint listener_id;
54         struct service_adapter *serv_adapter;
55 };
56
57 struct context_data {
58         sdp_record_t *record;
59         sdp_data_t attr_data;
60         struct sdp_xml_data *stack_head;
61         uint16_t attr_id;
62 };
63
64 struct pending_auth {
65         DBusConnection *conn;
66         DBusMessage *msg;
67         char *sender;
68         bdaddr_t dst;
69         char uuid[MAX_LEN_UUID_STR];
70 };
71
72 struct service_adapter {
73         struct btd_adapter *adapter;
74         GSList *pending_list;
75         GSList *records;
76 };
77
78 static struct service_adapter *serv_adapter_any = NULL;
79
80 static int compute_seq_size(sdp_data_t *data)
81 {
82         int unit_size = data->unitSize;
83         sdp_data_t *seq = data->val.dataseq;
84
85         for (; seq; seq = seq->next)
86                 unit_size += seq->unitSize;
87
88         return unit_size;
89 }
90
91 static void element_start(GMarkupParseContext *context,
92                 const gchar *element_name, const gchar **attribute_names,
93                 const gchar **attribute_values, gpointer user_data, GError **err)
94 {
95         struct context_data *ctx_data = user_data;
96
97         if (!strcmp(element_name, "record"))
98                 return;
99
100         if (!strcmp(element_name, "attribute")) {
101                 int i;
102                 for (i = 0; attribute_names[i]; i++) {
103                         if (!strcmp(attribute_names[i], "id")) {
104                                 ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
105                                 break;
106                         }
107                 }
108                 DBG("New attribute 0x%04x", ctx_data->attr_id);
109                 return;
110         }
111
112         if (ctx_data->stack_head) {
113                 struct sdp_xml_data *newelem = sdp_xml_data_alloc();
114                 newelem->next = ctx_data->stack_head;
115                 ctx_data->stack_head = newelem;
116         } else {
117                 ctx_data->stack_head = sdp_xml_data_alloc();
118                 ctx_data->stack_head->next = NULL;
119         }
120
121         if (!strcmp(element_name, "sequence"))
122                 ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
123         else if (!strcmp(element_name, "alternate"))
124                 ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
125         else {
126                 int i;
127                 /* Parse value, name, encoding */
128                 for (i = 0; attribute_names[i]; i++) {
129                         if (!strcmp(attribute_names[i], "value")) {
130                                 int curlen = strlen(ctx_data->stack_head->text);
131                                 int attrlen = strlen(attribute_values[i]);
132
133                                 /* Ensure we're big enough */
134                                 while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
135                                         sdp_xml_data_expand(ctx_data->stack_head);
136                                 }
137
138                                 memcpy(ctx_data->stack_head->text + curlen,
139                                                 attribute_values[i], attrlen);
140                                 ctx_data->stack_head->text[curlen + attrlen] = '\0';
141                         }
142
143                         if (!strcmp(attribute_names[i], "encoding")) {
144                                 if (!strcmp(attribute_values[i], "hex"))
145                                         ctx_data->stack_head->type = 1;
146                         }
147
148                         if (!strcmp(attribute_names[i], "name")) {
149                                 ctx_data->stack_head->name = strdup(attribute_values[i]);
150                         }
151                 }
152
153                 ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
154                                 ctx_data->stack_head, ctx_data->record);
155
156                 if (ctx_data->stack_head->data == NULL)
157                         error("Can't parse element %s", element_name);
158         }
159 }
160
161 static void element_end(GMarkupParseContext *context,
162                 const gchar *element_name, gpointer user_data, GError **err)
163 {
164         struct context_data *ctx_data = user_data;
165         struct sdp_xml_data *elem;
166
167         if (!strcmp(element_name, "record"))
168                 return;
169
170         if (!strcmp(element_name, "attribute")) {
171                 if (ctx_data->stack_head && ctx_data->stack_head->data) {
172                         int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
173                                                         ctx_data->stack_head->data);
174                         if (ret == -1)
175                                 DBG("Could not add attribute 0x%04x",
176                                                         ctx_data->attr_id);
177
178                         ctx_data->stack_head->data = NULL;
179                         sdp_xml_data_free(ctx_data->stack_head);
180                         ctx_data->stack_head = NULL;
181                 } else {
182                         DBG("No data for attribute 0x%04x", ctx_data->attr_id);
183                 }
184                 return;
185         }
186
187         if (!strcmp(element_name, "sequence")) {
188                 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
189
190                 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
191                         ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
192                         ctx_data->stack_head->data->dtd = SDP_SEQ32;
193                 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
194                         ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
195                         ctx_data->stack_head->data->dtd = SDP_SEQ16;
196                 } else {
197                         ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
198                 }
199         } else if (!strcmp(element_name, "alternate")) {
200                 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
201
202                 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
203                         ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
204                         ctx_data->stack_head->data->dtd = SDP_ALT32;
205                 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
206                         ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
207                         ctx_data->stack_head->data->dtd = SDP_ALT16;
208                 } else {
209                         ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
210                 }
211         }
212
213         if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
214                                         ctx_data->stack_head->next->data) {
215                 switch (ctx_data->stack_head->next->data->dtd) {
216                 case SDP_SEQ8:
217                 case SDP_SEQ16:
218                 case SDP_SEQ32:
219                 case SDP_ALT8:
220                 case SDP_ALT16:
221                 case SDP_ALT32:
222                         ctx_data->stack_head->next->data->val.dataseq =
223                                 sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
224                                                                 ctx_data->stack_head->data);
225                         ctx_data->stack_head->data = NULL;
226                         break;
227                 }
228
229                 elem = ctx_data->stack_head;
230                 ctx_data->stack_head = ctx_data->stack_head->next;
231
232                 sdp_xml_data_free(elem);
233         }
234 }
235
236 static GMarkupParser parser = {
237         element_start, element_end, NULL, NULL, NULL
238 };
239
240 static sdp_record_t *sdp_xml_parse_record(const char *data, int size)
241 {
242         GMarkupParseContext *ctx;
243         struct context_data *ctx_data;
244         sdp_record_t *record;
245
246         ctx_data = malloc(sizeof(*ctx_data));
247         if (!ctx_data)
248                 return NULL;
249
250         record = sdp_record_alloc();
251         if (!record) {
252                 free(ctx_data);
253                 return NULL;
254         }
255
256         memset(ctx_data, 0, sizeof(*ctx_data));
257         ctx_data->record = record;
258
259         ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
260
261         if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
262                 error("XML parsing error");
263                 g_markup_parse_context_free(ctx);
264                 sdp_record_free(record);
265                 free(ctx_data);
266                 return NULL;
267         }
268
269         g_markup_parse_context_free(ctx);
270
271         free(ctx_data);
272
273         return record;
274 }
275
276 static struct record_data *find_record(struct service_adapter *serv_adapter,
277                                         uint32_t handle, const char *sender)
278 {
279         GSList *list;
280
281         for (list = serv_adapter->records; list; list = list->next) {
282                 struct record_data *data = list->data;
283                 if (handle == data->handle && !strcmp(sender, data->sender))
284                         return data;
285         }
286
287         return NULL;
288 }
289
290 static struct pending_auth *next_pending(struct service_adapter *serv_adapter)
291 {
292         GSList *l = serv_adapter->pending_list;
293
294         if (l) {
295                 struct pending_auth *auth = l->data;
296                 return auth;
297         }
298
299         return NULL;
300 }
301
302 static struct pending_auth *find_pending_by_sender(
303                         struct service_adapter *serv_adapter,
304                         const char *sender)
305 {
306         GSList *l = serv_adapter->pending_list;
307
308         for (; l; l = l->next) {
309                 struct pending_auth *auth = l->data;
310                 if (g_str_equal(auth->sender, sender))
311                         return auth;
312         }
313
314         return NULL;
315 }
316
317 static void exit_callback(DBusConnection *conn, void *user_data)
318 {
319         struct record_data *user_record = user_data;
320         struct service_adapter *serv_adapter = user_record->serv_adapter;
321         struct pending_auth *auth;
322
323         DBG("remove record");
324
325         serv_adapter->records = g_slist_remove(serv_adapter->records,
326                                                 user_record);
327
328         auth = find_pending_by_sender(serv_adapter, user_record->sender);
329         if (auth) {
330                 serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
331                                                         auth);
332                 g_free(auth);
333         }
334
335         remove_record_from_server(user_record->handle);
336
337         g_free(user_record->sender);
338         g_free(user_record);
339 }
340
341 static int add_xml_record(DBusConnection *conn, const char *sender,
342                         struct service_adapter *serv_adapter,
343                         const char *record, dbus_uint32_t *handle)
344 {
345         struct record_data *user_record;
346         sdp_record_t *sdp_record;
347         bdaddr_t src;
348
349         sdp_record = sdp_xml_parse_record(record, strlen(record));
350         if (!sdp_record) {
351                 error("Parsing of XML service record failed");
352                 return -EIO;
353         }
354
355         if (serv_adapter->adapter)
356                 adapter_get_address(serv_adapter->adapter, &src);
357         else
358                 bacpy(&src, BDADDR_ANY);
359
360         if (add_record_to_server(&src, sdp_record) < 0) {
361                 error("Failed to register service record");
362                 sdp_record_free(sdp_record);
363                 return -EIO;
364         }
365
366         user_record = g_new0(struct record_data, 1);
367         user_record->handle = sdp_record->handle;
368         user_record->sender = g_strdup(sender);
369         user_record->serv_adapter = serv_adapter;
370         user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
371                                         exit_callback, user_record, NULL);
372
373         serv_adapter->records = g_slist_append(serv_adapter->records,
374                                                                 user_record);
375
376         DBG("listener_id %d", user_record->listener_id);
377
378         *handle = user_record->handle;
379
380         return 0;
381 }
382
383 static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
384                 struct service_adapter *serv_adapter,
385                 dbus_uint32_t handle, sdp_record_t *sdp_record)
386 {
387         bdaddr_t src;
388         int err;
389
390         if (remove_record_from_server(handle) < 0) {
391                 sdp_record_free(sdp_record);
392                 return btd_error_not_available(msg);
393         }
394
395         if (serv_adapter->adapter)
396                 adapter_get_address(serv_adapter->adapter, &src);
397         else
398                 bacpy(&src, BDADDR_ANY);
399
400         sdp_record->handle = handle;
401         err = add_record_to_server(&src, sdp_record);
402         if (err < 0) {
403                 sdp_record_free(sdp_record);
404                 error("Failed to update the service record");
405                 return btd_error_failed(msg, strerror(-err));
406         }
407
408         return dbus_message_new_method_return(msg);
409 }
410
411 static DBusMessage *update_xml_record(DBusConnection *conn,
412                                 DBusMessage *msg,
413                                 struct service_adapter *serv_adapter)
414 {
415         struct record_data *user_record;
416         sdp_record_t *sdp_record;
417         const char *record;
418         dbus_uint32_t handle;
419         int len;
420
421         if (dbus_message_get_args(msg, NULL,
422                                 DBUS_TYPE_UINT32, &handle,
423                                 DBUS_TYPE_STRING, &record,
424                                 DBUS_TYPE_INVALID) == FALSE)
425                 return btd_error_invalid_args(msg);
426
427         len = (record ? strlen(record) : 0);
428         if (len == 0)
429                 return btd_error_invalid_args(msg);
430
431         user_record = find_record(serv_adapter, handle,
432                                 dbus_message_get_sender(msg));
433         if (!user_record)
434                 return btd_error_not_available(msg);
435
436         sdp_record = sdp_xml_parse_record(record, len);
437         if (!sdp_record) {
438                 error("Parsing of XML service record failed");
439                 return btd_error_failed(msg,
440                                         "Parsing of XML service record failed");
441         }
442
443         return update_record(conn, msg, serv_adapter, handle, sdp_record);
444 }
445
446 static int remove_record(DBusConnection *conn, const char *sender,
447                         struct service_adapter *serv_adapter,
448                         dbus_uint32_t handle)
449 {
450         struct record_data *user_record;
451
452         DBG("remove record 0x%x", handle);
453
454         user_record = find_record(serv_adapter, handle, sender);
455         if (!user_record)
456                 return -1;
457
458         DBG("listner_id %d", user_record->listener_id);
459
460         g_dbus_remove_watch(conn, user_record->listener_id);
461
462         exit_callback(conn, user_record);
463
464         return 0;
465 }
466
467 static DBusMessage *add_service_record(DBusConnection *conn,
468                                         DBusMessage *msg, void *data)
469 {
470         struct service_adapter *serv_adapter = data;
471         DBusMessage *reply;
472         const char *sender, *record;
473         dbus_uint32_t handle;
474         int err;
475
476         if (dbus_message_get_args(msg, NULL,
477                         DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
478                 return btd_error_invalid_args(msg);
479
480         sender = dbus_message_get_sender(msg);
481         err = add_xml_record(conn, sender, serv_adapter, record, &handle);
482         if (err < 0)
483                 return btd_error_failed(msg, strerror(-err));
484
485         reply = dbus_message_new_method_return(msg);
486         if (!reply)
487                 return NULL;
488
489         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
490                                                         DBUS_TYPE_INVALID);
491
492         return reply;
493 }
494
495 static DBusMessage *update_service_record(DBusConnection *conn,
496                                         DBusMessage *msg, void *data)
497 {
498         struct service_adapter *serv_adapter = data;
499
500         return update_xml_record(conn, msg, serv_adapter);
501 }
502
503 static DBusMessage *remove_service_record(DBusConnection *conn,
504                                         DBusMessage *msg, void *data)
505 {
506         struct service_adapter *serv_adapter = data;
507         dbus_uint32_t handle;
508         const char *sender;
509
510         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
511                                                 DBUS_TYPE_INVALID) == FALSE)
512                 return btd_error_invalid_args(msg);
513
514         sender = dbus_message_get_sender(msg);
515
516         if (remove_record(conn, sender, serv_adapter, handle) < 0)
517                 return btd_error_not_available(msg);
518
519         return dbus_message_new_method_return(msg);
520 }
521
522 static void auth_cb(DBusError *derr, void *user_data)
523 {
524         struct service_adapter *serv_adapter = user_data;
525         DBusMessage *reply;
526         struct pending_auth *auth;
527         bdaddr_t src;
528
529         auth = next_pending(serv_adapter);
530         if (auth == NULL) {
531                 info("Authorization cancelled: Client exited");
532                 return;
533         }
534
535         if (derr) {
536                 error("Access denied: %s", derr->message);
537
538                 reply = btd_error_not_authorized(auth->msg);
539                 dbus_message_unref(auth->msg);
540                 g_dbus_send_message(auth->conn, reply);
541                 goto done;
542         }
543
544         g_dbus_send_reply(auth->conn, auth->msg,
545                         DBUS_TYPE_INVALID);
546
547 done:
548         dbus_connection_unref(auth->conn);
549
550         serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
551                                                                         auth);
552         g_free(auth);
553
554         auth = next_pending(serv_adapter);
555         if (auth == NULL)
556                 return;
557
558         if (serv_adapter->adapter)
559                 adapter_get_address(serv_adapter->adapter, &src);
560         else
561                 bacpy(&src, BDADDR_ANY);
562
563         btd_request_authorization(&src, &auth->dst,
564                                         auth->uuid, auth_cb, serv_adapter);
565 }
566
567 static DBusMessage *request_authorization(DBusConnection *conn,
568                                                 DBusMessage *msg, void *data)
569 {
570         struct record_data *user_record;
571         struct service_adapter *serv_adapter = data;
572         sdp_record_t *record;
573         sdp_list_t *services;
574         const char *sender;
575         dbus_uint32_t handle;
576         const char *address;
577         struct pending_auth *auth;
578         char uuid_str[MAX_LEN_UUID_STR];
579         uuid_t *uuid, *uuid128;
580         bdaddr_t src;
581
582         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
583                                         DBUS_TYPE_UINT32, &handle,
584                                         DBUS_TYPE_INVALID) == FALSE)
585                 return btd_error_invalid_args(msg);
586
587         sender = dbus_message_get_sender(msg);
588         if (find_pending_by_sender(serv_adapter, sender))
589                 return btd_error_does_not_exist(msg);
590
591         user_record = find_record(serv_adapter, handle, sender);
592         if (!user_record) {
593                 user_record = find_record(serv_adapter_any, handle, sender);
594                 if (!user_record)
595                         return btd_error_not_authorized(msg);
596         }
597
598         record = sdp_record_find(user_record->handle);
599         if (record == NULL)
600                 return btd_error_not_authorized(msg);
601
602         if (sdp_get_service_classes(record, &services) < 0) {
603                 sdp_record_free(record);
604                 return btd_error_not_authorized(msg);
605         }
606
607         if (services == NULL)
608                 return btd_error_not_authorized(msg);
609
610         uuid = services->data;
611         uuid128 = sdp_uuid_to_uuid128(uuid);
612
613         sdp_list_free(services, bt_free);
614
615         if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
616                 bt_free(uuid128);
617                 return btd_error_not_authorized(msg);
618         }
619         bt_free(uuid128);
620
621         auth = g_new0(struct pending_auth, 1);
622         auth->msg = dbus_message_ref(msg);
623         auth->conn = dbus_connection_ref(connection);
624         auth->sender = user_record->sender;
625         memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
626         str2ba(address, &auth->dst);
627
628         serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
629                                                                         auth);
630
631         auth = next_pending(serv_adapter);
632         if (auth == NULL)
633                 return btd_error_does_not_exist(msg);
634
635         if (serv_adapter->adapter)
636                 adapter_get_address(serv_adapter->adapter, &src);
637         else
638                 bacpy(&src, BDADDR_ANY);
639
640         if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
641                                                         serv_adapter) < 0) {
642                 serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
643                                                                         auth);
644                 g_free(auth);
645                 return btd_error_not_authorized(msg);
646         }
647
648         return NULL;
649 }
650
651 static DBusMessage *cancel_authorization(DBusConnection *conn,
652                                                 DBusMessage *msg, void *data)
653 {
654         DBusMessage *reply;
655         struct service_adapter *serv_adapter = data;
656         struct pending_auth *auth;
657         const gchar *sender;
658         bdaddr_t src;
659
660         sender = dbus_message_get_sender(msg);
661
662         auth = find_pending_by_sender(serv_adapter, sender);
663         if (auth == NULL)
664                 return btd_error_does_not_exist(msg);
665
666         if (serv_adapter->adapter)
667                 adapter_get_address(serv_adapter->adapter, &src);
668         else
669                 bacpy(&src, BDADDR_ANY);
670
671         btd_cancel_authorization(&src, &auth->dst);
672
673         reply = btd_error_not_authorized(auth->msg);
674         dbus_message_unref(auth->msg);
675         g_dbus_send_message(auth->conn, reply);
676
677         dbus_connection_unref(auth->conn);
678
679         serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
680                                                                         auth);
681         g_free(auth);
682
683         auth = next_pending(serv_adapter);
684         if (auth == NULL)
685                 goto done;
686
687         if (serv_adapter->adapter)
688                 adapter_get_address(serv_adapter->adapter, &src);
689         else
690                 bacpy(&src, BDADDR_ANY);
691
692         btd_request_authorization(&src, &auth->dst,
693                                         auth->uuid, auth_cb, serv_adapter);
694
695 done:
696         return dbus_message_new_method_return(msg);
697 }
698
699 static const GDBusMethodTable service_methods[] = {
700         { GDBUS_METHOD("AddRecord",
701                 GDBUS_ARGS({ "record", "s" }),
702                 GDBUS_ARGS({ "handle", "u" }),
703                 add_service_record) },
704         { GDBUS_METHOD("UpdateRecord",
705                 GDBUS_ARGS({ "handle", "u" }, { "record", "s" }), NULL,
706                 update_service_record) },
707         { GDBUS_METHOD("RemoveRecord",
708                 GDBUS_ARGS({ "handle", "u" }), NULL,
709                 remove_service_record) },
710         { GDBUS_ASYNC_METHOD("RequestAuthorization",
711                 GDBUS_ARGS({ "address", "s" }, { "handle", "u"}), NULL,
712                 request_authorization) },
713         { GDBUS_METHOD("CancelAuthorization",
714                 NULL, NULL, cancel_authorization) },
715         { }
716 };
717
718 static void path_unregister(void *data)
719 {
720         struct service_adapter *serv_adapter = data;
721         GSList *l, *next = NULL;
722
723         for (l = serv_adapter->records; l != NULL; l = next) {
724                 struct record_data *user_record = l->data;
725
726                 next = l->next;
727
728                 g_dbus_remove_watch(connection, user_record->listener_id);
729                 exit_callback(connection, user_record);
730         }
731
732         g_free(serv_adapter);
733 }
734
735 static int register_interface(const char *path, struct btd_adapter *adapter)
736 {
737         struct service_adapter *serv_adapter;
738
739         DBG("path %s", path);
740
741         serv_adapter = g_try_new0(struct service_adapter, 1);
742         if (serv_adapter == NULL)
743                 return -ENOMEM;
744
745         serv_adapter->adapter = adapter;
746         serv_adapter->pending_list = NULL;
747
748         if (g_dbus_register_interface(connection, path, SERVICE_INTERFACE,
749                                 service_methods, NULL, NULL, serv_adapter,
750                                                 path_unregister) == FALSE) {
751                 error("D-Bus failed to register %s interface",
752                                                         SERVICE_INTERFACE);
753                 g_free(serv_adapter);
754                 return -EIO;
755         }
756
757         DBG("Registered interface %s on path %s", SERVICE_INTERFACE, path);
758
759         if (serv_adapter->adapter == NULL)
760                 serv_adapter_any = serv_adapter;
761
762         return 0;
763 }
764
765 static void unregister_interface(const char *path)
766 {
767         DBG("path %s", path);
768
769         g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE);
770 }
771
772 static int service_probe(struct btd_adapter *adapter)
773 {
774         register_interface(adapter_get_path(adapter), adapter);
775
776         return 0;
777 }
778
779 static void service_remove(struct btd_adapter *adapter)
780 {
781         unregister_interface(adapter_get_path(adapter));
782 }
783
784 static struct btd_adapter_driver service_driver = {
785         .name   = "service",
786         .probe  = service_probe,
787         .remove = service_remove,
788 };
789
790 static const char *any_path;
791
792 static int service_init(void)
793 {
794         int err;
795
796         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
797         if (connection == NULL)
798                 return -EIO;
799
800         any_path = btd_adapter_any_request_path();
801         if (any_path != NULL) {
802                 if (register_interface(any_path, NULL) < 0) {
803                         btd_adapter_any_release_path();
804                         any_path = NULL;
805                 }
806         }
807
808         err = btd_register_adapter_driver(&service_driver);
809         if (err < 0) {
810                 dbus_connection_unref(connection);
811                 return err;
812         }
813
814         return 0;
815 }
816
817 static void service_exit(void)
818 {
819         btd_unregister_adapter_driver(&service_driver);
820
821         if (any_path != NULL) {
822                 unregister_interface(any_path);
823
824                 btd_adapter_any_release_path();
825                 any_path = NULL;
826         }
827
828         dbus_connection_unref(connection);
829 }
830
831 BLUETOOTH_PLUGIN_DEFINE(service, VERSION,
832                 BLUETOOTH_PLUGIN_PRIORITY_HIGH, service_init, service_exit)