All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/8] MAP client: notification support
@ 2013-02-06 14:45 Christian Fetzer
  2013-02-06 14:45 ` [RFC 1/8] obexd: Add get_service_record to obc_transport Christian Fetzer
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

This patchset adds the necessary blocks for receiving notifications in the MAP client.
So far this covers only bluetooth protocol related additions, leaving out end user D-Bus API changes.

The patchset consists of the following parts:
- Message Notification Server (MNS)
  Once connected, the MNS will receive XML based event reports from the MSE and parse them into a struct
  for further processing.

- RegisterNotification function
  The function sends the SetNotificationRegistration command to the MSE which will then try to connect
  to the MNS.

- Notification dispatcher (that dispatches event reports by their MAS instance id to the correct client instance)
  The message access part of every client instance registers a notification handler function.
  The MNS will call the associated handler for all received event report.

Since the dispatching needs to be done on the mas instance id, the message access part of the client
needs to be aware of the instance id of the server it connects to. Unfortunately this information is only
available as SDP attribute.

Due to the current transport layer abstraction in obexd, the MAP client has no direct access to SDP.
Therefore I have extended obc_transport to allow concrete transports (like Bluetooth) to specify
a get_service_record function and made it available through obc_session_get_service_record.
This way, transports can provide additional service information to the client implementations.
The bluetooth transport will now always do a sdp lookup (if the driver's obc_driver->force_service_lookup is set).
In addition it will cache sdp record associated with the connection and make it accessible in get_service_record.

Christian Fetzer (8):
  obexd: Add get_service_record to obc_transport
  obexd: Provide SDP record in get_service_record
  obexd: Read MAP client SDP attributes
  obexd: Add Message Notification Server (MNS)
  obexd: Add RegisterNotifications function
  obexd: Add MAP notification dispatcher
  obexd: Register MAP notification handler
  obexd: Notify registered notification handlers

 Makefile.obexd                |   4 +
 doc/obex-api.txt              |   7 +
 lib/sdp.h                     |   2 +
 obexd/client/bluetooth.c      |  51 ++++++-
 obexd/client/driver.h         |   1 +
 obexd/client/map-dispatcher.c |  86 +++++++++++
 obexd/client/map-dispatcher.h |  45 ++++++
 obexd/client/map-event.h      |  42 +++++
 obexd/client/map.c            | 144 +++++++++++++++++-
 obexd/client/mns.c            | 346 ++++++++++++++++++++++++++++++++++++++++++
 obexd/client/session.c        |  11 +-
 obexd/client/session.h        |   2 +
 obexd/client/transport.h      |   2 +
 obexd/plugins/bluetooth.c     |   2 +
 obexd/src/obexd.h             |   1 +
 src/profile.c                 |  55 +++++++
 16 files changed, 790 insertions(+), 11 deletions(-)
 create mode 100644 obexd/client/map-dispatcher.c
 create mode 100644 obexd/client/map-dispatcher.h
 create mode 100644 obexd/client/map-event.h
 create mode 100644 obexd/client/mns.c

-- 
1.8.1.2


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC 1/8] obexd: Add get_service_record to obc_transport
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 2/8] obexd: Provide SDP record in get_service_record Christian Fetzer
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

This adds a get_service_record function pointer to obc_transport,
which allows transports to provide the session specific service record.
This record can be queried using obc_session_get_service_record.
---
 obexd/client/session.c   | 6 ++++++
 obexd/client/session.h   | 2 ++
 obexd/client/transport.h | 1 +
 3 files changed, 9 insertions(+)

diff --git a/obexd/client/session.c b/obexd/client/session.c
index db37a86..32f58c3 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -827,6 +827,12 @@ fail:
 	return NULL;
 }
 
+const void *obc_session_get_service_record(struct obc_session *session)
+{
+	if (session->id > 0 && session->transport != NULL)
+		return session->transport->get_service_record(session->id);
+}
+
 const char *obc_session_get_owner(struct obc_session *session)
 {
 	if (session == NULL)
diff --git a/obexd/client/session.h b/obexd/client/session.h
index 402c042..8a3d629 100644
--- a/obexd/client/session.h
+++ b/obexd/client/session.h
@@ -54,6 +54,8 @@ const char *obc_session_get_target(struct obc_session *session);
 const char *obc_session_register(struct obc_session *session,
 						GDBusDestroyFunction destroy);
 
+const void *obc_session_get_service_record(struct obc_session *session);
+
 guint obc_session_queue(struct obc_session *session,
 				struct obc_transfer *transfer,
 				session_callback_t func, void *user_data,
diff --git a/obexd/client/transport.h b/obexd/client/transport.h
index 5140840..eb29bf3 100644
--- a/obexd/client/transport.h
+++ b/obexd/client/transport.h
@@ -31,6 +31,7 @@ struct obc_transport {
 				obc_transport_func func, void *user_data);
 	int (*getpacketopt) (GIOChannel *io, int *tx_mtu, int *rx_mtu);
 	void (*disconnect) (guint id);
+	const void *(*get_service_record)(guint id);
 };
 
 int obc_transport_register(struct obc_transport *transport);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 2/8] obexd: Provide SDP record in get_service_record
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
  2013-02-06 14:45 ` [RFC 1/8] obexd: Add get_service_record to obc_transport Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 3/8] obexd: Read MAP client SDP attributes Christian Fetzer
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

This caches the SDP record of the active session in the bluetooth transport
and makes the data available for clients in get_service_record.
The cached SDP record can be retreived using obc_session_get_service_record.

To have the SDP record also available when directly connecting by port,
the profile implementation has to specify force_service_lookup in its
obc_driver struct.

Profiles like MAP specify additional SDP attributes that are of interest
for the profile implementation.
---
 obexd/client/bluetooth.c | 51 +++++++++++++++++++++++++++++++++++++++++-------
 obexd/client/driver.h    |  1 +
 obexd/client/session.c   |  5 +++--
 obexd/client/transport.h |  1 +
 4 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/obexd/client/bluetooth.c b/obexd/client/bluetooth.c
index a832a3f..07c2228 100644
--- a/obexd/client/bluetooth.c
+++ b/obexd/client/bluetooth.c
@@ -51,7 +51,9 @@ struct bluetooth_session {
 	bdaddr_t src;
 	bdaddr_t dst;
 	uint16_t port;
+	gboolean force_service_lookup;
 	sdp_session_t *sdp;
+	sdp_record_t *sdp_record;
 	GIOChannel *io;
 	char *service;
 	obc_transport_func func;
@@ -82,6 +84,9 @@ static void session_destroy(struct bluetooth_session *session)
 	if (session->sdp)
 		sdp_close(session->sdp);
 
+	if (session->sdp_record)
+		sdp_record_free(session->sdp_record);
+
 	g_free(session->service);
 	g_free(session);
 }
@@ -160,7 +165,7 @@ static void search_callback(uint8_t type, uint16_t status,
 		sdp_record_t *rec;
 		sdp_list_t *protos;
 		sdp_data_t *data;
-		int recsize, ch = -1;
+		int recsize, ch = -1, psm = -1;
 
 		recsize = 0;
 		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
@@ -183,15 +188,31 @@ static void search_callback(uint8_t type, uint16_t status,
 		data = sdp_data_get(rec, 0x0200);
 		/* PSM must be odd and lsb of upper byte must be 0 */
 		if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
-			ch = data->val.uint16;
-
-		sdp_record_free(rec);
+			psm = data->val.uint16;
+
+		/* Preferably connect using L2CAP directly instead of RFCOMM.
+		 * If the session has already a port specified, use that to
+		 * connect. */
+		if (session->port == 0) {
+			if (psm > 0)
+				port = psm;
+			else if (ch > 0)
+				port = ch;
+		} else if (session->port > 0 &&
+				(session->port == ch || session->port == psm)) {
+			port = session->port;
+		}
 
-		if (ch > 0) {
-			port = ch;
+		/* Cache the sdp record associated with the service that we
+		 * attempt to connect. This allows reading it's application
+		 * specific parameters with get_service_record. */
+		if (port > 0) {
+			session->sdp_record = rec;
 			break;
 		}
 
+		sdp_record_free(rec);
+
 		scanned += recsize;
 		rsp += recsize;
 		bytesleft -= recsize;
@@ -362,7 +383,7 @@ static int session_connect(struct bluetooth_session *session)
 
 	DBG("session %p", session);
 
-	if (session->port > 0) {
+	if (session->port > 0 && !session->force_service_lookup) {
 		session->io = transport_connect(&session->src, &session->dst,
 							session->port,
 							transport_callback,
@@ -379,6 +400,7 @@ static int session_connect(struct bluetooth_session *session)
 
 static guint bluetooth_connect(const char *source, const char *destination,
 				const char *service, uint16_t port,
+				gboolean force_service_lookup,
 				obc_transport_func func, void *user_data)
 {
 	struct bluetooth_session *session;
@@ -398,6 +420,7 @@ static guint bluetooth_connect(const char *source, const char *destination,
 	session->func = func;
 	session->port = port;
 	session->user_data = user_data;
+	session->force_service_lookup = force_service_lookup;
 
 	session->service = g_strdup(service);
 	str2ba(destination, &session->dst);
@@ -459,11 +482,25 @@ static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
 	return 0;
 }
 
+static const void *get_bluetooth_service_record(guint id)
+{
+	GSList *l;
+
+	for (l = sessions; l; l = l->next) {
+		struct bluetooth_session *session = l->data;
+
+		if (session->id == id)
+			return session->sdp_record;
+	}
+	return NULL;
+}
+
 static struct obc_transport bluetooth = {
 	.name = "Bluetooth",
 	.connect = bluetooth_connect,
 	.getpacketopt = bluetooth_getpacketopt,
 	.disconnect = bluetooth_disconnect,
+	.get_service_record = get_bluetooth_service_record,
 };
 
 int bluetooth_init(void)
diff --git a/obexd/client/driver.h b/obexd/client/driver.h
index f1c0646..08ea09b 100644
--- a/obexd/client/driver.h
+++ b/obexd/client/driver.h
@@ -26,6 +26,7 @@ struct obc_driver {
 	const char *uuid;
 	void *target;
 	gsize target_len;
+	gboolean force_service_lookup;
 	int (*probe) (struct obc_session *session);
 	void (*remove) (struct obc_session *session);
 };
diff --git a/obexd/client/session.c b/obexd/client/session.c
index 32f58c3..dbbbc8e 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -407,8 +407,9 @@ static int session_connect(struct obc_session *session,
 	}
 
 	session->id = transport->connect(session->source, session->destination,
-					driver->uuid, session->channel,
-					transport_func, callback);
+						driver->uuid, session->channel,
+						driver->force_service_lookup,
+						transport_func, callback);
 	if (session->id == 0) {
 		obc_session_unref(callback->session);
 		g_free(callback);
diff --git a/obexd/client/transport.h b/obexd/client/transport.h
index eb29bf3..b131c50 100644
--- a/obexd/client/transport.h
+++ b/obexd/client/transport.h
@@ -28,6 +28,7 @@ struct obc_transport {
 	const char *name;
 	guint (*connect) (const char *source, const char *destination,
 				const char *service, uint16_t port,
+				gboolean force_service_lookup,
 				obc_transport_func func, void *user_data);
 	int (*getpacketopt) (GIOChannel *io, int *tx_mtu, int *rx_mtu);
 	void (*disconnect) (guint id);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 3/8] obexd: Read MAP client SDP attributes
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
  2013-02-06 14:45 ` [RFC 1/8] obexd: Add get_service_record to obc_transport Christian Fetzer
  2013-02-06 14:45 ` [RFC 2/8] obexd: Provide SDP record in get_service_record Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 4/8] obexd: Add Message Notification Server (MNS) Christian Fetzer
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

Parse SDP attributes mas_instance_id and supported_message_types from
the transport's service attributes as soon as a connection is
established.
---
 lib/sdp.h          |  2 ++
 obexd/client/map.c | 35 +++++++++++++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/lib/sdp.h b/lib/sdp.h
index a81e857..c3a0261 100644
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -294,6 +294,8 @@ extern "C" {
 #define SDP_ATTR_SUPPORTED_FUNCTIONS		0x0312
 #define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY	0x0313
 #define SDP_ATTR_SUPPORTED_REPOSITORIES		0x0314
+#define SDP_ATTR_MAS_INSTANCE_ID		0x0315
+#define SDP_ATTR_SUPPORTED_MESSAGE_TYPES	0x0316
 
 #define SDP_ATTR_SPECIFICATION_ID		0x0200
 #define SDP_ATTR_VENDOR_ID			0x0201
diff --git a/obexd/client/map.c b/obexd/client/map.c
index ea5681a..463d905 100644
--- a/obexd/client/map.c
+++ b/obexd/client/map.c
@@ -39,6 +39,8 @@
 #include "transfer.h"
 #include "session.h"
 #include "driver.h"
+#include "sdp.h"
+#include "sdp_lib.h"
 
 #define OBEX_MAS_UUID \
 	"\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
@@ -93,6 +95,8 @@ struct map_data {
 	struct obc_session *session;
 	DBusMessage *msg;
 	GHashTable *messages;
+	int16_t mas_instance_id;
+	uint8_t supported_message_types;
 };
 
 #define MAP_MSG_FLAG_PRIORITY	0x01
@@ -1538,6 +1542,30 @@ static void map_free(void *data)
 	g_free(map);
 }
 
+static void parse_service_record(struct map_data *map)
+{
+	sdp_data_t *data;
+	const sdp_record_t *rec = obc_session_get_service_record(map->session);
+
+	if (!rec)
+		return;
+
+	/* MAS instance id */
+	map->mas_instance_id = -1;
+	data = sdp_data_get(rec, SDP_ATTR_MAS_INSTANCE_ID);
+	if (data != NULL)
+		map->mas_instance_id = data->val.uint8;
+	else
+		DBG("Failed to read MAS instance id");
+
+	/* Supported Message Types */
+	data = sdp_data_get(rec, SDP_ATTR_SUPPORTED_MESSAGE_TYPES);
+	if (data != NULL)
+		map->supported_message_types = data->val.uint8;
+	else
+		DBG("Failed to read supported message types");
+}
+
 static int map_probe(struct obc_session *session)
 {
 	struct map_data *map;
@@ -1545,8 +1573,6 @@ static int map_probe(struct obc_session *session)
 
 	path = obc_session_get_path(session);
 
-	DBG("%s", path);
-
 	map = g_try_new0(struct map_data, 1);
 	if (!map)
 		return -ENOMEM;
@@ -1555,6 +1581,10 @@ static int map_probe(struct obc_session *session)
 	map->messages = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
 								map_msg_remove);
 
+	parse_service_record(map);
+
+	DBG("%s, instance id %d", path, map->mas_instance_id);
+
 	if (!g_dbus_register_interface(conn, path, MAP_INTERFACE, map_methods,
 					NULL, NULL, map, map_free)) {
 		map_free(map);
@@ -1579,6 +1609,7 @@ static struct obc_driver map = {
 	.uuid = MAS_UUID,
 	.target = OBEX_MAS_UUID,
 	.target_len = OBEX_MAS_UUID_LEN,
+	.force_service_lookup = TRUE,
 	.probe = map_probe,
 	.remove = map_remove
 };
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 4/8] obexd: Add Message Notification Server (MNS)
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (2 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 3/8] obexd: Read MAP client SDP attributes Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 5/8] obexd: Add RegisterNotifications function Christian Fetzer
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

This implements the MAP Message Notification Server (MNS)
which is part of the MCE.
---
 Makefile.obexd            |   3 +
 obexd/client/map-event.h  |  42 ++++++
 obexd/client/mns.c        | 348 ++++++++++++++++++++++++++++++++++++++++++++++
 obexd/plugins/bluetooth.c |   2 +
 obexd/src/obexd.h         |   1 +
 src/profile.c             |  55 ++++++++
 6 files changed, 451 insertions(+)
 create mode 100644 obexd/client/map-event.h
 create mode 100644 obexd/client/mns.c

diff --git a/Makefile.obexd b/Makefile.obexd
index ae05ae9..5824e0a 100644
--- a/Makefile.obexd
+++ b/Makefile.obexd
@@ -48,6 +48,9 @@ obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \
 				obexd/plugins/messages.h \
 				obexd/plugins/messages-dummy.c
 
+obexd_builtin_modules += mns
+obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
+				obexd/client/map-event.h
 
 libexec_PROGRAMS += obexd/src/obexd
 
diff --git a/obexd/client/map-event.h b/obexd/client/map-event.h
new file mode 100644
index 0000000..749f1e0
--- /dev/null
+++ b/obexd/client/map-event.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *  OBEX
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  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
+ *
+ */
+
+enum map_event_type {
+	MAP_ET_NEW_MESSAGE,
+	MAP_ET_DELIVERY_SUCCESS,
+	MAP_ET_SENDING_SUCCESS,
+	MAP_ET_DELIVERY_FAILURE,
+	MAP_ET_SENDING_FAILURE,
+	MAP_ET_MEMORY_FULL,
+	MAP_ET_MEMORY_AVAILABLE,
+	MAP_ET_MESSAGE_DELETED,
+	MAP_ET_MESSAGE_SHIFT
+};
+
+struct map_event {
+	enum map_event_type type;
+	char *handle;
+	char *folder;
+	char *old_folder;
+	char *msg_type;
+};
diff --git a/obexd/client/mns.c b/obexd/client/mns.c
new file mode 100644
index 0000000..81550ef
--- /dev/null
+++ b/obexd/client/mns.c
@@ -0,0 +1,348 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  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 <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "mimetype.h"
+#include "map_ap.h"
+#include "map-event.h"
+
+struct mns_session {
+	GString *buffer;
+	GObexApparam *inparams;
+	uint8_t mas_instance_id;
+};
+
+static const uint8_t MNS_TARGET[TARGET_SIZE] = {
+			0xbb, 0x58, 0x2b, 0x41, 0x42, 0x0c, 0x11, 0xdb,
+			0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66  };
+
+static int get_params(struct obex_session *os, struct mns_session *mns)
+{
+	const uint8_t *buffer;
+	ssize_t size;
+
+	size = obex_get_apparam(os, &buffer);
+	if (size < 0)
+		size = 0;
+
+	mns->inparams = g_obex_apparam_decode(buffer, size);
+	if (mns->inparams == NULL) {
+		DBG("Error when parsing parameters!");
+		return -EBADR;
+	}
+
+	return 0;
+}
+
+static void reset_request(struct mns_session *mns)
+{
+	if (mns->buffer) {
+		g_string_free(mns->buffer, TRUE);
+		mns->buffer = NULL;
+	}
+
+	if (mns->inparams) {
+		g_obex_apparam_free(mns->inparams);
+		mns->inparams = NULL;
+	}
+}
+
+static void mns_session_free(struct mns_session *mns)
+{
+	reset_request(mns);
+	g_free(mns);
+}
+
+static void *mns_connect(struct obex_session *os, int *err)
+{
+	struct mns_session *mns;
+
+	DBG("");
+
+	mns = g_new0(struct mns_session, 1);
+
+	manager_register_session(os);
+
+	return mns;
+}
+
+static void mns_disconnect(struct obex_session *os, void *user_data)
+{
+	struct mns_session *mns = user_data;
+
+	DBG("");
+
+	manager_unregister_session(os);
+
+	mns_session_free(mns);
+}
+
+static int mns_put(struct obex_session *os, void *user_data)
+{
+	struct mns_session *mns = user_data;
+	const char *type = obex_get_type(os);
+	const char *name = obex_get_name(os);
+	int ret;
+
+	DBG("PUT: name %s type %s mns %p", name, type, mns);
+
+	if (type == NULL)
+		return -EBADR;
+
+	ret = get_params(os, mns);
+	if (ret < 0)
+		goto failed;
+
+	ret = obex_put_stream_start(os, name);
+	if (ret < 0)
+		goto failed;
+
+	return 0;
+
+failed:
+	reset_request(mns);
+
+	return ret;
+}
+
+static void parse_event_report_type(struct map_event *event, const char *value)
+{
+	if (!g_ascii_strcasecmp(value, "NewMessage"))
+		event->type = MAP_ET_NEW_MESSAGE;
+	else if (!g_ascii_strcasecmp(value, "DeliverySuccess"))
+		event->type = MAP_ET_DELIVERY_SUCCESS;
+	else if (!g_ascii_strcasecmp(value, "SendingSuccess"))
+		event->type = MAP_ET_SENDING_SUCCESS;
+	else if (!g_ascii_strcasecmp(value, "DeliveryFailure"))
+		event->type = MAP_ET_DELIVERY_FAILURE;
+	else if (!g_ascii_strcasecmp(value, "SendingFailure"))
+		event->type = MAP_ET_SENDING_FAILURE;
+	else if (!g_ascii_strcasecmp(value, "MemoryFull"))
+		event->type = MAP_ET_MEMORY_FULL;
+	else if (!g_ascii_strcasecmp(value, "MemoryAvailable"))
+		event->type = MAP_ET_MEMORY_AVAILABLE;
+	else if (!g_ascii_strcasecmp(value, "MessageDeleted"))
+		event->type = MAP_ET_MESSAGE_DELETED;
+	else if (!g_ascii_strcasecmp(value, "MessageShift"))
+		event->type = MAP_ET_MESSAGE_SHIFT;
+}
+
+static void parse_event_report_handle(struct map_event *event,
+							const char *value)
+{
+	event->handle = g_strdup(value);
+}
+
+static void parse_event_report_folder(struct map_event *event,
+							const char *value)
+{
+	event->folder = g_strdup(value);
+}
+
+static void parse_event_report_old_folder(struct map_event *event,
+							const char *value)
+{
+	event->old_folder = g_strdup(value);
+}
+
+static void parse_event_report_msg_type(struct map_event *event,
+							const char *value)
+{
+	event->msg_type = g_strdup(value);
+}
+
+static struct map_event_report_parser {
+	const char *name;
+	void (*func) (struct map_event *event, const char *value);
+} event_report_parsers[] = {
+		{ "type", parse_event_report_type },
+		{ "handle", parse_event_report_handle },
+		{ "folder", parse_event_report_folder },
+		{ "old_folder", parse_event_report_old_folder },
+		{ "msg_type", parse_event_report_msg_type },
+		{ }
+};
+
+static void event_report_element(GMarkupParseContext *ctxt,
+				const gchar *element, const gchar **names,
+				const gchar **values, gpointer user_data,
+								GError **gerr)
+{
+	struct map_event *event = user_data;
+	const gchar *key;
+	gint i;
+
+	if (strcasecmp("event", element) != 0)
+		return;
+
+	for (i = 0, key = names[i]; key; key = names[++i]) {
+		struct map_event_report_parser *parser;
+
+		for (parser = event_report_parsers; parser && parser->name;
+								parser++) {
+			if (strcasecmp(key, parser->name) == 0) {
+				parser->func(event, values[i]);
+				break;
+			}
+		}
+	}
+}
+
+static const GMarkupParser event_report_parser = {
+	event_report_element,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static void map_event_free(struct map_event *event)
+{
+	g_free(event->handle);
+	g_free(event->folder);
+	g_free(event->old_folder);
+	g_free(event->msg_type);
+	g_free(event);
+}
+
+static void *event_report_open(const char *name, int oflag, mode_t mode,
+				void *driver_data, size_t *size, int *err)
+{
+	struct mns_session *mns = driver_data;
+
+	DBG("");
+
+	g_obex_apparam_get_uint8(mns->inparams, MAP_AP_MASINSTANCEID,
+							&mns->mas_instance_id);
+
+	mns->buffer = g_string_new("");
+
+	if (*err < 0)
+		return NULL;
+	else
+		return mns;
+}
+
+static int event_report_close(void *obj)
+{
+	struct mns_session *mns = obj;
+	GMarkupParseContext *ctxt;
+	struct map_event *event;
+
+	event = g_new0(struct map_event, 1);
+	ctxt = g_markup_parse_context_new(&event_report_parser, 0, event,
+									NULL);
+	g_markup_parse_context_parse(ctxt, mns->buffer->str, mns->buffer->len,
+									NULL);
+	g_markup_parse_context_free(ctxt);
+
+	DBG("Received event report for instance %d", mns->mas_instance_id);
+	DBG("type=%x, handle=%s, folder=%s, old_folder=%s, msg_type=%s",
+				event->type, event->handle, event->folder,
+					event->old_folder, event->msg_type);
+
+	map_event_free(event);
+
+	reset_request(mns);
+
+	return 0;
+}
+
+static ssize_t event_report_write(void *obj, const void *buf, size_t count)
+{
+	struct mns_session *mns = obj;
+
+	DBG("");
+
+	g_string_append_len(mns->buffer, buf, count);
+	return count;
+}
+
+static struct obex_service_driver mns = {
+	.name = "Message Notification server",
+	.service = OBEX_MNS,
+	.target = MNS_TARGET,
+	.target_size = TARGET_SIZE,
+	.connect = mns_connect,
+	.put = mns_put,
+	.disconnect = mns_disconnect,
+};
+
+static struct obex_mime_type_driver mime_event_report = {
+	.target = MNS_TARGET,
+	.target_size = TARGET_SIZE,
+	.mimetype = "x-bt/MAP-event-report",
+	.open = event_report_open,
+	.close = event_report_close,
+	.write = event_report_write,
+};
+
+static struct obex_mime_type_driver *mas_drivers[] = {
+	&mime_event_report,
+	NULL
+};
+
+static int mns_init(void)
+{
+	int err;
+
+	err = obex_mime_type_driver_register(&mime_event_report);
+	if (err < 0)
+		goto fail_mime_event;
+
+	err = obex_service_driver_register(&mns);
+	if (err < 0)
+		goto fail_mns_reg;
+
+	return 0;
+
+fail_mns_reg:
+	obex_mime_type_driver_unregister(&mime_event_report);
+fail_mime_event:
+	return err;
+}
+
+static void mns_exit(void)
+{
+	obex_service_driver_unregister(&mns);
+	obex_mime_type_driver_unregister(&mime_event_report);
+}
+
+OBEX_PLUGIN_DEFINE(mns, mns_init, mns_exit)
diff --git a/obexd/plugins/bluetooth.c b/obexd/plugins/bluetooth.c
index f80faa4..b9e9c91 100644
--- a/obexd/plugins/bluetooth.c
+++ b/obexd/plugins/bluetooth.c
@@ -336,6 +336,8 @@ static const char *service2uuid(uint16_t service)
 		return "00000002-0000-1000-8000-0002ee000002";
 	case OBEX_MAS:
 		return OBEX_MAS_UUID;
+	case OBEX_MNS:
+		return OBEX_MNS_UUID;
 	}
 
 	return NULL;
diff --git a/obexd/src/obexd.h b/obexd/src/obexd.h
index 1c9b2b3..42c3c4d 100644
--- a/obexd/src/obexd.h
+++ b/obexd/src/obexd.h
@@ -29,6 +29,7 @@
 #define OBEX_PCSUITE	(1 << 6)
 #define OBEX_SYNCEVOLUTION	(1 << 7)
 #define OBEX_MAS	(1 << 8)
+#define OBEX_MNS	(1 << 9)
 
 gboolean plugin_init(const char *pattern, const char *exclude);
 void plugin_cleanup(void);
diff --git a/src/profile.c b/src/profile.c
index 631a03f..89eed11 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -435,6 +435,44 @@
 		</attribute>						\
 	</record>"
 
+#define MNS_RECORD							\
+	"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>			\
+	<record>							\
+		<attribute id=\"0x0001\">				\
+			<sequence>					\
+				<uuid value=\"0x1133\"/>		\
+			</sequence>					\
+		</attribute>						\
+		<attribute id=\"0x0004\">				\
+			<sequence>					\
+				<sequence>				\
+					<uuid value=\"0x0100\"/>	\
+				</sequence>				\
+				<sequence>				\
+					<uuid value=\"0x0003\"/>	\
+					<uint8 value=\"0x%02x\"/>	\
+				</sequence>				\
+				<sequence>				\
+					<uuid value=\"0x0008\"/>	\
+				</sequence>				\
+			</sequence>					\
+		</attribute>						\
+		<attribute id=\"0x0009\">				\
+			<sequence>					\
+				<sequence>				\
+					<uuid value=\"0x1134\"/>	\
+					<uint16 value=\"0x%04x\"/>	\
+				</sequence>				\
+			</sequence>					\
+		</attribute>						\
+		<attribute id=\"0x0100\">				\
+			<text value=\"%s\"/>				\
+		</attribute>						\
+		<attribute id=\"0x0200\">				\
+			<uint16 value=\"%u\" name=\"psm\"/>		\
+		</attribute>						\
+	</record>"
+
 #define SYNC_RECORD							\
 	"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>			\
 	<record>							\
@@ -1709,6 +1747,20 @@ static char *get_mas_record(struct ext_profile *ext, struct ext_io *l2cap,
 								ext->name);
 }
 
+static char *get_mns_record(struct ext_profile *ext, struct ext_io *l2cap,
+							struct ext_io *rfcomm)
+{
+	uint16_t psm = 0;
+	uint8_t chan = 0;
+
+	if (l2cap)
+		psm = l2cap->psm;
+	if (rfcomm)
+		chan = rfcomm->chan;
+
+	return g_strdup_printf(MNS_RECORD, chan, ext->version, ext->name, psm);
+}
+
 static char *get_sync_record(struct ext_profile *ext, struct ext_io *l2cap,
 							struct ext_io *rfcomm)
 {
@@ -1899,6 +1951,9 @@ static struct default_settings {
 		.uuid		= OBEX_MNS_UUID,
 		.name		= "Message Notification",
 		.channel	= MNS_DEFAULT_CHANNEL,
+		.psm		= BTD_PROFILE_PSM_AUTO,
+		.get_record	= get_mns_record,
+		.version	= 0x0100
 	},
 };
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 5/8] obexd: Add RegisterNotifications function
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (3 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 4/8] obexd: Add Message Notification Server (MNS) Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 6/8] obexd: Add MAP notification dispatcher Christian Fetzer
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

This allows applications to register for all different types
of MAP event reports.

In response to this call, the MSE should connect to the local MNS
instance.
---
 doc/obex-api.txt   |  7 +++++
 obexd/client/map.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/doc/obex-api.txt b/doc/obex-api.txt
index 6246933..ddbb9ab 100644
--- a/doc/obex-api.txt
+++ b/doc/obex-api.txt
@@ -630,6 +630,13 @@ Methods		void SetFolder(string name)
 
 			Possible errors: org.bluez.obex.Error.Failed
 
+		void RegisterNotifications(boolean)
+
+			Register / unregister reception of notifications.
+
+			Possible errors: org.bluez.obex.Error.InvalidArguments
+					 org.bluez.obex.Error.Failed
+
 Filter:		uint16 Offset:
 
 			Offset of the first item, default is 0
diff --git a/obexd/client/map.c b/obexd/client/map.c
index 463d905..776f19c 100644
--- a/obexd/client/map.c
+++ b/obexd/client/map.c
@@ -1499,6 +1499,86 @@ fail:
 	return reply;
 }
 
