~indicator-network-developers/ofono/trunk.packaging

« back to all changes in this revision

Viewing changes to plugins/bluetooth.c

  • Committer: Kalle Valo
  • Date: 2011-02-21 07:46:07 UTC
  • mfrom: (2738.1.2125)
  • Revision ID: kalle.valo@canonical.com-20110221074607-u4rocuj2p75kpht9
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 
36
36
#include <ofono/dbus.h>
37
37
 
 
38
#include <btio.h>
38
39
#include "bluetooth.h"
39
40
 
40
41
static DBusConnection *connection;
41
42
static GHashTable *uuid_hash = NULL;
42
43
static GHashTable *adapter_address_hash = NULL;
43
44
static gint bluetooth_refcount;
 
45
static GSList *server_list = NULL;
 
46
static const char *adapter_any_name = "any";
 
47
static char *adapter_any_path;
 
48
 
 
49
#define TIMEOUT 60 /* Timeout for user response (seconds) */
 
50
 
 
51
struct server {
 
52
        guint8 channel;
 
53
        char *sdp_record;
 
54
        guint32 handle;
 
55
        GIOChannel *io;
 
56
        ConnectFunc connect_cb;
 
57
        gpointer user_data;
 
58
};
 
59
 
 
60
struct cb_data {
 
61
        struct server *server;
 
62
        char *path;
 
63
        guint source;
 
64
        GIOChannel *io;
 
65
};
44
66
 
45
67
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
46
68
                                char *buf, int size)
198
220
        }
199
221
 
200
222
done:
201
 
        g_slist_foreach(prop_handlers, (GFunc)g_free, NULL);
 
223
        g_slist_foreach(prop_handlers, (GFunc) g_free, NULL);
202
224
        g_slist_free(prop_handlers);
203
225
}
204
226
 
245
267
        const char *device_addr = NULL;
246
268
        const char *alias = NULL;
247
269
        struct bluetooth_profile *profile;
 
270
        struct DBusError derr;
248
271
 
249
272
        reply = dbus_pending_call_steal_reply(call);
250
273
 
251
 
        if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
252
 
                DBG("Bluetooth daemon is apparently not available.");
253
 
                goto done;
254
 
        }
255
 
 
256
 
        if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
257
 
                if (!dbus_message_is_error(reply, DBUS_ERROR_UNKNOWN_METHOD))
258
 
                        ofono_info("Error from GetProperties reply: %s",
259
 
                                        dbus_message_get_error_name(reply));
260
 
 
261
 
                goto done;
262
 
        }
 
274
        dbus_error_init(&derr);
 
275
 
 
276
        if (dbus_set_error_from_message(&derr, reply)) {
 
277
                ofono_error("Device.GetProperties replied an error: %s, %s",
 
278
                                        derr.name, derr.message);
 
279
                dbus_error_free(&derr);
 
280
                goto done;
 
281
        }
 
282
 
 
283
        DBG("");
263
284
 
264
285
        bluetooth_parse_properties(reply, "UUIDs", has_uuid, &have_uuid,
265
286
                                "Adapter", parse_string, &adapter,
375
396
{
376
397
        const char *path = user_data;
377
398
        DBusMessage *reply;
 
399
        DBusError derr;
378
400
        GSList *device_list = NULL;
379
401
        GSList *l;
380
402
        const char *addr;
381
403
 
382
404
        reply = dbus_pending_call_steal_reply(call);
383
405
 
384
 
        if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
385
 
                DBG("Bluetooth daemon is apparently not available.");
 
406
        dbus_error_init(&derr);
 
407
 
 
408
        if (dbus_set_error_from_message(&derr, reply)) {
 
409
                ofono_error("Adapter.GetProperties replied an error: %s, %s",
 
410
                                        derr.name, derr.message);
 
411
                dbus_error_free(&derr);
386
412
                goto done;
387
413
        }
388
414
 
 
415
        DBG("");
 
416
 
389
417
        bluetooth_parse_properties(reply,
390
418
                                        "Devices", parse_devices, &device_list,
391
419
                                        "Address", parse_string, &addr,
409
437
        dbus_message_unref(reply);
410
438
}
411
439
 
 
440
static void get_adapter_properties(const char *path, const char *handle,
 
441
                                                gpointer user_data)
 
442
{
 
443
        bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE,
 
444
                        "GetProperties", adapter_properties_cb,
 
445
                        g_strdup(path), g_free, -1, DBUS_TYPE_INVALID);
 
446
}
 
447
 
 
448
static void remove_record(struct server *server)
 
449
{
 
450
        DBusMessage *msg;
 
451
 
 
452
        if (server->handle == 0)
 
453
                return;
 
454
 
 
455
        msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path,
 
456
                                        BLUEZ_SERVICE_INTERFACE,
 
457
                                        "RemoveRecord");
 
458
        if (msg == NULL) {
 
459
                ofono_error("Unable to allocate D-Bus RemoveRecord message");
 
460
                return;
 
461
        }
 
462
 
 
463
        dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle,
 
464
                                        DBUS_TYPE_INVALID);
 
465
        g_dbus_send_message(connection, msg);
 
466
 
 
467
        ofono_info("Unregistered handle for channel %d: 0x%x",
 
468
                        server->channel, server->handle);
 
469
}
 
470
 
 
471
static void cb_data_destroy(gpointer data)
 
472
{
 
473
        struct cb_data *cb_data = data;
 
474
 
 
475
        if (cb_data->source != 0)
 
476
                g_source_remove(cb_data->source);
 
477
 
 
478
        g_free(cb_data->path);
 
479
        g_free(cb_data);
 
480
}
 
481
 
 
482
static void cancel_authorization(struct cb_data *user_data)
 
483
{
 
484
        DBusMessage *msg;
 
485
 
 
486
        msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path,
 
487
                                                BLUEZ_SERVICE_INTERFACE,
 
488
                                                "CancelAuthorization");
 
489
 
 
490
        if (msg == NULL) {
 
491
                ofono_error("Unable to allocate D-Bus CancelAuthorization"
 
492
                                " message");
 
493
                return;
 
494
        }
 
495
 
 
496
        g_dbus_send_message(connection, msg);
 
497
}
 
498
 
 
499
static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data)
 
500
{
 
501
        struct cb_data *cb_data = data;
 
502
 
 
503
        cancel_authorization(cb_data);
 
504
        cb_data->source = 0;
 
505
 
 
506
        return FALSE;
 
507
}
 
508
 
 
509
static void auth_cb(DBusPendingCall *call, gpointer user_data)
 
510
{
 
511
        struct cb_data *cb_data = user_data;
 
512
        struct server *server = cb_data->server;
 
513
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
 
514
        DBusError derr;
 
515
        GError *err = NULL;
 
516
 
 
517
        dbus_error_init(&derr);
 
518
 
 
519
        if (dbus_set_error_from_message(&derr, reply)) {
 
520
                ofono_error("RequestAuthorization error: %s, %s",
 
521
                                derr.name, derr.message);
 
522
 
 
523
                if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
 
524
                        cancel_authorization(cb_data);
 
525
 
 
526
                dbus_error_free(&derr);
 
527
        } else {
 
528
                ofono_info("RequestAuthorization succeeded");
 
529
 
 
530
                if (!bt_io_accept(cb_data->io, server->connect_cb,
 
531
                                        server->user_data, NULL, &err)) {
 
532
                        ofono_error("%s", err->message);
 
533
                        g_error_free(err);
 
534
                }
 
535
        }
 
536
 
 
537
        dbus_message_unref(reply);
 
538
}
 
539
 
 
540
static void new_connection(GIOChannel *io, gpointer user_data)
 
541
{
 
542
        struct server *server = user_data;
 
543
        struct cb_data *cbd;
 
544
        const char *addr;
 
545
        GError *err = NULL;
 
546
        char laddress[18], raddress[18];
 
547
        guint8 channel;
 
548
        GHashTableIter iter;
 
549
        gpointer key, value;
 
550
        const char *path;
 
551
 
 
552
        bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress,
 
553
                                        BT_IO_OPT_DEST, raddress,
 
554
                                        BT_IO_OPT_CHANNEL, &channel,
 
555
                                        BT_IO_OPT_INVALID);
 
556
        if (err) {
 
557
                ofono_error("%s", err->message);
 
558
                g_error_free(err);
 
559
                return;
 
560
        }
 
561
 
 
562
        ofono_info("New connection for %s on channel %u from: %s,", laddress,
 
563
                                                        channel, raddress);
 
564
 
 
565
        path = NULL;
 
566
        g_hash_table_iter_init(&iter, adapter_address_hash);
 
567
 
 
568
        while (g_hash_table_iter_next(&iter, &key, &value)) {
 
569
                if (g_str_equal(laddress, value) == TRUE) {
 
570
                        path = key;
 
571
                        break;
 
572
                }
 
573
        }
 
574
 
 
575
        if (path == NULL)
 
576
                return;
 
577
 
 
578
        cbd = g_try_new0(struct cb_data, 1);
 
579
        if (cbd == NULL) {
 
580
                ofono_error("Unable to allocate client cb_data structure");
 
581
                return;
 
582
        }
 
583
 
 
584
        cbd->path = g_strdup(path);
 
585
        cbd->server = server;
 
586
        cbd->io = io;
 
587
 
 
588
        addr = raddress;
 
589
 
 
590
        if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE,
 
591
                                        "RequestAuthorization",
 
592
                                        auth_cb, cbd, cb_data_destroy,
 
593
                                        TIMEOUT, DBUS_TYPE_STRING, &addr,
 
594
                                        DBUS_TYPE_UINT32, &server->handle,
 
595
                                        DBUS_TYPE_INVALID) < 0) {
 
596
                ofono_error("Request Bluetooth authorization failed");
 
597
                return;
 
598
        }
 
599
 
 
600
        ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle);
 
601
 
 
602
        cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 
603
                                        client_event, cbd);
 
604
}
 
605
 
 
606
static void remove_service_handle(gpointer data, gpointer user_data)
 
607
{
 
608
        struct server *server = data;
 
609
 
 
610
        server->handle = 0;
 
611
}
 
612
 
 
613
static void add_record_cb(DBusPendingCall *call, gpointer user_data)
 
614
{
 
615
        struct server *server = user_data;
 
616
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
 
617
        DBusError derr;
 
618
 
 
619
        dbus_error_init(&derr);
 
620
 
 
621
        if (dbus_set_error_from_message(&derr, reply)) {
 
622
                ofono_error("Replied with an error: %s, %s",
 
623
                                        derr.name, derr.message);
 
624
                dbus_error_free(&derr);
 
625
                goto done;
 
626
        }
 
627
 
 
628
        dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle,
 
629
                                        DBUS_TYPE_INVALID);
 
630
 
 
631
        ofono_info("Registered handle for channel %d: 0x%x",
 
632
                        server->channel, server->handle);
 
633
 
 
634
done:
 
635
        dbus_message_unref(reply);
 
636
}
 
637
 
 
638
static void add_record(gpointer data, gpointer user_data)
 
639
{
 
640
        struct server *server = data;
 
641
 
 
642
        if (server->sdp_record == NULL)
 
643
                return;
 
644
 
 
645
        bluetooth_send_with_reply(adapter_any_path,
 
646
                                        BLUEZ_SERVICE_INTERFACE, "AddRecord",
 
647
                                        add_record_cb, server, NULL, -1,
 
648
                                        DBUS_TYPE_STRING, &server->sdp_record,
 
649
                                        DBUS_TYPE_INVALID);
 
650
}
 
651
 
 
652
static void find_adapter_cb(DBusPendingCall *call, gpointer user_data)
 
653
{
 
654
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
 
655
        DBusError derr;
 
656
        const char *path;
 
657
 
 
658
        dbus_error_init(&derr);
 
659
 
 
660
        if (dbus_set_error_from_message(&derr, reply)) {
 
661
                ofono_error("Replied with an error: %s, %s",
 
662
                                        derr.name, derr.message);
 
663
                dbus_error_free(&derr);
 
664
                goto done;
 
665
        }
 
666
 
 
667
        dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 
668
                                        DBUS_TYPE_INVALID);
 
669
 
 
670
        adapter_any_path = g_strdup(path);
 
671
 
 
672
        g_slist_foreach(server_list, (GFunc) add_record, NULL);
 
673
 
 
674
done:
 
675
        dbus_message_unref(reply);
 
676
}
 
677
 
412
678
static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
413
679
                                void *user_data)
414
680
{
467
733
static void manager_properties_cb(DBusPendingCall *call, gpointer user_data)
468
734
{
469
735
        DBusMessage *reply;
 
736
        DBusError derr;
470
737
 
471
738
        reply = dbus_pending_call_steal_reply(call);
472
739
 
473
 
        if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
474
 
                DBG("Bluetooth daemon is apparently not available.");
 
740
        dbus_error_init(&derr);
 
741
 
 
742
        if (dbus_set_error_from_message(&derr, reply)) {
 
743
                ofono_error("Manager.GetProperties() replied an error: %s, %s",
 
744
                                        derr.name, derr.message);
 
745
                dbus_error_free(&derr);
475
746
                goto done;
476
747
        }
477
748
 
492
763
        profile->remove_all();
493
764
}
494
765
 
 
766
static void bluetooth_connect(DBusConnection *connection, void *user_data)
 
767
{
 
768
        bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
 
769
                                manager_properties_cb, NULL, NULL, -1,
 
770
                                DBUS_TYPE_INVALID);
 
771
 
 
772
        bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter",
 
773
                                find_adapter_cb, NULL, NULL, -1,
 
774
                                DBUS_TYPE_STRING, &adapter_any_name,
 
775
                                DBUS_TYPE_INVALID);
 
776
}
 
777
 
495
778
static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
496
779
{
497
780
        if (uuid_hash == NULL)
498
781
                return;
499
782
 
500
783
        g_hash_table_foreach(uuid_hash, bluetooth_remove_all_modem, NULL);
 
784
 
 
785
        g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL);
501
786
}
502
787
 
503
788
static guint bluetooth_watch;
513
798
        connection = ofono_dbus_get_connection();
514
799
 
515
800
        bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
516
 
                                        NULL, bluetooth_disconnect, NULL, NULL);
 
801
                                        bluetooth_connect,
 
802
                                        bluetooth_disconnect, NULL, NULL);
517
803
 
518
804
        adapter_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
519
805
                                                BLUEZ_MANAGER_INTERFACE,
558
844
        if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE)
559
845
                return;
560
846
 
 
847
        g_free(adapter_any_path);
 
848
        adapter_any_path = NULL;
 
849
 
561
850
        g_dbus_remove_watch(connection, bluetooth_watch);
562
851
        g_dbus_remove_watch(connection, adapter_added_watch);
563
852
        g_dbus_remove_watch(connection, adapter_removed_watch);
571
860
{
572
861
        bluetooth_ref();
573
862
 
574
 
        if (bluetooth_refcount == 0)
575
 
                return -EIO;
576
 
 
577
863
        g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
578
864
 
579
 
        bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
580
 
                                manager_properties_cb, NULL, NULL, -1,
581
 
                                DBUS_TYPE_INVALID);
 
865
        g_hash_table_foreach(adapter_address_hash,
 
866
                                (GHFunc) get_adapter_properties, NULL);
582
867
 
583
868
        return 0;
584
869
}
590
875
        bluetooth_unref();
591
876
}
592
877
 
 
878
struct server *bluetooth_register_server(guint8 channel, const char *sdp_record,
 
879
                                        ConnectFunc cb, gpointer user_data)
 
880
{
 
881
        struct server *server;
 
882
        GError *err;
 
883
 
 
884
        server = g_try_new0(struct server, 1);
 
885
        if (!server)
 
886
                return NULL;
 
887
 
 
888
        server->channel = channel;
 
889
 
 
890
        server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection,
 
891
                                        server, NULL, &err,
 
892
                                        BT_IO_OPT_CHANNEL, server->channel,
 
893
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
 
894
                                        BT_IO_OPT_INVALID);
 
895
        if (server->io == NULL) {
 
896
                g_error_free(err);
 
897
                g_free(server);
 
898
                return NULL;
 
899
        }
 
900
 
 
901
        bluetooth_ref();
 
902
 
 
903
        if (sdp_record != NULL)
 
904
                server->sdp_record = g_strdup(sdp_record);
 
905
 
 
906
        server->connect_cb = cb;
 
907
        server->user_data = user_data;
 
908
 
 
909
        server_list = g_slist_prepend(server_list, server);
 
910
 
 
911
        if (adapter_any_path != NULL)
 
912
                add_record(server, NULL);
 
913
 
 
914
        return server;
 
915
}
 
916
 
 
917
void bluetooth_unregister_server(struct server *server)
 
918
{
 
919
        server_list = g_slist_remove(server_list, server);
 
920
 
 
921
        remove_record(server);
 
922
 
 
923
        if (server->io != NULL) {
 
924
                g_io_channel_shutdown(server->io, TRUE, NULL);
 
925
                g_io_channel_unref(server->io);
 
926
                server->io = NULL;
 
927
        }
 
928
 
 
929
        g_free(server->sdp_record);
 
930
        g_free(server);
 
931
 
 
932
        bluetooth_unref();
 
933
}
 
934
 
593
935
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
594
936
                        OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL)