service.c revision 694f01921120bb2584b09b4ba502703cd8afd3f6
18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * BlueZ - Bluetooth protocol stack for Linux 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006-2007 Nokia Corporation 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This program is free software; you can redistribute it and/or modify 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * it under the terms of the GNU General Public License as published by 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * the Free Software Foundation; either version 2 of the License, or 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (at your option) any later version. 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This program is distributed in the hope that it will be useful, 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * GNU General Public License for more details. 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * You should have received a copy of the GNU General Public License 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * along with this program; if not, write to the Free Software 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#ifdef HAVE_CONFIG_H 268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <config.h> 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif 288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <errno.h> 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <stdlib.h> 318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <string.h> 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <bluetooth/bluetooth.h> 3428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <bluetooth/hci.h> 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <bluetooth/hci_lib.h> 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <bluetooth/sdp.h> 378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <bluetooth/sdp_lib.h> 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <gdbus.h> 408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 418f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "sdpd.h" 428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "sdp-xml.h" 438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "plugin.h" 448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "adapter.h" 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "error.h" 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "logging.h" 478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 488f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#define SERVICE_INTERFACE "org.bluez.Service" 498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic DBusConnection *connection = NULL; 518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic GSList *records = NULL; 528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct record_data { 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project uint32_t handle; 558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project char *sender; 56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block guint listener_id; 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}; 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct context_data { 608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project sdp_record_t *record; 618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project sdp_data_t attr_data; 628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project struct sdp_xml_data *stack_head; 638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project uint16_t attr_id; 648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}; 658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int compute_seq_size(sdp_data_t *data) 678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int unit_size = data->unitSize; 69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project sdp_data_t *seq = data->val.dataseq; 708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (; seq; seq = seq->next) 728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unit_size += seq->unitSize; 738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return unit_size; 758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void element_start(GMarkupParseContext *context, 785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const gchar *element_name, const gchar **attribute_names, 798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project const gchar **attribute_values, gpointer user_data, GError **err) 808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 818f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian struct context_data *ctx_data = user_data; 828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!strcmp(element_name, "record")) 848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!strcmp(element_name, "attribute")) { 878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int i; 888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (i = 0; attribute_names[i]; i++) { 898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!strcmp(attribute_names[i], "id")) { 908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx_data->attr_id = strtol(attribute_values[i], 0, 0); 9128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu break; 9228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu } 938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project debug("New attribute 0x%04x", ctx_data->attr_id); 958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (ctx_data->stack_head) { 998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project struct sdp_xml_data *newelem = sdp_xml_data_alloc(); 1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project newelem->next = ctx_data->stack_head; 1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ctx_data->stack_head = newelem; 1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 103 ctx_data->stack_head = sdp_xml_data_alloc(); 104 ctx_data->stack_head->next = NULL; 105 } 106 107 if (!strcmp(element_name, "sequence")) 108 ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); 109 else if (!strcmp(element_name, "alternate")) 110 ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); 111 else { 112 int i; 113 /* Parse value, name, encoding */ 114 for (i = 0; attribute_names[i]; i++) { 115 if (!strcmp(attribute_names[i], "value")) { 116 int curlen = strlen(ctx_data->stack_head->text); 117 int attrlen = strlen(attribute_values[i]); 118 119 /* Ensure we're big enough */ 120 while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) { 121 sdp_xml_data_expand(ctx_data->stack_head); 122 } 123 124 memcpy(ctx_data->stack_head->text + curlen, 125 attribute_values[i], attrlen); 126 ctx_data->stack_head->text[curlen + attrlen] = '\0'; 127 } 128 129 if (!strcmp(attribute_names[i], "encoding")) { 130 if (!strcmp(attribute_values[i], "hex")) 131 ctx_data->stack_head->type = 1; 132 } 133 134 if (!strcmp(attribute_names[i], "name")) { 135 ctx_data->stack_head->name = strdup(attribute_values[i]); 136 } 137 } 138 139 ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name, 140 ctx_data->stack_head, ctx_data->record); 141 142 if (ctx_data->stack_head->data == NULL) 143 error("Can't parse element %s", element_name); 144 } 145} 146 147static void element_end(GMarkupParseContext *context, 148 const gchar *element_name, gpointer user_data, GError **err) 149{ 150 struct context_data *ctx_data = user_data; 151 struct sdp_xml_data *elem; 152 153 if (!strcmp(element_name, "record")) 154 return; 155 156 if (!strcmp(element_name, "attribute")) { 157 if (ctx_data->stack_head && ctx_data->stack_head->data) { 158 int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id, 159 ctx_data->stack_head->data); 160 if (ret == -1) 161 debug("Trouble adding attribute\n"); 162 163 ctx_data->stack_head->data = NULL; 164 sdp_xml_data_free(ctx_data->stack_head); 165 ctx_data->stack_head = NULL; 166 } else { 167 debug("No data for attribute 0x%04x\n", ctx_data->attr_id); 168 } 169 return; 170 } 171 172 if (!strcmp(element_name, "sequence")) { 173 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); 174 175 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { 176 ctx_data->stack_head->data->unitSize += sizeof(uint32_t); 177 ctx_data->stack_head->data->dtd = SDP_SEQ32; 178 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { 179 ctx_data->stack_head->data->unitSize += sizeof(uint16_t); 180 ctx_data->stack_head->data->dtd = SDP_SEQ16; 181 } else { 182 ctx_data->stack_head->data->unitSize += sizeof(uint8_t); 183 } 184 } else if (!strcmp(element_name, "alternate")) { 185 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); 186 187 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { 188 ctx_data->stack_head->data->unitSize += sizeof(uint32_t); 189 ctx_data->stack_head->data->dtd = SDP_ALT32; 190 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { 191 ctx_data->stack_head->data->unitSize += sizeof(uint16_t); 192 ctx_data->stack_head->data->dtd = SDP_ALT16; 193 } else { 194 ctx_data->stack_head->data->unitSize += sizeof(uint8_t); 195 } 196 } 197 198 if (ctx_data->stack_head->next && ctx_data->stack_head->data && 199 ctx_data->stack_head->next->data) { 200 switch (ctx_data->stack_head->next->data->dtd) { 201 case SDP_SEQ8: 202 case SDP_SEQ16: 203 case SDP_SEQ32: 204 case SDP_ALT8: 205 case SDP_ALT16: 206 case SDP_ALT32: 207 ctx_data->stack_head->next->data->val.dataseq = 208 sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq, 209 ctx_data->stack_head->data); 210 ctx_data->stack_head->data = NULL; 211 break; 212 } 213 214 elem = ctx_data->stack_head; 215 ctx_data->stack_head = ctx_data->stack_head->next; 216 217 sdp_xml_data_free(elem); 218 } 219} 220 221static GMarkupParser parser = { 222 element_start, element_end, NULL, NULL, NULL 223}; 224 225static sdp_record_t *sdp_xml_parse_record(const char *data, int size) 226{ 227 GMarkupParseContext *ctx; 228 struct context_data *ctx_data; 229 sdp_record_t *record; 230 231 ctx_data = malloc(sizeof(*ctx_data)); 232 if (!ctx_data) 233 return NULL; 234 235 record = sdp_record_alloc(); 236 if (!record) { 237 free(ctx_data); 238 return NULL; 239 } 240 241 memset(ctx_data, 0, sizeof(*ctx_data)); 242 ctx_data->record = record; 243 244 ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL); 245 246 if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) { 247 error("XML parsing error"); 248 g_markup_parse_context_free(ctx); 249 sdp_record_free(record); 250 free(ctx_data); 251 return NULL; 252 } 253 254 g_markup_parse_context_free(ctx); 255 256 free(ctx_data); 257 258 return record; 259} 260 261static struct record_data *find_record(uint32_t handle, const char *sender) 262{ 263 GSList *list; 264 265 for (list = records; list; list = list->next) { 266 struct record_data *data = list->data; 267 if (handle == data->handle && !strcmp(sender, data->sender)) 268 return data; 269 } 270 271 return NULL; 272} 273 274static void exit_callback(void *user_data) 275{ 276 struct record_data *user_record = user_data; 277 278 debug("remove record"); 279 280 records = g_slist_remove(records, user_record); 281 282 remove_record_from_server(user_record->handle); 283 284 g_free(user_record->sender); 285 g_free(user_record); 286} 287 288static inline DBusMessage *invalid_arguments(DBusMessage *msg) 289{ 290 return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", 291 "Invalid arguments in method call"); 292} 293 294static inline DBusMessage *not_available(DBusMessage *msg) 295{ 296 return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable", 297 "Not Available"); 298} 299 300static inline DBusMessage *failed(DBusMessage *msg) 301{ 302 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed"); 303} 304 305static inline DBusMessage *failed_strerror(DBusMessage *msg, int err) 306{ 307 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 308 strerror(err)); 309} 310 311static int add_xml_record(DBusConnection *conn, const char *sender, 312 bdaddr_t *src, const char *record, 313 dbus_uint32_t *handle) 314{ 315 struct record_data *user_record; 316 sdp_record_t *sdp_record; 317 318 sdp_record = sdp_xml_parse_record(record, strlen(record)); 319 if (!sdp_record) { 320 error("Parsing of XML service record failed"); 321 return -EIO; 322 } 323 324 if (add_record_to_server(src, sdp_record) < 0) { 325 error("Failed to register service record"); 326 sdp_record_free(sdp_record); 327 return -EIO; 328 } 329 330 user_record = g_new0(struct record_data, 1); 331 332 user_record->handle = sdp_record->handle; 333 334 user_record->sender = g_strdup(sender); 335 336 records = g_slist_append(records, user_record); 337 338 user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender, 339 exit_callback, user_record, NULL); 340 341 debug("listener_id %d", user_record->listener_id); 342 343 *handle = user_record->handle; 344 345 return 0; 346} 347 348static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg, 349 bdaddr_t *src, dbus_uint32_t handle, sdp_record_t *sdp_record) 350{ 351 int err; 352 353 if (remove_record_from_server(handle) < 0) { 354 sdp_record_free(sdp_record); 355 return g_dbus_create_error(msg, 356 ERROR_INTERFACE ".NotAvailable", 357 "Not Available"); 358 } 359 360 sdp_record->handle = handle; 361 err = add_record_to_server(src, sdp_record); 362 if (err < 0) { 363 sdp_record_free(sdp_record); 364 error("Failed to update the service record"); 365 return g_dbus_create_error(msg, 366 ERROR_INTERFACE ".Failed", 367 strerror(EIO)); 368 } 369 370 return dbus_message_new_method_return(msg); 371} 372 373static DBusMessage *update_xml_record(DBusConnection *conn, 374 DBusMessage *msg, bdaddr_t *src) 375{ 376 struct record_data *user_record; 377 sdp_record_t *sdp_record; 378 const char *record; 379 dbus_uint32_t handle; 380 int len; 381 382 if (dbus_message_get_args(msg, NULL, 383 DBUS_TYPE_UINT32, &handle, 384 DBUS_TYPE_STRING, &record, 385 DBUS_TYPE_INVALID) == FALSE) 386 return NULL; 387 388 len = (record ? strlen(record) : 0); 389 if (len == 0) 390 return invalid_arguments(msg); 391 392 user_record = find_record(handle, dbus_message_get_sender(msg)); 393 if (!user_record) 394 return g_dbus_create_error(msg, 395 ERROR_INTERFACE ".NotAvailable", 396 "Not Available"); 397 398 sdp_record = sdp_xml_parse_record(record, len); 399 if (!sdp_record) { 400 error("Parsing of XML service record failed"); 401 sdp_record_free(sdp_record); 402 return g_dbus_create_error(msg, 403 ERROR_INTERFACE ".Failed", 404 strerror(EIO)); 405 } 406 407 return update_record(conn, msg, src, handle, sdp_record); 408} 409 410static int remove_record(DBusConnection *conn, const char *sender, 411 dbus_uint32_t handle) 412{ 413 struct record_data *user_record; 414 415 debug("remove record 0x%x", handle); 416 417 user_record = find_record(handle, sender); 418 if (!user_record) 419 return -1; 420 421 debug("listner_id %d", user_record->listener_id); 422 423 g_dbus_remove_watch(conn, user_record->listener_id); 424 425 exit_callback(user_record); 426 427 return 0; 428} 429 430static DBusMessage *add_service_record(DBusConnection *conn, 431 DBusMessage *msg, void *data) 432{ 433 struct adapter *adapter = data; 434 DBusMessage *reply; 435 const char *sender, *record; 436 dbus_uint32_t handle; 437 bdaddr_t src; 438 int err; 439 440 if (dbus_message_get_args(msg, NULL, 441 DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE) 442 return NULL; 443 444 sender = dbus_message_get_sender(msg); 445 str2ba(adapter->address, &src); 446 err = add_xml_record(conn, sender, &src, record, &handle); 447 if (err < 0) 448 return failed_strerror(msg, err); 449 450 reply = dbus_message_new_method_return(msg); 451 if (!reply) 452 return NULL; 453 454 dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle, 455 DBUS_TYPE_INVALID); 456 457 return reply; 458} 459 460static DBusMessage *update_service_record(DBusConnection *conn, 461 DBusMessage *msg, void *data) 462{ 463 struct adapter *adapter = data; 464 bdaddr_t src; 465 466 str2ba(adapter->address, &src); 467 468 return update_xml_record(conn, msg, &src); 469} 470 471static DBusMessage *remove_service_record(DBusConnection *conn, 472 DBusMessage *msg, void *data) 473{ 474 dbus_uint32_t handle; 475 const char *sender; 476 477 if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle, 478 DBUS_TYPE_INVALID) == FALSE) 479 return NULL; 480 481 sender = dbus_message_get_sender(msg); 482 483 if (remove_record(conn, sender, handle) < 0) 484 return not_available(msg); 485 486 return dbus_message_new_method_return(msg); 487} 488 489static DBusMessage *request_authorization(DBusConnection *conn, 490 DBusMessage *msg, void *data) 491{ 492 /* FIXME implement the request */ 493 494 return NULL; 495} 496 497static DBusMessage *cancel_authorization(DBusConnection *conn, 498 DBusMessage *msg, void *data) 499{ 500 /* FIXME implement cancel request */ 501 502 return dbus_message_new_method_return(msg); 503} 504 505static GDBusMethodTable service_methods[] = { 506 { "AddRecord", "s", "u", add_service_record }, 507 { "UpdateRecord", "us", "", update_service_record }, 508 { "RemoveRecord", "u", "", remove_service_record }, 509 { "RequestAuthorization","su", "", request_authorization, 510 G_DBUS_METHOD_FLAG_ASYNC}, 511 { "CancelAuthorization", "", "", cancel_authorization }, 512 { } 513}; 514 515static void path_unregister(void *data) 516{ 517 g_slist_foreach(records, (GFunc) exit_callback, NULL); 518} 519 520static int service_probe(struct adapter *adapter) 521{ 522 const char *path = adapter_get_path(adapter); 523 524 DBG("path %s", path); 525 526 if (!g_dbus_register_interface(connection, path, 527 SERVICE_INTERFACE, 528 service_methods, NULL, NULL, 529 adapter, path_unregister)) { 530 error("D-Bus failed to register %s interface", 531 SERVICE_INTERFACE); 532 return -1; 533 } 534 535 info("Registered interface %s on path %s", SERVICE_INTERFACE, path); 536 537 return 0; 538} 539 540static void service_remove(struct adapter *adapter) 541{ 542 const char *path = adapter_get_path(adapter); 543 544 DBG("path %s", path); 545 546 g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE); 547} 548 549static struct btd_adapter_driver service_driver = { 550 .name = "service", 551 .probe = service_probe, 552 .remove = service_remove, 553}; 554 555static int service_init(void) 556{ 557 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 558 if (connection == NULL) 559 return -EIO; 560 561 return btd_register_adapter_driver(&service_driver); 562} 563 564static void service_exit(void) 565{ 566 btd_unregister_adapter_driver(&service_driver); 567} 568 569BLUETOOTH_PLUGIN_DEFINE("service", service_init, service_exit) 570