+static void notification_registration_cb(struct obc_session *session,
+				struct obc_transfer *transfer,
+				GError *err, void *user_data)
+{
+	struct map_data *map = user_data;
+	DBusMessage *reply;
+
+	if (err != NULL) {
+		reply = g_dbus_create_error(map->msg,
+						ERROR_INTERFACE ".Failed",
+						"%s", err->message);
+		goto done;
+	}
+
+	reply = dbus_message_new_method_return(map->msg);
+
+done:
+	g_dbus_send_message(conn, reply);
+	dbus_message_unref(map->msg);
+}
+
+static DBusMessage *set_notification_registration(struct map_data *map,
+							DBusMessage *message,
+							GObexApparam *apparam)
+{
+	struct obc_transfer *transfer;
+	GError *err = NULL;
+	DBusMessage *reply;
+	char contents[2];
+
+	contents[0] = FILLER_BYTE;
+	contents[1] = '\0';
+
+	transfer = obc_transfer_put("x-bt/MAP-NotificationRegistration", NULL,
+					NULL, contents, sizeof(contents), &err);
+
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
+		goto fail;
+	}
+
+	obc_transfer_set_apparam(transfer, apparam);
+
+	if (obc_session_queue(map->session, transfer,
+				notification_registration_cb, map, &err)) {
+		map->msg = dbus_message_ref(message);
+		return NULL;
+	}
+
+fail:
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+								err->message);
+	g_error_free(err);
+	return reply;
+}
+
+static DBusMessage *map_register_notifications(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct map_data *map = user_data;
+	GObexApparam *apparam;
+	gboolean status;
+
+	if (map->mas_instance_id < 0)
+		return g_dbus_create_error(message,
+					ERROR_INTERFACE ".Failed",
+					"Unknown MAS instance id");
+
+	if (dbus_message_get_args(message, NULL, DBUS_TYPE_BOOLEAN, &status,
+					DBUS_TYPE_INVALID) == FALSE)
+		return g_dbus_create_error(message,
+					ERROR_INTERFACE ".InvalidArguments",
+					NULL);
+
+	apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_NOTIFICATIONSTATUS,
+							status ? 0x01 : 0x00);
+
+	return set_notification_registration(map, message, apparam);
+}
+
 static const GDBusMethodTable map_methods[] = {
 	{ GDBUS_ASYNC_METHOD("SetFolder",
 				GDBUS_ARGS({ "name", "s" }), NULL,
@@ -1519,6 +1599,10 @@ static const GDBusMethodTable map_methods[] = {
 			NULL,
 			NULL,
 			map_update_inbox) },
+	{ GDBUS_ASYNC_METHOD("RegisterNotifications",
+			GDBUS_ARGS({ "status", "b" }),
+			NULL,
+			map_register_notifications) },
 	{ }
 };
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 6/8] obexd: Add MAP notification dispatcher
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (4 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 5/8] obexd: Add RegisterNotifications function Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 7/8] obexd: Register MAP notification handler Christian Fetzer
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

The MAP specification allows to reuse one MNS instance for all local
MAS client instances. This dispatching of event reports to the
correct MAS client instance is done by the instance id.

The dispatcher component allows MAP client instances to
register a notification handler (map_aquire_mns).
Events reports are then forwarded by the notification server
using (mns_dispatch_notification).
---
 Makefile.obexd                |  1 +
 obexd/client/map-dispatcher.c | 86 +++++++++++++++++++++++++++++++++++++++++++
 obexd/client/map-dispatcher.h | 45 ++++++++++++++++++++++
 3 files changed, 132 insertions(+)
 create mode 100644 obexd/client/map-dispatcher.c
 create mode 100644 obexd/client/map-dispatcher.h

diff --git a/Makefile.obexd b/Makefile.obexd
index 5824e0a..02901a3 100644
--- a/Makefile.obexd
+++ b/Makefile.obexd
@@ -73,6 +73,7 @@ obexd_src_obexd_SOURCES = $(gdbus_sources) $(btio_sources) $(gobex_sources) \
 			obexd/client/ftp.h obexd/client/ftp.c \
 			obexd/client/opp.h obexd/client/opp.c \
 			obexd/client/map.h obexd/client/map.c \
+			obexd/client/map-dispatcher.h obexd/client/map-dispatcher.c \
 			obexd/client/transfer.h obexd/client/transfer.c \
 			obexd/client/transport.h obexd/client/transport.c \
 			obexd/client/dbus.h obexd/client/dbus.c \
diff --git a/obexd/client/map-dispatcher.c b/obexd/client/map-dispatcher.c
new file mode 100644
index 0000000..ed6e5bb
--- /dev/null
+++ b/obexd/client/map-dispatcher.c
@@ -0,0 +1,86 @@
+/*
+ *
+ *  OBEX
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  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 <glib.h>
+
+#include "log.h"
+#include "map-dispatcher.h"
+
+static GSList *mappings = NULL;
+
+struct mns_mapping {
+	int mas_instance_id;
+	map_handle_notification_func handler;
+};
+
+gboolean map_acquire_mns(int mas_instance_id,
+					map_handle_notification_func handler)
+{
+	struct mns_mapping *mapping;
+
+	mapping = g_try_new0(struct mns_mapping, 1);
+	if (mapping == NULL)
+		return FALSE;
+
+	mapping->mas_instance_id = mas_instance_id;
+	mapping->handler = handler;
+
+	mappings = g_slist_append(mappings, mapping);
+	DBG("Added MAP MNS mapping for instance %d", mas_instance_id);
+
+	return TRUE;
+}
+
+static struct mns_mapping *find_mapping(int mas_instance_id)
+{
+	GSList *list;
+
+	for (list = mappings; list; list = list->next) {
+		struct mns_mapping *mapping = list->data;
+		if (mapping->mas_instance_id == mas_instance_id)
+			return mapping;
+	}
+
+	DBG("Cannot find MAP MNS mapping for instance %d", mas_instance_id);
+	return NULL;
+}
+
+void map_release_mns(int mas_instance_id)
+{
+	struct mns_mapping *mapping = find_mapping(mas_instance_id);
+	if (mapping) {
+		mappings = g_slist_remove(mappings, mapping);
+		DBG("Removed MAP MNS mapping for instance %d", mas_instance_id);
+	}
+}
+
+void mns_dispatch_notification(int mas_instance_id, struct map_event *event)
+{
+	struct mns_mapping *mapping = find_mapping(mas_instance_id);
+	if (mapping)
+		mapping->handler(event);
+}
diff --git a/obexd/client/map-dispatcher.h b/obexd/client/map-dispatcher.h
new file mode 100644
index 0000000..8f65137
--- /dev/null
+++ b/obexd/client/map-dispatcher.h
@@ -0,0 +1,45 @@
+/*
+ *
+ *  OBEX
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  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
+ *
+ */
+
+#include "map-event.h"
+
+/* Handle notification in map client.
+ *
+ * event: Event report.
+ *
+ * Callback shall be called for every received event.
+ */
+typedef void (*map_handle_notification_func)(struct map_event *event);
+
+/* Registers client notification handler callback for events that are
+ * addressed to the given mas instance id.
+ */
+gboolean map_acquire_mns(int mas_instance_id, map_handle_notification_func);
+
+/* Unregisters client notification handler callback.
+ */
+void map_release_mns(int mas_instance_id);
+
+/* Dispatch notification to a registered notification handler callback.
+ */
+void mns_dispatch_notification(int mas_instance_id, struct map_event *event);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 7/8] obexd: Register MAP notification handler
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (5 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 6/8] obexd: Add MAP notification dispatcher Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-06 14:45 ` [RFC 8/8] obexd: Notify registered notification handlers Christian Fetzer
  2013-02-12  9:02 ` [RFC 0/8] MAP client: notification support Luiz Augusto von Dentz
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

---
 obexd/client/map.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/obexd/client/map.c b/obexd/client/map.c
index 776f19c..682f97a 100644
--- a/obexd/client/map.c
+++ b/obexd/client/map.c
@@ -41,6 +41,7 @@
 #include "driver.h"
 #include "sdp.h"
 #include "sdp_lib.h"
+#include "map-dispatcher.h"
 
 #define OBEX_MAS_UUID \
 	"\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
@@ -97,6 +98,7 @@ struct map_data {
 	GHashTable *messages;
 	int16_t mas_instance_id;
 	uint8_t supported_message_types;
+	gboolean mns_acquired;
 };
 
 #define MAP_MSG_FLAG_PRIORITY	0x01
@@ -1555,6 +1557,13 @@ fail:
 	return reply;
 }
 
+static void map_handle_notification(struct map_event *event)
+{
+	DBG("event: type=%x, handle=%s, folder=%s, old_folder=%s, msg_type=%s",
+				event->type, event->handle, event->folder,
+					event->old_folder, event->msg_type);
+}
+
 static DBusMessage *map_register_notifications(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -1573,9 +1582,22 @@ static DBusMessage *map_register_notifications(DBusConnection *connection,
 					ERROR_INTERFACE ".InvalidArguments",
 					NULL);
 
+	if (map->mns_acquired == status)
+		return g_dbus_create_error(message,
+					ERROR_INTERFACE ".InvalidArguments",
+					NULL);
+
 	apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_NOTIFICATIONSTATUS,
 							status ? 0x01 : 0x00);
 
+	if (status) {
+		map->mns_acquired = TRUE;
+		map_acquire_mns(map->mas_instance_id, &map_handle_notification);
+	} else {
+		map->mns_acquired = FALSE;
+		map_release_mns(map->mas_instance_id);
+	}
+
 	return set_notification_registration(map, message, apparam);
 }
 
@@ -1621,6 +1643,9 @@ static void map_free(void *data)
 {
 	struct map_data *map = data;
 
+	if (map->mns_acquired)
+		map_release_mns(map->mas_instance_id);
+
 	obc_session_unref(map->session);
 	g_hash_table_unref(map->messages);
 	g_free(map);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC 8/8] obexd: Notify registered notification handlers
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (6 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 7/8] obexd: Register MAP notification handler Christian Fetzer
@ 2013-02-06 14:45 ` Christian Fetzer
  2013-02-12  9:02 ` [RFC 0/8] MAP client: notification support Luiz Augusto von Dentz
  8 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-06 14:45 UTC (permalink / raw)
  To: linux-bluetooth

From: Christian Fetzer <christian.fetzer@bmw-carit.de>

---
 obexd/client/mns.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/obexd/client/mns.c b/obexd/client/mns.c
index 81550ef..f16d235 100644
--- a/obexd/client/mns.c
+++ b/obexd/client/mns.c
@@ -41,7 +41,7 @@
 #include "service.h"
 #include "mimetype.h"
 #include "map_ap.h"
-#include "map-event.h"
+#include "map-dispatcher.h"
 
 struct mns_session {
 	GString *buffer;
@@ -266,6 +266,8 @@ static int event_report_close(void *obj)
 	GMarkupParseContext *ctxt;
 	struct map_event *event;
 
+	DBG("");
+
 	event = g_new0(struct map_event, 1);
 	ctxt = g_markup_parse_context_new(&event_report_parser, 0, event,
 									NULL);
@@ -273,11 +275,7 @@ static int event_report_close(void *obj)
 									NULL);
 	g_markup_parse_context_free(ctxt);
 
-	DBG("Received event report for instance %d", mns->mas_instance_id);
-	DBG("type=%x, handle=%s, folder=%s, old_folder=%s, msg_type=%s",
-				event->type, event->handle, event->folder,
-					event->old_folder, event->msg_type);
-
+	mns_dispatch_notification(mns->mas_instance_id, event);
 	map_event_free(event);
 
 	reset_request(mns);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC 0/8] MAP client: notification support
  2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
                   ` (7 preceding siblings ...)
  2013-02-06 14:45 ` [RFC 8/8] obexd: Notify registered notification handlers Christian Fetzer
@ 2013-02-12  9:02 ` Luiz Augusto von Dentz
  2013-02-14  8:54   ` Christian Fetzer
  8 siblings, 1 reply; 11+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-12  9:02 UTC (permalink / raw)
  To: Christian Fetzer; +Cc: linux-bluetooth

Hi Christian,

On Wed, Feb 6, 2013 at 4:45 PM, Christian Fetzer
<christian.fetzer@oss.bmw-carit.de> wrote:
> From: Christian Fetzer <christian.fetzer@bmw-carit.de>
>
> This patchset adds the necessary blocks for receiving notifications in the MAP client.
> So far this covers only bluetooth protocol related additions, leaving out end user D-Bus API changes.
>
> The patchset consists of the following parts:
> - Message Notification Server (MNS)
>   Once connected, the MNS will receive XML based event reports from the MSE and parse them into a struct
>   for further processing.
>
> - RegisterNotification function
>   The function sends the SetNotificationRegistration command to the MSE which will then try to connect
>   to the MNS.
>
> - Notification dispatcher (that dispatches event reports by their MAS instance id to the correct client instance)
>   The message access part of every client instance registers a notification handler function.
>   The MNS will call the associated handler for all received event report.
>
> Since the dispatching needs to be done on the mas instance id, the message access part of the client
> needs to be aware of the instance id of the server it connects to. Unfortunately this information is only
> available as SDP attribute.
>
> Due to the current transport layer abstraction in obexd, the MAP client has no direct access to SDP.
> Therefore I have extended obc_transport to allow concrete transports (like Bluetooth) to specify
> a get_service_record function and made it available through obc_session_get_service_record.
> This way, transports can provide additional service information to the client implementations.
> The bluetooth transport will now always do a sdp lookup (if the driver's obc_driver->force_service_lookup is set).
> In addition it will cache sdp record associated with the connection and make it accessible in get_service_record.
>
> Christian Fetzer (8):
>   obexd: Add get_service_record to obc_transport
>   obexd: Provide SDP record in get_service_record
>   obexd: Read MAP client SDP attributes
>   obexd: Add Message Notification Server (MNS)
>   obexd: Add RegisterNotifications function
>   obexd: Add MAP notification dispatcher
>   obexd: Register MAP notification handler
>   obexd: Notify registered notification handlers
>
>  Makefile.obexd                |   4 +
>  doc/obex-api.txt              |   7 +
>  lib/sdp.h                     |   2 +
>  obexd/client/bluetooth.c      |  51 ++++++-
>  obexd/client/driver.h         |   1 +
>  obexd/client/map-dispatcher.c |  86 +++++++++++
>  obexd/client/map-dispatcher.h |  45 ++++++
>  obexd/client/map-event.h      |  42 +++++
>  obexd/client/map.c            | 144 +++++++++++++++++-
>  obexd/client/mns.c            | 346 ++++++++++++++++++++++++++++++++++++++++++
>  obexd/client/session.c        |  11 +-
>  obexd/client/session.h        |   2 +
>  obexd/client/transport.h      |   2 +
>  obexd/plugins/bluetooth.c     |   2 +
>  obexd/src/obexd.h             |   1 +
>  src/profile.c                 |  55 +++++++
>  16 files changed, 790 insertions(+), 11 deletions(-)
>  create mode 100644 obexd/client/map-dispatcher.c
>  create mode 100644 obexd/client/map-dispatcher.h
>  create mode 100644 obexd/client/map-event.h
>  create mode 100644 obexd/client/mns.c
>
> --
> 1.8.1.2

Did not like so much the thing with force_service_lookup although I
see that we gonna need it, but perhaps we should try to think about
other alternatives. The implementation of MNS as a proper driver is
what made us to integrate the server and client but we should go one
step forward and integrate client and server core specially the plugin
handling should be common to both client and server just the drivers
need to be different.


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC 0/8] MAP client: notification support
  2013-02-12  9:02 ` [RFC 0/8] MAP client: notification support Luiz Augusto von Dentz
@ 2013-02-14  8:54   ` Christian Fetzer
  0 siblings, 0 replies; 11+ messages in thread
From: Christian Fetzer @ 2013-02-14  8:54 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz

On 02/12/2013 10:02 AM, Luiz Augusto von Dentz wrote:
> Hi Christian,
>
> On Wed, Feb 6, 2013 at 4:45 PM, Christian Fetzer
> <christian.fetzer@oss.bmw-carit.de>  wrote:
>> From: Christian Fetzer<christian.fetzer@bmw-carit.de>
>>
>> This patchset adds the necessary blocks for receiving notifications in the MAP client.
>> So far this covers only bluetooth protocol related additions, leaving out end user D-Bus API changes.
>>
>> The patchset consists of the following parts:
>> - Message Notification Server (MNS)
>>    Once connected, the MNS will receive XML based event reports from the MSE and parse them into a struct
>>    for further processing.
>>
>> - RegisterNotification function
>>    The function sends the SetNotificationRegistration command to the MSE which will then try to connect
>>    to the MNS.
>>
>> - Notification dispatcher (that dispatches event reports by their MAS instance id to the correct client instance)
>>    The message access part of every client instance registers a notification handler function.
>>    The MNS will call the associated handler for all received event report.
>>
>> Since the dispatching needs to be done on the mas instance id, the message access part of the client
>> needs to be aware of the instance id of the server it connects to. Unfortunately this information is only
>> available as SDP attribute.
>>
>> Due to the current transport layer abstraction in obexd, the MAP client has no direct access to SDP.
>> Therefore I have extended obc_transport to allow concrete transports (like Bluetooth) to specify
>> a get_service_record function and made it available through obc_session_get_service_record.
>> This way, transports can provide additional service information to the client implementations.
>> The bluetooth transport will now always do a sdp lookup (if the driver's obc_driver->force_service_lookup is set).
>> In addition it will cache sdp record associated with the connection and make it accessible in get_service_record.
>>
>> Christian Fetzer (8):
>>    obexd: Add get_service_record to obc_transport
>>    obexd: Provide SDP record in get_service_record
>>    obexd: Read MAP client SDP attributes
>>    obexd: Add Message Notification Server (MNS)
>>    obexd: Add RegisterNotifications function
>>    obexd: Add MAP notification dispatcher
>>    obexd: Register MAP notification handler
>>    obexd: Notify registered notification handlers
>>
>>   Makefile.obexd                |   4 +
>>   doc/obex-api.txt              |   7 +
>>   lib/sdp.h                     |   2 +
>>   obexd/client/bluetooth.c      |  51 ++++++-
>>   obexd/client/driver.h         |   1 +
>>   obexd/client/map-dispatcher.c |  86 +++++++++++
>>   obexd/client/map-dispatcher.h |  45 ++++++
>>   obexd/client/map-event.h      |  42 +++++
>>   obexd/client/map.c            | 144 +++++++++++++++++-
>>   obexd/client/mns.c            | 346 ++++++++++++++++++++++++++++++++++++++++++
>>   obexd/client/session.c        |  11 +-
>>   obexd/client/session.h        |   2 +
>>   obexd/client/transport.h      |   2 +
>>   obexd/plugins/bluetooth.c     |   2 +
>>   obexd/src/obexd.h             |   1 +
>>   src/profile.c                 |  55 +++++++
>>   16 files changed, 790 insertions(+), 11 deletions(-)
>>   create mode 100644 obexd/client/map-dispatcher.c
>>   create mode 100644 obexd/client/map-dispatcher.h
>>   create mode 100644 obexd/client/map-event.h
>>   create mode 100644 obexd/client/mns.c
>>
>> --
>> 1.8.1.2
> Did not like so much the thing with force_service_lookup although I
> see that we gonna need it, but perhaps we should try to think about
> other alternatives. The implementation of MNS as a proper driver is
> what made us to integrate the server and client but we should go one
> step forward and integrate client and server core specially the plugin
> handling should be common to both client and server just the drivers
> need to be different.
One alternative might be doing the service lookup when needed.
Calling obc_session_get_service_record could trigger the lookup,
when there's no yet a cached sdp record available.
In case of MAP for example, when registering for notifications.
But, this would make the implementation more complex as we would need
obc_session_get_service_record to be asynchronous.
Personally, I don't see a big advantage in this.
Especially when we want to support newer profile versions later, we will 
need
to do the service lookup to get the remote profile version at the very 
beginning
of the session establishment.
What's your opinion on this? Any other ideas?

Indeed, the hard coded loading of client implementations is not very nice.
It would be better to have them loaded by plugin_init() that came with 
the server part.
I could send a patch that removes the static loading from 
obexd/client/manager.c,
adds OBEX_PLUGIN_DEFINE to all client plugins and adapts the makefile.
Is that the right approach? Should they be renamed and moved into the 
plugin directory as well?

Thanks and best regards,
Christian

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-02-14  8:54 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-06 14:45 [RFC 0/8] MAP client: notification support Christian Fetzer
2013-02-06 14:45 ` [RFC 1/8] obexd: Add get_service_record to obc_transport Christian Fetzer
2013-02-06 14:45 ` [RFC 2/8] obexd: Provide SDP record in get_service_record Christian Fetzer
2013-02-06 14:45 ` [RFC 3/8] obexd: Read MAP client SDP attributes Christian Fetzer
2013-02-06 14:45 ` [RFC 4/8] obexd: Add Message Notification Server (MNS) Christian Fetzer
2013-02-06 14:45 ` [RFC 5/8] obexd: Add RegisterNotifications function Christian Fetzer
2013-02-06 14:45 ` [RFC 6/8] obexd: Add MAP notification dispatcher Christian Fetzer
2013-02-06 14:45 ` [RFC 7/8] obexd: Register MAP notification handler Christian Fetzer
2013-02-06 14:45 ` [RFC 8/8] obexd: Notify registered notification handlers Christian Fetzer
2013-02-12  9:02 ` [RFC 0/8] MAP client: notification support Luiz Augusto von Dentz
2013-02-14  8:54   ` Christian Fetzer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.