* [PATCH] android: Avoid memory leak warnings for event_loop
From: Andrei Emeltchenko @ 2013-11-27 15:17 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Move creation of event_loop closer to g_main_loop_run. This avoids
calling g_main_loop_unref too many times in initialization error paths.
This is safe since g_main_loop_quit eval to NOOP if parameter == NULL.
---
android/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/main.c b/android/main.c
index c9733f3..9eaef7f 100644
--- a/android/main.c
+++ b/android/main.c
@@ -558,7 +558,6 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
- event_loop = g_main_loop_new(NULL, FALSE);
signal = setup_signalfd();
if (!signal)
return EXIT_FAILURE;
@@ -583,6 +582,8 @@ int main(int argc, char *argv[])
DBG("Entering main loop");
+ event_loop = g_main_loop_new(NULL, FALSE);
+
g_main_loop_run(event_loop);
g_source_remove(signal);
--
1.8.3.2
^ permalink raw reply related
* [RFC] build: Force GLib version check while building in maintainer mode
From: Szymon Janc @ 2013-11-27 15:44 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This will allow to catch up build errors introduced by using GLib API
introduced in newer GLib than minimal required even if building with
newer version.
---
acinclude.m4 | 2 ++
1 file changed, 2 insertions(+)
diff --git a/acinclude.m4 b/acinclude.m4
index 5bfa29d..2065852 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -21,6 +21,8 @@ AC_DEFUN([COMPILER_FLAGS], [
with_cflags="$with_cflags -Wredundant-decls"
with_cflags="$with_cflags -Wcast-align"
with_cflags="$with_cflags -DG_DISABLE_DEPRECATED"
+ with_cflags="$with_cflags -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_28"
+ with_cflags="$with_cflags -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_28"
fi
AC_SUBST([WARNING_CFLAGS], $with_cflags)
])
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/5] android: Avoid memory leak warnings for event_loop
From: Andrei Emeltchenko @ 2013-11-27 16:19 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Move creation of event_loop closer to g_main_loop_run. This avoids
calling g_main_loop_unref too many times in initialization error paths.
This is safe since g_main_loop_quit eval to NOOP if parameter == NULL.
---
android/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/main.c b/android/main.c
index bfd2a87..830eef2 100644
--- a/android/main.c
+++ b/android/main.c
@@ -559,7 +559,6 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
- event_loop = g_main_loop_new(NULL, FALSE);
signal = setup_signalfd();
if (!signal)
return EXIT_FAILURE;
@@ -584,6 +583,8 @@ int main(int argc, char *argv[])
DBG("Entering main loop");
+ event_loop = g_main_loop_new(NULL, FALSE);
+
g_main_loop_run(event_loop);
g_source_remove(signal);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/5] android/main: Remove timeout source on exit
From: Andrei Emeltchenko @ 2013-11-27 16:19 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385569154-11579-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This fixes memory leak types of warnings from some tools.
---
android/main.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/android/main.c b/android/main.c
index 830eef2..dd5c622 100644
--- a/android/main.c
+++ b/android/main.c
@@ -575,8 +575,10 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- if (!bt_bluetooth_start(option_index, adapter_ready))
+ if (!bt_bluetooth_start(option_index, adapter_ready)) {
+ g_source_remove(bluetooth_start_timeout);
return EXIT_FAILURE;
+ }
/* Use params: mtu = 0, flags = 0 */
start_sdp_server(0, 0);
@@ -589,6 +591,9 @@ int main(int argc, char *argv[])
g_source_remove(signal);
+ if (bluetooth_start_timeout > 0)
+ g_source_remove(bluetooth_start_timeout);
+
cleanup_hal_connection();
stop_sdp_server();
bt_bluetooth_cleanup();
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/5] android/main: Remove signal source on exit
From: Andrei Emeltchenko @ 2013-11-27 16:19 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385569154-11579-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Remove signal source on exit and move check capability function in order
to avoid extra check.
---
android/main.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/android/main.c b/android/main.c
index dd5c622..e408c21 100644
--- a/android/main.c
+++ b/android/main.c
@@ -536,6 +536,9 @@ int main(int argc, char *argv[])
GError *err = NULL;
guint signal;
+ if (!set_capabilities())
+ return EXIT_FAILURE;
+
/* Core Service (ID=0) should always be considered registered */
services[0] = true;
@@ -565,18 +568,17 @@ int main(int argc, char *argv[])
__btd_log_init("*", 0);
- if (!set_capabilities())
- return EXIT_FAILURE;
-
bluetooth_start_timeout = g_timeout_add_seconds(STARTUP_GRACE_SECONDS,
quit_eventloop, NULL);
if (bluetooth_start_timeout == 0) {
error("Failed to init startup timeout");
+ g_source_remove(signal);
return EXIT_FAILURE;
}
if (!bt_bluetooth_start(option_index, adapter_ready)) {
g_source_remove(bluetooth_start_timeout);
+ g_source_remove(signal);
return EXIT_FAILURE;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/5] android/socket: Cleanup sockets on unregister
From: Andrei Emeltchenko @ 2013-11-27 16:19 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385569154-11579-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This cleans up rfsock structures closing all sockets and making general cleanup
for servers and for connections. This will be called form socket unregister.
---
android/socket.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 1fb154d..d55db54 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -943,7 +943,27 @@ bool bt_socket_register(int sk, const bdaddr_t *addr)
return true;
}
+static void free_connection(gpointer data, gpointer user_data)
+{
+ struct rfcomm_sock *rfsock = data;
+
+ connections = g_list_remove(connections, rfsock);
+ cleanup_rfsock(rfsock);
+}
+
+static void free_server(gpointer data, gpointer user_data)
+{
+ struct rfcomm_sock *rfsock = data;
+
+ servers = g_list_remove(servers, rfsock);
+ cleanup_rfsock(rfsock);
+}
+
void bt_socket_unregister(void)
{
DBG("");
+
+ g_list_foreach(connections, free_connection, NULL);
+
+ g_list_foreach(servers, free_server, NULL);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 5/5] android/socket: Fix rfsock lists
From: Andrei Emeltchenko @ 2013-11-27 16:19 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1385569154-11579-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This fixes several places where rfsock structure were not removed
from the list due to connection errors.
---
android/socket.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index d55db54..3f07dc6 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -625,8 +625,6 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
return;
}
- connections = g_list_append(connections, rfsock_acc);
-
DBG("rfsock: fd %d real_sock %d chan %u sock %d",
rfsock->fd, rfsock->real_sock, rfsock->channel,
sock_acc);
@@ -636,6 +634,8 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
return;
}
+ connections = g_list_append(connections, rfsock_acc);
+
/* Handle events from Android */
cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
io_stack = g_io_channel_unix_new(rfsock_acc->fd);
@@ -700,7 +700,6 @@ static int handle_listen(void *buf)
}
rfsock->real_sock = g_io_channel_unix_get_fd(io);
- servers = g_list_append(servers, rfsock);
/* TODO: Add server watch */
g_io_channel_set_close_on_unref(io, TRUE);
@@ -717,6 +716,8 @@ static int handle_listen(void *buf)
rfsock->service_handle = sdp_service_register(profile, cmd->name);
+ servers = g_list_append(servers, rfsock);
+
return hal_fd;
}
@@ -787,6 +788,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
return;
fail:
+ connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
}
@@ -865,6 +867,7 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
return;
fail:
+ connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
}
--
1.8.3.2
^ permalink raw reply related
* Re: [RFC BlueZ v1] doc: Add GATT API
From: Claudio Takahasi @ 2013-11-27 19:45 UTC (permalink / raw)
To: Scott James Remnant; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CAHZ1yCmKocpuqhZXA_-=sxR6SPmfB1UdcRYH93evneM_nCqU7Q@mail.gmail.com>
Hi Scott:
On Fri, Nov 15, 2013 at 4:47 PM, Scott James Remnant <keybuk@google.com> wrote:
> On Tue, Nov 12, 2013 at 10:49 AM, Claudio Takahasi
> <claudio.takahasi@openbossa.org> wrote:
>
>> On Mon, Nov 11, 2013 at 3:56 PM, Scott James Remnant <keybuk@google.com> wrote:
>>> How will service changed be handled? How will BlueZ track the set of
>>> applications, and the set of services etc. defined by those
>>> applications in a manner that keeps handles consistent? How will it
>>> handle generating the Services Changed notification in the cases where
>>> the set of applications and/or services change, or the handles change?
>>
>> We implemented a hash of declarations. Using the "Id" provided in the
>> options dictionary (see RegisterAgent) we are able to identity if the
>> external service changed its attributes.
>> However, I don' t think we will upstream this approach soon, Marcel
>> wants a simpler approach: always send ServiceChanged.
>>
>
> While this is probably "spec sufficient", and probably sufficient for
> passing qualification, I'm not sure that this is necessarily the best
> approach since this means that BlueZ when acting as a GATT Server
> wouldn't be behaving quite the same as, say, a commodity BTLE device.
>
>>>> +Characteristic hierarchy
>>>> +========================
>>> :
>>>> +Service org.bluez
>>>> +Interface org.bluez.Characteristic1 [Experimental]
>>>> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY
>>>
>>> This would also need a "Permissions" property akin to the one you have
>>> for Descriptors - characteristics can be "not accessible", read-only,
>>> write-only, read/write - and can also require authorization,
>>> authentication, encryption and minimum encryption key sizes - as with
>>> descriptors.
>>
>> It is implemented already, there is an optional "Flags" property :
>> "array{string} Flags [read-only, optional]"
>>
>
> Flags seemed to correspond to the Flags characteristic descriptor and
> not the simple permissions of the characteristic itself.
"Flags" refers to Core SPEC page 1898: "3.3.1.1 Characteristic Properties"
The naming is not helping here. The original suggestion was
"Properties", but it may mislead to D-Bus Properties.
>
>>>> + array{byte} Value [read-write]
>>>> +
>>>> + Cached Value of the characteristic. If present, the
>>>> + value will be cached by bluetoothd and updated when the
>>>> + PropertiesChanged signal is emitted.
>>>> +
>>>> + External services must emit this signal when the
>>>> + characteristic supports notification/indication, so
>>>> + that clients can be notified of the new value.
>>>
>>> The PropertiesChanged signal explains how Notification will be handled
>>> - but how will Indication? How will a service receive the Indication
>>> Confirmation from the remote devices?
>>
>> The bluetoothd core manages the Confirmation. In my opinion clients
>> listening for PropertiesChanged don' t need to know the difference
>> between notification and indication.
>> Allow an external client to manage the Confirmation will insert
>> additional complexity without giving real benefits.
>>
>
> I'm thinking of the opposite way around - not the clients, but the services.
>
> If I implement a service over the D-Bus API, and a characteristic
> supports Indication, then is it not important that the service be
> informed when the clients confirm the Indication that is sent out?
I understand your concerns. However, moving this control to the
servers may require persistence, and access to device and connection
information in the server implementation.
One alternative could be extend the ApplcationAgent1 interface adding
a method to inform timeout (confirmation not received for a given
characteristic).
>
> Otherwise it makes Indications identical to Notifications when
> implementing a service using the BlueZ D-Bus API, which may cause
> issues with implementing certain profiles.
We can assume that Indication has higher priority, and the Properties
( Indication/Notification) can be inferred during the declaration.
>
>
>>>> +Application Agent hierarchy
>>>> +===========================
>>>> +
>>>> +Service unique name
>>>> +Interface org.bluez.ApplicationAgent1 [Experimental]
>>>> +Object path freely definable
>>>> +
>>>
>>> "Agent" seems unnnecessary here - if the object is an Application,
>>> then org.bluez.Application1 would be a decent enough name. Thus an
>>> "Application" consists of multiple Services, each of which consists of
>>> multiple Characteristics, each of which has multiple Descriptors
>>
>> IMO "Agent" gives a better association with its functionality, it
>> reminds me org.bluez.Agent1.
>> Let's wait the opinion of the others developers...
>>
>
> I was more thinking that we have "AgentManager" -> "Agent",
> "ProfileManager" -> "Profile", "ServiceManager" -> "Service" ... all
> of those use the agent-style pattern, but only "Pairing" Agent is
> called Agent.
>
> But honestly, bike shedding ;-) I'm only complaining because calling
> it "ApplicationAgent" would slightly screw up my naming convention
> inside Chromium
My first proposal was ServiceManager1 and Service1.
Maybe renaming the registration method to RegisterService() and moving
Release method to Service1 will make it similar to Profile1, and
easier to understand. Potential errors can be reported through a
method under Service1 interface.
However, this last suggestion will trigger unneeded calls of
GetManagedObjects(), basically one call per service registration.
I will try a new round based on your inputs and wait for feedbacks.
Regards,
Claudio
^ permalink raw reply
* Re: [PATCH 3/5] android/main: Remove signal source on exit
From: Andrei Emeltchenko @ 2013-11-27 20:25 UTC (permalink / raw)
To: Bluetooth Linux
In-Reply-To: <1385569154-11579-3-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi,
On Wed, Nov 27, 2013 at 6:19 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Remove signal source on exit and move check capability function in order
> to avoid extra check.
> ---
> android/main.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/android/main.c b/android/main.c
> index dd5c622..e408c21 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -536,6 +536,9 @@ int main(int argc, char *argv[])
> GError *err = NULL;
> guint signal;
>
> + if (!set_capabilities())
> + return EXIT_FAILURE;
> +
Please disregard this patch, debug needs to be initialized first.
> /* Core Service (ID=0) should always be considered registered */
> services[0] = true;
>
> @@ -565,18 +568,17 @@ int main(int argc, char *argv[])
>
> __btd_log_init("*", 0);
>
> - if (!set_capabilities())
> - return EXIT_FAILURE;
> -
> bluetooth_start_timeout = g_timeout_add_seconds(STARTUP_GRACE_SECONDS,
> quit_eventloop, NULL);
> if (bluetooth_start_timeout == 0) {
> error("Failed to init startup timeout");
> + g_source_remove(signal);
> return EXIT_FAILURE;
> }
>
> if (!bt_bluetooth_start(option_index, adapter_ready)) {
> g_source_remove(bluetooth_start_timeout);
> + g_source_remove(signal);
> return EXIT_FAILURE;
> }
>
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [RFC BlueZ v2] doc: Add GATT API
From: Claudio Takahasi @ 2013-11-27 20:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <CAKT1EBdB7cvhmnqf2FV-F=RWwdnvhpUuc3AENHaYCao_dNyH_w@mail.gmail.com>
This patch proposes an unified GATT API for local and remote services.
---
v2: API similar to Profile1 and ProfileManager1
doc/gatt-api.txt | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
create mode 100644 doc/gatt-api.txt
diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
new file mode 100644
index 0000000..d2545b2
--- /dev/null
+++ b/doc/gatt-api.txt
@@ -0,0 +1,145 @@
+BlueZ D-Bus GATT API description
+********************************
+
+GATT local and remote services share the same high-level D-Bus API. Local
+refers to GATT based service exported by a BlueZ plugin or an external
+application. Remote refers to GATT services exported by the peer.
+
+BlueZ acts as a proxy, translating ATT operations to D-Bus method calls and
+Properties (or the opposite). Support for D-Bus Object Manager is mandatory for
+external services to allow seamless GATT declarations (Service, Characteristic
+and Descriptors) discovery.
+
+Service hierarchy
+=================
+
+GATT remote and local service representation. Object path for local services
+is freely definable.
+
+External applications implementing local services must register the services
+using ServiceManager1 registration method and must implement the methods and
+properties defined in Service1 interface.
+
+Service org.bluez
+Interface org.bluez.Service1 [Experimental]
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX
+
+Methods void Release()
+
+ Release this service. At this point, it will not be
+ used by BlueZ anymore and can be destroyed by the
+ owner. Method applicable to external GATT services
+ implementations only (GATT servers).
+
+Properties string UUID [read-only]
+
+ 128-bit service UUID.
+
+ array{object} Includes [read-only]: Not implemented
+
+ Array of object paths representing the included
+ services of this service.
+
+
+Characteristic hierarchy
+========================
+
+For local GATT defined services, the object paths need to follow the service
+path hierarchy and are freely definable.
+
+Service org.bluez
+Interface org.bluez.Characteristic1 [Experimental]
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY
+
+Properties string UUID [read-only]
+
+ 128-bit characteristic UUID.
+
+ object Service [read-only]
+
+ Object path of the GATT service the characteristc
+ belongs to.
+
+ array{byte} Value [read-write]
+
+ Value read from the remote Bluetooth device or from
+ the external application implementing GATT services.
+
+ array{string} Flags [read-only, optional]
+
+ Defines how the characteristic value can be used. See
+ Core spec page 1898, "Table 3.5: Characteristic
+ Properties bit field" and page 1900, "Table 3.8:
+ Characteristic Extended Properties bit field". Allowed
+ values: "broadcast", "read", "write-without-response",
+ "write", "notify", "indicate",
+ "authenticated-signed-writes", "reliable-write", and
+ "writable-auxiliaries".
+
+
+Characteristic Descriptors hierarchy
+====================================
+
+Local or remote GATT characteristic descriptors hierarchy.
+
+Service org.bluez
+Interface org.bluez.Descriptor1 [Experimental]
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ
+
+Properties string UUID [read-only]
+
+ 128-bit descriptor UUID.
+
+ object Characteristic [read-only]
+
+ Object path of the GATT characteristc the descriptor
+ belongs to.
+
+ array{byte} Value [read-write]
+
+ Raw characteristic descriptor value read from the
+ remote Bluetooth device or from the external
+ application implementing GATT services.
+
+ string Permissions [read-only]: To be defined
+
+ Defines read/write authentication and authorization
+ requirements.
+
+Service Manager hierarchy
+=============================
+
+Service Manager allows external applications to register GATT based
+services. Services must follow the API for Service and Characteristic
+described above.
+
+Local GATT services, characteristics and characteristic descriptors are
+discovered automatically using the D-Bus Object Manager interface.
+
+Service org.bluez
+Interface org.bluez.ServiceManager1 [Experimental]
+Object path /org/bluez
+
+Methods RegisterService(object service, dict options)
+
+ Registers remote application service exported under
+ the interface Service1. Characteristic objects must
+ be hierarchical to their service and must use the
+ interface Characteristic1. D-Bus Object Manager is
+ used to fetch the exported objects.
+
+ "service" object path together with the D-Bus system
+ bus connection ID define the identification of the
+ application registering a GATT based service.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ UnregisterService(object service)
+
+ This unregisters the service that has been
+ previously registered. The object path parameter
+ must match the same value that has been used
+ on registration.
+
+ Possible errors: org.bluez.Error.DoesNotExist
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 00/17] GATT API: External Services
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
This patchset implements the minimal support for managing local
services declarations. Based on "[RFC BlueZ v2] doc: Add GATT API"
Features:
* API for internal and external services declaration
* Unix socket for testing purpose: services are exported
through unix sockets to avoid breaking the current attribute
server.
How to test:
Replace bluetooth.conf and reload DBus settings
$gatttool -L --primary (or interactive mode)
Upstreaming plan (steps):
* GATT Server: External Services
* GATT Server: External Characteristics (Server)
* GATT Server: External Descriptors (Server)
* Remove ATTIO and automatic connection mechanism from userspace
* Replace attribute server
* Fix all GATT internal plugins
* GATT Client: Remote Services
* ...
Alvaro Silva (7):
gatt: Add stub for gatt file
gatt: Register Manager D-Bus Interface
gatt: Add registering external service
gatt: Add external services tracking
gatt: Implement UnregisterService
gatt: Register ATT command/event handler
gatt: Add Discover All Primary Services
Andre Guedes (1):
gatt: Add helper for creating GATT services
Claudio Takahasi (9):
lib: Add GATT Primary Service UUID
gatt: Add server unix socket
gattrib: Use default ATT LE MTU for non-standard sockets
test: Add external service GATT skeleton
test: Add signal handling for gatt-service
test: Add registering external service
gatttool: Add unix socket connect
gatttool: Add unix socket support for interactive mode
bluetooth.conf: Add ObjectManager interface
Makefile.am | 2 +
Makefile.tools | 5 +
attrib/gattrib.c | 16 +--
attrib/gatttool.c | 27 +++-
attrib/gatttool.h | 1 +
attrib/interactive.c | 18 +--
attrib/utils.c | 54 ++++++++
lib/uuid.c | 14 ++
lib/uuid.h | 5 +
src/bluetooth.conf | 1 +
src/gatt-dbus.c | 296 ++++++++++++++++++++++++++++++++++++++++
src/gatt-dbus.h | 25 ++++
src/gatt.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt.h | 36 +++++
src/main.c | 4 +
test/gatt-service.c | 254 +++++++++++++++++++++++++++++++++++
16 files changed, 1106 insertions(+), 23 deletions(-)
create mode 100644 src/gatt-dbus.c
create mode 100644 src/gatt-dbus.h
create mode 100644 src/gatt.c
create mode 100644 src/gatt.h
create mode 100644 test/gatt-service.c
--
1.8.3.1
^ permalink raw reply
* [RFC BlueZ v0 01/17] gatt: Add stub for gatt file
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This file intend to implement functions to manipulate ATT transactions,
and expose functions to allow other entities to manage GATT based
services.
---
Makefile.am | 1 +
src/gatt.c | 38 ++++++++++++++++++++++++++++++++++++++
src/gatt.h | 26 ++++++++++++++++++++++++++
src/main.c | 4 ++++
4 files changed, 69 insertions(+)
create mode 100644 src/gatt.c
create mode 100644 src/gatt.h
diff --git a/Makefile.am b/Makefile.am
index 2bb2eb5..395f23e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -146,6 +146,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/adapter.h src/adapter.c \
src/profile.h src/profile.c \
src/service.h src/service.c \
+ src/gatt.h src/gatt.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
src/eir.h src/eir.c \
diff --git a/src/gatt.c b/src/gatt.c
new file mode 100644
index 0000000..1ada2ed
--- /dev/null
+++ b/src/gatt.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gatt.h"
+
+void gatt_init(void)
+{
+
+}
+
+void gatt_cleanup(void)
+{
+
+}
diff --git a/src/gatt.h b/src/gatt.h
new file mode 100644
index 0000000..03a68a1
--- /dev/null
+++ b/src/gatt.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void gatt_init(void);
+
+void gatt_cleanup(void);
diff --git a/src/main.c b/src/main.c
index 91d90b4..fccc838 100644
--- a/src/main.c
+++ b/src/main.c
@@ -55,6 +55,7 @@
#include "dbus-common.h"
#include "agent.h"
#include "profile.h"
+#include "gatt.h"
#include "systemd.h"
#define BLUEZ_NAME "org.bluez"
@@ -545,6 +546,8 @@ int main(int argc, char *argv[])
g_dbus_set_flags(gdbus_flags);
+ gatt_init();
+
if (option_compat == TRUE)
sdp_flags |= SDP_SERVER_COMPAT;
@@ -595,6 +598,7 @@ int main(int argc, char *argv[])
btd_profile_cleanup();
btd_agent_cleanup();
btd_device_cleanup();
+ gatt_cleanup();
adapter_cleanup();
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 02/17] gatt: Register Manager D-Bus Interface
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers the Service Manager D-Bus Interface. This
interface implements the methods to allow external application register
and unregister GATT Services.
---
Makefile.am | 1 +
src/gatt-dbus.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt-dbus.h | 25 +++++++++++++++++++
src/gatt.c | 9 +++++++
4 files changed, 110 insertions(+)
create mode 100644 src/gatt-dbus.c
create mode 100644 src/gatt-dbus.h
diff --git a/Makefile.am b/Makefile.am
index 395f23e..d88b1cb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -146,6 +146,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/adapter.h src/adapter.c \
src/profile.h src/profile.c \
src/service.h src/service.c \
+ src/gatt-dbus.h src/gatt-dbus.c \
src/gatt.h src/gatt.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
new file mode 100644
index 0000000..c28c33c
--- /dev/null
+++ b/src/gatt-dbus.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "log.h"
+
+#include "gatt-dbus.h"
+
+#define SERVICE_MGR_IFACE "org.bluez.ServiceManager1"
+
+static DBusMessage *register_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+ { GDBUS_EXPERIMENTAL_METHOD("RegisterService",
+ GDBUS_ARGS({ "service", "o"},
+ { "options", "a{sv}"}),
+ NULL, register_service) },
+ { GDBUS_EXPERIMENTAL_METHOD("UnregisterService",
+ GDBUS_ARGS({"service", "o"}),
+ NULL, unregister_service) },
+ { }
+};
+
+gboolean gatt_dbus_manager_register(void)
+{
+ return g_dbus_register_interface(btd_get_dbus_connection(),
+ "/org/bluez", SERVICE_MGR_IFACE,
+ methods, NULL, NULL, NULL, NULL);
+}
+
+void gatt_dbus_manager_unregister(void)
+{
+ g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
+ SERVICE_MGR_IFACE);
+}
diff --git a/src/gatt-dbus.h b/src/gatt-dbus.h
new file mode 100644
index 0000000..7812ba1
--- /dev/null
+++ b/src/gatt-dbus.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+gboolean gatt_dbus_manager_register(void);
+void gatt_dbus_manager_unregister(void);
diff --git a/src/gatt.c b/src/gatt.c
index 1ada2ed..45fd9f8 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,14 +25,23 @@
#include <config.h>
#endif
+#include <glib.h>
+
+#include "log.h"
+
+#include "gatt-dbus.h"
#include "gatt.h"
void gatt_init(void)
{
+ DBG("Starting GATT server");
+ gatt_dbus_manager_register();
}
void gatt_cleanup(void)
{
+ DBG("Stopping GATT server");
+ gatt_dbus_manager_unregister();
}
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 03/17] gatt: Add registering external service
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch allows external applications register a given service on
Bluez. Applications must provide an object path and a dictionary of
options. Options dictionary will be used later to provide additional
service information.
---
src/gatt-dbus.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 91 insertions(+), 1 deletion(-)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index c28c33c..69581a4 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -26,22 +26,112 @@
#endif
#include <stdint.h>
+#include <errno.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
+#include "adapter.h"
+#include "device.h"
+#include "lib/uuid.h"
#include "dbus-common.h"
#include "log.h"
+#include "error.h"
#include "gatt-dbus.h"
#define SERVICE_MGR_IFACE "org.bluez.ServiceManager1"
+struct external_app {
+ char *owner;
+ char *path;
+ GDBusClient *client;
+ unsigned int watch;
+};
+
+static GSList *external_apps = NULL;
+
+static int external_app_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct external_app *eapp = a;
+ const char *path = b;
+
+ return g_strcmp0(eapp->path, path);
+}
+
+static void external_app_watch_destroy(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+
+ /* TODO: Remove from the database */
+
+ external_apps = g_slist_remove(external_apps, eapp);
+
+ g_dbus_client_unref(eapp->client);
+
+ g_free(eapp->owner);
+ g_free(eapp->path);
+ g_free(eapp);
+}
+
+static struct external_app *new_external_app(DBusConnection *conn,
+ const char *sender, const char *path)
+{
+ struct external_app *eapp;
+ GDBusClient *client;
+
+ client = g_dbus_client_new(conn, sender, "/");
+ if (client == NULL)
+ return NULL;
+
+ eapp = g_new0(struct external_app, 1);
+
+ eapp->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+ sender, NULL, eapp, external_app_watch_destroy);
+ if (eapp->watch == 0) {
+ g_dbus_client_unref(client);
+ g_free(eapp);
+ return NULL;
+ }
+
+ eapp->owner = g_strdup(sender);
+ eapp->client = client;
+ eapp->path = g_strdup(path);
+
+ return eapp;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
- return dbus_message_new_method_return(msg);
+ struct external_app *eapp;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (dbus_message_iter_init(msg, &iter) == false)
+ goto invalid;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+ goto invalid;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
+ return btd_error_already_exists(msg);
+
+ eapp = new_external_app(conn, dbus_message_get_sender(msg), path);
+ if (eapp == NULL)
+ return btd_error_failed(msg, "Not enough resources");
+
+ external_apps = g_slist_prepend(external_apps, eapp);
+
+ DBG("New app %p: %s", eapp, path);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+invalid:
+ return btd_error_invalid_args(msg);
}
static DBusMessage *unregister_service(DBusConnection *conn,
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 04/17] lib: Add GATT Primary Service UUID
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
---
lib/uuid.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index 95e5a9a..87e0bd0 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -105,6 +105,9 @@ extern "C" {
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
+/* GATT UUIDs section */
+#define GATT_PRIM_SVC_UUID 0x2800
+
typedef struct {
enum {
BT_UUID_UNSPEC = 0,
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 05/17] gatt: Add helper for creating GATT services
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andre Guedes
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Andre Guedes <andre.guedes@openbossa.org>
This patch adds the btd_gatt_add_service() helper which adds a
GATT Service declaration to the local attribute database.
---
lib/uuid.c | 14 ++++++++++++++
lib/uuid.h | 2 ++
src/gatt.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt.h | 10 ++++++++++
4 files changed, 76 insertions(+)
diff --git a/lib/uuid.c b/lib/uuid.c
index 4363aee..15d1321 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -276,3 +276,17 @@ int bt_uuid_strcmp(const void *a, const void *b)
{
return strcasecmp(a, b);
}
+
+int bt_uuid_len(const bt_uuid_t *uuid)
+{
+ switch (uuid->type) {
+ case BT_UUID16:
+ return 2;
+ case BT_UUID32:
+ return 4;
+ case BT_UUID128:
+ return 16;
+ default:
+ return 0;
+ }
+}
diff --git a/lib/uuid.h b/lib/uuid.h
index 87e0bd0..f8b2593 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -136,6 +136,8 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
+int bt_uuid_len(const bt_uuid_t *uuid);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gatt.c b/src/gatt.c
index 45fd9f8..86023a4 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -27,11 +27,61 @@
#include <glib.h>
+#include "adapter.h"
+#include "device.h"
+
#include "log.h"
+#include "lib/uuid.h"
+#include "attrib/att.h"
#include "gatt-dbus.h"
#include "gatt.h"
+/* Common GATT UUIDs */
+static const bt_uuid_t primary_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_PRIM_SVC_UUID };
+
+struct btd_attribute {
+ uint16_t handle;
+ bt_uuid_t type;
+ uint16_t value_len;
+ uint8_t value[0];
+};
+
+static GList *local_attribute_db = NULL;
+static uint16_t next_handle = 0x0001;
+
+static int local_database_add(uint16_t handle, struct btd_attribute *attr)
+{
+ attr->handle = handle;
+
+ local_attribute_db = g_list_append(local_attribute_db, attr);
+
+ return 0;
+}
+
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
+{
+ uint16_t len = bt_uuid_len(uuid);
+ struct btd_attribute *attr = g_malloc0(sizeof(struct btd_attribute) +
+ len);
+
+ memcpy(&attr->type, &primary_uuid, sizeof(primary_uuid));
+
+ att_put_uuid(*uuid, attr->value);
+ attr->value_len = len;
+
+ if (local_database_add(next_handle, attr) < 0) {
+ g_free(attr);
+ return NULL;
+ }
+
+ /* TODO: missing overflow checking */
+ next_handle = next_handle + 1;
+
+ return attr;
+}
+
void gatt_init(void)
{
DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 03a68a1..41ca4b6 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -21,6 +21,16 @@
*
*/
+struct btd_attribute;
+
void gatt_init(void);
void gatt_cleanup(void);
+
+/* btd_gatt_add_service - Add a service declaration to local attribute database.
+ * @uuid: Service UUID.
+ *
+ * Returns a reference to service declaration attribute. In case of error,
+ * NULL is returned.
+ */
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 06/17] gatt: Add external services tracking
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
All primary services declarations provided by an external application
will be automatically inserted in the attribute database.
---
src/gatt-dbus.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 69581a4..a53eed2 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,15 +39,21 @@
#include "log.h"
#include "error.h"
+#include "gatt.h"
#include "gatt-dbus.h"
+#define SERVICE_IFACE "org.bluez.Service1"
#define SERVICE_MGR_IFACE "org.bluez.ServiceManager1"
+#define REGISTER_TIMER 1
+
struct external_app {
char *owner;
char *path;
GDBusClient *client;
+ GSList *proxies;
unsigned int watch;
+ guint register_timer;
};
static GSList *external_apps = NULL;
@@ -60,6 +66,36 @@ static int external_app_path_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(eapp->path, path);
}
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ if (g_strcmp0(interface, SERVICE_IFACE) != 0)
+ return;
+
+ eapp->proxies = g_slist_append(eapp->proxies, proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+}
+
+
static void external_app_watch_destroy(gpointer user_data)
{
struct external_app *eapp = user_data;
@@ -70,6 +106,9 @@ static void external_app_watch_destroy(gpointer user_data)
g_dbus_client_unref(eapp->client);
+ if (eapp->register_timer)
+ g_source_remove(eapp->register_timer);
+
g_free(eapp->owner);
g_free(eapp->path);
g_free(eapp);
@@ -99,9 +138,72 @@ static struct external_app *new_external_app(DBusConnection *conn,
eapp->client = client;
eapp->path = g_strdup(path);
+ g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+ NULL, eapp);
+
return eapp;
}
+static int register_external_service(GDBusProxy *proxy)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+ bt_uuid_t btuuid;
+
+ if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (bt_string_to_uuid(&btuuid, uuid) < 0)
+ return -EINVAL;
+
+ if (btd_gatt_add_service(&btuuid) == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static gboolean finish_register(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+ GSList *list;
+
+ /*
+ * It is not possible to detect when the last proxy object
+ * was reported. "Proxy added" handler reports objects
+ * added on demand or returned by GetManagedObjects().
+ * This timer helps to register all the GATT declarations
+ * (services, characteristics and descriptors) after fetching
+ * all the D-Bus objects.
+ */
+
+ eapp->register_timer = 0;
+
+ for (list = eapp->proxies; list; list = g_slist_next(list)) {
+ const char *interface, *path;
+ GDBusProxy *proxy = list->data;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ if (g_strcmp0(SERVICE_IFACE, interface) != 0)
+ continue;
+
+ if (g_strcmp0(path, eapp->path) != 0)
+ continue;
+
+ if (register_external_service(proxy) < 0) {
+ DBG("Inconsistent external service: %s", path);
+ continue;
+ }
+
+ DBG("External service: %s", path);
+ }
+
+ return FALSE;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -109,6 +211,8 @@ static DBusMessage *register_service(DBusConnection *conn,
DBusMessageIter iter;
const char *path;
+ DBG("Registering GATT Service");
+
if (dbus_message_iter_init(msg, &iter) == false)
goto invalid;
@@ -127,6 +231,8 @@ static DBusMessage *register_service(DBusConnection *conn,
external_apps = g_slist_prepend(external_apps, eapp);
DBG("New app %p: %s", eapp, path);
+ eapp->register_timer = g_timeout_add_seconds(REGISTER_TIMER,
+ finish_register, eapp);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 07/17] gatt: Implement UnregisterService
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch implements UnregisterService method of ServiceManager1.
External applications may call this method to unregister a given
service without leaving the system bus.
---
src/gatt-dbus.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index a53eed2..a7424d5 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -243,6 +243,31 @@ invalid:
static DBusMessage *unregister_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
+ struct external_app *eapp = user_data;
+ DBusMessageIter iter;
+ const char *path;
+ GSList *list;
+
+ DBG("Unregistering GATT Service");
+
+ if (dbus_message_iter_init(msg, &iter) == false)
+ return btd_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ list = g_slist_find_custom(external_apps, path, external_app_path_cmp);
+ if (list == NULL)
+ return btd_error_does_not_exist(msg);
+
+ eapp = list->data;
+ if (g_strcmp0(dbus_message_get_sender(msg), eapp->owner) != 0)
+ return btd_error_does_not_exist(msg);
+
+ g_dbus_remove_watch(conn, eapp->watch);
+
return dbus_message_new_method_return(msg);
}
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 08/17] gatt: Add server unix socket
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds a server unix socket to handle local ATT traffic. This
is a development purpose feature used to allow local testing without
breaking the current attribute server.
---
src/gatt.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/src/gatt.c b/src/gatt.c
index 86023a4..bbd44f0 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,6 +25,11 @@
#include <config.h>
#endif
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
#include <glib.h>
#include "adapter.h"
@@ -50,6 +55,7 @@ struct btd_attribute {
static GList *local_attribute_db = NULL;
static uint16_t next_handle = 0x0001;
+static guint unix_watch;
static int local_database_add(uint16_t handle, struct btd_attribute *attr)
{
@@ -82,11 +88,71 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct sockaddr_un uaddr;
+ socklen_t len = sizeof(uaddr);
+ GIOChannel *nio;
+ int err, nsk, sk;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ nsk = accept(sk, (struct sockaddr *) &uaddr, &len);
+ if (nsk < 0) {
+ err = errno;
+ error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
+ return TRUE;
+ }
+
+ nio = g_io_channel_unix_new(nsk);
+ g_io_channel_set_close_on_unref(nio, TRUE);
+ DBG("ATT UNIX socket: %p new client", nio);
+ g_io_channel_unref(nio);
+
+ return TRUE;
+}
+
void gatt_init(void)
{
+ struct sockaddr_un uaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0/bluetooth/unix_att",
+ };
+ GIOChannel *io;
+ int sk, err;
+
DBG("Starting GATT server");
gatt_dbus_manager_register();
+
+ sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC , 0);
+ if (sk < 0) {
+ err = errno;
+ error("ATT UNIX socket: %s(%d)", strerror(err), err);
+ return;
+ }
+
+ if (bind(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+ err = errno;
+ error("binding ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ if (listen(sk, 5) < 0) {
+ err = errno;
+ error("listen ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+ unix_watch = g_io_add_watch(io,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ unix_accept_cb, NULL);
+ g_io_channel_unref(io);
}
void gatt_cleanup(void)
@@ -94,4 +160,5 @@ void gatt_cleanup(void)
DBG("Stopping GATT server");
gatt_dbus_manager_unregister();
+ g_source_remove(unix_watch);
}
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 09/17] gattrib: Use default ATT LE MTU for non-standard sockets
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
This patch forces the MTU to 23 (default ATT MTU) if the transport
is not Bluetooth. This is a development purpose change to allow
testing GATT procedures over non-Bluetooth sockets.
---
attrib/gattrib.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 609b908..fccb2bf 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -468,18 +468,18 @@ GAttrib *g_attrib_new(GIOChannel *io)
struct _GAttrib *attrib;
uint16_t imtu;
uint16_t att_mtu;
- uint16_t cid;
- GError *gerr = NULL;
+ uint16_t cid = 0;
g_io_channel_set_encoding(io, NULL, NULL);
g_io_channel_set_buffered(io, FALSE);
- bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
- BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- return NULL;
+ if (bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid,
+ BT_IO_OPT_INVALID) == FALSE) {
+ /*
+ * Use default ATT LE MTU for non-standard transports. Used
+ * for testing purpose only. eg: Unix sockets
+ */
+ imtu = ATT_DEFAULT_LE_MTU;
}
attrib = g_try_new0(struct _GAttrib, 1);
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 10/17] gatt: Register ATT command/event handler
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers the ATT channel handler to manage incoming ATT
commands and events.
---
src/gatt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/src/gatt.c b/src/gatt.c
index bbd44f0..fcb7b56 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -38,6 +38,7 @@
#include "log.h"
#include "lib/uuid.h"
#include "attrib/att.h"
+#include "attrib/gattrib.h"
#include "gatt-dbus.h"
#include "gatt.h"
@@ -88,12 +89,83 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
+ uint8_t ecode)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ size_t plen;
+
+ plen = enc_error_resp(opcode, handle, ecode, pdu, sizeof(pdu));
+
+ g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
+}
+
+static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
+ gpointer user_data)
+{
+ GAttrib *attrib = user_data;
+
+ switch (ipdu[0]) {
+ case ATT_OP_ERROR:
+ break;
+
+ /* Requests */
+ case ATT_OP_WRITE_CMD:
+ case ATT_OP_WRITE_REQ:
+ case ATT_OP_READ_REQ:
+ case ATT_OP_READ_BY_TYPE_REQ:
+ case ATT_OP_MTU_REQ:
+ case ATT_OP_FIND_INFO_REQ:
+ case ATT_OP_FIND_BY_TYPE_REQ:
+ case ATT_OP_READ_BLOB_REQ:
+ case ATT_OP_READ_MULTI_REQ:
+ case ATT_OP_PREP_WRITE_REQ:
+ case ATT_OP_EXEC_WRITE_REQ:
+ case ATT_OP_READ_BY_GROUP_REQ:
+ case ATT_OP_SIGNED_WRITE_CMD:
+ send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
+ break;
+
+ /* Responses */
+ case ATT_OP_MTU_RESP:
+ case ATT_OP_FIND_INFO_RESP:
+ case ATT_OP_FIND_BY_TYPE_RESP:
+ case ATT_OP_READ_BY_TYPE_RESP:
+ case ATT_OP_READ_RESP:
+ case ATT_OP_READ_BLOB_RESP:
+ case ATT_OP_READ_MULTI_RESP:
+ case ATT_OP_READ_BY_GROUP_RESP:
+ case ATT_OP_WRITE_RESP:
+ case ATT_OP_PREP_WRITE_RESP:
+ case ATT_OP_EXEC_WRITE_RESP:
+ case ATT_OP_HANDLE_CNF:
+ break;
+
+ /* Notification & Indication */
+ case ATT_OP_HANDLE_NOTIFY:
+ case ATT_OP_HANDLE_IND:
+ break;
+ }
+}
+
+static gboolean unix_hup_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ GAttrib *attrib = user_data;
+
+ g_attrib_unregister_all(attrib);
+ g_attrib_unref(attrib);
+
+ return FALSE;
+}
+
static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct sockaddr_un uaddr;
socklen_t len = sizeof(uaddr);
GIOChannel *nio;
+ GAttrib *attrib;
int err, nsk, sk;
sk = g_io_channel_unix_get_fd(io);
@@ -108,6 +180,14 @@ static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
nio = g_io_channel_unix_new(nsk);
g_io_channel_set_close_on_unref(nio, TRUE);
DBG("ATT UNIX socket: %p new client", nio);
+
+ attrib = g_attrib_new(nio);
+
+ g_attrib_register(attrib, GATTRIB_ALL_EVENTS, GATTRIB_ALL_HANDLES,
+ channel_handler_cb, attrib, NULL);
+
+ g_io_add_watch(nio, G_IO_HUP, unix_hup_cb, attrib);
+
g_io_channel_unref(nio);
return TRUE;
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 11/17] gatt: Add Discover All Primary Services
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Alvaro Silva
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch adds ATT Read By Group request handling to the attribute
server. It is the primitive to implement Discover All Primary Services
procedure.
---
src/gatt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/src/gatt.c b/src/gatt.c
index fcb7b56..1dc8bde 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -100,6 +100,130 @@ static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
}
+static void read_by_group_resp(GAttrib *attrib, uint16_t start,
+ uint16_t end, bt_uuid_t *pattern)
+{
+ uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ GList *list;
+ struct btd_attribute *last = NULL;
+ uint8_t *group_start, *group_end = NULL, *group_uuid;
+ unsigned int uuid_type = BT_UUID_UNSPEC;
+ size_t group_len = 0, plen = 0;
+
+ /*
+ * Read By Group Type Response format:
+ * Attribute Opcode: 1 byte
+ * Length: 1 byte (size of each group)
+ * Group: start | end | <<UUID>>
+ */
+
+ opdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+ group_start = &opdu[2];
+ group_uuid = &opdu[6];
+
+ for (list = local_attribute_db; list;
+ last = list->data, list = g_list_next(list)) {
+ struct btd_attribute *attr = list->data;
+
+ if (attr->handle < start)
+ continue;
+
+ if (attr->handle > end)
+ break;
+
+ if (bt_uuid_cmp(&attr->type, pattern) != 0)
+ continue;
+
+ if (uuid_type != BT_UUID_UNSPEC &&
+ uuid_type != attr->type.type) {
+ /*
+ * Groups should contain the same length: UUID16 and
+ * UUID128 should be sent on different ATT PDUs
+ */
+ break;
+ }
+
+ /*
+ * MTU checking should not be shifted up, otherwise the
+ * handle of last end group will not be set properly.
+ */
+ if ((plen + group_len) >= ATT_DEFAULT_LE_MTU)
+ break;
+
+ /* Start Grouping handle */
+ att_put_u16(attr->handle, group_start);
+
+ /* Grouping <<UUID>>: Value is little endian */
+ memcpy(group_uuid, attr->value, attr->value_len);
+
+ if (last && group_end) {
+ att_put_u16(last->handle, group_end);
+ group_end += group_len;
+ plen += group_len;
+ }
+
+ /* Grouping initial settings: First grouping */
+ if (uuid_type == BT_UUID_UNSPEC) {
+ uuid_type = attr->type.type;
+
+ /* start(0xXXXX) | end(0xXXXX) | <<UUID>> */
+ group_len = 2 + 2 + bt_uuid_len(&attr->type);
+
+ /* 2: ATT Opcode and Length */
+ plen = 2 + group_len;
+
+ /* Size of each Attribute Data */
+ opdu[1] = group_len;
+
+ group_end = &opdu[4];
+ }
+
+ group_start += group_len;
+ group_uuid += group_len;
+ }
+
+ if (plen == 0) {
+ send_error(attrib, ATT_OP_READ_BY_GROUP_REQ, start,
+ ATT_ECODE_ATTR_NOT_FOUND);
+ return;
+ }
+
+ if (group_end)
+ att_put_u16(last->handle, group_end);
+
+ g_attrib_send(attrib, 0, opdu, plen, NULL, NULL, NULL);
+}
+
+static void read_by_group(GAttrib *attrib, const uint8_t *ipdu, size_t ilen)
+{
+ uint16_t decoded, start, end;
+ bt_uuid_t pattern;
+
+ decoded = dec_read_by_grp_req(ipdu, ilen, &start, &end, &pattern);
+ if (decoded == 0) {
+ send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_INVALID_PDU);
+ return;
+ }
+
+ if (start > end || start == 0x0000) {
+ send_error(attrib, ipdu[0], start, ATT_ECODE_INVALID_HANDLE);
+ return;
+ }
+
+ /*
+ * Restricting Read By Group Type to <<Primary>>.
+ * Removing the checking below requires changes to support
+ * dynamic values(defined in the upper layer) and additional
+ * security verification.
+ */
+ if (bt_uuid_cmp(&pattern, &primary_uuid) != 0) {
+ send_error(attrib, ipdu[0], start, ATT_ECODE_UNSUPP_GRP_TYPE);
+ return;
+ }
+
+ read_by_group_resp(attrib, start, end, &pattern);
+}
+
static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
gpointer user_data)
{
@@ -121,11 +245,14 @@ static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
case ATT_OP_READ_MULTI_REQ:
case ATT_OP_PREP_WRITE_REQ:
case ATT_OP_EXEC_WRITE_REQ:
- case ATT_OP_READ_BY_GROUP_REQ:
case ATT_OP_SIGNED_WRITE_CMD:
send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
break;
+ case ATT_OP_READ_BY_GROUP_REQ:
+ read_by_group(attrib, ipdu, ilen);
+ break;
+
/* Responses */
case ATT_OP_MTU_RESP:
case ATT_OP_FIND_INFO_RESP:
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 12/17] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
Makefile.tools | 5 ++
test/gatt-service.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 141 insertions(+)
create mode 100644 test/gatt-service.c
diff --git a/Makefile.tools b/Makefile.tools
index 78034f5..7eaf03d 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -292,3 +292,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
test/service-ftp.xml test/simple-player test/test-nap \
test/test-heartrate test/test-alert test/test-hfp \
test/test-cyclingspeed
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
+
+noinst_PROGRAMS += test/gatt-service
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..31aa06b
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define SERVICE_IFACE "org.bluez.Service1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *uuid = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+ return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+ void *user_data)
+{
+ return FALSE;
+}
+
+static DBusMessage *service_release(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ fprintf(stderr, "Terminating...\n");
+
+ g_main_loop_quit(main_loop);
+
+ return NULL;
+};
+
+static const GDBusMethodTable service_methods[] = {
+ { GDBUS_NOREPLY_METHOD("Release", NULL, NULL, service_release) },
+ { }
+};
+
+static const GDBusPropertyTable service_properties[] = {
+ { "UUID", "s", service_get_uuid },
+ { "Includes", "ao", service_get_includes, NULL,
+ service_exist_includes },
+ { }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+ static int id = 1;
+ char *path;
+
+ path = g_strdup_printf("/service%d", id++);
+ if (g_dbus_register_interface(conn, path, SERVICE_IFACE,
+ service_methods, NULL, service_properties,
+ g_strdup(uuid), g_free) == FALSE) {
+ fprintf(stderr, "Couldn't register service interface\n");
+ g_free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+ char *service_path;
+
+ service_path = register_service(conn, IAS_UUID);
+
+ services = g_slist_prepend(services, service_path);
+
+ printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *dbus_conn;
+
+ dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ g_dbus_attach_object_manager(dbus_conn);
+
+ printf("gatt-service unique name: %s\n",
+ dbus_bus_get_unique_name(dbus_conn));
+
+ create_services(dbus_conn);
+
+ g_main_loop_run(main_loop);
+
+ g_slist_free_full(services, g_free);
+ dbus_connection_unref(dbus_conn);
+
+ return 0;
+}
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 13/17] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
This patch implements signal handling to run cleanup tasks before
exiting.
---
test/gatt-service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index 31aa06b..06719b4 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,12 +27,14 @@
#include <errno.h>
#include <stdio.h>
+#include <sys/signalfd.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
#define SERVICE_IFACE "org.bluez.Service1"
+#define SERVICE_MGR_IFACE "org.bluez.ServiceManager1"
/* Immediate Alert Service UUID */
#define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
@@ -112,9 +114,57 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ g_main_loop_quit(main_loop);
+
+ return FALSE;
+}
+
+static guint setup_signalfd(void)
+{
+ GIOChannel *channel;
+ guint source;
+ sigset_t mask;
+ int fd;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ perror("Failed to set signal mask");
+ return 0;
+ }
+
+ fd = signalfd(-1, &mask, 0);
+ if (fd < 0) {
+ perror("Failed to create signal descriptor");
+ return 0;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
int main(int argc, char *argv[])
{
DBusConnection *dbus_conn;
+ guint signal;
+
+ signal = setup_signalfd();
+ if (signal == 0)
+ return -errno;
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
@@ -129,6 +179,8 @@ int main(int argc, char *argv[])
g_main_loop_run(main_loop);
+ g_source_remove(signal);
+
g_slist_free_full(services, g_free);
dbus_connection_unref(dbus_conn);
--
1.8.3.1
^ permalink raw reply related
* [RFC BlueZ v0 14/17] test: Add registering external service
From: Claudio Takahasi @ 2013-11-27 20:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1385585457-26951-1-git-send-email-claudio.takahasi@openbossa.org>
This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
test/gatt-service.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index 06719b4..c26a5be 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -114,6 +114,65 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static void register_external_service_reply(DBusPendingCall *call,
+ void *user_data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ dbus_set_error_from_message(&derr, reply);
+
+ if (dbus_error_is_set(&derr))
+ fprintf(stderr, "RegisterService: %s\n", derr.message);
+ else
+ printf("RegisterService: OK\n");
+
+ dbus_message_unref(reply);
+ dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+ DBusConnection *conn = b;
+ const char *path = a;
+ DBusMessage *msg;
+ DBusPendingCall *call;
+ DBusMessageIter iter, dict;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ SERVICE_MGR_IFACE, "RegisterService");
+ if (msg == NULL) {
+ fprintf(stderr, "Couldn't allocate D-Bus message\n");
+ return;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+ /* TODO: Add options dictionary */
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+ dbus_message_unref(msg);
+ return;
+ }
+
+ dbus_pending_call_set_notify(call, register_external_service_reply,
+ NULL, NULL);
+
+ dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+ g_slist_foreach(services, register_external_service, conn);
+}
+
static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
@@ -159,6 +218,7 @@ static guint setup_signalfd(void)
int main(int argc, char *argv[])
{
+ GDBusClient *client;
DBusConnection *dbus_conn;
guint signal;
@@ -177,8 +237,14 @@ int main(int argc, char *argv[])
create_services(dbus_conn);
+ client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+ g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
g_main_loop_run(main_loop);
+ g_dbus_client_unref(client);
+
g_source_remove(signal);
g_slist_free_full(services, g_free);
--
1.8.3.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox